i2c: Document the message size limit
[safe/jmp/linux-2.6] / drivers / block / cciss.c
index cd8c7c2..9e3af30 100644 (file)
@@ -257,6 +257,79 @@ static inline void removeQ(CommandList_struct *c)
        hlist_del_init(&c->list);
 }
 
+static void cciss_free_sg_chain_blocks(SGDescriptor_struct **cmd_sg_list,
+       int nr_cmds)
+{
+       int i;
+
+       if (!cmd_sg_list)
+               return;
+       for (i = 0; i < nr_cmds; i++) {
+               kfree(cmd_sg_list[i]);
+               cmd_sg_list[i] = NULL;
+       }
+       kfree(cmd_sg_list);
+}
+
+static SGDescriptor_struct **cciss_allocate_sg_chain_blocks(
+       ctlr_info_t *h, int chainsize, int nr_cmds)
+{
+       int j;
+       SGDescriptor_struct **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++) {
+               /* Need a block of chainsized s/g elements. */
+               cmd_sg_list[j] = kmalloc((chainsize *
+                       sizeof(*cmd_sg_list[j])), GFP_KERNEL);
+               if (!cmd_sg_list[j]) {
+                       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;
+}
+
+static void cciss_unmap_sg_chain_block(ctlr_info_t *h, CommandList_struct *c)
+{
+       SGDescriptor_struct *chain_sg;
+       u64bit temp64;
+
+       if (c->Header.SGTotal <= h->max_cmd_sgentries)
+               return;
+
+       chain_sg = &c->SG[h->max_cmd_sgentries - 1];
+       temp64.val32.lower = chain_sg->Addr.lower;
+       temp64.val32.upper = chain_sg->Addr.upper;
+       pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE);
+}
+
+static void cciss_map_sg_chain_block(ctlr_info_t *h, CommandList_struct *c,
+       SGDescriptor_struct *chain_block, int len)
+{
+       SGDescriptor_struct *chain_sg;
+       u64bit temp64;
+
+       chain_sg = &c->SG[h->max_cmd_sgentries - 1];
+       chain_sg->Ext = CCISS_SG_CHAIN;
+       chain_sg->Len = len;
+       temp64.val = pci_map_single(h->pdev, chain_block, len,
+                               PCI_DMA_TODEVICE);
+       chain_sg->Addr.lower = temp64.val32.lower;
+       chain_sg->Addr.upper = temp64.val32.upper;
+}
+
 #include "cciss_scsi.c"                /* For SCSI tape support */
 
 static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
@@ -1671,14 +1744,9 @@ static void cciss_softirq_done(struct request *rq)
        /* unmap the DMA mapping for all the scatter gather elements */
        for (i = 0; i < cmd->Header.SGList; i++) {
                if (curr_sg[sg_index].Ext == CCISS_SG_CHAIN) {
-                       temp64.val32.lower = cmd->SG[i].Addr.lower;
-                       temp64.val32.upper = cmd->SG[i].Addr.upper;
-                       pci_dma_sync_single_for_cpu(h->pdev, temp64.val,
-                                               cmd->SG[i].Len, ddir);
-                       pci_unmap_single(h->pdev, temp64.val,
-                                               cmd->SG[i].Len, ddir);
+                       cciss_unmap_sg_chain_block(h, cmd);
                        /* Point to the next block */
-                       curr_sg = h->cmd_sg_list[cmd->cmdindex]->sgchain;
+                       curr_sg = h->cmd_sg_list[cmd->cmdindex];
                        sg_index = 0;
                }
                temp64.val32.lower = curr_sg[sg_index].Addr.lower;
@@ -3080,7 +3148,6 @@ static void do_cciss_request(struct request_queue *q)
        SGDescriptor_struct *curr_sg;
        drive_info_struct *drv;
        int i, dir;
-       int nseg = 0;
        int sg_index = 0;
        int chained = 0;
 
@@ -3147,13 +3214,8 @@ static void do_cciss_request(struct request_queue *q)
        for (i = 0; i < seg; i++) {
                if (((sg_index+1) == (h->max_cmd_sgentries)) &&
                        !chained && ((seg - i) > 1)) {
-                       nseg = seg - i;
-                       curr_sg[sg_index].Len = (nseg) *
-                                       sizeof(SGDescriptor_struct);
-                       curr_sg[sg_index].Ext = CCISS_SG_CHAIN;
-
                        /* Point to next chain block. */
-                       curr_sg = h->cmd_sg_list[c->cmdindex]->sgchain;
+                       curr_sg = h->cmd_sg_list[c->cmdindex];
                        sg_index = 0;
                        chained = 1;
                }
@@ -3164,31 +3226,12 @@ static void do_cciss_request(struct request_queue *q)
                curr_sg[sg_index].Addr.lower = temp64.val32.lower;
                curr_sg[sg_index].Addr.upper = temp64.val32.upper;
                curr_sg[sg_index].Ext = 0;  /* we are not chaining */
-
                ++sg_index;
        }
-
-       if (chained) {
-               int len;
-               curr_sg = c->SG;
-               sg_index = h->max_cmd_sgentries - 1;
-               len = curr_sg[sg_index].Len;
-               /* Setup pointer to next chain block.
-                * Fill out last element in current chain
-                * block with address of next chain block.
-                */
-               temp64.val = pci_map_single(h->pdev,
-                                       h->cmd_sg_list[c->cmdindex]->sgchain,
-                                       len, dir);
-
-               h->cmd_sg_list[c->cmdindex]->sg_chain_dma = temp64.val;
-               curr_sg[sg_index].Addr.lower = temp64.val32.lower;
-               curr_sg[sg_index].Addr.upper = temp64.val32.upper;
-
-               pci_dma_sync_single_for_device(h->pdev,
-                               h->cmd_sg_list[c->cmdindex]->sg_chain_dma,
-                               len, dir);
-       }
+       if (chained)
+               cciss_map_sg_chain_block(h, c, h->cmd_sg_list[c->cmdindex],
+                       (seg - (h->max_cmd_sgentries - 1)) *
+                               sizeof(SGDescriptor_struct));
 
        /* track how many SG entries we are using */
        if (seg > h->maxSG)
@@ -4238,37 +4281,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 +4343,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 +4461,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