📄 cippd_event.c
字号:
Pccb_fork( pccb, pccb->Init_port, PPDPANIC_PCCBFB ) } else { for( pb = pccb->Form_pb.flink, next_pb = Pb->flink; pb != &pccb->Form_pb; pb = next_pb, next_pb = Pb->flink ) { Lock_pb( Pb ) if( Pb->pinfo.state != PS_PATH_FAILURE ) { if( Pb->pinfo.state != PS_OPEN ) { Pb->pinfo.reason = reason; ( void )cippd_log_path( pccb, Pb, NULL, W_ABORT_PATH ); Pb->pinfo.state = PS_PATH_FAILURE; Incr_pb_sem( Pb ) Pb_fork( Pb, cippd_clean_fpb, PPDPANIC_PBFB ) } else { ( void )panic( PPDPANIC_PSTATE ); } } Unlock_pb( Pb ) } for( i = ( CIPPD_MAXPATHS - 1 ); i >= 0; --i ) { if(( pb = pccb->Open_pb[ i ])) { Lock_pb( Pb ) if( Pb->pinfo.state == PS_OPEN ) { Pb->pinfo.reason = reason; ( void )cippd_log_path( pccb, Pb, NULL, W_FAIL_PATH ); Pb->pinfo.state = PS_PATH_FAILURE; Incr_pb_sem( Pb ) Pb_fork( Pb, cippd_clean_pb, PPDPANIC_PBFB ) } else if( Pb->pinfo.state != PS_PATH_FAILURE ) { ( void )panic( PPDPANIC_PSTATE ); } Unlock_pb( Pb ) } } } Unlock_pccb( pccb )}/* Name: cippd_poll - Poll Remote Ports for their Identification * * Abstract: This routine polls all remote ports, both known and unknown, * from a specific local port. Through this process new systems * are discovered and the state of CI PPD paths to known systems * verified. The polling process is itself sanity checked to * verify the operational status of the local port. * * Port Polling is accomplished by requesting remote port * identifications. Each time this routine is invoked the * identification of a subset of all potentially existing remote * ports accessible from the local port is requested. It takes * may take several routine invocations to sweep through all * potentially accessible remote ports. * * The number of ports polled during each invocation is a function * of the maximum number of ports to poll, the polling burst size, * and the next port to poll within the port's current sweep. The * first factor is governed by a dynamically adjustable parameter * as is the second at the discretion of individual port drivers. * * The state of established CI PPD paths is determined during each * sweep by transmitted all identification requests over a * specific physical cable. This allows the state of this * component of an established CI PPD path to be verified. When * the current sweep completes a new cable is chosen for the next * sweep. * * This routine is also responsible for allocating and adding to * the appropriate local port datagram free queue an initial * number of free datagram buffers. These buffers are used for * the reception of remote port identifications solicited both by * port polling and by the CI PPD finite state machine. They are * also used for reception of unsolicited START CI PPD datagrams * from various remote systems. * * Inputs: * * IPL_SCS - Interrupt processor level * cippd_max_port - CI PPD maximum port number to recognize * cippd_penable - CI PPD port polling enable flag * pccb - Port Command and Control Block pointer * ppd.cippd - CI PPD specific PCCB fields * fsmstatus - Finite State Machine status flags * nosanity_chk - Skip sanity checking flag * online - 1 * ppddgs - Num path establishment dgs left to allocate * * Outputs: * * IPL_SCS - Interrupt processor level * pccb - Port Command and Control Block pointer * ppd.cippd - CI PPD specific PCCB fields * fsmstatus.sanity - Port polling ( sanity check ) in progress * next_port - Next port to poll * poll_cable - CI cable to use for polling * ppddgs - Num path establishment dgs left to allocate * sanity_port - Sanity check remote port * * SMP: The PCCB is locked( EXTERNALLY ) to synchronize access and to * postpone crashing of the local port if it fails while polling * is in progress. */voidcippd_poll( pccb ) register PCCB *pccb;{ register SCSH *scsbp; register u_long nports, max_port, ( *test )();; /* Execute the following steps when port polling is currently enabled: * * 1. Allocate and add to the specific local port datagram free queue any * CI PPD path establishment datagrams remaining to be allocated. * 2. Continue the current polling sweep by requesting the identification * of all remote ports to be polled during the current interval. * 3. Enable a sanity check on local port functioning. * 4. Optionally test the current connectivity status of the specified * local port in a port specific fashion. * 5. Arrange for the next sweep during the next polling interval. * * CI PPD path establishment datagrams are allocated and added to * appropriate local port datagram free queues by this routine( Step 1 ) * contrary to normal expectations. Logically, one would expect * cippd_start(), the routine responsible for starting CI PPD activity on * a specified local port, to allocate and add them. It does not because * such allocations can fail, and such failures within cippd_start() create * unnecessairy complications. It is much easier and more robust to * perform the allocations within this routine, ancillary to port polling. * Individual datagram allocation attempts can still fail; however, such * failures can be ignored because many more opportunities exist to * allocate all required CI PPD path establishment datagrams. * * The sanity check on local port functioning is enabled( Step 3 ) only if * it has not been permanently disabled on the local port and at least one * port was polled during the current polling interval. This check * operates by requiring the request for identification of the very first * remote port polled to be transmitted before the next timer interval. * Failure to do so leads the CI PPD to assume the existence of a * questionable local port functional status and the local port is * explicitly crashed by the CI PPD. * * The current connectivity status of the specified local port is * optionally tested in a port specific fashion( Step 4 ) provided at least * one port was polled during the current polling interval. Such testing * MUST occur prior to making arrangements for the next sweep during the * next polling interval. Connectivity testing is bypassed whenever the * appropriate port driver has failed to establish a routine for testing * local port connectivity. Presumably it deems such testing of its local * ports unnecessary. * * Arrangements are made for the next sweep during the next polling * interval( Step 5 ) only when the current sweep completes. This of * course also requires at least one port to be polled during the current * polling interval. Arrangements for the next polling interval are not * made by this routine but external to it by cippd_timer(). */ if( cippd_penable ) { while( pccb->Ppddgs ) { if(( scsbp = ( *pccb->Alloc_dg )( pccb ))) { ( void )( *pccb->Add_dg )( pccb, scsbp ); --pccb->Ppddgs; } else { break; } } pccb->Sanity_port = pccb->Next_port; for( nports = pccb->Burst, max_port = Maxport( pccb ); nports > 0 && pccb->Next_port <= max_port; --nports, ++pccb->Next_port ) { if(( *pccb->Send_reqid )( pccb, NULL, ( u_long )pccb->Next_port, DEALLOC_BUF ) == RET_ALLOCFAIL ) { break; } } if( nports < pccb->Burst ) { if( !pccb->Fsmstatus.nosanity_chk ) { pccb->Fsmstatus.sanity = 1; } if( pccb->Next_port > max_port ) { if(( test = pccb->Test_lportconn )) { ( void )( *test )( pccb ); } pccb->Next_port = 0; if( ++pccb->Poll_cable > pccb->Max_cables ) { pccb->Poll_cable = FIRST_CABLE; } } } }}/* Name: cippd_timer - CI PPD Interval Timer Routine * * Abstract: This routine oversees all CI PPD timer related functions. It * is executed on a per port basis once every cippd_itime seconds * where cippd_itime is a dynamically adjustable parameter. * * Inputs: * * IPL_SOFTCLOCK - Interrupt processor level * cippd_max_port - CI PPD maximum port to recognize * cippd_itime - CI PPD port timer interval * pccb - Port Command and Control Block pointer * * Outputs: * * IPL_SOFTCLOCK - Interrupt processor level * pccb - Port Command and Control Block pointer * ppd.cippd - CI PPD specific PCCB fields * fsmstatus.timer - CI PPD interval timer activated status bit * poll_due - Port polling interval timer * poll_interval - Current port polling interval * timer_interval - Current CI timer interval * pb - Path Block pointer * ppd.cippd - CI PPD specific PB fields * due_time - CI PPD traffic interval timer * fsmpstatus.timer - CI PPD traffic interval timer activated bit * * SMP: The PCCB is locked to synchronize access and as required by * optional PD routines which notify local ports of continued CI * PPD activity. PCCB addresses are always valid because these * data structures are never deleted once their corresponding * ports have been initialized. * * PBs are locked to synchronize access and for the declaration * of CI PPD timeout configuration events when their traffic * interval timers have expired. */voidcippd_timer( pccb ) register PCCB *pccb;{ register pbq *pb, *next_pb; register u_long save_ipl = Splscs(), ( *notify )(); /* Each timer interval the following sequence of actions occurs: * * 1. IPL is synchronized to IPL_SCS. * 2. The PCCB is locked. * 3. The local port is optionally notified, in a port specific fashion, of * the continued activity of the CI PPD. * 4. A sanity check on port functioning is performed. * 5. The port's queue of formative PBs is scanned and CI PPD timeout * configuration events declared on each path whose traffic interval * timer has expired. Each PB is locked for the duration of its check. * 6. The next round of port polling from the port is initiated provided * the polling interval timer has expired. * 7. The next timer wake up on the local port is scheduled. * 8. The PCCB is unlocked. * 9. IPL is restored. * * Steps 3-6 are immediately bypassed whenever the local port is found to * not be currently online and functional. * * A sanity check on local port functioning( Step 4 ) consists of verifying * transmission of an identification request to the first remote port * polled during each polling interval. The CI PPD assumes the port is * broken, crashes the port, and aborts the remaining timer actions( Steps * 5-6 ) if the targeted request is not successfully transmitted prior to * expiration of the next timer interval. Sanity checking may be * permanently disabled on a per local port basis at the direction of the * appropriate port driver. * * NOTE: Port polling intervals( frequencies ) are computed as follows: * * ( polling burst size ) * Interval = ---------------------- * ( port contact frequency ) * ( number of ports ) * * Number of ports a dynamically adjustable parameter. Port contact * frequency and Polling burst size vary on a per port basis( actually on * an individual port driver basis ) and are also dynamically adjustable * parameters at the discretion of individual port drivers. * * CI PPD interval timers are permanently active and completely self * maintaining. Therefore, the next timer wake up on the local port is * scheduled regardless of whether the port is currently on or off line( * Step 7 ). The only time the next wake up is not scheduled is when the * port is permanently broken and the appropriate port driver has taken it * permanently offline. */ Lock_pccb( pccb ) if( pccb->Fsmstatus.online ) { if(( notify = pccb->Notify_port )) { ( void )( *notify )( pccb ); } if( pccb->Fsmstatus.sanity ) { ( void )( *pccb->Crash_lport )( pccb, SE_PPDSANITY, NULL ); } else { for( pb = pccb->Form_pb.flink, next_pb = pb->flink; pb != &pccb->Form_pb; pb = next_pb, next_pb = pb->flink ) { Lock_pb( Pb ) if( Pb->Fsmpstatus.timer && ( Pb->Due_time -= pccb->Timer_interval ) < 0 ) { Pb->Fsmpstatus.timer = 0; ( void )cippd_dispatch( pccb, Pb, CNFE_TIMEOUT, NULL ); } Unlock_pb( Pb ) } if(( pccb->Poll_due -= pccb->Timer_interval ) < 0 ) { ( void )cippd_poll( pccb ); pccb->Poll_due = Pinterval( pccb ); pccb->Poll_interval = pccb->Poll_due; } } } if( !pccb->Fsmstatus.broken ) { pccb->Timer_interval = cippd_itime; ( void )timeout( cippd_timer, ( u_char * )pccb, ( hz * cippd_itime )); } else { pccb->Fsmstatus.timer = 0; } Unlock_pccb( pccb ) ( void )splx( save_ipl );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -