config: tegra3: enable /dev mount with ACL
[linux-2.6.git] / drivers / scsi / 3w-xxxx.c
index d095321..7fe96ff 100644 (file)
@@ -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
    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
    -------
    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/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>
 #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);
@@ -484,9 +487,10 @@ static void tw_state_request_start(TW_Device_Extension *tw_dev, int *request_id)
 } /* End tw_state_request_start() */
 
 /* Show some statistics about the card */
-static ssize_t tw_show_stats(struct class_device *class_dev, char *buf)
+static ssize_t tw_show_stats(struct device *dev, struct device_attribute *attr,
+                            char *buf)
 {
-       struct Scsi_Host *host = class_to_shost(class_dev);
+       struct Scsi_Host *host = class_to_shost(dev);
        TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
        unsigned long flags = 0;
        ssize_t len;
@@ -519,8 +523,12 @@ static ssize_t tw_show_stats(struct class_device *class_dev, char *buf)
 } /* 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);
@@ -528,7 +536,7 @@ static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth)
 } /* End tw_change_queue_depth() */
 
 /* Create sysfs 'stats' entry */
-static struct class_device_attribute tw_host_stats_attr = {
+static struct device_attribute tw_host_stats_attr = {
        .attr = {
                .name =         "stats",
                .mode =         S_IRUGO,
@@ -537,7 +545,7 @@ static struct class_device_attribute tw_host_stats_attr = {
 };
 
 /* Host attributes initializer */
-static struct class_device_attribute *tw_host_attrs[] = {
+static struct device_attribute *tw_host_attrs[] = {
        &tw_host_stats_attr,
        NULL,
 };
@@ -873,7 +881,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;
@@ -881,6 +889,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->f_dentry->d_inode;
        unsigned long *cpu_addr;
        long timeout;
        TW_New_Ioctl *tw_ioctl;
@@ -891,9 +900,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)))
@@ -1022,10 +1034,12 @@ 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() */
 
 /* This function handles open for the character device */
+/* NOTE that this function races with remove. */
 static int tw_chrdev_open(struct inode *inode, struct file *file)
 {
        unsigned int minor_number;
@@ -1042,9 +1056,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 */
@@ -1290,7 +1305,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 */
@@ -1462,20 +1478,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];
-       void *buf;
-       unsigned int transfer_len;
-       unsigned long flags = 0;
-       struct scatterlist *sg = scsi_sglist(cmd);
-
-       local_irq_save(flags);
-       buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
-       transfer_len = min(sg->length, len);
-
-       memcpy(buf, data, transfer_len);
-
-       kunmap_atomic(buf - sg->offset, KM_IRQ0);
-       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 */
@@ -1944,7 +1947,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;
@@ -2020,6 +2023,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) 
 {
@@ -2248,6 +2253,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",
@@ -2256,6 +2270,7 @@ 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,
@@ -2294,8 +2309,6 @@ static int __devinit tw_probe(struct pci_dev *pdev, const struct pci_device_id *
        }
        tw_dev = (TW_Device_Extension *)host->hostdata;
 
-       memset(tw_dev, 0, sizeof(TW_Device_Extension));
-
        /* Save values to device extension */
        tw_dev->host = host;
        tw_dev->tw_pci_dev = pdev;