Commit d8d9129ea28e2177749627c82962feb26e8d11e9

Authored by Tejun Heo
Committed by Jeff Garzik
1 parent 68939ce5fc

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>

Showing 3 changed files with 32 additions and 0 deletions Side-by-side Diff

drivers/ata/libata-core.c
... ... @@ -6668,6 +6668,7 @@
6668 6668 EXPORT_SYMBOL_GPL(ata_link_next);
6669 6669 EXPORT_SYMBOL_GPL(ata_dev_next);
6670 6670 EXPORT_SYMBOL_GPL(ata_std_bios_param);
  6671 +EXPORT_SYMBOL_GPL(ata_scsi_unlock_native_capacity);
6671 6672 EXPORT_SYMBOL_GPL(ata_host_init);
6672 6673 EXPORT_SYMBOL_GPL(ata_host_alloc);
6673 6674 EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo);
drivers/ata/libata-scsi.c
... ... @@ -415,6 +415,35 @@
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 + */
  427 +void 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 447 * ata_get_identity - Handler for HDIO_GET_IDENTITY ioctl
419 448 * @ap: target port
420 449 * @sdev: SCSI device to get identify data for
include/linux/libata.h
... ... @@ -1023,6 +1023,7 @@
1023 1023 extern int ata_std_bios_param(struct scsi_device *sdev,
1024 1024 struct block_device *bdev,
1025 1025 sector_t capacity, int geom[]);
  1026 +extern void ata_scsi_unlock_native_capacity(struct scsi_device *sdev);
1026 1027 extern int ata_scsi_slave_config(struct scsi_device *sdev);
1027 1028 extern void ata_scsi_slave_destroy(struct scsi_device *sdev);
1028 1029 extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
... ... @@ -1174,6 +1175,7 @@
1174 1175 .slave_configure = ata_scsi_slave_config, \
1175 1176 .slave_destroy = ata_scsi_slave_destroy, \
1176 1177 .bios_param = ata_std_bios_param, \
  1178 + .unlock_native_capacity = ata_scsi_unlock_native_capacity, \
1177 1179 .sdev_attrs = ata_common_sdev_attrs
1178 1180  
1179 1181 #define ATA_NCQ_SHT(drv_name) \