Commit f343e578 authored by Ondrej Zary's avatar Ondrej Zary Committed by Damien Le Moal
Browse files

ata: pata_parport: add custom version of wait_after_reset



Some parallel adapters (e.g. EXP Computer MC-1285B EPP Cable) return
bogus values when there's no master device present. This can cause
reset to fail, preventing the lone slave device (such as EXP Computer
CD-865) from working.

Add custom version of wait_after_reset that ignores master failure when
a slave device is present. The custom version is also needed because
the generic ata_sff_wait_after_reset uses direct port I/O for slave
device detection.

Signed-off-by: default avatarOndrej Zary <linux@zary.sk>
Reviewed-by: default avatarSergey Shtylyov <s.shtylyov@omp.ru>
Signed-off-by: default avatarDamien Le Moal <dlemoal@kernel.org>
parent d2302427
Loading
Loading
Loading
Loading
+67 −1
Original line number Diff line number Diff line
@@ -80,6 +80,72 @@ static bool pata_parport_devchk(struct ata_port *ap, unsigned int device)
	return (nsect == 0x55) && (lbal == 0xaa);
}

static int pata_parport_wait_after_reset(struct ata_link *link,
					 unsigned int devmask,
					 unsigned long deadline)
{
	struct ata_port *ap = link->ap;
	struct pi_adapter *pi = ap->host->private_data;
	unsigned int dev0 = devmask & (1 << 0);
	unsigned int dev1 = devmask & (1 << 1);
	int rc, ret = 0;

	ata_msleep(ap, ATA_WAIT_AFTER_RESET);

	/* always check readiness of the master device */
	rc = ata_sff_wait_ready(link, deadline);
	if (rc) {
		/*
		 * some adapters return bogus values if master device is not
		 * present, so don't abort now if a slave device is present
		 */
		if (!dev1)
			return rc;
		ret = -ENODEV;
	}

	/*
	 * if device 1 was found in ata_devchk, wait for register
	 * access briefly, then wait for BSY to clear.
	 */
	if (dev1) {
		int i;

		pata_parport_dev_select(ap, 1);

		/*
		 * Wait for register access.  Some ATAPI devices fail
		 * to set nsect/lbal after reset, so don't waste too
		 * much time on it.  We're gonna wait for !BSY anyway.
		 */
		for (i = 0; i < 2; i++) {
			u8 nsect, lbal;

			nsect = pi->proto->read_regr(pi, 0, ATA_REG_NSECT);
			lbal = pi->proto->read_regr(pi, 0, ATA_REG_LBAL);
			if (nsect == 1 && lbal == 1)
				break;
			/* give drive a breather */
			ata_msleep(ap, 50);
		}

		rc = ata_sff_wait_ready(link, deadline);
		if (rc) {
			if (rc != -ENODEV)
				return rc;
			ret = rc;
		}
	}

	pata_parport_dev_select(ap, 0);
	if (dev1)
		pata_parport_dev_select(ap, 1);
	if (dev0)
		pata_parport_dev_select(ap, 0);

	return ret;
}

static int pata_parport_bus_softreset(struct ata_port *ap, unsigned int devmask,
				      unsigned long deadline)
{
@@ -94,7 +160,7 @@ static int pata_parport_bus_softreset(struct ata_port *ap, unsigned int devmask,
	ap->last_ctl = ap->ctl;

	/* wait the port to become ready */
	return ata_sff_wait_after_reset(&ap->link, devmask, deadline);
	return pata_parport_wait_after_reset(&ap->link, devmask, deadline);
}

static int pata_parport_softreset(struct ata_link *link, unsigned int *classes,