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

📄 uqserv.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 5 页
字号:
 *	from Pccb.contab, that matters when we send this message *	up to scs.) *						--Matthew Sacks * *	 *	SMP *		The index into the command ring and the count of buffers *		in the ring are incremented.  This manipulation is SMP *		protected. *	 *		If the there is no room in the ring for the command message *		and it is then added to the the waitq, the waitq must be * 		modified within the scope of the lock.	 * * *	Return  *	Values: * *	 *	 *  *	Side		 *	Effects: * */u_long	uq_ins_cring(scsbp,pccb)SCSH	*scsbp;PCCB	*pccb;{UQH	*uqbp;UQPPDH	*uqpbp;int i, s;short indx;	uqbp = UQ_header(scsbp);	s = splbio();	/* Raise IPL to muck with rings */	Lock_pccb(pccb);	if (Pccb.cmd_cnt < NCMD) {	/* we have room at the inn	*/		if( Pccb.uq->uqca.ca_cmddsc[Pccb.cmdrindx] & UQ_OWN ) {			Unlock_pccb (pccb);			panic("uqdriver: Command ring in invalid state");		}		uqpbp = Pos_to_ppdh(uqbp);		uqpbp->uqp_cid = Load_connid(scsbp->rconnid);/* Load conn id */		uqpbp->uqp_msgtype = UQT_SEQ; /* Sequential message */		uqpbp->uqp_credits = 0;		/* Zero credit field */		--Lpinfo.uq_credits[uqpbp->uqp_cid]; /* dec local credit cnt*/		Pccb.cmdbtab[Pccb.cmdrindx] = uqbp;		/*	 	*	NOTE:	 	*	The following two actions MUST be done in separate 	 	*	statements.  This is due to hardware which reads the	 	*	ring entries in two 16-bit reads. A race condition	 	*	exists if the controller reads the low-order 16-bits	 	*	first.  It is possible to get the old low-order and	 	*	the new high-order, resulting in an old command being	 	*	re-executed.  Make sure that the compiler never	 	*	optimizes these two statements.	 	*/		Pccb.uq->uqca.ca_cmddsc[Pccb.cmdrindx] = uqbp->ua;		WBFLUSH;		Pccb.uq->uqca.ca_cmddsc[Pccb.cmdrindx] |= (UQ_OWN | UQ_INT);		WBFLUSH;		Pccb.cmdrindx++;		Pccb.cmdrindx %= NCMD;		Pccb.cmd_cnt++;		i = *Pccb.Uqip;	/* Start the controller polling	*/	}	else 	{	/* Put it on the wait queue	*/		Insert_entry(uqbp->flink,Pccb.waitq);	}	WBFLUSH;	Unlock_pccb (pccb);	(void)splx(s);		}/* * * *	Name:		uq_poll_cring *	 *	Abstract:	This routine scans the command ring for free *			entries (i.e. entries which the controller has *			already pulled across). Any free entries are *			used as input to uq_ins_rspring which places *			them on either to response ring or free queue. *			If there are any commands on the wait queue they *			are placed in the now free command ring slots. *			 *	Inputs: * *	pccb			- Pointer to PCCB for this port *	      *	 *	 * *	Outputs: * *	 *	SMP	 *			The count of commnand messages currently in the ring *			and the ownership bits for the ring entries must be *			handled in an smp-safe manner.  See the comments to *			uq_poll_rspring because it is essentially the same *			situation. *			If a command message is removed from the waitq, the *			waitq must be modified in an smp safe manner. *	 * *	Return  *	Values: * *	 *	 *  *	Side		 *	Effects: * */uq_poll_cring(pccb)PCCB	*pccb;{UQH	*uqbp;UQH	*qp;int	s;	s = splbio();	while (Pccb.cmd_cnt != 0) {		Lock_pccb (pccb);		if (Pccb.cmd_cnt != 0) {	/* Is it still != 0?  */		if (Pccb.uq->uqca.ca_cmddsc[Pccb.uq_lastcmd] & UQ_OWN) {			Unlock_pccb (pccb);			(void)splx(s);			return;	 /* We don't own the descriptor	*/		}				/* get phys address of buffer */		uqbp = Pccb.cmdbtab[Pccb.uq_lastcmd];		/* Decrement count of in-use slots */		--Pccb.cmd_cnt;		Pccb.uq_lastcmd++;		Pccb.uq_lastcmd %= NCMD;			if(Pccb.waitq.flink != &Pccb.waitq){			qp = (UQH *)Pccb.waitq.flink;			Pccb.waitq.flink = qp->flink;			Pccb.waitq.flink->blink = qp->blink;			Unlock_pccb (pccb);			WBFLUSH;			uq_ins_cring( SCS_msg_header(qp), pccb );		}		else	Unlock_pccb (pccb);		/* Insert unused pkt on rspring or free	*/		uq_ins_rspring( uqbp, pccb );		       					/* queue				        */	} /* end if */	else Unlock_pccb(pccb);	} /* end while */	WBFLUSH;	(void)splx(s);}/* * * *	Name:		uq_intr		-Interrupt processing routine *	 *	Abstract:	This routine fields interrupts for UQ devices *			and performs the appropriate actions. *			 *	Inputs: *		 *	IPL_device	- Device IPL *	ctlr		- Index into port-specific structures *	 *	 * *	Outputs: * *	 *	 *	 * *	Return  *	Values: * *	 *	 *  *	Side		 *	Effects: * *		Dependent on state of adapter. *			S_RUN: 	If a buffer purge was requested the *				purge is done. *				If a response interrupt was received *				the response(s) is(are) processed and *				the appropriate messages sent to SCS. *				In all cases the command ring is scanned *				for free entries and those entries are *				added to the response ring/free queue *				via uq_ins_rspring. If there are any *				commands queued for transmission they are *				placed in the now free slots (if any). * *			S_STEPx: The SA register is read and verified. *				 The next step data is written to the SA *				 and the adapter state is advanced to the *				 next step. The final step informs SCS *				 about the new system and enables the  *				 adapter. */int	uqintr(ctlr)int	ctlr;				/* Controller index number */{	register PCCB *pccb;	struct uba_ctlr	*um = uqminfo[ctlr];	struct _uq *uq;	int count,i;	struct port_info *pcinfo = port_info_ptr[ctlr];	int	s;	pccb = pcinfo->pc_ptr;		/* Get pointer to PCCB	*//*	We expect an interrupt in the probe routine. This interrupt is for *	autoconf's benefit. Actual initialization is done via the poll *	method at probe time. */	if (Lpinfo.uq_flags & UQ_PRB)			return;				uq = Pccb.uq;			/* Get address of uq structure	*//*	If there is a fatal error in the SA register it is logged. The  *	port is then disabled and SCS is notified of the path crash. *	Port reinitialization may take place if reinit counters are not *	exceeded. */	if ((Lpinfo.sa = *Pccb.Uqsa) & UQ_ERR) { 		uq_error_log( pccb, UQ_SA_FATAL); 		uq_disable(pccb, PF_PORTERROR); 		return;	}	/*	Interrupt processing switch */	switch (Lpinfo.uq_state) {	case S_RUN:		if (uq->uqca.ca_bdp) {	/* Need to do a buffer purge	*/			s = spl6();			i = um->um_ubinfo; /* Save ubinfo		*/			um->um_ubinfo = (uq->uqca.ca_bdp>>8)<<28; /* Get datapath #	*/			ubapurge(um);	/* Purge the sucker		*/			um->um_ubinfo = i; /* Restore ubinfo		*/			uq->uqca.ca_bdp = 0; /* Clear purge request	*/			SA_W(pccb) = 0; /* Signal purge complete	*/			(void)splx(s);		}			if (uq->uqca.ca_rspint) { /* We got a response		*/			Pccb.uq->uqca.ca_rspint = 0; /* Clear interrupt indicator	*/			WBFLUSH;			uq_poll_rspring(pccb); /* Go poll the ring	*/		}		if (uq->uqca.ca_cmdint) { /* Command ring interrupt	*/			uq->uqca.ca_cmdint = 0; /* Clear indicator	*/			WBFLUSH;		}		uq_poll_cring(pccb);	/* Check if any cmd slots free	*/					/* and fill them if there are	*/		WBFLUSH;/* *	Check the response ring once more because of the race condition *	that might result in a response being placed in the ring after *	we have polled the ring. An interrupt might NOT be issued *	in this case and we could delay processing the response for a long *	period of time. */		s = Splscs ();		Lock_pccb (pccb);		if ((Pccb.uq->uqca.ca_rspdsc[Pccb.uq_lastrsp] & UQ_OWN) == 0){			Unlock_pccb (pccb);			splx (s);			uq_poll_rspring( pccb ); /* We got another response */		}		else	{			Unlock_pccb (pccb);			splx (s);			}					WBFLUSH;		break;	case S_STEP1:		cpu_printf(Pccb.init_leader, Pccb.reset_leader, "uqintr STEP1");		Wait_step(STEP1MASK, STEP1GOOD)		Pccb.step2r = *Pccb.Uqsa;		Lpinfo.uq_state = S_STEP2;		SA_W(pccb) = Pccb.step2w;		return;	case S_STEP2:		cpu_printf(Pccb.init_leader, Pccb.reset_leader, "uqintr STEP2");		Wait_step(STEP2MASK, STEP2GOOD)		Pccb.step3r = *Pccb.Uqsa;		Lpinfo.uq_state = S_STEP3;		SA_W(pccb) = Pccb.step3w;		return;	case S_STEP3:		cpu_printf(Pccb.init_leader, Pccb.reset_leader, "uqintr STEP3");		Wait_step(STEP3MASK, STEP3GOOD)		Pccb.step4r = *Pccb.Uqsa;		Lpinfo.uq_state = S_STEP4;		if (um->um_hd->uba_type & UBAXMI) {		    Pccb.uq->uqca.ca_scp_size = UQ_SCP_SIZE; /* Size of scratchpad */	            Pccb.uq->uqca.ca_scp_add = (u_long)Pccb.uqscp; /* Physical address of scratchpad */	        }		SA_W(pccb) = Pccb.step4w;		Pccb.reinit_cnt = UQ_MAX_REINIT; /* Reset reinit counter */		Lpinfo.uq_state = S_RUN;		/*		 * Initialize the data structures.		 */		uq_init_buffers( pccb );		uq_create_sys( pccb );		Pccb.init_leader = UQPath_Is_Up; /* done initing the port */		Pccb.reset_leader = UQPath_Is_Up;		if (Pccb.poll_rate == 0)	/* Set the rate for sa poll */			Pccb.poll_rate = 30 * hz;		if ( (Lpinfo.uq_flags & UQ_TIM) == 0 ) { /* If timer not yet on */			Lpinfo.uq_flags |= UQ_TIM; /* Indicate timer now on */			timeout(uq_timer,pccb,Pccb.poll_rate); /* Start timer*/		}		return;	}}/* * * *	Name:		uq_init *	 *	Abstract:	This routine starts the initialization process. *			It is called as a result of a local port crash. *			It is only called via the fork mechanism. *			 *	Inputs: * *	pccb		- Pointer to PCCB for this port *	 *	 * *	Outputs: * *	 *	 *	 * *	Return  *	Values: * *	 *	SMP:	see the comments at uq_disable(). *	 *  *	Side		 *	Effects: * *		The initialization process is started. If an error is  *		detected the local port is crashed. */void uq_init(pccb) PCCB	*pccb;{int	count, s, s2;	s = Splscs();	Lock_pccb (pccb);	Pccb.rip = 0;	/* Clear recovery in progress flag	*/	if (Pccb.init_leader ==  UQPath_Is_Up)  {	Pccb.init_leader = CURRENT_CPUDATA->cpu_num;	Unlock_pccb (pccb);	if (Pccb.init_leader == CURRENT_CPUDATA->cpu_num) {	/* inside here only if we are the cpu who will start the init */	/*	 * Start the hardware initialization sequence.	 */	s2 = splbio();	uq_port_reset(pccb);	(void)splx(s2);	count = 0;	while (count < DELAYTEN){	/* Wait for at most 10 seconds 	 */		if ((*Pccb.Uqsa & UQ_STEP1) != 0)			break;		/* We woke it up		*/		if ((Lpinfo.sa = *Pccb.Uqsa) & UQ_ERR) {			/* Got a fatal port err */			Cprintf("Called from uq_init, sa = %x\n", Lpinfo.sa);			uq_error_log( pccb, UQ_SA_FATAL); /* Log the error */			uq_disable(pccb, PF_PORTERROR );			(void)splx(s);			return;	/* CHECK */		}		(void)splx(s);		/* Don't do the delay at high ipl */		DELAY(10000);		s = Splscs();		count = count +1;	}	if (count >= DELAYTEN) { 	/* Reinit failed		*/		Cprintf("Called from uq_init, sa = %x\n", Lpinfo.sa);		uq_error_log( pccb, UQ_RESET_FAIL); /* Log the error */		uq_disable(pccb, PF_PORTERROR );		(void)splx(s);		return;	/* CHECK */	}	if (Lpinfo.uq_type == KDM_TYPE) {		*Pccb.Uqpd = Pccb.xmipd; /* Write interrupt info in PD reg */	}	Pccb.step1r = *Pccb.Uqsa;	if (Lpinfo.uq_type == BDA_TYPE) 		Pccb.step1r &= ~UQ_QB;	/* Necessary to turn off bit    */	Lpinfo.uq_state = S_STEP1;	SA_W(pccb) = Pccb.step1w;	}  /* end if */	/*	 * Initialization continues in interrupt routine.	 */	}  /* end if */		else Unlock_pccb (pccb);	(void)splx(s);	return;}/* * * *	Name:		uq_alloc_dg	- Allocate Datagram Buffer *	 *	Abstract:	This function allocates a UQSSP port specific *			message buffer. * *	Inputs: * *	IPL_SCS				- Interrupt processor level *	pccb				- Port Command and Control Block ptr * *	Outputs: * *	IPL_SCS				- Interrupt processor level *	scsbp				- Add of SCS header in message buffer * *	Return  *	Values: * *	Address of SCS header in message buffer on success *	Otherwise ( SCSH * )NULL *  *	Side		- Buffer is removed from the internal free queue *	Effects: * */ SCSH *uq_alloc_dg( pccb )PCCB	*pccb;{UQH	*uqbp;	Lock_pccb (pccb);	if ((uqbp = (UQH *)Pccb.uq_freel) != (UQH *)NULL){		Pccb.uq_freel = uqbp->flink;		Unlock_pccb (pccb);

⌨️ 快捷键说明

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