forked from Minki/linux
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>
This commit is contained in:
parent
7585eb1b7c
commit
4055dee7f5
@ -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);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
|
||||
if (err_mask) {
|
||||
ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
|
||||
"(err_mask=0x%x)\n", err_mask);
|
||||
return -EIO;
|
||||
}
|
||||
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))
|
||||
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)
|
||||
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)
|
||||
ign_dev_err = 1;
|
||||
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user