aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/atari_NCR5380.c72
-rw-r--r--drivers/scsi/atari_scsi.c47
2 files changed, 62 insertions, 57 deletions
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 371ca14f08ea..795522192d36 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -925,7 +925,7 @@ static int NCR5380_queue_command(struct Scsi_Host *instance,
925 * 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
926 * alter queues and touch the lock. 926 * alter queues and touch the lock.
927 */ 927 */
928 if (!falcon_get_lock()) 928 if (!NCR5380_acquire_dma_irq(instance))
929 return SCSI_MLQUEUE_HOST_BUSY; 929 return SCSI_MLQUEUE_HOST_BUSY;
930 930
931 local_irq_save(flags); 931 local_irq_save(flags);
@@ -960,6 +960,18 @@ static int NCR5380_queue_command(struct Scsi_Host *instance,
960 return 0; 960 return 0;
961} 961}
962 962
963static inline void maybe_release_dma_irq(struct Scsi_Host *instance)
964{
965 struct NCR5380_hostdata *hostdata = shost_priv(instance);
966
967 /* Caller does the locking needed to set & test these data atomically */
968 if (!hostdata->disconnected_queue &&
969 !hostdata->issue_queue &&
970 !hostdata->connected &&
971 !hostdata->retain_dma_intr)
972 NCR5380_release_dma_irq(instance);
973}
974
963/* 975/*
964 * Function : NCR5380_main (void) 976 * Function : NCR5380_main (void)
965 * 977 *
@@ -1082,9 +1094,11 @@ static void NCR5380_main(struct work_struct *work)
1082 cmd_get_tag(tmp, tmp->cmnd[0] != REQUEST_SENSE); 1094 cmd_get_tag(tmp, tmp->cmnd[0] != REQUEST_SENSE);
1083#endif 1095#endif
1084 if (!NCR5380_select(instance, tmp)) { 1096 if (!NCR5380_select(instance, tmp)) {
1097 local_irq_disable();
1085 hostdata->retain_dma_intr--; 1098 hostdata->retain_dma_intr--;
1086 /* release if target did not response! */ 1099 /* release if target did not response! */
1087 falcon_release_lock_if_possible(hostdata); 1100 maybe_release_dma_irq(instance);
1101 local_irq_restore(flags);
1088 break; 1102 break;
1089 } else { 1103 } else {
1090 local_irq_disable(); 1104 local_irq_disable();
@@ -2083,11 +2097,12 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
2083 case COMMAND_COMPLETE: 2097 case COMMAND_COMPLETE:
2084 /* Accept message by clearing ACK */ 2098 /* Accept message by clearing ACK */
2085 NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 2099 NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
2086 /* ++guenther: possible race with Falcon locking */
2087 hostdata->retain_dma_intr++;
2088 hostdata->connected = NULL;
2089 dprintk(NDEBUG_QUEUES, "scsi%d: command for target %d, lun %llu " 2100 dprintk(NDEBUG_QUEUES, "scsi%d: command for target %d, lun %llu "
2090 "completed\n", HOSTNO, cmd->device->id, cmd->device->lun); 2101 "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
2102
2103 local_irq_save(flags);
2104 hostdata->retain_dma_intr++;
2105 hostdata->connected = NULL;
2091#ifdef SUPPORT_TAGS 2106#ifdef SUPPORT_TAGS
2092 cmd_free_tag(cmd); 2107 cmd_free_tag(cmd);
2093 if (status_byte(cmd->SCp.Status) == QUEUE_FULL) { 2108 if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
@@ -2146,17 +2161,17 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
2146 2161
2147 dprintk(NDEBUG_AUTOSENSE, "scsi%d: performing request sense\n", HOSTNO); 2162 dprintk(NDEBUG_AUTOSENSE, "scsi%d: performing request sense\n", HOSTNO);
2148 2163
2149 local_irq_save(flags);
2150 LIST(cmd,hostdata->issue_queue); 2164 LIST(cmd,hostdata->issue_queue);
2151 SET_NEXT(cmd, hostdata->issue_queue); 2165 SET_NEXT(cmd, hostdata->issue_queue);
2152 hostdata->issue_queue = (struct scsi_cmnd *) cmd; 2166 hostdata->issue_queue = (struct scsi_cmnd *) cmd;
2153 local_irq_restore(flags);
2154 dprintk(NDEBUG_QUEUES, "scsi%d: REQUEST SENSE added to head of " 2167 dprintk(NDEBUG_QUEUES, "scsi%d: REQUEST SENSE added to head of "
2155 "issue queue\n", H_NO(cmd)); 2168 "issue queue\n", H_NO(cmd));
2156 } else { 2169 } else {
2157 cmd->scsi_done(cmd); 2170 cmd->scsi_done(cmd);
2158 } 2171 }
2159 2172
2173 local_irq_restore(flags);
2174
2160 NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 2175 NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
2161 /* 2176 /*
2162 * Restore phase bits to 0 so an interrupted selection, 2177 * Restore phase bits to 0 so an interrupted selection,
@@ -2167,12 +2182,14 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
2167 while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) 2182 while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
2168 barrier(); 2183 barrier();
2169 2184
2185 local_irq_save(flags);
2170 hostdata->retain_dma_intr--; 2186 hostdata->retain_dma_intr--;
2171 /* ++roman: For Falcon SCSI, release the lock on the 2187 /* ++roman: For Falcon SCSI, release the lock on the
2172 * ST-DMA here if no other commands are waiting on the 2188 * ST-DMA here if no other commands are waiting on the
2173 * disconnected queue. 2189 * disconnected queue.
2174 */ 2190 */
2175 falcon_release_lock_if_possible(hostdata); 2191 maybe_release_dma_irq(instance);
2192 local_irq_restore(flags);
2176 return; 2193 return;
2177 case MESSAGE_REJECT: 2194 case MESSAGE_REJECT:
2178 /* Accept message by clearing ACK */ 2195 /* Accept message by clearing ACK */
@@ -2331,6 +2348,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
2331 hostdata->last_message = msgout; 2348 hostdata->last_message = msgout;
2332 NCR5380_transfer_pio(instance, &phase, &len, &data); 2349 NCR5380_transfer_pio(instance, &phase, &len, &data);
2333 if (msgout == ABORT) { 2350 if (msgout == ABORT) {
2351 local_irq_save(flags);
2334#ifdef SUPPORT_TAGS 2352#ifdef SUPPORT_TAGS
2335 cmd_free_tag(cmd); 2353 cmd_free_tag(cmd);
2336#else 2354#else
@@ -2338,9 +2356,10 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
2338#endif 2356#endif
2339 hostdata->connected = NULL; 2357 hostdata->connected = NULL;
2340 cmd->result = DID_ERROR << 16; 2358 cmd->result = DID_ERROR << 16;
2341 cmd->scsi_done(cmd);
2342 NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 2359 NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
2343 falcon_release_lock_if_possible(hostdata); 2360 maybe_release_dma_irq(instance);
2361 local_irq_restore(flags);
2362 cmd->scsi_done(cmd);
2344 return; 2363 return;
2345 } 2364 }
2346 msgout = NOP; 2365 msgout = NOP;
@@ -2393,7 +2412,6 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
2393 unsigned char msg[3]; 2412 unsigned char msg[3];
2394 unsigned char *data; 2413 unsigned char *data;
2395 struct scsi_cmnd *tmp = NULL, *prev; 2414 struct scsi_cmnd *tmp = NULL, *prev;
2396/* unsigned long flags; */
2397 2415
2398 /* 2416 /*
2399 * Disable arbitration, etc. since the host adapter obviously 2417 * Disable arbitration, etc. since the host adapter obviously
@@ -2473,8 +2491,6 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
2473 && (tag == tmp->tag) 2491 && (tag == tmp->tag)
2474#endif 2492#endif
2475 ) { 2493 ) {
2476 /* ++guenther: prevent race with falcon_release_lock */
2477 hostdata->retain_dma_intr++;
2478 if (prev) { 2494 if (prev) {
2479 REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); 2495 REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
2480 SET_NEXT(prev, NEXT(tmp)); 2496 SET_NEXT(prev, NEXT(tmp));
@@ -2512,7 +2528,6 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
2512 hostdata->connected = tmp; 2528 hostdata->connected = tmp;
2513 dprintk(NDEBUG_RESELECTION, "scsi%d: nexus established, target = %d, lun = %llu, tag = %d\n", 2529 dprintk(NDEBUG_RESELECTION, "scsi%d: nexus established, target = %d, lun = %llu, tag = %d\n",
2514 HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag); 2530 HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
2515 hostdata->retain_dma_intr--;
2516} 2531}
2517 2532
2518 2533
@@ -2587,12 +2602,12 @@ int NCR5380_abort(struct scsi_cmnd *cmd)
2587#else 2602#else
2588 hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); 2603 hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
2589#endif 2604#endif
2605 maybe_release_dma_irq(instance);
2590 local_irq_restore(flags); 2606 local_irq_restore(flags);
2591 cmd->scsi_done(cmd); 2607 cmd->scsi_done(cmd);
2592 falcon_release_lock_if_possible(hostdata);
2593 return SUCCESS; 2608 return SUCCESS;
2594 } else { 2609 } else {
2595/* local_irq_restore(flags); */ 2610 local_irq_restore(flags);
2596 printk("scsi%d: abort of connected command failed!\n", HOSTNO); 2611 printk("scsi%d: abort of connected command failed!\n", HOSTNO);
2597 return FAILED; 2612 return FAILED;
2598 } 2613 }
@@ -2611,13 +2626,13 @@ int NCR5380_abort(struct scsi_cmnd *cmd)
2611 (*prev) = NEXT(tmp); 2626 (*prev) = NEXT(tmp);
2612 SET_NEXT(tmp, NULL); 2627 SET_NEXT(tmp, NULL);
2613 tmp->result = DID_ABORT << 16; 2628 tmp->result = DID_ABORT << 16;
2629 maybe_release_dma_irq(instance);
2614 local_irq_restore(flags); 2630 local_irq_restore(flags);
2615 dprintk(NDEBUG_ABORT, "scsi%d: abort removed command from issue queue.\n", 2631 dprintk(NDEBUG_ABORT, "scsi%d: abort removed command from issue queue.\n",
2616 HOSTNO); 2632 HOSTNO);
2617 /* Tagged queuing note: no tag to free here, hasn't been assigned 2633 /* Tagged queuing note: no tag to free here, hasn't been assigned
2618 * yet... */ 2634 * yet... */
2619 tmp->scsi_done(tmp); 2635 tmp->scsi_done(tmp);
2620 falcon_release_lock_if_possible(hostdata);
2621 return SUCCESS; 2636 return SUCCESS;
2622 } 2637 }
2623 } 2638 }
@@ -2695,15 +2710,22 @@ int NCR5380_abort(struct scsi_cmnd *cmd)
2695#else 2710#else
2696 hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); 2711 hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
2697#endif 2712#endif
2713 maybe_release_dma_irq(instance);
2698 local_irq_restore(flags); 2714 local_irq_restore(flags);
2699 tmp->scsi_done(tmp); 2715 tmp->scsi_done(tmp);
2700 falcon_release_lock_if_possible(hostdata);
2701 return SUCCESS; 2716 return SUCCESS;
2702 } 2717 }
2703 } 2718 }
2704 } 2719 }
2705 } 2720 }
2706 2721
2722 /* Maybe it is sufficient just to release the ST-DMA lock... (if
2723 * possible at all) At least, we should check if the lock could be
2724 * released after the abort, in case it is kept due to some bug.
2725 */
2726 maybe_release_dma_irq(instance);
2727 local_irq_restore(flags);
2728
2707 /* 2729 /*
2708 * Case 5 : If we reached this point, the command was not found in any of 2730 * Case 5 : If we reached this point, the command was not found in any of
2709 * the queues. 2731 * the queues.
@@ -2714,15 +2736,8 @@ int NCR5380_abort(struct scsi_cmnd *cmd)
2714 * broke. 2736 * broke.
2715 */ 2737 */
2716 2738
2717 local_irq_restore(flags);
2718 printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully before abortion\n", HOSTNO); 2739 printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully before abortion\n", HOSTNO);
2719 2740
2720 /* Maybe it is sufficient just to release the ST-DMA lock... (if
2721 * possible at all) At least, we should check if the lock could be
2722 * released after the abort, in case it is kept due to some bug.
2723 */
2724 falcon_release_lock_if_possible(hostdata);
2725
2726 return FAILED; 2741 return FAILED;
2727} 2742}
2728 2743
@@ -2738,14 +2753,15 @@ int NCR5380_abort(struct scsi_cmnd *cmd)
2738 2753
2739static int NCR5380_bus_reset(struct scsi_cmnd *cmd) 2754static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
2740{ 2755{
2741 SETUP_HOSTDATA(cmd->device->host); 2756 struct Scsi_Host *instance = cmd->device->host;
2757 struct NCR5380_hostdata *hostdata = shost_priv(instance);
2742 int i; 2758 int i;
2743 unsigned long flags; 2759 unsigned long flags;
2744#if defined(RESET_RUN_DONE) 2760#if defined(RESET_RUN_DONE)
2745 struct scsi_cmnd *connected, *disconnected_queue; 2761 struct scsi_cmnd *connected, *disconnected_queue;
2746#endif 2762#endif
2747 2763
2748 NCR5380_print_status(cmd->device->host); 2764 NCR5380_print_status(instance);
2749 2765
2750 /* get in phase */ 2766 /* get in phase */
2751 NCR5380_write(TARGET_COMMAND_REG, 2767 NCR5380_write(TARGET_COMMAND_REG,
@@ -2870,6 +2886,8 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
2870#ifdef REAL_DMA 2886#ifdef REAL_DMA
2871 hostdata->dma_len = 0; 2887 hostdata->dma_len = 0;
2872#endif 2888#endif
2889
2890 maybe_release_dma_irq(instance);
2873 local_irq_restore(flags); 2891 local_irq_restore(flags);
2874 2892
2875 /* we did no complete reset of all commands, so a wakeup is required */ 2893 /* we did no complete reset of all commands, so a wakeup is required */
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 70c662f9fee4..045112186f84 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -109,6 +109,9 @@
109#define NCR5380_dma_xfer_len(instance, cmd, phase) \ 109#define NCR5380_dma_xfer_len(instance, cmd, phase) \
110 atari_dma_xfer_len(cmd->SCp.this_residual, cmd, !((phase) & SR_IO)) 110 atari_dma_xfer_len(cmd->SCp.this_residual, cmd, !((phase) & SR_IO))
111 111
112#define NCR5380_acquire_dma_irq(instance) falcon_get_lock()
113#define NCR5380_release_dma_irq(instance) falcon_release_lock()
114
112#include "NCR5380.h" 115#include "NCR5380.h"
113 116
114 117
@@ -448,23 +451,13 @@ static void atari_scsi_fetch_restbytes(void)
448 * connected command and the disconnected queue is empty. 451 * connected command and the disconnected queue is empty.
449 */ 452 */
450 453
451static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata) 454static void falcon_release_lock(void)
452{ 455{
453 unsigned long flags;
454
455 if (IS_A_TT()) 456 if (IS_A_TT())
456 return; 457 return;
457 458
458 local_irq_save(flags); 459 if (stdma_is_locked_by(scsi_falcon_intr))
459
460 if (!hostdata->disconnected_queue &&
461 !hostdata->issue_queue &&
462 !hostdata->connected &&
463 !hostdata->retain_dma_intr &&
464 stdma_is_locked_by(scsi_falcon_intr))
465 stdma_release(); 460 stdma_release();
466
467 local_irq_restore(flags);
468} 461}
469 462
470/* This function manages the locking of the ST-DMA. 463/* This function manages the locking of the ST-DMA.
@@ -787,36 +780,30 @@ static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value)
787static int atari_scsi_bus_reset(struct scsi_cmnd *cmd) 780static int atari_scsi_bus_reset(struct scsi_cmnd *cmd)
788{ 781{
789 int rv; 782 int rv;
790 struct NCR5380_hostdata *hostdata = shost_priv(cmd->device->host); 783 unsigned long flags;
784
785 local_irq_save(flags);
791 786
792 /* For doing the reset, SCSI interrupts must be disabled first,
793 * since the 5380 raises its IRQ line while _RST is active and we
794 * can't disable interrupts completely, since we need the timer.
795 */
796 /* And abort a maybe active DMA transfer */
797 if (IS_A_TT()) {
798 atari_turnoff_irq(IRQ_TT_MFP_SCSI);
799#ifdef REAL_DMA 787#ifdef REAL_DMA
788 /* Abort a maybe active DMA transfer */
789 if (IS_A_TT()) {
800 tt_scsi_dma.dma_ctrl = 0; 790 tt_scsi_dma.dma_ctrl = 0;
801#endif
802 } else { 791 } else {
803 atari_turnoff_irq(IRQ_MFP_FSCSI);
804#ifdef REAL_DMA
805 st_dma.dma_mode_status = 0x90; 792 st_dma.dma_mode_status = 0x90;
806 atari_dma_active = 0; 793 atari_dma_active = 0;
807 atari_dma_orig_addr = NULL; 794 atari_dma_orig_addr = NULL;
808#endif
809 } 795 }
796#endif
810 797
811 rv = NCR5380_bus_reset(cmd); 798 rv = NCR5380_bus_reset(cmd);
812 799
813 if (IS_A_TT()) 800 /* The 5380 raises its IRQ line while _RST is active but the ST DMA
814 atari_turnon_irq(IRQ_TT_MFP_SCSI); 801 * "lock" has been released so this interrupt may end up handled by
815 else 802 * floppy or IDE driver (if one of them holds the lock). The NCR5380
816 atari_turnon_irq(IRQ_MFP_FSCSI); 803 * interrupt flag has been cleared already.
804 */
817 805
818 if (rv == SUCCESS) 806 local_irq_restore(flags);
819 falcon_release_lock_if_possible(hostdata);
820 807
821 return rv; 808 return rv;
822} 809}