Commit 8053b0ee authored by Finn Thain's avatar Finn Thain Committed by Martin K. Petersen

ncr5380: Merge DMA implementation from atari_NCR5380 core driver

Adopt the DMA implementation from atari_NCR5380.c. This means that
atari_scsi and sun3_scsi can make use of the NCR5380.c core driver
and the atari_NCR5380.c driver fork can be made redundant.
Signed-off-by: default avatarFinn Thain <fthain@telegraphics.com.au>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Tested-by: default avatarMichael Schmitz <schmitzmic@gmail.com>
Tested-by: default avatarOndrej Zary <linux@rainbow-software.org>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 438af51c
...@@ -31,9 +31,6 @@ ...@@ -31,9 +31,6 @@
/* /*
* Further development / testing that should be done : * Further development / testing that should be done :
* 1. Cleanup the NCR5380_transfer_dma function and DMA operation complete
* code so that everything does the same thing that's done at the
* end of a pseudo-DMA read operation.
* *
* 4. Test SCSI-II tagged queueing (I have no devices which support * 4. Test SCSI-II tagged queueing (I have no devices which support
* tagged queueing) * tagged queueing)
...@@ -117,6 +114,8 @@ ...@@ -117,6 +114,8 @@
* *
* PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases. * PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases.
* *
* REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
*
* These macros MUST be defined : * These macros MUST be defined :
* *
* NCR5380_read(register) - read from the specified register * NCR5380_read(register) - read from the specified register
...@@ -801,6 +800,72 @@ static void NCR5380_main(struct work_struct *work) ...@@ -801,6 +800,72 @@ static void NCR5380_main(struct work_struct *work)
} while (!done); } while (!done);
} }
/*
* NCR5380_dma_complete - finish DMA transfer
* @instance: the scsi host instance
*
* Called by the interrupt handler when DMA finishes or a phase
* mismatch occurs (which would end the DMA transfer).
*/
static void NCR5380_dma_complete(struct Scsi_Host *instance)
{
struct NCR5380_hostdata *hostdata = shost_priv(instance);
int transferred;
unsigned char **data;
int *count;
int saved_data = 0, overrun = 0;
unsigned char p;
if (hostdata->read_overruns) {
p = hostdata->connected->SCp.phase;
if (p & SR_IO) {
udelay(10);
if ((NCR5380_read(BUS_AND_STATUS_REG) &
(BASR_PHASE_MATCH | BASR_ACK)) ==
(BASR_PHASE_MATCH | BASR_ACK)) {
saved_data = NCR5380_read(INPUT_DATA_REG);
overrun = 1;
dsprintk(NDEBUG_DMA, instance, "read overrun handled\n");
}
}
}
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_read(RESET_PARITY_INTERRUPT_REG);
transferred = hostdata->dma_len - NCR5380_dma_residual(instance);
hostdata->dma_len = 0;
data = (unsigned char **)&hostdata->connected->SCp.ptr;
count = &hostdata->connected->SCp.this_residual;
*data += transferred;
*count -= transferred;
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) {
dsprintk(NDEBUG_DMA, instance,
"Got an input overrun, using saved byte\n");
*(*data)++ = saved_data;
(*count)--;
cnt--;
toPIO--;
}
if (toPIO > 0) {
dsprintk(NDEBUG_DMA, instance,
"Doing %d byte PIO to 0x%p\n", cnt, *data);
NCR5380_transfer_pio(instance, &p, &cnt, data);
*count -= toPIO - cnt;
}
}
}
}
#ifndef DONT_USE_INTR #ifndef DONT_USE_INTR
/** /**
...@@ -855,7 +920,22 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id) ...@@ -855,7 +920,22 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id)
dsprintk(NDEBUG_INTR, instance, "IRQ %d, BASR 0x%02x, SR 0x%02x, MR 0x%02x\n", dsprintk(NDEBUG_INTR, instance, "IRQ %d, BASR 0x%02x, SR 0x%02x, MR 0x%02x\n",
irq, basr, sr, mr); irq, basr, sr, mr);
if ((NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_mask) && if ((mr & MR_DMA_MODE) || (mr & MR_MONITOR_BSY)) {
/* Probably End of DMA, Phase Mismatch or Loss of BSY.
* We ack IRQ after clearing Mode Register. Workarounds
* for End of DMA errata need to happen in DMA Mode.
*/
dsprintk(NDEBUG_INTR, instance, "interrupt in DMA mode\n");
if (hostdata->connected) {
NCR5380_dma_complete(instance);
queue_work(hostdata->work_q, &hostdata->main_task);
} else {
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_read(RESET_PARITY_INTERRUPT_REG);
}
} else if ((NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_mask) &&
(sr & (SR_SEL | SR_IO | SR_BSY | SR_RST)) == (SR_SEL | SR_IO)) { (sr & (SR_SEL | SR_IO | SR_BSY | SR_RST)) == (SR_SEL | SR_IO)) {
/* Probably reselected */ /* Probably reselected */
NCR5380_write(SELECT_ENABLE_REG, 0); NCR5380_write(SELECT_ENABLE_REG, 0);
...@@ -1431,28 +1511,38 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, ...@@ -1431,28 +1511,38 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
register unsigned char p = *phase; register unsigned char p = *phase;
register unsigned char *d = *data; register unsigned char *d = *data;
unsigned char tmp; unsigned char tmp;
int result; int result = 0;
if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
*phase = tmp; *phase = tmp;
return -1; return -1;
} }
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); hostdata->connected->SCp.phase = p;
/* if (p & SR_IO) {
* Note : on my sample board, watch-dog timeouts occurred when interrupts if (hostdata->read_overruns)
* were not disabled for the duration of a single DMA transfer, from c -= hostdata->read_overruns;
* before the setting of DMA mode to after transfer of the last byte. else if (hostdata->flags & FLAG_DMA_FIXUP)
*/ --c;
}
if (hostdata->flags & FLAG_DMA_FIXUP) dsprintk(NDEBUG_DMA, instance, "initializing DMA %s: length %d, address %p\n",
NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY); (p & SR_IO) ? "receive" : "send", c, d);
else
NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
MR_ENABLE_EOP_INTR);
dprintk(NDEBUG_DMA, "scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG)); NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
MR_ENABLE_EOP_INTR);
if (!(hostdata->flags & FLAG_LATE_DMA_SETUP)) {
/* On the Medusa, it is a must to initialize the DMA before
* starting the NCR. This is also the cleaner way for the TT.
*/
if (p & SR_IO)
result = NCR5380_dma_recv_setup(instance, d, c);
else
result = NCR5380_dma_send_setup(instance, d, c);
}
/* /*
* On the PAS16 at least I/O recovery delays are not needed here. * On the PAS16 at least I/O recovery delays are not needed here.
...@@ -1470,6 +1560,29 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, ...@@ -1470,6 +1560,29 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
NCR5380_io_delay(1); NCR5380_io_delay(1);
} }
if (hostdata->flags & FLAG_LATE_DMA_SETUP) {
/* On the Falcon, the DMA setup must be done after the last
* NCR access, else the DMA setup gets trashed!
*/
if (p & SR_IO)
result = NCR5380_dma_recv_setup(instance, d, c);
else
result = NCR5380_dma_send_setup(instance, d, c);
}
/* On failure, NCR5380_dma_xxxx_setup() returns a negative int. */
if (result < 0)
return result;
/* For real DMA, result is the byte count. DMA interrupt is expected. */
if (result > 0) {
hostdata->dma_len = result;
return 0;
}
/* The result is zero iff pseudo DMA send/receive was completed. */
hostdata->dma_len = c;
/* /*
* A note regarding the DMA errata workarounds for early NMOS silicon. * A note regarding the DMA errata workarounds for early NMOS silicon.
* *
...@@ -1504,10 +1617,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, ...@@ -1504,10 +1617,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
* request. * request.
*/ */
if (p & SR_IO) { if (hostdata->flags & FLAG_DMA_FIXUP) {
result = NCR5380_dma_recv_setup(instance, d, if (p & SR_IO) {
hostdata->flags & FLAG_DMA_FIXUP ? c - 1 : c);
if (!result && (hostdata->flags & FLAG_DMA_FIXUP)) {
/* /*
* The workaround was to transfer fewer bytes than we * The workaround was to transfer fewer bytes than we
* intended to with the pseudo-DMA read function, wait for * intended to with the pseudo-DMA read function, wait for
...@@ -1533,11 +1644,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, ...@@ -1533,11 +1644,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
result = -1; result = -1;
shost_printk(KERN_ERR, instance, "PDMA read: !REQ timeout\n"); shost_printk(KERN_ERR, instance, "PDMA read: !REQ timeout\n");
} }
d[c - 1] = NCR5380_read(INPUT_DATA_REG); d[*count - 1] = NCR5380_read(INPUT_DATA_REG);
} } else {
} else {
result = NCR5380_dma_send_setup(instance, d, c);
if (!result && (hostdata->flags & FLAG_DMA_FIXUP)) {
/* /*
* Wait for the last byte to be sent. If REQ is being asserted for * Wait for the last byte to be sent. If REQ is being asserted for
* the byte we're interested, we'll ACK it and it will go false. * the byte we're interested, we'll ACK it and it will go false.
...@@ -1550,11 +1658,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, ...@@ -1550,11 +1658,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
} }
} }
} }
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); NCR5380_dma_complete(instance);
NCR5380_read(RESET_PARITY_INTERRUPT_REG);
*data = d + c;
*count = 0;
return result; return result;
} }
...@@ -1667,8 +1772,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) ...@@ -1667,8 +1772,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
do_abort(instance); do_abort(instance);
cmd->result = DID_ERROR << 16; cmd->result = DID_ERROR << 16;
/* XXX - need to source or sink data here, as appropriate */ /* XXX - need to source or sink data here, as appropriate */
} else }
cmd->SCp.this_residual -= transfersize - len;
} else { } else {
/* Break up transfer into 3 ms chunks, /* Break up transfer into 3 ms chunks,
* presuming 6 accesses per handshake. * presuming 6 accesses per handshake.
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize) #define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
#define NCR5380_dma_recv_setup cumanascsi_pread #define NCR5380_dma_recv_setup cumanascsi_pread
#define NCR5380_dma_send_setup cumanascsi_pwrite #define NCR5380_dma_send_setup cumanascsi_pwrite
#define NCR5380_dma_residual(instance) (0)
#define NCR5380_intr cumanascsi_intr #define NCR5380_intr cumanascsi_intr
#define NCR5380_queue_command cumanascsi_queue_command #define NCR5380_queue_command cumanascsi_queue_command
...@@ -245,7 +246,7 @@ static int cumanascsi1_probe(struct expansion_card *ec, ...@@ -245,7 +246,7 @@ static int cumanascsi1_probe(struct expansion_card *ec,
host->irq = ec->irq; host->irq = ec->irq;
ret = NCR5380_init(host, FLAG_DMA_FIXUP); ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP);
if (ret) if (ret)
goto out_unmap; goto out_unmap;
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#define NCR5380_dma_xfer_len(instance, cmd, phase) (0) #define NCR5380_dma_xfer_len(instance, cmd, phase) (0)
#define NCR5380_dma_recv_setup oakscsi_pread #define NCR5380_dma_recv_setup oakscsi_pread
#define NCR5380_dma_send_setup oakscsi_pwrite #define NCR5380_dma_send_setup oakscsi_pwrite
#define NCR5380_dma_residual(instance) (0)
#define NCR5380_queue_command oakscsi_queue_command #define NCR5380_queue_command oakscsi_queue_command
#define NCR5380_info oakscsi_info #define NCR5380_info oakscsi_info
...@@ -144,7 +145,7 @@ static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id) ...@@ -144,7 +145,7 @@ static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
host->irq = NO_IRQ; host->irq = NO_IRQ;
host->n_io_port = 255; host->n_io_port = 255;
ret = NCR5380_init(host, FLAG_DMA_FIXUP); ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP);
if (ret) if (ret)
goto out_unmap; goto out_unmap;
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#define NCR5380_dma_xfer_len(instance, cmd, phase) (0) #define NCR5380_dma_xfer_len(instance, cmd, phase) (0)
#define NCR5380_dma_recv_setup(instance, dst, len) (0) #define NCR5380_dma_recv_setup(instance, dst, len) (0)
#define NCR5380_dma_send_setup(instance, src, len) (0) #define NCR5380_dma_send_setup(instance, src, len) (0)
#define NCR5380_dma_residual(instance) (0)
#define NCR5380_implementation_fields /* none */ #define NCR5380_implementation_fields /* none */
......
...@@ -228,7 +228,7 @@ static int __init dtc_detect(struct scsi_host_template * tpnt) ...@@ -228,7 +228,7 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
instance->base = addr; instance->base = addr;
((struct NCR5380_hostdata *)(instance)->hostdata)->base = base; ((struct NCR5380_hostdata *)(instance)->hostdata)->base = base;
if (NCR5380_init(instance, 0)) if (NCR5380_init(instance, FLAG_LATE_DMA_SETUP))
goto out_unregister; goto out_unregister;
NCR5380_maybe_reset_bus(instance); NCR5380_maybe_reset_bus(instance);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
dtc_dma_xfer_len(cmd) dtc_dma_xfer_len(cmd)
#define NCR5380_dma_recv_setup dtc_pread #define NCR5380_dma_recv_setup dtc_pread
#define NCR5380_dma_send_setup dtc_pwrite #define NCR5380_dma_send_setup dtc_pwrite
#define NCR5380_dma_residual(instance) (0)
#define NCR5380_intr dtc_intr #define NCR5380_intr dtc_intr
#define NCR5380_queue_command dtc_queue_command #define NCR5380_queue_command dtc_queue_command
......
...@@ -466,7 +466,7 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt) ...@@ -466,7 +466,7 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
} }
#endif #endif
if (NCR5380_init(instance, flags)) if (NCR5380_init(instance, flags | FLAG_LATE_DMA_SETUP))
goto out_unregister; goto out_unregister;
switch (overrides[current_override].board) { switch (overrides[current_override].board) {
......
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
generic_NCR5380_dma_xfer_len(instance, cmd) generic_NCR5380_dma_xfer_len(instance, cmd)
#define NCR5380_dma_recv_setup generic_NCR5380_pread #define NCR5380_dma_recv_setup generic_NCR5380_pread
#define NCR5380_dma_send_setup generic_NCR5380_pwrite #define NCR5380_dma_send_setup generic_NCR5380_pwrite
#define NCR5380_dma_residual(instance) (0)
#define NCR5380_intr generic_NCR5380_intr #define NCR5380_intr generic_NCR5380_intr
#define NCR5380_queue_command generic_NCR5380_queue_command #define NCR5380_queue_command generic_NCR5380_queue_command
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
macscsi_dma_xfer_len(instance, cmd) macscsi_dma_xfer_len(instance, cmd)
#define NCR5380_dma_recv_setup macscsi_pread #define NCR5380_dma_recv_setup macscsi_pread
#define NCR5380_dma_send_setup macscsi_pwrite #define NCR5380_dma_send_setup macscsi_pwrite
#define NCR5380_dma_residual(instance) (0)
#define NCR5380_intr macscsi_intr #define NCR5380_intr macscsi_intr
#define NCR5380_queue_command macscsi_queue_command #define NCR5380_queue_command macscsi_queue_command
...@@ -386,7 +387,7 @@ static int __init mac_scsi_probe(struct platform_device *pdev) ...@@ -386,7 +387,7 @@ static int __init mac_scsi_probe(struct platform_device *pdev)
#endif #endif
host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0; host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0;
error = NCR5380_init(instance, host_flags); error = NCR5380_init(instance, host_flags | FLAG_LATE_DMA_SETUP);
if (error) if (error)
goto fail_init; goto fail_init;
......
...@@ -375,7 +375,7 @@ static int __init pas16_detect(struct scsi_host_template *tpnt) ...@@ -375,7 +375,7 @@ static int __init pas16_detect(struct scsi_host_template *tpnt)
instance->io_port = io_port; instance->io_port = io_port;
if (NCR5380_init(instance, FLAG_DMA_FIXUP)) if (NCR5380_init(instance, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP))
goto out_unregister; goto out_unregister;
NCR5380_maybe_reset_bus(instance); NCR5380_maybe_reset_bus(instance);
......
...@@ -105,6 +105,7 @@ ...@@ -105,6 +105,7 @@
#define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize) #define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
#define NCR5380_dma_recv_setup pas16_pread #define NCR5380_dma_recv_setup pas16_pread
#define NCR5380_dma_send_setup pas16_pwrite #define NCR5380_dma_send_setup pas16_pwrite
#define NCR5380_dma_residual(instance) (0)
#define NCR5380_intr pas16_intr #define NCR5380_intr pas16_intr
#define NCR5380_queue_command pas16_queue_command #define NCR5380_queue_command pas16_queue_command
......
...@@ -208,7 +208,7 @@ static int __init t128_detect(struct scsi_host_template *tpnt) ...@@ -208,7 +208,7 @@ static int __init t128_detect(struct scsi_host_template *tpnt)
instance->base = base; instance->base = base;
((struct NCR5380_hostdata *)instance->hostdata)->base = p; ((struct NCR5380_hostdata *)instance->hostdata)->base = p;
if (NCR5380_init(instance, FLAG_DMA_FIXUP)) if (NCR5380_init(instance, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP))
goto out_unregister; goto out_unregister;
NCR5380_maybe_reset_bus(instance); NCR5380_maybe_reset_bus(instance);
......
...@@ -79,6 +79,7 @@ ...@@ -79,6 +79,7 @@
#define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize) #define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
#define NCR5380_dma_recv_setup t128_pread #define NCR5380_dma_recv_setup t128_pread
#define NCR5380_dma_send_setup t128_pwrite #define NCR5380_dma_send_setup t128_pwrite
#define NCR5380_dma_residual(instance) (0)
#define NCR5380_intr t128_intr #define NCR5380_intr t128_intr
#define NCR5380_queue_command t128_queue_command #define NCR5380_queue_command t128_queue_command
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment