[SCSI] ibmvscsi: requeue while CRQ closed
CRQ send errors that return with H_CLOSED should return with SCSI_MLQUEUE_HOST_BUSY until firmware alerts the client of a CRQ transport event. The transport event will either reinitialize and requeue the requests or fail and return IO with DID_ERROR. To avoid failing the eh_* functions while re-attaching to the server adapter this will retry for a period of time while ibmvscsi_send_srp_event returns SCSI_MLQUEUE_HOST_BUSY. In ibmvscsi_eh_abort_handler() the loop includes the search of the event list. The lock on the hostdata is dropped while waiting to try again after failing ibmvscsi_send_srp_event. The event could have been purged if a login was in progress when the function was called. In ibmvscsi_eh_device_reset_handler() the loop includes the call to get_event_struct() because a failing call to ibmvscsi_send_srp_event() will have freed the event struct. Signed-off-by: Robert Jennings <rcj@linux.vnet.ibm.com> Signed-off-by: Brian King <brking@linux.vnet.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
Родитель
dc8875e107
Коммит
860784c8a2
|
@ -629,6 +629,16 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
|
|||
list_del(&evt_struct->list);
|
||||
del_timer(&evt_struct->timer);
|
||||
|
||||
/* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY.
|
||||
* Firmware will send a CRQ with a transport event (0xFF) to
|
||||
* tell this client what has happened to the transport. This
|
||||
* will be handled in ibmvscsi_handle_crq()
|
||||
*/
|
||||
if (rc == H_CLOSED) {
|
||||
dev_warn(hostdata->dev, "send warning. "
|
||||
"Receive queue closed, will retry.\n");
|
||||
goto send_busy;
|
||||
}
|
||||
dev_err(hostdata->dev, "send error %d\n", rc);
|
||||
atomic_inc(&hostdata->request_limit);
|
||||
goto send_error;
|
||||
|
@ -976,11 +986,14 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
|
|||
int rsp_rc;
|
||||
unsigned long flags;
|
||||
u16 lun = lun_from_dev(cmd->device);
|
||||
unsigned long wait_switch = 0;
|
||||
|
||||
/* First, find this command in our sent list so we can figure
|
||||
* out the correct tag
|
||||
*/
|
||||
spin_lock_irqsave(hostdata->host->host_lock, flags);
|
||||
wait_switch = jiffies + (init_timeout * HZ);
|
||||
do {
|
||||
found_evt = NULL;
|
||||
list_for_each_entry(tmp_evt, &hostdata->sent, list) {
|
||||
if (tmp_evt->cmnd == cmd) {
|
||||
|
@ -997,7 +1010,8 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
|
|||
evt = get_event_struct(&hostdata->pool);
|
||||
if (evt == NULL) {
|
||||
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
|
||||
sdev_printk(KERN_ERR, cmd->device, "failed to allocate abort event\n");
|
||||
sdev_printk(KERN_ERR, cmd->device,
|
||||
"failed to allocate abort event\n");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
|
@ -1015,19 +1029,31 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
|
|||
tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
|
||||
tsk_mgmt->task_tag = (u64) found_evt;
|
||||
|
||||
sdev_printk(KERN_INFO, cmd->device, "aborting command. lun 0x%lx, tag 0x%lx\n",
|
||||
tsk_mgmt->lun, tsk_mgmt->task_tag);
|
||||
|
||||
evt->sync_srp = &srp_rsp;
|
||||
|
||||
init_completion(&evt->comp);
|
||||
rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
|
||||
|
||||
if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
|
||||
break;
|
||||
|
||||
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
|
||||
msleep(10);
|
||||
spin_lock_irqsave(hostdata->host->host_lock, flags);
|
||||
} while (time_before(jiffies, wait_switch));
|
||||
|
||||
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
|
||||
|
||||
if (rsp_rc != 0) {
|
||||
sdev_printk(KERN_ERR, cmd->device,
|
||||
"failed to send abort() event. rc=%d\n", rsp_rc);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
sdev_printk(KERN_INFO, cmd->device,
|
||||
"aborting command. lun 0x%lx, tag 0x%lx\n",
|
||||
(((u64) lun) << 48), (u64) found_evt);
|
||||
|
||||
wait_for_completion(&evt->comp);
|
||||
|
||||
/* make sure we got a good response */
|
||||
|
@ -1099,12 +1125,16 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
|
|||
int rsp_rc;
|
||||
unsigned long flags;
|
||||
u16 lun = lun_from_dev(cmd->device);
|
||||
unsigned long wait_switch = 0;
|
||||
|
||||
spin_lock_irqsave(hostdata->host->host_lock, flags);
|
||||
wait_switch = jiffies + (init_timeout * HZ);
|
||||
do {
|
||||
evt = get_event_struct(&hostdata->pool);
|
||||
if (evt == NULL) {
|
||||
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
|
||||
sdev_printk(KERN_ERR, cmd->device, "failed to allocate reset event\n");
|
||||
sdev_printk(KERN_ERR, cmd->device,
|
||||
"failed to allocate reset event\n");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
|
@ -1121,19 +1151,30 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
|
|||
tsk_mgmt->lun = ((u64) lun) << 48;
|
||||
tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
|
||||
|
||||
sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
|
||||
tsk_mgmt->lun);
|
||||
|
||||
evt->sync_srp = &srp_rsp;
|
||||
|
||||
init_completion(&evt->comp);
|
||||
rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
|
||||
|
||||
if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
|
||||
break;
|
||||
|
||||
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
|
||||
msleep(10);
|
||||
spin_lock_irqsave(hostdata->host->host_lock, flags);
|
||||
} while (time_before(jiffies, wait_switch));
|
||||
|
||||
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
|
||||
|
||||
if (rsp_rc != 0) {
|
||||
sdev_printk(KERN_ERR, cmd->device,
|
||||
"failed to send reset event. rc=%d\n", rsp_rc);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
|
||||
(((u64) lun) << 48));
|
||||
|
||||
wait_for_completion(&evt->comp);
|
||||
|
||||
/* make sure we got a good response */
|
||||
|
|
Загрузка…
Ссылка в новой задаче