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

📄 mptscsih.c

📁 linux2.6.16版本
💻 C
📖 第 1 页 / 共 5 页
字号:
		dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",				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, ioc->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);			RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor)  + 1) & 0x03;			dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));			ioc->RequestNB[req_idx] = RequestNB;		}		sges_left -= sg_done;		/* NOTE: psge points to the beginning of the chain element		 * in current buffer. Get a chain buffer.		 */		if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {			dfailprintk((MYIOC_s_INFO_FMT			    "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n", 			    ioc->name, pReq->CDB[0], SCpnt));			return FAILED;		}		/* Update the tracking arrays.		 * If chainSge == NULL, update ReqToChain, else ChainToChain		 */		if (chainSge) {			ioc->ChainToChain[chain_idx] = newIndex;		} else {			ioc->ReqToChain[req_idx] = newIndex;		}		chain_idx = newIndex;		chain_dma_off = 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 *) (ioc->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. */intmptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr){	struct scsi_cmnd	*sc;	MPT_SCSI_HOST	*hd;	SCSIIORequest_t	*pScsiReq;	SCSIIOReply_t	*pScsiReply;	u16		 req_idx, req_idx_MR;	hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;	req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);	req_idx_MR = (mr != NULL) ?	    le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;	if ((req_idx != req_idx_MR) ||	    (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {		printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",		    ioc->name);		printk (MYIOC_s_ERR_FMT		    "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",		    ioc->name, req_idx, req_idx_MR, mf, mr,		    hd->ScsiLookup[req_idx_MR]);		return 0;	}	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(ioc, req_idx);		return 1;	}	sc->result = DID_OK << 16;		/* Set default reply as OK */	pScsiReq = (SCSIIORequest_t *) mf;	pScsiReply = (SCSIIOReply_t *) mr;	if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){		dmfprintk((MYIOC_s_INFO_FMT			"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",			ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));	}else{		dmfprintk((MYIOC_s_INFO_FMT			"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",			ioc->name, mf, mr, sc, req_idx));	}	if (pScsiReply == NULL) {		/* special context reply handling */		;	} else {		u32	 xfer_cnt;		u16	 status;		u8	 scsi_state, scsi_status;		status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;		scsi_state = pScsiReply->SCSIState;		scsi_status = pScsiReply->SCSIStatus;		xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);		sc->resid = sc->request_bufflen - xfer_cnt;		/*		 *  if we get a data underrun indication, yet no data was		 *  transferred and the SCSI status indicates that the		 *  command was never started, change the data underrun		 *  to success		 */		if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&		    (scsi_status == MPI_SCSI_STATUS_BUSY ||		     scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT ||		     scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) {			status = MPI_IOCSTATUS_SUCCESS;		}		dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n"			"IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n"			"resid=%d bufflen=%d xfer_cnt=%d\n",			ioc->id, sc->device->id, sc->device->lun,			status, scsi_state, scsi_status, sc->resid,			sc->request_bufflen, xfer_cnt));		if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)			mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);		/*		 *  Look for + dump FCP ResponseInfo[]!		 */		if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&		    pScsiReply->ResponseInfo) {			printk(KERN_NOTICE "ha=%d id=%d lun=%d: "			"FCP_ResponseInfo=%08xh\n",			ioc->id, sc->device->id, sc->device->lun,			le32_to_cpu(pScsiReply->ResponseInfo));		}		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 = SAM_STAT_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 */		case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:		/* 0x004B */		case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:		/* 0x004C */			/* Linux handles an unsolicited DID_RESET better			 * than an unsolicited DID_ABORT.			 */			sc->result = DID_RESET << 16;			/* GEM Workaround. */			if (ioc->bus_type == SPI)				mptscsih_no_negotiate(hd, sc);			break;		case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:	/* 0x0049 */			sc->resid = sc->request_bufflen - xfer_cnt;			if((xfer_cnt==0)||(sc->underflow > xfer_cnt))				sc->result=DID_SOFT_ERROR << 16;			else /* Sufficient data transfer occurred */				sc->result = (DID_OK << 16) | scsi_status;			dreplyprintk((KERN_NOTICE 			    "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));			break;		case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:		/* 0x0045 */			/*			 *  Do upfront check for valid SenseData and give it			 *  precedence!			 */			sc->result = (DID_OK << 16) | scsi_status;			if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {				/* Have already saved the status and sense data				 */				;			} else {				if (xfer_cnt < sc->underflow) {					if (scsi_status == SAM_STAT_BUSY)						sc->result = SAM_STAT_BUSY;					else						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;				}			}			dreplyprintk((KERN_NOTICE "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",					sc->underflow));			dreplyprintk((KERN_NOTICE "  ActBytesXferd=%02xh\n", xfer_cnt));			/* Report Queue Full			 */			if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);			break;		case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:		/* 0x0044 */			sc->resid=0;		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */			if (scsi_status == MPI_SCSI_STATUS_BUSY)				sc->result = (DID_BUS_BUSY << 16) | scsi_status;			else				sc->result = (DID_OK << 16) | scsi_status;			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);			}			else 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;			}			else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {				/* Device Inq. data indicates that it supports				 * QTags, but rejects QTag messages.				 * This command completed OK.				 *				 * Not real sure here either so do nothing...  */			}			if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL)				mptscsih_report_queue_full(sc, pScsiReply, pScsiReq);			/* Add handling of:			 * Reservation Conflict, Busy,			 * Command Terminated, CHECK			 */			break;		case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:		/* 0x0047 */			sc->result = DID_SOFT_ERROR << 16;			break;		case MPI_IOCSTATUS_INVALID_FUNCTION:		/* 0x0001 */		case MPI_IOCSTATUS_INVALID_SGL:			/* 0x0003 */		case MPI_IOCSTATUS_INTERNAL_ERROR:		/* 0x0004 */		case MPI_IOCSTATUS_RESERVED:			/* 0x0005 */		case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:	/* 0x0006 */		case MPI_IOCSTATUS_INVALID_FIELD:		/* 0x0007 */		case MPI_IOCSTATUS_INVALID_STATE:		/* 0x0008 */		case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:		/* 0x0046 */		case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:	/* 0x004A */		default:			/*			 * What to do?			 */			sc->result = DID_SOFT_ERROR << 16;			break;		}	/* switch(status) */		dreplyprintk((KERN_NOTICE "  sc->result is %08xh\n", sc->result));	} /* end of address reply case */	/* Unmap the DMA buffers, if any. */	if (sc->use_sg) {		pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,			    sc->use_sg, sc->sc_data_direction);	} else if (sc->request_bufflen) {		pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,				sc->request_bufflen, sc->sc_data_direction);	}	hd->ScsiLookup[req_idx] = NULL;	sc->scsi_done(sc);		/* Issue the command callback */	/* Free Chain buffers */	mptscsih_freeChainBuffers(ioc, req_idx);	return 1;}/* *	mptscsih_flush_running_cmds - For each command found, search *		Scsi_Host instance taskQ and reply to OS. *		Called only if recovering from a FW reload. *	@hd: Pointer to a SCSI HOST structure * *	Returns: None. * *	Must be called while new I/Os are being queued. */static voidmptscsih_flush_running_cmds(MPT_SCSI_HOST *hd){	MPT_ADAPTER *ioc = hd->ioc;	struct scsi_cmnd	*SCpnt;	MPT_FRAME_HDR	*mf;	int		 ii;	int		 max = ioc->req_depth;	dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));	for (ii= 0; ii < max; ii++) {		if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {			/* Command found.			 */			/* Null ScsiLookup index			 */			hd->ScsiLookup[ii] = NULL;			mf = MPT_INDEX_2_MFPTR(ioc, ii);			dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",					mf, SCpnt));			/* Set status, free OS resources (SG DMA buffers)			 * Do OS callback			 * Free driver resources (chain, msg buffers)			 */			if (SCpnt->use_sg) {				pci_unmap_sg(ioc->pcidev,					(struct scatterlist *) SCpnt->request_buffer,					SCpnt->use_sg,					SCpnt->sc_data_direction);			} else if (SCpnt->request_bufflen) {				pci_unmap_single(ioc->pcidev,					SCpnt->SCp.dma_handle,					SCpnt->request_bufflen,					SCpnt->sc_data_direction);			}			SCpnt->result = DID_RESET << 16;			SCpnt->host_scribble = NULL;			/* Free Chain buffers */			mptscsih_freeChainBuffers(ioc, ii);			/* Free Message frames */			mpt_free_msg_frame(ioc, mf);			SCpnt->scsi_done(SCpnt);	/* Issue the command callback */		}	}	return;}/* *	mptscsih_search_running_cmds - Delete any commands associated *		with the specified target and lun. Function called only *		when a lun is disable by mid-layer.

⌨️ 快捷键说明

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