Merge branch 'iommu/fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/joro...
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / block / cciss_scsi.c
index 6dc15b669694d933ca229ebcb98a8e9d51f58b5c..e1d0e2cfec72aaae4d332e693005d5d30833e8ab 100644 (file)
@@ -84,7 +84,6 @@ static struct scsi_host_template cciss_driver_template = {
        .queuecommand           = cciss_scsi_queue_command,
        .can_queue              = SCSI_CCISS_CAN_QUEUE,
        .this_id                = 7,
-       .sg_tablesize           = MAXSGENTRIES,
        .cmd_per_lun            = 1,
        .use_clustering         = DISABLE_CLUSTERING,
        /* Can't have eh_bus_reset_handler or eh_host_reset_handler for cciss */
@@ -94,13 +93,14 @@ static struct scsi_host_template cciss_driver_template = {
 
 #pragma pack(1)
 
-#define SCSI_PAD_32 4
-#define SCSI_PAD_64 4
+#define SCSI_PAD_32 0
+#define SCSI_PAD_64 0
 
 struct cciss_scsi_cmd_stack_elem_t {
        CommandList_struct cmd;
        ErrorInfo_struct Err;
        __u32 busaddr;
+       int cmdindex;
        u8 pad[IS_32_BIT * SCSI_PAD_32 + IS_64_BIT * SCSI_PAD_64];
 };
 
@@ -122,6 +122,7 @@ struct cciss_scsi_cmd_stack_t {
 struct cciss_scsi_adapter_data_t {
        struct Scsi_Host *scsi_host;
        struct cciss_scsi_cmd_stack_t cmd_stack;
+       SGDescriptor_struct **cmd_sg_list;
        int registered;
        spinlock_t lock; // to protect ccissscsi[ctlr]; 
 };
@@ -156,6 +157,7 @@ scsi_cmd_alloc(ctlr_info_t *h)
        memset(&c->Err, 0, sizeof(c->Err));
        /* set physical addr of cmd and addr of scsi parameters */
        c->cmd.busaddr = c->busaddr; 
+       c->cmd.cmdindex = c->cmdindex;
        /* (__u32) (stk->cmd_pool_handle + 
                (sizeof(struct cciss_scsi_cmd_stack_elem_t)*stk->top)); */
 
@@ -201,6 +203,11 @@ scsi_cmd_stack_setup(int ctlr, struct cciss_scsi_adapter_data_t *sa)
        struct cciss_scsi_cmd_stack_t *stk;
        size_t size;
 
+       sa->cmd_sg_list = cciss_allocate_sg_chain_blocks(hba[ctlr],
+               hba[ctlr]->chainsize, CMD_STACK_SIZE);
+       if (!sa->cmd_sg_list && hba[ctlr]->chainsize > 0)
+               return -ENOMEM;
+
        stk = &sa->cmd_stack; 
        size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
 
@@ -211,14 +218,16 @@ scsi_cmd_stack_setup(int ctlr, struct cciss_scsi_adapter_data_t *sa)
                pci_alloc_consistent(hba[ctlr]->pdev, size, &stk->cmd_pool_handle);
 
        if (stk->pool == NULL) {
-               printk("stk->pool is null\n");
-               return -1;
+               cciss_free_sg_chain_blocks(sa->cmd_sg_list, CMD_STACK_SIZE);
+               sa->cmd_sg_list = NULL;
+               return -ENOMEM;
        }
 
        for (i=0; i<CMD_STACK_SIZE; i++) {
                stk->elem[i] = &stk->pool[i];
                stk->elem[i]->busaddr = (__u32) (stk->cmd_pool_handle + 
                        (sizeof(struct cciss_scsi_cmd_stack_elem_t) * i));
+               stk->elem[i]->cmdindex = i;
        }
        stk->top = CMD_STACK_SIZE-1;
        return 0;
@@ -243,6 +252,7 @@ scsi_cmd_stack_free(int ctlr)
 
        pci_free_consistent(hba[ctlr]->pdev, size, stk->pool, stk->cmd_pool_handle);
        stk->pool = NULL;
+       cciss_free_sg_chain_blocks(sa->cmd_sg_list, CMD_STACK_SIZE);
 }
 
 #if 0
@@ -726,6 +736,8 @@ complete_scsi_command( CommandList_struct *cp, int timeout, __u32 tag)
        ctlr = hba[cp->ctlr];
 
        scsi_dma_unmap(cmd);
+       if (cp->Header.SGTotal > ctlr->max_cmd_sgentries)
+               cciss_unmap_sg_chain_block(ctlr, cp);
 
        cmd->result = (DID_OK << 16);           /* host byte */
        cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
@@ -848,6 +860,7 @@ cciss_scsi_detect(int ctlr)
        sh->io_port = 0;        // good enough?  FIXME, 
        sh->n_io_port = 0;      // I don't think we use these two...
        sh->this_id = SELF_SCSI_ID;  
+       sh->sg_tablesize = hba[ctlr]->maxsgentries;
 
        ((struct cciss_scsi_adapter_data_t *) 
                hba[ctlr]->scsi_ctlr)->scsi_host = sh;
@@ -1365,34 +1378,54 @@ cciss_scsi_proc_info(struct Scsi_Host *sh,
    dma mapping  and fills in the scatter gather entries of the 
    cciss command, cp. */
 
-static void
-cciss_scatter_gather(struct pci_dev *pdev, 
-               CommandList_struct *cp, 
-               struct scsi_cmnd *cmd)
+static void cciss_scatter_gather(ctlr_info_t *h, CommandList_struct *cp,
+       struct scsi_cmnd *cmd)
 {
        unsigned int len;
        struct scatterlist *sg;
        __u64 addr64;
-       int use_sg, i;
-
-       BUG_ON(scsi_sg_count(cmd) > MAXSGENTRIES);
-
-       use_sg = scsi_dma_map(cmd);
-       if (use_sg) {   /* not too many addrs? */
-               scsi_for_each_sg(cmd, sg, use_sg, i) {
+       int request_nsgs, i, chained, sg_index;
+       struct cciss_scsi_adapter_data_t *sa = h->scsi_ctlr;
+       SGDescriptor_struct *curr_sg;
+
+       BUG_ON(scsi_sg_count(cmd) > h->maxsgentries);
+
+       chained = 0;
+       sg_index = 0;
+       curr_sg = cp->SG;
+       request_nsgs = scsi_dma_map(cmd);
+       if (request_nsgs) {
+               scsi_for_each_sg(cmd, sg, request_nsgs, i) {
+                       if (sg_index + 1 == h->max_cmd_sgentries &&
+                               !chained && request_nsgs - i > 1) {
+                               chained = 1;
+                               sg_index = 0;
+                               curr_sg = sa->cmd_sg_list[cp->cmdindex];
+                       }
                        addr64 = (__u64) sg_dma_address(sg);
                        len  = sg_dma_len(sg);
-                       cp->SG[i].Addr.lower =
-                               (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
-                       cp->SG[i].Addr.upper =
-                               (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
-                       cp->SG[i].Len = len;
-                       cp->SG[i].Ext = 0;  // we are not chaining
+                       curr_sg[sg_index].Addr.lower =
+                               (__u32) (addr64 & 0x0FFFFFFFFULL);
+                       curr_sg[sg_index].Addr.upper =
+                               (__u32) ((addr64 >> 32) & 0x0FFFFFFFFULL);
+                       curr_sg[sg_index].Len = len;
+                       curr_sg[sg_index].Ext = 0;
+                       ++sg_index;
                }
+               if (chained)
+                       cciss_map_sg_chain_block(h, cp,
+                               sa->cmd_sg_list[cp->cmdindex],
+                               (request_nsgs - (h->max_cmd_sgentries - 1)) *
+                                       sizeof(SGDescriptor_struct));
        }
-
-       cp->Header.SGList = (__u8) use_sg;   /* no. SGs contig in this cmd */
-       cp->Header.SGTotal = (__u16) use_sg; /* total sgs in this cmd list */
+       /* track how many SG entries we are using */
+       if (request_nsgs > h->maxSG)
+               h->maxSG = request_nsgs;
+       cp->Header.SGTotal = (__u8) request_nsgs + chained;
+       if (request_nsgs > h->max_cmd_sgentries)
+               cp->Header.SGList = h->max_cmd_sgentries;
+       else
+               cp->Header.SGList = cp->Header.SGTotal;
        return;
 }
 
@@ -1490,7 +1523,7 @@ cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd
                BUG();
                break;
        }
-       cciss_scatter_gather(c->pdev, cp, cmd);
+       cciss_scatter_gather(c, cp, cmd);
 
        /* Put the request on the tail of the request queue */