Commit 5768718d authored by Finn Thain's avatar Finn Thain Committed by Martin K. Petersen
Browse files

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: default avatarStan Johnson <userm57@yahoo.com>
Fixes: 55181be8 ("ncr5380: Replace redundant flags with FLAG_NO_DMA_FIXUP")
Signed-off-by: default avatarFinn Thain <fthain@linux-m68k.org>
Link: https://lore.kernel.org/r/99dc7d1f4c825621b5b120963a69f6cd3e9ca659.1723001788.git.fthain@linux-m68k.org


Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 5551bc30
Loading
Loading
Loading
Loading
+39 −39
Original line number Diff line number Diff line
@@ -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,30 +1624,29 @@ 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 (NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
			                          BASR_DRQ, BASR_DRQ, 0) < 0) {
		 *
		 * 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;
				shost_printk(KERN_ERR, instance, "PDMA read: DRQ timeout\n");
					scmd_printk(KERN_ERR, hostdata->connected,
						    "PDMA fixup: !REQ 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) {
		} else if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH) {
			result = -1;
				shost_printk(KERN_ERR, instance, "PDMA write: DRQ and phase timeout\n");
			}
			scmd_printk(KERN_ERR, hostdata->connected,
				    "PDMA fixup: DRQ timeout\n");
		}
	}