lpfc_scsi.c
来自「linux 内核源代码」· C语言 代码 · 共 1,469 行 · 第 1/3 页
C
1,469 行
* least the underflow value or fail. */ if (!(resp_info & SNS_LEN_VALID) && (scsi_status == SAM_STAT_GOOD) && (scsi_bufflen(cmnd) - scsi_get_resid(cmnd) < cmnd->underflow)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, "0717 FCP command x%x residual " "underrun converted to error " "Data: x%x x%x x%x\n", cmnd->cmnd[0], scsi_bufflen(cmnd), scsi_get_resid(cmnd), cmnd->underflow); host_status = DID_ERROR; } } else if (resp_info & RESID_OVER) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "0720 FCP command x%x residual overrun error. " "Data: x%x x%x \n", cmnd->cmnd[0], scsi_bufflen(cmnd), scsi_get_resid(cmnd)); host_status = DID_ERROR; /* * Check SLI validation that all the transfer was actually done * (fcpi_parm should be zero). Apply check only to reads. */ } else if ((scsi_status == SAM_STAT_GOOD) && fcpi_parm && (cmnd->sc_data_direction == DMA_FROM_DEVICE)) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR, "0734 FCP Read Check Error Data: " "x%x x%x x%x x%x\n", be32_to_cpu(fcpcmd->fcpDl), be32_to_cpu(fcprsp->rspResId), fcpi_parm, cmnd->cmnd[0]); host_status = DID_ERROR; scsi_set_resid(cmnd, scsi_bufflen(cmnd)); } out: cmnd->result = ScsiResult(host_status, scsi_status);}static voidlpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, struct lpfc_iocbq *pIocbOut){ struct lpfc_scsi_buf *lpfc_cmd = (struct lpfc_scsi_buf *) pIocbIn->context1; struct lpfc_vport *vport = pIocbIn->vport; struct lpfc_rport_data *rdata = lpfc_cmd->rdata; struct lpfc_nodelist *pnode = rdata->pnode; struct scsi_cmnd *cmd = lpfc_cmd->pCmd; int result; struct scsi_device *sdev, *tmp_sdev; int depth = 0; lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; lpfc_cmd->status = pIocbOut->iocb.ulpStatus; if (lpfc_cmd->status) { if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT && (lpfc_cmd->result & IOERR_DRVR_MASK)) lpfc_cmd->status = IOSTAT_DRIVER_REJECT; else if (lpfc_cmd->status >= IOSTAT_CNT) lpfc_cmd->status = IOSTAT_DEFAULT; lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "0729 FCP cmd x%x failed <%d/%d> " "status: x%x result: x%x Data: x%x x%x\n", cmd->cmnd[0], cmd->device ? cmd->device->id : 0xffff, cmd->device ? cmd->device->lun : 0xffff, lpfc_cmd->status, lpfc_cmd->result, pIocbOut->iocb.ulpContext, lpfc_cmd->cur_iocbq.iocb.ulpIoTag); switch (lpfc_cmd->status) { case IOSTAT_FCP_RSP_ERROR: /* Call FCP RSP handler to determine result */ lpfc_handle_fcp_err(vport, lpfc_cmd, pIocbOut); break; case IOSTAT_NPORT_BSY: case IOSTAT_FABRIC_BSY: cmd->result = ScsiResult(DID_BUS_BUSY, 0); break; case IOSTAT_LOCAL_REJECT: if (lpfc_cmd->result == RJT_UNAVAIL_PERM || lpfc_cmd->result == IOERR_NO_RESOURCES || lpfc_cmd->result == RJT_LOGIN_REQUIRED) { cmd->result = ScsiResult(DID_REQUEUE, 0); break; } /* else: fall through */ default: cmd->result = ScsiResult(DID_ERROR, 0); break; } if ((pnode == NULL ) || (pnode->nlp_state != NLP_STE_MAPPED_NODE)) cmd->result = ScsiResult(DID_BUS_BUSY, SAM_STAT_BUSY); } else { cmd->result = ScsiResult(DID_OK, 0); } if (cmd->result || lpfc_cmd->fcp_rsp->rspSnsLen) { uint32_t *lp = (uint32_t *)cmd->sense_buffer; lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, "0710 Iodone <%d/%d> cmd %p, error " "x%x SNS x%x x%x Data: x%x x%x\n", cmd->device->id, cmd->device->lun, cmd, cmd->result, *lp, *(lp + 3), cmd->retries, scsi_get_resid(cmd)); } result = cmd->result; sdev = cmd->device; lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); cmd->scsi_done(cmd); if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { lpfc_release_scsi_buf(phba, lpfc_cmd); return; } if (!result) lpfc_rampup_queue_depth(vport, sdev); if (!result && pnode != NULL && ((jiffies - pnode->last_ramp_up_time) > LPFC_Q_RAMP_UP_INTERVAL * HZ) && ((jiffies - pnode->last_q_full_time) > LPFC_Q_RAMP_UP_INTERVAL * HZ) && (vport->cfg_lun_queue_depth > sdev->queue_depth)) { shost_for_each_device(tmp_sdev, sdev->host) { if (vport->cfg_lun_queue_depth > tmp_sdev->queue_depth){ if (tmp_sdev->id != sdev->id) continue; if (tmp_sdev->ordered_tags) scsi_adjust_queue_depth(tmp_sdev, MSG_ORDERED_TAG, tmp_sdev->queue_depth+1); else scsi_adjust_queue_depth(tmp_sdev, MSG_SIMPLE_TAG, tmp_sdev->queue_depth+1); pnode->last_ramp_up_time = jiffies; } } } /* * 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) { pnode->last_q_full_time = jiffies; shost_for_each_device(tmp_sdev, sdev->host) { if (tmp_sdev->id != sdev->id) continue; depth = scsi_track_queue_full(tmp_sdev, tmp_sdev->queue_depth - 1); } /* * The queue depth cannot be lowered any more. * Modify the returned error code to store * the final depth value set by * scsi_track_queue_full. */ if (depth == -1) depth = sdev->host->cmd_per_lun; if (depth) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "0711 detected queue full - lun queue " "depth adjusted to %d.\n", depth); } } lpfc_release_scsi_buf(phba, lpfc_cmd);}static voidlpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_nodelist *pnode){ struct lpfc_hba *phba = vport->phba; struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; struct lpfc_iocbq *piocbq = &(lpfc_cmd->cur_iocbq); int datadir = scsi_cmnd->sc_data_direction; char tag[2]; lpfc_cmd->fcp_rsp->rspSnsLen = 0; /* clear task management bits */ lpfc_cmd->fcp_cmnd->fcpCntl2 = 0; int_to_scsilun(lpfc_cmd->pCmd->device->lun, &lpfc_cmd->fcp_cmnd->fcp_lun); memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, 16); if (scsi_populate_tag_msg(scsi_cmnd, tag)) { switch (tag[0]) { case HEAD_OF_QUEUE_TAG: fcp_cmnd->fcpCntl1 = HEAD_OF_Q; break; case ORDERED_QUEUE_TAG: fcp_cmnd->fcpCntl1 = ORDERED_Q; break; default: fcp_cmnd->fcpCntl1 = SIMPLE_Q; break; } } else fcp_cmnd->fcpCntl1 = 0; /* * There are three possibilities here - use scatter-gather segment, use * the single mapping, or neither. Start the lpfc command prep by * bumping the bpl beyond the fcp_cmnd and fcp_rsp regions to the first * data bde entry. */ if (scsi_sg_count(scsi_cmnd)) { if (datadir == DMA_TO_DEVICE) { iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR; iocb_cmd->un.fcpi.fcpi_parm = 0; iocb_cmd->ulpPU = 0; fcp_cmnd->fcpCntl3 = WRITE_DATA; phba->fc4OutputRequests++; } else { iocb_cmd->ulpCommand = CMD_FCP_IREAD64_CR; iocb_cmd->ulpPU = PARM_READ_CHECK; iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd); fcp_cmnd->fcpCntl3 = READ_DATA; phba->fc4InputRequests++; } } else { iocb_cmd->ulpCommand = CMD_FCP_ICMND64_CR; iocb_cmd->un.fcpi.fcpi_parm = 0; iocb_cmd->ulpPU = 0; fcp_cmnd->fcpCntl3 = 0; phba->fc4ControlRequests++; } /* * Finish initializing those IOCB fields that are independent * of the scsi_cmnd request_buffer */ piocbq->iocb.ulpContext = pnode->nlp_rpi; if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE) piocbq->iocb.ulpFCP2Rcvy = 1; piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f); piocbq->context1 = lpfc_cmd; piocbq->iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl; piocbq->iocb.ulpTimeout = lpfc_cmd->timeout; piocbq->vport = vport;}static intlpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, unsigned int lun, uint8_t task_mgmt_cmd){ struct lpfc_iocbq *piocbq; IOCB_t *piocb; struct fcp_cmnd *fcp_cmnd; struct lpfc_rport_data *rdata = lpfc_cmd->rdata; struct lpfc_nodelist *ndlp = rdata->pnode; if ((ndlp == NULL) || (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) { return 0; } piocbq = &(lpfc_cmd->cur_iocbq); piocbq->vport = vport; piocb = &piocbq->iocb; fcp_cmnd = lpfc_cmd->fcp_cmnd; int_to_scsilun(lun, &lpfc_cmd->fcp_cmnd->fcp_lun); fcp_cmnd->fcpCntl2 = task_mgmt_cmd; piocb->ulpCommand = CMD_FCP_ICMND64_CR; piocb->ulpContext = ndlp->nlp_rpi; if (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) { piocb->ulpFCP2Rcvy = 1; } piocb->ulpClass = (ndlp->nlp_fcp_info & 0x0f); /* ulpTimeout is only one byte */ if (lpfc_cmd->timeout > 0xff) { /* * Do not timeout the command at the firmware level. * The driver will provide the timeout mechanism. */ piocb->ulpTimeout = 0; } else { piocb->ulpTimeout = lpfc_cmd->timeout; } return 1;}static voidlpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocbq, struct lpfc_iocbq *rspiocbq){ struct lpfc_scsi_buf *lpfc_cmd = (struct lpfc_scsi_buf *) cmdiocbq->context1; if (lpfc_cmd) lpfc_release_scsi_buf(phba, lpfc_cmd); return;}static intlpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport, unsigned tgt_id, unsigned int lun, struct lpfc_rport_data *rdata){ struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *iocbq; struct lpfc_iocbq *iocbqrsp; int ret; if (!rdata->pnode) return FAILED; lpfc_cmd->rdata = rdata; ret = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun, FCP_TARGET_RESET); if (!ret) return FAILED; iocbq = &lpfc_cmd->cur_iocbq; iocbqrsp = lpfc_sli_get_iocbq(phba); if (!iocbqrsp) return FAILED; /* Issue Target Reset to TGT <num> */ 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, &phba->sli.ring[phba->sli.fcp_ring], iocbq, iocbqrsp, lpfc_cmd->timeout); if (ret != IOCB_SUCCESS) { if (ret == IOCB_TIMEDOUT) iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; lpfc_cmd->status = IOSTAT_DRIVER_REJECT; } else { ret = SUCCESS; lpfc_cmd->result = iocbqrsp->iocb.un.ulpWord[4]; lpfc_cmd->status = iocbqrsp->iocb.ulpStatus; if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT && (lpfc_cmd->result & IOERR_DRVR_MASK)) lpfc_cmd->status = IOSTAT_DRIVER_REJECT; } lpfc_sli_release_iocbq(phba, iocbqrsp); return ret;}const char *lpfc_info(struct Scsi_Host *host){ struct lpfc_vport *vport = (struct lpfc_vport *) host->hostdata; struct lpfc_hba *phba = vport->phba; int len; static char lpfcinfobuf[384]; memset(lpfcinfobuf,0,384); if (phba && phba->pcidev){ strncpy(lpfcinfobuf, phba->ModelDesc, 256); len = strlen(lpfcinfobuf); snprintf(lpfcinfobuf + len, 384-len, " on PCI bus %02x device %02x irq %d", phba->pcidev->bus->number, phba->pcidev->devfn, phba->pcidev->irq); len = strlen(lpfcinfobuf); if (phba->Port[0]) { snprintf(lpfcinfobuf + len, 384-len, " port %s", phba->Port); } } return lpfcinfobuf;}static __inline__ void lpfc_poll_rearm_timer(struct lpfc_hba * phba){ unsigned long poll_tmo_expires = (jiffies + msecs_to_jiffies(phba->cfg_poll_tmo)); if (phba->sli.ring[LPFC_FCP_RING].txcmplq_cnt) mod_timer(&phba->fcp_poll_timer, poll_tmo_expires);}void lpfc_poll_start_timer(struct lpfc_hba * phba){ lpfc_poll_rearm_timer(phba);}void lpfc_poll_timeout(unsigned long ptr){ struct lpfc_hba *phba = (struct lpfc_hba *) ptr; if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { lpfc_sli_poll_fcp_ring (phba); if (phba->cfg_poll & DISABLE_FCP_RING_INT) lpfc_poll_rearm_timer(phba); }}static intlpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)){ struct Scsi_Host *shost = cmnd->device->host; struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; 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; struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); int err; err = fc_remote_port_chkready(rport); if (err) { cmnd->result = err; goto out_fail_command; } /* * Catch race where our node has transitioned, but the * transport is still transitioning. */ if (!ndlp) { cmnd->result = ScsiResult(DID_BUS_BUSY, 0); goto out_fail_command; } lpfc_cmd = lpfc_get_scsi_buf(phba); if (lpfc_cmd == NULL) { lpfc_adjust_queue_depth(phba); lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, "0707 driver's buffer pool is empty, " "IO busied\n"); goto out_host_busy; } /* * Store the midlayer's command structure for the completion phase * and complete the command initialization. */ lpfc_cmd->pCmd = cmnd; lpfc_cmd->rdata = rdata; lpfc_cmd->timeout = 0; cmnd->host_scribble = (unsigned char *)lpfc_cmd; cmnd->scsi_done = done; err = lpfc_scsi_prep_dma_buf(phba, lpfc_cmd); if (err) goto out_host_busy_free_buf; lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp); err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring], &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB); if (err) goto out_host_busy_free_buf; if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { lpfc_sli_poll_fcp_ring(phba); if (phba->cfg_poll & DISABLE_FCP_RING_INT) lpfc_poll_rearm_timer(phba); }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?