📄 uqserv.c
字号:
* 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 + -