mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 20:51:44 +00:00
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>
This commit is contained in:
parent
db429e9ec0
commit
e957b60d15
@ -302,14 +302,12 @@ 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);
|
||||
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,13 +350,10 @@ 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,
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user