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>
This commit is contained in:
Finn Thain 2014-11-12 16:12:16 +11:00 committed by Christoph Hellwig
parent e3c3da6734
commit e3f463b034
2 changed files with 193 additions and 16 deletions

View File

@ -71,6 +71,9 @@
* 1. Test linked command handling code after Eric is ready with * 1. Test linked command handling code after Eric is ready with
* the high level code. * the high level code.
*/ */
/* Adapted for the sun3 by Sam Creasey. */
#include <scsi/scsi_dbg.h> #include <scsi/scsi_dbg.h>
#include <scsi/scsi_transport_spi.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) static void merge_contiguous_buffers(struct scsi_cmnd *cmd)
{ {
#if !defined(CONFIG_SUN3)
unsigned long endaddr; unsigned long endaddr;
#if (NDEBUG & NDEBUG_MERGING) #if (NDEBUG & NDEBUG_MERGING)
unsigned long oldlen = cmd->SCp.this_residual; 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", dprintk(NDEBUG_MERGING, "merged %d buffers from %p, new length %08x\n",
cnt, cmd->SCp.ptr, cmd->SCp.this_residual); cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
#endif #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)) { prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp)) {
u8 lun = tmp->device->lun; u8 lun = tmp->device->lun;
#if (NDEBUG & NDEBUG_LISTS) dprintk(NDEBUG_LISTS,
if (prev != tmp) "MAIN tmp=%p target=%d busy=%d lun=%d\n",
printk("MAIN tmp=%p target=%d busy=%d lun=%llu\n", tmp, scmd_id(tmp), hostdata->busy[scmd_id(tmp)],
tmp, tmp->device->id, hostdata->busy[tmp->device->id], lun);
lun);
#endif
/* When we find one, remove it from the issue queue. */ /* When we find one, remove it from the issue queue. */
/* ++guenther: possible race with Falcon locking */ /* ++guenther: possible race with Falcon locking */
if ( if (
@ -1155,9 +1158,11 @@ static void NCR5380_main(struct work_struct *work)
static void NCR5380_dma_complete(struct Scsi_Host *instance) static void NCR5380_dma_complete(struct Scsi_Host *instance)
{ {
SETUP_HOSTDATA(instance); SETUP_HOSTDATA(instance);
int transfered, saved_data = 0, overrun = 0, cnt, toPIO; int transfered;
unsigned char **data, p; unsigned char **data;
volatile int *count; volatile int *count;
int saved_data = 0, overrun = 0;
unsigned char p;
if (!hostdata->connected) { if (!hostdata->connected) {
printk(KERN_WARNING "scsi%d: received end of DMA interrupt with " 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), HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
NCR5380_read(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); (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
@ -1196,6 +1219,8 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance)
*count -= transfered; *count -= transfered;
if (hostdata->read_overruns) { if (hostdata->read_overruns) {
int cnt, toPIO;
if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) { if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) {
cnt = toPIO = hostdata->read_overruns; cnt = toPIO = hostdata->read_overruns;
if (overrun) { 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) */ /* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
if (basr & BASR_PHASE_MATCH) 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", "BASR 0x%x, MR 0x%x, SR 0x%x\n",
HOSTNO, basr, NCR5380_read(MODE_REG), HOSTNO, basr, NCR5380_read(MODE_REG),
NCR5380_read(STATUS_REG)); NCR5380_read(STATUS_REG));
(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_DMA_ENABLE;
#endif
} }
} /* if !(SELECTION || PARITY) */ } /* if !(SELECTION || PARITY) */
handled = 1; 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, "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_DMA_ENABLE;
#endif
} }
if (!done) { if (!done) {
@ -1620,6 +1651,9 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
#ifndef SUPPORT_TAGS #ifndef SUPPORT_TAGS
hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
#endif #endif
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_INTR;
#endif
initialize_SCp(cmd); initialize_SCp(cmd);
@ -1843,9 +1877,54 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
SETUP_HOSTDATA(instance); SETUP_HOSTDATA(instance);
register int c = *count; register int c = *count;
register unsigned char p = *phase; 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; register unsigned char *d = *data;
unsigned char tmp; unsigned char tmp;
unsigned long flags;
if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
*phase = tmp; *phase = tmp;
@ -1893,6 +1972,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
NCR5380_dma_write_setup(instance, d, c); NCR5380_dma_write_setup(instance, d, c);
local_irq_restore(flags); local_irq_restore(flags);
} }
#endif /* !defined(CONFIG_SUN3) */
return 0; return 0;
} }
#endif /* defined(REAL_DMA) */ #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; unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected; struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected;
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_INTR;
#endif
while (1) { while (1) {
tmp = NCR5380_read(STATUS_REG); tmp = NCR5380_read(STATUS_REG);
/* We only have a valid SCSI phase when REQ is asserted */ /* 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; old_phase = phase;
NCR5380_dprint_phase(NDEBUG_INFORMATION, instance); 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)) { if (sink && (phase != PHASE_MSGOUT)) {
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); 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 defined(REAL_DMA)
if (!cmd->device->borken && if (
(transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) { #if !defined(CONFIG_SUN3)
!cmd->device->borken &&
#endif
(transfersize = NCR5380_dma_xfer_len(instance, cmd, phase)) >= DMA_MIN_SIZE) {
len = transfersize; len = transfersize;
cmd->SCp.phase = phase; cmd->SCp.phase = phase;
if (NCR5380_transfer_dma(instance, &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, NCR5380_transfer_pio(instance, &phase,
(int *)&cmd->SCp.this_residual, (int *)&cmd->SCp.this_residual,
(unsigned char **)&cmd->SCp.ptr); (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; break;
case PHASE_MSGIN: case PHASE_MSGIN:
len = 1; len = 1;
@ -2241,6 +2361,9 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
/* Wait for bus free to avoid nasty timeouts */ /* Wait for bus free to avoid nasty timeouts */
while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
barrier(); barrier();
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_DMA_ENABLE;
#endif
return; return;
/* /*
* The SCSI data pointer is *IMPLICITLY* saved on a disconnect * 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) static void NCR5380_reselect(struct Scsi_Host *instance)
{ {
SETUP_HOSTDATA(instance); SETUP_HOSTDATA(instance);
unsigned char target_mask; unsigned char target_mask;
unsigned char lun, phase; unsigned char lun;
int len;
#ifdef SUPPORT_TAGS #ifdef SUPPORT_TAGS
unsigned char tag; unsigned char tag;
#endif #endif
unsigned char msg[3]; 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; 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)) 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; len = 1;
data = msg; data = msg;
phase = PHASE_MSGIN; phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data); NCR5380_transfer_pio(instance, &phase, &len, &data);
#endif
if (!(msg[0] & 0x80)) { if (!(msg[0] & 0x80)) {
printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO); 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); 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 /* If the phase is still MSGIN, the target wants to send some more
* messages. In case it supports tagged queuing, this is probably a * messages. In case it supports tagged queuing, this is probably a
* SIMPLE_QUEUE_TAG for the I_T_L_Q nexus. * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
@ -2522,9 +2656,51 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
return; 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 */ /* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 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; hostdata->connected = tmp;
dprintk(NDEBUG_RESELECTION, "scsi%d: nexus established, target = %d, lun = %llu, tag = %d\n", dprintk(NDEBUG_RESELECTION, "scsi%d: nexus established, target = %d, lun = %llu, tag = %d\n",
HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag); HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);

View File

@ -89,6 +89,7 @@
#define REAL_DMA #define REAL_DMA
#define SUPPORT_TAGS #define SUPPORT_TAGS
#define MAX_TAGS 32 #define MAX_TAGS 32
#define DMA_MIN_SIZE 32
#define NCR5380_implementation_fields /* none */ #define NCR5380_implementation_fields /* none */