summaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-core.c
diff options
context:
space:
mode:
authorTejun Heo2008-02-07 02:34:08 +0100
committerJeff Garzik2008-02-11 20:29:47 +0100
commit4055dee7f525a702a060ea08a3fb9f045317355f (patch)
tree1239fe8cdb67bebbc126cf959d3f4376e4a9236c /drivers/ata/libata-core.c
parentpata_via: fix SATA cable detection on cx700 (diff)
downloadkernel-qcow2-linux-4055dee7f525a702a060ea08a3fb9f045317355f.tar.gz
kernel-qcow2-linux-4055dee7f525a702a060ea08a3fb9f045317355f.tar.xz
kernel-qcow2-linux-4055dee7f525a702a060ea08a3fb9f045317355f.zip
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: Tejun Heo <htejun@gmail.com> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata/libata-core.c')
-rw-r--r--drivers/ata/libata-core.c48
1 files changed, 33 insertions, 15 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 3011919f3ec8..004dae4ea5bc 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -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)
{
struct ata_eh_context *ehc = &dev->link->eh_context;
+ const char *dev_err_whine = "";
+ int ign_dev_err = 0;
unsigned int err_mask;
int rc;
@@ -3057,41 +3059,57 @@ static int ata_dev_set_mode(struct ata_device *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 */
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
SET_XFERMODE request but support PIO0-2 timings and no IORDY */
if (dev->xfer_shift == ATA_SHIFT_PIO && !ata_id_has_iordy(dev->id) &&
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.
Don't fail an MWDMA0 set IFF the device indicates it is in MWDMA0 */
if (dev->xfer_shift == ATA_SHIFT_MWDMA &&
dev->dma_mode == XFER_MW_DMA_0 &&
(dev->id[63] >> 8) & 1)
- err_mask &= ~AC_ERR_DEV;
+ ign_dev_err = 1;
- if (err_mask) {
- ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
- "(err_mask=0x%x)\n", err_mask);
- return -EIO;
- }
+ /* if the device is actually configured correctly, ignore dev err */
+ if (dev->xfer_mode == ata_xfer_mask2mode(ata_id_xfermask(dev->id)))
+ ign_dev_err = 1;
- 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;
+ if (err_mask & AC_ERR_DEV) {
+ if (!ign_dev_err)
+ goto fail;
+ else
+ dev_err_whine = " (device error ignored)";
+ }
DPRINTK("xfer_shift=%u, xfer_mode=0x%x\n",
dev->xfer_shift, (int)dev->xfer_mode);
- ata_dev_printk(dev, KERN_INFO, "configured for %s\n",
- ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)));
+ ata_dev_printk(dev, KERN_INFO, "configured for %s%s\n",
+ ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)),
+ dev_err_whine);
+
return 0;
+
+ fail:
+ ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
+ "(err_mask=0x%x)\n", err_mask);
+ return -EIO;
}
/**