Commit 9a069e19 authored by Giridhar Malavali's avatar Giridhar Malavali Committed by James Bottomley
Browse files

[SCSI] qla2xxx: Add BSG support for FC ELS/CT passthrough and vendor commands.



[jejb: fixed printk casting issues]
Signed-off-by: default avatarSarang Radke <sarang.radke@qlogic.com>
Signed-off-by: default avatarGiridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 90a86fc0
This diff is collapsed.
......@@ -31,6 +31,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_transport_fc.h>
#include <scsi/scsi_bsg_fc.h>
#define QLA2XXX_DRIVER_NAME "qla2xxx"
......@@ -228,6 +229,27 @@ struct srb_logio {
uint16_t flags;
};
struct srb_bsg_ctx {
#define SRB_ELS_CMD_RPT 3
#define SRB_ELS_CMD_HST 4
#define SRB_CT_CMD 5
uint16_t type;
};
struct srb_bsg {
struct srb_bsg_ctx ctx;
struct fc_bsg_job *bsg_job;
};
struct msg_echo_lb {
dma_addr_t send_dma;
dma_addr_t rcv_dma;
uint16_t req_sg_cnt;
uint16_t rsp_sg_cnt;
uint16_t options;
uint32_t transfer_size;
};
/*
* ISP I/O Register Set structure definitions.
*/
......@@ -522,6 +544,8 @@ typedef struct {
#define MBA_DISCARD_RND_FRAME 0x8048 /* discard RND frame due to error. */
#define MBA_REJECTED_FCP_CMD 0x8049 /* rejected FCP_CMD. */
/* ISP mailbox loopback echo diagnostic error code */
#define MBS_LB_RESET 0x17
/*
* Firmware options 1, 2, 3.
*/
......@@ -2230,6 +2254,13 @@ struct req_que {
int max_q_depth;
};
/* Place holder for FW buffer parameters */
struct qlfc_fw {
void *fw_buf;
dma_addr_t fw_dma;
uint32_t len;
};
/*
* Qlogic host adapter specific data structure.
*/
......@@ -2594,6 +2625,7 @@ struct qla_hw_data {
struct qla_statistics qla_stats;
struct isp_operations *isp_ops;
struct workqueue_struct *wq;
struct qlfc_fw fw_buf;
};
/*
......@@ -2766,4 +2798,127 @@ typedef struct scsi_qla_host {
#define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr)
/*
* BSG Vendor specific commands
*/
#define QL_VND_LOOPBACK 0x01
#define QLA84_RESET 0x02
#define QLA84_UPDATE_FW 0x03
#define QLA84_MGMT_CMD 0x04
/* BSG definations for interpreting CommandSent field */
#define INT_DEF_LB_LOOPBACK_CMD 0
#define INT_DEF_LB_ECHO_CMD 1
/* BSG Vendor specific definations */
typedef struct _A84_RESET {
uint16_t Flags;
uint16_t Reserved;
#define A84_RESET_FLAG_ENABLE_DIAG_FW 1
} __attribute__((packed)) A84_RESET, *PA84_RESET;
#define A84_ISSUE_WRITE_TYPE_CMD 0
#define A84_ISSUE_READ_TYPE_CMD 1
#define A84_CLEANUP_CMD 2
#define A84_ISSUE_RESET_OP_FW 3
#define A84_ISSUE_RESET_DIAG_FW 4
#define A84_ISSUE_UPDATE_OPFW_CMD 5
#define A84_ISSUE_UPDATE_DIAGFW_CMD 6
struct qla84_mgmt_param {
union {
struct {
uint32_t start_addr;
} mem; /* for QLA84_MGMT_READ/WRITE_MEM */
struct {
uint32_t id;
#define QLA84_MGMT_CONFIG_ID_UIF 1
#define QLA84_MGMT_CONFIG_ID_FCOE_COS 2
#define QLA84_MGMT_CONFIG_ID_PAUSE 3
#define QLA84_MGMT_CONFIG_ID_TIMEOUTS 4
uint32_t param0;
uint32_t param1;
} config; /* for QLA84_MGMT_CHNG_CONFIG */
struct {
uint32_t type;
#define QLA84_MGMT_INFO_CONFIG_LOG_DATA 1 /* Get Config Log Data */
#define QLA84_MGMT_INFO_LOG_DATA 2 /* Get Log Data */
#define QLA84_MGMT_INFO_PORT_STAT 3 /* Get Port Statistics */
#define QLA84_MGMT_INFO_LIF_STAT 4 /* Get LIF Statistics */
#define QLA84_MGMT_INFO_ASIC_STAT 5 /* Get ASIC Statistics */
#define QLA84_MGMT_INFO_CONFIG_PARAMS 6 /* Get Config Parameters */
#define QLA84_MGMT_INFO_PANIC_LOG 7 /* Get Panic Log */
uint32_t context;
/*
* context definitions for QLA84_MGMT_INFO_CONFIG_LOG_DATA
*/
#define IC_LOG_DATA_LOG_ID_DEBUG_LOG 0
#define IC_LOG_DATA_LOG_ID_LEARN_LOG 1
#define IC_LOG_DATA_LOG_ID_FC_ACL_INGRESS_LOG 2
#define IC_LOG_DATA_LOG_ID_FC_ACL_EGRESS_LOG 3
#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_INGRESS_LOG 4
#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_EGRESS_LOG 5
#define IC_LOG_DATA_LOG_ID_MESSAGE_TRANSMIT_LOG 6
#define IC_LOG_DATA_LOG_ID_MESSAGE_RECEIVE_LOG 7
#define IC_LOG_DATA_LOG_ID_LINK_EVENT_LOG 8
#define IC_LOG_DATA_LOG_ID_DCX_LOG 9
/*
* context definitions for QLA84_MGMT_INFO_PORT_STAT
*/
#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT0 0
#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT1 1
#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT0 2
#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT1 3
#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT0 4
#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT1 5
/*
* context definitions for QLA84_MGMT_INFO_LIF_STAT
*/
#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT0 0
#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT1 1
#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT0 2
#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT1 3
#define IC_LIF_STATISTICS_LIF_NUMBER_CPU 6
} info; /* for QLA84_MGMT_GET_INFO */
} u;
};
struct qla84_msg_mgmt {
uint16_t cmd;
#define QLA84_MGMT_READ_MEM 0x00
#define QLA84_MGMT_WRITE_MEM 0x01
#define QLA84_MGMT_CHNG_CONFIG 0x02
#define QLA84_MGMT_GET_INFO 0x03
uint16_t rsrvd;
struct qla84_mgmt_param mgmtp;/* parameters for cmd */
uint32_t len; /* bytes in payload following this struct */
uint8_t payload[0]; /* payload for cmd */
};
struct msg_update_fw {
/*
* diag_fw = 0 operational fw
* otherwise diagnostic fw
* offset, len, fw_len are present to overcome the current limitation
* of 128Kb xfer size. The fw is sent in smaller chunks. Each chunk
* specifies the byte "offset" where it fits in the fw buffer. The
* number of bytes in each chunk is specified in "len". "fw_len"
* is the total size of fw. The first chunk should start at offset = 0.
* When offset+len == fw_len, the fw is written to the HBA.
*/
uint32_t diag_fw;
uint32_t offset;/* start offset */
uint32_t len; /* num bytes in cur xfer */
uint32_t fw_len; /* size of fw in bytes */
uint8_t fw_bytes[0];
};
#endif
......@@ -627,6 +627,39 @@ struct els_entry_24xx {
uint32_t rx_len; /* Data segment 1 length. */
};
struct els_sts_entry_24xx {
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System Defined. */
uint8_t entry_status; /* Entry Status. */
uint32_t handle; /* System handle. */
uint16_t comp_status;
uint16_t nport_handle; /* N_PORT handle. */
uint16_t reserved_1;
uint8_t vp_index;
uint8_t sof_type;
uint32_t rx_xchg_address; /* Receive exchange address. */
uint16_t reserved_2;
uint8_t opcode;
uint8_t reserved_3;
uint8_t port_id[3];
uint8_t reserved_4;
uint16_t reserved_5;
uint16_t control_flags; /* Control flags. */
uint32_t total_byte_count;
uint32_t error_subcode_1;
uint32_t error_subcode_2;
};
/*
* ISP queue - Mailbox Command entry structure definition.
*/
......
......@@ -60,6 +60,8 @@ extern int qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *,
extern int qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern fc_port_t *
qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t );
/*
* Global Data in qla_os.c source file.
*/
......@@ -154,6 +156,7 @@ int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
int __qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
uint16_t, uint16_t, uint8_t);
extern int qla2x00_start_sp(srb_t *);
extern void qla2x00_ctx_sp_free(srb_t *);
/*
* Global Function Prototypes in qla_mbx.c source file.
......@@ -426,6 +429,8 @@ extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
extern void qla2x00_init_host_attr(scsi_qla_host_t *);
extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
extern int qla2x00_loopback_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16_t *);
extern int qla2x00_echo_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16_t *);
/*
* Global Function Prototypes in qla_dfs.c source file.
......
......@@ -62,7 +62,7 @@ qla2x00_ctx_sp_timeout(unsigned long __data)
ctx->free(sp);
}
static void
void
qla2x00_ctx_sp_free(srb_t *sp)
{
struct srb_ctx *ctx = sp->ctx;
......@@ -338,6 +338,16 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
rval = qla2x00_init_rings(vha);
ha->flags.chip_reset_done = 1;
if (rval == QLA_SUCCESS && IS_QLA84XX(ha)) {
/* Issue verify 84xx FW IOCB to complete 84xx initialization */
rval = qla84xx_init_chip(vha);
if (rval != QLA_SUCCESS) {
qla_printk(KERN_ERR, ha,
"Unable to initialize ISP84XX.\n");
qla84xx_put_chip(vha);
}
}
return (rval);
}
......@@ -2216,7 +2226,7 @@ qla2x00_rport_del(void *data)
*
* Returns a pointer to the allocated fcport, or NULL, if none available.
*/
static fc_port_t *
fc_port_t *
qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
{
fc_port_t *fcport;
......
......@@ -1025,6 +1025,119 @@ qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx)
/* Implicit: mbx->mbx10 = 0. */
}
static void
qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
{
struct fc_bsg_job *bsg_job = ((struct srb_bsg*)sp->ctx)->bsg_job;
els_iocb->entry_type = ELS_IOCB_TYPE;
els_iocb->entry_count = 1;
els_iocb->sys_define = 0;
els_iocb->entry_status = 0;
els_iocb->handle = sp->handle;
els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
els_iocb->tx_dsd_count = __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt);
els_iocb->vp_index = sp->fcport->vp_idx;
els_iocb->sof_type = EST_SOFI3;
els_iocb->rx_dsd_count = __constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt);
els_iocb->opcode =(((struct srb_bsg*)sp->ctx)->ctx.type == SRB_ELS_CMD_RPT) ?
bsg_job->request->rqst_data.r_els.els_code : bsg_job->request->rqst_data.h_els.command_code;
els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
els_iocb->port_id[1] = sp->fcport->d_id.b.area;
els_iocb->port_id[2] = sp->fcport->d_id.b.domain;
els_iocb->control_flags = 0;
els_iocb->rx_byte_count =
cpu_to_le32(bsg_job->reply_payload.payload_len);
els_iocb->tx_byte_count =
cpu_to_le32(bsg_job->request_payload.payload_len);
els_iocb->tx_address[0] = cpu_to_le32(LSD(sg_dma_address
(bsg_job->request_payload.sg_list)));
els_iocb->tx_address[1] = cpu_to_le32(MSD(sg_dma_address
(bsg_job->request_payload.sg_list)));
els_iocb->tx_len = cpu_to_le32(sg_dma_len
(bsg_job->request_payload.sg_list));
els_iocb->rx_address[0] = cpu_to_le32(LSD(sg_dma_address
(bsg_job->reply_payload.sg_list)));
els_iocb->rx_address[1] = cpu_to_le32(MSD(sg_dma_address
(bsg_job->reply_payload.sg_list)));
els_iocb->rx_len = cpu_to_le32(sg_dma_len
(bsg_job->reply_payload.sg_list));
}
static void
qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
{
uint16_t avail_dsds;
uint32_t *cur_dsd;
struct scatterlist *sg;
int index;
uint16_t tot_dsds;
scsi_qla_host_t *vha = sp->fcport->vha;
struct fc_bsg_job *bsg_job = ((struct srb_bsg*)sp->ctx)->bsg_job;
int loop_iterartion = 0;
int cont_iocb_prsnt = 0;
int entry_count = 1;
ct_iocb->entry_type = CT_IOCB_TYPE;
ct_iocb->entry_status = 0;
ct_iocb->sys_define = 0;
ct_iocb->handle = sp->handle;
ct_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
ct_iocb->vp_index = sp->fcport->vp_idx;
ct_iocb->comp_status = __constant_cpu_to_le16(0);
ct_iocb->cmd_dsd_count =
__constant_cpu_to_le16(bsg_job->request_payload.sg_cnt);
ct_iocb->timeout = 0;
ct_iocb->rsp_dsd_count =
__constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt);
ct_iocb->rsp_byte_count =
cpu_to_le32(bsg_job->reply_payload.payload_len);
ct_iocb->cmd_byte_count =
cpu_to_le32(bsg_job->request_payload.payload_len);
ct_iocb->dseg_0_address[0] = cpu_to_le32(LSD(sg_dma_address
(bsg_job->request_payload.sg_list)));
ct_iocb->dseg_0_address[1] = cpu_to_le32(MSD(sg_dma_address
(bsg_job->request_payload.sg_list)));
ct_iocb->dseg_0_len = cpu_to_le32(sg_dma_len
(bsg_job->request_payload.sg_list));
avail_dsds = 1;
cur_dsd = (uint32_t *)ct_iocb->dseg_1_address;
index = 0;
tot_dsds = bsg_job->reply_payload.sg_cnt;
for_each_sg(bsg_job->reply_payload.sg_list, sg, tot_dsds, index) {
dma_addr_t sle_dma;
cont_a64_entry_t *cont_pkt;
/* Allocate additional continuation packets? */
if (avail_dsds == 0) {
/*
* Five DSDs are available in the Cont.
* Type 1 IOCB.
*/
cont_pkt = qla2x00_prep_cont_type1_iocb(vha);
cur_dsd = (uint32_t *) cont_pkt->dseg_0_address;
avail_dsds = 5;
cont_iocb_prsnt = 1;
entry_count++;
}
sle_dma = sg_dma_address(sg);
*cur_dsd++ = cpu_to_le32(LSD(sle_dma));
*cur_dsd++ = cpu_to_le32(MSD(sle_dma));
*cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
loop_iterartion++;
avail_dsds--;
}
ct_iocb->entry_count = entry_count;
}
int
qla2x00_start_sp(srb_t *sp)
{
......@@ -1052,6 +1165,13 @@ qla2x00_start_sp(srb_t *sp)
qla24xx_logout_iocb(sp, pkt):
qla2x00_logout_iocb(sp, pkt);
break;
case SRB_ELS_CMD_RPT:
case SRB_ELS_CMD_HST:
qla24xx_els_iocb(sp, pkt);
break;
case SRB_CT_CMD:
qla24xx_ct_iocb(sp, pkt);
break;
default:
break;
}
......
......@@ -8,6 +8,7 @@
#include <linux/delay.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_bsg_fc.h>
static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
static void qla2x00_process_completed_request(struct scsi_qla_host *,
......@@ -881,7 +882,9 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
index);
return NULL;
}
req->outstanding_cmds[index] = NULL;
done:
return sp;
}
......@@ -981,6 +984,100 @@ done_post_logio_done_work:
lio->ctx.free(sp);
}
static void
qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
struct sts_entry_24xx *pkt, int iocb_type)
{
const char func[] = "ELS_CT_IOCB";
const char *type;
struct qla_hw_data *ha = vha->hw;
srb_t *sp;
struct srb_bsg *sp_bsg;
struct fc_bsg_job *bsg_job;
uint16_t comp_status;
uint32_t fw_status[3];
uint8_t* fw_sts_ptr;
sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
if (!sp)
return;
sp_bsg = (struct srb_bsg*)sp->ctx;
bsg_job = sp_bsg->bsg_job;
type = NULL;
switch (sp_bsg->ctx.type) {
case SRB_ELS_CMD_RPT:
case SRB_ELS_CMD_HST:
type = "els";
break;
case SRB_CT_CMD:
type = "ct pass-through";
break;
default:
qla_printk(KERN_WARNING, ha,
"%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
sp_bsg->ctx.type);
return;
}
comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status);
fw_status[1] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1);
fw_status[2] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2);
/* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
* fc payload to the caller
*/
bsg_job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(fw_status);
if (comp_status != CS_COMPLETE) {
if (comp_status == CS_DATA_UNDERRUN) {
bsg_job->reply->result = DID_OK << 16;
bsg_job->reply->reply_payload_rcv_len =
le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count);
DEBUG2(qla_printk(KERN_WARNING, ha,
"scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x "
"error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n",
vha->host_no, sp->handle, type, comp_status, fw_status[1], fw_status[2],
le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count)));
fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
}
else {
DEBUG2(qla_printk(KERN_WARNING, ha,
"scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x "
"error subcode 1=0x%x error subcode 2=0x%x.\n",
vha->host_no, sp->handle, type, comp_status,
le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1),
le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2)));
bsg_job->reply->result = DID_ERROR << 16;
bsg_job->reply->reply_payload_rcv_len = 0;
fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
}
DEBUG2(qla2x00_dump_buffer((uint8_t *)pkt, sizeof(*pkt)));
}
else {
bsg_job->reply->result = DID_OK << 16;;
bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len;
bsg_job->reply_len = 0;
}
dma_unmap_sg(&ha->pdev->dev,
bsg_job->request_payload.sg_list,
bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
dma_unmap_sg(&ha->pdev->dev,
bsg_job->reply_payload.sg_list,
bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
if ((sp_bsg->ctx.type == SRB_ELS_CMD_HST) ||
(sp_bsg->ctx.type == SRB_CT_CMD))
kfree(sp->fcport);
kfree(sp->ctx);
mempool_free(sp, ha->srb_mempool);
bsg_job->job_done(bsg_job);
}
static void
qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
struct logio_entry_24xx *logio)
......@@ -1749,6 +1846,13 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
qla24xx_logio_entry(vha, rsp->req,
(struct logio_entry_24xx *)pkt);
break;
case CT_IOCB_TYPE:
qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
clear_bit(MBX_INTERRUPT, &vha->hw->mbx_cmd_flags);
break;
case ELS_IOCB_TYPE:
qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
break;
default:
/* Type Not Supported. */
DEBUG4(printk(KERN_WARNING
......@@ -2046,7 +2150,6 @@ qla24xx_msix_default(int irq, void *dev_id)
set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
complete(&ha->mbx_intr_comp);
}
return IRQ_HANDLED;
}
......
......@@ -3635,6 +3635,157 @@ qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data)
return rval;
}
int
qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mresp)
{
int rval;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
uint32_t iter_cnt = 0x1;
DEBUG11(printk("scsi(%ld): entered.\n", vha->host_no));
memset(mcp->mb, 0 , sizeof(mcp->mb));
mcp->mb[0] = MBC_DIAGNOSTIC_LOOP_BACK;
mcp->mb[1] = mreq->options | BIT_6; // BIT_6 specifies 64 bit addressing
/* transfer count */
mcp->mb[10] = LSW(mreq->transfer_size);
mcp->mb[11] = MSW(mreq->transfer_size);
/* send data address */
mcp->mb[14] = LSW(mreq->send_dma);
mcp->mb[15] = MSW(mreq->send_dma);
mcp->mb[20] = LSW(MSD(mreq->send_dma));
mcp->mb[21] = MSW(MSD(mreq->send_dma));
/* recieve data address */
mcp->mb[16] = LSW(mreq->rcv_dma);
mcp->mb[17] = MSW(mreq->rcv_dma);
mcp->mb[6] = LSW(MSD(mreq->rcv_dma));
mcp->mb[7] = MSW(MSD(mreq->rcv_dma));
/* Iteration count */
mcp->mb[18] = LSW(iter_cnt);
mcp->mb[19] = MSW(iter_cnt);
mcp->out_mb = MBX_21|MBX_20|MBX_19|MBX_18|MBX_17|MBX_16|MBX_15|
MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0;
if (IS_QLA81XX(vha->hw))