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 14afaf5a2dSDavid Somayajulu #include <scsi/scsi_tcq.h> 15afaf5a2dSDavid Somayajulu 16afaf5a2dSDavid Somayajulu /** 17afaf5a2dSDavid Somayajulu * qla4xxx_get_req_pkt - returns a valid entry in request queue. 18afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 19afaf5a2dSDavid Somayajulu * @queue_entry: Pointer to pointer to queue entry structure 20afaf5a2dSDavid Somayajulu * 21afaf5a2dSDavid Somayajulu * This routine performs the following tasks: 22afaf5a2dSDavid Somayajulu * - returns the current request_in pointer (if queue not full) 23afaf5a2dSDavid Somayajulu * - advances the request_in pointer 24afaf5a2dSDavid Somayajulu * - checks for queue full 25afaf5a2dSDavid Somayajulu **/ 2647975477SAdrian Bunk static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha, 27afaf5a2dSDavid Somayajulu struct queue_entry **queue_entry) 28afaf5a2dSDavid Somayajulu { 29afaf5a2dSDavid Somayajulu uint16_t request_in; 30afaf5a2dSDavid Somayajulu uint8_t status = QLA_SUCCESS; 31afaf5a2dSDavid Somayajulu 32afaf5a2dSDavid Somayajulu *queue_entry = ha->request_ptr; 33afaf5a2dSDavid Somayajulu 34afaf5a2dSDavid Somayajulu /* get the latest request_in and request_out index */ 35afaf5a2dSDavid Somayajulu request_in = ha->request_in; 36afaf5a2dSDavid Somayajulu ha->request_out = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out); 37afaf5a2dSDavid Somayajulu 38afaf5a2dSDavid Somayajulu /* Advance request queue pointer and check for queue full */ 39afaf5a2dSDavid Somayajulu if (request_in == (REQUEST_QUEUE_DEPTH - 1)) { 40afaf5a2dSDavid Somayajulu request_in = 0; 41afaf5a2dSDavid Somayajulu ha->request_ptr = ha->request_ring; 42afaf5a2dSDavid Somayajulu } else { 43afaf5a2dSDavid Somayajulu request_in++; 44afaf5a2dSDavid Somayajulu ha->request_ptr++; 45afaf5a2dSDavid Somayajulu } 46afaf5a2dSDavid Somayajulu 47afaf5a2dSDavid Somayajulu /* request queue is full, try again later */ 48afaf5a2dSDavid Somayajulu if ((ha->iocb_cnt + 1) >= ha->iocb_hiwat) { 49afaf5a2dSDavid Somayajulu /* restore request pointer */ 50afaf5a2dSDavid Somayajulu ha->request_ptr = *queue_entry; 51afaf5a2dSDavid Somayajulu status = QLA_ERROR; 52afaf5a2dSDavid Somayajulu } else { 53afaf5a2dSDavid Somayajulu ha->request_in = request_in; 54afaf5a2dSDavid Somayajulu memset(*queue_entry, 0, sizeof(**queue_entry)); 55afaf5a2dSDavid Somayajulu } 56afaf5a2dSDavid Somayajulu 57afaf5a2dSDavid Somayajulu return status; 58afaf5a2dSDavid Somayajulu } 59afaf5a2dSDavid Somayajulu 60afaf5a2dSDavid Somayajulu /** 61afaf5a2dSDavid Somayajulu * qla4xxx_send_marker_iocb - issues marker iocb to HBA 62afaf5a2dSDavid Somayajulu * @ha: Pointer to host adapter structure. 63afaf5a2dSDavid Somayajulu * @ddb_entry: Pointer to device database entry 64afaf5a2dSDavid Somayajulu * @lun: SCSI LUN 65afaf5a2dSDavid Somayajulu * @marker_type: marker identifier 66afaf5a2dSDavid Somayajulu * 67afaf5a2dSDavid Somayajulu * This routine issues a marker IOCB. 68afaf5a2dSDavid Somayajulu **/ 6947975477SAdrian Bunk static int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, 70afaf5a2dSDavid Somayajulu struct ddb_entry *ddb_entry, int lun) 71afaf5a2dSDavid Somayajulu { 72afaf5a2dSDavid Somayajulu struct marker_entry *marker_entry; 73afaf5a2dSDavid Somayajulu unsigned long flags = 0; 74afaf5a2dSDavid Somayajulu uint8_t status = QLA_SUCCESS; 75afaf5a2dSDavid Somayajulu 76afaf5a2dSDavid Somayajulu /* Acquire hardware specific lock */ 77afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 78afaf5a2dSDavid Somayajulu 79afaf5a2dSDavid Somayajulu /* Get pointer to the queue entry for the marker */ 80afaf5a2dSDavid Somayajulu if (qla4xxx_get_req_pkt(ha, (struct queue_entry **) &marker_entry) != 81afaf5a2dSDavid Somayajulu QLA_SUCCESS) { 82afaf5a2dSDavid Somayajulu status = QLA_ERROR; 83afaf5a2dSDavid Somayajulu goto exit_send_marker; 84afaf5a2dSDavid Somayajulu } 85afaf5a2dSDavid Somayajulu 86afaf5a2dSDavid Somayajulu /* Put the marker in the request queue */ 87afaf5a2dSDavid Somayajulu marker_entry->hdr.entryType = ET_MARKER; 88afaf5a2dSDavid Somayajulu marker_entry->hdr.entryCount = 1; 89afaf5a2dSDavid Somayajulu marker_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index); 90afaf5a2dSDavid Somayajulu marker_entry->modifier = cpu_to_le16(MM_LUN_RESET); 91afaf5a2dSDavid Somayajulu int_to_scsilun(lun, &marker_entry->lun); 92afaf5a2dSDavid Somayajulu wmb(); 93afaf5a2dSDavid Somayajulu 94afaf5a2dSDavid Somayajulu /* Tell ISP it's got a new I/O request */ 95afaf5a2dSDavid Somayajulu writel(ha->request_in, &ha->reg->req_q_in); 96afaf5a2dSDavid Somayajulu readl(&ha->reg->req_q_in); 97afaf5a2dSDavid Somayajulu 98afaf5a2dSDavid Somayajulu exit_send_marker: 99afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 100afaf5a2dSDavid Somayajulu return status; 101afaf5a2dSDavid Somayajulu } 102afaf5a2dSDavid Somayajulu 10347975477SAdrian Bunk static struct continuation_t1_entry* qla4xxx_alloc_cont_entry( 104afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha) 105afaf5a2dSDavid Somayajulu { 106afaf5a2dSDavid Somayajulu struct continuation_t1_entry *cont_entry; 107afaf5a2dSDavid Somayajulu 108afaf5a2dSDavid Somayajulu cont_entry = (struct continuation_t1_entry *)ha->request_ptr; 109afaf5a2dSDavid Somayajulu 110afaf5a2dSDavid Somayajulu /* Advance request queue pointer */ 111afaf5a2dSDavid Somayajulu if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) { 112afaf5a2dSDavid Somayajulu ha->request_in = 0; 113afaf5a2dSDavid Somayajulu ha->request_ptr = ha->request_ring; 114afaf5a2dSDavid Somayajulu } else { 115afaf5a2dSDavid Somayajulu ha->request_in++; 116afaf5a2dSDavid Somayajulu ha->request_ptr++; 117afaf5a2dSDavid Somayajulu } 118afaf5a2dSDavid Somayajulu 119afaf5a2dSDavid Somayajulu /* Load packet defaults */ 120afaf5a2dSDavid Somayajulu cont_entry->hdr.entryType = ET_CONTINUE; 121afaf5a2dSDavid Somayajulu cont_entry->hdr.entryCount = 1; 122afaf5a2dSDavid Somayajulu cont_entry->hdr.systemDefined = (uint8_t) cpu_to_le16(ha->request_in); 123afaf5a2dSDavid Somayajulu 124afaf5a2dSDavid Somayajulu return cont_entry; 125afaf5a2dSDavid Somayajulu } 126afaf5a2dSDavid Somayajulu 12747975477SAdrian Bunk static uint16_t qla4xxx_calc_request_entries(uint16_t dsds) 128afaf5a2dSDavid Somayajulu { 129afaf5a2dSDavid Somayajulu uint16_t iocbs; 130afaf5a2dSDavid Somayajulu 131afaf5a2dSDavid Somayajulu iocbs = 1; 132afaf5a2dSDavid Somayajulu if (dsds > COMMAND_SEG) { 133afaf5a2dSDavid Somayajulu iocbs += (dsds - COMMAND_SEG) / CONTINUE_SEG; 134afaf5a2dSDavid Somayajulu if ((dsds - COMMAND_SEG) % CONTINUE_SEG) 135afaf5a2dSDavid Somayajulu iocbs++; 136afaf5a2dSDavid Somayajulu } 137afaf5a2dSDavid Somayajulu return iocbs; 138afaf5a2dSDavid Somayajulu } 139afaf5a2dSDavid Somayajulu 14047975477SAdrian Bunk static void qla4xxx_build_scsi_iocbs(struct srb *srb, 141afaf5a2dSDavid Somayajulu struct command_t3_entry *cmd_entry, 142afaf5a2dSDavid Somayajulu uint16_t tot_dsds) 143afaf5a2dSDavid Somayajulu { 144afaf5a2dSDavid Somayajulu struct scsi_qla_host *ha; 145afaf5a2dSDavid Somayajulu uint16_t avail_dsds; 146afaf5a2dSDavid Somayajulu struct data_seg_a64 *cur_dsd; 147afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd; 148afaf5a2dSDavid Somayajulu 149afaf5a2dSDavid Somayajulu cmd = srb->cmd; 150afaf5a2dSDavid Somayajulu ha = srb->ha; 151afaf5a2dSDavid Somayajulu 152afaf5a2dSDavid Somayajulu if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) { 153afaf5a2dSDavid Somayajulu /* No data being transferred */ 154afaf5a2dSDavid Somayajulu cmd_entry->ttlByteCnt = __constant_cpu_to_le32(0); 155afaf5a2dSDavid Somayajulu return; 156afaf5a2dSDavid Somayajulu } 157afaf5a2dSDavid Somayajulu 158afaf5a2dSDavid Somayajulu avail_dsds = COMMAND_SEG; 159afaf5a2dSDavid Somayajulu cur_dsd = (struct data_seg_a64 *) & (cmd_entry->dataseg[0]); 160afaf5a2dSDavid Somayajulu 161afaf5a2dSDavid Somayajulu /* Load data segments */ 162afaf5a2dSDavid Somayajulu if (cmd->use_sg) { 163afaf5a2dSDavid Somayajulu struct scatterlist *cur_seg; 164afaf5a2dSDavid Somayajulu struct scatterlist *end_seg; 165afaf5a2dSDavid Somayajulu 166afaf5a2dSDavid Somayajulu cur_seg = (struct scatterlist *)cmd->request_buffer; 167afaf5a2dSDavid Somayajulu end_seg = cur_seg + tot_dsds; 168afaf5a2dSDavid Somayajulu while (cur_seg < end_seg) { 169afaf5a2dSDavid Somayajulu dma_addr_t sle_dma; 170afaf5a2dSDavid Somayajulu 171afaf5a2dSDavid Somayajulu /* Allocate additional continuation packets? */ 172afaf5a2dSDavid Somayajulu if (avail_dsds == 0) { 173afaf5a2dSDavid Somayajulu struct continuation_t1_entry *cont_entry; 174afaf5a2dSDavid Somayajulu 175afaf5a2dSDavid Somayajulu cont_entry = qla4xxx_alloc_cont_entry(ha); 176afaf5a2dSDavid Somayajulu cur_dsd = 177afaf5a2dSDavid Somayajulu (struct data_seg_a64 *) 178afaf5a2dSDavid Somayajulu &cont_entry->dataseg[0]; 179afaf5a2dSDavid Somayajulu avail_dsds = CONTINUE_SEG; 180afaf5a2dSDavid Somayajulu } 181afaf5a2dSDavid Somayajulu 182afaf5a2dSDavid Somayajulu sle_dma = sg_dma_address(cur_seg); 183afaf5a2dSDavid Somayajulu cur_dsd->base.addrLow = cpu_to_le32(LSDW(sle_dma)); 184afaf5a2dSDavid Somayajulu cur_dsd->base.addrHigh = cpu_to_le32(MSDW(sle_dma)); 185afaf5a2dSDavid Somayajulu cur_dsd->count = cpu_to_le32(sg_dma_len(cur_seg)); 186afaf5a2dSDavid Somayajulu avail_dsds--; 187afaf5a2dSDavid Somayajulu 188afaf5a2dSDavid Somayajulu cur_dsd++; 189afaf5a2dSDavid Somayajulu cur_seg++; 190afaf5a2dSDavid Somayajulu } 191afaf5a2dSDavid Somayajulu } else { 192afaf5a2dSDavid Somayajulu cur_dsd->base.addrLow = cpu_to_le32(LSDW(srb->dma_handle)); 193afaf5a2dSDavid Somayajulu cur_dsd->base.addrHigh = cpu_to_le32(MSDW(srb->dma_handle)); 194afaf5a2dSDavid Somayajulu cur_dsd->count = cpu_to_le32(cmd->request_bufflen); 195afaf5a2dSDavid Somayajulu } 196afaf5a2dSDavid Somayajulu } 197afaf5a2dSDavid Somayajulu 198afaf5a2dSDavid Somayajulu /** 199afaf5a2dSDavid Somayajulu * qla4xxx_send_command_to_isp - issues command to HBA 200afaf5a2dSDavid Somayajulu * @ha: pointer to host adapter structure. 201afaf5a2dSDavid Somayajulu * @srb: pointer to SCSI Request Block to be sent to ISP 202afaf5a2dSDavid Somayajulu * 203afaf5a2dSDavid Somayajulu * This routine is called by qla4xxx_queuecommand to build an ISP 204afaf5a2dSDavid Somayajulu * command and pass it to the ISP for execution. 205afaf5a2dSDavid Somayajulu **/ 206afaf5a2dSDavid Somayajulu int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) 207afaf5a2dSDavid Somayajulu { 208afaf5a2dSDavid Somayajulu struct scsi_cmnd *cmd = srb->cmd; 209afaf5a2dSDavid Somayajulu struct ddb_entry *ddb_entry; 210afaf5a2dSDavid Somayajulu struct command_t3_entry *cmd_entry; 211afaf5a2dSDavid Somayajulu struct scatterlist *sg = NULL; 212afaf5a2dSDavid Somayajulu 213afaf5a2dSDavid Somayajulu uint16_t tot_dsds; 214afaf5a2dSDavid Somayajulu uint16_t req_cnt; 215afaf5a2dSDavid Somayajulu 216afaf5a2dSDavid Somayajulu unsigned long flags; 217afaf5a2dSDavid Somayajulu uint16_t cnt; 218afaf5a2dSDavid Somayajulu uint32_t index; 219afaf5a2dSDavid Somayajulu char tag[2]; 220afaf5a2dSDavid Somayajulu 221afaf5a2dSDavid Somayajulu /* Get real lun and adapter */ 222afaf5a2dSDavid Somayajulu ddb_entry = srb->ddb; 223afaf5a2dSDavid Somayajulu 224afaf5a2dSDavid Somayajulu /* Send marker(s) if needed. */ 225afaf5a2dSDavid Somayajulu if (ha->marker_needed == 1) { 226afaf5a2dSDavid Somayajulu if (qla4xxx_send_marker_iocb(ha, ddb_entry, 227afaf5a2dSDavid Somayajulu cmd->device->lun) != QLA_SUCCESS) 228afaf5a2dSDavid Somayajulu return QLA_ERROR; 229afaf5a2dSDavid Somayajulu 230afaf5a2dSDavid Somayajulu ha->marker_needed = 0; 231afaf5a2dSDavid Somayajulu } 232afaf5a2dSDavid Somayajulu tot_dsds = 0; 233afaf5a2dSDavid Somayajulu 234afaf5a2dSDavid Somayajulu /* Acquire hardware specific lock */ 235afaf5a2dSDavid Somayajulu spin_lock_irqsave(&ha->hardware_lock, flags); 236afaf5a2dSDavid Somayajulu 237afaf5a2dSDavid Somayajulu index = (uint32_t)cmd->request->tag; 238afaf5a2dSDavid Somayajulu 239afaf5a2dSDavid Somayajulu /* Calculate the number of request entries needed. */ 240afaf5a2dSDavid Somayajulu if (cmd->use_sg) { 241afaf5a2dSDavid Somayajulu sg = (struct scatterlist *)cmd->request_buffer; 242afaf5a2dSDavid Somayajulu tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg, 243afaf5a2dSDavid Somayajulu cmd->sc_data_direction); 244afaf5a2dSDavid Somayajulu if (tot_dsds == 0) 245afaf5a2dSDavid Somayajulu goto queuing_error; 246afaf5a2dSDavid Somayajulu } else if (cmd->request_bufflen) { 247afaf5a2dSDavid Somayajulu dma_addr_t req_dma; 248afaf5a2dSDavid Somayajulu 249afaf5a2dSDavid Somayajulu req_dma = pci_map_single(ha->pdev, cmd->request_buffer, 250afaf5a2dSDavid Somayajulu cmd->request_bufflen, 251afaf5a2dSDavid Somayajulu cmd->sc_data_direction); 252afaf5a2dSDavid Somayajulu if (dma_mapping_error(req_dma)) 253afaf5a2dSDavid Somayajulu goto queuing_error; 254afaf5a2dSDavid Somayajulu 255afaf5a2dSDavid Somayajulu srb->dma_handle = req_dma; 256afaf5a2dSDavid Somayajulu tot_dsds = 1; 257afaf5a2dSDavid Somayajulu } 258afaf5a2dSDavid Somayajulu req_cnt = qla4xxx_calc_request_entries(tot_dsds); 259afaf5a2dSDavid Somayajulu 260afaf5a2dSDavid Somayajulu if (ha->req_q_count < (req_cnt + 2)) { 261afaf5a2dSDavid Somayajulu cnt = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out); 262afaf5a2dSDavid Somayajulu if (ha->request_in < cnt) 263afaf5a2dSDavid Somayajulu ha->req_q_count = cnt - ha->request_in; 264afaf5a2dSDavid Somayajulu else 265afaf5a2dSDavid Somayajulu ha->req_q_count = REQUEST_QUEUE_DEPTH - 266afaf5a2dSDavid Somayajulu (ha->request_in - cnt); 267afaf5a2dSDavid Somayajulu } 268afaf5a2dSDavid Somayajulu 269afaf5a2dSDavid Somayajulu if (ha->req_q_count < (req_cnt + 2)) 270afaf5a2dSDavid Somayajulu goto queuing_error; 271afaf5a2dSDavid Somayajulu 272afaf5a2dSDavid Somayajulu /* total iocbs active */ 273afaf5a2dSDavid Somayajulu if ((ha->iocb_cnt + req_cnt) >= REQUEST_QUEUE_DEPTH) 274afaf5a2dSDavid Somayajulu goto queuing_error; 275afaf5a2dSDavid Somayajulu 276afaf5a2dSDavid Somayajulu /* Build command packet */ 277afaf5a2dSDavid Somayajulu cmd_entry = (struct command_t3_entry *) ha->request_ptr; 278afaf5a2dSDavid Somayajulu memset(cmd_entry, 0, sizeof(struct command_t3_entry)); 279afaf5a2dSDavid Somayajulu cmd_entry->hdr.entryType = ET_COMMAND; 280afaf5a2dSDavid Somayajulu cmd_entry->handle = cpu_to_le32(index); 281afaf5a2dSDavid Somayajulu cmd_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index); 282afaf5a2dSDavid Somayajulu cmd_entry->connection_id = cpu_to_le16(ddb_entry->connection_id); 283afaf5a2dSDavid Somayajulu 284afaf5a2dSDavid Somayajulu int_to_scsilun(cmd->device->lun, &cmd_entry->lun); 285afaf5a2dSDavid Somayajulu cmd_entry->cmdSeqNum = cpu_to_le32(ddb_entry->CmdSn); 286afaf5a2dSDavid Somayajulu cmd_entry->ttlByteCnt = cpu_to_le32(cmd->request_bufflen); 287afaf5a2dSDavid Somayajulu memcpy(cmd_entry->cdb, cmd->cmnd, cmd->cmd_len); 288afaf5a2dSDavid Somayajulu cmd_entry->dataSegCnt = cpu_to_le16(tot_dsds); 289afaf5a2dSDavid Somayajulu cmd_entry->hdr.entryCount = req_cnt; 290afaf5a2dSDavid Somayajulu 291afaf5a2dSDavid Somayajulu /* Set data transfer direction control flags 292afaf5a2dSDavid Somayajulu * NOTE: Look at data_direction bits iff there is data to be 293afaf5a2dSDavid Somayajulu * transferred, as the data direction bit is sometimed filled 294afaf5a2dSDavid Somayajulu * in when there is no data to be transferred */ 295afaf5a2dSDavid Somayajulu cmd_entry->control_flags = CF_NO_DATA; 296afaf5a2dSDavid Somayajulu if (cmd->request_bufflen) { 297afaf5a2dSDavid Somayajulu if (cmd->sc_data_direction == DMA_TO_DEVICE) 298afaf5a2dSDavid Somayajulu cmd_entry->control_flags = CF_WRITE; 299afaf5a2dSDavid Somayajulu else if (cmd->sc_data_direction == DMA_FROM_DEVICE) 300afaf5a2dSDavid Somayajulu cmd_entry->control_flags = CF_READ; 301d915058fSDavid C Somayajulu 302d915058fSDavid C Somayajulu ha->bytes_xfered += cmd->request_bufflen; 303d915058fSDavid C Somayajulu if (ha->bytes_xfered & ~0xFFFFF){ 304d915058fSDavid C Somayajulu ha->total_mbytes_xferred += ha->bytes_xfered >> 20; 305d915058fSDavid C Somayajulu ha->bytes_xfered &= 0xFFFFF; 306d915058fSDavid C Somayajulu } 307afaf5a2dSDavid Somayajulu } 308afaf5a2dSDavid Somayajulu 309afaf5a2dSDavid Somayajulu /* Set tagged queueing control flags */ 310afaf5a2dSDavid Somayajulu cmd_entry->control_flags |= CF_SIMPLE_TAG; 311afaf5a2dSDavid Somayajulu if (scsi_populate_tag_msg(cmd, tag)) 312afaf5a2dSDavid Somayajulu switch (tag[0]) { 313afaf5a2dSDavid Somayajulu case MSG_HEAD_TAG: 314afaf5a2dSDavid Somayajulu cmd_entry->control_flags |= CF_HEAD_TAG; 315afaf5a2dSDavid Somayajulu break; 316afaf5a2dSDavid Somayajulu case MSG_ORDERED_TAG: 317afaf5a2dSDavid Somayajulu cmd_entry->control_flags |= CF_ORDERED_TAG; 318afaf5a2dSDavid Somayajulu break; 319afaf5a2dSDavid Somayajulu } 320afaf5a2dSDavid Somayajulu 321afaf5a2dSDavid Somayajulu 322afaf5a2dSDavid Somayajulu /* Advance request queue pointer */ 323afaf5a2dSDavid Somayajulu ha->request_in++; 324afaf5a2dSDavid Somayajulu if (ha->request_in == REQUEST_QUEUE_DEPTH) { 325afaf5a2dSDavid Somayajulu ha->request_in = 0; 326afaf5a2dSDavid Somayajulu ha->request_ptr = ha->request_ring; 327afaf5a2dSDavid Somayajulu } else 328afaf5a2dSDavid Somayajulu ha->request_ptr++; 329afaf5a2dSDavid Somayajulu 330afaf5a2dSDavid Somayajulu 331afaf5a2dSDavid Somayajulu qla4xxx_build_scsi_iocbs(srb, cmd_entry, tot_dsds); 332afaf5a2dSDavid Somayajulu wmb(); 333afaf5a2dSDavid Somayajulu 334afaf5a2dSDavid Somayajulu /* 335afaf5a2dSDavid Somayajulu * Check to see if adapter is online before placing request on 336afaf5a2dSDavid Somayajulu * request queue. If a reset occurs and a request is in the queue, 337afaf5a2dSDavid Somayajulu * the firmware will still attempt to process the request, retrieving 338afaf5a2dSDavid Somayajulu * garbage for pointers. 339afaf5a2dSDavid Somayajulu */ 340afaf5a2dSDavid Somayajulu if (!test_bit(AF_ONLINE, &ha->flags)) { 341afaf5a2dSDavid Somayajulu DEBUG2(printk("scsi%ld: %s: Adapter OFFLINE! " 342afaf5a2dSDavid Somayajulu "Do not issue command.\n", 343afaf5a2dSDavid Somayajulu ha->host_no, __func__)); 344afaf5a2dSDavid Somayajulu goto queuing_error; 345afaf5a2dSDavid Somayajulu } 346afaf5a2dSDavid Somayajulu 347afaf5a2dSDavid Somayajulu srb->cmd->host_scribble = (unsigned char *)srb; 348afaf5a2dSDavid Somayajulu 349afaf5a2dSDavid Somayajulu /* update counters */ 350afaf5a2dSDavid Somayajulu srb->state = SRB_ACTIVE_STATE; 351afaf5a2dSDavid Somayajulu srb->flags |= SRB_DMA_VALID; 352afaf5a2dSDavid Somayajulu 353afaf5a2dSDavid Somayajulu /* Track IOCB used */ 354afaf5a2dSDavid Somayajulu ha->iocb_cnt += req_cnt; 355afaf5a2dSDavid Somayajulu srb->iocb_cnt = req_cnt; 356afaf5a2dSDavid Somayajulu ha->req_q_count -= req_cnt; 357afaf5a2dSDavid Somayajulu 358afaf5a2dSDavid Somayajulu /* Debug print statements */ 359afaf5a2dSDavid Somayajulu writel(ha->request_in, &ha->reg->req_q_in); 360afaf5a2dSDavid Somayajulu readl(&ha->reg->req_q_in); 361afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 362afaf5a2dSDavid Somayajulu 363afaf5a2dSDavid Somayajulu return QLA_SUCCESS; 364afaf5a2dSDavid Somayajulu 365afaf5a2dSDavid Somayajulu queuing_error: 366afaf5a2dSDavid Somayajulu 367afaf5a2dSDavid Somayajulu if (cmd->use_sg && tot_dsds) { 368afaf5a2dSDavid Somayajulu sg = (struct scatterlist *) cmd->request_buffer; 369afaf5a2dSDavid Somayajulu pci_unmap_sg(ha->pdev, sg, cmd->use_sg, 370afaf5a2dSDavid Somayajulu cmd->sc_data_direction); 371afaf5a2dSDavid Somayajulu } else if (tot_dsds) 372afaf5a2dSDavid Somayajulu pci_unmap_single(ha->pdev, srb->dma_handle, 373afaf5a2dSDavid Somayajulu cmd->request_bufflen, cmd->sc_data_direction); 374afaf5a2dSDavid Somayajulu spin_unlock_irqrestore(&ha->hardware_lock, flags); 375afaf5a2dSDavid Somayajulu 376afaf5a2dSDavid Somayajulu return QLA_ERROR; 377afaf5a2dSDavid Somayajulu } 378afaf5a2dSDavid Somayajulu 379