📄 msi_lpmaint.c
字号:
* * Fork process synchronization( Step 4 ) is accomplished by means of the * in-progress SIIBUF pointers. These pointers are never NULL except * during those rare circumstances when active fork processes must * temporarily release their locks. Therefore, the synchronization * protocol just consists of releasing and re-obtaining all locks( PCCB, * PCCB specific XFP and RFP ) until such time as both in-progress pointers * are tested to be non-NULL. The reason why such synchronization is * necessary is discussed at greater length below. * * Flushing the transmit-in-progress circular queue( Step 5 ) does not * disturb the SIIBUFs in the queue. What occurs is deallocation of the * MSI packets associated with each SIIBUF in the queue. This allows * recovery of their dynamically allocated memory. Logically this action * should occur during local port clean up. It MUST be done at this time * during the port disablement step because once the SII chip is reset( * Step 5 ) the SII RAM buffer may NOT be accessed. It is perfectly safe * to flush the transmit-in-progress circular queue at this time even * though it is not the logical moment to do so. This is because once the * local MSI port has been marked inactive( Step 7 ) no further attempt is * made either to access the elements on this queue or to add new ones. * * Resetting the SII chip( Step 6 ) stops any operation in progress, * disconnects the chip from the DSSI bus, returns all registers to their * default values, and prevents all access to the SII RAM buffer. Marking * the local MSI port inactive( Step 7 ) disables all future processing by * scheduled XFP, RFP and XFP_TIMER threads. The end result of both these * steps is to drive the local MSI port into a completely quiescent state * allowing for full clean up and eventual local port re-initialization. * * Synchronization to active fork processes( Step 4 ) is important in a * SMP environment for the following reason. Occassions exist when an * active fork process must temporarily release all locks including its * specific fork process lock( RFP or XFP ). Its expectations are to * eventually re-obtain these locks and continue with its processing. In a * SMP environment lacking fork process synchronization releasing these * locks allows another completely independent thread to obtain them and * crash the local port. Unfortunately, this almost always guarantees a * machine check when the fork process re-obtains its locks and resumes * processing. This is because the fork process does not know the SII RAM * buffer has been rendered inaccessible due to crashing of the local port * and almost always attempts to access it anyway. Fork process * synchronization protects against such machine checks by forcing * temporary postponement of local port crashing during those rare * occassions when active fork processes must temporarily release their * locks. * * At the time the decision is made to crash the port, the processor from * which the port is crashed exists in one of two states distinguished * mainly by whether the processor is at kernel mode or interrupt level. * The existence of these two possible environments does not interfere with * port disablement. Unfortunately, the same is not necessary true for * port clean up, a section of the port driver which is quite complicated * in its own right. Therefore, to avoid potential problems and to allow * certain code simplifying assumptions to be made, port clean up has been * structured into two stages, separated by both time and environment. * * The first stage of port clean up consists of those actions which should * be performed immediately following port disablement and are insensitive * to processor state. The second stage consists of those activities which * need not be performed immediately following port disablement and should * be executed within a constant well-defined processor state. The first * stage of port clean up is directed by this routine which then schedules * the second stage, directed by msi_clean_port(), through forking. It is * this act of forking which generates the constant environment necessary * for the second stage of port clean up. * * The PCCB fork block is used to schedule the second stage of clean up. * It should always be available because it is used only for port clean up * and re-initialization, these activities are single threaded, and * re-initialization always follows clean up. Guaranteed availability * of the PCCB fork block is one of the benefits of single threading of * port clean up and re-initialization. * * The first stage of port clean up includes: * * 1. Scheduling clean up of the local MSI port through forking. * 2. Unlocking the PCCB provided it was locked within this routine. * * Note that the first stage of port clean up currently does not contain * any processor state insensitive actions which must be immediately * performed following port disablement. However, the structure exists to * add them as it becomes necessary to do so. * * The second stage of port clean up consists solely of notifying the CI * PPD of failure of the local port. The CI PPD completes the clean up of * its portion of the local port including the failure and clean up all * paths, both formative and fully established, originating at the port. * Clean up of the last path triggers scheduling of port re-initialization * by the CI PPD. Successful completion of port re-initialization marks * the beginning of the next incarnation of the port and releases all * restriction on crashing the port if further requests to do so are made. */ if( !Test_pccb_lock( pccb )) { Lock_pccb( pccb ) unlock_pccb = 1; } else { unlock_pccb = 0; } if( pccb->Lpstatus.optlpcinfo ) { if(( pb = cippd_get_pb( pccb, ( SCSH * )&pccb->Lpcinfo.pport_addr, NO_BUF )) == NULL ) { pccb->Errlogopt.portnum = pccb->Lpcinfo.pport_addr; } } else { pb = NULL; pccb->Errlogopt.portnum = EL_UNDEF; } if( !pccb->Fsmstatus.cleanup ) { Set_lpc_event( reason ); } switch( Mask_esevmod( reason )) { case SE_BUSERROR: case SE_SWA: case SE_IMODE: case SE_TMODE: ( void )msi_log_devattn( pccb, reason, LOG_REGS ); break; case SE_NOPATH: case SE_MFQE: case SE_INVBNAME: case SE_INVBSIZE: ( void )msi_log_packet( pccb, pb, NULL, (( pccb->Lpstatus.optlpcinfo ) ? pccb->Lpcinfo.pkth : NULL ), (( pccb->Lpstatus.optlpcinfo ) ? pccb->Lpcinfo.pktsize : 0 ), reason, LPORT_EVENT ); break; case SE_PPDSANITY: default: ( void )panic( PANIC_UNKLPC ); } if( msi_lpc_panic ) { ( void )panic( PANIC_REQLPC ); } if( !pccb->Fsmstatus.cleanup ) { pccb->Fsmstatus.cleanup = 1; pccb->Fsmstatus.online = 0; if( !Test_rfp_lock( pccb )) { Lock_rfp( pccb ) unlock_rfp = 1; } else { unlock_rfp = 0; } if( !Test_xfp_lock( pccb )) { Lock_xfp( pccb ) unlock_xfp = 1; } else { unlock_xfp = 0; } while( pccb->Xbusy == NULL || pccb->Rbusy == NULL ) { Unlock_xfp( pccb ) Unlock_rfp( pccb ) Unlock_pccb( pccb ) Lock_pccb( pccb ) Lock_rfp( pccb ) Lock_xfp( pccb ) } Xflush_xbusy( pccb ) ( void )msi_disable( pccb ); if( unlock_xfp ) { Unlock_xfp( pccb ) } if( unlock_rfp ) { Unlock_rfp( pccb ) } pccb->lpinfo.reason = reason; Pccb_fork( pccb, msi_clean_port, PANIC_PCCBFB ) } if( unlock_pccb ) { Unlock_pccb( pccb ) }}/* Name: msi_remote_rst - Reset Remote Port and System * * Abstract: This function initiates resetting of a remote MSI port and * system. The remote system need NOT be known to be reset; * however, the remote port must be in the appropriate maintenance * state for it and the remote system to be reset. * * Initiating resetting of a remote port and system is * accomplished by initiating transmission of a MSI port specific * RST packet to the target remote port. A MSI port command * packet is used to contain the reset request. It is allocated * by this function and deallocated following packet transmission. * * Resetting of the remote port and system can optionally be * forced; however, the port must in an appropriate maintenance * state for this to occur. * * NOTE: SCA port numbers are 6 bytes in size; however, maximum * MSI port numbers only occupy 1 byte. * * NOTE: All attempts to transmit packets to the local ports own * station address are bypassed. The SII chip is not * capable of either internal loopback or simultaneous * transmission and reception; and, no need exists to * provide this function in software. * * Inputs: * * IPL_SCS - Interrupt processor level * force - If set, force maintenance reset * pccb - Port Command and Control Block pointer * rport - Station address of target remote port * * Outputs: * * IPL_SCS - Interrupt processor level * pccb - Port Command and Control Block pointer * pd.msi - MSI specific PCCB fields * comql - MSIB low priority command queue * lpstatus.xfork - 1 * xforkb - Transmit Fork Process fork block * * Return Values: * * RET_SUCCESS - Transmission successfully initiated * RET_ALLOCFAIL - Failed to allocate command packet * RET_INVLPSTATE - Local port in invalid state * RET_NOPATH - Invalid remote port station address * * SMP: The PCCB is locked allowing exclusive access to PCCB contents. * PCCB addresses are always valid because these data structures * are never deleted once their corresponding ports have been * initialized. * * The PCCB specific COMQL is locked allowing exclusive access to * the corresponding low priority command queue */u_longmsi_remote_rst( pccb, rport, force ) register PCCB *pccb; scaaddr *rport; u_long force;{ register MSIB *msibp; register u_long status = RET_SUCCESS; /* Only the Transmit Fork Process( XFP ) interfaces directly with the SII * chip for the purpose of processing outgoing MSI packets. All other * driver routines must interface with the XFP. Therefore the steps
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -