Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3564

kernel-2.6.18-194.11.1.el5.src.rpm

From: Marcus Barrow <mbarrow@redhat.com>
Date: Thu, 7 Aug 2008 13:47:24 -0400
Subject: [scsi] qla2xxx - mgmt. API, CT pass thru
Message-id: 20080807174724.12734.87987.sendpatchset@file.bos.redhat.com
O-Subject: [rhel 5.3 patch] qla2xxx - mgmt. API, CT pass thru
Bugzilla: 455900
RH-Acked-by: Mike Christie <mchristi@redhat.com>

BZ 455900  [QLogic 5.3] qla2xxx - mgmt. API, CT pass thru

This patch provides information for our management API for Fibre Channel devices.
This provides functionality that would formerly have been performed by ioctl's.
It creates two more entries in sysfs, along with our VPD info, SFP info and option
rom control. These entries are used to pass thru commands.

diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index ab70be2..31888b3 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -460,6 +460,296 @@ static struct bin_attribute sysfs_sfp_attr = {
 	.read = qla2x00_sysfs_read_sfp,
 };
 
+static fc_port_t *
+qla2x00_find_port(struct scsi_qla_host *ha, uint8_t *pn)
+{
+	fc_port_t *fcport;
+
+	list_for_each_entry(fcport, &ha->fcports, list)
+		if (!memcmp(pn, fcport->port_name, sizeof(fcport->port_name)))
+			return fcport;
+
+	return NULL;
+}
+
+static void
+qla2x00_wait_for_passthru_completion(struct scsi_qla_host *ha)
+{
+	if (wait_for_completion_timeout(&ha->pass_thru_intr_comp, 10 * HZ))
+		qla_printk(KERN_INFO, ha, "Passthru request completed.\n");
+	else {
+		qla_printk(KERN_WARNING, ha, "Passthru request timed out.\n");
+		ha->isp_ops->fw_dump(ha, 0);
+	}
+}
+
+static ssize_t
+qla2x00_sysfs_read_els(struct kobject *kobj, char *buf, loff_t off, 
+    size_t count)
+{
+	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(
+	    container_of(kobj, struct device, kobj)));
+
+	if (!ha->pass_thru_cmd_in_process || !ha->pass_thru_cmd_result) {
+		qla_printk(KERN_WARNING, ha,
+		    "Passthru ELS response is not available.\n");
+		return 0;
+	}
+
+	memcpy(buf, ha->pass_thru, count);
+
+	qla_printk(KERN_INFO, ha, "Passthru ELS response %X:\n", 
+	    ((ct_iu_t *)buf)->command);
+	qla2x00_print_byte_buf(buf, min(count, (size_t)64), 16);
+
+	ha->pass_thru_cmd_result = 0;
+	ha->pass_thru_cmd_in_process = 0;
+
+	return count;
+}
+
+static ssize_t
+qla2x00_sysfs_write_els(struct kobject *kobj, char *buf, loff_t off,
+    size_t count)
+{
+	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(
+	    container_of(kobj, struct device, kobj)));
+	els_request_t *request = (void *)buf;
+	struct els_entry_24xx *els_iocb;
+	unsigned long flags;
+	uint16_t nextlid = 0;
+	fc_port_t *fcport;
+
+	count -= sizeof(request->header);
+
+	if (count < sizeof(request->ct_iu)) {
+		qla_printk(KERN_WARNING, ha,
+		    "Passthru ELS buffer insufficient size %d...\n",
+                    (int)count);
+		goto els_error0;
+	}
+
+	if (ha->pass_thru_cmd_in_process || ha->pass_thru_cmd_result) {
+		qla_printk(KERN_WARNING, ha,
+		    "Passthru ELS request is already progress\n");
+		goto els_error0;
+	}
+
+	fcport = qla2x00_find_port(ha, request->header.WWPN);
+	if (!fcport) {
+		qla_printk(KERN_WARNING, ha,
+		    "Passthru ELS request failed find port\n");
+		goto els_error0;
+	}
+
+	if (qla2x00_fabric_login(ha, fcport, &nextlid)) {
+		qla_printk(KERN_WARNING, ha,
+		    "Passthru ELS request failed to login port %06X\n",
+		    fcport->d_id.b24);
+		goto els_error0;
+	}
+
+	ha->pass_thru_cmd_in_process = 1;
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	els_iocb = (void *)qla2x00_req_pkt(ha);
+	if (els_iocb == NULL) {
+		qla_printk(KERN_WARNING, ha,
+		    "Passthru ELS request failed to get request packet\n");
+		goto els_error1;
+	}
+
+	if (count > PAGE_SIZE) {
+		qla_printk(KERN_INFO, ha,
+		    "Passthru ELS request excessive size %d...\n",
+                    (int)count);
+		count = PAGE_SIZE;
+	}
+
+	memset(ha->pass_thru, 0, PAGE_SIZE);
+	memcpy(ha->pass_thru, &request->ct_iu, count);
+
+	els_iocb->entry_type = ELS_IOCB_TYPE;
+	els_iocb->entry_count = 1;
+	els_iocb->sys_define = 0;
+	els_iocb->entry_status = 0;
+	els_iocb->nport_handle = cpu_to_le16(fcport->loop_id);
+	els_iocb->tx_dsd_count = __constant_cpu_to_le16(1);
+	els_iocb->vp_index = ha->vp_idx;
+	els_iocb->sof_type = EST_SOFI3;
+	els_iocb->rx_dsd_count = __constant_cpu_to_le16(1);
+	els_iocb->opcode = 0;
+	els_iocb->port_id[0] = fcport->d_id.b.al_pa;
+	els_iocb->port_id[1] = fcport->d_id.b.area;
+	els_iocb->port_id[2] = fcport->d_id.b.domain;
+	els_iocb->control_flags = __constant_cpu_to_le16(0);
+	els_iocb->rx_byte_count = cpu_to_le32(PAGE_SIZE);
+	els_iocb->tx_byte_count = cpu_to_le32(count);
+	els_iocb->tx_address[0] = cpu_to_le32(LSD(ha->pass_thru_dma));
+	els_iocb->tx_address[1] = cpu_to_le32(MSD(ha->pass_thru_dma));
+	els_iocb->tx_len = els_iocb->tx_byte_count;
+	els_iocb->rx_address[0] = cpu_to_le32(LSD(ha->pass_thru_dma));
+	els_iocb->rx_address[1] = cpu_to_le32(MSD(ha->pass_thru_dma));
+	els_iocb->rx_len = els_iocb->rx_byte_count;
+
+	qla_printk(KERN_INFO, ha, "Passthru ELS request:\n");
+	qla2x00_print_byte_buf(ha->pass_thru, min(count, (size_t)32), 16);
+
+	qla_printk(KERN_INFO, ha, "Passthru ELS IOCB:\n");
+	qla2x00_print_word_buf(els_iocb, sizeof(*els_iocb), 8);
+
+	wmb();
+	qla2x00_isp_cmd(ha);
+
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	qla2x00_wait_for_passthru_completion(ha);
+
+	return count;
+
+els_error1:
+	ha->pass_thru_cmd_in_process = 0;
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+els_error0:
+	qla_printk(KERN_WARNING, ha, "Passthru ELS failed\n");
+	return 0;
+}
+
+static struct bin_attribute sysfs_els_attr = {
+	.attr = {
+		.name = "els",
+		.mode = S_IRUSR | S_IWUSR,
+		.owner = THIS_MODULE,
+	},
+	.size = 0,
+	.read = qla2x00_sysfs_read_els,
+	.write = qla2x00_sysfs_write_els,
+};
+
+static ssize_t
+qla2x00_sysfs_read_ct(struct kobject *kobj, char *buf, loff_t off,
+    size_t count)
+{
+	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(
+	    container_of(kobj, struct device, kobj)));
+
+	if (!ha->pass_thru_cmd_in_process || !ha->pass_thru_cmd_result) {
+		qla_printk(KERN_WARNING, ha,
+		    "Passthru CT response is not available.\n");
+		return 0;
+	}
+
+	memcpy(buf, ha->pass_thru, count);
+
+	qla_printk(KERN_INFO, ha, "Passthru CT response %X:\n", 
+	    ((ct_iu_t *)buf)->command);
+	qla2x00_print_byte_buf(buf, min(count, (size_t)64), 16);
+
+	ha->pass_thru_cmd_result = 0;
+	ha->pass_thru_cmd_in_process = 0;
+
+	return count;
+}
+
+static ssize_t
+qla2x00_sysfs_write_ct(struct kobject *kobj, char *buf, loff_t off,
+    size_t count)
+{
+	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(
+	    container_of(kobj, struct device, kobj)));
+	fc_ct_request_t *request = (void *)buf;
+	struct ct_entry_24xx *ct_iocb;
+	unsigned long flags;
+
+	if (count < sizeof(request->ct_iu)) {
+		qla_printk(KERN_WARNING, ha,
+		    "Passthru CT buffer insufficient size %d...\n",
+                    (int)count);
+		goto ct_error0;
+	}
+
+	if (ha->pass_thru_cmd_in_process || ha->pass_thru_cmd_result) {
+		qla_printk(KERN_WARNING, ha,
+		    "Passthru CT request is already progress\n");
+		goto ct_error0;
+	}
+
+	if (qla2x00_mgmt_svr_login(ha)) {
+		qla_printk(KERN_WARNING, ha,
+		    "Passthru CT request failed to login management server\n");
+		goto ct_error0;
+	}
+
+	ha->pass_thru_cmd_in_process = 1;
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	ct_iocb = (void *)qla2x00_req_pkt(ha);
+	if (ct_iocb == NULL) {
+		qla_printk(KERN_WARNING, ha,
+		    "Passthru CT request failed to get request packet\n");
+		goto ct_error1;
+	}
+
+	if (count > PAGE_SIZE) {
+		qla_printk(KERN_INFO, ha,
+		    "Passthru CT request excessive size %d...\n",
+		    (int)count);
+		count = PAGE_SIZE;
+	}
+
+	memset(ha->pass_thru, 0, PAGE_SIZE);
+	memcpy(ha->pass_thru, &request->ct_iu, count);
+
+	ct_iocb->entry_type = CT_IOCB_TYPE;
+	ct_iocb->entry_count = 1;
+	ct_iocb->entry_status = 0;
+	ct_iocb->comp_status = __constant_cpu_to_le16(0);
+	ct_iocb->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id);
+	ct_iocb->cmd_dsd_count = __constant_cpu_to_le16(1);
+	ct_iocb->vp_index = ha->vp_idx;
+	ct_iocb->timeout = __constant_cpu_to_le16(25);
+	ct_iocb->rsp_dsd_count = __constant_cpu_to_le16(1);
+	ct_iocb->rsp_byte_count = cpu_to_le32(PAGE_SIZE);
+	ct_iocb->cmd_byte_count = cpu_to_le32(count);
+	ct_iocb->dseg_0_address[0] = cpu_to_le32(LSD(ha->pass_thru_dma));
+	ct_iocb->dseg_0_address[1] = cpu_to_le32(MSD(ha->pass_thru_dma));
+	ct_iocb->dseg_0_len = ct_iocb->cmd_byte_count;
+	ct_iocb->dseg_1_address[0] = cpu_to_le32(LSD(ha->pass_thru_dma));
+	ct_iocb->dseg_1_address[1] = cpu_to_le32(MSD(ha->pass_thru_dma));
+	ct_iocb->dseg_1_len = ct_iocb->rsp_byte_count;
+
+	qla_printk(KERN_INFO, ha, "Passthru CT request:\n");
+	qla2x00_print_byte_buf(ha->pass_thru, min(count, (size_t)32), 16);
+
+	qla_printk(KERN_INFO, ha, "Passthru CT IOCB:\n");
+	qla2x00_print_word_buf(ct_iocb, sizeof(*ct_iocb), 8);
+
+	wmb();
+	qla2x00_isp_cmd(ha);
+
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	qla2x00_wait_for_passthru_completion(ha);
+
+	return count;
+
+ct_error1:
+	ha->pass_thru_cmd_in_process = 0;
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ct_error0:
+	qla_printk(KERN_WARNING, ha, "Passthru CT failed\n");
+	return 0;
+}
+
+static struct bin_attribute sysfs_ct_attr = {
+	.attr = {
+		.name = "ct",
+		.mode = S_IRUSR | S_IWUSR,
+		.owner = THIS_MODULE,
+	},
+	.size = 0,
+	.read = qla2x00_sysfs_read_ct,
+	.write = qla2x00_sysfs_write_ct,
+};
+
 static struct sysfs_entry {
 	char *name;
 	struct bin_attribute *attr;
@@ -471,6 +761,8 @@ static struct sysfs_entry {
 	{ "optrom_ctl", &sysfs_optrom_ctl_attr, },
 	{ "vpd", &sysfs_vpd_attr, 1 },
 	{ "sfp", &sysfs_sfp_attr, 1 },
+	{ "els", &sysfs_els_attr, 1 },
+	{ "ct", &sysfs_ct_attr, 1 },
 	{ NULL },
 };
 
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index ca7f70d..35f4448 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -1443,6 +1443,36 @@ qla2x00_dump_pkt(void *pkt)
 	printk("\n");
 }
 
+void
+qla2x00_print_byte_buf(void *buffer, size_t count, size_t per_line)
+{
+	uint8_t *p = buffer;
+	size_t i;
+
+	for (i = 0; i < count; i++){
+		if (i && per_line && !(i % per_line))
+			printk("\n");
+		printk(" %02X", *p++);
+	}
+	printk("\n");
+}
+
+void
+qla2x00_print_word_buf(void *buffer, size_t count, size_t per_line)
+{
+	uint16_t *p = buffer;
+	size_t i;
+
+	count /= sizeof(*p);
+
+	for (i = 0; i < count; i++) {
+		if (i && per_line && !(i % per_line))
+			printk("\n");
+		printk(" %04X", *p++);
+	}
+	printk("\n");
+}
+
 #if defined(QL_DEBUG_ROUTINES)
 /*
  * qla2x00_formatted_dump_buffer
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 2226de1..c3257d3 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -94,6 +94,89 @@
 #define MSD(x)	((uint32_t)((((uint64_t)(x)) >> 16) >> 16))
 
 
+/* ELS PT request buffer = 32 bytes */
+#define EXT_ELS_PT_REQ_WWPN_VALID	0x1
+#define EXT_ELS_PT_REQ_WWNN_VALID	0x2
+#define EXT_ELS_PT_REQ_PID_VALID	0x4
+typedef struct {
+	uint8_t     WWNN[8];
+	uint8_t     WWPN[8];
+	uint8_t     Id[4];
+	uint16_t    ValidMask;
+	uint16_t    Lid;
+	uint16_t    Rxid;
+	uint16_t    AccRjt;
+	uint32_t    Reserved;
+} ext_els_pt_req;
+
+/* CT IU */
+typedef struct {
+	uint8_t revision;
+	uint8_t in_id[3];
+	uint8_t gs_type;
+	uint8_t gs_subtype;
+	uint8_t options;
+	uint8_t reserved0;
+	uint16_t command;
+	uint16_t max_rsp_size;
+	uint8_t fragment_id;
+	uint8_t reserved1[3];
+} ct_iu_t;
+
+/* CT request format */
+typedef struct {
+	ct_iu_t ct_iu;
+	union {
+		struct {
+			uint8_t reserved;
+			uint8_t port_id[3];
+		} port_id;
+
+		struct {
+			uint8_t port_type;
+			uint8_t domain;
+			uint8_t area;
+			uint8_t reserved;
+		} gid_pt;
+
+		struct {
+			uint8_t reserved;
+			uint8_t port_id[3];
+			uint8_t fc4_types[32];
+		} rft_id;
+
+		struct {
+			uint8_t reserved;
+			uint8_t port_id[3];
+			uint16_t reserved2;
+			uint8_t fc4_feature;
+			uint8_t fc4_type;
+		} rff_id;
+
+		struct {
+			uint8_t reserved;
+			uint8_t port_id[3];
+			uint8_t node_name[8];
+		} rnn_id;
+
+		struct {
+			uint8_t node_name[8];
+			uint8_t name_len;
+			uint8_t sym_node_name[255];
+		} rsnn_nn;
+
+		struct {
+			uint8_t hba_indentifier[8];
+		} ghat;
+	} extended;
+} fc_ct_request_t;
+
+/* ELS request format */
+typedef struct {
+	ext_els_pt_req header;
+	ct_iu_t ct_iu;
+} els_request_t;
+
 /*
  * I/O register
 */
@@ -2409,6 +2492,8 @@ typedef struct scsi_qla_host {
 	/* SNS command interfaces for 2200. */
 	struct sns_cmd_pkt	*sns_cmd;
 	dma_addr_t		sns_cmd_dma;
+	char 			*pass_thru;
+	dma_addr_t		pass_thru_dma;
 
 #define SFP_DEV_SIZE	256
 #define SFP_BLOCK_SIZE	64
@@ -2451,6 +2536,8 @@ typedef struct scsi_qla_host {
 	 struct semaphore vport_sem;	/* Virtual port synchronization */
 	struct semaphore mbx_intr_sem;  /* Used for completion notification */
 
+	struct completion pass_thru_intr_comp;  /* For pass thru notification */
+
 	uint32_t	mbx_flags;
 #define  MBX_IN_PROGRESS	BIT_0
 #define  MBX_BUSY		BIT_1	/* Got the Access */
@@ -2576,6 +2663,11 @@ typedef struct scsi_qla_host {
 #define FC_VPORT_NO_FABRIC_SUPP	6
 #define FC_VPORT_NO_FABRIC_RSCS	7
 #define FC_VPORT_FAILED		8
+
+	/* pass through support */
+	int	pass_thru_cmd_result;
+	int	pass_thru_cmd_in_process;
+
 	struct qla_chip_state_84xx *cs84xx;
 	struct qla_statistics qla_stats;
 } scsi_qla_host_t;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 0409064..3106455 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -132,6 +132,8 @@ extern int qla2x00_start_scsi(srb_t *sp);
 extern int qla24xx_start_scsi(srb_t *sp);
 int qla2x00_marker(scsi_qla_host_t *, uint16_t, uint16_t, uint8_t);
 int __qla2x00_marker(scsi_qla_host_t *, uint16_t, uint16_t, uint8_t);
+extern request_t * qla2x00_req_pkt(scsi_qla_host_t *);
+extern void qla2x00_isp_cmd(scsi_qla_host_t *ha);
 
 /*
  * Global Function Prototypes in qla_mbx.c source file.
@@ -338,6 +340,8 @@ extern void qla2x00_dump_regs(scsi_qla_host_t *);
 extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
 extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *);
 extern void qla2x00_dump_pkt(void *);
+extern void qla2x00_print_byte_buf(void *, size_t, size_t);
+extern void qla2x00_print_word_buf(void *, size_t, size_t);
 
 /*
  * Global Function Prototypes in qla_gs.c source file.
@@ -358,6 +362,7 @@ extern int qla2x00_fdmi_register(scsi_qla_host_t *);
 extern int qla2x00_gfpn_id(scsi_qla_host_t *, sw_info_t *);
 extern int qla2x00_gpsc(scsi_qla_host_t *, sw_info_t *);
 extern void qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *);
+extern int qla2x00_mgmt_svr_login(scsi_qla_host_t *);
 
 /*
  * Global Function Prototypes in qla_attr.c source file.
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index d5f2896..fe7f501 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -1099,7 +1099,7 @@ qla2x00_sns_rnn_id(scsi_qla_host_t *ha)
  *
  * Returns 0 on success.
  */
-static int
+int
 qla2x00_mgmt_svr_login(scsi_qla_host_t *ha)
 {
 	int ret;
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 84e10ed..65a6bb9 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -14,8 +14,6 @@
 static inline uint16_t qla2x00_get_cmd_direction(struct scsi_cmnd *cmd);
 static inline cont_entry_t *qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *);
 static inline cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *);
-static request_t *qla2x00_req_pkt(scsi_qla_host_t *ha);
-static void qla2x00_isp_cmd(scsi_qla_host_t *ha);
 
 /**
  * qla2x00_get_cmd_direction() - Determine control_flag data direction.
@@ -508,7 +506,7 @@ qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
  *
  * Returns NULL if function failed, else, a pointer to the request packet.
  */
-static request_t *
+request_t *
 qla2x00_req_pkt(scsi_qla_host_t *ha)
 {
 	device_reg_t __iomem *reg = ha->iobase;
@@ -578,7 +576,7 @@ qla2x00_req_pkt(scsi_qla_host_t *ha)
  *
  * Note: The caller must hold the hardware lock before calling this routine.
  */
-static void
+void
 qla2x00_isp_cmd(scsi_qla_host_t *ha)
 {
 	device_reg_t __iomem *reg = ha->iobase;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 8530e9b..cef0cc1 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1502,7 +1502,30 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha)
 			qla2x00_status_cont_entry(ha, (sts_cont_entry_t *)pkt);
 			break;
 		case MS_IOCB_TYPE:
-			qla24xx_ms_entry(ha, (struct ct_entry_24xx *)pkt);
+			if (ha->outstanding_cmds[pkt->handle])
+				qla24xx_ms_entry(ha, (void *)pkt);
+			else {
+				if (ha->pass_thru_cmd_result)
+					qla_printk(KERN_INFO, ha,
+					    "Passthru cmd result on.\n");
+				if (!ha->pass_thru_cmd_in_process)
+					qla_printk(KERN_INFO, ha,
+					    "Passthru in process off.\n");
+
+				ha->pass_thru_cmd_result = 1;
+				complete(&ha->pass_thru_intr_comp);
+			}
+			break;
+		case ELS_IOCB_TYPE:
+			if (ha->pass_thru_cmd_result)
+				qla_printk(KERN_INFO, ha,
+				    "Passthru cmd result on.\n");
+			if (!ha->pass_thru_cmd_in_process)
+				qla_printk(KERN_INFO, ha,
+				    "Passthru in process off.\n");
+
+			ha->pass_thru_cmd_result = 1;
+			complete(&ha->pass_thru_intr_comp);
 			break;
 		case VP_RPT_ID_IOCB_TYPE:
 			qla24xx_report_id_acquisition(ha,
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 4836b23..83386fe 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1720,6 +1720,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	/* load the F/W, read paramaters, and init the H/W */
 	ha->instance = num_hosts;
 
+	init_completion(&ha->pass_thru_intr_comp);
+
 	init_MUTEX(&ha->mbx_cmd_sem);
 	init_MUTEX(&ha->vport_sem);
 	init_MUTEX_LOCKED(&ha->mbx_intr_sem);
@@ -2213,6 +2215,21 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
 			}
 			memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt));
 
+			/*Get consistent memory allocated for pass-thru commands */
+			ha->pass_thru = dma_alloc_coherent(&ha->pdev->dev,
+			    PAGE_SIZE, &ha->pass_thru_dma, GFP_KERNEL);
+			if (ha->pass_thru == NULL) {
+				/* error */
+				qla_printk(KERN_WARNING, ha,
+				    "Memory Allocation failed - pass_thru\n");
+
+				qla2x00_mem_free(ha);
+				msleep(100);
+
+				continue;
+			}
+			memset(ha->pass_thru, 0, PAGE_SIZE);
+
 			if (IS_FWI2_CAPABLE(ha)) {
 				/*
 				 * Get consistent memory allocated for SFP
@@ -2297,6 +2314,10 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
 		dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt),
 		    ha->ct_sns, ha->ct_sns_dma);
 
+	if (ha->pass_thru)
+		dma_free_coherent(&ha->pdev->dev, PAGE_SIZE,
+		    ha->pass_thru, ha->pass_thru_dma);
+
 	if (ha->sfp_data)
 		dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma);
 
@@ -2330,6 +2351,8 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
 	ha->sns_cmd_dma = 0;
 	ha->ct_sns = NULL;
 	ha->ct_sns_dma = 0;
+	ha->pass_thru = NULL;
+	ha->pass_thru_dma = 0;
 	ha->ms_iocb = NULL;
 	ha->ms_iocb_dma = 0;
 	ha->init_cb = NULL;