]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: David Wagner <david.wagner@qlogic.com> |
2 | Subject: qla2xxx: additional fixes/updates for SLES11 | |
3 | References: bnc#450197 | |
4 | ||
5 | Here's some additional updates/corrections to qla2xxx for SLES11. | |
6 | Should apply cleanly to the beta6 driver sources. | |
7 | ||
8 | [PATCH 1/5] qla2xxx: Add ISP84xx firmware-update support. | |
9 | [PATCH 2/5] qla2xxx: Add CT/ELS passthru support. | |
10 | [PATCH 3/5] qla2xxx: Use correct value for max vport in LOOP topology. | |
11 | [PATCH 4/5] qla2xxx: Correction of struct qla_flt_location. | |
12 | [PATCH 5/5] qla2xxx: Update version number to 8.02.01.02.11.0-k9. | |
13 | ||
14 | Corresponding upstream patches are queued in our local tree for | |
15 | for the next merge window (post 2.6.28). | |
16 | ||
17 | Signed-off-by: David Vasquez <david.vasquez@qlogic.com> | |
18 | Signed-off-by: Hannes Reinecke <hare@suse.de> | |
19 | ||
20 | diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile | |
21 | index c51fd1f..01ed81c 100644 | |
22 | --- a/drivers/scsi/qla2xxx/Makefile | |
23 | +++ b/drivers/scsi/qla2xxx/Makefile | |
24 | @@ -1,4 +1,5 @@ | |
25 | qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \ | |
26 | - qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o | |
27 | + qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o \ | |
28 | + qla_nlnk.o | |
29 | ||
30 | obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o | |
31 | diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c | |
32 | index ed73196..6d5210e 100644 | |
33 | --- a/drivers/scsi/qla2xxx/qla_attr.c | |
34 | +++ b/drivers/scsi/qla2xxx/qla_attr.c | |
35 | @@ -454,6 +454,287 @@ static struct bin_attribute sysfs_sfp_attr = { | |
36 | .read = qla2x00_sysfs_read_sfp, | |
37 | }; | |
38 | ||
39 | +static fc_port_t * | |
40 | +qla2x00_find_port(struct scsi_qla_host *ha, uint8_t *pn) | |
41 | +{ | |
42 | + fc_port_t *fcport; | |
43 | + | |
44 | + list_for_each_entry(fcport, &ha->fcports, list) | |
45 | + if (!memcmp(pn, fcport->port_name, sizeof(fcport->port_name))) | |
46 | + return fcport; | |
47 | + | |
48 | + return NULL; | |
49 | +} | |
50 | + | |
51 | +static void | |
52 | +qla2x00_wait_for_passthru_completion(struct scsi_qla_host *ha) | |
53 | +{ | |
54 | + if (!wait_for_completion_timeout(&ha->pass_thru_intr_comp, 10 * HZ)) { | |
55 | + DEBUG2(qla_printk(KERN_WARNING, ha, | |
56 | + "Passthru request timed out.\n")); | |
57 | + ha->isp_ops->fw_dump(ha, 0); | |
58 | + } | |
59 | +} | |
60 | + | |
61 | +static ssize_t | |
62 | +qla2x00_sysfs_read_els(struct kobject *kobj, struct bin_attribute *bin_attr, | |
63 | + char *buf, loff_t off, size_t count) | |
64 | +{ | |
65 | + struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, | |
66 | + struct device, kobj))); | |
67 | + | |
68 | + if (!IS_FWI2_CAPABLE(ha)) | |
69 | + return 0; | |
70 | + | |
71 | + if (!ha->pass_thru_cmd_in_process || !ha->pass_thru_cmd_result) { | |
72 | + DEBUG2(qla_printk(KERN_WARNING, ha, | |
73 | + "Passthru ELS response is not available.\n")); | |
74 | + return 0; | |
75 | + } | |
76 | + | |
77 | + memcpy(buf, ha->pass_thru, count); | |
78 | + | |
79 | + ha->pass_thru_cmd_result = 0; | |
80 | + ha->pass_thru_cmd_in_process = 0; | |
81 | + | |
82 | + return count; | |
83 | +} | |
84 | + | |
85 | +static ssize_t | |
86 | +qla2x00_sysfs_write_els(struct kobject *kobj, struct bin_attribute *bin_attr, | |
87 | + char *buf, loff_t off, size_t count) | |
88 | +{ | |
89 | + struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, | |
90 | + struct device, kobj))); | |
91 | + struct els_request *request = (struct els_request *) buf; | |
92 | + struct els_entry_24xx *els_iocb; | |
93 | + unsigned long flags; | |
94 | + uint16_t nextlid = 0; | |
95 | + fc_port_t *fcport; | |
96 | + | |
97 | + count -= sizeof(request->header); | |
98 | + | |
99 | + if (!IS_FWI2_CAPABLE(ha) || | |
100 | + atomic_read(&ha->loop_state) != LOOP_READY) | |
101 | + goto els_error0; | |
102 | + | |
103 | + if (count < sizeof(request->ct_iu)) { | |
104 | + DEBUG2(qla_printk(KERN_WARNING, ha, | |
105 | + "Passthru ELS buffer insufficient size %ld...\n", count)); | |
106 | + goto els_error0; | |
107 | + } | |
108 | + | |
109 | + if (ha->pass_thru_cmd_in_process || ha->pass_thru_cmd_result) { | |
110 | + DEBUG2(qla_printk(KERN_WARNING, ha, | |
111 | + "Passthru ELS request is already progress\n")); | |
112 | + goto els_error0; | |
113 | + } | |
114 | + | |
115 | + fcport = qla2x00_find_port(ha, request->header.WWPN); | |
116 | + if (!fcport) { | |
117 | + DEBUG2(qla_printk(KERN_WARNING, ha, | |
118 | + "Passthru ELS request failed find port\n")); | |
119 | + goto els_error0; | |
120 | + } | |
121 | + | |
122 | + if (qla2x00_fabric_login(ha, fcport, &nextlid)) { | |
123 | + DEBUG2(qla_printk(KERN_WARNING, ha, | |
124 | + "Passthru ELS request failed to login port %06X\n", | |
125 | + fcport->d_id.b24)); | |
126 | + goto els_error0; | |
127 | + } | |
128 | + | |
129 | + ha->pass_thru_cmd_in_process = 1; | |
130 | + spin_lock_irqsave(&ha->hardware_lock, flags); | |
131 | + | |
132 | + els_iocb = (void *)qla2x00_req_pkt(ha); | |
133 | + if (els_iocb == NULL) { | |
134 | + DEBUG2(qla_printk(KERN_WARNING, ha, | |
135 | + "Passthru ELS request failed to get request packet\n")); | |
136 | + goto els_error1; | |
137 | + } | |
138 | + | |
139 | + if (count > PAGE_SIZE) { | |
140 | + DEBUG2(qla_printk(KERN_INFO, ha, | |
141 | + "Passthru ELS request excessive size %ld...\n", count)); | |
142 | + count = PAGE_SIZE; | |
143 | + } | |
144 | + | |
145 | + memset(ha->pass_thru, 0, PAGE_SIZE); | |
146 | + memcpy(ha->pass_thru, &request->ct_iu, count); | |
147 | + | |
148 | + els_iocb->entry_type = ELS_IOCB_TYPE; | |
149 | + els_iocb->entry_count = 1; | |
150 | + els_iocb->sys_define = 0; | |
151 | + els_iocb->entry_status = 0; | |
152 | + els_iocb->nport_handle = cpu_to_le16(fcport->loop_id); | |
153 | + els_iocb->tx_dsd_count = __constant_cpu_to_le16(1); | |
154 | + els_iocb->vp_index = ha->vp_idx; | |
155 | + els_iocb->sof_type = EST_SOFI3; | |
156 | + els_iocb->rx_dsd_count = __constant_cpu_to_le16(1); | |
157 | + els_iocb->opcode = 0; | |
158 | + els_iocb->port_id[0] = fcport->d_id.b.al_pa; | |
159 | + els_iocb->port_id[1] = fcport->d_id.b.area; | |
160 | + els_iocb->port_id[2] = fcport->d_id.b.domain; | |
161 | + els_iocb->control_flags = __constant_cpu_to_le16(0); | |
162 | + els_iocb->rx_byte_count = cpu_to_le32(PAGE_SIZE); | |
163 | + els_iocb->tx_byte_count = cpu_to_le32(count); | |
164 | + els_iocb->tx_address[0] = cpu_to_le32(LSD(ha->pass_thru_dma)); | |
165 | + els_iocb->tx_address[1] = cpu_to_le32(MSD(ha->pass_thru_dma)); | |
166 | + els_iocb->tx_len = els_iocb->tx_byte_count; | |
167 | + els_iocb->rx_address[0] = cpu_to_le32(LSD(ha->pass_thru_dma)); | |
168 | + els_iocb->rx_address[1] = cpu_to_le32(MSD(ha->pass_thru_dma)); | |
169 | + els_iocb->rx_len = els_iocb->rx_byte_count; | |
170 | + | |
171 | + wmb(); | |
172 | + qla2x00_isp_cmd(ha); | |
173 | + | |
174 | + spin_unlock_irqrestore(&ha->hardware_lock, flags); | |
175 | + qla2x00_wait_for_passthru_completion(ha); | |
176 | + | |
177 | + return count; | |
178 | + | |
179 | +els_error1: | |
180 | + ha->pass_thru_cmd_in_process = 0; | |
181 | + spin_unlock_irqrestore(&ha->hardware_lock, flags); | |
182 | +els_error0: | |
183 | + DEBUG2(qla_printk(KERN_WARNING, ha, | |
184 | + "Passthru ELS failed on scsi(%ld)\n", ha->host_no)); | |
185 | + return 0; | |
186 | +} | |
187 | + | |
188 | +static struct bin_attribute sysfs_els_attr = { | |
189 | + .attr = { | |
190 | + .name = "els", | |
191 | + .mode = S_IRUSR | S_IWUSR, | |
192 | + .owner = THIS_MODULE, | |
193 | + }, | |
194 | + .size = 0, | |
195 | + .read = qla2x00_sysfs_read_els, | |
196 | + .write = qla2x00_sysfs_write_els, | |
197 | +}; | |
198 | + | |
199 | +static ssize_t | |
200 | +qla2x00_sysfs_read_ct(struct kobject *kobj, struct bin_attribute *bin_attr, | |
201 | + char *buf, loff_t off, size_t count) | |
202 | +{ | |
203 | + struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, | |
204 | + struct device, kobj))); | |
205 | + | |
206 | + if (!IS_FWI2_CAPABLE(ha)) | |
207 | + return 0; | |
208 | + | |
209 | + if (!ha->pass_thru_cmd_in_process || !ha->pass_thru_cmd_result) { | |
210 | + DEBUG2(qla_printk(KERN_WARNING, ha, | |
211 | + "Passthru CT response is not available.\n")); | |
212 | + return 0; | |
213 | + } | |
214 | + | |
215 | + memcpy(buf, ha->pass_thru, count); | |
216 | + | |
217 | + ha->pass_thru_cmd_result = 0; | |
218 | + ha->pass_thru_cmd_in_process = 0; | |
219 | + | |
220 | + return count; | |
221 | +} | |
222 | + | |
223 | +static ssize_t | |
224 | +qla2x00_sysfs_write_ct(struct kobject *kobj, struct bin_attribute *bin_attr, | |
225 | + char *buf, loff_t off, size_t count) | |
226 | +{ | |
227 | + struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj, | |
228 | + struct device, kobj))); | |
229 | + struct fc_ct_request *request = (struct fc_ct_request *) buf; | |
230 | + struct ct_entry_24xx *ct_iocb; | |
231 | + unsigned long flags; | |
232 | + | |
233 | + if (!IS_FWI2_CAPABLE(ha) || | |
234 | + atomic_read(&ha->loop_state) != LOOP_READY) | |
235 | + goto ct_error0; | |
236 | + | |
237 | + if (count < sizeof(request->ct_iu)) { | |
238 | + DEBUG2(qla_printk(KERN_WARNING, ha, | |
239 | + "Passthru CT buffer insufficient size %ld...\n", count)); | |
240 | + goto ct_error0; | |
241 | + } | |
242 | + | |
243 | + if (ha->pass_thru_cmd_in_process || ha->pass_thru_cmd_result) { | |
244 | + DEBUG2(qla_printk(KERN_WARNING, ha, | |
245 | + "Passthru CT request is already progress\n")); | |
246 | + goto ct_error0; | |
247 | + } | |
248 | + | |
249 | + if (qla2x00_mgmt_svr_login(ha)) { | |
250 | + DEBUG2(qla_printk(KERN_WARNING, ha, | |
251 | + "Passthru CT request failed to login management server\n")); | |
252 | + goto ct_error0; | |
253 | + } | |
254 | + | |
255 | + ha->pass_thru_cmd_in_process = 1; | |
256 | + spin_lock_irqsave(&ha->hardware_lock, flags); | |
257 | + | |
258 | + ct_iocb = (void *)qla2x00_req_pkt(ha); | |
259 | + if (ct_iocb == NULL) { | |
260 | + DEBUG2(qla_printk(KERN_WARNING, ha, | |
261 | + "Passthru CT request failed to get request packet\n")); | |
262 | + goto ct_error1; | |
263 | + } | |
264 | + | |
265 | + if (count > PAGE_SIZE) { | |
266 | + DEBUG2(qla_printk(KERN_INFO, ha, | |
267 | + "Passthru CT request excessive size %ld...\n", count)); | |
268 | + count = PAGE_SIZE; | |
269 | + } | |
270 | + | |
271 | + memset(ha->pass_thru, 0, PAGE_SIZE); | |
272 | + memcpy(ha->pass_thru, &request->ct_iu, count); | |
273 | + | |
274 | + ct_iocb->entry_type = CT_IOCB_TYPE; | |
275 | + ct_iocb->entry_count = 1; | |
276 | + ct_iocb->entry_status = 0; | |
277 | + ct_iocb->comp_status = __constant_cpu_to_le16(0); | |
278 | + ct_iocb->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id); | |
279 | + ct_iocb->cmd_dsd_count = __constant_cpu_to_le16(1); | |
280 | + ct_iocb->vp_index = ha->vp_idx; | |
281 | + ct_iocb->timeout = __constant_cpu_to_le16(25); | |
282 | + ct_iocb->rsp_dsd_count = __constant_cpu_to_le16(1); | |
283 | + ct_iocb->rsp_byte_count = cpu_to_le32(PAGE_SIZE); | |
284 | + ct_iocb->cmd_byte_count = cpu_to_le32(count); | |
285 | + ct_iocb->dseg_0_address[0] = cpu_to_le32(LSD(ha->pass_thru_dma)); | |
286 | + ct_iocb->dseg_0_address[1] = cpu_to_le32(MSD(ha->pass_thru_dma)); | |
287 | + ct_iocb->dseg_0_len = ct_iocb->cmd_byte_count; | |
288 | + ct_iocb->dseg_1_address[0] = cpu_to_le32(LSD(ha->pass_thru_dma)); | |
289 | + ct_iocb->dseg_1_address[1] = cpu_to_le32(MSD(ha->pass_thru_dma)); | |
290 | + ct_iocb->dseg_1_len = ct_iocb->rsp_byte_count; | |
291 | + | |
292 | + wmb(); | |
293 | + qla2x00_isp_cmd(ha); | |
294 | + | |
295 | + spin_unlock_irqrestore(&ha->hardware_lock, flags); | |
296 | + qla2x00_wait_for_passthru_completion(ha); | |
297 | + | |
298 | + return count; | |
299 | + | |
300 | +ct_error1: | |
301 | + ha->pass_thru_cmd_in_process = 0; | |
302 | + spin_unlock_irqrestore(&ha->hardware_lock, flags); | |
303 | +ct_error0: | |
304 | + DEBUG2(qla_printk(KERN_WARNING, ha, | |
305 | + "Passthru CT failed on scsi(%ld)\n", ha->host_no)); | |
306 | + return 0; | |
307 | +} | |
308 | + | |
309 | +static struct bin_attribute sysfs_ct_attr = { | |
310 | + .attr = { | |
311 | + .name = "ct", | |
312 | + .mode = S_IRUSR | S_IWUSR, | |
313 | + .owner = THIS_MODULE, | |
314 | + }, | |
315 | + .size = 0, | |
316 | + .read = qla2x00_sysfs_read_ct, | |
317 | + .write = qla2x00_sysfs_write_ct, | |
318 | +}; | |
319 | + | |
320 | static struct sysfs_entry { | |
321 | char *name; | |
322 | struct bin_attribute *attr; | |
323 | @@ -465,6 +746,8 @@ static struct sysfs_entry { | |
324 | { "optrom_ctl", &sysfs_optrom_ctl_attr, }, | |
325 | { "vpd", &sysfs_vpd_attr, 1 }, | |
326 | { "sfp", &sysfs_sfp_attr, 1 }, | |
327 | + { "els", &sysfs_els_attr, 1 }, | |
328 | + { "ct", &sysfs_ct_attr, 1 }, | |
329 | { NULL }, | |
330 | }; | |
331 | ||
332 | @@ -797,6 +1080,27 @@ qla2x00_total_isp_aborts_show(struct device *dev, | |
333 | ha->qla_stats.total_isp_aborts); | |
334 | } | |
335 | ||
336 | +static ssize_t | |
337 | +qla24xx_84xx_fw_version_show(struct device *dev, | |
338 | + struct device_attribute *attr, char *buf) | |
339 | +{ | |
340 | + int rval = QLA_SUCCESS; | |
341 | + uint16_t status[2] = {0, 0}; | |
342 | + scsi_qla_host_t *ha = shost_priv(class_to_shost(dev)); | |
343 | + | |
344 | + if (IS_QLA84XX(ha) && ha->cs84xx) { | |
345 | + if (ha->cs84xx->op_fw_version == 0) { | |
346 | + rval = qla84xx_verify_chip(ha, status); | |
347 | + } | |
348 | + | |
349 | + if ((rval == QLA_SUCCESS) && (status[0] == 0)) | |
350 | + return snprintf(buf, PAGE_SIZE, "%u\n", | |
351 | + (uint32_t)ha->cs84xx->op_fw_version); | |
352 | + } | |
353 | + | |
354 | + return snprintf(buf, PAGE_SIZE, "\n"); | |
355 | +} | |
356 | + | |
357 | static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL); | |
358 | static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); | |
359 | static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); | |
360 | @@ -821,6 +1125,8 @@ static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show, | |
361 | NULL); | |
362 | static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show, | |
363 | NULL); | |
364 | +static DEVICE_ATTR(84xx_fw_version, S_IRUGO, qla24xx_84xx_fw_version_show, | |
365 | + NULL); | |
366 | ||
367 | struct device_attribute *qla2x00_host_attrs[] = { | |
368 | &dev_attr_driver_version, | |
369 | @@ -840,6 +1146,7 @@ struct device_attribute *qla2x00_host_attrs[] = { | |
370 | &dev_attr_optrom_fcode_version, | |
371 | &dev_attr_optrom_fw_version, | |
372 | &dev_attr_total_isp_aborts, | |
373 | + &dev_attr_84xx_fw_version, | |
374 | NULL, | |
375 | }; | |
376 | ||
377 | diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h | |
378 | index a45e333..851dc96 100644 | |
379 | --- a/drivers/scsi/qla2xxx/qla_def.h | |
380 | +++ b/drivers/scsi/qla2xxx/qla_def.h | |
381 | @@ -94,6 +94,89 @@ | |
382 | #define LSD(x) ((uint32_t)((uint64_t)(x))) | |
383 | #define MSD(x) ((uint32_t)((((uint64_t)(x)) >> 16) >> 16)) | |
384 | ||
385 | +/* ELS PT request buffer = 32 bytes */ | |
386 | +#define EXT_ELS_PT_REQ_WWPN_VALID 0x1 | |
387 | +#define EXT_ELS_PT_REQ_WWNN_VALID 0x2 | |
388 | +#define EXT_ELS_PT_REQ_PID_VALID 0x4 | |
389 | + | |
390 | +struct ext_els_pt_req { | |
391 | + uint8_t WWNN[8]; | |
392 | + uint8_t WWPN[8]; | |
393 | + uint8_t Id[4]; | |
394 | + uint16_t ValidMask; | |
395 | + uint16_t Lid; | |
396 | + uint16_t Rxid; | |
397 | + uint16_t AccRjt; | |
398 | + uint32_t Reserved; | |
399 | +}; | |
400 | + | |
401 | +/* CT IU */ | |
402 | +struct ct_iu { | |
403 | + uint8_t revision; | |
404 | + uint8_t in_id[3]; | |
405 | + uint8_t gs_type; | |
406 | + uint8_t gs_subtype; | |
407 | + uint8_t options; | |
408 | + uint8_t reserved0; | |
409 | + uint16_t command; | |
410 | + uint16_t max_rsp_size; | |
411 | + uint8_t fragment_id; | |
412 | + uint8_t reserved1[3]; | |
413 | +}; | |
414 | + | |
415 | +/* CT request format */ | |
416 | +struct fc_ct_request { | |
417 | + struct ct_iu ct_iu; | |
418 | + union { | |
419 | + struct { | |
420 | + uint8_t reserved; | |
421 | + uint8_t port_id[3]; | |
422 | + } port_id; | |
423 | + | |
424 | + struct { | |
425 | + uint8_t port_type; | |
426 | + uint8_t domain; | |
427 | + uint8_t area; | |
428 | + uint8_t reserved; | |
429 | + } gid_pt; | |
430 | + | |
431 | + struct { | |
432 | + uint8_t reserved; | |
433 | + uint8_t port_id[3]; | |
434 | + uint8_t fc4_types[32]; | |
435 | + } rft_id; | |
436 | + | |
437 | + struct { | |
438 | + uint8_t reserved; | |
439 | + uint8_t port_id[3]; | |
440 | + uint16_t reserved2; | |
441 | + uint8_t fc4_feature; | |
442 | + uint8_t fc4_type; | |
443 | + } rff_id; | |
444 | + | |
445 | + struct { | |
446 | + uint8_t reserved; | |
447 | + uint8_t port_id[3]; | |
448 | + uint8_t node_name[8]; | |
449 | + } rnn_id; | |
450 | + | |
451 | + struct { | |
452 | + uint8_t node_name[8]; | |
453 | + uint8_t name_len; | |
454 | + uint8_t sym_node_name[255]; | |
455 | + } rsnn_nn; | |
456 | + | |
457 | + struct { | |
458 | + uint8_t hba_indentifier[8]; | |
459 | + } ghat; | |
460 | + } extended; | |
461 | +}; | |
462 | + | |
463 | +/* ELS request format */ | |
464 | +struct els_request { | |
465 | + struct ext_els_pt_req header; | |
466 | + struct ct_iu ct_iu; | |
467 | +}; | |
468 | ||
469 | /* | |
470 | * I/O register | |
471 | @@ -2161,6 +2244,14 @@ struct qla_statistics { | |
472 | uint64_t output_bytes; | |
473 | }; | |
474 | ||
475 | +#include "qla_nlnk.h" | |
476 | +/* place holder for fw buffer parameters for netlink */ | |
477 | +struct qlfc_fw { | |
478 | + void *fw_buf; | |
479 | + dma_addr_t fw_dma; | |
480 | + uint32_t len; | |
481 | +}; | |
482 | + | |
483 | /* | |
484 | * Linux Host Adapter structure | |
485 | */ | |
486 | @@ -2426,6 +2517,8 @@ typedef struct scsi_qla_host { | |
487 | /* SNS command interfaces for 2200. */ | |
488 | struct sns_cmd_pkt *sns_cmd; | |
489 | dma_addr_t sns_cmd_dma; | |
490 | + char *pass_thru; | |
491 | + dma_addr_t pass_thru_dma; | |
492 | ||
493 | #define SFP_DEV_SIZE 256 | |
494 | #define SFP_BLOCK_SIZE 64 | |
495 | @@ -2467,6 +2560,7 @@ typedef struct scsi_qla_host { | |
496 | struct mutex vport_lock; /* Virtual port synchronization */ | |
497 | struct completion mbx_cmd_comp; /* Serialize mbx access */ | |
498 | struct completion mbx_intr_comp; /* Used for completion notification */ | |
499 | + struct completion pass_thru_intr_comp; /* For pass thru notification */ | |
500 | ||
501 | uint32_t mbx_flags; | |
502 | #define MBX_IN_PROGRESS BIT_0 | |
503 | @@ -2608,8 +2702,13 @@ typedef struct scsi_qla_host { | |
504 | uint16_t max_npiv_vports; /* 63 or 125 per topoloty */ | |
505 | int cur_vport_count; | |
506 | ||
507 | + /* pass throuth support */ | |
508 | + int pass_thru_cmd_result; | |
509 | + int pass_thru_cmd_in_process; | |
510 | + | |
511 | struct qla_chip_state_84xx *cs84xx; | |
512 | struct qla_statistics qla_stats; | |
513 | + struct qlfc_fw fw_buf; | |
514 | } scsi_qla_host_t; | |
515 | ||
516 | ||
517 | diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h | |
518 | index d1d1420..0ccf534 100644 | |
519 | --- a/drivers/scsi/qla2xxx/qla_fw.h | |
520 | +++ b/drivers/scsi/qla2xxx/qla_fw.h | |
521 | @@ -1212,9 +1212,10 @@ struct qla_fdt_layout { | |
522 | ||
523 | struct qla_flt_location { | |
524 | uint8_t sig[4]; | |
525 | - uint32_t start_lo; | |
526 | - uint32_t start_hi; | |
527 | - uint16_t unused; | |
528 | + uint16_t start_lo; | |
529 | + uint16_t start_hi; | |
530 | + uint8_t version; | |
531 | + uint8_t unused[5]; | |
532 | uint16_t checksum; | |
533 | }; | |
534 | ||
535 | diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h | |
536 | index 753dbe6..de1efc6 100644 | |
537 | --- a/drivers/scsi/qla2xxx/qla_gbl.h | |
538 | +++ b/drivers/scsi/qla2xxx/qla_gbl.h | |
539 | @@ -121,6 +121,8 @@ extern int qla2x00_start_scsi(srb_t *sp); | |
540 | extern int qla24xx_start_scsi(srb_t *sp); | |
541 | int qla2x00_marker(scsi_qla_host_t *, uint16_t, uint16_t, uint8_t); | |
542 | int __qla2x00_marker(scsi_qla_host_t *, uint16_t, uint16_t, uint8_t); | |
543 | +extern request_t *qla2x00_req_pkt(scsi_qla_host_t *); | |
544 | +extern void qla2x00_isp_cmd(scsi_qla_host_t *ha); | |
545 | ||
546 | /* | |
547 | * Global Function Prototypes in qla_mbx.c source file. | |
548 | @@ -154,6 +156,10 @@ extern int | |
549 | qla2x00_issue_iocb(scsi_qla_host_t *, void *, dma_addr_t, size_t); | |
550 | ||
551 | extern int | |
552 | +qla2x00_issue_iocb_timeout(scsi_qla_host_t *, void *, dma_addr_t, size_t, | |
553 | + uint32_t); | |
554 | + | |
555 | +extern int | |
556 | qla2x00_abort_command(scsi_qla_host_t *, srb_t *); | |
557 | ||
558 | extern int | |
559 | @@ -258,6 +264,8 @@ qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *); | |
560 | ||
561 | extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *); | |
562 | ||
563 | +extern int qla84xx_reset(struct scsi_qla_host *, uint32_t); | |
564 | + | |
565 | /* | |
566 | * Global Function Prototypes in qla_isr.c source file. | |
567 | */ | |
568 | @@ -327,6 +335,8 @@ extern void qla24xx_fw_dump(scsi_qla_host_t *, int); | |
569 | extern void qla25xx_fw_dump(scsi_qla_host_t *, int); | |
570 | extern void qla2x00_dump_regs(scsi_qla_host_t *); | |
571 | extern void qla2x00_dump_buffer(uint8_t *, uint32_t); | |
572 | +extern void qla2x00_print_byte_buf(void *, size_t, size_t); | |
573 | +extern void qla2x00_print_word_buf(void *, size_t, size_t); | |
574 | ||
575 | /* | |
576 | * Global Function Prototypes in qla_gs.c source file. | |
577 | @@ -347,6 +357,7 @@ extern int qla2x00_fdmi_register(scsi_qla_host_t *); | |
578 | extern int qla2x00_gfpn_id(scsi_qla_host_t *, sw_info_t *); | |
579 | extern int qla2x00_gpsc(scsi_qla_host_t *, sw_info_t *); | |
580 | extern void qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *); | |
581 | +extern int qla2x00_mgmt_svr_login(scsi_qla_host_t *); | |
582 | ||
583 | /* | |
584 | * Global Function Prototypes in qla_attr.c source file. | |
585 | @@ -363,6 +374,13 @@ extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *); | |
586 | extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *); | |
587 | ||
588 | /* | |
589 | + * Global functions in qla_nlk.c | |
590 | + */ | |
591 | +extern int ql_nl_register(void); | |
592 | +extern void ql_nl_unregister(void); | |
593 | +extern void qla_free_nlnk_dmabuf(scsi_qla_host_t *); | |
594 | + | |
595 | +/* | |
596 | * Global Function Prototypes in qla_dfs.c source file. | |
597 | */ | |
598 | extern int qla2x00_dfs_setup(scsi_qla_host_t *); | |
599 | diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c | |
600 | index c2a4bfb..ceef231 100644 | |
601 | --- a/drivers/scsi/qla2xxx/qla_gs.c | |
602 | +++ b/drivers/scsi/qla2xxx/qla_gs.c | |
603 | @@ -1093,7 +1093,7 @@ qla2x00_sns_rnn_id(scsi_qla_host_t *ha) | |
604 | * | |
605 | * Returns 0 on success. | |
606 | */ | |
607 | -static int | |
608 | +int | |
609 | qla2x00_mgmt_svr_login(scsi_qla_host_t *ha) | |
610 | { | |
611 | int ret; | |
612 | diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c | |
613 | index ad2dd8c..407e87a 100644 | |
614 | --- a/drivers/scsi/qla2xxx/qla_init.c | |
615 | +++ b/drivers/scsi/qla2xxx/qla_init.c | |
616 | @@ -1241,8 +1241,11 @@ qla2x00_init_rings(scsi_qla_host_t *ha) | |
617 | ||
618 | DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no)); | |
619 | ||
620 | - if (ha->flags.npiv_supported) | |
621 | + if (ha->flags.npiv_supported) { | |
622 | + if (ha->operating_mode == LOOP) | |
623 | + ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1; | |
624 | mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports); | |
625 | + } | |
626 | ||
627 | mid_init_cb->options = __constant_cpu_to_le16(BIT_1); | |
628 | ||
629 | diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c | |
630 | index 85bc0a4..352517d 100644 | |
631 | --- a/drivers/scsi/qla2xxx/qla_iocb.c | |
632 | +++ b/drivers/scsi/qla2xxx/qla_iocb.c | |
633 | @@ -11,8 +11,6 @@ | |
634 | ||
635 | #include <scsi/scsi_tcq.h> | |
636 | ||
637 | -static request_t *qla2x00_req_pkt(scsi_qla_host_t *ha); | |
638 | -static void qla2x00_isp_cmd(scsi_qla_host_t *ha); | |
639 | ||
640 | /** | |
641 | * qla2x00_get_cmd_direction() - Determine control_flag data direction. | |
642 | @@ -476,7 +474,7 @@ qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun, | |
643 | * | |
644 | * Returns NULL if function failed, else, a pointer to the request packet. | |
645 | */ | |
646 | -static request_t * | |
647 | +request_t * | |
648 | qla2x00_req_pkt(scsi_qla_host_t *ha) | |
649 | { | |
650 | device_reg_t __iomem *reg = ha->iobase; | |
651 | @@ -546,7 +544,7 @@ qla2x00_req_pkt(scsi_qla_host_t *ha) | |
652 | * | |
653 | * Note: The caller must hold the hardware lock before calling this routine. | |
654 | */ | |
655 | -static void | |
656 | +void | |
657 | qla2x00_isp_cmd(scsi_qla_host_t *ha) | |
658 | { | |
659 | device_reg_t __iomem *reg = ha->iobase; | |
660 | diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c | |
661 | index a76efd9..758d0ee 100644 | |
662 | --- a/drivers/scsi/qla2xxx/qla_isr.c | |
663 | +++ b/drivers/scsi/qla2xxx/qla_isr.c | |
664 | @@ -1443,6 +1443,27 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha) | |
665 | case STATUS_CONT_TYPE: | |
666 | qla2x00_status_cont_entry(ha, (sts_cont_entry_t *)pkt); | |
667 | break; | |
668 | + case MS_IOCB_TYPE: | |
669 | + if (ha->pass_thru_cmd_result) | |
670 | + DEBUG2(qla_printk(KERN_INFO, ha, | |
671 | + "Passthru cmd result on.\n")); | |
672 | + if (!ha->pass_thru_cmd_in_process) | |
673 | + DEBUG2(qla_printk(KERN_INFO, ha, | |
674 | + "Passthru in process off.\n")); | |
675 | + | |
676 | + ha->pass_thru_cmd_result = 1; | |
677 | + complete(&ha->pass_thru_intr_comp); | |
678 | + break; | |
679 | + case ELS_IOCB_TYPE: | |
680 | + if (ha->pass_thru_cmd_result) | |
681 | + DEBUG2(qla_printk(KERN_INFO, ha, | |
682 | + "Passthru cmd result on.\n")); | |
683 | + if (!ha->pass_thru_cmd_in_process) | |
684 | + DEBUG2(qla_printk(KERN_INFO, ha, | |
685 | + "Passthru in process off.\n")); | |
686 | + | |
687 | + ha->pass_thru_cmd_result = 1; | |
688 | + complete(&ha->pass_thru_intr_comp); | |
689 | case VP_RPT_ID_IOCB_TYPE: | |
690 | qla24xx_report_id_acquisition(ha, | |
691 | (struct vp_rpt_id_entry_24xx *)pkt); | |
692 | diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c | |
693 | index 3402746..9d78629 100644 | |
694 | --- a/drivers/scsi/qla2xxx/qla_mbx.c | |
695 | +++ b/drivers/scsi/qla2xxx/qla_mbx.c | |
696 | @@ -681,7 +681,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr) | |
697 | * Context: | |
698 | * Kernel context. | |
699 | */ | |
700 | -static int | |
701 | +int | |
702 | qla2x00_issue_iocb_timeout(scsi_qla_host_t *ha, void *buffer, | |
703 | dma_addr_t phys_addr, size_t size, uint32_t tov) | |
704 | { | |
705 | @@ -2946,6 +2946,33 @@ qla2x00_dump_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t addr, | |
706 | ||
707 | /* 84XX Support **************************************************************/ | |
708 | ||
709 | +/* | |
710 | + * qla84xx_reset | |
711 | + * Resets the QLA8432 | |
712 | + */ | |
713 | +int | |
714 | +qla84xx_reset(struct scsi_qla_host *ha, uint32_t diag_fw) | |
715 | +{ | |
716 | + int rval; | |
717 | + mbx_cmd_t mc; | |
718 | + mbx_cmd_t *mcp = &mc; | |
719 | + | |
720 | + mcp->mb[0] = MBC_ISP84XX_RESET; | |
721 | + mcp->mb[1] = diag_fw; | |
722 | + mcp->out_mb = MBX_1 | MBX_0; | |
723 | + mcp->in_mb = MBX_1 | MBX_0; | |
724 | + mcp->tov = MBX_TOV_SECONDS; | |
725 | + mcp->flags = 0; | |
726 | + | |
727 | + rval = qla2x00_mailbox_command(ha, mcp); | |
728 | + | |
729 | + if (rval != QLA_SUCCESS) | |
730 | + DEBUG2_16(printk("%s(%ld): failed mb[0]=0x%x mb[1]=0x%x\n", | |
731 | + __func__, ha->host_no, mcp->mb[0], mcp->mb[1])); | |
732 | + | |
733 | + return (rval); | |
734 | +} | |
735 | + | |
736 | struct cs84xx_mgmt_cmd { | |
737 | union { | |
738 | struct verify_chip_entry_84xx req; | |
739 | diff --git a/drivers/scsi/qla2xxx/qla_nlnk.c b/drivers/scsi/qla2xxx/qla_nlnk.c | |
740 | new file mode 100644 | |
741 | index 0000000..2ab339d | |
742 | --- /dev/null | |
743 | +++ b/drivers/scsi/qla2xxx/qla_nlnk.c | |
744 | @@ -0,0 +1,434 @@ | |
745 | +/* | |
746 | + * QLogic Fibre Channel HBA Driver | |
747 | + * Copyright (c) 2003-2005 QLogic Corporation | |
748 | + * | |
749 | + * See LICENSE.qla2xxx for copyright and licensing details. | |
750 | + */ | |
751 | + | |
752 | +#include "qla_def.h" | |
753 | +#include <net/sock.h> | |
754 | +#include <net/netlink.h> | |
755 | +#include "qla_nlnk.h" | |
756 | + | |
757 | +static struct sock *ql_fc_nl_sock = NULL; | |
758 | +static int ql_fc_nl_event(struct notifier_block *this, | |
759 | + unsigned long event, void *ptr); | |
760 | + | |
761 | +static struct notifier_block ql_fc_nl_notifier = { | |
762 | + .notifier_call = ql_fc_nl_event, | |
763 | +}; | |
764 | + | |
765 | +/* | |
766 | + * local functions | |
767 | + */ | |
768 | +static int ql_fc_proc_nl_rcv_msg(struct sk_buff *skb, | |
769 | + struct nlmsghdr *nlh, int rcvlen); | |
770 | +static int ql_fc_nl_rsp(uint32_t pid, uint32_t seq, uint32_t type, | |
771 | + void *hdr, int hdr_len, void *payload, int size); | |
772 | + | |
773 | +static int qla84xx_update_fw(struct scsi_qla_host *ha, int rlen, | |
774 | + struct msg_update_fw *upd_fw) | |
775 | +{ | |
776 | + struct qlfc_fw *qlfw; | |
777 | + struct verify_chip_entry_84xx *mn; | |
778 | + dma_addr_t mn_dma; | |
779 | + int ret = 0; | |
780 | + uint32_t fw_ver; | |
781 | + uint16_t options; | |
782 | + | |
783 | + if (rlen < (sizeof(struct msg_update_fw) + upd_fw->len + | |
784 | + offsetof(struct qla_fc_msg, u))){ | |
785 | + DEBUG2_16(printk(KERN_ERR "%s(%lu): invalid len\n", | |
786 | + __func__, ha->host_no)); | |
787 | + return -EINVAL; | |
788 | + } | |
789 | + | |
790 | + qlfw = &ha->fw_buf; | |
791 | + if (!upd_fw->offset) { | |
792 | + if (qlfw->fw_buf || !upd_fw->fw_len || | |
793 | + upd_fw->len > upd_fw->fw_len) { | |
794 | + DEBUG2_16(printk(KERN_ERR "%s(%lu): invalid offset or " | |
795 | + "fw_len\n", __func__, ha->host_no)); | |
796 | + return -EINVAL; | |
797 | + } else { | |
798 | + qlfw->fw_buf = dma_alloc_coherent(&ha->pdev->dev, | |
799 | + upd_fw->fw_len, &qlfw->fw_dma, | |
800 | + GFP_KERNEL); | |
801 | + if (qlfw->fw_buf == NULL) { | |
802 | + DEBUG2_16(printk(KERN_ERR "%s: dma alloc " | |
803 | + "failed%lu\n", __func__, ha->host_no)); | |
804 | + return (-ENOMEM); | |
805 | + } | |
806 | + qlfw->len = upd_fw->fw_len; | |
807 | + } | |
808 | + fw_ver = le32_to_cpu(*((uint32_t *) | |
809 | + ((uint32_t *)upd_fw->fw_bytes + 2))); | |
810 | + if (!fw_ver) { | |
811 | + DEBUG2_16(printk(KERN_ERR "%s(%lu): invalid fw " | |
812 | + "revision 0x%x\n", __func__, ha->host_no, fw_ver)); | |
813 | + return -EINVAL; | |
814 | + } | |
815 | + } else { | |
816 | + /* make sure we have a buffer allocated */ | |
817 | + if (!qlfw->fw_buf || upd_fw->fw_len != qlfw->len || | |
818 | + ((upd_fw->offset + upd_fw->len) > upd_fw->fw_len)){ | |
819 | + DEBUG2_16(printk(KERN_ERR "%s(%lu): invalid size of " | |
820 | + "offset=0 expected\n", __func__, ha->host_no)); | |
821 | + return -EINVAL; | |
822 | + } | |
823 | + } | |
824 | + /* Copy the firmware into DMA Buffer */ | |
825 | + memcpy(((uint8_t *)qlfw->fw_buf + upd_fw->offset), | |
826 | + upd_fw->fw_bytes, upd_fw->len); | |
827 | + | |
828 | + if ((upd_fw->offset+upd_fw->len) != qlfw->len) | |
829 | + return 0; | |
830 | + | |
831 | + mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); | |
832 | + if (mn == NULL) { | |
833 | + DEBUG2_16(printk(KERN_ERR "%s: dma alloc for fw buffer " | |
834 | + "failed%lu\n", __func__, ha->host_no)); | |
835 | + return -ENOMEM; | |
836 | + } | |
837 | + | |
838 | + fw_ver = le32_to_cpu(*((uint32_t *)((uint32_t *)qlfw->fw_buf + 2))); | |
839 | + | |
840 | + /* Create iocb and issue it */ | |
841 | + memset(mn, 0, sizeof(*mn)); | |
842 | + | |
843 | + mn->entry_type = VERIFY_CHIP_IOCB_TYPE; | |
844 | + mn->entry_count = 1; | |
845 | + | |
846 | + options = VCO_FORCE_UPDATE | VCO_END_OF_DATA; | |
847 | + if (upd_fw->diag_fw) | |
848 | + options |= VCO_DIAG_FW; | |
849 | + mn->options = cpu_to_le16(options); | |
850 | + | |
851 | + mn->fw_ver = cpu_to_le32(fw_ver); | |
852 | + mn->fw_size = cpu_to_le32(qlfw->len); | |
853 | + mn->fw_seq_size = cpu_to_le32(qlfw->len); | |
854 | + | |
855 | + mn->dseg_address[0] = cpu_to_le32(LSD(qlfw->fw_dma)); | |
856 | + mn->dseg_address[1] = cpu_to_le32(MSD(qlfw->fw_dma)); | |
857 | + mn->dseg_length = cpu_to_le32(qlfw->len); | |
858 | + mn->data_seg_cnt = cpu_to_le16(1); | |
859 | + | |
860 | + ret = qla2x00_issue_iocb_timeout(ha, mn, mn_dma, 0, 120); | |
861 | + | |
862 | + if (ret != QLA_SUCCESS) { | |
863 | + DEBUG2_16(printk(KERN_ERR "%s(%lu): failed\n", __func__, | |
864 | + ha->host_no)); | |
865 | + } | |
866 | + | |
867 | + qla_free_nlnk_dmabuf(ha); | |
868 | + return ret; | |
869 | +} | |
870 | + | |
871 | +static int | |
872 | +qla84xx_mgmt_cmd(scsi_qla_host_t *ha, struct qla_fc_msg *cmd, int rlen, | |
873 | + uint32_t pid, uint32_t seq, uint32_t type) | |
874 | +{ | |
875 | + struct access_chip_84xx *mn; | |
876 | + dma_addr_t mn_dma, mgmt_dma; | |
877 | + void *mgmt_b = NULL; | |
878 | + int ret = 0; | |
879 | + int rsp_hdr_len, len = 0; | |
880 | + struct qla84_msg_mgmt *ql84_mgmt; | |
881 | + | |
882 | + ql84_mgmt = &cmd->u.utok.mgmt; | |
883 | + rsp_hdr_len = offsetof(struct qla_fc_msg, u) + | |
884 | + offsetof(struct qla84_msg_mgmt, payload); | |
885 | + | |
886 | + mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); | |
887 | + if (mn == NULL) { | |
888 | + DEBUG2_16(printk(KERN_ERR "%s: dma alloc for fw buffer " | |
889 | + "failed%lu\n", __FUNCTION__, ha->host_no)); | |
890 | + return (-ENOMEM); | |
891 | + } | |
892 | + | |
893 | + memset(mn, 0, sizeof (struct access_chip_84xx)); | |
894 | + | |
895 | + mn->entry_type = ACCESS_CHIP_IOCB_TYPE; | |
896 | + mn->entry_count = 1; | |
897 | + | |
898 | + switch (ql84_mgmt->cmd) { | |
899 | + case QLA84_MGMT_READ_MEM: | |
900 | + mn->options = cpu_to_le16(ACO_DUMP_MEMORY); | |
901 | + mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr); | |
902 | + break; | |
903 | + case QLA84_MGMT_WRITE_MEM: | |
904 | + if (rlen < (sizeof(struct qla84_msg_mgmt) + ql84_mgmt->len + | |
905 | + offsetof(struct qla_fc_msg, u))){ | |
906 | + ret = -EINVAL; | |
907 | + goto exit_mgmt0; | |
908 | + } | |
909 | + mn->options = cpu_to_le16(ACO_LOAD_MEMORY); | |
910 | + mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr); | |
911 | + break; | |
912 | + case QLA84_MGMT_CHNG_CONFIG: | |
913 | + mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM); | |
914 | + mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.id); | |
915 | + mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param0); | |
916 | + mn->parameter3 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param1); | |
917 | + break; | |
918 | + case QLA84_MGMT_GET_INFO: | |
919 | + mn->options = cpu_to_le16(ACO_REQUEST_INFO); | |
920 | + mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.type); | |
921 | + mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.context); | |
922 | + break; | |
923 | + default: | |
924 | + ret = -EIO; | |
925 | + goto exit_mgmt0; | |
926 | + } | |
927 | + | |
928 | + if ((len = ql84_mgmt->len) && ql84_mgmt->cmd != QLA84_MGMT_CHNG_CONFIG) { | |
929 | + mgmt_b = dma_alloc_coherent(&ha->pdev->dev, len, | |
930 | + &mgmt_dma, GFP_KERNEL); | |
931 | + if (mgmt_b == NULL) { | |
932 | + DEBUG2_16(printk(KERN_ERR "%s: dma alloc mgmt_b " | |
933 | + "failed%lu\n", __func__, ha->host_no)); | |
934 | + ret = -ENOMEM; | |
935 | + goto exit_mgmt0; | |
936 | + } | |
937 | + mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->len); | |
938 | + mn->dseg_count = cpu_to_le16(1); | |
939 | + mn->dseg_address[0] = cpu_to_le32(LSD(mgmt_dma)); | |
940 | + mn->dseg_address[1] = cpu_to_le32(MSD(mgmt_dma)); | |
941 | + mn->dseg_length = cpu_to_le32(len); | |
942 | + | |
943 | + if (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) { | |
944 | + memcpy(mgmt_b, ql84_mgmt->payload, len); | |
945 | + } | |
946 | + } | |
947 | + | |
948 | + ret = qla2x00_issue_iocb(ha, mn, mn_dma, 0); | |
949 | + cmd->error = ret; | |
950 | + | |
951 | + if ((ret != QLA_SUCCESS) || | |
952 | + (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) || | |
953 | + (ql84_mgmt->cmd == QLA84_MGMT_CHNG_CONFIG)) { | |
954 | + if (ret != QLA_SUCCESS) | |
955 | + DEBUG2_16(printk(KERN_ERR "%s(%lu): failed\n", | |
956 | + __func__, ha->host_no)); | |
957 | + ret = ql_fc_nl_rsp(pid, seq, type, cmd, rsp_hdr_len, NULL, 0); | |
958 | + } else if ((ql84_mgmt->cmd == QLA84_MGMT_READ_MEM)|| | |
959 | + (ql84_mgmt->cmd == QLA84_MGMT_GET_INFO)) { | |
960 | + ret = ql_fc_nl_rsp(pid, seq, type, cmd, rsp_hdr_len, mgmt_b, len); | |
961 | + } | |
962 | + | |
963 | + if (mgmt_b) | |
964 | + dma_free_coherent(&ha->pdev->dev, len, mgmt_b, mgmt_dma); | |
965 | + | |
966 | +exit_mgmt0: | |
967 | + dma_pool_free(ha->s_dma_pool, mn, mn_dma); | |
968 | + return ret; | |
969 | +} | |
970 | + | |
971 | +/* | |
972 | + * Netlink Interface Related Functions | |
973 | + */ | |
974 | + | |
975 | +static void | |
976 | +ql_fc_nl_rcv_msg(struct sk_buff *skb) | |
977 | +{ | |
978 | + struct nlmsghdr *nlh; | |
979 | + struct scsi_nl_hdr *snlh; | |
980 | + uint32_t rlen; | |
981 | + int err; | |
982 | + | |
983 | + while (skb->len >= NLMSG_SPACE(0)) { | |
984 | + err = 0; | |
985 | + | |
986 | + nlh = (struct nlmsghdr *) skb->data; | |
987 | + | |
988 | + if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*snlh))) || | |
989 | + (skb->len < nlh->nlmsg_len)) { | |
990 | + DEBUG2_16(printk(KERN_WARNING "%s: discarding partial " | |
991 | + "skb\n", __FUNCTION__)); | |
992 | + break; | |
993 | + } | |
994 | + | |
995 | + rlen = NLMSG_ALIGN(nlh->nlmsg_len); | |
996 | + if (rlen > skb->len) { | |
997 | + DEBUG2_16(printk(KERN_WARNING "%s: rlen > skb->len\n", | |
998 | + __FUNCTION__)); | |
999 | + rlen = skb->len; | |
1000 | + } | |
1001 | + | |
1002 | + if (nlh->nlmsg_type != FC_TRANSPORT_MSG) { | |
1003 | + DEBUG2_16(printk(KERN_WARNING "%s: Not " | |
1004 | + "FC_TRANSPORT_MSG\n", __FUNCTION__)); | |
1005 | + err = -EBADMSG; | |
1006 | + goto next_msg; | |
1007 | + } | |
1008 | + | |
1009 | + snlh = NLMSG_DATA(nlh); | |
1010 | + if ((snlh->version != SCSI_NL_VERSION) || | |
1011 | + (snlh->magic != SCSI_NL_MAGIC)) { | |
1012 | + DEBUG2_16(printk(KERN_WARNING "%s: Bad Version or " | |
1013 | + "Magic number\n", __FUNCTION__)); | |
1014 | + err = -EPROTOTYPE; | |
1015 | + goto next_msg; | |
1016 | + } | |
1017 | + err = ql_fc_proc_nl_rcv_msg(skb, nlh, rlen); | |
1018 | +next_msg: | |
1019 | + if (err) | |
1020 | + netlink_ack(skb, nlh, err); | |
1021 | + skb_pull(skb, rlen); | |
1022 | + } | |
1023 | +} | |
1024 | + | |
1025 | +static int | |
1026 | +ql_fc_proc_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int rcvlen) | |
1027 | +{ | |
1028 | + struct scsi_nl_hdr *snlh; | |
1029 | + struct qla_fc_msg *ql_cmd; | |
1030 | + struct Scsi_Host *shost; | |
1031 | + struct scsi_qla_host *ha; | |
1032 | + int err = 0; | |
1033 | + int rsp_hdr_len; | |
1034 | + | |
1035 | + snlh = NLMSG_DATA(nlh); | |
1036 | + | |
1037 | + /* Only vendor specific commands are supported */ | |
1038 | + if (!(snlh->msgtype & FC_NL_VNDR_SPECIFIC)) | |
1039 | + return -EBADMSG; | |
1040 | + | |
1041 | + ql_cmd = (struct qla_fc_msg *)((char *)snlh + sizeof (struct scsi_nl_hdr)); | |
1042 | + | |
1043 | + if (ql_cmd->magic != QL_FC_NL_MAGIC) | |
1044 | + return -EBADMSG; | |
1045 | + | |
1046 | + shost = scsi_host_lookup(ql_cmd->host_no); | |
1047 | + if (IS_ERR(shost)) { | |
1048 | + DEBUG2_16(printk(KERN_ERR "%s: could not find host no %u\n", | |
1049 | + __FUNCTION__, ql_cmd->host_no)); | |
1050 | + err = -ENODEV; | |
1051 | + goto exit_proc_nl_rcv_msg; | |
1052 | + } | |
1053 | + | |
1054 | + ha = (struct scsi_qla_host *)shost->hostdata; | |
1055 | + | |
1056 | + if (!ha || (!IS_QLA84XX(ha) && (ql_cmd->cmd != QLFC_GET_AEN))) { | |
1057 | + DEBUG2_16(printk(KERN_ERR "%s: invalid host ha = %p dtype = " | |
1058 | + "0x%x\n", __FUNCTION__, ha, (ha ? DT_MASK(ha): ~0))); | |
1059 | + err = -ENODEV; | |
1060 | + goto exit_proc_nl_rcv_msg; | |
1061 | + } | |
1062 | + | |
1063 | + switch (ql_cmd->cmd) { | |
1064 | + | |
1065 | + case QLA84_RESET: | |
1066 | + | |
1067 | + rsp_hdr_len = offsetof(struct qla_fc_msg, u); | |
1068 | + err = qla84xx_reset(ha, ql_cmd->u.utok.qla84_reset.diag_fw); | |
1069 | + ql_cmd->error = err; | |
1070 | + | |
1071 | + err = ql_fc_nl_rsp(NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq, | |
1072 | + (uint32_t)nlh->nlmsg_type, ql_cmd, rsp_hdr_len, NULL, 0); | |
1073 | + break; | |
1074 | + | |
1075 | + case QLA84_UPDATE_FW: | |
1076 | + rsp_hdr_len = offsetof(struct qla_fc_msg, u); | |
1077 | + err = qla84xx_update_fw(ha, (rcvlen - sizeof(struct scsi_nl_hdr)), | |
1078 | + &ql_cmd->u.utok.qla84_update_fw); | |
1079 | + ql_cmd->error = err; | |
1080 | + | |
1081 | + err = ql_fc_nl_rsp(NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq, | |
1082 | + (uint32_t)nlh->nlmsg_type, ql_cmd, rsp_hdr_len, NULL, 0); | |
1083 | + break; | |
1084 | + | |
1085 | + case QLA84_MGMT_CMD: | |
1086 | + err = qla84xx_mgmt_cmd(ha, ql_cmd, | |
1087 | + (rcvlen - sizeof(struct scsi_nl_hdr)), | |
1088 | + NETLINK_CREDS(skb)->pid, | |
1089 | + nlh->nlmsg_seq, (uint32_t)nlh->nlmsg_type); | |
1090 | + break; | |
1091 | + default: | |
1092 | + err = -EBADMSG; | |
1093 | + } | |
1094 | + | |
1095 | +exit_proc_nl_rcv_msg: | |
1096 | + return err; | |
1097 | +} | |
1098 | + | |
1099 | +static int | |
1100 | +ql_fc_nl_event(struct notifier_block *this, unsigned long event, void *ptr) | |
1101 | +{ | |
1102 | + DEBUG16(printk(KERN_WARNING "%s: event 0x%lx ptr = %p\n", __func__, | |
1103 | + event, ptr)); | |
1104 | + return NOTIFY_DONE; | |
1105 | +} | |
1106 | + | |
1107 | +static int | |
1108 | +ql_fc_nl_rsp(uint32_t pid, uint32_t seq, uint32_t type, void *hdr, int hdr_len, | |
1109 | + void *payload, int size) | |
1110 | +{ | |
1111 | + struct sk_buff *skb; | |
1112 | + struct nlmsghdr *nlh; | |
1113 | + int rc; | |
1114 | + int len = NLMSG_SPACE(size + hdr_len); | |
1115 | + | |
1116 | + skb = alloc_skb(len, GFP_ATOMIC); | |
1117 | + if (!skb) { | |
1118 | + DEBUG2_16(printk(KERN_ERR "%s: Could not alloc skb\n", | |
1119 | + __func__)); | |
1120 | + return -ENOMEM; | |
1121 | + } | |
1122 | + nlh = __nlmsg_put(skb, pid, seq, type, (len - sizeof(*nlh)), 0); | |
1123 | + nlh->nlmsg_flags = 0; | |
1124 | + memcpy(NLMSG_DATA(nlh), hdr, hdr_len); | |
1125 | + | |
1126 | + if (payload) | |
1127 | + memcpy((void *)((char *)(NLMSG_DATA(nlh)) + hdr_len), payload, size); | |
1128 | + | |
1129 | + rc = netlink_unicast(ql_fc_nl_sock, skb, pid, MSG_DONTWAIT); | |
1130 | + if (rc < 0) { | |
1131 | + DEBUG2_16(printk(KERN_ERR "%s: netlink_unicast failed\n", | |
1132 | + __func__)); | |
1133 | + return rc; | |
1134 | + } | |
1135 | + return 0; | |
1136 | +} | |
1137 | + | |
1138 | +void qla_free_nlnk_dmabuf(scsi_qla_host_t *ha) | |
1139 | +{ | |
1140 | + struct qlfc_fw *qlfw; | |
1141 | + | |
1142 | + qlfw = &ha->fw_buf; | |
1143 | + | |
1144 | + if (qlfw->fw_buf) { | |
1145 | + dma_free_coherent(&ha->pdev->dev, qlfw->len, qlfw->fw_buf, | |
1146 | + qlfw->fw_dma); | |
1147 | + memset(qlfw, 0, sizeof(struct qlfc_fw)); | |
1148 | + } | |
1149 | +} | |
1150 | + | |
1151 | +int | |
1152 | +ql_nl_register(void) | |
1153 | +{ | |
1154 | + int error = 0; | |
1155 | + | |
1156 | + error = netlink_register_notifier(&ql_fc_nl_notifier); | |
1157 | + if (!error) { | |
1158 | + | |
1159 | + ql_fc_nl_sock = netlink_kernel_create(&init_net, | |
1160 | + NETLINK_FCTRANSPORT, QL_FC_NL_GROUP_CNT, ql_fc_nl_rcv_msg, | |
1161 | + NULL, THIS_MODULE); | |
1162 | + | |
1163 | + if (!ql_fc_nl_sock) { | |
1164 | + netlink_unregister_notifier(&ql_fc_nl_notifier); | |
1165 | + error = -ENODEV; | |
1166 | + } | |
1167 | + } | |
1168 | + return (error); | |
1169 | +} | |
1170 | + | |
1171 | +void | |
1172 | +ql_nl_unregister() | |
1173 | +{ | |
1174 | + if (ql_fc_nl_sock) { | |
1175 | + sock_release(ql_fc_nl_sock->sk_socket); | |
1176 | + netlink_unregister_notifier(&ql_fc_nl_notifier); | |
1177 | + } | |
1178 | +} | |
1179 | diff --git a/drivers/scsi/qla2xxx/qla_nlnk.h b/drivers/scsi/qla2xxx/qla_nlnk.h | |
1180 | new file mode 100644 | |
1181 | index 0000000..d1488a6 | |
1182 | --- /dev/null | |
1183 | +++ b/drivers/scsi/qla2xxx/qla_nlnk.h | |
1184 | @@ -0,0 +1,168 @@ | |
1185 | +/* | |
1186 | + * QLogic Fibre Channel HBA Driver | |
1187 | + * Copyright (c) 2003-2005 QLogic Corporation | |
1188 | + * | |
1189 | + * See LICENSE.qla2xxx for copyright and licensing details. | |
1190 | + */ | |
1191 | +#ifndef _QLA_NLNK_H_ | |
1192 | +#define _QLA_NLNK_H_ | |
1193 | + | |
1194 | +#ifndef NETLINK_FCTRANSPORT | |
1195 | +#define NETLINK_FCTRANSPORT 20 | |
1196 | +#endif | |
1197 | +#define QL_FC_NL_GROUP_CNT 0 | |
1198 | + | |
1199 | +#define FC_TRANSPORT_MSG NLMSG_MIN_TYPE + 1 | |
1200 | + | |
1201 | +/* | |
1202 | + * Transport Message Types | |
1203 | + */ | |
1204 | +#define FC_NL_VNDR_SPECIFIC 0x8000 | |
1205 | + | |
1206 | +/* | |
1207 | + * Structures | |
1208 | + */ | |
1209 | + | |
1210 | +struct qla84_mgmt_param { | |
1211 | + union { | |
1212 | + struct { | |
1213 | + uint32_t start_addr; | |
1214 | + } mem; /* for QLA84_MGMT_READ/WRITE_MEM */ | |
1215 | + struct { | |
1216 | + uint32_t id; | |
1217 | +#define QLA84_MGMT_CONFIG_ID_UIF 1 | |
1218 | +#define QLA84_MGMT_CONFIG_ID_FCOE_COS 2 | |
1219 | +#define QLA84_MGMT_CONFIG_ID_PAUSE 3 | |
1220 | +#define QLA84_MGMT_CONFIG_ID_TIMEOUTS 4 | |
1221 | + | |
1222 | + uint32_t param0; | |
1223 | + uint32_t param1; | |
1224 | + } config; /* for QLA84_MGMT_CHNG_CONFIG */ | |
1225 | + | |
1226 | + struct { | |
1227 | + uint32_t type; | |
1228 | +#define QLA84_MGMT_INFO_CONFIG_LOG_DATA 1 /* Get Config Log Data */ | |
1229 | +#define QLA84_MGMT_INFO_LOG_DATA 2 /* Get Log Data */ | |
1230 | +#define QLA84_MGMT_INFO_PORT_STAT 3 /* Get Port Statistics */ | |
1231 | +#define QLA84_MGMT_INFO_LIF_STAT 4 /* Get LIF Statistics */ | |
1232 | +#define QLA84_MGMT_INFO_ASIC_STAT 5 /* Get ASIC Statistics */ | |
1233 | +#define QLA84_MGMT_INFO_CONFIG_PARAMS 6 /* Get Config Parameters */ | |
1234 | +#define QLA84_MGMT_INFO_PANIC_LOG 7 /* Get Panic Log */ | |
1235 | + | |
1236 | + uint32_t context; | |
1237 | +/* | |
1238 | + * context definitions for QLA84_MGMT_INFO_CONFIG_LOG_DATA | |
1239 | + */ | |
1240 | +#define IC_LOG_DATA_LOG_ID_DEBUG_LOG 0 | |
1241 | +#define IC_LOG_DATA_LOG_ID_LEARN_LOG 1 | |
1242 | +#define IC_LOG_DATA_LOG_ID_FC_ACL_INGRESS_LOG 2 | |
1243 | +#define IC_LOG_DATA_LOG_ID_FC_ACL_EGRESS_LOG 3 | |
1244 | +#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_INGRESS_LOG 4 | |
1245 | +#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_EGRESS_LOG 5 | |
1246 | +#define IC_LOG_DATA_LOG_ID_MESSAGE_TRANSMIT_LOG 6 | |
1247 | +#define IC_LOG_DATA_LOG_ID_MESSAGE_RECEIVE_LOG 7 | |
1248 | +#define IC_LOG_DATA_LOG_ID_LINK_EVENT_LOG 8 | |
1249 | +#define IC_LOG_DATA_LOG_ID_DCX_LOG 9 | |
1250 | + | |
1251 | +/* | |
1252 | + * context definitions for QLA84_MGMT_INFO_PORT_STAT | |
1253 | + */ | |
1254 | +#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT0 0 | |
1255 | +#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT1 1 | |
1256 | +#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT0 2 | |
1257 | +#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT1 3 | |
1258 | +#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT0 4 | |
1259 | +#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT1 5 | |
1260 | + | |
1261 | + | |
1262 | +/* | |
1263 | + * context definitions for QLA84_MGMT_INFO_LIF_STAT | |
1264 | + */ | |
1265 | +#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT0 0 | |
1266 | +#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT1 1 | |
1267 | +#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT0 2 | |
1268 | +#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT1 3 | |
1269 | +#define IC_LIF_STATISTICS_LIF_NUMBER_CPU 6 | |
1270 | + | |
1271 | + } info; /* for QLA84_MGMT_GET_INFO */ | |
1272 | + } u; | |
1273 | +}; | |
1274 | + | |
1275 | +#define QLFC_MAX_AEN 256 | |
1276 | +struct qlfc_aen_entry { | |
1277 | + uint16_t event_code; | |
1278 | + uint16_t payload[3]; | |
1279 | +}; | |
1280 | + | |
1281 | +struct qlfc_aen_log { | |
1282 | + uint32_t num_events; | |
1283 | + struct qlfc_aen_entry aen[QLFC_MAX_AEN]; | |
1284 | +}; | |
1285 | + | |
1286 | +struct qla84_msg_mgmt { | |
1287 | + uint16_t cmd; | |
1288 | +#define QLA84_MGMT_READ_MEM 0x00 | |
1289 | +#define QLA84_MGMT_WRITE_MEM 0x01 | |
1290 | +#define QLA84_MGMT_CHNG_CONFIG 0x02 | |
1291 | +#define QLA84_MGMT_GET_INFO 0x03 | |
1292 | + uint16_t rsrvd; | |
1293 | + struct qla84_mgmt_param mgmtp;/* parameters for cmd */ | |
1294 | + uint32_t len; /* bytes in payload following this struct */ | |
1295 | + uint8_t payload[0]; /* payload for cmd */ | |
1296 | +}; | |
1297 | + | |
1298 | +struct msg_update_fw { | |
1299 | + /* | |
1300 | + * diag_fw = 0 operational fw | |
1301 | + * otherwise diagnostic fw | |
1302 | + * offset, len, fw_len are present to overcome the current limitation | |
1303 | + * of 128Kb xfer size. The fw is sent in smaller chunks. Each chunk | |
1304 | + * specifies the byte "offset" where it fits in the fw buffer. The | |
1305 | + * number of bytes in each chunk is specified in "len". "fw_len" | |
1306 | + * is the total size of fw. The first chunk should start at offset = 0. | |
1307 | + * When offset+len == fw_len, the fw is written to the HBA. | |
1308 | + */ | |
1309 | + uint32_t diag_fw; | |
1310 | + uint32_t offset;/* start offset */ | |
1311 | + uint32_t len; /* num bytes in cur xfer */ | |
1312 | + uint32_t fw_len; /* size of fw in bytes */ | |
1313 | + uint8_t fw_bytes[0]; | |
1314 | +}; | |
1315 | + | |
1316 | +struct qla_fc_msg { | |
1317 | + | |
1318 | + uint64_t magic; | |
1319 | +#define QL_FC_NL_MAGIC 0x107784DDFCAB1FC1 | |
1320 | + uint16_t host_no; | |
1321 | + uint16_t vmsg_datalen; | |
1322 | + | |
1323 | + uint32_t cmd; | |
1324 | +#define QLA84_RESET 0x01 | |
1325 | +#define QLA84_UPDATE_FW 0x02 | |
1326 | +#define QLA84_MGMT_CMD 0x03 | |
1327 | +#define QLFC_GET_AEN 0x04 | |
1328 | + | |
1329 | + uint32_t error; /* interface or resource error holder*/ | |
1330 | + | |
1331 | + union { | |
1332 | + union { | |
1333 | + struct msg_reset { | |
1334 | + /* | |
1335 | + * diag_fw = 0 for operational fw | |
1336 | + * otherwise diagnostic fw | |
1337 | + */ | |
1338 | + uint32_t diag_fw; | |
1339 | + } qla84_reset; | |
1340 | + | |
1341 | + struct msg_update_fw qla84_update_fw; | |
1342 | + struct qla84_msg_mgmt mgmt; | |
1343 | + } utok; | |
1344 | + | |
1345 | + union { | |
1346 | + struct qla84_msg_mgmt mgmt; | |
1347 | + struct qlfc_aen_log aen_log; | |
1348 | + } ktou; | |
1349 | + } u; | |
1350 | +} __attribute__ ((aligned (sizeof(uint64_t)))); | |
1351 | + | |
1352 | +#endif /* _QLA_NLNK_H_ */ | |
1353 | diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c | |
1354 | index 4774acb..70d03a8 100644 | |
1355 | --- a/drivers/scsi/qla2xxx/qla_os.c | |
1356 | +++ b/drivers/scsi/qla2xxx/qla_os.c | |
1357 | @@ -1670,6 +1670,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |
1358 | init_completion(&ha->mbx_cmd_comp); | |
1359 | complete(&ha->mbx_cmd_comp); | |
1360 | init_completion(&ha->mbx_intr_comp); | |
1361 | + init_completion(&ha->pass_thru_intr_comp); | |
1362 | ||
1363 | INIT_LIST_HEAD(&ha->list); | |
1364 | INIT_LIST_HEAD(&ha->fcports); | |
1365 | @@ -1790,6 +1791,8 @@ qla2x00_remove_one(struct pci_dev *pdev) | |
1366 | ||
1367 | qla2x00_free_sysfs_attr(ha); | |
1368 | ||
1369 | + qla_free_nlnk_dmabuf(ha); | |
1370 | + | |
1371 | fc_remove_host(ha->host); | |
1372 | ||
1373 | scsi_remove_host(ha->host); | |
1374 | @@ -2020,10 +2023,19 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha) | |
1375 | sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, GFP_KERNEL); | |
1376 | if (!ha->ct_sns) | |
1377 | goto fail_free_ms_iocb; | |
1378 | + /*Get consistent memory allocated for pass-thru commands */ | |
1379 | + ha->pass_thru = dma_alloc_coherent(&ha->pdev->dev, | |
1380 | + PAGE_SIZE, &ha->pass_thru_dma, GFP_KERNEL); | |
1381 | + if (!ha->pass_thru) | |
1382 | + goto fail_free_ct_sns; | |
1383 | } | |
1384 | ||
1385 | return 0; | |
1386 | ||
1387 | +fail_free_ct_sns: | |
1388 | + dma_pool_free(ha->s_dma_pool, ha->ct_sns, ha->ct_sns_dma); | |
1389 | + ha->ct_sns = NULL; | |
1390 | + ha->ct_sns_dma = 0; | |
1391 | fail_free_ms_iocb: | |
1392 | dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); | |
1393 | ha->ms_iocb = NULL; | |
1394 | @@ -2092,6 +2104,10 @@ qla2x00_mem_free(scsi_qla_host_t *ha) | |
1395 | dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt), | |
1396 | ha->sns_cmd, ha->sns_cmd_dma); | |
1397 | ||
1398 | + if (ha->pass_thru) | |
1399 | + dma_free_coherent(&ha->pdev->dev, PAGE_SIZE, | |
1400 | + ha->pass_thru, ha->pass_thru_dma); | |
1401 | + | |
1402 | if (ha->ct_sns) | |
1403 | dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt), | |
1404 | ha->ct_sns, ha->ct_sns_dma); | |
1405 | @@ -2130,6 +2146,8 @@ qla2x00_mem_free(scsi_qla_host_t *ha) | |
1406 | ha->sns_cmd_dma = 0; | |
1407 | ha->ct_sns = NULL; | |
1408 | ha->ct_sns_dma = 0; | |
1409 | + ha->pass_thru = NULL; | |
1410 | + ha->pass_thru_dma = 0; | |
1411 | ha->ms_iocb = NULL; | |
1412 | ha->ms_iocb_dma = 0; | |
1413 | ha->init_cb = NULL; | |
1414 | @@ -2903,10 +2921,18 @@ qla2x00_module_init(void) | |
1415 | return -ENODEV; | |
1416 | } | |
1417 | ||
1418 | + if (ql_nl_register()) { | |
1419 | + kmem_cache_destroy(srb_cachep); | |
1420 | + fc_release_transport(qla2xxx_transport_template); | |
1421 | + fc_release_transport(qla2xxx_transport_vport_template); | |
1422 | + return -ENODEV; | |
1423 | + } | |
1424 | + | |
1425 | printk(KERN_INFO "QLogic Fibre Channel HBA Driver: %s\n", | |
1426 | qla2x00_version_str); | |
1427 | ret = pci_register_driver(&qla2xxx_pci_driver); | |
1428 | if (ret) { | |
1429 | + ql_nl_unregister(); | |
1430 | kmem_cache_destroy(srb_cachep); | |
1431 | fc_release_transport(qla2xxx_transport_template); | |
1432 | fc_release_transport(qla2xxx_transport_vport_template); | |
1433 | @@ -2922,6 +2948,7 @@ qla2x00_module_exit(void) | |
1434 | { | |
1435 | pci_unregister_driver(&qla2xxx_pci_driver); | |
1436 | qla2x00_release_firmware(); | |
1437 | + ql_nl_unregister(); | |
1438 | kmem_cache_destroy(srb_cachep); | |
1439 | fc_release_transport(qla2xxx_transport_template); | |
1440 | fc_release_transport(qla2xxx_transport_vport_template); | |
1441 | diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h | |
1442 | index eea6720..d88bb2c 100644 | |
1443 | --- a/drivers/scsi/qla2xxx/qla_version.h | |
1444 | +++ b/drivers/scsi/qla2xxx/qla_version.h | |
1445 | @@ -7,7 +7,7 @@ | |
1446 | /* | |
1447 | * Driver version | |
1448 | */ | |
1449 | -#define QLA2XXX_VERSION "8.02.01-k9" | |
1450 | +#define QLA2XXX_VERSION "8.02.01.02.11.0-k9" | |
1451 | ||
1452 | #define QLA_DRIVER_MAJOR_VER 8 | |
1453 | #define QLA_DRIVER_MINOR_VER 2 |