mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-01-01 11:29:27 +00:00
0ba83392d4
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
1450 lines
43 KiB
C
1450 lines
43 KiB
C
/*
|
|
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)
|
|
}
|
|
|