[SCSI] libsas: misc fixes to the eh path
- Correct one use after free of the sas task - update the reset required path to move straight to LUN reset - make the bigger hammer actually reset something instead of just trying to clear all the tasks. Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
@@ -498,10 +498,10 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Try to reset a device */
|
/* Try to reset a device */
|
||||||
static int try_to_reset_cmd_device(struct Scsi_Host *shost,
|
static int try_to_reset_cmd_device(struct scsi_cmnd *cmd)
|
||||||
struct scsi_cmnd *cmd)
|
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
struct Scsi_Host *shost = cmd->device->host;
|
||||||
|
|
||||||
if (!shost->hostt->eh_device_reset_handler)
|
if (!shost->hostt->eh_device_reset_handler)
|
||||||
goto try_bus_reset;
|
goto try_bus_reset;
|
||||||
@@ -541,6 +541,12 @@ Again:
|
|||||||
need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET;
|
need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET;
|
||||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||||
|
|
||||||
|
if (need_reset) {
|
||||||
|
SAS_DPRINTK("%s: task 0x%p requests reset\n",
|
||||||
|
__FUNCTION__, task);
|
||||||
|
goto reset;
|
||||||
|
}
|
||||||
|
|
||||||
SAS_DPRINTK("trying to find task 0x%p\n", task);
|
SAS_DPRINTK("trying to find task 0x%p\n", task);
|
||||||
res = sas_scsi_find_task(task);
|
res = sas_scsi_find_task(task);
|
||||||
|
|
||||||
@@ -551,18 +557,15 @@ Again:
|
|||||||
SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
|
SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
|
||||||
task);
|
task);
|
||||||
sas_eh_finish_cmd(cmd);
|
sas_eh_finish_cmd(cmd);
|
||||||
if (need_reset)
|
|
||||||
try_to_reset_cmd_device(shost, cmd);
|
|
||||||
continue;
|
continue;
|
||||||
case TASK_IS_ABORTED:
|
case TASK_IS_ABORTED:
|
||||||
SAS_DPRINTK("%s: task 0x%p is aborted\n",
|
SAS_DPRINTK("%s: task 0x%p is aborted\n",
|
||||||
__FUNCTION__, task);
|
__FUNCTION__, task);
|
||||||
sas_eh_finish_cmd(cmd);
|
sas_eh_finish_cmd(cmd);
|
||||||
if (need_reset)
|
|
||||||
try_to_reset_cmd_device(shost, cmd);
|
|
||||||
continue;
|
continue;
|
||||||
case TASK_IS_AT_LU:
|
case TASK_IS_AT_LU:
|
||||||
SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
|
SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
|
||||||
|
reset:
|
||||||
tmf_resp = sas_recover_lu(task->dev, cmd);
|
tmf_resp = sas_recover_lu(task->dev, cmd);
|
||||||
if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
|
if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
|
||||||
SAS_DPRINTK("dev %016llx LU %x is "
|
SAS_DPRINTK("dev %016llx LU %x is "
|
||||||
@@ -570,8 +573,6 @@ Again:
|
|||||||
SAS_ADDR(task->dev),
|
SAS_ADDR(task->dev),
|
||||||
cmd->device->lun);
|
cmd->device->lun);
|
||||||
sas_eh_finish_cmd(cmd);
|
sas_eh_finish_cmd(cmd);
|
||||||
if (need_reset)
|
|
||||||
try_to_reset_cmd_device(shost, cmd);
|
|
||||||
sas_scsi_clear_queue_lu(work_q, cmd);
|
sas_scsi_clear_queue_lu(work_q, cmd);
|
||||||
goto Again;
|
goto Again;
|
||||||
}
|
}
|
||||||
@@ -582,15 +583,15 @@ Again:
|
|||||||
task);
|
task);
|
||||||
tmf_resp = sas_recover_I_T(task->dev);
|
tmf_resp = sas_recover_I_T(task->dev);
|
||||||
if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
|
if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
|
||||||
|
struct domain_device *dev = task->dev;
|
||||||
SAS_DPRINTK("I_T %016llx recovered\n",
|
SAS_DPRINTK("I_T %016llx recovered\n",
|
||||||
SAS_ADDR(task->dev->sas_addr));
|
SAS_ADDR(task->dev->sas_addr));
|
||||||
sas_eh_finish_cmd(cmd);
|
sas_eh_finish_cmd(cmd);
|
||||||
if (need_reset)
|
sas_scsi_clear_queue_I_T(work_q, dev);
|
||||||
try_to_reset_cmd_device(shost, cmd);
|
|
||||||
sas_scsi_clear_queue_I_T(work_q, task->dev);
|
|
||||||
goto Again;
|
goto Again;
|
||||||
}
|
}
|
||||||
/* Hammer time :-) */
|
/* Hammer time :-) */
|
||||||
|
try_to_reset_cmd_device(cmd);
|
||||||
if (i->dft->lldd_clear_nexus_port) {
|
if (i->dft->lldd_clear_nexus_port) {
|
||||||
struct asd_sas_port *port = task->dev->port;
|
struct asd_sas_port *port = task->dev->port;
|
||||||
SAS_DPRINTK("clearing nexus for port:%d\n",
|
SAS_DPRINTK("clearing nexus for port:%d\n",
|
||||||
@@ -600,8 +601,6 @@ Again:
|
|||||||
SAS_DPRINTK("clear nexus port:%d "
|
SAS_DPRINTK("clear nexus port:%d "
|
||||||
"succeeded\n", port->id);
|
"succeeded\n", port->id);
|
||||||
sas_eh_finish_cmd(cmd);
|
sas_eh_finish_cmd(cmd);
|
||||||
if (need_reset)
|
|
||||||
try_to_reset_cmd_device(shost, cmd);
|
|
||||||
sas_scsi_clear_queue_port(work_q,
|
sas_scsi_clear_queue_port(work_q,
|
||||||
port);
|
port);
|
||||||
goto Again;
|
goto Again;
|
||||||
@@ -614,8 +613,6 @@ Again:
|
|||||||
SAS_DPRINTK("clear nexus ha "
|
SAS_DPRINTK("clear nexus ha "
|
||||||
"succeeded\n");
|
"succeeded\n");
|
||||||
sas_eh_finish_cmd(cmd);
|
sas_eh_finish_cmd(cmd);
|
||||||
if (need_reset)
|
|
||||||
try_to_reset_cmd_device(shost, cmd);
|
|
||||||
goto clear_q;
|
goto clear_q;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -629,8 +626,6 @@ Again:
|
|||||||
cmd->device->lun);
|
cmd->device->lun);
|
||||||
|
|
||||||
sas_eh_finish_cmd(cmd);
|
sas_eh_finish_cmd(cmd);
|
||||||
if (need_reset)
|
|
||||||
try_to_reset_cmd_device(shost, cmd);
|
|
||||||
goto clear_q;
|
goto clear_q;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user