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:
parent
5551bc30e4
commit
5768718da9
@ -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,45 +1609,44 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
|
||||
* request.
|
||||
*/
|
||||
|
||||
if (hostdata->flags & FLAG_DMA_FIXUP) {
|
||||
if (p & SR_IO) {
|
||||
/*
|
||||
* The workaround was to transfer fewer bytes than we
|
||||
* intended to with the pseudo-DMA read function, wait for
|
||||
* the chip to latch the last byte, read it, and then disable
|
||||
* pseudo-DMA mode.
|
||||
*
|
||||
* After REQ is asserted, the NCR5380 asserts DRQ and ACK.
|
||||
* REQ is deasserted when ACK is asserted, and not reasserted
|
||||
* until ACK goes false. Since the NCR5380 won't lower ACK
|
||||
* until DACK is asserted, which won't happen unless we twiddle
|
||||
* the DMA port or we take the NCR5380 out of DMA mode, we
|
||||
* can guarantee that we won't handshake another extra
|
||||
* byte.
|
||||
*/
|
||||
|
||||
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);
|
||||
} 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");
|
||||
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 receive function, wait for
|
||||
* the chip to latch the last byte, read it, and then disable
|
||||
* DMA mode.
|
||||
*
|
||||
* After REQ is asserted, the NCR5380 asserts DRQ and ACK.
|
||||
* REQ is deasserted when ACK is asserted, and not reasserted
|
||||
* until ACK goes false. Since the NCR5380 won't lower ACK
|
||||
* until DACK is asserted, which won't happen unless we twiddle
|
||||
* 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)) {
|
||||
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 {
|
||||
result = -1;
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user