scsi: NCR5380: Check for phase match during PDMA fixup

It's not an error for a target to change the bus phase during a transfer.
Unfortunately, the FLAG_DMA_FIXUP workaround does not allow for that -- a
phase change produces a DRQ timeout error and the device borken flag will
be set.

Check the phase match bit during FLAG_DMA_FIXUP processing. Don't forget to
decrement the command residual. While we are here, change shost_printk()
into scmd_printk() for better consistency with other DMA error messages.

Tested-by: Stan Johnson <userm57@yahoo.com>
Fixes: 55181be8ce ("ncr5380: Replace redundant flags with FLAG_NO_DMA_FIXUP")
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
Link: https://lore.kernel.org/r/99dc7d1f4c825621b5b120963a69f6cd3e9ca659.1723001788.git.fthain@linux-m68k.org
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Finn Thain 2024-08-07 13:36:28 +10:00 committed by Martin K. Petersen
parent 5551bc30e4
commit 5768718da9

View file

@ -1485,6 +1485,7 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
unsigned char **data)
{
struct NCR5380_hostdata *hostdata = shost_priv(instance);
struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(hostdata->connected);
int c = *count;
unsigned char p = *phase;
unsigned char *d = *data;
@ -1496,7 +1497,7 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
return -1;
}
NCR5380_to_ncmd(hostdata->connected)->phase = p;
ncmd->phase = p;
if (p & SR_IO) {
if (hostdata->read_overruns)
@ -1608,13 +1609,13 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
* request.
*/
if (hostdata->flags & FLAG_DMA_FIXUP) {
if (p & SR_IO) {
if ((hostdata->flags & FLAG_DMA_FIXUP) &&
(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) {
/*
* 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 receive function, wait for
* the chip to latch the last byte, read it, and then disable
* pseudo-DMA mode.
* DMA mode.
*
* After REQ is asserted, the NCR5380 asserts DRQ and ACK.
* REQ is deasserted when ACK is asserted, and not reasserted
@ -1623,31 +1624,30 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
* the DMA port or we take the NCR5380 out of DMA mode, we
* can guarantee that we won't handshake another extra
* byte.
*
* If sending, 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.
*/
if (NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
BASR_DRQ, BASR_DRQ, 0) < 0) {
result = -1;
shost_printk(KERN_ERR, instance, "PDMA read: DRQ timeout\n");
}
if (NCR5380_poll_politely(hostdata, STATUS_REG,
SR_REQ, 0, 0) < 0) {
result = -1;
shost_printk(KERN_ERR, instance, "PDMA read: !REQ timeout\n");
}
d[*count - 1] = NCR5380_read(INPUT_DATA_REG);
if (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
BASR_DRQ, BASR_DRQ, 0)) {
if ((p & SR_IO) &&
(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) {
if (!NCR5380_poll_politely(hostdata, STATUS_REG,
SR_REQ, 0, 0)) {
d[c] = NCR5380_read(INPUT_DATA_REG);
--ncmd->this_residual;
} else {
/*
* 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.
*/
if (NCR5380_poll_politely2(hostdata,
BUS_AND_STATUS_REG, BASR_DRQ, BASR_DRQ,
BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, 0) < 0) {
result = -1;
shost_printk(KERN_ERR, instance, "PDMA write: DRQ and phase timeout\n");
scmd_printk(KERN_ERR, hostdata->connected,
"PDMA fixup: !REQ timeout\n");
}
}
} else if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH) {
result = -1;
scmd_printk(KERN_ERR, hostdata->connected,
"PDMA fixup: DRQ timeout\n");
}
}
NCR5380_dma_complete(instance);