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

ncr5380: Correctly clear command pointers and lists after bus reset

Commands subject to exception handling are to be returned to the scsi
mid-layer. Make sure that the various command pointers and command lists
in the low-level driver are correctly cleansed of affected commands.

This fixes some bugs that I accidentally introduced in v4.5-rc1 including
the removal of INIT_LIST_HEAD for the 'autosense' and 'disconnected'
command lists, and the possible NULL pointer dereference in
NCR5380_bus_reset() that was reported by Dan Carpenter.

hostdata->sensing may also point to an affected command so this pointer
also has to be cleared. The abort handler calls complete_cmd() to take
care of this; let's have the bus reset handler do the same.

The issue queue may also contain an affected command. If so, remove it.
This also follows the abort handler logic.
Reported-by: default avatarDan Carpenter <dan.carpenter@oracle.com>
Fixes: 62717f53 ("ncr5380: Implement new eh_bus_reset_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 c6fff322
...@@ -2450,7 +2450,16 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) ...@@ -2450,7 +2450,16 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
* commands! * commands!
*/ */
if (list_del_cmd(&hostdata->unissued, cmd)) {
cmd->result = DID_RESET << 16;
cmd->scsi_done(cmd);
}
if (hostdata->selecting) {
hostdata->selecting->result = DID_RESET << 16;
complete_cmd(instance, hostdata->selecting);
hostdata->selecting = NULL; hostdata->selecting = NULL;
}
list_for_each_entry(ncmd, &hostdata->disconnected, list) { list_for_each_entry(ncmd, &hostdata->disconnected, list) {
struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
...@@ -2458,6 +2467,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) ...@@ -2458,6 +2467,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
set_host_byte(cmd, DID_RESET); set_host_byte(cmd, DID_RESET);
cmd->scsi_done(cmd); cmd->scsi_done(cmd);
} }
INIT_LIST_HEAD(&hostdata->disconnected);
list_for_each_entry(ncmd, &hostdata->autosense, list) { list_for_each_entry(ncmd, &hostdata->autosense, list) {
struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
...@@ -2465,6 +2475,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) ...@@ -2465,6 +2475,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
set_host_byte(cmd, DID_RESET); set_host_byte(cmd, DID_RESET);
cmd->scsi_done(cmd); cmd->scsi_done(cmd);
} }
INIT_LIST_HEAD(&hostdata->autosense);
if (hostdata->connected) { if (hostdata->connected) {
set_host_byte(hostdata->connected, DID_RESET); set_host_byte(hostdata->connected, DID_RESET);
...@@ -2472,12 +2483,6 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) ...@@ -2472,12 +2483,6 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
hostdata->connected = NULL; hostdata->connected = NULL;
} }
if (hostdata->sensing) {
set_host_byte(hostdata->connected, DID_RESET);
complete_cmd(instance, hostdata->sensing);
hostdata->sensing = NULL;
}
for (i = 0; i < 8; ++i) for (i = 0; i < 8; ++i)
hostdata->busy[i] = 0; hostdata->busy[i] = 0;
#ifdef REAL_DMA #ifdef REAL_DMA
......
...@@ -2646,7 +2646,16 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) ...@@ -2646,7 +2646,16 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
* commands! * commands!
*/ */
if (list_del_cmd(&hostdata->unissued, cmd)) {
cmd->result = DID_RESET << 16;
cmd->scsi_done(cmd);
}
if (hostdata->selecting) {
hostdata->selecting->result = DID_RESET << 16;
complete_cmd(instance, hostdata->selecting);
hostdata->selecting = NULL; hostdata->selecting = NULL;
}
list_for_each_entry(ncmd, &hostdata->disconnected, list) { list_for_each_entry(ncmd, &hostdata->disconnected, list) {
struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
...@@ -2654,6 +2663,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) ...@@ -2654,6 +2663,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
set_host_byte(cmd, DID_RESET); set_host_byte(cmd, DID_RESET);
cmd->scsi_done(cmd); cmd->scsi_done(cmd);
} }
INIT_LIST_HEAD(&hostdata->disconnected);
list_for_each_entry(ncmd, &hostdata->autosense, list) { list_for_each_entry(ncmd, &hostdata->autosense, list) {
struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
...@@ -2661,6 +2671,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) ...@@ -2661,6 +2671,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
set_host_byte(cmd, DID_RESET); set_host_byte(cmd, DID_RESET);
cmd->scsi_done(cmd); cmd->scsi_done(cmd);
} }
INIT_LIST_HEAD(&hostdata->autosense);
if (hostdata->connected) { if (hostdata->connected) {
set_host_byte(hostdata->connected, DID_RESET); set_host_byte(hostdata->connected, DID_RESET);
...@@ -2668,12 +2679,6 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) ...@@ -2668,12 +2679,6 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
hostdata->connected = NULL; hostdata->connected = NULL;
} }
if (hostdata->sensing) {
set_host_byte(hostdata->connected, DID_RESET);
complete_cmd(instance, hostdata->sensing);
hostdata->sensing = NULL;
}
#ifdef SUPPORT_TAGS #ifdef SUPPORT_TAGS
free_all_tags(hostdata); free_all_tags(hostdata);
#endif #endif
......
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