basic modification from way back
[powerpc.git] / drivers / scsi / stex.c
index ea0d824..69be132 100644 (file)
  *     Written By:
  *             Ed Lin <promise_linux@promise.com>
  *
- *     Version: 3.0.0.1
- *
  */
 
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
-#include <linux/sched.h>
 #include <linux/time.h>
 #include <linux/pci.h>
 #include <linux/blkdev.h>
@@ -37,9 +34,9 @@
 #include <scsi/scsi_tcq.h>
 
 #define DRV_NAME "stex"
-#define ST_DRIVER_VERSION "3.0.0.1"
+#define ST_DRIVER_VERSION "3.1.0.1"
 #define ST_VER_MAJOR           3
-#define ST_VER_MINOR           0
+#define ST_VER_MINOR           1
 #define ST_OEM                         0
 #define ST_BUILD_VER           1
 
@@ -76,8 +73,10 @@ enum {
        MU_STATE_STARTED                        = 4,
        MU_STATE_RESETTING                      = 5,
 
-       MU_MAX_DELAY_TIME                       = 240000,
+       MU_MAX_DELAY                            = 120,
        MU_HANDSHAKE_SIGNATURE                  = 0x55aaaa55,
+       MU_HANDSHAKE_SIGNATURE_HALF             = 0x5a5a0000,
+       MU_HARD_RESET_WAIT                      = 30000,
        HMU_PARTNER_TYPE                        = 2,
 
        /* firmware returned values */
@@ -120,7 +119,8 @@ enum {
 
        st_shasta                               = 0,
        st_vsc                                  = 1,
-       st_yosemite                             = 2,
+       st_vsc1                                 = 2,
+       st_yosemite                             = 3,
 
        PASSTHRU_REQ_TYPE                       = 0x00000001,
        PASSTHRU_REQ_NO_WAKEUP                  = 0x00000100,
@@ -150,6 +150,8 @@ enum {
        MGT_CMD_SIGNATURE                       = 0xba,
 
        INQUIRY_EVPD                            = 0x01,
+
+       ST_ADDITIONAL_MEM                       = 0x200000,
 };
 
 /* SCSI inquiry data */
@@ -211,7 +213,9 @@ struct handshake_frame {
        __le32 partner_ver_minor;
        __le32 partner_ver_oem;
        __le32 partner_ver_build;
-       u32 reserved1[4];
+       __le32 extra_offset;    /* NEW */
+       __le32 extra_size;      /* NEW */
+       u32 reserved1[2];
 };
 
 struct req_msg {
@@ -302,6 +306,7 @@ struct st_hba {
        void __iomem *mmio_base;        /* iomapped PCI memory space */
        void *dma_mem;
        dma_addr_t dma_handle;
+       size_t dma_size;
 
        struct Scsi_Host *host;
        struct pci_dev *pdev;
@@ -902,27 +907,34 @@ static int stex_handshake(struct st_hba *hba)
        void __iomem *base = hba->mmio_base;
        struct handshake_frame *h;
        dma_addr_t status_phys;
-       int i;
+       u32 data;
+       unsigned long before;
 
        if (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) {
                writel(MU_INBOUND_DOORBELL_HANDSHAKE, base + IDBL);
                readl(base + IDBL);
-               for (i = 0; readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE
-                       && i < MU_MAX_DELAY_TIME; i++) {
+               before = jiffies;
+               while (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) {
+                       if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) {
+                               printk(KERN_ERR DRV_NAME
+                                       "(%s): no handshake signature\n",
+                                       pci_name(hba->pdev));
+                               return -1;
+                       }
                        rmb();
                        msleep(1);
                }
-
-               if (i == MU_MAX_DELAY_TIME) {
-                       printk(KERN_ERR DRV_NAME
-                               "(%s): no handshake signature\n",
-                               pci_name(hba->pdev));
-                       return -1;
-               }
        }
 
        udelay(10);
 
+       data = readl(base + OMR1);
+       if ((data & 0xffff0000) == MU_HANDSHAKE_SIGNATURE_HALF) {
+               data &= 0x0000ffff;
+               if (hba->host->can_queue > data)
+                       hba->host->can_queue = data;
+       }
+
        h = (struct handshake_frame *)(hba->dma_mem + MU_REQ_BUFFER_SIZE);
        h->rb_phy = cpu_to_le32(hba->dma_handle);
        h->rb_phy_hi = cpu_to_le32((hba->dma_handle >> 16) >> 16);
@@ -932,6 +944,11 @@ static int stex_handshake(struct st_hba *hba)
        h->status_cnt = cpu_to_le16(MU_STATUS_COUNT);
        stex_gettime(&h->hosttime);
        h->partner_type = HMU_PARTNER_TYPE;
+       if (hba->dma_size > STEX_BUFFER_SIZE) {
+               h->extra_offset = cpu_to_le32(STEX_BUFFER_SIZE);
+               h->extra_size = cpu_to_le32(ST_ADDITIONAL_MEM);
+       } else
+               h->extra_offset = h->extra_size = 0;
 
        status_phys = hba->dma_handle + MU_REQ_BUFFER_SIZE;
        writel(status_phys, base + IMR0);
@@ -945,19 +962,18 @@ static int stex_handshake(struct st_hba *hba)
        readl(base + IDBL); /* flush */
 
        udelay(10);
-       for (i = 0; readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE
-               && i < MU_MAX_DELAY_TIME; i++) {
+       before = jiffies;
+       while (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) {
+               if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) {
+                       printk(KERN_ERR DRV_NAME
+                               "(%s): no signature after handshake frame\n",
+                               pci_name(hba->pdev));
+                       return -1;
+               }
                rmb();
                msleep(1);
        }
 
-       if (i == MU_MAX_DELAY_TIME) {
-               printk(KERN_ERR DRV_NAME
-                       "(%s): no signature after handshake frame\n",
-                       pci_name(hba->pdev));
-               return -1;
-       }
-
        writel(0, base + IMR0);
        readl(base + IMR0);
        writel(0, base + OMR0);
@@ -1039,9 +1055,9 @@ static void stex_hard_reset(struct st_hba *hba)
        pci_bctl &= ~PCI_BRIDGE_CTL_BUS_RESET;
        pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl);
 
-       for (i = 0; i < MU_MAX_DELAY_TIME; i++) {
+       for (i = 0; i < MU_HARD_RESET_WAIT; i++) {
                pci_read_config_word(hba->pdev, PCI_COMMAND, &pci_cmd);
-               if (pci_cmd & PCI_COMMAND_MASTER)
+               if (pci_cmd != 0xffff && (pci_cmd & PCI_COMMAND_MASTER))
                        break;
                msleep(1);
        }
@@ -1194,8 +1210,13 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto out_iounmap;
        }
 
+       hba->cardtype = (unsigned int) id->driver_data;
+       if (hba->cardtype == st_vsc && (pdev->subsystem_device & 0xf) == 0x1)
+               hba->cardtype = st_vsc1;
+       hba->dma_size = (hba->cardtype == st_vsc1) ?
+               (STEX_BUFFER_SIZE + ST_ADDITIONAL_MEM) : (STEX_BUFFER_SIZE);
        hba->dma_mem = dma_alloc_coherent(&pdev->dev,
-               STEX_BUFFER_SIZE, &hba->dma_handle, GFP_KERNEL);
+               hba->dma_size, &hba->dma_handle, GFP_KERNEL);
        if (!hba->dma_mem) {
                err = -ENOMEM;
                printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n",
@@ -1208,8 +1229,6 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        hba->copy_buffer = hba->dma_mem + MU_BUFFER_SIZE;
        hba->mu_status = MU_STATE_STARTING;
 
-       hba->cardtype = (unsigned int) id->driver_data;
-
        /* firmware uses id/lun pair for a logical drive, but lun would be
           always 0 if CONFIG_SCSI_MULTI_LUN not configured, so we use
           channel to map lun here */
@@ -1234,7 +1253,7 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (err)
                goto out_free_irq;
 
-       err = scsi_init_shared_tag_map(host, ST_CAN_QUEUE);
+       err = scsi_init_shared_tag_map(host, host->can_queue);
        if (err) {
                printk(KERN_ERR DRV_NAME "(%s): init shared queue failed\n",
                        pci_name(pdev));
@@ -1257,7 +1276,7 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 out_free_irq:
        free_irq(pdev->irq, hba);
 out_pci_free:
-       dma_free_coherent(&pdev->dev, STEX_BUFFER_SIZE,
+       dma_free_coherent(&pdev->dev, hba->dma_size,
                          hba->dma_mem, hba->dma_handle);
 out_iounmap:
        iounmap(hba->mmio_base);
@@ -1318,7 +1337,7 @@ static void stex_hba_free(struct st_hba *hba)
 
        pci_release_regions(hba->pdev);
 
-       dma_free_coherent(&hba->pdev->dev, STEX_BUFFER_SIZE,
+       dma_free_coherent(&hba->pdev->dev, hba->dma_size,
                          hba->dma_mem, hba->dma_handle);
 }
 
@@ -1347,15 +1366,32 @@ static void stex_shutdown(struct pci_dev *pdev)
 }
 
 static struct pci_device_id stex_pci_tbl[] = {
-       { 0x105a, 0x8350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
-       { 0x105a, 0xc350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
-       { 0x105a, 0xf350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
-       { 0x105a, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
-       { 0x105a, 0x4302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
-       { 0x105a, 0x8301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
-       { 0x105a, 0x8302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
-       { 0x1725, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc },
-       { 0x105a, 0x8650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_yosemite },
+       /* st_shasta */
+       { 0x105a, 0x8350, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               st_shasta }, /* SuperTrak EX8350/8300/16350/16300 */
+       { 0x105a, 0xc350, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               st_shasta }, /* SuperTrak EX12350 */
+       { 0x105a, 0x4302, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               st_shasta }, /* SuperTrak EX4350 */
+       { 0x105a, 0xe350, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               st_shasta }, /* SuperTrak EX24350 */
+
+       /* st_vsc */
+       { 0x105a, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc },
+
+       /* st_yosemite */
+       { 0x105a, 0x8650, PCI_ANY_ID, 0x4600, 0, 0,
+               st_yosemite }, /* SuperTrak EX4650 */
+       { 0x105a, 0x8650, PCI_ANY_ID, 0x4610, 0, 0,
+               st_yosemite }, /* SuperTrak EX4650o */
+       { 0x105a, 0x8650, PCI_ANY_ID, 0x8600, 0, 0,
+               st_yosemite }, /* SuperTrak EX8650EL */
+       { 0x105a, 0x8650, PCI_ANY_ID, 0x8601, 0, 0,
+               st_yosemite }, /* SuperTrak EX8650 */
+       { 0x105a, 0x8650, PCI_ANY_ID, 0x8602, 0, 0,
+               st_yosemite }, /* SuperTrak EX8654 */
+       { 0x105a, 0x8650, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               st_yosemite }, /* generic st_yosemite */
        { }     /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, stex_pci_tbl);