Commit 5162cf0c authored by Giridhar Malavali's avatar Giridhar Malavali Committed by James Bottomley

[SCSI] qla2xxx: Consolidated IOCB processing routines.

Signed-off-by: default avatarGiridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: default avatarChad Dupuis <chad.dupuis@qlogic.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 99b8212c
......@@ -14,7 +14,8 @@
* | Module Init and Probe | 0x0116 | 0xfa |
* | Mailbox commands | 0x112b | |
* | Device Discovery | 0x2084 | |
* | Queue Command and IO tracing | 0x302f | 0x3008 |
* | Queue Command and IO tracing | 0x302f | 0x3008,0x302d, |
* | | | 0x302e |
* | DPC Thread | 0x401c | |
* | Async Events | 0x5057 | 0x5052 |
* | Timer Routines | 0x6011 | 0x600e,0x600f |
......
......@@ -572,7 +572,7 @@ extern void qla2x00_set_model_info(scsi_qla_host_t *, uint8_t *,
size_t, char *);
extern int qla82xx_mbx_intr_enable(scsi_qla_host_t *);
extern int qla82xx_mbx_intr_disable(scsi_qla_host_t *);
extern void qla82xx_start_iocbs(srb_t *);
extern void qla82xx_start_iocbs(scsi_qla_host_t *);
extern int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *);
extern int qla82xx_check_md_needed(scsi_qla_host_t *);
extern void qla82xx_chip_reset_cleanup(scsi_qla_host_t *);
......
......@@ -11,8 +11,6 @@
#include <scsi/scsi_tcq.h>
static void qla2x00_isp_cmd(struct scsi_qla_host *, struct req_que *);
static void qla25xx_set_que(srb_t *, struct rsp_que **);
/**
* qla2x00_get_cmd_direction() - Determine control_flag data direction.
......@@ -467,6 +465,42 @@ qla2x00_start_scsi(srb_t *sp)
return (QLA_FUNCTION_FAILED);
}
/**
* qla2x00_start_iocbs() - Execute the IOCB command
*/
static void
qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req)
{
struct qla_hw_data *ha = vha->hw;
device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp;
if (IS_QLA82XX(ha)) {
qla82xx_start_iocbs(vha);
} else {
/* Adjust ring index. */
req->ring_index++;
if (req->ring_index == req->length) {
req->ring_index = 0;
req->ring_ptr = req->ring;
} else
req->ring_ptr++;
/* Set chip new ring index. */
if (ha->mqenable) {
WRT_REG_DWORD(&reg->isp25mq.req_q_in, req->ring_index);
RD_REG_DWORD(&ioreg->hccr);
} else if (IS_FWI2_CAPABLE(ha)) {
WRT_REG_DWORD(&reg->isp24.req_q_in, req->ring_index);
RD_REG_DWORD_RELAXED(&reg->isp24.req_q_in);
} else {
WRT_REG_WORD(ISP_REQ_Q_IN(ha, &reg->isp),
req->ring_index);
RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, &reg->isp));
}
}
}
/**
* qla2x00_marker() - Send a marker IOCB to the firmware.
* @ha: HA context
......@@ -516,7 +550,7 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
}
wmb();
qla2x00_isp_cmd(vha, req);
qla2x00_start_iocbs(vha, req);
return (QLA_SUCCESS);
}
......@@ -537,89 +571,140 @@ qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
}
/**
* qla2x00_isp_cmd() - Modify the request ring pointer.
* @ha: HA context
* qla24xx_calc_iocbs() - Determine number of Command Type 3 and
* Continuation Type 1 IOCBs to allocate.
*
* @dsds: number of data segment decriptors needed
*
* Note: The caller must hold the hardware lock before calling this routine.
* Returns the number of IOCB entries needed to store @dsds.
*/
static void
qla2x00_isp_cmd(struct scsi_qla_host *vha, struct req_que *req)
inline uint16_t
qla24xx_calc_iocbs(scsi_qla_host_t *vha, uint16_t dsds)
{
struct qla_hw_data *ha = vha->hw;
device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp;
uint16_t iocbs;
iocbs = 1;
if (dsds > 1) {
iocbs += (dsds - 1) / 5;
if ((dsds - 1) % 5)
iocbs++;
}
return iocbs;
}
ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x302d,
"IOCB data:\n");
ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302e,
(uint8_t *)req->ring_ptr, REQUEST_ENTRY_SIZE);
static inline int
qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt,
uint16_t tot_dsds)
{
uint32_t *cur_dsd = NULL;
scsi_qla_host_t *vha;
struct qla_hw_data *ha;
struct scsi_cmnd *cmd;
struct scatterlist *cur_seg;
uint32_t *dsd_seg;
void *next_dsd;
uint8_t avail_dsds;
uint8_t first_iocb = 1;
uint32_t dsd_list_len;
struct dsd_dma *dsd_ptr;
struct ct6_dsd *ctx;
/* Adjust ring index. */
req->ring_index++;
if (req->ring_index == req->length) {
req->ring_index = 0;
req->ring_ptr = req->ring;
} else
req->ring_ptr++;
cmd = sp->cmd;
/* Set chip new ring index. */
if (IS_QLA82XX(ha)) {
uint32_t dbval = 0x04 | (ha->portnum << 5);
/* Update entry type to indicate Command Type 3 IOCB */
*((uint32_t *)(&cmd_pkt->entry_type)) =
__constant_cpu_to_le32(COMMAND_TYPE_6);
/* write, read and verify logic */
dbval = dbval | (req->id << 8) | (req->ring_index << 16);
if (ql2xdbwr)
qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval);
else {
WRT_REG_DWORD(
(unsigned long __iomem *)ha->nxdb_wr_ptr,
dbval);
wmb();
while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) {
WRT_REG_DWORD((unsigned long __iomem *)
ha->nxdb_wr_ptr, dbval);
wmb();
}
/* No data transfer */
if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
cmd_pkt->byte_count = __constant_cpu_to_le32(0);
return 0;
}
} else if (ha->mqenable) {
/* Set chip new ring index. */
WRT_REG_DWORD(&reg->isp25mq.req_q_in, req->ring_index);
RD_REG_DWORD(&ioreg->hccr);
} else {
if (IS_FWI2_CAPABLE(ha)) {
WRT_REG_DWORD(&reg->isp24.req_q_in, req->ring_index);
RD_REG_DWORD_RELAXED(&reg->isp24.req_q_in);
vha = sp->fcport->vha;
ha = vha->hw;
/* Set transfer direction */
if (cmd->sc_data_direction == DMA_TO_DEVICE) {
cmd_pkt->control_flags =
__constant_cpu_to_le16(CF_WRITE_DATA);
ha->qla_stats.output_bytes += scsi_bufflen(cmd);
} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
cmd_pkt->control_flags =
__constant_cpu_to_le16(CF_READ_DATA);
ha->qla_stats.input_bytes += scsi_bufflen(cmd);
}
cur_seg = scsi_sglist(cmd);
ctx = sp->ctx;
while (tot_dsds) {
avail_dsds = (tot_dsds > QLA_DSDS_PER_IOCB) ?
QLA_DSDS_PER_IOCB : tot_dsds;
tot_dsds -= avail_dsds;
dsd_list_len = (avail_dsds + 1) * QLA_DSD_SIZE;
dsd_ptr = list_first_entry(&ha->gbl_dsd_list,
struct dsd_dma, list);
next_dsd = dsd_ptr->dsd_addr;
list_del(&dsd_ptr->list);
ha->gbl_dsd_avail--;
list_add_tail(&dsd_ptr->list, &ctx->dsd_list);
ctx->dsd_use_cnt++;
ha->gbl_dsd_inuse++;
if (first_iocb) {
first_iocb = 0;
dsd_seg = (uint32_t *)&cmd_pkt->fcp_data_dseg_address;
*dsd_seg++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
*dsd_seg++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
cmd_pkt->fcp_data_dseg_len = cpu_to_le32(dsd_list_len);
} else {
WRT_REG_WORD(ISP_REQ_Q_IN(ha, &reg->isp),
req->ring_index);
RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, &reg->isp));
*cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
*cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
*cur_dsd++ = cpu_to_le32(dsd_list_len);
}
cur_dsd = (uint32_t *)next_dsd;
while (avail_dsds) {
dma_addr_t sle_dma;
sle_dma = sg_dma_address(cur_seg);
*cur_dsd++ = cpu_to_le32(LSD(sle_dma));
*cur_dsd++ = cpu_to_le32(MSD(sle_dma));
*cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg));
cur_seg = sg_next(cur_seg);
avail_dsds--;
}
}
/* Null termination */
*cur_dsd++ = 0;
*cur_dsd++ = 0;
*cur_dsd++ = 0;
cmd_pkt->control_flags |= CF_DATA_SEG_DESCR_ENABLE;
return 0;
}
/**
* qla24xx_calc_iocbs() - Determine number of Command Type 3 and
* Continuation Type 1 IOCBs to allocate.
/*
* qla24xx_calc_dsd_lists() - Determine number of DSD list required
* for Command Type 6.
*
* @dsds: number of data segment decriptors needed
*
* Returns the number of IOCB entries needed to store @dsds.
* Returns the number of dsd list needed to store @dsds.
*/
inline uint16_t
qla24xx_calc_iocbs(scsi_qla_host_t *vha, uint16_t dsds)
qla24xx_calc_dsd_lists(uint16_t dsds)
{
uint16_t iocbs;
uint16_t dsd_lists = 0;
iocbs = 1;
if (dsds > 1) {
iocbs += (dsds - 1) / 5;
if ((dsds - 1) % 5)
iocbs++;
}
return iocbs;
dsd_lists = (dsds/QLA_DSDS_PER_IOCB);
if (dsds % QLA_DSDS_PER_IOCB)
dsd_lists++;
return dsd_lists;
}
/**
* qla24xx_build_scsi_iocbs() - Build IOCB command utilizing Command Type 7
* IOCB types.
......@@ -946,6 +1031,7 @@ qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *ha, srb_t *sp,
*cur_dsd++ = 0;
return 0;
}
static int
qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd,
uint16_t tot_dsds)
......@@ -1793,42 +1879,6 @@ qla2x00_alloc_iocbs(scsi_qla_host_t *vha, srb_t *sp)
return pkt;
}
static void
qla2x00_start_iocbs(srb_t *sp)
{
struct qla_hw_data *ha = sp->fcport->vha->hw;
struct req_que *req = ha->req_q_map[0];
device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp;
if (IS_QLA82XX(ha)) {
qla82xx_start_iocbs(sp);
} else {
/* Adjust ring index. */
req->ring_index++;
if (req->ring_index == req->length) {
req->ring_index = 0;
req->ring_ptr = req->ring;
} else
req->ring_ptr++;
/* Set chip new ring index. */
if (ha->mqenable) {
WRT_REG_DWORD(&reg->isp25mq.req_q_in, req->ring_index);
RD_REG_DWORD(&ioreg->hccr);
} else if (IS_QLA82XX(ha)) {
qla82xx_start_iocbs(sp);
} else if (IS_FWI2_CAPABLE(ha)) {
WRT_REG_DWORD(&reg->isp24.req_q_in, req->ring_index);
RD_REG_DWORD_RELAXED(&reg->isp24.req_q_in);
} else {
WRT_REG_WORD(ISP_REQ_Q_IN(ha, &reg->isp),
req->ring_index);
RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, &reg->isp));
}
}
}
static void
qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio)
{
......@@ -2161,6 +2211,372 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
ct_iocb->entry_count = entry_count;
}
/*
* qla82xx_start_scsi() - Send a SCSI command to the ISP
* @sp: command to send to the ISP
*
* Returns non-zero if a failure occurred, else zero.
*/
int
qla82xx_start_scsi(srb_t *sp)
{
int ret, nseg;
unsigned long flags;
struct scsi_cmnd *cmd;
uint32_t *clr_ptr;
uint32_t index;
uint32_t handle;
uint16_t cnt;
uint16_t req_cnt;
uint16_t tot_dsds;
struct device_reg_82xx __iomem *reg;
uint32_t dbval;
uint32_t *fcp_dl;
uint8_t additional_cdb_len;
struct ct6_dsd *ctx;
struct scsi_qla_host *vha = sp->fcport->vha;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = NULL;
struct rsp_que *rsp = NULL;
char tag[2];
/* Setup device pointers. */
ret = 0;
reg = &ha->iobase->isp82;
cmd = sp->cmd;
req = vha->req;
rsp = ha->rsp_q_map[0];
/* So we know we haven't pci_map'ed anything yet */
tot_dsds = 0;
dbval = 0x04 | (ha->portnum << 5);
/* Send marker if required */
if (vha->marker_needed != 0) {
if (qla2x00_marker(vha, req,
rsp, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x300c,
"qla2x00_marker failed for cmd=%p.\n", cmd);
return QLA_FUNCTION_FAILED;
}
vha->marker_needed = 0;
}
/* Acquire ring specific lock */
spin_lock_irqsave(&ha->hardware_lock, flags);
/* Check for room in outstanding command list. */
handle = req->current_outstanding_cmd;
for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) {
handle++;
if (handle == MAX_OUTSTANDING_COMMANDS)
handle = 1;
if (!req->outstanding_cmds[handle])
break;
}
if (index == MAX_OUTSTANDING_COMMANDS)
goto queuing_error;
/* Map the sg table so we have an accurate count of sg entries needed */
if (scsi_sg_count(cmd)) {
nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
scsi_sg_count(cmd), cmd->sc_data_direction);
if (unlikely(!nseg))
goto queuing_error;
} else
nseg = 0;
tot_dsds = nseg;
if (tot_dsds > ql2xshiftctondsd) {
struct cmd_type_6 *cmd_pkt;
uint16_t more_dsd_lists = 0;
struct dsd_dma *dsd_ptr;
uint16_t i;
more_dsd_lists = qla24xx_calc_dsd_lists(tot_dsds);
if ((more_dsd_lists + ha->gbl_dsd_inuse) >= NUM_DSD_CHAIN) {
ql_dbg(ql_dbg_io, vha, 0x300d,
"Num of DSD list %d is than %d for cmd=%p.\n",
more_dsd_lists + ha->gbl_dsd_inuse, NUM_DSD_CHAIN,
cmd);
goto queuing_error;
}
if (more_dsd_lists <= ha->gbl_dsd_avail)
goto sufficient_dsds;
else
more_dsd_lists -= ha->gbl_dsd_avail;
for (i = 0; i < more_dsd_lists; i++) {
dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC);
if (!dsd_ptr) {
ql_log(ql_log_fatal, vha, 0x300e,
"Failed to allocate memory for dsd_dma "
"for cmd=%p.\n", cmd);
goto queuing_error;
}
dsd_ptr->dsd_addr = dma_pool_alloc(ha->dl_dma_pool,
GFP_ATOMIC, &dsd_ptr->dsd_list_dma);
if (!dsd_ptr->dsd_addr) {
kfree(dsd_ptr);
ql_log(ql_log_fatal, vha, 0x300f,
"Failed to allocate memory for dsd_addr "
"for cmd=%p.\n", cmd);
goto queuing_error;
}
list_add_tail(&dsd_ptr->list, &ha->gbl_dsd_list);
ha->gbl_dsd_avail++;
}
sufficient_dsds:
req_cnt = 1;
if (req->cnt < (req_cnt + 2)) {
cnt = (uint16_t)RD_REG_DWORD_RELAXED(
&reg->req_q_out[0]);
if (req->ring_index < cnt)
req->cnt = cnt - req->ring_index;
else
req->cnt = req->length -
(req->ring_index - cnt);
}
if (req->cnt < (req_cnt + 2))
goto queuing_error;
ctx = sp->ctx = mempool_alloc(ha->ctx_mempool, GFP_ATOMIC);
if (!sp->ctx) {
ql_log(ql_log_fatal, vha, 0x3010,
"Failed to allocate ctx for cmd=%p.\n", cmd);
goto queuing_error;
}
memset(ctx, 0, sizeof(struct ct6_dsd));
ctx->fcp_cmnd = dma_pool_alloc(ha->fcp_cmnd_dma_pool,
GFP_ATOMIC, &ctx->fcp_cmnd_dma);
if (!ctx->fcp_cmnd) {
ql_log(ql_log_fatal, vha, 0x3011,
"Failed to allocate fcp_cmnd for cmd=%p.\n", cmd);
goto queuing_error_fcp_cmnd;
}
/* Initialize the DSD list and dma handle */
INIT_LIST_HEAD(&ctx->dsd_list);
ctx->dsd_use_cnt = 0;
if (cmd->cmd_len > 16) {
additional_cdb_len = cmd->cmd_len - 16;
if ((cmd->cmd_len % 4) != 0) {
/* SCSI command bigger than 16 bytes must be
* multiple of 4
*/
ql_log(ql_log_warn, vha, 0x3012,
"scsi cmd len %d not multiple of 4 "
"for cmd=%p.\n", cmd->cmd_len, cmd);
goto queuing_error_fcp_cmnd;
}
ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4;
} else {
additional_cdb_len = 0;
ctx->fcp_cmnd_len = 12 + 16 + 4;
}
cmd_pkt = (struct cmd_type_6 *)req->ring_ptr;
cmd_pkt->handle = MAKE_HANDLE(req->id, handle);
/* Zero out remaining portion of packet. */
/* tagged queuing modifier -- default is TSK_SIMPLE (0). */
clr_ptr = (uint32_t *)cmd_pkt + 2;
memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
/* Set NPORT-ID and LUN number*/
cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
cmd_pkt->vp_index = sp->fcport->vp_idx;
/* Build IOCB segments */
if (qla24xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds))
goto queuing_error_fcp_cmnd;
int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
/* build FCP_CMND IU */
memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd));
int_to_scsilun(sp->cmd->device->lun, &ctx->fcp_cmnd->lun);
ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len;
if (cmd->sc_data_direction == DMA_TO_DEVICE)
ctx->fcp_cmnd->additional_cdb_len |= 1;
else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
ctx->fcp_cmnd->additional_cdb_len |= 2;
/*
* Update tagged queuing modifier -- default is TSK_SIMPLE (0).
*/
if (scsi_populate_tag_msg(cmd, tag)) {
switch (tag[0]) {
case HEAD_OF_QUEUE_TAG:
ctx->fcp_cmnd->task_attribute =
TSK_HEAD_OF_QUEUE;
break;
case ORDERED_QUEUE_TAG:
ctx->fcp_cmnd->task_attribute =
TSK_ORDERED;
break;
}
}
memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
fcp_dl = (uint32_t *)(ctx->fcp_cmnd->cdb + 16 +
additional_cdb_len);
*fcp_dl = htonl((uint32_t)scsi_bufflen(cmd));
cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len);
cmd_pkt->fcp_cmnd_dseg_address[0] =
cpu_to_le32(LSD(ctx->fcp_cmnd_dma));
cmd_pkt->fcp_cmnd_dseg_address[1] =
cpu_to_le32(MSD(ctx->fcp_cmnd_dma));
sp->flags |= SRB_FCP_CMND_DMA_VALID;
cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
/* Set total data segment count. */
cmd_pkt->entry_count = (uint8_t)req_cnt;
/* Specify response queue number where
* completion should happen
*/
cmd_pkt->entry_status = (uint8_t) rsp->id;
} else {
struct cmd_type_7 *cmd_pkt;
req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
if (req->cnt < (req_cnt + 2)) {
cnt = (uint16_t)RD_REG_DWORD_RELAXED(
&reg->req_q_out[0]);
if (req->ring_index < cnt)
req->cnt = cnt - req->ring_index;
else
req->cnt = req->length -
(req->ring_index - cnt);
}
if (req->cnt < (req_cnt + 2))
goto queuing_error;
cmd_pkt = (struct cmd_type_7 *)req->ring_ptr;
cmd_pkt->handle = MAKE_HANDLE(req->id, handle);
/* Zero out remaining portion of packet. */
/* tagged queuing modifier -- default is TSK_SIMPLE (0).*/
clr_ptr = (uint32_t *)cmd_pkt + 2;
memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
/* Set NPORT-ID and LUN number*/
cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
cmd_pkt->vp_index = sp->fcport->vp_idx;
int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
host_to_fcp_swap((uint8_t *)&cmd_pkt->lun,
sizeof(cmd_pkt->lun));
/*
* Update tagged queuing modifier -- default is TSK_SIMPLE (0).
*/
if (scsi_populate_tag_msg(cmd, tag)) {
switch (tag[0]) {
case HEAD_OF_QUEUE_TAG:
cmd_pkt->task = TSK_HEAD_OF_QUEUE;
break;
case ORDERED_QUEUE_TAG:
cmd_pkt->task = TSK_ORDERED;
break;
}
}
/* Load SCSI command packet. */
memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len);
host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb));
cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
/* Build IOCB segments */
qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds);
/* Set total data segment count. */
cmd_pkt->entry_count = (uint8_t)req_cnt;
/* Specify response queue number where
* completion should happen.
*/
cmd_pkt->entry_status = (uint8_t) rsp->id;
}
/* Build command packet. */
req->current_outstanding_cmd = handle;
req->outstanding_cmds[handle] = sp;
sp->handle = handle;
sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
req->cnt -= req_cnt;
wmb();
/* Adjust ring index. */
req->ring_index++;
if (req->ring_index == req->length) {
req->ring_index = 0;
req->ring_ptr = req->ring;
} else
req->ring_ptr++;
sp->flags |= SRB_DMA_VALID;
/* Set chip new ring index. */
/* write, read and verify logic */
dbval = dbval | (req->id << 8) | (req->ring_index << 16);
if (ql2xdbwr)
qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval);
else {
WRT_REG_DWORD(
(unsigned long __iomem *)ha->nxdb_wr_ptr,
dbval);
wmb();
while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) {
WRT_REG_DWORD(
(unsigned long __iomem *)ha->nxdb_wr_ptr,
dbval);
wmb();
}
}
/* Manage unprocessed RIO/ZIO commands in response queue. */
if (vha->flags.process_response_queue &&
rsp->ring_ptr->signature != RESPONSE_PROCESSED)
qla24xx_process_response_queue(vha, rsp);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_SUCCESS;
queuing_error_fcp_cmnd:
dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, ctx->fcp_cmnd_dma);
queuing_error:
if (tot_dsds)
scsi_dma_unmap(cmd);
if (sp->ctx) {
mempool_free(sp->ctx, ha->ctx_mempool);
sp->ctx = NULL;
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_FUNCTION_FAILED;
}
int
qla2x00_start_sp(srb_t *sp)
{
......@@ -2213,7 +2629,7 @@ qla2x00_start_sp(srb_t *sp)
}
wmb();
qla2x00_start_iocbs(sp);
qla2x00_start_iocbs(sp->fcport->vha, ha->req_q_map[0]);
done:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return rval;
......
......@@ -2539,484 +2539,6 @@ qla82xx_start_firmware(scsi_qla_host_t *vha)
return qla82xx_check_rcvpeg_state(ha);
}
static inline int
qla2xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt,
uint16_t tot_dsds)
{
uint32_t *cur_dsd = NULL;
scsi_qla_host_t *vha;
struct qla_hw_data *ha;
struct scsi_cmnd *cmd;
struct scatterlist *cur_seg;
uint32_t *dsd_seg;
void *next_dsd;
uint8_t avail_dsds;
uint8_t first_iocb = 1;
uint32_t dsd_list_len;
struct dsd_dma *dsd_ptr;
struct ct6_dsd *ctx;
cmd = sp->cmd;
/* Update entry type to indicate Command Type 3 IOCB */
*((uint32_t *)(&cmd_pkt->entry_type)) =
__constant_cpu_to_le32(COMMAND_TYPE_6);
/* No data transfer */
if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
cmd_pkt->byte_count = __constant_cpu_to_le32(0);
return 0;
}
vha = sp->fcport->vha;
ha = vha->hw;
/* Set transfer direction */
if (cmd->sc_data_direction == DMA_TO_DEVICE) {
cmd_pkt->control_flags =
__constant_cpu_to_le16(CF_WRITE_DATA);
ha->qla_stats.output_bytes += scsi_bufflen(cmd);
} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
cmd_pkt->control_flags =
__constant_cpu_to_le16(CF_READ_DATA);
ha->qla_stats.input_bytes += scsi_bufflen(cmd);
}
cur_seg = scsi_sglist(cmd);
ctx = sp->ctx;
while (tot_dsds) {
avail_dsds = (tot_dsds > QLA_DSDS_PER_IOCB) ?
QLA_DSDS_PER_IOCB : tot_dsds;
tot_dsds -= avail_dsds;
dsd_list_len = (avail_dsds + 1) * QLA_DSD_SIZE;
dsd_ptr = list_first_entry(&ha->gbl_dsd_list,
struct dsd_dma, list);
next_dsd = dsd_ptr->dsd_addr;
list_del(&dsd_ptr->list);
ha->gbl_dsd_avail--;
list_add_tail(&dsd_ptr->list, &ctx->dsd_list);
ctx->dsd_use_cnt++;
ha->gbl_dsd_inuse++;
if (first_iocb) {
first_iocb = 0;
dsd_seg = (uint32_t *)&cmd_pkt->fcp_data_dseg_address;
*dsd_seg++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
*dsd_seg++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
cmd_pkt->fcp_data_dseg_len = cpu_to_le32(dsd_list_len);
} else {
*cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
*cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
*cur_dsd++ = cpu_to_le32(dsd_list_len);
}
cur_dsd = (uint32_t *)next_dsd;
while (avail_dsds) {
dma_addr_t sle_dma;
sle_dma = sg_dma_address(cur_seg);
*cur_dsd++ = cpu_to_le32(LSD(sle_dma));
*cur_dsd++ = cpu_to_le32(MSD(sle_dma));
*cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg));
cur_seg = sg_next(cur_seg);
avail_dsds--;
}
}
/* Null termination */
*cur_dsd++ = 0;
*cur_dsd++ = 0;
*cur_dsd++ = 0;
cmd_pkt->control_flags |= CF_DATA_SEG_DESCR_ENABLE;
return 0;
}
/*
* qla82xx_calc_dsd_lists() - Determine number of DSD list required
* for Command Type 6.
*
* @dsds: number of data segment decriptors needed
*
* Returns the number of dsd list needed to store @dsds.
*/
inline uint16_t
qla82xx_calc_dsd_lists(uint16_t dsds)
{
uint16_t dsd_lists = 0;
dsd_lists = (dsds/QLA_DSDS_PER_IOCB);
if (dsds % QLA_DSDS_PER_IOCB)
dsd_lists++;
return dsd_lists;
}
/*
* qla82xx_start_scsi() - Send a SCSI command to the ISP
* @sp: command to send to the ISP
*
* Returns non-zero if a failure occurred, else zero.
*/
int
qla82xx_start_scsi(srb_t *sp)
{
int ret, nseg;
unsigned long flags;
struct scsi_cmnd *cmd;
uint32_t *clr_ptr;
uint32_t index;
uint32_t handle;
uint16_t cnt;
uint16_t req_cnt;
uint16_t tot_dsds;
struct device_reg_82xx __iomem *reg;
uint32_t dbval;
uint32_t *fcp_dl;
uint8_t additional_cdb_len;
struct ct6_dsd *ctx;
struct scsi_qla_host *vha = sp->fcport->vha;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = NULL;
struct rsp_que *rsp = NULL;
char tag[2];
/* Setup device pointers. */
ret = 0;
reg = &ha->iobase->isp82;
cmd = sp->cmd;
req = vha->req;
rsp = ha->rsp_q_map[0];
/* So we know we haven't pci_map'ed anything yet */
tot_dsds = 0;
dbval = 0x04 | (ha->portnum << 5);
/* Send marker if required */
if (vha->marker_needed != 0) {
if (qla2x00_marker(vha, req,
rsp, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x300c,
"qla2x00_marker failed for cmd=%p.\n", cmd);
return QLA_FUNCTION_FAILED;
}
vha->marker_needed = 0;
}
/* Acquire ring specific lock */
spin_lock_irqsave(&ha->hardware_lock, flags);
/* Check for room in outstanding command list. */
handle = req->current_outstanding_cmd;
for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) {
handle++;
if (handle == MAX_OUTSTANDING_COMMANDS)
handle = 1;
if (!req->outstanding_cmds[handle])
break;
}
if (index == MAX_OUTSTANDING_COMMANDS)
goto queuing_error;
/* Map the sg table so we have an accurate count of sg entries needed */
if (scsi_sg_count(cmd)) {
nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
scsi_sg_count(cmd), cmd->sc_data_direction);
if (unlikely(!nseg))
goto queuing_error;
} else
nseg = 0;
tot_dsds = nseg;
if (tot_dsds > ql2xshiftctondsd) {
struct cmd_type_6 *cmd_pkt;
uint16_t more_dsd_lists = 0;
struct dsd_dma *dsd_ptr;
uint16_t i;
more_dsd_lists = qla82xx_calc_dsd_lists(tot_dsds);
if ((more_dsd_lists + ha->gbl_dsd_inuse) >= NUM_DSD_CHAIN) {
ql_dbg(ql_dbg_io, vha, 0x300d,
"Num of DSD list %d is than %d for cmd=%p.\n",
more_dsd_lists + ha->gbl_dsd_inuse, NUM_DSD_CHAIN,
cmd);
goto queuing_error;
}
if (more_dsd_lists <= ha->gbl_dsd_avail)
goto sufficient_dsds;
else
more_dsd_lists -= ha->gbl_dsd_avail;
for (i = 0; i < more_dsd_lists; i++) {
dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC);
if (!dsd_ptr) {
ql_log(ql_log_fatal, vha, 0x300e,
"Failed to allocate memory for dsd_dma "
"for cmd=%p.\n", cmd);
goto queuing_error;
}
dsd_ptr->dsd_addr = dma_pool_alloc(ha->dl_dma_pool,
GFP_ATOMIC, &dsd_ptr->dsd_list_dma);
if (!dsd_ptr->dsd_addr) {
kfree(dsd_ptr);
ql_log(ql_log_fatal, vha, 0x300f,
"Failed to allocate memory for dsd_addr "
"for cmd=%p.\n", cmd);
goto queuing_error;
}
list_add_tail(&dsd_ptr->list, &ha->gbl_dsd_list);
ha->gbl_dsd_avail++;
}
sufficient_dsds:
req_cnt = 1;
if (req->cnt < (req_cnt + 2)) {
cnt = (uint16_t)RD_REG_DWORD_RELAXED(
&reg->req_q_out[0]);
if (req->ring_index < cnt)
req->cnt = cnt - req->ring_index;
else
req->cnt = req->length -
(req->ring_index - cnt);
}
if (req->cnt < (req_cnt + 2))
goto queuing_error;
ctx = sp->ctx = mempool_alloc(ha->ctx_mempool, GFP_ATOMIC);
if (!sp->ctx) {
ql_log(ql_log_fatal, vha, 0x3010,
"Failed to allocate ctx for cmd=%p.\n", cmd);
goto queuing_error;
}
memset(ctx, 0, sizeof(struct ct6_dsd));
ctx->fcp_cmnd = dma_pool_alloc(ha->fcp_cmnd_dma_pool,
GFP_ATOMIC, &ctx->fcp_cmnd_dma);
if (!ctx->fcp_cmnd) {
ql_log(ql_log_fatal, vha, 0x3011,
"Failed to allocate fcp_cmnd for cmd=%p.\n", cmd);
goto queuing_error_fcp_cmnd;
}
/* Initialize the DSD list and dma handle */
INIT_LIST_HEAD(&ctx->dsd_list);
ctx->dsd_use_cnt = 0;
if (cmd->cmd_len > 16) {
additional_cdb_len = cmd->cmd_len - 16;
if ((cmd->cmd_len % 4) != 0) {
/* SCSI command bigger than 16 bytes must be
* multiple of 4
*/
ql_log(ql_log_warn, vha, 0x3012,
"scsi cmd len %d not multiple of 4 "
"for cmd=%p.\n", cmd->cmd_len, cmd);
goto queuing_error_fcp_cmnd;
}
ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4;
} else {
additional_cdb_len = 0;
ctx->fcp_cmnd_len = 12 + 16 + 4;
}
cmd_pkt = (struct cmd_type_6 *)req->ring_ptr;
cmd_pkt->handle = MAKE_HANDLE(req->id, handle);
/* Zero out remaining portion of packet. */
/* tagged queuing modifier -- default is TSK_SIMPLE (0). */
clr_ptr = (uint32_t *)cmd_pkt + 2;
memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
/* Set NPORT-ID and LUN number*/
cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
cmd_pkt->vp_index = sp->fcport->vp_idx;
/* Build IOCB segments */
if (qla2xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds))
goto queuing_error_fcp_cmnd;
int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
/* build FCP_CMND IU */
memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd));
int_to_scsilun(sp->cmd->device->lun, &ctx->fcp_cmnd->lun);
ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len;
if (cmd->sc_data_direction == DMA_TO_DEVICE)
ctx->fcp_cmnd->additional_cdb_len |= 1;
else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
ctx->fcp_cmnd->additional_cdb_len |= 2;
/*
* Update tagged queuing modifier -- default is TSK_SIMPLE (0).
*/
if (scsi_populate_tag_msg(cmd, tag)) {
switch (tag[0]) {
case HEAD_OF_QUEUE_TAG:
ctx->fcp_cmnd->task_attribute =
TSK_HEAD_OF_QUEUE;
break;
case ORDERED_QUEUE_TAG:
ctx->fcp_cmnd->task_attribute =
TSK_ORDERED;
break;
}
}
memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
fcp_dl = (uint32_t *)(ctx->fcp_cmnd->cdb + 16 +
additional_cdb_len);
*fcp_dl = htonl((uint32_t)scsi_bufflen(cmd));
cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len);
cmd_pkt->fcp_cmnd_dseg_address[0] =
cpu_to_le32(LSD(ctx->fcp_cmnd_dma));
cmd_pkt->fcp_cmnd_dseg_address[1] =
cpu_to_le32(MSD(ctx->fcp_cmnd_dma));
sp->flags |= SRB_FCP_CMND_DMA_VALID;
cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
/* Set total data segment count. */
cmd_pkt->entry_count = (uint8_t)req_cnt;
/* Specify response queue number where
* completion should happen
*/
cmd_pkt->entry_status = (uint8_t) rsp->id;
} else {
struct cmd_type_7 *cmd_pkt;
req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
if (req->cnt < (req_cnt + 2)) {
cnt = (uint16_t)RD_REG_DWORD_RELAXED(
&reg->req_q_out[0]);
if (req->ring_index < cnt)
req->cnt = cnt - req->ring_index;
else
req->cnt = req->length -
(req->ring_index - cnt);
}
if (req->cnt < (req_cnt + 2))
goto queuing_error;
cmd_pkt = (struct cmd_type_7 *)req->ring_ptr;
cmd_pkt->handle = MAKE_HANDLE(req->id, handle);
/* Zero out remaining portion of packet. */
/* tagged queuing modifier -- default is TSK_SIMPLE (0).*/
clr_ptr = (uint32_t *)cmd_pkt + 2;
memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
/* Set NPORT-ID and LUN number*/
cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
cmd_pkt->vp_index = sp->fcport->vp_idx;
int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
host_to_fcp_swap((uint8_t *)&cmd_pkt->lun,
sizeof(cmd_pkt->lun));
/*
* Update tagged queuing modifier -- default is TSK_SIMPLE (0).
*/
if (scsi_populate_tag_msg(cmd, tag)) {
switch (tag[0]) {
case HEAD_OF_QUEUE_TAG:
cmd_pkt->task = TSK_HEAD_OF_QUEUE;
break;
case ORDERED_QUEUE_TAG:
cmd_pkt->task = TSK_ORDERED;
break;
}
}
/* Load SCSI command packet. */
memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len);
host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb));
cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
/* Build IOCB segments */
qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds);
/* Set total data segment count. */
cmd_pkt->entry_count = (uint8_t)req_cnt;
/* Specify response queue number where
* completion should happen.
*/
cmd_pkt->entry_status = (uint8_t) rsp->id;
}
/* Build command packet. */
req->current_outstanding_cmd = handle;
req->outstanding_cmds[handle] = sp;
sp->handle = handle;
sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
req->cnt -= req_cnt;
wmb();
/* Adjust ring index. */
req->ring_index++;
if (req->ring_index == req->length) {
req->ring_index = 0;
req->ring_ptr = req->ring;
} else
req->ring_ptr++;
sp->flags |= SRB_DMA_VALID;
/* Set chip new ring index. */
/* write, read and verify logic */
dbval = dbval | (req->id << 8) | (req->ring_index << 16);
if (ql2xdbwr)
qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval);
else {
WRT_REG_DWORD(
(unsigned long __iomem *)ha->nxdb_wr_ptr,
dbval);
wmb();
while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) {
WRT_REG_DWORD(
(unsigned long __iomem *)ha->nxdb_wr_ptr,
dbval);
wmb();
}
}
/* Manage unprocessed RIO/ZIO commands in response queue. */
if (vha->flags.process_response_queue &&
rsp->ring_ptr->signature != RESPONSE_PROCESSED)
qla24xx_process_response_queue(vha, rsp);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_SUCCESS;
queuing_error_fcp_cmnd:
dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, ctx->fcp_cmnd_dma);
queuing_error:
if (tot_dsds)
scsi_dma_unmap(cmd);
if (sp->ctx) {
mempool_free(sp->ctx, ha->ctx_mempool);
sp->ctx = NULL;
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_FUNCTION_FAILED;
}
static uint32_t *
qla82xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
uint32_t length)
......@@ -3268,9 +2790,9 @@ qla82xx_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
}
void
qla82xx_start_iocbs(srb_t *sp)
qla82xx_start_iocbs(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = sp->fcport->vha->hw;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
struct device_reg_82xx __iomem *reg;
uint32_t dbval;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment