drm/radeon/kms/evergreen: fix LUT setup
[safe/jmp/linux-2.6] / drivers / scsi / 3w-xxxx.c
index e1b44d6..f65a1e9 100644 (file)
@@ -6,9 +6,9 @@
                     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>
 
-   Copyright (C) 1999-2007 3ware Inc.
+   Copyright (C) 1999-2009 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
 
 #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>
@@ -484,9 +485,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 +521,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 +534,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 +543,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,
 };
@@ -1026,10 +1032,12 @@ out:
 } /* 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;
 
+       cycle_kernel_lock();
        dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n");
 
        minor_number = iminor(inode);
@@ -1040,7 +1048,7 @@ static int tw_chrdev_open(struct inode *inode, struct file *file)
 } /* End tw_chrdev_open() */
 
 /* File operations struct for character device */
-static struct file_operations tw_fops = {
+static const struct file_operations tw_fops = {
        .owner          = THIS_MODULE,
        .ioctl          = tw_chrdev_ioctl,
        .open           = tw_chrdev_open,
@@ -1273,57 +1281,25 @@ static int tw_map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
        int use_sg;
 
        dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
-       
-       if (cmd->use_sg == 0)
-               return 0;
 
-       use_sg = pci_map_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
-       
-       if (use_sg == 0) {
+       use_sg = scsi_dma_map(cmd);
+       if (use_sg < 0) {
                printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n");
                return 0;
        }
 
        cmd->SCp.phase = TW_PHASE_SGLIST;
        cmd->SCp.have_data_in = use_sg;
-       
+
        return use_sg;
 } /* End tw_map_scsi_sg_data() */
 
-static u32 tw_map_scsi_single_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
-{
-       dma_addr_t mapping;
-
-       dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n");
-
-       if (cmd->request_bufflen == 0)
-               return 0;
-
-       mapping = pci_map_page(pdev, virt_to_page(cmd->request_buffer), offset_in_page(cmd->request_buffer), cmd->request_bufflen, DMA_BIDIRECTIONAL);
-
-       if (mapping == 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data(): pci_map_page() failed.\n");
-               return 0;
-       }
-
-       cmd->SCp.phase = TW_PHASE_SINGLE;
-       cmd->SCp.have_data_in = mapping;
-
-       return mapping;
-} /* End tw_map_scsi_single_data() */
-
 static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
 {
        dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n");
 
-       switch(cmd->SCp.phase) {
-               case TW_PHASE_SINGLE:
-                       pci_unmap_page(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, DMA_BIDIRECTIONAL);
-                       break;
-               case TW_PHASE_SGLIST:
-                       pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
-                       break;
-       }
+       if (cmd->SCp.phase == TW_PHASE_SGLIST)
+               scsi_dma_unmap(cmd);
 } /* End tw_unmap_scsi_data() */
 
 /* This function will reset a device extension */
@@ -1495,31 +1471,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;
-
-       if (cmd->use_sg) {
-               struct scatterlist *sg =
-                       (struct scatterlist *)cmd->request_buffer;
-               local_irq_save(flags);
-               buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
-               transfer_len = min(sg->length, len);
-       } else {
-               buf = cmd->request_buffer;
-               transfer_len = min(cmd->request_bufflen, len);
-       }
-
-       memcpy(buf, data, transfer_len);
-       
-       if (cmd->use_sg) {
-               struct scatterlist *sg;
-
-               sg = (struct scatterlist *)cmd->request_buffer;
-               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 */
@@ -1764,19 +1716,20 @@ static int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
 {
        TW_Command *command_packet;
        unsigned long command_que_value;
-       u32 lba = 0x0, num_sectors = 0x0, buffaddr = 0x0;
+       u32 lba = 0x0, num_sectors = 0x0;
        int i, use_sg;
        struct scsi_cmnd *srb;
-       struct scatterlist *sglist;
+       struct scatterlist *sglist, *sg;
 
        dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write()\n");
 
-       if (tw_dev->srb[request_id]->request_buffer == NULL) {
+       srb = tw_dev->srb[request_id];
+
+       sglist = scsi_sglist(srb);
+       if (!sglist) {
                printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Request buffer NULL.\n");
                return 1;
        }
-       sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
-       srb = tw_dev->srb[request_id];
 
        /* Initialize command packet */
        command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
@@ -1819,33 +1772,18 @@ static int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
        command_packet->byte8.io.lba = lba;
        command_packet->byte6.block_count = num_sectors;
 
-       /* Do this if there are no sg list entries */
-       if (tw_dev->srb[request_id]->use_sg == 0) {    
-               dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
-               buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
-               if (buffaddr == 0)
-                       return 1;
+       use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+       if (!use_sg)
+               return 1;
 
-               command_packet->byte8.io.sgl[0].address = buffaddr;
-               command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+       scsi_for_each_sg(tw_dev->srb[request_id], sg, use_sg, i) {
+               command_packet->byte8.io.sgl[i].address = sg_dma_address(sg);
+               command_packet->byte8.io.sgl[i].length = sg_dma_len(sg);
                command_packet->size+=2;
        }
 
-       /* Do this if we have multiple sg list entries */
-       if (tw_dev->srb[request_id]->use_sg > 0) {
-               use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
-               if (use_sg == 0)
-                       return 1;
-
-               for (i=0;i<use_sg; i++) {
-                       command_packet->byte8.io.sgl[i].address = sg_dma_address(&sglist[i]);
-                       command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
-                       command_packet->size+=2;
-               }
-       }
-
        /* Update SG statistics */
-       tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
+       tw_dev->sgl_entries = scsi_sg_count(tw_dev->srb[request_id]);
        if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
                tw_dev->max_sgl_entries = tw_dev->sgl_entries;
 
@@ -1864,10 +1802,17 @@ static int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
 /* This function will handle the request sense scsi command */
 static int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
 {
+       char request_buffer[18];
+
        dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
 
-       /* For now we just zero the request buffer */
-       memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+       memset(request_buffer, 0, sizeof(request_buffer));
+       request_buffer[0] = 0x70; /* Immediate fixed format */
+       request_buffer[7] = 10; /* minimum size per SPC: 18 bytes */
+       /* leave all other fields zero, giving effectively NO_SENSE return */
+       tw_transfer_internal(tw_dev, request_id, request_buffer,
+                            sizeof(request_buffer));
+
        tw_dev->state[request_id] = TW_S_COMPLETED;
        tw_state_request_finish(tw_dev, request_id);
 
@@ -2345,8 +2290,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;