Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e957b60d authored by Bartlomiej Zolnierkiewicz's avatar Bartlomiej Zolnierkiewicz
Browse files

ide-gd: implement block device ->set_capacity method (v2)



* Use ->probed_capacity to store native device capacity for ATA disks.

* Add ->set_capacity method to struct ide_disk_ops.

* Implement disk device ->set_capacity method for ATA disks.

* Implement block device ->set_capacity method.

v2:
* Check if LBA and HPA are supported in ide_disk_set_capacity().

* According to the spec the SET MAX ADDRESS command shall be
  immediately preceded by a READ NATIVE MAX ADDRESS command.

* Add ide_disk_hpa_{get_native,set}_capacity() helpers.

Together with the previous patch adding ->set_capacity block device
method this allows automatic disabling of Host Protected Area (HPA)
if any partitions overlapping HPA are detected.

Cc: Robert Hancock <hancockrwd@gmail.com>
Cc: Frans Pop <elendil@planet.nl>
Cc: "Andries E. Brouwer" <Andries.Brouwer@cwi.nl>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Emphatically-Acked-by: default avatarAlan Cox <alan@linux.intel.com>
Signed-off-by: default avatarBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
parent db429e9e
Loading
Loading
Loading
Loading
+56 −11
Original line number Diff line number Diff line
@@ -302,13 +302,11 @@ static const struct drive_list_entry hpa_list[] = {
	{ NULL,		NULL }
};

static void idedisk_check_hpa(ide_drive_t *drive)
static u64 ide_disk_hpa_get_native_capacity(ide_drive_t *drive, int lba48)
{
	unsigned long long capacity, set_max;
	int lba48 = ata_id_lba48_enabled(drive->id);
	u64 capacity, set_max;

	capacity = drive->capacity64;

	set_max  = idedisk_read_native_max_address(drive, lba48);

	if (ide_in_drive_list(drive->id, hpa_list)) {
@@ -320,9 +318,31 @@ static void idedisk_check_hpa(ide_drive_t *drive)
			set_max--;
	}

	return set_max;
}

static u64 ide_disk_hpa_set_capacity(ide_drive_t *drive, u64 set_max, int lba48)
{
	set_max = idedisk_set_max_address(drive, set_max, lba48);
	if (set_max)
		drive->capacity64 = set_max;

	return set_max;
}

static void idedisk_check_hpa(ide_drive_t *drive)
{
	u64 capacity, set_max;
	int lba48 = ata_id_lba48_enabled(drive->id);

	capacity = drive->capacity64;
	set_max  = ide_disk_hpa_get_native_capacity(drive, lba48);

	if (set_max <= capacity)
		return;

	drive->probed_capacity = set_max;

	printk(KERN_INFO "%s: Host Protected Area detected.\n"
			 "\tcurrent capacity is %llu sectors (%llu MB)\n"
			 "\tnative  capacity is %llu sectors (%llu MB)\n",
@@ -330,14 +350,11 @@ static void idedisk_check_hpa(ide_drive_t *drive)
			 capacity, sectors_to_MB(capacity),
			 set_max, sectors_to_MB(set_max));

	set_max = idedisk_set_max_address(drive, set_max, lba48);

	if (set_max) {
		drive->capacity64 = set_max;
	set_max = ide_disk_hpa_set_capacity(drive, set_max, lba48);
	if (set_max)
		printk(KERN_INFO "%s: Host Protected Area disabled.\n",
				 drive->name);
}
}

static int ide_disk_get_capacity(ide_drive_t *drive)
{
@@ -358,6 +375,8 @@ static int ide_disk_get_capacity(ide_drive_t *drive)
		drive->capacity64 = drive->cyl * drive->head * drive->sect;
	}

	drive->probed_capacity = drive->capacity64;

	if (lba) {
		drive->dev_flags |= IDE_DFLAG_LBA;

@@ -376,7 +395,7 @@ static int ide_disk_get_capacity(ide_drive_t *drive)
		       "%llu sectors (%llu MB)\n",
		       drive->name, (unsigned long long)drive->capacity64,
		       sectors_to_MB(drive->capacity64));
		drive->capacity64 = 1ULL << 28;
		drive->probed_capacity = drive->capacity64 = 1ULL << 28;
	}

	if ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) &&
@@ -392,6 +411,31 @@ static int ide_disk_get_capacity(ide_drive_t *drive)
	return 0;
}

static u64 ide_disk_set_capacity(ide_drive_t *drive, u64 capacity)
{
	u64 set = min(capacity, drive->probed_capacity);
	u16 *id = drive->id;
	int lba48 = ata_id_lba48_enabled(id);

	if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 ||
	    ata_id_hpa_enabled(id) == 0)
		goto out;

	/*
	 * according to the spec the SET MAX ADDRESS command shall be
	 * immediately preceded by a READ NATIVE MAX ADDRESS command
	 */
	capacity = ide_disk_hpa_get_native_capacity(drive, lba48);
	if (capacity == 0)
		goto out;

	set = ide_disk_hpa_set_capacity(drive, set, lba48);
	if (set)
		return set;
out:
	return drive->capacity64;
}

static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
{
	ide_drive_t *drive = q->queuedata;
@@ -741,6 +785,7 @@ static int ide_disk_set_doorlock(ide_drive_t *drive, struct gendisk *disk,

const struct ide_disk_ops ide_ata_disk_ops = {
	.check		= ide_disk_check,
	.set_capacity	= ide_disk_set_capacity,
	.get_capacity	= ide_disk_get_capacity,
	.setup		= ide_disk_setup,
	.flush		= ide_disk_flush,
+14 −0
Original line number Diff line number Diff line
@@ -287,6 +287,19 @@ static int ide_gd_media_changed(struct gendisk *disk)
	return ret;
}

static unsigned long long ide_gd_set_capacity(struct gendisk *disk,
					      unsigned long long capacity)
{
	struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
	ide_drive_t *drive = idkp->drive;
	const struct ide_disk_ops *disk_ops = drive->disk_ops;

	if (disk_ops->set_capacity)
		return disk_ops->set_capacity(drive, capacity);

	return drive->capacity64;
}

static int ide_gd_revalidate_disk(struct gendisk *disk)
{
	struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
@@ -315,6 +328,7 @@ static struct block_device_operations ide_gd_ops = {
	.locked_ioctl		= ide_gd_ioctl,
	.getgeo			= ide_gd_getgeo,
	.media_changed		= ide_gd_media_changed,
	.set_capacity		= ide_gd_set_capacity,
	.revalidate_disk	= ide_gd_revalidate_disk
};

+2 −2
Original line number Diff line number Diff line
@@ -397,6 +397,7 @@ struct ide_drive_s;
struct ide_disk_ops {
	int		(*check)(struct ide_drive_s *, const char *);
	int		(*get_capacity)(struct ide_drive_s *);
	u64		(*set_capacity)(struct ide_drive_s *, u64);
	void		(*setup)(struct ide_drive_s *);
	void		(*flush)(struct ide_drive_s *);
	int		(*init_media)(struct ide_drive_s *, struct gendisk *);
@@ -568,8 +569,7 @@ struct ide_drive_s {
	unsigned int	drive_data;	/* used by set_pio_mode/dev_select() */
	unsigned int	failures;	/* current failure count */
	unsigned int	max_failures;	/* maximum allowed failure count */
	u64		probed_capacity;/* initial reported media capacity (ide-cd only currently) */

	u64		probed_capacity;/* initial/native media capacity */
	u64		capacity64;	/* total number of sectors */

	int		lun;		/* logical unit */