diff options
Diffstat (limited to 'drivers/scsi/3w-xxxx.c')
| -rw-r--r-- | drivers/scsi/3w-xxxx.c | 74 |
1 files changed, 48 insertions, 26 deletions
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index a0537f09aa2..752624e6bc0 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1,14 +1,14 @@ /* 3w-xxxx.c -- 3ware Storage Controller device driver for Linux. - Written By: Adam Radford <linuxraid@amcc.com> + Written By: Adam Radford <linuxraid@lsi.com> Modifications By: Joel Jacobson <linux@3ware.com> Arnaldo Carvalho de Melo <acme@conectiva.com.br> Brad Strand <linux@3ware.com> - Copyright (C) 1999-2007 3ware Inc. + Copyright (C) 1999-2010 3ware Inc. - Kernel compatiblity By: Andre Hedrick <andre@suse.com> + Kernel compatibility By: Andre Hedrick <andre@suse.com> Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com> Further tiny build fixes and trivial hoovering Alan Cox @@ -47,10 +47,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Bugs/Comments/Suggestions should be mailed to: - linuxraid@amcc.com + linuxraid@lsi.com For more information, goto: - http://www.amcc.com + http://www.lsi.com History ------- @@ -194,17 +194,18 @@ 1.26.02.002 - Free irq handler in __tw_shutdown(). Turn on RCD bit for caching mode page. Serialize reset code. + 1.26.02.003 - Force 60 second timeout default. */ #include <linux/module.h> #include <linux/reboot.h> -#include <linux/smp_lock.h> #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/moduleparam.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/delay.h> +#include <linux/gfp.h> #include <linux/pci.h> #include <linux/time.h> #include <linux/mutex.h> @@ -215,16 +216,18 @@ #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> #include <scsi/scsi_cmnd.h> +#include <scsi/scsi_eh.h> #include "3w-xxxx.h" /* Globals */ -#define TW_DRIVER_VERSION "1.26.02.002" +#define TW_DRIVER_VERSION "1.26.02.003" +static DEFINE_MUTEX(tw_mutex); static TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; static int tw_device_extension_count = 0; static int twe_major = -1; /* Module parameters */ -MODULE_AUTHOR("AMCC"); +MODULE_AUTHOR("LSI"); MODULE_DESCRIPTION("3ware Storage Controller Linux Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(TW_DRIVER_VERSION); @@ -521,8 +524,12 @@ static ssize_t tw_show_stats(struct device *dev, struct device_attribute *attr, } /* End tw_show_stats() */ /* This function will set a devices queue depth */ -static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth) +static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth, + int reason) { + if (reason != SCSI_QDEPTH_DEFAULT) + return -EOPNOTSUPP; + if (queue_depth > TW_Q_LENGTH-2) queue_depth = TW_Q_LENGTH-2; scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); @@ -875,7 +882,7 @@ static int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which) } /* End tw_allocate_memory() */ /* This function handles ioctl for the character device */ -static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static long tw_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int request_id; dma_addr_t dma_handle; @@ -883,6 +890,7 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int unsigned long flags; unsigned int data_buffer_length = 0; unsigned long data_buffer_length_adjusted = 0; + struct inode *inode = file_inode(file); unsigned long *cpu_addr; long timeout; TW_New_Ioctl *tw_ioctl; @@ -893,9 +901,12 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl()\n"); + mutex_lock(&tw_mutex); /* Only let one of these through at a time */ - if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) + if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) { + mutex_unlock(&tw_mutex); return -EINTR; + } /* First copy down the buffer length */ if (copy_from_user(&data_buffer_length, argp, sizeof(unsigned int))) @@ -1024,6 +1035,7 @@ out2: dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle); out: mutex_unlock(&tw_dev->ioctl_lock); + mutex_unlock(&tw_mutex); return retval; } /* End tw_chrdev_ioctl() */ @@ -1033,7 +1045,6 @@ static int tw_chrdev_open(struct inode *inode, struct file *file) { unsigned int minor_number; - cycle_kernel_lock(); dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n"); minor_number = iminor(inode); @@ -1046,9 +1057,10 @@ static int tw_chrdev_open(struct inode *inode, struct file *file) /* File operations struct for character device */ static const struct file_operations tw_fops = { .owner = THIS_MODULE, - .ioctl = tw_chrdev_ioctl, + .unlocked_ioctl = tw_chrdev_ioctl, .open = tw_chrdev_open, - .release = NULL + .release = NULL, + .llseek = noop_llseek, }; /* This function will free up device extension resources */ @@ -1294,7 +1306,8 @@ static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd) { dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n"); - scsi_dma_unmap(cmd); + if (cmd->SCp.phase == TW_PHASE_SGLIST) + scsi_dma_unmap(cmd); } /* End tw_unmap_scsi_data() */ /* This function will reset a device extension */ @@ -1466,12 +1479,7 @@ static int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id) static void tw_transfer_internal(TW_Device_Extension *tw_dev, int request_id, void *data, unsigned int len) { - struct scsi_cmnd *cmd = tw_dev->srb[request_id]; - unsigned long flags; - - local_irq_save(flags); - scsi_sg_copy_from_buffer(cmd, data, len); - local_irq_restore(flags); + scsi_sg_copy_from_buffer(tw_dev->srb[request_id], data, len); } /* This function is called by the isr to complete an inquiry command */ @@ -1940,7 +1948,7 @@ static int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int r } /* End tw_scsiop_test_unit_ready_complete() */ /* This is the main scsi queue function to handle scsi opcodes */ -static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) +static int tw_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) { unsigned char *command = SCpnt->cmnd; int request_id = 0; @@ -2002,7 +2010,8 @@ static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd printk(KERN_NOTICE "3w-xxxx: scsi%d: Unknown scsi opcode: 0x%x\n", tw_dev->host->host_no, *command); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); - SCpnt->result = (DID_BAD_TARGET << 16); + SCpnt->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + scsi_build_sense_buffer(1, SCpnt->sense_buffer, ILLEGAL_REQUEST, 0x20, 0); done(SCpnt); retval = 0; } @@ -2016,6 +2025,8 @@ static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd return retval; } /* End tw_scsi_queue() */ +static DEF_SCSI_QCMD(tw_scsi_queue) + /* This function is the interrupt service routine */ static irqreturn_t tw_interrupt(int irq, void *dev_instance) { @@ -2244,6 +2255,15 @@ static void tw_shutdown(struct pci_dev *pdev) __tw_shutdown(tw_dev); } /* End tw_shutdown() */ +/* This function gets called when a disk is coming online */ +static int tw_slave_configure(struct scsi_device *sdev) +{ + /* Force 60 second timeout */ + blk_queue_rq_timeout(sdev->request_queue, 60 * HZ); + + return 0; +} /* End tw_slave_configure() */ + static struct scsi_host_template driver_template = { .module = THIS_MODULE, .name = "3ware Storage Controller", @@ -2252,17 +2272,19 @@ static struct scsi_host_template driver_template = { .bios_param = tw_scsi_biosparam, .change_queue_depth = tw_change_queue_depth, .can_queue = TW_Q_LENGTH-2, + .slave_configure = tw_slave_configure, .this_id = -1, .sg_tablesize = TW_MAX_SGL_LENGTH, .max_sectors = TW_MAX_SECTORS, .cmd_per_lun = TW_MAX_CMDS_PER_LUN, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = tw_host_attrs, - .emulated = 1 + .emulated = 1, + .no_write_same = 1, }; /* This function will probe and initialize a card */ -static int __devinit tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) +static int tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) { struct Scsi_Host *host = NULL; TW_Device_Extension *tw_dev; @@ -2403,7 +2425,7 @@ static void tw_remove(struct pci_dev *pdev) } /* End tw_remove() */ /* PCI Devices supported by this driver */ -static struct pci_device_id tw_pci_tbl[] __devinitdata = { +static struct pci_device_id tw_pci_tbl[] = { { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_7000, |
