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

📄 mptscsih.c

📁 该文件是rt_linux
💻 C
📖 第 1 页 / 共 5 页
字号:
		}	}	if (hd->resetPending) {		/* Prevent new commands from being issued		 * while reloading the FW.		 */		did_errcode = 1;		goto did_error;	}	/*	 *  Put together a MPT SCSI request...	 */	if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) {		dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",				hd->ioc->name));		did_errcode = 2;		goto did_error;	}	pScsiReq = (SCSIIORequest_t *) mf;	my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);	ADD_INDEX_LOG(my_idx);	/*	 *  The scsi layer should be handling this stuff	 *  (In 2.3.x it does -DaveM)	 */	/*  BUG FIX!  19991030 -sralston	 *    TUR's being issued with scsictl=0x02000000 (DATA_IN)!	 *    Seems we may receive a buffer (datalen>0) even when there	 *    will be no data transfer!  GRRRRR...	 */	datadir = mptscsih_io_direction(SCpnt);	if (datadir == SCSI_DATA_READ) {		datalen = SCpnt->request_bufflen;		scsidir = MPI_SCSIIO_CONTROL_READ;	/* DATA IN  (host<--ioc<--dev) */	} else if (datadir == SCSI_DATA_WRITE) {		datalen = SCpnt->request_bufflen;		scsidir = MPI_SCSIIO_CONTROL_WRITE;	/* DATA OUT (host-->ioc-->dev) */	} else {		datalen = 0;		scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER;	}	/* Default to untagged. Once a target structure has been allocated,	 * use the Inquiry data to determine if device supports tagged.	 */	qtag = MPI_SCSIIO_CONTROL_UNTAGGED;	if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)			&& (SCpnt->device->tagged_supported)) {		/*		 *  Some drives are too stupid to handle fairness issues		 *  with tagged queueing. We throw in the odd ordered		 *  tag to stop them starving themselves.		 */		if ((jiffies - hd->qtag_tick) > (5*HZ)) {			qtag = MPI_SCSIIO_CONTROL_ORDEREDQ;			hd->qtag_tick = jiffies;		}		else			qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;	}	scsictl = scsidir | qtag;	/* Use the above information to set up the message frame	 */	pScsiReq->TargetID = target;	pScsiReq->Bus = hd->port;	pScsiReq->ChainOffset = 0;	pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;	pScsiReq->CDBLength = SCpnt->cmd_len;	pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;	pScsiReq->Reserved = 0;	pScsiReq->MsgFlags = mpt_msg_flags();	pScsiReq->LUN[0] = 0;	pScsiReq->LUN[1] = lun;	pScsiReq->LUN[2] = 0;	pScsiReq->LUN[3] = 0;	pScsiReq->LUN[4] = 0;	pScsiReq->LUN[5] = 0;	pScsiReq->LUN[6] = 0;	pScsiReq->LUN[7] = 0;	pScsiReq->Control = cpu_to_le32(scsictl);	/*	 *  Write SCSI CDB into the message	 */	cmd_len = SCpnt->cmd_len;	for (ii=0; ii < cmd_len; ii++)		pScsiReq->CDB[ii] = SCpnt->cmnd[ii];	for (ii=cmd_len; ii < 16; ii++)		pScsiReq->CDB[ii] = 0;	/* DataLength */	pScsiReq->DataLength = cpu_to_le32(datalen);	/* SenseBuffer low address */	pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));	/* Now add the SG list	 * Always have a SGE even if null length.	 */	rc = SUCCESS;	if (datalen == 0) {		/* Add a NULL SGE */		mpt_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0,			(dma_addr_t) -1);	} else {		/* Add a 32 or 64 bit SGE */		rc = mptscsih_AddSGE(hd, SCpnt, pScsiReq, my_idx);	}	if (rc == SUCCESS) {		hd->ScsiLookup[my_idx] = SCpnt;		SCpnt->host_scribble = NULL;#ifdef	DROP_TEST		numTotCmds++;		/* If the IOC number and target match, increment		 * counter. If counter matches DROP_THIS, do not		 * issue command to FW to force a reset.		 * Save the MF pointer so we can free resources		 * when task mgmt completes.		 */		if ((hd->ioc->id == DROP_IOC) && (target == DROP_TARGET)) {			dropCounter++;			if (dropCounter == DROP_THIS_CMD) {				dropCounter = 0;				/* If global is set, then we are already				 * doing something - so keep issuing commands.				 */				if (dropMfPtr == NULL) {					dropTestNum++;					dropMfPtr = mf;					atomic_inc(&queue_depth);					printk(MYIOC_s_INFO_FMT						"Dropped SCSI cmd (%p)\n",						hd->ioc->name, SCpnt);					printk("mf (%p) req (%4x) tot cmds (%d)\n",						mf, my_idx, numTotCmds);					return 0;				}			}		}#endif		/* SCSI specific processing */		issueCmd = 1;		if (hd->is_spi) {			int dvStatus = hd->ioc->spi_data.dvStatus[target];			if (dvStatus || hd->ioc->spi_data.forceDv) {				/* Write SDP1 on this I/O to this target */				if (dvStatus & MPT_SCSICFG_NEGOTIATE) {					mptscsih_writeSDP1(hd, 0, target, hd->negoNvram);					dvStatus &= ~MPT_SCSICFG_NEGOTIATE;					hd->ioc->spi_data.dvStatus[target] =  dvStatus;				} else if (dvStatus & MPT_SCSICFG_BLK_NEGO) {					mptscsih_writeSDP1(hd, 0, target, MPT_SCSICFG_BLK_NEGO);					dvStatus &= ~MPT_SCSICFG_BLK_NEGO;					hd->ioc->spi_data.dvStatus[target] =  dvStatus;				}#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION				if ((dvStatus & MPT_SCSICFG_NEED_DV) || hd->ioc->spi_data.forceDv) {					unsigned long lflags;					/* Schedule DV if necessary */					spin_lock_irqsave(&dvtaskQ_lock, lflags);					if (!dvtaskQ_active) {						dvtaskQ_active = 1;						spin_unlock_irqrestore(&dvtaskQ_lock, lflags);						mptscsih_dvTask.sync = 0;						mptscsih_dvTask.routine = mptscsih_domainValidation;						mptscsih_dvTask.data = (void *) hd;						SCHEDULE_TASK(&mptscsih_dvTask);					} else {						spin_unlock_irqrestore(&dvtaskQ_lock, lflags);					}					hd->ioc->spi_data.forceDv = 0;				}				/* Trying to do DV to this target, extend timeout.				 * Wait to issue intil flag is clear 				 */				if (dvStatus & MPT_SCSICFG_DV_PENDING) {					mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);					issueCmd = 0;				}				if (qtag == MPI_SCSIIO_CONTROL_UNTAGGED)					hd->ioc->spi_data.iocntr[target]++;				/* Set the DV flags.				 */				if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)					mptscsih_set_dvflags(hd, pScsiReq);#endif			}		}		if (issueCmd) {			mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf);			dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",					hd->ioc->name, SCpnt, mf, my_idx));		} else {			ddvtprintk((MYIOC_s_INFO_FMT "Pending cmd=%p idx %d\n",					hd->ioc->name, SCpnt, my_idx));			/* Place this command on the pendingQ if possible */			spin_lock_irqsave(&hd->freedoneQlock, flags);			if (!Q_IS_EMPTY(&hd->freeQ)) {				buffer = hd->freeQ.head;				Q_DEL_ITEM(buffer);				/* Save the mf pointer				 */				buffer->argp = (void *)mf;				/* Add to the pendingQ				 */				Q_ADD_TAIL(&hd->pendingQ.head, buffer, MPT_DONE_Q);				spin_unlock_irqrestore(&hd->freedoneQlock, flags);			} else {				spin_unlock_irqrestore(&hd->freedoneQlock, flags);				SCpnt->result = (DID_BUS_BUSY << 16);				SCpnt->scsi_done(SCpnt);			}		}	} else {		mptscsih_freeChainBuffers(hd, my_idx);		mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);		did_errcode = 3;		goto did_error;	}	return 0;did_error:	dprintk((MYIOC_s_WARN_FMT "_qcmd did_errcode=%d (sc=%p)\n",			hd->ioc->name, did_errcode, SCpnt));	/* Just wish OS to issue a retry */	SCpnt->result = (DID_BUS_BUSY << 16);	spin_lock_irqsave(&hd->freedoneQlock, flags);	if (!Q_IS_EMPTY(&hd->freeQ)) {		buffer = hd->freeQ.head;		Q_DEL_ITEM(buffer);		/* Set the Scsi_Cmnd pointer		 */		buffer->argp = (void *)SCpnt;		/* Add to the doneQ		 */		Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q);		spin_unlock_irqrestore(&hd->freedoneQlock, flags);	} else {		spin_unlock_irqrestore(&hd->freedoneQlock, flags);		SCpnt->scsi_done(SCpnt);	}	return 0;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* *	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.	 */	sges_left = SCpnt->use_sg;	if (SCpnt->use_sg) {		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));	} 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));		mpt_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);		mpt_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);		mpt_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.			 */			mpt_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));			mpt_add_chain((char *)chainSge, nextChain, sgeOffset, hd->ChainBufferDMA + chain_dma_off);		} else {			/* The original MF buffer requires a chain buffer -			 * set 

⌨️ 快捷键说明

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