From 17bd9a2f4c35de29d2539a2ff6851d61be281e25 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 29 Oct 2007 21:21:37 +0100 Subject: libata and bogus LBA48 drives A colleague noticed recent versions of Ubuntu no longer detect his 80 GB ST380020ACE drive. This drive is special in that it advertises LBA48 support, but has the lba_capacity_2 field set to zero (cfr. http://lkml.org/lkml/2004/3/30/163). Upon closer look, libata indeed doesn't seem to handle this case yet. Below is an (untested) fix. Signed-off-by: Jeff Garzik --- include/linux/ata.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/linux/ata.h b/include/linux/ata.h index 61535e72834d..304825b1c977 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -425,6 +425,8 @@ static inline int ata_id_has_lba48(const u16 *id) { if ((id[83] & 0xC000) != 0x4000) return 0; + if (!ata_id_u64(id, 100)) + return 0; return id[83] & (1 << 10); } -- cgit v1.2.3-59-g8ed1b From 6bbfd53d47abd1fb20d7c93a9b19a75970b66f49 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 5 Nov 2007 22:58:58 +0000 Subject: libata: handle broken cable reporting One or two ancient drives predated the cable spec and didn't sent the valid bits for the field. I had hoped to leave this out of libata as a piece of historical annoyance but a recent CD drive shows the same bug so we have to import support for it. Same concept as Bartlomiej's changes old IDE except that as we have centralised blacklists we can avoid keeping another private table of stuff Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 21 ++++++++++++++++++++- include/linux/ata.h | 9 +++++++++ include/linux/libata.h | 1 + 3 files changed, 30 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 3ed3cf2f5568..ec3ce120a517 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4241,6 +4241,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "ST340823A", NULL, ATA_HORKAGE_HPA_SIZE, }, { "ST320413A", NULL, ATA_HORKAGE_HPA_SIZE, }, + /* Devices which get the IVB wrong */ + { "QUANTUM FIREBALLlct10 05", "A03.0900", ATA_HORKAGE_IVB, }, + { "TSSTcorp CDDVDW SH-S202J", "SB00", ATA_HORKAGE_IVB, }, + /* End Marker */ { } }; @@ -4301,6 +4305,21 @@ static int ata_dma_blacklisted(const struct ata_device *dev) return (dev->horkage & ATA_HORKAGE_NODMA) ? 1 : 0; } +/** + * ata_is_40wire - check drive side detection + * @dev: device + * + * Perform drive side detection decoding, allowing for device vendors + * who can't follow the documentation. + */ + +static int ata_is_40wire(struct ata_device *dev) +{ + if (dev->horkage & ATA_HORKAGE_IVB) + return ata_drive_40wire_relaxed(dev->id); + return ata_drive_40wire(dev->id); +} + /** * ata_dev_xfermask - Compute supported xfermask of the given device * @dev: Device to compute xfermask for @@ -4370,7 +4389,7 @@ static void ata_dev_xfermask(struct ata_device *dev) if (xfer_mask & (0xF8 << ATA_SHIFT_UDMA)) /* UDMA/44 or higher would be available */ if ((ap->cbl == ATA_CBL_PATA40) || - (ata_drive_40wire(dev->id) && + (ata_is_40wire(dev) && (ap->cbl == ATA_CBL_PATA_UNK || ap->cbl == ATA_CBL_PATA80))) { ata_dev_printk(dev, KERN_WARNING, diff --git a/include/linux/ata.h b/include/linux/ata.h index 304825b1c977..5c4e54a2a8d6 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -537,6 +537,15 @@ static inline int ata_drive_40wire(const u16 *dev_id) return 1; } +static inline int ata_drive_40wire_relaxed(const u16 *dev_id) +{ + if (ata_id_is_sata(dev_id)) + return 0; /* SATA */ + if ((dev_id[93] & 0x2000) == 0x2000) + return 0; /* 80 wire */ + return 1; +} + static inline int atapi_cdb_len(const u16 *dev_id) { u16 tmp = dev_id[0] & 0x3; diff --git a/include/linux/libata.h b/include/linux/libata.h index 1e277852ba42..56a5673aebad 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -339,6 +339,7 @@ enum { ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */ ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */ ATA_HORKAGE_IPM = (1 << 7), /* Link PM problems */ + ATA_HORKAGE_IVB = (1 << 8), /* cbl det validity bit bugs */ /* DMA mask for user DMA control: User visible values; DO NOT renumber */ -- cgit v1.2.3-59-g8ed1b