aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/stex.c249
1 files changed, 166 insertions, 83 deletions
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index af5bafcccf1f..79216ee8112b 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -64,24 +64,24 @@ enum {
64 YH2I_REQ_HI = 0xc4, 64 YH2I_REQ_HI = 0xc4,
65 65
66 /* MU register value */ 66 /* MU register value */
67 MU_INBOUND_DOORBELL_HANDSHAKE = 1, 67 MU_INBOUND_DOORBELL_HANDSHAKE = (1 << 0),
68 MU_INBOUND_DOORBELL_REQHEADCHANGED = 2, 68 MU_INBOUND_DOORBELL_REQHEADCHANGED = (1 << 1),
69 MU_INBOUND_DOORBELL_STATUSTAILCHANGED = 4, 69 MU_INBOUND_DOORBELL_STATUSTAILCHANGED = (1 << 2),
70 MU_INBOUND_DOORBELL_HMUSTOPPED = 8, 70 MU_INBOUND_DOORBELL_HMUSTOPPED = (1 << 3),
71 MU_INBOUND_DOORBELL_RESET = 16, 71 MU_INBOUND_DOORBELL_RESET = (1 << 4),
72 72
73 MU_OUTBOUND_DOORBELL_HANDSHAKE = 1, 73 MU_OUTBOUND_DOORBELL_HANDSHAKE = (1 << 0),
74 MU_OUTBOUND_DOORBELL_REQUESTTAILCHANGED = 2, 74 MU_OUTBOUND_DOORBELL_REQUESTTAILCHANGED = (1 << 1),
75 MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED = 4, 75 MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED = (1 << 2),
76 MU_OUTBOUND_DOORBELL_BUSCHANGE = 8, 76 MU_OUTBOUND_DOORBELL_BUSCHANGE = (1 << 3),
77 MU_OUTBOUND_DOORBELL_HASEVENT = 16, 77 MU_OUTBOUND_DOORBELL_HASEVENT = (1 << 4),
78 MU_OUTBOUND_DOORBELL_REQUEST_RESET = (1 << 27),
78 79
79 /* MU status code */ 80 /* MU status code */
80 MU_STATE_STARTING = 1, 81 MU_STATE_STARTING = 1,
81 MU_STATE_FMU_READY_FOR_HANDSHAKE = 2, 82 MU_STATE_STARTED = 2,
82 MU_STATE_SEND_HANDSHAKE_FRAME = 3, 83 MU_STATE_RESETTING = 3,
83 MU_STATE_STARTED = 4, 84 MU_STATE_FAILED = 4,
84 MU_STATE_RESETTING = 5,
85 85
86 MU_MAX_DELAY = 120, 86 MU_MAX_DELAY = 120,
87 MU_HANDSHAKE_SIGNATURE = 0x55aaaa55, 87 MU_HANDSHAKE_SIGNATURE = 0x55aaaa55,
@@ -111,6 +111,8 @@ enum {
111 111
112 SS_H2I_INT_RESET = 0x100, 112 SS_H2I_INT_RESET = 0x100,
113 113
114 SS_I2H_REQUEST_RESET = 0x2000,
115
114 SS_MU_OPERATIONAL = 0x80000000, 116 SS_MU_OPERATIONAL = 0x80000000,
115 117
116 STEX_CDB_LENGTH = 16, 118 STEX_CDB_LENGTH = 16,
@@ -312,6 +314,10 @@ struct st_hba {
312 struct st_ccb *wait_ccb; 314 struct st_ccb *wait_ccb;
313 __le32 *scratch; 315 __le32 *scratch;
314 316
317 char work_q_name[20];
318 struct workqueue_struct *work_q;
319 struct work_struct reset_work;
320 wait_queue_head_t reset_waitq;
315 unsigned int mu_status; 321 unsigned int mu_status;
316 unsigned int cardtype; 322 unsigned int cardtype;
317 int msi_enabled; 323 int msi_enabled;
@@ -578,6 +584,9 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
578 lun = cmd->device->lun; 584 lun = cmd->device->lun;
579 hba = (struct st_hba *) &host->hostdata[0]; 585 hba = (struct st_hba *) &host->hostdata[0];
580 586
587 if (unlikely(hba->mu_status == MU_STATE_RESETTING))
588 return SCSI_MLQUEUE_HOST_BUSY;
589
581 switch (cmd->cmnd[0]) { 590 switch (cmd->cmnd[0]) {
582 case MODE_SENSE_10: 591 case MODE_SENSE_10:
583 { 592 {
@@ -842,7 +851,6 @@ static irqreturn_t stex_intr(int irq, void *__hba)
842 void __iomem *base = hba->mmio_base; 851 void __iomem *base = hba->mmio_base;
843 u32 data; 852 u32 data;
844 unsigned long flags; 853 unsigned long flags;
845 int handled = 0;
846 854
847 spin_lock_irqsave(hba->host->host_lock, flags); 855 spin_lock_irqsave(hba->host->host_lock, flags);
848 856
@@ -853,12 +861,16 @@ static irqreturn_t stex_intr(int irq, void *__hba)
853 writel(data, base + ODBL); 861 writel(data, base + ODBL);
854 readl(base + ODBL); /* flush */ 862 readl(base + ODBL); /* flush */
855 stex_mu_intr(hba, data); 863 stex_mu_intr(hba, data);
856 handled = 1; 864 spin_unlock_irqrestore(hba->host->host_lock, flags);
865 if (unlikely(data & MU_OUTBOUND_DOORBELL_REQUEST_RESET &&
866 hba->cardtype == st_shasta))
867 queue_work(hba->work_q, &hba->reset_work);
868 return IRQ_HANDLED;
857 } 869 }
858 870
859 spin_unlock_irqrestore(hba->host->host_lock, flags); 871 spin_unlock_irqrestore(hba->host->host_lock, flags);
860 872
861 return IRQ_RETVAL(handled); 873 return IRQ_NONE;
862} 874}
863 875
864static void stex_ss_mu_intr(struct st_hba *hba) 876static void stex_ss_mu_intr(struct st_hba *hba)
@@ -940,7 +952,6 @@ static irqreturn_t stex_ss_intr(int irq, void *__hba)
940 void __iomem *base = hba->mmio_base; 952 void __iomem *base = hba->mmio_base;
941 u32 data; 953 u32 data;
942 unsigned long flags; 954 unsigned long flags;
943 int handled = 0;
944 955
945 spin_lock_irqsave(hba->host->host_lock, flags); 956 spin_lock_irqsave(hba->host->host_lock, flags);
946 957
@@ -949,12 +960,15 @@ static irqreturn_t stex_ss_intr(int irq, void *__hba)
949 /* clear the interrupt */ 960 /* clear the interrupt */
950 writel(data, base + YI2H_INT_C); 961 writel(data, base + YI2H_INT_C);
951 stex_ss_mu_intr(hba); 962 stex_ss_mu_intr(hba);
952 handled = 1; 963 spin_unlock_irqrestore(hba->host->host_lock, flags);
964 if (unlikely(data & SS_I2H_REQUEST_RESET))
965 queue_work(hba->work_q, &hba->reset_work);
966 return IRQ_HANDLED;
953 } 967 }
954 968
955 spin_unlock_irqrestore(hba->host->host_lock, flags); 969 spin_unlock_irqrestore(hba->host->host_lock, flags);
956 970
957 return IRQ_RETVAL(handled); 971 return IRQ_NONE;
958} 972}
959 973
960static int stex_common_handshake(struct st_hba *hba) 974static int stex_common_handshake(struct st_hba *hba)
@@ -1047,7 +1061,7 @@ static int stex_ss_handshake(struct st_hba *hba)
1047 struct st_msg_header *msg_h; 1061 struct st_msg_header *msg_h;
1048 struct handshake_frame *h; 1062 struct handshake_frame *h;
1049 __le32 *scratch; 1063 __le32 *scratch;
1050 u32 data; 1064 u32 data, scratch_size;
1051 unsigned long before; 1065 unsigned long before;
1052 int ret = 0; 1066 int ret = 0;
1053 1067
@@ -1075,13 +1089,16 @@ static int stex_ss_handshake(struct st_hba *hba)
1075 stex_gettime(&h->hosttime); 1089 stex_gettime(&h->hosttime);
1076 h->partner_type = HMU_PARTNER_TYPE; 1090 h->partner_type = HMU_PARTNER_TYPE;
1077 h->extra_offset = h->extra_size = 0; 1091 h->extra_offset = h->extra_size = 0;
1078 h->scratch_size = cpu_to_le32((hba->sts_count+1)*sizeof(u32)); 1092 scratch_size = (hba->sts_count+1)*sizeof(u32);
1093 h->scratch_size = cpu_to_le32(scratch_size);
1079 1094
1080 data = readl(base + YINT_EN); 1095 data = readl(base + YINT_EN);
1081 data &= ~4; 1096 data &= ~4;
1082 writel(data, base + YINT_EN); 1097 writel(data, base + YINT_EN);
1083 writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI); 1098 writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI);
1099 readl(base + YH2I_REQ_HI);
1084 writel(hba->dma_handle, base + YH2I_REQ); 1100 writel(hba->dma_handle, base + YH2I_REQ);
1101 readl(base + YH2I_REQ); /* flush */
1085 1102
1086 scratch = hba->scratch; 1103 scratch = hba->scratch;
1087 before = jiffies; 1104 before = jiffies;
@@ -1097,7 +1114,7 @@ static int stex_ss_handshake(struct st_hba *hba)
1097 msleep(1); 1114 msleep(1);
1098 } 1115 }
1099 1116
1100 *scratch = 0; 1117 memset(scratch, 0, scratch_size);
1101 msg_h->flag = 0; 1118 msg_h->flag = 0;
1102 return ret; 1119 return ret;
1103} 1120}
@@ -1106,19 +1123,24 @@ static int stex_handshake(struct st_hba *hba)
1106{ 1123{
1107 int err; 1124 int err;
1108 unsigned long flags; 1125 unsigned long flags;
1126 unsigned int mu_status;
1109 1127
1110 err = (hba->cardtype == st_yel) ? 1128 err = (hba->cardtype == st_yel) ?
1111 stex_ss_handshake(hba) : stex_common_handshake(hba); 1129 stex_ss_handshake(hba) : stex_common_handshake(hba);
1130 spin_lock_irqsave(hba->host->host_lock, flags);
1131 mu_status = hba->mu_status;
1112 if (err == 0) { 1132 if (err == 0) {
1113 spin_lock_irqsave(hba->host->host_lock, flags);
1114 hba->req_head = 0; 1133 hba->req_head = 0;
1115 hba->req_tail = 0; 1134 hba->req_tail = 0;
1116 hba->status_head = 0; 1135 hba->status_head = 0;
1117 hba->status_tail = 0; 1136 hba->status_tail = 0;
1118 hba->out_req_cnt = 0; 1137 hba->out_req_cnt = 0;
1119 hba->mu_status = MU_STATE_STARTED; 1138 hba->mu_status = MU_STATE_STARTED;
1120 spin_unlock_irqrestore(hba->host->host_lock, flags); 1139 } else
1121 } 1140 hba->mu_status = MU_STATE_FAILED;
1141 if (mu_status == MU_STATE_RESETTING)
1142 wake_up_all(&hba->reset_waitq);
1143 spin_unlock_irqrestore(hba->host->host_lock, flags);
1122 return err; 1144 return err;
1123} 1145}
1124 1146
@@ -1138,17 +1160,11 @@ static int stex_abort(struct scsi_cmnd *cmd)
1138 1160
1139 base = hba->mmio_base; 1161 base = hba->mmio_base;
1140 spin_lock_irqsave(host->host_lock, flags); 1162 spin_lock_irqsave(host->host_lock, flags);
1141 if (tag < host->can_queue && hba->ccb[tag].cmd == cmd) 1163 if (tag < host->can_queue &&
1164 hba->ccb[tag].req && hba->ccb[tag].cmd == cmd)
1142 hba->wait_ccb = &hba->ccb[tag]; 1165 hba->wait_ccb = &hba->ccb[tag];
1143 else { 1166 else
1144 for (tag = 0; tag < host->can_queue; tag++) 1167 goto out;
1145 if (hba->ccb[tag].cmd == cmd) {
1146 hba->wait_ccb = &hba->ccb[tag];
1147 break;
1148 }
1149 if (tag >= host->can_queue)
1150 goto out;
1151 }
1152 1168
1153 if (hba->cardtype == st_yel) { 1169 if (hba->cardtype == st_yel) {
1154 data = readl(base + YI2H_INT); 1170 data = readl(base + YI2H_INT);
@@ -1222,6 +1238,37 @@ static void stex_hard_reset(struct st_hba *hba)
1222 hba->pdev->saved_config_space[i]); 1238 hba->pdev->saved_config_space[i]);
1223} 1239}
1224 1240
1241static int stex_yos_reset(struct st_hba *hba)
1242{
1243 void __iomem *base;
1244 unsigned long flags, before;
1245 int ret = 0;
1246
1247 base = hba->mmio_base;
1248 writel(MU_INBOUND_DOORBELL_RESET, base + IDBL);
1249 readl(base + IDBL); /* flush */
1250 before = jiffies;
1251 while (hba->out_req_cnt > 0) {
1252 if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {
1253 printk(KERN_WARNING DRV_NAME
1254 "(%s): reset timeout\n", pci_name(hba->pdev));
1255 ret = -1;
1256 break;
1257 }
1258 msleep(1);
1259 }
1260
1261 spin_lock_irqsave(hba->host->host_lock, flags);
1262 if (ret == -1)
1263 hba->mu_status = MU_STATE_FAILED;
1264 else
1265 hba->mu_status = MU_STATE_STARTED;
1266 wake_up_all(&hba->reset_waitq);
1267 spin_unlock_irqrestore(hba->host->host_lock, flags);
1268
1269 return ret;
1270}
1271
1225static void stex_ss_reset(struct st_hba *hba) 1272static void stex_ss_reset(struct st_hba *hba)
1226{ 1273{
1227 writel(SS_H2I_INT_RESET, hba->mmio_base + YH2I_INT); 1274 writel(SS_H2I_INT_RESET, hba->mmio_base + YH2I_INT);
@@ -1229,66 +1276,86 @@ static void stex_ss_reset(struct st_hba *hba)
1229 ssleep(5); 1276 ssleep(5);
1230} 1277}
1231 1278
1232static int stex_reset(struct scsi_cmnd *cmd) 1279static int stex_do_reset(struct st_hba *hba)
1233{ 1280{
1234 struct st_hba *hba; 1281 struct st_ccb *ccb;
1235 void __iomem *base; 1282 unsigned long flags;
1236 unsigned long flags, before; 1283 unsigned int mu_status = MU_STATE_RESETTING;
1284 u16 tag;
1237 1285
1238 hba = (struct st_hba *) &cmd->device->host->hostdata[0]; 1286 spin_lock_irqsave(hba->host->host_lock, flags);
1287 if (hba->mu_status == MU_STATE_STARTING) {
1288 spin_unlock_irqrestore(hba->host->host_lock, flags);
1289 printk(KERN_INFO DRV_NAME "(%s): request reset during init\n",
1290 pci_name(hba->pdev));
1291 return 0;
1292 }
1293 while (hba->mu_status == MU_STATE_RESETTING) {
1294 spin_unlock_irqrestore(hba->host->host_lock, flags);
1295 wait_event_timeout(hba->reset_waitq,
1296 hba->mu_status != MU_STATE_RESETTING,
1297 MU_MAX_DELAY * HZ);
1298 spin_lock_irqsave(hba->host->host_lock, flags);
1299 mu_status = hba->mu_status;
1300 }
1239 1301
1240 printk(KERN_INFO DRV_NAME 1302 if (mu_status != MU_STATE_RESETTING) {
1241 "(%s): resetting host\n", pci_name(hba->pdev)); 1303 spin_unlock_irqrestore(hba->host->host_lock, flags);
1242 scsi_print_command(cmd); 1304 return (mu_status == MU_STATE_STARTED) ? 0 : -1;
1305 }
1243 1306
1244 hba->mu_status = MU_STATE_RESETTING; 1307 hba->mu_status = MU_STATE_RESETTING;
1308 spin_unlock_irqrestore(hba->host->host_lock, flags);
1309
1310 if (hba->cardtype == st_yosemite)
1311 return stex_yos_reset(hba);
1245 1312
1246 if (hba->cardtype == st_shasta) 1313 if (hba->cardtype == st_shasta)
1247 stex_hard_reset(hba); 1314 stex_hard_reset(hba);
1248 else if (hba->cardtype == st_yel) 1315 else if (hba->cardtype == st_yel)
1249 stex_ss_reset(hba); 1316 stex_ss_reset(hba);
1250 1317
1251 if (hba->cardtype != st_yosemite) { 1318 spin_lock_irqsave(hba->host->host_lock, flags);
1252 if (stex_handshake(hba)) { 1319 for (tag = 0; tag < hba->host->can_queue; tag++) {
1253 printk(KERN_WARNING DRV_NAME 1320 ccb = &hba->ccb[tag];
1254 "(%s): resetting: handshake failed\n", 1321 if (ccb->req == NULL)
1255 pci_name(hba->pdev)); 1322 continue;
1256 return FAILED; 1323 ccb->req = NULL;
1324 if (ccb->cmd) {
1325 scsi_dma_unmap(ccb->cmd);
1326 ccb->cmd->result = DID_RESET << 16;
1327 ccb->cmd->scsi_done(ccb->cmd);
1328 ccb->cmd = NULL;
1257 } 1329 }
1258 return SUCCESS;
1259 } 1330 }
1331 spin_unlock_irqrestore(hba->host->host_lock, flags);
1260 1332
1261 /* st_yosemite */ 1333 if (stex_handshake(hba) == 0)
1262 writel(MU_INBOUND_DOORBELL_RESET, hba->mmio_base + IDBL); 1334 return 0;
1263 readl(hba->mmio_base + IDBL); /* flush */
1264 before = jiffies;
1265 while (hba->out_req_cnt > 0) {
1266 if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {
1267 printk(KERN_WARNING DRV_NAME
1268 "(%s): reset timeout\n", pci_name(hba->pdev));
1269 return FAILED;
1270 }
1271 msleep(1);
1272 }
1273 1335
1274 base = hba->mmio_base; 1336 printk(KERN_WARNING DRV_NAME "(%s): resetting: handshake failed\n",
1275 writel(0, base + IMR0); 1337 pci_name(hba->pdev));
1276 readl(base + IMR0); 1338 return -1;
1277 writel(0, base + OMR0); 1339}
1278 readl(base + OMR0); 1340
1279 writel(0, base + IMR1); 1341static int stex_reset(struct scsi_cmnd *cmd)
1280 readl(base + IMR1); 1342{
1281 writel(0, base + OMR1); 1343 struct st_hba *hba;
1282 readl(base + OMR1); /* flush */ 1344
1283 spin_lock_irqsave(hba->host->host_lock, flags); 1345 hba = (struct st_hba *) &cmd->device->host->hostdata[0];
1284 hba->req_head = 0; 1346
1285 hba->req_tail = 0; 1347 printk(KERN_INFO DRV_NAME
1286 hba->status_head = 0; 1348 "(%s): resetting host\n", pci_name(hba->pdev));
1287 hba->status_tail = 0; 1349 scsi_print_command(cmd);
1288 hba->out_req_cnt = 0; 1350
1289 hba->mu_status = MU_STATE_STARTED; 1351 return stex_do_reset(hba) ? FAILED : SUCCESS;
1290 spin_unlock_irqrestore(hba->host->host_lock, flags); 1352}
1291 return SUCCESS; 1353
1354static void stex_reset_work(struct work_struct *work)
1355{
1356 struct st_hba *hba = container_of(work, struct st_hba, reset_work);
1357
1358 stex_do_reset(hba);
1292} 1359}
1293 1360
1294static int stex_biosparam(struct scsi_device *sdev, 1361static int stex_biosparam(struct scsi_device *sdev,
@@ -1583,12 +1650,24 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1583 1650
1584 hba->host = host; 1651 hba->host = host;
1585 hba->pdev = pdev; 1652 hba->pdev = pdev;
1653 init_waitqueue_head(&hba->reset_waitq);
1654
1655 snprintf(hba->work_q_name, sizeof(hba->work_q_name),
1656 "stex_wq_%d", host->host_no);
1657 hba->work_q = create_singlethread_workqueue(hba->work_q_name);
1658 if (!hba->work_q) {
1659 printk(KERN_ERR DRV_NAME "(%s): create workqueue failed\n",
1660 pci_name(pdev));
1661 err = -ENOMEM;
1662 goto out_ccb_free;
1663 }
1664 INIT_WORK(&hba->reset_work, stex_reset_work);
1586 1665
1587 err = stex_request_irq(hba); 1666 err = stex_request_irq(hba);
1588 if (err) { 1667 if (err) {
1589 printk(KERN_ERR DRV_NAME "(%s): request irq failed\n", 1668 printk(KERN_ERR DRV_NAME "(%s): request irq failed\n",
1590 pci_name(pdev)); 1669 pci_name(pdev));
1591 goto out_ccb_free; 1670 goto out_free_wq;
1592 } 1671 }
1593 1672
1594 err = stex_handshake(hba); 1673 err = stex_handshake(hba);
@@ -1617,6 +1696,8 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1617 1696
1618out_free_irq: 1697out_free_irq:
1619 stex_free_irq(hba); 1698 stex_free_irq(hba);
1699out_free_wq:
1700 destroy_workqueue(hba->work_q);
1620out_ccb_free: 1701out_ccb_free:
1621 kfree(hba->ccb); 1702 kfree(hba->ccb);
1622out_pci_free: 1703out_pci_free:
@@ -1684,6 +1765,8 @@ static void stex_hba_free(struct st_hba *hba)
1684{ 1765{
1685 stex_free_irq(hba); 1766 stex_free_irq(hba);
1686 1767
1768 destroy_workqueue(hba->work_q);
1769
1687 iounmap(hba->mmio_base); 1770 iounmap(hba->mmio_base);
1688 1771
1689 pci_release_regions(hba->pdev); 1772 pci_release_regions(hba->pdev);