diff options
author | Mike Miller <mike.miller@hp.com> | 2010-06-02 15:58:00 -0400 |
---|---|---|
committer | Jens Axboe <jaxboe@fusionio.com> | 2010-08-07 12:12:33 -0400 |
commit | 0c2b39087c900bdb240b50ac95ee9da00d844565 (patch) | |
tree | 8762af580586072ef0a9124f5d0c88afaf00fa27 /drivers/block | |
parent | 664a717d3ac5871efc1fd3bb5a32c552dc339d3f (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.c | 236 |
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); | |||
167 | static LIST_HEAD(scan_q); | 167 | static LIST_HEAD(scan_q); |
168 | 168 | ||
169 | static void do_cciss_request(struct request_queue *q); | 169 | static void do_cciss_request(struct request_queue *q); |
170 | static irqreturn_t do_cciss_intr(int irq, void *dev_id); | 170 | static irqreturn_t do_cciss_intx(int irq, void *dev_id); |
171 | static irqreturn_t do_cciss_msix_intr(int irq, void *dev_id); | ||
171 | static int cciss_open(struct block_device *bdev, fmode_t mode); | 172 | static int cciss_open(struct block_device *bdev, fmode_t mode); |
172 | static int cciss_release(struct gendisk *disk, fmode_t mode); | 173 | static int cciss_release(struct gendisk *disk, fmode_t mode); |
173 | static int cciss_ioctl(struct block_device *bdev, fmode_t mode, | 174 | static 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); |
198 | static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c); | 199 | static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c); |
199 | 200 | ||
200 | static void fail_all_cmds(unsigned long ctlr); | ||
201 | static int add_to_scan_list(struct ctlr_info *h); | 201 | static int add_to_scan_list(struct ctlr_info *h); |
202 | static int scan_thread(void *data); | 202 | static int scan_thread(void *data); |
203 | static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c); | 203 | static 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 | ||
3127 | static inline u32 cciss_tag_contains_index(u32 tag) | ||
3128 | { | ||
3129 | #define DIRECT_LOOKUP_BIT 0x04 | ||
3130 | return tag & DIRECT_LOOKUP_BIT; | ||
3131 | } | ||
3132 | |||
3133 | static inline u32 cciss_tag_to_index(u32 tag) | ||
3134 | { | ||
3135 | #define DIRECT_LOOKUP_SHIFT 3 | ||
3136 | return tag >> DIRECT_LOOKUP_SHIFT; | ||
3137 | } | ||
3138 | |||
3139 | static inline u32 cciss_tag_discard_error_bits(u32 tag) | ||
3140 | { | ||
3141 | #define CCISS_ERROR_BITS 0x03 | ||
3142 | return tag & ~CCISS_ERROR_BITS; | ||
3143 | } | ||
3144 | |||
3145 | static inline void cciss_mark_tag_indexed(u32 *tag) | ||
3146 | { | ||
3147 | *tag |= DIRECT_LOOKUP_BIT; | ||
3148 | } | ||
3149 | |||
3150 | static 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) | |||
3306 | static inline long interrupt_not_for_us(ctlr_info_t *h) | 3334 | static 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 | ||
3312 | static irqreturn_t do_cciss_intr(int irq, void *dev_id) | 3340 | static 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 | |||
3350 | static 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 */ | ||
3365 | static 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 */ | ||
3379 | static 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 | |||
3399 | static 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 | */ | ||
3429 | static 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 | ||
4537 | static 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 | |||
4578 | module_init(cciss_init); | 4624 | module_init(cciss_init); |
4579 | module_exit(cciss_cleanup); | 4625 | module_exit(cciss_cleanup); |