1afaf5a2dSDavid Somayajulu /* 2afaf5a2dSDavid Somayajulu * QLogic iSCSI HBA Driver 3afaf5a2dSDavid Somayajulu * Copyright (c) 2003-2006 QLogic Corporation 4afaf5a2dSDavid Somayajulu * 5afaf5a2dSDavid Somayajulu * See LICENSE.qla4xxx for copyright and licensing details. 6afaf5a2dSDavid Somayajulu */ 7afaf5a2dSDavid Somayajulu 8afaf5a2dSDavid Somayajulu #include "ql4_def.h" 9e08c182cSDavid C Somayajulu #include "ql4_glbl.h" 10e08c182cSDavid C Somayajulu #include "ql4_dbg.h" 11e08c182cSDavid C Somayajulu #include "ql4_inline.h" 12e08c182cSDavid C Somayajulu 13afaf5a2dSDavid Somayajulu #include <scsi/scsi_tcq.h> 14afaf5a2dSDavid Somayajulu 1516ed55f9SKaren Higgins static int 1616ed55f9SKaren Higgins qla4xxx_space_in_req_ring(struct scsi_qla_host *ha, uint16_t req_cnt) 1716ed55f9SKaren Higgins { 1816ed55f9SKaren Higgins uint16_t cnt; 1916ed55f9SKaren Higgins 2016ed55f9SKaren Higgins /* Calculate number of free request entries. */ 2116ed55f9SKaren Higgins if ((req_cnt + 2) >= ha->req_q_count) { 22b173a132SVikas Chaudhary cnt = (uint16_t) ha->isp_ops->rd_shdw_req_q_out(ha); 2316ed55f9SKaren Higgins if (ha->request_in < cnt) 2416ed55f9SKaren Higgins ha->req_q_count = cnt - ha->request_in; 2516ed55f9SKaren Higgins else 2616ed55f9SKaren Higgins ha->req_q_count = REQUEST_QUEUE_DEPTH - 2716ed55f9SKaren Higgins (ha->request_in - cnt); 2816ed55f9SKaren Higgins } 2916ed55f9SKaren Higgins 3016ed55f9SKaren Higgins /* Check if room for request in request ring. */ 3116ed55f9SKaren Higgins if ((req_cnt + 2) < ha->req_q_count) 3216ed55f9SKaren Higgins return 1; 3316ed55f9SKaren Higgins else 3416ed55f9SKaren Higgins return 0; 3516ed55f9SKaren Higgins } 3616ed55f9SKaren Higgins 3716ed55f9SKaren Higgins static void qla4xxx_advance_req_ring_ptr(struct scsi_qla_host *ha) 3816ed55f9SKaren Higgins { 3916ed55f9SKaren Higgins /* Advance request queue pointer */ 4016ed55f9SKaren Higgins if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) { 4116ed55f9SKaren Higgins ha->request_in = 0; 4216ed55f9SKaren Higgins ha->request_ptr = ha->request_ring; 4316ed55f9SKaren Higgins } else { 4416ed55f9SKaren Higgins ha->request_in++; 4516ed55f9SKaren Higgins ha->request_ptr++; 4616ed55f9SKaren Higgins } 4716ed55f9SKaren Higgins } 4816ed55f9SKaren Higgins 49afaf5a2dSDavid Somayajulu /** 50afaf5a2dSDavid Somayajulu * qla4xxx_get_req_pkt - returns a valid entry in request queue. 51afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 52afaf5a2dSDavid Somayajulu * @queue_entry: Pointer to pointer to queue entry structure 53afaf5a2dSDavid Somayajulu * 54afaf5a2dSDavid Somayajulu * This routine performs the following tasks: 55afaf5a2dSDavid Somayajulu * - returns the current request_in pointer (if queue not full) 56afaf5a2dSDavid Somayajulu * - advances the request_in pointer 57afaf5a2dSDavid Somayajulu * - checks for queue full 58afaf5a2dSDavid Somayajulu **/ 5947975477SAdrian Bunk static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha, 60afaf5a2dSDavid Somayajulu struct queue_entry **queue_entry) 61afaf5a2dSDavid Somayajulu { 6216ed55f9SKaren Higgins uint16_t req_cnt = 1; 63afaf5a2dSDavid Somayajulu 6416ed55f9SKaren Higgins if (qla4xxx_space_in_req_ring(ha, req_cnt)) { 65afaf5a2dSDavid Somayajulu *queue_entry = ha->request_ptr; 66afaf5a2dSDavid Somayajulu memset(*queue_entry, 0, sizeof(**queue_entry)); 6716ed55f9SKaren Higgins 6816ed55f9SKaren Higgins qla4xxx_advance_req_ring_ptr(ha); 6916ed55f9SKaren Higgins ha->req_q_count -= req_cnt; 7016ed55f9SKaren Higgins return QLA_SUCCESS; 71afaf5a2dSDavid Somayajulu } 72afaf5a2dSDavid Somayajulu 7316ed55f9SKaren Higgins return QLA_ERROR; 74afaf5a2dSDavid Somayajulu } 75afaf5a2dSDavid Somayajulu 76afaf5a2dSDavid Somayajulu /** 77afaf5a2dSDavid Somayajulu * qla4xxx_send_marker_iocb - issues marker iocb to HBA 78afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 79afaf5a2dSDavid Somayajulu * @ddb_entry: Pointer to device database entry 80afaf5a2dSDavid Somayajulu * @lun: SCSI LUN 81afaf5a2dSDavid Somayajulu * @marker_type: marker identifier 82afaf5a2dSDavid Somayajulu * 83afaf5a2dSDavid Somayajulu * This routine issues a marker IOCB. 84afaf5a2dSDavid Somayajulu **/ 859d562913SDavid C Somayajulu int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, 869d562913SDavid C Somayajulu struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod) 87afaf5a2dSDavid Somayajulu { 881c3f0b8eSMathieu Desnoyers struct qla4_marker_entry *marker_entry; 89afaf5a2dSDavid Somayajulu unsigned long flags = 0; 90afaf5a2dSDavid Somayajulu uint8_t status = QLA_SUCCESS; 91afaf5a2dSDavid Somayajulu 92afaf5a2dSDavid Somayajulu /* Acquire hardware specific lock */ 93afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 94afaf5a2dSDavid Somayajulu 95afaf5a2dSDavid Somayajulu /* Get pointer to the queue entry for the marker */ 96afaf5a2dSDavid Somayajulu if (qla4xxx_get_req_pkt(ha, (struct queue_entry **) &marker_entry) != 97afaf5a2dSDavid Somayajulu QLA_SUCCESS) { 98afaf5a2dSDavid Somayajulu status = QLA_ERROR; 99afaf5a2dSDavid Somayajulu goto exit_send_marker; 100afaf5a2dSDavid Somayajulu } 101afaf5a2dSDavid Somayajulu 102afaf5a2dSDavid Somayajulu /* Put the marker in the request queue */ 103afaf5a2dSDavid Somayajulu marker_entry->hdr.entryType = ET_MARKER; 104afaf5a2dSDavid Somayajulu marker_entry->hdr.entryCount = 1; 105afaf5a2dSDavid Somayajulu marker_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index); 1069d562913SDavid C Somayajulu marker_entry->modifier = cpu_to_le16(mrkr_mod); 107afaf5a2dSDavid Somayajulu int_to_scsilun(lun, &marker_entry->lun); 108afaf5a2dSDavid Somayajulu wmb(); 109afaf5a2dSDavid Somayajulu 110afaf5a2dSDavid Somayajulu /* Tell ISP it's got a new I/O request */ 111f4f5df23SVikas Chaudhary ha->isp_ops->queue_iocb(ha); 112afaf5a2dSDavid Somayajulu 113afaf5a2dSDavid Somayajulu exit_send_marker: 114afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 115afaf5a2dSDavid Somayajulu return status; 116afaf5a2dSDavid Somayajulu } 117afaf5a2dSDavid Somayajulu 11816ed55f9SKaren Higgins static struct continuation_t1_entry * 11916ed55f9SKaren Higgins qla4xxx_alloc_cont_entry(struct scsi_qla_host *ha) 120afaf5a2dSDavid Somayajulu { 121afaf5a2dSDavid Somayajulu struct continuation_t1_entry *cont_entry; 122afaf5a2dSDavid Somayajulu 123afaf5a2dSDavid Somayajulu cont_entry = (struct continuation_t1_entry *)ha->request_ptr; 124afaf5a2dSDavid Somayajulu 12516ed55f9SKaren Higgins qla4xxx_advance_req_ring_ptr(ha); 126afaf5a2dSDavid Somayajulu 127afaf5a2dSDavid Somayajulu /* Load packet defaults */ 128afaf5a2dSDavid Somayajulu cont_entry->hdr.entryType = ET_CONTINUE; 129afaf5a2dSDavid Somayajulu cont_entry->hdr.entryCount = 1; 130afaf5a2dSDavid Somayajulu cont_entry->hdr.systemDefined = (uint8_t) cpu_to_le16(ha->request_in); 131afaf5a2dSDavid Somayajulu 132afaf5a2dSDavid Somayajulu return cont_entry; 133afaf5a2dSDavid Somayajulu } 134afaf5a2dSDavid Somayajulu 13547975477SAdrian Bunk static uint16_t qla4xxx_calc_request_entries(uint16_t dsds) 136afaf5a2dSDavid Somayajulu { 137afaf5a2dSDavid Somayajulu uint16_t iocbs; 138afaf5a2dSDavid Somayajulu 139afaf5a2dSDavid Somayajulu iocbs = 1; 140afaf5a2dSDavid Somayajulu if (dsds > COMMAND_SEG) { 141afaf5a2dSDavid Somayajulu iocbs += (dsds - COMMAND_SEG) / CONTINUE_SEG; 142afaf5a2dSDavid Somayajulu if ((dsds - COMMAND_SEG) % CONTINUE_SEG) 143afaf5a2dSDavid Somayajulu iocbs++; 144afaf5a2dSDavid Somayajulu } 145afaf5a2dSDavid Somayajulu return iocbs; 146afaf5a2dSDavid Somayajulu } 147afaf5a2dSDavid Somayajulu 14847975477SAdrian Bunk static void qla4xxx_build_scsi_iocbs(struct srb *srb, 149afaf5a2dSDavid Somayajulu struct command_t3_entry *cmd_entry, 150afaf5a2dSDavid Somayajulu uint16_t tot_dsds) 151afaf5a2dSDavid Somayajulu { 152afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha; 153afaf5a2dSDavid Somayajulu uint16_t avail_dsds; 154afaf5a2dSDavid Somayajulu struct data_seg_a64 *cur_dsd; 155afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd; 1565f7186c8SFUJITA Tomonori struct scatterlist *sg; 1575f7186c8SFUJITA Tomonori int i; 158afaf5a2dSDavid Somayajulu 159afaf5a2dSDavid Somayajulu cmd = srb->cmd; 160afaf5a2dSDavid Somayajulu ha = srb->ha; 161afaf5a2dSDavid Somayajulu 1625f7186c8SFUJITA Tomonori if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { 163afaf5a2dSDavid Somayajulu /* No data being transferred */ 164afaf5a2dSDavid Somayajulu cmd_entry->ttlByteCnt = __constant_cpu_to_le32(0); 165afaf5a2dSDavid Somayajulu return; 166afaf5a2dSDavid Somayajulu } 167afaf5a2dSDavid Somayajulu 168afaf5a2dSDavid Somayajulu avail_dsds = COMMAND_SEG; 169afaf5a2dSDavid Somayajulu cur_dsd = (struct data_seg_a64 *) & (cmd_entry->dataseg[0]); 170afaf5a2dSDavid Somayajulu 1715f7186c8SFUJITA Tomonori scsi_for_each_sg(cmd, sg, tot_dsds, i) { 172afaf5a2dSDavid Somayajulu dma_addr_t sle_dma; 173afaf5a2dSDavid Somayajulu 174afaf5a2dSDavid Somayajulu /* Allocate additional continuation packets? */ 175afaf5a2dSDavid Somayajulu if (avail_dsds == 0) { 176afaf5a2dSDavid Somayajulu struct continuation_t1_entry *cont_entry; 177afaf5a2dSDavid Somayajulu 178afaf5a2dSDavid Somayajulu cont_entry = qla4xxx_alloc_cont_entry(ha); 179afaf5a2dSDavid Somayajulu cur_dsd = 180afaf5a2dSDavid Somayajulu (struct data_seg_a64 *) 181afaf5a2dSDavid Somayajulu &cont_entry->dataseg[0]; 182afaf5a2dSDavid Somayajulu avail_dsds = CONTINUE_SEG; 183afaf5a2dSDavid Somayajulu } 184afaf5a2dSDavid Somayajulu 1855f7186c8SFUJITA Tomonori sle_dma = sg_dma_address(sg); 186afaf5a2dSDavid Somayajulu cur_dsd->base.addrLow = cpu_to_le32(LSDW(sle_dma)); 187afaf5a2dSDavid Somayajulu cur_dsd->base.addrHigh = cpu_to_le32(MSDW(sle_dma)); 1885f7186c8SFUJITA Tomonori cur_dsd->count = cpu_to_le32(sg_dma_len(sg)); 189afaf5a2dSDavid Somayajulu avail_dsds--; 190afaf5a2dSDavid Somayajulu 191afaf5a2dSDavid Somayajulu cur_dsd++; 192afaf5a2dSDavid Somayajulu } 193afaf5a2dSDavid Somayajulu } 194afaf5a2dSDavid Somayajulu 195afaf5a2dSDavid Somayajulu /** 196f4f5df23SVikas Chaudhary * qla4_8xxx_queue_iocb - Tell ISP it's got new request(s) 197f4f5df23SVikas Chaudhary * @ha: pointer to host adapter structure. 198f4f5df23SVikas Chaudhary * 199f4f5df23SVikas Chaudhary * This routine notifies the ISP that one or more new request 200f4f5df23SVikas Chaudhary * queue entries have been placed on the request queue. 201f4f5df23SVikas Chaudhary **/ 202f4f5df23SVikas Chaudhary void qla4_8xxx_queue_iocb(struct scsi_qla_host *ha) 203f4f5df23SVikas Chaudhary { 204f4f5df23SVikas Chaudhary uint32_t dbval = 0; 205f4f5df23SVikas Chaudhary unsigned long wtime; 206f4f5df23SVikas Chaudhary 207f4f5df23SVikas Chaudhary dbval = 0x14 | (ha->func_num << 5); 208f4f5df23SVikas Chaudhary dbval = dbval | (0 << 8) | (ha->request_in << 16); 209f4f5df23SVikas Chaudhary writel(dbval, (unsigned long __iomem *)ha->nx_db_wr_ptr); 210f4f5df23SVikas Chaudhary wmb(); 211f4f5df23SVikas Chaudhary 212f4f5df23SVikas Chaudhary wtime = jiffies + (2 * HZ); 213f4f5df23SVikas Chaudhary while (readl((void __iomem *)ha->nx_db_rd_ptr) != dbval && 214f4f5df23SVikas Chaudhary !time_after_eq(jiffies, wtime)) { 215f4f5df23SVikas Chaudhary writel(dbval, (unsigned long __iomem *)ha->nx_db_wr_ptr); 216f4f5df23SVikas Chaudhary wmb(); 217f4f5df23SVikas Chaudhary } 218f4f5df23SVikas Chaudhary } 219f4f5df23SVikas Chaudhary 220f4f5df23SVikas Chaudhary /** 221f4f5df23SVikas Chaudhary * qla4_8xxx_complete_iocb - Tell ISP we're done with response(s) 222f4f5df23SVikas Chaudhary * @ha: pointer to host adapter structure. 223f4f5df23SVikas Chaudhary * 224f4f5df23SVikas Chaudhary * This routine notifies the ISP that one or more response/completion 225f4f5df23SVikas Chaudhary * queue entries have been processed by the driver. 226f4f5df23SVikas Chaudhary * This also clears the interrupt. 227f4f5df23SVikas Chaudhary **/ 228f4f5df23SVikas Chaudhary void qla4_8xxx_complete_iocb(struct scsi_qla_host *ha) 229f4f5df23SVikas Chaudhary { 230f4f5df23SVikas Chaudhary writel(ha->response_out, &ha->qla4_8xxx_reg->rsp_q_out); 231f4f5df23SVikas Chaudhary readl(&ha->qla4_8xxx_reg->rsp_q_out); 232f4f5df23SVikas Chaudhary } 233f4f5df23SVikas Chaudhary 234f4f5df23SVikas Chaudhary /** 235f4f5df23SVikas Chaudhary * qla4xxx_queue_iocb - Tell ISP it's got new request(s) 236f4f5df23SVikas Chaudhary * @ha: pointer to host adapter structure. 237f4f5df23SVikas Chaudhary * 238f4f5df23SVikas Chaudhary * This routine is notifies the ISP that one or more new request 239f4f5df23SVikas Chaudhary * queue entries have been placed on the request queue. 240f4f5df23SVikas Chaudhary **/ 241f4f5df23SVikas Chaudhary void qla4xxx_queue_iocb(struct scsi_qla_host *ha) 242f4f5df23SVikas Chaudhary { 243f4f5df23SVikas Chaudhary writel(ha->request_in, &ha->reg->req_q_in); 244f4f5df23SVikas Chaudhary readl(&ha->reg->req_q_in); 245f4f5df23SVikas Chaudhary } 246f4f5df23SVikas Chaudhary 247f4f5df23SVikas Chaudhary /** 248f4f5df23SVikas Chaudhary * qla4xxx_complete_iocb - Tell ISP we're done with response(s) 249f4f5df23SVikas Chaudhary * @ha: pointer to host adapter structure. 250f4f5df23SVikas Chaudhary * 251f4f5df23SVikas Chaudhary * This routine is notifies the ISP that one or more response/completion 252f4f5df23SVikas Chaudhary * queue entries have been processed by the driver. 253f4f5df23SVikas Chaudhary * This also clears the interrupt. 254f4f5df23SVikas Chaudhary **/ 255f4f5df23SVikas Chaudhary void qla4xxx_complete_iocb(struct scsi_qla_host *ha) 256f4f5df23SVikas Chaudhary { 257f4f5df23SVikas Chaudhary writel(ha->response_out, &ha->reg->rsp_q_out); 258f4f5df23SVikas Chaudhary readl(&ha->reg->rsp_q_out); 259f4f5df23SVikas Chaudhary } 260f4f5df23SVikas Chaudhary 261f4f5df23SVikas Chaudhary /** 262afaf5a2dSDavid Somayajulu * qla4xxx_send_command_to_isp - issues command to HBA 263afaf5a2dSDavid Somayajulu * @ha: pointer to host adapter structure. 264afaf5a2dSDavid Somayajulu * @srb: pointer to SCSI Request Block to be sent to ISP 265afaf5a2dSDavid Somayajulu * 266afaf5a2dSDavid Somayajulu * This routine is called by qla4xxx_queuecommand to build an ISP 267afaf5a2dSDavid Somayajulu * command and pass it to the ISP for execution. 268afaf5a2dSDavid Somayajulu **/ 269afaf5a2dSDavid Somayajulu int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) 270afaf5a2dSDavid Somayajulu { 271afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd = srb->cmd; 272afaf5a2dSDavid Somayajulu struct ddb_entry *ddb_entry; 273afaf5a2dSDavid Somayajulu struct command_t3_entry *cmd_entry; 2745f7186c8SFUJITA Tomonori int nseg; 275afaf5a2dSDavid Somayajulu uint16_t tot_dsds; 276afaf5a2dSDavid Somayajulu uint16_t req_cnt; 277afaf5a2dSDavid Somayajulu unsigned long flags; 278afaf5a2dSDavid Somayajulu uint32_t index; 279afaf5a2dSDavid Somayajulu char tag[2]; 280afaf5a2dSDavid Somayajulu 281afaf5a2dSDavid Somayajulu /* Get real lun and adapter */ 282afaf5a2dSDavid Somayajulu ddb_entry = srb->ddb; 283afaf5a2dSDavid Somayajulu 284afaf5a2dSDavid Somayajulu tot_dsds = 0; 285afaf5a2dSDavid Somayajulu 286afaf5a2dSDavid Somayajulu /* Acquire hardware specific lock */ 287afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 288afaf5a2dSDavid Somayajulu 289afaf5a2dSDavid Somayajulu index = (uint32_t)cmd->request->tag; 290afaf5a2dSDavid Somayajulu 29116ed55f9SKaren Higgins /* 29216ed55f9SKaren Higgins * Check to see if adapter is online before placing request on 29316ed55f9SKaren Higgins * request queue. If a reset occurs and a request is in the queue, 29416ed55f9SKaren Higgins * the firmware will still attempt to process the request, retrieving 29516ed55f9SKaren Higgins * garbage for pointers. 29616ed55f9SKaren Higgins */ 29716ed55f9SKaren Higgins if (!test_bit(AF_ONLINE, &ha->flags)) { 29816ed55f9SKaren Higgins DEBUG2(printk("scsi%ld: %s: Adapter OFFLINE! " 29916ed55f9SKaren Higgins "Do not issue command.\n", 30016ed55f9SKaren Higgins ha->host_no, __func__)); 30116ed55f9SKaren Higgins goto queuing_error; 30216ed55f9SKaren Higgins } 30316ed55f9SKaren Higgins 304afaf5a2dSDavid Somayajulu /* Calculate the number of request entries needed. */ 3055f7186c8SFUJITA Tomonori nseg = scsi_dma_map(cmd); 3065f7186c8SFUJITA Tomonori if (nseg < 0) 307afaf5a2dSDavid Somayajulu goto queuing_error; 3085f7186c8SFUJITA Tomonori tot_dsds = nseg; 309afaf5a2dSDavid Somayajulu 310afaf5a2dSDavid Somayajulu req_cnt = qla4xxx_calc_request_entries(tot_dsds); 31116ed55f9SKaren Higgins if (!qla4xxx_space_in_req_ring(ha, req_cnt)) 312afaf5a2dSDavid Somayajulu goto queuing_error; 313afaf5a2dSDavid Somayajulu 314afaf5a2dSDavid Somayajulu /* total iocbs active */ 315afaf5a2dSDavid Somayajulu if ((ha->iocb_cnt + req_cnt) >= REQUEST_QUEUE_DEPTH) 316afaf5a2dSDavid Somayajulu goto queuing_error; 317afaf5a2dSDavid Somayajulu 318afaf5a2dSDavid Somayajulu /* Build command packet */ 319afaf5a2dSDavid Somayajulu cmd_entry = (struct command_t3_entry *) ha->request_ptr; 320afaf5a2dSDavid Somayajulu memset(cmd_entry, 0, sizeof(struct command_t3_entry)); 321afaf5a2dSDavid Somayajulu cmd_entry->hdr.entryType = ET_COMMAND; 322afaf5a2dSDavid Somayajulu cmd_entry->handle = cpu_to_le32(index); 323afaf5a2dSDavid Somayajulu cmd_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index); 324afaf5a2dSDavid Somayajulu cmd_entry->connection_id = cpu_to_le16(ddb_entry->connection_id); 325afaf5a2dSDavid Somayajulu 326afaf5a2dSDavid Somayajulu int_to_scsilun(cmd->device->lun, &cmd_entry->lun); 327afaf5a2dSDavid Somayajulu cmd_entry->cmdSeqNum = cpu_to_le32(ddb_entry->CmdSn); 3285f7186c8SFUJITA Tomonori cmd_entry->ttlByteCnt = cpu_to_le32(scsi_bufflen(cmd)); 329afaf5a2dSDavid Somayajulu memcpy(cmd_entry->cdb, cmd->cmnd, cmd->cmd_len); 330afaf5a2dSDavid Somayajulu cmd_entry->dataSegCnt = cpu_to_le16(tot_dsds); 331afaf5a2dSDavid Somayajulu cmd_entry->hdr.entryCount = req_cnt; 332afaf5a2dSDavid Somayajulu 333afaf5a2dSDavid Somayajulu /* Set data transfer direction control flags 334afaf5a2dSDavid Somayajulu * NOTE: Look at data_direction bits iff there is data to be 335afaf5a2dSDavid Somayajulu * transferred, as the data direction bit is sometimed filled 336afaf5a2dSDavid Somayajulu * in when there is no data to be transferred */ 337afaf5a2dSDavid Somayajulu cmd_entry->control_flags = CF_NO_DATA; 3385f7186c8SFUJITA Tomonori if (scsi_bufflen(cmd)) { 339afaf5a2dSDavid Somayajulu if (cmd->sc_data_direction == DMA_TO_DEVICE) 340afaf5a2dSDavid Somayajulu cmd_entry->control_flags = CF_WRITE; 341afaf5a2dSDavid Somayajulu else if (cmd->sc_data_direction == DMA_FROM_DEVICE) 342afaf5a2dSDavid Somayajulu cmd_entry->control_flags = CF_READ; 343d915058fSDavid C Somayajulu 3445f7186c8SFUJITA Tomonori ha->bytes_xfered += scsi_bufflen(cmd); 345d915058fSDavid C Somayajulu if (ha->bytes_xfered & ~0xFFFFF){ 346d915058fSDavid C Somayajulu ha->total_mbytes_xferred += ha->bytes_xfered >> 20; 347d915058fSDavid C Somayajulu ha->bytes_xfered &= 0xFFFFF; 348d915058fSDavid C Somayajulu } 349afaf5a2dSDavid Somayajulu } 350afaf5a2dSDavid Somayajulu 351afaf5a2dSDavid Somayajulu /* Set tagged queueing control flags */ 352afaf5a2dSDavid Somayajulu cmd_entry->control_flags |= CF_SIMPLE_TAG; 353afaf5a2dSDavid Somayajulu if (scsi_populate_tag_msg(cmd, tag)) 354afaf5a2dSDavid Somayajulu switch (tag[0]) { 355afaf5a2dSDavid Somayajulu case MSG_HEAD_TAG: 356afaf5a2dSDavid Somayajulu cmd_entry->control_flags |= CF_HEAD_TAG; 357afaf5a2dSDavid Somayajulu break; 358afaf5a2dSDavid Somayajulu case MSG_ORDERED_TAG: 359afaf5a2dSDavid Somayajulu cmd_entry->control_flags |= CF_ORDERED_TAG; 360afaf5a2dSDavid Somayajulu break; 361afaf5a2dSDavid Somayajulu } 362afaf5a2dSDavid Somayajulu 36316ed55f9SKaren Higgins qla4xxx_advance_req_ring_ptr(ha); 364afaf5a2dSDavid Somayajulu qla4xxx_build_scsi_iocbs(srb, cmd_entry, tot_dsds); 365afaf5a2dSDavid Somayajulu wmb(); 366afaf5a2dSDavid Somayajulu 3675369887aSVikas Chaudhary srb->cmd->host_scribble = (unsigned char *)(unsigned long)index; 368afaf5a2dSDavid Somayajulu 369afaf5a2dSDavid Somayajulu /* update counters */ 370afaf5a2dSDavid Somayajulu srb->state = SRB_ACTIVE_STATE; 371afaf5a2dSDavid Somayajulu srb->flags |= SRB_DMA_VALID; 372afaf5a2dSDavid Somayajulu 373afaf5a2dSDavid Somayajulu /* Track IOCB used */ 374afaf5a2dSDavid Somayajulu ha->iocb_cnt += req_cnt; 375afaf5a2dSDavid Somayajulu srb->iocb_cnt = req_cnt; 376afaf5a2dSDavid Somayajulu ha->req_q_count -= req_cnt; 377afaf5a2dSDavid Somayajulu 378f4f5df23SVikas Chaudhary ha->isp_ops->queue_iocb(ha); 379afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 380afaf5a2dSDavid Somayajulu 381afaf5a2dSDavid Somayajulu return QLA_SUCCESS; 382afaf5a2dSDavid Somayajulu 383afaf5a2dSDavid Somayajulu queuing_error: 3845f7186c8SFUJITA Tomonori if (tot_dsds) 3855f7186c8SFUJITA Tomonori scsi_dma_unmap(cmd); 386afaf5a2dSDavid Somayajulu 387afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 388afaf5a2dSDavid Somayajulu 389afaf5a2dSDavid Somayajulu return QLA_ERROR; 390afaf5a2dSDavid Somayajulu } 391afaf5a2dSDavid Somayajulu 392