/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2007 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2008 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
lpfc_adjust_queue_depth(struct lpfc_hba *phba)
{
unsigned long flags;
+ uint32_t evt_posted;
spin_lock_irqsave(&phba->hbalock, flags);
atomic_inc(&phba->num_rsrc_err);
spin_unlock_irqrestore(&phba->hbalock, flags);
spin_lock_irqsave(&phba->pport->work_port_lock, flags);
- if ((phba->pport->work_port_events &
- WORKER_RAMP_DOWN_QUEUE) == 0) {
+ evt_posted = phba->pport->work_port_events & WORKER_RAMP_DOWN_QUEUE;
+ if (!evt_posted)
phba->pport->work_port_events |= WORKER_RAMP_DOWN_QUEUE;
- }
spin_unlock_irqrestore(&phba->pport->work_port_lock, flags);
- spin_lock_irqsave(&phba->hbalock, flags);
- if (phba->work_wait)
- wake_up(phba->work_wait);
- spin_unlock_irqrestore(&phba->hbalock, flags);
-
+ if (!evt_posted)
+ lpfc_worker_wake_up(phba);
return;
}
{
unsigned long flags;
struct lpfc_hba *phba = vport->phba;
+ uint32_t evt_posted;
atomic_inc(&phba->num_cmd_success);
if (vport->cfg_lun_queue_depth <= sdev->queue_depth)
spin_unlock_irqrestore(&phba->hbalock, flags);
spin_lock_irqsave(&phba->pport->work_port_lock, flags);
- if ((phba->pport->work_port_events &
- WORKER_RAMP_UP_QUEUE) == 0) {
+ evt_posted = phba->pport->work_port_events & WORKER_RAMP_UP_QUEUE;
+ if (!evt_posted)
phba->pport->work_port_events |= WORKER_RAMP_UP_QUEUE;
- }
spin_unlock_irqrestore(&phba->pport->work_port_lock, flags);
- spin_lock_irqsave(&phba->hbalock, flags);
- if (phba->work_wait)
- wake_up(phba->work_wait);
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ if (!evt_posted)
+ lpfc_worker_wake_up(phba);
+ return;
}
void
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
- for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+ for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
shost = lpfc_shost_from_vport(vports[i]);
shost_for_each_device(sdev, shost) {
new_queue_depth =
new_queue_depth);
}
}
- lpfc_destroy_vport_work_array(vports);
+ lpfc_destroy_vport_work_array(phba, vports);
atomic_set(&phba->num_rsrc_err, 0);
atomic_set(&phba->num_cmd_success, 0);
}
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
- for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+ for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
shost = lpfc_shost_from_vport(vports[i]);
shost_for_each_device(sdev, shost) {
+ if (vports[i]->cfg_lun_queue_depth <=
+ sdev->queue_depth)
+ continue;
if (sdev->ordered_tags)
scsi_adjust_queue_depth(sdev,
MSG_ORDERED_TAG,
sdev->queue_depth+1);
}
}
- lpfc_destroy_vport_work_array(vports);
+ lpfc_destroy_vport_work_array(phba, vports);
atomic_set(&phba->num_rsrc_err, 0);
atomic_set(&phba->num_cmd_success, 0);
}
(num_bde * sizeof (struct ulp_bde64));
iocb_cmd->ulpBdeCount = 1;
iocb_cmd->ulpLe = 1;
- fcp_cmnd->fcpDl = be32_to_cpu(scsi_bufflen(scsi_cmnd));
+ fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd));
return 0;
}
int result;
struct scsi_device *sdev, *tmp_sdev;
int depth = 0;
+ unsigned long flags;
lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
lpfc_cmd->result == IOERR_NO_RESOURCES ||
lpfc_cmd->result == RJT_LOGIN_REQUIRED) {
cmd->result = ScsiResult(DID_REQUEUE, 0);
- break;
- } /* else: fall through */
+ break;
+ } /* else: fall through */
default:
cmd->result = ScsiResult(DID_ERROR, 0);
break;
}
- if ((pnode == NULL )
+ if (!pnode || !NLP_CHK_NODE_ACT(pnode)
|| (pnode->nlp_state != NLP_STE_MAPPED_NODE))
cmd->result = ScsiResult(DID_BUS_BUSY, SAM_STAT_BUSY);
} else {
cmd->scsi_done(cmd);
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
+ /*
+ * If there is a thread waiting for command completion
+ * wake up the thread.
+ */
+ spin_lock_irqsave(sdev->host->host_lock, flags);
+ lpfc_cmd->pCmd = NULL;
+ if (lpfc_cmd->waitq)
+ wake_up(lpfc_cmd->waitq);
+ spin_unlock_irqrestore(sdev->host->host_lock, flags);
lpfc_release_scsi_buf(phba, lpfc_cmd);
return;
}
if (!result)
lpfc_rampup_queue_depth(vport, sdev);
- if (!result && pnode != NULL &&
+ if (!result && pnode && NLP_CHK_NODE_ACT(pnode) &&
((jiffies - pnode->last_ramp_up_time) >
LPFC_Q_RAMP_UP_INTERVAL * HZ) &&
((jiffies - pnode->last_q_full_time) >
* Check for queue full. If the lun is reporting queue full, then
* back off the lun queue depth to prevent target overloads.
*/
- if (result == SAM_STAT_TASK_SET_FULL && pnode != NULL) {
+ if (result == SAM_STAT_TASK_SET_FULL && pnode &&
+ NLP_CHK_NODE_ACT(pnode)) {
pnode->last_q_full_time = jiffies;
shost_for_each_device(tmp_sdev, sdev->host) {
}
}
+ /*
+ * If there is a thread waiting for command completion
+ * wake up the thread.
+ */
+ spin_lock_irqsave(sdev->host->host_lock, flags);
+ lpfc_cmd->pCmd = NULL;
+ if (lpfc_cmd->waitq)
+ wake_up(lpfc_cmd->waitq);
+ spin_unlock_irqrestore(sdev->host->host_lock, flags);
+
lpfc_release_scsi_buf(phba, lpfc_cmd);
}
int datadir = scsi_cmnd->sc_data_direction;
char tag[2];
+ if (!pnode || !NLP_CHK_NODE_ACT(pnode))
+ return;
+
lpfc_cmd->fcp_rsp->rspSnsLen = 0;
/* clear task management bits */
lpfc_cmd->fcp_cmnd->fcpCntl2 = 0;
piocbq->iocb.ulpContext = pnode->nlp_rpi;
if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE)
piocbq->iocb.ulpFCP2Rcvy = 1;
+ else
+ piocbq->iocb.ulpFCP2Rcvy = 0;
piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f);
piocbq->context1 = lpfc_cmd;
struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
struct lpfc_nodelist *ndlp = rdata->pnode;
- if ((ndlp == NULL) || (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
+ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) ||
+ ndlp->nlp_state != NLP_STE_MAPPED_NODE)
return 0;
- }
piocbq = &(lpfc_cmd->cur_iocbq);
piocbq->vport = vport;
struct lpfc_iocbq *iocbq;
struct lpfc_iocbq *iocbqrsp;
int ret;
+ int status;
- if (!rdata->pnode)
+ if (!rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode))
return FAILED;
lpfc_cmd->rdata = rdata;
- ret = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun,
+ status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun,
FCP_TARGET_RESET);
- if (!ret)
+ if (!status)
return FAILED;
iocbq = &lpfc_cmd->cur_iocbq;
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
"0702 Issue Target Reset to TGT %d Data: x%x x%x\n",
tgt_id, rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag);
- ret = lpfc_sli_issue_iocb_wait(phba,
+ status = lpfc_sli_issue_iocb_wait(phba,
&phba->sli.ring[phba->sli.fcp_ring],
iocbq, iocbqrsp, lpfc_cmd->timeout);
- if (ret != IOCB_SUCCESS) {
- if (ret == IOCB_TIMEDOUT)
+ if (status != IOCB_SUCCESS) {
+ if (status == IOCB_TIMEDOUT) {
iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
+ ret = TIMEOUT_ERROR;
+ } else
+ ret = FAILED;
lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
} else {
ret = SUCCESS;
* Catch race where our node has transitioned, but the
* transport is still transitioning.
*/
- if (!ndlp) {
+ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
cmnd->result = ScsiResult(DID_BUS_BUSY, 0);
goto out_fail_command;
}
struct lpfc_iocbq *abtsiocb;
struct lpfc_scsi_buf *lpfc_cmd;
IOCB_t *cmd, *icmd;
- unsigned int loop_count = 0;
int ret = SUCCESS;
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
lpfc_block_error_handler(cmnd);
lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
if (phba->cfg_poll & DISABLE_FCP_RING_INT)
lpfc_sli_poll_fcp_ring (phba);
+ lpfc_cmd->waitq = &waitq;
/* Wait for abort to complete */
- while (lpfc_cmd->pCmd == cmnd)
- {
- if (phba->cfg_poll & DISABLE_FCP_RING_INT)
- lpfc_sli_poll_fcp_ring (phba);
+ wait_event_timeout(waitq,
+ (lpfc_cmd->pCmd != cmnd),
+ (2*vport->cfg_devloss_tmo*HZ));
- schedule_timeout_uninterruptible(LPFC_ABORT_WAIT * HZ);
- if (++loop_count
- > (2 * vport->cfg_devloss_tmo)/LPFC_ABORT_WAIT)
- break;
- }
+ spin_lock_irq(shost->host_lock);
+ lpfc_cmd->waitq = NULL;
+ spin_unlock_irq(shost->host_lock);
if (lpfc_cmd->pCmd == cmnd) {
ret = FAILED;
struct lpfc_iocbq *iocbq, *iocbqrsp;
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
struct lpfc_nodelist *pnode = rdata->pnode;
- uint32_t cmd_result = 0, cmd_status = 0;
- int ret = FAILED;
- int iocb_status = IOCB_SUCCESS;
- int cnt, loopcnt;
+ unsigned long later;
+ int ret = SUCCESS;
+ int status;
+ int cnt;
lpfc_block_error_handler(cmnd);
- loopcnt = 0;
/*
* If target is not in a MAPPED state, delay the reset until
* target is rediscovered or devloss timeout expires.
*/
- while (1) {
- if (!pnode)
- goto out;
-
- if (pnode->nlp_state != NLP_STE_MAPPED_NODE) {
- schedule_timeout_uninterruptible(msecs_to_jiffies(500));
- loopcnt++;
- rdata = cmnd->device->hostdata;
- if (!rdata ||
- (loopcnt > ((vport->cfg_devloss_tmo * 2) + 1))){
- lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
- "0721 LUN Reset rport "
- "failure: cnt x%x rdata x%p\n",
- loopcnt, rdata);
- goto out;
- }
- pnode = rdata->pnode;
- if (!pnode)
- goto out;
- }
+ later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies;
+ while (time_after(later, jiffies)) {
+ if (!pnode || !NLP_CHK_NODE_ACT(pnode))
+ return FAILED;
if (pnode->nlp_state == NLP_STE_MAPPED_NODE)
break;
+ schedule_timeout_uninterruptible(msecs_to_jiffies(500));
+ rdata = cmnd->device->hostdata;
+ if (!rdata)
+ break;
+ pnode = rdata->pnode;
+ }
+ if (!rdata || pnode->nlp_state != NLP_STE_MAPPED_NODE) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+ "0721 LUN Reset rport "
+ "failure: msec x%x rdata x%p\n",
+ jiffies_to_msecs(jiffies - later), rdata);
+ return FAILED;
}
-
lpfc_cmd = lpfc_get_scsi_buf(phba);
if (lpfc_cmd == NULL)
- goto out;
-
+ return FAILED;
lpfc_cmd->timeout = 60;
lpfc_cmd->rdata = rdata;
- ret = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, cmnd->device->lun,
- FCP_TARGET_RESET);
- if (!ret)
- goto out_free_scsi_buf;
-
+ status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd,
+ cmnd->device->lun,
+ FCP_TARGET_RESET);
+ if (!status) {
+ lpfc_release_scsi_buf(phba, lpfc_cmd);
+ return FAILED;
+ }
iocbq = &lpfc_cmd->cur_iocbq;
/* get a buffer for this IOCB command response */
iocbqrsp = lpfc_sli_get_iocbq(phba);
- if (iocbqrsp == NULL)
- goto out_free_scsi_buf;
-
+ if (iocbqrsp == NULL) {
+ lpfc_release_scsi_buf(phba, lpfc_cmd);
+ return FAILED;
+ }
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
"0703 Issue target reset to TGT %d LUN %d "
"rpi x%x nlp_flag x%x\n", cmnd->device->id,
cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
- iocb_status = lpfc_sli_issue_iocb_wait(phba,
- &phba->sli.ring[phba->sli.fcp_ring],
- iocbq, iocbqrsp, lpfc_cmd->timeout);
-
- if (iocb_status == IOCB_TIMEDOUT)
+ status = lpfc_sli_issue_iocb_wait(phba,
+ &phba->sli.ring[phba->sli.fcp_ring],
+ iocbq, iocbqrsp, lpfc_cmd->timeout);
+ if (status == IOCB_TIMEDOUT) {
iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
-
- if (iocb_status == IOCB_SUCCESS)
- ret = SUCCESS;
- else
- ret = iocb_status;
-
- cmd_result = iocbqrsp->iocb.un.ulpWord[4];
- cmd_status = iocbqrsp->iocb.ulpStatus;
-
+ ret = TIMEOUT_ERROR;
+ } else {
+ if (status != IOCB_SUCCESS)
+ ret = FAILED;
+ lpfc_release_scsi_buf(phba, lpfc_cmd);
+ }
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+ "0713 SCSI layer issued device reset (%d, %d) "
+ "return x%x status x%x result x%x\n",
+ cmnd->device->id, cmnd->device->lun, ret,
+ iocbqrsp->iocb.ulpStatus,
+ iocbqrsp->iocb.un.ulpWord[4]);
lpfc_sli_release_iocbq(phba, iocbqrsp);
-
- /*
- * All outstanding txcmplq I/Os should have been aborted by the device.
- * Unfortunately, some targets do not abide by this forcing the driver
- * to double check.
- */
cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, cmnd->device->lun,
- LPFC_CTX_LUN);
+ LPFC_CTX_TGT);
if (cnt)
lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
cmnd->device->id, cmnd->device->lun,
- LPFC_CTX_LUN);
- loopcnt = 0;
- while(cnt) {
- schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ);
-
- if (++loopcnt
- > (2 * vport->cfg_devloss_tmo)/LPFC_RESET_WAIT)
- break;
-
+ LPFC_CTX_TGT);
+ later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies;
+ while (time_after(later, jiffies) && cnt) {
+ schedule_timeout_uninterruptible(msecs_to_jiffies(20));
cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id,
- cmnd->device->lun, LPFC_CTX_LUN);
+ cmnd->device->lun, LPFC_CTX_TGT);
}
-
if (cnt) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
"0719 device reset I/O flush failure: "
"cnt x%x\n", cnt);
ret = FAILED;
}
-
-out_free_scsi_buf:
- if (iocb_status != IOCB_TIMEDOUT) {
- lpfc_release_scsi_buf(phba, lpfc_cmd);
- }
- lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
- "0713 SCSI layer issued device reset (%d, %d) "
- "return x%x status x%x result x%x\n",
- cmnd->device->id, cmnd->device->lun, ret,
- cmd_status, cmd_result);
-out:
return ret;
}
struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ndlp = NULL;
int match;
- int ret = FAILED, i, err_count = 0;
- int cnt, loopcnt;
+ int ret = SUCCESS, status, i;
+ int cnt;
struct lpfc_scsi_buf * lpfc_cmd;
+ unsigned long later;
lpfc_block_error_handler(cmnd);
-
- lpfc_cmd = lpfc_get_scsi_buf(phba);
- if (lpfc_cmd == NULL)
- goto out;
-
- /* The lpfc_cmd storage is reused. Set all loop invariants. */
- lpfc_cmd->timeout = 60;
-
/*
* Since the driver manages a single bus device, reset all
* targets known to the driver. Should any target reset
match = 0;
spin_lock_irq(shost->host_lock);
list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
+ if (!NLP_CHK_NODE_ACT(ndlp))
+ continue;
if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
- i == ndlp->nlp_sid &&
+ ndlp->nlp_sid == i &&
ndlp->rport) {
match = 1;
break;
spin_unlock_irq(shost->host_lock);
if (!match)
continue;
-
- ret = lpfc_scsi_tgt_reset(lpfc_cmd, vport, i,
- cmnd->device->lun,
- ndlp->rport->dd_data);
- if (ret != SUCCESS) {
+ lpfc_cmd = lpfc_get_scsi_buf(phba);
+ if (lpfc_cmd) {
+ lpfc_cmd->timeout = 60;
+ status = lpfc_scsi_tgt_reset(lpfc_cmd, vport, i,
+ cmnd->device->lun,
+ ndlp->rport->dd_data);
+ if (status != TIMEOUT_ERROR)
+ lpfc_release_scsi_buf(phba, lpfc_cmd);
+ }
+ if (!lpfc_cmd || status != SUCCESS) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
"0700 Bus Reset on target %d failed\n",
i);
- err_count++;
- break;
+ ret = FAILED;
}
}
-
- if (ret != IOCB_TIMEDOUT)
- lpfc_release_scsi_buf(phba, lpfc_cmd);
-
- if (err_count == 0)
- ret = SUCCESS;
- else
- ret = FAILED;
-
/*
* All outstanding txcmplq I/Os should have been aborted by
* the targets. Unfortunately, some targets do not abide by
if (cnt)
lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
0, 0, LPFC_CTX_HOST);
- loopcnt = 0;
- while(cnt) {
- schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ);
-
- if (++loopcnt
- > (2 * vport->cfg_devloss_tmo)/LPFC_RESET_WAIT)
- break;
-
+ later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies;
+ while (time_after(later, jiffies) && cnt) {
+ schedule_timeout_uninterruptible(msecs_to_jiffies(20));
cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST);
}
-
if (cnt) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
"0715 Bus Reset I/O flush failure: "
"cnt x%x left x%x\n", cnt, i);
ret = FAILED;
}
-
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
"0714 SCSI layer issued Bus Reset Data: x%x\n", ret);
-out:
return ret;
}
.slave_destroy = lpfc_slave_destroy,
.scan_finished = lpfc_scan_finished,
.this_id = -1,
- .sg_tablesize = LPFC_SG_SEG_CNT,
- .use_sg_chaining = ENABLE_SG_CHAINING,
+ .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT,
.cmd_per_lun = LPFC_CMD_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = lpfc_hba_attrs,
.slave_destroy = lpfc_slave_destroy,
.scan_finished = lpfc_scan_finished,
.this_id = -1,
- .sg_tablesize = LPFC_SG_SEG_CNT,
+ .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT,
.cmd_per_lun = LPFC_CMD_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
- .use_sg_chaining = ENABLE_SG_CHAINING,
.shost_attrs = lpfc_vport_attrs,
.max_sectors = 0xFFFF,
};