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.
*/
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);

View 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;

View 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;