[PATCH 11/15] ps3disk: Provide a gendisk per accessible region
Andre Heider
a.heider at gmail.com
Tue Aug 2 06:03:02 EST 2011
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.heider at 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
More information about the Linuxppc-dev
mailing list