sys7.1-doc-wip/OS/SCSIMgr/SCSIBoot.a
2019-07-27 22:37:48 +08:00

550 lines
21 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; 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