[PATCH v2 66/72] ncr5380: Fix soft lockups

Finn Thain
2015-12-06T01:32:32Z

[-- Attachment #1: ncr5380-max_sectors --]
[-- Type: text/plain, Size: 3098 bytes --]

When exercising dmx3191d using sequential IO from dd, the driver is sent
512 KiB WRITE commands and 128 KiB READs. For a PIO transfer, the rate is
is only about 300 KiB/s, so these are long-running commands.

Because of the rudimentary design of the chip, it is necessary to poll the
SCSI bus signals during PIO and this tends to hog the CPU. The driver will
accept new commands while others execute, and this causes a soft lockup
because the workqueue item will not terminate until the issue queue is
emptied.

Fix the unresponsiveness and soft lockup issues by calling cond_resched()
after each command is completed and by limiting the transfer size for
drivers that don't use DMA in information transfer phases.

Signed-off-by: Finn Thain <fthain@telegraphics.com.au>

---
drivers/scsi/NCR5380.c | 10 ++++++++--
drivers/scsi/atari_NCR5380.c | 10 ++++++++--
2 files changed, 16 insertions(+), 4 deletions(-)

Index: linux/drivers/scsi/NCR5380.c
===================================================================
--- linux.orig/drivers/scsi/NCR5380.c 2015-12-06 12:31:11.000000000 +1100
+++ linux/drivers/scsi/NCR5380.c 2015-12-06 12:31:14.000000000 +1100
@@ -643,6 +643,10 @@ static int NCR5380_init(struct Scsi_Host

prepare_info(instance);

+#ifndef REAL_DMA
+ instance->max_sectors = 128;
+#endif
+
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(TARGET_COMMAND_REG, 0);
@@ -885,10 +889,10 @@ static void NCR5380_main(struct work_str
struct scsi_cmnd *cmd;
int done;

- spin_lock_irq(&hostdata->lock);
do {
done = 1;

+ spin_lock_irq(&hostdata->lock);
while (!hostdata->connected &&
(cmd = dequeue_next_cmd(instance))) {

@@ -925,8 +929,10 @@ static void NCR5380_main(struct work_str
NCR5380_information_transfer(instance);
done = 0;
}
+ spin_unlock_irq(&hostdata->lock);
+ if (!done)
+ cond_resched();
} while (!done);
- spin_unlock_irq(&hostdata->lock);
}

#ifndef DONT_USE_INTR
Index: linux/drivers/scsi/atari_NCR5380.c
===================================================================
--- linux.orig/drivers/scsi/atari_NCR5380.c 2015-12-06 12:31:12.000000000 +1100
+++ linux/drivers/scsi/atari_NCR5380.c 2015-12-06 12:31:14.000000000 +1100
@@ -678,6 +678,10 @@ static int __init NCR5380_init(struct Sc

prepare_info(instance);

+#ifndef REAL_DMA
+ instance->max_sectors = 128;
+#endif
+
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(TARGET_COMMAND_REG, 0);
@@ -971,10 +975,10 @@ static void NCR5380_main(struct work_str
* alter queues and touch the Falcon lock.
*/

- spin_lock_irq(&hostdata->lock);
do {
done = 1;

+ spin_lock_irq(&hostdata->lock);
while (!hostdata->connected &&
(cmd = dequeue_next_cmd(instance))) {

@@ -1021,8 +1025,10 @@ static void NCR5380_main(struct work_str
NCR5380_information_transfer(instance);
done = 0;
}
+ spin_unlock_irq(&hostdata->lock);
+ if (!done)
+ cond_resched();
} while (!done);
- spin_unlock_irq(&hostdata->lock);
}