/*
	File:		XPT.c

	Contains:	routines that implement the CAM Transport layer

	Entry points:
		OSErr	SCSITrap (short scsiSelector, SCSI_PB *pbPtr )
			Single entry point (Jerry's _NewSCSI trap).  Uses scsiSelector to choose a routine
			from those shown below.
		
	Client Calls
		void	SCSIAction (SCSI_PB *, Boolean syncCall, void (*callback)())
		SCSI_PB *NewSCSI_PB (void)
		void	DisposeSCSI_PB (SCSI_PB *)
			
	OS Module Calls
			
		OSErr	InitSCSIMgr ()
		
		long	SCSIRegisterBus (SIMinitInfo * SIMinfo)
			Called to register a SCSI bus for use with the XPT. 
			Several characteristics of the Bus are specified as well as the software
			entry points and the number of bytes required for a static data space
			(for global variables).  The XPT returns a BusID that will be used for
			that Bus as well as a pointer to the allocated static space.
			SIMinitInfo is defined as shown:
			
			typedef struct { // directions are for SCSIRegisterBus call ( -> parm, <- result)
				long	staticSize;			// -> num bytes SIM needs for static vars
				void	(*SIMinit)();		// -> pointer to the SIM init routine
				void	(*SIMaction)();		// -> pointer to the SIM action routine
				Boolean	oldCallCapable;		// -> T if this SIM can handle old-API calls
				ushort	busID;				// <- bus number for the registered bus
				char *	SIMstaticPtr;		// <- alloc. ptr to the SIM's static vars
			} SIMinitInfo; 
			
		

		OSErr	SCSIDeregisterBus (ushort busID)
		
		void	SCSIAsyncEvent (long what, 
								ushort busID, 
								ushort targetID, 
								ushort lun, 
								long dataBfr, 
								long dataCnt)
		
	Written by:	Paul Wolf

	Copyright:	© 1992-1994 by Apple Computer, Inc., all rights reserved.

	Change History (most recent first):
	
	  <SM33>	  2/1/94	DCB		Making sure our busy patch version gets set.
	  <SM32>	 1/31/94	DCB		Fixed a bug in the way I checked the version number for the SCSI
									Busy patch.
	  <SM31>	 1/25/94	DCB		Getting rid of compiler warning.
	  <SM30>	 1/25/94	DCB		Don't block interrupts when polling since this screws up
									interrupt latency and besides we have the file system patches
									now.
	   <ML4>	  1/9/94	pdw		Added check for SCSIBusyPatch version number so that init can
									run and only patch when necessary.
	   <ML3>	  1/5/94	pdw		Converted SCSIGlobal uses to new format and rolled in new
	   								SCSIBusy Patch.
	   <ML2>	12/15/93	pdw		Checking in for the build.
	  <SM28>	12/19/93	DCB		Poll at all interrupt levels now since we might have a deferred
									task pending but not an interrupt.  Also block interrupts at
									level 2 if not already blocked so we don't get re-entered when
									we don't expect it.  This won't crash the SCSI Manager but could
									lead to calling a completion routine when syncUnsafe is non-zero
									which causes file system headaches until SCSI Busy gets fixed.
	  <SM27>	11/22/93	pdw		Rolling in from <MCxx>.
	   <MC7>	11/11/93	pdw		Added support back in for forceSyncAlways debugging.
	   <MC6>	11/10/93	pdw		Added forceSync functionality which is used only when inDebugger
									and interrupts are blocked.  This fixes the hang using Macsbug
									log which was caused by the FSCallAsync-always change to the
									File System.
	   <MC5>	 11/5/93	pdw		Series of attempts and re-attempts to fix various VM/FileShare
									problems.
	  <SM26>	10/29/93	DCB		<MC> roll-in.
	   <MC4>	10/28/93	pdw		Added fix: we didn't use to return the result in D0 in
									synchronous requests like we were supposed to.  Now we do.
	  <SM25>	10/14/93	pdw		<MC> roll-in.
	   <MC3>	10/12/93	pdw		Added support for Synchronous data transfers, rewrote State
									Machine, message handling etc.
	   <MC2>	 9/26/93	pdw		Had to add a header file because of changes elsewhere.
	  <SM24>	 9/12/93	pdw		Removed SIMRegisterHAL support. Check for nonzero staticSize
									before allocating globals for SIM. Fixed up the reregister stuff
									a bit - moved common register/reregister stuff into sepearate
									routine.  Added ability to alloc new SIM globals in Reregister.
	  <SM23>	  9/9/93	pdw		Lots of little changes.  Name changes, temporary cache_bug
									stuff.
	  <SM22>	 8/13/93	pdw		Added check for nonZeroStatus to see if CallComp should do a
									virtual ID mapping.
	  <SM21>	 7/17/93	pdw		Lots of little things.
	  <SM20>	  7/8/93	pdw		Adding record events around Inquiry, GetVirtualID and Create
									Xref calls.
	  <SM19>	  7/1/93	pdw		Fixed RemoveRefNum bug where it would always return an error.
									We now "return" after setting up the noErr return value.
	  <SM18>	 6/29/93	pdw		Massive checkins: Change asynchronicity mechanism to CallMachine
									stack switching mechanism.  Adding support for Cold Fusion.
									Rearranging HW/SW Init code. Some code optimizations.
	  <SM17>	 5/29/93	PW		Adding SCSIDebug.h to includes.
	  <SM16>	 5/25/93	DCB		Rollin from Ludwig. (The next item below)
	  <LW15>	 5/20/93	DCB		Added call to ciDebuggerPatch. This is a patch to _DebugUtil
									which prevents deferred completion routines from occuring when
									we are in a debugger.
	  <SM15>	  5/5/93	PW		Converted names to meanies-friendly names.  Updated with latest
									from Ludwig stuff.
	  <LW14>	  5/1/93	PW		Added check for non-zero QLink to allow clients to see if we
									support pre-linked requests. Changed one last name:
									SCSI_RegisterWithNewXPT.
	  <LW13>	 4/30/93	DCB		Remove InitXPTRecorder if recording is turned off.
	  <LW11>	 4/14/93	DCB		Added ReRegisterAll Sims and fixed several bugs in the
									re-register SIM call.  This allows us to install a new XPT at a
									later date.
	  <LW10>	 4/13/93	MB		(Really DCB) Fixing sign extension problem in GetRefNum.
	   <LW9>	 3/26/93	PW		Rolling in SuperMario changes. Removing useless RejectMsg stuff.
									Changed refNumXref stuff to use -1 in bus field instead of -1 in
									whole device ident as magic value.
	  <SM13>	 3/20/93	PW		Removing EnableUserCode/DisableUserCode calls from
									CallCompRoutine, SIMActionΙ - leaving it up to the SIM to do 
									these calls instead (if necessary for that SIM).
	   <LW8>	  3/1/93	DCB		Changed parameters to CallCompRoutine to make life easier for
									developers.
	   <LW7>	 2/17/93	PW		Adding forceSyncAlways stuff (from PDM) because it will be
									useful for running benchmarks.
	  <SM12>	  2/4/93	PW		Enabled BusInquiry on PDM.  Fixed forceSync stuff by making
									callback from XPTAction.
	  <SM11>	 1/31/93	PW		Update from the latest of Ludwig. Also changes required for PDM
									(will update Ludwig with these as needed myself).
	   <LW6>	 1/30/93	PW		Added glue code for calling completion routines (saving
									registers that were getting trashed by File Manager).
	   <LW5>	 1/27/93	PW		Added clear of diReserved in GetRefNum.
	   <LW4>	 1/27/93	PW		Removed "fix" for 'double completion on autosense" bug. Fixed it
									a much better way in CompAutoSense (a way that works).
	   <LW3>	 1/12/93	DCB		Added enable and disable user code calls around calls to
									completion routines to allow page faults in the completion
									routines.
	   <LW2>	  1/8/93	PW		Adding Disable/Enable user code calls around call to completion
									routine to fix async comp -> old-API deadlock bug. Added ISRs 8
									through 0x0F to complete the set. Removed explicit Quadra int
									support from DispatchISR.
	  <SM10>	 12/9/92	PW		Got rid of selective DoVirtualMap stuff. Now we always do the
									mapping.
	   <SM9>	 12/5/92	PW		Handle returned fail from CallSIMaction. Added SetAsyncCallback
									partial support. Changed RefNum function names. Added
									InterleaveFactor support. Added check for invalid bus num in
									CallSIMaction.
	   <SM8>	11/20/92	PW		Added some Includes that were removed from headers. Changed
									InitXPT & XPTregBus to reflect change from linked list of
									BusInfos to array. Removed DItoBus macro. Added maxbuses (16)
									restriction to XPTregBus. Added error checking. Added init of
									new fn ptrs to SIMinfo.  Made Abort,Term,Reset async callbacks
									work. Changed sync from scSync flag to scComp=0. Removed
									EngineInq, Setup & DecodeDI. Removed calling of CompFn on XPT
									errs. Filled out XPT_ISR2 & 3.
	   <SM7>	 11/1/92	DCB		Fixed finalStatus length bug in CallCompRoutine that was
									stripping off the top byte of the scsiResult.
	   <SM6>	10/30/92	DCB		Changed over to multiple ISR routines for improved efficiency
	   <SM5>	 10/8/92	PW		Added variable-sized SCSI_IO support.  Lots of trivial name
									changes.
	   <SM4>	 9/17/92	PW		Added check for function code not supported.
	   <SM3>	 9/14/92	DCB		Added some Parameter Block validation.
	   <SM2>	  8/1/92	PW		Added comments.

*/


#include <Types.h>
#include <Memory.h>
#include <OSUtils.h>
#include <Errors.h>
#include <SCSIStandard.h>
#include <SCSI.h>
#include <Slots.h>
#include <Start.h>


#include "CUtils.h"

#include "ACAM.h"
#include "SCSIDebug.h"
#include "SCSIGlue.h"
#include "BootItt.h"			// for IsItt

#include "XPT.h"
#include "XPTpriv.h"

#include "Recorder.h"

#ifdef TESTGLOBALS
extern short	testGlobal3;
extern short	testGlobal2;
extern short	testGlobal1;
#endif

#define GetVBLQHdr() ((QHdrPtr) 0x0160)
#define inVBL 6

// ************ Internal-only Function Prototypes **************

void	SetRefNum( SCSI_Driver_PB *, XPTglobals * );
void	GetRefNum( SCSI_Driver_PB *, XPTglobals * );
void 	RemoveRefNum( SCSI_Driver_PB *, XPTglobals * );

OSErr	ReRegisterAllSIMs( XPTglobals *);
OSErr	XPTRegisterBus( SIMinitInfo * SIMinfo, XPTglobals *XPTg );
OSErr	XPTDeregisterBus( ushort busID, XPTglobals *XPTg );
OSErr	XPTReregisterBus( SIMinitInfo * SIMinfoPtr, XPTglobals *XPTg);
void	XPTRegisterCommon( SIMinitInfo * SIMinfoPtr);
OSErr	XPTKillXPT( XPTglobals *XPTg);

void	SyncWait( SCSI_PB *pbPtr, XPTglobals *XPTg );

void	TryToRecover ( XPTglobals *XPTg);
OSErr	XPTAction( SCSI_PB *pbPtr, XPTglobals *XPTg );
Boolean OldSCSIExists( void);

void	InitXPTRecorder( long sizeOfTape );

void	XPT_ISR0(void);
void	XPT_ISR1(void);
void	XPT_ISR2(void);
void	XPT_ISR3(void);
void	XPT_ISR4(void);
void	XPT_ISR5(void);
void	XPT_ISR6(void);
void	XPT_ISR7(void);
void	XPT_ISR8(void);
void	XPT_ISR9(void);
void	XPT_ISRa(void);
void	XPT_ISRb(void);
void	XPT_ISRc(void);
void	XPT_ISRd(void);
void	XPT_ISRe(void);
void	XPT_ISRf(void);


/*********************************************************************************
	InitXPT	-	Initialize XPT Globals and stuff
*********************************************************************************/

OSErr	
InitXPT( void )
{
	XPTglobals	*XPTg;

	
#ifdef TESTGLOBALS
	short	testG;
	testG = testGlobal3;
	testG = testGlobal1;
#endif

	InitRecorder();

// This gets a bit complicated if there is already a XPT installed.  If there is
// then we need to manage the transition from the old one to the new one.  This
// is accomplished by the routine ReRegisterAllSIMs:
//

// Allocate room for XPT globals and store XPTg ptr in magic spot in SCSIGlobals

	XPTg = (XPTglobals *) NewPtrSysClear( sizeof(XPTglobals));		//&&&& NewPtrSysClear
	if (XPTg == nil)
		return (memFullErr);

// Build Driver List (for RefNum to DeviceIdent cross-ref)
	
	XPTg->Drivers = (DrvrList *) NewPtrSysClear( sizeof(DrvrList));

	if ( XPTg->Drivers == nil ) {
		DisposPtr( (Ptr)XPTg);
		return (memFullErr);
	}
	
	XPTg->Drivers->DrvrCnt = 0;

// Initialize static fields in the completionDT

	XPTg->completionDT.qType = dtQType;
	XPTg->completionDT.dtAddr = DeferredCall;
	
	if ( ISITT() ) {
		// Let the old instantiation of KillXPT know what version of busyPatch we currently use.
		// It will compare this against its own linked in value and remove its patch if they
		// aren't the same.
		SCSIGlobals->newBusyPatchVers = kbusyPatchVers;
	
		if( ReRegisterAllSIMs(XPTg) )
			return(memFullErr);
	}
	else if ( OldSCSIExists() ) {
		XlateOldSCSIGlobals( XPTg );	// if New is replacing Old SCSI Mgr, xlate old's globals
	}

	Init_SCSIXlate();
	InitXPTAsm();
	
	if( (XPTg->debugPatch = ciDebuggerPatch( (Ptr) NGetTrapAddress( _DebugUtil, OSTrap ))) != nil )
		NSetTrapAddress( (long) XPTg->debugPatch, _DebugUtil, OSTrap );
	
	if (SCSIGlobals->busyPatchVers != kbusyPatchVers) {
		if( (SCSIGlobals->busyPatch = ciBusyPatch( (Ptr) NGetTrapAddress( _SCSIDispatch, ToolTrap ))) != nil ) {
			NSetTrapAddress( (long) SCSIGlobals->busyPatch, _SCSIDispatch, ToolTrap );
			SCSIGlobals->busyPatchVers = kbusyPatchVers;	
		}
	}
	
	SetXPTg( XPTg);
	
	InitSyncWait( XPTg );
	
	// Setup the A089 Trap
	NSetTrapAddress ( (long)SCSIAtomic, 0x89, OSTrap );

	return (0);
}


/*ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
	OldSCSIExists 	-	
ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ*/

Boolean OldSCSIExists( void)
{
	return( NGetTrapAddress(0xA815, ToolTrap) != 
			NGetTrapAddress(UNIMPTRAP, ToolTrap) );
}

/*********************************************************************************
	GetXPTg, SetXPTg	-	store and retrieve the XPT globals pointer
*********************************************************************************/

#if 0
XPTglobals *
GetXPTg( void )
{
	return(*(XPTglobals **)(*((Ptr *)0xC0C) + 0x1B4) );
}
#endif

void
SetXPTg( XPTglobals *XPTg )
{
	*(XPTglobals **)(*((Ptr *)0xC0C) + 0x1B4) = XPTg;
	SCSIGlobals->tempXPTGInUse = 0;	// Remember that we are using the real globals

}

void
SetTempXPTg( XPTglobals *XPTg )
{
	SCSIGlobals->tempXPTGGlobals = XPTg;	// Save the globals in a temporary spot
	SCSIGlobals->tempXPTGInUse = tempXPT;	// Remember that we did this
}


/*********************************************************************************
	SCSITrap	-	This is our NewSCSI trap entry point
*********************************************************************************/

OSErr
SCSITrap( short scsiSelector, void * pbPtr )
{
	XPTglobals	*XPTg;
	ushort		busID;
	
	XPTg = GetXPTg();
	
	if (scsiSelector == xptSCSIAction) {						// Do a SCSI_PB action
		return (XPTAction( (SCSI_PB *)pbPtr, XPTg));
	}

	switch (scsiSelector) {

	case xptSCSIRegisterBus:	
		return (XPTRegisterBus( (SIMinitInfo *)pbPtr, XPTg));
		break;

	case xptSCSIDeregisterBus:
		busID = ((SCSI_PB *)pbPtr)->scsiDevice.bus;
		return ( XPTDeregisterBus( busID, XPTg) );
		break;

	case xptSCSIReregisterBus:
		return (XPTReregisterBus( (SIMinitInfo *)pbPtr, XPTg));
		break;

	case xptSCSIKillXPT:
		return ( XPTKillXPT( XPTg) );
		break;

	default:
		return (scsiFunctionNotAvailable);
		break;
	}
}

		
/*********************************************************************************
	XPTRegisterBus	-	Register new SIM/HBA with Xpt
*********************************************************************************/

OSErr	
XPTRegisterBus (SIMinitInfo * SIMinfoPtr, XPTglobals *XPTg)
{
	ushort		busID;
	uchar *		busG;
	BusInfo		*thisBusInfoPtr;
	
	
// Get next bus number and see if this one would be one too many

	if (XPTg->numBuses == kMaxBuses) {
		return( scsiTooManyBuses);
	}
	
	if (XPTg->numBuses > kMaxBuses) {
		IfDebugStr("\pWay too many bus registrations");
		return( scsiTooManyBuses);
	}

// Allocate memory for SIM's static vars

	if (SIMinfoPtr->staticSize) {		// if SIM wants some statics
		busG = (uchar *) NewPtrSysClear((Size)SIMinfoPtr->staticSize);
		if (busG == 0) {
			IfDebugStr("\pCouldn't allocate bus statics");
			return( memFullErr);
		}
	}
	
// Get a BusInfo structure for this Bus's info
//		there are some BusInfos that are allocated in the XPT's globals already so
//		we try there first, if no room then we NewPtrSysClear another BusInfo spot.

	if (XPTg->numBuses < kNumBusInfos) {
		thisBusInfoPtr = &(XPTg->TopBusInfos[ XPTg->numBuses]);
	}
	else {
		thisBusInfoPtr = (BusInfo *)NewPtrSysClear(sizeof(BusInfo));
		if (thisBusInfoPtr == 0) {
			return( memFullErr);
		}
	}


// At this point, we've got everything a registration needs so we can consider
//		it a done deal.  We will now increment the number of buses.
//		and find an empty bus number for this SIM.

	XPTg->numBuses+=1;
	for( busID = 0; busID < XPTg->numBuses; busID+=1 ) {
		if( XPTg->BusInfoPtr[busID] == nil )
			break;
	}
	
		
// We must put this pointer in XPT's BusInfoPtrs

	XPTg->BusInfoPtr[busID] = thisBusInfoPtr;
	
	
// Set up the return values in the SIMinitInfo
	
	SIMinfoPtr->busID = busID;				// -> bus number for the registered bus
	SIMinfoPtr->SIMstaticPtr = busG;		// -> alloc. ptr to the SIM's static vars


//	Do all the common stuff - sticking our values in the SIM's init pb
	
	XPTRegisterCommon( SIMinfoPtr);
	

// Set up the XPT's BusInfo with what's known about the HBA so far

	thisBusInfoPtr->initInfo = *SIMinfoPtr;
	
	
// If we need to, allocate a new SCSI_IO for old API emulation.

	if ((SIMinfoPtr->ioPBSize > XPTg->xptIOpbSize) && SIMinfoPtr->oldCallCapable)
	{
		if (XPTg->xptIOpbSize)			// if not first time thru, dispose old one
			DisposPtr( (char *)(XPTg->xptIOptr));
			
		if (NewXPTioPB( SIMinfoPtr->ioPBSize, XPTg))
			return (memFullErr);
	}

// If we need to, adjust the maxIOpbSize field

	if (SIMinfoPtr->ioPBSize > XPTg->maxIOpbSize)
		XPTg->maxIOpbSize = SIMinfoPtr->ioPBSize;


// If we got this far, call the SIMinit routine and return it's result as our result

	return ( (SIMinfoPtr->SIMinit) (SIMinfoPtr) );
}


/*********************************************************************************
	XPTReregisterBus	-	Re-Register existing SIM/HBA with XPT
*********************************************************************************/

OSErr	
XPTReregisterBus (SIMinitInfo * SIMinfoPtr, XPTglobals *XPTg)
{
	ushort		busID;
	BusInfo		*thisBusInfoPtr;
	
	// If we are in the transition from one XPT to another then use the
	// temporary XPT globals
	if( SCSIGlobals->tempXPTGInUse == tempXPT )
		XPTg = SCSIGlobals->tempXPTGGlobals;
	

// Allocate memory for SIM's static vars

	if (SIMinfoPtr->SIMstaticPtr == 0) {	// if the SIM wants new globals
		if (SIMinfoPtr->staticSize) {		// and if SIM wants more than 0
			SIMinfoPtr->SIMstaticPtr = (uchar *) NewPtrSysClear((Size)SIMinfoPtr->staticSize);
			if (SIMinfoPtr->SIMstaticPtr == 0) {
				IfDebugStr("\pCouldn't allocate bus statics");
				return( memFullErr);
			}
		}
	}
	
// Get the bus ID

	busID = SIMinfoPtr->busID;
	
//	Do all the common stuff - sticking our values in the SIM's init pb
	
	XPTRegisterCommon( SIMinfoPtr);


// If we don't have a BusInfo structure for this Bus's info then go get one
//		there are some BusInfos that are allocated in the XPT's globals already so
//		we try there first, if no room then we NewPtrSysClear another BusInfo spot.

	if( XPTg->BusInfoPtr[busID] == nil ) {
		if (XPTg->numBuses < kNumBusInfos) {
			thisBusInfoPtr = &(XPTg->TopBusInfos[XPTg->numBuses]);
		}
		else {
			thisBusInfoPtr = (BusInfo *)NewPtrSysClear(sizeof(BusInfo));
			if (thisBusInfoPtr == 0) {
				return( memFullErr);
			}
		}
		XPTg->numBuses+=1;
		XPTg->BusInfoPtr[busID] = thisBusInfoPtr;
	}

// Copy SIMinitInfo data into XPT's BusInfoPtr

	XPTg->BusInfoPtr[busID]->initInfo = *SIMinfoPtr;
	
	
// If we need to, allocate a new SCSI_IO for old API emulation.

	if ((SIMinfoPtr->ioPBSize > XPTg->xptIOpbSize) && SIMinfoPtr->oldCallCapable)
	{
		if (XPTg->xptIOptr)				// if not first time thru, dispose old one
			DisposPtr( (char *)(XPTg->xptIOptr));
			
		if (NewXPTioPB( SIMinfoPtr->ioPBSize, XPTg))
			return (memFullErr);
	}


// If we need to, adjust the maxIOpbSize field

	if (SIMinfoPtr->ioPBSize > XPTg->maxIOpbSize)
		XPTg->maxIOpbSize = SIMinfoPtr->ioPBSize;


// We do not call the SIM's Initialization routine on reregister.  Instead,
//	the SIM will get the data out upon return
	
	return ( noErr);
}

		
/*********************************************************************************
	XPTRegisterCommon	-	Common between Register and Reregister code
*********************************************************************************/

void	
XPTRegisterCommon( SIMinitInfo * SIMinfoPtr)
{
	
// Set up the return values in the SIMinitInfo
	
	SIMinfoPtr->MakeCallback = XPTCallCompRoutine;
	SIMinfoPtr->EnteringSIM	 = VMDisableUserCode;
	SIMinfoPtr->ExitingSIM	 = VMEnableUserCode;
	
	switch ( SIMinfoPtr->busID) 
	{
	case 0:
		SIMinfoPtr->XPT_ISR = XPT_ISR0;		// -> ptr to the XPT's ISR (so SIM can install it)
		break;
	case 1:
		SIMinfoPtr->XPT_ISR = XPT_ISR1;			
		break;
	case 2:
		SIMinfoPtr->XPT_ISR = XPT_ISR2;			
		break;
	case 3:
		SIMinfoPtr->XPT_ISR = XPT_ISR3;			
		break;
	case 4:
		SIMinfoPtr->XPT_ISR = XPT_ISR4;			
		break;
	case 5:
		SIMinfoPtr->XPT_ISR = XPT_ISR5;			
		break;
	case 6:
		SIMinfoPtr->XPT_ISR = XPT_ISR6;			
		break;
	case 7:
		SIMinfoPtr->XPT_ISR = XPT_ISR7;	
		break;
	case 8:
		SIMinfoPtr->XPT_ISR = XPT_ISR8;	
		break;
	case 9:
		SIMinfoPtr->XPT_ISR = XPT_ISR9;	
		break;
	case 0x0a:
		SIMinfoPtr->XPT_ISR = XPT_ISRa;	
		break;
	case 0x0b:
		SIMinfoPtr->XPT_ISR = XPT_ISRb;	
		break;
	case 0x0c:
		SIMinfoPtr->XPT_ISR = XPT_ISRc;	
		break;
	case 0x0d:
		SIMinfoPtr->XPT_ISR = XPT_ISRd;	
		break;
	case 0x0e:
		SIMinfoPtr->XPT_ISR = XPT_ISRe;	
		break;
	case 0x0f:
		SIMinfoPtr->XPT_ISR = XPT_ISRf;	
		break;
	}
}
	


/*********************************************************************************
	XPTDeregisterBus	-	Remove registration of SIM/HBA
*********************************************************************************/

OSErr
XPTDeregisterBus (ushort busID, XPTglobals *XPTg)
{
#pragma unused (busID)
#pragma unused (XPTg)

	return (scsiFunctionNotAvailable);
}


/*********************************************************************************
	XPTKillXPT	-	Render XPT and its stuff inoperative (might be used for patching)
*********************************************************************************/

OSErr
XPTKillXPT ( XPTglobals *XPTg)
{
	ulong	* oldPatch;
	
	RemoveSyncWait(XPTg);				// Get rid of our patch to syncWait
	
	// Disable patch by changing the enabled variable in the patch
	// this variable is embedded in the code 4 bytes before the 
	// actual beginning of the code.
	oldPatch = (ulong *)(XPTg->debugPatch);
	*(--oldPatch) = 0;	// disable the  patch
	
	// Ditto for the SCSIBusy Patch if it changed.
	if( SCSIGlobals->newBusyPatchVers != kbusyPatchVers ) {
		// Let the new XPT know that there isn't a SCSI Busy patch.
		SCSIGlobals->busyPatchVers = 0;
		oldPatch = (ulong *)(SCSIGlobals->busyPatch);
		*(--oldPatch) = 0;	// disable the  patch
	}
	
	DisposPtr( (char *)(XPTg->xptIOptr));
	DisposPtr((Ptr)XPTg);				// Get rid of our globals
										// Anything else I missed? !!!
	return (noErr);
}


#if 0
/*********************************************************************************
	XPTAsyncEvent	-	notifies clients of event that they had registered for
*********************************************************************************/

OSErr	
XPTAsyncEvent (SCSI_PB *pbPtr, XPTglobals *XPTg)
{

/*SCSIAsyncEvent (long what, 
						ushort busID, 
						ushort targetID, 
						ushort lun, 
						long dataBfr, 
						long dataCnt)*/
						
	return (scsiFunctionNotAvailable);
}
#endif

/*********************************************************************************
	XPTAction	-	perform an Action (either XPT or pass it to SIM)
*********************************************************************************/

OSErr	
XPTAction (SCSI_PB *pbPtr, XPTglobals *XPTg)
{
	Boolean		needSyncWait = false;	// assume that the call won't need syncWait
	OSErr		result = noErr;			// error returned synchronously (result in D0)
	BusInfo		*busInfoPtr;
	Boolean		forceSync = false;
	pascal void	(*oldCompletion)(SCSI_IO *);
	
	if (pbPtr->qLink) {											// <LW14> pdw F§ TOP
		pbPtr->scsiResult = scsiQLinkInvalid;
		return ( pbPtr->scsiResult);
	}															// <LW14> pdw F§ BOT
	
	// We have to see if the Function code is handled by the XPT or by the SIM

	switch (pbPtr->scsiFunctionCode) {
	
	case SCSIExecIO:				// SIM
	case SCSIResetBus:				// SIM						// <SM8> pdw
	case SCSIResetDevice:			// SIM						// <SM8> pdw
	case SCSIReleaseQ:				// SIM						// <SM8> pdw
	case SCSIAbortCommand:			// SIM						// <SM8> pdw
	case SCSITerminateIO:			// SIM						// <SM8> pdw

#if forceSyncAlways		// will poll always (not just when int level high)
		{
#else
		if (SCSIGlobals->inDebugger && InterruptLevel() >1 ) {
#endif
			forceSync = true;
			oldCompletion = pbPtr->scsiCompletion;
			pbPtr->scsiCompletion = 0;
		}

		((SCSI_IO *)pbPtr)->savedA5 = getCurrentA5();
		if( pbPtr->scsiCompletion == 0)							// <SM8> pdw
			needSyncWait = true;

		if( needSyncWait && XPTg->syncUnsafeCount ) {
			pbPtr->scsiResult = scsiBusy;
			return ( pbPtr->scsiResult);
		}

		if ( (((SCSI_PB *)pbPtr)->scsiDevice).bus >= XPTg->numBuses) {
			pbPtr->scsiResult = scsiBusInvalid;
			return ( pbPtr->scsiResult);
		}
		
		busInfoPtr = XPTg->BusInfoPtr[ (((SCSI_PB *)pbPtr)->scsiDevice).bus];
	
		if( busInfoPtr )
			(busInfoPtr->initInfo.SIMaction) (pbPtr, (busInfoPtr->initInfo).SIMstaticPtr);
		else{
			pbPtr->scsiResult = scsiBusInvalid;
			return ( pbPtr->scsiResult);
		}
		
		if ( needSyncWait) {
			SyncWait( pbPtr, XPTg);
			if (forceSync) {
				if (oldCompletion!=0) {
					pbPtr->scsiCompletion = oldCompletion;
					XPTCallCompRoutine( (SCSI_IO *)pbPtr );
					return (noErr);
				}
			}
			return (pbPtr->scsiResult);				// return the error! (unlike Cyclone)
		}
		
		break;
		
	case SCSIBusInquiry:			// SIM
		IfRecordEvent( *(long *)&pbPtr->scsiDevice, (long)'Inq-');
		pbPtr->scsiResult = noErr;
		if ( pbPtr->scsiPBLength < sizeof(SCSIBusInquiryPB)) {
			pbPtr->scsiResult = scsiPBLengthError;
		}	
		else if ( pbPtr->scsiDevice.bus == 0xff) {
			((SCSIBusInquiryPB *)pbPtr)->scsiIOpbSize = sizeof(SCSI_IO); 
			((SCSIBusInquiryPB *)pbPtr)->scsiMaxIOpbSize = XPTg->maxIOpbSize; 
			((SCSIBusInquiryPB *)pbPtr)->scsiHiBusID = XPTg->numBuses - 1;
			BlockMove("Apple Computer \0",((SCSIBusInquiryPB *)pbPtr)->scsiSIMVendor,16);
		}
		else if ( pbPtr->scsiDevice.bus >= XPTg->numBuses) {
			pbPtr->scsiResult = scsiBusInvalid;
		}
		else {
			((SCSIBusInquiryPB *)pbPtr)->scsiIOpbSize = sizeof(SCSI_IO); 
			((SCSIBusInquiryPB *)pbPtr)->scsiMaxIOpbSize = XPTg->maxIOpbSize; 
			((SCSIBusInquiryPB *)pbPtr)->scsiHiBusID = XPTg->numBuses - 1;
			pbPtr->scsiResult = CallSIMaction( pbPtr, XPTg);
		}
		IfRecordEvent( (long)(pbPtr->scsiResult), (long)'-Inq');
		return ( pbPtr->scsiResult);
		break;
		
	case SCSISetAsyncCallback:		// XPT & SIM
		result = CallSIMaction( pbPtr, XPTg);
		break;

	case SCSIGetVirtualIDInfo:		// XPT
		IfRecordEvent( *(long *)(&(((SCSIGetVirtualIDInfoPB *)pbPtr)->scsiOldCallID)), (long)'Vid-');
		GetVirtualIDInfo( (SCSIGetVirtualIDInfoPB *) pbPtr, XPTg);
		IfRecordEvent( *(long *)(&(((SCSIGetVirtualIDInfoPB *)pbPtr)->scsiOldCallID)), *(long *)&(pbPtr->scsiDevice));
		break;
		
	case SCSICreateRefNumXref:		// XPT
		IfRecordEvent( *(long *)(&(((SCSI_Driver_PB *)pbPtr)->scsiDevice)), (long)'Xrf-');
		SetRefNum( (SCSI_Driver_PB *) pbPtr, XPTg);
		IfRecordEvent( *(long *)(&(((SCSI_Driver_PB *)pbPtr)->scsiDriver)), (long)(pbPtr->scsiResult));
		break;
		
	case SCSILookupRefNumXref:		// XPT
		GetRefNum( (SCSI_Driver_PB *) pbPtr, XPTg);
		break;
		
	case SCSIRemoveRefNumXref:		// XPT
		RemoveRefNum( (SCSI_Driver_PB *) pbPtr, XPTg);
		break;

	case SCSIGenerateInterleaveID:	// XPT
		((SCSIGenerateInterleaveIDPB *) pbPtr)->scsiInterleaveID = XPTg->nextInterleave++;
		break;

	case SCSINop:					// XPT
		break;

	default:
		result = CallSIMaction( pbPtr, XPTg);
		break;
		
	}
	
	return (result);
}


/*********************************************************************************
	CallSIMaction	-	perform an Action (either Xpt or pass it to SIM)
*********************************************************************************/

OSErr
CallSIMaction( void * pbPtr, XPTglobals * XPTg)
{
	BusInfo		*busInfoPtr;
	
	if ( (((SCSI_PB *)pbPtr)->scsiDevice).bus >= XPTg->numBuses)
		return (scsiBusInvalid);
		
	busInfoPtr = XPTg->BusInfoPtr[ (((SCSI_PB *)pbPtr)->scsiDevice).bus];

	if( busInfoPtr ) {
		(busInfoPtr->initInfo.SIMaction) (pbPtr, (busInfoPtr->initInfo).SIMstaticPtr);
		return ( noErr);
	}
	return(scsiBusInvalid);
}


/*********************************************************************************
	SyncWait	-	wait for a synchronous request to be completed
*********************************************************************************/

void
SyncWait( SCSI_PB *pbPtr, XPTglobals *XPTg)
{
	IfRecordEvent( (long)(pbPtr), (long)'Xsyw');
	
	do {
		CheckInterrupts( XPTg);
	} while (pbPtr->scsiResult == scsiRequestInProgress);
}


/*********************************************************************************
	CheckInterrupts	-	
*********************************************************************************/

void
CheckInterrupts (XPTglobals	* XPTg)
{
#if forceSyncAlways		// will poll always (not just when int level high)
	DispatchISR();
#else
	// GROSS Hack Alert!
	//
	// In theory the private DT Queue is a SIM private since it is only used by the
	// pseudo DMA machines.  However if I actually poll all SIMs at all interrupt 
	// levels the overhead is such that basic operations that depend on syncwait start
	// to slow down.  To get around this I only poll when I _have_ to which means if 
	// there is something in our private deferred task queue or if it is busy (we are
	// working on soemthing and hadn't blocked ints at the VIA yet.)
	if (InterruptLevel() > 1 || SCSIGlobals->privDTQueue.qHead || SCSIGlobals->privDTQueue.qFlags ) 
	{
		if (bset(inVBL, (char *)&((GetVBLQHdr()->qFlags))))	// make VBL busy: was it already?
			DispatchISR();									// yes: check interrupt sources
		else {
			DispatchISR();									// no: check interrupt sources
			bclr(inVBL, (char *)&((GetVBLQHdr()->qFlags)));	//  and clr busy bit (return to prev value)
		}
	}
#endif
	
	if ( bclr( kbResetFromSync, &XPTg->flags ))
		TryToRecover( XPTg);
}


/*********************************************************************************
	TryToRecover	-	
*********************************************************************************/

void
TryToRecover ( XPTglobals *XPTg)
{
#pragma unused (XPTg)

	SCSIResetBusPB	rstPB;
	
	Clear( &rstPB, sizeof(rstPB));
	rstPB.scsiDevice.bus = 0;
	SCSIAction( (SCSI_PB *)&rstPB);

	rstPB.scsiDevice.bus = 1;
	SCSIAction( (SCSI_PB *)&rstPB);
}


/*********************************************************************************
	DispatchISR	-	
*********************************************************************************/

void
DispatchISR ( void)
{
	short			i;
	XPTglobals *	XPTg;
	BusInfo *		busInfoPtr;
	
	
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	XPTg = GetXPTg();

	for (i=0; i< XPTg->numBuses; i+=1)
	{
		busInfoPtr = XPTg->BusInfoPtr[i];		
		((busInfoPtr->initInfo).SIMInterruptPoll) ( (busInfoPtr->initInfo).SIMstaticPtr);
	}

	VMEnableUserCode();			// enable user code (allow page faults)
}



/*********************************************************************************
	SetRefNum, GetNextRefNum, RemoveRefNum	-	
*********************************************************************************/

void
SetRefNum( SCSI_Driver_PB * pbPtr, XPTglobals * XPTg)
{
	ulong	index;
	Ptr 	temp;
	ulong 	size;
	
	pbPtr->scsiDevice.diReserved = 0;
	
	for ( index = 0; index < XPTg->Drivers->DrvrCnt; index+=1 ) {
		if ( pbPtr->scsiDevice == XPTg->Drivers->Drvr[index].DevID ) {
			pbPtr->scsiResult = scsiDeviceConflict;
			return;
		}
	}
	size = sizeof(DrvrList) + sizeof(RefInfo) * (index + 1);
	temp = NewPtrSysClear(size);
	if ( temp ) {
		BlockMove(XPTg->Drivers,temp,size - sizeof(RefInfo));
		DisposPtr((Ptr)XPTg->Drivers);
		XPTg->Drivers = (DrvrList *)temp;
	}
	else {
		pbPtr->scsiResult = memFullErr;
		return;
	}
	XPTg->Drivers->DrvrCnt+=1;
	XPTg->Drivers->Drvr[index].DevID = pbPtr->scsiDevice;
	XPTg->Drivers->Drvr[index].DRefNum = pbPtr->scsiDriver;
	pbPtr->scsiResult = noErr;
}

void
GetRefNum( SCSI_Driver_PB * pbPtr, XPTglobals * XPTg)
{
	ulong index;
	
	pbPtr->scsiResult = noErr;	/* Can't Fail */

	if ( pbPtr->scsiDevice.bus == 0xFF ) {	/* Marker for Give me the first in the list */
		pbPtr->scsiDriver = 0;	/* Not a driver */
		if ( XPTg->Drivers->DrvrCnt ) 
			pbPtr->scsiNextDevice = XPTg->Drivers->Drvr[0].DevID;	/* First one in the list */
		else 
			pbPtr->scsiNextDevice.bus = 0xFF ;	/* Nobody home */
		return;
	}

	pbPtr->scsiDevice.diReserved = 0;	/* Get rid of "unused" byte which might have
											   (like the installer's setting of the high
											   bit) extraneaous stuff in it!  */
	for ( index = 0; index < XPTg->Drivers->DrvrCnt; index+=1 ) {
		if ( pbPtr->scsiDevice == XPTg->Drivers->Drvr[index].DevID ) {
			pbPtr->scsiDriver = XPTg->Drivers->Drvr[index].DRefNum;
			if ( index + 1 == XPTg->Drivers->DrvrCnt )
				pbPtr->scsiNextDevice.bus = 0xFF ;	/* Nobody home */
			else
				pbPtr->scsiNextDevice = XPTg->Drivers->Drvr[index + 1].DevID;
			return;
		}
	}
	pbPtr->scsiDriver =	0;		/* Not a driver */
	pbPtr->scsiNextDevice.bus = 0xFF ;	/* Nobody home */
}

void
RemoveRefNum( SCSI_Driver_PB * pbPtr, XPTglobals * XPTg)
{
	ulong index,remainder;
	
	pbPtr->scsiDevice.diReserved = 0;
	
	for ( index = 0; index < XPTg->Drivers->DrvrCnt; index+=1 ) {
		if ( pbPtr->scsiDevice == XPTg->Drivers->Drvr[index].DevID ) {
			for ( remainder = index; remainder < XPTg->Drivers->DrvrCnt - 1; remainder+=1 ) 
				XPTg->Drivers->Drvr[remainder] = XPTg->Drivers->Drvr[remainder + 1];
			XPTg->Drivers->DrvrCnt -= 1;
			pbPtr->scsiResult = noErr;	/* Removed it */
			return;															//<SM19>pdw
		}
	}
	pbPtr->scsiResult = scsiNoSuchXref;
}


/*********************************************************************************
	XPTCallCompRoutine 	-	Called by the SIM's CompleteIO
*********************************************************************************/

void
XPTCallCompRoutine( SCSI_IO * ioPtr )		// <SM7>
{
	pascal void	(*fn)(SCSI_IO *);
	// Ptr			oldA5;
	XPTglobals *	XPTg;
	
//--- If we need to do virtual ID mapping, and result==noErr then do it		// <SM10> pdw

	XPTg = GetXPTg();
	if (XPTg->oldIDBusNumber[ioPtr->scsiDevice.targetID]<0) {
		if ( ioPtr->scsiFunctionCode == SCSIExecIO)							// <LW14> pdw F§
			if ( ioPtr->scsiResult==noErr || ioPtr->scsiResult==scsiNonZeroStatus || ioPtr->scsiResult==scsiDataRunError )
				if( XPTg->BusInfoPtr[ioPtr->scsiDevice.bus]->initInfo.oldCallCapable)
					XPTg->oldIDBusNumber[ioPtr->scsiDevice.targetID] = ioPtr->scsiDevice.bus;
	}

	ioPtr->qLink = 0;	// set qLink back to NIL in case pb is reused		// <LW14> pdw F§
	
//--- Call the completion routine (with proper A5) as long as routine ptr isn't NIL

	// scsiCompletion was moved into the header - therefore we can call it for any pb <SM8>
	if( (fn=ioPtr->scsiCompletion) != nil ) {
		// oldA5 = getCurrentA5(); now it's done in CallCompRoutineGlue
		IfRecordEvent( (long)(ioPtr), (long)'xcC-');
		CallCompRoutineGlue( ioPtr, &(XPTg->completionDT));		// MAKE CALLBACK	
		IfRecordEvent( (long)(fn), (long)'-xcC');
	}
}


/*********************************************************************************
	ReRegisterAllSIMs	-	
*********************************************************************************/

OSErr
ReRegisterAllSIMs( XPTglobals *XPTg )
{
	long 			OldXPT;
	Boolean			*oldSIMs;
	ulong			id;
	SCSIGetVirtualIDInfoPB dIdent;	
	SCSI_Driver_PB 	drvrPB;
	SCSIBusInquiryPB scPB;
	uchar			busID;
	uchar			highBusID;
	SCSI_PB			reRegister;

// Setup our globals in a temporary spot so we don't step on any existing globals
// Use GetVirtualID to build up a list of virtual IDs
// Use BusInquiry to build up a list of existing SIMs
// SetTrapAddress to the new XPT and remember the address of the old one.
// Use the old XPT to send a ReRegisterSIM call to each SIM
// Call KillXPT to get rid of the old XPT (Note Kill XPT can't call SetTrapAddress!!!)
// Put our Globals in the normal spot
// Install any patches (such as vSyncWait) that we will use (this MUST be done AFTER KillXPT)
// If the normal internal SIMs didn't already exist then tell InitItt to install them

	SetTempXPTg( XPTg);

// Use the old XPT to find all of the virtual IDs

	Clear((char *)&dIdent,sizeof(dIdent));
	
	for( id = 0; id < 7; id+=1 ) {
		dIdent.scsiOldCallID = id;
		dIdent.scsiFunctionCode = SCSIGetVirtualIDInfo;
		dIdent.scsiCompletion = nil;
		dIdent.scsiPBLength = sizeof(SCSIGetVirtualIDInfoPB);
		SCSIAction((SCSI_PB *) &dIdent);
		if( dIdent.scsiExists )
			XPTg->oldIDBusNumber[id] = dIdent.scsiDevice.bus;
		else
			XPTg->oldIDBusNumber[id] = -1;
	}

// Now go get all of the existing Drivers which have been registered
	
	Clear((char *)&drvrPB,sizeof(drvrPB));
	
	/* Get the devIdent of the first driver registered with Itt */
	drvrPB.scsiDevice.bus = 0xff;				/* Give us the first one in the list */
	drvrPB.scsiPBLength = sizeof(drvrPB);
	drvrPB.scsiFunctionCode = SCSILookupRefNumXref;
	SCSIAction( (SCSI_PB *) &drvrPB );
	drvrPB.scsiDevice = drvrPB.scsiNextDevice;		/* Get The first one in the list */

	while( drvrPB.scsiDevice.bus != 0xff ) {
		SCSIAction( (SCSI_PB *) &drvrPB );
		SetRefNum(&drvrPB,XPTg);					/* Register with the new set of globals */
		drvrPB.scsiDevice = drvrPB.scsiNextDevice;	/* Get The next one in the list */
	} 

// Look for existing SIMs

	Clear((char *)&scPB,sizeof(scPB));
	
	*(long *)&(scPB.scsiDevice) = 0xff;	// XPT Inquiry
	scPB.scsiFunctionCode = SCSIBusInquiry;
	scPB.scsiPBLength = sizeof(SCSIBusInquiryPB);
	SCSIAction( (SCSI_PB *) &scPB );		// Get info for the XPT
	
	highBusID = scPB.scsiHiBusID;
	if( (oldSIMs = (Boolean *)NewPtrSysClear(sizeof(Boolean) * (highBusID + 1))) == 0 ) {
		IfDebugStr("\pNot enough memory to switch XPTs");	// Yikes, this would be really bad...
		return(memFullErr);
	}

	for( busID = 0; busID <= highBusID; busID+=1 ) {
		scPB.scsiDevice.bus = busID;
		scPB.scsiFunctionCode = SCSIBusInquiry;
		scPB.scsiPBLength = sizeof(SCSIBusInquiryPB);
		if( SCSIAction( (SCSI_PB *) &scPB ) == noErr)
			oldSIMs[busID] = true;
	}

// Remember the old TrapAddress and setup the new one

	OldXPT = NGetTrapAddress(SCSIATOM, OSTrap);
	NSetTrapAddress ( (long)SCSIAtomic, 0x89, OSTrap );
	
// And... Re-Register all existing SIMs

	Clear((char *)&reRegister,sizeof(reRegister));
	
	for( busID = 0; busID <= highBusID; busID+=1 ) {
		if( oldSIMs[busID] ) {
			reRegister.scsiPBLength = sizeof(reRegister);
			reRegister.scsiDevice.bus = busID;
			reRegister.scsiFunctionCode = SCSIRegisterWithNewXPT;
			CallOldXPT( &reRegister,xptSCSIAction,OldXPT );
		}
	}
	
// Get rid of the old XPT and get out of here
	CallOldXPT(0, xptSCSIKillXPT, OldXPT);
	
	SetXPTg(XPTg);		// Put the real XPT Globals in place
	
	DisposPtr((Ptr)oldSIMs);
}


/*********************************************************************************
	XPT_ISR0	-	
*********************************************************************************/
#if 0
void
XPT_ISR0 (void)
{
	BusInfo *		busInfoPtr;
		
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	//									vv
	busInfoPtr = GetXPTg()->BusInfoPtr[0];		
	((busInfoPtr->initInfo).SIM_ISR)( (busInfoPtr->initInfo).SIMstaticPtr);

	VMEnableUserCode();			// enable user code (allow page faults)
}

void
XPT_ISR1 (void)
{
	BusInfo *		busInfoPtr;
		
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	//									vv
	busInfoPtr = GetXPTg()->BusInfoPtr[1];		
	((busInfoPtr->initInfo).SIM_ISR)((busInfoPtr->initInfo).SIMstaticPtr);

	VMEnableUserCode();			// enable user code (allow page faults)
}
#endif

void
XPT_ISR2 (void)
{
	BusInfo *		busInfoPtr;
		
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	//									vv
	busInfoPtr = GetXPTg()->BusInfoPtr[2];		
	((busInfoPtr->initInfo).SIM_ISR)((busInfoPtr->initInfo).SIMstaticPtr);

	VMEnableUserCode();			// enable user code (allow page faults)
}

void
XPT_ISR3 (void)
{
	BusInfo *		busInfoPtr;
		
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	//									vv
	busInfoPtr = GetXPTg()->BusInfoPtr[3];		
	((busInfoPtr->initInfo).SIM_ISR)((busInfoPtr->initInfo).SIMstaticPtr);

	VMEnableUserCode();			// enable user code (allow page faults)
}

void
XPT_ISR4 (void)
{
	BusInfo *		busInfoPtr;
		
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	//									vv
	busInfoPtr = GetXPTg()->BusInfoPtr[4];		
	((busInfoPtr->initInfo).SIM_ISR)((busInfoPtr->initInfo).SIMstaticPtr);

	VMEnableUserCode();			// enable user code (allow page faults)
}

void
XPT_ISR5 (void)
{
	BusInfo *		busInfoPtr;
		
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	//									vv
	busInfoPtr = GetXPTg()->BusInfoPtr[5];		
	((busInfoPtr->initInfo).SIM_ISR)((busInfoPtr->initInfo).SIMstaticPtr);

	VMEnableUserCode();			// enable user code (allow page faults)
}

void
XPT_ISR6 (void)
{
	BusInfo *		busInfoPtr;
		
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	//									vv
	busInfoPtr = GetXPTg()->BusInfoPtr[6];		
	((busInfoPtr->initInfo).SIM_ISR)((busInfoPtr->initInfo).SIMstaticPtr);

	VMEnableUserCode();			// enable user code (allow page faults)
}

void
XPT_ISR7 (void)
{
	BusInfo *		busInfoPtr;
		
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	//									vv
	busInfoPtr = GetXPTg()->BusInfoPtr[7];		
	((busInfoPtr->initInfo).SIM_ISR)((busInfoPtr->initInfo).SIMstaticPtr);

	VMEnableUserCode();			// enable user code (allow page faults)
}

void
XPT_ISR8 (void)
{
	BusInfo *		busInfoPtr;
		
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	//									vv
	busInfoPtr = GetXPTg()->BusInfoPtr[8];		
	((busInfoPtr->initInfo).SIM_ISR)((busInfoPtr->initInfo).SIMstaticPtr);

	VMEnableUserCode();			// enable user code (allow page faults)
}

void
XPT_ISR9 (void)
{
	BusInfo *		busInfoPtr;
		
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	//									vv
	busInfoPtr = GetXPTg()->BusInfoPtr[9];		
	((busInfoPtr->initInfo).SIM_ISR)((busInfoPtr->initInfo).SIMstaticPtr);

	VMEnableUserCode();			// enable user code (allow page faults)
}

void
XPT_ISRa (void)
{
	BusInfo *		busInfoPtr;
		
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	//									vv
	busInfoPtr = GetXPTg()->BusInfoPtr[0x0a];		
	((busInfoPtr->initInfo).SIM_ISR)((busInfoPtr->initInfo).SIMstaticPtr);

	VMEnableUserCode();			// enable user code (allow page faults)
}

void
XPT_ISRb (void)
{
	BusInfo *		busInfoPtr;
		
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	//									vv
	busInfoPtr = GetXPTg()->BusInfoPtr[0x0b];		
	((busInfoPtr->initInfo).SIM_ISR)((busInfoPtr->initInfo).SIMstaticPtr);

	VMEnableUserCode();			// enable user code (allow page faults)
}

void
XPT_ISRc (void)
{
	BusInfo *		busInfoPtr;
		
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	//									vv
	busInfoPtr = GetXPTg()->BusInfoPtr[0x0c];		
	((busInfoPtr->initInfo).SIM_ISR)((busInfoPtr->initInfo).SIMstaticPtr);

	VMEnableUserCode();			// enable user code (allow page faults)
}

void
XPT_ISRd (void)
{
	BusInfo *		busInfoPtr;
		
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	//									vv
	busInfoPtr = GetXPTg()->BusInfoPtr[0x0d];		
	((busInfoPtr->initInfo).SIM_ISR)((busInfoPtr->initInfo).SIMstaticPtr);

	VMEnableUserCode();			// enable user code (allow page faults)
}

void
XPT_ISRe (void)
{
	BusInfo *		busInfoPtr;
		
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	//									vv
	busInfoPtr = GetXPTg()->BusInfoPtr[0x0e];		
	((busInfoPtr->initInfo).SIM_ISR)((busInfoPtr->initInfo).SIMstaticPtr);

	VMEnableUserCode();			// enable user code (allow page faults)
}

void
XPT_ISRf (void)
{
	BusInfo *		busInfoPtr;
		
	VMDisableUserCode();		// disable user code (so page faults won't happen)

	//									vv
	busInfoPtr = GetXPTg()->BusInfoPtr[0x0f];		
	((busInfoPtr->initInfo).SIM_ISR)((busInfoPtr->initInfo).SIMstaticPtr);

	VMEnableUserCode();			// enable user code (allow page faults)
}

