summaryrefslogtreecommitdiff
path: root/drivers/scsi/NCR5380.c
diff options
context:
space:
mode:
authorFinn Thain <fthain@telegraphics.com.au>2016-01-03 08:06:07 +0300
committerMartin K. Petersen <martin.petersen@oracle.com>2016-01-07 05:43:09 +0300
commit0a4e36125451165847c6d4e7d5633d92e53f5c69 (patch)
tree9512674edc9e8fbdd229e8d585d0228184fab8ac /drivers/scsi/NCR5380.c
parentcd46140a9a2f8fe0208262dc5f4d1fba15c93063 (diff)
downloadlinux-0a4e36125451165847c6d4e7d5633d92e53f5c69.tar.xz
ncr5380: Fix soft lockups
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. 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. And although PDMA may run at several MiB/s, interrupts are disabled for the duration of the transfer. Fix the unresponsiveness and soft lockup issues by calling cond_resched() after each command is completed and by limiting max_sectors for drivers that don't implement real DMA. Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Reviewed-by: Hannes Reinecke <hare@suse.com> Tested-by: Ondrej Zary <linux@rainbow-software.org> Tested-by: Michael Schmitz <schmitzmic@gmail.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/NCR5380.c')
-rw-r--r--drivers/scsi/NCR5380.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 9616f397e134..38b03af36a6a 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -890,10 +890,10 @@ static void NCR5380_main(struct work_struct *work)
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))) {
@@ -930,8 +930,10 @@ static void NCR5380_main(struct work_struct *work)
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