X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fscsi%2Fqla2xxx%2Fqla_iocb.c;h=6e14c8eaca82061a1acb391fa0e06dab90471f14;hb=bf6583b5831d3195c45f98ec3016499389cbe18f;hp=59d62cbb994e770341c9f5a08617cc54777b5644;hpb=bdf796210e01145fd77bbb3ae644d04f982b6c3b;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 59d62cb..6e14c8e 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1,22 +1,9 @@ -/****************************************************************************** - * QLOGIC LINUX SOFTWARE +/* + * QLogic Fibre Channel HBA Driver + * Copyright (c) 2003-2008 QLogic Corporation * - * QLogic ISP2x00 device driver for Linux 2.6.x - * Copyright (C) 2003-2004 QLogic Corporation - * (www.qlogic.com) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * 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. - * - ******************************************************************************/ - + * See LICENSE.qla2xxx for copyright and licensing details. + */ #include "qla_def.h" #include @@ -24,10 +11,8 @@ #include -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. @@ -167,6 +152,8 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, uint32_t *cur_dsd; scsi_qla_host_t *ha; struct scsi_cmnd *cmd; + struct scatterlist *sg; + int i; cmd = sp->cmd; @@ -175,7 +162,7 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, __constant_cpu_to_le32(COMMAND_TYPE); /* No data transfer */ - if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) { + if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { cmd_pkt->byte_count = __constant_cpu_to_le32(0); return; } @@ -189,46 +176,23 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address; /* Load data segments */ - if (cmd->use_sg != 0) { - struct scatterlist *cur_seg; - struct scatterlist *end_seg; - - cur_seg = (struct scatterlist *)cmd->request_buffer; - end_seg = cur_seg + tot_dsds; - while (cur_seg < end_seg) { - cont_entry_t *cont_pkt; - - /* Allocate additional continuation packets? */ - if (avail_dsds == 0) { - /* - * Seven DSDs are available in the Continuation - * Type 0 IOCB. - */ - cont_pkt = qla2x00_prep_cont_type0_iocb(ha); - cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address; - avail_dsds = 7; - } - - *cur_dsd++ = cpu_to_le32(sg_dma_address(cur_seg)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg)); - avail_dsds--; - - cur_seg++; + scsi_for_each_sg(cmd, sg, tot_dsds, i) { + cont_entry_t *cont_pkt; + + /* Allocate additional continuation packets? */ + if (avail_dsds == 0) { + /* + * Seven DSDs are available in the Continuation + * Type 0 IOCB. + */ + cont_pkt = qla2x00_prep_cont_type0_iocb(ha); + cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address; + avail_dsds = 7; } - } else { - dma_addr_t req_dma; - struct page *page; - unsigned long offset; - page = virt_to_page(cmd->request_buffer); - offset = ((unsigned long)cmd->request_buffer & ~PAGE_MASK); - req_dma = pci_map_page(ha->pdev, page, offset, - cmd->request_bufflen, cmd->sc_data_direction); - - sp->dma_handle = req_dma; - - *cur_dsd++ = cpu_to_le32(req_dma); - *cur_dsd++ = cpu_to_le32(cmd->request_bufflen); + *cur_dsd++ = cpu_to_le32(sg_dma_address(sg)); + *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + avail_dsds--; } } @@ -247,6 +211,8 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, uint32_t *cur_dsd; scsi_qla_host_t *ha; struct scsi_cmnd *cmd; + struct scatterlist *sg; + int i; cmd = sp->cmd; @@ -255,7 +221,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, __constant_cpu_to_le32(COMMAND_A64_TYPE); /* No data transfer */ - if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) { + if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { cmd_pkt->byte_count = __constant_cpu_to_le32(0); return; } @@ -269,50 +235,26 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address; /* Load data segments */ - if (cmd->use_sg != 0) { - struct scatterlist *cur_seg; - struct scatterlist *end_seg; - - cur_seg = (struct scatterlist *)cmd->request_buffer; - end_seg = cur_seg + tot_dsds; - while (cur_seg < end_seg) { - 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 Continuation - * Type 1 IOCB. - */ - cont_pkt = qla2x00_prep_cont_type1_iocb(ha); - cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; - avail_dsds = 5; - } - - 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)); - avail_dsds--; - - cur_seg++; + scsi_for_each_sg(cmd, sg, tot_dsds, i) { + 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 Continuation + * Type 1 IOCB. + */ + cont_pkt = qla2x00_prep_cont_type1_iocb(ha); + cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; + avail_dsds = 5; } - } else { - dma_addr_t req_dma; - struct page *page; - unsigned long offset; - - page = virt_to_page(cmd->request_buffer); - offset = ((unsigned long)cmd->request_buffer & ~PAGE_MASK); - req_dma = pci_map_page(ha->pdev, page, offset, - cmd->request_bufflen, cmd->sc_data_direction); - - sp->dma_handle = req_dma; - *cur_dsd++ = cpu_to_le32(LSD(req_dma)); - *cur_dsd++ = cpu_to_le32(MSD(req_dma)); - *cur_dsd++ = cpu_to_le32(cmd->request_bufflen); + 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)); + avail_dsds--; } } @@ -325,26 +267,27 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, int qla2x00_start_scsi(srb_t *sp) { - int ret; + int ret, nseg; unsigned long flags; - scsi_qla_host_t *ha; + scsi_qla_host_t *ha, *pha; struct scsi_cmnd *cmd; uint32_t *clr_ptr; uint32_t index; uint32_t handle; cmd_entry_t *cmd_pkt; - struct scatterlist *sg; uint16_t cnt; uint16_t req_cnt; uint16_t tot_dsds; - device_reg_t __iomem *reg; - char tag[2]; + struct device_reg_2xxx __iomem *reg; /* Setup device pointers. */ ret = 0; ha = sp->ha; - reg = ha->iobase; + pha = to_qla_parent(ha); + reg = &ha->iobase->isp; cmd = sp->cmd; + /* So we know we haven't pci_map'ed anything yet */ + tot_dsds = 0; /* Send marker if required */ if (ha->marker_needed != 0) { @@ -355,7 +298,7 @@ qla2x00_start_scsi(srb_t *sp) } /* Acquire ring specific lock */ - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock_irqsave(&pha->hardware_lock, flags); /* Check for room in outstanding command list. */ handle = ha->current_outstanding_cmd; @@ -363,14 +306,25 @@ qla2x00_start_scsi(srb_t *sp) handle++; if (handle == MAX_OUTSTANDING_COMMANDS) handle = 1; - if (ha->outstanding_cmds[handle] == 0) + if (!ha->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; + /* Calculate the number of request entries needed. */ - req_cnt = (ha->calc_request_entries)(cmd->request->nr_hw_segments); + req_cnt = ha->isp_ops->calc_req_entries(tot_dsds); if (ha->req_q_cnt < (req_cnt + 2)) { cnt = RD_REG_WORD_RELAXED(ISP_REQ_Q_OUT(ha, reg)); if (ha->req_ring_index < cnt) @@ -382,19 +336,6 @@ qla2x00_start_scsi(srb_t *sp) if (ha->req_q_cnt < (req_cnt + 2)) goto queuing_error; - /* Finally, we have enough space, now perform mappings. */ - tot_dsds = 0; - if (cmd->use_sg) { - sg = (struct scatterlist *) cmd->request_buffer; - tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg, - cmd->sc_data_direction); - if (tot_dsds == 0) - goto queuing_error; - } else if (cmd->request_bufflen) { - tot_dsds++; - } - req_cnt = (ha->calc_request_entries)(tot_dsds); - /* Build command packet */ ha->current_outstanding_cmd = handle; ha->outstanding_cmds[handle] = sp; @@ -415,25 +356,13 @@ qla2x00_start_scsi(srb_t *sp) /* Update tagged queuing modifier */ cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG); - if (scsi_populate_tag_msg(cmd, tag)) { - switch (tag[0]) { - case MSG_HEAD_TAG: - cmd_pkt->control_flags = - __constant_cpu_to_le16(CF_HEAD_TAG); - break; - case MSG_ORDERED_TAG: - cmd_pkt->control_flags = - __constant_cpu_to_le16(CF_ORDERED_TAG); - break; - } - } /* Load SCSI command packet. */ memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len); - cmd_pkt->byte_count = cpu_to_le32((uint32_t)cmd->request_bufflen); + cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); /* Build IOCB segments */ - (ha->build_scsi_iocbs)(sp, cmd_pkt, tot_dsds); + ha->isp_ops->build_iocbs(sp, cmd_pkt, tot_dsds); /* Set total data segment count. */ cmd_pkt->entry_count = (uint8_t)req_cnt; @@ -447,21 +376,25 @@ qla2x00_start_scsi(srb_t *sp) } else ha->request_ring_ptr++; - ha->actthreads++; - ha->total_ios++; sp->flags |= SRB_DMA_VALID; - sp->state = SRB_ACTIVE_STATE; - sp->u_start = jiffies; /* Set chip new ring index. */ WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), ha->req_ring_index); RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, reg)); /* PCI Posting. */ - spin_unlock_irqrestore(&ha->hardware_lock, flags); + /* Manage unprocessed RIO/ZIO commands in response queue. */ + if (ha->flags.process_response_queue && + ha->response_ring_ptr->signature != RESPONSE_PROCESSED) + qla2x00_process_response_queue(ha); + + spin_unlock_irqrestore(&pha->hardware_lock, flags); return (QLA_SUCCESS); queuing_error: - spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (tot_dsds) + scsi_dma_unmap(cmd); + + spin_unlock_irqrestore(&pha->hardware_lock, flags); return (QLA_FUNCTION_FAILED); } @@ -481,40 +414,52 @@ int __qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun, uint8_t type) { - mrk_entry_t *pkt; + mrk_entry_t *mrk; + struct mrk_entry_24xx *mrk24; + scsi_qla_host_t *pha = to_qla_parent(ha); - pkt = (mrk_entry_t *)qla2x00_req_pkt(ha); - if (pkt == NULL) { - DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__)); + mrk24 = NULL; + mrk = (mrk_entry_t *)qla2x00_req_pkt(pha); + if (mrk == NULL) { + DEBUG2_3(printk("%s(%ld): failed to allocate Marker IOCB.\n", + __func__, ha->host_no)); return (QLA_FUNCTION_FAILED); } - pkt->entry_type = MARKER_TYPE; - pkt->modifier = type; - + mrk->entry_type = MARKER_TYPE; + mrk->modifier = type; if (type != MK_SYNC_ALL) { - pkt->lun = cpu_to_le16(lun); - SET_TARGET_ID(ha, pkt->target, loop_id); + if (IS_FWI2_CAPABLE(ha)) { + mrk24 = (struct mrk_entry_24xx *) mrk; + mrk24->nport_handle = cpu_to_le16(loop_id); + mrk24->lun[1] = LSB(lun); + mrk24->lun[2] = MSB(lun); + host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun)); + mrk24->vp_index = ha->vp_idx; + } else { + SET_TARGET_ID(ha, mrk->target, loop_id); + mrk->lun = cpu_to_le16(lun); + } } wmb(); - /* Issue command to ISP */ - qla2x00_isp_cmd(ha); + qla2x00_isp_cmd(pha); return (QLA_SUCCESS); } -int +int qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun, uint8_t type) { int ret; unsigned long flags = 0; + scsi_qla_host_t *pha = to_qla_parent(ha); - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock_irqsave(&pha->hardware_lock, flags); ret = __qla2x00_marker(ha, loop_id, lun, type); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock_irqrestore(&pha->hardware_lock, flags); return (ret); } @@ -541,7 +486,12 @@ qla2x00_req_pkt(scsi_qla_host_t *ha) for (timer = HZ; timer; timer--) { if ((req_cnt + 2) >= ha->req_q_cnt) { /* Calculate number of free request entries. */ - cnt = qla2x00_debounce_register(ISP_REQ_Q_OUT(ha, reg)); + if (IS_FWI2_CAPABLE(ha)) + cnt = (uint16_t)RD_REG_DWORD( + ®->isp24.req_q_out); + else + cnt = qla2x00_debounce_register( + ISP_REQ_Q_OUT(ha, ®->isp)); if (ha->req_ring_index < cnt) ha->req_q_cnt = cnt - ha->req_ring_index; else @@ -574,7 +524,7 @@ qla2x00_req_pkt(scsi_qla_host_t *ha) /* Check for pending interrupts. */ /* During init we issue marker directly */ - if (!ha->marker_needed) + if (!ha->marker_needed && !ha->flags.init_done) qla2x00_poll(ha); spin_lock_irq(&ha->hardware_lock); @@ -592,7 +542,7 @@ qla2x00_req_pkt(scsi_qla_host_t *ha) * * Note: The caller must hold the hardware lock before calling this routine. */ -void +static void qla2x00_isp_cmd(scsi_qla_host_t *ha) { device_reg_t __iomem *reg = ha->iobase; @@ -610,6 +560,252 @@ qla2x00_isp_cmd(scsi_qla_host_t *ha) ha->request_ring_ptr++; /* Set chip new ring index. */ - WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), ha->req_ring_index); - RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, reg)); /* PCI Posting. */ + if (IS_FWI2_CAPABLE(ha)) { + WRT_REG_DWORD(®->isp24.req_q_in, ha->req_ring_index); + RD_REG_DWORD_RELAXED(®->isp24.req_q_in); + } else { + WRT_REG_WORD(ISP_REQ_Q_IN(ha, ®->isp), ha->req_ring_index); + RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, ®->isp)); + } + +} + +/** + * qla24xx_calc_iocbs() - Determine number of Command Type 3 and + * Continuation Type 1 IOCBs to allocate. + * + * @dsds: number of data segment decriptors needed + * + * Returns the number of IOCB entries needed to store @dsds. + */ +static inline uint16_t +qla24xx_calc_iocbs(uint16_t dsds) +{ + uint16_t iocbs; + + iocbs = 1; + if (dsds > 1) { + iocbs += (dsds - 1) / 5; + if ((dsds - 1) % 5) + iocbs++; + } + return iocbs; +} + +/** + * qla24xx_build_scsi_iocbs() - Build IOCB command utilizing Command Type 7 + * IOCB types. + * + * @sp: SRB command to process + * @cmd_pkt: Command type 3 IOCB + * @tot_dsds: Total number of segments to transfer + */ +static inline void +qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, + uint16_t tot_dsds) +{ + uint16_t avail_dsds; + uint32_t *cur_dsd; + scsi_qla_host_t *ha; + struct scsi_cmnd *cmd; + struct scatterlist *sg; + int i; + + cmd = sp->cmd; + + /* Update entry type to indicate Command Type 3 IOCB */ + *((uint32_t *)(&cmd_pkt->entry_type)) = + __constant_cpu_to_le32(COMMAND_TYPE_7); + + /* No data transfer */ + if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { + cmd_pkt->byte_count = __constant_cpu_to_le32(0); + return; + } + + ha = sp->ha; + + /* Set transfer direction */ + if (cmd->sc_data_direction == DMA_TO_DEVICE) + cmd_pkt->task_mgmt_flags = + __constant_cpu_to_le16(TMF_WRITE_DATA); + else if (cmd->sc_data_direction == DMA_FROM_DEVICE) + cmd_pkt->task_mgmt_flags = + __constant_cpu_to_le16(TMF_READ_DATA); + + /* One DSD is available in the Command Type 3 IOCB */ + avail_dsds = 1; + cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address; + + /* Load data segments */ + + scsi_for_each_sg(cmd, sg, tot_dsds, i) { + 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 Continuation + * Type 1 IOCB. + */ + cont_pkt = qla2x00_prep_cont_type1_iocb(ha); + cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; + avail_dsds = 5; + } + + 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)); + avail_dsds--; + } +} + + +/** + * qla24xx_start_scsi() - Send a SCSI command to the ISP + * @sp: command to send to the ISP + * + * Returns non-zero if a failure occured, else zero. + */ +int +qla24xx_start_scsi(srb_t *sp) +{ + int ret, nseg; + unsigned long flags; + scsi_qla_host_t *ha, *pha; + struct scsi_cmnd *cmd; + uint32_t *clr_ptr; + uint32_t index; + uint32_t handle; + struct cmd_type_7 *cmd_pkt; + uint16_t cnt; + uint16_t req_cnt; + uint16_t tot_dsds; + struct device_reg_24xx __iomem *reg; + + /* Setup device pointers. */ + ret = 0; + ha = sp->ha; + pha = to_qla_parent(ha); + reg = &ha->iobase->isp24; + cmd = sp->cmd; + /* So we know we haven't pci_map'ed anything yet */ + tot_dsds = 0; + + /* Send marker if required */ + if (ha->marker_needed != 0) { + if (qla2x00_marker(ha, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) { + return QLA_FUNCTION_FAILED; + } + ha->marker_needed = 0; + } + + /* Acquire ring specific lock */ + spin_lock_irqsave(&pha->hardware_lock, flags); + + /* Check for room in outstanding command list. */ + handle = ha->current_outstanding_cmd; + for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { + handle++; + if (handle == MAX_OUTSTANDING_COMMANDS) + handle = 1; + if (!ha->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; + + req_cnt = qla24xx_calc_iocbs(tot_dsds); + if (ha->req_q_cnt < (req_cnt + 2)) { + cnt = (uint16_t)RD_REG_DWORD_RELAXED(®->req_q_out); + if (ha->req_ring_index < cnt) + ha->req_q_cnt = cnt - ha->req_ring_index; + else + ha->req_q_cnt = ha->request_q_length - + (ha->req_ring_index - cnt); + } + if (ha->req_q_cnt < (req_cnt + 2)) + goto queuing_error; + + /* Build command packet. */ + ha->current_outstanding_cmd = handle; + ha->outstanding_cmds[handle] = sp; + sp->ha = ha; + sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle; + ha->req_q_cnt -= req_cnt; + + cmd_pkt = (struct cmd_type_7 *)ha->request_ring_ptr; + cmd_pkt->handle = 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)); + + /* 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; + wmb(); + + /* Adjust ring index. */ + ha->req_ring_index++; + if (ha->req_ring_index == ha->request_q_length) { + ha->req_ring_index = 0; + ha->request_ring_ptr = ha->request_ring; + } else + ha->request_ring_ptr++; + + sp->flags |= SRB_DMA_VALID; + + /* Set chip new ring index. */ + WRT_REG_DWORD(®->req_q_in, ha->req_ring_index); + RD_REG_DWORD_RELAXED(®->req_q_in); /* PCI Posting. */ + + /* Manage unprocessed RIO/ZIO commands in response queue. */ + if (ha->flags.process_response_queue && + ha->response_ring_ptr->signature != RESPONSE_PROCESSED) + qla24xx_process_response_queue(ha); + + spin_unlock_irqrestore(&pha->hardware_lock, flags); + return QLA_SUCCESS; + +queuing_error: + if (tot_dsds) + scsi_dma_unmap(cmd); + + spin_unlock_irqrestore(&pha->hardware_lock, flags); + + return QLA_FUNCTION_FAILED; }