aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/3w-xxxx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/3w-xxxx.c')
-rw-r--r--drivers/scsi/3w-xxxx.c74
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,