aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorMike Miller <mike.miller@hp.com>2010-06-02 15:58:00 -0400
committerJens Axboe <jaxboe@fusionio.com>2010-08-07 12:12:33 -0400
commit0c2b39087c900bdb240b50ac95ee9da00d844565 (patch)
tree8762af580586072ef0a9124f5d0c88afaf00fa27 /drivers/block
parent664a717d3ac5871efc1fd3bb5a32c552dc339d3f (diff)
cciss: clean up interrupt handler
Simplify the interrupt handler code to more closely match hpsa and to hopefully make it easier to follow. Signed-off-by: Mike Miller <mike.miller@hp.com> Cc: Stephen M. Cameron <scameron@beardog.cce.hp.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/cciss.c236
1 files changed, 141 insertions, 95 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 6db790c2802f..cae6a1383282 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -167,7 +167,8 @@ static DEFINE_MUTEX(scan_mutex);
167static LIST_HEAD(scan_q); 167static LIST_HEAD(scan_q);
168 168
169static void do_cciss_request(struct request_queue *q); 169static void do_cciss_request(struct request_queue *q);
170static irqreturn_t do_cciss_intr(int irq, void *dev_id); 170static irqreturn_t do_cciss_intx(int irq, void *dev_id);
171static irqreturn_t do_cciss_msix_intr(int irq, void *dev_id);
171static int cciss_open(struct block_device *bdev, fmode_t mode); 172static int cciss_open(struct block_device *bdev, fmode_t mode);
172static int cciss_release(struct gendisk *disk, fmode_t mode); 173static int cciss_release(struct gendisk *disk, fmode_t mode);
173static int cciss_ioctl(struct block_device *bdev, fmode_t mode, 174static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
@@ -197,7 +198,6 @@ static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c,
197 int attempt_retry); 198 int attempt_retry);
198static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c); 199static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c);
199 200
200static void fail_all_cmds(unsigned long ctlr);
201static int add_to_scan_list(struct ctlr_info *h); 201static int add_to_scan_list(struct ctlr_info *h);
202static int scan_thread(void *data); 202static int scan_thread(void *data);
203static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c); 203static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c);
@@ -3124,6 +3124,34 @@ after_error_processing:
3124 blk_complete_request(cmd->rq); 3124 blk_complete_request(cmd->rq);
3125} 3125}
3126 3126
3127static inline u32 cciss_tag_contains_index(u32 tag)
3128{
3129#define DIRECT_LOOKUP_BIT 0x04
3130 return tag & DIRECT_LOOKUP_BIT;
3131}
3132
3133static inline u32 cciss_tag_to_index(u32 tag)
3134{
3135#define DIRECT_LOOKUP_SHIFT 3
3136 return tag >> DIRECT_LOOKUP_SHIFT;
3137}
3138
3139static inline u32 cciss_tag_discard_error_bits(u32 tag)
3140{
3141#define CCISS_ERROR_BITS 0x03
3142 return tag & ~CCISS_ERROR_BITS;
3143}
3144
3145static inline void cciss_mark_tag_indexed(u32 *tag)
3146{
3147 *tag |= DIRECT_LOOKUP_BIT;
3148}
3149
3150static inline void cciss_set_tag_index(u32 *tag, u32 index)
3151{
3152 *tag |= (index << DIRECT_LOOKUP_SHIFT);
3153}
3154
3127/* 3155/*
3128 * Get a request and submit it to the controller. 3156 * Get a request and submit it to the controller.
3129 */ 3157 */
@@ -3172,8 +3200,8 @@ static void do_cciss_request(struct request_queue *q)
3172 /* got command from pool, so use the command block index instead */ 3200 /* got command from pool, so use the command block index instead */
3173 /* for direct lookups. */ 3201 /* for direct lookups. */
3174 /* The first 2 bits are reserved for controller error reporting. */ 3202 /* The first 2 bits are reserved for controller error reporting. */
3175 c->Header.Tag.lower = (c->cmdindex << 3); 3203 cciss_set_tag_index(&c->Header.Tag.lower, c->cmdindex);
3176 c->Header.Tag.lower |= 0x04; /* flag for direct lookup. */ 3204 cciss_mark_tag_indexed(&c->Header.Tag.lower);
3177 memcpy(&c->Header.LUN, drv->LunID, sizeof(drv->LunID)); 3205 memcpy(&c->Header.LUN, drv->LunID, sizeof(drv->LunID));
3178 c->Request.CDBLen = 10; /* 12 byte commands not in FW yet; */ 3206 c->Request.CDBLen = 10; /* 12 byte commands not in FW yet; */
3179 c->Request.Type.Type = TYPE_CMD; /* It is a command. */ 3207 c->Request.Type.Type = TYPE_CMD; /* It is a command. */
@@ -3306,15 +3334,73 @@ static inline int interrupt_pending(ctlr_info_t *h)
3306static inline long interrupt_not_for_us(ctlr_info_t *h) 3334static inline long interrupt_not_for_us(ctlr_info_t *h)
3307{ 3335{
3308 return (((h->access.intr_pending(h) == 0) || 3336 return (((h->access.intr_pending(h) == 0) ||
3309 (h->interrupts_enabled == 0))); 3337 (h->interrupts_enabled == 0)));
3310} 3338}
3311 3339
3312static irqreturn_t do_cciss_intr(int irq, void *dev_id) 3340static inline int bad_tag(ctlr_info_t *h, u32 tag_index,
3341 u32 raw_tag)
3313{ 3342{
3314 ctlr_info_t *h = dev_id; 3343 if (unlikely(tag_index >= h->nr_cmds)) {
3344 dev_warn(&h->pdev->dev, "bad tag 0x%08x ignored.\n", raw_tag);
3345 return 1;
3346 }
3347 return 0;
3348}
3349
3350static inline void finish_cmd(ctlr_info_t *h, CommandList_struct *c,
3351 u32 raw_tag)
3352{
3353 removeQ(c);
3354 if (likely(c->cmd_type == CMD_RWREQ))
3355 complete_command(h, c, 0);
3356 else if (c->cmd_type == CMD_IOCTL_PEND)
3357 complete(c->waiting);
3358#ifdef CONFIG_CISS_SCSI_TAPE
3359 else if (c->cmd_type == CMD_SCSI)
3360 complete_scsi_command(c, 0, raw_tag);
3361#endif
3362}
3363
3364/* process completion of an indexed ("direct lookup") command */
3365static inline u32 process_indexed_cmd(ctlr_info_t *h, u32 raw_tag)
3366{
3367 u32 tag_index;
3315 CommandList_struct *c; 3368 CommandList_struct *c;
3369
3370 tag_index = cciss_tag_to_index(raw_tag);
3371 if (bad_tag(h, tag_index, raw_tag))
3372 return get_next_completion(h);
3373 c = h->cmd_pool + tag_index;
3374 finish_cmd(h, c, raw_tag);
3375 return get_next_completion(h);
3376}
3377
3378/* process completion of a non-indexed command */
3379static inline u32 process_nonindexed_cmd(ctlr_info_t *h, u32 raw_tag)
3380{
3381 u32 tag;
3382 CommandList_struct *c = NULL;
3383 struct hlist_node *tmp;
3384 __u32 busaddr_masked, tag_masked;
3385
3386 tag = cciss_tag_discard_error_bits(raw_tag);
3387 hlist_for_each_entry(c, tmp, &h->cmpQ, list) {
3388 busaddr_masked = cciss_tag_discard_error_bits(c->busaddr);
3389 tag_masked = cciss_tag_discard_error_bits(tag);
3390 if (busaddr_masked == tag_masked) {
3391 finish_cmd(h, c, raw_tag);
3392 return get_next_completion(h);
3393 }
3394 }
3395 bad_tag(h, h->nr_cmds + 1, raw_tag);
3396 return get_next_completion(h);
3397}
3398
3399static irqreturn_t do_cciss_intx(int irq, void *dev_id)
3400{
3401 ctlr_info_t *h = dev_id;
3316 unsigned long flags; 3402 unsigned long flags;
3317 __u32 a, a1, a2; 3403 u32 raw_tag;
3318 3404
3319 if (interrupt_not_for_us(h)) 3405 if (interrupt_not_for_us(h))
3320 return IRQ_NONE; 3406 return IRQ_NONE;
@@ -3324,50 +3410,41 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id)
3324 */ 3410 */
3325 spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); 3411 spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
3326 while (interrupt_pending(h)) { 3412 while (interrupt_pending(h)) {
3327 while ((a = get_next_completion(h)) != FIFO_EMPTY) { 3413 raw_tag = get_next_completion(h);
3328 a1 = a; 3414 while (raw_tag != FIFO_EMPTY) {
3329 if ((a & 0x04)) { 3415 if (cciss_tag_contains_index(raw_tag))
3330 a2 = (a >> 3); 3416 raw_tag = process_indexed_cmd(h, raw_tag);
3331 if (a2 >= h->nr_cmds) { 3417 else
3332 printk(KERN_WARNING 3418 raw_tag = process_nonindexed_cmd(h, raw_tag);
3333 "cciss: controller cciss%d failed, stopping.\n", 3419 }
3334 h->ctlr); 3420 }
3335 spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
3336 fail_all_cmds(h->ctlr);
3337 return IRQ_HANDLED;
3338 }
3339 3421
3340 c = h->cmd_pool + a2; 3422 spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
3341 a = c->busaddr; 3423 return IRQ_HANDLED;
3424}
3342 3425
3343 } else { 3426/* Add a second interrupt handler for MSI/MSI-X mode. In this mode we never
3344 struct hlist_node *tmp; 3427 * check the interrupt pending register because it is not set.
3428 */
3429static irqreturn_t do_cciss_msix_intr(int irq, void *dev_id)
3430{
3431 ctlr_info_t *h = dev_id;
3432 unsigned long flags;
3433 u32 raw_tag;
3345 3434
3346 a &= ~3; 3435 if (interrupt_not_for_us(h))
3347 c = NULL; 3436 return IRQ_NONE;
3348 hlist_for_each_entry(c, tmp, &h->cmpQ, list) { 3437 /*
3349 if (c->busaddr == a) 3438 * If there are completed commands in the completion queue,
3350 break; 3439 * we had better do something about it.
3351 } 3440 */
3352 } 3441 spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
3353 /* 3442 raw_tag = get_next_completion(h);
3354 * If we've found the command, take it off the 3443 while (raw_tag != FIFO_EMPTY) {
3355 * completion Q and free it 3444 if (cciss_tag_contains_index(raw_tag))
3356 */ 3445 raw_tag = process_indexed_cmd(h, raw_tag);
3357 if (c && c->busaddr == a) { 3446 else
3358 removeQ(c); 3447 raw_tag = process_nonindexed_cmd(h, raw_tag);
3359 if (c->cmd_type == CMD_RWREQ) {
3360 complete_command(h, c, 0);
3361 } else if (c->cmd_type == CMD_IOCTL_PEND) {
3362 complete(c->waiting);
3363 }
3364# ifdef CONFIG_CISS_SCSI_TAPE
3365 else if (c->cmd_type == CMD_SCSI)
3366 complete_scsi_command(c, 0, a1);
3367# endif
3368 continue;
3369 }
3370 }
3371 } 3448 }
3372 3449
3373 spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); 3450 spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
@@ -4230,11 +4307,21 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
4230 4307
4231 /* make sure the board interrupts are off */ 4308 /* make sure the board interrupts are off */
4232 hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); 4309 hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
4233 if (request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intr, 4310 if (hba[i]->msi_vector || hba[i]->msix_vector) {
4234 IRQF_DISABLED | IRQF_SHARED, hba[i]->devname, hba[i])) { 4311 if (request_irq(hba[i]->intr[SIMPLE_MODE_INT],
4235 printk(KERN_ERR "cciss: Unable to get irq %d for %s\n", 4312 do_cciss_msix_intr,
4236 hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname); 4313 IRQF_DISABLED, hba[i]->devname, hba[i])) {
4237 goto clean2; 4314 printk(KERN_ERR "cciss: Unable to get irq %d for %s\n",
4315 hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname);
4316 goto clean2;
4317 }
4318 } else {
4319 if (request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intx,
4320 IRQF_DISABLED, hba[i]->devname, hba[i])) {
4321 printk(KERN_ERR "cciss: Unable to get irq %d for %s\n",
4322 hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname);
4323 goto clean2;
4324 }
4238 } 4325 }
4239 4326
4240 printk(KERN_INFO "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n", 4327 printk(KERN_INFO "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n",
@@ -4534,46 +4621,5 @@ static void __exit cciss_cleanup(void)
4534 bus_unregister(&cciss_bus_type); 4621 bus_unregister(&cciss_bus_type);
4535} 4622}
4536 4623
4537static void fail_all_cmds(unsigned long ctlr)
4538{
4539 /* If we get here, the board is apparently dead. */
4540 ctlr_info_t *h = hba[ctlr];
4541 CommandList_struct *c;
4542 unsigned long flags;
4543
4544 printk(KERN_WARNING "cciss%d: controller not responding.\n", h->ctlr);
4545 h->alive = 0; /* the controller apparently died... */
4546
4547 spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
4548
4549 pci_disable_device(h->pdev); /* Make sure it is really dead. */
4550
4551 /* move everything off the request queue onto the completed queue */
4552 while (!hlist_empty(&h->reqQ)) {
4553 c = hlist_entry(h->reqQ.first, CommandList_struct, list);
4554 removeQ(c);
4555 h->Qdepth--;
4556 addQ(&h->cmpQ, c);
4557 }
4558
4559 /* Now, fail everything on the completed queue with a HW error */
4560 while (!hlist_empty(&h->cmpQ)) {
4561 c = hlist_entry(h->cmpQ.first, CommandList_struct, list);
4562 removeQ(c);
4563 if (c->cmd_type != CMD_MSG_STALE)
4564 c->err_info->CommandStatus = CMD_HARDWARE_ERR;
4565 if (c->cmd_type == CMD_RWREQ) {
4566 complete_command(h, c, 0);
4567 } else if (c->cmd_type == CMD_IOCTL_PEND)
4568 complete(c->waiting);
4569#ifdef CONFIG_CISS_SCSI_TAPE
4570 else if (c->cmd_type == CMD_SCSI)
4571 complete_scsi_command(c, 0, 0);
4572#endif
4573 }
4574 spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
4575 return;
4576}
4577
4578module_init(cciss_init); 4624module_init(cciss_init);
4579module_exit(cciss_cleanup); 4625module_exit(cciss_cleanup);