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

📄 mptctl.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		ioctl->status &= ~MPT_IOCTL_STATUS_DID_IOCRESET;		break;	case MPT_IOC_PRE_RESET:	default:		break;	}	return 1;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* *  MPT ioctl handler *  cmd - specify the particular IOCTL command to be issued *  arg - data specific to the command. Must not be null. */static long__mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg){	mpt_ioctl_header __user *uhdr = (void __user *) arg;	mpt_ioctl_header	 khdr;	int iocnum;	unsigned iocnumX;	int nonblock = (file->f_flags & O_NONBLOCK);	int ret;	MPT_ADAPTER *iocp = NULL;	dctlprintk(("mptctl_ioctl() called\n"));	if (copy_from_user(&khdr, uhdr, sizeof(khdr))) {		printk(KERN_ERR "%s::mptctl_ioctl() @%d - "				"Unable to copy mpt_ioctl_header data @ %p\n",				__FILE__, __LINE__, uhdr);		return -EFAULT;	}	ret = -ENXIO;				/* (-6) No such device or address */	/* Verify intended MPT adapter - set iocnum and the adapter	 * pointer (iocp)	 */	iocnumX = khdr.iocnum & 0xFF;	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||	    (iocp == NULL)) {		dctlprintk((KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n",				__FILE__, __LINE__, iocnumX));		return -ENODEV;	}	if (!iocp->active) {		printk(KERN_ERR "%s::mptctl_ioctl() @%d - Controller disabled.\n",				__FILE__, __LINE__);		return -EFAULT;	}	/* Handle those commands that are just returning	 * information stored in the driver.	 * These commands should never time out and are unaffected	 * by TM and FW reloads.	 */	if ((cmd & ~IOCSIZE_MASK) == (MPTIOCINFO & ~IOCSIZE_MASK)) {		return mptctl_getiocinfo(arg, _IOC_SIZE(cmd));	} else if (cmd == MPTTARGETINFO) {		return mptctl_gettargetinfo(arg);	} else if (cmd == MPTTEST) {		return mptctl_readtest(arg);	} else if (cmd == MPTEVENTQUERY) {		return mptctl_eventquery(arg);	} else if (cmd == MPTEVENTENABLE) {		return mptctl_eventenable(arg);	} else if (cmd == MPTEVENTREPORT) {		return mptctl_eventreport(arg);	} else if (cmd == MPTFWREPLACE) {		return mptctl_replace_fw(arg);	}	/* All of these commands require an interrupt or	 * are unknown/illegal.	 */	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)		return ret;	dctlprintk((MYIOC_s_INFO_FMT ": mptctl_ioctl()\n", iocp->name));	if (cmd == MPTFWDOWNLOAD)		ret = mptctl_fw_download(arg);	else if (cmd == MPTCOMMAND)		ret = mptctl_mpt_command(arg);	else if (cmd == MPTHARDRESET)		ret = mptctl_do_reset(arg);	else if ((cmd & ~IOCSIZE_MASK) == (HP_GETHOSTINFO & ~IOCSIZE_MASK))		ret = mptctl_hp_hostinfo(arg, _IOC_SIZE(cmd));	else if (cmd == HP_GETTARGETINFO)		ret = mptctl_hp_targetinfo(arg);	else		ret = -EINVAL;	up(&iocp->ioctl->sem_ioc);	return ret;}static longmptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg){	long ret;	lock_kernel();	ret = __mptctl_ioctl(file, cmd, arg);	unlock_kernel();	return ret;}static int mptctl_do_reset(unsigned long arg){	struct mpt_ioctl_diag_reset __user *urinfo = (void __user *) arg;	struct mpt_ioctl_diag_reset krinfo;	MPT_ADAPTER		*iocp;	dctlprintk((KERN_INFO "mptctl_do_reset called.\n"));	if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) {		printk(KERN_ERR "%s@%d::mptctl_do_reset - "				"Unable to copy mpt_ioctl_diag_reset struct @ %p\n",				__FILE__, __LINE__, urinfo);		return -EFAULT;	}	if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {		dctlprintk((KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n",				__FILE__, __LINE__, krinfo.hdr.iocnum));		return -ENODEV; /* (-6) No such device or address */	}	if (mpt_HardResetHandler(iocp, CAN_SLEEP) != 0) {		printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n",			__FILE__, __LINE__);		return -1;	}	return 0;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * MPT FW download function.  Cast the arg into the mpt_fw_xfer structure. * This structure contains: iocnum, firmware length (bytes), *      pointer to user space memory where the fw image is stored. * * Outputs:	None. * Return:	0 if successful *		-EFAULT if data unavailable *		-ENXIO  if no such device *		-EAGAIN if resource problem *		-ENOMEM if no memory for SGE *		-EMLINK if too many chain buffers required *		-EBADRQC if adapter does not support FW download *		-EBUSY if adapter is busy *		-ENOMSG if FW upload returned bad status */static intmptctl_fw_download(unsigned long arg){	struct mpt_fw_xfer __user *ufwdl = (void __user *) arg;	struct mpt_fw_xfer	 kfwdl;	dctlprintk((KERN_INFO "mptctl_fwdl called. mptctl_id = %xh\n", mptctl_id)); //tc	if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) {		printk(KERN_ERR "%s@%d::_ioctl_fwdl - "				"Unable to copy mpt_fw_xfer struct @ %p\n",				__FILE__, __LINE__, ufwdl);		return -EFAULT;	}	return mptctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen);}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * FW Download engine. * Outputs:	None. * Return:	0 if successful *		-EFAULT if data unavailable *		-ENXIO  if no such device *		-EAGAIN if resource problem *		-ENOMEM if no memory for SGE *		-EMLINK if too many chain buffers required *		-EBADRQC if adapter does not support FW download *		-EBUSY if adapter is busy *		-ENOMSG if FW upload returned bad status */static intmptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen){	FWDownload_t		*dlmsg;	MPT_FRAME_HDR		*mf;	MPT_ADAPTER		*iocp;	FWDownloadTCSGE_t	*ptsge;	MptSge_t		*sgl, *sgIn;	char			*sgOut;	struct buflist		*buflist;	struct buflist		*bl;	dma_addr_t		 sgl_dma;	int			 ret;	int			 numfrags = 0;	int			 maxfrags;	int			 n = 0;	u32			 sgdir;	u32			 nib;	int			 fw_bytes_copied = 0;	int			 i;	int			 sge_offset = 0;	u16			 iocstat;	pFWDownloadReply_t	 ReplyMsg = NULL;	dctlprintk((KERN_INFO "mptctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id));	dctlprintk((KERN_INFO "DbG: kfwdl.bufp  = %p\n", ufwbuf));	dctlprintk((KERN_INFO "DbG: kfwdl.fwlen = %d\n", (int)fwlen));	dctlprintk((KERN_INFO "DbG: kfwdl.ioc   = %04xh\n", ioc));	if ((ioc = mpt_verify_adapter(ioc, &iocp)) < 0) {		dctlprintk(("%s@%d::_ioctl_fwdl - ioc%d not found!\n",				__FILE__, __LINE__, ioc));		return -ENODEV; /* (-6) No such device or address */	}	/*  Valid device. Get a message frame and construct the FW download message.	 */	if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL)		return -EAGAIN;	dlmsg = (FWDownload_t*) mf;	ptsge = (FWDownloadTCSGE_t *) &dlmsg->SGL;	sgOut = (char *) (ptsge + 1);	/*	 * Construct f/w download request	 */	dlmsg->ImageType = MPI_FW_DOWNLOAD_ITYPE_FW;	dlmsg->Reserved = 0;	dlmsg->ChainOffset = 0;	dlmsg->Function = MPI_FUNCTION_FW_DOWNLOAD;	dlmsg->Reserved1[0] = dlmsg->Reserved1[1] = dlmsg->Reserved1[2] = 0;	dlmsg->MsgFlags = 0;	/* Set up the Transaction SGE.	 */	ptsge->Reserved = 0;	ptsge->ContextSize = 0;	ptsge->DetailsLength = 12;	ptsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;	ptsge->Reserved_0100_Checksum = 0;	ptsge->ImageOffset = 0;	ptsge->ImageSize = cpu_to_le32(fwlen);	/* Add the SGL	 */	/*	 * Need to kmalloc area(s) for holding firmware image bytes.	 * But we need to do it piece meal, using a proper	 * scatter gather list (with 128kB MAX hunks).	 *	 * A practical limit here might be # of sg hunks that fit into	 * a single IOC request frame; 12 or 8 (see below), so:	 * For FC9xx: 12 x 128kB == 1.5 mB (max)	 * For C1030:  8 x 128kB == 1   mB (max)	 * We could support chaining, but things get ugly(ier:)	 *	 * Set the sge_offset to the start of the sgl (bytes).	 */	sgdir = 0x04000000;		/* IOC will READ from sys mem */	sge_offset = sizeof(MPIHeader_t) + sizeof(FWDownloadTCSGE_t);	if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, sge_offset,				    &numfrags, &buflist, &sgl_dma, iocp)) == NULL)		return -ENOMEM;	/*	 * We should only need SGL with 2 simple_32bit entries (up to 256 kB)	 * for FC9xx f/w image, but calculate max number of sge hunks	 * we can fit into a request frame, and limit ourselves to that.	 * (currently no chain support)	 * maxfrags = (Request Size - FWdownload Size ) / Size of 32 bit SGE	 *	Request		maxfrags	 *	128		12	 *	96		8	 *	64		4	 */	maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t))			/ (sizeof(dma_addr_t) + sizeof(u32));	if (numfrags > maxfrags) {		ret = -EMLINK;		goto fwdl_out;	}	dctlprintk((KERN_INFO "DbG: sgl buffer  = %p, sgfrags = %d\n", sgl, numfrags));	/*	 * Parse SG list, copying sgl itself,	 * plus f/w image hunks from user space as we go...	 */	ret = -EFAULT;	sgIn = sgl;	bl = buflist;	for (i=0; i < numfrags; i++) {		/* Get the SGE type: 0 - TCSGE, 3 - Chain, 1 - Simple SGE		 * Skip everything but Simple. If simple, copy from		 *	user space into kernel space.		 * Note: we should not have anything but Simple as		 *	Chain SGE are illegal.		 */		nib = (sgIn->FlagsLength & 0x30000000) >> 28;		if (nib == 0 || nib == 3) {			;		} else if (sgIn->Address) {			mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);			n++;			if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {				printk(KERN_ERR "%s@%d::_ioctl_fwdl - "						"Unable to copy f/w buffer hunk#%d @ %p\n",						__FILE__, __LINE__, n, ufwbuf);				goto fwdl_out;			}			fw_bytes_copied += bl->len;		}		sgIn++;		bl++;		sgOut += (sizeof(dma_addr_t) + sizeof(u32));	}#ifdef MPT_DEBUG	{		u32 *m = (u32 *)mf;		printk(KERN_INFO MYNAM ": F/W download request:\n" KERN_INFO " ");		for (i=0; i < 7+numfrags*2; i++)			printk(" %08x", le32_to_cpu(m[i]));		printk("\n");	}#endif	/*	 * Finally, perform firmware download.	 */	iocp->ioctl->wait_done = 0;	mpt_put_msg_frame(mptctl_id, iocp, mf);	/* Now wait for the command to complete */	ret = wait_event_interruptible_timeout(mptctl_wait,	     iocp->ioctl->wait_done == 1,	     HZ*60);	if(ret <=0 && (iocp->ioctl->wait_done != 1 )) {	/* Now we need to reset the board */		mptctl_timeout_expired(iocp->ioctl);		ret = -ENODATA;		goto fwdl_out;	}	if (sgl)		kfree_sgl(sgl, sgl_dma, buflist, iocp);	ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame;	iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;	if (iocstat == MPI_IOCSTATUS_SUCCESS) {		printk(KERN_INFO MYNAM ": F/W update successfully sent to %s!\n", iocp->name);		return 0;	} else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) {		printk(KERN_WARNING MYNAM ": ?Hmmm...  %s says it doesn't support F/W download!?!\n",				iocp->name);		printk(KERN_WARNING MYNAM ": (time to go bang on somebodies door)\n");		return -EBADRQC;	} else if (iocstat == MPI_IOCSTATUS_BUSY) {		printk(KERN_WARNING MYNAM ": Warning!  %s says: IOC_BUSY!\n", iocp->name);		printk(KERN_WARNING MYNAM ": (try again later?)\n");		return -EBUSY;	} else {		printk(KERN_WARNING MYNAM "::ioctl_fwdl() ERROR!  %s returned [bad] status = %04xh\n",				    iocp->name, iocstat);		printk(KERN_WARNING MYNAM ": (bad VooDoo)\n");		return -ENOMSG;	}	return 0;fwdl_out:        kfree_sgl(sgl, sgl_dma, buflist, iocp);	return ret;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * SGE Allocation routine * * Inputs:	bytes - number of bytes to be transferred *		sgdir - data direction *		sge_offset - offset (in bytes) from the start of the request *			frame to the first SGE *		ioc - pointer to the mptadapter * Outputs:	frags - number of scatter gather elements *		blp - point to the buflist pointer *		sglbuf_dma - pointer to the (dma) sgl * Returns:	Null if failes *		pointer to the (virtual) sgl if successful. */static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,		 struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc){	MptSge_t	*sglbuf = NULL;		/* pointer to array of SGE */						/* and chain buffers */	struct buflist	*buflist = NULL;	/* kernel routine */	MptSge_t	*sgl;	int		 numfrags = 0;	int		 fragcnt = 0;	int		 alloc_sz = min(bytes,MAX_KMALLOC_SZ);	// avoid kernel warning msg!	int		 bytes_allocd = 0;	int		 this_alloc;	dma_addr_t	 pa;					// phys addr	int		 i, buflist_ent;	int		 sg_spill = MAX_FRAGS_SPILL1;	int		 dir;	/* initialization */	*frags = 0;	*blp = NULL;	/* Allocate and initialize an array of kernel	 * structures for the SG elements.	 */	i = MAX_SGL_BYTES / 8;	buflist = kmalloc(i, GFP_USER);	if (buflist == NULL)		return NULL;	memset(buflist, 0, i);	buflist_ent = 0;	/* Allocate a single block of memory to store the sg elements and	 * the chain buffers.  The calling routine is responsible for	 * copying the data in this array into the correct place in the	 * request and chain buffers.	 */	sglbuf = pci_alloc_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf_dma);	if (sglbuf == NULL)		goto free_and_fail;	if (sgdir & 0x04000000)		dir = PCI_DMA_TODEVICE;	else		dir = PCI_DMA_FROMDEVICE;	/* At start:	 *	sgl = sglbuf = point to beginning of sg buffer	 *	buflist_ent = 0 = first kernel structure	 *	sg_spill = number of SGE that can be written before the first	 *		chain element.	 *	 */	sgl = sglbuf;	sg_spill = ((ioc->req_sz - sge_offset)/(sizeof(dma_addr_t) + sizeof(u32))) - 1;	while (bytes_allocd < bytes) {		this_alloc = min(alloc_sz, bytes-bytes_allocd);		buflist[buflist_ent].len = this_alloc;		buflist[buflist_ent].kptr = pci_alloc_consistent(ioc->pcidev,								 this_alloc,								 &pa);		if (buflist[buflist_ent].kptr == NULL) {

⌨️ 快捷键说明

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