This changes the behavior to name the block devices for lpars other than OtherOS. Instead of a single disk with an alphanumeric suffix (/dev/ps3da), disks are now numeric, while each accessible region gets its own alphanumeric suffix:
/dev/ps3d1a /dev/ps3d1b The old behavior for OtherOS is kept: - only one region will be exposed as block device - the block device name stays the same Signed-off-by: Andre Heider <a.hei...@gmail.com> --- drivers/block/ps3disk.c | 118 ++++++++++++++++++++++++++++++---------------- 1 files changed, 77 insertions(+), 41 deletions(-) diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 96e00ff..cba8b45 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -35,18 +35,19 @@ #define PS3DISK_MINORS 16 -#define PS3DISK_NAME "ps3d%c" +#define PS3DISK_NAME_OTHEROS "ps3d%c" +#define PS3DISK_NAME "ps3d%c%c" struct ps3disk_private { spinlock_t lock; /* Request queue spinlock */ struct request_queue *queue; - struct gendisk *gendisk; - unsigned int region_idx; /* first accessible region */ unsigned int blocking_factor; struct request *req; + unsigned int devidx; u64 raw_capacity; unsigned char model[ATA_ID_PROD_LEN+1]; + struct gendisk *gendisk[0]; /* Must be last */ }; @@ -126,7 +127,9 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, int write = rq_data_dir(req), res; const char *op = write ? "write" : "read"; u64 start_sector, sectors; - unsigned int region_id = dev->regions[priv->region_idx].id; + unsigned int region_idx = MINOR(disk_devt(req->rq_disk)) & + (PS3DISK_MINORS - 1); + unsigned int region_id = dev->regions[region_idx].id; #ifdef DEBUG unsigned int n = 0; @@ -410,6 +413,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev) struct request_queue *queue; struct gendisk *gendisk; unsigned int region_idx; + unsigned int otheros = ps3_get_ss_laid() == PS3_SS_LAID_OTHEROS; if (dev->blk_size < 512) { dev_err(&dev->sbd.core, @@ -430,7 +434,9 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev) __set_bit(devidx, &ps3disk_mask); mutex_unlock(&ps3disk_mask_mutex); - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = kzalloc(sizeof(*priv) + + dev->num_regions * sizeof(struct gendisk), + GFP_KERNEL); if (!priv) { error = -ENOMEM; goto fail; @@ -450,6 +456,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev) if (error) goto fail_free_bounce; + priv->devidx = devidx; ps3disk_identify(dev); queue = blk_init_queue(ps3disk_request, &priv->lock); @@ -475,45 +482,60 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev) blk_queue_max_segments(queue, -1); blk_queue_max_segment_size(queue, dev->bounce_size); - gendisk = alloc_disk(PS3DISK_MINORS); - if (!gendisk) { - dev_err(&dev->sbd.core, "%s:%u: alloc_disk failed\n", __func__, - __LINE__); - error = -ENOMEM; - goto fail_cleanup_queue; - } + dev_info(&dev->sbd.core, "%s (%llu MiB)\n", + priv->model, priv->raw_capacity >> 11); - priv->gendisk = gendisk; + for (region_idx = 0; region_idx < dev->num_regions; region_idx++) { + if (test_bit(region_idx, &dev->accessible_regions) == 0) + continue; - /* find first accessible region */ - for (region_idx = 0; region_idx < dev->num_regions; region_idx++) - if (test_bit(region_idx, &dev->accessible_regions)) { - priv->region_idx = region_idx; - break; + gendisk = alloc_disk(PS3DISK_MINORS * PS3_STORAGE_MAX_REGIONS); + if (!gendisk) { + dev_err(&dev->sbd.core, "%s:%u: alloc_disk failed\n", + __func__, __LINE__); + error = -ENOMEM; + goto fail_cleanup_queue; } - gendisk->major = ps3disk_major; - gendisk->first_minor = devidx * PS3DISK_MINORS; - gendisk->fops = &ps3disk_fops; - gendisk->queue = queue; - gendisk->private_data = dev; - gendisk->driverfs_dev = &dev->sbd.core; - snprintf(gendisk->disk_name, sizeof(gendisk->disk_name), PS3DISK_NAME, - devidx+'a'); - priv->blocking_factor = dev->blk_size >> 9; - set_capacity(gendisk, - dev->regions[priv->region_idx].size * - priv->blocking_factor); - - dev_info(&dev->sbd.core, - "%s is a %s (%llu MiB total, %lu MiB for OtherOS)\n", - gendisk->disk_name, priv->model, priv->raw_capacity >> 11, - get_capacity(gendisk) >> 11); - - add_disk(gendisk); + priv->gendisk[region_idx] = gendisk; + gendisk->major = ps3disk_major; + gendisk->first_minor = devidx * PS3DISK_MINORS + region_idx; + gendisk->fops = &ps3disk_fops; + gendisk->queue = queue; + gendisk->private_data = dev; + gendisk->driverfs_dev = &dev->sbd.core; + + if (otheros) { + /* keep the old block device name for OtherOS */ + snprintf(gendisk->disk_name, sizeof(gendisk->disk_name), + PS3DISK_NAME_OTHEROS, 'a' + devidx); + } else { + snprintf(gendisk->disk_name, sizeof(gendisk->disk_name), + PS3DISK_NAME, '1' + devidx, 'a' + region_idx); + } + + priv->blocking_factor = dev->blk_size >> 9; + set_capacity(gendisk, dev->regions[region_idx].size * + priv->blocking_factor); + + dev_info(&dev->sbd.core, + "%s (%lu MiB region)\n", + gendisk->disk_name, get_capacity(gendisk) >> 11); + + add_disk(gendisk); + + /* keep old behavior for OtherOS - only one region */ + if (otheros) + break; + } + return 0; fail_cleanup_queue: + for (region_idx = 0; region_idx < dev->num_regions; region_idx++) + if (priv->gendisk[region_idx]) + del_gendisk(priv->gendisk[region_idx]); + blk_cleanup_queue(queue); fail_teardown: ps3stor_teardown(dev); @@ -533,14 +555,28 @@ static int ps3disk_remove(struct ps3_system_bus_device *_dev) { struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); + unsigned int region_idx; mutex_lock(&ps3disk_mask_mutex); - __clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS, - &ps3disk_mask); + __clear_bit(priv->devidx, &ps3disk_mask); mutex_unlock(&ps3disk_mask_mutex); - del_gendisk(priv->gendisk); + + for (region_idx = 0; region_idx < dev->num_regions; region_idx++) { + if (test_bit(region_idx, &dev->accessible_regions) == 0) + continue; + + del_gendisk(priv->gendisk[region_idx]); + } + blk_cleanup_queue(priv->queue); - put_disk(priv->gendisk); + + for (region_idx = 0; region_idx < dev->num_regions; region_idx++) { + if (test_bit(region_idx, &dev->accessible_regions) == 0) + continue; + + put_disk(priv->gendisk[region_idx]); + } + dev_notice(&dev->sbd.core, "Synchronizing disk cache\n"); ps3disk_sync_cache(dev); ps3stor_teardown(dev); -- 1.7.5.4 _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev