* because also a timer int can trigger an abort or reset, which would
* alter queues and touch the lock.
*/
- if (!falcon_get_lock())
+ if (!NCR5380_acquire_dma_irq(instance))
return SCSI_MLQUEUE_HOST_BUSY;
local_irq_save(flags);
return 0;
}
+static inline void maybe_release_dma_irq(struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+
+ /* Caller does the locking needed to set & test these data atomically */
+ if (!hostdata->disconnected_queue &&
+ !hostdata->issue_queue &&
+ !hostdata->connected &&
+ !hostdata->retain_dma_intr)
+ NCR5380_release_dma_irq(instance);
+}
+
/*
* Function : NCR5380_main (void)
*
cmd_get_tag(tmp, tmp->cmnd[0] != REQUEST_SENSE);
#endif
if (!NCR5380_select(instance, tmp)) {
+ local_irq_disable();
hostdata->retain_dma_intr--;
/* release if target did not response! */
- falcon_release_lock_if_possible(hostdata);
+ maybe_release_dma_irq(instance);
+ local_irq_restore(flags);
break;
} else {
local_irq_disable();
case COMMAND_COMPLETE:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- /* ++guenther: possible race with Falcon locking */
- hostdata->retain_dma_intr++;
- hostdata->connected = NULL;
dprintk(NDEBUG_QUEUES, "scsi%d: command for target %d, lun %llu "
"completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
+
+ local_irq_save(flags);
+ hostdata->retain_dma_intr++;
+ hostdata->connected = NULL;
#ifdef SUPPORT_TAGS
cmd_free_tag(cmd);
if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
dprintk(NDEBUG_AUTOSENSE, "scsi%d: performing request sense\n", HOSTNO);
- local_irq_save(flags);
LIST(cmd,hostdata->issue_queue);
SET_NEXT(cmd, hostdata->issue_queue);
hostdata->issue_queue = (struct scsi_cmnd *) cmd;
- local_irq_restore(flags);
dprintk(NDEBUG_QUEUES, "scsi%d: REQUEST SENSE added to head of "
"issue queue\n", H_NO(cmd));
} else {
cmd->scsi_done(cmd);
}
+ local_irq_restore(flags);
+
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
/*
* Restore phase bits to 0 so an interrupted selection,
while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
barrier();
+ local_irq_save(flags);
hostdata->retain_dma_intr--;
/* ++roman: For Falcon SCSI, release the lock on the
* ST-DMA here if no other commands are waiting on the
* disconnected queue.
*/
- falcon_release_lock_if_possible(hostdata);
+ maybe_release_dma_irq(instance);
+ local_irq_restore(flags);
return;
case MESSAGE_REJECT:
/* Accept message by clearing ACK */
hostdata->last_message = msgout;
NCR5380_transfer_pio(instance, &phase, &len, &data);
if (msgout == ABORT) {
+ local_irq_save(flags);
#ifdef SUPPORT_TAGS
cmd_free_tag(cmd);
#else
#endif
hostdata->connected = NULL;
cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- falcon_release_lock_if_possible(hostdata);
+ maybe_release_dma_irq(instance);
+ local_irq_restore(flags);
+ cmd->scsi_done(cmd);
return;
}
msgout = NOP;
unsigned char msg[3];
unsigned char *data;
struct scsi_cmnd *tmp = NULL, *prev;
-/* unsigned long flags; */
/*
* Disable arbitration, etc. since the host adapter obviously
&& (tag == tmp->tag)
#endif
) {
- /* ++guenther: prevent race with falcon_release_lock */
- hostdata->retain_dma_intr++;
if (prev) {
REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
SET_NEXT(prev, NEXT(tmp));
hostdata->connected = tmp;
dprintk(NDEBUG_RESELECTION, "scsi%d: nexus established, target = %d, lun = %llu, tag = %d\n",
HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
- hostdata->retain_dma_intr--;
}
#else
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
+ maybe_release_dma_irq(instance);
local_irq_restore(flags);
cmd->scsi_done(cmd);
- falcon_release_lock_if_possible(hostdata);
return SUCCESS;
} else {
-/* local_irq_restore(flags); */
+ local_irq_restore(flags);
printk("scsi%d: abort of connected command failed!\n", HOSTNO);
return FAILED;
}
(*prev) = NEXT(tmp);
SET_NEXT(tmp, NULL);
tmp->result = DID_ABORT << 16;
+ maybe_release_dma_irq(instance);
local_irq_restore(flags);
dprintk(NDEBUG_ABORT, "scsi%d: abort removed command from issue queue.\n",
HOSTNO);
/* Tagged queuing note: no tag to free here, hasn't been assigned
* yet... */
tmp->scsi_done(tmp);
- falcon_release_lock_if_possible(hostdata);
return SUCCESS;
}
}
#else
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
+ maybe_release_dma_irq(instance);
local_irq_restore(flags);
tmp->scsi_done(tmp);
- falcon_release_lock_if_possible(hostdata);
return SUCCESS;
}
}
}
}
+ /* Maybe it is sufficient just to release the ST-DMA lock... (if
+ * possible at all) At least, we should check if the lock could be
+ * released after the abort, in case it is kept due to some bug.
+ */
+ maybe_release_dma_irq(instance);
+ local_irq_restore(flags);
+
/*
* Case 5 : If we reached this point, the command was not found in any of
* the queues.
* broke.
*/
- local_irq_restore(flags);
printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully before abortion\n", HOSTNO);
- /* Maybe it is sufficient just to release the ST-DMA lock... (if
- * possible at all) At least, we should check if the lock could be
- * released after the abort, in case it is kept due to some bug.
- */
- falcon_release_lock_if_possible(hostdata);
-
return FAILED;
}
static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
{
- SETUP_HOSTDATA(cmd->device->host);
+ struct Scsi_Host *instance = cmd->device->host;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
int i;
unsigned long flags;
#if defined(RESET_RUN_DONE)
struct scsi_cmnd *connected, *disconnected_queue;
#endif
- NCR5380_print_status(cmd->device->host);
+ NCR5380_print_status(instance);
/* get in phase */
NCR5380_write(TARGET_COMMAND_REG,
#ifdef REAL_DMA
hostdata->dma_len = 0;
#endif
+
+ maybe_release_dma_irq(instance);
local_irq_restore(flags);
/* we did no complete reset of all commands, so a wakeup is required */
#define NCR5380_dma_xfer_len(instance, cmd, phase) \
atari_dma_xfer_len(cmd->SCp.this_residual, cmd, !((phase) & SR_IO))
+#define NCR5380_acquire_dma_irq(instance) falcon_get_lock()
+#define NCR5380_release_dma_irq(instance) falcon_release_lock()
+
#include "NCR5380.h"
* connected command and the disconnected queue is empty.
*/
-static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata)
+static void falcon_release_lock(void)
{
- unsigned long flags;
-
if (IS_A_TT())
return;
- local_irq_save(flags);
-
- if (!hostdata->disconnected_queue &&
- !hostdata->issue_queue &&
- !hostdata->connected &&
- !hostdata->retain_dma_intr &&
- stdma_is_locked_by(scsi_falcon_intr))
+ if (stdma_is_locked_by(scsi_falcon_intr))
stdma_release();
-
- local_irq_restore(flags);
}
/* This function manages the locking of the ST-DMA.
static int atari_scsi_bus_reset(struct scsi_cmnd *cmd)
{
int rv;
- struct NCR5380_hostdata *hostdata = shost_priv(cmd->device->host);
+ unsigned long flags;
+
+ local_irq_save(flags);
- /* For doing the reset, SCSI interrupts must be disabled first,
- * since the 5380 raises its IRQ line while _RST is active and we
- * can't disable interrupts completely, since we need the timer.
- */
- /* And abort a maybe active DMA transfer */
- if (IS_A_TT()) {
- atari_turnoff_irq(IRQ_TT_MFP_SCSI);
#ifdef REAL_DMA
+ /* Abort a maybe active DMA transfer */
+ if (IS_A_TT()) {
tt_scsi_dma.dma_ctrl = 0;
-#endif
} else {
- atari_turnoff_irq(IRQ_MFP_FSCSI);
-#ifdef REAL_DMA
st_dma.dma_mode_status = 0x90;
atari_dma_active = 0;
atari_dma_orig_addr = NULL;
-#endif
}
+#endif
rv = NCR5380_bus_reset(cmd);
- if (IS_A_TT())
- atari_turnon_irq(IRQ_TT_MFP_SCSI);
- else
- atari_turnon_irq(IRQ_MFP_FSCSI);
+ /* The 5380 raises its IRQ line while _RST is active but the ST DMA
+ * "lock" has been released so this interrupt may end up handled by
+ * floppy or IDE driver (if one of them holds the lock). The NCR5380
+ * interrupt flag has been cleared already.
+ */
- if (rv == SUCCESS)
- falcon_release_lock_if_possible(hostdata);
+ local_irq_restore(flags);
return rv;
}