cciss: factor out scatter gather chain block allocation and freeing
authorStephen M. Cameron <scameron@beardog.cce.hp.com>
Fri, 26 Feb 2010 22:01:22 +0000 (16:01 -0600)
committerJens Axboe <jens.axboe@oracle.com>
Sun, 28 Feb 2010 18:42:31 +0000 (19:42 +0100)
cciss: factor out scatter gather chain block allocation and freeing
Rationale is that I want to use this code from the scsi half of the
driver.

Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
drivers/block/cciss.c

index cd8c7c2..eddb916 100644 (file)
@@ -257,6 +257,59 @@ static inline void removeQ(CommandList_struct *c)
        hlist_del_init(&c->list);
 }
 
+static void cciss_free_sg_chain_blocks(struct Cmd_sg_list **cmd_sg_list,
+       int nr_cmds)
+{
+       int i;
+
+       if (!cmd_sg_list)
+               return;
+       for (i = 0; i < nr_cmds; i++) {
+               if (cmd_sg_list[i]) {
+                       kfree(cmd_sg_list[i]->sgchain);
+                       kfree(cmd_sg_list[i]);
+                       cmd_sg_list[i] = NULL;
+               }
+       }
+       kfree(cmd_sg_list);
+}
+
+static struct Cmd_sg_list **cciss_allocate_sg_chain_blocks(ctlr_info_t *h,
+       int chainsize, int nr_cmds)
+{
+       int j;
+       struct Cmd_sg_list **cmd_sg_list;
+
+       if (chainsize <= 0)
+               return NULL;
+
+       cmd_sg_list = kmalloc(sizeof(*cmd_sg_list) * nr_cmds, GFP_KERNEL);
+       if (!cmd_sg_list)
+               return NULL;
+
+       /* Build up chain blocks for each command */
+       for (j = 0; j < nr_cmds; j++) {
+               cmd_sg_list[j] = kmalloc(sizeof(*cmd_sg_list[j]), GFP_KERNEL);
+               if (!cmd_sg_list[j]) {
+                       dev_err(&h->pdev->dev, "Cannot get memory "
+                               "for chain block.\n");
+                       goto clean;
+               }
+               /* Need a block of chainsized s/g elements. */
+               cmd_sg_list[j]->sgchain = kmalloc((chainsize *
+                       sizeof(SGDescriptor_struct)), GFP_KERNEL);
+               if (!cmd_sg_list[j]->sgchain) {
+                       dev_err(&h->pdev->dev, "Cannot get memory "
+                               "for s/g chains.\n");
+                       goto clean;
+               }
+       }
+       return cmd_sg_list;
+clean:
+       cciss_free_sg_chain_blocks(cmd_sg_list, nr_cmds);
+       return NULL;
+}
+
 #include "cciss_scsi.c"                /* For SCSI tape support */
 
 static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
@@ -4238,37 +4291,10 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
                        goto clean4;
                }
        }
-       hba[i]->cmd_sg_list = kmalloc(sizeof(struct Cmd_sg_list *) *
-                                               hba[i]->nr_cmds,
-                                               GFP_KERNEL);
-       if (!hba[i]->cmd_sg_list) {
-               printk(KERN_ERR "cciss%d: Cannot get memory for "
-                       "s/g chaining.\n", i);
+       hba[i]->cmd_sg_list = cciss_allocate_sg_chain_blocks(hba[i],
+               hba[i]->chainsize, hba[i]->nr_cmds);
+       if (!hba[i]->cmd_sg_list && hba[i]->chainsize > 0)
                goto clean4;
-       }
-       /* Build up chain blocks for each command */
-       if (hba[i]->chainsize > 0) {
-               for (j = 0; j < hba[i]->nr_cmds; j++) {
-                       hba[i]->cmd_sg_list[j] =
-                                       kmalloc(sizeof(struct Cmd_sg_list),
-                                                       GFP_KERNEL);
-                       if (!hba[i]->cmd_sg_list[j]) {
-                               printk(KERN_ERR "cciss%d: Cannot get memory "
-                                       "for chain block.\n", i);
-                               goto clean4;
-                       }
-                       /* Need a block of chainsized s/g elements. */
-                       hba[i]->cmd_sg_list[j]->sgchain =
-                                       kmalloc((hba[i]->chainsize *
-                                               sizeof(SGDescriptor_struct)),
-                                               GFP_KERNEL);
-                       if (!hba[i]->cmd_sg_list[j]->sgchain) {
-                               printk(KERN_ERR "cciss%d: Cannot get memory "
-                                       "for s/g chains\n", i);
-                               goto clean4;
-                       }
-               }
-       }
 
        spin_lock_init(&hba[i]->lock);
 
@@ -4327,16 +4353,7 @@ clean4:
        for (k = 0; k < hba[i]->nr_cmds; k++)
                kfree(hba[i]->scatter_list[k]);
        kfree(hba[i]->scatter_list);
-       /* Only free up extra s/g lists if controller supports them */
-       if (hba[i]->chainsize > 0) {
-               for (j = 0; j < hba[i]->nr_cmds; j++) {
-                       if (hba[i]->cmd_sg_list[j]) {
-                               kfree(hba[i]->cmd_sg_list[j]->sgchain);
-                               kfree(hba[i]->cmd_sg_list[j]);
-                       }
-               }
-               kfree(hba[i]->cmd_sg_list);
-       }
+       cciss_free_sg_chain_blocks(hba[i]->cmd_sg_list, hba[i]->nr_cmds);
        if (hba[i]->cmd_pool)
                pci_free_consistent(hba[i]->pdev,
                                    hba[i]->nr_cmds * sizeof(CommandList_struct),
@@ -4454,16 +4471,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
        for (j = 0; j < hba[i]->nr_cmds; j++)
                kfree(hba[i]->scatter_list[j]);
        kfree(hba[i]->scatter_list);
-       /* Only free up extra s/g lists if controller supports them */
-       if (hba[i]->chainsize > 0) {
-               for (j = 0; j < hba[i]->nr_cmds; j++) {
-                       if (hba[i]->cmd_sg_list[j]) {
-                               kfree(hba[i]->cmd_sg_list[j]->sgchain);
-                               kfree(hba[i]->cmd_sg_list[j]);
-                       }
-               }
-               kfree(hba[i]->cmd_sg_list);
-       }
+       cciss_free_sg_chain_blocks(hba[i]->cmd_sg_list, hba[i]->nr_cmds);
        /*
         * Deliberately omit pci_disable_device(): it does something nasty to
         * Smart Array controllers that pci_enable_device does not undo