]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.25/patches.drivers/qla2xxx-8.02.01.02.11.0-k9-update
Disable build of xen kernel.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.drivers / qla2xxx-8.02.01.02.11.0-k9-update
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