]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/patches/suse-2.6.27.31/patches.drivers/qla2xxx-8.02.01.02.11.0-k9-update
Move xen patchset to new version's subdir.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.drivers / qla2xxx-8.02.01.02.11.0-k9-update
CommitLineData
00e5a55c
BS
1From: David Wagner <david.wagner@qlogic.com>
2Subject: qla2xxx: additional fixes/updates for SLES11
3References: bnc#450197
4
5Here's some additional updates/corrections to qla2xxx for SLES11.
6Should 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
14Corresponding upstream patches are queued in our local tree for
15for the next merge window (post 2.6.28).
16
17Signed-off-by: David Vasquez <david.vasquez@qlogic.com>
18Signed-off-by: Hannes Reinecke <hare@suse.de>
19
20diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
21index 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
31diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
32index 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
377diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
378index 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
517diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
518index 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
535diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
536index 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 *);
599diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
600index 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;
612diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
613index 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
629diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
630index 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;
660diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
661index 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);
692diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
693index 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;
739diff --git a/drivers/scsi/qla2xxx/qla_nlnk.c b/drivers/scsi/qla2xxx/qla_nlnk.c
740new file mode 100644
741index 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+}
1179diff --git a/drivers/scsi/qla2xxx/qla_nlnk.h b/drivers/scsi/qla2xxx/qla_nlnk.h
1180new file mode 100644
1181index 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_ */
1353diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
1354index 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);
1441diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
1442index 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