1 From: Hannes Reinecke <hare@suse.de>
2 Subject: cciss: Ignore stale commands after reboot
6 When doing an unexpected shutdown like kexec the cciss
7 firmware might still have some commands in flight, which
8 it is trying to complete.
9 The driver is doing it's best on resetting the HBA,
10 but sadly there's a firmware issue causing the firmware
11 _not_ to abort or drop old commands.
12 So the firmware will send us commands which we haven't
13 accounted for, causing the driver to panic.
15 This patch also updates the queue handling to using
16 kernel-provided hashed lists; without it we wouldn't
17 be able to detect stale commands at all.
18 Queue handling is backported from mainline.
20 Signed-off-by: Hannes Reinecke <hare@suse.de>
22 diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
23 index d7ec8e4..28d3f3d 100644
24 --- a/drivers/block/cciss.c
25 +++ b/drivers/block/cciss.c
26 @@ -214,31 +214,27 @@ static struct block_device_operations cciss_fops = {
28 * Enqueuing and dequeuing functions for cmdlists.
30 -static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c)
31 +static inline void addQ(struct hlist_head *list, CommandList_struct *c)
33 - if (*Qptr == NULL) {
35 - c->next = c->prev = c;
37 - c->prev = (*Qptr)->prev;
39 - (*Qptr)->prev->next = c;
42 + hlist_add_head(&c->list, list);
45 -static inline CommandList_struct *removeQ(CommandList_struct **Qptr,
46 - CommandList_struct *c)
47 +static inline void removeQ(CommandList_struct *c)
49 - if (c && c->next != c) {
52 - c->prev->next = c->next;
53 - c->next->prev = c->prev;
57 + * After kexec/dump some commands might still
58 + * be in flight, which the firmware will try
59 + * to complete. Resetting the firmware doesn't work
60 + * with old fw revisions, so we have to mark
61 + * them off as 'stale' to prevent the driver from
64 + if (unlikely(hlist_unhashed(&c->list))) {
65 + c->cmd_type = CMD_MSG_STALE;
70 + hlist_del_init(&c->list);
73 #include "cciss_scsi.c" /* For SCSI tape support */
74 @@ -505,6 +501,7 @@ static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool)
78 + INIT_HLIST_NODE(&c->list);
79 c->busaddr = (__u32) cmd_dma_handle;
80 temp64.val = (__u64) err_dma_handle;
81 c->ErrDesc.Addr.lower = temp64.val32.lower;
82 @@ -2549,7 +2548,8 @@ static void start_io(ctlr_info_t *h)
84 CommandList_struct *c;
86 - while ((c = h->reqQ) != NULL) {
87 + while (!hlist_empty(&h->reqQ)) {
88 + c = hlist_entry(h->reqQ.first, CommandList_struct, list);
89 /* can't do anything if fifo is full */
90 if ((h->access.fifo_full(h))) {
91 printk(KERN_WARNING "cciss: fifo full\n");
92 @@ -2557,14 +2557,14 @@ static void start_io(ctlr_info_t *h)
95 /* Get the first entry from the Request Q */
96 - removeQ(&(h->reqQ), c);
100 /* Tell the controller execute command */
101 h->access.submit_command(h, c);
103 /* Put job onto the completed Q */
104 - addQ(&(h->cmpQ), c);
109 @@ -2577,7 +2577,7 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
110 memset(c->err_info, 0, sizeof(ErrorInfo_struct));
112 /* add it to software queue and then send it to the controller */
113 - addQ(&(h->reqQ), c);
116 if (h->Qdepth > h->maxQsinceinit)
117 h->maxQsinceinit = h->Qdepth;
118 @@ -2898,7 +2898,7 @@ static void do_cciss_request(struct request_queue *q)
120 spin_lock_irq(q->queue_lock);
122 - addQ(&(h->reqQ), c);
125 if (h->Qdepth > h->maxQsinceinit)
126 h->maxQsinceinit = h->Qdepth;
127 @@ -2986,16 +2986,12 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id)
131 + struct hlist_node *tmp;
134 - if ((c = h->cmpQ) == NULL) {
135 - printk(KERN_WARNING
136 - "cciss: Completion of %08x ignored\n",
140 - while (c->busaddr != a) {
144 + hlist_for_each_entry(c, tmp, &h->cmpQ, list) {
145 + if (c->busaddr == a)
149 @@ -3003,8 +2999,8 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id)
150 * If we've found the command, take it off the
151 * completion Q and free it
153 - if (c->busaddr == a) {
154 - removeQ(&h->cmpQ, c);
155 + if (c && c->busaddr == a) {
157 if (c->cmd_type == CMD_RWREQ) {
158 complete_command(h, c, 0);
159 } else if (c->cmd_type == CMD_IOCTL_PEND) {
160 @@ -3423,6 +3419,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
163 hba[i]->busy_initializing = 1;
164 + INIT_HLIST_HEAD(&hba[i]->cmpQ);
165 + INIT_HLIST_HEAD(&hba[i]->reqQ);
167 if (cciss_pci_init(hba[i], pdev) != 0)
169 @@ -3730,16 +3728,19 @@ static void fail_all_cmds(unsigned long ctlr)
170 pci_disable_device(h->pdev); /* Make sure it is really dead. */
172 /* move everything off the request queue onto the completed queue */
173 - while ((c = h->reqQ) != NULL) {
174 - removeQ(&(h->reqQ), c);
175 + while (!hlist_empty(&h->reqQ)) {
176 + c = hlist_entry(h->reqQ.first, CommandList_struct, list);
179 - addQ(&(h->cmpQ), c);
183 /* Now, fail everything on the completed queue with a HW error */
184 - while ((c = h->cmpQ) != NULL) {
185 - removeQ(&h->cmpQ, c);
186 - c->err_info->CommandStatus = CMD_HARDWARE_ERR;
187 + while (!hlist_empty(&h->cmpQ)) {
188 + c = hlist_entry(h->cmpQ.first, CommandList_struct, list);
190 + if (c->cmd_type != CMD_MSG_STALE)
191 + c->err_info->CommandStatus = CMD_HARDWARE_ERR;
192 if (c->cmd_type == CMD_RWREQ) {
193 complete_command(h, c, 0);
194 } else if (c->cmd_type == CMD_IOCTL_PEND)
195 diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
196 index 24a7efa..15e2b84 100644
197 --- a/drivers/block/cciss.h
198 +++ b/drivers/block/cciss.h
199 @@ -89,8 +89,8 @@ struct ctlr_info
200 struct access_method access;
202 /* queue and queue Info */
203 - CommandList_struct *reqQ;
204 - CommandList_struct *cmpQ;
205 + struct hlist_head reqQ;
206 + struct hlist_head cmpQ;
208 unsigned int maxQsinceinit;
210 diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h
211 index 43bf559..e4ca588 100644
212 --- a/drivers/block/cciss_cmd.h
213 +++ b/drivers/block/cciss_cmd.h
214 @@ -249,6 +249,7 @@ typedef struct _ErrorInfo_struct {
215 #define CMD_SCSI 0x03
216 #define CMD_MSG_DONE 0x04
217 #define CMD_MSG_TIMEOUT 0x05
218 +#define CMD_MSG_STALE 0xff
220 /* This structure needs to be divisible by 8 for new
222 @@ -265,8 +266,7 @@ typedef struct _CommandList_struct {
226 - struct _CommandList_struct *prev;
227 - struct _CommandList_struct *next;
228 + struct hlist_node list;
230 struct completion *waiting;