diff options
Diffstat (limited to 'drivers/scsi/3w-xxxx.c')
-rw-r--r-- | drivers/scsi/3w-xxxx.c | 60 |
1 files changed, 29 insertions, 31 deletions
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 99a259c5a0c0..e1b44d6c0c32 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c | |||
@@ -6,7 +6,7 @@ | |||
6 | Arnaldo Carvalho de Melo <acme@conectiva.com.br> | 6 | Arnaldo Carvalho de Melo <acme@conectiva.com.br> |
7 | Brad Strand <linux@3ware.com> | 7 | Brad Strand <linux@3ware.com> |
8 | 8 | ||
9 | Copyright (C) 1999-2005 3ware Inc. | 9 | Copyright (C) 1999-2007 3ware Inc. |
10 | 10 | ||
11 | Kernel compatiblity By: Andre Hedrick <andre@suse.com> | 11 | Kernel compatiblity By: Andre Hedrick <andre@suse.com> |
12 | Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com> | 12 | Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com> |
@@ -191,6 +191,9 @@ | |||
191 | before shutting down card. | 191 | before shutting down card. |
192 | Change to new 'change_queue_depth' api. | 192 | Change to new 'change_queue_depth' api. |
193 | Fix 'handled=1' ISR usage, remove bogus IRQ check. | 193 | Fix 'handled=1' ISR usage, remove bogus IRQ check. |
194 | 1.26.02.002 - Free irq handler in __tw_shutdown(). | ||
195 | Turn on RCD bit for caching mode page. | ||
196 | Serialize reset code. | ||
194 | */ | 197 | */ |
195 | 198 | ||
196 | #include <linux/module.h> | 199 | #include <linux/module.h> |
@@ -214,7 +217,7 @@ | |||
214 | #include "3w-xxxx.h" | 217 | #include "3w-xxxx.h" |
215 | 218 | ||
216 | /* Globals */ | 219 | /* Globals */ |
217 | #define TW_DRIVER_VERSION "1.26.02.001" | 220 | #define TW_DRIVER_VERSION "1.26.02.002" |
218 | static TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; | 221 | static TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; |
219 | static int tw_device_extension_count = 0; | 222 | static int tw_device_extension_count = 0; |
220 | static int twe_major = -1; | 223 | static int twe_major = -1; |
@@ -226,7 +229,7 @@ MODULE_LICENSE("GPL"); | |||
226 | MODULE_VERSION(TW_DRIVER_VERSION); | 229 | MODULE_VERSION(TW_DRIVER_VERSION); |
227 | 230 | ||
228 | /* Function prototypes */ | 231 | /* Function prototypes */ |
229 | static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset); | 232 | static int tw_reset_device_extension(TW_Device_Extension *tw_dev); |
230 | 233 | ||
231 | /* Functions */ | 234 | /* Functions */ |
232 | 235 | ||
@@ -984,24 +987,12 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int | |||
984 | /* Now wait for the command to complete */ | 987 | /* Now wait for the command to complete */ |
985 | timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout); | 988 | timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout); |
986 | 989 | ||
987 | /* See if we reset while waiting for the ioctl to complete */ | ||
988 | if (test_bit(TW_IN_RESET, &tw_dev->flags)) { | ||
989 | clear_bit(TW_IN_RESET, &tw_dev->flags); | ||
990 | retval = -ERESTARTSYS; | ||
991 | goto out2; | ||
992 | } | ||
993 | |||
994 | /* We timed out, and didn't get an interrupt */ | 990 | /* We timed out, and didn't get an interrupt */ |
995 | if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) { | 991 | if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) { |
996 | /* Now we need to reset the board */ | 992 | /* Now we need to reset the board */ |
997 | printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd); | 993 | printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd); |
998 | retval = -EIO; | 994 | retval = -EIO; |
999 | spin_lock_irqsave(tw_dev->host->host_lock, flags); | 995 | if (tw_reset_device_extension(tw_dev)) { |
1000 | tw_dev->state[request_id] = TW_S_COMPLETED; | ||
1001 | tw_state_request_finish(tw_dev, request_id); | ||
1002 | tw_dev->posted_request_count--; | ||
1003 | spin_unlock_irqrestore(tw_dev->host->host_lock, flags); | ||
1004 | if (tw_reset_device_extension(tw_dev, 1)) { | ||
1005 | printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no); | 996 | printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no); |
1006 | } | 997 | } |
1007 | goto out2; | 998 | goto out2; |
@@ -1336,7 +1327,7 @@ static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd) | |||
1336 | } /* End tw_unmap_scsi_data() */ | 1327 | } /* End tw_unmap_scsi_data() */ |
1337 | 1328 | ||
1338 | /* This function will reset a device extension */ | 1329 | /* This function will reset a device extension */ |
1339 | static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset) | 1330 | static int tw_reset_device_extension(TW_Device_Extension *tw_dev) |
1340 | { | 1331 | { |
1341 | int i = 0; | 1332 | int i = 0; |
1342 | struct scsi_cmnd *srb; | 1333 | struct scsi_cmnd *srb; |
@@ -1382,15 +1373,10 @@ static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_rese | |||
1382 | printk(KERN_WARNING "3w-xxxx: scsi%d: Reset sequence failed.\n", tw_dev->host->host_no); | 1373 | printk(KERN_WARNING "3w-xxxx: scsi%d: Reset sequence failed.\n", tw_dev->host->host_no); |
1383 | return 1; | 1374 | return 1; |
1384 | } | 1375 | } |
1385 | TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); | ||
1386 | 1376 | ||
1387 | /* Wake up any ioctl that was pending before the reset */ | 1377 | TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); |
1388 | if ((tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE) || (ioctl_reset)) { | 1378 | clear_bit(TW_IN_RESET, &tw_dev->flags); |
1389 | clear_bit(TW_IN_RESET, &tw_dev->flags); | 1379 | tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; |
1390 | } else { | ||
1391 | tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; | ||
1392 | wake_up(&tw_dev->ioctl_wqueue); | ||
1393 | } | ||
1394 | 1380 | ||
1395 | return 0; | 1381 | return 0; |
1396 | } /* End tw_reset_device_extension() */ | 1382 | } /* End tw_reset_device_extension() */ |
@@ -1437,14 +1423,18 @@ static int tw_scsi_eh_reset(struct scsi_cmnd *SCpnt) | |||
1437 | "WARNING: Command (0x%x) timed out, resetting card.\n", | 1423 | "WARNING: Command (0x%x) timed out, resetting card.\n", |
1438 | SCpnt->cmnd[0]); | 1424 | SCpnt->cmnd[0]); |
1439 | 1425 | ||
1426 | /* Make sure we are not issuing an ioctl or resetting from ioctl */ | ||
1427 | mutex_lock(&tw_dev->ioctl_lock); | ||
1428 | |||
1440 | /* Now reset the card and some of the device extension data */ | 1429 | /* Now reset the card and some of the device extension data */ |
1441 | if (tw_reset_device_extension(tw_dev, 0)) { | 1430 | if (tw_reset_device_extension(tw_dev)) { |
1442 | printk(KERN_WARNING "3w-xxxx: scsi%d: Reset failed.\n", tw_dev->host->host_no); | 1431 | printk(KERN_WARNING "3w-xxxx: scsi%d: Reset failed.\n", tw_dev->host->host_no); |
1443 | goto out; | 1432 | goto out; |
1444 | } | 1433 | } |
1445 | 1434 | ||
1446 | retval = SUCCESS; | 1435 | retval = SUCCESS; |
1447 | out: | 1436 | out: |
1437 | mutex_unlock(&tw_dev->ioctl_lock); | ||
1448 | return retval; | 1438 | return retval; |
1449 | } /* End tw_scsi_eh_reset() */ | 1439 | } /* End tw_scsi_eh_reset() */ |
1450 | 1440 | ||
@@ -1660,9 +1650,9 @@ static int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int reques | |||
1660 | request_buffer[4] = 0x8; /* caching page */ | 1650 | request_buffer[4] = 0x8; /* caching page */ |
1661 | request_buffer[5] = 0xa; /* page length */ | 1651 | request_buffer[5] = 0xa; /* page length */ |
1662 | if (*flags & 0x1) | 1652 | if (*flags & 0x1) |
1663 | request_buffer[6] = 0x4; /* WCE on */ | 1653 | request_buffer[6] = 0x5; /* WCE on, RCD on */ |
1664 | else | 1654 | else |
1665 | request_buffer[6] = 0x0; /* WCE off */ | 1655 | request_buffer[6] = 0x1; /* WCE off, RCD on */ |
1666 | tw_transfer_internal(tw_dev, request_id, request_buffer, | 1656 | tw_transfer_internal(tw_dev, request_id, request_buffer, |
1667 | sizeof(request_buffer)); | 1657 | sizeof(request_buffer)); |
1668 | 1658 | ||
@@ -2012,6 +2002,10 @@ static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd | |||
2012 | int retval = 1; | 2002 | int retval = 1; |
2013 | TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; | 2003 | TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; |
2014 | 2004 | ||
2005 | /* If we are resetting due to timed out ioctl, report as busy */ | ||
2006 | if (test_bit(TW_IN_RESET, &tw_dev->flags)) | ||
2007 | return SCSI_MLQUEUE_HOST_BUSY; | ||
2008 | |||
2015 | /* Save done function into Scsi_Cmnd struct */ | 2009 | /* Save done function into Scsi_Cmnd struct */ |
2016 | SCpnt->scsi_done = done; | 2010 | SCpnt->scsi_done = done; |
2017 | 2011 | ||
@@ -2100,6 +2094,10 @@ static irqreturn_t tw_interrupt(int irq, void *dev_instance) | |||
2100 | 2094 | ||
2101 | handled = 1; | 2095 | handled = 1; |
2102 | 2096 | ||
2097 | /* If we are resetting, bail */ | ||
2098 | if (test_bit(TW_IN_RESET, &tw_dev->flags)) | ||
2099 | goto tw_interrupt_bail; | ||
2100 | |||
2103 | /* Check controller for errors */ | 2101 | /* Check controller for errors */ |
2104 | if (tw_check_bits(status_reg_value)) { | 2102 | if (tw_check_bits(status_reg_value)) { |
2105 | dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); | 2103 | dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); |
@@ -2276,6 +2274,9 @@ static void __tw_shutdown(TW_Device_Extension *tw_dev) | |||
2276 | /* Disable interrupts */ | 2274 | /* Disable interrupts */ |
2277 | TW_DISABLE_INTERRUPTS(tw_dev); | 2275 | TW_DISABLE_INTERRUPTS(tw_dev); |
2278 | 2276 | ||
2277 | /* Free up the IRQ */ | ||
2278 | free_irq(tw_dev->tw_pci_dev->irq, tw_dev); | ||
2279 | |||
2279 | printk(KERN_WARNING "3w-xxxx: Shutting down host %d.\n", tw_dev->host->host_no); | 2280 | printk(KERN_WARNING "3w-xxxx: Shutting down host %d.\n", tw_dev->host->host_no); |
2280 | 2281 | ||
2281 | /* Tell the card we are shutting down */ | 2282 | /* Tell the card we are shutting down */ |
@@ -2444,9 +2445,6 @@ static void tw_remove(struct pci_dev *pdev) | |||
2444 | twe_major = -1; | 2445 | twe_major = -1; |
2445 | } | 2446 | } |
2446 | 2447 | ||
2447 | /* Free up the IRQ */ | ||
2448 | free_irq(tw_dev->tw_pci_dev->irq, tw_dev); | ||
2449 | |||
2450 | /* Shutdown the card */ | 2448 | /* Shutdown the card */ |
2451 | __tw_shutdown(tw_dev); | 2449 | __tw_shutdown(tw_dev); |
2452 | 2450 | ||