+ /* Setup device pointers. */
+ ret = 0;
+ ha = sp->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(&ha->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] == 0)
+ break;
+ }
+ if (index == MAX_OUTSTANDING_COMMANDS)
+ goto queuing_error;
+
+ /* Map the sg table so we have an accurate count of sg entries needed */
+ 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) {
+ dma_addr_t req_dma;
+
+ req_dma = pci_map_single(ha->pdev, cmd->request_buffer,
+ cmd->request_bufflen, cmd->sc_data_direction);
+ if (dma_mapping_error(req_dma))
+ goto queuing_error;
+
+ sp->dma_handle = req_dma;
+ tot_dsds = 1;
+ }
+
+ 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;
+
+ 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)cmd->request_bufflen);
+
+ /* 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();