lpfc_scsi.c
来自「底层驱动开发」· C语言 代码 · 共 1,284 行 · 第 1/3 页
C
1,284 行
spin_lock_irqsave(phba->host->host_lock, iflag); lpfc_free_scsi_buf(lpfc_cmd); cmd->host_scribble = NULL; spin_unlock_irqrestore(phba->host->host_lock, iflag); cmd->scsi_done(cmd);}static voidlpfc_scsi_prep_cmnd(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_nodelist *pnode){ 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; 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_cmnd->device->tagged_supported) { switch (scsi_cmnd->tag) { 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_cmnd->use_sg) { 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_cmnd->request_bufflen; fcp_cmnd->fcpCntl3 = READ_DATA; phba->fc4InputRequests++; } } else if (scsi_cmnd->request_buffer && scsi_cmnd->request_bufflen) { 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_cmnd->request_bufflen; 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;}static intlpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd, uint8_t task_mgmt_cmd){ struct lpfc_sli *psli; struct lpfc_iocbq *piocbq; IOCB_t *piocb; struct fcp_cmnd *fcp_cmnd; struct scsi_device *scsi_dev = lpfc_cmd->pCmd->device; struct lpfc_rport_data *rdata = scsi_dev->hostdata; struct lpfc_nodelist *ndlp = rdata->pnode; if ((ndlp == 0) || (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) { return 0; } psli = &phba->sli; piocbq = &(lpfc_cmd->cur_iocbq); piocb = &piocbq->iocb; fcp_cmnd = lpfc_cmd->fcp_cmnd; int_to_scsilun(lpfc_cmd->pCmd->device->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; } lpfc_cmd->rdata = rdata; switch (task_mgmt_cmd) { case FCP_LUN_RESET: /* Issue LUN Reset to TGT <num> LUN <num> */ lpfc_printf_log(phba, KERN_INFO, LOG_FCP, "%d:0703 Issue LUN Reset to TGT %d LUN %d " "Data: x%x x%x\n", phba->brd_no, scsi_dev->id, scsi_dev->lun, ndlp->nlp_rpi, ndlp->nlp_flag); break; case FCP_ABORT_TASK_SET: /* Issue Abort Task Set to TGT <num> LUN <num> */ lpfc_printf_log(phba, KERN_INFO, LOG_FCP, "%d:0701 Issue Abort Task Set to TGT %d LUN %d " "Data: x%x x%x\n", phba->brd_no, scsi_dev->id, scsi_dev->lun, ndlp->nlp_rpi, ndlp->nlp_flag); break; case FCP_TARGET_RESET: /* Issue Target Reset to TGT <num> */ lpfc_printf_log(phba, KERN_INFO, LOG_FCP, "%d:0702 Issue Target Reset to TGT %d " "Data: x%x x%x\n", phba->brd_no, scsi_dev->id, ndlp->nlp_rpi, ndlp->nlp_flag); break; } return (1);}static intlpfc_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; int ret; ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_TARGET_RESET); if (!ret) return FAILED; lpfc_cmd->scsi_hba = phba; iocbq = &lpfc_cmd->cur_iocbq; list_remove_head(lpfc_iocb_list, iocbqrsp, struct lpfc_iocbq, list); if (!iocbqrsp) return FAILED; memset(iocbqrsp, 0, sizeof (struct lpfc_iocbq)); iocbq->iocb_flag |= LPFC_IO_POLL; ret = lpfc_sli_issue_iocb_wait_high_priority(phba, &phba->sli.ring[phba->sli.fcp_ring], iocbq, SLI_IOCB_HIGH_PRIORITY, iocbqrsp, lpfc_cmd->timeout); if (ret != IOCB_SUCCESS) { lpfc_cmd->status = IOSTAT_DRIVER_REJECT; ret = FAILED; } 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; } /* * 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); /* Return response IOCB to free list. */ list_add_tail(&iocbqrsp->list, lpfc_iocb_list); return ret;}static voidlpfc_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 voidlpfc_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_hba *phba = (struct lpfc_hba *) host->hostdata[0]; 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 intlpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)){ struct lpfc_hba *phba = (struct lpfc_hba *) cmnd->device->host->hostdata[0]; 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 list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list; int err = 0; /* * The target pointer is guaranteed not to be NULL because the driver * only clears the device->hostdata field in lpfc_slave_destroy. This * approach guarantees no further IO calls on this target. */ if (!ndlp) { cmnd->result = ScsiResult(DID_NO_CONNECT, 0); goto out_fail_command; } /* * A Fibre Channel target is present and functioning only when the node * state is MAPPED. Any other state is a failure. */ if (ndlp->nlp_state != NLP_STE_MAPPED_NODE) { if ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) || (ndlp->nlp_state == NLP_STE_UNUSED_NODE)) { cmnd->result = ScsiResult(DID_NO_CONNECT, 0); goto out_fail_command; } else if (ndlp->nlp_state == NLP_STE_NPR_NODE) { cmnd->result = ScsiResult(DID_BUS_BUSY, 0); goto out_fail_command; } /* * The device is most likely recovered and the driver * needs a bit more time to finish. Ask the midlayer * to retry. */ goto out_host_busy; } list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list); if (lpfc_cmd == NULL) { printk(KERN_WARNING "%s: No buffer available - list empty, " "total count %d\n", __FUNCTION__, phba->total_scsi_bufs); 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(phba, 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; return 0; out_host_busy_free_buf: lpfc_free_scsi_buf(lpfc_cmd); cmnd->host_scribble = NULL; out_host_busy: return SCSI_MLQUEUE_HOST_BUSY; out_fail_command: done(cmnd); return 0;}static int__lpfc_abort_handler(struct scsi_cmnd *cmnd){ 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_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; /* * 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; list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { cmd = &iocb->iocb; if (iocb->context1 != lpfc_cmd) continue; list_del_init(&iocb->list); pring->txq_cnt--; if (!iocb->iocb_cmpl) { list_add_tail(&iocb->list, lpfc_iocb_list); } else { cmd->ulpStatus = IOSTAT_LOCAL_REJECT; cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; lpfc_scsi_cmd_iocb_cmpl_aborted(phba, iocb, iocb); } goto out; } list_remove_head(lpfc_iocb_list, abtsiocb, struct lpfc_iocbq, list); if (abtsiocb == NULL) return FAILED;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?