📄 scs_protocol.c
字号:
* SCS protocol sequence timeout queue. * * The CB is locked to synchronize access and to prevent deletion. * Locking the CB also prevents PB deletion as required by PD * routines which transmit messages. Only those CBs retrieved by * this routine from PB work queues are explicitly locked by it * and these CBs are unlocked prior to exiting. CBs provided to * this routine must be locked EXTERNALLY and are never unlocked * before exiting. CBs are always indirectly locked through their * CBVTEs. * * The PB is locked to synchronize access, to prevent deletion, * and for PB insertion onto the SCS protocol sequence timeout * queue. PBs are always unlocked just prior to request * transmission as required by PD routines which transmit * messages in this particular case. */voidscs_request( request, cb, pb, scsbp ) register u_long request; register CB *cb; register PB *pb; register SCSH *scsbp;{ register CBVTE *cbvte; static struct { u_short mtype; u_short mlength; struct { u_char credits : 1; u_char conn_info : 1; u_char : 6; } flags; } format[ 5 ] = { { SCS_CONN_REQ, sizeof( CONN_REQ ), 1, 1 }, { SCS_ACCEPT_REQ, sizeof( ACCEPT_REQ ), 1, 1 }, { SCS_REJECT_REQ, sizeof( REJECT_REQ ), 0, 0 }, { SCS_DISCONN_REQ, sizeof( DISCONN_REQ ), 0, 0 }, { SCS_CREDIT_REQ, sizeof( CREDIT_REQ ), 1, 0 } }; /* Servicing SCS requests and initiating transmission of SCS sequenced * messages proceeds as follows: * * 1. Lock the PB. * 2. Verify the path state. * 3. Obtain both a CB on whose behalf the request is to be made and a * port specific message buffer to contain the request as needed. * 4. Lock the CB whenever it was obtained by this routine and not * provided to it. * 5. Format the SCS sequenced message according to the its type. * 6. Unlock the PB. * 7. Initiate sequenced message transmission. * 8. Lock the PB. * 9. Start a sanity check on this current protocol sequence provided the * path is still open. * 10. Unlock the PB. * 11. Unlock the CB whenever it was obtained by this routine and not * provided to it. * * Only failure of the path can result in a failure to verify the path * state( Step 2 ). Servicing of the current request is aborted and any * message buffer provided to this routine is attached to the PB as its SCS * send message buffer. Provided CBs are not placed on the PB work queue * because their requests would never be serviced anyway due to failure of * the path. * * When obtaining CBs and message buffers( Step 3 ), the following two * possibilities exist: * * 1. The message buffer is explicitly provided but the CB is not. * 2. The CB is explicitly provided but the message buffer is not. * * The first possibility occurs when when servicing of a postponed request * is to resume making use of the explicitly provided message buffer. The * very first CB on the PB's work queue is obtained( Step 3 ) and locked( * Step 4 ). The absence of connections with postponed requests or failure * of the path immediately terminates next request processing. The * explicitly provided message buffer is attached to the PB as its SCS * send message buffer and the PB is unlocked before returning. The PB * must always be unlocked and then re-locked after locking each CB in * order to maintain the SCA locking hierarchy. Cached PB addresses remain * valid because possession of the SCA database lock prevents PB deletion. * * The second possibility occurs when servicing on behalf of a connection * is directly requested. The PB's SCS send message buffer is retrieved( * Step 3 ). Unavailability of this buffer forces postponement of the * request by caching the request type and placing the CB on to the PB work * queue. * * Sanity checks on current protocol sequences( Step 9 ) are initiated as * follows: * * 1. Compute the maximum time interval for reception of the corresponding * response. * 2. Place the PB on to the SCS protocol sequence timeout queue. * 3. Schedule the SCS interval timer routine whenever the queue was * previously empty. * * PBs are removed from the SCS protocol sequence timeout queue when * corresponding responses are received. SCS assumes a path has failed if * the proper response is not received before the PB's sanity interval * timer expires and the path is crashed. */ Lock_pb( pb ) if( pb->pinfo.state != PS_OPEN ) { if( scsbp ) { pb->scs_msgbuf = scsbp; } Unlock_pb( pb ) return; } else if( cb == NULL ) { while( pb->scs_cb.flink != &pb->scs_cb ) { cb = Pos_to_cb( pb->scs_cb.flink, scs_cb ); cbvte = Get_cbvte( cb->cinfo.lconnid ); Unlock_pb( pb ) Lock_cbvte( cbvte ) Lock_pb( pb ) if( pb->pinfo.state == PS_OPEN && &cb->scs_cb == pb->scs_cb.flink){ Remove_entry( cb->scs_cb ) request = cb->cinfo.cbstate; cb->cinfo.cbstate = CB_NOT_WAIT; break; } else { Unlock_cbvte( cbvte ) if( pb->pinfo.state != PS_OPEN ) { break; } } } if( request == CB_NOT_WAIT ) { pb->scs_msgbuf = scsbp; Unlock_pb( pb ) return; } } else if(( scsbp = pb->scs_msgbuf )) { pb->scs_msgbuf = NULL; cbvte = NULL; } else { cb->cinfo.cbstate = request; Insert_entry( cb->scs_cb, pb->scs_cb ) Unlock_pb( pb ) return; } if( request <= CB_MAX_PEND ) { scsbp->mtype = format[ --request ].mtype; } else { ( void )panic( SCSPANIC_SCSMSG ); } if( format[ request ].flags.credits ) { scsbp->credit = cb->cinfo.pend_rec_credit; cb->cinfo.rec_credit += cb->cinfo.pend_rec_credit; cb->cinfo.pend_rec_credit = 0; } else { scsbp->credit = 0; } Move_connid( cb->cinfo.rconnid, scsbp->rconnid ) Move_connid( cb->cinfo.lconnid, scsbp->sconnid ) if(( Reject_req( scsbp )->reason = cb->cinfo.reason )) { cb->cinfo.reason = 0; } if( format[ request ].flags.conn_info ) { Conn_req( scsbp )->min_credit = cb->cinfo.min_snd_credit; Move_name( cb->cinfo.rproc_name, Conn_req( scsbp )->rproc_name ) Move_name( cb->cinfo.lproc_name, Conn_req( scsbp )->sproc_name ) Move_name( cb->cinfo.lconn_data, Conn_req( scsbp )->sproc_data ) } else { Conn_req( scsbp )->min_credit = 0; } if( pb->pinfo.status.sanity ) { ( void )panic( SCSPANIC_SANITY ); } else { Unlock_pb( pb ) ( void )( *cb->Send_msg )( cb->pccb, pb, scsbp, format[ request ].mlength, RECEIVE_BUF ); Lock_pb( pb ) if( pb->pinfo.state == PS_OPEN ) { pb->pinfo.status.sanity = 1; pb->pinfo.duetime = scs_sanity; Insert_entry( pb->timeout, scs_timeoutq ) if( scs_timeoutq.flink == &scs_timeoutq ) { ( void )timeout( scs_timer, NULL, 1 ); } } } Unlock_pb( pb ) if( cbvte ) { Unlock_cbvte( cbvte ) }}/* Name: scs_response - Send SCS Sequenced Message Response * * Abstract: This routine initiates transmission of a SCS response over a * specific path. A SCS response is only transmitted following * reception and processing of the corresponding SCS request. * Five such responses are supported: * * 1. Response to a connection request * 2. Response to a connection acceptance request. * 3. Response to a connection rejection request. * 4. Response to a connection termination request. * 5. Response to a request for extension or withdrawal of send * credits. * * SCS applies flow control to its own communication on a per path * basis. Only one SCS request is transmitted across each path at * a given moment. However, SCS responses may always be * immediately transmitted because the message buffer containing * the SCS request on the originating system is reserved for * reception of its corresponding SCS response. * * The message buffer containing the SCS response is always * derived from recyclement of the message buffer containing the * SCS request. * * Inputs: * * IPL_SCS - Interrupt processor level * scsbp - Address of SCS header of message buffer * pb - Path Block pointer * * Outputs: * * IPL_SCS - Interrupt processor level * * SMP: The SCA database is locked( EXTERNALLY ) to guarantee the * validity of PB addresses and to prevent PB deletion. * * The PB is locked to synchronize access to the path's current * path state. It is unlocked immediately following retrieval of * the current path state as required by PD functions/routines * which both transmit messages and add them to appropriate local * port free pools in these particular cases. */voidscs_response( scsbp, pb ) register SCSH *scsbp; PB *pb;{ CONNID save_connid; register u_long state; static u_short rsp_lengths[] = { sizeof( CONN_RSP ), sizeof( ACCEPT_RSP ), sizeof( REJECT_RSP ), sizeof( DISCONN_RSP ), sizeof( CREDIT_RSP ) }; /* The SCS response is formated from the SCS request and transmitted only * if the path is currently open. Otherwise the message buffer is added to * the appropriate local port's free message pool or deallocated depending * upon whether the path( but not the local port ) has failed. * * The PB is locked only for retrieval of the current path state because * the interfaces to both the message transmission and message addition * routines require it to be unlocked in this particular instance. * Unlocking the PB does not present a problem for the following reasons: * * 1. It is not particularly crucial if the path state changes between the * time the PB is unlocked and the cached value is checked. It is true * this could result in an attempt to transmit a SCS response on a * failed path. However, this possibility has always existed and there * is no way to eliminate it. * * 2. It is acceptable to continue to reference PB contents even though it * the data structure is unlocked. The cached PB address is valid * because the SCA database is currently locked preventing PB deletion, * and the contents accessed are static. This includes the path failure * reason which can not change once set for a given path incarnation and * is accessed only after the path has been found to have failed. * * NOTE: The SCS response message type is always 1 more then its * corresponding SCS request message type. * * NOTE: The sending and receiving connection identification numbers of the * SCS request are always the receiving and sending connection * identification numbers of the corresponding SCS response. */ if( scsbp->mtype > SCS_MAX_SCSMSG ) { ( void )panic( SCSPANIC_SCSMSG ); } Lock_pb( pb ) state = pb->pinfo.state; Unlock_pb( pb ) if( state == PS_OPEN ) { ++scsbp->mtype; if( scsbp->mtype != SCS_CREDIT_RSP ) { scsbp->credit = 0; } Move_connid( scsbp->rconnid, save_connid ) Move_connid( scsbp->sconnid, scsbp->rconnid ) Move_connid( save_connid, scsbp->sconnid ) Accept_req( scsbp )->min_credit = 0; ( void )( *pb->Send_msg )( pb->pccb, pb, scsbp, rsp_lengths[(( scsbp->mtype - 1 ) >>1 )], RECEIVE_BUF ); } else if( state == PS_PATH_FAILURE && Port_failure( pb->pinfo.reason )) { ( void )( *pb->Dealloc_msg )( pb->pccb, scsbp ); } else { ( void )( *pb->Add_msg )( pb->pccb, scsbp ); }}/* Name: scs_timer - SCS Protocol Interval Timer * * Abstract: This routine oversees all SCS timer related activities. It is * executed once per second per system but only when SCS requires * some timer related function. * * Timer related functions currently performed include: * * 1. Declaring SCS protocol sequence time outs on open paths. * * Inputs: * * IPL_SOFTCLOCK - Interrupt processor level * lk_scadb - SCA database lock structure * scs_timeoutq - SCS protocol sequence timeout queue head * * Outputs: * * IPL_SOFTCLOCK - Interrupt processor level * * SMP: The SCA database is locked for traversal of the SCS protocol * sequence timeout queue and for removing PBs from this queue * when it becomes necessary. It also postpones premature PB * deletion. * * PBs are locked to synchronize access and for removing them from * the SCS protocol sequence timeout queue when it becomes * necessary. PB locks are released before crashing the * corresponding path. */voidscs_timer(){ register pbq *qp; register PB *pb; register u_long save_ipl = Splscs(); /* Each timer interval the following sequence of actions occurs: * * 1. IPL is synchronized to IPL_SCS. * 2. The SCA database is locked. * 3. The SCS protocol sequence timeout queue of PBs is scanned and the * corresponding paths crashed on protocol timer expirations. Each PB * is locked for the duration of its check. * 4. The next invocation of the SCS interval timer is scheduled provided * the SCS protocol sequence timeout queue is not empty following * processing. * 5. The SCA database is unlocked. * 6. IPL is restored. */ Lock_scadb() for( qp = scs_timeoutq.flink; qp != &scs_timeoutq; ) { pb = Pos_to_pb( qp, timeout ); qp = qp->flink; Lock_pb( pb ) if( !pb->pinfo.status.sanity ) { ( void )panic( SCSPANIC_SANITY ); } else if( --pb->pinfo.duetime == 0 ) { Remove_scs_timeoutq( pb ) ( void )( *pb->Crash_path )( pb->pccb, pb, E_TIMEOUT, 0, NULL ); } Unlock_pb( pb ) } if( scs_timeoutq.flink != &scs_timeoutq ) { ( void )timeout( scs_timer, NULL, hz ); } Unlock_scadb() ( void )splx( save_ipl );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -