Commit dc183965 authored by Finn Thain's avatar Finn Thain Committed by Martin K. Petersen

ncr5380: Forget aborted commands

The list structures and related logic used in the NCR5380 driver mean that
a command cannot be queued twice (i.e. can't appear on more than one queue
and can't appear on the same queue more than once).

The abort handler must forget the command so that the mid-layer can re-use
it. E.g. the ML may send it back to the LLD via via scsi_eh_get_sense().

Fix this and also fix two error paths, so that commands get forgotten iff
completed.

Fixes: 8b00c3d5 ("ncr5380: Implement new eh_abort_handler")
Tested-by: default avatarMichael Schmitz <schmitzmic@gmail.com>
Cc: <stable@vger.kernel.org> # 4.5
Signed-off-by: default avatarFinn Thain <fthain@telegraphics.com.au>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 71a00593
...@@ -1796,6 +1796,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) ...@@ -1796,6 +1796,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
do_abort(instance); do_abort(instance);
cmd->result = DID_ERROR << 16; cmd->result = DID_ERROR << 16;
complete_cmd(instance, cmd); complete_cmd(instance, cmd);
hostdata->connected = NULL;
return; return;
#endif #endif
case PHASE_DATAIN: case PHASE_DATAIN:
...@@ -1845,7 +1846,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) ...@@ -1845,7 +1846,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
sink = 1; sink = 1;
do_abort(instance); do_abort(instance);
cmd->result = DID_ERROR << 16; cmd->result = DID_ERROR << 16;
complete_cmd(instance, cmd);
/* XXX - need to source or sink data here, as appropriate */ /* XXX - need to source or sink data here, as appropriate */
} else } else
cmd->SCp.this_residual -= transfersize - len; cmd->SCp.this_residual -= transfersize - len;
...@@ -2294,14 +2294,14 @@ static bool list_del_cmd(struct list_head *haystack, ...@@ -2294,14 +2294,14 @@ static bool list_del_cmd(struct list_head *haystack,
* [disconnected -> connected ->]... * [disconnected -> connected ->]...
* [autosense -> connected ->] done * [autosense -> connected ->] done
* *
* If cmd is unissued then just remove it.
* If cmd is disconnected, try to select the target.
* If cmd is connected, try to send an abort message.
* If cmd is waiting for autosense, give it a chance to complete but check
* that it isn't left connected.
* If cmd was not found at all then presumably it has already been completed, * If cmd was not found at all then presumably it has already been completed,
* in which case return SUCCESS to try to avoid further EH measures. * in which case return SUCCESS to try to avoid further EH measures.
*
* If the command has not completed yet, we must not fail to find it. * If the command has not completed yet, we must not fail to find it.
* We have no option but to forget the aborted command (even if it still
* lacks sense data). The mid-layer may re-issue a command that is in error
* recovery (see scsi_send_eh_cmnd), but the logic and data structures in
* this driver are such that a command can appear on one queue only.
* *
* The lock protects driver data structures, but EH handlers also use it * The lock protects driver data structures, but EH handlers also use it
* to serialize their own execution and prevent their own re-entry. * to serialize their own execution and prevent their own re-entry.
...@@ -2327,6 +2327,7 @@ static int NCR5380_abort(struct scsi_cmnd *cmd) ...@@ -2327,6 +2327,7 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
"abort: removed %p from issue queue\n", cmd); "abort: removed %p from issue queue\n", cmd);
cmd->result = DID_ABORT << 16; cmd->result = DID_ABORT << 16;
cmd->scsi_done(cmd); /* No tag or busy flag to worry about */ cmd->scsi_done(cmd); /* No tag or busy flag to worry about */
goto out;
} }
if (hostdata->selecting == cmd) { if (hostdata->selecting == cmd) {
...@@ -2344,6 +2345,8 @@ static int NCR5380_abort(struct scsi_cmnd *cmd) ...@@ -2344,6 +2345,8 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
/* Can't call NCR5380_select() and send ABORT because that /* Can't call NCR5380_select() and send ABORT because that
* means releasing the lock. Need a bus reset. * means releasing the lock. Need a bus reset.
*/ */
set_host_byte(cmd, DID_ERROR);
complete_cmd(instance, cmd);
result = FAILED; result = FAILED;
goto out; goto out;
} }
...@@ -2351,45 +2354,9 @@ static int NCR5380_abort(struct scsi_cmnd *cmd) ...@@ -2351,45 +2354,9 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
if (hostdata->connected == cmd) { if (hostdata->connected == cmd) {
dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd); dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
hostdata->connected = NULL; hostdata->connected = NULL;
if (do_abort(instance)) {
set_host_byte(cmd, DID_ERROR);
complete_cmd(instance, cmd);
result = FAILED;
goto out;
}
set_host_byte(cmd, DID_ABORT);
#ifdef REAL_DMA #ifdef REAL_DMA
hostdata->dma_len = 0; hostdata->dma_len = 0;
#endif #endif
if (cmd->cmnd[0] == REQUEST_SENSE)
complete_cmd(instance, cmd);
else {
struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
/* Perform autosense for this command */
list_add(&ncmd->list, &hostdata->autosense);
}
}
if (list_find_cmd(&hostdata->autosense, cmd)) {
dsprintk(NDEBUG_ABORT, instance,
"abort: found %p on sense queue\n", cmd);
spin_unlock_irqrestore(&hostdata->lock, flags);
queue_work(hostdata->work_q, &hostdata->main_task);
msleep(1000);
spin_lock_irqsave(&hostdata->lock, flags);
if (list_del_cmd(&hostdata->autosense, cmd)) {
dsprintk(NDEBUG_ABORT, instance,
"abort: removed %p from sense queue\n", cmd);
set_host_byte(cmd, DID_ABORT);
complete_cmd(instance, cmd);
goto out;
}
}
if (hostdata->connected == cmd) {
dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
hostdata->connected = NULL;
if (do_abort(instance)) { if (do_abort(instance)) {
set_host_byte(cmd, DID_ERROR); set_host_byte(cmd, DID_ERROR);
complete_cmd(instance, cmd); complete_cmd(instance, cmd);
...@@ -2397,9 +2364,14 @@ static int NCR5380_abort(struct scsi_cmnd *cmd) ...@@ -2397,9 +2364,14 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
goto out; goto out;
} }
set_host_byte(cmd, DID_ABORT); set_host_byte(cmd, DID_ABORT);
#ifdef REAL_DMA complete_cmd(instance, cmd);
hostdata->dma_len = 0; goto out;
#endif }
if (list_del_cmd(&hostdata->autosense, cmd)) {
dsprintk(NDEBUG_ABORT, instance,
"abort: removed %p from sense queue\n", cmd);
set_host_byte(cmd, DID_ERROR);
complete_cmd(instance, cmd); complete_cmd(instance, cmd);
} }
......
...@@ -1907,6 +1907,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) ...@@ -1907,6 +1907,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
do_abort(instance); do_abort(instance);
cmd->result = DID_ERROR << 16; cmd->result = DID_ERROR << 16;
complete_cmd(instance, cmd); complete_cmd(instance, cmd);
hostdata->connected = NULL;
return; return;
#endif #endif
case PHASE_DATAIN: case PHASE_DATAIN:
...@@ -1964,7 +1965,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) ...@@ -1964,7 +1965,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
sink = 1; sink = 1;
do_abort(instance); do_abort(instance);
cmd->result = DID_ERROR << 16; cmd->result = DID_ERROR << 16;
complete_cmd(instance, cmd);
/* XXX - need to source or sink data here, as appropriate */ /* XXX - need to source or sink data here, as appropriate */
} else { } else {
#ifdef REAL_DMA #ifdef REAL_DMA
...@@ -2489,14 +2489,14 @@ static bool list_del_cmd(struct list_head *haystack, ...@@ -2489,14 +2489,14 @@ static bool list_del_cmd(struct list_head *haystack,
* [disconnected -> connected ->]... * [disconnected -> connected ->]...
* [autosense -> connected ->] done * [autosense -> connected ->] done
* *
* If cmd is unissued then just remove it.
* If cmd is disconnected, try to select the target.
* If cmd is connected, try to send an abort message.
* If cmd is waiting for autosense, give it a chance to complete but check
* that it isn't left connected.
* If cmd was not found at all then presumably it has already been completed, * If cmd was not found at all then presumably it has already been completed,
* in which case return SUCCESS to try to avoid further EH measures. * in which case return SUCCESS to try to avoid further EH measures.
*
* If the command has not completed yet, we must not fail to find it. * If the command has not completed yet, we must not fail to find it.
* We have no option but to forget the aborted command (even if it still
* lacks sense data). The mid-layer may re-issue a command that is in error
* recovery (see scsi_send_eh_cmnd), but the logic and data structures in
* this driver are such that a command can appear on one queue only.
* *
* The lock protects driver data structures, but EH handlers also use it * The lock protects driver data structures, but EH handlers also use it
* to serialize their own execution and prevent their own re-entry. * to serialize their own execution and prevent their own re-entry.
...@@ -2522,6 +2522,7 @@ static int NCR5380_abort(struct scsi_cmnd *cmd) ...@@ -2522,6 +2522,7 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
"abort: removed %p from issue queue\n", cmd); "abort: removed %p from issue queue\n", cmd);
cmd->result = DID_ABORT << 16; cmd->result = DID_ABORT << 16;
cmd->scsi_done(cmd); /* No tag or busy flag to worry about */ cmd->scsi_done(cmd); /* No tag or busy flag to worry about */
goto out;
} }
if (hostdata->selecting == cmd) { if (hostdata->selecting == cmd) {
...@@ -2539,6 +2540,8 @@ static int NCR5380_abort(struct scsi_cmnd *cmd) ...@@ -2539,6 +2540,8 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
/* Can't call NCR5380_select() and send ABORT because that /* Can't call NCR5380_select() and send ABORT because that
* means releasing the lock. Need a bus reset. * means releasing the lock. Need a bus reset.
*/ */
set_host_byte(cmd, DID_ERROR);
complete_cmd(instance, cmd);
result = FAILED; result = FAILED;
goto out; goto out;
} }
...@@ -2546,45 +2549,9 @@ static int NCR5380_abort(struct scsi_cmnd *cmd) ...@@ -2546,45 +2549,9 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
if (hostdata->connected == cmd) { if (hostdata->connected == cmd) {
dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd); dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
hostdata->connected = NULL; hostdata->connected = NULL;
if (do_abort(instance)) {
set_host_byte(cmd, DID_ERROR);
complete_cmd(instance, cmd);
result = FAILED;
goto out;
}
set_host_byte(cmd, DID_ABORT);
#ifdef REAL_DMA #ifdef REAL_DMA
hostdata->dma_len = 0; hostdata->dma_len = 0;
#endif #endif
if (cmd->cmnd[0] == REQUEST_SENSE)
complete_cmd(instance, cmd);
else {
struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
/* Perform autosense for this command */
list_add(&ncmd->list, &hostdata->autosense);
}
}
if (list_find_cmd(&hostdata->autosense, cmd)) {
dsprintk(NDEBUG_ABORT, instance,
"abort: found %p on sense queue\n", cmd);
spin_unlock_irqrestore(&hostdata->lock, flags);
queue_work(hostdata->work_q, &hostdata->main_task);
msleep(1000);
spin_lock_irqsave(&hostdata->lock, flags);
if (list_del_cmd(&hostdata->autosense, cmd)) {
dsprintk(NDEBUG_ABORT, instance,
"abort: removed %p from sense queue\n", cmd);
set_host_byte(cmd, DID_ABORT);
complete_cmd(instance, cmd);
goto out;
}
}
if (hostdata->connected == cmd) {
dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
hostdata->connected = NULL;
if (do_abort(instance)) { if (do_abort(instance)) {
set_host_byte(cmd, DID_ERROR); set_host_byte(cmd, DID_ERROR);
complete_cmd(instance, cmd); complete_cmd(instance, cmd);
...@@ -2592,9 +2559,14 @@ static int NCR5380_abort(struct scsi_cmnd *cmd) ...@@ -2592,9 +2559,14 @@ static int NCR5380_abort(struct scsi_cmnd *cmd)
goto out; goto out;
} }
set_host_byte(cmd, DID_ABORT); set_host_byte(cmd, DID_ABORT);
#ifdef REAL_DMA complete_cmd(instance, cmd);
hostdata->dma_len = 0; goto out;
#endif }
if (list_del_cmd(&hostdata->autosense, cmd)) {
dsprintk(NDEBUG_ABORT, instance,
"abort: removed %p from sense queue\n", cmd);
set_host_byte(cmd, DID_ERROR);
complete_cmd(instance, cmd); complete_cmd(instance, cmd);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment