diff options
author | Tejun Heo <htejun@gmail.com> | 2007-09-02 23:32:57 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-10-12 14:55:39 -0400 |
commit | 05027adccc09401a7e31d5ef51040dc75ab03c22 (patch) | |
tree | 83fbb8e65d26e10e1fd74377bc13fd358a61c13e | |
parent | c728a9149f519cbb9f610962873f4e22ed4a6efd (diff) |
libata: remiplement ata_hpa_resize()
This patch reimplement ata_hpa_resize() such that...
* All HPA related decisions are made inside ata_hpa_resize() proper.
ata_hpa_resize() returns 0 if configuration can proceed, -errno if
device needs to be reset and reconfigured.
* All errors are handled properly. If HPA unlocking isn't requested,
HPA handling is disabled automatically to avoid unnecessary device
detection failure.
* Messages are trimmed. HPA detection message is printed only during
initial configuration. HPA unlocked message is printed only during
initial configuration or unlocking results in different size.
* Instead of using sectors returned in TF of SET_MAX, re-read IDENTIFY
data as that's the value the device is going to use.
* It's called early during ata_dev_configure() as IDENTIFY data might
change after resizing.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/ata/libata-core.c | 124 |
1 files changed, 85 insertions, 39 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c7614bdc0cb9..b01b5a897dcf 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -915,7 +915,6 @@ static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors) | |||
915 | * ata_set_max_sectors - Set max sectors | 915 | * ata_set_max_sectors - Set max sectors |
916 | * @dev: target device | 916 | * @dev: target device |
917 | * @new_sectors: new max sectors value to set for the device | 917 | * @new_sectors: new max sectors value to set for the device |
918 | * @res_sectors: result max sectors | ||
919 | * | 918 | * |
920 | * Set max sectors of @dev to @new_sectors. | 919 | * Set max sectors of @dev to @new_sectors. |
921 | * | 920 | * |
@@ -924,8 +923,7 @@ static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors) | |||
924 | * previous non-volatile SET_MAX) by the drive. -EIO on other | 923 | * previous non-volatile SET_MAX) by the drive. -EIO on other |
925 | * errors. | 924 | * errors. |
926 | */ | 925 | */ |
927 | static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors, | 926 | static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors) |
928 | u64 *res_sectors) | ||
929 | { | 927 | { |
930 | unsigned int err_mask; | 928 | unsigned int err_mask; |
931 | struct ata_taskfile tf; | 929 | struct ata_taskfile tf; |
@@ -964,11 +962,6 @@ static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors, | |||
964 | return -EIO; | 962 | return -EIO; |
965 | } | 963 | } |
966 | 964 | ||
967 | if (lba48) | ||
968 | *res_sectors = ata_tf_to_lba48(&tf); | ||
969 | else | ||
970 | *res_sectors = ata_tf_to_lba(&tf); | ||
971 | |||
972 | return 0; | 965 | return 0; |
973 | } | 966 | } |
974 | 967 | ||
@@ -979,41 +972,93 @@ static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors, | |||
979 | * Read the size of an LBA28 or LBA48 disk with HPA features and resize | 972 | * Read the size of an LBA28 or LBA48 disk with HPA features and resize |
980 | * it if required to the full size of the media. The caller must check | 973 | * it if required to the full size of the media. The caller must check |
981 | * the drive has the HPA feature set enabled. | 974 | * the drive has the HPA feature set enabled. |
975 | * | ||
976 | * RETURNS: | ||
977 | * 0 on success, -errno on failure. | ||
982 | */ | 978 | */ |
983 | 979 | static int ata_hpa_resize(struct ata_device *dev) | |
984 | static u64 ata_hpa_resize(struct ata_device *dev) | ||
985 | { | 980 | { |
986 | u64 sectors = dev->n_sectors; | 981 | struct ata_eh_context *ehc = &dev->link->eh_context; |
987 | u64 hpa_sectors; | 982 | int print_info = ehc->i.flags & ATA_EHI_PRINTINFO; |
983 | u64 sectors = ata_id_n_sectors(dev->id); | ||
984 | u64 native_sectors; | ||
988 | int rc; | 985 | int rc; |
989 | 986 | ||
990 | rc = ata_read_native_max_address(dev, &hpa_sectors); | 987 | /* do we need to do it? */ |
991 | if (rc) | 988 | if (dev->class != ATA_DEV_ATA || |
989 | !ata_id_has_lba(dev->id) || !ata_id_hpa_enabled(dev->id) || | ||
990 | (dev->horkage & ATA_HORKAGE_BROKEN_HPA)) | ||
992 | return 0; | 991 | return 0; |
993 | 992 | ||
994 | if (hpa_sectors > sectors) { | 993 | /* read native max address */ |
995 | ata_dev_printk(dev, KERN_INFO, | 994 | rc = ata_read_native_max_address(dev, &native_sectors); |
996 | "Host Protected Area detected:\n" | 995 | if (rc) { |
997 | "\tcurrent size: %lld sectors\n" | 996 | /* If HPA isn't going to be unlocked, skip HPA |
998 | "\tnative size: %lld sectors\n", | 997 | * resizing from the next try. |
999 | (long long)sectors, (long long)hpa_sectors); | 998 | */ |
1000 | 999 | if (!ata_ignore_hpa) { | |
1001 | if (ata_ignore_hpa) { | 1000 | ata_dev_printk(dev, KERN_WARNING, "HPA support seems " |
1002 | rc = ata_set_max_sectors(dev, hpa_sectors, &hpa_sectors); | 1001 | "broken, will skip HPA handling\n"); |
1003 | 1002 | dev->horkage |= ATA_HORKAGE_BROKEN_HPA; | |
1004 | if (rc == 0) { | 1003 | |
1005 | ata_dev_printk(dev, KERN_INFO, "native size " | 1004 | /* we can continue if device aborted the command */ |
1006 | "increased to %lld sectors\n", | 1005 | if (rc == -EACCES) |
1007 | (long long)hpa_sectors); | 1006 | rc = 0; |
1008 | return hpa_sectors; | ||
1009 | } | ||
1010 | } | 1007 | } |
1011 | } else if (hpa_sectors < sectors) | ||
1012 | ata_dev_printk(dev, KERN_WARNING, "%s 1: hpa sectors (%lld) " | ||
1013 | "is smaller than sectors (%lld)\n", __FUNCTION__, | ||
1014 | (long long)hpa_sectors, (long long)sectors); | ||
1015 | 1008 | ||
1016 | return sectors; | 1009 | return rc; |
1010 | } | ||
1011 | |||
1012 | /* nothing to do? */ | ||
1013 | if (native_sectors <= sectors || !ata_ignore_hpa) { | ||
1014 | if (!print_info || native_sectors == sectors) | ||
1015 | return 0; | ||
1016 | |||
1017 | if (native_sectors > sectors) | ||
1018 | ata_dev_printk(dev, KERN_INFO, | ||
1019 | "HPA detected: current %llu, native %llu\n", | ||
1020 | (unsigned long long)sectors, | ||
1021 | (unsigned long long)native_sectors); | ||
1022 | else if (native_sectors < sectors) | ||
1023 | ata_dev_printk(dev, KERN_WARNING, | ||
1024 | "native sectors (%llu) is smaller than " | ||
1025 | "sectors (%llu)\n", | ||
1026 | (unsigned long long)native_sectors, | ||
1027 | (unsigned long long)sectors); | ||
1028 | return 0; | ||
1029 | } | ||
1030 | |||
1031 | /* let's unlock HPA */ | ||
1032 | rc = ata_set_max_sectors(dev, native_sectors); | ||
1033 | if (rc == -EACCES) { | ||
1034 | /* if device aborted the command, skip HPA resizing */ | ||
1035 | ata_dev_printk(dev, KERN_WARNING, "device aborted resize " | ||
1036 | "(%llu -> %llu), skipping HPA handling\n", | ||
1037 | (unsigned long long)sectors, | ||
1038 | (unsigned long long)native_sectors); | ||
1039 | dev->horkage |= ATA_HORKAGE_BROKEN_HPA; | ||
1040 | return 0; | ||
1041 | } else if (rc) | ||
1042 | return rc; | ||
1043 | |||
1044 | /* re-read IDENTIFY data */ | ||
1045 | rc = ata_dev_reread_id(dev, 0); | ||
1046 | if (rc) { | ||
1047 | ata_dev_printk(dev, KERN_ERR, "failed to re-read IDENTIFY " | ||
1048 | "data after HPA resizing\n"); | ||
1049 | return rc; | ||
1050 | } | ||
1051 | |||
1052 | if (print_info) { | ||
1053 | u64 new_sectors = ata_id_n_sectors(dev->id); | ||
1054 | ata_dev_printk(dev, KERN_INFO, | ||
1055 | "HPA unlocked: %llu -> %llu, native %llu\n", | ||
1056 | (unsigned long long)sectors, | ||
1057 | (unsigned long long)new_sectors, | ||
1058 | (unsigned long long)native_sectors); | ||
1059 | } | ||
1060 | |||
1061 | return 0; | ||
1017 | } | 1062 | } |
1018 | 1063 | ||
1019 | /** | 1064 | /** |
@@ -1837,6 +1882,11 @@ int ata_dev_configure(struct ata_device *dev) | |||
1837 | if (rc) | 1882 | if (rc) |
1838 | return rc; | 1883 | return rc; |
1839 | 1884 | ||
1885 | /* massage HPA, do it early as it might change IDENTIFY data */ | ||
1886 | rc = ata_hpa_resize(dev); | ||
1887 | if (rc) | ||
1888 | return rc; | ||
1889 | |||
1840 | /* print device capabilities */ | 1890 | /* print device capabilities */ |
1841 | if (ata_msg_probe(ap)) | 1891 | if (ata_msg_probe(ap)) |
1842 | ata_dev_printk(dev, KERN_DEBUG, | 1892 | ata_dev_printk(dev, KERN_DEBUG, |
@@ -1904,10 +1954,6 @@ int ata_dev_configure(struct ata_device *dev) | |||
1904 | dev->flags |= ATA_DFLAG_FLUSH_EXT; | 1954 | dev->flags |= ATA_DFLAG_FLUSH_EXT; |
1905 | } | 1955 | } |
1906 | 1956 | ||
1907 | if (!(dev->horkage & ATA_HORKAGE_BROKEN_HPA) && | ||
1908 | ata_id_hpa_enabled(dev->id)) | ||
1909 | dev->n_sectors = ata_hpa_resize(dev); | ||
1910 | |||
1911 | /* config NCQ */ | 1957 | /* config NCQ */ |
1912 | ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); | 1958 | ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); |
1913 | 1959 | ||