cciss: switch to using hlist for command list management
authorJens Axboe <jens.axboe@oracle.com>
Thu, 20 Nov 2008 08:46:09 +0000 (09:46 +0100)
committerJens Axboe <jens.axboe@oracle.com>
Mon, 29 Dec 2008 07:28:43 +0000 (08:28 +0100)
This both cleans up the code and also helps detect the spurious case
of a command attempted being removed from a queue it doesn't belong
to.

Acked-by: Mike Miller <mike.miller@hp.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
drivers/block/cciss.c
drivers/block/cciss.h
drivers/block/cciss_cmd.h

index 9f7c543..4e07b5c 100644 (file)
@@ -215,31 +215,17 @@ static struct block_device_operations cciss_fops = {
 /*
  * Enqueuing and dequeuing functions for cmdlists.
  */
-static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c)
+static inline void addQ(struct hlist_head *list, CommandList_struct *c)
 {
-       if (*Qptr == NULL) {
-               *Qptr = c;
-               c->next = c->prev = c;
-       } else {
-               c->prev = (*Qptr)->prev;
-               c->next = (*Qptr);
-               (*Qptr)->prev->next = c;
-               (*Qptr)->prev = c;
-       }
+       hlist_add_head(&c->list, list);
 }
 
-static inline CommandList_struct *removeQ(CommandList_struct **Qptr,
-                                         CommandList_struct *c)
+static inline void removeQ(CommandList_struct *c)
 {
-       if (c && c->next != c) {
-               if (*Qptr == c)
-                       *Qptr = c->next;
-               c->prev->next = c->next;
-               c->next->prev = c->prev;
-       } else {
-               *Qptr = NULL;
-       }
-       return c;
+       if (WARN_ON(hlist_unhashed(&c->list)))
+               return;
+
+       hlist_del_init(&c->list);
 }
 
 #include "cciss_scsi.c"                /* For SCSI tape support */
@@ -506,6 +492,7 @@ static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool)
                c->cmdindex = i;
        }
 
+       INIT_HLIST_NODE(&c->list);
        c->busaddr = (__u32) cmd_dma_handle;
        temp64.val = (__u64) err_dma_handle;
        c->ErrDesc.Addr.lower = temp64.val32.lower;
@@ -2548,7 +2535,8 @@ static void start_io(ctlr_info_t *h)
 {
        CommandList_struct *c;
 
-       while ((c = h->reqQ) != NULL) {
+       while (!hlist_empty(&h->reqQ)) {
+               c = hlist_entry(h->reqQ.first, CommandList_struct, list);
                /* can't do anything if fifo is full */
                if ((h->access.fifo_full(h))) {
                        printk(KERN_WARNING "cciss: fifo full\n");
@@ -2556,14 +2544,14 @@ static void start_io(ctlr_info_t *h)
                }
 
                /* Get the first entry from the Request Q */
-               removeQ(&(h->reqQ), c);
+               removeQ(c);
                h->Qdepth--;
 
                /* Tell the controller execute command */
                h->access.submit_command(h, c);
 
                /* Put job onto the completed Q */
-               addQ(&(h->cmpQ), c);
+               addQ(&h->cmpQ, c);
        }
 }
 
@@ -2576,7 +2564,7 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
        memset(c->err_info, 0, sizeof(ErrorInfo_struct));
 
        /* add it to software queue and then send it to the controller */
-       addQ(&(h->reqQ), c);
+       addQ(&h->reqQ, c);
        h->Qdepth++;
        if (h->Qdepth > h->maxQsinceinit)
                h->maxQsinceinit = h->Qdepth;
@@ -2897,7 +2885,7 @@ static void do_cciss_request(struct request_queue *q)
 
        spin_lock_irq(q->queue_lock);
 
-       addQ(&(h->reqQ), c);
+       addQ(&h->reqQ, c);
        h->Qdepth++;
        if (h->Qdepth > h->maxQsinceinit)
                h->maxQsinceinit = h->Qdepth;
@@ -2985,16 +2973,12 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id)
                                a = c->busaddr;
 
                        } else {
+                               struct hlist_node *tmp;
+
                                a &= ~3;
-                               if ((c = h->cmpQ) == NULL) {
-                                       printk(KERN_WARNING
-                                              "cciss: Completion of %08x ignored\n",
-                                              a1);
-                                       continue;
-                               }
-                               while (c->busaddr != a) {
-                                       c = c->next;
-                                       if (c == h->cmpQ)
+                               c = NULL;
+                               hlist_for_each_entry(c, tmp, &h->cmpQ, list) {
+                                       if (c->busaddr == a)
                                                break;
                                }
                        }
@@ -3002,8 +2986,8 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id)
                         * If we've found the command, take it off the
                         * completion Q and free it
                         */
-                       if (c->busaddr == a) {
-                               removeQ(&h->cmpQ, c);
+                       if (c && c->busaddr == a) {
+                               removeQ(c);
                                if (c->cmd_type == CMD_RWREQ) {
                                        complete_command(h, c, 0);
                                } else if (c->cmd_type == CMD_IOCTL_PEND) {
@@ -3423,6 +3407,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
                return -1;
 
        hba[i]->busy_initializing = 1;
+       INIT_HLIST_HEAD(&hba[i]->cmpQ);
+       INIT_HLIST_HEAD(&hba[i]->reqQ);
 
        if (cciss_pci_init(hba[i], pdev) != 0)
                goto clean1;
@@ -3730,15 +3716,17 @@ static void fail_all_cmds(unsigned long ctlr)
        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);
+       while (!hlist_empty(&h->reqQ)) {
+               c = hlist_entry(h->reqQ.first, CommandList_struct, list);
+               removeQ(c);
                h->Qdepth--;
-               addQ(&(h->cmpQ), c);
+               addQ(&h->cmpQ, c);
        }
 
        /* Now, fail everything on the completed queue with a HW error */
-       while ((c = h->cmpQ) != NULL) {
-               removeQ(&h->cmpQ, c);
+       while (!hlist_empty(&h->cmpQ)) {
+               c = hlist_entry(h->cmpQ.first, CommandList_struct, list);
+               removeQ(c);
                c->err_info->CommandStatus = CMD_HARDWARE_ERR;
                if (c->cmd_type == CMD_RWREQ) {
                        complete_command(h, c, 0);
index 24a7efa..15e2b84 100644 (file)
@@ -89,8 +89,8 @@ struct ctlr_info
        struct access_method access;
 
        /* queue and queue Info */ 
-       CommandList_struct *reqQ;
-       CommandList_struct  *cmpQ;
+       struct hlist_head reqQ;
+       struct hlist_head cmpQ;
        unsigned int Qdepth;
        unsigned int maxQsinceinit;
        unsigned int maxSG;
index 43bf559..24e22de 100644 (file)
@@ -265,8 +265,7 @@ typedef struct _CommandList_struct {
   int                     ctlr;
   int                     cmd_type; 
   long                    cmdindex;
-  struct _CommandList_struct *prev;
-  struct _CommandList_struct *next;
+  struct hlist_node list;
   struct request *        rq;
   struct completion *waiting;
   int   retry_count;