diff options
author | Jens Axboe <jens.axboe@oracle.com> | 2008-11-20 03:46:09 -0500 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2008-12-29 02:28:43 -0500 |
commit | 8a3173de4ab4cdacc43675dc5c077f9a5bf17f5f (patch) | |
tree | e1998a856a09c805c588740c8c83d50dd9663c40 | |
parent | 7c0990c7ee988aa193abbb7da3faeb9279146dbf (diff) |
cciss: switch to using hlist for command list management
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>
-rw-r--r-- | drivers/block/cciss.c | 72 | ||||
-rw-r--r-- | drivers/block/cciss.h | 4 | ||||
-rw-r--r-- | drivers/block/cciss_cmd.h | 3 |
3 files changed, 33 insertions, 46 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 9f7c543cc04b..4e07b5ca847c 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -215,31 +215,17 @@ static struct block_device_operations cciss_fops = { | |||
215 | /* | 215 | /* |
216 | * Enqueuing and dequeuing functions for cmdlists. | 216 | * Enqueuing and dequeuing functions for cmdlists. |
217 | */ | 217 | */ |
218 | static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c) | 218 | static inline void addQ(struct hlist_head *list, CommandList_struct *c) |
219 | { | 219 | { |
220 | if (*Qptr == NULL) { | 220 | hlist_add_head(&c->list, list); |
221 | *Qptr = c; | ||
222 | c->next = c->prev = c; | ||
223 | } else { | ||
224 | c->prev = (*Qptr)->prev; | ||
225 | c->next = (*Qptr); | ||
226 | (*Qptr)->prev->next = c; | ||
227 | (*Qptr)->prev = c; | ||
228 | } | ||
229 | } | 221 | } |
230 | 222 | ||
231 | static inline CommandList_struct *removeQ(CommandList_struct **Qptr, | 223 | static inline void removeQ(CommandList_struct *c) |
232 | CommandList_struct *c) | ||
233 | { | 224 | { |
234 | if (c && c->next != c) { | 225 | if (WARN_ON(hlist_unhashed(&c->list))) |
235 | if (*Qptr == c) | 226 | return; |
236 | *Qptr = c->next; | 227 | |
237 | c->prev->next = c->next; | 228 | hlist_del_init(&c->list); |
238 | c->next->prev = c->prev; | ||
239 | } else { | ||
240 | *Qptr = NULL; | ||
241 | } | ||
242 | return c; | ||
243 | } | 229 | } |
244 | 230 | ||
245 | #include "cciss_scsi.c" /* For SCSI tape support */ | 231 | #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) | |||
506 | c->cmdindex = i; | 492 | c->cmdindex = i; |
507 | } | 493 | } |
508 | 494 | ||
495 | INIT_HLIST_NODE(&c->list); | ||
509 | c->busaddr = (__u32) cmd_dma_handle; | 496 | c->busaddr = (__u32) cmd_dma_handle; |
510 | temp64.val = (__u64) err_dma_handle; | 497 | temp64.val = (__u64) err_dma_handle; |
511 | c->ErrDesc.Addr.lower = temp64.val32.lower; | 498 | c->ErrDesc.Addr.lower = temp64.val32.lower; |
@@ -2548,7 +2535,8 @@ static void start_io(ctlr_info_t *h) | |||
2548 | { | 2535 | { |
2549 | CommandList_struct *c; | 2536 | CommandList_struct *c; |
2550 | 2537 | ||
2551 | while ((c = h->reqQ) != NULL) { | 2538 | while (!hlist_empty(&h->reqQ)) { |
2539 | c = hlist_entry(h->reqQ.first, CommandList_struct, list); | ||
2552 | /* can't do anything if fifo is full */ | 2540 | /* can't do anything if fifo is full */ |
2553 | if ((h->access.fifo_full(h))) { | 2541 | if ((h->access.fifo_full(h))) { |
2554 | printk(KERN_WARNING "cciss: fifo full\n"); | 2542 | printk(KERN_WARNING "cciss: fifo full\n"); |
@@ -2556,14 +2544,14 @@ static void start_io(ctlr_info_t *h) | |||
2556 | } | 2544 | } |
2557 | 2545 | ||
2558 | /* Get the first entry from the Request Q */ | 2546 | /* Get the first entry from the Request Q */ |
2559 | removeQ(&(h->reqQ), c); | 2547 | removeQ(c); |
2560 | h->Qdepth--; | 2548 | h->Qdepth--; |
2561 | 2549 | ||
2562 | /* Tell the controller execute command */ | 2550 | /* Tell the controller execute command */ |
2563 | h->access.submit_command(h, c); | 2551 | h->access.submit_command(h, c); |
2564 | 2552 | ||
2565 | /* Put job onto the completed Q */ | 2553 | /* Put job onto the completed Q */ |
2566 | addQ(&(h->cmpQ), c); | 2554 | addQ(&h->cmpQ, c); |
2567 | } | 2555 | } |
2568 | } | 2556 | } |
2569 | 2557 | ||
@@ -2576,7 +2564,7 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c) | |||
2576 | memset(c->err_info, 0, sizeof(ErrorInfo_struct)); | 2564 | memset(c->err_info, 0, sizeof(ErrorInfo_struct)); |
2577 | 2565 | ||
2578 | /* add it to software queue and then send it to the controller */ | 2566 | /* add it to software queue and then send it to the controller */ |
2579 | addQ(&(h->reqQ), c); | 2567 | addQ(&h->reqQ, c); |
2580 | h->Qdepth++; | 2568 | h->Qdepth++; |
2581 | if (h->Qdepth > h->maxQsinceinit) | 2569 | if (h->Qdepth > h->maxQsinceinit) |
2582 | h->maxQsinceinit = h->Qdepth; | 2570 | h->maxQsinceinit = h->Qdepth; |
@@ -2897,7 +2885,7 @@ static void do_cciss_request(struct request_queue *q) | |||
2897 | 2885 | ||
2898 | spin_lock_irq(q->queue_lock); | 2886 | spin_lock_irq(q->queue_lock); |
2899 | 2887 | ||
2900 | addQ(&(h->reqQ), c); | 2888 | addQ(&h->reqQ, c); |
2901 | h->Qdepth++; | 2889 | h->Qdepth++; |
2902 | if (h->Qdepth > h->maxQsinceinit) | 2890 | if (h->Qdepth > h->maxQsinceinit) |
2903 | h->maxQsinceinit = h->Qdepth; | 2891 | h->maxQsinceinit = h->Qdepth; |
@@ -2985,16 +2973,12 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id) | |||
2985 | a = c->busaddr; | 2973 | a = c->busaddr; |
2986 | 2974 | ||
2987 | } else { | 2975 | } else { |
2976 | struct hlist_node *tmp; | ||
2977 | |||
2988 | a &= ~3; | 2978 | a &= ~3; |
2989 | if ((c = h->cmpQ) == NULL) { | 2979 | c = NULL; |
2990 | printk(KERN_WARNING | 2980 | hlist_for_each_entry(c, tmp, &h->cmpQ, list) { |
2991 | "cciss: Completion of %08x ignored\n", | 2981 | if (c->busaddr == a) |
2992 | a1); | ||
2993 | continue; | ||
2994 | } | ||
2995 | while (c->busaddr != a) { | ||
2996 | c = c->next; | ||
2997 | if (c == h->cmpQ) | ||
2998 | break; | 2982 | break; |
2999 | } | 2983 | } |
3000 | } | 2984 | } |
@@ -3002,8 +2986,8 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id) | |||
3002 | * If we've found the command, take it off the | 2986 | * If we've found the command, take it off the |
3003 | * completion Q and free it | 2987 | * completion Q and free it |
3004 | */ | 2988 | */ |
3005 | if (c->busaddr == a) { | 2989 | if (c && c->busaddr == a) { |
3006 | removeQ(&h->cmpQ, c); | 2990 | removeQ(c); |
3007 | if (c->cmd_type == CMD_RWREQ) { | 2991 | if (c->cmd_type == CMD_RWREQ) { |
3008 | complete_command(h, c, 0); | 2992 | complete_command(h, c, 0); |
3009 | } else if (c->cmd_type == CMD_IOCTL_PEND) { | 2993 | } else if (c->cmd_type == CMD_IOCTL_PEND) { |
@@ -3423,6 +3407,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, | |||
3423 | return -1; | 3407 | return -1; |
3424 | 3408 | ||
3425 | hba[i]->busy_initializing = 1; | 3409 | hba[i]->busy_initializing = 1; |
3410 | INIT_HLIST_HEAD(&hba[i]->cmpQ); | ||
3411 | INIT_HLIST_HEAD(&hba[i]->reqQ); | ||
3426 | 3412 | ||
3427 | if (cciss_pci_init(hba[i], pdev) != 0) | 3413 | if (cciss_pci_init(hba[i], pdev) != 0) |
3428 | goto clean1; | 3414 | goto clean1; |
@@ -3730,15 +3716,17 @@ static void fail_all_cmds(unsigned long ctlr) | |||
3730 | pci_disable_device(h->pdev); /* Make sure it is really dead. */ | 3716 | pci_disable_device(h->pdev); /* Make sure it is really dead. */ |
3731 | 3717 | ||
3732 | /* move everything off the request queue onto the completed queue */ | 3718 | /* move everything off the request queue onto the completed queue */ |
3733 | while ((c = h->reqQ) != NULL) { | 3719 | while (!hlist_empty(&h->reqQ)) { |
3734 | removeQ(&(h->reqQ), c); | 3720 | c = hlist_entry(h->reqQ.first, CommandList_struct, list); |
3721 | removeQ(c); | ||
3735 | h->Qdepth--; | 3722 | h->Qdepth--; |
3736 | addQ(&(h->cmpQ), c); | 3723 | addQ(&h->cmpQ, c); |
3737 | } | 3724 | } |
3738 | 3725 | ||
3739 | /* Now, fail everything on the completed queue with a HW error */ | 3726 | /* Now, fail everything on the completed queue with a HW error */ |
3740 | while ((c = h->cmpQ) != NULL) { | 3727 | while (!hlist_empty(&h->cmpQ)) { |
3741 | removeQ(&h->cmpQ, c); | 3728 | c = hlist_entry(h->cmpQ.first, CommandList_struct, list); |
3729 | removeQ(c); | ||
3742 | c->err_info->CommandStatus = CMD_HARDWARE_ERR; | 3730 | c->err_info->CommandStatus = CMD_HARDWARE_ERR; |
3743 | if (c->cmd_type == CMD_RWREQ) { | 3731 | if (c->cmd_type == CMD_RWREQ) { |
3744 | complete_command(h, c, 0); | 3732 | complete_command(h, c, 0); |
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 24a7efa993ab..15e2b84734e3 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h | |||
@@ -89,8 +89,8 @@ struct ctlr_info | |||
89 | struct access_method access; | 89 | struct access_method access; |
90 | 90 | ||
91 | /* queue and queue Info */ | 91 | /* queue and queue Info */ |
92 | CommandList_struct *reqQ; | 92 | struct hlist_head reqQ; |
93 | CommandList_struct *cmpQ; | 93 | struct hlist_head cmpQ; |
94 | unsigned int Qdepth; | 94 | unsigned int Qdepth; |
95 | unsigned int maxQsinceinit; | 95 | unsigned int maxQsinceinit; |
96 | unsigned int maxSG; | 96 | unsigned int maxSG; |
diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h index 43bf5593b59b..24e22dea1a99 100644 --- a/drivers/block/cciss_cmd.h +++ b/drivers/block/cciss_cmd.h | |||
@@ -265,8 +265,7 @@ typedef struct _CommandList_struct { | |||
265 | int ctlr; | 265 | int ctlr; |
266 | int cmd_type; | 266 | int cmd_type; |
267 | long cmdindex; | 267 | long cmdindex; |
268 | struct _CommandList_struct *prev; | 268 | struct hlist_node list; |
269 | struct _CommandList_struct *next; | ||
270 | struct request * rq; | 269 | struct request * rq; |
271 | struct completion *waiting; | 270 | struct completion *waiting; |
272 | int retry_count; | 271 | int retry_count; |