]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - include/linux/ata.h
libata: switch to using block layer tagging support
[linux-2.6-omap-h63xx.git] / include / linux / ata.h
index 81d9adeb819e74665166854a4b142f2ee2a3a34e..a53318b8cbd0ea9a4b7a69f3376cb11036a5ff32 100644 (file)
@@ -30,6 +30,7 @@
 #define __LINUX_ATA_H__
 
 #include <linux/types.h>
+#include <asm/byteorder.h>
 
 /* defines only for the constants which don't work well as enums */
 #define ATA_DMA_BOUNDARY       0xffffUL
@@ -781,6 +782,76 @@ static inline int atapi_id_dmadir(const u16 *dev_id)
        return ata_id_major_version(dev_id) >= 7 && (dev_id[62] & 0x8000);
 }
 
+/*
+ * ata_id_is_lba_capacity_ok() performs a sanity check on
+ * the claimed LBA capacity value for the device.
+ *
+ * Returns 1 if LBA capacity looks sensible, 0 otherwise.
+ *
+ * It is called only once for each device.
+ */
+static inline int ata_id_is_lba_capacity_ok(u16 *id)
+{
+       unsigned long lba_sects, chs_sects, head, tail;
+
+       /* No non-LBA info .. so valid! */
+       if (id[ATA_ID_CYLS] == 0)
+               return 1;
+
+       lba_sects = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
+
+       /*
+        * The ATA spec tells large drives to return
+        * C/H/S = 16383/16/63 independent of their size.
+        * Some drives can be jumpered to use 15 heads instead of 16.
+        * Some drives can be jumpered to use 4092 cyls instead of 16383.
+        */
+       if ((id[ATA_ID_CYLS] == 16383 ||
+            (id[ATA_ID_CYLS] == 4092 && id[ATA_ID_CUR_CYLS] == 16383)) &&
+           id[ATA_ID_SECTORS] == 63 &&
+           (id[ATA_ID_HEADS] == 15 || id[ATA_ID_HEADS] == 16) &&
+           (lba_sects >= 16383 * 63 * id[ATA_ID_HEADS]))
+               return 1;
+
+       chs_sects = id[ATA_ID_CYLS] * id[ATA_ID_HEADS] * id[ATA_ID_SECTORS];
+
+       /* perform a rough sanity check on lba_sects: within 10% is OK */
+       if (lba_sects - chs_sects < chs_sects/10)
+               return 1;
+
+       /* some drives have the word order reversed */
+       head = (lba_sects >> 16) & 0xffff;
+       tail = lba_sects & 0xffff;
+       lba_sects = head | (tail << 16);
+
+       if (lba_sects - chs_sects < chs_sects/10) {
+               *(__le32 *)&id[ATA_ID_LBA_CAPACITY] = __cpu_to_le32(lba_sects);
+               return 1;       /* LBA capacity is (now) good */
+       }
+
+       return 0;       /* LBA capacity value may be bad */
+}
+
+static inline void ata_id_to_hd_driveid(u16 *id)
+{
+#ifdef __BIG_ENDIAN
+       /* accessed in struct hd_driveid as 8-bit values */
+       id[ATA_ID_MAX_MULTSECT]  = __cpu_to_le16(id[ATA_ID_MAX_MULTSECT]);
+       id[ATA_ID_CAPABILITY]    = __cpu_to_le16(id[ATA_ID_CAPABILITY]);
+       id[ATA_ID_OLD_PIO_MODES] = __cpu_to_le16(id[ATA_ID_OLD_PIO_MODES]);
+       id[ATA_ID_OLD_DMA_MODES] = __cpu_to_le16(id[ATA_ID_OLD_DMA_MODES]);
+       id[ATA_ID_MULTSECT]      = __cpu_to_le16(id[ATA_ID_MULTSECT]);
+
+       /* as 32-bit values */
+       *(u32 *)&id[ATA_ID_LBA_CAPACITY] = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
+       *(u32 *)&id[ATA_ID_SPG]          = ata_id_u32(id, ATA_ID_SPG);
+
+       /* as 64-bit value */
+       *(u64 *)&id[ATA_ID_LBA_CAPACITY_2] =
+               ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
+#endif
+}
+
 static inline int is_multi_taskfile(struct ata_taskfile *tf)
 {
        return (tf->command == ATA_CMD_READ_MULTI) ||