[PATCH] cciss: direct lookup for command completions
authorMike Miller <mike.miller@hp.com>
Tue, 13 Sep 2005 08:25:22 +0000 (01:25 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Tue, 13 Sep 2005 15:22:30 +0000 (08:22 -0700)
This patch changes the way we complete commands.  In the old method when we
got a completion we searched our command list from the top until we find it.

This method uses a tag associated with each command (not SCSI command tagging)
to index us directly to the completed command.  This helps performance.

Signed-off-by: Don Brace <dab@hp.com>
Signed-off-by: Mike Miller <mike.miller@hp.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
drivers/block/cciss_scsi.c

index 3c6a6a21d540a24f8aaf16417970b5d081384215..a12b95eef18e02088703328a73ec8a3672daa04e 100644 (file)
@@ -174,6 +174,8 @@ static int sendcmd_withirq(__u8     cmd, int ctlr, void *buff, size_t size,
        unsigned int use_unit_num, unsigned int log_unit, __u8  page_code,
        int cmd_type);
 
+static void fail_all_cmds(unsigned long ctlr);
+
 #ifdef CONFIG_PROC_FS
 static int cciss_proc_get_info(char *buffer, char **start, off_t offset, 
                int length, int *eof, void *data);
@@ -387,6 +389,8 @@ static CommandList_struct * cmd_alloc(ctlr_info_t *h, int get_from_pool)
                        return NULL;
                memset(c, 0, sizeof(CommandList_struct));
 
+               c->cmdindex = -1;
+
                c->err_info = (ErrorInfo_struct *)pci_alloc_consistent(
                                        h->pdev, sizeof(ErrorInfo_struct), 
                                        &err_dma_handle);
@@ -417,6 +421,8 @@ static CommandList_struct * cmd_alloc(ctlr_info_t *h, int get_from_pool)
                err_dma_handle = h->errinfo_pool_dhandle 
                                        + i*sizeof(ErrorInfo_struct);
                 h->nr_allocs++;
+
+               c->cmdindex = i;
         }
 
        c->busaddr = (__u32) cmd_dma_handle;
@@ -2257,7 +2263,11 @@ queue:
        /* fill in the request */ 
        drv = creq->rq_disk->private_data;
        c->Header.ReplyQueue = 0;  // unused in simple mode
-       c->Header.Tag.lower = c->busaddr;  // use the physical address the cmd block for tag
+       /* got command from pool, so use the command block index instead */
+       /* for direct lookups. */
+       /* The first 2 bits are reserved for controller error reporting. */
+       c->Header.Tag.lower = (c->cmdindex << 3);
+       c->Header.Tag.lower |= 0x04; /* flag for direct lookup. */
        c->Header.LUN.LogDev.VolId= drv->LunID;
        c->Header.LUN.LogDev.Mode = 1;
        c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
@@ -2332,7 +2342,7 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
        ctlr_info_t *h = dev_id;
        CommandList_struct *c;
        unsigned long flags;
-       __u32 a, a1;
+       __u32 a, a1, a2;
        int j;
        int start_queue = h->next_to_run;
 
@@ -2350,10 +2360,21 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
                while((a = h->access.command_completed(h)) != FIFO_EMPTY) 
                {
                        a1 = a;
+                       if ((a & 0x04)) {
+                               a2 = (a >> 3);
+                               if (a2 >= NR_CMDS) {
+                                       printk(KERN_WARNING "cciss: controller cciss%d failed, stopping.\n", h->ctlr);
+                                       fail_all_cmds(h->ctlr);
+                                       return IRQ_HANDLED;
+                               }
+
+                               c = h->cmd_pool + a2;
+                               a = c->busaddr;
+
+                       } else {
                        a &= ~3;
-                       if ((c = h->cmpQ) == NULL)
-                       {  
-                               printk(KERN_WARNING "cciss: Completion of %08lx ignored\n", (unsigned long)a1);
+                               if ((c = h->cmpQ) == NULL) {
+                                       printk(KERN_WARNING "cciss: Completion of %08x ignored\n", a1);
                                continue;       
                        } 
                        while(c->busaddr != a) {
@@ -2361,6 +2382,7 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
                                if (c == h->cmpQ) 
                                        break;
                        }
+                       }
                        /*
                         * If we've found the command, take it off the
                         * completion Q and free it
@@ -3124,5 +3146,43 @@ static void __exit cciss_cleanup(void)
        remove_proc_entry("cciss", proc_root_driver);
 }
 
+static void fail_all_cmds(unsigned long ctlr)
+{
+       /* If we get here, the board is apparently dead. */
+       ctlr_info_t *h = hba[ctlr];
+       CommandList_struct *c;
+       unsigned long flags;
+
+       printk(KERN_WARNING "cciss%d: controller not responding.\n", h->ctlr);
+       h->alive = 0;   /* the controller apparently died... */
+
+       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+
+       pci_disable_device(h->pdev); /* Make sure it is really dead. */
+
+       /* move everything off the request queue onto the completed queue */
+       while( (c = h->reqQ) != NULL ) {
+               removeQ(&(h->reqQ), c);
+               h->Qdepth--;
+               addQ (&(h->cmpQ), c);
+       }
+
+       /* Now, fail everything on the completed queue with a HW error */
+       while( (c = h->cmpQ) != NULL ) {
+               removeQ(&h->cmpQ, c);
+               c->err_info->CommandStatus = CMD_HARDWARE_ERR;
+               if (c->cmd_type == CMD_RWREQ) {
+                       complete_command(h, c, 0);
+               } else if (c->cmd_type == CMD_IOCTL_PEND)
+                       complete(c->waiting);
+#ifdef CONFIG_CISS_SCSI_TAPE
+                       else if (c->cmd_type == CMD_SCSI)
+                               complete_scsi_command(c, 0, 0);
+#endif
+       }
+       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+       return;
+}
+
 module_init(cciss_init);
 module_exit(cciss_cleanup);
index dec27a961120060daff46f2317c60d74f517f866..ef277baee9fdc565834a04dda71f1da3014bba72 100644 (file)
@@ -101,6 +101,7 @@ struct ctlr_info
 #ifdef CONFIG_CISS_SCSI_TAPE
        void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
 #endif
+       unsigned char alive;
 };
 
 /*  Defining the diffent access_menthods */
index a88a88817623fb34b230141eba5f0ae7d068c95b..53fea549ba8b23a6714cfd8a33fc55705893986e 100644 (file)
@@ -226,6 +226,10 @@ typedef struct _ErrorInfo_struct {
 #define CMD_MSG_DONE   0x04
 #define CMD_MSG_TIMEOUT 0x05
 
+/* This structure needs to be divisible by 8 for new
+ * indexing method.
+ */
+#define PADSIZE (sizeof(long) - 4)
 typedef struct _CommandList_struct {
   CommandListHeader_struct Header;
   RequestBlock_struct      Request;
@@ -236,14 +240,14 @@ typedef struct _CommandList_struct {
   ErrorInfo_struct *      err_info; /* pointer to the allocated mem */ 
   int                     ctlr;
   int                     cmd_type; 
+  long                    cmdindex;
   struct _CommandList_struct *prev;
   struct _CommandList_struct *next;
   struct request *        rq;
   struct completion *waiting;
   int   retry_count;
-#ifdef CONFIG_CISS_SCSI_TAPE
   void * scsi_cmd;
-#endif
+  char   pad[PADSIZE];
 } CommandList_struct;
 
 //Configuration Table Structure
index f16e3caed58a36129ff7046531607ea6cfb07fa3..df4afacc75d79b99e9defab474b8659b1ba0c51e 100644 (file)
@@ -93,6 +93,7 @@ struct cciss_scsi_cmd_stack_elem_t {
        CommandList_struct cmd;
        ErrorInfo_struct Err;
        __u32 busaddr;
+       __u32 pad;
 };
 
 #pragma pack()