| From 0a0bcf9ed483728d0e174d3b5ac2104e69a9952f Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 27 Sep 2018 11:17:11 +1000 |
| Subject: scsi: NCR5380: Check for bus reset |
| |
| From: Finn Thain <fthain@telegraphics.com.au> |
| |
| [ Upstream commit 6b0e87a6aafe12d75c2bea6fc8e49e88b98b3083 ] |
| |
| The SR_RST bit isn't latched. Hence, detecting a bus reset isn't reliable. |
| When it is detected, the right thing to do is to drop all connected and |
| disconnected commands. The code for that is already present so refactor it and |
| call it when SR_RST is set. |
| |
| Tested-by: Michael Schmitz <schmitzmic@gmail.com> |
| Signed-off-by: Finn Thain <fthain@telegraphics.com.au> |
| Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/scsi/NCR5380.c | 74 +++++++++++++++++++++++++----------------- |
| 1 file changed, 45 insertions(+), 29 deletions(-) |
| |
| diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c |
| index bce6c990d060a..8ec68dcc0cc4a 100644 |
| --- a/drivers/scsi/NCR5380.c |
| +++ b/drivers/scsi/NCR5380.c |
| @@ -131,6 +131,7 @@ |
| |
| static int do_abort(struct Scsi_Host *); |
| static void do_reset(struct Scsi_Host *); |
| +static void bus_reset_cleanup(struct Scsi_Host *); |
| |
| /** |
| * initialize_SCp - init the scsi pointer field |
| @@ -885,7 +886,14 @@ static irqreturn_t __maybe_unused NCR5380_intr(int irq, void *dev_id) |
| /* Probably Bus Reset */ |
| NCR5380_read(RESET_PARITY_INTERRUPT_REG); |
| |
| - dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n"); |
| + if (sr & SR_RST) { |
| + /* Certainly Bus Reset */ |
| + shost_printk(KERN_WARNING, instance, |
| + "bus reset interrupt\n"); |
| + bus_reset_cleanup(instance); |
| + } else { |
| + dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n"); |
| + } |
| #ifdef SUN3_SCSI_VME |
| dregs->csr |= CSR_DMA_ENABLE; |
| #endif |
| @@ -2297,31 +2305,12 @@ out: |
| } |
| |
| |
| -/** |
| - * NCR5380_host_reset - reset the SCSI host |
| - * @cmd: SCSI command undergoing EH |
| - * |
| - * Returns SUCCESS |
| - */ |
| - |
| -static int NCR5380_host_reset(struct scsi_cmnd *cmd) |
| +static void bus_reset_cleanup(struct Scsi_Host *instance) |
| { |
| - struct Scsi_Host *instance = cmd->device->host; |
| struct NCR5380_hostdata *hostdata = shost_priv(instance); |
| int i; |
| - unsigned long flags; |
| struct NCR5380_cmd *ncmd; |
| |
| - spin_lock_irqsave(&hostdata->lock, flags); |
| - |
| -#if (NDEBUG & NDEBUG_ANY) |
| - shost_printk(KERN_INFO, instance, __func__); |
| -#endif |
| - NCR5380_dprint(NDEBUG_ANY, instance); |
| - NCR5380_dprint_phase(NDEBUG_ANY, instance); |
| - |
| - do_reset(instance); |
| - |
| /* reset NCR registers */ |
| NCR5380_write(MODE_REG, MR_BASE); |
| NCR5380_write(TARGET_COMMAND_REG, 0); |
| @@ -2333,14 +2322,6 @@ static int NCR5380_host_reset(struct scsi_cmnd *cmd) |
| * commands! |
| */ |
| |
| - list_for_each_entry(ncmd, &hostdata->unissued, list) { |
| - struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); |
| - |
| - cmd->result = DID_RESET << 16; |
| - cmd->scsi_done(cmd); |
| - } |
| - INIT_LIST_HEAD(&hostdata->unissued); |
| - |
| if (hostdata->selecting) { |
| hostdata->selecting->result = DID_RESET << 16; |
| complete_cmd(instance, hostdata->selecting); |
| @@ -2374,6 +2355,41 @@ static int NCR5380_host_reset(struct scsi_cmnd *cmd) |
| |
| queue_work(hostdata->work_q, &hostdata->main_task); |
| maybe_release_dma_irq(instance); |
| +} |
| + |
| +/** |
| + * NCR5380_host_reset - reset the SCSI host |
| + * @cmd: SCSI command undergoing EH |
| + * |
| + * Returns SUCCESS |
| + */ |
| + |
| +static int NCR5380_host_reset(struct scsi_cmnd *cmd) |
| +{ |
| + struct Scsi_Host *instance = cmd->device->host; |
| + struct NCR5380_hostdata *hostdata = shost_priv(instance); |
| + unsigned long flags; |
| + struct NCR5380_cmd *ncmd; |
| + |
| + spin_lock_irqsave(&hostdata->lock, flags); |
| + |
| +#if (NDEBUG & NDEBUG_ANY) |
| + shost_printk(KERN_INFO, instance, __func__); |
| +#endif |
| + NCR5380_dprint(NDEBUG_ANY, instance); |
| + NCR5380_dprint_phase(NDEBUG_ANY, instance); |
| + |
| + list_for_each_entry(ncmd, &hostdata->unissued, list) { |
| + struct scsi_cmnd *scmd = NCR5380_to_scmd(ncmd); |
| + |
| + scmd->result = DID_RESET << 16; |
| + scmd->scsi_done(scmd); |
| + } |
| + INIT_LIST_HEAD(&hostdata->unissued); |
| + |
| + do_reset(instance); |
| + bus_reset_cleanup(instance); |
| + |
| spin_unlock_irqrestore(&hostdata->lock, flags); |
| |
| return SUCCESS; |
| -- |
| 2.20.1 |
| |