Commit 14d2bac1 authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik
Browse files

[PATCH] libata: improve ata_bus_probe()



Improve ata_bus_probe() such that configuration failures are handled
better.  Each device is given ATA_PROBE_MAX_TRIES chances, but any
non-transient error (revalidation failure with -ENODEV, configuration
failure with -EINVAL...) disables the device directly.  Any IO error
results in SATA PHY speed down and ata_set_mode() failure lowers
transfer mode.  The last try always puts a device into PIO-0.

After each failure, the whole port is reset to make sure that the
controller and all the devices are in a known and stable state.  The
reset also applies SATA SPD configuration if necessary.

Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent cf176e1a
Loading
Loading
Loading
Loading
+49 −16
Original line number Diff line number Diff line
@@ -1370,11 +1370,18 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
static int ata_bus_probe(struct ata_port *ap)
{
	unsigned int classes[ATA_MAX_DEVICES];
	int i, rc, found = 0;
	int tries[ATA_MAX_DEVICES];
	int i, rc, down_xfermask;
	struct ata_device *dev;

	ata_port_probe(ap);

	for (i = 0; i < ATA_MAX_DEVICES; i++)
		tries[i] = ATA_PROBE_MAX_TRIES;

 retry:
	down_xfermask = 0;

	/* reset and determine device classes */
	for (i = 0; i < ATA_MAX_DEVICES; i++)
		classes[i] = ATA_DEV_UNKNOWN;
@@ -1404,21 +1411,23 @@ static int ata_bus_probe(struct ata_port *ap)
		dev = &ap->device[i];
		dev->class = classes[i];

		if (!ata_dev_enabled(dev))
			continue;

		WARN_ON(dev->id != NULL);
		if (ata_dev_read_id(ap, dev, &dev->class, 1, &dev->id)) {
			dev->class = ATA_DEV_NONE;
			continue;
		if (!tries[i]) {
			ata_down_xfermask_limit(ap, dev, 1);
			ata_dev_disable(ap, dev);
		}

		if (ata_dev_configure(ap, dev, 1)) {
			ata_dev_disable(ap, dev);
		if (!ata_dev_enabled(dev))
			continue;
		}

		found = 1;
		kfree(dev->id);
		dev->id = NULL;
		rc = ata_dev_read_id(ap, dev, &dev->class, 1, &dev->id);
		if (rc)
			goto fail;

		rc = ata_dev_configure(ap, dev, 1);
		if (rc)
			goto fail;
	}

	/* configure transfer mode */
@@ -1427,12 +1436,18 @@ static int ata_bus_probe(struct ata_port *ap)
		 * return error code and failing device on failure as
		 * ata_set_mode() does.
		 */
		if (found)
		for (i = 0; i < ATA_MAX_DEVICES; i++)
			if (ata_dev_enabled(&ap->device[i])) {
				ap->ops->set_mode(ap);
				break;
			}
		rc = 0;
	} else {
		while (ata_set_mode(ap, &dev))
			ata_dev_disable(ap, dev);
		rc = ata_set_mode(ap, &dev);
		if (rc) {
			down_xfermask = 1;
			goto fail;
		}
	}

	for (i = 0; i < ATA_MAX_DEVICES; i++)
@@ -1443,6 +1458,24 @@ static int ata_bus_probe(struct ata_port *ap)
	ata_port_disable(ap);
	ap->ops->port_disable(ap);
	return -ENODEV;

 fail:
	switch (rc) {
	case -EINVAL:
	case -ENODEV:
		tries[dev->devno] = 0;
		break;
	case -EIO:
		ata_down_sata_spd_limit(ap);
		/* fall through */
	default:
		tries[dev->devno]--;
		if (down_xfermask &&
		    ata_down_xfermask_limit(ap, dev, tries[dev->devno] == 1))
			tries[dev->devno] = 0;
	}

	goto retry;
}

/**
+3 −0
Original line number Diff line number Diff line
@@ -211,6 +211,9 @@ enum {
	/* Masks for port functions */
	ATA_PORT_PRIMARY	= (1 << 0),
	ATA_PORT_SECONDARY	= (1 << 1),

	/* how hard are we gonna try to probe/recover devices */
	ATA_PROBE_MAX_TRIES	= 3,
};

enum hsm_task_states {