sys7.1-doc-wip/OS/SCSIMgr/SCSIBoot.a

550 lines
21 KiB
Plaintext
Raw Normal View History

2019-07-27 14:37:48 +00:00
;
; File: SCSIBoot.a
;
; Contains: This is the SCSI boot code for the Macintosh.
;
; Written by: Erich Ringewald
;
; Copyright: © 1985-1993 by Apple Computer, Inc. All rights reserved.
;
; Change History (most recent first):
;
; <SM9> 10/14/93 pdw Comment changes.
; <SM8> 5/29/93 PW Added line to heap munging code (after driver is called) that
; updates TheZone as well as ApplZone.
; <SM7> 2/13/93 PW Added <LW2> change.
; <LW2> 2/11/93 PW Added ability to tell drivers not to munge the heap by passing a
; flag register (D6) from StartSearch or LateLoad.
; <SM6> 11/3/92 SWC Changed SCSIEqu.a->SCSI.a.
; <SM5> 10/22/92 CSS Change some branch short instructions to branches.
; <SM4> 6/2/92 kc Roll in Pandora/Horror/Zydeco changes. Comments follow:
; <H2> 12/21/91 jmp (BG,Z3) Added fix for busy status from drive while spinning up.
; <Z2> 10/2/90 CCH Added a cache flush after SCSI reads during boot.
; <SM1> 5/22/92 CS Cyclone (Pandora) roll in.
; <9> 5/1/92 JSM Dont use onMacXX style conditionals. This file now has no
; conditionals.
; <8> 12/27/91 RB Changed the flush cache code for 040's so it calls CacheFlush
; <7> 9/16/91 JSM Cleanup header.
; <6> 6/12/91 LN Changed #include 'HardwareEqu.a' to 'HardwarePrivateEqu.a'
; <5> 9/21/90 BG Removing EclipseNOPS and other 040-related kludges as 040s are
; now working more reliably.
; <4> 7/19/90 BG Added EclipseNOPs for flakey 040s.
; <3> 6/22/90 CCH Added a data cache push for 68040's after a SCSI block read.
; <2> 5/16/90 MSH Added hasPowerControls to hcmac conditional.
; <1.4> 8/22/89 SES Removed references to nFiles.
; <1.3> 5/26/89 GGD Deleted the hack that was added for flakey PRAM on MvMac in
; December.
; <1.2> 12/13/88 rwh Added hack to set default OS to Mac OS while MvMac PRAM is
; flakey.
; <1.1> 11/10/88 CCH Fixed Header.
; <1.0> 11/9/88 CCH Adding to EASE.
; <•1.2> 9/23/88 CCH Got rid of inc.sum.d and empty nFiles
; <1.1> 4/18/88 CSL Added support for JVC drive for HcMac
; <1.0> 2/10/88 BBM Adding file for the first time into EASE…
; <C895> 9/30/87 MSH Port to HcMac (Laguna)
; <C859> 6/15/87 SHF Fixed bug in register usage in SRead routine.
; <C846> 4/28/87 SHF Bug fixes.
; <C770> 2/7/87 SHF Fixed bug in SRead read retry (stack problem).
; <C613> 1/12/87 SHF Fixed driver count decrement size (long to word).
; <C608> 1/9/87 SHF Fixed register-usage bug for booting non-Mac drivers.
; <C478> 12/11/86 SHF Changes for Becks to allow booting a non-Mac OS.
; <A382> 11/8/86 SHF Took out checksum bypass for driver checksums of 0.
; <A349> 11/4/86 SHF Made the error-handling more forgiving (especially for 532-byte
; sectors).
; <A311> 10/31/86 SHF Added checksum for drivers having the appropriate boot code
; partition map entry; we now search for appropriate driver
; partition map entries and data partition map entries.
; <A300> 10/29/86 SHF Go through all 8 devices (InitSCSIMgr sets the bit in SCSIDrvrs
; corresponding to the CPU's SCSI id).
; <A244> 10/27/86 SHF Read 512 instead of 256 bytes of blocks 0 and 1.
; <A211> 10/17/86 SHF Put the Status phase check after the Command trap, added retry
; to accomodate Unit Attention devices.
; <C185> 9/30/86 SHF Fixed the mask value for the Status phase check.
; <C165> 9/29/86 SHF Checks for Status phase after bad Select.
; <C136> 9/3/86 SHF Added explicit .b, .w, .l; now checks NewPtr value
; <C66> 7/9/86 SHF Fixed zero sbDrvrCount field bug in 'Openit'
; <C26> 5/29/86 SHF Deleted _SCSIReset call in SCSILoad to avoid Unit Attn
; recurrence. InitIO in StartInit now does the reset.
; <C1> 4/15/86 RDC Deleted old MidMac changes
; 2/19/86 BBM Made some modifications to work under MPW
; 1/16/86 ELR Fixed polarity of beq to bpl for tst of SCSI byte.
; 10/28/85 ELR Fixed bug in SCSILoad which didn't correctly look at SCSIFlags
; 10/27/85 ELR Removed inclusion of SCSIMacs and SCSIBootEqu; this is now
; included in NewEqu.
; 10/27/85 ELR Added Flag "SCSIDrvrs" which is a bitmap for loaded SCSI
; drivers. Now SCSILoad can be called repeatedly to check for new
; devices coming online. A call to SCSILoad was placed in the
; RDBootBlocks loop in StartInit to facilitate this.
; 9/27/85 ELR Bunch of changes in a last ditch effort to get something to
; work.
; 9/16/85 RDC More changes for MidMac
; 9/13/85 RDC Added changes for Milwaukee (MidMac) Fixed SetTrapaddress call
; to work with new ROM's Added include of HWequ.text
; 9/6/85 ELR New Today.
;
BLANKS ON
STRING ASIS
PRINT OFF
LOAD 'StandardEqu.d'
INCLUDE 'HardwarePrivateEqu.a'
INCLUDE 'SCSI.a'
PRINT ON
MACHINE MC68020
;
; Equates for the partition map blocks
;
PMSigWord EQU $504D ; offset 0
map_blks EQU 4 ; see partition design document
part_phys_blk EQU 8
part_blks EQU 12
name EQU 16
type EQU 48
boot_size EQU 96
boot_cksum EQU 116
SCSIBoots PROC EXPORT
EXPORT SCSILoad ; this is called by startinit
;---------------------------------------------------------------
;
; SCSILoad -- loads in SCSI device drivers. Called by the start code.
;
; Modified to handle arbitrary combinations of requested drivers. <A349/03Nov86>
;
; On entry, d0.b is a bit map of devices for which we want to load drivers.
; D6 = mask to OR with D5 when calling driver's installation point
; On exit, d0.b is a bit map of devices for which we either:
;
; (a) successfully loaded drivers - or -
; (b) the device(s) didn't respond and it would be useful to try
; them later (possibly when they are powered up, etc.).
;
; If a device responded to the select but didn't have a valid driver, then
; we clear the bit associated with that SCSI ID so that we don't waste any
; more time polling it.
;
; --------------------------------------
;
; For NuMac only....
;
; d3 contains the following fields taken from parameter RAM in StartSearch.a:
;
; bits 0-7: partition number
; bits 8-15: device ID (used for slots)
; bits 16-23: OS type to boot (normally Mac OS)
; bits 24-31: reserved
;
SCSILoad
btst.b #7,HWCfgFlags ; is there a SCSI chip? <A349/03Nov86>
bne.s Start ; yes, so continue <A349/03Nov86>
moveq.l #0,d0 ; 0: don't try any more devices <A349/03Nov86>
rts ; <A349/03Nov86>
; deleted old code <C1/15Apr86>
; Start the load procedure. Assumes the SCSI bus has already been reset
; <C26/29May86>; makes a pass through the 7 SCSI devices,
; attempting to load 0-7 drivers. On entry, d0 has a bit map (byte wide)
; of drivers to attempt to load. We compare this with the list of drivers
; already loaded in order to decide which ones to load now. <A311/31Oct86>
; InitSCSIMgr has already set the SCSIDrvrs bit corresponding to the CPU's
; SCSI bus ID.
Start
movem.l a0-a6/d1-d7,-(sp) ; don't clobber this stuff
move.b d0,-(sp) ; save the map <A311>
; hard reset of the SCSI bus removed here <C26/29May86>
; start command to portable drives removed here
moveq.l #7,d5 ; start with SCSI device 7 <A300>
CheckNext
btst.b d5,(sp) ; do we want this one? <A311>
beq.s @1 ; nope <A311>
btst.b d5,SCSIDrvrs ; is it already loaded? <A349/04Nov86>
bne.s @1 ; yes, so skip it <A349/04Nov86>
bsr.s OpenIt ; try to install the driver
beq.s @1 ; don't clear bit in map <A349/04Nov86>
; If the return value is non-zero, then it means a drive was there but that
; block 0 or 1 (or the driver's checksum) weren't cool. In this case we
; clear the bit in the map to be returned to the caller. <A349/04Nov86>
bclr.b d5,(sp) ; don't try this one again <A349/04Nov86>
@1
dbra d5,CheckNext ; do the next one
moveq.l #0,d0 ; clear upper nonsense <A349/04Nov86>
move.b (sp)+,d0 ; pop the map byte <A311>
movem.l (sp)+,a0-a6/d1-d7 ; restore everything else
tst.w d0 ; set con. codes for word <A349/04Nov86>
rts
;---------------------------------------------------------------
;
; OpenIt. This routine solicits the SCSI device whose ID is in d5
; for a driver. If one is found, it is loaded into the system heap
; and given an installation call. d3 contains boot information
; passed in by StartSearch.a.
;
;
; Equates for the local stack frame <A311>
;
DriverStart EQU -4 ; 1st blk # of driver (long)
DriverBlks EQU DriverStart-4 ; # of blks in driver (long)
BootOS EQU DriverBlks-2 ; boot OS type (word)
MapCnt EQU BootOS-4 ; # of part. map blocks (long)
CurMapBlk EQU MapCnt-4 ; counter variable (long)
BlockBuf EQU CurMapBlk-512 ; after link, EA = 0(sp)
FrameSize EQU BlockBuf ; value for link instruction
OpenIt
move.l d3,-(sp) ; preserve register <C478>
link a6,#FrameSize ; need some locals <A311>
move.l sp,a2 ; start of blk buffer <A311>
swap d3 ; OS type (low byte) <C478>
moveq.l #0,d0 ; clear upper bits <C478>
move.b d3,d0 ; get the byte <C478>
move.w d0,BootOS(a6) ; store as a word <C478>
moveq.l #0,d3 ; d3 gets block location
moveq.l #1,d2 ; d2 gets block count
move.w #512,d4 ; d4 gets block size <A244>
bsr SRead ; read the block from unit in d5
bne.w ZeroExit ; OK to try later <A349/04Nov86>
cmpi.w #SBSigWord,SBSig(sp) ; is it for real?
bne.w NonZeroExit ; no -- don't try again <A349/04Nov86>
move.w SBBlkSize(sp),d4 ; get the block size
move.w SBDrvCount(sp),d0 ; get the driver count
beq NonZeroExit ; no drivers: no retry <A349/04Nov86><SM5> CSS
lea SBDrvrs(sp),a0 ; point at driver list
move.l SBData(sp),d7 ; save the default data block pointer...
NextDD
move.w BootOS(a6),d1 ; desired driver type <C608>
cmp.w DDType(a0),d1 ; is this the one? <C608>
beq.s FoundDD
addq.l #DDLen,a0 ; move to the next driver
subq.w #1,d0 ; decrement count <C613>
bne.s NextDD
bra NonZeroExit ; no matching drivers... <A349/04Nov86><SM5> CSS
FoundDD
bset.b d5,SCSIDrvrs ; show we tried to load the driver
move.l DDBlock(a0),d3 ; block #
move.l d3,DriverStart(a6) ; save a local copy <A311>
moveq.l #0,d2 ; clear high word <A311>
move.w DDSize(a0),d2 ; # blocks
move.l d2,DriverBlks(a6) ; local copy <A311>
move.l d4,d0 ; block size of driver
mulu d2,d0 ; times # blocks is byte size
_NewPtr ,SYS ; head for the system heap
bne.s NonZeroExit ; no room in the inn <A349/04Nov86>
move.l a0,a3 ; put the driver here
move.l a0,a2
bsr SRead ; load the driver
bne.s DisposExit ; deallocate on error <A349/04Nov86>
moveq.l #1,d3 ; now read block 1
move.l d3,CurMapBlk(a6) ; initialize counter <A311>
moveq.l #1,d2 ; do a single block
move.w #512,d4 ; full block <A244>
move.l sp,a2 ; ontop of block 0 is OK
bsr SRead ; preserves a2
bne.s DisposExit ; error in read of block 1
cmp.w #SBMac,BootOS(a6) ; are we booting Mac OS? <C478>
bne.s CallDriver ; no, so skip partition stuff <C478>
cmp.w #PDSigWord,(a2) ; old partition map? <A311>
beq.s CallDriver ; yes, so just call it <A311>
; Just in case someone defines a new signature word for block 1, we'll
; be nice and assume that the driver knows how to handle this new type.
cmp.w #PMSigWord,(a2) ; new partition entry? <A311>
bne.s CallDriver ; no, so be nice <A311>
move.l map_blks(a2),d0 ; get count of map blocks <A311>
move.l d0,MapCnt(a6) ; and save it locally
bra.s DoNewPartition ; go do everything else
CallDriver
move.l a2,a0 ; pointer to the partition block
; We assume that if the driver is for the Mac OS, it will install itself and return.
; If it's another OS type (such as UNIX), it should take control of the machine
; and never return.
; <LW2>pdw thru next
or.l D6, D5 ; OR in control mask from client
jsr (a3) ; install the driver...
and.l #$00FFFFFF, D5 ; get rid of bit(s) that were in D6
; Make the System Heap growable by making the App Heap and TheZone the same zone as the System.
MOVE.L SysZone,A0 ; which zone is the system zone
MOVE.L A0,TheZone ; make THE REAL zone that zone
MOVE.L A0,ApplZone ; good-bye to the app zone (make it same zone)
MOVE.L bkLim(A0),HeapEnd ; end of System heap is now end of App Heap.
; <LW2>pdw from prev
ZeroExit
moveq.l #0,d0 ; assume success <A349/04Nov86>
bra.s OpenItRts ; <A349/04Nov86>
DisposExit
move.l a3,a0 ; restore ptr to driver <A349/04Nov86>
_DisposPtr ; get rid of bad driver <A349/04Nov86>
NonZeroExit
moveq.l #-1,d0 ; bad sig or checksum <A349/04Nov86>
OpenItRts
unlk a6 ; clean up <A311>
move.l (sp)+,d3 ; restore register <C478>
tst.w d0 ; set con. codes <C545>
rts
;---------------------------------------------------------------
;
; DoNewPartition -- This is called when the signature word on block 1
; matches the new partition map signature value. The first task is to
; look for the partition map block for the driver itself (which contains a
; checksum field, among other things). After we find one that matches the
; Mac driver information we found in block 0, we do a checksum on the
; driver (this helps to avoid loading garbage or trashed drivers, which
; will cause a sad Mac at bootup time). If the checksum is good, we try
; to find the first HFS partition entry in the partition map. If we pass
; all these stages, then we finally call the driver.
;
DoNewPartition ; new subroutine <A311>
cmp.l #'Appl',type+0(a2) ; 'Apple_Driver' type?
bne.s NextMapEntry
cmp.l #'e_Dr',type+4(a2)
bne.s NextMapEntry
cmp.l #'iver',type+8(a2)
bne.s NextMapEntry
cmp.l #'Maci',name+0(a2) ; 'Macintosh' name?
bne.s NextMapEntry ; only check 4 letters
move.l DriverStart(a6),d0 ; starting block of driver
cmp.l part_phys_blk(a2),d0 ; same driver from block 0?
bne.s NextMapEntry ; starts somewhere else...
move.l a3,a0 ; pointer to driver
move.l boot_size(a2),d1 ; size of driver (bytes)
bsr DoCksum ; put checksum in d0
cmp.l boot_cksum(a2),d0 ; matches saved value?
beq.s CkSumOK ; yes, so continue
bra.s DisposExit ; else remove driver <A349/04Nov86>
NextMapEntry
addq.l #1,CurMapBlk(a6) ; increment to next map block
move.l CurMapBlk(a6),d3 ; get updated value
cmp.l MapCnt(a6),d3 ; greater than maximum?
bhi.s CksumOK ; if so, just look for data partition
moveq.l #1,d2 ; read 1 block (from blk d3)
move.w #512,d4 ; block size
bsr.s SRead ; preserves a2 (ptr to block)
bne.s NextMapEntry ; error in read
cmp.w #PMSigWord,(a2) ; new partition entry?
bne.s NextMapEntry ; try another if not
bra.s DoNewPartition ; try to use this one
; We have validated this partition map entry as belonging to a Macintosh
; driver, and it has a good checksum (or none at all). Now we'll scan the
; list of partition map blocks again, this time looking for the first
; Macintosh HFS partition. If we find one, we'll load it, and call the
; driver, passing a pointer to it. If we don't find an HFS partition,
; then we deallocate the driver and continue with the next drive.
CkSumOK
moveq.l #0,d0 ; prime the loop variable
move.l d0,CurMapBlk(a6) ; save it
LookForDataPt
addq.l #1,CurMapBlk(a6) ; increment to next map block
move.l CurMapBlk(a6),d3 ; get updated value
cmp.l MapCnt(a6),d3 ; greater than maximum?
bhi.w DisposExit ; if so, we give up
moveq.l #1,d2 ; read 1 block (from blk d3)
move.w #512,d4 ; block size
bsr.s SRead ; preserves a2 (ptr to block)
bne.s LookForDataPt ; error in read
cmp.w #PMSigWord,(a2) ; new partition entry?
bne.s LookForDataPt ; try another if not
cmp.l #'Appl',type+0(a2) ; 'Apple_HFS' type?
bne.s LookForDataPt
cmp.l #'e_HF',type+4(a2)
bne.s LookForDataPt
cmp.b #'S',type+8(a2)
bne.s LookForDataPt
bra.w CallDriver ; finally got a data partition
;------------------------------------------------------------------
;
; Read block. d3 is block. d2 is block count. d4 is blocksize. d5 is unit.
; a2 is the transfer address. d6 used for a pointer into the stack.
; d7 is as follows: bit 31 is a retry flag, d7.w is the error code. <A349/04Nov86>
;
SRead
move.l d6,-(sp) ; save d6 <LW2>pdw
move.l d7,-(sp) ; save d7 <A349/04Nov86>
moveq.l #0,d7 ; clear flag & errcode <A349/04Nov86>
swap d2 ; save block count <C846>
move.w d4,d2 ; block size to LSW <C846>
SReadAgain
lea Scratch8,a0
move.b #8,(a0)+ ; read command
swap d3
andi.b #$1F,d3 ; isolate disk address
move.b d3,(a0)+ ; LUN and disk address
swap d3
move.w d3,(a0)+ ; disk address
move.l d2,d4 ; block count & size <C846>
swap d4 ; block count in low word
move.b d4,(a0)+ ; block count (byte) <C859>
clr.b (a0)+ ; cmdbyte
mulu.w d2,d4 ; size (d2) * count (d4) = total bytes
sub.w #(SCSIZE*2),sp ; make room for 2 commands...
move.l sp,d6 ; save this pointer...
subq.l #2,sp ; space for return value
_SCSIGet
move.w (sp),d7 ; error condition? <A349/04Nov86>
bne RdDone ; go report it <A349/04Nov86>
move.w d5,-(sp) ; selid
_SCSISelect
move.w (sp),d7 ; error condition? <A349/04Nov86>
bne RdDone ; go report it <A349/04Nov86> <SM5> CSS
pea Scratch8
move.w #6,-(sp) ; count
_SCSICmd
move.w (sp),d7 ; remember the result <A349/04Nov86>
bne.s Compl ; try to clean up <A349/04Nov86>
move.l d6,a0 ; point at command block
move.w #SCINC,(a0)+ ; read command
move.l a2,(a0)+ ; to this address
move.l d4,(a0)+ ; this many bytes
move.w #SCSTOP,(a0) ; then stop
move.l d6,-(sp) ; pass a pointer to this thing
_SCSIRead ; we'll save the error, <A349/04Nov86>
move.w (sp),d7 ; but still do completion
Compl
pea Scratch8 ; address for status byte
pea Scratch8+2 ; address for message byte
move.l #OneSecTicks,-(sp) ; wait up to one sec
_SCSIComplete
tst.w d7 ; error before complete? <A349/04Nov86>
beq.s ChkComplErr ; no, so continue <C846>
cmp.w #scPhaseErr,d7 ; phase error? <C846>
beq.s ChkStat ; yes, so check status <C846>
;
; Ignore SCSIComplete's phase error because it means it had <A349/04Nov86>
; to read extra bytes beyond the 512 requested to get to the
; Status phase. In the case of 532-byte sector sizes, we'll
; get this error each time during boot, so we want to ignore
; it. Note: the Mac+ SCSIMgr code doesn't signal this error.
;
ChkComplErr
move.w (sp),d7 ; check Complete ret code <A349/04Nov86>
cmp.w #scComplPhaseErr,d7 ; an error to ignore? <A349/04Nov86>
bne.s RdDone ; only ignore phase errors <A349/04Nov86>
ChkStat
move.w Scratch8,d7 ; SCSI command status byte
beq.s RdDone ; no error <A349/04Nov86>
cmp.w #2,d7 ; 'check condition' or 'busy' status? <H2>
beq.s @ChkOrBsy ; ...check condition <H2>
cmp.w #8,d7 ; ...busy condition <H2>
bne.l RdDone ; we got neither condition...bail <H2>
@ChkOrBsy
bset.l #31,d7 ; have we done a retry? <A349/04Nov86>
bne.s RdDone ; yes, so return <C770/07Feb87>
add.w #(SCSIZE*2)+2,sp ; clean up for retry... <C770/07Feb87>
bra.w SReadAgain ; try 1 more time only <C770/07Feb87>
RdDone
jsr ([jCacheFlush]) ; flush the cache <Z2>
add.w #(SCSIZE*2)+2,sp ; remove TIB and return value
move.w d7,d0 ; return error code <A349/04Nov86>
move.l (sp)+,d7 ; restore old d7 <A349/04Nov86>
move.l (sp)+,d6 ; restore old d6 <LW2>pdw
tst.w d0 ; test return value <A349/04Nov86>
rts
;-----------------------------------------------
;
; Checksum routine added <A311/31Oct86>. It uses the algorithm in the
; partition design document. On entry, a0 points to the driver and d1
; has the size in bytes (word quantity).
;
; Returns 16-bit checksum in d0. Destroys d1,d7,a0.
;
DoCksum
moveq.l #0,d0 ; initialize sum register
moveq.l #0,d7 ; zero-extended byte
bra.s CkDecr ; handle 0 bytes <A349/04Nov86>
CkLoop
move.b (a0)+,d7 ; get a byte
add.w d7,d0 ; add to checksum
rol.w #1,d0 ; and rotate
CkDecr
dbra d1,CkLoop ; next byte
tst.w d0 ; convert a checksum of 0
bne.s @1 ; into $FFFF (as per
subq.w #1,d0 ; algorithm description).
@1
rts
END