diff options
| author | Gerald Britton <gbritton@alum.mit.edu> | 2007-05-14 13:53:01 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-19 00:03:49 -0400 |
| commit | e9ca75b53576ddf82ea2d803f87c59dffac7bc42 (patch) | |
| tree | 4f4763a1960572dcf144de622729098ade4e8ea7 | |
| parent | dec04cff500d4e543c55ab1beb0af85d8ed7e6bd (diff) | |
cciss: Fix pci_driver.shutdown while device is still active
Fix an Oops in the cciss driver caused by system shutdown while a filesystem
on a cciss device is still active. The cciss_remove_one function only
properly removes the device if the device has been cleanly released by its
users, which is not the case when the pci_driver.shutdown method is called.
This patch adds a new cciss_shutdown function to better match the pattern
used by various SCSI drivers: deactivate device interrupts and flush caches.
It also alters the cciss_remove_one function to match and readds the
__devexit annotation that was removed when cciss_remove_one was serving as
the pci_driver.shutdown method.
Signed-off-by: Gerald Britton <gbritton@alum.mit.edu>
Acked-by: Mike Miller <mike.miller@hp.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | drivers/block/cciss.c | 45 |
1 files changed, 30 insertions, 15 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 370dfe1c422e..5acc6c44aead 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
| @@ -3469,13 +3469,39 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, | |||
| 3469 | return -1; | 3469 | return -1; |
| 3470 | } | 3470 | } |
| 3471 | 3471 | ||
| 3472 | static void cciss_remove_one(struct pci_dev *pdev) | 3472 | static void cciss_shutdown(struct pci_dev *pdev) |
| 3473 | { | 3473 | { |
| 3474 | ctlr_info_t *tmp_ptr; | 3474 | ctlr_info_t *tmp_ptr; |
| 3475 | int i, j; | 3475 | int i; |
| 3476 | char flush_buf[4]; | 3476 | char flush_buf[4]; |
| 3477 | int return_code; | 3477 | int return_code; |
| 3478 | 3478 | ||
| 3479 | tmp_ptr = pci_get_drvdata(pdev); | ||
| 3480 | if (tmp_ptr == NULL) | ||
| 3481 | return; | ||
| 3482 | i = tmp_ptr->ctlr; | ||
| 3483 | if (hba[i] == NULL) | ||
| 3484 | return; | ||
| 3485 | |||
| 3486 | /* Turn board interrupts off and send the flush cache command */ | ||
| 3487 | /* sendcmd will turn off interrupt, and send the flush... | ||
| 3488 | * To write all data in the battery backed cache to disks */ | ||
| 3489 | memset(flush_buf, 0, 4); | ||
| 3490 | return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL, | ||
| 3491 | TYPE_CMD); | ||
| 3492 | if (return_code == IO_OK) { | ||
| 3493 | printk(KERN_INFO "Completed flushing cache on controller %d\n", i); | ||
| 3494 | } else { | ||
| 3495 | printk(KERN_WARNING "Error flushing cache on controller %d\n", i); | ||
| 3496 | } | ||
| 3497 | free_irq(hba[i]->intr[2], hba[i]); | ||
| 3498 | } | ||
| 3499 | |||
| 3500 | static void __devexit cciss_remove_one(struct pci_dev *pdev) | ||
| 3501 | { | ||
| 3502 | ctlr_info_t *tmp_ptr; | ||
| 3503 | int i, j; | ||
| 3504 | |||
| 3479 | if (pci_get_drvdata(pdev) == NULL) { | 3505 | if (pci_get_drvdata(pdev) == NULL) { |
| 3480 | printk(KERN_ERR "cciss: Unable to remove device \n"); | 3506 | printk(KERN_ERR "cciss: Unable to remove device \n"); |
| 3481 | return; | 3507 | return; |
| @@ -3506,18 +3532,7 @@ static void cciss_remove_one(struct pci_dev *pdev) | |||
| 3506 | 3532 | ||
| 3507 | cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ | 3533 | cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ |
| 3508 | 3534 | ||
| 3509 | /* Turn board interrupts off and send the flush cache command */ | 3535 | cciss_shutdown(pdev); |
| 3510 | /* sendcmd will turn off interrupt, and send the flush... | ||
| 3511 | * To write all data in the battery backed cache to disks */ | ||
| 3512 | memset(flush_buf, 0, 4); | ||
| 3513 | return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL, | ||
| 3514 | TYPE_CMD); | ||
| 3515 | if (return_code == IO_OK) { | ||
| 3516 | printk(KERN_INFO "Completed flushing cache on controller %d\n", i); | ||
| 3517 | } else { | ||
| 3518 | printk(KERN_WARNING "Error flushing cache on controller %d\n", i); | ||
| 3519 | } | ||
| 3520 | free_irq(hba[i]->intr[2], hba[i]); | ||
| 3521 | 3536 | ||
| 3522 | #ifdef CONFIG_PCI_MSI | 3537 | #ifdef CONFIG_PCI_MSI |
| 3523 | if (hba[i]->msix_vector) | 3538 | if (hba[i]->msix_vector) |
| @@ -3550,7 +3565,7 @@ static struct pci_driver cciss_pci_driver = { | |||
| 3550 | .probe = cciss_init_one, | 3565 | .probe = cciss_init_one, |
| 3551 | .remove = __devexit_p(cciss_remove_one), | 3566 | .remove = __devexit_p(cciss_remove_one), |
| 3552 | .id_table = cciss_pci_device_id, /* id_table */ | 3567 | .id_table = cciss_pci_device_id, /* id_table */ |
| 3553 | .shutdown = cciss_remove_one, | 3568 | .shutdown = cciss_shutdown, |
| 3554 | }; | 3569 | }; |
| 3555 | 3570 | ||
| 3556 | /* | 3571 | /* |
