⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mptscsih.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *	mptscsih_AddSGE - Add a SGE (plus chain buffers) to the *	SCSIIORequest_t Message Frame. *	@hd: Pointer to MPT_SCSI_HOST structure *	@SCpnt: Pointer to Scsi_Cmnd structure *	@pReq: Pointer to SCSIIORequest_t structure * *	Returns ... */static intmptscsih_AddSGE(MPT_SCSI_HOST *hd, Scsi_Cmnd *SCpnt,		SCSIIORequest_t *pReq, int req_idx){	char 	*psge;	char	*chainSge;	struct scatterlist *sg;	int	 frm_sz;	int	 sges_left, sg_done;	int	 chain_idx = MPT_HOST_NO_CHAIN;	int	 sgeOffset;	int	 numSgeSlots, numSgeThisFrame;	u32	 sgflags, sgdir, thisxfer = 0;	int	 chain_dma_off = 0;	int	 newIndex;	int	 ii;	dma_addr_t v2;	sgdir = le32_to_cpu(pReq->Control) & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK;	if (sgdir == MPI_SCSIIO_CONTROL_WRITE)  {		sgdir = MPT_TRANSFER_HOST_TO_IOC;	} else {		sgdir = MPT_TRANSFER_IOC_TO_HOST;	}	psge = (char *) &pReq->SGL;	frm_sz = hd->ioc->req_sz;	/* Map the data portion, if any.	 * sges_left  = 0 if no data transfer.	 */	if ( (sges_left = SCpnt->use_sg) ) {		if ( (sges_left = pci_map_sg(hd->ioc->pcidev,			       (struct scatterlist *) SCpnt->request_buffer,			       SCpnt->use_sg,			       scsi_to_pci_dma_dir(SCpnt->sc_data_direction)))			== 0 )				return FAILED;	} else if (SCpnt->request_bufflen) {		dma_addr_t	 buf_dma_addr;		scPrivate	*my_priv;		buf_dma_addr = pci_map_single(hd->ioc->pcidev,				      SCpnt->request_buffer,				      SCpnt->request_bufflen,				      scsi_to_pci_dma_dir(SCpnt->sc_data_direction));		/* We hide it here for later unmap. */		my_priv = (scPrivate *) &SCpnt->SCp;		my_priv->p1 = (void *)(ulong) buf_dma_addr;		dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",				hd->ioc->name, SCpnt, SCpnt->request_bufflen));		mptscsih_add_sge((char *) &pReq->SGL,			0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,			buf_dma_addr);		return SUCCESS;	}	/* Handle the SG case.	 */	sg = (struct scatterlist *) SCpnt->request_buffer;	sg_done  = 0;	sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);	chainSge = NULL;	/* Prior to entering this loop - the following must be set	 * current MF:  sgeOffset (bytes)	 *              chainSge (Null if original MF is not a chain buffer)	 *              sg_done (num SGE done for this MF)	 */nextSGEset:	numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) );	numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots;	sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir;	/* Get first (num - 1) SG elements	 * Skip any SG entries with a length of 0	 * NOTE: at finish, sg and psge pointed to NEXT data/location positions	 */	for (ii=0; ii < (numSgeThisFrame-1); ii++) {		thisxfer = sg_dma_len(sg);		if (thisxfer == 0) {			sg ++; /* Get next SG element from the OS */			sg_done++;			continue;		}		v2 = sg_dma_address(sg);		mptscsih_add_sge(psge, sgflags | thisxfer, v2);		sg++;		/* Get next SG element from the OS */		psge += (sizeof(u32) + sizeof(dma_addr_t));		sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));		sg_done++;	}	if (numSgeThisFrame == sges_left) {		/* Add last element, end of buffer and end of list flags.		 */		sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT |				MPT_SGE_FLAGS_END_OF_BUFFER |				MPT_SGE_FLAGS_END_OF_LIST;		/* Add last SGE and set termination flags.		 * Note: Last SGE may have a length of 0 - which should be ok.		 */		thisxfer = sg_dma_len(sg);		v2 = sg_dma_address(sg);		mptscsih_add_sge(psge, sgflags | thisxfer, v2);		/*		sg++;		psge += (sizeof(u32) + sizeof(dma_addr_t));		*/		sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));		sg_done++;		if (chainSge) {			/* The current buffer is a chain buffer,			 * but there is not another one.			 * Update the chain element			 * Offset and Length fields.			 */			mptscsih_add_chain((char *)chainSge, 0, sgeOffset, hd->ChainBufferDMA + chain_dma_off);		} else {			/* The current buffer is the original MF			 * and there is no Chain buffer.			 */			pReq->ChainOffset = 0;		}	} else {		/* At least one chain buffer is needed.		 * Complete the first MF		 *  - last SGE element, set the LastElement bit		 *  - set ChainOffset (words) for orig MF		 *             (OR finish previous MF chain buffer)		 *  - update MFStructPtr ChainIndex		 *  - Populate chain element		 * Also		 * Loop until done.		 */		dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",				hd->ioc->name, sg_done));		/* Set LAST_ELEMENT flag for last non-chain element		 * in the buffer. Since psge points at the NEXT		 * SGE element, go back one SGE element, update the flags		 * and reset the pointer. (Note: sgflags & thisxfer are already		 * set properly).		 */		if (sg_done) {			u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t)));			sgflags = le32_to_cpu(*ptmp);			sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT;			*ptmp = cpu_to_le32(sgflags);		}		if (chainSge) {			/* The current buffer is a chain buffer.			 * chainSge points to the previous Chain Element.			 * Update its chain element Offset and Length (must			 * include chain element size) fields.			 * Old chain element is now complete.			 */			u8 nextChain = (u8) (sgeOffset >> 2);			sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));			mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, hd->ChainBufferDMA + chain_dma_off);		} else {			/* The original MF buffer requires a chain buffer -			 * set the offset.			 * Last element in this MF is a chain element.			 */			pReq->ChainOffset = (u8) (sgeOffset >> 2);		}		sges_left -= sg_done;		/* NOTE: psge points to the beginning of the chain element		 * in current buffer. Get a chain buffer.		 */		if ((mptscsih_getFreeChainBuffer(hd, &newIndex)) == FAILED)			return FAILED;		/* Update the tracking arrays.		 * If chainSge == NULL, update ReqToChain, else ChainToChain		 */		if (chainSge) {			hd->ChainToChain[chain_idx] = newIndex;		} else {			hd->ReqToChain[req_idx] = newIndex;		}		chain_idx = newIndex;		chain_dma_off = hd->ioc->req_sz * chain_idx;		/* Populate the chainSGE for the current buffer.		 * - Set chain buffer pointer to psge and fill		 *   out the Address and Flags fields.		 */		chainSge = (char *) psge;		dsgprintk((KERN_INFO "  Current buff @ %p (index 0x%x)",				psge, req_idx));		/* Start the SGE for the next buffer		 */		psge = (char *) (hd->ChainBuffer + chain_dma_off);		sgeOffset = 0;		sg_done = 0;		dsgprintk((KERN_INFO "  Chain buff @ %p (index 0x%x)\n",				psge, chain_idx));		/* Start the SGE for the next buffer		 */		goto nextSGEset;	}	return SUCCESS;} /* mptscsih_AddSGE() *//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* *	mptscsih_io_done - Main SCSI IO callback routine registered to *	Fusion MPT (base) driver *	@ioc: Pointer to MPT_ADAPTER structure *	@mf: Pointer to original MPT request frame *	@r: Pointer to MPT reply frame (NULL if TurboReply) * *	This routine is called from mpt.c::mpt_interrupt() at the completion *	of any SCSI IO request. *	This routine is registered with the Fusion MPT (base) driver at driver *	load/init time via the mpt_register() API call. * *	Returns 1 indicating alloc'd request frame ptr should be freed. */static intmptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr){	Scsi_Cmnd	*sc;	MPT_SCSI_HOST	*hd;	SCSIIORequest_t	*pScsiReq;	SCSIIOReply_t	*pScsiReply;#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)	unsigned long	 flags;#endif	u16		 req_idx;	hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);	sc = hd->ScsiLookup[req_idx];	if (sc == NULL) {		MPIHeader_t *hdr = (MPIHeader_t *)mf;		/* Remark: writeSDP1 will use the ScsiDoneCtx		 * If a SCSI I/O cmd, device disabled by OS and		 * completion done. Cannot touch sc struct. Just free mem.		 */		if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST)			printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", ioc->name);		mptscsih_freeChainBuffers(hd, req_idx);		return 1;	}	dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",			ioc->name, mf, mr, sc, req_idx));	sc->result = DID_OK << 16;		/* Set default reply as OK */	pScsiReq = (SCSIIORequest_t *) mf;	pScsiReply = (SCSIIOReply_t *) mr;#ifdef MPTSCSIH_DBG_TIMEOUT	if (ioc->timeout_cnt > 0) {		int ii, left = 0;		for (ii=0; ii < 8; ii++) {			if (sc == foo_to[ii]) {				printk(MYIOC_s_INFO_FMT "complete (%p, %ld)\n",					ioc->name, sc, jiffies);				foo_to[ii] = NULL;			}			if (foo_to[ii] != NULL)				left++;		}		if (left == 0) {			ioc->timeout_maxcnt = 0;			ioc->timeout_cnt = 0;		}	}#endif	if (pScsiReply == NULL) {		/* special context reply handling */		/* If regular Inquiry cmd - save inquiry data		 */		if (pScsiReq->CDB[0] == INQUIRY) {			int	 dlen;			dlen = le32_to_cpu(pScsiReq->DataLength);			mptscsih_initTarget(hd,					sc->channel,					sc->target,					pScsiReq->LUN[1],					sc->buffer,					dlen);		}	} else {		u32	 xfer_cnt;		u16	 status;		u8	 scsi_state, scsi_status;		status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;		scsi_state = pScsiReply->SCSIState;		dprintk((KERN_NOTICE "  Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n",				ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1],				mf, mr, sc));		dprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh"				", SCSIStatus=%02xh, IOCLogInfo=%08xh\n",				status, scsi_state, pScsiReply->SCSIStatus,				le32_to_cpu(pScsiReply->IOCLogInfo)));		if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)			copy_sense_data(sc, hd, mf, pScsiReply);		switch(status) {		case MPI_IOCSTATUS_BUSY:			/* 0x0002 */			/* CHECKME!			 * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry)			 * But not: DID_BUS_BUSY lest one risk			 * killing interrupt handler:-(			 */			sc->result = STS_BUSY;			break;		case MPI_IOCSTATUS_SCSI_INVALID_BUS:		/* 0x0041 */		case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:	/* 0x0042 */			sc->result = DID_BAD_TARGET << 16;			break;		case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:	/* 0x0043 */			/* Spoof to SCSI Selection Timeout! */			sc->result = DID_NO_CONNECT << 16;			if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)				hd->sel_timeout[pScsiReq->TargetID]++;			break;		case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:	/* 0x0048 */#ifndef MPT_SCSI_USE_NEW_EH			search_taskQ_for_cmd(sc, hd);#endif			/* Linux handles an unsolicited DID_RESET better			 * than an unsolicited DID_ABORT.			 */			sc->result = DID_RESET << 16;			/* GEM Workaround. */			if (hd->is_spi)				mptscsih_no_negotiate(hd, sc->target);			break;		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */#ifndef MPT_SCSI_USE_NEW_EH			search_taskQ_for_cmd(sc, hd);#endif			sc->result = DID_RESET << 16;			/* GEM Workaround. */			if (hd->is_spi)				mptscsih_no_negotiate(hd, sc->target);			break;		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */			sc->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | 					(CHECK_CONDITION << 1);			sc->sense_buffer[0] = 0x70;			sc->sense_buffer[2] = NO_SENSE;			sc->sense_buffer[12] = 0;			sc->sense_buffer[13] = 0;			dprintk((KERN_NOTICE "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->target));			break;		case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */			/*			 *  Do upfront check for valid SenseData and give it			 *  precedence!			 */			scsi_status = pScsiReply->SCSIStatus;			sc->result = (DID_OK << 16) | scsi_status;			xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);			if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {				/* Have already saved the status and sense data				 */				;			} else {				if ( (xfer_cnt == 0) || (sc->underflow > xfer_cnt)) {					sc->result = DID_SOFT_ERROR << 16;				}				if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {					/* What to do?				 	*/					sc->result = DID_SOFT_ERROR << 16;				}				else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {					/*  Not real sure here either...  */					sc->result = DID_RESET << 16;				}			}			/* Give report and update residual count.			 */			dprintk((KERN_NOTICE "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",					sc->underflow));			dprintk((KERN_NOTICE "  ActBytesXferd=%02xh\n", xfer_cnt));#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)			sc->resid = sc->request_bufflen - xfer_cnt;			dprintk((KERN_NOTICE "  SET sc->resid=%02xh\n", sc->resid));#endif			/* Report Queue Full			 */			if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);			/* If regular Inquiry cmd and some data was transferred,			 * save inquiry data			 */			if ( (pScsiReq->CDB[0] == INQUIRY) && xfer_cnt ) {				mptscsih_initTarget(hd,						sc->channel,						sc->target,						pScsiReq->LUN[1],						sc->buffer,						xfer_cnt);			}			break;		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */			sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;			if (scsi_state == 0) {				;			} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {				/*				 * If running against circa 200003dd 909 MPT f/w,				 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL				 * (QUEUE_FULL) returned from device! --> get 0x0000?128				 * and with SenseBytes set to 0.				 */				if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)					mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -