summaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-core.c
diff options
context:
space:
mode:
authorTejun Heo2007-09-03 05:32:57 +0200
committerJeff Garzik2007-10-12 20:55:39 +0200
commit05027adccc09401a7e31d5ef51040dc75ab03c22 (patch)
tree83fbb8e65d26e10e1fd74377bc13fd358a61c13e /drivers/ata/libata-core.c
parentlibata: clean up read/set native_max address functions (diff)
downloadkernel-qcow2-linux-05027adccc09401a7e31d5ef51040dc75ab03c22.tar.gz
kernel-qcow2-linux-05027adccc09401a7e31d5ef51040dc75ab03c22.tar.xz
kernel-qcow2-linux-05027adccc09401a7e31d5ef51040dc75ab03c22.zip
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>
Diffstat (limited to 'drivers/ata/libata-core.c')
-rw-r--r--drivers/ata/libata-core.c124
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)
* ata_set_max_sectors - Set max sectors
* @dev: target device
* @new_sectors: new max sectors value to set for the device
- * @res_sectors: result max sectors
*
* Set max sectors of @dev to @new_sectors.
*
@@ -924,8 +923,7 @@ static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors)
* previous non-volatile SET_MAX) by the drive. -EIO on other
* errors.
*/
-static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors,
- u64 *res_sectors)
+static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors)
{
unsigned int err_mask;
struct ata_taskfile tf;
@@ -964,11 +962,6 @@ static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors,
return -EIO;
}
- if (lba48)
- *res_sectors = ata_tf_to_lba48(&tf);
- else
- *res_sectors = ata_tf_to_lba(&tf);
-
return 0;
}
@@ -979,41 +972,93 @@ static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors,
* Read the size of an LBA28 or LBA48 disk with HPA features and resize
* it if required to the full size of the media. The caller must check
* the drive has the HPA feature set enabled.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
*/
-
-static u64 ata_hpa_resize(struct ata_device *dev)
+static int ata_hpa_resize(struct ata_device *dev)
{
- u64 sectors = dev->n_sectors;
- u64 hpa_sectors;
+ struct ata_eh_context *ehc = &dev->link->eh_context;
+ int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
+ u64 sectors = ata_id_n_sectors(dev->id);
+ u64 native_sectors;
int rc;
- rc = ata_read_native_max_address(dev, &hpa_sectors);
- if (rc)
+ /* do we need to do it? */
+ if (dev->class != ATA_DEV_ATA ||
+ !ata_id_has_lba(dev->id) || !ata_id_hpa_enabled(dev->id) ||
+ (dev->horkage & ATA_HORKAGE_BROKEN_HPA))
return 0;
- if (hpa_sectors > sectors) {
- ata_dev_printk(dev, KERN_INFO,
- "Host Protected Area detected:\n"
- "\tcurrent size: %lld sectors\n"
- "\tnative size: %lld sectors\n",
- (long long)sectors, (long long)hpa_sectors);
-
- if (ata_ignore_hpa) {
- rc = ata_set_max_sectors(dev, hpa_sectors, &hpa_sectors);
-
- if (rc == 0) {
- ata_dev_printk(dev, KERN_INFO, "native size "
- "increased to %lld sectors\n",
- (long long)hpa_sectors);
- return hpa_sectors;
- }
+ /* read native max address */
+ rc = ata_read_native_max_address(dev, &native_sectors);
+ if (rc) {
+ /* If HPA isn't going to be unlocked, skip HPA
+ * resizing from the next try.
+ */
+ if (!ata_ignore_hpa) {
+ ata_dev_printk(dev, KERN_WARNING, "HPA support seems "
+ "broken, will skip HPA handling\n");
+ dev->horkage |= ATA_HORKAGE_BROKEN_HPA;
+
+ /* we can continue if device aborted the command */
+ if (rc == -EACCES)
+ rc = 0;
}
- } else if (hpa_sectors < sectors)
- ata_dev_printk(dev, KERN_WARNING, "%s 1: hpa sectors (%lld) "
- "is smaller than sectors (%lld)\n", __FUNCTION__,
- (long long)hpa_sectors, (long long)sectors);
- return sectors;
+ return rc;
+ }
+
+ /* nothing to do? */
+ if (native_sectors <= sectors || !ata_ignore_hpa) {
+ if (!print_info || native_sectors == sectors)
+ return 0;
+
+ if (native_sectors > sectors)
+ ata_dev_printk(dev, KERN_INFO,
+ "HPA detected: current %llu, native %llu\n",
+ (unsigned long long)sectors,
+ (unsigned long long)native_sectors);
+ else if (native_sectors < sectors)
+ ata_dev_printk(dev, KERN_WARNING,
+ "native sectors (%llu) is smaller than "
+ "sectors (%llu)\n",
+ (unsigned long long)native_sectors,
+ (unsigned long long)sectors);
+ return 0;
+ }
+
+ /* let's unlock HPA */
+ rc = ata_set_max_sectors(dev, native_sectors);
+ if (rc == -EACCES) {
+ /* if device aborted the command, skip HPA resizing */
+ ata_dev_printk(dev, KERN_WARNING, "device aborted resize "
+ "(%llu -> %llu), skipping HPA handling\n",
+ (unsigned long long)sectors,
+ (unsigned long long)native_sectors);
+ dev->horkage |= ATA_HORKAGE_BROKEN_HPA;
+ return 0;
+ } else if (rc)
+ return rc;
+
+ /* re-read IDENTIFY data */
+ rc = ata_dev_reread_id(dev, 0);
+ if (rc) {
+ ata_dev_printk(dev, KERN_ERR, "failed to re-read IDENTIFY "
+ "data after HPA resizing\n");
+ return rc;
+ }
+
+ if (print_info) {
+ u64 new_sectors = ata_id_n_sectors(dev->id);
+ ata_dev_printk(dev, KERN_INFO,
+ "HPA unlocked: %llu -> %llu, native %llu\n",
+ (unsigned long long)sectors,
+ (unsigned long long)new_sectors,
+ (unsigned long long)native_sectors);
+ }
+
+ return 0;
}
/**
@@ -1837,6 +1882,11 @@ int ata_dev_configure(struct ata_device *dev)
if (rc)
return rc;
+ /* massage HPA, do it early as it might change IDENTIFY data */
+ rc = ata_hpa_resize(dev);
+ if (rc)
+ return rc;
+
/* print device capabilities */
if (ata_msg_probe(ap))
ata_dev_printk(dev, KERN_DEBUG,
@@ -1904,10 +1954,6 @@ int ata_dev_configure(struct ata_device *dev)
dev->flags |= ATA_DFLAG_FLUSH_EXT;
}
- if (!(dev->horkage & ATA_HORKAGE_BROKEN_HPA) &&
- ata_id_hpa_enabled(dev->id))
- dev->n_sectors = ata_hpa_resize(dev);
-
/* config NCQ */
ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));