diff options
author | Tejun Heo <tj@kernel.org> | 2010-05-15 20:09:34 +0200 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2010-06-02 13:50:10 -0400 |
commit | d8d9129ea28e2177749627c82962feb26e8d11e9 (patch) | |
tree | f930703c8e3ba66cadcaf712ee7ce9b36a6d0823 /drivers/ata/libata-scsi.c | |
parent | 68939ce5fc17ee9c03ef6e543d4f82bd9f5583d4 (diff) | |
download | linux-d8d9129ea28e2177749627c82962feb26e8d11e9.tar.gz linux-d8d9129ea28e2177749627c82962feb26e8d11e9.tar.bz2 linux-d8d9129ea28e2177749627c82962feb26e8d11e9.zip |
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/libata-scsi.c')
-rw-r--r-- | drivers/ata/libata-scsi.c | 29 |
1 files changed, 29 insertions, 0 deletions
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, } /** + * ata_scsi_unlock_native_capacity - unlock native capacity + * @sdev: SCSI device to adjust device capacity for + * + * This function is called if a partition on @sdev extends beyond + * the end of the device. It requests EH to unlock HPA. + * + * LOCKING: + * Defined by the SCSI layer. Might sleep. + */ +void ata_scsi_unlock_native_capacity(struct scsi_device *sdev) +{ + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct ata_device *dev; + unsigned long flags; + + spin_lock_irqsave(ap->lock, flags); + + dev = ata_scsi_find_dev(ap, sdev); + if (dev && dev->n_sectors < dev->n_native_sectors) { + dev->flags |= ATA_DFLAG_UNLOCK_HPA; + dev->link->eh_info.action |= ATA_EH_RESET; + ata_port_schedule_eh(ap); + } + + spin_unlock_irqrestore(ap->lock, flags); + ata_port_wait_eh(ap); +} + +/** * ata_get_identity - Handler for HDIO_GET_IDENTITY ioctl * @ap: target port * @sdev: SCSI device to get identify data for |