diff --git a/drivers/net/ethernet/brocade/bna/Makefile b/drivers/net/ethernet/brocade/bna/Makefile
index a5d604de7fea7cad94af3306f9f5905b6972f743..d501f520b0bc70d75f42549c338bdf81990c1821 100644
--- a/drivers/net/ethernet/brocade/bna/Makefile
+++ b/drivers/net/ethernet/brocade/bna/Makefile
@@ -6,6 +6,7 @@
 obj-$(CONFIG_BNA) += bna.o
 
 bna-objs := bnad.o bnad_ethtool.o bna_ctrl.o bna_txrx.o
-bna-objs += bfa_ioc.o bfa_ioc_ct.o bfa_cee.o cna_fwimg.o
+bna-objs += bfa_msgq.o bfa_ioc.o bfa_ioc_ct.o bfa_cee.o
+bna-objs += cna_fwimg.o
 
 EXTRA_CFLAGS := -Idrivers/net/bna
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.c b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
index 3cdea65aee12f284a0016484da1ebf4abd89ecda..2d5c4fd778ee86b3673aef7dbb820fe8d6ffae13 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
@@ -1968,18 +1968,22 @@ bfa_nw_ioc_mbox_regisr(struct bfa_ioc *ioc, enum bfi_mclass mc,
  * @param[in]	ioc	IOC instance
  * @param[i]	cmd	Mailbox command
  */
-void
-bfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc, struct bfa_mbox_cmd *cmd)
+bool
+bfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc, struct bfa_mbox_cmd *cmd,
+			bfa_mbox_cmd_cbfn_t cbfn, void *cbarg)
 {
 	struct bfa_ioc_mbox_mod *mod = &ioc->mbox_mod;
 	u32			stat;
 
+	cmd->cbfn = cbfn;
+	cmd->cbarg = cbarg;
+
 	/**
 	 * If a previous command is pending, queue new command
 	 */
 	if (!list_empty(&mod->cmd_q)) {
 		list_add_tail(&cmd->qe, &mod->cmd_q);
-		return;
+		return true;
 	}
 
 	/**
@@ -1988,7 +1992,7 @@ bfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc, struct bfa_mbox_cmd *cmd)
 	stat = readl(ioc->ioc_regs.hfn_mbox_cmd);
 	if (stat) {
 		list_add_tail(&cmd->qe, &mod->cmd_q);
-		return;
+		return true;
 	}
 
 	/**
@@ -1996,7 +2000,7 @@ bfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc, struct bfa_mbox_cmd *cmd)
 	 */
 	bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
 
-	return;
+	return false;
 }
 
 /**
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.h b/drivers/net/ethernet/brocade/bna/bfa_ioc.h
index bda866ba6e905acb23212bfdd54fe3051dd1a5ef..33ba5f40ca3720b3b034ec6a78646223a88e0a56 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.h
@@ -253,7 +253,9 @@ struct bfa_ioc_hwif {
 /**
  * IOC mailbox interface
  */
-void bfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc, struct bfa_mbox_cmd *cmd);
+bool bfa_nw_ioc_mbox_queue(struct bfa_ioc *ioc,
+			struct bfa_mbox_cmd *cmd,
+			bfa_mbox_cmd_cbfn_t cbfn, void *cbarg);
 void bfa_nw_ioc_mbox_isr(struct bfa_ioc *ioc);
 void bfa_nw_ioc_mbox_regisr(struct bfa_ioc *ioc, enum bfi_mclass mc,
 		bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg);
diff --git a/drivers/net/ethernet/brocade/bna/bfa_msgq.c b/drivers/net/ethernet/brocade/bna/bfa_msgq.c
new file mode 100644
index 0000000000000000000000000000000000000000..ed52187827879755e9ac332b8252c8128c4b6f80
--- /dev/null
+++ b/drivers/net/ethernet/brocade/bna/bfa_msgq.c
@@ -0,0 +1,669 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+/**
+ * @file bfa_msgq.c MSGQ module source file.
+ */
+
+#include "bfi.h"
+#include "bfa_msgq.h"
+#include "bfa_ioc.h"
+
+#define call_cmdq_ent_cbfn(_cmdq_ent, _status)				\
+{									\
+	bfa_msgq_cmdcbfn_t cbfn;					\
+	void *cbarg;							\
+	cbfn = (_cmdq_ent)->cbfn;					\
+	cbarg = (_cmdq_ent)->cbarg;					\
+	(_cmdq_ent)->cbfn = NULL;					\
+	(_cmdq_ent)->cbarg = NULL;					\
+	if (cbfn) {							\
+		cbfn(cbarg, (_status));					\
+	}								\
+}
+
+static void bfa_msgq_cmdq_dbell(struct bfa_msgq_cmdq *cmdq);
+static void bfa_msgq_cmdq_copy_rsp(struct bfa_msgq_cmdq *cmdq);
+
+enum cmdq_event {
+	CMDQ_E_START			= 1,
+	CMDQ_E_STOP			= 2,
+	CMDQ_E_FAIL			= 3,
+	CMDQ_E_POST			= 4,
+	CMDQ_E_INIT_RESP		= 5,
+	CMDQ_E_DB_READY			= 6,
+};
+
+bfa_fsm_state_decl(cmdq, stopped, struct bfa_msgq_cmdq, enum cmdq_event);
+bfa_fsm_state_decl(cmdq, init_wait, struct bfa_msgq_cmdq, enum cmdq_event);
+bfa_fsm_state_decl(cmdq, ready, struct bfa_msgq_cmdq, enum cmdq_event);
+bfa_fsm_state_decl(cmdq, dbell_wait, struct bfa_msgq_cmdq,
+			enum cmdq_event);
+
+static void
+cmdq_sm_stopped_entry(struct bfa_msgq_cmdq *cmdq)
+{
+	struct bfa_msgq_cmd_entry *cmdq_ent;
+
+	cmdq->producer_index = 0;
+	cmdq->consumer_index = 0;
+	cmdq->flags = 0;
+	cmdq->token = 0;
+	cmdq->offset = 0;
+	cmdq->bytes_to_copy = 0;
+	while (!list_empty(&cmdq->pending_q)) {
+		bfa_q_deq(&cmdq->pending_q, &cmdq_ent);
+		bfa_q_qe_init(&cmdq_ent->qe);
+		call_cmdq_ent_cbfn(cmdq_ent, BFA_STATUS_FAILED);
+	}
+}
+
+static void
+cmdq_sm_stopped(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
+{
+	switch (event) {
+	case CMDQ_E_START:
+		bfa_fsm_set_state(cmdq, cmdq_sm_init_wait);
+		break;
+
+	case CMDQ_E_STOP:
+	case CMDQ_E_FAIL:
+		/* No-op */
+		break;
+
+	case CMDQ_E_POST:
+		cmdq->flags |= BFA_MSGQ_CMDQ_F_DB_UPDATE;
+		break;
+
+	default:
+		bfa_sm_fault(event);
+	}
+}
+
+static void
+cmdq_sm_init_wait_entry(struct bfa_msgq_cmdq *cmdq)
+{
+	bfa_wc_down(&cmdq->msgq->init_wc);
+}
+
+static void
+cmdq_sm_init_wait(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
+{
+	switch (event) {
+	case CMDQ_E_STOP:
+	case CMDQ_E_FAIL:
+		bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
+		break;
+
+	case CMDQ_E_POST:
+		cmdq->flags |= BFA_MSGQ_CMDQ_F_DB_UPDATE;
+		break;
+
+	case CMDQ_E_INIT_RESP:
+		if (cmdq->flags & BFA_MSGQ_CMDQ_F_DB_UPDATE) {
+			cmdq->flags &= ~BFA_MSGQ_CMDQ_F_DB_UPDATE;
+			bfa_fsm_set_state(cmdq, cmdq_sm_dbell_wait);
+		} else
+			bfa_fsm_set_state(cmdq, cmdq_sm_ready);
+		break;
+
+	default:
+		bfa_sm_fault(event);
+	}
+}
+
+static void
+cmdq_sm_ready_entry(struct bfa_msgq_cmdq *cmdq)
+{
+}
+
+static void
+cmdq_sm_ready(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
+{
+	switch (event) {
+	case CMDQ_E_STOP:
+	case CMDQ_E_FAIL:
+		bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
+		break;
+
+	case CMDQ_E_POST:
+		bfa_fsm_set_state(cmdq, cmdq_sm_dbell_wait);
+		break;
+
+	default:
+		bfa_sm_fault(event);
+	}
+}
+
+static void
+cmdq_sm_dbell_wait_entry(struct bfa_msgq_cmdq *cmdq)
+{
+	bfa_msgq_cmdq_dbell(cmdq);
+}
+
+static void
+cmdq_sm_dbell_wait(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
+{
+	switch (event) {
+	case CMDQ_E_STOP:
+	case CMDQ_E_FAIL:
+		bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
+		break;
+
+	case CMDQ_E_POST:
+		cmdq->flags |= BFA_MSGQ_CMDQ_F_DB_UPDATE;
+		break;
+
+	case CMDQ_E_DB_READY:
+		if (cmdq->flags & BFA_MSGQ_CMDQ_F_DB_UPDATE) {
+			cmdq->flags &= ~BFA_MSGQ_CMDQ_F_DB_UPDATE;
+			bfa_fsm_set_state(cmdq, cmdq_sm_dbell_wait);
+		} else
+			bfa_fsm_set_state(cmdq, cmdq_sm_ready);
+		break;
+
+	default:
+		bfa_sm_fault(event);
+	}
+}
+
+static void
+bfa_msgq_cmdq_dbell_ready(void *arg)
+{
+	struct bfa_msgq_cmdq *cmdq = (struct bfa_msgq_cmdq *)arg;
+	bfa_fsm_send_event(cmdq, CMDQ_E_DB_READY);
+}
+
+static void
+bfa_msgq_cmdq_dbell(struct bfa_msgq_cmdq *cmdq)
+{
+	struct bfi_msgq_h2i_db *dbell =
+		(struct bfi_msgq_h2i_db *)(&cmdq->dbell_mb.msg[0]);
+
+	memset(dbell, 0, sizeof(struct bfi_msgq_h2i_db));
+	bfi_h2i_set(dbell->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_DOORBELL_PI, 0);
+	dbell->mh.mtag.i2htok = 0;
+	dbell->idx.cmdq_pi = htons(cmdq->producer_index);
+
+	if (!bfa_nw_ioc_mbox_queue(cmdq->msgq->ioc, &cmdq->dbell_mb,
+				bfa_msgq_cmdq_dbell_ready, cmdq)) {
+		bfa_msgq_cmdq_dbell_ready(cmdq);
+	}
+}
+
+static void
+__cmd_copy(struct bfa_msgq_cmdq *cmdq, struct bfa_msgq_cmd_entry *cmd)
+{
+	size_t len = cmd->msg_size;
+	int num_entries = 0;
+	size_t to_copy;
+	u8 *src, *dst;
+
+	src = (u8 *)cmd->msg_hdr;
+	dst = (u8 *)cmdq->addr.kva;
+	dst += (cmdq->producer_index * BFI_MSGQ_CMD_ENTRY_SIZE);
+
+	while (len) {
+		to_copy = (len < BFI_MSGQ_CMD_ENTRY_SIZE) ?
+				len : BFI_MSGQ_CMD_ENTRY_SIZE;
+		memcpy(dst, src, to_copy);
+		len -= to_copy;
+		src += BFI_MSGQ_CMD_ENTRY_SIZE;
+		BFA_MSGQ_INDX_ADD(cmdq->producer_index, 1, cmdq->depth);
+		dst = (u8 *)cmdq->addr.kva;
+		dst += (cmdq->producer_index * BFI_MSGQ_CMD_ENTRY_SIZE);
+		num_entries++;
+	}
+
+}
+
+static void
+bfa_msgq_cmdq_ci_update(struct bfa_msgq_cmdq *cmdq, struct bfi_mbmsg *mb)
+{
+	struct bfi_msgq_i2h_db *dbell = (struct bfi_msgq_i2h_db *)mb;
+	struct bfa_msgq_cmd_entry *cmd;
+	int posted = 0;
+
+	cmdq->consumer_index = ntohs(dbell->idx.cmdq_ci);
+
+	/* Walk through pending list to see if the command can be posted */
+	while (!list_empty(&cmdq->pending_q)) {
+		cmd =
+		(struct bfa_msgq_cmd_entry *)bfa_q_first(&cmdq->pending_q);
+		if (ntohs(cmd->msg_hdr->num_entries) <=
+			BFA_MSGQ_FREE_CNT(cmdq)) {
+			list_del(&cmd->qe);
+			__cmd_copy(cmdq, cmd);
+			posted = 1;
+			call_cmdq_ent_cbfn(cmd, BFA_STATUS_OK);
+		} else {
+			break;
+		}
+	}
+
+	if (posted)
+		bfa_fsm_send_event(cmdq, CMDQ_E_POST);
+}
+
+static void
+bfa_msgq_cmdq_copy_next(void *arg)
+{
+	struct bfa_msgq_cmdq *cmdq = (struct bfa_msgq_cmdq *)arg;
+
+	if (cmdq->bytes_to_copy)
+		bfa_msgq_cmdq_copy_rsp(cmdq);
+}
+
+static void
+bfa_msgq_cmdq_copy_req(struct bfa_msgq_cmdq *cmdq, struct bfi_mbmsg *mb)
+{
+	struct bfi_msgq_i2h_cmdq_copy_req *req =
+		(struct bfi_msgq_i2h_cmdq_copy_req *)mb;
+
+	cmdq->token = 0;
+	cmdq->offset = ntohs(req->offset);
+	cmdq->bytes_to_copy = ntohs(req->len);
+	bfa_msgq_cmdq_copy_rsp(cmdq);
+}
+
+static void
+bfa_msgq_cmdq_copy_rsp(struct bfa_msgq_cmdq *cmdq)
+{
+	struct bfi_msgq_h2i_cmdq_copy_rsp *rsp =
+		(struct bfi_msgq_h2i_cmdq_copy_rsp *)&cmdq->copy_mb.msg[0];
+	int copied;
+	u8 *addr = (u8 *)cmdq->addr.kva;
+
+	memset(rsp, 0, sizeof(struct bfi_msgq_h2i_cmdq_copy_rsp));
+	bfi_h2i_set(rsp->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_CMDQ_COPY_RSP, 0);
+	rsp->mh.mtag.i2htok = htons(cmdq->token);
+	copied = (cmdq->bytes_to_copy >= BFI_CMD_COPY_SZ) ? BFI_CMD_COPY_SZ :
+		cmdq->bytes_to_copy;
+	addr += cmdq->offset;
+	memcpy(rsp->data, addr, copied);
+
+	cmdq->token++;
+	cmdq->offset += copied;
+	cmdq->bytes_to_copy -= copied;
+
+	if (!bfa_nw_ioc_mbox_queue(cmdq->msgq->ioc, &cmdq->copy_mb,
+				bfa_msgq_cmdq_copy_next, cmdq)) {
+		bfa_msgq_cmdq_copy_next(cmdq);
+	}
+}
+
+static void
+bfa_msgq_cmdq_attach(struct bfa_msgq_cmdq *cmdq, struct bfa_msgq *msgq)
+{
+	cmdq->depth = BFA_MSGQ_CMDQ_NUM_ENTRY;
+	INIT_LIST_HEAD(&cmdq->pending_q);
+	cmdq->msgq = msgq;
+	bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
+}
+
+static void bfa_msgq_rspq_dbell(struct bfa_msgq_rspq *rspq);
+
+enum rspq_event {
+	RSPQ_E_START			= 1,
+	RSPQ_E_STOP			= 2,
+	RSPQ_E_FAIL			= 3,
+	RSPQ_E_RESP			= 4,
+	RSPQ_E_INIT_RESP		= 5,
+	RSPQ_E_DB_READY			= 6,
+};
+
+bfa_fsm_state_decl(rspq, stopped, struct bfa_msgq_rspq, enum rspq_event);
+bfa_fsm_state_decl(rspq, init_wait, struct bfa_msgq_rspq,
+			enum rspq_event);
+bfa_fsm_state_decl(rspq, ready, struct bfa_msgq_rspq, enum rspq_event);
+bfa_fsm_state_decl(rspq, dbell_wait, struct bfa_msgq_rspq,
+			enum rspq_event);
+
+static void
+rspq_sm_stopped_entry(struct bfa_msgq_rspq *rspq)
+{
+	rspq->producer_index = 0;
+	rspq->consumer_index = 0;
+	rspq->flags = 0;
+}
+
+static void
+rspq_sm_stopped(struct bfa_msgq_rspq *rspq, enum rspq_event event)
+{
+	switch (event) {
+	case RSPQ_E_START:
+		bfa_fsm_set_state(rspq, rspq_sm_init_wait);
+		break;
+
+	case RSPQ_E_STOP:
+	case RSPQ_E_FAIL:
+		/* No-op */
+		break;
+
+	default:
+		bfa_sm_fault(event);
+	}
+}
+
+static void
+rspq_sm_init_wait_entry(struct bfa_msgq_rspq *rspq)
+{
+	bfa_wc_down(&rspq->msgq->init_wc);
+}
+
+static void
+rspq_sm_init_wait(struct bfa_msgq_rspq *rspq, enum rspq_event event)
+{
+	switch (event) {
+	case RSPQ_E_FAIL:
+	case RSPQ_E_STOP:
+		bfa_fsm_set_state(rspq, rspq_sm_stopped);
+		break;
+
+	case RSPQ_E_INIT_RESP:
+		bfa_fsm_set_state(rspq, rspq_sm_ready);
+		break;
+
+	default:
+		bfa_sm_fault(event);
+	}
+}
+
+static void
+rspq_sm_ready_entry(struct bfa_msgq_rspq *rspq)
+{
+}
+
+static void
+rspq_sm_ready(struct bfa_msgq_rspq *rspq, enum rspq_event event)
+{
+	switch (event) {
+	case RSPQ_E_STOP:
+	case RSPQ_E_FAIL:
+		bfa_fsm_set_state(rspq, rspq_sm_stopped);
+		break;
+
+	case RSPQ_E_RESP:
+		bfa_fsm_set_state(rspq, rspq_sm_dbell_wait);
+		break;
+
+	default:
+		bfa_sm_fault(event);
+	}
+}
+
+static void
+rspq_sm_dbell_wait_entry(struct bfa_msgq_rspq *rspq)
+{
+	if (!bfa_nw_ioc_is_disabled(rspq->msgq->ioc))
+		bfa_msgq_rspq_dbell(rspq);
+}
+
+static void
+rspq_sm_dbell_wait(struct bfa_msgq_rspq *rspq, enum rspq_event event)
+{
+	switch (event) {
+	case RSPQ_E_STOP:
+	case RSPQ_E_FAIL:
+		bfa_fsm_set_state(rspq, rspq_sm_stopped);
+		break;
+
+	case RSPQ_E_RESP:
+		rspq->flags |= BFA_MSGQ_RSPQ_F_DB_UPDATE;
+		break;
+
+	case RSPQ_E_DB_READY:
+		if (rspq->flags & BFA_MSGQ_RSPQ_F_DB_UPDATE) {
+			rspq->flags &= ~BFA_MSGQ_RSPQ_F_DB_UPDATE;
+			bfa_fsm_set_state(rspq, rspq_sm_dbell_wait);
+		} else
+			bfa_fsm_set_state(rspq, rspq_sm_ready);
+		break;
+
+	default:
+		bfa_sm_fault(event);
+	}
+}
+
+static void
+bfa_msgq_rspq_dbell_ready(void *arg)
+{
+	struct bfa_msgq_rspq *rspq = (struct bfa_msgq_rspq *)arg;
+	bfa_fsm_send_event(rspq, RSPQ_E_DB_READY);
+}
+
+static void
+bfa_msgq_rspq_dbell(struct bfa_msgq_rspq *rspq)
+{
+	struct bfi_msgq_h2i_db *dbell =
+		(struct bfi_msgq_h2i_db *)(&rspq->dbell_mb.msg[0]);
+
+	memset(dbell, 0, sizeof(struct bfi_msgq_h2i_db));
+	bfi_h2i_set(dbell->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_DOORBELL_CI, 0);
+	dbell->mh.mtag.i2htok = 0;
+	dbell->idx.rspq_ci = htons(rspq->consumer_index);
+
+	if (!bfa_nw_ioc_mbox_queue(rspq->msgq->ioc, &rspq->dbell_mb,
+				bfa_msgq_rspq_dbell_ready, rspq)) {
+		bfa_msgq_rspq_dbell_ready(rspq);
+	}
+}
+
+static void
+bfa_msgq_rspq_pi_update(struct bfa_msgq_rspq *rspq, struct bfi_mbmsg *mb)
+{
+	struct bfi_msgq_i2h_db *dbell = (struct bfi_msgq_i2h_db *)mb;
+	struct bfi_msgq_mhdr *msghdr;
+	int num_entries;
+	int mc;
+	u8 *rspq_qe;
+
+	rspq->producer_index = ntohs(dbell->idx.rspq_pi);
+
+	while (rspq->consumer_index != rspq->producer_index) {
+		rspq_qe = (u8 *)rspq->addr.kva;
+		rspq_qe += (rspq->consumer_index * BFI_MSGQ_RSP_ENTRY_SIZE);
+		msghdr = (struct bfi_msgq_mhdr *)rspq_qe;
+
+		mc = msghdr->msg_class;
+		num_entries = ntohs(msghdr->num_entries);
+
+		if ((mc > BFI_MC_MAX) || (rspq->rsphdlr[mc].cbfn == NULL))
+			break;
+
+		(rspq->rsphdlr[mc].cbfn)(rspq->rsphdlr[mc].cbarg, msghdr);
+
+		BFA_MSGQ_INDX_ADD(rspq->consumer_index, num_entries,
+				rspq->depth);
+	}
+
+	bfa_fsm_send_event(rspq, RSPQ_E_RESP);
+}
+
+static void
+bfa_msgq_rspq_attach(struct bfa_msgq_rspq *rspq, struct bfa_msgq *msgq)
+{
+	rspq->depth = BFA_MSGQ_RSPQ_NUM_ENTRY;
+	rspq->msgq = msgq;
+	bfa_fsm_set_state(rspq, rspq_sm_stopped);
+}
+
+static void
+bfa_msgq_init_rsp(struct bfa_msgq *msgq,
+		 struct bfi_mbmsg *mb)
+{
+	bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_INIT_RESP);
+	bfa_fsm_send_event(&msgq->rspq, RSPQ_E_INIT_RESP);
+}
+
+static void
+bfa_msgq_init(void *arg)
+{
+	struct bfa_msgq *msgq = (struct bfa_msgq *)arg;
+	struct bfi_msgq_cfg_req *msgq_cfg =
+		(struct bfi_msgq_cfg_req *)&msgq->init_mb.msg[0];
+
+	memset(msgq_cfg, 0, sizeof(struct bfi_msgq_cfg_req));
+	bfi_h2i_set(msgq_cfg->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_INIT_REQ, 0);
+	msgq_cfg->mh.mtag.i2htok = 0;
+
+	bfa_dma_be_addr_set(msgq_cfg->cmdq.addr, msgq->cmdq.addr.pa);
+	msgq_cfg->cmdq.q_depth = htons(msgq->cmdq.depth);
+	bfa_dma_be_addr_set(msgq_cfg->rspq.addr, msgq->rspq.addr.pa);
+	msgq_cfg->rspq.q_depth = htons(msgq->rspq.depth);
+
+	bfa_nw_ioc_mbox_queue(msgq->ioc, &msgq->init_mb, NULL, NULL);
+}
+
+static void
+bfa_msgq_isr(void *cbarg, struct bfi_mbmsg *msg)
+{
+	struct bfa_msgq *msgq = (struct bfa_msgq *)cbarg;
+
+	switch (msg->mh.msg_id) {
+	case BFI_MSGQ_I2H_INIT_RSP:
+		bfa_msgq_init_rsp(msgq, msg);
+		break;
+
+	case BFI_MSGQ_I2H_DOORBELL_PI:
+		bfa_msgq_rspq_pi_update(&msgq->rspq, msg);
+		break;
+
+	case BFI_MSGQ_I2H_DOORBELL_CI:
+		bfa_msgq_cmdq_ci_update(&msgq->cmdq, msg);
+		break;
+
+	case BFI_MSGQ_I2H_CMDQ_COPY_REQ:
+		bfa_msgq_cmdq_copy_req(&msgq->cmdq, msg);
+		break;
+
+	default:
+		BUG_ON(1);
+	}
+}
+
+static void
+bfa_msgq_notify(void *cbarg, enum bfa_ioc_event event)
+{
+	struct bfa_msgq *msgq = (struct bfa_msgq *)cbarg;
+
+	switch (event) {
+	case BFA_IOC_E_ENABLED:
+		bfa_wc_init(&msgq->init_wc, bfa_msgq_init, msgq);
+		bfa_wc_up(&msgq->init_wc);
+		bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_START);
+		bfa_wc_up(&msgq->init_wc);
+		bfa_fsm_send_event(&msgq->rspq, RSPQ_E_START);
+		bfa_wc_wait(&msgq->init_wc);
+		break;
+
+	case BFA_IOC_E_DISABLED:
+		bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_STOP);
+		bfa_fsm_send_event(&msgq->rspq, RSPQ_E_STOP);
+		break;
+
+	case BFA_IOC_E_FAILED:
+		bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_FAIL);
+		bfa_fsm_send_event(&msgq->rspq, RSPQ_E_FAIL);
+		break;
+
+	default:
+		break;
+	}
+}
+
+u32
+bfa_msgq_meminfo(void)
+{
+	return roundup(BFA_MSGQ_CMDQ_SIZE, BFA_DMA_ALIGN_SZ) +
+		roundup(BFA_MSGQ_RSPQ_SIZE, BFA_DMA_ALIGN_SZ);
+}
+
+void
+bfa_msgq_memclaim(struct bfa_msgq *msgq, u8 *kva, u64 pa)
+{
+	msgq->cmdq.addr.kva = kva;
+	msgq->cmdq.addr.pa  = pa;
+
+	kva += roundup(BFA_MSGQ_CMDQ_SIZE, BFA_DMA_ALIGN_SZ);
+	pa += roundup(BFA_MSGQ_CMDQ_SIZE, BFA_DMA_ALIGN_SZ);
+
+	msgq->rspq.addr.kva = kva;
+	msgq->rspq.addr.pa = pa;
+}
+
+void
+bfa_msgq_attach(struct bfa_msgq *msgq, struct bfa_ioc *ioc)
+{
+	msgq->ioc    = ioc;
+
+	bfa_msgq_cmdq_attach(&msgq->cmdq, msgq);
+	bfa_msgq_rspq_attach(&msgq->rspq, msgq);
+
+	bfa_nw_ioc_mbox_regisr(msgq->ioc, BFI_MC_MSGQ, bfa_msgq_isr, msgq);
+	bfa_q_qe_init(&msgq->ioc_notify);
+	bfa_ioc_notify_init(&msgq->ioc_notify, bfa_msgq_notify, msgq);
+	bfa_nw_ioc_notify_register(msgq->ioc, &msgq->ioc_notify);
+}
+
+void
+bfa_msgq_regisr(struct bfa_msgq *msgq, enum bfi_mclass mc,
+		bfa_msgq_mcfunc_t cbfn, void *cbarg)
+{
+	msgq->rspq.rsphdlr[mc].cbfn	= cbfn;
+	msgq->rspq.rsphdlr[mc].cbarg	= cbarg;
+}
+
+void
+bfa_msgq_cmd_post(struct bfa_msgq *msgq,  struct bfa_msgq_cmd_entry *cmd)
+{
+	if (ntohs(cmd->msg_hdr->num_entries) <=
+		BFA_MSGQ_FREE_CNT(&msgq->cmdq)) {
+		__cmd_copy(&msgq->cmdq, cmd);
+		call_cmdq_ent_cbfn(cmd, BFA_STATUS_OK);
+		bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_POST);
+	} else {
+		list_add_tail(&cmd->qe, &msgq->cmdq.pending_q);
+	}
+}
+
+void
+bfa_msgq_rsp_copy(struct bfa_msgq *msgq, u8 *buf, size_t buf_len)
+{
+	struct bfa_msgq_rspq *rspq = &msgq->rspq;
+	size_t len = buf_len;
+	size_t to_copy;
+	int ci;
+	u8 *src, *dst;
+
+	ci = rspq->consumer_index;
+	src = (u8 *)rspq->addr.kva;
+	src += (ci * BFI_MSGQ_RSP_ENTRY_SIZE);
+	dst = buf;
+
+	while (len) {
+		to_copy = (len < BFI_MSGQ_RSP_ENTRY_SIZE) ?
+				len : BFI_MSGQ_RSP_ENTRY_SIZE;
+		memcpy(dst, src, to_copy);
+		len -= to_copy;
+		dst += BFI_MSGQ_RSP_ENTRY_SIZE;
+		BFA_MSGQ_INDX_ADD(ci, 1, rspq->depth);
+		src = (u8 *)rspq->addr.kva;
+		src += (ci * BFI_MSGQ_RSP_ENTRY_SIZE);
+	}
+}
diff --git a/drivers/net/ethernet/brocade/bna/bfa_msgq.h b/drivers/net/ethernet/brocade/bna/bfa_msgq.h
new file mode 100644
index 0000000000000000000000000000000000000000..a6a565a366dca5401616e38ffc2702ccb6500a5d
--- /dev/null
+++ b/drivers/net/ethernet/brocade/bna/bfa_msgq.h
@@ -0,0 +1,130 @@
+/*
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2005-2011 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ */
+
+#ifndef __BFA_MSGQ_H__
+#define __BFA_MSGQ_H__
+
+#include "bfa_defs.h"
+#include "bfi.h"
+#include "bfa_ioc.h"
+#include "bfa_cs.h"
+
+#define BFA_MSGQ_FREE_CNT(_q)						\
+	(((_q)->consumer_index - (_q)->producer_index - 1) & ((_q)->depth - 1))
+
+#define BFA_MSGQ_INDX_ADD(_q_indx, _qe_num, _q_depth)			\
+	((_q_indx) = (((_q_indx) + (_qe_num)) & ((_q_depth) - 1)))
+
+#define BFA_MSGQ_CMDQ_NUM_ENTRY		128
+#define BFA_MSGQ_CMDQ_SIZE						\
+	(BFI_MSGQ_CMD_ENTRY_SIZE * BFA_MSGQ_CMDQ_NUM_ENTRY)
+
+#define BFA_MSGQ_RSPQ_NUM_ENTRY		128
+#define BFA_MSGQ_RSPQ_SIZE						\
+	(BFI_MSGQ_RSP_ENTRY_SIZE * BFA_MSGQ_RSPQ_NUM_ENTRY)
+
+#define bfa_msgq_cmd_set(_cmd, _cbfn, _cbarg, _msg_size, _msg_hdr)	\
+do {									\
+	(_cmd)->cbfn = (_cbfn);						\
+	(_cmd)->cbarg = (_cbarg);					\
+	(_cmd)->msg_size = (_msg_size);					\
+	(_cmd)->msg_hdr = (_msg_hdr);					\
+} while (0)
+
+struct bfa_msgq;
+
+typedef void (*bfa_msgq_cmdcbfn_t)(void *cbarg, enum bfa_status status);
+
+struct bfa_msgq_cmd_entry {
+	struct list_head				qe;
+	bfa_msgq_cmdcbfn_t		cbfn;
+	void				*cbarg;
+	size_t				msg_size;
+	struct bfi_msgq_mhdr *msg_hdr;
+};
+
+enum bfa_msgq_cmdq_flags {
+	BFA_MSGQ_CMDQ_F_DB_UPDATE	= 1,
+};
+
+struct bfa_msgq_cmdq {
+	bfa_fsm_t			fsm;
+	enum bfa_msgq_cmdq_flags flags;
+
+	u16			producer_index;
+	u16			consumer_index;
+	u16			depth; /* FW Q depth is 16 bits */
+	struct bfa_dma addr;
+	struct bfa_mbox_cmd dbell_mb;
+
+	u16			token;
+	int				offset;
+	int				bytes_to_copy;
+	struct bfa_mbox_cmd copy_mb;
+
+	struct list_head		pending_q; /* pending command queue */
+
+	struct bfa_msgq *msgq;
+};
+
+enum bfa_msgq_rspq_flags {
+	BFA_MSGQ_RSPQ_F_DB_UPDATE	= 1,
+};
+
+typedef void (*bfa_msgq_mcfunc_t)(void *cbarg, struct bfi_msgq_mhdr *mhdr);
+
+struct bfa_msgq_rspq {
+	bfa_fsm_t			fsm;
+	enum bfa_msgq_rspq_flags flags;
+
+	u16			producer_index;
+	u16			consumer_index;
+	u16			depth; /* FW Q depth is 16 bits */
+	struct bfa_dma addr;
+	struct bfa_mbox_cmd dbell_mb;
+
+	int				nmclass;
+	struct {
+		bfa_msgq_mcfunc_t	cbfn;
+		void			*cbarg;
+	} rsphdlr[BFI_MC_MAX];
+
+	struct bfa_msgq *msgq;
+};
+
+struct bfa_msgq {
+	struct bfa_msgq_cmdq cmdq;
+	struct bfa_msgq_rspq rspq;
+
+	struct bfa_wc			init_wc;
+	struct bfa_mbox_cmd init_mb;
+
+	struct bfa_ioc_notify ioc_notify;
+	struct bfa_ioc *ioc;
+};
+
+u32 bfa_msgq_meminfo(void);
+void bfa_msgq_memclaim(struct bfa_msgq *msgq, u8 *kva, u64 pa);
+void bfa_msgq_attach(struct bfa_msgq *msgq, struct bfa_ioc *ioc);
+void bfa_msgq_regisr(struct bfa_msgq *msgq, enum bfi_mclass mc,
+		     bfa_msgq_mcfunc_t cbfn, void *cbarg);
+void bfa_msgq_cmd_post(struct bfa_msgq *msgq,
+		       struct bfa_msgq_cmd_entry *cmd);
+void bfa_msgq_rsp_copy(struct bfa_msgq *msgq, u8 *buf, size_t buf_len);
+
+#endif
diff --git a/drivers/net/ethernet/brocade/bna/bfi.h b/drivers/net/ethernet/brocade/bna/bfi.h
index 088211c2724fe10b800df4f686af3c561d24a8d1..6a53183e411e4406c9e02e923a1b88e4c44c98a7 100644
--- a/drivers/net/ethernet/brocade/bna/bfi.h
+++ b/drivers/net/ethernet/brocade/bna/bfi.h
@@ -192,6 +192,8 @@ enum bfi_mclass {
 
 #define BFI_BOOT_LOADER_OS		0
 
+#define BFI_FWBOOT_ENV_OS		0
+
 #define BFI_BOOT_MEMTEST_RES_ADDR   0x900
 #define BFI_BOOT_MEMTEST_RES_SIG    0xA0A1A2A3
 
@@ -395,6 +397,105 @@ union bfi_ioc_i2h_msg_u {
 	u32			mboxmsg[BFI_IOC_MSGSZ];
 };
 
+/**
+ *----------------------------------------------------------------------
+ *				MSGQ
+ *----------------------------------------------------------------------
+ */
+
+enum bfi_msgq_h2i_msgs {
+	BFI_MSGQ_H2I_INIT_REQ	   = 1,
+	BFI_MSGQ_H2I_DOORBELL_PI	= 2,
+	BFI_MSGQ_H2I_DOORBELL_CI	= 3,
+	BFI_MSGQ_H2I_CMDQ_COPY_RSP      = 4,
+};
+
+enum bfi_msgq_i2h_msgs {
+	BFI_MSGQ_I2H_INIT_RSP	   = BFA_I2HM(BFI_MSGQ_H2I_INIT_REQ),
+	BFI_MSGQ_I2H_DOORBELL_PI	= BFA_I2HM(BFI_MSGQ_H2I_DOORBELL_PI),
+	BFI_MSGQ_I2H_DOORBELL_CI	= BFA_I2HM(BFI_MSGQ_H2I_DOORBELL_CI),
+	BFI_MSGQ_I2H_CMDQ_COPY_REQ      = BFA_I2HM(BFI_MSGQ_H2I_CMDQ_COPY_RSP),
+};
+
+/* Messages(commands/responsed/AENS will have the following header */
+struct bfi_msgq_mhdr {
+	u8	msg_class;
+	u8	msg_id;
+	u16	msg_token;
+	u16	num_entries;
+	u8	enet_id;
+	u8	rsvd[1];
+};
+
+#define bfi_msgq_mhdr_set(_mh, _mc, _mid, _tok, _enet_id) do {	\
+	(_mh).msg_class	 = (_mc);	\
+	(_mh).msg_id	    = (_mid);       \
+	(_mh).msg_token	 = (_tok);       \
+	(_mh).enet_id	   = (_enet_id);   \
+} while (0)
+
+/*
+ * Mailbox  for messaging interface
+ */
+#define BFI_MSGQ_CMD_ENTRY_SIZE	 (64)    /* TBD */
+#define BFI_MSGQ_RSP_ENTRY_SIZE	 (64)    /* TBD */
+
+#define bfi_msgq_num_cmd_entries(_size)				 \
+	(((_size) + BFI_MSGQ_CMD_ENTRY_SIZE - 1) / BFI_MSGQ_CMD_ENTRY_SIZE)
+
+struct bfi_msgq {
+	union bfi_addr_u addr;
+	u16 q_depth;     /* Total num of entries in the queue */
+	u8 rsvd[2];
+};
+
+/* BFI_ENET_MSGQ_CFG_REQ TBD init or cfg? */
+struct bfi_msgq_cfg_req {
+	struct bfi_mhdr mh;
+	struct bfi_msgq cmdq;
+	struct bfi_msgq rspq;
+};
+
+/* BFI_ENET_MSGQ_CFG_RSP */
+struct bfi_msgq_cfg_rsp {
+	struct bfi_mhdr mh;
+	u8 cmd_status;
+	u8 rsvd[3];
+};
+
+/* BFI_MSGQ_H2I_DOORBELL */
+struct bfi_msgq_h2i_db {
+	struct bfi_mhdr mh;
+	union {
+		u16 cmdq_pi;
+		u16 rspq_ci;
+	} idx;
+};
+
+/* BFI_MSGQ_I2H_DOORBELL */
+struct bfi_msgq_i2h_db {
+	struct bfi_mhdr mh;
+	union {
+		u16 rspq_pi;
+		u16 cmdq_ci;
+	} idx;
+};
+
+#define BFI_CMD_COPY_SZ 28
+
+/* BFI_MSGQ_H2I_CMD_COPY_RSP */
+struct bfi_msgq_h2i_cmdq_copy_rsp {
+	struct bfi_mhdr mh;
+	u8	      data[BFI_CMD_COPY_SZ];
+};
+
+/* BFI_MSGQ_I2H_CMD_COPY_REQ */
+struct bfi_msgq_i2h_cmdq_copy_req {
+	struct bfi_mhdr mh;
+	u16     offset;
+	u16     len;
+};
+
 #pragma pack()
 
 #endif /* __BFI_H__ */
diff --git a/drivers/net/ethernet/brocade/bna/bna_ctrl.c b/drivers/net/ethernet/brocade/bna/bna_ctrl.c
index cb2594c564dc16936bf3650f5297ec8bd278035b..7d955177827427b65239f4c3045764c08059bec4 100644
--- a/drivers/net/ethernet/brocade/bna/bna_ctrl.c
+++ b/drivers/net/ethernet/brocade/bna/bna_ctrl.c
@@ -183,7 +183,8 @@ bna_ll_isr(void *llarg, struct bfi_mbmsg *msg)
 			if (to_post) {
 				mb_qe = bfa_q_first(&bna->mbox_mod.posted_q);
 				bfa_nw_ioc_mbox_queue(&bna->device.ioc,
-							&mb_qe->cmd);
+							&mb_qe->cmd, NULL,
+							NULL);
 			}
 		} else {
 			snprintf(message, BNA_MESSAGE_SIZE,
@@ -234,7 +235,8 @@ bna_mbox_send(struct bna *bna, struct bna_mbox_qe *mbox_qe)
 	bna->mbox_mod.msg_pending++;
 	if (bna->mbox_mod.state == BNA_MBOX_FREE) {
 		list_add_tail(&mbox_qe->qe, &bna->mbox_mod.posted_q);
-		bfa_nw_ioc_mbox_queue(&bna->device.ioc, &mbox_qe->cmd);
+		bfa_nw_ioc_mbox_queue(&bna->device.ioc, &mbox_qe->cmd,
+					NULL, NULL);
 		bna->mbox_mod.state = BNA_MBOX_POSTED;
 	} else {
 		list_add_tail(&mbox_qe->qe, &bna->mbox_mod.posted_q);