diff options
author | Grant Grundler <grundler@google.com> | 2010-08-17 13:56:53 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2010-10-21 20:21:03 -0400 |
commit | 295124dce4ddfd40b1f12d3ffd2779673e87c701 (patch) | |
tree | cccdc9d6270fbc72b9147050232c627f7ddee23b /include/linux/ata.h | |
parent | 1aadf5c3bbbbb0db09dcb5aa26c61326e0d3e9e7 (diff) |
[libata] support for > 512 byte sectors (e.g. 4K Native)
This change enables my x86 machine to recognize and talk to a
"Native 4K" SATA device.
When I started working on this, I didn't know Matthew Wilcox had
posted a similar patch 2 years ago:
http://git.kernel.org/?p=linux/kernel/git/willy/ata.git;a=shortlog;h=refs/heads/ata-large-sectors
Gwendal Grignou pointed me at the the above code and small portions of
this patch include Matthew's work. That's why Mathew is first on the
"Signed-off-by:". I've NOT included his use of a bitmap to determine
512 vs Native for ATA command block size - just used a simple table.
And bugs are almost certainly mine.
Lastly, the patch has been tested with a native 4K 'Engineering
Sample' drive provided by Hitachi GST.
Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
Signed-off-by: Grant Grundler <grundler@google.com>
Reviewed-by: Gwendal Grignou <gwendal@google.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'include/linux/ata.h')
-rw-r--r-- | include/linux/ata.h | 46 |
1 files changed, 40 insertions, 6 deletions
diff --git a/include/linux/ata.h b/include/linux/ata.h index fe6e681a9d74..0c4929fa34d3 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h | |||
@@ -89,6 +89,7 @@ enum { | |||
89 | ATA_ID_SPG = 98, | 89 | ATA_ID_SPG = 98, |
90 | ATA_ID_LBA_CAPACITY_2 = 100, | 90 | ATA_ID_LBA_CAPACITY_2 = 100, |
91 | ATA_ID_SECTOR_SIZE = 106, | 91 | ATA_ID_SECTOR_SIZE = 106, |
92 | ATA_ID_LOGICAL_SECTOR_SIZE = 117, /* and 118 */ | ||
92 | ATA_ID_LAST_LUN = 126, | 93 | ATA_ID_LAST_LUN = 126, |
93 | ATA_ID_DLF = 128, | 94 | ATA_ID_DLF = 128, |
94 | ATA_ID_CSFO = 129, | 95 | ATA_ID_CSFO = 129, |
@@ -640,16 +641,49 @@ static inline int ata_id_flush_ext_enabled(const u16 *id) | |||
640 | return (id[ATA_ID_CFS_ENABLE_2] & 0x2400) == 0x2400; | 641 | return (id[ATA_ID_CFS_ENABLE_2] & 0x2400) == 0x2400; |
641 | } | 642 | } |
642 | 643 | ||
643 | static inline int ata_id_has_large_logical_sectors(const u16 *id) | 644 | static inline u32 ata_id_logical_sector_size(const u16 *id) |
644 | { | 645 | { |
645 | if ((id[ATA_ID_SECTOR_SIZE] & 0xc000) != 0x4000) | 646 | /* T13/1699-D Revision 6a, Sep 6, 2008. Page 128. |
646 | return 0; | 647 | * IDENTIFY DEVICE data, word 117-118. |
647 | return id[ATA_ID_SECTOR_SIZE] & (1 << 13); | 648 | * 0xd000 ignores bit 13 (logical:physical > 1) |
649 | */ | ||
650 | if ((id[ATA_ID_SECTOR_SIZE] & 0xd000) == 0x5000) | ||
651 | return (((id[ATA_ID_LOGICAL_SECTOR_SIZE+1] << 16) | ||
652 | + id[ATA_ID_LOGICAL_SECTOR_SIZE]) * sizeof(u16)) ; | ||
653 | return ATA_SECT_SIZE; | ||
654 | } | ||
655 | |||
656 | static inline u8 ata_id_log2_per_physical_sector(const u16 *id) | ||
657 | { | ||
658 | /* T13/1699-D Revision 6a, Sep 6, 2008. Page 128. | ||
659 | * IDENTIFY DEVICE data, word 106. | ||
660 | * 0xe000 ignores bit 12 (logical sector > 512 bytes) | ||
661 | */ | ||
662 | if ((id[ATA_ID_SECTOR_SIZE] & 0xe000) == 0x6000) | ||
663 | return (id[ATA_ID_SECTOR_SIZE] & 0xf); | ||
664 | return 0; | ||
648 | } | 665 | } |
649 | 666 | ||
650 | static inline u16 ata_id_logical_per_physical_sectors(const u16 *id) | 667 | /* Offset of logical sectors relative to physical sectors. |
668 | * | ||
669 | * If device has more than one logical sector per physical sector | ||
670 | * (aka 512 byte emulation), vendors might offset the "sector 0" address | ||
671 | * so sector 63 is "naturally aligned" - e.g. FAT partition table. | ||
672 | * This avoids Read/Mod/Write penalties when using FAT partition table | ||
673 | * and updating "well aligned" (FS perspective) physical sectors on every | ||
674 | * transaction. | ||
675 | */ | ||
676 | static inline u16 ata_id_logical_sector_offset(const u16 *id, | ||
677 | u8 log2_per_phys) | ||
651 | { | 678 | { |
652 | return 1 << (id[ATA_ID_SECTOR_SIZE] & 0xf); | 679 | u16 word_209 = id[209]; |
680 | |||
681 | if ((log2_per_phys > 1) && (word_209 & 0xc000) == 0x4000) { | ||
682 | u16 first = word_209 & 0x3fff; | ||
683 | if (first > 0) | ||
684 | return (1 << log2_per_phys) - first; | ||
685 | } | ||
686 | return 0; | ||
653 | } | 687 | } |
654 | 688 | ||
655 | static inline int ata_id_has_lba48(const u16 *id) | 689 | static inline int ata_id_has_lba48(const u16 *id) |