[PATCH] cciss: add support for 1024 logical volumes
Mike Miller [Thu, 7 Dec 2006 04:35:12 +0000 (20:35 -0800)]
Add the support for a large number of logical volumes.  We will soon have
hardware that support up to 1024 logical volumes.

Signed-off-by: Mike Miller <mike.miller@hp.com>
Cc: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

drivers/block/cciss.c
drivers/block/cciss.h
drivers/block/cciss_cmd.h
include/linux/cciss_ioctl.h

index 70cf932..c99cb7e 100644 (file)
@@ -1315,6 +1315,11 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
        /* if it's the controller it's already added */
        if (drv_index) {
                disk->queue = blk_init_queue(do_cciss_request, &h->lock);
+               sprintf(disk->disk_name, "cciss/c%dd%d", ctlr, drv_index);
+               disk->major = h->major;
+               disk->first_minor = drv_index << NWD_SHIFT;
+               disk->fops = &cciss_fops;
+               disk->private_data = &h->drv[drv_index];
 
                /* Set up queue information */
                disk->queue->backing_dev_info.ra_pages = READ_AHEAD;
@@ -1393,11 +1398,6 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
 
        /* Set busy_configuring flag for this operation */
        spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
-       if (h->num_luns >= CISS_MAX_LUN) {
-               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
-               return -EINVAL;
-       }
-
        if (h->busy_configuring) {
                spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
                return -EBUSY;
@@ -1430,17 +1430,8 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
                                              0, 0, TYPE_CMD);
 
                if (return_code == IO_OK) {
-                       listlength |=
-                           (0xff & (unsigned int)(ld_buff->LUNListLength[0]))
-                           << 24;
-                       listlength |=
-                           (0xff & (unsigned int)(ld_buff->LUNListLength[1]))
-                           << 16;
-                       listlength |=
-                           (0xff & (unsigned int)(ld_buff->LUNListLength[2]))
-                           << 8;
-                       listlength |=
-                           0xff & (unsigned int)(ld_buff->LUNListLength[3]);
+                       listlength =
+                               be32_to_cpu(*(__u32 *) ld_buff->LUNListLength);
                } else {        /* reading number of logical volumes failed */
                        printk(KERN_WARNING "cciss: report logical volume"
                               " command failed\n");
@@ -1491,6 +1482,14 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
                                if (drv_index == -1)
                                        goto freeret;
 
+                               /*Check if the gendisk needs to be allocated */
+                               if (!h->gendisk[drv_index]){
+                                       h->gendisk[drv_index] = alloc_disk(1 << NWD_SHIFT);
+                                       if (!h->gendisk[drv_index]){
+                                               printk(KERN_ERR "cciss: could not allocate new disk %d\n", drv_index);
+                                               goto mem_msg;
+                                       }
+                               }
                        }
                        h->drv[drv_index].LunID = lunid;
                        cciss_update_drive_info(ctlr, drv_index);
@@ -1528,6 +1527,7 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
 static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
                           int clear_all)
 {
+       int i;
        ctlr_info_t *h = get_host(disk);
 
        if (!capable(CAP_SYS_RAWIO))
@@ -1551,9 +1551,35 @@ static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
                                del_gendisk(disk);
                        if (q) {
                                blk_cleanup_queue(q);
+                               /* Set drv->queue to NULL so that we do not try
+                                * to call blk_start_queue on this queue in the
+                                * interrupt handler
+                                */
                                drv->queue = NULL;
                        }
+                       /* If clear_all is set then we are deleting the logical
+                        * drive, not just refreshing its info.  For drives
+                        * other than disk 0 we will call put_disk.  We do not
+                        * do this for disk 0 as we need it to be able to
+                        * configure the controller.
+                       */
+                       if (clear_all){
+                               /* This isn't pretty, but we need to find the
+                                * disk in our array and NULL our the pointer.
+                                * This is so that we will call alloc_disk if
+                                * this index is used again later.
+                               */
+                               for (i=0; i < CISS_MAX_LUN; i++){
+                                       if(h->gendisk[i] == disk){
+                                               h->gendisk[i] = NULL;
+                                               break;
+                                       }
+                               }
+                               put_disk(disk);
+                       }
                }
+       } else {
+               set_capacity(disk, 0);
        }
 
        --h->num_luns;
@@ -3119,13 +3145,7 @@ geo_inq:
 /* Returns -1 if no free entries are left.  */
 static int alloc_cciss_hba(void)
 {
-       struct gendisk *disk[NWD];
-       int i, n;
-       for (n = 0; n < NWD; n++) {
-               disk[n] = alloc_disk(1 << NWD_SHIFT);
-               if (!disk[n])
-                       goto out;
-       }
+       int i;
 
        for (i = 0; i < MAX_CTLR; i++) {
                if (!hba[i]) {
@@ -3133,20 +3153,18 @@ static int alloc_cciss_hba(void)
                        p = kzalloc(sizeof(ctlr_info_t), GFP_KERNEL);
                        if (!p)
                                goto Enomem;
-                       for (n = 0; n < NWD; n++)
-                               p->gendisk[n] = disk[n];
+                       p->gendisk[0] = alloc_disk(1 << NWD_SHIFT);
+                       if (!p->gendisk[0])
+                               goto Enomem;
                        hba[i] = p;
                        return i;
                }
        }
        printk(KERN_WARNING "cciss: This driver supports a maximum"
               " of %d controllers.\n", MAX_CTLR);
-       goto out;
-      Enomem:
+       return -1;
+Enomem:
        printk(KERN_ERR "cciss: out of memory.\n");
-      out:
-       while (n--)
-               put_disk(disk[n]);
        return -1;
 }
 
@@ -3156,7 +3174,7 @@ static void free_hba(int i)
        int n;
 
        hba[i] = NULL;
-       for (n = 0; n < NWD; n++)
+       for (n = 0; n < CISS_MAX_LUN; n++)
                put_disk(p->gendisk[n]);
        kfree(p);
 }
@@ -3169,9 +3187,8 @@ static void free_hba(int i)
 static int __devinit cciss_init_one(struct pci_dev *pdev,
                                    const struct pci_device_id *ent)
 {
-       request_queue_t *q;
        int i;
-       int j;
+       int j = 0;
        int rc;
        int dac;
 
@@ -3283,16 +3300,29 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 
        hba[i]->busy_initializing = 0;
 
-       for (j = 0; j < NWD; j++) {     /* mfm */
+       do {
                drive_info_struct *drv = &(hba[i]->drv[j]);
                struct gendisk *disk = hba[i]->gendisk[j];
+               request_queue_t *q;
+
+               /* Check if the disk was allocated already */
+               if (!disk){
+                       hba[i]->gendisk[j] = alloc_disk(1 << NWD_SHIFT);
+                       disk = hba[i]->gendisk[j];
+               }
+
+               /* Check that the disk was able to be allocated */
+               if (!disk) {
+                       printk(KERN_ERR "cciss: unable to allocate memory for disk %d\n", j);
+                       goto clean4;
+               }
 
                q = blk_init_queue(do_cciss_request, &hba[i]->lock);
                if (!q) {
                        printk(KERN_ERR
                               "cciss:  unable to allocate queue for disk %d\n",
                               j);
-                       break;
+                       goto clean4;
                }
                drv->queue = q;
 
@@ -3324,7 +3354,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
                blk_queue_hardsect_size(q, drv->block_size);
                set_capacity(disk, drv->nr_blocks);
                add_disk(disk);
-       }
+               j++;
+       } while (j <= hba[i]->highest_lun);
 
        return 1;
 
@@ -3347,6 +3378,15 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        unregister_blkdev(hba[i]->major, hba[i]->devname);
       clean1:
        hba[i]->busy_initializing = 0;
+       /* cleanup any queues that may have been initialized */
+       for (j=0; j <= hba[i]->highest_lun; j++){
+               drive_info_struct *drv = &(hba[i]->drv[j]);
+               if (drv->queue)
+                       blk_cleanup_queue(drv->queue);
+       }
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
        free_hba(i);
        return -1;
 }
@@ -3394,7 +3434,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
        remove_proc_entry(hba[i]->devname, proc_cciss);
 
        /* remove it from the disk list */
-       for (j = 0; j < NWD; j++) {
+       for (j = 0; j < CISS_MAX_LUN; j++) {
                struct gendisk *disk = hba[i]->gendisk[j];
                if (disk) {
                        request_queue_t *q = disk->queue;
index c3df673..b70988d 100644 (file)
@@ -6,7 +6,6 @@
 #include "cciss_cmd.h"
 
 
-#define NWD            16
 #define NWD_SHIFT      4
 #define MAX_PART       (1 << NWD_SHIFT)
 
@@ -112,7 +111,7 @@ struct ctlr_info
        int                     next_to_run;
 
        // Disk structures we need to pass back
-       struct gendisk   *gendisk[NWD];
+       struct gendisk   *gendisk[CISS_MAX_LUN];
 #ifdef CONFIG_CISS_SCSI_TAPE
        void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
        /* list of block side commands the scsi error handling sucked up */
index b2147cc..43bf559 100644 (file)
@@ -89,7 +89,7 @@ typedef union _u64bit
 //###########################################################################
 //STRUCTURES
 //###########################################################################
-#define CISS_MAX_LUN   16      
+#define CISS_MAX_LUN   1024
 #define CISS_MAX_PHYS_LUN      1024
 // SCSI-3 Cmmands 
 
index 6e27f42..cb57c30 100644 (file)
@@ -80,7 +80,7 @@ typedef __u32 DriverVer_type;
 #define HWORD __u16
 #define DWORD __u32
 
-#define CISS_MAX_LUN   16      
+#define CISS_MAX_LUN   1024
 
 #define LEVEL2LUN   1   // index into Target(x) structure, due to byte swapping
 #define LEVEL3LUN   0