diff options
author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2009-06-07 07:52:52 -0400 |
---|---|---|
committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2009-06-07 07:52:52 -0400 |
commit | e957b60d1583022a0f7c03267d37fcae2ddb78b1 (patch) | |
tree | 5e9518eb38d427b9ac41c9b90b31b9b2453aebfc | |
parent | db429e9ec0f9dee2d8e50c154f04f29f880fc9d6 (diff) |
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: Alan Cox <alan@linux.intel.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
-rw-r--r-- | drivers/ide/ide-disk.c | 67 | ||||
-rw-r--r-- | drivers/ide/ide-gd.c | 14 | ||||
-rw-r--r-- | include/linux/ide.h | 4 |
3 files changed, 72 insertions, 13 deletions
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index a9fbe2c31210..61a6d3546221 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c | |||
@@ -302,14 +302,12 @@ static const struct drive_list_entry hpa_list[] = { | |||
302 | { NULL, NULL } | 302 | { NULL, NULL } |
303 | }; | 303 | }; |
304 | 304 | ||
305 | static void idedisk_check_hpa(ide_drive_t *drive) | 305 | static u64 ide_disk_hpa_get_native_capacity(ide_drive_t *drive, int lba48) |
306 | { | 306 | { |
307 | unsigned long long capacity, set_max; | 307 | u64 capacity, set_max; |
308 | int lba48 = ata_id_lba48_enabled(drive->id); | ||
309 | 308 | ||
310 | capacity = drive->capacity64; | 309 | capacity = drive->capacity64; |
311 | 310 | set_max = idedisk_read_native_max_address(drive, lba48); | |
312 | set_max = idedisk_read_native_max_address(drive, lba48); | ||
313 | 311 | ||
314 | if (ide_in_drive_list(drive->id, hpa_list)) { | 312 | if (ide_in_drive_list(drive->id, hpa_list)) { |
315 | /* | 313 | /* |
@@ -320,9 +318,31 @@ static void idedisk_check_hpa(ide_drive_t *drive) | |||
320 | set_max--; | 318 | set_max--; |
321 | } | 319 | } |
322 | 320 | ||
321 | return set_max; | ||
322 | } | ||
323 | |||
324 | static u64 ide_disk_hpa_set_capacity(ide_drive_t *drive, u64 set_max, int lba48) | ||
325 | { | ||
326 | set_max = idedisk_set_max_address(drive, set_max, lba48); | ||
327 | if (set_max) | ||
328 | drive->capacity64 = set_max; | ||
329 | |||
330 | return set_max; | ||
331 | } | ||
332 | |||
333 | static void idedisk_check_hpa(ide_drive_t *drive) | ||
334 | { | ||
335 | u64 capacity, set_max; | ||
336 | int lba48 = ata_id_lba48_enabled(drive->id); | ||
337 | |||
338 | capacity = drive->capacity64; | ||
339 | set_max = ide_disk_hpa_get_native_capacity(drive, lba48); | ||
340 | |||
323 | if (set_max <= capacity) | 341 | if (set_max <= capacity) |
324 | return; | 342 | return; |
325 | 343 | ||
344 | drive->probed_capacity = set_max; | ||
345 | |||
326 | printk(KERN_INFO "%s: Host Protected Area detected.\n" | 346 | printk(KERN_INFO "%s: Host Protected Area detected.\n" |
327 | "\tcurrent capacity is %llu sectors (%llu MB)\n" | 347 | "\tcurrent capacity is %llu sectors (%llu MB)\n" |
328 | "\tnative capacity is %llu sectors (%llu MB)\n", | 348 | "\tnative capacity is %llu sectors (%llu MB)\n", |
@@ -330,13 +350,10 @@ static void idedisk_check_hpa(ide_drive_t *drive) | |||
330 | capacity, sectors_to_MB(capacity), | 350 | capacity, sectors_to_MB(capacity), |
331 | set_max, sectors_to_MB(set_max)); | 351 | set_max, sectors_to_MB(set_max)); |
332 | 352 | ||
333 | set_max = idedisk_set_max_address(drive, set_max, lba48); | 353 | set_max = ide_disk_hpa_set_capacity(drive, set_max, lba48); |
334 | 354 | if (set_max) | |
335 | if (set_max) { | ||
336 | drive->capacity64 = set_max; | ||
337 | printk(KERN_INFO "%s: Host Protected Area disabled.\n", | 355 | printk(KERN_INFO "%s: Host Protected Area disabled.\n", |
338 | drive->name); | 356 | drive->name); |
339 | } | ||
340 | } | 357 | } |
341 | 358 | ||
342 | static int ide_disk_get_capacity(ide_drive_t *drive) | 359 | static int ide_disk_get_capacity(ide_drive_t *drive) |
@@ -358,6 +375,8 @@ static int ide_disk_get_capacity(ide_drive_t *drive) | |||
358 | drive->capacity64 = drive->cyl * drive->head * drive->sect; | 375 | drive->capacity64 = drive->cyl * drive->head * drive->sect; |
359 | } | 376 | } |
360 | 377 | ||
378 | drive->probed_capacity = drive->capacity64; | ||
379 | |||
361 | if (lba) { | 380 | if (lba) { |
362 | drive->dev_flags |= IDE_DFLAG_LBA; | 381 | drive->dev_flags |= IDE_DFLAG_LBA; |
363 | 382 | ||
@@ -376,7 +395,7 @@ static int ide_disk_get_capacity(ide_drive_t *drive) | |||
376 | "%llu sectors (%llu MB)\n", | 395 | "%llu sectors (%llu MB)\n", |
377 | drive->name, (unsigned long long)drive->capacity64, | 396 | drive->name, (unsigned long long)drive->capacity64, |
378 | sectors_to_MB(drive->capacity64)); | 397 | sectors_to_MB(drive->capacity64)); |
379 | drive->capacity64 = 1ULL << 28; | 398 | drive->probed_capacity = drive->capacity64 = 1ULL << 28; |
380 | } | 399 | } |
381 | 400 | ||
382 | if ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && | 401 | if ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && |
@@ -392,6 +411,31 @@ static int ide_disk_get_capacity(ide_drive_t *drive) | |||
392 | return 0; | 411 | return 0; |
393 | } | 412 | } |
394 | 413 | ||
414 | static u64 ide_disk_set_capacity(ide_drive_t *drive, u64 capacity) | ||
415 | { | ||
416 | u64 set = min(capacity, drive->probed_capacity); | ||
417 | u16 *id = drive->id; | ||
418 | int lba48 = ata_id_lba48_enabled(id); | ||
419 | |||
420 | if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 || | ||
421 | ata_id_hpa_enabled(id) == 0) | ||
422 | goto out; | ||
423 | |||
424 | /* | ||
425 | * according to the spec the SET MAX ADDRESS command shall be | ||
426 | * immediately preceded by a READ NATIVE MAX ADDRESS command | ||
427 | */ | ||
428 | capacity = ide_disk_hpa_get_native_capacity(drive, lba48); | ||
429 | if (capacity == 0) | ||
430 | goto out; | ||
431 | |||
432 | set = ide_disk_hpa_set_capacity(drive, set, lba48); | ||
433 | if (set) | ||
434 | return set; | ||
435 | out: | ||
436 | return drive->capacity64; | ||
437 | } | ||
438 | |||
395 | static void idedisk_prepare_flush(struct request_queue *q, struct request *rq) | 439 | static void idedisk_prepare_flush(struct request_queue *q, struct request *rq) |
396 | { | 440 | { |
397 | ide_drive_t *drive = q->queuedata; | 441 | ide_drive_t *drive = q->queuedata; |
@@ -741,6 +785,7 @@ static int ide_disk_set_doorlock(ide_drive_t *drive, struct gendisk *disk, | |||
741 | 785 | ||
742 | const struct ide_disk_ops ide_ata_disk_ops = { | 786 | const struct ide_disk_ops ide_ata_disk_ops = { |
743 | .check = ide_disk_check, | 787 | .check = ide_disk_check, |
788 | .set_capacity = ide_disk_set_capacity, | ||
744 | .get_capacity = ide_disk_get_capacity, | 789 | .get_capacity = ide_disk_get_capacity, |
745 | .setup = ide_disk_setup, | 790 | .setup = ide_disk_setup, |
746 | .flush = ide_disk_flush, | 791 | .flush = ide_disk_flush, |
diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c index 4b6b71e2cdf5..214119026b3f 100644 --- a/drivers/ide/ide-gd.c +++ b/drivers/ide/ide-gd.c | |||
@@ -287,6 +287,19 @@ static int ide_gd_media_changed(struct gendisk *disk) | |||
287 | return ret; | 287 | return ret; |
288 | } | 288 | } |
289 | 289 | ||
290 | static unsigned long long ide_gd_set_capacity(struct gendisk *disk, | ||
291 | unsigned long long capacity) | ||
292 | { | ||
293 | struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); | ||
294 | ide_drive_t *drive = idkp->drive; | ||
295 | const struct ide_disk_ops *disk_ops = drive->disk_ops; | ||
296 | |||
297 | if (disk_ops->set_capacity) | ||
298 | return disk_ops->set_capacity(drive, capacity); | ||
299 | |||
300 | return drive->capacity64; | ||
301 | } | ||
302 | |||
290 | static int ide_gd_revalidate_disk(struct gendisk *disk) | 303 | static int ide_gd_revalidate_disk(struct gendisk *disk) |
291 | { | 304 | { |
292 | struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); | 305 | struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); |
@@ -315,6 +328,7 @@ static struct block_device_operations ide_gd_ops = { | |||
315 | .locked_ioctl = ide_gd_ioctl, | 328 | .locked_ioctl = ide_gd_ioctl, |
316 | .getgeo = ide_gd_getgeo, | 329 | .getgeo = ide_gd_getgeo, |
317 | .media_changed = ide_gd_media_changed, | 330 | .media_changed = ide_gd_media_changed, |
331 | .set_capacity = ide_gd_set_capacity, | ||
318 | .revalidate_disk = ide_gd_revalidate_disk | 332 | .revalidate_disk = ide_gd_revalidate_disk |
319 | }; | 333 | }; |
320 | 334 | ||
diff --git a/include/linux/ide.h b/include/linux/ide.h index 9fed365a598b..e96ace12872a 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h | |||
@@ -397,6 +397,7 @@ struct ide_drive_s; | |||
397 | struct ide_disk_ops { | 397 | struct ide_disk_ops { |
398 | int (*check)(struct ide_drive_s *, const char *); | 398 | int (*check)(struct ide_drive_s *, const char *); |
399 | int (*get_capacity)(struct ide_drive_s *); | 399 | int (*get_capacity)(struct ide_drive_s *); |
400 | u64 (*set_capacity)(struct ide_drive_s *, u64); | ||
400 | void (*setup)(struct ide_drive_s *); | 401 | void (*setup)(struct ide_drive_s *); |
401 | void (*flush)(struct ide_drive_s *); | 402 | void (*flush)(struct ide_drive_s *); |
402 | int (*init_media)(struct ide_drive_s *, struct gendisk *); | 403 | int (*init_media)(struct ide_drive_s *, struct gendisk *); |
@@ -568,8 +569,7 @@ struct ide_drive_s { | |||
568 | unsigned int drive_data; /* used by set_pio_mode/dev_select() */ | 569 | unsigned int drive_data; /* used by set_pio_mode/dev_select() */ |
569 | unsigned int failures; /* current failure count */ | 570 | unsigned int failures; /* current failure count */ |
570 | unsigned int max_failures; /* maximum allowed failure count */ | 571 | unsigned int max_failures; /* maximum allowed failure count */ |
571 | u64 probed_capacity;/* initial reported media capacity (ide-cd only currently) */ | 572 | u64 probed_capacity;/* initial/native media capacity */ |
572 | |||
573 | u64 capacity64; /* total number of sectors */ | 573 | u64 capacity64; /* total number of sectors */ |
574 | 574 | ||
575 | int lun; /* logical unit */ | 575 | int lun; /* logical unit */ |