📄 ci_error.c
字号:
* Events 2-4 take place quite frequently. The remaining events occur * extremely rarely. Any scheme for port driver protection against extraneous * machine checks must take the frequencies of these events into account. * * To summarize, the only machine checks the CI port driver needs to guard * against are those that result from driver attempts to access inaccessible * local port registers. Normally, all registers are of course fully * accessible. Machine checks would be extremely common if this was not the * case. However, a number of well-defined circumstances do exist under which * registers become inaccessible. The most likely of these is loss of power, * either system-wide or just isolated to the bus on which the CI adapter * resides. Certain CI hardware port types( CI750, CIBCI ) are also subject to * completely independent losses of power. The adapters for these port types * are located within their own physically separate cabinets. This makes them * vulnerable not only to separate losses of power but to becoming uncabled * from the busses on which they reside. Either unfortunate circumstances * results in inaccessibility of most, but not all, local port registers. The * registers of a sufficiently broken local port may also become inaccessible. * * The best most idealistic machine check protection strategy for the CI port * driver would be for it to always provide transparent protection against * machine checks during all register accesses. Unfortunately, this is not * possible because the only protective mechanisms currently available are * expensive and are not transparent. * * The next best strategy is a defensive one: the CI port driver only protects * against machine checks on local CI ports known to have lost power, become * physically uncabled, or to have suffered a sufficient hardware failure. In * other words, protective mechanisms are employed only for those local ports * determined to be at risk. At all other times the driver makes no attempt to * protect against machine checks during register accesses. * * Implementation of this strategy is also unfortunately not possible. This is * because for it to succeed the CI port driver would have to meet the * following two requirements: * * 1. It would have to be immediately notified when any of the events which * could result in inaccessible local CI port registers occurs. * 2. It would have to immediately protect all subsequent register accesses on * notification of local port machine check vulnerability. * * The first requirement can not be met because the driver is never notified of * system-wide or bus associated power loss. Ironically ULTRIX crashes with a * machine check when such power loss occurs! Furthermore, while the driver is * notified of independent CI port power loss, uncabling, and fatal errors * through interrupts; handling of such interrupts maybe temporarily blocked * postponing notification. Such blockage is due to processor IPL level in * single processor environments and current unavailability of critical locks * in SMP environments. The end result is the same, inability to immediately * notify the driver of local port machine check vulnerability on register * accesses. * * The second requirement for implementation of the next best strategy can also * not be met. To meet it requires CI port driver determination of whether a * local CI port is currently vulnerable to machine checks prior to each * register access and to employ protective mechanisms only if it is. Meeting * this requirement is much too costly given the frequency with which certain * register accesses are made. * * The machine check protection strategy actually employed by the CI port * driver is a realistic one and possesses the following two basic * characteristics: * * 1. It never attempts to protect against machine checks during register * accesses that take place frequently( Events 2-4 above ). * 2. It considers a local port to always be at risk and protects against * machine checks during all infrequent register accesses( Events 1,5-6 * above ). * 3. The first checks it makes during interrupt processing are for uncabled * or powerless local ports before allowing any subsequent register accesses * by the current thread to occur. * * At first glance it may seem that this strategy is not all that rigorous, * and that better ones could be designed, and to some extent this is true. * However, this strategy is actually the best one available given the tools * which are currently provided by the Ultrix kernel. * * The basic tool employed for machine check protection is the BADADDR() macro. * This macro determines whether a specified byte, word, or longword address is * addressable and "returns" 1 if it is not. It is used in the machine check * protection strategy to determine whether a register is accessible before * attempting to access it. Therefore, the actual register accesses are never * themselves actually protected. * * This mechanism is as defensive as it is possible to be without being * paranoid and without seriously affecting performance of mainline code paths. * It will serve until it is possible to transparently protect against machine * during all register accesses. *//* Libraries and Include Files. */#include "../h/types.h"#include "../h/param.h"#include "../h/systm.h"#include "../h/vmmac.h"#include "../h/time.h"#include "../h/ksched.h"#include "../h/errlog.h"#include "../h/smp_lock.h"#ifdef vax#include "../machine/mtpr.h"#endif vax#include "../../machine/common/cpuconf.h"#include "../machine/cpu.h"#include "../machine/pte.h"#include "../io/xmi/xmireg.h"#include "../io/scs/sca.h"#include "../io/scs/scaparam.h"#include "../io/scs/scamachmac.h"#include "../io/ci/cippdsysap.h"#include "../io/ci/cisysap.h"#include "../io/msi/msisysap.h"#include "../io/bi/bvpsysap.h"#include "../io/gvp/gvpsysap.h"#include "../io/uba/uqsysap.h"#include "../io/sysap/sysap.h"#include "../io/ci/cippdscs.h"#include "../io/ci/ciscs.h"#include "../io/msi/msiscs.h"#include "../io/bi/bvpscs.h"#include "../io/gvp/gvpscs.h"#include "../io/uba/uqscs.h"#include "../io/scs/scs.h"#include "../io/gvp/gvp.h"#include "../io/ci/cippd.h"#include "../io/ci/ciport.h"#include "../io/ci/ciadapter.h"/* External Variables and Routines. */extern SCSIB lscs;extern struct el_rec *ealloc();extern u_short ci_severity;extern u_short ci_errlog;extern u_long ci_bhole_pfn;extern scaaddr scs_system_id;extern CLSTAB ci_cltab[ ES_FE + 1 ][ ESC_PPD + 1 ];extern u_char *ci_black_hole, scs_node_name[];extern void ci_dealloc_pkt(), ci_log_packet(), ci_unmap_port(), ci_unmapped_isr(), cippd_stop();/* Name: ci_cleanup_port - Clean up Local CI Port * * Abstract: This routine directs the second stage of local CI port clean * up. It is always invoked by forking to it. * * Failed local CI ports are cleaned up in two stages. The first * stage 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. This routine direct this second * stage of port clean up and the constant environment necessary * for its proper execution is provided by always forking to it. * * Inputs: * * IPL_SCS - Interrupt processor level * pccb - Port Command and Control Block pointer * lpinfo.reason - Reason for port failure * ppd.cippd - CI PPD specific PCCB fields * fsmstatus.cleanup - 1 * fsmstatus.fkip - 1 * fsmstatus.online - 0 * * Outputs: * * IPL_SCS - Interrupt processor level * pccb - Port Command and Control Block pointer * ppd.cippd - CI PPD specific PCCB fields * fsmstatus.fkip - 0 * * SMP: The PCCB is locked to synchronize access. PCCB locking is * probably unnecessary because of lack of conflict for the PCCB * due to single threading of port clean up and re-initialization. * It is done anyway to guarantee unrestricted access and because * the CI PPD interval timer may still be active. PCCB addresses * are always valid because these data structures are never * deleted once their corresponding ports have been initialized. */voidci_cleanup_port( pccb ) register PCCB *pccb;{ register GVPH **lp, **ep, *cibp; register u_long code, pf_reason; register u_long save_ipl = Splscs(); /* The steps involved in the second stage of local port clean up include: * * 1. Locking the PCCB. * 2. Removing and deallocating all packets logged to the local port * datagram and message buffer logout areas at time of failure. * 3. Map the specific local port crash reason into a generic one. * 4. Unlocking the PCCB. * 5. Notifying the CI PPD of failure of the local port. * * CI ports logout all internalized queue entries to the appropriate area * only when power failure is detected. Both logout areas are scanned in * their entirety and any packets found are deallocated( Step 3 ). The * logout areas are also re-initialized to GVPH_FREE( -1 ) to be able to * differentiate logged packets from empty logout area slots on subsequent * power failures. * * 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( Step 5 ). Clean up of the last * path triggers scheduling of port re-initialization by the CI PPD. The * PCCB lock is released( Step 4 ) prior to notifying the CI PPD of local * port failure instead of after it as required by the SCA architecture. */ Lock_pccb( pccb ) Pccb_fork_done( pccb, PANIC_PCCBFB ) for( lp = ( GVPH ** )pccb->Pqb.Dqe_logout, ep = ( GVPH ** )pccb->Pqb.Dqe_logout + ( 2 * CI_NLOG ); lp < ep; ++lp ) { if(( cibp = *lp ) != ( GVPH * )GVPH_FREE ) { ( void )ci_dealloc_pkt( cibp ); *lp = ( GVPH * )GVPH_FREE; } } if( Eseverity( pccb->lpinfo.reason ) == ES_FE ) { pf_reason = PF_FATALERROR; } else if( Ecode( pccb->lpinfo.reason ) == SE_POWER || Ecode( pccb->lpinfo.reason ) == SE_POWERUP ) { pf_reason = PF_POWER; } else { pf_reason = PF_PORTERROR; } Unlock_pccb( pccb ) ( void )cippd_stop( pccb, pf_reason ); ( void )splx( save_ipl );}/* Name: ci_console_log - Log CI Events to Console Terminal * * Abstract: This routine logs CI events to the console terminal. The event * is always one of the following types: * * PATH_EVENT - Path specific event * RPORT_EVENT - Remote port specific event * LPORT_EVENT - Local port specific event * * Explicit formatting information must be provided for each * event. This requires updating of the following tables each * time a new event is defined: * * 1. The appropriate entry within the CI console logging table( * ci_cltab[][] ) must be updated to reflect the new maximum * code represented within the associated format table. * * 2. The associated format table itself( ci_cli[], ci_clw[], * ci_clre[], ci_cle[], ci_clse[], ci_clfe[], ci_clppdse[] ) * must be updated with both the class of variable information * and exact text to be displayed. However, the appropriate * table should be updated with a NULL entry whenever the CI * port driver is specifically NOT to log a new event. This * applies only to ci_clppdse[] when a new CI PPD severe error * event is to be specifically logged only by the CI PPD and * not by appropriate port drivers such as the CI port driver. * * NOTE: Console logging of events is bypassed whenever the event * severity does not warrant console logging according to * the current CI severity level( ci_severity ). Such * bypassing is overridden when the ECLAWAYS bit is set in * the event code indicating that the event is always to be * logged regardless of the current severity level. * * NOTE: This routine does NOT log events arising external to the * CI port driver with the exception of those CI PPD severe * error events which are candidates for application of the * local port crash severity modifier( ESM_LPC ). * * Inputs: * * IPL_SCS - Interrupt processor level * ci_cltab - CI console logging table * ci_severity - CI console logging severity level * cibp - Address of CI port header( OPTIONAL ) * event - Event code * event_type - PATH_EVENT, LPORT_EVENT, RPORT_EVENT * cpu - CPU type code * cpusw - CPU switch structure * pb - Path Block pointer( OPTIONAL ) * pccb - Port Command and Control Block pointer * pd.gvp.type.ci - CI specific PCCB fields * devattn.cicpurevlev - Out-of-revision CPU microcode logging info * devattn.cirevlev - Port microcode information * max_fn_level - Maximum functional microcode revision level * max_rom_level - Maximum PROM/self-test microcode rev level * * Outputs: * * IPL_SCS - Interrupt processor level * * SMP: The PCCB is locked( EXTERNALLY ) to synchronize access and * prevent premature PB deletion when a PB is provided. * * PBs do NOT require locking when provided because only static * fields are accessed. SBs NEVER require locking. */voidci_console_log( pccb, pb, cibp, event, event_type ) register PCCB *pccb; register PB *pb; register GVPH *cibp; register u_long event; u_long event_type;{ register u_long fcode, severity = Eseverity( event ), data; /* Events are logged according to their type and the class of variable * information they display. Console messages for path specific events( * PATH_EVENT ) display the local and remote port station addresses and * remote system name by default when the event is of severity level error( * ES_E ) or severe error( ES_SE ). Console messages for local port * specific events( LPORT_EVENT ) display the local port station address by * default when they are of severity level error( ES_E ) or higher. * Console messages for remote port specific events( RPORT_EVENT ) do not * display any information by default. * * The following classes of variable information currently exist: * * 1. Remote CI port station address. * 2. Local CI port station address. * 3. CI port parameter register( PPR ) only. * 4. CI port registers. * 5. BI registers. * 6. CI packet fields.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -