[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:
committed by
James Bottomley
parent
dc8875e107
commit
860784c8a2
@@ -629,6 +629,16 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
|
|||||||
list_del(&evt_struct->list);
|
list_del(&evt_struct->list);
|
||||||
del_timer(&evt_struct->timer);
|
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);
|
dev_err(hostdata->dev, "send error %d\n", rc);
|
||||||
atomic_inc(&hostdata->request_limit);
|
atomic_inc(&hostdata->request_limit);
|
||||||
goto send_error;
|
goto send_error;
|
||||||
@@ -976,11 +986,14 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
|
|||||||
int rsp_rc;
|
int rsp_rc;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u16 lun = lun_from_dev(cmd->device);
|
u16 lun = lun_from_dev(cmd->device);
|
||||||
|
unsigned long wait_switch = 0;
|
||||||
|
|
||||||
/* First, find this command in our sent list so we can figure
|
/* First, find this command in our sent list so we can figure
|
||||||
* out the correct tag
|
* out the correct tag
|
||||||
*/
|
*/
|
||||||
spin_lock_irqsave(hostdata->host->host_lock, flags);
|
spin_lock_irqsave(hostdata->host->host_lock, flags);
|
||||||
|
wait_switch = jiffies + (init_timeout * HZ);
|
||||||
|
do {
|
||||||
found_evt = NULL;
|
found_evt = NULL;
|
||||||
list_for_each_entry(tmp_evt, &hostdata->sent, list) {
|
list_for_each_entry(tmp_evt, &hostdata->sent, list) {
|
||||||
if (tmp_evt->cmnd == cmd) {
|
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);
|
evt = get_event_struct(&hostdata->pool);
|
||||||
if (evt == NULL) {
|
if (evt == NULL) {
|
||||||
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
|
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;
|
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->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
|
||||||
tsk_mgmt->task_tag = (u64) found_evt;
|
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;
|
evt->sync_srp = &srp_rsp;
|
||||||
|
|
||||||
init_completion(&evt->comp);
|
init_completion(&evt->comp);
|
||||||
rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
|
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);
|
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) {
|
if (rsp_rc != 0) {
|
||||||
sdev_printk(KERN_ERR, cmd->device,
|
sdev_printk(KERN_ERR, cmd->device,
|
||||||
"failed to send abort() event. rc=%d\n", rsp_rc);
|
"failed to send abort() event. rc=%d\n", rsp_rc);
|
||||||
return FAILED;
|
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);
|
wait_for_completion(&evt->comp);
|
||||||
|
|
||||||
/* make sure we got a good response */
|
/* 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;
|
int rsp_rc;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u16 lun = lun_from_dev(cmd->device);
|
u16 lun = lun_from_dev(cmd->device);
|
||||||
|
unsigned long wait_switch = 0;
|
||||||
|
|
||||||
spin_lock_irqsave(hostdata->host->host_lock, flags);
|
spin_lock_irqsave(hostdata->host->host_lock, flags);
|
||||||
|
wait_switch = jiffies + (init_timeout * HZ);
|
||||||
|
do {
|
||||||
evt = get_event_struct(&hostdata->pool);
|
evt = get_event_struct(&hostdata->pool);
|
||||||
if (evt == NULL) {
|
if (evt == NULL) {
|
||||||
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
|
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;
|
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->lun = ((u64) lun) << 48;
|
||||||
tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
|
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;
|
evt->sync_srp = &srp_rsp;
|
||||||
|
|
||||||
init_completion(&evt->comp);
|
init_completion(&evt->comp);
|
||||||
rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
|
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);
|
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) {
|
if (rsp_rc != 0) {
|
||||||
sdev_printk(KERN_ERR, cmd->device,
|
sdev_printk(KERN_ERR, cmd->device,
|
||||||
"failed to send reset event. rc=%d\n", rsp_rc);
|
"failed to send reset event. rc=%d\n", rsp_rc);
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
|
||||||
|
(((u64) lun) << 48));
|
||||||
|
|
||||||
wait_for_completion(&evt->comp);
|
wait_for_completion(&evt->comp);
|
||||||
|
|
||||||
/* make sure we got a good response */
|
/* make sure we got a good response */
|
||||||
|
Reference in New Issue
Block a user