📄 uqserv.c
字号:
pccb->type = DYN_PCCB; /* Structure type */ pccb->pdt = &uqpdt; /* Init PDT pointer */ Pccb.uq_ctlr = ctlr; /* Save ctlr number */ Pccb.reinit_cnt = UQ_MAX_REINIT; /* Initialize reinit counter */ if (uba_hd[numuba].uba_type & UBABDA) Lpinfo.uq_type = BDA_TYPE; /* BDA is a special case and must */ /* be flagged now */ if (uba_hd[numuba].uba_type & UBAXMI) { Lpinfo.uq_type = KDM_TYPE; /* KDM is also a special case and */ /* must be flagged now */ xmidata = get_xmi(numxmi); Pccb.xmipd = (xmidata->xmiintr_dst) | UQ_XMI_LEVEL15; } /* the next line must be done before calling uq_port_reset */ Pccb.init_leader = Pccb.reset_leader = CURRENT_CPUDATA->cpu_num; Lpinfo.uq_flags |= UQ_PRB; /* Flag that we are in probe */ uq_set_reg(pccb, reg); /* Set up register pointers */ if (Lpinfo.uq_type == BDA_TYPE) { bdar = (struct bda_regs *)((long)(Pccb.Uqip) - UQB_IP); Pccb.bda_init_vec = bdar->bda_biic.biic_int_ctrl; Pccb.bda_init_dest = bdar->bda_biic.biic_int_dst; Pccb.bda_init_errvec = bdar->bda_biic.biic_err; } uq_port_reset(pccb); /* Bang it on the head */ count = 0; while (count < DELAYTEN){ /* Wait for at most 10 seconds */ if ((*Pccb.Uqsa & UQ_STEP1) != 0) break; /* We woke it up */ DELAY(10000); count = count +1; } if (count == DELAYTEN) return(0); /* Not there or dead */ if ( (Lpinfo.sa = *Pccb.Uqsa) & UQ_ERR) { uq_error_log( pccb, UQ_SA_FATAL); return(0); /* If error then return */ } #ifdef mips KM_ALLOC( pcinfo, struct port_info *, sizeof(struct port_info), KM_SCA, KM_NOW_CL_CA | KM_NOCACHE)#else KM_ALLOC( pcinfo, struct port_info *, sizeof(struct port_info), KM_SCA, KM_NOW_CL_CA )#endif mips if ( pcinfo == (struct port_info *)NULL ) return(0); pcinfo->pc_ptr = pccb; /* Save address for later use */ Pccb.uq = &pcinfo->uq; /* Save address of comm area */ port_info_ptr[ctlr] = pcinfo; /* Save pointer to port_info struct */ uq_init_buffers( pccb ); /* Map communications area *//* Setup bus-specific information */ if (uba_hd[numuba].uba_type & UBAXMI) { /* Allocate controller scratchpad area */ KM_ALLOC( scp, UQ_SCP *, UQ_SCP_SIZE, KM_SCA, KM_NOW_CL_CA ) if ( scp == (UQ_SCP *)NULL ) return(0); Pccb.uqscp = (struct _uqscp *)svtophy(scp); }/* Setup controller-specific information */ switch(Lpinfo.uq_type) { case BDA_TYPE: Pccb.uq_ivec = 0; /* BDA gets vector from BIIC reg */ break; case KDM_TYPE: Pccb.uq_ivec = (uba_hd[numuba].uh_lastiv -= 4); break; default: Pccb.uq_ivec = (uba_hd[numuba].uh_lastiv -= 4); break; }/* *//* Initialize step information *//* */ Pccb.step1w = (((uba_hd[numuba].uba_type & UBAXMI) != 0) ? 0 : UQ_ERR ) | (NCMDL2<<11) | (NRSPL2<<8) | UQ_IE | (Pccb.uq_ivec/4); Pccb.step2w = ((int)&Pccb.uqptr->uqca.ca_ringbase)| (((uba_hd[numuba].uba_type & UBA780) != 0) ? UQ_PI : 0); Pccb.step3w = ((int)&Pccb.uqptr->uqca.ca_ringbase)>>16;/* *//* initialize the SMP lock *//* */ Init_pccb_lock(pccb);/* *//* Initialize the port *//* */ if (Lpinfo.uq_type == KDM_TYPE) { *Pccb.Uqpd = Pccb.xmipd; /* Write interrupt info in PD reg */ } Lpinfo.uq_state = S_STEP1; /* Port now in STEP1 state */ Pccb.step1r = *Pccb.Uqsa; /* Save step data in case of error */ if (Lpinfo.uq_type == BDA_TYPE) Pccb.step1r &= ~UQ_QB; /* Necessary to turn off bit */ SA_W(pccb) = Pccb.step1w; /* Write step 1 data */ if(!(step_wait( pccb, STEP1MASK, STEP1GOOD))) /* Wait for step 2 */ return(0); /* Step failed */ Pccb.step2r = *Pccb.Uqsa; /* Save step data in case of error */ Lpinfo.uq_state = S_STEP2; /* Port now in STEP2 state */ SA_W(pccb) = Pccb.step2w; /* Write step 2 data */ if(!(step_wait( pccb, STEP2MASK, STEP2GOOD))) /* Wait for step 3 */ return(0); /* Step failed */ Pccb.step3r = *Pccb.Uqsa; /* Save step data in case of error */ Lpinfo.uq_state = S_STEP3; /* Port now in STEP3 state */ SA_W(pccb) = Pccb.step3w; /* Write step 3 data */ if(!(step_wait( pccb, STEP3MASK, STEP3GOOD))) /* Wait for step 4 */ return(0); /* Step failed */ Pccb.step4r = *Pccb.Uqsa; /* Save step data in case of error */ Lpinfo.uq_type = (Pccb.step4r>>4) & 0x7F; Lpinfo.uq_state = S_STEP4; /* Port now in STEP3 state *//* *//* Set up SCS info *//* */ pccb->lpinfo.name = Ctrl_from_num( "uq ", Pccb.uq_ctlr); /* Local port name */ Scaaddr_low( pccb->lpinfo.addr ) = *(u_short *)&Pccb.uq_ctlr; /* Remote port address */ Scaaddr_mid( pccb->lpinfo.addr ) = 0; Scaaddr_hi( pccb->lpinfo.addr ) = 0; pccb->lpinfo.type.hwtype = HPT_UQSSP; /* Local port hardware type */ pccb->lpinfo.type.swtype = SPT_UQSSP; /* Local port software type */ if( Lpinfo.uq_type == BDA_TYPE ) { /* Local port interconnect */ pccb->lpinfo.type.ictype = ICT_BI; } else if( Lpinfo.uq_type == KDM_TYPE ) { pccb->lpinfo.type.ictype = ICT_XMI; } else if( Pccb.step1r & UQ_QB ) { pccb->lpinfo.type.ictype = ICT_QB; } else { pccb->lpinfo.type.ictype = ICT_UB; } pccb->lpinfo.type.dual_path = 0; /* Single path port *//* *//* Insert PCCB on system queue *//* */ s = Splscs(); Lock_scadb (); Insert_entry(pccb->flink, scs_lport_db); Unlock_scadb (); /* keep ipl up for scs call */ if((i = scs_initialize()) != RET_SUCCESS){ /* Init the SCS layer */ (void)splx(s); /* Lower IPL */ Remove_entry(pccb->flink); /* Remove from lport_db queue */ uq_port_reset(pccb); /* Reset the device */ Lpinfo.uq_flags &= ~UQ_PRB; /* We are now out of probe */ return(0); /* Return with err if init fails */ } (void)splx(s); /* Restore IPL */ uq_init_buffers( pccb ); /* Restock the response ring and */ /* free queue after controller */ /* stomps on ring. */ Pccb.step4w = (( (uq_cinfo[Lpinfo.uq_type].burst & UQ_BURST) > 0 ? (uq_cinfo[Lpinfo.uq_type].burst & UQ_BURST) : 0) <<2) | UQ_GO | (uqerror ? UQ_LF : 0); if (uba_hd[numuba].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 */ Pccb.step4w |= UQ_CS; } SA_W(pccb) = Pccb.step4w; /* Enable the controller */ Lpinfo.uq_state = S_RUN; /* Controller is online */ if(!(uq_create_sys( pccb ))) { /* Create new system */ return(0); /* Couldn't create the system */ } if(Pccb.poll_rate == 0) /* Set the rate for the sa poll */ Pccb.poll_rate = hz;/* *//* Start the SA register watchdog timer. This time will not start *//* running until the timer queues are enabled. *//* */ 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 */ } Pccb.init_leader = Pccb.reset_leader = UQPath_Is_Up; Lpinfo.uq_flags &= ~UQ_PRB; /* We are now out of probe *//* * Return size of device structure. Because the uq device structure * contains an extra word for the KDB50 we must check the device type * and return the size based on that type. For all but the KDB the * size is struct uqdevice less one short. */ return( Pccb.uqregsize );}/* * * * Name: uq_port_reset * * Abstract: Perform reset of controller * * Inputs: * * pccb - pointer to PCCB for this port * * * * Outputs: * * * SMP: This code should only be entered by the cpu * currently equal to init_leader, although no * lock is currently asserted. Because of this * design, no calls to lock primitives are done. * In other words, the caller of uq_port_reset is * obligated to take care of smp-safety. * * * Return * Values: * * * * * Side * Effects: * */void uq_port_reset( pccb ) /* Reset controller */PCCB *pccb;{unsigned int count; /* A debugging macro */ cpu_printf (Pccb.init_leader, Pccb.reset_leader, "uq_port_reset"); switch(Lpinfo.uq_type) { case BDA_TYPE: { struct bda_regs *bdar= (struct bda_regs *)((long)(Pccb.Uqip) - UQB_IP); bisst(&bdar->bda_biic.biic_ctrl); bdar->bda_biic.biic_int_ctrl = (Pccb.bda_init_vec & 0x0ffff); bdar->bda_biic.biic_int_dst = Pccb.bda_init_dest; bdar->bda_biic.biic_err = Pccb.bda_init_errvec; } break; case KDM_TYPE: { struct xmi_reg *xmir= (struct xmi_reg *)((long)(Pccb.Uqip) - UQX_IP); u_long vec; if(Pccb.reinit_cnt >= (UQ_MAX_REINIT-1)) { /* Try soft reset first */ *Pccb.Uqip = 1; xmir->xmi_xbe = xmir->xmi_xbe & XMI_NHALT; DELAY(600000); /* delay 600 msec. */ count = 0; while (count < 400) { DELAY(1000) /* wait one msec. */ count++; if ((!(xmir->xmi_xbe & XMI_XBAD)) && (!(xmir->xmi_xbe & XMI_STF))) break; } /* end while */ /* if the while loop timed out, do hard init */ if (count >= 400) xmisst(xmir); else break; /* i.e, continue soft init */ } else { /* Else hard init */ xmisst(xmir); } } break; default: *Pccb.Uqip = 0; break; } return;}/* * * * Name: uq_set_reg * * Abstract: Setup uq port register pointers. * * Inputs: * * pccb - pointer to PCCB for this port * reg - Base address of IP register * * * * Outputs: The port register offsets are added to the IP * physical address to get the physical address for * each of the port registers. The offsets are * bus-dependent. * * * * * * Return * Values: * * * * * Side * Effects: Port registers are accessible via the pccb fields. * */void uq_set_reg( pccb, reg ) /* Set up pointers to IO registers */register PCCB *pccb;caddr_t reg;{ if (uba_hd[numuba].uba_type & UBABDA) { Pccb.Uqip = ( u_short * )(( u_char * )reg + UQB_IP_OFF); Pccb.Uqsa = ( u_short * )(( u_char * )reg + UQB_SA_OFF); Pccb.Uqsaw = ( u_short * )(( u_char * )reg + UQB_SAW_OFF); Pccb.uqregsize = 6; } else if (uba_hd[numuba].uba_type & UBAXMI) { Pccb.Uqip = ( u_short * )(( u_char * )reg + UQX_IP_OFF); Pccb.Uqsa = ( u_short * )(( u_char * )reg + UQX_SA_OFF); Pccb.Uqpd = ( u_long * )(( u_char * )reg + UQX_PD_OFF); Pccb.uqregsize = 12; } else { Pccb.Uqip = ( u_short * )(( u_char * )reg + UQ_IP); Pccb.Uqsa = ( u_short * )(( u_char * )reg + UQ_SA); Pccb.uqregsize = 4; }}/* * * * Name: step_wait * * Abstract: Waits for the specified initialization step to * complete. * * Inputs: * * pccb - pointer to PCCB for this port * mask - mask of interesting bits * result - what those bits should be * * * * Outputs: * * * * * * Return * Values: * * * * * Side * Effects: * */u_long step_wait( pccb, mask, result ) /* Wait for step to complete */PCCB *pccb;short mask;short result;{register int count; count = 0; while (count < DELAYTEN){ /* Wait for at most 10 seconds */ if((*Pccb.Uqsa & mask) == result) break; /* Got the step - hoo ray */ DELAY(10000); /* Spin our wheels for 10 ms */ count = count+1; } if (count == DELAYTEN) { /* If we timed out then return failure */ return(0); } else return(RET_SUCCESS); } /* * * * Name: uq_create_sys * * * Abstract: Obtain the necessary data structures to make a system * known to SCS. Initialize these structures and call the * appropriate routine to make the system known. * * Inputs: * * pccb - Pointer to PCCB for this port * * pd.uq.uq_ctlr - Controller number * pd.uq.step4r - Data read during step 4 of initialization * lpinfo.name - Local port name * * * * * Outputs: * * pccb - Pointer to PCCB for this port * * lpinfo.uq.uq_type - UQSSP model number for this device * pd.uq.pb - Pointer to PB for this port * * sb - System block for this port * * various fields initialized * * pb - Path Block for this port * * various fields initialized * * SMP: locking not neccessary because only one cpu-thread is * permitted to an initialization. * * * Return * Values: * * 0 - System could not be created * 1 - System could be created * * * Side * Effects: * * The SB and PB for the port are allocated and initialized. The PB * is placed on the System Block PB queue and the SB is place on the * scs_config_db systemwide queue. scs_new_path is called to notify * SCS of the existence of a new path to the system. */u_long uq_create_sys(pccb)PCCB *pccb;{ register PIB *pib = &uq_pib; register SIB *sib = &uq_sib; PB *pb; SB *sb; int i, s; cpu_printf (Pccb.init_leader, Pccb.reset_leader, "uq_create_sys"); (void)bzero( pib, sizeof(PIB)); /* Clear pib */ (void)bzero( sib, sizeof(SIB)); /* Clear sib */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -