diff options
author | Finn Thain <fthain@telegraphics.com.au> | 2014-11-12 16:12:16 +1100 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2014-11-20 09:11:17 +0100 |
commit | e3f463b034bad82cd247d9a1b39209ba7152e545 (patch) | |
tree | 0be618efc3c39caf2ee4ceab33b051bd850252db /drivers/scsi/atari_NCR5380.c | |
parent | e3c3da67340ac7d1d2f630f319eb718474b0d9c3 (diff) | |
download | linux-e3f463b034bad82cd247d9a1b39209ba7152e545.tar.bz2 |
atari_NCR5380: Merge from sun3_NCR5380.c
There is very little difference between the sun3_NCR5380.c core driver
and atari_NCR5380.c. The former is a fork of the latter.
Merge the sun3_NCR5380.c core driver into atari_NCR5380.c so that
sun3_scsi.c can adopt the latter and the former can be deleted.
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Tested-by: Michael Schmitz <schmitzmic@gmail.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'drivers/scsi/atari_NCR5380.c')
-rw-r--r-- | drivers/scsi/atari_NCR5380.c | 208 |
1 files changed, 192 insertions, 16 deletions
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c index 795522192d36..1331b8cf5fe9 100644 --- a/drivers/scsi/atari_NCR5380.c +++ b/drivers/scsi/atari_NCR5380.c @@ -71,6 +71,9 @@ * 1. Test linked command handling code after Eric is ready with * the high level code. */ + +/* Adapted for the sun3 by Sam Creasey. */ + #include <scsi/scsi_dbg.h> #include <scsi/scsi_transport_spi.h> @@ -458,6 +461,7 @@ static void free_all_tags(void) static void merge_contiguous_buffers(struct scsi_cmnd *cmd) { +#if !defined(CONFIG_SUN3) unsigned long endaddr; #if (NDEBUG & NDEBUG_MERGING) unsigned long oldlen = cmd->SCp.this_residual; @@ -482,6 +486,7 @@ static void merge_contiguous_buffers(struct scsi_cmnd *cmd) dprintk(NDEBUG_MERGING, "merged %d buffers from %p, new length %08x\n", cnt, cmd->SCp.ptr, cmd->SCp.this_residual); #endif +#endif /* !defined(CONFIG_SUN3) */ } /* @@ -1041,12 +1046,10 @@ static void NCR5380_main(struct work_struct *work) prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp)) { u8 lun = tmp->device->lun; -#if (NDEBUG & NDEBUG_LISTS) - if (prev != tmp) - printk("MAIN tmp=%p target=%d busy=%d lun=%llu\n", - tmp, tmp->device->id, hostdata->busy[tmp->device->id], - lun); -#endif + dprintk(NDEBUG_LISTS, + "MAIN tmp=%p target=%d busy=%d lun=%d\n", + tmp, scmd_id(tmp), hostdata->busy[scmd_id(tmp)], + lun); /* When we find one, remove it from the issue queue. */ /* ++guenther: possible race with Falcon locking */ if ( @@ -1155,9 +1158,11 @@ static void NCR5380_main(struct work_struct *work) static void NCR5380_dma_complete(struct Scsi_Host *instance) { SETUP_HOSTDATA(instance); - int transfered, saved_data = 0, overrun = 0, cnt, toPIO; - unsigned char **data, p; + int transfered; + unsigned char **data; volatile int *count; + int saved_data = 0, overrun = 0; + unsigned char p; if (!hostdata->connected) { printk(KERN_WARNING "scsi%d: received end of DMA interrupt with " @@ -1183,6 +1188,24 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance) HOSTNO, NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG)); +#if defined(CONFIG_SUN3) + if ((sun3scsi_dma_finish(rq_data_dir(hostdata->connected->request)))) { + pr_err("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", + instance->host_no); + BUG(); + } + + /* make sure we're not stuck in a data phase */ + if ((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == + (BASR_PHASE_MATCH | BASR_ACK)) { + pr_err("scsi%d: BASR %02x\n", instance->host_no, + NCR5380_read(BUS_AND_STATUS_REG)); + pr_err("scsi%d: bus stuck in data phase -- probably a single byte overrun!\n", + instance->host_no); + BUG(); + } +#endif + (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); @@ -1196,6 +1219,8 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance) *count -= transfered; if (hostdata->read_overruns) { + int cnt, toPIO; + if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) { cnt = toPIO = hostdata->read_overruns; if (overrun) { @@ -1275,11 +1300,14 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id) { /* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */ if (basr & BASR_PHASE_MATCH) - printk(KERN_NOTICE "scsi%d: unknown interrupt, " + dprintk(NDEBUG_INTR, "scsi%d: unknown interrupt, " "BASR 0x%x, MR 0x%x, SR 0x%x\n", HOSTNO, basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); +#ifdef SUN3_SCSI_VME + dregs->csr |= CSR_DMA_ENABLE; +#endif } } /* if !(SELECTION || PARITY) */ handled = 1; @@ -1288,6 +1316,9 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id) "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); +#ifdef SUN3_SCSI_VME + dregs->csr |= CSR_DMA_ENABLE; +#endif } if (!done) { @@ -1620,6 +1651,9 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) #ifndef SUPPORT_TAGS hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); #endif +#ifdef SUN3_SCSI_VME + dregs->csr |= CSR_INTR; +#endif initialize_SCp(cmd); @@ -1843,9 +1877,54 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, SETUP_HOSTDATA(instance); register int c = *count; register unsigned char p = *phase; + unsigned long flags; + +#if defined(CONFIG_SUN3) + /* sanity check */ + if (!sun3_dma_setup_done) { + pr_err("scsi%d: transfer_dma without setup!\n", + instance->host_no); + BUG(); + } + hostdata->dma_len = c; + + dprintk(NDEBUG_DMA, "scsi%d: initializing DMA for %s, %d bytes %s %p\n", + instance->host_no, (p & SR_IO) ? "reading" : "writing", + c, (p & SR_IO) ? "to" : "from", *data); + + /* netbsd turns off ints here, why not be safe and do it too */ + local_irq_save(flags); + + /* send start chain */ + sun3scsi_dma_start(c, *data); + + if (p & SR_IO) { + NCR5380_write(TARGET_COMMAND_REG, 1); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + NCR5380_write(INITIATOR_COMMAND_REG, 0); + NCR5380_write(MODE_REG, + (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR)); + NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); + } else { + NCR5380_write(TARGET_COMMAND_REG, 0); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_DATA); + NCR5380_write(MODE_REG, + (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR)); + NCR5380_write(START_DMA_SEND_REG, 0); + } + +#ifdef SUN3_SCSI_VME + dregs->csr |= CSR_DMA_ENABLE; +#endif + + local_irq_restore(flags); + + sun3_dma_active = 1; + +#else /* !defined(CONFIG_SUN3) */ register unsigned char *d = *data; unsigned char tmp; - unsigned long flags; if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { *phase = tmp; @@ -1893,6 +1972,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, NCR5380_dma_write_setup(instance, d, c); local_irq_restore(flags); } +#endif /* !defined(CONFIG_SUN3) */ + return 0; } #endif /* defined(REAL_DMA) */ @@ -1928,6 +2009,10 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) unsigned char phase, tmp, extended_msg[10], old_phase = 0xff; struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected; +#ifdef SUN3_SCSI_VME + dregs->csr |= CSR_INTR; +#endif + while (1) { tmp = NCR5380_read(STATUS_REG); /* We only have a valid SCSI phase when REQ is asserted */ @@ -1937,6 +2022,33 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) old_phase = phase; NCR5380_dprint_phase(NDEBUG_INFORMATION, instance); } +#if defined(CONFIG_SUN3) + if (phase == PHASE_CMDOUT) { +#if defined(REAL_DMA) + void *d; + unsigned long count; + + if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { + count = cmd->SCp.buffer->length; + d = sg_virt(cmd->SCp.buffer); + } else { + count = cmd->SCp.this_residual; + d = cmd->SCp.ptr; + } + /* this command setup for dma yet? */ + if ((count >= DMA_MIN_SIZE) && (sun3_dma_setup_done != cmd)) { + if (cmd->request->cmd_type == REQ_TYPE_FS) { + sun3scsi_dma_setup(d, count, + rq_data_dir(cmd->request)); + sun3_dma_setup_done = cmd; + } + } +#endif +#ifdef SUN3_SCSI_VME + dregs->csr |= CSR_INTR; +#endif + } +#endif /* CONFIG_SUN3 */ if (sink && (phase != PHASE_MSGOUT)) { NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); @@ -1998,8 +2110,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) */ #if defined(REAL_DMA) - if (!cmd->device->borken && - (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) { + if ( +#if !defined(CONFIG_SUN3) + !cmd->device->borken && +#endif + (transfersize = NCR5380_dma_xfer_len(instance, cmd, phase)) >= DMA_MIN_SIZE) { len = transfersize; cmd->SCp.phase = phase; if (NCR5380_transfer_dma(instance, &phase, @@ -2036,6 +2151,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) NCR5380_transfer_pio(instance, &phase, (int *)&cmd->SCp.this_residual, (unsigned char **)&cmd->SCp.ptr); +#if defined(CONFIG_SUN3) && defined(REAL_DMA) + /* if we had intended to dma that command clear it */ + if (sun3_dma_setup_done == cmd) + sun3_dma_setup_done = NULL; +#endif break; case PHASE_MSGIN: len = 1; @@ -2241,6 +2361,9 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) /* Wait for bus free to avoid nasty timeouts */ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) barrier(); +#ifdef SUN3_SCSI_VME + dregs->csr |= CSR_DMA_ENABLE; +#endif return; /* * The SCSI data pointer is *IMPLICITLY* saved on a disconnect @@ -2400,17 +2523,20 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) */ +/* it might eventually prove necessary to do a dma setup on + reselection, but it doesn't seem to be needed now -- sam */ + static void NCR5380_reselect(struct Scsi_Host *instance) { SETUP_HOSTDATA(instance); unsigned char target_mask; - unsigned char lun, phase; - int len; + unsigned char lun; #ifdef SUPPORT_TAGS unsigned char tag; #endif unsigned char msg[3]; - unsigned char *data; + int __maybe_unused len; + unsigned char __maybe_unused *data, __maybe_unused phase; struct scsi_cmnd *tmp = NULL, *prev; /* @@ -2447,10 +2573,18 @@ static void NCR5380_reselect(struct Scsi_Host *instance) while (!(NCR5380_read(STATUS_REG) & SR_REQ)) ; +#if defined(CONFIG_SUN3) && defined(REAL_DMA) + /* acknowledge toggle to MSGIN */ + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(PHASE_MSGIN)); + + /* peek at the byte without really hitting the bus */ + msg[0] = NCR5380_read(CURRENT_SCSI_DATA_REG); +#else len = 1; data = msg; phase = PHASE_MSGIN; NCR5380_transfer_pio(instance, &phase, &len, &data); +#endif if (!(msg[0] & 0x80)) { printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO); @@ -2460,7 +2594,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) } lun = (msg[0] & 0x07); -#ifdef SUPPORT_TAGS +#if defined(SUPPORT_TAGS) && !defined(CONFIG_SUN3) /* If the phase is still MSGIN, the target wants to send some more * messages. In case it supports tagged queuing, this is probably a * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus. @@ -2522,9 +2656,51 @@ static void NCR5380_reselect(struct Scsi_Host *instance) return; } +#if defined(CONFIG_SUN3) && defined(REAL_DMA) + /* engage dma setup for the command we just saw */ + { + void *d; + unsigned long count; + + if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) { + count = tmp->SCp.buffer->length; + d = sg_virt(tmp->SCp.buffer); + } else { + count = tmp->SCp.this_residual; + d = tmp->SCp.ptr; + } + /* setup this command for dma if not already */ + if ((count >= DMA_MIN_SIZE) && (sun3_dma_setup_done != tmp)) { + sun3scsi_dma_setup(d, count, rq_data_dir(tmp->request)); + sun3_dma_setup_done = tmp; + } + } + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); +#endif + /* Accept message by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +#if defined(SUPPORT_TAGS) && defined(CONFIG_SUN3) + /* If the phase is still MSGIN, the target wants to send some more + * messages. In case it supports tagged queuing, this is probably a + * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus. + */ + tag = TAG_NONE; + if (phase == PHASE_MSGIN && setup_use_tagged_queuing) { + /* Accept previous IDENTIFY message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + len = 2; + data = msg + 1; + if (!NCR5380_transfer_pio(instance, &phase, &len, &data) && + msg[1] == SIMPLE_QUEUE_TAG) + tag = msg[2]; + dprintk(NDEBUG_TAGS, "scsi%d: target mask %02x, lun %d sent tag %d at reselection\n" + HOSTNO, target_mask, lun, tag); + } +#endif + 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); |