mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-22 23:29:27 +00:00
4325cdcc78
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.
662 lines
27 KiB
Plaintext
662 lines
27 KiB
Plaintext
;_______________________________________________________________________________________
|
|
;
|
|
; File: SCSILinkPatch.a
|
|
;
|
|
; Contains: New SCSI Manager linked patches. These patches are in addition to the
|
|
; SCSI Manager patches in the CPU specific patch files. The patches in
|
|
; this file are generally not CPU specific (except for perhaps the MacPlus).
|
|
;
|
|
; Written by: David Wong, December 11, 1990
|
|
;
|
|
; Copyright: © 1989-1992 by Apple Computer, Inc. All rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM6> 11/3/92 SWC Changed SCSIEqu.a->SCSI.a.
|
|
; <SM4> 8/11/92 CSS Update from Reality:
|
|
; <16> 8/10/92 csd #1035754 <gbm>: Added another cache flush to be more Õ040 studly
|
|
; and locked out interrupts while changing code that could get
|
|
; called at interrupt time.
|
|
; <15> 8/1/92 csd #1035754 <dty>: The delay patch in the previous version is not
|
|
; the best way to work around the problem. Instead, we change the
|
|
; number of blocks read so that we never read between 9 and 16
|
|
; blocks.
|
|
; <14> 7/31/92 csd #1035754 <dty>: Patch the SCSI drivers in RAM to add a delay in
|
|
; order to avoid the Quantum cache bug.
|
|
; <4> 3/3/92 kc Move TransactionFlag, and FreeHookPending into SCSIGlobals.
|
|
; <3> 2/12/92 RLM change jsr to jmp
|
|
; <2> 2/12/92 RLM InstallProc roll-in (SCSIC96Install & SCSIBusyPlusInstall). ¥
|
|
; Pre-SuperMario Comments Follow ¥
|
|
; <13> 11/25/91 DTY Roll in the SCSIBusy fix from 7-Up. Based on Dave WongÕs
|
|
; original code.
|
|
; <12> 10/28/91 SAM/KSM Rolled in Regatta changes.
|
|
; Put one of those semicolon things before a comment made in the
|
|
; last rev.
|
|
; (pdw,ag) Added SCSIC96Install proc to install 53c96 SCSIMgr
|
|
; changes.
|
|
; <11> 9/16/91 JSM Cleanup header.
|
|
; <10> 6/12/91 LN added #include 'InternalOnlyEqu.a'
|
|
; <9> 6/12/91 LN removed #include 'HardwareEqu.a'
|
|
; <8> 3/13/91 djw <wnm>(BRC #83534) I ignorantly did not know a TAS instruction
|
|
; does not work on all machines. Replaced it with a BSET.
|
|
; <7> 2/28/91 djw <dnf>(BRC #83534) Modify "free hook" patch to only call freehook
|
|
; at the end of a SCSI transaction. Fixed bug if out of range
|
|
; selector would crash.
|
|
; <6> 1/19/91 eh (eva for djw) don't load this patch under AUX
|
|
; <5> 12/20/90 djw call "SCSIFreeHook" through _DeferUserFn to make it VM friendly.
|
|
; Delete check on *BSY for _SCSIBusy (unreliable).
|
|
; <4> 12/15/90 djw Fixing comments and changing SCSIBusy to access SCSI chip more
|
|
; efficiently.
|
|
; <3> 12/14/90 dnf (with djw) Call SCSIFreeHook when freeing the bus. Fix stack
|
|
; problems in SCSIBusy.
|
|
; <2> 12/13/90 djw Added SCSIBusy and SCSIDispatch patches for file
|
|
; system/fileshare/CDROM problem.
|
|
; <1> 12/6/90 djw first checked in
|
|
;
|
|
|
|
;_______________________________________________________________________________________
|
|
;
|
|
; File Organization
|
|
;
|
|
; Additions to this file should be grouped together by patch, that is install and
|
|
; resident code together. Add newer patches to the end of the file. Please include
|
|
; a DETAILED description of the problem and the solution the patch addresses.
|
|
;_______________________________________________________________________________________
|
|
|
|
String Asis
|
|
Print Off
|
|
LOAD 'StandardEqu.d'
|
|
Include 'HardwarePrivateEqu.a'
|
|
Include 'SCSI.a'
|
|
Include 'SCSIPriv.a'
|
|
Include 'LinkedPatchMacros.a'
|
|
Include 'UniversalEqu.a' ; <2> ag
|
|
Print On
|
|
|
|
; ; <2> ag
|
|
; MACRO setTrapA0 &trapNumber
|
|
;
|
|
; Install the patch pointed to by A0 as trap &trapNumber.
|
|
; This handles OS traps and Toolbox traps by checking the toolbox bit.
|
|
;
|
|
|
|
MACRO
|
|
setTrapA0 &trapNumber
|
|
LCLA &realTrapNumber
|
|
&realTrapNumber: SETA &EVAL(&trapNumber)
|
|
IF (&realTrapNumber AND $800) = 0 THEN ; it is an OS trap
|
|
&realTrapNumber: SETA &realTrapNumber AND $FF
|
|
IF &realTrapNumber < 128 THEN
|
|
moveq #&realTrapNumber,d0 ; move trap number (sometimes sign extended)
|
|
ELSE
|
|
moveq #&realTrapNumber-$100,d0 ; move trap number (sometimes sign extended)
|
|
ENDIF
|
|
_SetTrapAddress newOS
|
|
ELSE
|
|
&realTrapNumber: SETA &realTrapNumber AND $3FF
|
|
IF &realTrapNumber < 128 THEN
|
|
moveq #&realTrapNumber,d0 ; move trap number
|
|
ELSE
|
|
move.w #&realTrapNumber,d0 ; move trap number
|
|
ENDIF
|
|
_SetTrapAddress newTool
|
|
ENDIF
|
|
ENDM
|
|
|
|
|
|
Roms Plus,SE,II,Portable,IIci,notAUX ; <6> djw
|
|
|
|
;=======================================================================================
|
|
|
|
;_______________________________________________________________________________________ <2> pdw
|
|
; Installer for new scsi manager code on machines with c96
|
|
;
|
|
|
|
export SCSIC96Install ;<RLM>
|
|
|
|
SCSIC96Install InstallProc (IIci,hasC96)
|
|
|
|
TestFor SCSI96_1Exists
|
|
beq.s @exit ; if this box doesn't have a c96, exit
|
|
|
|
leaResident SCSIMgr_96,a0 ; addr of vector
|
|
setTrapA0 $a815 ; patch SCSIDispatch to ROM
|
|
|
|
leaResident SCSIInit96,a0
|
|
jsr (a0)
|
|
|
|
@exit rts
|
|
Endp
|
|
|
|
;_______________________________________________________________________________________ <2> djw
|
|
; SCSIDispatch - fixes for FileShare problem
|
|
;
|
|
; Detailed description of the FileShare problem:
|
|
;
|
|
; FileShare has a deadlock problem which is caused by the SCSI manager not being
|
|
; asynchronous. The actual problem case was during system task time, the CDROM
|
|
; systemTask called the SCSI manager directly to polled the CDROM drive whether it
|
|
; has a disk insert event. While the SCSI manager is busy with this transaction, a
|
|
; level 4 (SCC) interrupt occurs for fileshare. At interrupt time, fileshare makes
|
|
; an async file system I/O call which is to a SCSI device (hard drive). The SCSI
|
|
; driver calls _SCSIGet, and gets an error - SCSI manager busy. The driver then
|
|
; loops waiting for the SCSI manager to become free. This will never happen because
|
|
; the SCSI manager at event time has been interrupted and cannot complete until we
|
|
; return from interrupt - deadlock.
|
|
;
|
|
; The solution (short of a real async SCSI manager) is for the file system to check
|
|
; that the SCSI manager is free before processing its I/O request. If the SCSI
|
|
; manager is busy, then the file system will queue the request and defer it. When
|
|
; the SCSI manager becomes free, it will call the file system to run its deferred
|
|
; I/O. This solution has the undesirable effect of gating file system I/O on the
|
|
; SCSI manager whether or not the target device is SCSI.
|
|
;
|
|
; SCSIDispatch will be patched for two reasons: The addition of a new private
|
|
; selector routine _SCSIBusy to be called only by the file system; and a call a new
|
|
; "hook" vector "jSCSIFreeHook" at the end of a SCSI transaction when the SCSI Mgr
|
|
; is free.
|
|
;
|
|
; The "jSCSIFreeHook" is defined to be called at the end of a SCSI transaction. A
|
|
; normal SCSI transaction is defined to begin with SCSIGet and end with SCSIComplete.
|
|
; A SCSI transaction may be aborted and considered ended without calling SCSIComplete
|
|
; only when SCSISelect returns an error. An error from SCSISelect means the you never
|
|
; got on the bus.
|
|
;
|
|
;_______________________________________________________________________________________
|
|
; Detailed description of the "jSCSIFreeHook and HDSC Setup problem
|
|
;
|
|
; Calling "jSCSIFreeHook" in the FileShare problem case, will result in calling the
|
|
; file system. The file system in turn may call the SCSI driver to do a deferred
|
|
; file I/O. If the SCSI bus is busy when this happens, the driver will loop waiting
|
|
; for the bus to clear. While the driver is looping, the system will hang. We
|
|
; do not check for the bus being clear before calling "jSCSIFreeHook", because it may
|
|
; be some unknown number of milliseconds before this happens, and we would slow down
|
|
; every transaction. The rule for calling "jSCSIFreeHook" is to only call at the END
|
|
; of a transaction because we know the bus is becoming free.
|
|
;
|
|
; There is a problem in calling SCSIComplete multiple times. Normally SCSIComplete
|
|
; signals an end to the transaction. As long as the bus is free or is going to be
|
|
; free, calling SCSIComplete is ok. However, there was a case where during a format,
|
|
; HDSC Setup called SCSIComplete multiple times to determine whether the drive was
|
|
; still formatting. This meant the bus was still busy and the system hung. The bus
|
|
; never became free because we were looping in the driver and HDSC Setup could not
|
|
; call SCSIComplete again to get the status. The fix was to change HDSC Setup to
|
|
; not use SCSIComplete as its status call. Until async SCSI operations, hopefully
|
|
; only formatting will cause this problem.
|
|
;
|
|
;_______________________________________________________________________________________
|
|
; Mac Plus SCSIBusy Installer - Install routine to get SCSIGlobals on MacPlus
|
|
;
|
|
|
|
If not forRom then ; <4> kc.start
|
|
|
|
SCSIBusyPlusInstall InstallProc (Plus)
|
|
|
|
leaResident SCSIBusyVector,a0 ; addr of vector
|
|
leaResident SCSIBusyPlus,a1 ; addr of routine valid on mac plus
|
|
move.l a1,(a0) ; install vector
|
|
rts
|
|
Endp
|
|
|
|
;_______________________________________________________________________________________
|
|
; Other Macs SCSIBusy Installer - Install routine to get SCSIGlobals on other Macs
|
|
;
|
|
|
|
SCSIBusyOtherInstall InstallProc (SE,Portable,II,IIci,notAUX) ; <6> djw
|
|
|
|
leaResident SCSIBusyVector,a0 ; addr of vector
|
|
leaResident SCSIBusyOthers,a1 ; addr of routine valid on all other macs
|
|
move.l a1,(a0) ; install vector
|
|
rts
|
|
Endp
|
|
Endif ; <4> kc.end
|
|
|
|
;_______________________________________________________________________________________
|
|
; Common SCSIDispatch
|
|
;
|
|
; Insert ourselve in the return chain so that after we call the existing SCSI
|
|
; manager, we will return here to check for busy. Because the SCSI manager is
|
|
; stack based, we must shift the stack and insert our return address.
|
|
|
|
SCSIDispatchCommon PatchProc _SCSIDispatch,(Plus,SE,Portable,II,IIci,notAUX) ; <6> djw
|
|
|
|
Export SCSIBusyPlus
|
|
Export SCSIBusyOthers
|
|
|
|
with ExpandMemRec
|
|
|
|
;=====================================================
|
|
; Head patch to check for the new scsiBusy selector
|
|
;=====================================================
|
|
|
|
cmpi.w #scsiBusy,4(sp) ; check selector after the return addr
|
|
bne.s @Continue ; not scsiBusy
|
|
|
|
movea.l (sp)+,a0 ; pop a0 = return addr
|
|
adda.w #2,sp ; pop selector
|
|
If forRom then ; <4> kc.start
|
|
With scsiGlobalRecord
|
|
movea.l SCSIGlobals, a1 ; addr of record
|
|
lea TransactionFlag(a1),a1 ; is the SCSI Mgr free?
|
|
EndWith
|
|
Else
|
|
lea TransactionFlag(pc),a1 ; is the SCSI Mgr free?
|
|
Endif ; <4> kc.end
|
|
move.w (a1),(sp) ; return transaction flag on stack
|
|
jmp (a0) ; done
|
|
|
|
; Check for the selector being in range
|
|
|
|
@Continue
|
|
moveq.l #0,d0
|
|
move.w 4(sp),d0 ; d0 = scsi selector
|
|
cmpi.w #numSelectors,d0 ; valid selector?
|
|
bhs.s @CallOld ; out of range - let the ROM handle it
|
|
|
|
;===================================================================================
|
|
; Head patch for "jSCSIFreeHook" and "TransactionFlag"
|
|
;
|
|
; Only patch selectors indicated by the table "TransFlagTbl". Call through to
|
|
; the ROM to handle the other selectors.
|
|
;===================================================================================
|
|
|
|
lea TransFlagTbl,a0 ; get bit flag table address
|
|
tst.b (a0,d0.w) ; any flags set?
|
|
bne.s @SetUpPatch ; flags set - do the patch
|
|
|
|
@CallOld
|
|
|
|
if forROM then ;<RLM>
|
|
import SCSIMgr ;<RLM>
|
|
jmp SCSIMgr ;<RLM> <3>
|
|
else
|
|
jmpOld ; wrong selector - call old scsimgr
|
|
endif ;<RLM>
|
|
|
|
;===================================================================================
|
|
; Setup for "jSCSIFreeHook" and "TransactionFlag" patches
|
|
;
|
|
; "jsr" into the ROM to execute the SCSI selector and return to this patch.
|
|
; Because the SCSI manager is stack based, we must shift the parameters 6 bytes on
|
|
; the stack to make room for our return address and for saving the SCSI selector
|
|
; (while not disturbing the stack parameters).
|
|
;===================================================================================
|
|
|
|
@SetUpPatch
|
|
btst.b #fSetTransFlag,(a0,d0.w) ; are we setting the transaction flag?
|
|
beq.s @ContinueSetup ; no - just continue
|
|
If forRom then ; <4> kc.start
|
|
With scsiGlobalRecord
|
|
movea.l SCSIGlobals, a1 ; addr of record
|
|
lea TransactionFlag(a1),a1 ; is the SCSI Mgr free?
|
|
EndWith
|
|
Else
|
|
lea TransactionFlag(pc),a1 ; is the SCSI Mgr free?
|
|
Endif ; <4> kc.end
|
|
addq.w #1,(a1) ; inc the transaction flag now
|
|
|
|
@ContinueSetup
|
|
lea ParamSizeTable,a0 ; get table of paramblk sizes
|
|
add.l d0,d0 ; index words
|
|
move.w (a0,d0),d0 ; d0 = parameter block size
|
|
|
|
subq.l #2,sp ; make room for saving scsi selector
|
|
movea.l sp,a1 ; a1 = destination reg
|
|
move.l 2(a1),d1 ; d1 = original return addr
|
|
movea.l a1,a0 ; a0 = source reg
|
|
addq.w #6,a0 ; shift parameters (4byte ret_addr,2byte selector)
|
|
|
|
@Loop
|
|
move.w (a0)+,(a1)+ ; shift the stack
|
|
dbra d0,@Loop
|
|
move.l d1,(a1)+ ; orig return addr after params
|
|
move.w (sp),(a1) ; save scsi selector above return addr
|
|
|
|
; Call the old _SCSIDispatch code and return
|
|
|
|
|
|
if forROM then ;<RLM>
|
|
import SCSIMgr ;<RLM>
|
|
jsr SCSIMgr ;<RLM>
|
|
else
|
|
jsrOld ; call the old _SCSIDispatch
|
|
endif ;<RLM>
|
|
|
|
|
|
; On return, the stack has the function result code, the original return address,
|
|
; and the saved selector. Get the saved selector for later and move the result
|
|
; code to where the selector was. The return address is in the right place.
|
|
|
|
move.w 6(sp),d0 ; need SCSIDispatch selector for table lookup
|
|
move.w (sp)+,4(sp) ; move function result code, ret addr is in place
|
|
|
|
;========================================================================================
|
|
; Check if "TransactionFlag" should be cleared
|
|
;========================================================================================
|
|
|
|
lea TransFlagTbl,a0 ; addr of bit flag table
|
|
btst.b #fClearTransFlag,(a0,d0) ; do we unconditionally clear the flag?
|
|
bne.s @ClearFlag
|
|
btst.b #fClearTransErr,(a0,d0) ; do we clear only on an error result?
|
|
beq.s @CheckFreeHook ; no - check for executing the freehook
|
|
tst.w 4(sp) ; check the function result
|
|
beq.s @CheckFreeHook ; just check the freehook
|
|
@ClearFlag
|
|
If forRom then ; <4> kc.start
|
|
With scsiGlobalRecord
|
|
movea.l SCSIGlobals, a1 ; addr of record
|
|
lea TransactionFlag(a1),a1 ; is the SCSI Mgr free?
|
|
EndWith
|
|
Else
|
|
lea TransactionFlag(pc),a1 ; is the SCSI Mgr free?
|
|
Endif ; <4> kc.end
|
|
tst.w (a1) ; is it already zero?
|
|
beq.s @alreadyZero
|
|
subq.w #1,(a1) ; clear the transaction flag
|
|
@alreadyZero
|
|
|
|
;========================================================================================
|
|
; Check if "jSCSIFreeHook" should be called
|
|
;
|
|
; Check if the SCSI manager is free (TransactionFlag). The SCSI manager should only
|
|
; be free on error conditions during SCSISelect, or after SCSIComplete. The SCSI bus
|
|
; is allowed to still be busy at this point, but should require no additional intervention
|
|
; from the processor (a device could just be slow getting off the bus). SCSISelect
|
|
; with errors, and SCSIComplete should leave the bus in a condition of becoming free.
|
|
;
|
|
; If SCSIComplete returns with a timeout error, then the SCSI manager will be free, but
|
|
; the bus may still be busy. In this case, the "jSCSIFreeHook" will not be called.
|
|
;========================================================================================
|
|
|
|
@CheckFreeHook
|
|
btst.b #fDoFreeHook,(a0,d0) ; do we execute the freehook?
|
|
beq.s @Done ; no - we are done
|
|
If forRom then ; <4> kc.start
|
|
With scsiGlobalRecord
|
|
movea.l SCSIGlobals, a1 ; addr of record
|
|
lea TransactionFlag(a1),a1 ; is the SCSI Mgr free?
|
|
EndWith
|
|
Else
|
|
lea TransactionFlag(pc),a1 ; is the SCSI Mgr free?
|
|
Endif ; <4> kc.end
|
|
tst.w (a1) ; test flag
|
|
bne.s @Done ; scsi mgr busy - done
|
|
|
|
;========================================================================================
|
|
; SCSI manager is free - call the routine which runs "jSCSIFreeHook".
|
|
;
|
|
; A routine is executed through _DeferUserFn (to allow VM page fault processing) which
|
|
; actually executes the "jSCSIFreeHook". The reason why a routine is used instead of
|
|
; running "jSCSIFreeHook" directly, is so that we only have one outstanding call to
|
|
; "jSCSIFreeHook" at a time. So the routine is after the _DeferUserFn so we know it
|
|
; has run.
|
|
;========================================================================================
|
|
|
|
If forRom then ; <4> kc.start
|
|
With scsiGlobalRecord
|
|
movea.l SCSIGlobals, a0 ; addr of record
|
|
lea FreeHookPending(a0),a0 ; get address of freehook pending flag
|
|
EndWith
|
|
Else
|
|
lea FreeHookPending(pc),a0 ; get address of freehook pending flag
|
|
Endif ; <4> kc.end
|
|
bset.b #0,(a0) ; test and set the freehook pending flag <8> djw
|
|
bne.s @Done ; one already pending - done
|
|
|
|
lea PostFreeHook,a0 ; get addr of routine to execute
|
|
_DeferUserFn ; execute deferred
|
|
|
|
@Done
|
|
rts
|
|
|
|
;========================================================================================
|
|
; PostFreeHook routine
|
|
;
|
|
; This routine is executed through _DeferUserFn to run the "jSCSIFreeHook". This
|
|
; routine will clear the FreeHookPending flag so that other SCSI completions will
|
|
; generate calls to "jSCSIFreeHook".
|
|
|
|
PostFreeHook
|
|
movea.l ExpandMem,a0 ; a0 = ptr to expand mem
|
|
move.l jSCSIFreeHook(a0),d0 ; d0 = SCSI free vector
|
|
beq.s @Done ; no freehook to execute
|
|
movea.l d0,a0
|
|
jsr (a0) ; execute "jSCSIFreeHook"
|
|
@Done
|
|
If forRom then ; <4> kc.start
|
|
With scsiGlobalRecord
|
|
movea.l SCSIGlobals, a0 ; addr of record
|
|
lea FreeHookPending(a0),a0 ; get address of freehook pending flag
|
|
EndWith
|
|
Else
|
|
lea FreeHookPending(pc),a0 ; get address of freehook pending flag
|
|
Endif ; <4> kc.end
|
|
clr.b (a0) ; clear pending flag
|
|
rts
|
|
|
|
endwith
|
|
|
|
;_______________________________________________________________________________________
|
|
; SCSIBusyPlus - return G_State on a MacPlus
|
|
;
|
|
; WARNING...WARNING...WARNING... if the SCSIDispatch patch in the MacPlus patch file
|
|
; changes, then the equate @G_State may become invalid.
|
|
;
|
|
|
|
SCSIBusyPlus
|
|
|
|
@G_State Equ $23 ; offset in MacPlus SCSI dispatcher to G_State global
|
|
@scsiRd Equ $580000 ; read base addr of NCR5380 on Plus
|
|
|
|
leaOld a0 ; a0 = addr of patched _SCSIDispatch
|
|
move.b @G_State(a0),d0 ; d0 = G_State byte embedded in system patch
|
|
movea.l #@scsiRd,a1 ; hard coded read base addr for SCSI chip
|
|
bra SCSIBusyCommon
|
|
|
|
;_______________________________________________________________________________________
|
|
; SCSIBusyOthers - return G_State on Macs other than a Plus
|
|
;
|
|
with SCSIGlobalRecord
|
|
|
|
SCSIBusyOthers
|
|
movea.l SCSIGlobals,a0 ; a0 = ptr to SCSI global record
|
|
move.b G_State(a0),d0 ; d0 = G_State byte
|
|
movea.l SCSIBase,a1 ; read base of SCSI hardware supported by lowmem
|
|
; fall through to SCSIBusyCommon
|
|
|
|
; SCSIBusy common routine - a1 = read base addr of SCSI chip, d0 = G_State busy bit
|
|
|
|
SCSIBusyCommon
|
|
andi.w #$01,d0 ; mask only busy bit from G_State
|
|
; <djw> moveq.l #$40,d1 ; mask for current bus status
|
|
; <djw> and.b sCSR(a1),d1 ; read and mask current bus status register
|
|
; <djw> rol.b #2,d1 ; get BSY bit (bit 6) to bit 0
|
|
; <djw> or.b d1,d0 ; if either SCSI mgr or bus is busy then return busy
|
|
movea.l (sp)+,a0 ; pop a0 = return addr
|
|
adda.w #2,sp ; pop selector
|
|
move.w d0,(sp) ; result on stack
|
|
jmp (a0) ; done
|
|
|
|
endwith
|
|
|
|
If not forRom then ; <4> kc.start
|
|
;_______________________________________________________________________________________
|
|
; Pending freehook call flag, and ParamSizeTable
|
|
;
|
|
; The ParamSizeTable contains the number of words of arguments passed to _SCSIDispatch
|
|
; for each of the various selectors. The count includes any arguments, the result
|
|
; word, and the selector word. The count does not include the return address on the
|
|
; stack. The count is then adjusted for a "dbra" loop count. The FreeHookPending
|
|
; flag is set if an outstanding "jSCSIFreeHook" call has been posted to _DeferUserFn.
|
|
; The flag is check before posting any calls to _DeferUserFn. This prevents overflowing
|
|
; VM's defered function queue.
|
|
;
|
|
; In SuperMario, this is part of SCSIGlobals.
|
|
|
|
FreeHookPending dc.l 0 ; location of pending free-hook flag
|
|
SCSIBusyVector dc.l 0
|
|
|
|
Endif ; <4> kc.end
|
|
ParamSizeTable ; parameters on stack in words + selector + result - dbra
|
|
dc.w 2-1 ; selector 0 SCSIReset
|
|
dc.w 2-1 ; 1 SCSIGet
|
|
dc.w 3-1 ; 2 SCSISelect
|
|
dc.w 5-1 ; 3 SCSICmd
|
|
dc.w 8-1 ; 4 SCSIComplete
|
|
dc.w 4-1 ; 5 SCSIRead
|
|
dc.w 4-1 ; 6 SCSIWrite
|
|
dc.w 2-1 ; 7 SCSIInstall (unused)
|
|
dc.w 4-1 ; 8 SCSIRBlind
|
|
dc.w 4-1 ; 9 SCSIWBlind
|
|
dc.w 2-1 ; 10 SCSIStat
|
|
dc.w 3-1 ; 11 SCSISelAtn
|
|
dc.w 4-1 ; 12 SCSIMsgIn
|
|
dc.w 3-1 ; 13 SCSIMsgOut
|
|
|
|
If not forRom then ; <4> kc.start
|
|
;_______________________________________________________________________________________
|
|
; SCSI Transaction Flag table and transaction flag
|
|
;
|
|
; The TransFlagTbl is an array of bit flags which indicate whether: to execute
|
|
; the "jSCSIFreeHook" vector; to set the "TransactionFlag"; to clear the
|
|
; "TransactionFlag".
|
|
;
|
|
; In SuperMario, this is part of SCSIGlobals.
|
|
|
|
TransactionFlag dc.w 0 ; location to store SCSI transaction flag
|
|
|
|
Endif ; <4> kc.end
|
|
|
|
TransFlagTbl
|
|
dc.b (1<<fDoFreeHook)+(1<<fClearTransFlag) ; 0 SCSIReset
|
|
dc.b (1<<fSetTransFlag)+(1<<fClearTransErr) ; 1 SCSIGet
|
|
dc.b (1<<fClearTransErr)+(1<<fDoFreeHook) ; 2 SCSISelect
|
|
dc.b 0 ; 3 SCSICmd
|
|
dc.b (1<<fDoFreeHook)+(1<<fClearTransFlag) ; 4 SCSIComplete
|
|
dc.b 0 ; 5 SCSIRead
|
|
dc.b 0 ; 6 SCSIWrite
|
|
dc.b 0 ; 7 SCSIInstall (unused)
|
|
dc.b 0 ; 8 SCSIRBlind
|
|
dc.b 0 ; 9 SCSIWBlind
|
|
dc.b 0 ; 10 SCSIStat
|
|
dc.b (1<<fClearTransErr)+(1<<fDoFreeHook) ; 11 SCSISelAtn
|
|
dc.b 0 ; 12 SCSIMsgIn
|
|
dc.b 0 ; 13 SCSIMsgOut
|
|
|
|
|
|
Endp ; end SCSIDispatchCommon
|
|
|
|
|
|
;_______________________________________________________________________________________ <2> djw
|
|
;
|
|
PatchSCSIDrivers InstallProc (Plus,SE,Portable,II,IIci)
|
|
|
|
JSROpcode equ $4EB9
|
|
NOPOpcode equ $4E714E71
|
|
LowestDriverVersion equ $0026
|
|
HighestDriverVersion equ $0029
|
|
BlockPinningFirstLong equ $0C820000
|
|
BlockPinning2ndLong equ $01006308
|
|
scsiVersion equ -$E
|
|
|
|
leaResident SCSIPatchToBlockIOInDriver, A2 ; pointer to patch code
|
|
move.l A2, D0 ; so we can strip it
|
|
_StripAddress ; we might get called in 32-bit mode
|
|
move.l D0, A2 ; clean version of the address
|
|
|
|
move.l UTableBase, A0 ; pointer to unit table
|
|
add.l #32 * 4, A0 ; entry #32 * sizeof(DCEHandle)
|
|
|
|
moveq #7, D4 ; 8 possible scsi drivers
|
|
|
|
@checkSCSIDriverLoop
|
|
move.l (A0), D1 ; get DCEHandle for this driver
|
|
bz.s @nextSCSIDriver ; no driver here, try the next one
|
|
move.l D1, A1 ; DCEHandle for this driver
|
|
move.l (A1),A1 ; get the DCE
|
|
btst #dRAMBased, dCtlFlags+1(A1) ; do we have a handle or pointer?
|
|
move.l dCtlDriver(A1), A1 ; handle or pointer
|
|
bz.s @havePointer ; skip the deref if dRAMBased=0
|
|
move.l (A1), A1 ; get pointer to RAM driver
|
|
@havePointer
|
|
move.w scsiVersion(A1), D1 ; version field for AppleÕs SCSI driver
|
|
sub.w #LowestDriverVersion, D1 ; normalize $27-$29 => $0-$2
|
|
bmi.s @nextSCSIDriver ; bail if earlier than $27
|
|
cmp.w #HighestDriverVersion-LowestDriverVersion, D1 ; check high end of supported versions
|
|
bgt.s @nextSCSIDriver ; bail if later than $29
|
|
|
|
add.w D1, D1 ; times 2 for sizeof(word)
|
|
move.w OffsetsToBlockPinningInDriver(PC, D1), D2 ; get offset to patch location
|
|
|
|
cmpi.l #BlockPinningFirstLong, (A1, D2.w) ; is the data what we expect?
|
|
bne.s @nextSCSIDriver
|
|
cmpi.l #BlockPinning2ndLong, 4(A1, D2.w) ; is the second long correct?
|
|
bne.s @nextSCSIDriver
|
|
|
|
; Change the driver to call our patch
|
|
|
|
add.w D2, A1
|
|
move SR, -(SP) ; save current state of the world
|
|
ori.w #$0700, SR ; weÕre not safe for page faults
|
|
move.w #JSROpcode, (A1)+ ; patch in a JSR
|
|
move.l A2, (A1)+ ; patch in operand
|
|
|
|
; The patch does the entire block pinning that the driver did, so NOP out these instructions
|
|
; after the JSR to our patch.
|
|
|
|
moveq #2, D1
|
|
@blastSomeInstructionsLoop
|
|
move.l #NOPOpcode, (A1)+
|
|
dbra D1, @blastSomeInstructionsLoop
|
|
_FlushDataCache ; we wrote into a copyback cache
|
|
_FlushInstructionCache ; we changed code
|
|
move (SP)+, SR ; weÕre safe for page faults again
|
|
|
|
@nextSCSIDriver
|
|
addq #4, A0 ; point to next DCEPtr in the unit table
|
|
dbra D4, @checkSCSIDriverLoop ; do the rest of the SCSI drivers
|
|
rts
|
|
|
|
OffsetsToBlockPinningInDriver
|
|
dc.w $0CA8 ; Offset to offending code in driver version $26
|
|
dc.w $0CA8 ; Offset to offending code in driver version $27
|
|
dc.w $0CA8 ; Offset to offending code in driver version $28
|
|
dc.w $1046 ; Offset to offending code in driver version $29
|
|
EndProc
|
|
|
|
; The Quantum firmware has a bug where the cache gets corrupt after a read of 10 to 15
|
|
; blocks if another read comes in after a certain amount of time. Our patch changes the
|
|
; SCSI driver so that we never read 10 to 15 blocks. If a read request in this range
|
|
; comes in, break the read down into two reads of 9 blocks and change.
|
|
;
|
|
; Register usage:
|
|
; D2 -> count (number of blocks remaining to be read. Could be > 256.)
|
|
; D3 -> wrflag (non zero if driver is doing a write.)
|
|
; D5 <- nb (number of blocks to be read in this pass. Must be ² 256.)
|
|
|
|
SCSIPatchToBlockIOInDriver Proc Export
|
|
|
|
SCSISmallestSafeBlock equ 9
|
|
SCSILargestSafeBlock equ 16
|
|
SCSILargestIOBlockSize equ 256
|
|
|
|
move.l D2,D5 ; Potential number of blocks to read in this pass
|
|
tst.w D3 ; Are we reading or writing?
|
|
bnz.s @pinBlocksToReadOrWriteTo256 ; If weÕre writing, just pin the blocks to 256
|
|
cmp.l #SCSISmallestSafeBlock, D2 ; Are we reading less than 10 blocks?
|
|
bls.s @rejoinDriver ; Yeah. Go back to the driver
|
|
cmp.l #SCSILargestSafeBlock, D2 ; Are we reading more than 15 blocks?
|
|
bhs.s @pinBlocksToReadOrWriteTo256 ; Yes. This read is safe. Go make sure weÕre not reading more than 256 blocks
|
|
move.l #SCSISmallestSafeBlock, D5 ; WeÕre reading 10 to 15 blocks. Read only 9. (WeÕll get the rest on the next pass.)
|
|
bra.s @rejoinDriver ; Go back to the driver
|
|
@pinBlocksToReadOrWriteTo256 ; Make sure we donÕt operate on more than 256 blocks in a pass
|
|
cmp.l #SCSILargestIOBlockSize, D2 ; Are we operating on more than 256 blocks?
|
|
bls.s @rejoinDriver ; No. Get on with it.
|
|
move.l #SCSILargestIOBlockSize, D5 ; Pin the operation to 256 blocks.
|
|
@rejoinDriver
|
|
rts ; Go back to the driver. (D5 = nb)
|
|
|
|
;=======================================================================================
|
|
;=======================================================================================
|
|
|
|
End |