/* File: BootItt.c Contains: Code that loads in SCSI Drivers at boot time Entry points: InitSCSIBoot IttBoot IsItt Written by: Clinton Bauder Copyright: © 1992-1994 by Apple Computer, Inc., all rights reserved. Change History (most recent first): 1/28/94 chp Move a local variable declaration inside a conditional compilation block so it won't generate a compiler warning when it is not used. 1/25/94 DCB Fixed a minor error in the way we interpret PRAM. The code was assuming that SCSI ID 7 had a fixed unit table entry which is not true. (only 0-6) 1/13/94 chp Adjust the usage of dNeedLock and dRAMBased, since the former local definitions were different than the constants defined in Inside Mac, and now in Devices.h. 1/13/94 chp Modify SOpenDriver to use new driver types in Devices.h. 11/22/93 pdw Rolling in from . 11/9/93 pdw Fixed problem with almost-bootable floppies. IttBoot now returns the refNum of the default disk whenever it sees it. We also init SCSIDrvrs in here and call InitSCSIBoot from InitItt instead of from StartSearch. 10/29/93 DCB Don't load SIMs from the SlotManager at INIT time. 10/14/93 pdw roll-in. 9/26/93 pdw Fixed a little problem with the forceBoot stuff - should work just fine now. 9/26/93 pdw Added forceBoot ability, fixed CmdShOptDel, fixed multi-bus booting bugs, a couple of other little bug fixes/changes. 9/12/93 pdw Name changes. Added start of check for VirtualID info for generating mask when running post-boot. 9/9/93 pdw Lots of little changes. Name changes, temporary cache_bug stuff. 8/23/93 pdw Added support for LimitPRAMClear, IgnoreCmdOptShDel, LoadDefaultOnly - three options required for AIX security, enabled by setting bits in PRAM $76. 7/8/93 pdw Changed some shorts to longs. 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. 5/31/93 PW Made references to block numbers in the DDM and the Partition map relative to the DDM. 5/29/93 PW Quoting instead of <> StandardGlue.h 5/29/93 PW Started putting in AIX boot stuff. Added check for PRAM OSType instead of constant sbMac check. 5/25/93 DCB Rollin from Ludwig. (The next two items below) 5/24/93 PW Fixing "conflict with Figment" bug which is actually our failing to clear a parameter block before using it. 5/21/93 PW Using scsiMaxTarget in BusInquiry for highestSCSIID instead of figuring it out based on scsiBusWideXX characteristics. 5/24/93 PW Fixing "conflict with Figment" bug which is actually our failing to clear a parameter block before using it. 5/5/93 PW Converted names to meanies-friendly names. 3/26/93 PW Cleared parameter blocks before using them. 3/20/93 PW Included SysEqu. 3/23/93 DCB Fixed a bug which prevented bootable CDs from booting. We need to ignore Data Run errors at least until we have read block zero. For now we will ignore them completely. 3/10/93 DCB Fixed a shine-through problem (again) which caused the high nybble of D5 to get loaded with a weird value when loading drivers. 3/8/93 DCB Fixed bug where startup disk wouldn't boot if CMD_OPT_SHFT_DEL was released after nothing else booted. 3/8/93 PW Included SysEqu. 3/1/93 DCB Changed startup PRAM to match slot drivers. Also added code to scan for srsrcs of type SIM. 2/17/93 PW Got rid of TIB - no longer supported. 2/13/93 PW Moved SetLoadFlag macro from BootItt.h to a routine in BootItt.c for SCSIDrvrs lo-mem support. 2/1/93 PW Update from the latest of Ludwig. Also changes required for PDM (will update Ludwig with these as needed myself). 1/27/93 DCB Added code for CmdOptShiftDel startup sequence to fix Radar Bug 1051033. 1/27/93 PW Changed kSlow to scsiTransferPolled. 12/9/92 PW Removed scsiDoVirtualMap flag so I had to remove its use in BootItt. 12/5/92 PW Changed some names mostly. 12/4/92 CB Added Support for booting drives with a non-512 byte block size. (CD-ROMs, some MOs etc.) 11/24/92 PW Narrowed check for same VID info to only same bus for old driver loading qualification. 11/20/92 DCB Added explicit clear of the scsiCompletion field and setup of the length field for SCSIActions 10/30/92 DCB Added a workaround for the Conner bug so that we can boot with those drives. 10/8/92 DCB Changed offset for new driver loading to 8 bytes. This gives driver writers greater flexibility. 10/8/92 PW (dcb) Added support for variable sized SCSI_IOs. Lots of trivial name changes. 9/17/92 PW Changed SCSI_DriverPB to SCSI_Driver_PB. 8/31/92 DCB Fixed a problem with reading partition maps that had more than one driver entry which caused disks to not mount. 8/20/92 DCB Changed boot code so it no longer used Select w/Atn to solve a problem with Conner drives. 7/28/92 PW Resolve differences between pdw and (d)cb sources. 7/28/92 PW Added this comment. <0> 6/24/92 DCB New Today */ #include #include #include #include #include #include #include #include #include #include #include #include #include //#include "IPLRecord.h" #include "SCSIDebug.h" #include "CUtils.h" #include "ACAM.h" #include "XPT.h" #include "XPTpriv.h" #include "BootItt.h" short ScanDrive( DevInfo *, BootInfo *, Boolean * forceBootablePtr); short AttemptDriverLoad( DevInfo *, BootInfo *, Boolean * forceBootablePtr); short ScRead(DevInfo *, ulong, ulong,ushort, Ptr); ulong CheckSumDrvr( Ptr driver,ushort length ); void SetLoadFlag( BootInfo * BInfo, DeviceIdent devIdent); short LoadDriver( DevInfo *, ulong, ulong, Boolean, Ptr, Ptr, Partition * ); Boolean Ck4EjectableVolume( short drvrRefNum); void DummyOldCallRead( short scsiID); #define DONT_WAIT 1 #define KEEP_WAITING 0 /*———————————————————————————————————————————————————————————————————————— ISITT - ————————————————————————————————————————————————————————————————————————*/ Boolean ISITT() { return( NGetTrapAddress(SCSIATOM, OSTrap) != NGetTrapAddress(UNIMPTRAP, ToolTrap) ); } /*———————————————————————————————————————————————————————————————————————— INITSCSIBOOT - ————————————————————————————————————————————————————————————————————————*/ void INITSCSIBOOT( void ) { BootInfo *BInfo; ushort numBuses, bus; XPTglobals *XPTg; // We will store our globals with the XPTs globals SCSIBusInquiryPB scPB; // Info about the scsi buses SCSIGetVirtualIDInfoPB vidPB; // to determine (at init time) if we need to mask in SCSIDrvrs #if ForROM #if !forIttInit char macIDpram; // Since the XPT isn't loaded at PrimaryInit and since SecondaryInit is too late // to load a SCSI Interface Module (SIM) we are going to try and help NuBus and // PDS developers out by loading SIMs here at the start of StartSearch. We do // this by loading sRSRCs of Category CatIntBus and cType TypSIM. Slots are // searched for sRSRCs of this type and then loaded as a driver. SpBlock tempSp; // Slot Manager PB used to locate SIMs SpBlock loadSp; // Slot Manager PB used to load SIMs SEBlock simSe; // exec block that will be passed to each slot SIM /* Start with slot zero and look from there... */ tempSp.spSlot = 0; tempSp.spID = 0; tempSp.spExtDev = 0; tempSp.spDrvrHW = 0; tempSp.spHwDev = 0; tempSp.spTBMask = 3; /* don't pay attention to hardware or software vendors */ tempSp.spCategory = CatIntBus; tempSp.spCType = TypSIM; tempSp.spDrvrSW = DrvrSwScsi43; while( SNextTypeSRsrc((SpBlockPtr)&tempSp) == noErr ) { loadSp = tempSp; /* Don't touch the original parameter block or SNext Loop will get screwed up and will start at the begining again */ simSe.seSlot = loadSp.spSlot; simSe.sesRsrcId = loadSp.spID; loadSp.spsExecPBlk = (Ptr)&simSe; if (noErr == SGetDriver((SpBlockPtr)&loadSp)) { SOpenDriver((SpBlockPtr)&loadSp); } } // Old SCSI Manager compatibility ———— // Certain old applications and SCSI utilities use the SCSIDrvrs lo-mem. We'll generate // it's default value here by setting the host ID bit (found in byte 2 of PRAM). ReadXPRam( 1, 0x02, &macIDpram); // read 1 byte at location 2 SCSIDrvrs = 1 << ( macIDpram & 0x07 ); // set bit at host ID #endif #endif Clear( (char *)&scPB, sizeof(scPB)); Clear( (char *)&vidPB, sizeof(vidPB)); // Find out how manuy buses there are in the sytem and alloc a BootInfo with that many IDmasks on the end scPB.scsiDevice.bus = -1; // XPT=-1 scPB.scsiFlags = 0; scPB.scsiFunctionCode = SCSIBusInquiry; scPB.scsiPBLength = sizeof(SCSIBusInquiryPB); // scPB.scsiCompletion = nil; // SCSIAction( (SCSI_PB *) &scPB ); if ( scPB.scsiResult != noErr) { DebugStr("\pInitSCSIBoot:BusInquiry failed getting numBuses"); } numBuses = scPB.scsiHiBusID + 1; if( (BInfo = (BootInfo *)NewPtrSysClear(sizeof(BootInfo) + sizeof(ulong) * numBuses)) == nil ) return; // Get PRAM, Set up the BInfo and store it (in XPT's globals) GetDefaultStartup( &(BInfo->startPRAM)); BInfo->BusCount = numBuses; BInfo->defltDrvrRefNum = KEEP_WAITING; XPTg = GetXPTg(); XPTg->BootStorage = (Ptr)BInfo; // Start with the mask so far of the drivers that we // loaded at original boot time. This is only needed // when we're running as an init or a patch (i.e. on Quadras). for (bus = 0; bus <= scPB.scsiHiBusID; bus+=1) { BInfo->IDmasks[bus] = SCSIDrvrs; // change to check VirtualID!!!%%%_debugger vidPB.scsiDevice.bus = bus; vidPB.scsiDevice.targetID = 0; vidPB.scsiFlags = 0; vidPB.scsiFunctionCode = SCSIGetVirtualIDInfo; vidPB.scsiPBLength = sizeof(SCSIGetVirtualIDInfoPB); vidPB.scsiCompletion = nil; SCSIAction( (SCSI_PB *) &vidPB ); if ( vidPB.scsiResult != noErr) { // !!! _debugger WE NEED TO DO SOMETHING WITH THIS } } } /*———————————————————————————————————————————————————————————————————————— IttBoot - ————————————————————————————————————————————————————————————————————————*/ short ITTBOOT( ulong onlyStartup, Boolean * forceBootPtr ) { SCSIGetVirtualIDInfoPB getVIDPB; /* for scanning for refNum-driven startup */ SCSIBusInquiryPB biPB; /* Info about the scsi busses */ BootInfo * BInfo; SCSI_IO * ioPtr; /* Our SCSI Parameter block */ uchar busID; /* Current scsi bus */ char hostSCSIID; /* host Mac SCSI ID */ char highestSCSIID; /* highest SCSI ID on this bus */ char scsiID; /* Current target */ DevInfo device; /* Current Device */ DevInfo fakeScanDevice; /* Device ident used for fake scan of boot ID on higher priority buses */ DevInfo startdevice; /* Startup Device */ short defRefNum = 0; /* Default refnum for startup */ short forceBootRefNum =0; /* Force boot (from specially marked ejectable media) */ XPTglobals *XPTg; /* We will store our globals with the XPTs globals */ ulong longPRAM; ushort PRAMRefNum; char * trashBlockPtr; ushort maxSCPBSize; // The largest PB we will need pdw Boolean foundBus; Boolean csodKeysDown; Boolean forcedBoot; Boolean unknownPRAM; // set when we figure out that we can't figure it out //——— Initialization ——— XPTg = GetXPTg(); BInfo = (BootInfo *) XPTg->BootStorage; if ( (*(short *)(lm_KeyMap + 6) == (short) CmdShiftOptDel) && !Ck4IgnoreCmdShOptDel()) { csodKeysDown = true; bset( kbCSOD, &(XPTg->flags)); } else csodKeysDown = false; // Initialize our 2 much-used PBs Clear( (char *)&biPB, sizeof(biPB)); biPB.scsiFunctionCode = SCSIBusInquiry; biPB.scsiPBLength = sizeof(SCSIBusInquiryPB); Clear((char *)&getVIDPB, sizeof(getVIDPB)); getVIDPB.scsiFunctionCode = SCSIGetVirtualIDInfo; getVIDPB.scsiPBLength = sizeof(SCSIGetVirtualIDInfo); // Find out just how big our ioPB needs to be biPB.scsiDevice.bus = -1; // XPT (we're getting max size of all bus's PBs) SCSIAction( (SCSI_PB *) &biPB ); if ( biPB.scsiResult != noErr) { IfDebugStr("\pIttBoot:BusInquiry failed getting maxSCPBSize"); return (DONT_WAIT); } maxSCPBSize = biPB.scsiMaxIOpbSize; // Initialize a 1 block trash buffer for our use if( (trashBlockPtr = NewPtrSysClear(0x200)) == nil ) return (DONT_WAIT); /* Try and boot with a driver that is already loaded... */ // Initialize a SCSI_IO parameter block for our use if( (ioPtr = (SCSI_IO *)NewPtrSysClear(maxSCPBSize)) == nil ) return (DONT_WAIT); /* Try and boot with a driver that is already loaded... */ ioPtr->scsiPBLength = maxSCPBSize; device.ioPB = ioPtr; /* Remember PB for later use */ startdevice.ioPB = ioPtr; /* Remember PB for later use */ //——— Deal with Default Boot Device first ——— // Determine the type of PRAM unknownPRAM =false; // If slot style PRAM... (new style) if( (BInfo->startPRAM.slotDev.sdSlotNum & 0xF0) == 0 ) { // Loop through Buses looking for one with this slot number and sRsrc ID foundBus = false; for( busID = 0; busID < BInfo->BusCount; busID+=1 ) { biPB.scsiDevice.bus = busID; SCSIAction( (SCSI_PB *) &biPB ); /* Get info for the internal (first) bus */ if ( biPB.scsiResult != noErr) DebugStr("\pIttBoot:BusInquiry failed getting scsiHBAslotNumber"); if( biPB.scsiHBAslotNumber == BInfo->startPRAM.slotDev.sdSlotNum && biPB.scsiSIMsRsrcID == BInfo->startPRAM.slotDev.sdSRsrcID ) { device.DevIdent.diReserved = 0; device.DevIdent.bus = busID; device.DevIdent.targetID = (BInfo->startPRAM.slotDev.sdExtDevID>>3) & 0x1f; // upper 5 bits device.DevIdent.LUN = BInfo->startPRAM.slotDev.sdExtDevID & 0x07; // lower 3 bits if( device.DevIdent.LUN ) // Only do select w/atn + identify message for non-zero luns device.IdentMsg = true; else device.IdentMsg = false; foundBus = true; break; // from for loop } } if (!foundBus) defRefNum = DONT_WAIT; // don't wait anymore else { startdevice = device; // Don't load a driver from the startup device if CmdShiftOptDel keys are down if ( csodKeysDown ) { defRefNum = DONT_WAIT; // Tell WaitForInternal to stop trying bset( kbCSODatBoot, &(XPTg->flags)); } else { // hit each device at this ID that might want higher priority VID mapping for( busID=0; busIDdefltDrvrRefNum; } else { defRefNum = AttemptDriverLoad( &startdevice, BInfo, forceBootPtr); BInfo->defltDrvrRefNum = defRefNum; } } } } // if the PRAM is a fixed drefnum for a SCSI device... (old style) else { startdevice.DevIdent.bus = -1; // dummy value for now longPRAM = *(ulong *)&BInfo->startPRAM; PRAMRefNum = (ushort) (longPRAM & 0xFFFF); if( PRAMRefNum >= 0xFFD9 && PRAMRefNum <= 0xFFDF ) { device.IdentMsg = false; // !!! device.DevIdent.diReserved = 0; device.DevIdent.bus = -1; // dummy value for now device.DevIdent.targetID = ~PRAMRefNum - 32; device.DevIdent.LUN = 0; /* Don't Scan LUNs */ // If we have an old ID mapping already, we simply use that bus // else, we need to scan all of the oldCallCapable buses until - // 1. we find a device (getVID.scsiExists == true) or, // 2. we run out of buses getVIDPB.scsiOldCallID = device.DevIdent.targetID; SCSIAction((SCSI_PB *) &getVIDPB); if ( getVIDPB.scsiResult != noErr) { IfDebugStr("\pIttBoot:getVID failed"); return (DONT_WAIT); // don't wait for it } if ( !getVIDPB.scsiExists ) // doesn't already exist? scan { // Scan OldCallCapable bus(es) until finding VID or running out of buses for ( busID = 0; busIDBusCount; busID+=1 ) { biPB.scsiDevice.bus = busID; SCSIAction( (SCSI_PB *) &biPB ); if( !(biPB.scsiFeatureFlags & scsiBusOldCallCapable)) continue; DummyOldCallRead( device.DevIdent.targetID); // if old-ID mapping now exists, then no more scanning SCSIAction((SCSI_PB *) &getVIDPB); if ( getVIDPB.scsiExists ) { break; // get out of loop } } } // after scan, if old-ID mapping now exists, this is the bus if (getVIDPB.scsiExists) { device.DevIdent.bus = getVIDPB.scsiDevice.bus; startdevice = device; if( TestLoadFlag( BInfo, device.DevIdent) ) { // we already hit the boot device, so we return that value defRefNum = BInfo->defltDrvrRefNum; } else if (csodKeysDown) { defRefNum = DONT_WAIT; // Don't WaitForInternal search keep trying bset( kbCSODatBoot, &(XPTg->flags)); } else { defRefNum = AttemptDriverLoad( &device, BInfo, forceBootPtr); BInfo->defltDrvrRefNum = defRefNum; } } else defRefNum = KEEP_WAITING; // no device yet - keep waiting } else // unknown PRAM format { unknownPRAM = true; defRefNum = DONT_WAIT; // don't wait anymore } } // If we're not supposed to continue on and look for other disks, let's exit here if( onlyStartup || Ck4OnlyLoadFromDefault() ) { DisposPtr( (Ptr)ioPtr ); DisposPtr( trashBlockPtr ); return (defRefNum); } //——— Scan all buses for other disks ——— *forceBootPtr = false; for( busID = 0; busID < BInfo->BusCount; busID+=1 ) { biPB.scsiDevice.bus = busID; SCSIAction( (SCSI_PB *) &biPB ); /* Get info for this bus */ if ( biPB.scsiResult != noErr) DebugStr("\p IttBoot:BusInquiry failed getting scsiMaxTarget"); highestSCSIID = biPB.scsiMaxTarget; hostSCSIID = biPB.scsiInitiatorID; for( scsiID = highestSCSIID; scsiID >= 0; scsiID-=1 ) { if (scsiID == hostSCSIID) { continue; } device.DevIdent.diReserved = 0; device.DevIdent.bus = busID; device.DevIdent.targetID = scsiID; device.DevIdent.LUN = 0; /* Don't Scan LUNs */ device.IdentMsg = false; // !!! if( TestLoadFlag(BInfo,device.DevIdent) ) { continue; /* We have already made a decision on this */ } if (unknownPRAM || !csodKeysDown) { forceBootRefNum = AttemptDriverLoad( &device, BInfo, &forcedBoot); } else if( device.DevIdent != startdevice.DevIdent) { bset( kbCSODatScan, &(XPTg->flags)); forceBootRefNum = AttemptDriverLoad( &device, BInfo, &forcedBoot); } // If this last one was a force boot, remember that and its refNum if ( forcedBoot && forceBootRefNum<0) { *forceBootPtr = true; defRefNum = forceBootRefNum; } } } DisposPtr( (Ptr)ioPtr ); DisposPtr( trashBlockPtr ); return (defRefNum); } /*———————————————————————————————————————————————————————————————————————— AttemptDriverLoad - ————————————————————————————————————————————————————————————————————————*/ /* Attempt to load a driver for this device ** ** First ask the SIM to try. If the SIM doesn't know how to do this or ** if it fails then we look at the device and try to load a driver from ** the device. Failing this we again ask the SIM to try. This allows ** SIMs to either over-ride drivers on the device or only install an emergency ** "There wasn't any other driver to boot with" driver */ short // refNum AttemptDriverLoad( DevInfo * devInfoPtr, BootInfo * BInfo, Boolean * forceBootablePtr ) { SCSILoadDriverPB LoadPB; /* PB for Loading SIM Drivers */ short dRefNum; /* The driver we loaded */ OSErr err; Clear((char *)&LoadPB,sizeof(LoadPB)); dRefNum = 0; // 0 means we haven't found it but we haven't given up LoadPB.scsiDevice = devInfoPtr->DevIdent; LoadPB.scsiCompletion = 0; LoadPB.scsiDiskLoadFailed = 0; LoadPB.scsiPBLength = sizeof(LoadPB); LoadPB.scsiFunctionCode = SCSILoadDriver; err = SCSIAction( (SCSI_PB *) &LoadPB ); if( err != 0 || LoadPB.scsiLoadedRefNum == 0 ) { dRefNum = ScanDrive( devInfoPtr, BInfo, forceBootablePtr); if( dRefNum == 0 ) { LoadPB.scsiDiskLoadFailed = 1; if( SCSIAction( (SCSI_PB *) &LoadPB ) == noErr ) dRefNum = LoadPB.scsiLoadedRefNum; } } else { dRefNum = LoadPB.scsiLoadedRefNum; // DCB } return ( dRefNum ); } /*———————————————————————————————————————————————————————————————————————— ScanDrive - ————————————————————————————————————————————————————————————————————————*/ /* Scan The partition map for a driver and try to load it ** ** First Examine the driver map in block 0 ** If it was valid Load in Block 1 and find out if it is a new partition map ** If not we load the driver and assume it is of type "Apple_Driver" ** If it is a new map we scan for a Driver Partition Map which matches the ** Entry in the driver map (Block 0) and the first HFS Partition ** If all of that succeeds we attempt to load the driver. "Apple_Driver43"s get ** a device Ident in d5 while older "Apple_Drivers" get a SCSI ID. */ short ScanDrive( DevInfo * devInfoPtr, BootInfo * BInfo, Boolean * forceBootablePtr ) { Block0 *realBlock0; /* a buffer for block zero (Physical) */ Partition *curBlock; /* the current block we are working on */ Partition *HFSBlock; /* first HFS Partition map entry */ Partition *drvrBlock; /* Driver's Partition map entry */ ddMap *bootDrvr; /* Scratch */ ushort d; /* driver index (for scanning DDM) */ ulong drvrBlockStart; /* The starting block number of the driver */ ushort drvrSize; /* The size (in blocks) of the driver */ ulong b; /* partition block number index */ Boolean drvrIs43; /* false if old, true if new (4pt3) */ short dRefNum; /* The driver we loaded */ short partMapCount; /* Length of partition map */ ulong DDMBlockNum; /* block number of DDM */ uchar osType; /* OS Type read from PRAM */ // Initialize and alloc needed memory dRefNum = KEEP_WAITING; /* don't have it yet - haven't given up */ HFSBlock = drvrBlock = curBlock = nil; /* Nobody home yet - needed for cleanup */ if( (realBlock0 = (Block0 *) NewPtrSysClear(512)) == nil ) goto Cleanup; /* Punt */ if( (curBlock = (Partition *) NewPtrSysClear(512)) == nil ) goto Cleanup; /* Punt */ // Read block 0 and see if it is a DDM or an IPLRecord or neither if( ScRead( devInfoPtr, 0, 1, 512, (Ptr) realBlock0) ) /* Get block 0 (DDM/IPLRecord?) */ goto Cleanup; if( realBlock0->sbSig == sbSIGWord ) { // udoublet at 0 DDMBlockNum = 0; } else if( ( (ipl_rec_area *)realBlock0 )->IPL_record_id == IPLRECID) { // uquadlet at 0 DDMBlockNum = ( (ipl_rec_area *)realBlock0 )->boot_prg_start; if( ScRead( devInfoPtr, DDMBlockNum, 1, 512, (Ptr) realBlock0) ) goto Cleanup; } else { SetLoadFlag(BInfo,devInfoPtr->DevIdent); /* Don't try me again! */ goto Cleanup; } // Scan through drivers in DDM to find one that matches our OSType ReadXPRam( 1, 0x77, &osType); for( drvrBlockStart = 0, bootDrvr = (ddMap *)&realBlock0->ddBlock, d = 0 ; d < realBlock0->sbDrvrCount ; d+=1 ) { if( bootDrvr[d].ddType == osType) { drvrBlockStart = bootDrvr[d].ddBlock + DDMBlockNum; drvrSize = bootDrvr[d].ddSize; break; } } if( drvrBlockStart == 0 ) { /* No Drivers in ddm */ SetLoadFlag(BInfo,devInfoPtr->DevIdent); /* Don't try me again! */ dRefNum = DONT_WAIT; goto Cleanup; } // Read first block of part map to determine if it's valid and to find part map length if( ScRead( devInfoPtr, DDMBlockNum+1,1,512,(Ptr)curBlock) ) { SetLoadFlag(BInfo,devInfoPtr->DevIdent); /* Don't try me again! */ goto Cleanup; } if( curBlock->pmSig != newPMSigWord ) { /* Old Style PMap or one we don't recognize */ /* Be friendly and try to boot it anyway */ if( TestLoadFlag(BInfo,devInfoPtr->DevIdent) == 0 ) dRefNum = LoadDriver(devInfoPtr,drvrBlockStart,drvrSize,false, (Ptr)realBlock0,(Ptr)curBlock, 0); // SetLoadFlag(BInfo,devInfoPtr->DevIdent); goto Cleanup; } // Scan through part map to find HFS and driver partitions for( b=1, drvrIs43 = 0, partMapCount = curBlock->pmMapBlkCnt ; b <= partMapCount ; b+=1 ) { if( ScRead( devInfoPtr, DDMBlockNum+b, 1, 512, (Ptr)curBlock) ) { SetLoadFlag( BInfo, devInfoPtr->DevIdent); /* Don't try me again! */ goto Cleanup; } if( drvrBlock == 0 && *(long *) &curBlock->pmParType[0] == 'Appl' && *(long *) &curBlock->pmParType[4] == 'e_Dr' && *(long *) &curBlock->pmParType[8] == 'iver' ) { if( curBlock->pmPyPartStart != drvrBlockStart - DDMBlockNum) // continue; /* Whoops, not the driver from the DDM! */ // drvrIs43 = (*(short *)&(curBlock->pmParType[12]) == '43') ? true : false; // *forceBootablePtr = (*(long *)&(curBlock->pmParType[28]) == 'pdm!') ? true : false; drvrBlock = curBlock; if( (curBlock = (Partition *) NewPtrSysClear(512)) == nil ) goto Cleanup; /* Punt */ } else if( HFSBlock == 0 && *(long *) &curBlock->pmParType[0] == 'Appl' && *(long *) &curBlock->pmParType[4] == 'e_HF' && curBlock->pmParType[8] == 'S' ) { HFSBlock = curBlock; if( (curBlock = (Partition *) NewPtrSysClear(512)) == nil ) goto Cleanup; /* Punt */ } if( drvrBlock && HFSBlock ) break; // } // Load the driver whether we found an HFS partition or not if( HFSBlock) { if( TestLoadFlag( BInfo, devInfoPtr->DevIdent) == 0 ) { dRefNum = LoadDriver( devInfoPtr, drvrBlockStart, drvrSize, drvrIs43, (Ptr)realBlock0, (Ptr)HFSBlock, drvrBlock ); // SetLoadFlag( BInfo, devInfoPtr->DevIdent); } } if (*forceBootablePtr) *forceBootablePtr = Ck4EjectableVolume( dRefNum); Cleanup: if( realBlock0 ) DisposPtr((Ptr) realBlock0); if( curBlock ) DisposPtr((Ptr) curBlock); if( HFSBlock ) DisposPtr((Ptr) HFSBlock); if( drvrBlock ) DisposPtr((Ptr) drvrBlock); return (dRefNum); } /*———————————————————————————————————————————————————————————————————————— LoadDriver - ————————————————————————————————————————————————————————————————————————*/ short LoadDriver( DevInfo * devInfoPtr, ulong DrvrStart, ulong DrvrLength, Boolean NewDrvr, Ptr BZero, // Ptr HFSBlock, Partition * drvrBlock ) { #pragma unused (drvrBlock) Ptr theDrvr; short dRefNum; SCSI_Driver_PB myPB; SCSIGetVirtualIDInfoPB myVIDpb; //--- Check to see if it's OK to load and install the driver Clear((char *)&myPB, sizeof(myPB)); Clear((char *)&myVIDpb, sizeof(myVIDpb)); if( NewDrvr) { //--- Driver43 --- myPB.scsiDevice = devInfoPtr->DevIdent; myPB.scsiCompletion = nil; myPB.scsiPBLength = sizeof(SCSI_Driver_PB); myPB.scsiFunctionCode = SCSILookupRefNumXref; SCSIAction((SCSI_PB *) &myPB); dRefNum = myPB.scsiDriver; if( dRefNum != 0 ) return (dRefNum); /* Already installed */ } else { //--- Old style driver --- //--- Don't load old driver if SCSI ID is 7 or higher if( devInfoPtr->DevIdent.targetID >= 7) return (DONT_WAIT); //--- Don't load old driver if device doesn't match VirtualIDInfo myVIDpb.scsiOldCallID = devInfoPtr->DevIdent.targetID; myVIDpb.scsiFunctionCode = SCSIGetVirtualIDInfo; SCSIAction((SCSI_PB *) &myVIDpb); // get the info about this ID if (myVIDpb.scsiExists && myVIDpb.scsiDevice.bus != devInfoPtr->DevIdent.bus) // pdw return (DONT_WAIT); //--- Don't load it if a driver is already installed at the static drvr slot for this ID dRefNum = ~(devInfoPtr->DevIdent.targetID + 32); /* Convert SCSI ID to DRefNum */ if( GetDCtlEntry(dRefNum) != nil ) return (DONT_WAIT); } //--- Now try to load the driver and do a checksum on it if( (theDrvr = NewPtrSys(DrvrLength * ((Block0 *)BZero)->sbBlkSize)) == nil ) // return (DONT_WAIT); /* No memory - give up */ if( ScRead( devInfoPtr, DrvrStart, DrvrLength, ((Block0 *)BZero)->sbBlkSize, theDrvr) ) { DisposPtr(theDrvr); return (KEEP_WAITING); } FlushInstructionCache(); FlushDataCache(); if( drvrBlock && *(long *)drvrBlock->pmPartName == 'Maci' ) { /* !!! Why do a long comparison when the checksum routine returns a short ? I don't have any idea - but this is the way the original SCSIBoot.a file did it so I will continue to do it the same way until further notice. -DCB */ if( (ulong) drvrBlock->pmBootCksum != CheckSumDrvr( theDrvr,drvrBlock->pmBootSize ) ) { DisposPtr(theDrvr); return (DONT_WAIT); } } //--- Jump to driver if( NewDrvr ) { //--- Driver43 (NOTE! Driver43s start at Driver + 8 bytes!!! JmpToDrvr( *(ulong *)&devInfoPtr->DevIdent, theDrvr + 8, BZero, HFSBlock); // /* Find out where the driver installed itself */ myPB.scsiDevice = devInfoPtr->DevIdent; myPB.scsiCompletion = nil; myPB.scsiPBLength = sizeof(SCSI_Driver_PB); myPB.scsiFunctionCode = SCSILookupRefNumXref; SCSIAction((SCSI_PB *) &myPB); return (myPB.scsiDriver); } else { //--- Old style driver JmpToDrvr( devInfoPtr->DevIdent.targetID, theDrvr, (Ptr) BZero, HFSBlock); //!!! Add At_App_Time dRefNum = ~(devInfoPtr->DevIdent.targetID + 32); /* Convert SCSI ID to DRefNum */ if( GetDCtlEntry(dRefNum) == nil ) return (DONT_WAIT); /* Something went wrong - didn't install */ /* Ok, it installed - register it with the SCSI Manager */ myPB.scsiDevice = devInfoPtr->DevIdent; myPB.scsiPBLength = sizeof(SCSI_Driver_PB); myPB.scsiDriver = dRefNum; myPB.scsiFunctionCode = SCSICreateRefNumXref; SCSIAction((SCSI_PB *) &myPB); return (dRefNum); } } /*———————————————————————————————————————————————————————————————————————— SetLoadFlag - ————————————————————————————————————————————————————————————————————————*/ void SetLoadFlag( BootInfo * BInfo, DeviceIdent devIdent) { SCSIGetVirtualIDInfoPB getVIDPB; Clear((char *)&getVIDPB, sizeof(getVIDPB)); BInfo->IDmasks[ devIdent.bus] |= (1 << devIdent.targetID); getVIDPB.scsiOldCallID = devIdent.targetID; getVIDPB.scsiFunctionCode = SCSIGetVirtualIDInfo; SCSIAction((SCSI_PB *) &getVIDPB); // get the info about this ID if ( getVIDPB.scsiExists && (getVIDPB.scsiDevice.bus == devIdent.bus)) SCSIDrvrs |= 1< uchar *buffer ) { uchar *cmd; cmd = (uchar *)&(devInfoPtr->ioPB->scsiCDB); /* 10 byte commands are easier but the @#$%^&*! Connor 40s don't return real data from the FIRST 10 byte command after a reset or power on. Therefore we issue 6 byte commands unless the data requested exceeds the addressing capacity of a 6 byte command. */ if( (block & 0xFFE00000) || (length & 0xFFFFFF00) ) { // cmd[0] = 0x28; /* Properly pumped up 10 byte scsi command */ cmd[1] = 0; /* !!! Add support for embedded luns? */ cmd[2] = block>>24; cmd[3] = block>>16; cmd[4] = block>>8; cmd[5] = block; cmd[6] = 0; /* reserved */ cmd[7] = length>>8; cmd[8] = length; cmd[9] = 0; /* reserved */ devInfoPtr->ioPB->scsiCDBLength = 10; } else { cmd[0] = 0x8; /* Wimpy 6 byte command */ cmd[1] = block>>16 & 0x1f; /* !!! Add support for embedded luns? */ cmd[2] = block>>8; cmd[3] = block; cmd[4] = length; cmd[5] = 0; /* reserved */ devInfoPtr->ioPB->scsiCDBLength = 6; } devInfoPtr->ioPB->scsiDataPtr = buffer; devInfoPtr->ioPB->scsiDataLength = length * blocklen; /* */ devInfoPtr->ioPB->scsiFlags = scsiDirectionIn | scsiSIMQNoFreeze | scsiDisableAutosense; devInfoPtr->ioPB->scsiIOFlags = scsiNoParityCheck; if( devInfoPtr->IdentMsg == 0 ) devInfoPtr->ioPB->scsiIOFlags |= scsiDisableSelectWAtn; devInfoPtr->ioPB->scsiDevice = devInfoPtr->DevIdent; devInfoPtr->ioPB->scsiFunctionCode = SCSIExecIO; devInfoPtr->ioPB->scsiCompletion = nil; devInfoPtr->ioPB->scsiTransferType = scsiTransferPolled; SCSIAction( (SCSI_PB *) devInfoPtr->ioPB); if( devInfoPtr->ioPB->scsiSCSIstatus ) // status will be cleared upon entry to SIMAction SCSIAction( (SCSI_PB *) devInfoPtr->ioPB); /* Retry, to clear out unit attention */ if( devInfoPtr->ioPB->scsiResult == scsiDataRunError ) // Not all drives are 512/block devInfoPtr->ioPB->scsiResult = noErr; // We don't discover this until after we load block zero return( !(devInfoPtr->ioPB->scsiResult == noErr && devInfoPtr->ioPB->scsiSCSIstatus == 0) ); } /*———————————————————————————————————————————————————————————————————————— SOpenDriver - ————————————————————————————————————————————————————————————————————————*/ OSErr SOpenDriver(SpBlockPtr sp) { OSErr err; short refnum; unsigned int count; AuxDCEHandle myDCE; DriverHeaderHandle driver; unsigned char name [32]; ParamBlockRec ioPB; driver = (DriverHeaderHandle) sp->spResult; HLock((Handle) driver); /* copy the driver name out of the driver header */ BlockMove((**driver).drvrName, name, 1 + (**driver).drvrName[0]); for( count = 48; count < *(ulong *)UnitNtryCnt ; count+=1 ) { refnum = ~count; if( GetDCtlEntry(refnum) == 0 ) break; /* Use the first empty spot we find */ } if( (err = DrvrInstallResrvMem(*driver, refnum)) != noErr ) return(err); myDCE = (AuxDCE**)GetDCtlEntry(refnum); (**myDCE).dCtlDriver = (Ptr)driver; (**driver).drvrFlags |= 1 << dNeedLock << 8 | 1 << dRAMBased; (**myDCE).dCtlFlags = (**driver).drvrFlags; (**myDCE).dCtlDelay = (**driver).drvrDelay; (**myDCE).dCtlEMask = (**driver).drvrEMask; (**myDCE).dCtlMenu = (**driver).drvrMenu; (**myDCE).dCtlSlot = sp->spSlot; (**myDCE).dCtlSlotId = sp->spID; (**myDCE).dCtlExtDev = sp->spExtDev; ioPB.slotDevParam.ioVRefNum = 0; ioPB.slotDevParam.ioFlags = 0; ioPB.slotDevParam.ioPermssn = 0; ioPB.slotDevParam.ioCompletion = 0; ioPB.slotDevParam.ioMix = (Ptr)0; ioPB.slotDevParam.ioNamePtr = name; ioPB.slotDevParam.ioSlot = sp->spSlot; ioPB.slotDevParam.ioID = sp->spID; PBOpenSync(&ioPB); if( ioPB.slotDevParam.ioResult < 0 ) { DisposeHandle((Handle) driver); /* dispose the driver */ DisposeHandle((Handle) myDCE); /* dispose the DCE */ ((long *)(*(long *)UTableBase))[count] = nil; /* clear the unit table entry */ } return(ioPB.slotDevParam.ioResult); } /*———————————————————————————————————————————————————————————————————————— Ck4EjectableVolume - ————————————————————————————————————————————————————————————————————————*/ Boolean Ck4EjectableVolume( short drvrRefNum) { DrvQEl * qElPtr; char diskType; qElPtr = (DrvQEl *)(GetDrvQHdr()->qHead); while (qElPtr) { if (qElPtr->dQRefNum == drvrRefNum) { diskType = *(( (char *)qElPtr )-3); if ( diskType ==1 || diskType ==2) return (true); } qElPtr = (DrvQEl *)(qElPtr->qLink); } return (false); } /*———————————————————————————————————————————————————————————————————————— DummyOldCallRead - ————————————————————————————————————————————————————————————————————————*/ void DummyOldCallRead( short scsiID) { char cdb[6]; SCSIInstr tib[2]; char data[0x200]; short stat, msg; tib[0].scOpcode = scInc; tib[0].scParam1 = &data; tib[0].scParam2 = 0x200; tib[1].scOpcode = scStop; tib[1].scParam1 = 0; tib[1].scParam2 = 0; cdb[0] = 0x08; cdb[1] = 0x00; cdb[2] = 0x00; cdb[3] = 0x00; cdb[4] = 0x01; cdb[5] = 0x00; SCSIGet(); if (SCSISelect( scsiID)) return; if (!SCSICmd( cdb, 6)) SCSIRead( (Ptr)tib); SCSIComplete( &stat, &msg, 60*60); }