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 + -
显示快捷键?