scsi: stex: Support Pegasus 3 product
authorCharles <charles.chiou@tw.promise.com>
Fri, 17 Feb 2017 02:51:34 +0000 (10:51 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 15 Mar 2017 23:20:13 +0000 (19:20 -0400)
Pegasus series is a RAID support product using Thunderbolt technology.
The newest product, Pegasus 3(P3) supports Thunderbolt 3 technology with
a different chip.

1. Change driver version.

2. Add P3 VID, DID and define it's device address.

3. P3 use msi interrupt, so stex_request_irq P3 type enable msi.

4. For hibernation, use msi_lock in stex_ss_handshake to prevent msi
   register write again when handshaking.

5. P3 doesn't need read() as flush.

6. In stex_ss_intr & stex_abort, P3 only clear interrupt register when
   getting vendor defined interrupt.

Signed-off-by: Charles.Chiou <charles.chiou@tw.promise.com>
Signed-off-by: Paul.Lyu <paul.lyu@tw.promise.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/stex.c

index 5b23175a584cc68fc99c0d4f099bcba4c47f0702..e177dfe08939d13f13ae8e7230246e02615e173b 100644 (file)
@@ -38,9 +38,9 @@
 #include <scsi/scsi_eh.h>
 
 #define DRV_NAME "stex"
-#define ST_DRIVER_VERSION      "5.00.0000.01"
-#define ST_VER_MAJOR           5
-#define ST_VER_MINOR           00
+#define ST_DRIVER_VERSION      "6.02.0000.01"
+#define ST_VER_MAJOR           6
+#define ST_VER_MINOR           02
 #define ST_OEM                         0000
 #define ST_BUILD_VER           01
 
@@ -64,6 +64,13 @@ enum {
        YI2H_INT_C                              = 0xa0,
        YH2I_REQ                                = 0xc0,
        YH2I_REQ_HI                             = 0xc4,
+       PSCRATCH0                               = 0xb0,
+       PSCRATCH1                               = 0xb4,
+       PSCRATCH2                               = 0xb8,
+       PSCRATCH3                               = 0xbc,
+       PSCRATCH4                               = 0xc8,
+       MAILBOX_BASE                    = 0x1000,
+       MAILBOX_HNDSHK_STS              = 0x0,
 
        /* MU register value */
        MU_INBOUND_DOORBELL_HANDSHAKE           = (1 << 0),
@@ -87,7 +94,7 @@ enum {
        MU_STATE_STOP                           = 5,
        MU_STATE_NOCONNECT                      = 6,
 
-       MU_MAX_DELAY                            = 120,
+       MU_MAX_DELAY                            = 50,
        MU_HANDSHAKE_SIGNATURE                  = 0x55aaaa55,
        MU_HANDSHAKE_SIGNATURE_HALF             = 0x5a5a0000,
        MU_HARD_RESET_WAIT                      = 30000,
@@ -135,6 +142,7 @@ enum {
        st_yosemite                             = 2,
        st_seq                                  = 3,
        st_yel                                  = 4,
+       st_P3                                   = 5,
 
        PASSTHRU_REQ_TYPE                       = 0x00000001,
        PASSTHRU_REQ_NO_WAKEUP                  = 0x00000100,
@@ -339,6 +347,7 @@ struct st_hba {
        u16 rq_size;
        u16 sts_count;
        u8  supports_pm;
+       int msi_lock;
 };
 
 struct st_card_info {
@@ -540,11 +549,15 @@ stex_ss_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag)
 
        ++hba->req_head;
        hba->req_head %= hba->rq_count+1;
-
-       writel((addr >> 16) >> 16, hba->mmio_base + YH2I_REQ_HI);
-       readl(hba->mmio_base + YH2I_REQ_HI); /* flush */
-       writel(addr, hba->mmio_base + YH2I_REQ);
-       readl(hba->mmio_base + YH2I_REQ); /* flush */
+       if (hba->cardtype == st_P3) {
+               writel((addr >> 16) >> 16, hba->mmio_base + YH2I_REQ_HI);
+               writel(addr, hba->mmio_base + YH2I_REQ);
+       } else {
+               writel((addr >> 16) >> 16, hba->mmio_base + YH2I_REQ_HI);
+               readl(hba->mmio_base + YH2I_REQ_HI); /* flush */
+               writel(addr, hba->mmio_base + YH2I_REQ);
+               readl(hba->mmio_base + YH2I_REQ); /* flush */
+       }
 }
 
 static void return_abnormal_state(struct st_hba *hba, int status)
@@ -974,15 +987,31 @@ static irqreturn_t stex_ss_intr(int irq, void *__hba)
 
        spin_lock_irqsave(hba->host->host_lock, flags);
 
-       data = readl(base + YI2H_INT);
-       if (data && data != 0xffffffff) {
-               /* clear the interrupt */
-               writel(data, base + YI2H_INT_C);
-               stex_ss_mu_intr(hba);
-               spin_unlock_irqrestore(hba->host->host_lock, flags);
-               if (unlikely(data & SS_I2H_REQUEST_RESET))
-                       queue_work(hba->work_q, &hba->reset_work);
-               return IRQ_HANDLED;
+       if (hba->cardtype == st_yel) {
+               data = readl(base + YI2H_INT);
+               if (data && data != 0xffffffff) {
+                       /* clear the interrupt */
+                       writel(data, base + YI2H_INT_C);
+                       stex_ss_mu_intr(hba);
+                       spin_unlock_irqrestore(hba->host->host_lock, flags);
+                       if (unlikely(data & SS_I2H_REQUEST_RESET))
+                               queue_work(hba->work_q, &hba->reset_work);
+                       return IRQ_HANDLED;
+               }
+       } else {
+               data = readl(base + PSCRATCH4);
+               if (data != 0xffffffff) {
+                       if (data != 0) {
+                               /* clear the interrupt */
+                               writel(data, base + PSCRATCH1);
+                               writel((1 << 22), base + YH2I_INT);
+                       }
+                       stex_ss_mu_intr(hba);
+                       spin_unlock_irqrestore(hba->host->host_lock, flags);
+                       if (unlikely(data & SS_I2H_REQUEST_RESET))
+                               queue_work(hba->work_q, &hba->reset_work);
+                       return IRQ_HANDLED;
+               }
        }
 
        spin_unlock_irqrestore(hba->host->host_lock, flags);
@@ -1080,19 +1109,36 @@ static int stex_ss_handshake(struct st_hba *hba)
        struct st_msg_header *msg_h;
        struct handshake_frame *h;
        __le32 *scratch;
-       u32 data, scratch_size;
+       u32 data, scratch_size, mailboxdata, operationaldata;
        unsigned long before;
        int ret = 0;
 
        before = jiffies;
-       while ((readl(base + YIOA_STATUS) & SS_MU_OPERATIONAL) == 0) {
-               if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) {
-                       printk(KERN_ERR DRV_NAME
-                               "(%s): firmware not operational\n",
-                               pci_name(hba->pdev));
-                       return -1;
+
+       if (hba->cardtype == st_yel) {
+               operationaldata = readl(base + YIOA_STATUS);
+               while (operationaldata != SS_MU_OPERATIONAL) {
+                       if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) {
+                               printk(KERN_ERR DRV_NAME
+                                       "(%s): firmware not operational\n",
+                                       pci_name(hba->pdev));
+                               return -1;
+                       }
+                       msleep(1);
+                       operationaldata = readl(base + YIOA_STATUS);
+               }
+       } else {
+               operationaldata = readl(base + PSCRATCH3);
+               while (operationaldata != SS_MU_OPERATIONAL) {
+                       if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) {
+                               printk(KERN_ERR DRV_NAME
+                                       "(%s): firmware not operational\n",
+                                       pci_name(hba->pdev));
+                               return -1;
+                       }
+                       msleep(1);
+                       operationaldata = readl(base + PSCRATCH3);
                }
-               msleep(1);
        }
 
        msg_h = (struct st_msg_header *)hba->dma_mem;
@@ -1111,30 +1157,60 @@ static int stex_ss_handshake(struct st_hba *hba)
        scratch_size = (hba->sts_count+1)*sizeof(u32);
        h->scratch_size = cpu_to_le32(scratch_size);
 
-       data = readl(base + YINT_EN);
-       data &= ~4;
-       writel(data, base + YINT_EN);
-       writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI);
-       readl(base + YH2I_REQ_HI);
-       writel(hba->dma_handle, base + YH2I_REQ);
-       readl(base + YH2I_REQ); /* flush */
+       if (hba->cardtype == st_yel) {
+               data = readl(base + YINT_EN);
+               data &= ~4;
+               writel(data, base + YINT_EN);
+               writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI);
+               readl(base + YH2I_REQ_HI);
+               writel(hba->dma_handle, base + YH2I_REQ);
+               readl(base + YH2I_REQ); /* flush */
+       } else {
+               data = readl(base + YINT_EN);
+               data &= ~(1 << 0);
+               data &= ~(1 << 2);
+               writel(data, base + YINT_EN);
+               if (hba->msi_lock == 0) {
+                       /* P3 MSI Register cannot access twice */
+                       writel((1 << 6), base + YH2I_INT);
+                       hba->msi_lock  = 1;
+               }
+               writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI);
+               writel(hba->dma_handle, base + YH2I_REQ);
+       }
 
-       scratch = hba->scratch;
        before = jiffies;
-       while (!(le32_to_cpu(*scratch) & SS_STS_HANDSHAKE)) {
-               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));
-                       ret = -1;
-                       break;
+       scratch = hba->scratch;
+       if (hba->cardtype == st_yel) {
+               while (!(le32_to_cpu(*scratch) & SS_STS_HANDSHAKE)) {
+                       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));
+                               ret = -1;
+                               break;
+                       }
+                       rmb();
+                       msleep(1);
+               }
+       } else {
+               mailboxdata = readl(base + MAILBOX_BASE + MAILBOX_HNDSHK_STS);
+               while (mailboxdata != SS_STS_HANDSHAKE) {
+                       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));
+                               ret = -1;
+                               break;
+                       }
+                       rmb();
+                       msleep(1);
+                       mailboxdata = readl(base + MAILBOX_BASE + MAILBOX_HNDSHK_STS);
                }
-               rmb();
-               msleep(1);
        }
-
        memset(scratch, 0, scratch_size);
        msg_h->flag = 0;
+
        return ret;
 }
 
@@ -1144,8 +1220,10 @@ static int stex_handshake(struct st_hba *hba)
        unsigned long flags;
        unsigned int mu_status;
 
-       err = (hba->cardtype == st_yel) ?
-               stex_ss_handshake(hba) : stex_common_handshake(hba);
+       if (hba->cardtype == st_yel || hba->cardtype == st_P3)
+               err = stex_ss_handshake(hba);
+       else
+               err = stex_common_handshake(hba);
        spin_lock_irqsave(hba->host->host_lock, flags);
        mu_status = hba->mu_status;
        if (err == 0) {
@@ -1190,6 +1268,15 @@ static int stex_abort(struct scsi_cmnd *cmd)
 
                writel(data, base + YI2H_INT_C);
                stex_ss_mu_intr(hba);
+       } else if (hba->cardtype == st_P3) {
+               data = readl(base + PSCRATCH4);
+               if (data == 0xffffffff)
+                       goto fail_out;
+               if (data != 0) {
+                       writel(data, base + PSCRATCH1);
+                       writel((1 << 22), base + YH2I_INT);
+               }
+               stex_ss_mu_intr(hba);
        } else {
                data = readl(base + ODBL);
                if (data == 0 || data == 0xffffffff)
@@ -1197,7 +1284,6 @@ static int stex_abort(struct scsi_cmnd *cmd)
 
                writel(data, base + ODBL);
                readl(base + ODBL); /* flush */
-
                stex_mu_intr(hba, data);
        }
        if (hba->wait_ccb == NULL) {
@@ -1293,6 +1379,12 @@ static void stex_ss_reset(struct st_hba *hba)
        ssleep(5);
 }
 
+static void stex_p3_reset(struct st_hba *hba)
+{
+       writel(SS_H2I_INT_RESET, hba->mmio_base + YH2I_INT);
+       ssleep(5);
+}
+
 static int stex_do_reset(struct st_hba *hba)
 {
        unsigned long flags;
@@ -1329,7 +1421,8 @@ static int stex_do_reset(struct st_hba *hba)
                stex_hard_reset(hba);
        else if (hba->cardtype == st_yel)
                stex_ss_reset(hba);
-
+       else if (hba->cardtype == st_P3)
+               stex_p3_reset(hba);
 
        return_abnormal_state(hba, DID_RESET);
 
@@ -1414,6 +1507,26 @@ static struct pci_device_id stex_pci_tbl[] = {
        /* st_yel */
        { 0x105a, 0x8650, 0x1033, PCI_ANY_ID, 0, 0, st_yel },
        { 0x105a, 0x8760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_yel },
+
+       /* st_P3, pluto */
+       { PCI_VENDOR_ID_PROMISE, 0x8870, PCI_VENDOR_ID_PROMISE,
+               0x8870, 0, 0, st_P3 },
+       /* st_P3, p3 */
+       { PCI_VENDOR_ID_PROMISE, 0x8870, PCI_VENDOR_ID_PROMISE,
+               0x4300, 0, 0, st_P3 },
+
+       /* st_P3, SymplyStor4E */
+       { PCI_VENDOR_ID_PROMISE, 0x8871, PCI_VENDOR_ID_PROMISE,
+               0x4311, 0, 0, st_P3 },
+       /* st_P3, SymplyStor8E */
+       { PCI_VENDOR_ID_PROMISE, 0x8871, PCI_VENDOR_ID_PROMISE,
+               0x4312, 0, 0, st_P3 },
+       /* st_P3, SymplyStor4 */
+       { PCI_VENDOR_ID_PROMISE, 0x8871, PCI_VENDOR_ID_PROMISE,
+               0x4321, 0, 0, st_P3 },
+       /* st_P3, SymplyStor8 */
+       { PCI_VENDOR_ID_PROMISE, 0x8871, PCI_VENDOR_ID_PROMISE,
+               0x4322, 0, 0, st_P3 },
        { }     /* terminate list */
 };
 
@@ -1482,6 +1595,19 @@ static struct st_card_info stex_card_info[] = {
                .map_sg         = stex_ss_map_sg,
                .send           = stex_ss_send_cmd,
        },
+
+       /* st_P3 */
+       {
+               .max_id         = 129,
+               .max_lun        = 256,
+               .max_channel    = 0,
+               .rq_count       = 801,
+               .rq_size        = 512,
+               .sts_count      = 801,
+               .alloc_rq       = stex_ss_alloc_req,
+               .map_sg         = stex_ss_map_sg,
+               .send           = stex_ss_send_cmd,
+       },
 };
 
 static int stex_set_dma_mask(struct pci_dev * pdev)
@@ -1502,7 +1628,7 @@ static int stex_request_irq(struct st_hba *hba)
        struct pci_dev *pdev = hba->pdev;
        int status;
 
-       if (msi) {
+       if (msi || hba->cardtype == st_P3) {
                status = pci_enable_msi(pdev);
                if (status != 0)
                        printk(KERN_ERR DRV_NAME
@@ -1513,7 +1639,8 @@ static int stex_request_irq(struct st_hba *hba)
        } else
                hba->msi_enabled = 0;
 
-       status = request_irq(pdev->irq, hba->cardtype == st_yel ?
+       status = request_irq(pdev->irq,
+               (hba->cardtype == st_yel || hba->cardtype == st_P3) ?
                stex_ss_intr : stex_intr, IRQF_SHARED, DRV_NAME, hba);
 
        if (status != 0) {
@@ -1597,12 +1724,12 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        case 0x4265:
                break;
        default:
-               if (hba->cardtype == st_yel)
+               if (hba->cardtype == st_yel || hba->cardtype == st_P3)
                        hba->supports_pm = 1;
        }
 
        sts_offset = scratch_offset = (ci->rq_count+1) * ci->rq_size;
-       if (hba->cardtype == st_yel)
+       if (hba->cardtype == st_yel || hba->cardtype == st_P3)
                sts_offset += (ci->sts_count+1) * sizeof(u32);
        cp_offset = sts_offset + (ci->sts_count+1) * sizeof(struct status_msg);
        hba->dma_size = cp_offset + sizeof(struct st_frame);
@@ -1642,7 +1769,7 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto out_pci_free;
        }
 
-       if (hba->cardtype == st_yel)
+       if (hba->cardtype == st_yel || hba->cardtype == st_P3)
                hba->scratch = (__le32 *)(hba->dma_mem + scratch_offset);
        hba->status_buffer = (struct status_msg *)(hba->dma_mem + sts_offset);
        hba->copy_buffer = hba->dma_mem + cp_offset;
@@ -1653,8 +1780,9 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        hba->map_sg = ci->map_sg;
        hba->send = ci->send;
        hba->mu_status = MU_STATE_STARTING;
+       hba->msi_lock = 0;
 
-       if (hba->cardtype == st_yel)
+       if (hba->cardtype == st_yel || hba->cardtype == st_P3)
                host->sg_tablesize = 38;
        else
                host->sg_tablesize = 32;
@@ -1736,28 +1864,29 @@ static void stex_hba_stop(struct st_hba *hba, int st_sleep_mic)
 
        spin_lock_irqsave(hba->host->host_lock, flags);
 
-       if (hba->cardtype == st_yel && hba->supports_pm == 1)
-       {
-               if(st_sleep_mic == ST_NOTHANDLED)
-               {
+       if ((hba->cardtype == st_yel || hba->cardtype == st_P3) &&
+               hba->supports_pm == 1) {
+               if (st_sleep_mic == ST_NOTHANDLED) {
                        spin_unlock_irqrestore(hba->host->host_lock, flags);
                        return;
                }
        }
        req = hba->alloc_rq(hba);
-       if (hba->cardtype == st_yel) {
+       if (hba->cardtype == st_yel || hba->cardtype == st_P3) {
                msg_h = (struct st_msg_header *)req - 1;
                memset(msg_h, 0, hba->rq_size);
        } else
                memset(req, 0, hba->rq_size);
 
-       if ((hba->cardtype == st_yosemite || hba->cardtype == st_yel)
+       if ((hba->cardtype == st_yosemite || hba->cardtype == st_yel
+               || hba->cardtype == st_P3)
                && st_sleep_mic == ST_IGNORED) {
                req->cdb[0] = MGT_CMD;
                req->cdb[1] = MGT_CMD_SIGNATURE;
                req->cdb[2] = CTLR_CONFIG_CMD;
                req->cdb[3] = CTLR_SHUTDOWN;
-       } else if (hba->cardtype == st_yel && st_sleep_mic != ST_IGNORED) {
+       } else if ((hba->cardtype == st_yel || hba->cardtype == st_P3)
+               && st_sleep_mic != ST_IGNORED) {
                req->cdb[0] = MGT_CMD;
                req->cdb[1] = MGT_CMD_SIGNATURE;
                req->cdb[2] = CTLR_CONFIG_CMD;
@@ -1768,16 +1897,13 @@ static void stex_hba_stop(struct st_hba *hba, int st_sleep_mic)
                req->cdb[1] = CTLR_POWER_STATE_CHANGE;
                req->cdb[2] = CTLR_POWER_SAVING;
        }
-
        hba->ccb[tag].cmd = NULL;
        hba->ccb[tag].sg_count = 0;
        hba->ccb[tag].sense_bufflen = 0;
        hba->ccb[tag].sense_buffer = NULL;
        hba->ccb[tag].req_type = PASSTHRU_REQ_TYPE;
-
        hba->send(hba, req, tag);
        spin_unlock_irqrestore(hba->host->host_lock, flags);
-
        before = jiffies;
        while (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE) {
                if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {
@@ -1833,12 +1959,13 @@ static void stex_shutdown(struct pci_dev *pdev)
                stex_hba_stop(hba, ST_S5);
 }
 
-static int stex_choice_sleep_mic(pm_message_t state)
+static int stex_choice_sleep_mic(struct st_hba *hba, pm_message_t state)
 {
        switch (state.event) {
        case PM_EVENT_SUSPEND:
                return ST_S3;
        case PM_EVENT_HIBERNATE:
+               hba->msi_lock = 0;
                return ST_S4;
        default:
                return ST_NOTHANDLED;
@@ -1849,8 +1976,9 @@ static int stex_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct st_hba *hba = pci_get_drvdata(pdev);
 
-       if (hba->cardtype == st_yel && hba->supports_pm == 1)
-               stex_hba_stop(hba, stex_choice_sleep_mic(state));
+       if ((hba->cardtype == st_yel || hba->cardtype == st_P3)
+               && hba->supports_pm == 1)
+               stex_hba_stop(hba, stex_choice_sleep_mic(hba, state));
        else
                stex_hba_stop(hba, ST_IGNORED);
        return 0;