Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ae72a1e authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik
Browse files

libata: improve probe failure handling



* Move forcing device to PIO0 on device disable into
  ata_dev_disable().  This makes both old and new EHs act the same
  way.

* Speed down only PIO mode on probe failure.  All commands used during
  probing are PIO commands.  There's no point in speeding down DMA.

* Retry at least once after -ENODEV.  Some devices report garbled
  IDENTIFY data after certain events.  This shouldn't cause device
  detach and re-attach.

* Rearrange EH failure path for simplicity.

Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 458337db
Loading
Loading
Loading
Loading
+19 −20
Original line number Diff line number Diff line
@@ -600,6 +600,8 @@ void ata_dev_disable(struct ata_device *dev)
{
	if (ata_dev_enabled(dev) && ata_msg_drv(dev->ap)) {
		ata_dev_printk(dev, KERN_WARNING, "disabled\n");
		ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 |
					     ATA_DNXFER_QUIET);
		dev->class++;
	}
}
@@ -1778,9 +1780,8 @@ int ata_bus_probe(struct ata_port *ap)
{
	unsigned int classes[ATA_MAX_DEVICES];
	int tries[ATA_MAX_DEVICES];
	int i, rc, down_xfermask;
	int i, rc;
	struct ata_device *dev;
	int dnxfer_sel;

	ata_port_probe(ap);

@@ -1788,8 +1789,6 @@ int ata_bus_probe(struct ata_port *ap)
		tries[i] = ATA_PROBE_MAX_TRIES;

 retry:
	down_xfermask = 0;

	/* reset and determine device classes */
	ap->ops->phy_reset(ap);

@@ -1837,10 +1836,8 @@ int ata_bus_probe(struct ata_port *ap)

	/* configure transfer mode */
	rc = ata_set_mode(ap, &dev);
	if (rc) {
		down_xfermask = 1;
	if (rc)
		goto fail;
	}

	for (i = 0; i < ATA_MAX_DEVICES; i++)
		if (ata_dev_enabled(&ap->device[i]))
@@ -1852,27 +1849,29 @@ int ata_bus_probe(struct ata_port *ap)
	return -ENODEV;

 fail:
	tries[dev->devno]--;

	switch (rc) {
	case -EINVAL:
	case -ENODEV:
		/* eeek, something went very wrong, give up */
		tries[dev->devno] = 0;
		break;

	case -ENODEV:
		/* give it just one more chance */
		tries[dev->devno] = min(tries[dev->devno], 1);
	case -EIO:
		if (tries[dev->devno] == 1) {
			/* This is the last chance, better to slow
			 * down than lose it.
			 */
			sata_down_spd_limit(ap);
		/* fall through */
	default:
		tries[dev->devno]--;
		dnxfer_sel = ATA_DNXFER_ANY;
		if (tries[dev->devno] == 1)
			dnxfer_sel = ATA_DNXFER_FORCE_PIO0;
		if (down_xfermask && ata_down_xfermask_limit(dev, dnxfer_sel))
			tries[dev->devno] = 0;
			ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
		}
	}

	if (!tries[dev->devno]) {
		ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0);
	if (!tries[dev->devno])
		ata_dev_disable(dev);
	}

	goto retry;
}
+18 −17
Original line number Diff line number Diff line
@@ -1964,8 +1964,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
{
	struct ata_eh_context *ehc = &ap->eh_context;
	struct ata_device *dev;
	int down_xfermask, i, rc;
	int dnxfer_sel;
	int i, rc;

	DPRINTK("ENTER\n");

@@ -1994,7 +1993,6 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
	}

 retry:
	down_xfermask = 0;
	rc = 0;

	/* if UNLOADING, finish immediately */
@@ -2039,10 +2037,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
	/* configure transfer mode if necessary */
	if (ehc->i.flags & ATA_EHI_SETMODE) {
		rc = ata_set_mode(ap, &dev);
		if (rc) {
			down_xfermask = 1;
		if (rc)
			goto dev_fail;
		}
		ehc->i.flags &= ~ATA_EHI_SETMODE;
	}

@@ -2054,22 +2050,27 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
	goto out;

 dev_fail:
	ehc->tries[dev->devno]--;

	switch (rc) {
	case -ENODEV:
		/* device missing, schedule probing */
		ehc->i.probe_mask |= (1 << dev->devno);
	case -EINVAL:
		/* eeek, something went very wrong, give up */
		ehc->tries[dev->devno] = 0;
		break;

	case -ENODEV:
		/* device missing or wrong IDENTIFY data, schedule probing */
		ehc->i.probe_mask |= (1 << dev->devno);
		/* give it just one more chance */
		ehc->tries[dev->devno] = min(ehc->tries[dev->devno], 1);
	case -EIO:
		if (ehc->tries[dev->devno] == 1) {
			/* This is the last chance, better to slow
			 * down than lose it.
			 */
			sata_down_spd_limit(ap);
	default:
		ehc->tries[dev->devno]--;
		dnxfer_sel = ATA_DNXFER_ANY;
		if (ehc->tries[dev->devno] == 1)
			dnxfer_sel = ATA_DNXFER_FORCE_PIO0;
		if (down_xfermask && ata_down_xfermask_limit(dev, dnxfer_sel))
			ehc->tries[dev->devno] = 0;
			ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
		}
	}

	if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {