| From stable-bounces@linux.kernel.org Sat May 19 10:21:58 2007 |
| From: Gerald Britton <gbritton@alum.mit.edu> |
| Date: Sat, 19 May 2007 10:18:22 -0700 |
| Subject: cciss: fix pci_driver.shutdown while device is still active |
| To: gbritton@alum.mit.edu, mike.miller@hp.com, stable@kernel.org, mm-commits@vger.kernel.org |
| Message-ID: <200705191718.l4JHILKW007005@shell0.pdx.osdl.net> |
| |
| From: Gerald Britton <gbritton@alum.mit.edu> |
| |
| 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: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| Signed-off-by: Chris Wright <chrisw@sous-sol.org> |
| |
| |
| --- |
| drivers/block/cciss.c | 45 ++++++++++++++++++++++++++++++--------------- |
| 1 file changed, 30 insertions(+), 15 deletions(-) |
| |
| --- linux-2.6.21.4.orig/drivers/block/cciss.c |
| +++ linux-2.6.21.4/drivers/block/cciss.c |
| @@ -3405,13 +3405,39 @@ static int __devinit cciss_init_one(stru |
| return -1; |
| } |
| |
| -static void cciss_remove_one(struct pci_dev *pdev) |
| +static void cciss_shutdown(struct pci_dev *pdev) |
| { |
| ctlr_info_t *tmp_ptr; |
| - int i, j; |
| + int i; |
| char flush_buf[4]; |
| int return_code; |
| |
| + tmp_ptr = pci_get_drvdata(pdev); |
| + if (tmp_ptr == NULL) |
| + return; |
| + i = tmp_ptr->ctlr; |
| + if (hba[i] == NULL) |
| + return; |
| + |
| + /* Turn board interrupts off and send the flush cache command */ |
| + /* sendcmd will turn off interrupt, and send the flush... |
| + * To write all data in the battery backed cache to disks */ |
| + memset(flush_buf, 0, 4); |
| + return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL, |
| + TYPE_CMD); |
| + if (return_code == IO_OK) { |
| + printk(KERN_INFO "Completed flushing cache on controller %d\n", i); |
| + } else { |
| + printk(KERN_WARNING "Error flushing cache on controller %d\n", i); |
| + } |
| + free_irq(hba[i]->intr[2], hba[i]); |
| +} |
| + |
| +static void __devexit cciss_remove_one(struct pci_dev *pdev) |
| +{ |
| + ctlr_info_t *tmp_ptr; |
| + int i, j; |
| + |
| if (pci_get_drvdata(pdev) == NULL) { |
| printk(KERN_ERR "cciss: Unable to remove device \n"); |
| return; |
| @@ -3442,18 +3468,7 @@ static void cciss_remove_one(struct pci_ |
| |
| cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ |
| |
| - /* Turn board interrupts off and send the flush cache command */ |
| - /* sendcmd will turn off interrupt, and send the flush... |
| - * To write all data in the battery backed cache to disks */ |
| - memset(flush_buf, 0, 4); |
| - return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL, |
| - TYPE_CMD); |
| - if (return_code == IO_OK) { |
| - printk(KERN_INFO "Completed flushing cache on controller %d\n", i); |
| - } else { |
| - printk(KERN_WARNING "Error flushing cache on controller %d\n", i); |
| - } |
| - free_irq(hba[i]->intr[2], hba[i]); |
| + cciss_shutdown(pdev); |
| |
| #ifdef CONFIG_PCI_MSI |
| if (hba[i]->msix_vector) |
| @@ -3486,7 +3501,7 @@ static struct pci_driver cciss_pci_drive |
| .probe = cciss_init_one, |
| .remove = __devexit_p(cciss_remove_one), |
| .id_table = cciss_pci_device_id, /* id_table */ |
| - .shutdown = cciss_remove_one, |
| + .shutdown = cciss_shutdown, |
| }; |
| |
| /* |