📄 uqserv.c
字号:
pib->lport_name = pccb->lpinfo.name; /* Local port name */ pib->type.hwtype = HPT_UQSSP; /* Local port type */ pib->type.dual_path = 0; /* Single path port */ Scaaddr_low( pib->rport_addr ) = *(u_short *)&Pccb.uq_ctlr; /* Remote port address */ Scaaddr_mid( pib->rport_addr ) = 0; Scaaddr_hi( pib->rport_addr ) = 0;/* If we can't get a pb then it's no go */ s = Splscs(); /* Set IPL to SCS level */ if((pb = scs_alloc_pb( PS_OPEN, pccb, pib )) == (PB *)NULL) { (void)splx(s); /* Reset IPL */ return(0); } (void)splx(s); /* Reset IPL */ sib->max_msg = sizeof(MSCP_MAXBUF); /* Max message size */ sib->npaths = 1; /* Only 1 path to these devices */ bcopy("UQ ",&sib->swtype,4); /* Software type is UQ port */ bcopy("3.00",&sib->swver,4); /* Software version */ (void)scs_unix_to_vms((struct timeval *)&boottime, &sib->swincrn); bcopy(uq_cinfo[Lpinfo.uq_type].name,&sib->hwtype,4); /* Controller type in ASCII*/ sib->hwver.val[0] = (long)(Pccb.step4r & 0xF); /* Microcode version number */ sib->hwver.val[1] = (long)Pccb.uq_ctlr; /* Controller number */ sib->hwver.val[2] = (long)Lpinfo.uq_type; /* Controller model code */ *(u_long *)sib->node_name = pccb->lpinfo.name; /* SCA Node name */ bcopy(" ",(u_long *)sib->node_name+1,4);/* The system id of uq controllers is as follows: *//* *//* 47 32 31 0 *//* +----------------+------------------------------------+ *//* ! ! ! *//* ! UQSSP model # ! Device Address (CSR) ! *//* ! ! ! *//* +----------------+------------------------------------+ *//* */ { register u_long addr_tmp = *(u_long *)&Pccb.Uqip; Scaaddr_low( sib->sysid ) = ( addr_tmp & 0xffff ); Scaaddr_mid( sib->sysid ) = ( u_short )(( addr_tmp >> 16 ) & 0xffff ); Scaaddr_hi( sib->sysid ) = *(u_short *)&Lpinfo.uq_type; }/* If we can't get a sb then it's no go */ s = Splscs(); /* Set IPL to SCS level */ if((sb = scs_alloc_sb( sib )) == (SB *)NULL) { (void)scs_dealloc_pb( pccb,pb ); /* Deallocate PB */ (void)splx(s); /* Reset IPL */ return(0); } (void)splx(s); /* Reset IPL */ for (i=0; i<NCON; i++) Lpinfo.uq_credits[i] = 1; /* Give initial credit of 1 */ s = Splscs(); /* Set IPL to SCS level */ Lock_pccb (pccb); Pccb.pb = pb; /* Save on pccb */ pb->sb = sb; /* Point to System Block */ Insert_entry(pb->flink,Sb->pbs); /* Insert PB on SB queue */ Unlock_pccb (pccb); Lock_scadb (); Insert_entry(sb->flink,scs_config_db); /* Insert SB on system-wide */ /* configuration database */ Unlock_scadb (); scs_new_path( sb, pb ); (void)splx(s); /* Reset IPL */ return(RET_SUCCESS);}/* * * * Name: uq_init_buffers * * Abstract: Map the communications area and packet buffers. * Initialize the ring pointers and place the * packet buffers on the response ring or free queue. * * Inputs: * * pccb - Pointer to PCCB for this port * pd.uq.uq_mapped - Set to 1 if the communications area has * been mapped. * * ctlr - Controller number * * * * Outputs: * * pccb * pd.uq.uqptr - Unibus address of communcations/packet area * pd.uq.uq_ubainfo - Mapping information for communications area * pd.uq.uq_mapped - Set to 1 if the comm area is mapped * pd.uq.rsp_cnt - Number of used response ring entries * pd.uq.cmd_cnt - Number of used command ring entries * pd.uq.rsprindx - Index of next empty response ring entry * pd.uq.cmdrindx - Index of next empty command ring entry * pd.uq.uq_lastrsp - Index of next response ring entry to poll * pd.uq.uq_lastcmd - Index of next command ring entry to poll * pd.uq.uq_freel - List of free packet buffers * * * * Return * Values: * * * * * Side * Effects: * */uq_init_buffers(pccb)PCCB *pccb;{ register UQ *uq; register UQ *uuq; int i; cpu_printf (Pccb.init_leader, Pccb.reset_leader, "uq_init_buffers"); uq = Pccb.uq; if (Pccb.uq_mapped == 0) { /* Need to map communication area */ /* and command/response packet buffers */ if ((Lpinfo.uq_type == BDA_TYPE) || (Lpinfo.uq_type == KDM_TYPE)) { Pccb.uqptr = (UQ *) (Pccb.uq_ubainfo = svtophy(uq)); } else { if(Pccb.step1r & UQ_QB) /* it's a Q-22 bus so use all 8k map reg */ Pccb.uq_ubainfo = qballoc(numuba, (caddr_t)uq, sizeof ( UQ ), 0); else Pccb.uq_ubainfo = uballoc(numuba, (caddr_t)uq, sizeof ( UQ ), 0); if(uba_hd[numuba].uba_type & UBAUVI) Pccb.uqptr = (UQ *)(Pccb.uq_ubainfo & 0x3fffff); else if(Pccb.step1r & UQ_QB) /* it's a Q-22 bus so use all 8k map reg */ Pccb.uqptr = (UQ *)(Pccb.uq_ubainfo & 0x3fffff); else Pccb.uqptr = (UQ *)(Pccb.uq_ubainfo & 0x3ffff); } Pccb.uq_mapped = 1; /* Indicate mapping completed */ } if(Lpinfo.uq_type == KDM_TYPE) { uq->uqca.ca_xmi.flags = 0; /* No flags set */ uq->uqca.ca_xmi.psi = SSP_PSI_512; /* Use 512 page size for now */#ifdef notdef uq->uqca.ca_xmi.psi = SSP_PSI_4096; /* MIPS page size = 4096 */#endif notdef uq->uqca.ca_xmi.pfn = SSP_PFN_MASK; /* PFN mask */ } Pccb.rsp_cnt = 0; /* Clear various counters and */ Pccb.cmd_cnt = 0; /* pointers. */ Pccb.rsprindx = 0; Pccb.cmdrindx = 0; Pccb.uq_lastrsp = 0; Pccb.uq_lastcmd = 0; Pccb.ncon = 0; /* Mark connection count as 0 */ Pccb.uq_con = 0; /* Clear connection vector */ Pccb.uq_freel = (uqbq *)NULL; /* Initialize free list */ Init_queue(Pccb.waitq); /* Initialize command wait queue */ Init_queue(Pccb.scswaitq); /* Initialize SCS command wait queue */ uuq = Pccb.uqptr; /* Get unibus address of com area */ for (i = 0; i < NBUF; i++) { /* Process buffers */ /* Save unibus address of buffer */ Pccb.uq->uq_buf[i].uqh.ua = (long)&uuq->uq_buf[i].app_buf; /* Place buffer in rsp ring or on free queue if ring is full */ uq_ins_rspring((UQH *)&Pccb.uq->uq_buf[i],pccb); }}/* * * * Name: uq_ins_rspring - Insert buffer on response ring * * Abstract: This routine takes as input a pointer to a buffer. * It checks the response ring for empty slots. If * the ring is not full it places the buffer on the ring. * If the ring is full the buffer is placed on the * free buffer queue. * * Inputs: * * bp - Pointer to UQ_header portion of buffer to * insert. * pccb - Pointer to PCCB for this port * pd.uq.rsp_cnt - Count of "used" entries in response ring * pd.uq.rsprindx - Pointer to next location in ring to receive * packet. * * * * Outputs: * * pccb * pd.uq.rsp_cnt - If buffer added to ring this value is * incremented. * pd.uq.rsprinx - If buffer added to ring this value is * incremented mod ring size. * pd.uq_freel - If buffer is added to free list this * location now points to new buffer and * approriate links are updated. * * * SMP * The index into the response ring and the count of buffers * in the ring are incremented. This must be SMP * protected. * * If the buffer is placed on the Pccb's buffer free list, then * that linked list is modified inside the scope of the lock. * * Return * Values: * * * * * Side * Effects: * */uq_ins_rspring( uqbp,pccb )UQH *uqbp; /* Pointer to UQ header in buffer */PCCB *pccb; /* Pointer to PCCB */{UQPPDH *uqpbp;int s; s = splbio(); Lock_pccb (pccb); if(Pccb.rsp_cnt < NRSP) { /* Ring not full */ uqpbp = Pos_to_ppdh(uqbp); uqpbp->uqp_msglen = sizeof(MSCP_MAXBUF) + sizeof(UQPPDH); /* * 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_rspdsc[Pccb.rsprindx] = uqbp->ua; WBFLUSH; Pccb.uq->uqca.ca_rspdsc[Pccb.rsprindx] |= (UQ_OWN | UQ_INT); WBFLUSH; /* Save physical address of buffer */ Pccb.rspbtab[Pccb.rsprindx] = uqbp; Pccb.rsp_cnt++; /* Increment count of used slots */ Pccb.rsprindx++; /* Increment index into the ring */ Pccb.rsprindx %= NRSP; /* modulo ring size */ } else { /* Ring full - place on free list */ uqbp->flink = Pccb.uq_freel; Pccb.uq_freel = (uqbq *)uqbp; } WBFLUSH; Unlock_pccb (pccb); (void)splx(s);}/* * * * Name: uq_poll_rspring * * Abstract: Check the response ring for any new responses. * If there are any convert them to SCS messages * and send them on their way. This routine will * loop until the outstanding response count goes * to zero or until it encounters an unused entry. * * Inputs: * * pccb - Pointer to PCCB for this port. * * * * Outputs: * * pccb * pd.uq.rsp_cnt - If a response is retrieved this value is * decremented. * pd.uq.lpinfo.uq_credits[con] - If a response is retrieved the * credits given in the response packet are * added to the total for this connection. * pd.uq.last_rsp - If a response is retrieved this value is * incremented mod ring size. This value is * the next ring entry to examine for a * response. * * * * SMP * The count of buffers loaded into the ring and the ownership * bits for the buffers in the ring must be modified in an * smp-safe manner. The response buffer count is tested before * locking the pccb; then, after the pccb is locked, we read * it again to make sure another cpu hasn't come in to do our work * for us - if it is still not zero then we look at the * ownership bit for the next response entry; if we own the * entry, we save it for later in uqbp. The Pccb gets unlocked. * We give uqbp to SCS. And then we start over again. * * Return * Values: * * * * * Side * Effects: * * If a response is found a call to scs_msg_rec or scs_dg_rec is generated * depending on the message type of the response. If there is an entry * on the free buffer queue that entry is placed in the response ring * in place of used entry. If no buffer is available uq_poll_cring is * called to scan the command ring for used entries. That routine will * place any free buffers on the response ring/free queue as described * in uq_ins_rspring. */uq_poll_rspring(pccb)PCCB *pccb;{UQH *uqbp;UQH *rp;UQPPDH *uqpbp;SCSH *scsbp;char con;u_char mtype;short msglen;int save_ipl, s;int pb_not_null = 1; save_ipl = splbio(); /* Raise IPL to muck with rings */ while (Pccb.rsp_cnt != 0) { /* There are outstanding responses */ Lock_pccb(pccb); if (Pccb.rsp_cnt != 0) { /* Is it still != 0, if not then leave */ if (Pccb.uq->uqca.ca_rspdsc[Pccb.uq_lastrsp] & UQ_OWN) { Unlock_pccb(pccb); (void)splx(save_ipl); return; /* But we don't own any */ } /* Get buffer address */ uqbp = Pccb.rspbtab[Pccb.uq_lastrsp]; /* Decrement count of used slots */ --Pccb.rsp_cnt; Pccb.uq_lastrsp++; /* Increment response pointer */ Pccb.uq_lastrsp %= NRSP; if (Pccb.pb == NULL) pb_not_null = 0; /* We just removed a buffer from the response ring, so we try to insert another one in */ /* Are there any buffers on the freeq? */ if ((rp = (UQH *)Pccb.uq_freel) != (UQH *)NULL) { Pccb.uq_freel = rp->flink; /* Update list pointer */ Unlock_pccb (pccb); uq_ins_rspring(rp,pccb); /* Fill the slot */ } else /* No - Poll the command ring to see if we can */ /* scare some up. */ { Unlock_pccb (pccb); uq_poll_cring(pccb); } uqpbp = Pos_to_ppdh(uqbp); /* position to uqssp header */ con = uqpbp->uqp_cid; /* get connection id */ mtype = uqpbp->uqp_msgtype; /* message type */ msglen = uqpbp->uqp_msglen; /* message length */ /* Was it a Last fail packet? */ if((Pccb.uq_con & (short)(1 << con)) == 0) { Pccb.lfptr[con] = uqbp; (void)splx(save_ipl); return; } Lpinfo.uq_credits[con] += (u_short)uqpbp->uqp_credits; /* The uqssp format packet must be converted into an SCS format packet before we send it up; see the comments to uq_ins_cring() */ scsbp = SCS_msg_header(uqbp); /* Position to scs header */ scsbp->credit = (short)uqpbp->uqp_credits; /* Update the credits */ scsbp->rconnid = Pccb.contab[con]; /* Insert remote connection id */ Store_connid( scsbp->sconnid ) = con; /* Insert sending connection id */ if (mtype == UQT_SEQ) { /* Sequential Message Type */ s = Splscs(); /* Set IPL to SCS level */ scsbp->mtype = SCS_APPL_MSG; /* Application Message */ if (pb_not_null) scs_msg_rec( pccb, scsbp, (sizeof(SCSH) + msglen) ); (void)splx(s); /* Reset IPL */ } if (mtype == UQT_DG) { /*Datagram Message Type */ s = Splscs(); /* Set IPL to SCS level */ scsbp->mtype = SCS_APPL_DG; scs_dg_rec( pccb, scsbp, (sizeof(SCSH) + msglen) ); (void)splx(s); /* Reset IPL */ } } /* end if */ else Unlock_pccb(pccb); } /* end while */ WBFLUSH; (void)splx(save_ipl);}/* * * * Name: uq_ins_cring * * Abstract: This routine will place a buffer on the command * ring if there is an available slot. If no slot is * available the buffer is placed on the wait queue * for later retrieval. If the command is placed on * the ring the IP register on the controller is read * to initiate polling of the ring. * * * Inputs: * * scsbp - Pointer to SCS header of buffer to use * uqpbp.msglen - Size of application message * pccb - Pointer to PCCB for this port * pd.uq.cmd_cnt - Number of used entries on the command ring * pd.uq.cmdrindx - Index into ring to place next buffer * pd.uq.waitq - Wait queue for queued commands * lpinfo.uq.uq_credits[i] - Number of credits available on this * connection * Outputs: * * pccb - Pointer to PCCB for this port * pd.uq.cmd_cnt - Incremented if command placed on ring * pd.uq.cmdbtab[i] - Address of buffer placed in ring entry i. * - Valid if command * * * * The SCS layer has given us an sca format command and uq * must convert it into an uqssp format command. * * In order to do this uq overwrites the scs sconnid field * (1 long word) with a uqssp command packet header (1 long word); * this is done in two steps - in uq_send_msg() uq writes * in the uq header Size field; here, uq_ins_cring() writes in the * Credit field, the Message Type field, and the uq Connid. The uq * Connid (1 byte) is copied from the low byte of the * scs-packet's rconnid. The scs-packet's rconnid is the scs * sconnid uq_conn() gave to scs at connection startup. * * When the response packet comes back from the uq controller, * uq_poll_rspring() inserts the scs rconnid which was saved * in Pccb.contab by uq_conn() at connection start-up. * The uqssp header is then overwritten with an scs sconnid; * this scs sconnid is equal to the uq connid. (Technically, * this scs sconnid may be incorrect in its seq-num field; but * this doesn't matter because it is the rconnid, restored
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -