summaryrefslogtreecommitdiff
path: root/drivers/scsi/qla2xxx/qla_nx.c
diff options
context:
space:
mode:
authorGiridhar Malavali <giridhar.malavali@qlogic.com>2011-11-18 09:03:18 -0800
committerJames Bottomley <JBottomley@Parallels.com>2011-12-15 10:55:10 +0400
commit5162cf0c4e3962b28a9c8bc1ce89d266db67aa55 (patch)
tree2227318fbacfa974c1aea9d8f4d645f9e659711a /drivers/scsi/qla2xxx/qla_nx.c
parent99b8212c491913bd077063c138676ad5af8c6d3d (diff)
[SCSI] qla2xxx: Consolidated IOCB processing routines.
Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_nx.c')
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c482
1 files changed, 2 insertions, 480 deletions
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index 805b4b734754..24447ddb4b66 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -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;