diff options
author | Ed Lin <ed.lin@promise.com> | 2009-09-29 02:58:33 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-10-29 13:03:26 -0400 |
commit | 9eb46d2a08de537e14e92216bf18e7cb541d2f67 (patch) | |
tree | 659275fbba68b4e5e5a8cf9ffa667ea5e6b2376c /drivers/scsi/stex.c | |
parent | cbacfb5fd9a4689b55157753b8ba4455415fb85c (diff) |
[SCSI] stex: add support for reset request from firmware
Add support for reset request from firmware for controllers
of st_shasta and st_yel type. Code adjustments necessary
for this change are also included.
Signed-off-by: Ed Lin <ed.lin@promise.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/stex.c')
-rw-r--r-- | drivers/scsi/stex.c | 249 |
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 | ||
864 | static void stex_ss_mu_intr(struct st_hba *hba) | 876 | static 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 | ||
960 | static int stex_common_handshake(struct st_hba *hba) | 974 | static 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 | ||
1241 | static 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 | |||
1225 | static void stex_ss_reset(struct st_hba *hba) | 1272 | static 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 | ||
1232 | static int stex_reset(struct scsi_cmnd *cmd) | 1279 | static 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); | 1341 | static 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 | |
1354 | static 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 | ||
1294 | static int stex_biosparam(struct scsi_device *sdev, | 1361 | static 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 | ||
1618 | out_free_irq: | 1697 | out_free_irq: |
1619 | stex_free_irq(hba); | 1698 | stex_free_irq(hba); |
1699 | out_free_wq: | ||
1700 | destroy_workqueue(hba->work_q); | ||
1620 | out_ccb_free: | 1701 | out_ccb_free: |
1621 | kfree(hba->ccb); | 1702 | kfree(hba->ccb); |
1622 | out_pci_free: | 1703 | out_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); |