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

📄 mptscsih.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
			SCpnt->scsi_done(SCpnt);	/* Issue the command callback */                        MPT_HOST_UNLOCK(flags);#endif		}	}	return;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* *	mptscsih_initChainBuffers - Allocate memory for and initialize *	chain buffers, chain buffer control arrays and spinlock. *	@hd: Pointer to MPT_SCSI_HOST structure *	@init: If set, initialize the spin lock. */static intmptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init){	MPT_FRAME_HDR	*chain;	u8		*mem;	unsigned long	flags;	int		sz, ii, num_chain;	int 		scale, num_sge;	/* ReqToChain size must equal the req_depth	 * index = req_idx	 */	if (hd->ReqToChain == NULL) {		sz = hd->ioc->req_depth * sizeof(int);		mem = kmalloc(sz, GFP_ATOMIC);		if (mem == NULL)			return -1;		hd->ReqToChain = (int *) mem;	}	for (ii = 0; ii < hd->ioc->req_depth; ii++)		hd->ReqToChain[ii] = MPT_HOST_NO_CHAIN;	/* ChainToChain size must equal the total number	 * of chain buffers to be allocated.	 * index = chain_idx	 *	 * Calculate the number of chain buffers needed(plus 1) per I/O	 * then multiply the the maximum number of simultaneous cmds	 *	 * num_sge = num sge in request frame + last chain buffer	 * scale = num sge per chain buffer if no chain element	 */	scale = hd->ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));	if (sizeof(dma_addr_t) == sizeof(u64))		num_sge =  scale + (hd->ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));	else		num_sge =  1+ scale + (hd->ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));	num_chain = 1;	while (hd->max_sge - num_sge > 0) {		num_chain++;		num_sge += (scale - 1);	}	num_chain++;	if ((int) hd->ioc->chip_type > (int) FC929)		num_chain *= MPT_SCSI_CAN_QUEUE;	else		num_chain *= MPT_FC_CAN_QUEUE;	hd->num_chain = num_chain;	sz = num_chain * sizeof(int);	if (hd->ChainToChain == NULL) {		mem = kmalloc(sz, GFP_ATOMIC);		if (mem == NULL)			return -1;		hd->ChainToChain = (int *) mem;	} else {		mem = (u8 *) hd->ChainToChain;	}	memset(mem, 0xFF, sz);	sz = num_chain * hd->ioc->req_sz;	if (hd->ChainBuffer == NULL) {		/* Allocate free chain buffer pool		 */		mem = pci_alloc_consistent(hd->ioc->pcidev, sz, &hd->ChainBufferDMA);		if (mem == NULL)			return -1;		hd->ChainBuffer = (u8*)mem;	} else {		mem = (u8 *) hd->ChainBuffer;	}	memset(mem, 0, sz);	dprintk((KERN_INFO "  ChainBuffer    @ %p(%p), sz=%d\n",		 hd->ChainBuffer, (void *)(ulong)hd->ChainBufferDMA, sz));	/* Initialize the free chain Q.	 */	if (init) {		spin_lock_init(&hd->FreeChainQlock);	}	spin_lock_irqsave (&hd->FreeChainQlock, flags);	Q_INIT(&hd->FreeChainQ, MPT_FRAME_HDR);	/* Post the chain buffers to the FreeChainQ.	 */	mem = (u8 *)hd->ChainBuffer;	for (ii=0; ii < num_chain; ii++) {		chain = (MPT_FRAME_HDR *) mem;		Q_ADD_TAIL(&hd->FreeChainQ.head, &chain->u.frame.linkage, MPT_FRAME_HDR);		mem += hd->ioc->req_sz;	}	spin_unlock_irqrestore(&hd->FreeChainQlock, flags);	return 0;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* *  Hack! It might be nice to report if a device is returning QUEUE_FULL *  but maybe not each and every time... */static long last_queue_full = 0;/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* *	mptscsih_report_queue_full - Report QUEUE_FULL status returned *	from a SCSI target device. *	@sc: Pointer to Scsi_Cmnd structure *	@pScsiReply: Pointer to SCSIIOReply_t *	@pScsiReq: Pointer to original SCSI request * *	This routine periodically reports QUEUE_FULL status returned from a *	SCSI target device.  It reports this to the console via kernel *	printk() API call, not more than once every 10 seconds. */static voidmptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq){	long time = jiffies;	if (time - last_queue_full > 10 * HZ) {		char *ioc_str = "ioc?";		if (sc->host != NULL && sc->host->hostdata != NULL)			ioc_str = ((MPT_SCSI_HOST *)sc->host->hostdata)->ioc->name;		printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",				ioc_str, 0, sc->target, sc->lun);		last_queue_full = time;	}}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/static int BeenHereDoneThat = 0;static char *info_kbuf = NULL;/*  SCSI host fops start here...  *//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** *	mptscsih_detect - Register MPT adapter(s) as SCSI host(s) with *	linux scsi mid-layer. *	@tpnt: Pointer to Scsi_Host_Template structure * *	(linux Scsi_Host_Template.detect routine) * *	Returns number of SCSI host adapters that were successfully *	registered with the linux scsi mid-layer via the scsi_register() *	API call. */intmptscsih_detect(Scsi_Host_Template *tpnt){	struct Scsi_Host	*sh;	MPT_SCSI_HOST		*hd;	MPT_ADAPTER		*ioc;	MPT_DONE_Q		*freedoneQ;	unsigned long		 flags;	int			 sz, ii;	int			 numSGE = 0;	int			 scale;	int			 ioc_cap;	u8			*mem;	if (! BeenHereDoneThat++) {		show_mptmod_ver(my_NAME, my_VERSION);		ScsiDoneCtx = mpt_register(mptscsih_io_done, MPTSCSIH_DRIVER);		ScsiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSCSIH_DRIVER);		ScsiScanDvCtx = mpt_register(mptscsih_scandv_complete, MPTSCSIH_DRIVER);#ifndef MPT_SCSI_USE_NEW_EH		spin_lock_init(&mytaskQ_lock);#endif		if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) {			dprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n"));		} else {			/* FIXME! */		}		if (mpt_reset_register(ScsiDoneCtx, mptscsih_ioc_reset) == 0) {			dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));		} else {			/* FIXME! */		}	}	dprintk((KERN_INFO MYNAM ": mpt_scsih_detect()\n"));#ifdef MODULE	/* Evaluate the command line arguments, if any */	if (mptscsih)		mptscsih_setup(mptscsih);#endif#ifndef MPT_SCSI_USE_NEW_EH	atomic_set(&mpt_taskQdepth, 0);#endif	for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {		/* 20010202 -sralston		 *  Added sanity check on readiness of the MPT adapter.		 */		if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {			printk(MYIOC_s_WARN_FMT "Skipping because it's not operational!\n",					ioc->name);			continue;		}		if (!ioc->active) {			printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",					ioc->name);			continue;		}		/*  Sanity check - ensure at least 1 port is INITIATOR capable		 */		ioc_cap = 0;		for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {			if (ioc->pfacts[ii].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)				ioc_cap ++;		}		if (!ioc_cap) {			printk(MYIOC_s_WARN_FMT "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",					ioc->name, ioc);			continue;		}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)		tpnt->proc_dir = &proc_mpt_scsihost;#endif		tpnt->proc_info = mptscsih_proc_info;		sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST));		if (sh != NULL) {			spin_lock_irqsave(&ioc->FreeQlock, flags);			sh->io_port = 0;			sh->n_io_port = 0;			sh->irq = 0;			/* Yikes!  This is important!			 * Otherwise, by default, linux			 * only scans target IDs 0-7!			 * pfactsN->MaxDevices unreliable			 * (not supported in early			 *	versions of the FW).			 * max_id = 1 + actual max id,			 * max_lun = 1 + actual last lun,			 *	see hosts.h :o(			 */			if ((int)ioc->chip_type > (int)FC929)				sh->max_id = MPT_MAX_SCSI_DEVICES;			else {				/* For FC, increase the queue depth				 * from MPT_SCSI_CAN_QUEUE (31)				 * to MPT_FC_CAN_QUEUE (63).				 */				sh->can_queue = MPT_FC_CAN_QUEUE;				sh->max_id = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;			}			sh->max_lun = MPT_LAST_LUN + 1;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)			sh->max_sectors = MPT_SCSI_MAX_SECTORS;#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) || defined CONFIG_HIGHIO			sh->highmem_io = 1;#endif			/* MPI uses {port, bus, id, lun}, but logically maps			 * devices on different ports to different buses, i.e.,			 * bus 1 may be the 2nd bus on port 0 or the 1st bus on port 1.			 * Map bus to channel, ignore port number in SCSI....			 *	hd->port = 0;			 * If max_channel > 0, need to adjust mem alloc, free, DV			 * and all access to VirtDev			 */			sh->max_channel = 0;			sh->this_id = ioc->pfacts[0].PortSCSIID;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44)			/* OS entry to allow host drivers to force			 * a queue depth on a per device basis.			 */			sh->select_queue_depths = mptscsih_select_queue_depths;#endif			/* Required entry.			 */			sh->unique_id = ioc->id;			/* Verify that we won't exceed the maximum			 * number of chain buffers			 * We can optimize:  ZZ = req_sz/sizeof(SGE)			 * For 32bit SGE's:			 *  numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ			 *               + (req_sz - 64)/sizeof(SGE)			 * A slightly different algorithm is required for			 * 64bit SGEs.			 */			scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));			if (sizeof(dma_addr_t) == sizeof(u64)) {				numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +					(ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));			} else {				numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +					(ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));			}			if (numSGE < sh->sg_tablesize) {				/* Reset this value */				dprintk((MYIOC_s_INFO_FMT					 "Resetting sg_tablesize to %d from %d\n",					 ioc->name, numSGE, sh->sg_tablesize));				sh->sg_tablesize = numSGE;			}			/* Set the pci device pointer in Scsi_Host structure.			 */			scsi_set_pci_device(sh, ioc->pcidev);			spin_unlock_irqrestore(&ioc->FreeQlock, flags);			hd = (MPT_SCSI_HOST *) sh->hostdata;			hd->ioc = ioc;			hd->max_sge = sh->sg_tablesize;			if ((int)ioc->chip_type > (int)FC929)				hd->is_spi = 1;			if (DmpService &&			    (ioc->chip_type == FC919 || ioc->chip_type == FC929))				hd->is_multipath = 1;			/* SCSI needs Scsi_Cmnd lookup table!			 * (with size equal to req_depth*PtrSz!)			 */			sz = hd->ioc->req_depth * sizeof(void *);			mem = kmalloc(sz, GFP_ATOMIC);			if (mem == NULL)				goto done;			memset(mem, 0, sz);			hd->ScsiLookup = (struct scsi_cmnd **) mem;			dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",				 ioc->name, hd->ScsiLookup, sz));			if (mptscsih_initChainBuffers(hd, 1) < 0)				goto done;			/* Allocate memory for free and doneQ's			 */			sz = sh->can_queue * sizeof(MPT_DONE_Q);			mem = kmalloc(sz, GFP_ATOMIC);			if (mem == NULL)				goto done;			memset(mem, 0xFF, sz);			hd->memQ = mem;			/* Initialize the free, done and pending Qs.			 */			Q_INIT(&hd->freeQ, MPT_DONE_Q);			Q_INIT(&hd->doneQ, MPT_DONE_Q);			Q_INIT(&hd->pendingQ, MPT_DONE_Q);			spin_lock_init(&hd->freedoneQlock);			mem = hd->memQ;			for (ii=0; ii < sh->can_queue; ii++) {				freedoneQ = (MPT_DONE_Q *) mem;				Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q);				mem += sizeof(MPT_DONE_Q);			}			/* Initialize this Scsi_Host			 * internal task Q.			 */			Q_INIT(&hd->taskQ, MPT_FRAME_HDR);			hd->taskQcnt = 0;			/* Allocate memory for the device structures.			 * A non-Null pointer at an offset			 * indicates a device exists.			 * max_id = 1 + maximum id (hosts.h)			 */			sz = sh->max_id * sizeof(void *);			mem = kmalloc(sz, GFP_ATOMIC);			if (mem == NULL)				goto done;			memset(mem, 0, sz);			hd->Targets = (VirtDevice **) mem;			dprintk((KERN_INFO "  Targets @ %p, sz=%d\n", hd->Targets, sz));			/* Clear the TM flags			 */			hd->tmPending = 0;#ifdef MPT_SCSI_USE_NEW_EH			hd->tmState = TM_STATE_NONE;#endif			hd->resetPending = 0;			hd->abortSCpnt = NULL;			hd->tmPtr = NULL;			hd->numTMrequests = 0;			/* Clear the pointer used to store			 * single-threaded commands, i.e., those			 * issued during a bus scan, dv and			 * configuration pages.			 */			hd->cmdPtr = NULL;			/* Attach the SCSI Host to the IOC structure			 */			ioc->sh = sh;			/* Initialize this SCSI Hosts' timers			 * To use, set the timer expires field			 * and add_timer			 */			init_timer(&hd->timer);			hd->timer.data = (unsigned long) hd;			hd->timer.function = mptscsih_timer_expired;			init_timer(&hd->TMtimer);			hd->TMtimer.data = (unsigned long) hd;			hd->TMtimer.function = mptscsih_taskmgmt_timeout;			hd->qtag_tick = jiffies;			/* Moved Earlier Pam D */			/* ioc->sh = sh;	*/#ifdef MPTSCSIH_DBG_TIMEOUT			hd->ioc->timeout_hard = 0;			hd->ioc->timeout_delta = 30 * HZ;			hd->ioc->timeout_maxcnt = 0;			hd->ioc->timeout_cnt = 0;			for (ii=0; ii < 8; ii++)				foo_to[ii] = NULL;#endif			if (hd->is_spi) {				/* Update with the driver setup				 * values.				 */				if (hd->ioc->spi_data.maxBusWidth > driver_setup.max_width)					hd->ioc->spi_data.maxBusWidth = driver_setup.max_width;				if (hd->ioc->spi_data.minSyncFactor < driver_setup.min_sync_fac)

⌨️ 快捷键说明

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