mptbase.c

来自「linux 内核源代码」· C语言 代码 · 共 2,293 行 · 第 1/5 页

C
2,293
字号
			ioc->name, recovery_state);	} else {		printk(MYIOC_s_INFO_FMT			"pci-resume: success\n", ioc->name);	}	return 0;}#endifstatic intmpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase){	if ((MptDriverClass[index] == MPTSPI_DRIVER &&	     ioc->bus_type != SPI) ||	    (MptDriverClass[index] == MPTFC_DRIVER &&	     ioc->bus_type != FC) ||	    (MptDriverClass[index] == MPTSAS_DRIVER &&	     ioc->bus_type != SAS))		/* make sure we only call the relevant reset handler		 * for the bus */		return 0;	return (MptResetHandlers[index])(ioc, reset_phase);}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** *	mpt_do_ioc_recovery - Initialize or recover MPT adapter. *	@ioc: Pointer to MPT adapter structure *	@reason: Event word / reason *	@sleepFlag: Use schedule if CAN_SLEEP else use udelay. * *	This routine performs all the steps necessary to bring the IOC *	to a OPERATIONAL state. * *	This routine also pre-fetches the LAN MAC address of a Fibre Channel *	MPT adapter. * *	Returns: *		 0 for success *		-1 if failed to get board READY *		-2 if READY but IOCFacts Failed *		-3 if READY but PrimeIOCFifos Failed *		-4 if READY but IOCInit Failed */static intmpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag){	int	 hard_reset_done = 0;	int	 alt_ioc_ready = 0;	int	 hard;	int	 rc=0;	int	 ii;	u8	 cb_idx;	int	 handlers;	int	 ret = 0;	int	 reset_alt_ioc_active = 0;	int	 irq_allocated = 0;	u8	*a;	printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,	    reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");	/* Disable reply interrupts (also blocks FreeQ) */	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);	ioc->active = 0;	if (ioc->alt_ioc) {		if (ioc->alt_ioc->active)			reset_alt_ioc_active = 1;		/* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */		CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);		ioc->alt_ioc->active = 0;	}	hard = 1;	if (reason == MPT_HOSTEVENT_IOC_BRINGUP)		hard = 0;	if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {		if (hard_reset_done == -4) {			printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",			    ioc->name);			if (reset_alt_ioc_active && ioc->alt_ioc) {				/* (re)Enable alt-IOC! (reply interrupt, FreeQ) */				dprintk(ioc, printk(MYIOC_s_INFO_FMT				    "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));				CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);				ioc->alt_ioc->active = 1;			}		} else {			printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);		}		return -1;	}	/* hard_reset_done = 0 if a soft reset was performed	 * and 1 if a hard reset was performed.	 */	if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {		if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)			alt_ioc_ready = 1;		else			printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);	}	for (ii=0; ii<5; ii++) {		/* Get IOC facts! Allow 5 retries */		if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)			break;	}	if (ii == 5) {		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT		    "Retry IocFacts failed rc=%x\n", ioc->name, rc));		ret = -2;	} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {		MptDisplayIocCapabilities(ioc);	}	if (alt_ioc_ready) {		if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {			dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT			    "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));			/* Retry - alt IOC was initialized once			 */			rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);		}		if (rc) {			dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT			    "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));			alt_ioc_ready = 0;			reset_alt_ioc_active = 0;		} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {			MptDisplayIocCapabilities(ioc->alt_ioc);		}	}	/*	 * Device is reset now. It must have de-asserted the interrupt line	 * (if it was asserted) and it should be safe to register for the	 * interrupt now.	 */	if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {		ioc->pci_irq = -1;		if (ioc->pcidev->irq) {			if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))				printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",				    ioc->name);			rc = request_irq(ioc->pcidev->irq, mpt_interrupt,			    IRQF_SHARED, ioc->name, ioc);			if (rc < 0) {				printk(MYIOC_s_ERR_FMT "Unable to allocate "				    "interrupt %d!\n", ioc->name, ioc->pcidev->irq);				if (mpt_msi_enable)					pci_disable_msi(ioc->pcidev);				return -EBUSY;			}			irq_allocated = 1;			ioc->pci_irq = ioc->pcidev->irq;			pci_set_master(ioc->pcidev);		/* ?? */			pci_set_drvdata(ioc->pcidev, ioc);			dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "			    "%d\n", ioc->name, ioc->pcidev->irq));		}	}	/* Prime reply & request queues!	 * (mucho alloc's) Must be done prior to	 * init as upper addresses are needed for init.	 * If fails, continue with alt-ioc processing	 */	if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))		ret = -3;	/* May need to check/upload firmware & data here!	 * If fails, continue with alt-ioc processing	 */	if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))		ret = -4;// NEW!	if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {		printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",		    ioc->alt_ioc->name, rc);		alt_ioc_ready = 0;		reset_alt_ioc_active = 0;	}	if (alt_ioc_ready) {		if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {			alt_ioc_ready = 0;			reset_alt_ioc_active = 0;			printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",			    ioc->alt_ioc->name, rc);		}	}	if (reason == MPT_HOSTEVENT_IOC_BRINGUP){		if (ioc->upload_fw) {			ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT			    "firmware upload required!\n", ioc->name));			/* Controller is not operational, cannot do upload			 */			if (ret == 0) {				rc = mpt_do_upload(ioc, sleepFlag);				if (rc == 0) {					if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {						/*						 * Maintain only one pointer to FW memory						 * so there will not be two attempt to						 * downloadboot onboard dual function						 * chips (mpt_adapter_disable,						 * mpt_diag_reset)						 */						ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT						    "mpt_upload:  alt_%s has cached_fw=%p \n",						    ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));						ioc->alt_ioc->cached_fw = NULL;					}				} else {					printk(MYIOC_s_WARN_FMT					    "firmware upload failure!\n", ioc->name);					ret = -5;				}			}		}	}	if (ret == 0) {		/* Enable! (reply interrupt) */		CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);		ioc->active = 1;	}	if (reset_alt_ioc_active && ioc->alt_ioc) {		/* (re)Enable alt-IOC! (reply interrupt) */		dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",		    ioc->alt_ioc->name));		CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);		ioc->alt_ioc->active = 1;	}	/*  Enable MPT base driver management of EventNotification	 *  and EventAck handling.	 */	if ((ret == 0) && (!ioc->facts.EventState))		(void) SendEventNotification(ioc, 1);	/* 1=Enable EventNotification */	if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)		(void) SendEventNotification(ioc->alt_ioc, 1);	/* 1=Enable EventNotification */	/*	Add additional "reason" check before call to GetLanConfigPages	 *	(combined with GetIoUnitPage2 call).  This prevents a somewhat	 *	recursive scenario; GetLanConfigPages times out, timer expired	 *	routine calls HardResetHandler, which calls into here again,	 *	and we try GetLanConfigPages again...	 */	if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {		/*		 * Initalize link list for inactive raid volumes.		 */		init_MUTEX(&ioc->raid_data.inactive_list_mutex);		INIT_LIST_HEAD(&ioc->raid_data.inactive_list);		if (ioc->bus_type == SAS) {			/* clear persistency table */			if(ioc->facts.IOCExceptions &			    MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {				ret = mptbase_sas_persist_operation(ioc,				    MPI_SAS_OP_CLEAR_NOT_PRESENT);				if(ret != 0)					goto out;			}			/* Find IM volumes			 */			mpt_findImVolumes(ioc);		} else if (ioc->bus_type == FC) {			if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&			    (ioc->lan_cnfg_page0.Header.PageLength == 0)) {				/*				 *  Pre-fetch the ports LAN MAC address!				 *  (LANPage1_t stuff)				 */				(void) GetLanConfigPages(ioc);				a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;				dprintk(ioc, printk(MYIOC_s_DEBUG_FMT				    "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",				    ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));			}		} else {			/* Get NVRAM and adapter maximums from SPP 0 and 2			 */			mpt_GetScsiPortSettings(ioc, 0);			/* Get version and length of SDP 1			 */			mpt_readScsiDevicePageHeaders(ioc, 0);			/* Find IM volumes			 */			if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)				mpt_findImVolumes(ioc);			/* Check, and possibly reset, the coalescing value			 */			mpt_read_ioc_pg_1(ioc);			mpt_read_ioc_pg_4(ioc);		}		GetIoUnitPage2(ioc);		mpt_get_manufacturing_pg_0(ioc);	}	/*	 * Call each currently registered protocol IOC reset handler	 * with post-reset indication.	 * NOTE: If we're doing _IOC_BRINGUP, there can be no	 * MptResetHandlers[] registered yet.	 */	if (hard_reset_done) {		rc = handlers = 0;		for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {			if ((ret == 0) && MptResetHandlers[cb_idx]) {				dprintk(ioc, printk(MYIOC_s_DEBUG_FMT				    "Calling IOC post_reset handler #%d\n",				    ioc->name, cb_idx));				rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);				handlers++;			}			if (alt_ioc_ready && MptResetHandlers[cb_idx]) {				drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT				    "Calling IOC post_reset handler #%d\n",				    ioc->alt_ioc->name, cb_idx));				rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);				handlers++;			}		}		/* FIXME?  Examine results here? */	} out:	if ((ret != 0) && irq_allocated) {		free_irq(ioc->pci_irq, ioc);		if (mpt_msi_enable)			pci_disable_msi(ioc->pcidev);	}	return ret;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** *	mpt_detect_bound_ports - Search for matching PCI bus/dev_function *	@ioc: Pointer to MPT adapter structure *	@pdev: Pointer to (struct pci_dev) structure * *	Search for PCI bus/dev_function which matches *	PCI bus/dev_function (+/-1) for newly discovered 929, *	929X, 1030 or 1035. * *	If match on PCI dev_function +/-1 is found, bind the two MPT adapters *	using alt_ioc pointer fields in their %MPT_ADAPTER structures. */static voidmpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev){	struct pci_dev *peer=NULL;	unsigned int slot = PCI_SLOT(pdev->devfn);	unsigned int func = PCI_FUNC(pdev->devfn);	MPT_ADAPTER *ioc_srch;	dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"	    " searching for devfn match on %x or %x\n",	    ioc->name, pci_name(pdev), pdev->bus->number,	    pdev->devfn, func-1, func+1));	peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));	if (!peer) {		peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));		if (!peer)			return;	}	list_for_each_entry(ioc_srch, &ioc_list, list) {		struct pci_dev *_pcidev = ioc_srch->pcidev;		if (_pcidev == peer) {			/* Paranoia checks */			if (ioc->alt_ioc != NULL) {				printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",					ioc->name, ioc->alt_ioc->name);				break;			} else if (ioc_srch->alt_ioc != NULL) {				printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",					ioc_srch->name, ioc_srch->alt_ioc->name);				break;			}			dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",				ioc->name, ioc_srch->name));			ioc_srch->alt_ioc = ioc;			ioc->alt_ioc = ioc_srch;		}	}	pci_dev_put(peer);}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//** *	mpt_adapter_disable - Disable misbehaving MPT adapter. *	@ioc: Pointer to MPT adapter structure */static voidmpt_adapter_disable(MPT_ADAPTER *ioc){	int sz;	int ret;	if (ioc->cached_fw != NULL) {		ddlprintk(ioc, printk(MYIOC_s_INFO_FMT		    "mpt_adapter_disable: Pushing FW onto adapter\n", ioc->name));		if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {			printk(MYIOC_s_WARN_FMT "firmware downloadboot failure (%d)!\n",			    ioc->name, ret);		}	}	/* Disable adapter interrupts! */	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);	ioc->active = 0;	/* Clear any lingering interrupt */	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);	if (ioc->alloc != NULL) {		sz = ioc->alloc_sz;		dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free  @ %p, sz=%d bytes\n",		    ioc->name, ioc->alloc, ioc->alloc_sz));		pci_free_consistent(ioc->pcidev, sz,				ioc->alloc, ioc->alloc_dma);		ioc->reply_frames = NULL;		ioc->req_frames = NULL;		ioc->alloc = NULL;		ioc->alloc_total -= sz;	}	if (ioc->sense_buf_pool != NULL) {		sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);		pci_free_consiste

⌨️ 快捷键说明

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