X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fscsi%2Fstex.c;h=f308a030882916aed13c1805ef9213758e1313eb;hb=bbd1ae412c9eb09ae7bb11cfaf7018a2367d493f;hp=3cf3106a29b8e45fb6515817e5c9280cff07900d;hpb=deb81d80ba27da8dfabc29ccb5977db8f4942a0a;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 3cf3106..f308a03 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -11,15 +11,12 @@ * Written By: * Ed Lin * - * Version: 2.9.0.13 - * */ #include #include #include #include -#include #include #include #include @@ -35,13 +32,15 @@ #include #include #include +#include +#include #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 { @@ -181,7 +223,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 +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; + dst->sz_in_byte = cpu_to_le32(scsi_bufflen(cmd)); - 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; + nseg = scsi_dma_map(cmd); + if (nseg < 0) + return -EIO; + if (nseg) { + ccb->sg_count = nseg; + dst->sg_count = cpu_to_le16((u16)nseg); - ccb->sg_count = n_elem; - dst->sg_count = cpu_to_le16((u16)n_elem); - - 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 @@ -489,7 +452,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++; @@ -537,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]) { @@ -548,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 @@ -570,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); @@ -595,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; @@ -613,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; @@ -680,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) @@ -702,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; } @@ -723,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; } @@ -741,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) { @@ -764,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; @@ -794,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); @@ -824,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); @@ -837,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); @@ -871,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) @@ -901,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; @@ -927,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); } @@ -948,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; + } + + /* 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; } @@ -1052,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", @@ -1068,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", @@ -1082,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; @@ -1108,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)); @@ -1131,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); @@ -1156,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; @@ -1185,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); } @@ -1214,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);