[SCSI] m68k: new mac_esp scsi driver
[safe/jmp/linux-2.6] / drivers / scsi / stex.c
index cfb2971..f308a03 100644 (file)
  *     Written By:
  *             Ed Lin <promise_linux@promise.com>
  *
- *     Version: 2.9.0.13
- *
  */
 
 #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>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_eh.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.6.0000.1"
+#define ST_VER_MAJOR           3
+#define ST_VER_MINOR           6
 #define ST_OEM                         0
-#define ST_BUILD_VER           13
+#define ST_BUILD_VER           1
 
 enum {
        /* MU register offset */
@@ -76,8 +75,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 */
@@ -114,18 +115,21 @@ enum {
        SG_CF_64B                               = 0x40, /* 64 bit item */
        SG_CF_HOST                              = 0x20, /* sg in host memory */
 
-       ST_MAX_ARRAY_SUPPORTED                  = 16,
-       ST_MAX_TARGET_NUM                       = (ST_MAX_ARRAY_SUPPORTED+1),
-       ST_MAX_LUN_PER_TARGET                   = 16,
-
        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 +137,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 +211,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 {
@@ -242,7 +284,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 +304,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;
@@ -319,22 +363,14 @@ static struct status_msg *stex_get_status(struct st_hba *hba)
        return status;
 }
 
-static void stex_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
-{
-       cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
-
-       cmd->sense_buffer[0] = 0x70;    /* fixed format, current */
-       cmd->sense_buffer[2] = sk;
-       cmd->sense_buffer[7] = 18 - 8;  /* additional sense length */
-       cmd->sense_buffer[12] = asc;
-       cmd->sense_buffer[13] = ascq;
-}
-
 static void stex_invalid_field(struct scsi_cmnd *cmd,
                               void (*done)(struct scsi_cmnd *))
 {
+       cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
        /* "Invalid field in cbd" */
-       stex_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0);
+       scsi_build_sense_buffer(0, cmd->sense_buffer, ILLEGAL_REQUEST, 0x24,
+                               0x0);
        done(cmd);
 }
 
@@ -352,117 +388,44 @@ static struct req_msg *stex_alloc_req(struct st_hba *hba)
 static int stex_map_sg(struct st_hba *hba,
        struct req_msg *req, struct st_ccb *ccb)
 {
-       struct pci_dev *pdev = hba->pdev;
        struct scsi_cmnd *cmd;
-       dma_addr_t dma_handle;
-       struct scatterlist *src;
+       struct scatterlist *sg;
        struct st_sgtable *dst;
-       int i;
+       int i, nseg;
 
        cmd = ccb->cmd;
        dst = (struct st_sgtable *)req->variable;
        dst->max_sg_count = cpu_to_le16(ST_MAX_SG);
-       dst->sz_in_byte = cpu_to_le32(cmd->request_bufflen);
-
-       if (cmd->use_sg) {
-               int n_elem;
-
-               src = (struct scatterlist *) cmd->request_buffer;
-               n_elem = pci_map_sg(pdev, src,
-                       cmd->use_sg, cmd->sc_data_direction);
-               if (n_elem <= 0)
-                       return -EIO;
+       dst->sz_in_byte = cpu_to_le32(scsi_bufflen(cmd));
 
-               ccb->sg_count = n_elem;
-               dst->sg_count = cpu_to_le16((u16)n_elem);
+       nseg = scsi_dma_map(cmd);
+       if (nseg < 0)
+               return -EIO;
+       if (nseg) {
+               ccb->sg_count = nseg;
+               dst->sg_count = cpu_to_le16((u16)nseg);
 
-               for (i = 0; i < n_elem; i++, src++) {
-                       dst->table[i].count = cpu_to_le32((u32)sg_dma_len(src));
+               scsi_for_each_sg(cmd, sg, nseg, i) {
+                       dst->table[i].count = cpu_to_le32((u32)sg_dma_len(sg));
                        dst->table[i].addr =
-                               cpu_to_le32(sg_dma_address(src) & 0xffffffff);
+                               cpu_to_le32(sg_dma_address(sg) & 0xffffffff);
                        dst->table[i].addr_hi =
-                               cpu_to_le32((sg_dma_address(src) >> 16) >> 16);
+                               cpu_to_le32((sg_dma_address(sg) >> 16) >> 16);
                        dst->table[i].ctrl = SG_CF_64B | SG_CF_HOST;
                }
                dst->table[--i].ctrl |= SG_CF_EOT;
-               return 0;
        }
 
-       dma_handle = pci_map_single(pdev, cmd->request_buffer,
-               cmd->request_bufflen, cmd->sc_data_direction);
-       cmd->SCp.dma_handle = dma_handle;
-
-       ccb->sg_count = 1;
-       dst->sg_count = cpu_to_le16(1);
-       dst->table[0].addr = cpu_to_le32(dma_handle & 0xffffffff);
-       dst->table[0].addr_hi = cpu_to_le32((dma_handle >> 16) >> 16);
-       dst->table[0].count = cpu_to_le32((u32)cmd->request_bufflen);
-       dst->table[0].ctrl = SG_CF_EOT | SG_CF_64B | SG_CF_HOST;
-
        return 0;
 }
 
-static void stex_internal_copy(struct scsi_cmnd *cmd,
-       const void *src, size_t *count, int sg_count)
-{
-       size_t lcount;
-       size_t len;
-       void *s, *d, *base = NULL;
-       if (*count > cmd->request_bufflen)
-               *count = cmd->request_bufflen;
-       lcount = *count;
-       while (lcount) {
-               len = lcount;
-               s = (void *)src;
-               if (cmd->use_sg) {
-                       size_t offset = *count - lcount;
-                       s += offset;
-                       base = scsi_kmap_atomic_sg(cmd->request_buffer,
-                               sg_count, &offset, &len);
-                       if (base == NULL) {
-                               *count -= lcount;
-                               return;
-                       }
-                       d = base + offset;
-               } else
-                       d = cmd->request_buffer;
-
-               memcpy(d, s, len);
-
-               lcount -= len;
-               if (cmd->use_sg)
-                       scsi_kunmap_atomic_sg(base);
-       }
-}
-
-static int stex_direct_copy(struct scsi_cmnd *cmd,
-       const void *src, size_t count)
-{
-       struct st_hba *hba = (struct st_hba *) &cmd->device->host->hostdata[0];
-       size_t cp_len = count;
-       int n_elem = 0;
-
-       if (cmd->use_sg) {
-               n_elem = pci_map_sg(hba->pdev, cmd->request_buffer,
-                       cmd->use_sg, cmd->sc_data_direction);
-               if (n_elem <= 0)
-                       return 0;
-       }
-
-       stex_internal_copy(cmd, src, &cp_len, n_elem);
-
-       if (cmd->use_sg)
-               pci_unmap_sg(hba->pdev, cmd->request_buffer,
-                       cmd->use_sg, cmd->sc_data_direction);
-       return cp_len == count;
-}
-
 static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb)
 {
        struct st_frame *p;
        size_t count = sizeof(struct st_frame);
 
        p = hba->copy_buffer;
+       count = scsi_sg_copy_to_buffer(ccb->cmd, p, count);
        memset(p->base, 0, sizeof(u32)*6);
        *(unsigned long *)(p->base) = pci_resource_start(hba->pdev, 0);
        p->rom_addr = 0;
@@ -480,7 +443,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);
+       count = scsi_sg_copy_from_buffer(ccb->cmd, p, count);
 }
 
 static void
@@ -536,7 +499,7 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
        u16 tag;
        host = cmd->device->host;
        id = cmd->device->id;
-       lun = cmd->device->channel; /* firmware lun issue work around */
+       lun = cmd->device->lun;
        hba = (struct st_hba *) &host->hostdata[0];
 
        switch (cmd->cmnd[0]) {
@@ -547,20 +510,38 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
                unsigned char page;
                page = cmd->cmnd[2] & 0x3f;
                if (page == 0x8 || page == 0x3f) {
-                       stex_direct_copy(cmd, ms10_caching_page,
-                                       sizeof(ms10_caching_page));
+                       scsi_sg_copy_from_buffer(cmd, ms10_caching_page,
+                                                sizeof(ms10_caching_page));
                        cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
                        done(cmd);
                } else
                        stex_invalid_field(cmd, done);
                return 0;
        }
+       case REPORT_LUNS:
+               /*
+                * The shasta firmware does not report actual luns in the
+                * target, so fail the command to force sequential lun scan.
+                * Also, the console device does not support this command.
+                */
+               if (hba->cardtype == st_shasta || id == host->max_id - 1) {
+                       stex_invalid_field(cmd, done);
+                       return 0;
+               }
+               break;
+       case TEST_UNIT_READY:
+               if (id == host->max_id - 1) {
+                       cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+                       done(cmd);
+                       return 0;
+               }
+               break;
        case INQUIRY:
-               if (id != ST_MAX_ARRAY_SUPPORTED)
+               if (id != host->max_id - 1)
                        break;
                if (lun == 0 && (cmd->cmnd[1] & INQUIRY_EVPD) == 0) {
-                       stex_direct_copy(cmd, console_inq_page,
-                               sizeof(console_inq_page));
+                       scsi_sg_copy_from_buffer(cmd, (void *)console_inq_page,
+                                                sizeof(console_inq_page));
                        cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
                        done(cmd);
                } else
@@ -569,14 +550,16 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
        case PASSTHRU_CMD:
                if (cmd->cmnd[1] == PASSTHRU_GET_DRVVER) {
                        struct st_drvver ver;
+                       size_t cp_len = sizeof(ver);
                        ver.major = ST_VER_MAJOR;
                        ver.minor = ST_VER_MINOR;
                        ver.oem = ST_OEM;
                        ver.build = ST_BUILD_VER;
                        ver.signature[0] = PASSTHRU_SIGNATURE;
-                       ver.console_id = ST_MAX_ARRAY_SUPPORTED;
+                       ver.console_id = host->max_id - 1;
                        ver.host_no = hba->host->host_no;
-                       cmd->result = stex_direct_copy(cmd, &ver, sizeof(ver)) ?
+                       cp_len = scsi_sg_copy_from_buffer(cmd, &ver, cp_len);
+                       cmd->result = sizeof(ver) == cp_len ?
                                DID_OK << 16 | COMMAND_COMPLETE << 8 :
                                DID_ERROR << 16 | COMMAND_COMPLETE << 8;
                        done(cmd);
@@ -594,6 +577,7 @@ 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;
 
@@ -612,18 +596,6 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
        return 0;
 }
 
-static void stex_unmap_sg(struct st_hba *hba, struct scsi_cmnd *cmd)
-{
-       if (cmd->sc_data_direction != DMA_NONE) {
-               if (cmd->use_sg)
-                       pci_unmap_sg(hba->pdev, cmd->request_buffer,
-                               cmd->use_sg, cmd->sc_data_direction);
-               else
-                       pci_unmap_single(hba->pdev, cmd->SCp.dma_handle,
-                               cmd->request_bufflen, cmd->sc_data_direction);
-       }
-}
-
 static void stex_scsi_done(struct st_ccb *ccb)
 {
        struct scsi_cmnd *cmd = ccb->cmd;
@@ -679,7 +651,35 @@ 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);
+       count = scsi_sg_copy_from_buffer(ccb->cmd, resp->variable, count);
+}
+
+static void stex_ys_commands(struct st_hba *hba,
+       struct st_ccb *ccb, struct status_msg *resp)
+{
+       if (ccb->cmd->cmnd[0] == MGT_CMD &&
+               resp->scsi_status != SAM_STAT_CHECK_CONDITION) {
+               scsi_set_resid(ccb->cmd, scsi_bufflen(ccb->cmd) -
+                       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;
+
+               scsi_sg_copy_to_buffer(ccb->cmd, hba->copy_buffer,
+                                      STEX_EXTRA_SIZE);
+               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;
+       }
 }
 
 static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
@@ -701,8 +701,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;
        }
@@ -722,6 +731,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;
                }
 
@@ -740,10 +750,14 @@ 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);
+
+                       scsi_dma_unmap(ccb->cmd);
                        stex_scsi_done(ccb);
                        hba->out_req_cnt--;
                } else if (ccb->req_type & PASSTHRU_REQ_TYPE) {
@@ -763,7 +777,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;
@@ -793,27 +807,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);
@@ -823,6 +844,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);
@@ -836,19 +862,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);
@@ -870,6 +895,11 @@ static int stex_abort(struct scsi_cmnd *cmd)
        u32 data;
        int result = SUCCESS;
        unsigned long flags;
+
+       printk(KERN_INFO DRV_NAME
+               "(%s): aborting command\n", pci_name(hba->pdev));
+       scsi_print_command(cmd);
+
        base = hba->mmio_base;
        spin_lock_irqsave(host->host_lock, flags);
        if (tag < host->can_queue && hba->ccb[tag].cmd == cmd)
@@ -900,7 +930,7 @@ static int stex_abort(struct scsi_cmnd *cmd)
        }
 
 fail_out:
-       stex_unmap_sg(hba, cmd);
+       scsi_dma_unmap(cmd);
        hba->wait_ccb->req = NULL; /* nullify the req's future return */
        hba->wait_ccb = NULL;
        result = FAILED;
@@ -926,13 +956,18 @@ static void stex_hard_reset(struct st_hba *hba)
        pci_read_config_byte(bus->self, PCI_BRIDGE_CONTROL, &pci_bctl);
        pci_bctl |= PCI_BRIDGE_CTL_BUS_RESET;
        pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl);
-       msleep(1);
+
+       /*
+        * 1 ms may be enough for 8-port controllers. But 16-port controllers
+        * require more time to finish bus reset. Use 100 ms here for safety
+        */
+       msleep(100);
        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);
        }
@@ -947,45 +982,67 @@ 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];
 
+       printk(KERN_INFO DRV_NAME
+               "(%s): resetting host\n", pci_name(hba->pdev));
+       scsi_print_command(cmd);
+
        hba->mu_status = MU_STATE_RESETTING;
 
        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;
        }
-       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);
 
+       /* 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);
+       }
+
+       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;
 }
@@ -1051,7 +1108,7 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto out_scsi_host_put;
        }
 
-       hba->mmio_base = ioremap(pci_resource_start(pdev, 0),
+       hba->mmio_base = ioremap_nocache(pci_resource_start(pdev, 0),
                pci_resource_len(pdev, 0));
        if ( !hba->mmio_base) {
                printk(KERN_ERR DRV_NAME "(%s): memory map failed\n",
@@ -1067,8 +1124,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",
@@ -1081,14 +1143,18 @@ 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 */
-       host->max_channel = ST_MAX_LUN_PER_TARGET - 1;
-       host->max_id = ST_MAX_TARGET_NUM;
-       host->max_lun = 1;
+       if (hba->cardtype == st_shasta) {
+               host->max_lun = 8;
+               host->max_id = 16 + 1;
+       } else if (hba->cardtype == st_yosemite) {
+               host->max_lun = 128;
+               host->max_id = 1 + 1;
+       } else {
+               /* st_vsc and st_vsc1 */
+               host->max_lun = 1;
+               host->max_id = 128 + 1;
+       }
+       host->max_channel = 0;
        host->unique_id = host->host_no;
        host->max_cmd_len = STEX_CDB_LENGTH;
 
@@ -1107,7 +1173,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));
@@ -1130,7 +1196,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);
@@ -1155,9 +1221,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;
@@ -1184,7 +1257,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);
 }
 
@@ -1213,14 +1286,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);