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>
This commit is contained in:
Jens Axboe 2008-11-20 09:46:09 +01:00
parent 7c0990c7ee
commit 8a3173de4a
3 changed files with 33 additions and 46 deletions

View file

@ -215,31 +215,17 @@ static struct block_device_operations cciss_fops = {
/* /*
* Enqueuing and dequeuing functions for cmdlists. * 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) { hlist_add_head(&c->list, list);
*Qptr = c;
c->next = c->prev = c;
} else {
c->prev = (*Qptr)->prev;
c->next = (*Qptr);
(*Qptr)->prev->next = c;
(*Qptr)->prev = c;
}
} }
static inline CommandList_struct *removeQ(CommandList_struct **Qptr, static inline void removeQ(CommandList_struct *c)
CommandList_struct *c)
{ {
if (c && c->next != c) { if (WARN_ON(hlist_unhashed(&c->list)))
if (*Qptr == c) return;
*Qptr = c->next;
c->prev->next = c->next; hlist_del_init(&c->list);
c->next->prev = c->prev;
} else {
*Qptr = NULL;
}
return c;
} }
#include "cciss_scsi.c" /* For SCSI tape support */ #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; c->cmdindex = i;
} }
INIT_HLIST_NODE(&c->list);
c->busaddr = (__u32) cmd_dma_handle; c->busaddr = (__u32) cmd_dma_handle;
temp64.val = (__u64) err_dma_handle; temp64.val = (__u64) err_dma_handle;
c->ErrDesc.Addr.lower = temp64.val32.lower; c->ErrDesc.Addr.lower = temp64.val32.lower;
@ -2548,7 +2535,8 @@ static void start_io(ctlr_info_t *h)
{ {
CommandList_struct *c; 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 */ /* can't do anything if fifo is full */
if ((h->access.fifo_full(h))) { if ((h->access.fifo_full(h))) {
printk(KERN_WARNING "cciss: fifo full\n"); 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 */ /* Get the first entry from the Request Q */
removeQ(&(h->reqQ), c); removeQ(c);
h->Qdepth--; h->Qdepth--;
/* Tell the controller execute command */ /* Tell the controller execute command */
h->access.submit_command(h, c); h->access.submit_command(h, c);
/* Put job onto the completed Q */ /* 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)); memset(c->err_info, 0, sizeof(ErrorInfo_struct));
/* add it to software queue and then send it to the controller */ /* add it to software queue and then send it to the controller */
addQ(&(h->reqQ), c); addQ(&h->reqQ, c);
h->Qdepth++; h->Qdepth++;
if (h->Qdepth > h->maxQsinceinit) if (h->Qdepth > h->maxQsinceinit)
h->maxQsinceinit = h->Qdepth; h->maxQsinceinit = h->Qdepth;
@ -2897,7 +2885,7 @@ static void do_cciss_request(struct request_queue *q)
spin_lock_irq(q->queue_lock); spin_lock_irq(q->queue_lock);
addQ(&(h->reqQ), c); addQ(&h->reqQ, c);
h->Qdepth++; h->Qdepth++;
if (h->Qdepth > h->maxQsinceinit) if (h->Qdepth > h->maxQsinceinit)
h->maxQsinceinit = h->Qdepth; h->maxQsinceinit = h->Qdepth;
@ -2985,16 +2973,12 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id)
a = c->busaddr; a = c->busaddr;
} else { } else {
struct hlist_node *tmp;
a &= ~3; a &= ~3;
if ((c = h->cmpQ) == NULL) { c = NULL;
printk(KERN_WARNING hlist_for_each_entry(c, tmp, &h->cmpQ, list) {
"cciss: Completion of %08x ignored\n", if (c->busaddr == a)
a1);
continue;
}
while (c->busaddr != a) {
c = c->next;
if (c == h->cmpQ)
break; 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 * If we've found the command, take it off the
* completion Q and free it * completion Q and free it
*/ */
if (c->busaddr == a) { if (c && c->busaddr == a) {
removeQ(&h->cmpQ, c); removeQ(c);
if (c->cmd_type == CMD_RWREQ) { if (c->cmd_type == CMD_RWREQ) {
complete_command(h, c, 0); complete_command(h, c, 0);
} else if (c->cmd_type == CMD_IOCTL_PEND) { } else if (c->cmd_type == CMD_IOCTL_PEND) {
@ -3423,6 +3407,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
return -1; return -1;
hba[i]->busy_initializing = 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) if (cciss_pci_init(hba[i], pdev) != 0)
goto clean1; 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. */ pci_disable_device(h->pdev); /* Make sure it is really dead. */
/* move everything off the request queue onto the completed queue */ /* move everything off the request queue onto the completed queue */
while ((c = h->reqQ) != NULL) { while (!hlist_empty(&h->reqQ)) {
removeQ(&(h->reqQ), c); c = hlist_entry(h->reqQ.first, CommandList_struct, list);
removeQ(c);
h->Qdepth--; h->Qdepth--;
addQ(&(h->cmpQ), c); addQ(&h->cmpQ, c);
} }
/* Now, fail everything on the completed queue with a HW error */ /* Now, fail everything on the completed queue with a HW error */
while ((c = h->cmpQ) != NULL) { while (!hlist_empty(&h->cmpQ)) {
removeQ(&h->cmpQ, c); c = hlist_entry(h->cmpQ.first, CommandList_struct, list);
removeQ(c);
c->err_info->CommandStatus = CMD_HARDWARE_ERR; c->err_info->CommandStatus = CMD_HARDWARE_ERR;
if (c->cmd_type == CMD_RWREQ) { if (c->cmd_type == CMD_RWREQ) {
complete_command(h, c, 0); complete_command(h, c, 0);

View file

@ -89,8 +89,8 @@ struct ctlr_info
struct access_method access; struct access_method access;
/* queue and queue Info */ /* queue and queue Info */
CommandList_struct *reqQ; struct hlist_head reqQ;
CommandList_struct *cmpQ; struct hlist_head cmpQ;
unsigned int Qdepth; unsigned int Qdepth;
unsigned int maxQsinceinit; unsigned int maxQsinceinit;
unsigned int maxSG; unsigned int maxSG;

View file

@ -265,8 +265,7 @@ typedef struct _CommandList_struct {
int ctlr; int ctlr;
int cmd_type; int cmd_type;
long cmdindex; long cmdindex;
struct _CommandList_struct *prev; struct hlist_node list;
struct _CommandList_struct *next;
struct request * rq; struct request * rq;
struct completion *waiting; struct completion *waiting;
int retry_count; int retry_count;