* and the BPL BDE is setup in the IOCB.
*/
static struct lpfc_scsi_buf *
-lpfc_get_scsi_buf(struct lpfc_hba * phba)
+lpfc_new_scsi_buf(struct lpfc_hba * phba)
{
struct lpfc_scsi_buf *psb;
struct ulp_bde64 *bpl;
kfree (psb);
return NULL;
}
+ psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP;
psb->fcp_cmnd = psb->data;
psb->fcp_rsp = psb->data + sizeof(struct fcp_cmnd);
return psb;
}
-static void
-lpfc_free_scsi_buf(struct lpfc_scsi_buf * psb)
+struct lpfc_scsi_buf*
+lpfc_sli_get_scsi_buf(struct lpfc_hba * phba)
{
- struct lpfc_hba *phba = psb->scsi_hba;
+ struct lpfc_scsi_buf * lpfc_cmd = NULL;
+ struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
+
+ list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
+ return lpfc_cmd;
+}
+static void
+lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
+{
/*
* There are only two special cases to consider. (1) the scsi command
* requested scatter-gather usage or (2) the scsi command allocated
}
}
+ psb->pCmd = NULL;
list_add_tail(&psb->list, &phba->lpfc_scsi_buf_list);
}
*lp, *(lp + 3), cmd->retries, cmd->resid);
}
+ cmd->scsi_done(cmd);
+
spin_lock_irqsave(phba->host->host_lock, iflag);
- lpfc_free_scsi_buf(lpfc_cmd);
- cmd->host_scribble = NULL;
+ lpfc_release_scsi_buf(phba, lpfc_cmd);
spin_unlock_irqrestore(phba->host->host_lock, iflag);
-
- cmd->scsi_done(cmd);
}
static void
lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba)
{
struct lpfc_iocbq *iocbq;
- struct lpfc_iocbq *iocbqrsp = NULL;
- struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
+ struct lpfc_iocbq *iocbqrsp;
int ret;
ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_TARGET_RESET);
lpfc_cmd->scsi_hba = phba;
iocbq = &lpfc_cmd->cur_iocbq;
- list_remove_head(lpfc_iocb_list, iocbqrsp, struct lpfc_iocbq, list);
+ iocbqrsp = lpfc_sli_get_iocbq(phba);
+
if (!iocbqrsp)
return FAILED;
lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
}
- /*
- * All outstanding txcmplq I/Os should have been aborted by the target.
- * Unfortunately, some targets do not abide by this forcing the driver
- * to double check.
- */
- lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
- lpfc_cmd->pCmd->device->id,
- lpfc_cmd->pCmd->device->lun, 0, LPFC_CTX_TGT);
-
lpfc_sli_release_iocbq(phba, iocbqrsp);
return ret;
}
-static void
-lpfc_scsi_cmd_iocb_cleanup (struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
- struct lpfc_iocbq *pIocbOut)
-{
- unsigned long iflag;
- struct lpfc_scsi_buf *lpfc_cmd =
- (struct lpfc_scsi_buf *) pIocbIn->context1;
-
- spin_lock_irqsave(phba->host->host_lock, iflag);
- lpfc_free_scsi_buf(lpfc_cmd);
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
-}
-
-static void
-lpfc_scsi_cmd_iocb_cmpl_aborted(struct lpfc_hba *phba,
- struct lpfc_iocbq *pIocbIn,
- struct lpfc_iocbq *pIocbOut)
-{
- struct scsi_cmnd *ml_cmd =
- ((struct lpfc_scsi_buf *) pIocbIn->context1)->pCmd;
-
- lpfc_scsi_cmd_iocb_cleanup (phba, pIocbIn, pIocbOut);
- ml_cmd->host_scribble = NULL;
-}
-
const char *
lpfc_info(struct Scsi_Host *host)
{
struct lpfc_sli *psli = &phba->sli;
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
struct lpfc_nodelist *ndlp = rdata->pnode;
- struct lpfc_scsi_buf *lpfc_cmd = NULL;
+ struct lpfc_scsi_buf *lpfc_cmd;
struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
- struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
int err;
err = fc_remote_port_chkready(rport);
cmnd->result = ScsiResult(DID_BUS_BUSY, 0);
goto out_fail_command;
}
-
- list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
+ lpfc_cmd = lpfc_sli_get_scsi_buf (phba);
if (lpfc_cmd == NULL) {
printk(KERN_WARNING "%s: No buffer available - list empty, "
"total count %d\n", __FUNCTION__, phba->total_scsi_bufs);
return 0;
out_host_busy_free_buf:
- lpfc_free_scsi_buf(lpfc_cmd);
+ lpfc_release_scsi_buf(phba, lpfc_cmd);
cmnd->host_scribble = NULL;
out_host_busy:
return SCSI_MLQUEUE_HOST_BUSY;
struct lpfc_hba *phba =
(struct lpfc_hba *)cmnd->device->host->hostdata[0];
struct lpfc_sli_ring *pring = &phba->sli.ring[phba->sli.fcp_ring];
- struct lpfc_iocbq *iocb, *next_iocb;
- struct lpfc_iocbq *abtsiocb = NULL;
+ struct lpfc_iocbq *iocb;
+ struct lpfc_iocbq *abtsiocb;
struct lpfc_scsi_buf *lpfc_cmd;
- struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
IOCB_t *cmd, *icmd;
- unsigned long snum;
- unsigned int id, lun;
unsigned int loop_count = 0;
- int ret = IOCB_SUCCESS;
+ int ret = SUCCESS;
- /*
- * If the host_scribble data area is NULL, then the driver has already
- * completed this command, but the midlayer did not see the completion
- * before the eh fired. Just return SUCCESS.
- */
- lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
- if (!lpfc_cmd)
- return SUCCESS;
- /* save these now since lpfc_cmd can be freed */
- id = lpfc_cmd->pCmd->device->id;
- lun = lpfc_cmd->pCmd->device->lun;
- snum = lpfc_cmd->pCmd->serial_number;
+ lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
+ BUG_ON(!lpfc_cmd);
- list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
- cmd = &iocb->iocb;
- if (iocb->context1 != lpfc_cmd)
- continue;
+ /*
+ * If pCmd field of the corresponding lpfc_scsi_buf structure
+ * points to a different SCSI command, then the driver has
+ * already completed this command, but the midlayer did not
+ * see the completion before the eh fired. Just return
+ * SUCCESS.
+ */
+ iocb = &lpfc_cmd->cur_iocbq;
+ if (lpfc_cmd->pCmd != cmnd)
+ goto out;
- list_del_init(&iocb->list);
- pring->txq_cnt--;
- if (!iocb->iocb_cmpl)
- lpfc_sli_release_iocbq(phba, iocb);
- else {
- cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
- cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
- lpfc_scsi_cmd_iocb_cmpl_aborted(phba, iocb, iocb);
- }
+ BUG_ON(iocb->context1 != lpfc_cmd);
+ abtsiocb = lpfc_sli_get_iocbq(phba);
+ if (abtsiocb == NULL) {
+ ret = FAILED;
goto out;
}
- list_remove_head(lpfc_iocb_list, abtsiocb, struct lpfc_iocbq, list);
- if (abtsiocb == NULL)
- return FAILED;
-
/*
- * The scsi command was not in the txq. Check the txcmplq and if it is
- * found, send an abort to the FW.
+ * The scsi command can not be in txq and it is in flight because the
+ * pCmd is still pointig at the SCSI command we have to abort. There
+ * is no need to search the txcmplq. Just send an abort to the FW.
*/
- list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
- if (iocb->context1 != lpfc_cmd)
- continue;
- iocb->iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl_aborted;
- cmd = &iocb->iocb;
- icmd = &abtsiocb->iocb;
- icmd->un.acxri.abortType = ABORT_TYPE_ABTS;
- icmd->un.acxri.abortContextTag = cmd->ulpContext;
- icmd->un.acxri.abortIoTag = cmd->ulpIoTag;
-
- icmd->ulpLe = 1;
- icmd->ulpClass = cmd->ulpClass;
- if (phba->hba_state >= LPFC_LINK_UP)
- icmd->ulpCommand = CMD_ABORT_XRI_CN;
- else
- icmd->ulpCommand = CMD_CLOSE_XRI_CN;
+ cmd = &iocb->iocb;
+ icmd = &abtsiocb->iocb;
+ icmd->un.acxri.abortType = ABORT_TYPE_ABTS;
+ icmd->un.acxri.abortContextTag = cmd->ulpContext;
+ icmd->un.acxri.abortIoTag = cmd->ulpIoTag;
- abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;
- if (lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0) ==
- IOCB_ERROR) {
- lpfc_sli_release_iocbq(phba, abtsiocb);
- ret = IOCB_ERROR;
- break;
- }
+ icmd->ulpLe = 1;
+ icmd->ulpClass = cmd->ulpClass;
+ if (phba->hba_state >= LPFC_LINK_UP)
+ icmd->ulpCommand = CMD_ABORT_XRI_CN;
+ else
+ icmd->ulpCommand = CMD_CLOSE_XRI_CN;
- /* Wait for abort to complete */
- while (cmnd->host_scribble)
- {
- spin_unlock_irq(phba->host->host_lock);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(LPFC_ABORT_WAIT*HZ);
- spin_lock_irq(phba->host->host_lock);
- if (++loop_count
- > (2 * phba->cfg_nodev_tmo)/LPFC_ABORT_WAIT)
- break;
- }
+ abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;
+ if (lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0) == IOCB_ERROR) {
+ lpfc_sli_release_iocbq(phba, abtsiocb);
+ ret = FAILED;
+ goto out;
+ }
- if(cmnd->host_scribble) {
- lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0748 abort handler timed "
- "out waiting for abort to "
- "complete. Data: "
- "x%x x%x x%x x%lx\n",
- phba->brd_no, ret, id, lun, snum);
- cmnd->host_scribble = NULL;
- iocb->iocb_cmpl = lpfc_scsi_cmd_iocb_cleanup;
- ret = IOCB_ERROR;
- }
+ /* Wait for abort to complete */
+ while (lpfc_cmd->pCmd == cmnd)
+ {
+ spin_unlock_irq(phba->host->host_lock);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(LPFC_ABORT_WAIT*HZ);
+ spin_lock_irq(phba->host->host_lock);
+ if (++loop_count
+ > (2 * phba->cfg_nodev_tmo)/LPFC_ABORT_WAIT)
+ break;
+ }
- break;
+ if (lpfc_cmd->pCmd == cmnd) {
+ ret = FAILED;
+ lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
+ "%d:0748 abort handler timed out waiting for "
+ "abort to complete: ret %#x, ID %d, LUN %d, "
+ "snum %#lx\n",
+ phba->brd_no, ret, cmnd->device->id,
+ cmnd->device->lun, cmnd->serial_number);
}
out:
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d:0749 SCSI layer issued abort device "
- "Data: x%x x%x x%x x%lx\n",
- phba->brd_no, ret, id, lun, snum);
+ "%d:0749 SCSI layer issued abort device: ret %#x, "
+ "ID %d, LUN %d, snum %#lx\n",
+ phba->brd_no, ret, cmnd->device->id,
+ cmnd->device->lun, cmnd->serial_number);
- return ret == IOCB_SUCCESS ? SUCCESS : FAILED;
+ return ret;
}
static int
{
struct Scsi_Host *shost = cmnd->device->host;
struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0];
- struct lpfc_scsi_buf *lpfc_cmd = NULL;
- struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
- struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
- struct lpfc_iocbq *iocbq, *iocbqrsp = NULL;
+ struct lpfc_scsi_buf *lpfc_cmd;
+ struct lpfc_iocbq *iocbq, *iocbqrsp;
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
struct lpfc_nodelist *pnode = rdata->pnode;
int ret = FAILED;
break;
}
- list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
+ lpfc_cmd = lpfc_sli_get_scsi_buf (phba);
if (lpfc_cmd == NULL)
goto out;
iocbq = &lpfc_cmd->cur_iocbq;
/* get a buffer for this IOCB command response */
- list_remove_head(lpfc_iocb_list, iocbqrsp, struct lpfc_iocbq, list);
+ iocbqrsp = lpfc_sli_get_iocbq(phba);
if (iocbqrsp == NULL)
goto out_free_scsi_buf;
}
if (cnt) {
- lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
+ lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
"%d:0719 LUN Reset I/O flush failure: cnt x%x\n",
phba->brd_no, cnt);
+ ret = FAILED;
}
lpfc_sli_release_iocbq(phba, iocbqrsp);
phba->brd_no, lpfc_cmd->pCmd->device->id,
lpfc_cmd->pCmd->device->lun, ret, lpfc_cmd->status,
lpfc_cmd->result);
- lpfc_free_scsi_buf(lpfc_cmd);
+ lpfc_release_scsi_buf(phba, lpfc_cmd);
out:
return ret;
}
int ret = FAILED, i, err_count = 0;
int cnt, loopcnt;
unsigned int midlayer_id = 0;
- struct lpfc_scsi_buf * lpfc_cmd = NULL;
- struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
+ struct lpfc_scsi_buf * lpfc_cmd;
- list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
+ lpfc_cmd = lpfc_sli_get_scsi_buf (phba);
if (lpfc_cmd == NULL)
goto out;
phba->brd_no, cnt, i);
}
- if (!err_count)
+ if (cnt == 0)
ret = SUCCESS;
+ else
+ ret = FAILED;
- lpfc_free_scsi_buf(lpfc_cmd);
+ lpfc_release_scsi_buf(phba, lpfc_cmd);
lpfc_printf_log(phba,
KERN_ERR,
LOG_FCP,
}
for (i = 0; i < num_to_alloc; i++) {
- scsi_buf = lpfc_get_scsi_buf(phba);
+ scsi_buf = lpfc_new_scsi_buf(phba);
if (!scsi_buf) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
"%d:0706 Failed to allocate command "
LPFC_ABORT_IOCB
} lpfc_iocb_type;
+struct lpfc_iocbq *
+lpfc_sli_get_iocbq(struct lpfc_hba * phba)
+{
+ struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
+ struct lpfc_iocbq * iocbq = NULL;
+
+ list_remove_head(lpfc_iocb_list, iocbq, struct lpfc_iocbq, list);
+ return iocbq;
+}
+
void
lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq)
{
struct lpfc_iocbq *next_iocb;
struct lpfc_iocbq *cmdiocbp;
struct lpfc_iocbq *saveq;
- struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno];
uint8_t iocb_cmd_type;
lpfc_iocb_type type;
}
rmb();
- lpfc_iocb_list = &phba->lpfc_iocb_list;
while (pring->rspidx != portRspPut) {
/*
* Build a completion list and call the appropriate handler.
* received.
*/
entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx);
- list_remove_head(lpfc_iocb_list, rspiocbp, struct lpfc_iocbq,
- list);
+ rspiocbp = lpfc_sli_get_iocbq(phba);
if (rspiocbp == NULL) {
printk(KERN_ERR "%s: out of buffers! Failing "
"completion.\n", __FUNCTION__);
struct lpfc_sli_ring * pring,
struct lpfc_iocbq * cmdiocb)
{
- struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
- struct lpfc_iocbq *abtsiocbp = NULL;
+ struct lpfc_iocbq *abtsiocbp;
IOCB_t *icmd = NULL;
IOCB_t *iabt = NULL;
/* issue ABTS for this IOCB based on iotag */
- list_remove_head(lpfc_iocb_list, abtsiocbp, struct lpfc_iocbq, list);
+ abtsiocbp = lpfc_sli_get_iocbq(phba);
if (abtsiocbp == NULL)
return 0;
}
static int
-lpfc_sli_validate_iocb_cmd(struct lpfc_scsi_buf *lpfc_cmd, uint16_t tgt_id,
- uint64_t lun_id, struct lpfc_iocbq *iocb,
- uint32_t ctx, lpfc_ctx_cmd ctx_cmd)
+lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, uint16_t tgt_id,
+ uint64_t lun_id, uint32_t ctx,
+ lpfc_ctx_cmd ctx_cmd)
{
+ struct lpfc_scsi_buf *lpfc_cmd;
+ struct scsi_cmnd *cmnd;
int rc = 1;
- if (lpfc_cmd == NULL)
+ if (!(iocbq->iocb_flag & LPFC_IO_FCP))
+ return rc;
+
+ lpfc_cmd = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq);
+ cmnd = lpfc_cmd->pCmd;
+
+ if (cmnd == NULL)
return rc;
switch (ctx_cmd) {
case LPFC_CTX_LUN:
- if ((lpfc_cmd->pCmd->device->id == tgt_id) &&
- (lpfc_cmd->pCmd->device->lun == lun_id))
+ if ((cmnd->device->id == tgt_id) &&
+ (cmnd->device->lun == lun_id))
rc = 0;
break;
case LPFC_CTX_TGT:
- if (lpfc_cmd->pCmd->device->id == tgt_id)
+ if (cmnd->device->id == tgt_id)
rc = 0;
break;
case LPFC_CTX_CTX:
- if (iocb->iocb.ulpContext == ctx)
+ if (iocbq->iocb.ulpContext == ctx)
rc = 0;
+ break;
case LPFC_CTX_HOST:
rc = 0;
break;
lpfc_sli_sum_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd ctx_cmd)
{
- struct lpfc_iocbq *iocb, *next_iocb;
- IOCB_t *cmd = NULL;
- struct lpfc_scsi_buf *lpfc_cmd;
- int sum = 0, ret_val = 0;
+ struct lpfc_iocbq *iocbq;
+ int sum, i;
- /* Next check the txcmplq */
- list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
- cmd = &iocb->iocb;
-
- /* Must be a FCP command */
- if ((cmd->ulpCommand != CMD_FCP_ICMND64_CR) &&
- (cmd->ulpCommand != CMD_FCP_IWRITE64_CR) &&
- (cmd->ulpCommand != CMD_FCP_IREAD64_CR)) {
- continue;
- }
+ for (i = 1, sum = 0; i <= phba->sli.last_iotag; i++) {
+ iocbq = phba->sli.iocbq_lookup[i];
- /* context1 MUST be a struct lpfc_scsi_buf */
- lpfc_cmd = (struct lpfc_scsi_buf *) (iocb->context1);
- ret_val = lpfc_sli_validate_iocb_cmd(lpfc_cmd, tgt_id, lun_id,
- NULL, 0, ctx_cmd);
- if (ret_val != 0)
- continue;
- sum++;
+ if (lpfc_sli_validate_fcp_iocb (iocbq, tgt_id, lun_id,
+ 0, ctx_cmd) == 0)
+ sum++;
}
+
return sum;
}
uint16_t tgt_id, uint64_t lun_id, uint32_t ctx,
lpfc_ctx_cmd abort_cmd)
{
- struct lpfc_iocbq *iocb, *next_iocb;
- struct lpfc_iocbq *abtsiocb = NULL;
- struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
+ struct lpfc_iocbq *iocbq;
+ struct lpfc_iocbq *abtsiocb;
IOCB_t *cmd = NULL;
- struct lpfc_scsi_buf *lpfc_cmd;
int errcnt = 0, ret_val = 0;
+ int i;
- list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
- cmd = &iocb->iocb;
-
- /* Must be a FCP command */
- if ((cmd->ulpCommand != CMD_FCP_ICMND64_CR) &&
- (cmd->ulpCommand != CMD_FCP_IWRITE64_CR) &&
- (cmd->ulpCommand != CMD_FCP_IREAD64_CR)) {
- continue;
- }
+ for (i = 1; i <= phba->sli.last_iotag; i++) {
+ iocbq = phba->sli.iocbq_lookup[i];
- /* context1 MUST be a struct lpfc_scsi_buf */
- lpfc_cmd = (struct lpfc_scsi_buf *) (iocb->context1);
- ret_val = lpfc_sli_validate_iocb_cmd(lpfc_cmd, tgt_id, lun_id,
- iocb, ctx, abort_cmd);
- if (ret_val != 0)
+ if (lpfc_sli_validate_fcp_iocb (iocbq, tgt_id, lun_id,
+ 0, abort_cmd) != 0)
continue;
/* issue ABTS for this IOCB based on iotag */
- list_remove_head(lpfc_iocb_list, abtsiocb, struct lpfc_iocbq,
- list);
+ abtsiocb = lpfc_sli_get_iocbq(phba);
if (abtsiocb == NULL) {
errcnt++;
continue;
}
+ cmd = &iocbq->iocb;
abtsiocb->iocb.un.acxri.abortType = ABORT_TYPE_ABTS;
abtsiocb->iocb.un.acxri.abortContextTag = cmd->ulpContext;
abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag;