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 | /* |