aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFinn Thain <fthain@telegraphics.com.au>2014-11-12 00:12:08 -0500
committerChristoph Hellwig <hch@lst.de>2014-11-20 03:11:13 -0500
commit16b29e75a78ae03250233468b68f7ae467d3dc7a (patch)
treea5ba9e016d5557d2a6f5fb60dc83ae906ae771af
parentcbad48deb38d8e442db9760ca1f950cd24429707 (diff)
atari_scsi: Fix atari_scsi deadlocks on Falcon
Don't disable irqs when waiting for the ST DMA "lock"; its release may require an interrupt. Introduce stdma_try_lock() for use in soft irq context. atari_scsi now tells the SCSI mid-layer to defer queueing a command if the ST DMA lock is not available, as per Michael's patch: http://marc.info/?l=linux-m68k&m=139095335824863&w=2 The falcon_got_lock variable is race prone: we can't disable IRQs while waiting to acquire the lock, so after acquiring it there must be some interval during which falcon_got_lock remains false. Introduce stdma_is_locked_by() to replace falcon_got_lock. The falcon_got_lock tests in the EH handlers are incorrect these days. It can happen that an EH handler is called after a command completes normally. Remove these checks along with falcon_got_lock. Also remove the complicated and racy fairness wait queues. If fairness is an issue (when SCSI competes with IDE for the ST DMA interrupt), the solution is likely to be a lower value for host->can_queue. Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Reviewed-by: Hannes Reinecke <hare@suse.de> Tested-by: Michael Schmitz <schmitzmic@gmail.com> Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--arch/m68k/atari/stdma.c61
-rw-r--r--arch/m68k/include/asm/atari_stdma.h4
-rw-r--r--drivers/scsi/atari_NCR5380.c33
-rw-r--r--drivers/scsi/atari_scsi.c75
4 files changed, 66 insertions, 107 deletions
diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c
index ddbf43ca8858..e5a66596b116 100644
--- a/arch/m68k/atari/stdma.c
+++ b/arch/m68k/atari/stdma.c
@@ -59,6 +59,31 @@ static irqreturn_t stdma_int (int irq, void *dummy);
59/************************* End of Prototypes **************************/ 59/************************* End of Prototypes **************************/
60 60
61 61
62/**
63 * stdma_try_lock - attempt to acquire ST DMA interrupt "lock"
64 * @handler: interrupt handler to use after acquisition
65 *
66 * Returns !0 if lock was acquired; otherwise 0.
67 */
68
69int stdma_try_lock(irq_handler_t handler, void *data)
70{
71 unsigned long flags;
72
73 local_irq_save(flags);
74 if (stdma_locked) {
75 local_irq_restore(flags);
76 return 0;
77 }
78
79 stdma_locked = 1;
80 stdma_isr = handler;
81 stdma_isr_data = data;
82 local_irq_restore(flags);
83 return 1;
84}
85EXPORT_SYMBOL(stdma_try_lock);
86
62 87
63/* 88/*
64 * Function: void stdma_lock( isrfunc isr, void *data ) 89 * Function: void stdma_lock( isrfunc isr, void *data )
@@ -78,19 +103,10 @@ static irqreturn_t stdma_int (int irq, void *dummy);
78 103
79void stdma_lock(irq_handler_t handler, void *data) 104void stdma_lock(irq_handler_t handler, void *data)
80{ 105{
81 unsigned long flags;
82
83 local_irq_save(flags); /* protect lock */
84
85 /* Since the DMA is used for file system purposes, we 106 /* Since the DMA is used for file system purposes, we
86 have to sleep uninterruptible (there may be locked 107 have to sleep uninterruptible (there may be locked
87 buffers) */ 108 buffers) */
88 wait_event(stdma_wait, !stdma_locked); 109 wait_event(stdma_wait, stdma_try_lock(handler, data));
89
90 stdma_locked = 1;
91 stdma_isr = handler;
92 stdma_isr_data = data;
93 local_irq_restore(flags);
94} 110}
95EXPORT_SYMBOL(stdma_lock); 111EXPORT_SYMBOL(stdma_lock);
96 112
@@ -122,22 +138,25 @@ void stdma_release(void)
122EXPORT_SYMBOL(stdma_release); 138EXPORT_SYMBOL(stdma_release);
123 139
124 140
125/* 141/**
126 * Function: int stdma_others_waiting( void ) 142 * stdma_is_locked_by - allow lock holder to check whether it needs to release.
127 * 143 * @handler: interrupt handler previously used to acquire lock.
128 * Purpose: Check if someone waits for the ST-DMA lock.
129 *
130 * Inputs: none
131 *
132 * Returns: 0 if no one is waiting, != 0 otherwise
133 * 144 *
145 * Returns !0 if locked for the given handler; 0 otherwise.
134 */ 146 */
135 147
136int stdma_others_waiting(void) 148int stdma_is_locked_by(irq_handler_t handler)
137{ 149{
138 return waitqueue_active(&stdma_wait); 150 unsigned long flags;
151 int result;
152
153 local_irq_save(flags);
154 result = stdma_locked && (stdma_isr == handler);
155 local_irq_restore(flags);
156
157 return result;
139} 158}
140EXPORT_SYMBOL(stdma_others_waiting); 159EXPORT_SYMBOL(stdma_is_locked_by);
141 160
142 161
143/* 162/*
diff --git a/arch/m68k/include/asm/atari_stdma.h b/arch/m68k/include/asm/atari_stdma.h
index 8e389b7fa70c..d24e34d870dc 100644
--- a/arch/m68k/include/asm/atari_stdma.h
+++ b/arch/m68k/include/asm/atari_stdma.h
@@ -8,11 +8,11 @@
8 8
9/***************************** Prototypes *****************************/ 9/***************************** Prototypes *****************************/
10 10
11int stdma_try_lock(irq_handler_t, void *);
11void stdma_lock(irq_handler_t handler, void *data); 12void stdma_lock(irq_handler_t handler, void *data);
12void stdma_release( void ); 13void stdma_release( void );
13int stdma_others_waiting( void );
14int stdma_islocked( void ); 14int stdma_islocked( void );
15void *stdma_locked_by( void ); 15int stdma_is_locked_by(irq_handler_t);
16void stdma_init( void ); 16void stdma_init( void );
17 17
18/************************* End of Prototypes **************************/ 18/************************* End of Prototypes **************************/
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 4eeb9684977b..7a6f90ce0316 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -879,10 +879,10 @@ static void NCR5380_exit(struct Scsi_Host *instance)
879 * 879 *
880 */ 880 */
881 881
882static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd, 882static int NCR5380_queue_command(struct Scsi_Host *instance,
883 void (*done)(struct scsi_cmnd *)) 883 struct scsi_cmnd *cmd)
884{ 884{
885 SETUP_HOSTDATA(cmd->device->host); 885 struct NCR5380_hostdata *hostdata = shost_priv(instance);
886 struct scsi_cmnd *tmp; 886 struct scsi_cmnd *tmp;
887 unsigned long flags; 887 unsigned long flags;
888 888
@@ -893,7 +893,7 @@ static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd,
893 printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n", 893 printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
894 H_NO(cmd)); 894 H_NO(cmd));
895 cmd->result = (DID_ERROR << 16); 895 cmd->result = (DID_ERROR << 16);
896 done(cmd); 896 cmd->scsi_done(cmd);
897 return 0; 897 return 0;
898 } 898 }
899#endif /* (NDEBUG & NDEBUG_NO_WRITE) */ 899#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
@@ -904,8 +904,6 @@ static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd,
904 */ 904 */
905 905
906 SET_NEXT(cmd, NULL); 906 SET_NEXT(cmd, NULL);
907 cmd->scsi_done = done;
908
909 cmd->result = 0; 907 cmd->result = 0;
910 908
911 /* 909 /*
@@ -915,7 +913,6 @@ static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd,
915 * sense data is only guaranteed to be valid while the condition exists. 913 * sense data is only guaranteed to be valid while the condition exists.
916 */ 914 */
917 915
918 local_irq_save(flags);
919 /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA. 916 /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
920 * Otherwise a running NCR5380_main may steal the lock. 917 * Otherwise a running NCR5380_main may steal the lock.
921 * Lock before actually inserting due to fairness reasons explained in 918 * Lock before actually inserting due to fairness reasons explained in
@@ -928,11 +925,11 @@ static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd,
928 * because also a timer int can trigger an abort or reset, which would 925 * because also a timer int can trigger an abort or reset, which would
929 * alter queues and touch the lock. 926 * alter queues and touch the lock.
930 */ 927 */
931 if (!IS_A_TT()) { 928 if (!falcon_get_lock())
932 /* perhaps stop command timer here */ 929 return SCSI_MLQUEUE_HOST_BUSY;
933 falcon_get_lock(); 930
934 /* perhaps restart command timer here */ 931 local_irq_save(flags);
935 } 932
936 if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { 933 if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
937 LIST(cmd, hostdata->issue_queue); 934 LIST(cmd, hostdata->issue_queue);
938 SET_NEXT(cmd, hostdata->issue_queue); 935 SET_NEXT(cmd, hostdata->issue_queue);
@@ -956,15 +953,13 @@ static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd,
956 * If we're not in an interrupt, we can call NCR5380_main() 953 * If we're not in an interrupt, we can call NCR5380_main()
957 * unconditionally, because it cannot be already running. 954 * unconditionally, because it cannot be already running.
958 */ 955 */
959 if (in_interrupt() || ((flags >> 8) & 7) >= 6) 956 if (in_interrupt() || irqs_disabled())
960 queue_main(); 957 queue_main();
961 else 958 else
962 NCR5380_main(NULL); 959 NCR5380_main(NULL);
963 return 0; 960 return 0;
964} 961}
965 962
966static DEF_SCSI_QCMD(NCR5380_queue_command)
967
968/* 963/*
969 * Function : NCR5380_main (void) 964 * Function : NCR5380_main (void)
970 * 965 *
@@ -2554,10 +2549,6 @@ int NCR5380_abort(struct scsi_cmnd *cmd)
2554 2549
2555 local_irq_save(flags); 2550 local_irq_save(flags);
2556 2551
2557 if (!IS_A_TT() && !falcon_got_lock)
2558 printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n",
2559 HOSTNO);
2560
2561 dprintk(NDEBUG_ABORT, "scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO, 2552 dprintk(NDEBUG_ABORT, "scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
2562 NCR5380_read(BUS_AND_STATUS_REG), 2553 NCR5380_read(BUS_AND_STATUS_REG),
2563 NCR5380_read(STATUS_REG)); 2554 NCR5380_read(STATUS_REG));
@@ -2756,10 +2747,6 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
2756 struct scsi_cmnd *connected, *disconnected_queue; 2747 struct scsi_cmnd *connected, *disconnected_queue;
2757#endif 2748#endif
2758 2749
2759 if (!IS_A_TT() && !falcon_got_lock)
2760 printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
2761 H_NO(cmd));
2762
2763 NCR5380_print_status(cmd->device->host); 2750 NCR5380_print_status(cmd->device->host);
2764 2751
2765 /* get in phase */ 2752 /* get in phase */
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 48fabebdbbb0..b2e86d0630ce 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -184,7 +184,7 @@ static void atari_scsi_fetch_restbytes(void);
184static irqreturn_t scsi_tt_intr(int irq, void *dummy); 184static irqreturn_t scsi_tt_intr(int irq, void *dummy);
185static irqreturn_t scsi_falcon_intr(int irq, void *dummy); 185static irqreturn_t scsi_falcon_intr(int irq, void *dummy);
186static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata); 186static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata);
187static void falcon_get_lock(void); 187static int falcon_get_lock(void);
188#ifdef CONFIG_ATARI_SCSI_RESET_BOOT 188#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
189static void atari_scsi_reset_boot(void); 189static void atari_scsi_reset_boot(void);
190#endif 190#endif
@@ -473,17 +473,10 @@ static void atari_scsi_fetch_restbytes(void)
473#endif /* REAL_DMA */ 473#endif /* REAL_DMA */
474 474
475 475
476static int falcon_got_lock = 0;
477static DECLARE_WAIT_QUEUE_HEAD(falcon_fairness_wait);
478static int falcon_trying_lock = 0;
479static DECLARE_WAIT_QUEUE_HEAD(falcon_try_wait);
480static int falcon_dont_release = 0; 476static int falcon_dont_release = 0;
481 477
482/* This function releases the lock on the DMA chip if there is no 478/* This function releases the lock on the DMA chip if there is no
483 * connected command and the disconnected queue is empty. On 479 * connected command and the disconnected queue is empty.
484 * releasing, instances of falcon_get_lock are awoken, that put
485 * themselves to sleep for fairness. They can now try to get the lock
486 * again (but others waiting longer more probably will win).
487 */ 480 */
488 481
489static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata) 482static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata)
@@ -495,20 +488,12 @@ static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata)
495 488
496 local_irq_save(flags); 489 local_irq_save(flags);
497 490
498 if (falcon_got_lock && !hostdata->disconnected_queue && 491 if (!hostdata->disconnected_queue &&
499 !hostdata->issue_queue && !hostdata->connected) { 492 !hostdata->issue_queue &&
500 493 !hostdata->connected &&
501 if (falcon_dont_release) { 494 !falcon_dont_release &&
502#if 0 495 stdma_is_locked_by(scsi_falcon_intr))
503 printk("WARNING: Lock release not allowed. Ignored\n");
504#endif
505 local_irq_restore(flags);
506 return;
507 }
508 falcon_got_lock = 0;
509 stdma_release(); 496 stdma_release();
510 wake_up(&falcon_fairness_wait);
511 }
512 497
513 local_irq_restore(flags); 498 local_irq_restore(flags);
514} 499}
@@ -517,51 +502,19 @@ static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata)
517 * If the DMA isn't locked already for SCSI, it tries to lock it by 502 * If the DMA isn't locked already for SCSI, it tries to lock it by
518 * calling stdma_lock(). But if the DMA is locked by the SCSI code and 503 * calling stdma_lock(). But if the DMA is locked by the SCSI code and
519 * there are other drivers waiting for the chip, we do not issue the 504 * there are other drivers waiting for the chip, we do not issue the
520 * command immediately but wait on 'falcon_fairness_queue'. We will be 505 * command immediately but tell the SCSI mid-layer to defer.
521 * waked up when the DMA is unlocked by some SCSI interrupt. After that
522 * we try to get the lock again.
523 * But we must be prepared that more than one instance of
524 * falcon_get_lock() is waiting on the fairness queue. They should not
525 * try all at once to call stdma_lock(), one is enough! For that, the
526 * first one sets 'falcon_trying_lock', others that see that variable
527 * set wait on the queue 'falcon_try_wait'.
528 * Complicated, complicated.... Sigh...
529 */ 506 */
530 507
531static void falcon_get_lock(void) 508static int falcon_get_lock(void)
532{ 509{
533 unsigned long flags;
534
535 if (IS_A_TT()) 510 if (IS_A_TT())
536 return; 511 return 1;
537 512
538 local_irq_save(flags); 513 if (in_interrupt())
514 return stdma_try_lock(scsi_falcon_intr, NULL);
539 515
540 wait_event_cmd(falcon_fairness_wait, 516 stdma_lock(scsi_falcon_intr, NULL);
541 in_interrupt() || !falcon_got_lock || !stdma_others_waiting(), 517 return 1;
542 local_irq_restore(flags),
543 local_irq_save(flags));
544
545 while (!falcon_got_lock) {
546 if (in_irq())
547 panic("Falcon SCSI hasn't ST-DMA lock in interrupt");
548 if (!falcon_trying_lock) {
549 falcon_trying_lock = 1;
550 stdma_lock(scsi_falcon_intr, NULL);
551 falcon_got_lock = 1;
552 falcon_trying_lock = 0;
553 wake_up(&falcon_try_wait);
554 } else {
555 wait_event_cmd(falcon_try_wait,
556 falcon_got_lock && !falcon_trying_lock,
557 local_irq_restore(flags),
558 local_irq_save(flags));
559 }
560 }
561
562 local_irq_restore(flags);
563 if (!falcon_got_lock)
564 panic("Falcon SCSI: someone stole the lock :-(\n");
565} 518}
566 519
567 520