-/*
- * qla2x00_extend_timeout
- * This routine will extend the timeout to the specified value.
- *
- * Input:
- * cmd = SCSI command structure
- *
- * Returns:
- * None.
- */
-void
-qla2x00_extend_timeout(struct scsi_cmnd *cmd, int timeout)
-{
- srb_t *sp = (srb_t *) CMD_SP(cmd);
- u_long our_jiffies = (timeout * HZ) + jiffies;
-
- sp->ext_history= 0;
- sp->e_start = jiffies;
- if (cmd->eh_timeout.function) {
- mod_timer(&cmd->eh_timeout,our_jiffies);
- sp->ext_history |= 1;
- }
- if (sp->timer.function != NULL) {
- /*
- * Our internal timer should timeout before the midlayer has a
- * chance begin the abort process
- */
- mod_timer(&sp->timer,our_jiffies - (QLA_CMD_TIMER_DELTA * HZ));
-
- sp->ext_history |= 2;
- }
-}
-
-/**************************************************************************
-* qla2x00_cmd_timeout
-*
-* Description:
-* Handles the command if it times out in any state.
-*
-* Input:
-* sp - pointer to validate
-*
-* Returns:
-* None.
-* Note:Need to add the support for if( sp->state == SRB_FAILOVER_STATE).
-**************************************************************************/
-void
-qla2x00_cmd_timeout(srb_t *sp)
-{
- int t, l;
- int processed;
- scsi_qla_host_t *vis_ha, *dest_ha;
- struct scsi_cmnd *cmd;
- ulong flags;
- fc_port_t *fcport;
-
- cmd = sp->cmd;
- vis_ha = (scsi_qla_host_t *)cmd->device->host->hostdata;
-
- DEBUG3(printk("cmd_timeout: Entering sp->state = %x\n", sp->state));
-
- t = cmd->device->id;
- l = cmd->device->lun;
- fcport = sp->fclun->fcport;
- dest_ha = sp->ha;
-
- /*
- * If IO is found either in retry Queue
- * OR in Lun Queue
- * Return this IO back to host
- */
- spin_lock_irqsave(&vis_ha->list_lock, flags);
- processed = 0;
- if (sp->state == SRB_PENDING_STATE) {
- __del_from_pending_queue(vis_ha, sp);
- DEBUG2(printk("scsi(%ld): Found in Pending queue pid %ld, "
- "State = %x., fcport state=%d jiffies=%lx\n",
- vis_ha->host_no, cmd->serial_number, sp->state,
- atomic_read(&fcport->state), jiffies));
-
- /*
- * If FC_DEVICE is marked as dead return the cmd with
- * DID_NO_CONNECT status. Otherwise set the host_byte to
- * DID_BUS_BUSY to let the OS retry this cmd.
- */
- if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
- atomic_read(&fcport->ha->loop_state) == LOOP_DEAD) {
- cmd->result = DID_NO_CONNECT << 16;
- if (atomic_read(&fcport->ha->loop_state) == LOOP_DOWN)
- sp->err_id = SRB_ERR_LOOP;
- else
- sp->err_id = SRB_ERR_PORT;
- } else {
- cmd->result = DID_BUS_BUSY << 16;
- }
- __add_to_done_queue(vis_ha, sp);
- processed++;
- }
- spin_unlock_irqrestore(&vis_ha->list_lock, flags);
-
- if (processed) {
- qla2x00_done(vis_ha);
- return;
- }
-
- spin_lock_irqsave(&dest_ha->list_lock, flags);
- if ((sp->state == SRB_RETRY_STATE) ||
- (sp->state == SRB_SCSI_RETRY_STATE)) {
-
- DEBUG2(printk("scsi(%ld): Found in (Scsi) Retry queue or "
- "failover Q pid %ld, State = %x., fcport state=%d "
- "jiffies=%lx retried=%d\n",
- dest_ha->host_no, cmd->serial_number, sp->state,
- atomic_read(&fcport->state), jiffies, cmd->retries));
-
- if ((sp->state == SRB_RETRY_STATE)) {
- __del_from_retry_queue(dest_ha, sp);
- } else if ((sp->state == SRB_SCSI_RETRY_STATE)) {
- __del_from_scsi_retry_queue(dest_ha, sp);
- }
-
- /*
- * If FC_DEVICE is marked as dead return the cmd with
- * DID_NO_CONNECT status. Otherwise set the host_byte to
- * DID_BUS_BUSY to let the OS retry this cmd.
- */
- if ((atomic_read(&fcport->state) == FCS_DEVICE_DEAD) ||
- atomic_read(&dest_ha->loop_state) == LOOP_DEAD) {
- qla2x00_extend_timeout(cmd, EXTEND_CMD_TIMEOUT);
- cmd->result = DID_NO_CONNECT << 16;
- if (atomic_read(&dest_ha->loop_state) == LOOP_DOWN)
- sp->err_id = SRB_ERR_LOOP;
- else
- sp->err_id = SRB_ERR_PORT;
- } else {
- cmd->result = DID_BUS_BUSY << 16;
- }
-
- __add_to_done_queue(dest_ha, sp);
- processed++;
- }
- spin_unlock_irqrestore(&dest_ha->list_lock, flags);
-
- if (processed) {
- qla2x00_done(dest_ha);
-
- return;
- }
-
- DEBUG3(printk("cmd_timeout: Leaving\n");)
-}
-
-/**************************************************************************
-* qla2x00_done
-* Process completed commands.
-*
-* Input:
-* old_ha = adapter block pointer.
-*
-**************************************************************************/
-void
-qla2x00_done(scsi_qla_host_t *old_ha)
-{
- os_lun_t *lq;
- struct scsi_cmnd *cmd;
- unsigned long flags = 0;
- scsi_qla_host_t *ha;
- scsi_qla_host_t *vis_ha;
- int send_marker_once = 0;
- srb_t *sp, *sptemp;
- LIST_HEAD(local_sp_list);
-
- /*
- * Get into local queue such that we do not wind up calling done queue
- * tasklet for the same IOs from DPC or any other place.
- */
- spin_lock_irqsave(&old_ha->list_lock, flags);
- list_splice_init(&old_ha->done_queue, &local_sp_list);
- spin_unlock_irqrestore(&old_ha->list_lock, flags);
-
- /*
- * All done commands are in the local queue, now do the call back.
- */
- list_for_each_entry_safe(sp, sptemp, &local_sp_list, list) {
- old_ha->done_q_cnt--;
- sp->state = SRB_NO_QUEUE_STATE;
-
- /* remove command from local list */
- list_del_init(&sp->list);
-
- cmd = sp->cmd;
- if (cmd == NULL)
- continue;
-
- vis_ha = (scsi_qla_host_t *)cmd->device->host->hostdata;
- lq = sp->lun_queue;
- ha = sp->ha;
-
- if (sp->flags & SRB_DMA_VALID) {
- sp->flags &= ~SRB_DMA_VALID;
-
- /* Release memory used for this I/O */
- if (cmd->use_sg) {
- pci_unmap_sg(ha->pdev, cmd->request_buffer,
- cmd->use_sg, cmd->sc_data_direction);
- } else if (cmd->request_bufflen) {
- pci_unmap_page(ha->pdev, sp->dma_handle,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- }
- }
-
-
- switch (host_byte(cmd->result)) {
- case DID_OK:
- case DID_ERROR:
- break;
-
- case DID_RESET:
- /*
- * Set marker needed, so we don't have to
- * send multiple markers
- */
- if (!send_marker_once) {
- ha->marker_needed = 1;
- send_marker_once++;
- }
-
- /*
- * WORKAROUND
- *
- * A backdoor device-reset requires different
- * error handling. This code differentiates
- * between normal error handling and the
- * backdoor method.
- *
- */
- if (ha->host->eh_active != EH_ACTIVE)
- cmd->result = DID_BUS_BUSY << 16;
- break;
-
-
- case DID_ABORT:
- sp->flags &= ~SRB_ABORT_PENDING;
- sp->flags |= SRB_ABORTED;
-
- if (sp->flags & SRB_TIMEOUT)
- cmd->result = DID_TIME_OUT << 16;
-
- break;
-
- default:
- DEBUG2(printk("scsi(%ld:%d:%d) %s: did_error "
- "= %d, comp-scsi= 0x%x-0x%x.\n",
- vis_ha->host_no,
- cmd->device->id, cmd->device->lun,
- __func__,
- host_byte(cmd->result),
- CMD_COMPL_STATUS(cmd),
- CMD_SCSI_STATUS(cmd)));
- break;
- }
-
- /*
- * Call the mid-level driver interrupt handler -- via sp_put()
- */
- sp_put(ha, sp);
- } /* end of while */
-}
-
-/*
- * qla2x00_process_response_queue_in_zio_mode
- * Process response queue completion as fast as possible
- * to achieve Zero Interrupt Opertions-ZIO
- *
- * Input:
- * ha = adapter block pointer.
- *
- * Context:
- * Kernel context.
- */
-static inline void
-qla2x00_process_response_queue_in_zio_mode(scsi_qla_host_t *ha)
-{
- unsigned long flags;
-
- /* Check for unprocessed commands in response queue. */
- if (!ha->flags.process_response_queue)
- return;
- if (!ha->flags.online)
- return;
- if (ha->response_ring_ptr->signature == RESPONSE_PROCESSED)
- return;
-
- spin_lock_irqsave(&ha->hardware_lock,flags);
- qla2x00_process_response_queue(ha);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
- if (!list_empty(&ha->done_queue))
- qla2x00_done(ha);
-}
-
-/*
- * qla2x00_next
- * Retrieve and process next job in the LUN queue.
- *
- * Input:
- * tq = SCSI target queue pointer.
- * lq = SCSI LUN queue pointer.
- * TGT_LOCK must be already obtained.
- *
- * Output:
- * Releases TGT_LOCK upon exit.
- *
- * Context:
- * Kernel/Interrupt context.
- *
- * Note: This routine will always try to start I/O from visible HBA.
- */
-void
-qla2x00_next(scsi_qla_host_t *vis_ha)
-{
- int rval;
- unsigned long flags;
- scsi_qla_host_t *dest_ha;
- fc_port_t *fcport;
- srb_t *sp, *sptemp;
- LIST_HEAD(local_sp_list);
-
- dest_ha = NULL;
-
- spin_lock_irqsave(&vis_ha->list_lock, flags);
- list_splice_init(&vis_ha->pending_queue, &local_sp_list);
- vis_ha->qthreads = 0;
- spin_unlock_irqrestore(&vis_ha->list_lock, flags);
-
- list_for_each_entry_safe(sp, sptemp, &local_sp_list, list) {
- list_del_init(&sp->list);
- sp->state = SRB_NO_QUEUE_STATE;
-
- fcport = sp->fclun->fcport;
- dest_ha = fcport->ha;
-
- /* If device is dead then send request back to OS */
- if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) {
- sp->cmd->result = DID_NO_CONNECT << 16;
- if (atomic_read(&dest_ha->loop_state) == LOOP_DOWN)
- sp->err_id = SRB_ERR_LOOP;
- else
- sp->err_id = SRB_ERR_PORT;
-
- DEBUG3(printk("scsi(%ld): loop/port is down - pid=%ld, "
- "sp=%p err_id=%d loopid=0x%x queued to dest HBA "
- "scsi%ld.\n", dest_ha->host_no,
- sp->cmd->serial_number, sp, sp->err_id,
- fcport->loop_id, dest_ha->host_no));
- /*
- * Initiate a failover - done routine will initiate.
- */
- add_to_done_queue(vis_ha, sp);
-
- continue;
- }
-
- /*
- * SCSI Kluge: Whenever, we need to wait for an event such as
- * loop down (i.e. loop_down_timer ) or port down (i.e. LUN
- * request qeueue is suspended) then we will recycle new
- * commands back to the SCSI layer. We do this because this is
- * normally a temporary condition and we don't want the
- * mid-level scsi.c driver to get upset and start aborting
- * commands. The timeout value is extracted from the command
- * minus 1-second and put on a retry queue (watchdog). Once the
- * command timeout it is returned to the mid-level with a BUSY
- * status, so the mid-level will retry it. This process
- * continues until the LOOP DOWN time expires or the condition
- * goes away.
- */
- if (!(sp->flags & SRB_IOCTL) &&
- (atomic_read(&fcport->state) != FCS_ONLINE ||
- test_bit(ABORT_ISP_ACTIVE, &dest_ha->dpc_flags) ||
- atomic_read(&dest_ha->loop_state) != LOOP_READY)) {
-
- DEBUG3(printk("scsi(%ld): port=(0x%x) retry_q(%d) "
- "loop state = %d, loop counter = 0x%x dpc flags "
- "= 0x%lx\n",
- dest_ha->host_no,
- fcport->loop_id,
- atomic_read(&fcport->state),
- atomic_read(&dest_ha->loop_state),
- atomic_read(&dest_ha->loop_down_timer),
- dest_ha->dpc_flags));
-
- qla2x00_extend_timeout(sp->cmd, EXTEND_CMD_TIMEOUT);
- add_to_retry_queue(vis_ha, sp);
-
- continue;
- }
-
- /*
- * If this request's lun is suspended then put the request on
- * the scsi_retry queue.
- */
- if (!(sp->flags & SRB_IOCTL) &&
- sp->lun_queue->q_state == LUN_STATE_WAIT) {
- DEBUG3(printk("scsi(%ld): lun wait state - pid=%ld, "
- "opcode=%d, allowed=%d, retries=%d\n",
- dest_ha->host_no,
- sp->cmd->serial_number,
- sp->cmd->cmnd[0],
- sp->cmd->allowed,
- sp->cmd->retries));
-
- add_to_scsi_retry_queue(vis_ha, sp);
-
- continue;
- }
-
- sp->lun_queue->io_cnt++;
-
- rval = qla2x00_start_scsi(sp);
- if (rval != QLA_SUCCESS) {
- /* Place request back on top of device queue */
- /* add to the top of queue */
- add_to_pending_queue_head(vis_ha, sp);
-
- sp->lun_queue->io_cnt--;
- }
- }
-
- if (!IS_QLA2100(vis_ha) && !IS_QLA2200(vis_ha)) {
- /* Process response_queue if ZIO support is enabled*/
- qla2x00_process_response_queue_in_zio_mode(vis_ha);
-
- }
-}
-
-
-/**************************************************************************
-* qla2x00_check_tgt_status
-*
-* Description:
-* Checks to see if the target or loop is down.
-*
-* Input:
-* cmd - pointer to Scsi cmd structure
-*
-* Returns:
-* 1 - if target is present
-* 0 - if target is not present
-*
-**************************************************************************/
-int
-qla2x00_check_tgt_status(scsi_qla_host_t *ha, struct scsi_cmnd *cmd)
-{
- os_lun_t *lq;
- unsigned int b, t, l;
- fc_port_t *fcport;
-
- /* Generate LU queue on bus, target, LUN */
- b = cmd->device->channel;
- t = cmd->device->id;
- l = cmd->device->lun;
-
- if ((lq = GET_LU_Q(ha,t,l)) == NULL) {
- return (QLA_FUNCTION_FAILED);
- }
-
- fcport = lq->fclun->fcport;
-
- if (TGT_Q(ha, t) == NULL ||
- l >= ha->max_luns ||
- atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
- atomic_read(&ha->loop_state) == LOOP_DEAD ||
- (!atomic_read(&ha->loop_down_timer) &&
- atomic_read(&ha->loop_state) == LOOP_DOWN) ||
- test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
- test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
- atomic_read(&ha->loop_state) != LOOP_READY) {
-
- DEBUG(printk(KERN_INFO
- "scsi(%ld:%2d:%2d:%2d): %s connection is down\n",
- ha->host_no,
- b, t, l,
- __func__));
-
- cmd->result = DID_NO_CONNECT << 16;
- return (QLA_FUNCTION_FAILED);
- }
- return (QLA_SUCCESS);
-}
-
-/**************************************************************************
-* qla2x00_check_port_status
-*
-* Description:
-* Checks to see if the port or loop is down.
-*
-* Input:
-* fcport - pointer to fc_port_t structure.
-*
-* Returns:
-* 1 - if port is present
-* 0 - if port is not present
-*
-**************************************************************************/
-int
-qla2x00_check_port_status(scsi_qla_host_t *ha, fc_port_t *fcport)
-{
- if (fcport == NULL) {
- return (QLA_FUNCTION_FAILED);
- }
-
- if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
- atomic_read(&ha->loop_state) == LOOP_DEAD) {
- return (QLA_FUNCTION_FAILED);
- }
-
- if ((atomic_read(&fcport->state) != FCS_ONLINE) ||
- (!atomic_read(&ha->loop_down_timer) &&
- atomic_read(&ha->loop_state) == LOOP_DOWN) ||
- (test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)) ||
- test_bit(CFG_ACTIVE, &ha->cfg_flags) ||
- test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
- atomic_read(&ha->loop_state) != LOOP_READY) {
-
- DEBUG(printk(KERN_INFO
- "scsi(%ld): Connection is down. fcport=%p.\n",
- ha->host_no, fcport));
-
- return (QLA_BUSY);
- }
-
- return (QLA_SUCCESS);
-}
-