diff options
| -rw-r--r-- | drivers/scsi/stex.c | 194 |
1 files changed, 164 insertions, 30 deletions
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index cfb29716b5e2..a54e6c1026b7 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | * Written By: | 11 | * Written By: |
| 12 | * Ed Lin <promise_linux@promise.com> | 12 | * Ed Lin <promise_linux@promise.com> |
| 13 | * | 13 | * |
| 14 | * Version: 2.9.0.13 | 14 | * Version: 3.0.0.1 |
| 15 | * | 15 | * |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| @@ -37,11 +37,11 @@ | |||
| 37 | #include <scsi/scsi_tcq.h> | 37 | #include <scsi/scsi_tcq.h> |
| 38 | 38 | ||
| 39 | #define DRV_NAME "stex" | 39 | #define DRV_NAME "stex" |
| 40 | #define ST_DRIVER_VERSION "2.9.0.13" | 40 | #define ST_DRIVER_VERSION "3.0.0.1" |
| 41 | #define ST_VER_MAJOR 2 | 41 | #define ST_VER_MAJOR 3 |
| 42 | #define ST_VER_MINOR 9 | 42 | #define ST_VER_MINOR 0 |
| 43 | #define ST_OEM 0 | 43 | #define ST_OEM 0 |
| 44 | #define ST_BUILD_VER 13 | 44 | #define ST_BUILD_VER 1 |
| 45 | 45 | ||
| 46 | enum { | 46 | enum { |
| 47 | /* MU register offset */ | 47 | /* MU register offset */ |
| @@ -120,12 +120,18 @@ enum { | |||
| 120 | 120 | ||
| 121 | st_shasta = 0, | 121 | st_shasta = 0, |
| 122 | st_vsc = 1, | 122 | st_vsc = 1, |
| 123 | st_yosemite = 2, | ||
| 123 | 124 | ||
| 124 | PASSTHRU_REQ_TYPE = 0x00000001, | 125 | PASSTHRU_REQ_TYPE = 0x00000001, |
| 125 | PASSTHRU_REQ_NO_WAKEUP = 0x00000100, | 126 | PASSTHRU_REQ_NO_WAKEUP = 0x00000100, |
| 126 | ST_INTERNAL_TIMEOUT = 30, | 127 | ST_INTERNAL_TIMEOUT = 30, |
| 127 | 128 | ||
| 129 | ST_TO_CMD = 0, | ||
| 130 | ST_FROM_CMD = 1, | ||
| 131 | |||
| 128 | /* vendor specific commands of Promise */ | 132 | /* vendor specific commands of Promise */ |
| 133 | MGT_CMD = 0xd8, | ||
| 134 | SINBAND_MGT_CMD = 0xd9, | ||
| 129 | ARRAY_CMD = 0xe0, | 135 | ARRAY_CMD = 0xe0, |
| 130 | CONTROLLER_CMD = 0xe1, | 136 | CONTROLLER_CMD = 0xe1, |
| 131 | DEBUGGING_CMD = 0xe2, | 137 | DEBUGGING_CMD = 0xe2, |
| @@ -133,14 +139,48 @@ enum { | |||
| 133 | 139 | ||
| 134 | PASSTHRU_GET_ADAPTER = 0x05, | 140 | PASSTHRU_GET_ADAPTER = 0x05, |
| 135 | PASSTHRU_GET_DRVVER = 0x10, | 141 | PASSTHRU_GET_DRVVER = 0x10, |
| 142 | |||
| 143 | CTLR_CONFIG_CMD = 0x03, | ||
| 144 | CTLR_SHUTDOWN = 0x0d, | ||
| 145 | |||
| 136 | CTLR_POWER_STATE_CHANGE = 0x0e, | 146 | CTLR_POWER_STATE_CHANGE = 0x0e, |
| 137 | CTLR_POWER_SAVING = 0x01, | 147 | CTLR_POWER_SAVING = 0x01, |
| 138 | 148 | ||
| 139 | PASSTHRU_SIGNATURE = 0x4e415041, | 149 | PASSTHRU_SIGNATURE = 0x4e415041, |
| 150 | MGT_CMD_SIGNATURE = 0xba, | ||
| 140 | 151 | ||
| 141 | INQUIRY_EVPD = 0x01, | 152 | INQUIRY_EVPD = 0x01, |
| 142 | }; | 153 | }; |
| 143 | 154 | ||
| 155 | /* SCSI inquiry data */ | ||
| 156 | typedef struct st_inq { | ||
| 157 | u8 DeviceType :5; | ||
| 158 | u8 DeviceTypeQualifier :3; | ||
| 159 | u8 DeviceTypeModifier :7; | ||
| 160 | u8 RemovableMedia :1; | ||
| 161 | u8 Versions; | ||
| 162 | u8 ResponseDataFormat :4; | ||
| 163 | u8 HiSupport :1; | ||
| 164 | u8 NormACA :1; | ||
| 165 | u8 ReservedBit :1; | ||
| 166 | u8 AERC :1; | ||
| 167 | u8 AdditionalLength; | ||
| 168 | u8 Reserved[2]; | ||
| 169 | u8 SoftReset :1; | ||
| 170 | u8 CommandQueue :1; | ||
| 171 | u8 Reserved2 :1; | ||
| 172 | u8 LinkedCommands :1; | ||
| 173 | u8 Synchronous :1; | ||
| 174 | u8 Wide16Bit :1; | ||
| 175 | u8 Wide32Bit :1; | ||
| 176 | u8 RelativeAddressing :1; | ||
| 177 | u8 VendorId[8]; | ||
| 178 | u8 ProductId[16]; | ||
| 179 | u8 ProductRevisionLevel[4]; | ||
| 180 | u8 VendorSpecific[20]; | ||
| 181 | u8 Reserved3[40]; | ||
| 182 | } ST_INQ; | ||
| 183 | |||
| 144 | struct st_sgitem { | 184 | struct st_sgitem { |
| 145 | u8 ctrl; /* SG_CF_xxx */ | 185 | u8 ctrl; /* SG_CF_xxx */ |
| 146 | u8 reserved[3]; | 186 | u8 reserved[3]; |
| @@ -242,7 +282,8 @@ struct st_drvver { | |||
| 242 | #define MU_REQ_BUFFER_SIZE (MU_REQ_COUNT * sizeof(struct req_msg)) | 282 | #define MU_REQ_BUFFER_SIZE (MU_REQ_COUNT * sizeof(struct req_msg)) |
| 243 | #define MU_STATUS_BUFFER_SIZE (MU_STATUS_COUNT * sizeof(struct status_msg)) | 283 | #define MU_STATUS_BUFFER_SIZE (MU_STATUS_COUNT * sizeof(struct status_msg)) |
| 244 | #define MU_BUFFER_SIZE (MU_REQ_BUFFER_SIZE + MU_STATUS_BUFFER_SIZE) | 284 | #define MU_BUFFER_SIZE (MU_REQ_BUFFER_SIZE + MU_STATUS_BUFFER_SIZE) |
| 245 | #define STEX_BUFFER_SIZE (MU_BUFFER_SIZE + sizeof(struct st_frame)) | 285 | #define STEX_EXTRA_SIZE max(sizeof(struct st_frame), sizeof(ST_INQ)) |
| 286 | #define STEX_BUFFER_SIZE (MU_BUFFER_SIZE + STEX_EXTRA_SIZE) | ||
| 246 | 287 | ||
| 247 | struct st_ccb { | 288 | struct st_ccb { |
| 248 | struct req_msg *req; | 289 | struct req_msg *req; |
| @@ -403,7 +444,7 @@ static int stex_map_sg(struct st_hba *hba, | |||
| 403 | } | 444 | } |
| 404 | 445 | ||
| 405 | static void stex_internal_copy(struct scsi_cmnd *cmd, | 446 | static void stex_internal_copy(struct scsi_cmnd *cmd, |
| 406 | const void *src, size_t *count, int sg_count) | 447 | const void *src, size_t *count, int sg_count, int direction) |
| 407 | { | 448 | { |
| 408 | size_t lcount; | 449 | size_t lcount; |
| 409 | size_t len; | 450 | size_t len; |
| @@ -427,7 +468,10 @@ static void stex_internal_copy(struct scsi_cmnd *cmd, | |||
| 427 | } else | 468 | } else |
| 428 | d = cmd->request_buffer; | 469 | d = cmd->request_buffer; |
| 429 | 470 | ||
| 430 | memcpy(d, s, len); | 471 | if (direction == ST_TO_CMD) |
| 472 | memcpy(d, s, len); | ||
| 473 | else | ||
| 474 | memcpy(s, d, len); | ||
| 431 | 475 | ||
| 432 | lcount -= len; | 476 | lcount -= len; |
| 433 | if (cmd->use_sg) | 477 | if (cmd->use_sg) |
| @@ -449,7 +493,7 @@ static int stex_direct_copy(struct scsi_cmnd *cmd, | |||
| 449 | return 0; | 493 | return 0; |
| 450 | } | 494 | } |
| 451 | 495 | ||
| 452 | stex_internal_copy(cmd, src, &cp_len, n_elem); | 496 | stex_internal_copy(cmd, src, &cp_len, n_elem, ST_TO_CMD); |
| 453 | 497 | ||
| 454 | if (cmd->use_sg) | 498 | if (cmd->use_sg) |
| 455 | pci_unmap_sg(hba->pdev, cmd->request_buffer, | 499 | pci_unmap_sg(hba->pdev, cmd->request_buffer, |
| @@ -480,7 +524,7 @@ static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb) | |||
| 480 | p->subid = | 524 | p->subid = |
| 481 | hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device; | 525 | hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device; |
| 482 | 526 | ||
| 483 | stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count); | 527 | stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count, ST_TO_CMD); |
| 484 | } | 528 | } |
| 485 | 529 | ||
| 486 | static void | 530 | static void |
| @@ -594,8 +638,14 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) | |||
| 594 | return SCSI_MLQUEUE_HOST_BUSY; | 638 | return SCSI_MLQUEUE_HOST_BUSY; |
| 595 | 639 | ||
| 596 | req = stex_alloc_req(hba); | 640 | req = stex_alloc_req(hba); |
| 597 | req->lun = lun; | 641 | |
| 598 | req->target = id; | 642 | if (hba->cardtype == st_yosemite) { |
| 643 | req->lun = lun * (ST_MAX_TARGET_NUM - 1) + id; | ||
| 644 | req->target = 0; | ||
| 645 | } else { | ||
| 646 | req->lun = lun; | ||
| 647 | req->target = id; | ||
| 648 | } | ||
| 599 | 649 | ||
| 600 | /* cdb */ | 650 | /* cdb */ |
| 601 | memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH); | 651 | memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH); |
| @@ -679,7 +729,51 @@ static void stex_copy_data(struct st_ccb *ccb, | |||
| 679 | 729 | ||
| 680 | if (ccb->cmd == NULL) | 730 | if (ccb->cmd == NULL) |
| 681 | return; | 731 | return; |
| 682 | stex_internal_copy(ccb->cmd, resp->variable, &count, ccb->sg_count); | 732 | stex_internal_copy(ccb->cmd, |
| 733 | resp->variable, &count, ccb->sg_count, ST_TO_CMD); | ||
| 734 | } | ||
| 735 | |||
| 736 | static void stex_ys_commands(struct st_hba *hba, | ||
| 737 | struct st_ccb *ccb, struct status_msg *resp) | ||
| 738 | { | ||
| 739 | size_t count; | ||
| 740 | |||
| 741 | if (ccb->cmd->cmnd[0] == MGT_CMD && | ||
| 742 | resp->scsi_status != SAM_STAT_CHECK_CONDITION) { | ||
| 743 | ccb->cmd->request_bufflen = | ||
| 744 | le32_to_cpu(*(__le32 *)&resp->variable[0]); | ||
| 745 | return; | ||
| 746 | } | ||
| 747 | |||
| 748 | if (resp->srb_status != 0) | ||
| 749 | return; | ||
| 750 | |||
| 751 | /* determine inquiry command status by DeviceTypeQualifier */ | ||
| 752 | if (ccb->cmd->cmnd[0] == INQUIRY && | ||
| 753 | resp->scsi_status == SAM_STAT_GOOD) { | ||
| 754 | ST_INQ *inq_data; | ||
| 755 | |||
| 756 | count = STEX_EXTRA_SIZE; | ||
| 757 | stex_internal_copy(ccb->cmd, hba->copy_buffer, | ||
| 758 | &count, ccb->sg_count, ST_FROM_CMD); | ||
| 759 | inq_data = (ST_INQ *)hba->copy_buffer; | ||
| 760 | if (inq_data->DeviceTypeQualifier != 0) | ||
| 761 | ccb->srb_status = SRB_STATUS_SELECTION_TIMEOUT; | ||
| 762 | else | ||
| 763 | ccb->srb_status = SRB_STATUS_SUCCESS; | ||
| 764 | } else if (ccb->cmd->cmnd[0] == REPORT_LUNS) { | ||
| 765 | u8 *report_lun_data = (u8 *)hba->copy_buffer; | ||
| 766 | |||
| 767 | count = STEX_EXTRA_SIZE; | ||
| 768 | stex_internal_copy(ccb->cmd, report_lun_data, | ||
| 769 | &count, ccb->sg_count, ST_FROM_CMD); | ||
| 770 | if (report_lun_data[2] || report_lun_data[3]) { | ||
| 771 | report_lun_data[2] = 0x00; | ||
| 772 | report_lun_data[3] = 0x08; | ||
| 773 | stex_internal_copy(ccb->cmd, report_lun_data, | ||
| 774 | &count, ccb->sg_count, ST_TO_CMD); | ||
| 775 | } | ||
| 776 | } | ||
| 683 | } | 777 | } |
| 684 | 778 | ||
| 685 | static void stex_mu_intr(struct st_hba *hba, u32 doorbell) | 779 | static void stex_mu_intr(struct st_hba *hba, u32 doorbell) |
| @@ -701,8 +795,17 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell) | |||
| 701 | return; | 795 | return; |
| 702 | } | 796 | } |
| 703 | 797 | ||
| 704 | if (unlikely(hba->mu_status != MU_STATE_STARTED || | 798 | /* |
| 705 | hba->out_req_cnt <= 0)) { | 799 | * it's not a valid status payload if: |
| 800 | * 1. there are no pending requests(e.g. during init stage) | ||
| 801 | * 2. there are some pending requests, but the controller is in | ||
| 802 | * reset status, and its type is not st_yosemite | ||
| 803 | * firmware of st_yosemite in reset status will return pending requests | ||
| 804 | * to driver, so we allow it to pass | ||
| 805 | */ | ||
| 806 | if (unlikely(hba->out_req_cnt <= 0 || | ||
| 807 | (hba->mu_status == MU_STATE_RESETTING && | ||
| 808 | hba->cardtype != st_yosemite))) { | ||
| 706 | hba->status_tail = hba->status_head; | 809 | hba->status_tail = hba->status_head; |
| 707 | goto update_status; | 810 | goto update_status; |
| 708 | } | 811 | } |
| @@ -722,6 +825,7 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell) | |||
| 722 | if (unlikely(ccb->req == NULL)) { | 825 | if (unlikely(ccb->req == NULL)) { |
| 723 | printk(KERN_WARNING DRV_NAME | 826 | printk(KERN_WARNING DRV_NAME |
| 724 | "(%s): lagging req\n", pci_name(hba->pdev)); | 827 | "(%s): lagging req\n", pci_name(hba->pdev)); |
| 828 | hba->out_req_cnt--; | ||
| 725 | continue; | 829 | continue; |
| 726 | } | 830 | } |
| 727 | 831 | ||
| @@ -740,9 +844,13 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell) | |||
| 740 | ccb->scsi_status = resp->scsi_status; | 844 | ccb->scsi_status = resp->scsi_status; |
| 741 | 845 | ||
| 742 | if (likely(ccb->cmd != NULL)) { | 846 | if (likely(ccb->cmd != NULL)) { |
| 847 | if (hba->cardtype == st_yosemite) | ||
| 848 | stex_ys_commands(hba, ccb, resp); | ||
| 849 | |||
| 743 | if (unlikely(ccb->cmd->cmnd[0] == PASSTHRU_CMD && | 850 | if (unlikely(ccb->cmd->cmnd[0] == PASSTHRU_CMD && |
| 744 | ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER)) | 851 | ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER)) |
| 745 | stex_controller_info(hba, ccb); | 852 | stex_controller_info(hba, ccb); |
| 853 | |||
| 746 | stex_unmap_sg(hba, ccb->cmd); | 854 | stex_unmap_sg(hba, ccb->cmd); |
| 747 | stex_scsi_done(ccb); | 855 | stex_scsi_done(ccb); |
| 748 | hba->out_req_cnt--; | 856 | hba->out_req_cnt--; |
| @@ -947,6 +1055,7 @@ static int stex_reset(struct scsi_cmnd *cmd) | |||
| 947 | { | 1055 | { |
| 948 | struct st_hba *hba; | 1056 | struct st_hba *hba; |
| 949 | unsigned long flags; | 1057 | unsigned long flags; |
| 1058 | unsigned long before; | ||
| 950 | hba = (struct st_hba *) &cmd->device->host->hostdata[0]; | 1059 | hba = (struct st_hba *) &cmd->device->host->hostdata[0]; |
| 951 | 1060 | ||
| 952 | hba->mu_status = MU_STATE_RESETTING; | 1061 | hba->mu_status = MU_STATE_RESETTING; |
| @@ -954,20 +1063,37 @@ static int stex_reset(struct scsi_cmnd *cmd) | |||
| 954 | if (hba->cardtype == st_shasta) | 1063 | if (hba->cardtype == st_shasta) |
| 955 | stex_hard_reset(hba); | 1064 | stex_hard_reset(hba); |
| 956 | 1065 | ||
| 957 | if (stex_handshake(hba)) { | 1066 | if (hba->cardtype != st_yosemite) { |
| 958 | printk(KERN_WARNING DRV_NAME | 1067 | if (stex_handshake(hba)) { |
| 959 | "(%s): resetting: handshake failed\n", | 1068 | printk(KERN_WARNING DRV_NAME |
| 960 | pci_name(hba->pdev)); | 1069 | "(%s): resetting: handshake failed\n", |
| 961 | return FAILED; | 1070 | pci_name(hba->pdev)); |
| 1071 | return FAILED; | ||
| 1072 | } | ||
| 1073 | spin_lock_irqsave(hba->host->host_lock, flags); | ||
| 1074 | hba->req_head = 0; | ||
| 1075 | hba->req_tail = 0; | ||
| 1076 | hba->status_head = 0; | ||
| 1077 | hba->status_tail = 0; | ||
| 1078 | hba->out_req_cnt = 0; | ||
| 1079 | spin_unlock_irqrestore(hba->host->host_lock, flags); | ||
| 1080 | return SUCCESS; | ||
| 962 | } | 1081 | } |
| 963 | spin_lock_irqsave(hba->host->host_lock, flags); | ||
| 964 | hba->req_head = 0; | ||
| 965 | hba->req_tail = 0; | ||
| 966 | hba->status_head = 0; | ||
| 967 | hba->status_tail = 0; | ||
| 968 | hba->out_req_cnt = 0; | ||
| 969 | spin_unlock_irqrestore(hba->host->host_lock, flags); | ||
| 970 | 1082 | ||
| 1083 | /* st_yosemite */ | ||
| 1084 | writel(MU_INBOUND_DOORBELL_RESET, hba->mmio_base + IDBL); | ||
| 1085 | readl(hba->mmio_base + IDBL); /* flush */ | ||
| 1086 | before = jiffies; | ||
| 1087 | while (hba->out_req_cnt > 0) { | ||
| 1088 | if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) { | ||
| 1089 | printk(KERN_WARNING DRV_NAME | ||
| 1090 | "(%s): reset timeout\n", pci_name(hba->pdev)); | ||
| 1091 | return FAILED; | ||
| 1092 | } | ||
| 1093 | msleep(1); | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | hba->mu_status = MU_STATE_STARTED; | ||
| 971 | return SUCCESS; | 1097 | return SUCCESS; |
| 972 | } | 1098 | } |
| 973 | 1099 | ||
| @@ -1155,9 +1281,16 @@ static void stex_hba_stop(struct st_hba *hba) | |||
| 1155 | req = stex_alloc_req(hba); | 1281 | req = stex_alloc_req(hba); |
| 1156 | memset(req->cdb, 0, STEX_CDB_LENGTH); | 1282 | memset(req->cdb, 0, STEX_CDB_LENGTH); |
| 1157 | 1283 | ||
| 1158 | req->cdb[0] = CONTROLLER_CMD; | 1284 | if (hba->cardtype == st_yosemite) { |
| 1159 | req->cdb[1] = CTLR_POWER_STATE_CHANGE; | 1285 | req->cdb[0] = MGT_CMD; |
| 1160 | req->cdb[2] = CTLR_POWER_SAVING; | 1286 | req->cdb[1] = MGT_CMD_SIGNATURE; |
| 1287 | req->cdb[2] = CTLR_CONFIG_CMD; | ||
| 1288 | req->cdb[3] = CTLR_SHUTDOWN; | ||
| 1289 | } else { | ||
| 1290 | req->cdb[0] = CONTROLLER_CMD; | ||
| 1291 | req->cdb[1] = CTLR_POWER_STATE_CHANGE; | ||
| 1292 | req->cdb[2] = CTLR_POWER_SAVING; | ||
| 1293 | } | ||
| 1161 | 1294 | ||
| 1162 | hba->ccb[tag].cmd = NULL; | 1295 | hba->ccb[tag].cmd = NULL; |
| 1163 | hba->ccb[tag].sg_count = 0; | 1296 | hba->ccb[tag].sg_count = 0; |
| @@ -1221,6 +1354,7 @@ static struct pci_device_id stex_pci_tbl[] = { | |||
| 1221 | { 0x105a, 0x8301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta }, | 1354 | { 0x105a, 0x8301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta }, |
| 1222 | { 0x105a, 0x8302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta }, | 1355 | { 0x105a, 0x8302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta }, |
| 1223 | { 0x1725, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc }, | 1356 | { 0x1725, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc }, |
| 1357 | { 0x105a, 0x8650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_yosemite }, | ||
| 1224 | { } /* terminate list */ | 1358 | { } /* terminate list */ |
| 1225 | }; | 1359 | }; |
| 1226 | MODULE_DEVICE_TABLE(pci, stex_pci_tbl); | 1360 | MODULE_DEVICE_TABLE(pci, stex_pci_tbl); |
