Commit 4055dee7 authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik

libata: ignore deverr on SETXFER if mode is configured

Some controllers (VIA CX700) raise device error on SETXFER even after
mode configuration succeeded.  Update ata_dev_set_mode() such that
device error is ignored if transfer mode is configured correctly.  To
implement this, device is revalidated even after device error on
SETXFER.

This fixes kernel bugzilla bug 8563.
Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 7585eb1b
...@@ -3048,6 +3048,8 @@ int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel) ...@@ -3048,6 +3048,8 @@ int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel)
static int ata_dev_set_mode(struct ata_device *dev) static int ata_dev_set_mode(struct ata_device *dev)
{ {
struct ata_eh_context *ehc = &dev->link->eh_context; struct ata_eh_context *ehc = &dev->link->eh_context;
const char *dev_err_whine = "";
int ign_dev_err = 0;
unsigned int err_mask; unsigned int err_mask;
int rc; int rc;
...@@ -3057,41 +3059,57 @@ static int ata_dev_set_mode(struct ata_device *dev) ...@@ -3057,41 +3059,57 @@ static int ata_dev_set_mode(struct ata_device *dev)
err_mask = ata_dev_set_xfermode(dev); err_mask = ata_dev_set_xfermode(dev);
if (err_mask & ~AC_ERR_DEV)
goto fail;
/* revalidate */
ehc->i.flags |= ATA_EHI_POST_SETMODE;
rc = ata_dev_revalidate(dev, ATA_DEV_UNKNOWN, 0);
ehc->i.flags &= ~ATA_EHI_POST_SETMODE;
if (rc)
return rc;
/* Old CFA may refuse this command, which is just fine */ /* Old CFA may refuse this command, which is just fine */
if (dev->xfer_shift == ATA_SHIFT_PIO && ata_id_is_cfa(dev->id)) if (dev->xfer_shift == ATA_SHIFT_PIO && ata_id_is_cfa(dev->id))
err_mask &= ~AC_ERR_DEV; ign_dev_err = 1;
/* Some very old devices and some bad newer ones fail any kind of /* Some very old devices and some bad newer ones fail any kind of
SET_XFERMODE request but support PIO0-2 timings and no IORDY */ SET_XFERMODE request but support PIO0-2 timings and no IORDY */
if (dev->xfer_shift == ATA_SHIFT_PIO && !ata_id_has_iordy(dev->id) && if (dev->xfer_shift == ATA_SHIFT_PIO && !ata_id_has_iordy(dev->id) &&
dev->pio_mode <= XFER_PIO_2) dev->pio_mode <= XFER_PIO_2)
err_mask &= ~AC_ERR_DEV; ign_dev_err = 1;
/* Early MWDMA devices do DMA but don't allow DMA mode setting. /* Early MWDMA devices do DMA but don't allow DMA mode setting.
Don't fail an MWDMA0 set IFF the device indicates it is in MWDMA0 */ Don't fail an MWDMA0 set IFF the device indicates it is in MWDMA0 */
if (dev->xfer_shift == ATA_SHIFT_MWDMA && if (dev->xfer_shift == ATA_SHIFT_MWDMA &&
dev->dma_mode == XFER_MW_DMA_0 && dev->dma_mode == XFER_MW_DMA_0 &&
(dev->id[63] >> 8) & 1) (dev->id[63] >> 8) & 1)
err_mask &= ~AC_ERR_DEV; ign_dev_err = 1;
if (err_mask) { /* if the device is actually configured correctly, ignore dev err */
ata_dev_printk(dev, KERN_ERR, "failed to set xfermode " if (dev->xfer_mode == ata_xfer_mask2mode(ata_id_xfermask(dev->id)))
"(err_mask=0x%x)\n", err_mask); ign_dev_err = 1;
return -EIO;
}
ehc->i.flags |= ATA_EHI_POST_SETMODE; if (err_mask & AC_ERR_DEV) {
rc = ata_dev_revalidate(dev, ATA_DEV_UNKNOWN, 0); if (!ign_dev_err)
ehc->i.flags &= ~ATA_EHI_POST_SETMODE; goto fail;
if (rc) else
return rc; dev_err_whine = " (device error ignored)";
}
DPRINTK("xfer_shift=%u, xfer_mode=0x%x\n", DPRINTK("xfer_shift=%u, xfer_mode=0x%x\n",
dev->xfer_shift, (int)dev->xfer_mode); dev->xfer_shift, (int)dev->xfer_mode);
ata_dev_printk(dev, KERN_INFO, "configured for %s\n", ata_dev_printk(dev, KERN_INFO, "configured for %s%s\n",
ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode))); ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)),
dev_err_whine);
return 0; return 0;
fail:
ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
"(err_mask=0x%x)\n", err_mask);
return -EIO;
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment