diff options
-rw-r--r-- | drivers/scsi/atari_NCR5380.c | 72 | ||||
-rw-r--r-- | drivers/scsi/atari_scsi.c | 47 |
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 | ||
963 | static 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 | ||
2739 | static int NCR5380_bus_reset(struct scsi_cmnd *cmd) | 2754 | static 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 | ||
451 | static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata) | 454 | static 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) | |||
787 | static int atari_scsi_bus_reset(struct scsi_cmnd *cmd) | 780 | static 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 | } |