📄 ci_subr.c
字号:
* 1. Allocating a full size CI port specific datagram buffer for use as a * port command packet. * 2. Formatting the SNDLB specific portion of the command packet. * 3. Formatting the generic Vaxport header. * 4. Initiating port command execution. * * Port command execution( Step 4 ) leads to loopback datagram transmission * over the CI to the local port itself. The local port is used as the * target for the loopback datagram because it is the only port guaranteed * to be present. The loopback packet is transmitted over the current * polling cable instead of allowing the port to choose the physical cable * for transmission. The port is always crashed whenever loopback datagram * transmission can not be successfully initiated. * * Successful reception of the loopback datagram( LBREC ) successfully * completes the connectivity test on the current cable. Local port * loopback cable status is updated and any bad->good loopback cable * transitions are logged. The connectivity test on the current cable is * also completed by either failure to transmit the loopback datagram or * failure to successfully receive the loopback datagram. Such failure is * noted the next time this routine is invoked( Phase 1 ) to test the * connectivity status of the target cable. * * Prior to testing local port connectivity, the CI PPD port polling burst * size and contact frequency for the local port are reset from CI * configuration variables. */ pccb->Contact = ci_cippdcontact; pccb->Burst = ci_cippdburst; ( void )ci_update_cable( pccb, NULL, NULL, CABLE_LB_GB ); if( pccb->Lpstatus.connectivity ) { if(( npaths = pccb->lpinfo.Nform_paths + pccb->lpinfo.Npaths ) <= 1 && ( npaths == 0 || cippd_get_pb( pccb, ( SCSH * )&pccb->lpinfo.addr, NO_BUF ))) { pccb->Lpstatus.connectivity = 0; pccb->Lbstatus.cable0_test = 0; pccb->Lbstatus.cable1_test = 0; skip_test = 0; } else if( pccb->Poll_cable == FIRST_CABLE ) { if( pccb->Lbstatus.cable0_prev || !pccb->Lbstatus.cable0_test ) { skip_test = 0; } else { skip_test = 1; } } else if( pccb->Lbstatus.cable1_prev || !pccb->Lbstatus.cable1_test ){ skip_test = 0; } else { skip_test = 1; } if( skip_test ) { return; } } if(( scsbp = gvp_alloc_dg( pccb ))) { cibp = Scs_to_pd( scsbp, pccb ); bp = Sndlb( Pd_to_ppd( cibp, pccb )); bp->lblength = LBDSIZE; ( void )bcopy( pccb->Lbdata, bp->lbdata, LBDSIZE ); ( void )bcopy(( u_char * )&pccb->Lbcrc, bp->crc, sizeof( u_long )); Format_gvph( pccb, cibp, SNDLB, Scaaddr_low( pccb->lpinfo.addr ), RECEIVE_BUF ) if(( Cselect( cibp ) = pccb->Poll_cable ) == FIRST_CABLE ) { pccb->Lbstatus.cable0_curr = 1; pccb->Lbstatus.cable0_test = 1; } else { pccb->Lbstatus.cable1_curr = 1; pccb->Lbstatus.cable1_test = 1; } Insqti_maintenance( cibp, pccb ) }}/* Name: ci_update_ptype - Update Hardware Port Type of Remote Port * * Abstract: This routine updates the remote port's hardware port type as * necessary. It is required because CI750, CI780, and CIBCI CI * ports all identify themselves as CI780 CI ports to requests for * identification. * * This routine is invoked by the CI PPD finite state machine * after it has received both an identification packet and a * START/STACK CI PPD datagram. It is only at this time that * sufficient information is available for correctly specifying * the remote port's hardware port type. * * NOTE: This is an optional PD routine( Update_ptype ) for use by * the CI PPD finite state machine. The CI port driver * provides it because it is unable to easily distinguish * between certain CI ports until a certain point in the * path establishment process. Other port drivers do not * have such needs and need not provide this routine. * * Inputs: * * IPL_SCS - Interrupt processor level * pb - Path Block pointer * * Outputs: * * IPL_SCS - Interrupt processor level * pb - Path Block pointer * pinfo.type.hwtype - Remote hardware port type * * SMP: The PB is locked( EXTERNALLY ) postponing potential PB deletion * and allowing exclusive access to PB contents. */voidci_update_ptype( pb ) PB *pb;{ if( pb->pinfo.type.hwtype == HPT_CI780 ) { if( bcmp(( char *)&pb->sb->sinfo.hwtype, "V750", 4 ) == 0 ) { pb->pinfo.type.hwtype = HPT_CI750; } else if(( bcmp(( char *)&pb->sb->sinfo.hwtype, "V780", 4 ) != 0 ) && ( bcmp(( char *)&pb->sb->sinfo.hwtype, "8600", 4 ) != 0 )) { pb->pinfo.type.hwtype = HPT_CIBCI; } }}/* Name: ci_alloc_pkt - Allocate CI Port Command Packet * * Abstract: This function allocates a CI port specific command packet from * dynamic kernel memory. Such packets must always be directed to * the local port response queue following command execution. * They must never be directed to the appropriate local port free * queue. * * NOTE: The CI specific PCCB field pkt_size must contain the size * of the largest CI port command to always be directed to * the local port response queue following command * execution. Currently this is the SETCKT port command. * * Inputs: * * IPL_SCS - Interrupt processor level * pccb - Port Command and Control Block pointer * pd.gvp.type.ci - CI specific PCCB fields * pkt_size - Size of port command packet * * Outputs: * * IPL_SCS - Interrupt processor level * * Return Values: * * Address of generic Vaxport header in buffer on success * Otherwise NULL * * SMP: No locks are required. PCCB addresses are always valid * allowing access to static fields because these data structures * are never deleted once their corresponding ports have been * initialized. */GVPH *ci_alloc_pkt( pccb ) PCCB *pccb;{ register GVPH *cibp; KM_ALLOC( cibp, GVPH *, pccb->Pkt_size, KM_SCABUF, KM_NOWAIT|KM_WIRED ) if( cibp ) { U_long( cibp->size ) = ( u_long )(( DYN_CICMD << 16 ) | pccb->Pkt_size ); Dm_msg_dg( cibp, pccb->Pkt_size ) } return( cibp );}/* Name: ci_dealloc_pkt - Deallocate CI Port Command Packet * * Abstract: This routine deallocates a CI port specific command packet to * dynamic kernel memory. * * Inputs: * * IPL_SCS - Interrupt processor level * cibp - Address of generic Vaxport header * * Outputs: * * IPL_SCS - Interrupt processor level * * SMP: No locks are required. */voidci_dealloc_pkt( cibp ) GVPH *cibp;{ KM_FREE(( char * )cibp, KM_SCABUF )}/* Name: ci_update_cable - Update Cable Status of Path Block * * Abstract: This routine checks for the specified cable transition. The * following types of transitions may be checked for: * * 1. Cable transitions from good to bad. * 2. Cable transitions from bad to good. * 3. Cables transition from crossed to uncrossed or uncrossed to * crossed. * 4. Loopback cable transitions from good to bad. * 5. Loopback cable transitions from bad to good. * * Occurrence of a cable transition triggers logging of the event. * * Inputs: * * IPL_SCS - Interrupt processor level * cibp - Address of generic Vaxport header( OPTIONAL ) * pb - Address of Path Block( OPTIONAL ) * pccb - Port Command and Control Block pointer * type - CABLE_BG, CABLE_GB, CABLE_CROSSED, * CABLE_LB_BG, or CABLE_LB_GB * * Outputs: * * IPL_SCS - Interrupt processor level * pb - Path Block pointer * pd.gvp.type.ci - CI specific PB fields * pstatus - Path status flag bits * cable0 - Cable0 status flag * cable1 - Cable1 status flag * cables_crossed - Cables crossed flag * pccb - Port Command and Control Block pointer * pd.gvp.type.ci - CI specific PCCB fields * lbstatus - Loopback status flags * cable0_curr - Cable 0 current status flags * cable0_prev - Cable 0 previous status flags * cable1_curr - Cable 1 current status flags * cable1_prev - Cable 1 previous status flags * * SMP: The PCCB is locked( EXTERNALLY ) in case the occurrence of a * cable transition requires its logging. * * The PB is locked( EXTERNALLY ), whenever one is provided, * postponing potential deletion and allowing exclusive access to * PB contents. */voidci_update_cable( pccb, pb, cibp, type ) PCCB *pccb; PB *pb; GVPH *cibp; u_long type;{ register LBRECH *lb; register u_long event = 0; /* The following types of transition checks update the cables status of * appropriate PBs utilizing information found within CI port packets: * * 1. CABLE_GB - Cable transitions from cable good to cable bad. * 2. CABLE_BG - Cable transitions from cable bad to cable good. * 3. CABLE_CROSSED - Cable transitions from cables crossed to cables * uncrossed or from cables uncrossed to cables crossed. * * Determination of whether loopback cables have transitioned from good to * bad( CABLE_LB_GB ) updates the loopback cable status of appropriate * PCCBs and does NOT utilize CI port packets but only PCCB information. * * The last type of cable transition checking, whether loopback cables have * transitioned from bad to good, utilizes CI port packets but only when * such packets are provided. Otherwise, only PCCB information is used in * such determinations together with the additional assumption that the * appropriate loopback cable status are now good. The loopback cable * statuses of appropriate PCCBs are always updated. */ switch( type ) { case CABLE_GB: if( Cable0_status( cibp ) != CABLE_ACK ) { if( !pb->Pstatus.cable0 ) { event = W_CABLE0_GB; pb->Pstatus.cable0 = 1; } } else if( !pb->Pstatus.cable1 ) { event = W_CABLE1_GB; pb->Pstatus.cable1 = 1; } break; case CABLE_BG: if( Receive_cable( cibp ) == CS_CABLE0 ) { if( pb->Pstatus.cable0 ) { event = I_CABLE0_BG; pb->Pstatus.cable0 = 0; } } else if( pb->Pstatus.cable1 ) { event = I_CABLE1_BG; pb->Pstatus.cable1 = 0; } break; case CABLE_CROSSED: if( Send_cable( cibp ) == Receive_cable( cibp )) { if( pb->Pstatus.cables_crossed ) { event = I_CABLES_CU; pb->Pstatus.cables_crossed = 0; } } else if( !pb->Pstatus.cables_crossed ) { event = W_CABLES_UC; pb->Pstatus.cables_crossed = 1; } break; case CABLE_LB_GB: if( pccb->Poll_cable == FIRST_CABLE ) { if( !pccb->Lbstatus.cable0_prev && pccb->Lbstatus.cable0_curr){ event = W_CABLE0_LBGB; } pccb->Lbstatus.cable0_prev = pccb->Lbstatus.cable0_curr; } else { if( !pccb->Lbstatus.cable1_prev && pccb->Lbstatus.cable1_curr){ event = W_CABLE1_LBGB; } pccb->Lbstatus.cable1_prev = pccb->Lbstatus.cable1_curr; } break; case CABLE_LB_BG: lb = Lbrec( Pd_to_ppd( cibp, pccb )); if( Comp_loopback( pccb, lb )) { if( Cselect( cibp ) == CS_CABLE0 ) { pccb->Lbstatus.cable0_curr = 0; if( pccb->Lbstatus.cable0_prev ) { event = I_CABLE0_LBBG; } } else { pccb->Lbstatus.cable1_curr = 0; if( pccb->Lbstatus.cable1_prev ) { event = I_CABLE1_LBBG; } } } break; default: ( void )panic( PANIC_CABLE ); } if( event ) { ( void )ci_log_packet( pccb, pb, NULL, event, RPORT_EVENT ); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -