Merge branch 'intx' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/misc-2.6
[pandora-kernel.git] / drivers / scsi / stex.c
index 3cf3106..ba6bcda 100644 (file)
@@ -11,8 +11,6 @@
  *     Written By:
  *             Ed Lin <promise_linux@promise.com>
  *
- *     Version: 2.9.0.13
- *
  */
 
 #include <linux/init.h>
 #include <scsi/scsi_tcq.h>
 
 #define DRV_NAME "stex"
-#define ST_DRIVER_VERSION "2.9.0.13"
-#define ST_VER_MAJOR           2
-#define ST_VER_MINOR           9
+#define ST_DRIVER_VERSION "3.1.0.1"
+#define ST_VER_MAJOR           3
+#define ST_VER_MINOR           1
 #define ST_OEM                         0
-#define ST_BUILD_VER           13
+#define ST_BUILD_VER           1
 
 enum {
        /* MU register offset */
@@ -76,8 +74,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,12 +120,19 @@ enum {
 
        st_shasta                               = 0,
        st_vsc                                  = 1,
+       st_vsc1                                 = 2,
+       st_yosemite                             = 3,
 
        PASSTHRU_REQ_TYPE                       = 0x00000001,
        PASSTHRU_REQ_NO_WAKEUP                  = 0x00000100,
        ST_INTERNAL_TIMEOUT                     = 30,
 
+       ST_TO_CMD                               = 0,
+       ST_FROM_CMD                             = 1,
+
        /* vendor specific commands of Promise */
+       MGT_CMD                                 = 0xd8,
+       SINBAND_MGT_CMD                         = 0xd9,
        ARRAY_CMD                               = 0xe0,
        CONTROLLER_CMD                          = 0xe1,
        DEBUGGING_CMD                           = 0xe2,
@@ -133,14 +140,50 @@ enum {
 
        PASSTHRU_GET_ADAPTER                    = 0x05,
        PASSTHRU_GET_DRVVER                     = 0x10,
+
+       CTLR_CONFIG_CMD                         = 0x03,
+       CTLR_SHUTDOWN                           = 0x0d,
+
        CTLR_POWER_STATE_CHANGE                 = 0x0e,
        CTLR_POWER_SAVING                       = 0x01,
 
        PASSTHRU_SIGNATURE                      = 0x4e415041,
+       MGT_CMD_SIGNATURE                       = 0xba,
 
        INQUIRY_EVPD                            = 0x01,
+
+       ST_ADDITIONAL_MEM                       = 0x200000,
 };
 
+/* SCSI inquiry data */
+typedef struct st_inq {
+       u8 DeviceType                   :5;
+       u8 DeviceTypeQualifier          :3;
+       u8 DeviceTypeModifier           :7;
+       u8 RemovableMedia               :1;
+       u8 Versions;
+       u8 ResponseDataFormat           :4;
+       u8 HiSupport                    :1;
+       u8 NormACA                      :1;
+       u8 ReservedBit                  :1;
+       u8 AERC                         :1;
+       u8 AdditionalLength;
+       u8 Reserved[2];
+       u8 SoftReset                    :1;
+       u8 CommandQueue                 :1;
+       u8 Reserved2                    :1;
+       u8 LinkedCommands               :1;
+       u8 Synchronous                  :1;
+       u8 Wide16Bit                    :1;
+       u8 Wide32Bit                    :1;
+       u8 RelativeAddressing           :1;
+       u8 VendorId[8];
+       u8 ProductId[16];
+       u8 ProductRevisionLevel[4];
+       u8 VendorSpecific[20];
+       u8 Reserved3[40];
+} ST_INQ;
+
 struct st_sgitem {
        u8 ctrl;        /* SG_CF_xxx */
        u8 reserved[3];
@@ -171,7 +214,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 {
@@ -181,7 +226,7 @@ struct req_msg {
        u8 task_attr;
        u8 task_manage;
        u8 prd_entry;
-       u8 payload_sz;          /* payload size in 4-byte */
+       u8 payload_sz;          /* payload size in 4-byte, not used */
        u8 cdb[STEX_CDB_LENGTH];
        u8 variable[REQ_VARIABLE_LEN];
 };
@@ -242,7 +287,8 @@ struct st_drvver {
 #define MU_REQ_BUFFER_SIZE     (MU_REQ_COUNT * sizeof(struct req_msg))
 #define MU_STATUS_BUFFER_SIZE  (MU_STATUS_COUNT * sizeof(struct status_msg))
 #define MU_BUFFER_SIZE         (MU_REQ_BUFFER_SIZE + MU_STATUS_BUFFER_SIZE)
-#define STEX_BUFFER_SIZE       (MU_BUFFER_SIZE + sizeof(struct st_frame))
+#define STEX_EXTRA_SIZE                max(sizeof(struct st_frame), sizeof(ST_INQ))
+#define STEX_BUFFER_SIZE       (MU_BUFFER_SIZE + STEX_EXTRA_SIZE)
 
 struct st_ccb {
        struct req_msg *req;
@@ -261,6 +307,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;
@@ -403,7 +450,7 @@ static int stex_map_sg(struct st_hba *hba,
 }
 
 static void stex_internal_copy(struct scsi_cmnd *cmd,
-       const void *src, size_t *count, int sg_count)
+       const void *src, size_t *count, int sg_count, int direction)
 {
        size_t lcount;
        size_t len;
@@ -427,7 +474,10 @@ static void stex_internal_copy(struct scsi_cmnd *cmd,
                } else
                        d = cmd->request_buffer;
 
-               memcpy(d, s, len);
+               if (direction == ST_TO_CMD)
+                       memcpy(d, s, len);
+               else
+                       memcpy(s, d, len);
 
                lcount -= len;
                if (cmd->use_sg)
@@ -449,7 +499,7 @@ static int stex_direct_copy(struct scsi_cmnd *cmd,
                        return 0;
        }
 
-       stex_internal_copy(cmd, src, &cp_len, n_elem);
+       stex_internal_copy(cmd, src, &cp_len, n_elem, ST_TO_CMD);
 
        if (cmd->use_sg)
                pci_unmap_sg(hba->pdev, cmd->request_buffer,
@@ -463,6 +513,7 @@ static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb)
        size_t count = sizeof(struct st_frame);
 
        p = hba->copy_buffer;
+       stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count, ST_FROM_CMD);
        memset(p->base, 0, sizeof(u32)*6);
        *(unsigned long *)(p->base) = pci_resource_start(hba->pdev, 0);
        p->rom_addr = 0;
@@ -480,7 +531,7 @@ static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb)
        p->subid =
                hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device;
 
-       stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count);
+       stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count, ST_TO_CMD);
 }
 
 static void
@@ -489,7 +540,6 @@ stex_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag)
        req->tag = cpu_to_le16(tag);
        req->task_attr = TASK_ATTRIBUTE_SIMPLE;
        req->task_manage = 0; /* not supported yet */
-       req->payload_sz = (u8)(sizeof(struct req_msg)/sizeof(u32));
 
        hba->ccb[tag].req = req;
        hba->out_req_cnt++;
@@ -595,8 +645,14 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
                return SCSI_MLQUEUE_HOST_BUSY;
 
        req = stex_alloc_req(hba);
-       req->lun = lun;
-       req->target = id;
+
+       if (hba->cardtype == st_yosemite) {
+               req->lun = lun * (ST_MAX_TARGET_NUM - 1) + id;
+               req->target = 0;
+       } else {
+               req->lun = lun;
+               req->target = id;
+       }
 
        /* cdb */
        memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH);
@@ -680,7 +736,51 @@ static void stex_copy_data(struct st_ccb *ccb,
 
        if (ccb->cmd == NULL)
                return;
-       stex_internal_copy(ccb->cmd, resp->variable, &count, ccb->sg_count);
+       stex_internal_copy(ccb->cmd,
+               resp->variable, &count, ccb->sg_count, ST_TO_CMD);
+}
+
+static void stex_ys_commands(struct st_hba *hba,
+       struct st_ccb *ccb, struct status_msg *resp)
+{
+       size_t count;
+
+       if (ccb->cmd->cmnd[0] == MGT_CMD &&
+               resp->scsi_status != SAM_STAT_CHECK_CONDITION) {
+               ccb->cmd->request_bufflen =
+                       le32_to_cpu(*(__le32 *)&resp->variable[0]);
+               return;
+       }
+
+       if (resp->srb_status != 0)
+               return;
+
+       /* determine inquiry command status by DeviceTypeQualifier */
+       if (ccb->cmd->cmnd[0] == INQUIRY &&
+               resp->scsi_status == SAM_STAT_GOOD) {
+               ST_INQ *inq_data;
+
+               count = STEX_EXTRA_SIZE;
+               stex_internal_copy(ccb->cmd, hba->copy_buffer,
+                       &count, ccb->sg_count, ST_FROM_CMD);
+               inq_data = (ST_INQ *)hba->copy_buffer;
+               if (inq_data->DeviceTypeQualifier != 0)
+                       ccb->srb_status = SRB_STATUS_SELECTION_TIMEOUT;
+               else
+                       ccb->srb_status = SRB_STATUS_SUCCESS;
+       } else if (ccb->cmd->cmnd[0] == REPORT_LUNS) {
+               u8 *report_lun_data = (u8 *)hba->copy_buffer;
+
+               count = STEX_EXTRA_SIZE;
+               stex_internal_copy(ccb->cmd, report_lun_data,
+                       &count, ccb->sg_count, ST_FROM_CMD);
+               if (report_lun_data[2] || report_lun_data[3]) {
+                       report_lun_data[2] = 0x00;
+                       report_lun_data[3] = 0x08;
+                       stex_internal_copy(ccb->cmd, report_lun_data,
+                               &count, ccb->sg_count, ST_TO_CMD);
+               }
+       }
 }
 
 static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
@@ -702,8 +802,17 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
                return;
        }
 
-       if (unlikely(hba->mu_status != MU_STATE_STARTED ||
-               hba->out_req_cnt <= 0)) {
+       /*
+        * it's not a valid status payload if:
+        * 1. there are no pending requests(e.g. during init stage)
+        * 2. there are some pending requests, but the controller is in
+        *     reset status, and its type is not st_yosemite
+        * firmware of st_yosemite in reset status will return pending requests
+        * to driver, so we allow it to pass
+        */
+       if (unlikely(hba->out_req_cnt <= 0 ||
+                       (hba->mu_status == MU_STATE_RESETTING &&
+                        hba->cardtype != st_yosemite))) {
                hba->status_tail = hba->status_head;
                goto update_status;
        }
@@ -723,6 +832,7 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
                if (unlikely(ccb->req == NULL)) {
                        printk(KERN_WARNING DRV_NAME
                                "(%s): lagging req\n", pci_name(hba->pdev));
+                       hba->out_req_cnt--;
                        continue;
                }
 
@@ -741,9 +851,13 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
                ccb->scsi_status = resp->scsi_status;
 
                if (likely(ccb->cmd != NULL)) {
+                       if (hba->cardtype == st_yosemite)
+                               stex_ys_commands(hba, ccb, resp);
+
                        if (unlikely(ccb->cmd->cmnd[0] == PASSTHRU_CMD &&
                                ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER))
                                stex_controller_info(hba, ccb);
+
                        stex_unmap_sg(hba, ccb->cmd);
                        stex_scsi_done(ccb);
                        hba->out_req_cnt--;
@@ -764,7 +878,7 @@ update_status:
        readl(base + IMR1); /* flush */
 }
 
-static irqreturn_t stex_intr(int irq, void *__hba, struct pt_regs *regs)
+static irqreturn_t stex_intr(int irq, void *__hba)
 {
        struct st_hba *hba = __hba;
        void __iomem *base = hba->mmio_base;
@@ -794,27 +908,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);
@@ -824,6 +945,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);
@@ -837,19 +963,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);
@@ -931,9 +1056,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);
        }
@@ -948,6 +1073,7 @@ static int stex_reset(struct scsi_cmnd *cmd)
 {
        struct st_hba *hba;
        unsigned long flags;
+       unsigned long before;
        hba = (struct st_hba *) &cmd->device->host->hostdata[0];
 
        hba->mu_status = MU_STATE_RESETTING;
@@ -955,38 +1081,55 @@ static int stex_reset(struct scsi_cmnd *cmd)
        if (hba->cardtype == st_shasta)
                stex_hard_reset(hba);
 
-       if (stex_handshake(hba)) {
-               printk(KERN_WARNING DRV_NAME
-                       "(%s): resetting: handshake failed\n",
-                       pci_name(hba->pdev));
-               return FAILED;
+       if (hba->cardtype != st_yosemite) {
+               if (stex_handshake(hba)) {
+                       printk(KERN_WARNING DRV_NAME
+                               "(%s): resetting: handshake failed\n",
+                               pci_name(hba->pdev));
+                       return FAILED;
+               }
+               spin_lock_irqsave(hba->host->host_lock, flags);
+               hba->req_head = 0;
+               hba->req_tail = 0;
+               hba->status_head = 0;
+               hba->status_tail = 0;
+               hba->out_req_cnt = 0;
+               spin_unlock_irqrestore(hba->host->host_lock, flags);
+               return SUCCESS;
+       }
+
+       /* st_yosemite */
+       writel(MU_INBOUND_DOORBELL_RESET, hba->mmio_base + IDBL);
+       readl(hba->mmio_base + IDBL); /* flush */
+       before = jiffies;
+       while (hba->out_req_cnt > 0) {
+               if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {
+                       printk(KERN_WARNING DRV_NAME
+                               "(%s): reset timeout\n", pci_name(hba->pdev));
+                       return FAILED;
+               }
+               msleep(1);
        }
-       spin_lock_irqsave(hba->host->host_lock, flags);
-       hba->req_head = 0;
-       hba->req_tail = 0;
-       hba->status_head = 0;
-       hba->status_tail = 0;
-       hba->out_req_cnt = 0;
-       spin_unlock_irqrestore(hba->host->host_lock, flags);
 
+       hba->mu_status = MU_STATE_STARTED;
        return SUCCESS;
 }
 
 static int stex_biosparam(struct scsi_device *sdev,
        struct block_device *bdev, sector_t capacity, int geom[])
 {
-       int heads = 255, sectors = 63, cylinders;
+       int heads = 255, sectors = 63;
 
        if (capacity < 0x200000) {
                heads = 64;
                sectors = 32;
        }
 
-       cylinders = sector_div(capacity, heads * sectors);
+       sector_div(capacity, heads * sectors);
 
        geom[0] = heads;
        geom[1] = sectors;
-       geom[2] = cylinders;
+       geom[2] = capacity;
 
        return 0;
 }
@@ -1068,8 +1211,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",
@@ -1082,8 +1230,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 */
@@ -1108,7 +1254,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));
@@ -1131,7 +1277,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);
@@ -1156,9 +1302,16 @@ static void stex_hba_stop(struct st_hba *hba)
        req = stex_alloc_req(hba);
        memset(req->cdb, 0, STEX_CDB_LENGTH);
 
-       req->cdb[0] = CONTROLLER_CMD;
-       req->cdb[1] = CTLR_POWER_STATE_CHANGE;
-       req->cdb[2] = CTLR_POWER_SAVING;
+       if (hba->cardtype == st_yosemite) {
+               req->cdb[0] = MGT_CMD;
+               req->cdb[1] = MGT_CMD_SIGNATURE;
+               req->cdb[2] = CTLR_CONFIG_CMD;
+               req->cdb[3] = CTLR_SHUTDOWN;
+       } else {
+               req->cdb[0] = CONTROLLER_CMD;
+               req->cdb[1] = CTLR_POWER_STATE_CHANGE;
+               req->cdb[2] = CTLR_POWER_SAVING;
+       }
 
        hba->ccb[tag].cmd = NULL;
        hba->ccb[tag].sg_count = 0;
@@ -1185,7 +1338,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);
 }
 
@@ -1214,14 +1367,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 },
+       /* 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);