]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/3w-9xxx.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc-merge
[linux-2.6-omap-h63xx.git] / drivers / scsi / 3w-9xxx.c
index a6ac61611f35296c2a1d4402940075d10e38dc0a..d9152d02088c81bb4c498360d5ed7232f10718dd 100644 (file)
@@ -60,6 +60,8 @@
                  Remove un-needed eh_abort handler.
                  Add support for embedded firmware error strings.
    2.26.02.003 - Correctly handle single sgl's with use_sg=1.
+   2.26.02.004 - Add support for 9550SX controllers.
+   2.26.02.005 - Fix use_sg == 0 mapping on systems with 4GB or higher.
 */
 
 #include <linux/module.h>
@@ -72,6 +74,7 @@
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
@@ -82,7 +85,7 @@
 #include "3w-9xxx.h"
 
 /* Globals */
-#define TW_DRIVER_VERSION "2.26.02.003"
+#define TW_DRIVER_VERSION "2.26.02.005"
 static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
 static unsigned int twa_device_extension_count;
 static int twa_major = -1;
@@ -614,7 +617,7 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
        void __user *argp = (void __user *)arg;
 
        /* Only let one of these through at a time */
-       if (down_interruptible(&tw_dev->ioctl_sem)) {
+       if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) {
                retval = TW_IOCTL_ERROR_OS_EINTR;
                goto out;
        }
@@ -851,7 +854,7 @@ out3:
        /* Now free ioctl buf memory */
        dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
 out2:
-       up(&tw_dev->ioctl_sem);
+       mutex_unlock(&tw_dev->ioctl_lock);
 out:
        return retval;
 } /* End twa_chrdev_ioctl() */
@@ -892,11 +895,6 @@ static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value)
                writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
        }
 
-       if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) {
-               TW_PRINTK(tw_dev->host, TW_DRIVER, 0xf, "SBUF Write Error: clearing");
-               writel(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
-       }
-
        if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {
                if (tw_dev->reset_print == 0) {
                        TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Microcontroller Error: clearing");
@@ -930,6 +928,36 @@ out:
        return retval;
 } /* End twa_empty_response_queue() */
 
+/* This function will clear the pchip/response queue on 9550SX */
+static int twa_empty_response_queue_large(TW_Device_Extension *tw_dev)
+{
+       u32 status_reg_value, response_que_value;
+       int count = 0, retval = 1;
+
+       if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9550SX) {
+               status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+               while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) {
+                       response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev));
+                       if ((response_que_value & TW_9550SX_DRAIN_COMPLETED) == TW_9550SX_DRAIN_COMPLETED) {
+                               /* P-chip settle time */
+                               msleep(500);
+                               retval = 0;
+                               goto out;
+                       }
+                       status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+                       count++;
+               }
+               if (count == TW_MAX_RESPONSE_DRAIN)
+                       goto out;
+               
+               retval = 0;
+       } else
+               retval = 0;
+out:
+       return retval;
+} /* End twa_empty_response_queue_large() */
+
 /* This function passes sense keys from firmware to scsi layer */
 static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host)
 {
@@ -991,8 +1019,7 @@ static void twa_free_device_extension(TW_Device_Extension *tw_dev)
                                    tw_dev->generic_buffer_virt[0],
                                    tw_dev->generic_buffer_phys[0]);
 
-       if (tw_dev->event_queue[0])
-               kfree(tw_dev->event_queue[0]);
+       kfree(tw_dev->event_queue[0]);
 } /* End twa_free_device_extension() */
 
 /* This function will free a request id */
@@ -1157,7 +1184,7 @@ static int twa_initialize_device_extension(TW_Device_Extension *tw_dev)
        tw_dev->error_sequence_id = 1;
        tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
 
-       init_MUTEX(&tw_dev->ioctl_sem);
+       mutex_init(&tw_dev->ioctl_lock);
        init_waitqueue_head(&tw_dev->ioctl_wqueue);
 
        retval = 0;
@@ -1382,7 +1409,7 @@ static dma_addr_t twa_map_scsi_single_data(TW_Device_Extension *tw_dev, int requ
        dma_addr_t mapping;
        struct scsi_cmnd *cmd = tw_dev->srb[request_id];
        struct pci_dev *pdev = tw_dev->tw_pci_dev;
-       int retval = 0;
+       dma_addr_t retval = 0;
 
        if (cmd->request_bufflen == 0) {
                retval = 0;
@@ -1613,8 +1640,16 @@ static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset)
        int tries = 0, retval = 1, flashed = 0, do_soft_reset = soft_reset;
 
        while (tries < TW_MAX_RESET_TRIES) {
-               if (do_soft_reset)
+               if (do_soft_reset) {
                        TW_SOFT_RESET(tw_dev);
+                       /* Clear pchip/response queue on 9550SX */
+                       if (twa_empty_response_queue_large(tw_dev)) {
+                               TW_PRINTK(tw_dev->host, TW_DRIVER, 0x36, "Response queue (large) empty failed during reset sequence");
+                               do_soft_reset = 1;
+                               tries++;
+                               continue;
+                       }
+               }
 
                /* Make sure controller is in a good state */
                if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 60)) {
@@ -1698,7 +1733,9 @@ static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
 
        tw_dev->num_resets++;
 
-       printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Unit #%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, TW_DRIVER, 0x2c, SCpnt->device->id, SCpnt->cmnd[0]);
+       sdev_printk(KERN_WARNING, SCpnt->device,
+               "WARNING: (0x%02X:0x%04X): Command (0x%x) timed out, resetting card.\n",
+               TW_DRIVER, 0x2c, SCpnt->cmnd[0]);
 
        /* Now reset the card and some of the device extension data */
        if (twa_reset_device_extension(tw_dev, 0)) {
@@ -1762,7 +1799,7 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
        int i, sg_count;
        struct scsi_cmnd *srb = NULL;
        struct scatterlist *sglist = NULL;
-       u32 buffaddr = 0x0;
+       dma_addr_t buffaddr = 0x0;
        int retval = 1;
 
        if (tw_dev->srb[request_id]) {
@@ -2034,7 +2071,10 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
                goto out_free_device_extension;
        }
 
-       mem_addr = pci_resource_start(pdev, 1);
+       if (pdev->device == PCI_DEVICE_ID_3WARE_9000)
+               mem_addr = pci_resource_start(pdev, 1);
+       else
+               mem_addr = pci_resource_start(pdev, 2);
 
        /* Save base address */
        tw_dev->base_addr = ioremap(mem_addr, PAGE_SIZE);
@@ -2148,6 +2188,8 @@ static void twa_remove(struct pci_dev *pdev)
 static struct pci_device_id twa_pci_tbl[] __devinitdata = {
        { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9550SX,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        { }
 };
 MODULE_DEVICE_TABLE(pci, twa_pci_tbl);