From: Finn Thain Date: Mon, 22 Feb 2016 23:07:04 +0000 (+1100) Subject: ncr5380: Correctly clear command pointers and lists after bus reset X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=1884c2838f31e6bf20f21459ed9921f8c92ed3ef;p=openwrt%2Fstaging%2Fblogic.git 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: Dan Carpenter Fixes: 62717f537e1b ("ncr5380: Implement new eh_bus_reset_handler") Tested-by: Michael Schmitz Cc: # 4.5 Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index d72867257346..ce577f413328 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -2450,7 +2450,16 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) * commands! */ - hostdata->selecting = NULL; + 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; + } list_for_each_entry(ncmd, &hostdata->disconnected, list) { struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); @@ -2458,6 +2467,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) set_host_byte(cmd, DID_RESET); cmd->scsi_done(cmd); } + INIT_LIST_HEAD(&hostdata->disconnected); list_for_each_entry(ncmd, &hostdata->autosense, list) { struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); @@ -2465,6 +2475,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) set_host_byte(cmd, DID_RESET); cmd->scsi_done(cmd); } + INIT_LIST_HEAD(&hostdata->autosense); if (hostdata->connected) { set_host_byte(hostdata->connected, DID_RESET); @@ -2472,12 +2483,6 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) 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) hostdata->busy[i] = 0; #ifdef REAL_DMA diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c index e65478651ca9..af0421829701 100644 --- a/drivers/scsi/atari_NCR5380.c +++ b/drivers/scsi/atari_NCR5380.c @@ -2646,7 +2646,16 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) * commands! */ - hostdata->selecting = NULL; + 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; + } list_for_each_entry(ncmd, &hostdata->disconnected, list) { struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); @@ -2654,6 +2663,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) set_host_byte(cmd, DID_RESET); cmd->scsi_done(cmd); } + INIT_LIST_HEAD(&hostdata->disconnected); list_for_each_entry(ncmd, &hostdata->autosense, list) { struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); @@ -2661,6 +2671,7 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) set_host_byte(cmd, DID_RESET); cmd->scsi_done(cmd); } + INIT_LIST_HEAD(&hostdata->autosense); if (hostdata->connected) { set_host_byte(hostdata->connected, DID_RESET); @@ -2668,12 +2679,6 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd) hostdata->connected = NULL; } - if (hostdata->sensing) { - set_host_byte(hostdata->connected, DID_RESET); - complete_cmd(instance, hostdata->sensing); - hostdata->sensing = NULL; - } - #ifdef SUPPORT_TAGS free_all_tags(hostdata); #endif