diff options
author | Alan Cox <alan@lxorguk.ukuu.org.uk> | 2007-04-10 19:23:13 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-04-28 14:16:06 -0400 |
commit | 1e999736cafdffc374f22eed37b291129ef82e4e (patch) | |
tree | d71e0907827841de66f172dec0cc4d550bd2cec8 /drivers/ata | |
parent | 6bfff31e77cfa1b13490337e5a4dbaa3407e83ac (diff) |
libata: HPA support
Signed-off-by: Alan Cox <alan@redhat.com>
Add support for ignoring the BIOS HPA result (off by default) and setting
the disk to the full available size unless already frozen.
Tested with various platforms/disks and confirmed to work with the
Macintosh (which broke earlier) and ata_piix (breakage due to the LBA48
readback that Tejun fixed).
For normal users this brings us, I believe, to feature parity with old IDE
(and of course more featured in some areas too).
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/libata-core.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b5839f84b384..6d0a946afe84 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -89,6 +89,10 @@ int libata_fua = 0; | |||
89 | module_param_named(fua, libata_fua, int, 0444); | 89 | module_param_named(fua, libata_fua, int, 0444); |
90 | MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)"); | 90 | MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)"); |
91 | 91 | ||
92 | static int ata_ignore_hpa = 0; | ||
93 | module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644); | ||
94 | MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk)"); | ||
95 | |||
92 | static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ; | 96 | static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ; |
93 | module_param(ata_probe_timeout, int, 0444); | 97 | module_param(ata_probe_timeout, int, 0444); |
94 | MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)"); | 98 | MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)"); |
@@ -808,6 +812,202 @@ void ata_id_c_string(const u16 *id, unsigned char *s, | |||
808 | *p = '\0'; | 812 | *p = '\0'; |
809 | } | 813 | } |
810 | 814 | ||
815 | static u64 ata_tf_to_lba48(struct ata_taskfile *tf) | ||
816 | { | ||
817 | u64 sectors = 0; | ||
818 | |||
819 | sectors |= ((u64)(tf->hob_lbah & 0xff)) << 40; | ||
820 | sectors |= ((u64)(tf->hob_lbam & 0xff)) << 32; | ||
821 | sectors |= (tf->hob_lbal & 0xff) << 24; | ||
822 | sectors |= (tf->lbah & 0xff) << 16; | ||
823 | sectors |= (tf->lbam & 0xff) << 8; | ||
824 | sectors |= (tf->lbal & 0xff); | ||
825 | |||
826 | return ++sectors; | ||
827 | } | ||
828 | |||
829 | static u64 ata_tf_to_lba(struct ata_taskfile *tf) | ||
830 | { | ||
831 | u64 sectors = 0; | ||
832 | |||
833 | sectors |= (tf->device & 0x0f) << 24; | ||
834 | sectors |= (tf->lbah & 0xff) << 16; | ||
835 | sectors |= (tf->lbam & 0xff) << 8; | ||
836 | sectors |= (tf->lbal & 0xff); | ||
837 | |||
838 | return ++sectors; | ||
839 | } | ||
840 | |||
841 | /** | ||
842 | * ata_read_native_max_address_ext - LBA48 native max query | ||
843 | * @dev: Device to query | ||
844 | * | ||
845 | * Perform an LBA48 size query upon the device in question. Return the | ||
846 | * actual LBA48 size or zero if the command fails. | ||
847 | */ | ||
848 | |||
849 | static u64 ata_read_native_max_address_ext(struct ata_device *dev) | ||
850 | { | ||
851 | unsigned int err; | ||
852 | struct ata_taskfile tf; | ||
853 | |||
854 | ata_tf_init(dev, &tf); | ||
855 | |||
856 | tf.command = ATA_CMD_READ_NATIVE_MAX_EXT; | ||
857 | tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR; | ||
858 | tf.protocol |= ATA_PROT_NODATA; | ||
859 | tf.device |= 0x40; | ||
860 | |||
861 | err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); | ||
862 | if (err) | ||
863 | return 0; | ||
864 | |||
865 | return ata_tf_to_lba48(&tf); | ||
866 | } | ||
867 | |||
868 | /** | ||
869 | * ata_read_native_max_address - LBA28 native max query | ||
870 | * @dev: Device to query | ||
871 | * | ||
872 | * Performa an LBA28 size query upon the device in question. Return the | ||
873 | * actual LBA28 size or zero if the command fails. | ||
874 | */ | ||
875 | |||
876 | static u64 ata_read_native_max_address(struct ata_device *dev) | ||
877 | { | ||
878 | unsigned int err; | ||
879 | struct ata_taskfile tf; | ||
880 | |||
881 | ata_tf_init(dev, &tf); | ||
882 | |||
883 | tf.command = ATA_CMD_READ_NATIVE_MAX; | ||
884 | tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; | ||
885 | tf.protocol |= ATA_PROT_NODATA; | ||
886 | tf.device |= 0x40; | ||
887 | |||
888 | err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); | ||
889 | if (err) | ||
890 | return 0; | ||
891 | |||
892 | return ata_tf_to_lba(&tf); | ||
893 | } | ||
894 | |||
895 | /** | ||
896 | * ata_set_native_max_address_ext - LBA48 native max set | ||
897 | * @dev: Device to query | ||
898 | * | ||
899 | * Perform an LBA48 size set max upon the device in question. Return the | ||
900 | * actual LBA48 size or zero if the command fails. | ||
901 | */ | ||
902 | |||
903 | static u64 ata_set_native_max_address_ext(struct ata_device *dev, u64 new_sectors) | ||
904 | { | ||
905 | unsigned int err; | ||
906 | struct ata_taskfile tf; | ||
907 | |||
908 | new_sectors--; | ||
909 | |||
910 | ata_tf_init(dev, &tf); | ||
911 | |||
912 | tf.command = ATA_CMD_SET_MAX_EXT; | ||
913 | tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR; | ||
914 | tf.protocol |= ATA_PROT_NODATA; | ||
915 | tf.device |= 0x40; | ||
916 | |||
917 | tf.lbal = (new_sectors >> 0) & 0xff; | ||
918 | tf.lbam = (new_sectors >> 8) & 0xff; | ||
919 | tf.lbah = (new_sectors >> 16) & 0xff; | ||
920 | |||
921 | tf.hob_lbal = (new_sectors >> 24) & 0xff; | ||
922 | tf.hob_lbam = (new_sectors >> 32) & 0xff; | ||
923 | tf.hob_lbah = (new_sectors >> 40) & 0xff; | ||
924 | |||
925 | err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); | ||
926 | if (err) | ||
927 | return 0; | ||
928 | |||
929 | return ata_tf_to_lba48(&tf); | ||
930 | } | ||
931 | |||
932 | /** | ||
933 | * ata_set_native_max_address - LBA28 native max set | ||
934 | * @dev: Device to query | ||
935 | * | ||
936 | * Perform an LBA28 size set max upon the device in question. Return the | ||
937 | * actual LBA28 size or zero if the command fails. | ||
938 | */ | ||
939 | |||
940 | static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors) | ||
941 | { | ||
942 | unsigned int err; | ||
943 | struct ata_taskfile tf; | ||
944 | |||
945 | new_sectors--; | ||
946 | |||
947 | ata_tf_init(dev, &tf); | ||
948 | |||
949 | tf.command = ATA_CMD_SET_MAX; | ||
950 | tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; | ||
951 | tf.protocol |= ATA_PROT_NODATA; | ||
952 | |||
953 | tf.lbal = (new_sectors >> 0) & 0xff; | ||
954 | tf.lbam = (new_sectors >> 8) & 0xff; | ||
955 | tf.lbah = (new_sectors >> 16) & 0xff; | ||
956 | tf.device |= ((new_sectors >> 24) & 0x0f) | 0x40; | ||
957 | |||
958 | err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); | ||
959 | if (err) | ||
960 | return 0; | ||
961 | |||
962 | return ata_tf_to_lba(&tf); | ||
963 | } | ||
964 | |||
965 | /** | ||
966 | * ata_hpa_resize - Resize a device with an HPA set | ||
967 | * @dev: Device to resize | ||
968 | * | ||
969 | * Read the size of an LBA28 or LBA48 disk with HPA features and resize | ||
970 | * it if required to the full size of the media. The caller must check | ||
971 | * the drive has the HPA feature set enabled. | ||
972 | */ | ||
973 | |||
974 | static u64 ata_hpa_resize(struct ata_device *dev) | ||
975 | { | ||
976 | u64 sectors = dev->n_sectors; | ||
977 | u64 hpa_sectors; | ||
978 | |||
979 | if (ata_id_has_lba48(dev->id)) | ||
980 | hpa_sectors = ata_read_native_max_address_ext(dev); | ||
981 | else | ||
982 | hpa_sectors = ata_read_native_max_address(dev); | ||
983 | |||
984 | /* if no hpa, both should be equal */ | ||
985 | ata_dev_printk(dev, KERN_INFO, "%s 1: sectors = %lld, hpa_sectors = %lld\n", | ||
986 | __FUNCTION__, sectors, hpa_sectors); | ||
987 | |||
988 | if (hpa_sectors > sectors) { | ||
989 | ata_dev_printk(dev, KERN_INFO, | ||
990 | "Host Protected Area detected:\n" | ||
991 | "\tcurrent size: %lld sectors\n" | ||
992 | "\tnative size: %lld sectors\n", | ||
993 | sectors, hpa_sectors); | ||
994 | |||
995 | if (ata_ignore_hpa) { | ||
996 | if (ata_id_has_lba48(dev->id)) | ||
997 | hpa_sectors = ata_set_native_max_address_ext(dev, hpa_sectors); | ||
998 | else | ||
999 | hpa_sectors = ata_set_native_max_address(dev, hpa_sectors); | ||
1000 | |||
1001 | if (hpa_sectors) { | ||
1002 | ata_dev_printk(dev, KERN_INFO, | ||
1003 | "native size increased to %lld sectors\n", hpa_sectors); | ||
1004 | return hpa_sectors; | ||
1005 | } | ||
1006 | } | ||
1007 | } | ||
1008 | return sectors; | ||
1009 | } | ||
1010 | |||
811 | static u64 ata_id_n_sectors(const u16 *id) | 1011 | static u64 ata_id_n_sectors(const u16 *id) |
812 | { | 1012 | { |
813 | if (ata_id_has_lba(id)) { | 1013 | if (ata_id_has_lba(id)) { |
@@ -1662,6 +1862,7 @@ int ata_dev_configure(struct ata_device *dev) | |||
1662 | snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id)); | 1862 | snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id)); |
1663 | 1863 | ||
1664 | dev->n_sectors = ata_id_n_sectors(id); | 1864 | dev->n_sectors = ata_id_n_sectors(id); |
1865 | dev->n_sectors_boot = dev->n_sectors; | ||
1665 | 1866 | ||
1666 | /* SCSI only uses 4-char revisions, dump full 8 chars from ATA */ | 1867 | /* SCSI only uses 4-char revisions, dump full 8 chars from ATA */ |
1667 | ata_id_c_string(dev->id, fwrevbuf, ATA_ID_FW_REV, | 1868 | ata_id_c_string(dev->id, fwrevbuf, ATA_ID_FW_REV, |
@@ -1688,6 +1889,9 @@ int ata_dev_configure(struct ata_device *dev) | |||
1688 | dev->flags |= ATA_DFLAG_FLUSH_EXT; | 1889 | dev->flags |= ATA_DFLAG_FLUSH_EXT; |
1689 | } | 1890 | } |
1690 | 1891 | ||
1892 | if (ata_id_hpa_enabled(dev->id)) | ||
1893 | dev->n_sectors = ata_hpa_resize(dev); | ||
1894 | |||
1691 | /* config NCQ */ | 1895 | /* config NCQ */ |
1692 | ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); | 1896 | ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); |
1693 | 1897 | ||
@@ -3346,6 +3550,11 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, | |||
3346 | "%llu != %llu\n", | 3550 | "%llu != %llu\n", |
3347 | (unsigned long long)dev->n_sectors, | 3551 | (unsigned long long)dev->n_sectors, |
3348 | (unsigned long long)new_n_sectors); | 3552 | (unsigned long long)new_n_sectors); |
3553 | /* Are we the boot time size - if so we appear to be the | ||
3554 | same disk at this point and our HPA got reapplied */ | ||
3555 | if (ata_ignore_hpa && dev->n_sectors_boot == new_n_sectors | ||
3556 | && ata_id_hpa_enabled(new_id)) | ||
3557 | return 1; | ||
3349 | return 0; | 3558 | return 0; |
3350 | } | 3559 | } |
3351 | 3560 | ||