aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2010-05-15 14:09:34 -0400
committerJeff Garzik <jgarzik@redhat.com>2010-06-02 13:50:10 -0400
commitd8d9129ea28e2177749627c82962feb26e8d11e9 (patch)
treef930703c8e3ba66cadcaf712ee7ce9b36a6d0823 /drivers/ata
parent68939ce5fc17ee9c03ef6e543d4f82bd9f5583d4 (diff)
libata: implement on-demand HPA unlocking
Implement ata_scsi_unlock_native_capacity() which will be called through SCSI layer when block layer notices that partitions on a device extend beyond the end of the device. It requests EH to unlock HPA, waits for completion and returns the current device capacity. This allows libata to unlock HPA on demand instead of having to decide whether to unlock upfront. Unlocking on demand is safer than unlocking by upfront because some BIOSes write private data to the area beyond HPA limit. This was suggested by Ben Hutchings. Signed-off-by: Tejun Heo <tj@kernel.org> Suggested-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/libata-core.c1
-rw-r--r--drivers/ata/libata-scsi.c29
2 files changed, 30 insertions, 0 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 1e5d0a36a0a4..ddf8e4862787 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -6668,6 +6668,7 @@ EXPORT_SYMBOL_GPL(ata_dummy_port_info);
6668EXPORT_SYMBOL_GPL(ata_link_next); 6668EXPORT_SYMBOL_GPL(ata_link_next);
6669EXPORT_SYMBOL_GPL(ata_dev_next); 6669EXPORT_SYMBOL_GPL(ata_dev_next);
6670EXPORT_SYMBOL_GPL(ata_std_bios_param); 6670EXPORT_SYMBOL_GPL(ata_std_bios_param);
6671EXPORT_SYMBOL_GPL(ata_scsi_unlock_native_capacity);
6671EXPORT_SYMBOL_GPL(ata_host_init); 6672EXPORT_SYMBOL_GPL(ata_host_init);
6672EXPORT_SYMBOL_GPL(ata_host_alloc); 6673EXPORT_SYMBOL_GPL(ata_host_alloc);
6673EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo); 6674EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo);
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index cfa9dd3d7253..a54273d2c3c6 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -415,6 +415,35 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
415} 415}
416 416
417/** 417/**
418 * ata_scsi_unlock_native_capacity - unlock native capacity
419 * @sdev: SCSI device to adjust device capacity for
420 *
421 * This function is called if a partition on @sdev extends beyond
422 * the end of the device. It requests EH to unlock HPA.
423 *
424 * LOCKING:
425 * Defined by the SCSI layer. Might sleep.
426 */
427void ata_scsi_unlock_native_capacity(struct scsi_device *sdev)
428{
429 struct ata_port *ap = ata_shost_to_port(sdev->host);
430 struct ata_device *dev;
431 unsigned long flags;
432
433 spin_lock_irqsave(ap->lock, flags);
434
435 dev = ata_scsi_find_dev(ap, sdev);
436 if (dev && dev->n_sectors < dev->n_native_sectors) {
437 dev->flags |= ATA_DFLAG_UNLOCK_HPA;
438 dev->link->eh_info.action |= ATA_EH_RESET;
439 ata_port_schedule_eh(ap);
440 }
441
442 spin_unlock_irqrestore(ap->lock, flags);
443 ata_port_wait_eh(ap);
444}
445
446/**
418 * ata_get_identity - Handler for HDIO_GET_IDENTITY ioctl 447 * ata_get_identity - Handler for HDIO_GET_IDENTITY ioctl
419 * @ap: target port 448 * @ap: target port
420 * @sdev: SCSI device to get identify data for 449 * @sdev: SCSI device to get identify data for