mirror of
https://github.com/LIV2/at_apollo_device.git
synced 2025-12-06 06:32:49 +00:00
6681 lines
240 KiB
ArmAsm
6681 lines
240 KiB
ArmAsm
;******************************************************************************
|
||
;****** ******
|
||
;****** "AT-Apollo.device" v5.03 driver source ******
|
||
;****** ******
|
||
;****** ---------------------------------------------------------------- ******
|
||
;****** ******
|
||
;****** (c) Copyright 1996-2023 Fr<46>d<EFBFBD>ric REQUIN ******
|
||
;****** ******
|
||
;******************************************************************************
|
||
|
||
;******** Usage under PowerVisor v1.42 ********
|
||
;>mode no more
|
||
;>log main ram:scsi.log
|
||
;>log
|
||
|
||
;CPU020 SET 1
|
||
;DEBUG SET 1
|
||
;SERDBG SET 1
|
||
;PROTECT SET 1
|
||
PVDBG = 0
|
||
|
||
incdir "AINCLUDE:"
|
||
include "exec/ables.i"
|
||
include "exec/devices.i"
|
||
include "exec/errors.i"
|
||
include "exec/execbase.i"
|
||
include "exec/interrupts.i"
|
||
include "exec/initializers.i"
|
||
include "exec/memory.i"
|
||
include "exec/resident.i"
|
||
include "exec/tasks.i"
|
||
include "hardware/intbits.i"
|
||
include "hardware/ata_apollo.i"
|
||
include "hardware/ata_ident.i"
|
||
include "hardware/ata_regs.i"
|
||
include "devices/apollo_at.i"
|
||
include "devices/cd.i"
|
||
include "devices/hardblocks.i"
|
||
include "devices/newstyle.i"
|
||
include "devices/timer.i"
|
||
include "devices/trackdisk.i"
|
||
include "devices/scsicmds.i"
|
||
include "devices/scsidisk.i"
|
||
include "libraries/configvars.i"
|
||
include "lvo/exec.i"
|
||
include "lvo/expansion.i"
|
||
include "lvo/pv.i"
|
||
include "lvo/timer.i"
|
||
|
||
;---------------
|
||
;Constants used:
|
||
;---------------
|
||
|
||
BLOCK_SIZE = 512 ;Block/sector size (in bytes)
|
||
CONST_NUM = $082C ;Manufacturer : BSC
|
||
PRODUCT_COMBI = $22 ;AT + SCSI + memory card (not used here)
|
||
PRODUCT_ATA = $6 ;AT-Bus IDE card
|
||
|
||
ATA_TimeOut = 500000
|
||
ATAPI_TimeOut = 1000000
|
||
|
||
IFD DEBUG
|
||
Debug
|
||
move.l 4.w,a6
|
||
lea ApolloRomTag(pc),a1
|
||
moveq #0,d1
|
||
jsr _LVOInitResident(a6)
|
||
|
||
move.l d0,a6
|
||
lea IoStd(pc),a1
|
||
moveq #0,d0
|
||
moveq #0,d1
|
||
bsr.w Open
|
||
|
||
lea IoStd(pc),a1
|
||
move.l IO_DEVICE(a1),a6
|
||
move.w #CMD_READ,IO_COMMAND(a1)
|
||
move.l #BLOCK_SIZE*16,IO_LENGTH(a1)
|
||
move.l #Buffer,IO_DATA(a1)
|
||
move.l #0,IO_OFFSET(a1)
|
||
bset #IOB_QUICK,IO_FLAGS(a1)
|
||
bsr.w BeginIO
|
||
|
||
lea IoStd(pc),a1
|
||
move.l IO_DEVICE(a1),a6
|
||
move.w #CMD_READ,IO_COMMAND(a1)
|
||
move.l #BLOCK_SIZE*16,IO_LENGTH(a1)
|
||
move.l #Buffer,IO_DATA(a1)
|
||
move.l #0,IO_OFFSET(a1)
|
||
bset #IOB_QUICK,IO_FLAGS(a1)
|
||
bra.w BeginIO
|
||
|
||
lea IoStd(pc),a1
|
||
lea ScsiCmd(pc),a2
|
||
move.l IO_DEVICE(a1),a6
|
||
|
||
move.w #HD_SCSICMD,IO_COMMAND(a1)
|
||
move.l #scsi_SIZEOF,IO_LENGTH(a1)
|
||
move.l a2,IO_DATA(a1)
|
||
bset #IOB_QUICK,IO_FLAGS(a1)
|
||
|
||
move.l #Buffer,scsi_Data(a2)
|
||
move.l #BLOCK_SIZE*16,scsi_Length(a2)
|
||
move.l #Command,scsi_Command(a2)
|
||
move.w #10,scsi_CmdLength(a2)
|
||
|
||
bra.w BeginIO
|
||
|
||
IoStd
|
||
blk.b IOSTD_SIZE,0
|
||
ScsiCmd
|
||
blk.b scsi_SIZEOF,0
|
||
Command
|
||
dc.b $28,$00,$00,$00,$01,$00,$00,$00,$04,$00
|
||
Buffer
|
||
blk.b BLOCK_SIZE*16,$55
|
||
|
||
ENDC
|
||
|
||
ProgStart
|
||
moveq #0,d0
|
||
rts
|
||
|
||
ApolloRomTag
|
||
dc.w RTC_MATCHWORD
|
||
dc.l ApolloRomTag
|
||
dc.l EndRomTag
|
||
dc.b RTF_AUTOINIT
|
||
dc.b 5 ;Version
|
||
dc.b NT_DEVICE ;Node type
|
||
dc.b 0 ;Priority
|
||
dc.l ATName
|
||
dc.l IDString
|
||
dc.l Init
|
||
Init
|
||
dc.l ad_SIZEOF ;Device structure size
|
||
dc.l FuncTable ;Functions table
|
||
dc.l DataTable ;Data to initialize
|
||
dc.l InitRoutine ;Init routine
|
||
|
||
;*************** Device initialization table **********************************
|
||
|
||
DataTable
|
||
INITBYTE LN_TYPE,NT_DEVICE ;LN_TYPE = NT_DEVICE
|
||
INITLONG LN_NAME,ATName ;LN_NAME = ATName
|
||
INITBYTE LIB_FLAGS,LIBF_CHANGED!LIBF_SUMUSED
|
||
INITWORD LIB_VERSION,5
|
||
INITWORD LIB_REVISION,3
|
||
INITLONG LIB_IDSTRING,IDString
|
||
dc.w 0
|
||
|
||
;*************** Device verification through checksum *************************
|
||
|
||
IFD PROTECT
|
||
Cks
|
||
dc.l $11111111
|
||
|
||
NumLong
|
||
dc.w (EndRomTag-NumLong)/4-1
|
||
ENDC
|
||
|
||
;*************** Device functions table ****************************************
|
||
|
||
FuncTable
|
||
dc.w -1 ;Relative pointers
|
||
dc.w Open-FuncTable ;OpenDevice() call
|
||
dc.w Close-FuncTable ;CloseDevice() call
|
||
dc.w Expunge-FuncTable ;Expunge() call
|
||
dc.w Null-FuncTable ;Not used
|
||
dc.w BeginIO-FuncTable ;BeginIO() call
|
||
dc.w AbortIO-FuncTable ;AbortIO() call
|
||
dc.w GetRdskLba-FuncTable ;Not standard : RDB sector number
|
||
dc.w GetBlkSize-FuncTable ;Not standard : sector size
|
||
dc.w Null-FuncTable ;Not used
|
||
dc.w -1
|
||
|
||
ATName
|
||
dc.b "AT-Apollo.device",0
|
||
dc.b "$VER: "
|
||
IDString
|
||
dc.b "AT-Apollo.device 5.03 (8 Dec 1999 F.Requin)",13,10,0
|
||
CDName
|
||
dc.b "Apollo device rewrite by F. Requin",0
|
||
TaskName
|
||
dc.b "AT-Apollo.task",0
|
||
DaemonName
|
||
dc.b "AT-Apollo.daemon",0
|
||
ExpansionName
|
||
dc.b "expansion.library",0
|
||
TimerName
|
||
dc.b "timer.device",0
|
||
|
||
IFD SERDBG
|
||
DbgInitMess
|
||
dc.b "init",10,0
|
||
DbgDev0Mess
|
||
dc.b "dev0",10,0
|
||
DbgDev1Mess
|
||
dc.b "dev1",10,0
|
||
DbgDev2Mess
|
||
dc.b "dev2",10,0
|
||
DbgDev3Mess
|
||
dc.b "dev3",10,0
|
||
DbgEndMess
|
||
dc.b "end scan",10,0
|
||
DbgTaskMess
|
||
dc.b "task",10,0
|
||
DbgDaemonMess
|
||
dc.b "daemon",10,0
|
||
DbgOpenMess
|
||
dc.b "open *",10,0
|
||
DbgUnitMess
|
||
dc.b "init *",10,0
|
||
DbgBusOkMess
|
||
dc.b "bus ok",10,0
|
||
DbgSelectMess
|
||
dc.b "select",10,0
|
||
DbgReadyMess
|
||
dc.b "ready",10,0
|
||
DbgDetectMess
|
||
dc.b "detect",10,0
|
||
ENDC
|
||
|
||
even
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Device initialization routine ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;D0.l : AT-Apollo.device base address
|
||
;A0.l : AmigaDos SegList
|
||
;A4.l : expansion.library base address
|
||
;A6.l : ExecBase
|
||
|
||
InitRoutine
|
||
movem.l d1-d7/a0-a5,-(sp)
|
||
move.l d0,a5 ;A5 : AT-Apollo.device base address
|
||
move.l a6,ad_SysLib(a5) ;Save ExecBase
|
||
move.l a0,ad_SegList(a5) ;Save SegList
|
||
|
||
IFD SERDBG
|
||
movem.l a0-a3/d0/d1,-(sp)
|
||
lea DbgInitMess(pc),a0
|
||
sub.l a1,a1
|
||
lea _LVORawPutChar(a6),a2
|
||
sub.l a3,a3
|
||
jsr _LVORawDoFmt(a6)
|
||
movem.l (sp)+,a0-a3/d0/d1
|
||
ENDC
|
||
|
||
;*************** Checksum test ************************************************
|
||
|
||
IFD PROTECT
|
||
lea FuncTable(pc),a0
|
||
move.l Cks(pc),d0
|
||
move.w NumLong(pc),d1
|
||
.CheckLoop
|
||
add.l (a0)+,d0
|
||
dbra d1,.CheckLoop
|
||
tst.l d0
|
||
beq.b .CksOk
|
||
move.l #$BADC0DE,d7
|
||
jsr _LVOAlert(a6)
|
||
bra.w .Error
|
||
.CksOk
|
||
ENDC
|
||
|
||
;*************** Memory allocation ********************************************
|
||
|
||
moveq #MAX_UNIT*4,d0
|
||
move.l #(MEMF_PUBLIC!MEMF_CLEAR),d1
|
||
jsr _LVOAllocMem(a6)
|
||
move.l d0,ad_CfgDevAddr(a5)
|
||
beq.w .Error
|
||
move.l d0,a4 ;A4 : 16-pointer array of
|
||
; "ConfigDev" structures
|
||
|
||
moveq #MAX_UNIT*4,d0
|
||
move.l #MEMF_PUBLIC!MEMF_CLEAR,d1
|
||
jsr _LVOAllocMem(a6)
|
||
move.l d0,ad_BoardAddr(a5)
|
||
beq.w .Error
|
||
move.l d0,a3 ;A3 : 16-pointer array of
|
||
; board base addresses
|
||
|
||
moveq #MAX_UNIT,d0
|
||
move.l #MEMF_PUBLIC!MEMF_CLEAR,d1
|
||
jsr _LVOAllocMem(a6)
|
||
move.l d0,ad_DevMaskArray(a5)
|
||
beq.w .Error
|
||
move.l d0,a2 ;A2 : 16-byte array of
|
||
; device selection masks
|
||
|
||
;*************** Opening "timer.device" ***************************************
|
||
|
||
moveq #IOTV_SIZE,d0
|
||
move.l #MEMF_PUBLIC!MEMF_CLEAR,d1
|
||
jsr _LVOAllocMem(a6)
|
||
move.l d0,ad_TimerIO(a5)
|
||
beq.w .Error
|
||
|
||
lea TimerName(pc),a0 ;A0: "timer.device"
|
||
move.l d0,a1 ;A1: timerequest structure
|
||
moveq #UNIT_VBLANK,d0 ;D0: Precision : 1/50th second
|
||
moveq #0,d1 ;D1: Flags
|
||
jsr _LVOOpenDevice(a6) ;Open device
|
||
tst.l d0 ;Everything went well ?
|
||
bne.w .Error ;No, end of init
|
||
|
||
;*************** Opening "expansion.library" **********************************
|
||
|
||
lea ExpansionName(pc),a1
|
||
moveq #0,d0
|
||
jsr _LVOOpenLibrary(a6)
|
||
tst.l d0
|
||
beq.w .Error
|
||
move.l d0,a6 ;A6 : ExpansionBase
|
||
|
||
;*************** Scanning of "Apollo" cards and drives ************************
|
||
|
||
moveq #0,d7 ;Unit number = 0
|
||
moveq #0,d5 ;Controller number = 0
|
||
sub.l a0,a0 ;Start of "ConfigDev" list
|
||
.Loop
|
||
move.l #CONST_NUM,d0 ;Manufacturer ID
|
||
moveq #-1,d1 ;Any product ID
|
||
jsr _LVOFindConfigDev(a6)
|
||
tst.l d0
|
||
beq.w .End ;0 : no more card, end of loop
|
||
move.l d0,a0 ;A0 : "ConfigDev" structure
|
||
move.b cd_Rom+er_Product(a0),d0 ;D0 : Product ID
|
||
cmpi.b #PRODUCT_ATA,d0 ;AT card?
|
||
beq.b .FoundProd ;Yes, continue
|
||
cmpi.b #PRODUCT_COMBI,d0 ;AT + SCSI card ?
|
||
bne.b .Loop ;No, next card
|
||
|
||
.FoundProd
|
||
; move.l cd_Unused(a0),d0 ;D0 : Special identifier
|
||
; cmpi.l #'APOL',d0 ;Apollo controller ON ?
|
||
; beq.b .FoundCtrl ;Yes, continue
|
||
; cmpi.l #'APOX',d0 ;Apollo controller OFF ?
|
||
; bne.b .Loop ;No, next card
|
||
|
||
.FoundCtrl
|
||
move.l #113,cd_Unused+4(a0)
|
||
lea CDName(pc),a1
|
||
move.l a1,LN_NAME(a0) ;"ConfigDev" structure name
|
||
move.l a5,cd_Driver(a0) ;Device address
|
||
move.l cd_BoardAddr(a0),a1 ;A1 : First IDE port address
|
||
add.l #ata_DataPort,a1
|
||
|
||
;*************** Primary connector auto-detect ********************************
|
||
|
||
IFD SERDBG
|
||
movem.l a0-a3/a6/d0/d1,-(sp)
|
||
move.l ad_SysLib(a5),a6
|
||
lea DbgDev0Mess(pc),a0
|
||
sub.l a1,a1
|
||
lea _LVORawPutChar(a6),a2
|
||
sub.l a3,a3
|
||
jsr _LVORawDoFmt(a6)
|
||
movem.l (sp)+,a0-a3/a6/d0/d1
|
||
ENDC
|
||
|
||
move.b #ATAF_MASTER,d6 ;Disk #0 (master)
|
||
bsr.w TestDevice ;Test if drive is present
|
||
beq.b .NoMaster1
|
||
|
||
bsr.w TestMirror ;D<>codage incomplet ?
|
||
beq.b .NoSlave1 ;Yes, no slave present
|
||
|
||
IFD SERDBG
|
||
movem.l a0-a3/a6/d0/d1,-(sp)
|
||
move.l ad_SysLib(a5),a6
|
||
lea DbgDev1Mess(pc),a0
|
||
sub.l a1,a1
|
||
lea _LVORawPutChar(a6),a2
|
||
sub.l a3,a3
|
||
jsr _LVORawDoFmt(a6)
|
||
movem.l (sp)+,a0-a3/a6/d0/d1
|
||
ENDC
|
||
|
||
.NoMaster1
|
||
move.b #ATAF_SLAVE,d6 ;Disk #1 (slave)
|
||
bsr.w TestDevice ;Test if drive is present
|
||
|
||
.NoSlave1
|
||
addq.b #1,d5 ;Next controller
|
||
bsr.w TestPort2 ;4-IDE interface present ?
|
||
bne.b .Loop ;No, next Apollo card
|
||
|
||
;*************** Secondary connector auto-detect ******************************
|
||
|
||
lea ata_NextPort(a1),a1 ;Yes, second IDE port address
|
||
|
||
IFD SERDBG
|
||
movem.l a0-a3/a6/d0/d1,-(sp)
|
||
move.l ad_SysLib(a5),a6
|
||
lea DbgDev2Mess(pc),a0
|
||
sub.l a1,a1
|
||
lea _LVORawPutChar(a6),a2
|
||
sub.l a3,a3
|
||
jsr _LVORawDoFmt(a6)
|
||
movem.l (sp)+,a0-a3/a6/d0/d1
|
||
ENDC
|
||
|
||
move.b #ATAF_MASTER,d6 ;Disk #0 (master)
|
||
bsr.w TestDevice ;Test if drive is present
|
||
beq.b .NoMaster2
|
||
|
||
bsr.w TestMirror ;Incomplete decoding ?
|
||
beq.b .NoSlave2 ;Yes, no slave present
|
||
|
||
IFD SERDBG
|
||
movem.l a0-a3/a6/d0/d1,-(sp)
|
||
move.l ad_SysLib(a5),a6
|
||
lea DbgDev3Mess(pc),a0
|
||
sub.l a1,a1
|
||
lea _LVORawPutChar(a6),a2
|
||
sub.l a3,a3
|
||
jsr _LVORawDoFmt(a6)
|
||
movem.l (sp)+,a0-a3/a6/d0/d1
|
||
ENDC
|
||
|
||
.NoMaster2
|
||
move.b #ATAF_SLAVE,d6 ;Disk #1 (slave)
|
||
bsr.w TestDevice ;Test if drive is present
|
||
|
||
.NoSlave2
|
||
addq.b #1,d5 ;Next controller
|
||
bra.w .Loop ;Next Apollo card
|
||
|
||
;*************** End : closing "expansion.library" ****************************
|
||
|
||
.End
|
||
IFD SERDBG
|
||
movem.l a0-a3/a6/d0/d1,-(sp)
|
||
move.l ad_SysLib(a5),a6
|
||
lea DbgEndMess(pc),a0
|
||
sub.l a1,a1
|
||
lea _LVORawPutChar(a6),a2
|
||
sub.l a3,a3
|
||
jsr _LVORawDoFmt(a6)
|
||
movem.l (sp)+,a0-a3/a6/d0/d1
|
||
ENDC
|
||
|
||
move.l a6,a1 ;A1 : ExpansionBase
|
||
move.l ad_SysLib(a5),a6 ;A6 : ExecBase
|
||
jsr _LVOCloseLibrary(a6) ;Close the library
|
||
|
||
;*************** Closing "timer.device" ***************************************
|
||
|
||
move.l ad_TimerIO(a5),a1 ;A1 : timerequest
|
||
jsr _LVOCloseDevice(a6) ;Close the device
|
||
|
||
move.l ad_TimerIO(a5),a1 ;A1 : timerequest
|
||
moveq #IOTV_SIZE,d0 ;D0 : Size
|
||
jsr _LVOFreeMem(a6) ;Free the memory
|
||
|
||
;*************** Start the device tasks ***************************************
|
||
|
||
move.w d7,ad_NumUnits(a5) ;Number of detected units
|
||
beq.b .Error ;No unit : error
|
||
|
||
IFD SERDBG
|
||
movem.l a0-a3/a6/d0/d1,-(sp)
|
||
move.l ad_SysLib(a5),a6
|
||
lea DbgTaskMess(pc),a0
|
||
sub.l a1,a1
|
||
lea _LVORawPutChar(a6),a2
|
||
sub.l a3,a3
|
||
jsr _LVORawDoFmt(a6)
|
||
movem.l (sp)+,a0-a3/a6/d0/d1
|
||
ENDC
|
||
|
||
bsr.b InitTask ;Apollo task initialization
|
||
beq.b .Error ;Error : exit
|
||
|
||
IFD SERDBG
|
||
movem.l a0-a3/a6/d0/d1,-(sp)
|
||
move.l ad_SysLib(a5),a6
|
||
lea DbgDaemonMess(pc),a0
|
||
sub.l a1,a1
|
||
lea _LVORawPutChar(a6),a2
|
||
sub.l a3,a3
|
||
jsr _LVORawDoFmt(a6)
|
||
movem.l (sp)+,a0-a3/a6/d0/d1
|
||
ENDC
|
||
|
||
bsr.w InitDaemon ;Apollo deamon initialization
|
||
beq.b .Error ;Error : exit
|
||
|
||
move.l a5,d0 ;Return the device's pointer
|
||
movem.l (sp)+,d1-d7/a0-a5 ;Restore registers
|
||
rts ;End
|
||
|
||
;*************** Error : return a null pointer ********************************
|
||
|
||
.Error
|
||
moveq #0,d0 ;Return a null pointer
|
||
movem.l (sp)+,d1-d7/a0-a5 ;Restore registers
|
||
rts ;End
|
||
|
||
;;*****************************************************************************
|
||
;******** ********
|
||
;******** Initialize the device task ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A5.l : AT-Apollo.device base address
|
||
;A6.l : ExecBase
|
||
|
||
;Return value:
|
||
;-------------
|
||
;Z Flag (0:Ok, 1:Error)
|
||
|
||
InitTask
|
||
movem.l a2/a3,-(sp) ;Save A2 & A3
|
||
|
||
;*************** Memory allocation of the "TaskData" structure ****************
|
||
|
||
move.l #td_SIZEOF,d0 ;Memory allocation
|
||
move.l #MEMF_PUBLIC!MEMF_CLEAR,d1 ;for "Unit" & "Task" structures
|
||
jsr _LVOAllocMem(a6) ;and for the task's stack
|
||
move.l d0,ad_TaskData(a5) ;Save the pointer
|
||
beq.b .Error ;Null pointer : error
|
||
move.l d0,a2 ;A2 : "TaskData" structure
|
||
lea td_Task(a2),a1 ;A1 : "Task" structure
|
||
lea td_Stack(a2),a0 ;A0 : Task's stack
|
||
|
||
;*************** Initialization of the task's stack ***************************
|
||
|
||
move.l a0,TC_SPLOWER(a1) ;Lower limit
|
||
lea STACK_SIZE(a0),a0 ;+ Stack size
|
||
move.l a0,TC_SPUPPER(a1) ;Upper limit
|
||
move.l a5,-(a0) ;Save the device address on the stack
|
||
move.l a0,TC_SPREG(a1) ;Current stack pointer
|
||
|
||
;*************** Initialization of the message list ***************************
|
||
|
||
lea MP_MSGLIST+LH_HEAD(a2),a0
|
||
move.l a0,LH_TAILPRED(a0) ;lh_TailPred = &lh_Head;
|
||
addq.l #LH_TAIL,a0
|
||
clr.l (a0) ;lh_Tail = NULL;
|
||
move.l a0,-(a0) ;lh_Head = &lh_Tail;
|
||
|
||
;*************** Initialization of "Task" & "MsgPort" structures **************
|
||
|
||
lea TaskName(pc),a0
|
||
move.l a0,LN_NAME(a1) ;Node name
|
||
move.b #NT_TASK,LN_TYPE(a1) ;Node type : Task
|
||
move.b #5,LN_PRI(a1) ;Priority : 5
|
||
|
||
move.l a1,MP_SIGTASK(a2) ;Task to wake-up : the device
|
||
lea ATName(pc),a0
|
||
move.l a0,LN_NAME(a2) ;Node name
|
||
moveq #NT_MSGPORT,d0
|
||
move.b d0,LN_TYPE(a2) ;Node type : MessagePort
|
||
moveq #PA_IGNORE,d0
|
||
move.b d0,MP_FLAGS(a2) ;Flags : ignore messages
|
||
|
||
;*************** Add the task to Exec's task list *****************************
|
||
|
||
lea TaskCode(pc),a2 ;A2: Start of execution
|
||
sub.l a3,a3 ;A3: End of execution
|
||
jsr _LVOAddTask(a6) ;Add the task to Exec's list
|
||
|
||
moveq #1,d0 ;Flag Z=0 : Ok
|
||
movem.l (sp)+,a2/a3 ;Restore registers
|
||
rts ;End
|
||
|
||
.Error
|
||
moveq #0,d0 ;Flag Z=1 : Error
|
||
movem.l (sp)+,a2/a3 ;Restore registers
|
||
rts ;End
|
||
|
||
;;*****************************************************************************
|
||
;******** ********
|
||
;******** Initialize the device diskchange deamon ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A5.l : AT-Apollo.device base address
|
||
;A6.l : ExecBase
|
||
|
||
;Return value:
|
||
;-------------
|
||
;Z Flag (0:Ok, 1:Error)
|
||
|
||
InitDaemon
|
||
movem.l a2/a3,-(sp) ;Save A2 & A3
|
||
|
||
;*************** Memory allocation ********************************************
|
||
|
||
move.l #dd_SIZEOF,d0 ;Structure size
|
||
move.l #MEMF_PUBLIC!MEMF_CLEAR,d1 ;Public memory, cleared
|
||
jsr _LVOAllocMem(a6) ;Memory allocation
|
||
move.l d0,ad_DaemonData(a5) ;Save the pointer
|
||
beq.b .Error ;Null pointer : error
|
||
|
||
;*************** Initialization of the "DeamonData" structure *****************
|
||
|
||
move.l d0,a1 ;A1 : "DeamonData" structure
|
||
lea dd_Stack(a1),a0 ;A0 : Task's stack
|
||
|
||
move.l a0,TC_SPLOWER(a1) ;Lower limit
|
||
lea STACK_SIZE(a0),a0 ;+ Stack size
|
||
move.l a0,TC_SPUPPER(a1) ;Upper limit
|
||
move.l a5,-(a0) ;Save the device address on the stack
|
||
move.l a0,TC_SPREG(a1) ;Current stack pointer
|
||
|
||
lea DaemonName(pc),a0
|
||
move.l a0,LN_NAME(a1) ;Task's name
|
||
move.b #NT_TASK,LN_TYPE(a1) ;Node type : Task
|
||
move.b #5,LN_PRI(a1) ;Priority : 5
|
||
|
||
;*************** Add the task to Exec's tasks list ****************************
|
||
|
||
lea DaemonCode(pc),a2 ;Start of code
|
||
lea -1,a3 ;End of code : address Error
|
||
jsr _LVOAddTask(a6) ;Add the task
|
||
|
||
moveq #1,d0 ;Flag Z=0: Ok
|
||
movem.l (sp)+,a2/a3 ;Restore registers
|
||
rts ;End
|
||
|
||
.Error
|
||
moveq #0,d0 ;Flag Z=1: Error
|
||
movem.l (sp)+,a2/a3 ;Restore registers
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Read/write caches memory allocate ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A3.l : ApolloUnit base address
|
||
;A6.l : ExecBase
|
||
|
||
AllocCache
|
||
tst.b au_RCacheOn(a3) ;Read cache activated ?
|
||
beq.b .NoReadCache ;No, skip read cache memory allocate
|
||
|
||
;*************** Read cache memory allocate ***********************************
|
||
|
||
move.l au_RCacheSize(a3),d0 ;D0: Number of buffers
|
||
move.b au_SectShift(a3),d1 ;D1: Block size
|
||
lsl.l d1,d0 ;D0 x D1 = Cache size
|
||
moveq #0,d1 ;Any memory type
|
||
jsr _LVOAllocMem(a6) ;Memory allocation
|
||
move.l d0,au_RCacheAddr(a3) ;Save the cache address
|
||
beq.b .Error ;No memory : exit
|
||
move.b #4,au_RCacheCount(a3) ;4 reads before cache fetch
|
||
moveq #-1,d0
|
||
move.l d0,au_RCacheBlock(a3) ;Cache not valid
|
||
|
||
.NoReadCache
|
||
tst.b au_WCacheOn(a3) ;Write cache activated ?
|
||
beq.b .NoWriteCache ;No, skip write cache memory allocate
|
||
tst.b au_DevType(a3) ;Direct access peripheral ?
|
||
bne.b .NoWriteCache ;No, skip write cache memory allocate
|
||
|
||
;*************** Write cache memory allocate : tags & flags *******************
|
||
|
||
moveq #1,d2
|
||
add.w au_WCacheSize(a3),d2 ;D2: Number of buffers
|
||
move.w d2,d0
|
||
mulu #(ct_SIZEOF+cf_SIZEOF),d0 ;D0: Cache size
|
||
move.l #MEMF_PUBLIC!MEMF_CLEAR,d1 ;Public memory, cleared
|
||
jsr _LVOAllocMem(a6) ;Memory allocation
|
||
move.l d0,au_WCacheTags(a3) ;Save tags address
|
||
beq.b .Error ;No memory : exit
|
||
move.l d0,a2 ;A2: Tags address
|
||
mulu #ct_SIZEOF,d2 ;D2: Flags offset
|
||
add.l d2,d0
|
||
move.l d0,au_WCacheFlags(a3) ;Save flags address
|
||
|
||
;*************** Write cache memory allocate : buffers ************************
|
||
|
||
addq.l #ct_Data,a2
|
||
move.w au_WCacheSize(a3),d2 ;D2: Number of buffers - 1
|
||
.Loop
|
||
move.l au_SectSize(a3),d0 ;D0: Block size
|
||
moveq #0,d1 ;Any memory type
|
||
jsr _LVOAllocMem(a6) ;Memory allocation
|
||
move.l d0,(a2) ;Save the buffer address
|
||
beq.b .Error ;No memory : exit
|
||
addq.l #ct_SIZEOF,a2 ;Next buffer
|
||
dbra d2,.Loop ;Loop
|
||
|
||
.NoWriteCache
|
||
moveq #1,d0 ;Flag Z=0: Ok
|
||
.Error
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Read/Write caches memory de-allocate ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A3.l : ApolloUnit base address
|
||
;A6.l : ExecBase
|
||
|
||
FreeCache
|
||
move.l au_WCacheTags(a3),d3 ;Write cache activated ?
|
||
beq.b .NoWriteCache ;No, skip write cache memory de-allocate
|
||
|
||
;*************** Write cache buffers de-allocate ******************************
|
||
|
||
move.l d3,a2 ;A2: Tags address
|
||
addq.l #ct_Data,a2
|
||
move.w au_WCacheSize(a3),d2 ;D2: Number of buffers - 1
|
||
.Loop
|
||
move.l (a2),d0 ;D0: Buffer address
|
||
beq.b .Empty ;Null, exit from the loop
|
||
move.l d0,a1 ;A1: Buffer address to free-up
|
||
move.l au_SectSize(a3),d0 ;D0: Size of the memory to free-up
|
||
jsr _LVOFreeMem(a6) ;Free the memory
|
||
clr.l (a2) ;Clear the pointer
|
||
addq.l #ct_SIZEOF,a2 ;Next buffer
|
||
dbra d2,.Loop ;Loop
|
||
|
||
;*************** Write cache Flags & Tags de-allocate *************************
|
||
|
||
.Empty
|
||
move.l d3,a1 ;A1: Flags & Tags address
|
||
moveq #1,d0
|
||
add.w au_WCacheSize(a3),d0 ;D0: Number of buffers
|
||
mulu #(ct_SIZEOF+cf_SIZEOF),d0 ;Size of the memory to free-up
|
||
jsr _LVOFreeMem(a6) ;Free the memory
|
||
clr.l au_WCacheTags(a3)
|
||
clr.l au_WCacheFlags(a3) ;Clear the pointers
|
||
sf.b au_WCacheOn(a3) ;Clear the flag
|
||
|
||
.NoWriteCache
|
||
move.l au_RCacheAddr(a3),d0 ;Read cache activated ?
|
||
beq.b .NoReadCache ;No, skip read cache memory de-allocate
|
||
|
||
;*************** Read cache memory de-allocate ********************************
|
||
|
||
move.l d0,a1 ;A1: Read cache address
|
||
move.l au_RCacheSize(a3),d0 ;D0: Number of buffers
|
||
move.b au_SectShift(a3),d1 ;D1: Block size
|
||
lsl.l d1,d0 ;D0 x D1 = Cache size
|
||
jsr _LVOFreeMem(a6) ;Free the memory
|
||
clr.l au_RCacheAddr(a3) ;Clear the pointer
|
||
sf.b au_RCacheOn(a3) ;Clear the flag
|
||
|
||
.NoReadCache
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Device opening routine ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;D0.l : Unit number
|
||
;D1.l : Flags
|
||
;A1.l : Standard I/O Request
|
||
;A6.l : AT-Apollo.device base address
|
||
|
||
Open
|
||
IFD SERDBG
|
||
movem.l a0-a3/a6/d0/d1,-(sp)
|
||
move.l ad_SysLib(a6),a6
|
||
lea DbgOpenMess(pc),a0
|
||
addi.b #'0',d0
|
||
move.b d0,5(a0)
|
||
sub.l a1,a1
|
||
lea _LVORawPutChar(a6),a2
|
||
sub.l a3,a3
|
||
jsr _LVORawDoFmt(a6)
|
||
movem.l (sp)+,a0-a3/a6/d0/d1
|
||
ENDC
|
||
|
||
movem.l d2/a2-a4,-(sp)
|
||
move.l a1,a2 ;A2 : Standard I/O Request
|
||
move.l a6,IO_DEVICE(a2) ;Device pointer
|
||
cmp.w ad_NumUnits(a6),d0 ;Unit number too high ?
|
||
bcc.b .Error ;Yes, error
|
||
|
||
move.w d0,d2 ;D2 : Unit number
|
||
|
||
;-------- 68000 --------
|
||
IFND CPU020
|
||
add.w d0,d0
|
||
add.w d0,d0 ;Unit number x 4
|
||
lea ad_Units(a6,d0.w),a4
|
||
ENDC
|
||
|
||
;-------- 68020+ --------
|
||
IFD CPU020
|
||
lea ad_Units(a6,d0.w*4),a4
|
||
ENDC
|
||
|
||
move.l (a4),d0 ;"ApolloUnit" structure pointer
|
||
bne.b .AlreadyInit ;Not null : structure already initialized
|
||
bsr.b InitUnit ;Otherwise, initialize the structure
|
||
move.l (a4),d0
|
||
beq.b .Error ;Still null : error
|
||
.AlreadyInit
|
||
move.l d0,a3 ;A3 : "ApolloUnit" structue
|
||
move.l d0,IO_UNIT(a2) ;Save the pointer
|
||
addq.w #1,LIB_OPENCNT(a6) ;Increment both counters
|
||
addq.w #1,au_OpenCount(a3) ;(Device & Unit)
|
||
bclr #LIBB_DELEXP,ad_Flags(a6) ;Clear the "Expunge" flag
|
||
moveq #0,d0 ;No error
|
||
.End
|
||
move.b d0,IO_ERROR(a2) ;End
|
||
movem.l (sp)+,d2/a2-a4
|
||
rts
|
||
.Error
|
||
moveq #IOERR_OPENFAIL,d0 ;Error : opening has failed
|
||
bra.b .End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Device closing routine ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;A1.l : Standard I/O Request
|
||
;A6.l : AT-Apollo.device base address
|
||
|
||
Close
|
||
move.l a2,-(sp) ;Save A2
|
||
move.l IO_UNIT(a1),a2 ;A2 : "ApolloUnit" structure
|
||
|
||
moveq #-1,d0 ;Forbid I/O structure use
|
||
move.l d0,IO_UNIT(a1) ;by putting -1
|
||
move.l d0,IO_DEVICE(a1) ;in both fields
|
||
|
||
subq.w #1,au_OpenCount(a2) ;Decrease the open counter
|
||
subq.w #1,LIB_OPENCNT(a6) ;(Device & Unit)
|
||
bne.b .End ;Not the last close ?
|
||
btst #LIBB_DELEXP,ad_Flags(a6) ;"Expunge" flag set ?
|
||
beq.b .End ;No
|
||
bsr.b Expunge ;Yes
|
||
.End
|
||
moveq #0,d0 ;End, return null
|
||
move.l (sp)+,a2 ;Restore A2
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Device expunge routine ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;A6.l : AT-Apollo.device base address
|
||
|
||
Expunge
|
||
bset #LIBB_DELEXP,ad_Flags(a6) ;Set the "Expunge" flag
|
||
Null
|
||
moveq #0,d0 ;End, return null
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** ApolloUnit initialization ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;D2.w : Unit number
|
||
;A2.l : Standard I/O Request
|
||
;A6.l : AT-Apollo.device base address
|
||
|
||
InitUnit
|
||
IFD SERDBG
|
||
movem.l a0-a3/a6/d0/d1,-(sp)
|
||
move.l ad_SysLib(a6),a6
|
||
lea DbgUnitMess(pc),a0
|
||
move.b d2,d0
|
||
addi.b #'0',d0
|
||
move.b d0,5(a0)
|
||
sub.l a1,a1
|
||
lea _LVORawPutChar(a6),a2
|
||
sub.l a3,a3
|
||
jsr _LVORawDoFmt(a6)
|
||
movem.l (sp)+,a0-a3/a6/d0/d1
|
||
ENDC
|
||
|
||
movem.l d1-d7/a0-a6,-(sp)
|
||
|
||
move.l a6,a5 ;A5: AT-Apollo.device base address
|
||
move.l ad_SysLib(a5),a6 ;A6: ExecBase
|
||
|
||
;*************** "ApolloUnit" structure initialization ************************
|
||
|
||
move.l #au_SIZEOF,d0 ;D0: ApolloUnit structure size
|
||
move.l #MEMF_PUBLIC!MEMF_CLEAR,d1 ;Public memory, cleared
|
||
jsr _LVOAllocMem(a6) ;Allocate memory for ApolloUnit
|
||
tst.l d0
|
||
beq.w .End ;Out of memory error : exit
|
||
|
||
move.l d0,a3 ;A3: ApolloUnit base address
|
||
move.b d2,au_UnitNumber(a3) ;Unit number
|
||
move.l a5,au_Device(a3) ;AT-Apollo.device base address
|
||
|
||
move.w #$4EF9,d0 ;JMP instruction
|
||
move.w d0,au_ReadJmp(a3)
|
||
move.w d0,au_WriteJmp(a3)
|
||
move.w d0,au_FormatJmp(a3)
|
||
move.w d0,au_SeekJmp(a3)
|
||
move.w d0,au_EjectJmp(a3)
|
||
move.w d0,au_ScsiJmp(a3) ;Jump table initialization
|
||
|
||
lea au_SoftList(a3),a0 ;Interrupts list
|
||
move.l a0,LH_TAILPRED(a0)
|
||
addq.l #LH_TAIL,a0
|
||
clr.l (a0)
|
||
move.l a0,-(a0) ;The list is empty
|
||
|
||
move.l ad_DevMaskArray(a5),a0 ;ATA/ATAPI device mask
|
||
move.b (a0,d2.w),d0 ;for "ata_DevHead" register
|
||
move.b d0,d1
|
||
|
||
btst #ATAB_LBA,d0 ;LBA addressing ?
|
||
beq.b .NoLBA ;No, skip
|
||
st.b au_LBAMode(a3) ;Yes, set au_LBAMode flag
|
||
.NoLBA
|
||
|
||
bset #ATAB_ATAPI,d0 ;ATAPI drive ?
|
||
beq.b .Ata ;No, skip
|
||
|
||
;-------- 68000 --------
|
||
IFND CPU020
|
||
move.l #ATAPI_TimeOut,au_NumLoop(a3) ;Number of loops for BUSY
|
||
ENDC
|
||
|
||
;-------- 68020+ --------
|
||
IFD CPU020
|
||
move.l #ATAPI_TimeOut*8,au_NumLoop(a3) ;Number of loops x 8 for BUSY
|
||
ENDC
|
||
|
||
lea atapi_Read(pc),a0
|
||
move.l a0,au_ReadSub(a3) ;Read routine
|
||
lea atapi_Write(pc),a0
|
||
move.l a0,au_WriteSub(a3) ;Write routine
|
||
lea atapi_Write(pc),a0
|
||
move.l a0,au_FormatSub(a3) ;Format routine
|
||
lea atapi_Seek(pc),a0
|
||
move.l a0,au_SeekSub(a3) ;Seek routine
|
||
lea atapi_Eject(pc),a0
|
||
move.l a0,au_EjectSub(a3) ;Eject routine
|
||
lea atapi_ScsiCmd(pc),a0
|
||
move.l a0,au_ScsiSub(a3) ;SCSI-Direct routine
|
||
|
||
st.b au_AtapiDev(a3) ;au_AtapiDev set
|
||
st.b au_LBAMode(a3) ;au_LBAMode set
|
||
bra.b .Atapi
|
||
|
||
.Ata
|
||
;-------- 68000 --------
|
||
IFND CPU020
|
||
move.l #ATA_TimeOut,au_NumLoop(a3) ;Number of loops for BUSY
|
||
ENDC
|
||
|
||
;-------- 68020+ --------
|
||
IFD CPU020
|
||
move.l #ATA_TimeOut*8,au_NumLoop(a3) ;Number of loops x 8 for BUSY
|
||
ENDC
|
||
|
||
lea ata_SlowReadNorm(pc),a0
|
||
move.l a0,au_ReadSub(a3) ;Read routine
|
||
lea ata_SlowWriteNorm(pc),a0
|
||
move.l a0,au_WriteSub(a3) ;Write routine
|
||
lea ata_SlowWriteNorm(pc),a0
|
||
move.l a0,au_FormatSub(a3) ;Format routine
|
||
lea ata_Seek(pc),a0
|
||
move.l a0,au_SeekSub(a3) ;Seek routine
|
||
lea ata_Eject(pc),a0
|
||
move.l a0,au_EjectSub(a3) ;Eject routine
|
||
lea ata_ScsiCmd(pc),a0
|
||
move.l a0,au_ScsiSub(a3) ;SCSI-Direct routine
|
||
|
||
.Atapi
|
||
andi.b #%11110000,d0 ;Keep the selection bits
|
||
move.b d0,au_DevMask(a3) ;Unit select mask (ATA & ATAPI)
|
||
|
||
andi.b #ATAF_DEV,d0
|
||
move.b d0,au_OldDevMask(a3) ;Unit select mask (ATA only)
|
||
|
||
andi.b #%00001111,d1 ;Keep the controller number
|
||
move.b d1,au_CtrlNumber(a3)
|
||
|
||
;-------- 68000 --------
|
||
IFND CPU020
|
||
move.w d2,d1 ;D1 : Unit number
|
||
add.w d1,d1
|
||
add.w d1,d1 ;Unit number x 4
|
||
ENDC
|
||
|
||
move.l ad_CfgDevAddr(a5),a0 ;"ConfigDev" structure address
|
||
|
||
;-------- 68020+ --------
|
||
IFND CPU020
|
||
move.l (a0,d1.w),au_CfgDevAddr(a3) ;"ConfigDev" linked to the unit
|
||
ENDC
|
||
|
||
;-------- 68020+ --------
|
||
IFD CPU020
|
||
move.l (a0,d2.w*4),au_CfgDevAddr(a3) ;"ConfigDev" linked to the unit
|
||
ENDC
|
||
|
||
move.l ad_BoardAddr(a5),a0 ;Board address
|
||
|
||
;-------- 68000 --------
|
||
IFND CPU020
|
||
move.l (a0,d1.w),au_PortAddr(a3) ;IDE port linked to the unit
|
||
ENDC
|
||
|
||
;-------- 68020+ --------
|
||
IFD CPU020
|
||
move.l (a0,d2.w*4),au_PortAddr(a3) ;IDE port linked to the unit
|
||
ENDC
|
||
|
||
bsr.w UnitInfo ;Retrieve the unit info
|
||
beq.b .End ;Error : exit
|
||
|
||
;-------- 68000 --------
|
||
IFND CPU020
|
||
move.l a3,ad_Units(a5,d1.w) ;ApolloUnit structure address
|
||
ENDC
|
||
|
||
;-------- 68020+ --------
|
||
IFD CPU020
|
||
move.l a3,ad_Units(a5,d2.w*4) ;ApolloUnit structure address
|
||
ENDC
|
||
|
||
.End
|
||
movem.l (sp)+,d1-d7/a0-a6 ;Restore registers
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Return the RDB's block address ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : Standard I/O Request
|
||
|
||
GetRdskLba
|
||
move.l IO_UNIT(a1),a0
|
||
move.l au_RDBSector(a0),d0 ;Block address of the RDB
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Return sector size (in power of 2!) ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : Standard I/O Request
|
||
|
||
GetBlkSize
|
||
moveq #0,d0
|
||
move.l IO_UNIT(a1),a0
|
||
move.b au_SectShift(a0),d0 ;Sector size
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Fast block copy ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A0.l : Source address
|
||
;A1.l : Destination address
|
||
;A3.l : ApolloUnit base address
|
||
|
||
CopyBlock
|
||
movem.l d0-d7/a0-a6,-(sp) ;Save all registers
|
||
|
||
moveq #11*4,d7 ;D7: address increment
|
||
move.l au_SectSize(a3),d6
|
||
lsr.w #8,d6
|
||
subq.w #1,d6 ;D6: number of 256-byte chunks
|
||
.CopyLoop
|
||
movem.l (a0)+,d0-d5/a2-a6
|
||
movem.l d0-d5/a2-a6,(a1) ;1st transfer of 11 long words
|
||
add.l d7,a1
|
||
movem.l (a0)+,d0-d5/a2-a6
|
||
movem.l d0-d5/a2-a6,(a1) ;2nd transfer of 11 long words
|
||
add.l d7,a1
|
||
movem.l (a0)+,d0-d5/a2-a6
|
||
movem.l d0-d5/a2-a6,(a1) ;3rd transfer of 11 long words
|
||
add.l d7,a1
|
||
movem.l (a0)+,d0-d5/a2-a6
|
||
movem.l d0-d5/a2-a6,(a1) ;4th transfer of 11 long words
|
||
add.l d7,a1
|
||
movem.l (a0)+,d0-d5/a2-a6
|
||
movem.l d0-d5/a2-a6,(a1) ;5th transfer of 11 long words
|
||
add.l d7,a1
|
||
movem.l (a0)+,d0-d5/a2-a4
|
||
movem.l d0-d5/a2-a4,(a1) ;One more transfer of 9 long words
|
||
lea 9*4(a1),a1 ;256 bytes : 5 * 11 + 9 long words
|
||
dbra d6,.CopyLoop ;Loop
|
||
|
||
movem.l (sp)+,d0-d7/a0-a6 ;Restore all registers
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** AT-Apollo.device BeginIO() entry ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
IFD DEBUG
|
||
IMMEDIATES_CMD = %11111111111111111111111111111111
|
||
ENDC
|
||
|
||
IFND DEBUG
|
||
IMMEDIATES_CMD = %10000000001111111111000111100011
|
||
ENDC
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : Standard I/O Request
|
||
;A6.l : AT-Apollo.device base address
|
||
|
||
BeginIO
|
||
movem.l d0-d7/a0-a6,-(sp) ;Save all registers
|
||
|
||
move.b #NT_MESSAGE,LN_TYPE(a1) ;For WaitIO() correct behavior
|
||
|
||
move.l IO_UNIT(a1),a3 ;A3 : ApolloUnit base address
|
||
move.l ad_TaskData(a6),a4 ;A4 : TaskData structure
|
||
move.l ad_SysLib(a6),a5 ;A5 : ExecBase
|
||
|
||
;*************** Commands decode **********************************************
|
||
|
||
move.w IO_COMMAND(a1),d0 ;D0 : Command sent to the device
|
||
cmpi.w #APCMD_UNITPARAMS,d0 ;Command <= APCMD_UNITPARAMS ?
|
||
bls.b .Ok1 ;Yes, valid command
|
||
cmpi.w #NSCMD_DEVICEQUERY,d0 ;NSCMD_DEVICEQUERY command ?
|
||
beq.b .Ok2 ;Yes, valid command
|
||
cmpi.w #NSCMD_TD_READ64,d0 ;Command < NSCMD_TD_READ64 ?
|
||
bcs.w .Error ;Yes, invalid command
|
||
cmpi.w #NSCMD_TD_FORMAT64,d0 ;Command > NSCMD_TD_FORMAT64 ?
|
||
bhi.b .Error ;Yes, invalid command
|
||
subi.w #$8007,d0 ;$C000-$C003 -> bits #24-27
|
||
.Ok2
|
||
subi.w #$3FE1,d0 ;$4000 -> bit #31
|
||
.Ok1
|
||
|
||
move.w #$4000,$DFF09A ;Disable interrupts
|
||
addq.b #1,IDNestCnt(a5) ;Increment Exec counter
|
||
|
||
move.l #IMMEDIATES_CMD,d1
|
||
btst d0,d1 ;Immediate command ?
|
||
bne.b .Immediate ;Yes, execute it right away
|
||
|
||
; btst #UNITB_STOPPED,UNIT_FLAGS(a4) ;Unit stopped ?
|
||
; bne.b .QueueMsg ;Yes, queue the message
|
||
|
||
tst.b au_AtapiDev(a3) ;ATAPI protocol ?
|
||
bne.b .QueueMsg ;Yes, queue the message
|
||
|
||
bset #UNITB_ACTIVE,UNIT_FLAGS(a4) ;Set unit as active
|
||
beq.b .Immediate ;Unit was not active : immediate command
|
||
|
||
;*************** Deferred command execution ***********************************
|
||
|
||
.QueueMsg
|
||
bset #UNITB_INTASK,UNIT_FLAGS(a4) ;Command will run inside the unit task
|
||
bclr #IOB_QUICK,IO_FLAGS(a1) ;Clear the "quick" bit
|
||
|
||
subq.b #1,IDNestCnt(a5) ;Decrement Exec counter
|
||
bge.b .Enable1 ;> 0 : skip next instruction
|
||
move.w #$C000,$DFF09A ;Enable interrupts
|
||
.Enable1
|
||
|
||
move.l a4,a0
|
||
move.l a5,a6 ;A6: ExecBase
|
||
jsr _LVOPutMsg(a6) ;Send the I/O request
|
||
|
||
movem.l (sp)+,d0-d7/a0-a6 ;Restore registers
|
||
rts ;End
|
||
|
||
;*************** Immediate command execution **********************************
|
||
|
||
.Immediate
|
||
; bset #UNITB_ACTIVE,UNIT_FLAGS(a4) ;The unit is active
|
||
subq.b #1,IDNestCnt(a5) ;Decrement Exec counter
|
||
bge.b .Enable2 ;> 0 : skip next instruction
|
||
move.w #$C000,$DFF09A ;Enable interrupts
|
||
.Enable2
|
||
|
||
bsr.b PerformIO ;Execute the command
|
||
|
||
bclr #UNITB_ACTIVE,UNIT_FLAGS(a4) ;End of the command
|
||
|
||
btst #IOB_QUICK,IO_FLAGS(a1) ;If "quick" bit is set :
|
||
bne.b .NoReply ;No answer
|
||
move.l a5,a6 ;A6 : ExecBase
|
||
jsr _LVOReplyMsg(a6) ;Otherwise, reply to the message
|
||
.NoReply
|
||
|
||
movem.l (sp)+,d0-d7/a0-a6 ;Restore registers
|
||
rts ;End
|
||
|
||
;*************** Error : command is not supported *****************************
|
||
|
||
.Error
|
||
move.b #IOERR_NOCMD,IO_ERROR(a1) ;Error code
|
||
bset #IOB_QUICK,IO_FLAGS(a1) ;No waiting
|
||
|
||
movem.l (sp)+,d0-d7/a0-a6 ;Restore registers
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** I/O request dispatch ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : Standard I/O Request
|
||
;A3.l : ApolloUnit base address
|
||
;A4.l : TaskData structure
|
||
;A5.l : ExecBase
|
||
;A6.l : AT-Apollo.device base address
|
||
|
||
PerformIO
|
||
clr.b IO_ERROR(a1) ;No error
|
||
move.w IO_COMMAND(a1),d0 ;D0 : I/O command
|
||
cmpi.w #NSCMD_DEVICEQUERY,d0 ;Check NSD device query command
|
||
beq.w cmd_DevQuery
|
||
cmpi.w #NSCMD_TD_READ64,d0 ;Check NSD 64-bit commands
|
||
bcc.b .Cmd64
|
||
|
||
;-------- Optimized code --------
|
||
IFND CPU020
|
||
add.w d0,d0
|
||
move.w .Map32(pc,d0.w),d0 ;Indexed by the command value
|
||
ENDC
|
||
|
||
IFD CPU020
|
||
move.w .Map32(pc,d0.w*2),d0 ;Indexed by the command value
|
||
ENDC
|
||
|
||
jmp .Map32(pc,d0.w) ;Execute command
|
||
|
||
.Cmd64
|
||
subi.w #NSCMD_TD_READ64,d0
|
||
|
||
;-------- Optimized code --------
|
||
IFND CPU020
|
||
add.w d0,d0
|
||
move.w .Map64(pc,d0.w),d0 ;Indexed by the command value
|
||
ENDC
|
||
|
||
IFD CPU020
|
||
move.w .Map64(pc,d0.w*2),d0 ;Indexed by the command value
|
||
ENDC
|
||
|
||
jmp .Map64(pc,d0.w) ;Execute command
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** AT-Apollo.device command table ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Command: Code: Mask:
|
||
;-------------------------------------
|
||
.Map64
|
||
dc.w cmd_Read64-.Map64 ;NSCMD_TD_READ64 ($C000) ($01000000)
|
||
dc.w cmd_Write64-.Map64 ;NSCMD_TD_WRITE64 ($C001) ($02000000)
|
||
dc.w cmd_Seek64-.Map64 ;NSCMD_TD_SEEK64 ($C002) ($04000000)
|
||
dc.w cmd_Write64-.Map64 ;NSCMD_TD_FORMAT64 ($C003) ($08000000)
|
||
|
||
.Map32
|
||
dc.w cmd_Invalid-.Map32 ;CMD_INVALID ($0000) ($00000001)
|
||
dc.w cmd_Reset-.Map32 ;CMD_RESET ($0001) ($00000002)
|
||
dc.w cmd_Read32-.Map32 ;CMD_READ ($0002) ($00000004)
|
||
dc.w cmd_Write32-.Map32 ;CMD_WRITE ($0003) ($00000008)
|
||
dc.w cmd_Update-.Map32 ;CMD_UPDATE ($0004) ($00000010)
|
||
dc.w cmd_Reset-.Map32 ;CMD_CLEAR ($0005) ($00000020)
|
||
dc.w cmd_Reset-.Map32 ;CMD_STOP ($0006) ($00000040)
|
||
dc.w cmd_Reset-.Map32 ;CMD_START ($0007) ($00000080)
|
||
dc.w cmd_Flush-.Map32 ;CMD_FLUSH ($0008) ($00000100)
|
||
dc.w cmd_Reset-.Map32 ;TD_MOTOR ($0009) ($00000200)
|
||
dc.w cmd_Seek32-.Map32 ;TD_SEEK ($000A) ($00000400)
|
||
dc.w cmd_Write32-.Map32 ;TD_FORMAT ($000B) ($00000800)
|
||
dc.w cmd_Remove-.Map32 ;TD_REMOVE ($000C) ($00001000)
|
||
dc.w cmd_ChangeNum-.Map32 ;TD_CHANGENUM ($000D) ($00002000)
|
||
dc.w cmd_ChangeState-.Map32 ;TD_CHANGESTATE ($000E) ($00004000)
|
||
dc.w cmd_ProtStatus-.Map32 ;TD_PROTSTATUS ($000F) ($00008000)
|
||
dc.w cmd_Invalid-.Map32 ;TD_RAWREAD ($0010) ($00010000)
|
||
dc.w cmd_Invalid-.Map32 ;TD_RAWWRITE ($0011) ($00020000)
|
||
dc.w cmd_GetDriveType-.Map32 ;TD_GETDRIVETYPE ($0012) ($00040000)
|
||
dc.w cmd_GetNumTracks-.Map32 ;TD_GETNUMTRACKS ($0013) ($00080000)
|
||
dc.w cmd_AddChangeInt-.Map32 ;TD_ADDCHANGEINT ($0014) ($00100000)
|
||
dc.w cmd_RemChangeInt-.Map32 ;TD_REMCHANGEINT ($0015) ($00200000)
|
||
dc.w cmd_GetGeometry-.Map32 ;TD_GETGEOMETRY ($0016) ($00400000)
|
||
dc.w cmd_Eject-.Map32 ;TD_EJECT ($0017) ($00800000)
|
||
dc.w cmd_Invalid-.Map32 ; - ($0018) -
|
||
dc.w cmd_Invalid-.Map32 ; - ($0019) -
|
||
dc.w cmd_Invalid-.Map32 ; - ($001A) -
|
||
dc.w cmd_Invalid-.Map32 ; - ($001B) -
|
||
dc.w cmd_ScsiDirect-.Map32 ;HD_SCSICMD ($001C) ($10000000)
|
||
dc.w cmd_TestChanged-.Map32 ;APCMD_TESTCHANGED ($001D) ($20000000)
|
||
dc.w cmd_UnitParams-.Map32 ;APCMD_UNITPARAMS ($001E) ($40000000)
|
||
; cmd_DevQuery ;NSCMD_DEVICEQUERY ($4000) ($80000000)
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** AT-Apollo.device AbortIO() entry ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
AbortIO
|
||
moveq #0,d0
|
||
rts
|
||
|
||
;******************************************************************************
|
||
; ----------- BEGIN OF THE DRIVE LOW-LEVEL I/O ROUTINES -----------
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1 : Standard I/O Request (must be saved)
|
||
;A3 : ApolloUnit base address
|
||
;A4 : TaskData structure (must be saved)
|
||
;A5 : ExecBase (must be saved)
|
||
;A6 : AT-Apollo.device base address (must be saved)
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Invalid command ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_Invalid
|
||
move.b #IOERR_NOCMD,IO_ERROR(a1) ;Error : command is not supported
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Reset command ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_Reset
|
||
clr.l IO_ACTUAL(a1)
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** 64-bit read command ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_Read64
|
||
move.b au_SectShift(a3),d2 ;D2: Logical shift (9 or 11)
|
||
move.l IO_OFFSET(a1),d0 ;D0: Position [31..0]
|
||
move.l IO_ACTUAL(a1),d1 ;D1: Position [63..32]
|
||
lsr.l d2,d0
|
||
ror.l d2,d1
|
||
or.l d1,d0 ;D0: Position / Block size = LBA
|
||
bra.b jmp_Read
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** 32-bit read command ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_Read32
|
||
move.b au_SectShift(a3),d2 ;D2: Logical shift (9 or 11)
|
||
move.l IO_OFFSET(a1),d0 ;D0: Position [31..0]
|
||
lsr.l d2,d0 ;D0: Position / Block size = LBA
|
||
|
||
jmp_Read
|
||
move.l IO_LENGTH(a1),d1
|
||
lsr.l d2,d1 ;D1: Number of blocks
|
||
|
||
movem.l a2/a4,-(sp) ;Save A2 & A4
|
||
move.l IO_DATA(a1),a0 ;A0: Buffer pointer
|
||
move.l au_WCacheTags(a3),a2 ;A2: Write cache tags
|
||
move.l au_WCacheFlags(a3),a4 ;A4: Write cache flags
|
||
|
||
;*************** Interrupts management ****************************************
|
||
|
||
tst.b au_IntDisable(a3) ;Check the interrupts disable option
|
||
beq.b .IntEna1 ;Not set: skip the next 2 lines
|
||
move.w #$4000,$DFF09A ;Disable interrupts
|
||
addq.b #1,IDNestCnt(a5) ;Increment Exec counter
|
||
.IntEna1
|
||
|
||
;*************** Read one block from the write cache **************************
|
||
|
||
moveq #1,d2
|
||
cmp.l d2,d1 ;One block read ?
|
||
bne.w .NoReadCache ;No, jump to ".NoReadCache"
|
||
tst.b au_WCacheOn(a3) ;Write cache activated ?
|
||
beq.b .NoWriteCache ;No, jump to ".NoWriteCache"
|
||
|
||
move.w d0,d2 ;D2: Block's LBA
|
||
and.w au_WCacheSize(a3),d2 ;D2: Buffer index in the cache
|
||
|
||
;-------- Optimized code --------
|
||
IFND CPU020
|
||
add.l d2,d2
|
||
tst.b cf_Valid(a4,d2.l) ;Valid buffer ?
|
||
ENDC
|
||
|
||
IFD CPU020
|
||
tst.b cf_Valid(a4,d2.l*2) ;Valid buffer ?
|
||
ENDC
|
||
|
||
beq.b .NoWriteCache ;No, the block is not in the cache
|
||
|
||
;-------- Optimized code --------
|
||
IFND CPU020
|
||
add.l d2,d2
|
||
add.l d2,d2
|
||
cmp.l ct_Offset(a2,d2.l),d0 ;Same location on drive ?
|
||
ENDC
|
||
|
||
IFD CPU020
|
||
cmp.l ct_Offset(a2,d2.l*8),d0 ;Same location on drive ?
|
||
ENDC
|
||
|
||
bne.b .NoWriteCache ;No, the block is not in the cache
|
||
move.l a1,-(sp) ;Save A1
|
||
move.l a0,a1 ;A1: Destination address
|
||
|
||
;-------- Optimized code --------
|
||
IFND CPU020
|
||
move.l ct_Data(a2,d2.l),a0 ;A0: Source address
|
||
ENDC
|
||
|
||
IFD CPU020
|
||
move.l ct_Data(a2,d2.l*8),a0 ;A0: Source address
|
||
ENDC
|
||
|
||
bsr.w CopyBlock ;Copy the block
|
||
move.l (sp)+,a1 ;Restore A1
|
||
move.l au_SectSize(a3),IO_ACTUAL(a1) ;One block read
|
||
bra.w .End ;End
|
||
.NoWriteCache
|
||
|
||
;*************** Read one block from the read cache ***************************
|
||
|
||
tst.b au_RCacheOn(a3) ;Read cache activated ?
|
||
beq.b .NoReadCache ;No, jump to ".NoReadCache"
|
||
|
||
move.l au_RCacheBlock(a3),d2 ;D2: Cache location on disk
|
||
cmp.l d2,d0 ;Data location > Cache location ?
|
||
bcs.b .OutCache ;No, start a new cache read
|
||
add.l au_RCacheSize(a3),d2 ;+ Cache size
|
||
cmp.l d2,d0 ;Data location > End of cache ?
|
||
bcc.b .OutCache ;Yes, start a new cache read
|
||
move.b #1,au_RCacheCount(a3) ;1 read before cache fetch
|
||
sub.l au_RCacheBlock(a3),d0
|
||
move.b au_SectShift(a3),d1
|
||
lsl.l d1,d0 ;D0: Data offset in cache
|
||
move.l a1,-(sp) ;Save A1
|
||
move.l a0,a1 ;A1: Destination address
|
||
move.l au_RCacheAddr(a3),a0 ;A0: Read cache address
|
||
add.l d0,a0 ;A0: + Offset = Source address
|
||
bsr.w CopyBlock ;Copy one block
|
||
move.l (sp)+,a1 ;Restore A1
|
||
move.l au_SectSize(a3),IO_ACTUAL(a1) ;One block read
|
||
bra.b .End ;End
|
||
|
||
;*************** Prepare cache read fetch *************************************
|
||
|
||
.OutCache
|
||
cmp.l au_RCacheNext(a3),d0 ;Data location = next read cache location ?
|
||
beq.b .ReadCache ;Yes, fetch the read cache
|
||
move.l d0,au_RCacheNext(a3) ;Next read cache location:
|
||
addq.l #1,au_RCacheNext(a3) ;Data location + 1
|
||
move.b #4,au_RCacheCount(a3) ;4 reads before cache fetch
|
||
|
||
;*************** Read data from drive *****************************************
|
||
|
||
.NoReadCache
|
||
movem.l d0/d1,-(sp) ;Save D0 & D1
|
||
jsr au_ReadJmp(a3) ;Read the blocks
|
||
move.b d0,IO_ERROR(a1) ;Error code
|
||
move.l d1,IO_ACTUAL(a1) ;Number of bytes read
|
||
movem.l (sp)+,d0/d1 ;Restore D0 & D1
|
||
|
||
;*************** Take care of buffers not yet written *************************
|
||
|
||
tst.b au_WCacheUpd(a3) ;Buffers already updated ?
|
||
beq.b .End ;Yes, exit
|
||
|
||
move.l a1,-(sp) ;Save A1
|
||
move.w au_WCacheSize(a3),d3 ;D3: Number of buffers - 1
|
||
move.b au_SectShift(a3),d4 ;D4: Block size (Log 2)
|
||
move.l a0,d5 ;D5: Data address in memory
|
||
.Loop
|
||
tst.b (a4) ;Buffer not "dirty" ?
|
||
beq.b .NoCopy ;Yes, no copy
|
||
move.l (a2),d2 ;D2: Buffer location on drive
|
||
sub.l d0,d2 ;- Data location on drive
|
||
bcs.b .NoCopy ;Negative : no copy
|
||
cmp.l d1,d2 ;>= Data size ?
|
||
bcc.b .NoCopy ;Yes, no copy
|
||
lsl.l d4,d2
|
||
add.l d5,d2 ;+ Data address in memory
|
||
move.l ct_Data(a2),a0 ;A0: Source address
|
||
move.l d2,a1 ;A1: Destination address
|
||
bsr.w CopyBlock ;Copy the block
|
||
.NoCopy
|
||
addq.l #ct_SIZEOF,a2
|
||
addq.l #cf_SIZEOF,a4 ;Next buffer
|
||
dbra d3,.Loop ;Loop
|
||
move.l (sp)+,a1 ;Restore A1
|
||
|
||
;*************** End of command : interrupts management ***********************
|
||
|
||
.End
|
||
movem.l (sp)+,a2/a4 ;Restore A2 & A4
|
||
tst.b au_IntDisable(a3) ;Check the interrupts disable option
|
||
beq.b .IntEna2 ;Not set: skip the next 3 lines
|
||
subq.b #1,IDNestCnt(a5) ;Decrement Exec counter
|
||
bge.b .IntEna2 ;> 0 : skip next instruction
|
||
move.w #$C000,$DFF09A ;Enable interrupts
|
||
.IntEna2
|
||
rts ;End of the I/O command
|
||
|
||
;*************** Read cache fetch *********************************************
|
||
|
||
.ReadCache
|
||
addq.l #1,au_RCacheNext(a3) ;+ 1 to the read cache location
|
||
subq.b #1,au_RCacheCount(a3) ;Decrement the access count
|
||
bne.b .NoReadCache ;Not null : no cache fetch yet
|
||
movem.l d0/d1/a0,-(sp) ;Save D0, D1 & A0
|
||
move.l au_RCacheSize(a3),d1 ;D1: Read cache size
|
||
add.l d1,d0
|
||
move.l d0,au_RCacheNext(a3) ;Next read cache location
|
||
move.l au_RCacheAddr(a3),a0 ;A0: Read cache address
|
||
move.l (sp),d0 ;D0: Current read cache location
|
||
jsr au_ReadJmp(a3) ;Read cache fetch
|
||
tst.b d0 ;Error code check
|
||
movem.l (sp)+,d0/d1/a0 ;Restore D0, D1 & A0
|
||
beq.b .Copy ;No error : copy the block
|
||
|
||
moveq #-1,d2
|
||
move.l d2,au_RCacheBlock(a3) ;Otherwise, invalid read cache
|
||
jsr au_ReadJmp(a3) ;Read the blocks
|
||
move.b d0,IO_ERROR(a1) ;Error code
|
||
move.l d1,IO_ACTUAL(a1) ;Number of bytes read
|
||
bra.b .End ;End
|
||
|
||
;*************** Block copy after the read cache fetch ************************
|
||
|
||
.Copy
|
||
move.l d0,au_RCacheBlock(a3) ;Valid read cache
|
||
move.l a1,-(sp) ;Save A1
|
||
move.l a0,a1 ;A1: Destination address
|
||
move.l au_RCacheAddr(a3),a0 ;A0: Source address
|
||
bsr.w CopyBlock ;Copy one block
|
||
move.l (sp)+,a1 ;Restore A1
|
||
move.l au_SectSize(a3),IO_ACTUAL(a1) ;One block read
|
||
bra.b .End ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** 64-bit write command ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_Write64
|
||
tst.b au_DevType(a3) ;Direct access peripheral ?
|
||
bne.b err_WriteProt ;No, error
|
||
move.b au_SectShift(a3),d2 ;D2: Logical shift (9 or 11)
|
||
move.l IO_OFFSET(a1),d0 ;D0: Position [31..0]
|
||
move.l IO_ACTUAL(a1),d1 ;D1: Position [63..32]
|
||
lsr.l d2,d0
|
||
ror.l d2,d1
|
||
or.l d1,d0 ;D0: Position/Block size = LBA
|
||
bra.b jmp_Write
|
||
|
||
err_WriteProt
|
||
move.b #TDERR_WriteProt,IO_ERROR(a1)
|
||
clr.l IO_ACTUAL(a1)
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** 32-bit write command ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_Write32
|
||
tst.b au_DevType(a3) ;Direct access peripheral ?
|
||
bne.b err_WriteProt ;No, error
|
||
move.b au_SectShift(a3),d2 ;D2: Logical shift (9 or 11)
|
||
move.l IO_OFFSET(a1),d0 ;D0: Position [31..0]
|
||
lsr.l d2,d0 ;D0: Position/Block size = LBA
|
||
|
||
jmp_Write
|
||
move.l IO_LENGTH(a1),d1
|
||
lsr.l d2,d1 ;D1: Number of blocks
|
||
|
||
movem.l a2/a4,-(sp) ;Save A2 & A4
|
||
move.l IO_DATA(a1),a0 ;A0: Buffer address
|
||
move.l au_WCacheTags(a3),a2 ;A2: Write cache tags
|
||
move.l au_WCacheFlags(a3),a4 ;A4: Write cache flags
|
||
|
||
;*************** Interrupts management ****************************************
|
||
|
||
tst.b au_IntDisable(a3) ;Check the interrupts disable option
|
||
beq.b .IntEna1 ;Not set: skip the next 2 lines
|
||
move.w #$4000,$DFF09A ;Disable interrupts
|
||
addq.b #1,IDNestCnt(a5) ;Increment Exec counter
|
||
.IntEna1
|
||
|
||
;*************** Conflict management with the read cache **********************
|
||
|
||
tst.b au_RCacheOn(a3) ;Read cache activated ?
|
||
beq.b .NoReadCache ;No, jump to ".NoReadCache"
|
||
|
||
move.l au_RCacheBlock(a3),d2 ;D2: Cache location on disk
|
||
sub.l d0,d2 ;- Data location on drive
|
||
bcs.b .Negative ;Negative : jump to ".Negative"
|
||
cmp.l d1,d2 ;>= Data size ?
|
||
bcc.b .NoReadCache ;Yes, no conflict with the read cache
|
||
bra.b .DisRCache ;No, there is a conflict
|
||
.Negative
|
||
neg.l d2 ;Positive number
|
||
cmp.l au_RCacheSize(a3),d2 ;>= Cache size ?
|
||
bcc.b .NoReadCache ;Yes, no conflict with the read cache
|
||
.DisRCache
|
||
moveq #-1,d2
|
||
move.l d2,au_RCacheBlock(a3) ;Conflict : invalidate the read cache
|
||
|
||
;*************** Conflict management with the write cache *********************
|
||
|
||
.NoReadCache
|
||
tst.b au_WCacheOn(a3) ;Write cache activated ?
|
||
beq.b .NoWriteCache ;No, jump to ".NoWriteCache"
|
||
cmpi.l #1,d1 ;One block write ?
|
||
beq.b .WriteOne ;Yes, jump to ".WriteOne"
|
||
|
||
move.w au_WCacheSize(a3),d3 ;D3: Number of buffers - 1
|
||
.Loop
|
||
tst.b cf_Valid(a4) ;Valid buffer ?
|
||
beq.b .Next ;No, next buffer
|
||
move.l (a2),d2 ;D2: Buffer location on drive
|
||
sub.l d0,d2 ;- Data location on drive
|
||
bcs.b .Next ;Negative : next buffer
|
||
cmp.l d1,d2 ;>= Data size ?
|
||
bcc.b .Next ;Yes, next buffer
|
||
sf.b (a4) ;Update done
|
||
sf.b cf_Valid(a4) ;Invalidate the buffer
|
||
.Next
|
||
addq.l #ct_SIZEOF,a2
|
||
addq.l #cf_SIZEOF,a4 ;Next buffer
|
||
dbra d3,.Loop ;Loop
|
||
|
||
;*************** Write data to the drive **************************************
|
||
|
||
.NoWriteCache
|
||
jsr au_WriteJmp(a3) ;Write data routine
|
||
move.b d0,IO_ERROR(a1) ;Error code
|
||
move.l d1,IO_ACTUAL(a1) ;Number of bytes written
|
||
|
||
;*************** End of command : interrupts management ***********************
|
||
|
||
.End
|
||
movem.l (sp)+,a2/a4 ;Restore A2 & A4
|
||
tst.b au_IntDisable(a3) ;Check the interrupts disable option
|
||
beq.b .IntEna2 ;Not set: skip the next 3 lines
|
||
subq.b #1,IDNestCnt(a5) ;Decrement Exec counter
|
||
bge.b .IntEna2 ;> 0 : skip next instruction
|
||
move.w #$C000,$DFF09A ;Enable interrupts
|
||
.IntEna2
|
||
rts ;End of the I/O command
|
||
|
||
;*************** Write a block into the cache *********************************
|
||
|
||
.WriteOne
|
||
move.l d0,d2 ;D2: Block's LBA
|
||
and.w au_WCacheSize(a3),d2 ;D2: Buffer index in the cache
|
||
|
||
IFND CPU020
|
||
add.w d2,d2 ;D2: N<> x 2 -> Flags index
|
||
move.w d2,d3
|
||
add.w d3,d3
|
||
add.w d3,d3 ;D3: N<> x 8 -> Tags index
|
||
ENDC
|
||
|
||
;-------- Optimized code --------
|
||
IFND CPU020
|
||
tst.b cf_Update(a4,d2.w) ;Update done ?
|
||
ENDC
|
||
|
||
IFD CPU020
|
||
tst.b cf_Update(a4,d2.w*2) ;Update done ?
|
||
ENDC
|
||
|
||
beq.b .NoUpdate ;Yes, do not write this buffer
|
||
|
||
;-------- Optimized code --------
|
||
IFND CPU020
|
||
cmp.l ct_Offset(a2,d3.w),d0 ;Same location on drive ?
|
||
ENDC
|
||
|
||
IFD CPU020
|
||
cmp.l ct_Offset(a2,d2.w*8),d0 ;Same location on drive ?
|
||
ENDC
|
||
|
||
beq.b .NoUpdate ;Yes, do not write this buffer
|
||
movem.l d0/a0,-(sp) ;Save D0 & A0
|
||
|
||
;-------- Optimized code --------
|
||
IFND CPU020
|
||
move.l ct_Data(a2,d3.w),a0 ;A0: Buffer address
|
||
move.l ct_Offset(a2,d3.w),d0 ;D0: Buffer location on drive
|
||
ENDC
|
||
|
||
IFD CPU020
|
||
move.l ct_Data(a2,d2.w*8),a0 ;A0: Buffer address
|
||
move.l ct_Offset(a2,d2.w*8),d0 ;D0: Buffer location on drive
|
||
ENDC
|
||
|
||
moveq #1,d1 ;D1: One block to write
|
||
jsr au_WriteJmp(a3) ;Write the block
|
||
movem.l (sp)+,d0/a0 ;Restore D0 & A0
|
||
.NoUpdate
|
||
|
||
move.l a1,-(sp) ;Save A1
|
||
|
||
;-------- Optimized code --------
|
||
IFND CPU020
|
||
st.b cf_Update(a4,d2.w) ;Buffer is "dirty"
|
||
st.b cf_Valid(a4,d2.w) ;Valid buffer
|
||
move.l d0,ct_Offset(a2,d3.w) ;Buffer location on drive
|
||
move.l ct_Data(a2,d3.w),a1 ;A1: Destination address
|
||
ENDC
|
||
|
||
IFD CPU020
|
||
st.b cf_Update(a4,d2.w*2) ;Buffer is "dirty"
|
||
st.b cf_Valid(a4,d2.w*2) ;Valid buffer
|
||
move.l d0,ct_Offset(a2,d2.w*8) ;Buffer location on drive
|
||
move.l ct_Data(a2,d2.w*8),a1 ;A1: Destination address
|
||
ENDC
|
||
|
||
bsr.w CopyBlock ;Copy the block
|
||
move.l (sp)+,a1 ;Restore A1
|
||
st.b au_WCacheUpd(a3) ;Cache contains "dirty" buffers
|
||
move.l au_SectSize(a3),IO_ACTUAL(a1) ;One block written
|
||
bra.b .End ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Force buffers update ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_Update
|
||
tst.b au_WCacheUpd(a3) ;Buffers up to date ?
|
||
beq.b .NoUpdate ;Yes, end of command
|
||
|
||
;*************** Update loop **************************************************
|
||
|
||
move.l a1,-(sp) ;Save A1
|
||
move.l au_WCacheTags(a3),a1 ;A1: Write cache tags
|
||
move.l au_WCacheFlags(a3),a2 ;A2: Write cache flags
|
||
move.w au_WCacheSize(a3),d2 ;D2: Number of buffers - 1
|
||
.Loop
|
||
tst.b (a2) ;"dirty"content in buffer ?
|
||
beq.b .NoWrite ;No, jump to ".NoWrite"
|
||
movem.l (a1),d0/a0 ;D0: Buffer location on drive
|
||
;A0: Data address in memory
|
||
moveq #1,d1 ;D1: One block to write
|
||
jsr au_WriteJmp(a3) ;Write the buffer
|
||
tst.b d0 ;Error code check
|
||
bne.b .Error ;Error : exit
|
||
sf.b (a2) ;Buffer not "dirty" anymore
|
||
.NoWrite
|
||
addq.l #ct_SIZEOF,a1
|
||
addq.l #cf_SIZEOF,a2 ;Next buffer
|
||
dbra d2,.Loop ;Loop
|
||
sf.b au_WCacheUpd(a3) ;Write cache up to date
|
||
|
||
;*************** End of command ***********************************************
|
||
|
||
.Error
|
||
move.l (sp)+,a1 ;Restore A1
|
||
|
||
.NoUpdate
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** 64-bit seek command ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_Seek64
|
||
move.b au_SectShift(a3),d2 ;D2: Logical shift (9 or 11)
|
||
move.l IO_OFFSET(a1),d0 ;D0: Position [31..0]
|
||
move.l IO_ACTUAL(a1),d1 ;D1: Position [63..32]
|
||
lsr.l d2,d0
|
||
ror.l d2,d1
|
||
or.l d1,d0 ;D0: Position / Block size = LBA
|
||
bra.b jmp_Seek
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** 32-bit seek command ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_Seek32
|
||
move.b au_SectShift(a3),d2 ;D2: Logical shift (9 or 11)
|
||
move.l IO_OFFSET(a1),d0 ;D0: Position [31..0]
|
||
lsr.l d2,d0 ;D0: Position/Block size = LBA
|
||
|
||
jmp_Seek
|
||
jsr au_SeekJmp(a3) ;Head seek
|
||
move.b d0,IO_ERROR(a1) ;Error code
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Number of media changes ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_ChangeNum
|
||
move.l au_ChangeNum(a3),IO_ACTUAL(a1)
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Media present ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_ChangeState
|
||
moveq #0,d0
|
||
tst.b au_DiskPresent(a3)
|
||
bne.b .End
|
||
moveq #1,d0
|
||
.End
|
||
move.l d0,IO_ACTUAL(a1)
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** "DiskChange" software interrupts added by these commands ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_Remove
|
||
tst.l au_RemoveInt(a3)
|
||
beq.b .Ok
|
||
move.b #TDERR_DriveInUse,IO_ERROR(a1)
|
||
rts
|
||
.Ok
|
||
move.l IO_DATA(a1),au_RemoveInt(a3)
|
||
rts
|
||
|
||
cmd_AddChangeInt
|
||
move.l a1,-(sp)
|
||
|
||
exg a5,a6
|
||
jsr _LVOForbid(a6)
|
||
|
||
lea au_SoftList(a3),a0
|
||
move.l (sp),a1
|
||
move.l (a0),d0
|
||
move.l a1,(a0)
|
||
movem.l d0/a0,(a1)
|
||
move.l d0,a0
|
||
move.l a1,LN_PRED(a0)
|
||
|
||
jsr _LVOPermit(a6)
|
||
exg a5,a6
|
||
|
||
move.l (sp)+,a1
|
||
bclr #IOB_QUICK,IO_FLAGS(a1)
|
||
bclr #UNITB_ACTIVE,UNIT_FLAGS(a4)
|
||
addq.l #4,sp
|
||
movem.l (sp)+,d0-d7/a0-a6
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** "DiskChange" software interrupt removal command ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_RemChangeInt
|
||
move.l a1,-(sp)
|
||
|
||
exg a5,a6
|
||
jsr _LVOForbid(a6)
|
||
|
||
lea au_SoftList(a3),a0
|
||
move.l (sp),a1
|
||
move.l (a1)+,a0
|
||
move.l (a1),a1
|
||
move.l a0,(a1)
|
||
move.l a1,LN_PRED(a0)
|
||
|
||
jsr _LVOPermit(a6)
|
||
exg a5,a6
|
||
|
||
move.l (sp)+,a1
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Drive type identification ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_GetDriveType
|
||
move.l #1,IO_ACTUAL(a1) ;Type : 3"5 drive
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Number of tracks ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_GetNumTracks
|
||
moveq #0,d0
|
||
move.w au_Cylinders(a3),d0 ;Number of tracks
|
||
move.l d0,IO_ACTUAL(a1)
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** I/O request flush ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_Flush
|
||
move.l a1,-(sp) ;Save A1
|
||
exg a5,a6 ;A5: Device, A6: ExecBase
|
||
jsr _LVOForbid(a6) ;Stop multi-tasking
|
||
.Loop
|
||
move.l a4,a0
|
||
jsr _LVOGetMsg(a6) ;Get a message
|
||
tst.l d0
|
||
beq.b .End ;No more messages : exit
|
||
move.l d0,a1
|
||
move.b #IOERR_ABORTED,IO_ERROR(a1) ;Error : aborted command
|
||
jsr _LVOReplyMsg(a6) ;Reply to message
|
||
bra.b .Loop ;Loop
|
||
.End
|
||
jsr _LVOPermit(a6) ;Resume multi-tasking
|
||
exg a5,a6 ;A5: ExecBase, A6: Device
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Write protect status command ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_ProtStatus
|
||
clr.l IO_ACTUAL(a1)
|
||
tst.b au_DevType(a3) ;Direct access peripheral ?
|
||
beq.b .End ;Yes, exit
|
||
not.l IO_ACTUAL(a1) ;No, write protect (CD-ROM drive)
|
||
.End
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Media eject command ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_Eject
|
||
tst.b au_Removable(a3) ;Removable media ?
|
||
beq.b .End ;No, end of the command
|
||
jsr au_EjectJmp(a3) ;Yes, eject media
|
||
move.b d0,IO_ERROR(a1) ;Error code
|
||
.End
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Drive geometry command ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_GetGeometry
|
||
move.l IO_DATA(a1),a0
|
||
move.l IO_LENGTH(a1),d0 ;D0: Response length
|
||
moveq #dg_SIZEOF,d2
|
||
cmp.l d2,d0 ;= sizeof(DriveGeometry) ?
|
||
beq.b .Standard ;Yes, CBM defined info
|
||
move.w #BLOCK_SIZE,d2
|
||
cmp.l d2,d0 ;= BLOCK_SIZE ?
|
||
beq.b .Apollo ;Yes, Apollo-Install info
|
||
addq.l #2,d2
|
||
cmp.l d2,d0 ;= BLOCK_SIZE + 2 ?
|
||
beq.b .Ata ;Yes, ATA-3 auto-detect
|
||
.Error
|
||
move.b #TDERR_NotSpecified,IO_ERROR(a1) ;No, error
|
||
rts ;End
|
||
|
||
.Ata
|
||
bsr.w ata_Identify ;ATA-3 disk identify
|
||
beq.b .Error ;An error has occured
|
||
move.l d2,IO_ACTUAL(a1) ;Returned data length
|
||
rts ;End
|
||
|
||
.Apollo
|
||
lea au_ModelID(a3),a2
|
||
moveq #7,d0 ;8 long words (or 32 bytes) to copy
|
||
.Loop
|
||
move.l (a2)+,(a0)+ ;Copy one long word
|
||
dbra d0,.Loop ;Loop
|
||
move.l au_Blocks(a3),d0
|
||
move.b au_SectShift(a3),d1
|
||
lsl.l d1,d0
|
||
move.l d0,(a0)+ ;Number of bytes
|
||
move.b au_Heads(a3),(a0)+ ;Number of heads
|
||
move.b au_SectorsT(a3),(a0)+ ;Number of sectors per track
|
||
move.w au_Cylinders(a3),(a0)+ ;Number of cylinders
|
||
move.w au_SectSize+2(a3),(a0) ;Sector size
|
||
|
||
move.l d2,IO_ACTUAL(a1) ;Returned data length
|
||
rts ;End
|
||
|
||
.Standard
|
||
move.l au_SectSize(a3),(a0)+ ;Sector size
|
||
move.l au_Blocks(a3),(a0)+ ;Total number of blocks
|
||
moveq #0,d0
|
||
move.w au_Cylinders(a3),d0
|
||
move.l d0,(a0)+ ;Number of cylinders
|
||
move.w au_SectorsC(a3),d0
|
||
move.l d0,(a0)+ ;Number of sectors per cylinder
|
||
moveq #0,d0
|
||
move.b au_Heads(a3),d0
|
||
move.l d0,(a0)+ ;Number of heads
|
||
move.b au_SectorsT(a3),d0
|
||
move.l d0,(a0)+ ;Number of sectors per track
|
||
move.l #MEMF_PUBLIC,(a0)+ ;Memory type for the buffers
|
||
move.b au_DevType(a3),(a0)+ ;Peripheral type
|
||
move.b au_Removable(a3),d0
|
||
andi.b #DGF_REMOVABLE,d0
|
||
move.b d0,(a0)+ ;Unit flags
|
||
clr.w (a0)
|
||
move.l d2,IO_ACTUAL(a1) ;Returned data length
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Apollo parameters set/clear command ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_UnitParams
|
||
tst.l IO_OFFSET(a1) ;Reading parameters?
|
||
bne.b .Write ;No, writing parameters
|
||
|
||
move.l au_RCacheSize(a3),d0 ;D0 : Read cache size
|
||
lsr.l #3,d0 ;/ 8
|
||
lsl.l #8,d0
|
||
|
||
move.w au_WCacheSize(a3),d1 ;D1 : Write cache size
|
||
.Loop
|
||
addq.b #1,d0
|
||
lsr.w #1,d1
|
||
bne.b .Loop ;Log 2 computation
|
||
swap d0
|
||
|
||
move.b au_Flags(a3),d0 ;Apollo flags
|
||
|
||
tst.b au_Swapped(a3)
|
||
beq.b .NoSwap
|
||
bset #AUB_SWAP,d0 ;Swapped data
|
||
.NoSwap
|
||
|
||
tst.b au_SlowDevice(a3)
|
||
beq.b .NoSlow
|
||
bset #AUB_SLOW,d0 ;Slow peripheral
|
||
.NoSlow
|
||
|
||
rts ;End
|
||
|
||
.Write
|
||
bsr.w cmd_Update ;Flush the write caches
|
||
exg a5,a6 ;A5 : AT-Apollo.device, A6 : ExecBase
|
||
bsr.w ClrParams ;Clear the old Apollo parameters
|
||
move.l IO_ACTUAL(a1),d0 ;D0 : new Apollo parameters
|
||
bsr.w SetParams ;Set the new Apollo parameters
|
||
exg a5,a6 ;A5 : ExecBase, A6 : AT-Apollo.device
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Media changed test command ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_TestChanged
|
||
tst.b au_AtapiDev(a3) ;ATAPI protocol ?
|
||
beq.b .NoTest ;No, skip the test
|
||
tst.b au_Removable(a3) ;Removable media ?
|
||
beq.b .NoTest ;No, skip the test
|
||
tst.b au_Used(a3) ;Unit used lately ?
|
||
bne.b .NoTest ;No, skip the test
|
||
bsr.w atapi_TestUnit ;"Test Unit Ready" command
|
||
tst.b d0 ;Not ready ?
|
||
bne.b .NotPresent ;Yes, media not present
|
||
cmpi.b #6,au_SenseKey(a3) ;No, sense Key = 6 ? (Unit attention)
|
||
beq.b .Present ;Yes, media present
|
||
|
||
;*************** Media not present ********************************************
|
||
|
||
.NotPresent
|
||
tst.b au_DiskPresent(a3) ;Media not present already detected ?
|
||
beq.b .NoTest ;Yes, do nothing
|
||
sf.b au_DiskPresent(a3) ;No, clear the flag
|
||
bra.b .Changed ;Software interrupts generation
|
||
|
||
;*************** Media present ************************************************
|
||
|
||
.Present
|
||
tst.b au_DiskPresent(a3) ;Media present already detected ?
|
||
bne.b .NoTest ;Yes, do nothing
|
||
st.b au_DiskPresent(a3) ;No, set the flag
|
||
|
||
;*************** Media changed ************************************************
|
||
|
||
.Changed
|
||
moveq #-1,d0
|
||
move.l d0,au_RCacheBlock(a3) ;Invalidate caches
|
||
addq.l #1,au_ChangeNum(a3) ;Increment the counter
|
||
|
||
movem.l a1/a2,-(sp)
|
||
exg a5,a6
|
||
jsr _LVOForbid(a6) ;Stop multi-tasking
|
||
|
||
move.l au_RemoveInt(a3),d0
|
||
beq.b .NoSoft
|
||
move.l d0,a1
|
||
jsr _LVOCause(a6) ;Trigger a software interrupt
|
||
.NoSoft
|
||
|
||
move.l au_SoftList(a3),a2 ;List of software interrupts
|
||
.SoftLoop
|
||
move.l (a2),d0
|
||
beq.b .SoftEnd
|
||
move.l IO_DATA(a2),a1
|
||
move.l d0,a2
|
||
jsr _LVOCause(a6) ;Trigger a software interrupt
|
||
bra.b .SoftLoop
|
||
.SoftEnd
|
||
|
||
jsr _LVOPermit(a6) ;Resume multi-tasking
|
||
exg a5,a6
|
||
movem.l (sp)+,a1/a2
|
||
|
||
.NoTest
|
||
sf.b au_Used(a3) ;Clear the flag
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-2 commands ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;A1.l : Standard I/O Request
|
||
;A3.l : ApolloUnit base address
|
||
|
||
cmd_ScsiDirect
|
||
moveq #scsi_SIZEOF,d0
|
||
move.l d0,IO_ACTUAL(a1)
|
||
move.l IO_DATA(a1),a2 ;A2: SCSICmd structure
|
||
|
||
;*************** PowerVisor v1.43 debugging ***********************************
|
||
|
||
IF PVDBG=1
|
||
movem.l d0-d2/a0-a6,-(sp)
|
||
move.l au_Device(a3),a5
|
||
tst.l ad_PVBase(a5)
|
||
beq.w .NoDebug1
|
||
tst.l ad_PVPort(a5)
|
||
beq.w .NoDebug1
|
||
|
||
lea CommandString(pc),a0
|
||
lea Digit(pc),a1
|
||
move.l scsi_Command(a2),a4
|
||
bsr.w IdentifyCmd
|
||
move.w scsi_CmdLength(a2),d0
|
||
subq.w #1,d0
|
||
moveq #0,d1
|
||
.CmdLoop
|
||
move.b #"$",(a0)+
|
||
move.b (a4)+,d1
|
||
move.w d1,d2
|
||
lsr.b #4,d1
|
||
andi.b #%00001111,d2
|
||
move.b (a1,d1.w),(a0)+
|
||
move.b (a1,d2.w),(a0)+
|
||
move.b #",",(a0)+
|
||
dbra d0,.CmdLoop
|
||
clr.b -(a0)
|
||
|
||
move.w scsi_SenseLength(a2),-(sp)
|
||
move.l scsi_SenseData(a2),-(sp)
|
||
moveq #0,d0
|
||
move.b scsi_Flags(a2),d0
|
||
move.w d0,-(sp)
|
||
move.w scsi_CmdLength(a2),-(sp)
|
||
pea CommandString(pc)
|
||
move.l scsi_Length(a2),-(sp)
|
||
move.l scsi_Data(a2),-(sp)
|
||
move.l ad_CmdStr(a5),-(sp)
|
||
|
||
move.l ad_SysLib(a5),a6
|
||
lea FormatString1(pc),a0
|
||
move.l sp,a1
|
||
lea PutChProc(pc),a2
|
||
lea OutputString(pc),a3
|
||
jsr _LVORawDoFmt(a6)
|
||
lea 26(sp),sp
|
||
move.l ad_PVBase(a5),a6
|
||
move.l ad_PVPort(a5),a0
|
||
lea OutputString(pc),a1
|
||
jsr _LVOPP_Print(a6)
|
||
|
||
.NoDebug1
|
||
movem.l (sp)+,d0-d2/a0-a6
|
||
ENDIF
|
||
|
||
jsr au_ScsiJmp(a3)
|
||
|
||
;*************** PowerVisor v1.43 debugging ***********************************
|
||
|
||
IF PVDBG=1
|
||
movem.l d0-d2/a0-a6,-(sp)
|
||
move.l au_Device(a3),a5
|
||
tst.l ad_PVBase(a5)
|
||
beq.w .NoDebug2
|
||
tst.l ad_PVPort(a5)
|
||
beq.w .NoDebug2
|
||
|
||
move.w scsi_SenseActual(a2),d2
|
||
move.l scsi_SenseData(a2),a4
|
||
|
||
moveq #0,d0
|
||
move.b scsi_Status(a2),d0
|
||
move.w d0,-(sp)
|
||
move.w d2,-(sp)
|
||
move.w scsi_CmdActual(a2),-(sp)
|
||
move.l scsi_Actual(a2),-(sp)
|
||
|
||
move.l ad_SysLib(a5),a6
|
||
lea FormatString2(pc),a0
|
||
move.l sp,a1
|
||
lea PutChProc(pc),a2
|
||
lea OutputString(pc),a3
|
||
jsr _LVORawDoFmt(a6)
|
||
lea 10(sp),sp
|
||
move.l ad_PVBase(a5),a6
|
||
move.l ad_PVPort(a5),a0
|
||
lea OutputString(pc),a1
|
||
jsr _LVOPP_Print(a6)
|
||
|
||
.DataLoop1
|
||
tst.w d2
|
||
beq.b .NoDebug2
|
||
moveq #15,d1
|
||
moveq #0,d0
|
||
lea Digit(pc),a1
|
||
lea OutputString(pc),a0
|
||
.DataLoop2
|
||
move.b #"$",(a0)+
|
||
move.b (a4),d0
|
||
lsr.b #4,d0
|
||
move.b (a1,d0.w),(a0)+
|
||
move.b (a4)+,d0
|
||
andi.b #%00001111,d0
|
||
move.b (a1,d0.w),(a0)+
|
||
move.b #",",(a0)+
|
||
subq.w #1,d2
|
||
beq.b .EndLoop
|
||
dbra d1,.DataLoop2
|
||
.EndLoop
|
||
move.b #10,-1(a0)
|
||
clr.b (a0)
|
||
|
||
move.l ad_PVBase(a5),a6
|
||
move.l ad_PVPort(a5),a0
|
||
lea OutputString(pc),a1
|
||
jsr _LVOPP_Print(a6)
|
||
bra.b .DataLoop1
|
||
|
||
.NoDebug2
|
||
movem.l (sp)+,d0-d2/a0-a6
|
||
ENDIF
|
||
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** List of supported commands ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cmd_DevQuery
|
||
move.l IO_DATA(a1),a0
|
||
lea .Support(pc),a2
|
||
move.l #nsdqr_SIZEOF,d0
|
||
clr.l (a0)+ ;DevQueryFormat = 0
|
||
move.l d0,(a0)+ ;SizeAvailable = nsdqr_SIZEOF
|
||
move.w #NSDEVTYPE_TRACKDISK,(a0)+ ;DeviceType = NSDEVTYPE_TRACKDISK
|
||
clr.w (a0)+ ;DeviceSubType = 0
|
||
move.l a2,(a0)+
|
||
move.l d0,IO_ACTUAL(a1)
|
||
rts
|
||
|
||
.Support
|
||
dc.w CMD_RESET
|
||
dc.w CMD_READ
|
||
dc.w CMD_WRITE
|
||
dc.w CMD_UPDATE
|
||
dc.w CMD_CLEAR
|
||
dc.w CMD_STOP
|
||
dc.w CMD_START
|
||
dc.w CMD_FLUSH
|
||
dc.w TD_MOTOR
|
||
dc.w TD_SEEK
|
||
dc.w TD_FORMAT
|
||
dc.w TD_REMOVE
|
||
dc.w TD_CHANGENUM
|
||
dc.w TD_CHANGESTATE
|
||
dc.w TD_PROTSTATUS
|
||
dc.w TD_GETDRIVETYPE
|
||
dc.w TD_GETNUMTRACKS
|
||
dc.w TD_ADDCHANGEINT
|
||
dc.w TD_REMCHANGEINT
|
||
dc.w TD_GETGEOMETRY
|
||
dc.w TD_EJECT
|
||
dc.w HD_SCSICMD
|
||
dc.w NSCMD_DEVICEQUERY
|
||
dc.w NSCMD_TD_READ64
|
||
dc.w NSCMD_TD_WRITE64
|
||
dc.w NSCMD_TD_SEEK64
|
||
dc.w NSCMD_TD_FORMAT64
|
||
dc.w 0
|
||
|
||
;******************************************************************************
|
||
; ----------- END OF THE DRIVE LOW-LEVEL I/O ROUTINES -----------
|
||
;******************************************************************************
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** T<>che attendant les messages envoy<6F>s au device ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cnop 0,4 ;Long word alignment
|
||
dc.l 16 ;Segment size
|
||
dc.l 0 ;Next segment pointer
|
||
TaskCode
|
||
move.l 4(sp),a5 ;A5 : AT-Apollo.device base address
|
||
move.l ad_SysLib(a5),a6 ;A6 : ExecBase
|
||
move.l ad_TaskData(a5),a4 ;A4 : "TaskData" structure
|
||
|
||
;*************** Debugging with PowerVisor v1.42 ******************************
|
||
|
||
IF PVDBG=1
|
||
lea PVName(pc),a1 ;A1 : "powervisor.library"
|
||
moveq #1,d0 ;D0 : Version = 1
|
||
jsr _LVOOpenLibrary(a6) ;Open the library
|
||
move.l d0,ad_PVBase(a5) ;Save the base address
|
||
beq.b .NoDebug ;Null : no debugging
|
||
move.l d0,a6 ;A6 : PVBase
|
||
jsr _LVOPP_InitPortPrint(a6) ;MessagePort initialization
|
||
move.l d0,ad_PVPort(a5) ;Save its address
|
||
move.l ad_SysLib(a5),a6 ;A6 : ExecBase
|
||
.NoDebug
|
||
ENDIF
|
||
|
||
bsr.w CreateMsgPort
|
||
move.l d0,ad_TimerMP(a5) ;MessagePort for the "timer.device"
|
||
|
||
move.l d0,a0
|
||
moveq #IOTV_SIZE,d0
|
||
bsr.w CreateIORequest
|
||
move.l d0,ad_TimerIO(a5)
|
||
|
||
lea TimerName(pc),a0 ;A0: "timer.device"
|
||
move.l d0,a1 ;A1: timerequest
|
||
moveq #UNIT_MICROHZ,d0 ;D0: Accuracy: 1/1000000th of a second
|
||
moveq #0,d1 ;D1: Flags
|
||
jsr _LVOOpenDevice(a6)
|
||
|
||
moveq #-1,d0
|
||
jsr _LVOAllocSignal(a6) ;Signal allocation
|
||
move.b d0,MP_SIGBIT(a4) ;Used for messages receipt
|
||
clr.b MP_FLAGS(a4)
|
||
moveq #0,d7
|
||
bset d0,d7 ;Mask for Wait()
|
||
bra.b .Jump
|
||
.NoMessage
|
||
andi.b #$FF&~(UNITF_INTASK!UNITF_ACTIVE),UNIT_FLAGS(a4)
|
||
.Wait
|
||
move.l d7,d0
|
||
jsr _LVOWait(a6) ;Wait for a signal
|
||
.Jump
|
||
bset #UNITB_ACTIVE,UNIT_FLAGS(a4)
|
||
bne.b .Wait
|
||
.Loop
|
||
move.l a4,a0
|
||
jsr _LVOGetMsg(a6) ;Get a message (Standard I/O Request)
|
||
tst.l d0 ;Null pointer ?
|
||
beq.b .NoMessage ;Yes, no more message
|
||
move.l d0,a1 ;A1 : I/O structure
|
||
exg a6,a5 ;Swap A5 & A6
|
||
move.l IO_UNIT(a1),a3 ;A3 : ApolloUnit base address
|
||
bsr.w PerformIO ;Process the I/O request
|
||
exg a6,a5 ;Swap A5 & A6
|
||
jsr _LVOReplyMsg(a6) ;Reply to the message
|
||
bra.b .Loop ;Loop
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Disk change deamon task ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
cnop 0,4 ;Long word alignment
|
||
dc.l 16 ;Segment size
|
||
dc.l 0 ;Next segment pointer
|
||
DaemonCode
|
||
move.l 4(sp),a5 ;A5 : AT-Apollo.device base address
|
||
move.l ad_SysLib(a5),a6 ;A6 : ExecBase
|
||
move.l ad_DaemonData(a5),a4 ;A4 : "DaemonData" structure
|
||
|
||
bsr.w CreateMsgPort
|
||
move.l d0,dd_TimerMP(a4) ;Message-Port for the "timer.device"
|
||
|
||
move.l d0,a0
|
||
moveq #IOTV_SIZE,d0
|
||
bsr.b CreateIORequest
|
||
move.l d0,dd_TimerIO(a4) ;IoRequest for the "timer.device"
|
||
|
||
lea TimerName(pc),a0 ;A0 : "timer.device"
|
||
move.l d0,a1 ;A1 : IoRequest
|
||
moveq #UNIT_VBLANK,d0 ;D0 : Accuracy: vertical blank
|
||
moveq #0,d1 ;D1 : Flags
|
||
jsr _LVOOpenDevice(a6) ;Open the "timer.device"
|
||
|
||
bsr.w CreateMsgPort
|
||
move.l d0,dd_DevMP(a4) ;Message-Port for the "AT-Apollo.device"
|
||
|
||
moveq #0,d2
|
||
lea dd_DevIO(a4),a3
|
||
.InitLoop
|
||
move.l dd_DevMP(a4),a0
|
||
moveq #IOSTD_SIZE,d0
|
||
bsr.b CreateIORequest
|
||
move.l d0,(a3)+
|
||
|
||
move.l d0,a1 ;A1 : "StdIoRequest" structure
|
||
move.w #APCMD_TESTCHANGED,IO_COMMAND(a1) ;"Test Changed" command
|
||
move.l d2,d0 ;D0 : Unit number
|
||
moveq #0,d1 ;D1 : Flags
|
||
exg a5,a6
|
||
bsr.w Open ;Open the unit
|
||
exg a5,a6
|
||
|
||
addq.w #1,d2 ;Next unit
|
||
cmp.w ad_NumUnits(a5),d2 ;All units open ?
|
||
bne.b .InitLoop ;No, loop
|
||
|
||
.WaitLoop
|
||
move.l dd_TimerIO(a4),a1
|
||
move.w #TR_ADDREQUEST,IO_COMMAND(a1)
|
||
move.l #3,IOTV_TIME+TV_SECS(a1) ;3-second wait
|
||
clr.l IOTV_TIME+TV_MICRO(a1)
|
||
jsr _LVODoIO(a6) ;Start waiting
|
||
|
||
moveq #0,d2
|
||
lea dd_DevIO(a4),a3
|
||
.TestLoop
|
||
move.l (a3)+,a1
|
||
jsr _LVODoIO(a6)
|
||
addq.w #1,d2 ;Next unit
|
||
cmp.w ad_NumUnits(a5),d2 ;All units tested ?
|
||
bne.b .TestLoop ;No, loop
|
||
bra.b .WaitLoop ;Go back to the 3-second wait
|
||
|
||
CreateIORequest
|
||
movem.l d2/d3,-(sp)
|
||
move.l d0,d2
|
||
move.l a0,d3
|
||
beq.b .End
|
||
move.l #MEMF_CLEAR!MEMF_PUBLIC,d1
|
||
jsr _LVOAllocMem(a6)
|
||
move.l d0,a0
|
||
tst.l d0
|
||
beq.b .End
|
||
move.b #NT_REPLYMSG,LN_TYPE(a0)
|
||
move.l d3,MN_REPLYPORT(a0)
|
||
move.w d2,MN_LENGTH(a0)
|
||
.End
|
||
move.l a0,d0
|
||
movem.l (sp)+,d2/d3
|
||
rts
|
||
|
||
CreateMsgPort
|
||
moveq #MP_SIZE,d0
|
||
move.l #MEMF_CLEAR!MEMF_PUBLIC,d1
|
||
jsr _LVOAllocMem(a6)
|
||
move.l d0,-(sp)
|
||
beq.b .End
|
||
moveq #-1,d0
|
||
jsr _LVOAllocSignal(a6)
|
||
move.l (sp),a0
|
||
move.b #NT_MSGPORT,LN_TYPE(a0)
|
||
clr.b MP_FLAGS(a0)
|
||
move.b d0,MP_SIGBIT(a0)
|
||
bmi.b .NoSig
|
||
move.l ThisTask(a6),MP_SIGTASK(a0)
|
||
lea MP_MSGLIST(a0),a1
|
||
move.l a1,MLH_TAILPRED(a1)
|
||
addq.l #MLH_TAIL,a1
|
||
clr.l (a1)
|
||
move.l a1,-(a1)
|
||
.End
|
||
move.l (sp)+,d0
|
||
rts
|
||
.NoSig
|
||
moveq #MP_SIZE,d0
|
||
move.l a0,a1
|
||
jsr _LVOFreeMem(a6)
|
||
clr.l (sp)
|
||
bra.b .End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** CMD_READ command for ATAPI drives ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;D0.l : Logical Block Address (LBA)
|
||
;D1.w : Number of blocks to read
|
||
;A0.l : Destination buffer
|
||
;A3.l : ApolloUnit base address
|
||
|
||
;Return values:
|
||
;--------------
|
||
;D0.b : Error code
|
||
;D1.l : Number of bytes read
|
||
|
||
atapi_Read
|
||
movem.l d2-d6/a0-a6,-(sp)
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
clr.w -(sp)
|
||
lsl.l #8,d1
|
||
movem.l d0/d1,-(sp) ;LBA / Number of blocks
|
||
move.w #SCSI_READ10,-(sp) ;ATAPI READ(10) command
|
||
move.l sp,a4 ;A4 : CDB for the READ command
|
||
|
||
moveq #0,d6 ;D6: Byte counter
|
||
bsr.w SendPacket ;Send CDB's 12 bytes
|
||
beq.w atapi_ErrCmd ;An error has occured
|
||
|
||
.Loop
|
||
bsr.w WaitBusySlow ;Wait for BUSY == 0
|
||
beq.w atapi_ErrCmd ;Time-out elapsed : error
|
||
btst #ATAPIB_DATAREQ,d0 ;Some data to transfer ?
|
||
beq.w atapi_EndCmd ;No, skip
|
||
move.b atapi_Reason(a5),d0 ;Interrupt Reason Register
|
||
andi.b #ATAPIF_MASK,d0 ;Bits IO & CoD
|
||
cmpi.b #ATAPIF_READ,d0 ;Ready to read data ?
|
||
bne.w atapi_ErrCmd ;No, error
|
||
move.b atapi_ByteCntH(a5),d5
|
||
lsl.w #8,d5
|
||
move.b atapi_ByteCntL(a5),d5 ;D5.w : Number of bytes to read
|
||
move.l d5,d4
|
||
lsr.w #3,d5
|
||
subq.w #1,d5
|
||
.ReadLoop
|
||
movem.w (a5),d0-d3 ;Reading two long words from the ATA bus
|
||
movem.w d0-d3,(a0) ;Writing the two long words into memory
|
||
addq.l #8,a0
|
||
dbra d5,.ReadLoop ;Loop
|
||
btst #2,d4 ;One more double long word to read ?
|
||
beq.b .NoLong ;No, skip
|
||
move.l (a5),(a0)+ ;Reading one long word from the ATA bus into memory
|
||
.NoLong
|
||
btst #1,d4 ;One more long word to read ?
|
||
beq.b .NoWord ;No, skip
|
||
move.w (a5),(a0)+ ;Reading one word from the ATA bus into memory
|
||
.NoWord
|
||
add.l d4,d6 ;Number of bytes already read
|
||
bra.b .Loop ;Loop
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** CMD_WRITE command for ATAPI drives ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;D0.l : Logical Block Address (LBA)
|
||
;D1.w : Number of blocks to write
|
||
;A0.l : Source buffer
|
||
;A3.l : ApolloUnit base address
|
||
|
||
;Return values:
|
||
;--------------
|
||
;D0.b : Error code
|
||
;D1.l : Number of bytes written
|
||
|
||
atapi_Write
|
||
movem.l d2-d6/a0-a6,-(sp)
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
clr.w -(sp)
|
||
lsl.l #8,d1
|
||
movem.l d0/d1,-(sp) ;LBA / Number of blocks
|
||
move.w #SCSI_WRITE10,-(sp) ;ATAPI command WRITE(10)
|
||
move.l sp,a4 ;A4 : CDB for the WRITE command
|
||
|
||
moveq #0,d6 ;D6: Byte counter
|
||
bsr.w SendPacket ;Send CDB's 12 bytes
|
||
beq.w atapi_ErrCmd ;An error has occured
|
||
|
||
.Loop
|
||
bsr.w WaitBusySlow ;Wait for BUSY == 0
|
||
beq.w atapi_ErrCmd ;Time-out elapsed : error
|
||
btst #ATAPIB_DATAREQ,d0 ;Some data to transfer ?
|
||
beq.w atapi_EndCmd ;No, skip
|
||
move.b atapi_Reason(a5),d0 ;Interrupt Reason Register
|
||
andi.b #ATAPIF_MASK,d0 ;Bits IO & CoD
|
||
cmpi.b #ATAPIF_WRITE,d0 ;Ready to write data ?
|
||
bne.w atapi_ErrCmd ;No, error
|
||
move.b atapi_ByteCntH(a5),d5
|
||
lsl.w #8,d5
|
||
move.b atapi_ByteCntL(a5),d5 ;D5.w : Number of bytes to write
|
||
move.l d5,d4
|
||
lsr.w #3,d5
|
||
subq.w #1,d5
|
||
.WriteLoop
|
||
movem.w (a0),d0-d3 ;Reading two long words from memory
|
||
movem.w d0-d3,(a5) ;Writing the two long words to the ATA bus
|
||
addq.l #8,a0
|
||
dbra d5,.WriteLoop ;Loop
|
||
btst #2,d4 ;One more double long word to write ?
|
||
beq.b .NoLong ;No, skip
|
||
move.l (a0)+,d0 ;Reading one long word from memory
|
||
swap d0
|
||
swap d0 ;Swap LSBs <-> MSBs
|
||
move.l d0,(a5) ;Writing one long word to the ATA bus
|
||
.NoLong
|
||
btst #1,d4 ;One more long word to write ?
|
||
beq.b .NoWord ;No, skip
|
||
move.w (a0)+,d0 ;Reading one word from memory
|
||
move.w d0,(a5) ;Writing one word to the ATA bus
|
||
.NoWord
|
||
add.l d4,d6 ;Number of bytes already written
|
||
bra.b .Loop ;Loop
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** "Test Unit Ready" command for ATAPI drives ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A3.l : ApolloUnit base address
|
||
|
||
;Return value:
|
||
;-------------
|
||
;D0.b : Sense Key
|
||
|
||
atapi_TestUnit
|
||
movem.l d2-d6/a0-a6,-(sp)
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
clr.l -(sp)
|
||
clr.l -(sp)
|
||
clr.l -(sp) ;ATAPI command "Test Unit Ready"
|
||
move.l sp,a4 ;A4 : CDB for the TEST UNIT READY command
|
||
|
||
bsr.w SendPacket ;Send CDB's 12 bytes
|
||
beq.b atapi_ErrCmd ;An error has occured
|
||
|
||
bsr.w WaitBusySlow ;Wait for BUSY == 0
|
||
beq.b atapi_ErrCmd ;Time-out elapsed : error
|
||
|
||
move.b atapi_Error(a5),d0
|
||
lsr.b #4,d0 ;D0: Sense key
|
||
beq.b .NoSense
|
||
move.b d0,au_SenseKey(a3)
|
||
.NoSense
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
lea 12(sp),sp ;Restore stack
|
||
movem.l (sp)+,d2-d6/a0-a6 ;Restore registers
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** TD_SEEK command for ATAPI drive ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;D0.l : Logical Block Address (LBA)
|
||
;A3.l : ApolloUnit base address
|
||
|
||
;Return value:
|
||
;-------------
|
||
;D0.b : Error code
|
||
|
||
atapi_Seek
|
||
movem.l d2-d6/a0-a6,-(sp)
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
clr.l -(sp)
|
||
clr.w -(sp)
|
||
move.l d0,-(sp) ;LBA
|
||
move.w #SCSI_SEEK10,-(sp) ;ATAPI command SEEK(10)
|
||
move.l sp,a4 ;A4 : CDB for the SEEK command
|
||
|
||
move.l d1,d6 ;Save D1 into D6 !
|
||
bsr.w SendPacket ;Send CDB's 12 bytes
|
||
beq.b atapi_ErrCmd ;An error has occured
|
||
|
||
bsr.w WaitBusySlow ;Wait for BUSY == 0
|
||
beq.b atapi_ErrCmd ;Time-out elapsed : error
|
||
|
||
bra.b atapi_EndCmd ;End of the command
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** TD_EJECT command for ATAPI drive ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A3.l : ApolloUnit base address
|
||
|
||
;Return value:
|
||
;-------------
|
||
;D0.b : Error code
|
||
|
||
atapi_Eject
|
||
movem.l d2-d6/a0-a6,-(sp)
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
clr.l -(sp)
|
||
clr.w -(sp)
|
||
move.w #$0200,-(sp) ;Flags : eject
|
||
clr.w -(sp)
|
||
move.w #SCSI_STARTSTOP!1<<8,-(sp) ;ATAPI command START/STOP UNIT
|
||
move.l sp,a4 ;A4 : CDB for the START/STOP UNIT command
|
||
|
||
move.l d1,d6 ;Save D1 into D6 !
|
||
bsr.w SendPacket ;Send CDB's 12 bytes
|
||
beq.b atapi_ErrCmd ;An error has occured
|
||
|
||
bsr.w WaitBusySlow ;Wait for BUSY == 0
|
||
beq.b atapi_ErrCmd ;Time-out elapsed : error
|
||
|
||
bra.b atapi_EndCmd ;End of the command
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** End of ATAPI commands ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
atapi_ErrCmd
|
||
lea 12(sp),sp ;Restore stack
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #CDERR_ABORTED,d0 ;D0: Error code
|
||
move.l d6,d1 ;D1: Number of bytes read
|
||
movem.l (sp)+,d2-d6/a0-a6 ;Restore registers
|
||
rts ;End
|
||
|
||
atapi_EndCmd
|
||
st.b au_Used(a3) ;Unit has been used
|
||
|
||
moveq #0,d0
|
||
btst #ATAPIB_CHECK,atapi_Status(a5) ;An error has occured ?
|
||
beq.b .End ;No, exit
|
||
|
||
move.b atapi_Error(a5),d0
|
||
lsr.b #4,d0 ;D0: Sense key
|
||
move.b .ErrorMap(pc,d0.w),d0 ;D0: Error code
|
||
|
||
.End
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
move.l d6,d1 ;D1: Number of bytes read
|
||
lea 12(sp),sp ;Restore stack
|
||
movem.l (sp)+,d2-d6/a0-a6 ;Restore registers
|
||
rts ;End
|
||
|
||
.ErrorMap
|
||
dc.b CDERR_NotSpecified ;NO SENSE
|
||
dc.b CDERR_NoSecHdr ;RECOVERED ERROR
|
||
dc.b CDERR_NoDisk ;NOT READY
|
||
dc.b CDERR_NoSecHdr ;MEDIUM ERROR
|
||
dc.b CDERR_NoSecHdr ;HARDWARE ERROR
|
||
dc.b CDERR_NOCMD ;ILLEGAL REQUEST
|
||
dc.b CDERR_NoDisk ;UNIT ATTENTION
|
||
dc.b CDERR_WriteProt ;DATA PROTECT
|
||
dc.b CDERR_NotSpecified ;Reserved
|
||
dc.b CDERR_NotSpecified ;Reserved
|
||
dc.b CDERR_NotSpecified ;Reserved
|
||
dc.b CDERR_ABORTED ;ABORTED COMMAND
|
||
dc.b CDERR_NotSpecified ;Reserved
|
||
dc.b CDERR_NotSpecified ;Reserved
|
||
dc.b CDERR_NoSecHdr ;MISCOMPARE
|
||
dc.b CDERR_NotSpecified ;Reserved
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** CMD_READ command for ATA drives ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;D0.l : Logical Block Address (LBA)
|
||
;D1.l : Number of blocks to read
|
||
;A0.l : Destination buffer
|
||
;A3.l : ApolloUnit base address
|
||
|
||
;Return values:
|
||
;--------------
|
||
;D0.b : Error code
|
||
;D1.l : Number of blocks lus
|
||
|
||
;*************** Normal slow read *********************************************
|
||
|
||
ata_SlowReadNorm
|
||
movem.l d1/d2/a0/a5/a6,-(sp)
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
cmp.l au_Blocks(a3),d0 ;LBA >= Total number of blocks ?
|
||
bcc.b .Error ;Yes, error
|
||
tst.l d1 ;Is number of blocks to read null ?
|
||
beq.b .EndLoop ;Yes, exit
|
||
|
||
bsr.w CalcBlockAddr ;Compute block address
|
||
beq.b .Error ;Error : exit
|
||
|
||
.SectLoop
|
||
move.b d1,ata_SectorCnt(a5) ;Number of sectors to read
|
||
move.b #ATA_READ,ata_Command(a5) ;ATA read command ($20)
|
||
|
||
.ReadLoop
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
btst #ATAB_DATAREQ,d0 ;DREQ = 1 ?
|
||
beq.b .Error ;No, error
|
||
move.b d0,d2 ;"ata_Status" into D2
|
||
|
||
moveq #BLOCK_SIZE/4-1,d0 ;Number of long words to read (minus 1)
|
||
.Loop
|
||
move.w (a5),(a0)+ ;One word transfer
|
||
move.w (a5),(a0)+ ;One word transfer
|
||
dbra d0,.Loop ;Loop
|
||
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
btst #ATAB_ERROR,d2 ;Check ATA error bit
|
||
bne.b .Error ;Set : exit with an error
|
||
subq.l #1,d1 ;One sector read
|
||
tst.b d1 ;Null LSB ?
|
||
bne.b .ReadLoop ;No, loop
|
||
|
||
tst.l d1 ;No more sector to read ?
|
||
beq.b .EndLoop ;Yes, exit
|
||
bsr.w IncrBlockAddr ;No, CHS/LBA address increment
|
||
bra.b .SectLoop ;Loop
|
||
|
||
.EndLoop
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #0,d0 ;No error
|
||
.End
|
||
move.l (sp)+,d1 ;Number of blocks read
|
||
move.b au_SectShift(a3),d2 ;Logical shift (9 or 11)
|
||
lsl.l d2,d1 ;Number of bytes read
|
||
movem.l (sp)+,d2/a0/a5/a6 ;Restore registers
|
||
rts ;End
|
||
|
||
.Error
|
||
sub.l d1,(sp) ;Number of blocks already read
|
||
bsr.w ResumeError ;Drive reset
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #TDERR_NotSpecified,d0 ;Error code
|
||
bra.b .End ;End
|
||
|
||
;*************** Swapped slow read ********************************************
|
||
|
||
ata_SlowReadSwap
|
||
movem.l d1-d3/a0/a5/a6,-(sp)
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
cmp.l au_Blocks(a3),d0 ;LBA >= Total number of blocks ?
|
||
bcc.w .Error ;Yes, error
|
||
tst.l d1 ;Is number of blocks to read null ?
|
||
beq.b .EndLoop ;Yes, exit
|
||
|
||
bsr.w CalcBlockAddr ;Compute block address
|
||
beq.b .Error ;Error : exit
|
||
|
||
.SectLoop
|
||
move.b d1,ata_SectorCnt(a5) ;Number of sectors to read
|
||
move.b #ATA_READ,ata_Command(a5) ;ATA read command ($20)
|
||
|
||
.ReadLoop
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
btst #ATAB_DATAREQ,d0 ;DREQ = 1 ?
|
||
beq.b .Error ;No, error
|
||
move.b d0,d2 ;"ata_Status" into D2
|
||
|
||
moveq #BLOCK_SIZE/4-1,d0 ;Number of long words to read (minus 1)
|
||
.Loop
|
||
move.w (a5),d3
|
||
rol.w #8,d3
|
||
move.w d3,(a0)+ ;Swapped word read
|
||
move.w (a5),d3
|
||
rol.w #8,d3
|
||
move.w d3,(a0)+ ;Swapped word read
|
||
dbra d0,.Loop ;Loop
|
||
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
btst #ATAB_ERROR,d2 ;Check ATA error bit
|
||
bne.b .Error ;Set : exit with an error
|
||
subq.l #1,d1 ;One sector read
|
||
tst.b d1 ;Null LSB ?
|
||
bne.b .ReadLoop ;No, loop
|
||
|
||
tst.l d1 ;No more sector to read ?
|
||
beq.b .EndLoop ;Yes, exit
|
||
bsr.w IncrBlockAddr ;No, CHS/LBA address increment
|
||
bra.b .SectLoop ;Loop
|
||
|
||
.EndLoop
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #0,d0 ;No error
|
||
.End
|
||
move.l (sp)+,d1 ;Number of blocks read
|
||
move.b au_SectShift(a3),d2 ;Logical shift (9 or 11)
|
||
lsl.l d2,d1 ;Number of bytes read
|
||
movem.l (sp)+,d2/d3/a0/a5/a6 ;Restore registers
|
||
rts ;End
|
||
|
||
.Error
|
||
sub.l d1,(sp) ;Number of blocks already read
|
||
bsr.w ResumeError ;Drive reset
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #TDERR_NotSpecified,d0 ;Error code
|
||
bra.b .End ;End
|
||
|
||
;*************** Normal fast read *********************************************
|
||
|
||
ata_FastReadNorm
|
||
movem.l d1-d7/a0-a6,-(sp)
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
cmp.l au_Blocks(a3),d0 ;LBA >= Total number of blocks ?
|
||
bcc.w .Error1 ;Yes, error
|
||
tst.l d1 ;Is number of blocks to read null ?
|
||
beq.w .EndLoop ;Yes, exit
|
||
|
||
bsr.w CalcBlockAddr ;Compute block address
|
||
beq.w .Error1 ;Error : exit
|
||
|
||
lea $3D0(a5),a5 ;A5 : Source
|
||
moveq #$30,d7 ;D7 : Incr<63>ment
|
||
|
||
.SectLoop
|
||
move.b d1,ata_SectorCnt(a5) ;Number of sectors to read
|
||
move.b #ATA_READ,ata_Command(a5) ;ATA read command ($20)
|
||
movem.l d1/a3/a6,-(sp) ;Save D1, A3 & A6
|
||
|
||
.ReadLoop
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.w .Error2 ;Time-out elapsed : error
|
||
btst #ATAB_DATAREQ,d0 ;DREQ = 1 ?
|
||
beq.w .Error2 ;No, error
|
||
move.w d0,-(sp) ;Save "ata_Status"
|
||
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;1st 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;2nd 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;3rd 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;4th 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;5th 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;6th 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;7th 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;8th 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;9th 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;10th 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l $10(a5),d0-d6/a1
|
||
movem.l d0-d6/a1,(a0) ;Last 8-long-word transfer
|
||
lea $20(a0),a0 ;512 bytes : 12*10+8 long words
|
||
|
||
move.w (sp)+,d1 ;D1 : ata_Status
|
||
move.l 4(sp),a3 ;Restore A3
|
||
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error2 ;Time-out elapsed : error
|
||
btst #ATAB_ERROR,d1 ;Check ATA error bit
|
||
bne.b .Error2 ;Set : exit with an error
|
||
subq.l #1,(sp) ;One sector read
|
||
tst.b 3(sp) ;Null LSB ?
|
||
bne.w .ReadLoop ;No, loop
|
||
|
||
movem.l (sp)+,d1/a3/a6 ;Restore D1, A3 & A6
|
||
tst.l d1 ;No more sector to read ?
|
||
beq.b .EndLoop ;Yes, exit
|
||
bsr.w IncrBlockAddr ;No, CHS/LBA address incremement
|
||
bra.w .SectLoop ;Loop
|
||
|
||
.EndLoop
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #0,d0 ;No error
|
||
.End
|
||
move.l (sp)+,d1 ;Number of blocks read
|
||
move.b au_SectShift(a3),d2 ;Logical shift (9 or 11)
|
||
lsl.l d2,d1 ;Number of bytes read
|
||
movem.l (sp)+,d2-d7/a0-a6 ;Restore registers
|
||
rts ;End
|
||
|
||
.Error2
|
||
movem.l (sp)+,d1/a3/a6 ;Restore D1, A3 & A6
|
||
|
||
.Error1
|
||
sub.l d1,(sp) ;Number of blocks already read
|
||
bsr.w ResumeError ;Drive reset
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #TDERR_NotSpecified,d0 ;Error code
|
||
bra.b .End ;End
|
||
|
||
;*************** Swapped fast read ********************************************
|
||
|
||
ata_FastReadSwap
|
||
movem.l d1-d7/a0-a6,-(sp)
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
cmp.l au_Blocks(a3),d0 ;LBA >= Total number of blocks ?
|
||
bcc.w .Error1 ;Yes, error
|
||
tst.l d1 ;Is number of blocks to read null ?
|
||
beq.w .EndLoop ;Yes, exit
|
||
|
||
bsr.w CalcBlockAddr ;Compute block address
|
||
beq.w .Error1 ;Error : exit
|
||
|
||
lea $3D0(a5),a5 ;A5 : Source
|
||
moveq #$30,d7 ;D7 : Increment
|
||
.SectLoop
|
||
move.b d1,ata_SectorCnt(a5) ;Number of sectors to read
|
||
move.b #ATA_READ,ata_Command(a5) ;ATA read command ($20)
|
||
movem.l d1/a3/a6,-(sp) ;Save D1, A3 & A6
|
||
|
||
|
||
;*************** Fast read, followed by fast swap *****************************
|
||
|
||
.Loop
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.w .Error2 ;Time-out elapsed : error
|
||
btst #ATAB_DATAREQ,d0 ;DREQ = 1 ?
|
||
beq.w .Error2 ;No, error
|
||
move.w d0,-(sp) ;Save "ata_Status"
|
||
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;1st 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;2nd 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;3rd 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;4th 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;5th 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;6th 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;7th 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;8th 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;9th 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l (a5),d0-d6/a1-a4/a6
|
||
movem.l d0-d6/a1-a4/a6,(a0) ;10th 12-long-word transfer
|
||
add.l d7,a0
|
||
movem.l $10(a5),d0-d6/a1
|
||
movem.l d0-d6/a1,(a0) ;Last 8-long-word transfer
|
||
lea $20(a0),a0 ;512 bytes : 12*10+8 long words
|
||
|
||
lea -BLOCK_SIZE(a0),a0
|
||
moveq #BLOCK_SIZE/8-1,d0 ;Nomber of 8-byte bursts
|
||
.SwapLoop
|
||
movem.w (a0)+,d2-d5 ;Read 8 bytes from memory
|
||
rol.w #8,d2
|
||
rol.w #8,d3
|
||
rol.w #8,d4
|
||
rol.w #8,d5 ;Swap LSBs <-> MSBs
|
||
movem.w d2-d5,-8(a0) ;Write 8 bytes to memory
|
||
dbra d0,.SwapLoop ;Loop
|
||
|
||
move.w (sp)+,d1 ;D1 : ata_Status
|
||
move.l 4(sp),a3 ;Restore A3
|
||
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error2 ;Time-out elapsed : error
|
||
btst #ATAB_ERROR,d1 ;Check ATA error bit
|
||
bne.b .Error2 ;Set : exit with an error
|
||
subq.l #1,(sp) ;One sector read
|
||
tst.b 3(sp) ;Null LSB ?
|
||
bne.w .Loop ;No, loop
|
||
|
||
movem.l (sp)+,d1/a3/a6 ;Restore D1, A3 & A6
|
||
tst.l d1 ;No more sector to read ?
|
||
beq.b .EndLoop ;Yes, exit
|
||
bsr.w IncrBlockAddr ;No, CHS/LBA address increment
|
||
bra.w .SectLoop ;Loop
|
||
|
||
.EndLoop
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #0,d0 ;No error
|
||
.End
|
||
move.l (sp)+,d1 ;Number of blocks read
|
||
move.b au_SectShift(a3),d2 ;Logical shift (9 or 11)
|
||
lsl.l d2,d1 ;Number of bytes read
|
||
movem.l (sp)+,d2-d7/a0-a6 ;Restore registers
|
||
rts ;End
|
||
|
||
.Error2
|
||
movem.l (sp)+,d1/a3/a6 ;Restore D1, A3 & A6
|
||
|
||
.Error1
|
||
sub.l d1,(sp) ;Number of blocks already read
|
||
bsr.w ResumeError ;Drive reset
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #TDERR_NotSpecified,d0 ;Error code
|
||
bra.b .End ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** CMD_WRITE command for ATA drives ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;D0.l : Logical Block Address (LBA)
|
||
;D1.l : Number of blocks to write
|
||
;A0.l : Source buffer
|
||
;A3.l : ApolloUnit base address
|
||
|
||
;Return values:
|
||
;--------------
|
||
;D0.b : Error code
|
||
;D1.l : Number of bytes written
|
||
|
||
;*************** Normal slow write ********************************************
|
||
|
||
ata_SlowWriteNorm
|
||
movem.l d0-d2/a0/a5/a6,-(sp)
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
cmp.l au_Blocks(a3),d0 ;LBA >= Total number of blocks ?
|
||
bcc.b .Error ;Yes, error
|
||
tst.l d1 ;Number of blocks to write is null ?
|
||
beq.b .EndLoop ;Yes, exit
|
||
|
||
bsr.w CalcBlockAddr ;Compute block address
|
||
beq.b .Error ;Error : exit
|
||
|
||
.SectLoop
|
||
move.b d1,ata_SectorCnt(a5) ;Number of sectors to write
|
||
move.b #ATA_WRITE,ata_Command(a5) ;ATA write command ($30)
|
||
|
||
.WriteLoop
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
btst #ATAB_ERROR,d0 ;Check ATA error bit
|
||
bne.b .Error ;Set : exit with an error
|
||
btst #ATAB_DATAREQ,d0 ;DREQ = 1 ?
|
||
beq.b .Error ;No, error
|
||
|
||
moveq #BLOCK_SIZE/4-1,d0 ;Number of long words to write (minus 1)
|
||
.Loop
|
||
move.w (a0)+,(a5) ;One word transfer
|
||
move.w (a0)+,(a5) ;One word transfer
|
||
dbra d0,.Loop ;Loop
|
||
|
||
subq.l #1,d1 ;One sector written
|
||
tst.b d1 ;Null LSB ?
|
||
bne.b .WriteLoop ;No, loop
|
||
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
tst.l d1 ;More sectors to write ?
|
||
bne.b .Continue ;Yes, continue
|
||
btst #ATAB_ERROR,d0 ;Check ATA error bit
|
||
bne.b .Error ;Set : exit with an error
|
||
|
||
.EndLoop
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #0,d0 ;No error
|
||
.End
|
||
addq.l #4,sp
|
||
move.l (sp)+,d1 ;Number of blocks written
|
||
move.b au_SectShift(a3),d2 ;Logical shift (9 or 11)
|
||
lsl.l d2,d1 ;Number of bytes written
|
||
movem.l (sp)+,d2/a0/a5/a6 ;Restore registers
|
||
rts ;End
|
||
|
||
.Continue
|
||
move.l (sp),d0 ;Logical block number (LBA)
|
||
add.l 4(sp),d0 ;+ Number of blocks to write
|
||
sub.l d1,d0 ;- Number of remaining blocks to write
|
||
bsr.w CalcBlockAddr ;Compute block address
|
||
beq.b .Error
|
||
bra.b .SectLoop ;Loop
|
||
|
||
.Error
|
||
sub.l d1,4(sp) ;Number of blocks already written
|
||
bsr.w ResumeError ;Drive reset
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #TDERR_NotSpecified,d0 ;Error code
|
||
bra.b .End ;End
|
||
|
||
;*************** Swapped slow write *******************************************
|
||
|
||
ata_SlowWriteSwap
|
||
movem.l d0-d2/a0/a5/a6,-(sp)
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
cmp.l au_Blocks(a3),d0 ;LBA >= Total number of blocks ?
|
||
bcc.b .Error ;Yes, error
|
||
tst.l d1 ;Is number of blocks to write null ?
|
||
beq.b .EndLoop ;Yes, exit
|
||
|
||
bsr.w CalcBlockAddr ;Compute block address
|
||
beq.b .Error ;Error : exit
|
||
|
||
.SectLoop
|
||
move.b d1,ata_SectorCnt(a5) ;Number of sectors to write
|
||
move.b #ATA_WRITE,ata_Command(a5) ;ATA write command ($30)
|
||
|
||
.WriteLoop
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
btst #ATAB_ERROR,d0 ;Check ATA error bit
|
||
bne.b .Error ;Set : exit with an error
|
||
btst #ATAB_DATAREQ,d0 ;DREQ = 1 ?
|
||
beq.b .Error ;No, error
|
||
|
||
moveq #BLOCK_SIZE/4-1,d0 ;Number of long words to write (minus 1)
|
||
.Loop
|
||
move.w (a0)+,d2
|
||
rol.w #8,d2
|
||
move.w d2,(a5) ;Swapped word write
|
||
move.w (a0)+,d2
|
||
rol.w #8,d2
|
||
move.w d2,(a5) ;Swapped word write
|
||
dbra d0,.Loop ;Loop
|
||
|
||
subq.l #1,d1 ;One sector written
|
||
tst.b d1 ;Null LSB ?
|
||
bne.b .WriteLoop ;No, loop
|
||
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
tst.l d1 ;More sectors to write ?
|
||
bne.b .Continue ;Yes, continue
|
||
btst #ATAB_ERROR,d0 ;Check ATA error bit
|
||
bne.b .Error ;Set : exit with an error
|
||
|
||
.EndLoop
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #0,d0 ;No error
|
||
.End
|
||
addq.l #4,sp
|
||
move.l (sp)+,d1 ;Number of blocks written
|
||
move.b au_SectShift(a3),d2 ;Logical shift (9 or 11)
|
||
lsl.l d2,d1 ;Number of bytes written
|
||
movem.l (sp)+,d2/a0/a5/a6 ;Restore registers
|
||
rts ;End
|
||
|
||
.Continue
|
||
move.l (sp),d0 ;Logical block number (LBA)
|
||
add.l 4(sp),d0 ;+ Number of blocks to write
|
||
sub.l d1,d0 ;- Number of remaining blocks to write
|
||
bsr.w CalcBlockAddr ;Compute block address
|
||
beq.b .Error
|
||
bra.w .SectLoop ;Loop
|
||
|
||
.Error
|
||
sub.l d1,4(sp) ;Number of blocks already written
|
||
bsr.w ResumeError ;Drive reset
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #TDERR_NotSpecified,d0 ;Error code
|
||
bra.b .End ;End
|
||
|
||
;*************** Normal fast write ********************************************
|
||
|
||
ata_FastWriteNorm
|
||
movem.l d0-d7/a0-a6,-(sp)
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
cmp.l au_Blocks(a3),d0 ;LBA >= Total number of blocks ?
|
||
bcc.w .Error1 ;Yes, error
|
||
tst.l d1 ;Is number of blocks to write null ?
|
||
beq.w .EndLoop ;Yes, exit
|
||
|
||
bsr.w CalcBlockAddr ;Compute block address
|
||
beq.w .Error1 ;Error : exit
|
||
|
||
.SectLoop
|
||
move.b d1,ata_SectorCnt(a5) ;Number of sectors to write
|
||
move.b #ATA_WRITE,ata_Command(a5) ;ATA write command ($30)
|
||
movem.l a3/a6,-(sp) ;Save A3 & A6
|
||
|
||
.WriteLoop
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.w .Error2 ;Time-out elapsed : error
|
||
btst #ATAB_ERROR,d0 ;Check ATA error bit
|
||
bne.w .Error2 ;Set : exit with an error
|
||
btst #ATAB_DATAREQ,d0 ;DREQ = 1 ?
|
||
beq.w .Error2 ;No, error
|
||
|
||
movem.l (a0)+,d0/d2-d7/a1-a4/a6
|
||
movem.l d0/d2-d7/a1-a4/a6,(a5) ;1st 12-long-word transfer
|
||
movem.l (a0)+,d0/d2-d7/a1-a4/a6
|
||
movem.l d0/d2-d7/a1-a4/a6,(a5) ;2nd 12-long-word transfer
|
||
movem.l (a0)+,d0/d2-d7/a1-a4/a6
|
||
movem.l d0/d2-d7/a1-a4/a6,(a5) ;3rd 12-long-word transfer
|
||
movem.l (a0)+,d0/d2-d7/a1-a4/a6
|
||
movem.l d0/d2-d7/a1-a4/a6,(a5) ;4th 12-long-word transfer
|
||
movem.l (a0)+,d0/d2-d7/a1-a4/a6
|
||
movem.l d0/d2-d7/a1-a4/a6,(a5) ;5th 12-long-word transfer
|
||
movem.l (a0)+,d0/d2-d7/a1-a4/a6
|
||
movem.l d0/d2-d7/a1-a4/a6,(a5) ;6th 12-long-word transfer
|
||
movem.l (a0)+,d0/d2-d7/a1-a4/a6
|
||
movem.l d0/d2-d7/a1-a4/a6,(a5) ;7th 12-long-word transfer
|
||
movem.l (a0)+,d0/d2-d7/a1-a4/a6
|
||
movem.l d0/d2-d7/a1-a4/a6,(a5) ;8th 12-long-word transfer
|
||
movem.l (a0)+,d0/d2-d7/a1-a4/a6
|
||
movem.l d0/d2-d7/a1-a4/a6,(a5) ;9th 12-long-word transfer
|
||
movem.l (a0)+,d0/d2-d7/a1-a4/a6
|
||
movem.l d0/d2-d7/a1-a4/a6,(a5) ;10th 12-long-word transfer
|
||
movem.l (a0)+,d0/d2-d7/a1
|
||
movem.l d0/d2-d7/a1,(a5) ;Last 8-long-word transfer
|
||
;512 bytes : 12*10+8 long words
|
||
movem.l (sp),a3/a6 ;Restore A3 & A6
|
||
subq.l #1,d1 ;One sector written
|
||
tst.b d1 ;Null LSB ?
|
||
bne.b .WriteLoop ;No, loop
|
||
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error2 ;Time-out elapsed : error
|
||
movem.l (sp)+,a3/a6 ;Restore A3 & A6
|
||
tst.l d1 ;More sectors to write ?
|
||
bne.b .Continue ;Yes, continue
|
||
btst #ATAB_ERROR,d0 ;Check ATA error bit
|
||
bne.b .Error1 ;Set : exit with an error
|
||
|
||
.EndLoop
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #0,d0 ;No error
|
||
.End
|
||
addq.l #4,sp
|
||
move.l (sp)+,d1 ;Number of blocks written
|
||
move.b au_SectShift(a3),d2 ;Logical shift (9 or 11)
|
||
lsl.l d2,d1 ;Number of bytes written
|
||
movem.l (sp)+,d2-d7/a0-a6 ;Restore registers
|
||
rts ;End
|
||
|
||
.Continue
|
||
move.l (sp),d0 ;Logical block number (LBA)
|
||
add.l 4(sp),d0 ;+ Number of blocks to write
|
||
sub.l d1,d0 ;- Number of remaining blocks to write
|
||
bsr.w CalcBlockAddr ;Compute block address
|
||
beq.b .Error1
|
||
bra.w .SectLoop ;Loop
|
||
|
||
.Error2
|
||
movem.l (sp)+,a3/a6 ;Restore A3 & A6
|
||
|
||
.Error1
|
||
sub.l d1,4(sp) ;Number of blocks already written
|
||
bsr.w ResumeError ;Drive reset
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #TDERR_NotSpecified,d0 ;Error code
|
||
bra.b .End ;End
|
||
|
||
;*************** Swapped fast write *******************************************
|
||
|
||
ata_FastWriteSwap
|
||
movem.l d0-d7/a0/a5/a6,-(sp)
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
cmp.l au_Blocks(a3),d0 ;LBA >= Total number of blocks ?
|
||
bcc.w .Error ;Yes, error
|
||
tst.l d1 ;Is number of blocks to write null ?
|
||
beq.b .EndLoop ;Yes, exit
|
||
|
||
bsr.w CalcBlockAddr ;Compute block address
|
||
beq.w .Error ;Error : exit
|
||
|
||
.SectLoop
|
||
move.b d1,ata_SectorCnt(a5) ;Number of sectors to write
|
||
move.b #ATA_WRITE,ata_Command(a5) ;ATA write command ($30)
|
||
|
||
.WriteLoop
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.w .Error ;Time-out elapsed : error
|
||
btst #ATAB_ERROR,d0 ;Check ATA error bit
|
||
bne.w .Error ;Set : exit with an error
|
||
btst #ATAB_DATAREQ,d0 ;DREQ = 1 ?
|
||
beq.b .Error ;No, error
|
||
|
||
moveq #BLOCK_SIZE/32-1,d0 ;Number of 32-byte bursts (minus 1)
|
||
.Loop
|
||
movem.w (a0)+,d2-d7
|
||
rol.w #8,d2
|
||
rol.w #8,d3
|
||
rol.w #8,d4
|
||
rol.w #8,d5
|
||
rol.w #8,d6
|
||
rol.w #8,d7
|
||
movem.w d2-d7,(a5) ;6-word transfer
|
||
movem.w (a0)+,d2-d7
|
||
rol.w #8,d2
|
||
rol.w #8,d3
|
||
rol.w #8,d4
|
||
rol.w #8,d5
|
||
rol.w #8,d6
|
||
rol.w #8,d7
|
||
movem.w d2-d7,(a5) ;6-word transfer
|
||
movem.w (a0)+,d2-d5
|
||
rol.w #8,d2
|
||
rol.w #8,d3
|
||
rol.w #8,d4
|
||
rol.w #8,d5
|
||
movem.w d2-d5,(a5) ;4-word transfer
|
||
dbra d0,.Loop ;Loop
|
||
|
||
subq.l #1,d1 ;One secteur written
|
||
tst.b d1 ;Null LSB ?
|
||
bne.b .WriteLoop ;No, loop
|
||
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
tst.l d1 ;More sectors to write ?
|
||
bne.b .Continue ;Yes, continue
|
||
btst #ATAB_ERROR,d0 ;Check ATA error bit
|
||
bne.b .Error ;Set : exit with an error
|
||
|
||
.EndLoop
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #0,d0 ;No error
|
||
.End
|
||
addq.l #4,sp
|
||
move.l (sp)+,d1 ;Number of blocks written
|
||
move.b au_SectShift(a3),d2 ;Logical shift (9)
|
||
lsl.l d2,d1 ;Number of bytes written
|
||
movem.l (sp)+,d2-d7/a0/a5/a6 ;Restore registers
|
||
rts ;End
|
||
|
||
.Continue
|
||
move.l (sp),d0 ;Logical block number (LBA)
|
||
add.l 4(sp),d0 ;+ Number of blocks to write
|
||
sub.l d1,d0 ;- Number of remaining blocks to write
|
||
bsr.w CalcBlockAddr ;Compute block address
|
||
beq.b .Error
|
||
bra.w .SectLoop ;Loop
|
||
|
||
.Error
|
||
sub.l d1,4(sp) ;Number of blocks already written
|
||
bsr.w ResumeError ;Drive reset
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #TDERR_NotSpecified,d0 ;Error code
|
||
bra.b .End ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** TD_SEEK command for ATA drives ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;D0.l : Logical Block Address (LBA)
|
||
;A3.l : ApolloUnit base address
|
||
|
||
;Return value:
|
||
;-------------
|
||
;D0.b : Error code
|
||
|
||
ata_Seek
|
||
movem.l a5/a6,-(sp) ;Save A5 & A6
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
cmp.l au_Blocks(a3),d0 ;LBA >= Total number of blocks ?
|
||
bcc.b .Error1 ;Yes, error
|
||
|
||
bsr.w CalcBlockAddr ;Otherwise, compute block address
|
||
beq.b .Error2 ;Error : exit
|
||
|
||
move.b #ATA_SEEK,ata_Command(a5) ;ATA seek command ($70)
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error3 ;Time-out elapsed : error
|
||
btst #ATAB_ERROR,d0 ;Check ATA error bit
|
||
bne.b .Error3 ;Set : exit with an error
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #0,d0 ;No error
|
||
movem.l (sp)+,a5/a6 ;Restore A5 & A6
|
||
rts ;End
|
||
|
||
.Error1
|
||
move.w #$0521,d1 ;Illegal request + LBA out of range
|
||
bra.b .EndErr
|
||
|
||
.Error2
|
||
move.w #$0205,d1 ;Not ready + Logical unit not respond
|
||
bra.b .EndErr
|
||
|
||
.Error3
|
||
bsr.w CurrBlockAddr
|
||
move.w #$0B02,d1 ;Aborted command + No seek complete
|
||
|
||
.EndErr
|
||
move.l d0,au_LBASense(a3)
|
||
move.w d1,au_SenseKey(a3)
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #TDERR_NotSpecified,d0 ;Error code
|
||
movem.l (sp)+,a5/a6 ;Restore A5 & A6
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** TD_EJECT command for ATA drives ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A3.l : ApolloUnit base address
|
||
|
||
;Return value:
|
||
;-------------
|
||
;D0.b : Error code
|
||
|
||
ata_Eject
|
||
movem.l a5/a6,-(sp) ;Save A5 & A6
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
move.b au_DevMask,ata_DevHead(a5) ;Select the drive
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
move.b #ATA_MEDIAEJECT,ata_Command(a5) ;Send the EJECT command
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
btst #ATAB_ERROR,d0 ;Check ATA error bit
|
||
bne.b .Error ;Set : exit with an error
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #0,d0 ;No error
|
||
movem.l (sp)+,a5/a6 ;Restore A5 & A6
|
||
rts ;End
|
||
|
||
.Error
|
||
move.w #$0205,au_SenseKey(a3) ;Not ready + Logical unit not respond
|
||
clr.l au_LBASense(a3)
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #TDERR_NotSpecified,d0 ;Error code
|
||
movem.l (sp)+,a5/a6 ;Restore A5 & A6
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** "AutoDetect" command for an ATA drive (3) ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A0.l : Destination buffer
|
||
;A3.l : ApolloUnit base address
|
||
|
||
;Return value:
|
||
;-------------
|
||
;Z Flag (0:Ok, 1:Error)
|
||
|
||
ata_Identify
|
||
movem.l d0/d1/a5/a6,-(sp) ;Save D0, D1, A5 & A6
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
;*************** Sending the command to the drive *****************************
|
||
|
||
move.b #ATA_IDENTDEV,d1 ;ATA command
|
||
tst.b au_AtapiDev(a3)
|
||
beq.b .NoAtapi
|
||
move.b #ATAPI_IDENTDEV,d1 ;ATAPI command
|
||
.NoAtapi
|
||
|
||
move.b au_DevMask(a3),ata_DevHead(a5) ;Drive select
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.w .Error ;Time-out elapsed : error
|
||
move.b d1,ata_Command(a5) ;IDENTIFY DEVICE command
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.w .Error ;Time-out elapsed : error
|
||
btst #ATAB_DATAREQ,d0 ;DREQ = 1 ?
|
||
beq.w .Error ;No, error
|
||
|
||
;*************** Reading parameters *******************************************
|
||
|
||
move.l #idev_SIZEOF/2-1,d0 ;D0: Words to read minus 1
|
||
.Loop1
|
||
move.w (a5),d1 ; Read one word
|
||
rol.w #8,d1 ; Swap LSB <-> MSB
|
||
move.w d1,(a0)+ ; Store 1 Word
|
||
dbra d0,.Loop1 ;Loop
|
||
lea -idev_SIZEOF(a0),a0 ;Restore A0
|
||
|
||
btst #ATAB_ERROR,ata_Status(a5) ;Check ATA error bit
|
||
bne.w .Error ;Set : exit with an error
|
||
|
||
tst.b au_AtapiDev(a3) ;ATAPI protocol ?
|
||
beq.w .Ata ;No, skip
|
||
|
||
;*************** Dummy geometry for ATAPI drive *******************************
|
||
|
||
move.b (a0),d0
|
||
andi.b #%00001111,d0 ;D0 : Drive type
|
||
|
||
cmpi.b #DG_CDROM,d0
|
||
beq.b .CdRom
|
||
cmpi.b #DG_WORM,d0
|
||
beq.b .CdRom
|
||
cmpi.b #DG_OPTICAL_DISK,d0
|
||
beq.b .CdRom
|
||
cmpi.b #DG_DIRECT_ACCESS,d0
|
||
beq.b .Direct
|
||
bra.w .End
|
||
|
||
.Direct
|
||
cmpi.l #"LS-1",idev_ModelNumber(a0)
|
||
bne.b .NoLS
|
||
cmpi.w #"20",idev_ModelNumber+4(a0)
|
||
bne.b .NoLS
|
||
|
||
;LS-120 drive geometry
|
||
move.w #2,idev_Heads(a0) ;2 heads
|
||
move.w #18,idev_Sectors(a0) ;18 sectors
|
||
move.w #6848,idev_Cylinders(a0) ;6848 cylinders
|
||
st.b au_SlowDevice(a3) ;Slow peripheral
|
||
bra.w .End
|
||
|
||
.NoLS
|
||
cmpi.l #"ZIP ",idev_ModelNumber+8(a0)
|
||
bne.w .End
|
||
cmpi.l #"100 ",idev_ModelNumber+12(a0)
|
||
bne.w .End
|
||
|
||
;ZIP 100 drive geometry
|
||
move.w #1,idev_Heads(a0) ;1 head
|
||
move.w #64,idev_Sectors(a0) ;64 sectors
|
||
move.w #3072,idev_Cylinders(a0) ;3072 cylinders
|
||
sf.b au_SlowDevice(a3) ;Fast peripheral
|
||
bra.b .End
|
||
|
||
.CdRom
|
||
;CD-ROM drive geometry
|
||
move.w #1,idev_Heads(a0) ;1 head
|
||
move.w #75,idev_Sectors(a0) ;75 sectors
|
||
move.w #4440,idev_Cylinders(a0) ;4440 cylinders
|
||
st.b au_SlowDevice(a3) ;Slow peripheral
|
||
bra.b .End
|
||
|
||
;*************** Special geometry for ATA drives > 8 GB ***********************
|
||
|
||
.Ata
|
||
cmpi.w #16,idev_Heads(a0) ;16 heads ?
|
||
bne.b .End ;No, skip
|
||
cmpi.w #63,idev_Sectors(a0) ;63 sectors ?
|
||
bne.b .End ;No, skip
|
||
cmpi.w #16383,idev_Cylinders(a0) ;16383 cylindres ?
|
||
bne.b .End ;No, skip
|
||
|
||
move.l idev_LbaCapacity(a0),d0 ;Real number of blocks
|
||
swap d0
|
||
cmpi.l #(63*16*65535),d0 ;Drive capacity > 32 GB ?
|
||
bhi.b .More32GB ;Yes, special computation
|
||
|
||
divu #(63*16),d0
|
||
move.w d0,idev_Cylinders(a0) ;New cylinders numbers
|
||
bra.b .End
|
||
|
||
.More32GB
|
||
move.l d2,-(sp) ;Save D2
|
||
lsr.l #4,d0 ;/ 16 heads
|
||
move.w #255,d1 ;Start with 255 sectors
|
||
.Loop2
|
||
move.l d0,d2
|
||
divu d1,d2
|
||
bvs.b .OvlLoop2 ;Overflow : end computation
|
||
swap d2
|
||
tst.w d2 ;Null remainder ?
|
||
beq.b .EndLoop2 ;Yes, exit
|
||
subq.w #1,d1 ;No, decrease the number of sectors
|
||
bra.b .Loop2
|
||
.OvlLoop2
|
||
addq.w #1,d1 ;Increase the number of sectors
|
||
.EndLoop2
|
||
divu d1,d0
|
||
move.w d0,idev_Cylinders(a0) ;New number of cylinders
|
||
move.w d1,idev_Sectors(a0) ;New number of sectors
|
||
move.l (sp)+,d2 ;Restore D2
|
||
|
||
;*************** End of routine ***********************************************
|
||
|
||
.End
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #1,d0 ;Flag Z = 0 : Ok
|
||
movem.l (sp)+,d0/d1/a5/a6 ;Restore D0, D1, A5 & A6
|
||
rts ;End
|
||
|
||
;*************** An error has occured *****************************************
|
||
|
||
.Error
|
||
bsr.w ResumeError ;Re-initialize the drive
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #0,d0 ;Flag Z = 1 : Error
|
||
movem.l (sp)+,d0/d1/a5/a6 ;Restore D0, D1, A5 & A6
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Increase the CHS/LBA address of the last accessed block ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A3.l : ApolloUnit base address
|
||
;A5.l : Apollo card base address
|
||
|
||
IncrBlockAddr
|
||
tst.b au_LBAMode(a3)
|
||
beq.b .CHSMode
|
||
|
||
;*************** LBA addressing of blocks *************************************
|
||
|
||
addq.b #1,ata_SectorNum(a5)
|
||
bne.b .EndLBA
|
||
addq.b #1,ata_CylinderL(a5)
|
||
bne.b .EndLBA
|
||
addq.b #1,ata_CylinderH(a5)
|
||
bne.b .EndLBA
|
||
addq.b #1,ata_DevHead(a5)
|
||
.EndLBA
|
||
rts
|
||
|
||
;*************** CHS addressing of blocks *************************************
|
||
|
||
.CHSMode
|
||
move.b ata_SectorNum(a5),d0 ;Current sector number
|
||
cmp.b au_SectorsT(a3),d0 ;== Number of sectors ?
|
||
beq.b .NextHead ;Yes, increase the head number
|
||
addq.b #1,ata_SectorNum(a5) ;No, increase the sector number
|
||
rts ;End
|
||
|
||
.NextHead
|
||
move.b #1,ata_SectorNum(a5) ;Sector number = 1
|
||
move.b ata_DevHead(a5),d0
|
||
and.b #ATAF_HEADS,d0 ;Head number
|
||
addq.b #1,d0 ;+1
|
||
cmp.b au_Heads(a3),d0 ;== Number of heads ?
|
||
beq.b .NextCylinder ;Yes, increase the cylinder number
|
||
addq.b #1,ata_DevHead(a5) ;No, increase the head number
|
||
rts ;End
|
||
|
||
.NextCylinder
|
||
and.b #ATAF_SELECT,ata_DevHead(a5) ;Head number = 0
|
||
addq.b #1,ata_CylinderL(a5) ;Increase the LSB
|
||
bne.b .EndCHS ;Not null : end
|
||
addq.b #1,ata_CylinderH(a5) ;Null : increase the MSB
|
||
.EndCHS
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Block address computing (CHS or LBA) ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;D0.l : Logical block number
|
||
;A3.l : ApolloUnit base address
|
||
;A5.l : IDE interface base address
|
||
;A6.l : AT-Apollo.device base address
|
||
|
||
;Return value:
|
||
;-------------
|
||
;Z Flag (0:Ok, 1:Error)
|
||
|
||
CalcBlockAddr
|
||
movem.l d0-d2,-(sp) ;Save D0, D1 & D2
|
||
tst.b au_LBAMode(a3) ;LBA mode ?
|
||
beq.b .CHSMode ;No, CHS mode
|
||
|
||
;*************** LBA mode (max capacity : 128 GB) *****************************
|
||
|
||
move.w d0,d2 ;D2.w : LBA[15..0]
|
||
swap d0 ;D0.w : LBA[27..16]
|
||
move.b d0,d1 ;D1.b : LBA[23..16]
|
||
lsr.w #8,d0 ;D0.b : LBA[27..24]
|
||
or.b au_DevMask(a3),d0 ; + Drive select
|
||
|
||
move.b d0,ata_DevHead(a5) ;Write the drive select + LBA[27..24]
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
move.b d1,ata_CylinderH(a5) ;Write LBA[23..16]
|
||
move.b d2,ata_SectorNum(a5) ;Write LBA[7..0]
|
||
lsr.w #8,d2
|
||
move.b d2,ata_CylinderL(a5) ;Write LBA[15..8]
|
||
|
||
moveq #1,d0 ;Flag Z = 0 : Ok
|
||
movem.l (sp)+,d0-d2 ;Restore D0, D1 & D2
|
||
rts ;End
|
||
|
||
;*************** CHS mode (max capacity : 8 GB) *******************************
|
||
|
||
.CHSMode
|
||
move.w au_SectorsC(a3),d1 ;D1.w : Number of sectors per cylinder
|
||
divu d1,d0 ;Block number/Number of sectors
|
||
move.w d0,d1 ;D1.w : Cylinder number
|
||
clr.w d0
|
||
swap d0 ;D0.l : Remainder
|
||
moveq #0,d2
|
||
move.b au_SectorsT(a3),d2 ;D2.w : Number of sectors per track
|
||
divu d2,d0
|
||
or.b au_DevMask(a3),d0 ;D0.b : Head number + drive select
|
||
move.b d0,ata_DevHead(a5) ;Write the head number + drive select
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
swap d0
|
||
addq.b #1,d0 ;D0.b : Sector number
|
||
move.b d0,ata_SectorNum(a5) ;Write the sector number
|
||
move.b d1,ata_CylinderL(a5) ;Write the cylinder number (LSB)
|
||
lsr.w #8,d1
|
||
move.b d1,ata_CylinderH(a5) ;Write the cylinder number (MSB)
|
||
|
||
moveq #1,d0 ;Flag Z = 0 : Ok
|
||
movem.l (sp)+,d0-d2 ;Restore D0, D1 & D2
|
||
rts ;End
|
||
|
||
.Error
|
||
moveq #0,d0 ;Flag Z = 1 : Error
|
||
movem.l (sp)+,d0-d2 ;Restore D0, D1 & D2
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Get the current position from the ATA registers ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A3.l : ApolloUnit base address
|
||
;A5.l : IDE interface base address
|
||
|
||
;Return value:
|
||
;-------------
|
||
;D0.l : Block number
|
||
|
||
CurrBlockAddr
|
||
tst.b au_LBAMode(a3)
|
||
bne.b .LBA
|
||
|
||
;*************** CHS mode *****************************************************
|
||
|
||
movem.l d1/d2,-(sp)
|
||
moveq #0,d1
|
||
move.b au_SectorsT(a3),d1 ;D1 : Number of sectors per track
|
||
move.w au_SectorsC(a3),d2 ;D2 : Number of sectors per cylinder
|
||
move.b ata_CylinderH(a5),d0
|
||
lsl.w #8,d0
|
||
move.b ata_CylinderL(a5),d0 ;D0 : Cylinder number
|
||
mulu d2,d0
|
||
move.b ata_DevHead(a5),d2
|
||
andi.w #ATAF_HEADS,d2 ;D2 : Head number
|
||
mulu d1,d2
|
||
add.l d2,d0
|
||
move.b ata_SectorNum(a5),d1 ;D1 : Sector number
|
||
subq.l #1,d1 ;minus 1
|
||
add.l d1,d0 ;D0 : LBA address
|
||
movem.l (sp)+,d1/d2
|
||
rts
|
||
|
||
;*************** LBA mode *****************************************************
|
||
|
||
.LBA
|
||
move.b ata_DevHead(a5),d0
|
||
andi.b #ATAF_HEADS,d0 ;LBA[27..24]
|
||
lsl.w #8,d0
|
||
move.b ata_CylinderH(a5),d0 ;LBA[23..16]
|
||
swap d0
|
||
move.b ata_CylinderL(a5),d0 ;LBA[15..8]
|
||
lsl.w #8,d0
|
||
move.b ata_SectorNum(a5),d0 ;LBA[7..0]
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Drive geometry for Apollo-Install tool (2) ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;*************** Special information for the Apollo-Install tool **************
|
||
|
||
DG_Apollo
|
||
lea au_ModelID(a3),a0
|
||
moveq #7,d0 ;8 long words (or 32 bytes) to copy
|
||
.Loop
|
||
move.l (a0)+,(a2)+ ;One long word copy
|
||
dbra d0,.Loop ;Loop
|
||
move.l au_Blocks(a3),d0
|
||
move.b au_SectShift(a3),d1
|
||
lsl.l d1,d0
|
||
move.l d0,(a2)+ ;Number of bytes
|
||
move.b au_Heads(a3),(a2)+ ;Number of heads
|
||
move.b au_SectorsT(a3),(a2)+ ;Number of sectors per track
|
||
move.w au_Cylinders(a3),(a2)+ ;Number of cylinders
|
||
move.w au_SectSize+2(a3),(a2) ;Sector size
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Detect and test an ATA drive ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A0.l : "ConfigDev" structure address
|
||
;A1.l : IDE interface base address
|
||
;A2.l : 16-byte array of device selection masks
|
||
;A3.l : 16-pointer array of board base addresses
|
||
;A4.l : 16-pointer array of "ConfigDev" structures
|
||
;A5.l : AT-Apollo.device base address
|
||
;D5.b : Controller number (0 to 7)
|
||
;D6.b : Drive select mask (0: $00, 1: $10)
|
||
;D7.b : Unit number (0 to 15)
|
||
|
||
;Return values:
|
||
;--------------
|
||
;D7.b : Next unit number
|
||
;Z Flag (0:Ok, 1:Error)
|
||
|
||
TestDevice
|
||
movem.l d0-d6/a0-a6,-(sp) ;Save registers
|
||
|
||
move.l a5,a6 ;A6: AT-Apollo.device base address
|
||
move.l a1,a5 ;A5: Apollo board base address
|
||
move.l a0,d3 ;D3: "ConfigDev" structure address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
;*************** Test the presence of drives on the ATA bus *******************
|
||
|
||
move.b d6,ata_DevHead(a5) ;Select the drive
|
||
moveq #7,d1 ;8 registers to test
|
||
moveq #-1,d0 ;D0 : $FFFFFFFF
|
||
.BusLoop
|
||
cmp.l (a1),d0 ;$FFFFFFFF present everywhere ?
|
||
bne.b .BusFound ;No, there is something
|
||
lea ata_NextReg(a1),a1 ;Yes, next register
|
||
dbra d1,.BusLoop ;Loop
|
||
bra.b .Error ;No drive: error
|
||
.BusFound
|
||
|
||
IFD SERDBG
|
||
movem.l a0-a3/a6/d0/d1,-(sp)
|
||
move.l ad_SysLib(a6),a6
|
||
lea DbgBusOkMess(pc),a0
|
||
sub.l a1,a1
|
||
lea _LVORawPutChar(a6),a2
|
||
sub.l a3,a3
|
||
jsr _LVORawDoFmt(a6)
|
||
movem.l (sp)+,a0-a3/a6/d0/d1
|
||
ENDC
|
||
|
||
;*************** ATA drive detection ******************************************
|
||
|
||
moveq #99,d2 ;100 retries
|
||
move.b d6,d0
|
||
andi.b #ATAF_DEV,d0 ;We keep the master/slave bit
|
||
.DevLoop
|
||
move.b d6,ata_DevHead(a5) ;Select the drive
|
||
move.b ata_DevHead(a5),d1 ;Read back the register
|
||
andi.b #ATAF_DEV,d1 ;We keep the master/slave bit
|
||
cmp.b d0,d1 ;Drive select done ?
|
||
beq.b .DevFound ;Yes, we have an ATA/ATAPI drive
|
||
dbra d2,.DevLoop ;No, new try
|
||
bra.b .Error ;Nothing found: error
|
||
.DevFound
|
||
|
||
IFD SERDBG
|
||
movem.l a0-a3/a6/d0/d1,-(sp)
|
||
move.l ad_SysLib(a6),a6
|
||
lea DbgSelectMess(pc),a0
|
||
sub.l a1,a1
|
||
lea _LVORawPutChar(a6),a2
|
||
sub.l a3,a3
|
||
jsr _LVORawDoFmt(a6)
|
||
movem.l (sp)+,a0-a3/a6/d0/d1
|
||
ENDC
|
||
|
||
;*************** Wait for the drive initialization (max. 15s) *****************
|
||
|
||
move.l a6,-(sp) ;Save A6
|
||
move.l ad_TimerIO(a6),a1 ;A1: timerequest structure
|
||
lea IOTV_TIME(a1),a0 ;A0: timeval structure
|
||
move.l IO_DEVICE(a1),a6 ;A6: TimerBase
|
||
jsr _LVOGetSysTime(a6) ;Read the system clock
|
||
moveq #15,d2 ;15 seconds
|
||
add.l (a0),d2 ;D2: + number of seconds
|
||
|
||
.WaitReset
|
||
move.b ata_Status(a5),d0 ;Read the ATA status register
|
||
beq.b .TestMaster ;Null : check if it is the master
|
||
btst #ATAB_BUSY,d0 ;Wait for BUSY=0 (end of Reset)
|
||
bne.b .TestTime ;BUSY=1, check the elapsed time
|
||
btst #ATAB_DEVREADY,d0 ;Wait for READY=1 (drive ready)
|
||
bne.b .AutoDetect ;READY=1, try an auto-detect
|
||
.TestTime
|
||
jsr _LVOGetSysTime(a6) ;Read the system clock
|
||
cmp.l (a0),d2 ;Time elapsed ?
|
||
bne.b .WaitReset ;No, still waiting
|
||
|
||
;*************** An error has occured *****************************************
|
||
|
||
move.l (sp)+,a6 ;A6: AT-Apollo.device base address
|
||
.Error
|
||
moveq #99,d0 ;100 retries
|
||
.DesLoop
|
||
move.b #0,ata_DevHead(a5) ;Deselect the drive
|
||
tst.b ata_DevHead(a5) ;Deselect done ?
|
||
beq.b .EndLoop ;Yes, exit
|
||
dbra d0,.DesLoop ;No, try again
|
||
|
||
.EndLoop
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #0,d0
|
||
movem.l (sp)+,d0-d6/a0-a6 ;Restore registers
|
||
rts ;End
|
||
|
||
;*************** Check if the drive is master *********************************
|
||
|
||
.TestMaster
|
||
btst #ATAB_DEV,d6 ;Master drive ?
|
||
beq.b .TestTime ;Yes, continue
|
||
|
||
;*************** Auto-detect of an ATA/ATAPI drive ****************************
|
||
|
||
.AutoDetect
|
||
move.l (sp)+,a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD SERDBG
|
||
movem.l a0-a3/a6/d0/d1,-(sp)
|
||
move.l ad_SysLib(a6),a6
|
||
lea DbgReadyMess(pc),a0
|
||
sub.l a1,a1
|
||
lea _LVORawPutChar(a6),a2
|
||
sub.l a3,a3
|
||
jsr _LVORawDoFmt(a6)
|
||
movem.l (sp)+,a0-a3/a6/d0/d1
|
||
ENDC
|
||
|
||
bclr #ATAB_ATAPI,d6 ;ATA protocol : clear bit #7
|
||
move.b d6,ata_DevHead(a5) ;Select the drive
|
||
move.b #ATA_IDENTDEV,ata_Command(a5) ;Auto-Detect ATA
|
||
|
||
IFND CPU020
|
||
move.l #ATA_TimeOut,d0 ;Number of loops
|
||
ENDC
|
||
|
||
IFD CPU020
|
||
move.l #ATA_TimeOut*8,d0 ;Number of loops x 8
|
||
ENDC
|
||
|
||
.BusyLoop1
|
||
btst #ATAB_BUSY,ata_Status(a5) ;Check the BUSY bit
|
||
beq.b .BusyOk1 ;BUSY == 0 : continue
|
||
subq.l #1,d0 ;i--
|
||
bne.b .BusyLoop1 ;i != 0, loop
|
||
bra.b .Error ;Time-out elapsed : error
|
||
.BusyOk1
|
||
btst #ATAB_ERROR,ata_Status(a5) ;Check ATA error bit
|
||
beq.b .DevOk ;Clear : ATA drive found
|
||
|
||
bset #ATAB_ATAPI,d6 ;ATAPI protocol : set bit #7
|
||
move.b d6,atapi_DriveSel(a5) ;Select the drive
|
||
move.b #ATAPI_IDENTDEV,atapi_Command(a5) ;Auto-Detect ATAPI
|
||
|
||
IFND CPU020
|
||
move.l #ATAPI_TimeOut,d0 ;Number of loops
|
||
ENDC
|
||
|
||
IFD CPU020
|
||
move.l #ATAPI_TimeOut*8,d0 ;Number of loops x 8
|
||
ENDC
|
||
|
||
.BusyLoop2
|
||
btst #ATAB_BUSY,ata_Status(a5) ;Check the BUSY bit
|
||
beq.b .BusyOk2 ;BUSY == 0 : continue
|
||
subq.l #1,d0 ;i--
|
||
bne.b .BusyLoop2 ;i != 0, loop
|
||
bra.b .Error ;Time-out elapsed : error
|
||
.BusyOk2
|
||
btst #ATAPIB_CHECK,atapi_Status(a5) ;An error has occured ?
|
||
beq.b .DevOk ;No, we found an ATAPI drive
|
||
|
||
andi.b #ATAF_DEV,d6 ;Yes, switch back to ATA mode (old ATA drives ?)
|
||
bra.b .InitArray ;Initialize the arrays
|
||
|
||
.DevOk
|
||
IFD SERDBG
|
||
movem.l a0-a3/a6/d0/d1,-(sp)
|
||
move.l ad_SysLib(a6),a6
|
||
lea DbgDetectMess(pc),a0
|
||
sub.l a1,a1
|
||
lea _LVORawPutChar(a6),a2
|
||
sub.l a3,a3
|
||
jsr _LVORawDoFmt(a6)
|
||
movem.l (sp)+,a0-a3/a6/d0/d1
|
||
ENDC
|
||
|
||
moveq #idev_SIZEOF/4-1,d1 ;D1: Long words to read minus 1
|
||
.Loop
|
||
move.l (a5),d0 ;Reading one long word
|
||
dbra d1,.Loop ;Loop
|
||
|
||
.InitArray
|
||
tst.b d6 ;ATAPI drive ?
|
||
bmi.b .AtapiDev ;Yes, skip next line
|
||
bsr.b TestLBA ;Check LBA addressing
|
||
|
||
.AtapiDev
|
||
move.b d6,d0 ;Drive select mask
|
||
or.b d5,d0 ;Controller number
|
||
move.b d0,(a2,d7.w)
|
||
|
||
;-------- Optimized code --------
|
||
IFND CPU020
|
||
move.l d7,d0
|
||
add.l d0,d0
|
||
add.l d0,d0
|
||
move.l d3,(a4,d0.w) ;"ConfigDev" structure
|
||
move.l a5,(a3,d0.w) ;Apollo card base address
|
||
ENDC
|
||
|
||
IFD CPU020
|
||
move.l d3,(a4,d7.w*4) ;"ConfigDev" structure
|
||
move.l a5,(a3,d7.w*4) ;Apollo card base address
|
||
ENDC
|
||
|
||
addq.l #1,d7 ;Increase the unit number
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #-1,d0
|
||
movem.l (sp)+,d0-d6/a0-a6 ;Restore registers
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Check if the drive supports LBA mode ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A5.l : IDE interface base address
|
||
;A6.l : AT-Apollo.device base address
|
||
;D6.b : Drive select mask
|
||
|
||
;Return value:
|
||
;-------------
|
||
;D6.b : Updated drive select mask
|
||
|
||
TestLBA
|
||
movem.l d0/d1,-(sp) ;Save D0 & D1
|
||
moveq #0,d0
|
||
bset #ATAB_LBA,d6 ;LBA mode activated
|
||
move.b d6,ata_DevHead(a5) ;Drive selected
|
||
move.b d0,ata_SectorNum(a5)
|
||
move.b d0,ata_CylinderL(a5)
|
||
move.b d0,ata_CylinderH(a5) ;Block number : 0
|
||
move.b #1,ata_SectorCnt(a5) ;Only one sector
|
||
move.b #ATA_READ,ata_Command(a5) ;ATA read command ($20)
|
||
|
||
IFND CPU020
|
||
move.l #ATA_TimeOut,d0 ;Number of loops
|
||
ENDC
|
||
|
||
IFD CPU020
|
||
move.l #ATA_TimeOut*8,d0 ;Number of loops x 8
|
||
ENDC
|
||
.BusyLoop1
|
||
btst #ATAB_BUSY,ata_Status(a5) ;Check the BUSY bit
|
||
beq.b .BusyOk1 ;BUSY == 0 : continue
|
||
subq.l #1,d0 ;i--
|
||
bne.b .BusyLoop1 ;i != 0, loop
|
||
bra.b .NoLBA ;Waiting too long : LBA mode not supported
|
||
.BusyOk1
|
||
btst #ATAB_DATAREQ,ata_Status(a5) ;Check DREQ bit
|
||
beq.b .NoLBA ;DREQ=0 : LBA mode not supported
|
||
|
||
move.b ata_Status(a5),-(sp) ;Save "ata_Status"
|
||
|
||
moveq #BLOCK_SIZE/4-1,d1 ;Number of long words to read (minus 1)
|
||
.Loop
|
||
move.l (a5),d0 ;Reading one long word
|
||
dbra d1,.Loop ;Loop
|
||
|
||
move.b (sp)+,d1 ;D1 : ata_Status
|
||
btst #ATAB_ERROR,d1 ;Check ATA error bit
|
||
bne.b .NoLBA ;Set : LBA mode not supported
|
||
|
||
IFND CPU020
|
||
move.l #ATA_TimeOut,d0 ;Number of loops
|
||
ENDC
|
||
|
||
IFD CPU020
|
||
move.l #ATA_TimeOut*8,d0 ;Number of loops x 8
|
||
ENDC
|
||
.BusyLoop2
|
||
btst #ATAB_BUSY,ata_Status(a5) ;Check the BUSY bit
|
||
beq.b .End ;BUSY == 0 : exit
|
||
subq.l #1,d0 ;i--
|
||
bne.b .BusyLoop2 ;i != 0, loop
|
||
|
||
.NoLBA
|
||
bclr #ATAB_LBA,d6 ;Deactivate LBA mode
|
||
.End
|
||
movem.l (sp)+,d0/d1 ;Restore registers
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Check if address decoding is incomplete ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;A1.l : IDE interface base address
|
||
|
||
;Return value:
|
||
;-------------
|
||
;Z Flag : 0=Decoding OK, 1=Decoding incomplete
|
||
|
||
TestMirror
|
||
movem.l d0/a5/a6,-(sp)
|
||
move.l a5,a6
|
||
move.l a1,a5
|
||
move.b #ATAF_MASTER,ata_DevHead(a5)
|
||
move.b #ATA_NOP,ata_Command(a5)
|
||
|
||
IFND CPU020
|
||
move.l #ATA_TimeOut,d0 ;Number of loops
|
||
ENDC
|
||
|
||
IFD CPU020
|
||
move.l #ATA_TimeOut*8,d0 ;Number of loops x 8
|
||
ENDC
|
||
.BusyLoop
|
||
btst #ATAB_BUSY,ata_Status(a5) ;Check the BUSY bit
|
||
beq.b .BusyOk ;BUSY == 0 : exit
|
||
subq.l #1,d0 ;i--
|
||
bne.b .BusyLoop ;i != 0, loop
|
||
bra.b .DecOk
|
||
.BusyOk
|
||
|
||
move.b ata_Status(a5),d0
|
||
move.b #ATAF_SLAVE,ata_DevHead(a5)
|
||
cmp.b ata_Status(a5),d0 ;Incomplete address decoding ?
|
||
bne.b .DecOk ;No, exit
|
||
|
||
moveq #0,d0
|
||
movem.l (sp)+,d0/a5/a6
|
||
rts
|
||
|
||
.DecOk
|
||
moveq #-1,d0
|
||
movem.l (sp)+,d0/a5/a6
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** IDE-Mux board presence check ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;A1.l : IDE interface base address
|
||
|
||
;Return value:
|
||
;-------------
|
||
; D0 : 0=Present, -1=Not present
|
||
|
||
TestPort2
|
||
movem.l d1/a5,-(sp)
|
||
lea ata_NextPort(a1),a5 ;A5 : Second port address
|
||
|
||
moveq #$55,d0
|
||
move.b d0,ata_SectorCnt(a1) ;Sector Count = $55
|
||
cmp.b ata_SectorCnt(a5),d0 ;Incomplete address decoding ?
|
||
bne.b .NoMirror ;No, skip
|
||
|
||
add.b d0,d0
|
||
move.b d0,ata_SectorCnt(a1) ;Sector Count = $AA
|
||
cmp.b ata_SectorCnt(a5),d0 ;Incomplete address decoding ?
|
||
bne.b .NoMirror ;No, skip
|
||
|
||
bra.b .Mirror ;Yes
|
||
|
||
.NoMirror
|
||
moveq #5,d1 ;6 registers to test
|
||
moveq #-1,d0 ;D0 : $FFFFFFFF
|
||
.TestLoop
|
||
cmp.l (a5),d0 ;We found $FFFFFFFF everywhere ?
|
||
bne.b .Found ;No, IDE-Mux board present
|
||
lea ata_NextReg(a5),a5 ;Yes, next register
|
||
dbra d1,.TestLoop ;Loop
|
||
|
||
.Mirror
|
||
move.b ata_AltStatus(a1),d0
|
||
cmp.b ata_Status(a1),d0 ;Status = Alternate Status ?
|
||
bne.b .Found ;No, IDE-Mux board present
|
||
|
||
movem.l (sp)+,d1/a5 ;Yes, no IDE-Mux board
|
||
moveq #-1,d0
|
||
rts
|
||
|
||
.Found
|
||
movem.l (sp)+,d1/a5 ;IDE-Mux board found
|
||
moveq #0,d0
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** ApolloUnit structure initialization ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A3.l : ApolloUnit base address
|
||
;A6.l : ExecBase
|
||
|
||
;Return value:
|
||
;-------------
|
||
;Z Flag (0:Ok, 1:Error)
|
||
|
||
UnitInfo
|
||
movem.l d0-d3/a0-a2,-(sp) ;Save D0 - D3, A0 - A2
|
||
|
||
lea -BLOCK_SIZE(sp),sp ;Allocate one block on the stack
|
||
move.l sp,a0 ;A0 : buffer's address
|
||
|
||
;******** Allocate memory *****************************************************
|
||
|
||
; move.l #BLOCK_SIZE,d0 ;Sector size
|
||
; moveq #0,d1 ;Any memory
|
||
; jsr _LVOAllocMem(a6) ;Allocate one buffer
|
||
; tst.l d0 ;No more memory ?
|
||
; beq.w .Error ;Yes, error
|
||
; move.l d0,a0 ;A0 : buffer's address
|
||
|
||
;******** Device identification ***********************************************
|
||
|
||
moveq #-1,d0
|
||
move.l d0,au_RDBSector(a3) ;Invalidate RDB's LBA
|
||
|
||
bsr.w ata_Identify ;ATA-3 disk identify
|
||
beq.w .Search ;Error : search by trial/error
|
||
|
||
lea idev_ModelNumber(a0),a1 ;A1: Source
|
||
lea au_ModelID(a3),a2 ;A2: Destination
|
||
moveq #7,d0 ;8 long words to copy
|
||
.CopyLoop
|
||
move.l (a1)+,(a2)+ ;Copy one long word
|
||
dbra d0,.CopyLoop ;Loop
|
||
|
||
move.l idev_RevisionNumber(a0),(a2)+ ;Firmware version
|
||
|
||
movem.l idev_SerialNumber(a0),d0-d2
|
||
movem.l d0-d2,(a2) ;Serial number
|
||
|
||
;******** Drive geometry ******************************************************
|
||
|
||
move.w idev_Heads(a0),d0
|
||
move.b d0,au_Heads(a3) ;D0: Number of heads
|
||
move.w idev_Sectors(a0),d1
|
||
move.b d1,au_SectorsT(a3) ;D1: Number of sectors per track
|
||
move.w idev_Cylinders(a0),d2
|
||
move.w d2,au_Cylinders(a3) ;D2: Number of cylinders
|
||
mulu d1,d0 ;D0 x D1 =
|
||
move.w d0,au_SectorsC(a3) ;Number of sectors per cylinder
|
||
mulu d2,d0 ; x D2 =
|
||
move.l d0,au_Blocks(a3) ;Number of blocks
|
||
|
||
tst.b 1(a0) ;Removable media ?
|
||
bpl.b .NoRemove ;No, skip
|
||
st.b au_Removable(a3) ;Yes, set the removable flag
|
||
move.b #6,au_SenseKey(a3) ;Sense key = 6 (Unit attention)
|
||
.NoRemove
|
||
st.b au_DiskPresent(a3) ;Default : media present
|
||
|
||
moveq #9,d1 ;2^9 bytes block
|
||
move.b (a0),d2
|
||
andi.b #%00001111,d2 ;Device type
|
||
tst.b au_AtapiDev(a3) ;ATAPI device ?
|
||
bne.b .AtapiDev ;Yes, skip next line
|
||
moveq #DG_DIRECT_ACCESS,d2 ;No, device type = hard drive
|
||
.AtapiDev
|
||
move.b d2,au_DevType(a3) ;Save the device type
|
||
beq.b .Direct ;Hard drive : skip next line
|
||
moveq #11,d1 ;2^11 bytes block
|
||
.Direct
|
||
moveq #0,d2
|
||
bset d1,d2
|
||
move.b d1,au_SectShift(a3) ;Block size (Log 2)
|
||
move.l d2,au_SectSize(a3) ;Block size
|
||
|
||
;******** Drive geometry search ***********************************************
|
||
|
||
tst.b au_Removable(a3) ;Removable media ?
|
||
bne.b .LastOk ;Yes, skip the search
|
||
subq.l #1,d0 ;D0: last sector's LBA address
|
||
moveq #1,d1 ;D1: one sector to read
|
||
jsr au_ReadJmp(a3) ;Read the media's last sector
|
||
tst.b d0 ;Check the error code
|
||
beq.b .LastOk ;No error : next step
|
||
.Search
|
||
tst.b au_AtapiDev(a3) ;Error : ATAPI peripheral ?
|
||
bne.b .LastOk ;Yes, skip the CHS search
|
||
bsr.w SearchCHS ;No, search by trials and errors
|
||
.LastOk
|
||
|
||
;******** Rigid Disk Block (RDB) read *****************************************
|
||
|
||
tst.b au_DevType(a3) ;Hard drive ?
|
||
bne.b .NoRDB ;No, skip
|
||
bsr.b RDBInfo ;Yes, retrieve info from the RDB
|
||
.NoRDB
|
||
|
||
;******** End : free up the memory ********************************************
|
||
|
||
;.Continue
|
||
; move.l a0,a1
|
||
; move.l #BLOCK_SIZE,d0
|
||
; jsr _LVOFreeMem(a6)
|
||
lea BLOCK_SIZE(sp),sp ;Restore the stack
|
||
|
||
moveq #1,d0 ;Flag Z = 0 : Ok
|
||
movem.l (sp)+,d0-d3/a0-a2 ;Restore D0 to D3 & A0 to A2
|
||
rts ;End
|
||
|
||
;******** Error : exit ********************************************************
|
||
|
||
.Error
|
||
moveq #0,d0 ;Flag Z = 1 : Error
|
||
movem.l (sp)+,d0-d3/a0-a2 ;Restore D0 to D3 & A0 to A2
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Rigid Disk Block search on the disk ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A3.l : ApolloUnit base address
|
||
;A6.l : ExecBase
|
||
|
||
RDBInfo
|
||
moveq #0,d3 ;D3 : point to the non-swapped routines
|
||
|
||
;******** Rigid Disk Block search loop ****************************************
|
||
|
||
moveq #0,d2 ;D2 : block's LBA = 0
|
||
.RDBLoop
|
||
sf.b au_Swapped(a3) ;Clear the byte swapped flag
|
||
move.l d2,d0 ;Block's LBA
|
||
moveq #1,d1 ;One block to read
|
||
jsr au_ReadJmp(a3) ;Read the block
|
||
tst.b d0 ;Error code check
|
||
bne.b .End ;Error : exit
|
||
cmpi.l #"RDSK",rdb_ID(a0) ;Valid RDB identifier ?
|
||
beq.b .RDBFound ;Yes, Apollo RDB found
|
||
cmpi.l #"DRKS",rdb_ID(a0) ;Swapped RDB identifier ?
|
||
beq.b .InvRDBFound ;Yes, A600/1200/4000 RDB found
|
||
.NextRDB
|
||
addq.b #1,d2 ;Next block
|
||
cmp.b #RDB_LOCATION_LIMIT,d2 ;RDB reserved area scanned ?
|
||
bne.b .RDBLoop ;No, resume RDB search
|
||
.End
|
||
rts ;Yes, exit
|
||
|
||
;******** Swapped RDB found ***************************************************
|
||
|
||
.InvRDBFound
|
||
moveq #BLOCK_SIZE/4-1,d3 ;Number of long words to swap (minus 1)
|
||
.InvLoop
|
||
movem.w (a0)+,d0/d1 ;Reading one word long
|
||
rol.w #8,d0
|
||
rol.w #8,d1 ;Swap LSBs <-> MSBs
|
||
movem.w d0/d1,-4(a0) ;Swapped long word write
|
||
dbra d3,.InvLoop ;Loop
|
||
lea -BLOCK_SIZE(a0),a0 ;Restore A0
|
||
st.b au_Swapped(a3) ;Set the byte swapped flag
|
||
moveq #4,d3 ;D3 : point to the swapped routines
|
||
|
||
;******** Regular RDB found ***************************************************
|
||
|
||
.RDBFound
|
||
move.l a0,-(sp) ;Save A0
|
||
move.l rdb_SummedLongs(a0),d1 ;RDB size (in long words)
|
||
subq.w #1,d1 ;-1 : for DBRA
|
||
moveq #0,d0
|
||
.SumLoop
|
||
add.l (a0)+,d0 ;Long words summing
|
||
dbra d1,.SumLoop ;Loop
|
||
move.l (sp)+,a0 ;Restore A0
|
||
tst.l d0 ;Valid checksum ?
|
||
bne.b .NextRDB ;No, resume RDB search
|
||
|
||
;*************** Valid RDB : update ApolloUnit ********************************
|
||
|
||
move.l d2,au_RDBSector(a3) ;Yes, save the RDB's LBA
|
||
|
||
cmpi.l #'Apol',rdb_ControllerProduct(a0) ;Apollo controller ?
|
||
bne.b .End ;No, exit
|
||
|
||
move.l rdb_ControllerRevision(a0),d0 ;Yes, set the Apollo parameters
|
||
bra.b SetParams2
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Set the Apollo specific parameters ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;D0.l : Apollo specific parameters (rdb_ControllerRevision)
|
||
;A3.l : ApolloUnit base address
|
||
;A6.l : ExecBase
|
||
|
||
SetParams
|
||
moveq #0,d3
|
||
btst #AUB_SWAP,d0 ;Swapped mode ?
|
||
beq.b .Swap ;No, skip
|
||
st.b au_Swapped(a3) ;Yes
|
||
moveq #4,d3
|
||
.Swap
|
||
|
||
btst #AUB_SLOW,d0 ;Slow peripheral ?
|
||
sne.b au_SlowDevice(a3) ;Yes
|
||
|
||
;******** Second entry point for "RDBInfo" ************************************
|
||
|
||
SetParams2
|
||
move.l a0,-(sp)
|
||
move.l d3,d2
|
||
|
||
btst #AUB_FREAD,d0 ;Read-mode = Safe ?
|
||
bne.b .NoFRead ;Yes, disable fast read
|
||
st.b au_ReadMode(a3) ;No, enable fast read
|
||
addq.l #2,d2
|
||
.NoFRead
|
||
|
||
btst #AUB_FWRITE,d0 ;Write-mode = Safe ?
|
||
bne.b .NoFWrite ;Yes, disable fast write
|
||
st.b au_WriteMode(a3) ;No, enable fast write
|
||
addq.l #2,d3
|
||
.NoFWrite
|
||
|
||
tst.b au_AtapiDev(a3)
|
||
bne.b .NoAtaFunc
|
||
lea .FuncMap(pc),a0
|
||
move.w 0(a0,d2.l),d2
|
||
move.w 8(a0,d3.l),d3
|
||
ext.l d2
|
||
ext.l d3
|
||
add.l a0,d2
|
||
add.l a0,d3
|
||
move.l d2,au_ReadSub(a3)
|
||
move.l d3,au_WriteSub(a3)
|
||
move.l d3,au_FormatSub(a3)
|
||
.NoAtaFunc
|
||
|
||
btst #AUB_INTDIS,d0 ;Interrupts disabled option ?
|
||
sne.b au_IntDisable(a3) ;Yes
|
||
|
||
btst #AUB_RCACHE,d0 ;Read cache activated option ?
|
||
sne.b au_RCacheOn(a3) ;Yes
|
||
|
||
btst #AUB_WCACHE,d0 ;Write cache activated option ?
|
||
sne.b au_WCacheOn(a3) ;Yes
|
||
|
||
swap d0 ;Caches sizes
|
||
cmpi.b #3,d0
|
||
bcs.b .WCSizeNOk
|
||
cmpi.b #8,d0
|
||
bhi.b .WCSizeNOk ;Boundaries check
|
||
bra.b .WCSizeOk
|
||
.WCSizeNOk
|
||
move.b #6,d0 ;Default size : 2^6 (64) blocks
|
||
.WCSizeOk
|
||
moveq #0,d1
|
||
bset d0,d1
|
||
subq.w #1,d1
|
||
move.w d1,au_WCacheSize(a3) ;Write cache size - 1
|
||
|
||
lsr.w #8,d0
|
||
beq.b .RCSizeNOk
|
||
cmpi.b #32,d0
|
||
bhi.b .RCSizeNOk ;Boundaries check
|
||
bra.b .RCSizeOk
|
||
.RCSizeNOk
|
||
moveq #4,d0 ;Default size : 4 x 8 (32) blocks
|
||
.RCSizeOk
|
||
lsl.w #3,d0 ; x 8
|
||
ext.l d0
|
||
move.l d0,au_RCacheSize(a3) ;Read-Prefetch cache size
|
||
|
||
bsr.w AllocCache ;Cache memory allocation
|
||
bne.b .End ;No error : end
|
||
|
||
bsr.w FreeCache ;Error : free cache memory
|
||
.End
|
||
move.l (sp)+,a0
|
||
rts ;End
|
||
|
||
.FuncMap
|
||
dc.w ata_SlowReadNorm-.FuncMap
|
||
dc.w ata_FastReadNorm-.FuncMap
|
||
dc.w ata_SlowReadSwap-.FuncMap
|
||
dc.w ata_FastReadSwap-.FuncMap
|
||
dc.w ata_SlowWriteNorm-.FuncMap
|
||
dc.w ata_FastWriteNorm-.FuncMap
|
||
dc.w ata_SlowWriteSwap-.FuncMap
|
||
dc.w ata_FastWriteSwap-.FuncMap
|
||
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Clear the Apollo specific parameters ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A3.l : ApolloUnit base address
|
||
;A6.l : ExecBase
|
||
|
||
ClrParams
|
||
sf.b au_Swapped(a3)
|
||
sf.b au_SlowDevice(a3)
|
||
sf.b au_ReadMode(a3)
|
||
sf.b au_WriteMode(a3)
|
||
sf.b au_SlowDevice(a3) ;Clear the flags
|
||
bra.w FreeCache ;Free the caches
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Find drive geometry by trial and error ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A0.l : Buffer adddress
|
||
;A3.l : ApolloUnit base address
|
||
|
||
SearchCHS
|
||
|
||
;*************** Find the number of sectors ***********************************
|
||
|
||
moveq #0,d0 ;D0: Head number = 0
|
||
moveq #1,d1 ;D1: Sector number = 1
|
||
moveq #0,d2 ;D2: Cylinder number = 0
|
||
.SearchSec
|
||
bsr.b ata_ReadSectorCHS ;Read one sector
|
||
beq.b .SecFound ;Error : max sector found
|
||
addq.b #1,d1 ;Otherwise, increment the sector number
|
||
cmpi.b #65,d1 ;Is sector number == 65 ?
|
||
bne.b .SearchSec ;No, go on looping
|
||
moveq #36,d1 ;Yes, sector number = 36
|
||
.SecFound
|
||
subq.b #1,d1
|
||
move.b d1,au_SectorsT(a3) ;Number of sectors per track
|
||
|
||
;*************** Find the number of heads *************************************
|
||
|
||
moveq #0,d0 ;D0: Head number = 0
|
||
moveq #1,d1 ;D1: Sector number = 1
|
||
moveq #0,d2 ;D2: Cylinder number = 0
|
||
.SearchHead
|
||
bsr.b ata_ReadSectorCHS ;Read one sector
|
||
beq.b .HeadFound ;Error : max head found
|
||
addq.b #1,d0 ;Otherwise, increment the head number
|
||
cmpi.b #16,d0 ;Is head number = 16 ?
|
||
bne.b .SearchHead ;No, go on looping
|
||
.HeadFound
|
||
move.b d0,au_Heads(a3) ;Number of heads
|
||
|
||
;*************** Find the number of cylinders (binary search) *****************
|
||
|
||
moveq #0,d0 ;D0: Head number = 0
|
||
moveq #1,d1 ;D1: Sector number = 1
|
||
move.w #32768,d2 ;D2: Cylinder number = 32768
|
||
move.w d2,d3 ;D3: Cylinder increment = 32768
|
||
.SearchCyl
|
||
lsr.w #1,d3 ;Increment / 2
|
||
beq.b .CylFound ;Null increment : end of search
|
||
bsr.b ata_ReadSectorCHS ;Read one sector
|
||
beq.b .Dec ;Error : jump to ".Dec"
|
||
add.w d3,d2 ;No error : increment the cylinder number
|
||
bra.b .SearchCyl ;Loop
|
||
.Dec
|
||
sub.l d3,d2 ;Decrement the cylinder number
|
||
bra.b .SearchCyl ;Loop
|
||
.CylFound
|
||
bsr.b ata_ReadSectorCHS ;Read the drive's last sector
|
||
beq.b .Jump ;Error : jump to ".Jump"
|
||
addq.l #1,d2 ;No error : increase the cylinder number
|
||
.Jump
|
||
move.w d2,au_Cylinders(a3) ;Number of cylinders
|
||
|
||
;*************** Additional geometry data *************************************
|
||
|
||
move.b au_Heads(a3),d0 ;Number of heads
|
||
move.b au_SectorsT(a3),d1 ;Number of sectors per track
|
||
mulu d1,d0
|
||
move.w d0,au_SectorsC(a3) ;Number of sectors per cylinder
|
||
mulu d2,d0
|
||
move.l d0,au_Blocks(a3) ;Total number of blocks
|
||
|
||
moveq #DG_DIRECT_ACCESS,d0 ;Type : hard drive
|
||
move.b d0,au_DevType(a3)
|
||
moveq #9,d1 ;Block size : 2^9 bytes
|
||
bset d1,d0
|
||
move.b d1,au_SectShift(a3) ;Size (log 2)
|
||
move.l d0,au_SectSize(a3) ;Size (in bytes)
|
||
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Read one sector, using CHS addressing ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;D0.b : Head number
|
||
;D1.b : Sector number
|
||
;D2.w : Cylinder number
|
||
;A0.l : Buffer address
|
||
;A3.l : ApolloUnit base address
|
||
|
||
;Return value:
|
||
;-------------
|
||
;Z Flag (0:Ok, 1:Error)
|
||
|
||
ata_ReadSectorCHS
|
||
movem.l d0-d2/a5/a6,-(sp) ;Save D0, D1, D2, A5 & A6
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
or.b au_OldDevMask(a3),d0 ;Head number ORed with old selection mask
|
||
move.b d0,ata_DevHead(a5)
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
move.b d1,ata_SectorNum(a5) ;Sector number
|
||
move.b d2,ata_CylinderL(a5) ;Cylinder number (LSB)
|
||
lsr.w #8,d2
|
||
move.b d2,ata_CylinderH(a5) ;Cylinder number (MSB)
|
||
move.b #1,ata_SectorCnt(a5) ;Only one sector
|
||
move.b #ATA_READ,ata_Command(a5) ;ATA read command ($20)
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
|
||
moveq #BLOCK_SIZE/4-1,d1 ;Number of long words to read (minus 1)
|
||
.Loop
|
||
move.l (a5),(a0)+ ;Reading one word long
|
||
dbra d1,.Loop ;Loop
|
||
lea -BLOCK_SIZE(a0),a0 ;Restore A0
|
||
|
||
btst #ATAB_ERROR,d0 ;Check ATA error bit
|
||
bne.b .Error ;Set : exit with an error
|
||
btst #ATAB_DATAREQ,ata_Status(a5) ;It remains some data to read ?
|
||
bne.b .Error ;Yes, error
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #1,d0 ;Flag Z = 0 : Ok
|
||
movem.l (sp)+,d0-d2/a5/a6 ;Restore D0, D1, D2, A5 & A6
|
||
rts ;End
|
||
|
||
.Error
|
||
bsr.w ResumeError ;Drive reset
|
||
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
moveq #0,d0 ;Flag Z = 1 : Error
|
||
movem.l (sp)+,d0-d2/a5/a6 ;Restore D0, D1, D2, A5 & A6
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Send an ATAPI packet ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A3.l : ApolloUnit base address
|
||
;A4.l : SCSI CDB address
|
||
;A5.l : IDE interface base address
|
||
;A6.l : AT-Apollo.device base address
|
||
|
||
;Return value:
|
||
;-------------
|
||
;Z Flag (0:Ok, 1:Error)
|
||
|
||
SendPacket
|
||
movem.l d0/d1,-(sp) ;Save D0 & D1
|
||
|
||
move.b au_DevMask(a3),atapi_DriveSel(a5) ;Drive select
|
||
bsr.b WaitBusy ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
moveq #0,d0
|
||
move.b d0,atapi_Features(a5)
|
||
move.b d0,atapi_ByteCntH(a5)
|
||
move.b d0,atapi_ByteCntL(a5)
|
||
move.b #ATAPI_PACKET,atapi_Command(a5) ;Send the CDB
|
||
bsr.b WaitBusySlow ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
btst #ATAB_DATAREQ,d0 ;DREQ = 1 ?
|
||
beq.b .Error ;No, error
|
||
|
||
move.b atapi_Reason(a5),d0 ;Interrupt Reason Register
|
||
andi.b #ATAPIF_MASK,d0 ;Bits IO & CoD
|
||
cmpi.b #ATAPIF_COMMAND,d0 ;Ready to accept the command ?
|
||
bne.b .Error ;No, error
|
||
|
||
moveq #5,d1 ;6 words to send
|
||
.SendLoop
|
||
move.w (a4)+,(a5) ;Send the CDB
|
||
dbra d1,.SendLoop
|
||
lea -12(a4),a4 ;Restore A4
|
||
|
||
moveq #1,d0 ;Flag Z = 0 : Ok
|
||
movem.l (sp)+,d0/d1 ;Restore D0 & D1
|
||
rts ;End
|
||
|
||
.Error
|
||
moveq #0,d0 ;Flag Z = 1 : Error
|
||
movem.l (sp)+,d0/d1 ;Restore D0 & D1
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Wait for BUSY flag being cleared ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A3.l : ApolloUnit base address
|
||
;A5.l : IDE interface base address
|
||
|
||
;Return values:
|
||
;--------------
|
||
;Z Flag (0:Ok, 1:Error)
|
||
;D0.b : ata_Status
|
||
|
||
WaitBusy
|
||
movem.l d1,-(sp) ;Save D1
|
||
move.l au_NumLoop(a3),d1 ;i = NumLoop
|
||
.Wait
|
||
move.b ata_Status(a5),d0 ;Read the ata_Status register
|
||
btst #ATAB_BUSY,d0 ;Check the BUSY bit
|
||
beq.b .Ok ;BUSY == 0 : exit
|
||
subq.l #1,d1 ;i--
|
||
bne.b .Wait ;i != 0 : loop
|
||
.Ok
|
||
tst.l d1 ;Update the Z flag
|
||
movem.l (sp)+,d1 ;Restore D1
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Wait for BUSY flag being cleared (using timer.device) ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A3.l : ApolloUnit base address
|
||
;A5.l : IDE interface base address
|
||
;A6.l : AT-Apollo.device base address
|
||
|
||
;Return values:
|
||
;--------------
|
||
;Z Flag (0:Ok, 1:Error)
|
||
;D0.b : ata_Status
|
||
|
||
WaitBusySlow
|
||
tst.b au_SlowDevice(a3) ;Slow peripheral ?
|
||
beq.b WaitBusy ;No, regular wait
|
||
|
||
movem.l d1-d3/a0-a2,-(sp) ;Save the registers
|
||
|
||
move.w #1000,d3 ;1000 retries
|
||
.Wait1
|
||
move.b ata_Status(a5),d0 ;Read the ata_Status register
|
||
btst #ATAB_BUSY,d0 ;Check the BUSY bit
|
||
beq.b .End ;BUSY == 0 : exit
|
||
subq.w #1,d3
|
||
bne.b .Wait1 ;Loop
|
||
|
||
lea .WaitTable(pc),a2
|
||
.Wait2
|
||
move.l (a2)+,d3 ;Number of micro-seconds
|
||
beq.b .End ;Null : end
|
||
move.w (a2)+,d2 ;Number of tests
|
||
.Wait3
|
||
move.l ad_TimerIO(a6),a1
|
||
move.w #TR_ADDREQUEST,IO_COMMAND(a1)
|
||
clr.l IOTV_TIME+TV_SECS(a1)
|
||
move.l d3,IOTV_TIME+TV_MICRO(a1)
|
||
move.l ad_SysLib(a6),a6
|
||
jsr _LVODoIO(a6)
|
||
move.l au_Device(a3),a6
|
||
|
||
move.b ata_Status(a5),d0 ;Read the ata_Status register
|
||
btst #ATAB_BUSY,d0 ;Check the BUSY bit
|
||
beq.b .End ;BUSY == 0 : exit
|
||
|
||
dbra d2,.Wait3
|
||
bra.b .Wait2 ;Loop
|
||
.End
|
||
tst.l d3 ;Set/Clear the Z flag
|
||
movem.l (sp)+,d1-d3/a0-a2 ;Restore the registers
|
||
rts ;End
|
||
|
||
.WaitTable
|
||
dc.l 1000 ; 1 ms
|
||
dc.w 19 ;x 20
|
||
dc.l 5000 ; 5 ms
|
||
dc.w 15 ;x 16
|
||
dc.l 10000 ; 10 ms
|
||
dc.w 19 ;x 20
|
||
dc.l 20000 ; 20 ms
|
||
dc.w 9 ;x 10
|
||
dc.l 50000 ; 50 ms
|
||
dc.w 9 ;x 10
|
||
dc.l 100000 ; 100 ms
|
||
dc.w 89 ;x 90
|
||
dc.l 0 ;--------
|
||
;10000 ms
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Wait for BUSY flag being cleared (4 times longer) ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A3.l : ApolloUnit base address
|
||
;A5.l : IDE interface base address
|
||
|
||
;Return values:
|
||
;--------------
|
||
;Z Flag (0:Ok, 1:Error)
|
||
;D0.b : ata_Status
|
||
|
||
WaitBusyLong
|
||
movem.l d1,-(sp) ;Save D0
|
||
move.l au_NumLoop(a3),d1
|
||
lsl.l #2,d1 ;i = NumLoop x 4
|
||
.Wait
|
||
move.b ata_Status(a5),d0 ;Read the ata_Status register
|
||
btst #ATAB_BUSY,d0 ;Check the BUSY bit
|
||
beq.b .Ok ;BUSY == 0 : exit
|
||
subq.l #1,d1 ;i--
|
||
bne.b .Wait ;i != 0 : loop
|
||
.Ok
|
||
tst.l d1 ;Update the Z flag
|
||
movem.l (sp)+,d1 ;Restore D0
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Reset drive after an error ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A3.l : ApolloUnit base address
|
||
;A5.l : IDE interface base address
|
||
;A6.l : AT-Apollo.device base address
|
||
|
||
;Return values:
|
||
;--------------
|
||
;Z Flag (0:Ok, 1:Error)
|
||
|
||
ResumeError
|
||
tst.b au_AtapiDev(a3) ;Check protocol used
|
||
beq.b .Ata
|
||
move.b #ATAPI_RESET,atapi_Command(a5) ;ATAPI drive reset
|
||
bra.b WaitBusyLong ;Wait for BUSY == 0
|
||
|
||
.Ata
|
||
move.b #ATA_RECALIBRATE,ata_Command(a5) ;ATA drive recalibrate
|
||
bra.b WaitBusyLong ;Wait for BUSY == 0
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Freeze CPU 68030/040/060 data cache ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A6.l : AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
FreezeCache
|
||
movem.l d0/d1/a0/a5/a6,-(sp)
|
||
|
||
move.l ad_SysLib(a6),a6 ;A6 : ExecBase
|
||
cmpi.w #33,LIB_VERSION(a6) ;Version > 33 ?
|
||
bls.b .Kick1x ;No, use our own routine
|
||
|
||
move.l #CACRF_FreezeD,d0 ;Yes, use CacheControl()
|
||
move.l #CACRF_FreezeD,d1
|
||
jsr _LVOCacheControl(a6) ;Freeze CPU data cache
|
||
|
||
.End
|
||
movem.l (sp)+,d0/d1/a0/a5/a6
|
||
rts
|
||
|
||
.Kick1x
|
||
move.w AttnFlags(a6),d0
|
||
btst #AFB_68030,d0 ;030+ CPU ?
|
||
beq.b .End ;No, exit
|
||
lea .Super(pc),a5
|
||
jsr _LVOSupervisor(a6)
|
||
bra.b .End
|
||
|
||
.Super
|
||
movec cacr,d0
|
||
bset #CACRB_FreezeD,d0
|
||
movec d0,cacr
|
||
rte
|
||
ENDC
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Unfreeze CPU 68030/040/060 data cache ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A6.l : AT-Apollo.device base address
|
||
|
||
IFD CPU020
|
||
UnFreezeCache
|
||
movem.l d0/d1/a0/a5/a6,-(sp)
|
||
|
||
move.l ad_SysLib(a6),a6 ;A6 : ExecBase
|
||
cmpi.w #33,LIB_VERSION(a6) ;Version > 33 ?
|
||
bls.b .Kick1x ;No, use our own routine
|
||
|
||
moveq #0,d0 ;Yes, use CacheControl()
|
||
move.l #CACRF_FreezeD,d1
|
||
jsr _LVOCacheControl(a6) ;Unfreeze CPU data cache
|
||
|
||
.End
|
||
movem.l (sp)+,d0/d1/a0/a5/a6
|
||
rts
|
||
|
||
.Kick1x
|
||
move.w AttnFlags(a6),d0
|
||
btst #AFB_68030,d0 ;030+ CPU ?
|
||
beq.b .End ;No, exit
|
||
lea .Super(pc),a5
|
||
jsr _LVOSupervisor(a6)
|
||
bra.b .End
|
||
|
||
.Super
|
||
movec cacr,d0
|
||
bclr #CACRB_FreezeD,d0
|
||
movec d0,cacr
|
||
rte
|
||
ENDC
|
||
|
||
;******************************************************************************
|
||
; ---------- "SCSI DIRECT" IMPLEMENTATION FOR ATA & ATAPI DRIVES ----------
|
||
;******************************************************************************
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-2 commands for ATA drives ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : Standard I/O Request
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
ata_ScsiCmd
|
||
move.l a1,-(sp) ;Save A1
|
||
|
||
clr.l scsi_Actual(a2)
|
||
clr.w scsi_CmdActual(a2)
|
||
clr.w scsi_SenseActual(a2) ;We clear the command's
|
||
clr.b scsi_Status(a2) ;sizes and states
|
||
|
||
move.l scsi_Command(a2),a1
|
||
move.b (a1),d0 ;D0: Command byte
|
||
cmpi.b #SCSI_REQUESTSENSE,d0 ;$03: REQUEST SENSE command
|
||
beq.w scsi_RequestSense
|
||
clr.w au_SenseKey(a3) ;No, clear the errors
|
||
clr.l au_LBASense(a3)
|
||
|
||
tst.b d0 ;$00: TEST UNIT READY command
|
||
beq.w scsi_TestUnitReady
|
||
subq.b #1,d0 ;$01: RE-ZERO UNIT command
|
||
; beq.w scsi_RezeroUnit
|
||
subq.b #3,d0 ;$04: FORMAT UNIT command
|
||
; beq.b scsi_FormatUnit
|
||
subq.b #4,d0 ;$08: READ(6) command
|
||
beq.w scsi_Read6
|
||
subq.b #2,d0 ;$0A: WRITE(6) command
|
||
beq.w scsi_Write6
|
||
subq.b #1,d0 ;$0B: SEEK(6) command
|
||
beq.w scsi_Seek6
|
||
subq.b #7,d0 ;$12: INQUIRY command
|
||
beq.w scsi_Inquiry
|
||
subq.b #1,d0 ;$13: VERIFY(6) command
|
||
; beq.w scsi_Verify6
|
||
subq.b #3,d0 ;$16: RESERVE(6) command
|
||
; beq.b scsi_Reserve6
|
||
subq.b #1,d0 ;$17: RELEASE(6) command
|
||
; beq.b scsi_Release6
|
||
subq.b #3,d0 ;$1A: MODE SENSE(6) command
|
||
beq.w scsi_ModeSense6
|
||
subq.b #3,d0 ;$1D: SEND DIAGNOSTIC command
|
||
; beq.b scsi_SendDiagnostic
|
||
subq.b #8,d0 ;$25: READ CAPACITY command
|
||
beq.w scsi_ReadCapacity
|
||
subq.b #3,d0 ;$28: READ(10) command
|
||
beq.w scsi_Read10
|
||
subq.b #2,d0 ;$2A: WRITE(10) command
|
||
beq.w scsi_Write10
|
||
subq.b #1,d0 ;$2B: SEEK(10) command
|
||
beq.w scsi_Seek10
|
||
subq.b #4,d0 ;$2F: VERIFY(10) command
|
||
beq.w scsi_Verify10
|
||
subi.b #$26,d0 ;$55: MODE SELECT(10) command
|
||
; beq.w scsi_ModeSelect10
|
||
subq.b #1,d0 ;$56: RESERVE(10) command
|
||
; beq.b scsi_Reserve10
|
||
subq.b #1,d0 ;$57: RELEASE(10) command
|
||
; beq.b scsi_Release10
|
||
subq.b #3,d0 ;$5A: MODE SENSE(10) command
|
||
; beq.b scsi_ModeSense10
|
||
subi.b #$4E,d0 ;$A8: READ(12) command
|
||
beq.w scsi_Read12
|
||
subq.b #2,d0 ;$AA: WRITE(12) command
|
||
beq.w scsi_Write12
|
||
subq.b #5,d0 ;$AF: VERIFY(12) command
|
||
beq.w scsi_Verify12
|
||
|
||
ScsiInvCmd
|
||
move.w #$0520,au_SenseKey(a3) ;Illegal request + Invalid cmd opcode
|
||
|
||
ScsiError
|
||
btst #SCSIB_AUTOSENSE,scsi_Flags(a2) ;Auto-Sense mode ?
|
||
beq.b .Error1 ;No, exit
|
||
|
||
lea -18(sp),sp
|
||
|
||
moveq #0,d1
|
||
move.w au_SenseKey(a3),d0
|
||
move.b d0,d1
|
||
clr.b d0
|
||
|
||
move.l sp,a0
|
||
move.b #$70,(a0)+ ;Current error
|
||
|
||
IFD CPU020
|
||
|
||
move.w d1,(a0)+ ;Sense key
|
||
move.l au_LBASense(a3),(a0)+ ;LBA where the error occured
|
||
|
||
ELSE
|
||
|
||
clr.b (a0)+
|
||
move.b d1,(a0)+
|
||
move.b au_LBASense(a3),(a0)+ ;LBA where the error occured
|
||
move.b au_LBASense+1(a3),(a0)+ ;LBA where the error occured
|
||
move.b au_LBASense+2(a3),(a0)+ ;LBA where the error occured
|
||
move.b au_LBASense+3(a3),(a0)+ ;LBA where the error occured
|
||
|
||
ENDC
|
||
|
||
move.b #10,(a0)+ ;Additional size
|
||
|
||
|
||
clr.l (a0)+
|
||
move.w d0,(a0)+ ;Additional sense code
|
||
clr.l (a0)+
|
||
|
||
moveq #4,d0 ;4 bytes for the "Old Auto-Sense"
|
||
btst #SCSIB_OLDAUTOSENSE,scsi_Flags(a2) ;Old Auto-Sense mode ?
|
||
bne.b .OldAS ;Yes, skip next line
|
||
move.w scsi_SenseLength(a2),d0 ;No, keep the size into account
|
||
.OldAS
|
||
cmpi.w #18,d0 ;Greater than 18 ?
|
||
bls.b .Lower ;No, skip
|
||
moveq #18,d0 ;Yes, limit to 18
|
||
.Lower
|
||
move.w d0,scsi_SenseActual(a2)
|
||
subq.w #1,d0
|
||
bcs.b .Error2
|
||
|
||
move.l sp,a0 ;A0: Source
|
||
move.l scsi_SenseData(a2),a1 ;A1: Destination
|
||
.SenseLoop
|
||
move.b (a0)+,(a1)+ ;Copy one byte
|
||
dbra d0,.SenseLoop ;Loop
|
||
|
||
.Error2
|
||
lea 18(sp),sp ;Restore stack
|
||
.Error1
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-2 commands for ATAPI drives ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : Standard I/O Request
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
atapi_ScsiCmd
|
||
movem.l a1/a4-a6,-(sp) ;Save A1, A4, A5 & A6
|
||
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
|
||
clr.l -(sp)
|
||
clr.l -(sp)
|
||
clr.l -(sp) ;Allocate CDB size on the stack
|
||
|
||
;*************** CPU data cache managemnt *************************************
|
||
|
||
IFD CPU020
|
||
bsr.w FreezeCache ;Freeze CPU data cache
|
||
ENDC
|
||
|
||
;*************** Initialize various variables *********************************
|
||
|
||
clr.w scsi_SenseActual(a2) ;No sense key
|
||
clr.b scsi_Status(a2) ;No error
|
||
clr.l scsi_Actual(a2) ;No data transfered
|
||
move.w scsi_CmdLength(a2),d0 ;D0: Command length
|
||
cmpi.w #12,d0 ;CDB size greater than 12 bytes ?
|
||
bhi.w .Error ;Yes, error
|
||
cmpi.w #6,d0 ;CDB size less than 6 bytes ?
|
||
bcs.w .Error ;Yes, error
|
||
move.w d0,scsi_CmdActual(a2) ;Otherwise, write the size into CmdActual
|
||
lsr.w #1,d0
|
||
subq.w #1,d0
|
||
|
||
;*************** CDB copy *****************************************************
|
||
|
||
move.l scsi_Command(a2),a0
|
||
move.l sp,a1
|
||
.CopyLoop
|
||
move.w (a0)+,(a1)+ ;CDB copy loop
|
||
dbra d0,.CopyLoop
|
||
|
||
;*************** SCSI-1 compatibility *****************************************
|
||
|
||
move.l sp,a4
|
||
move.b (a4),d0
|
||
cmpi.b #$20,d0 ;SCSI-2 commands ?
|
||
bcc.b .SendCDB ;Yes, no conversion
|
||
cmpi.b #SCSI_READ6,d0 ;READ(6) command ?
|
||
beq.b .BlkCmd ;Yes, convert it
|
||
cmpi.b #SCSI_WRITE6,d0 ;WRITE(6) command ?
|
||
beq.b .BlkCmd ;Yes, convert it
|
||
cmpi.b #SCSI_SEEK6,d0 ;SEEK(6) command ?
|
||
beq.b .BlkCmd ;Yes, convert it
|
||
cmpi.b #SCSI_MODESELECT6,d0 ;MODE SELECT(6) command ?
|
||
beq.b .ModeCmd ;Yes, convert it
|
||
cmpi.b #SCSI_MODESENSE6,d0 ;MODE SENSE(6) command ?
|
||
beq.b .ModeCmd ;Yes, convert it
|
||
bra.b .SendCDB ;No conversion
|
||
.BlkCmd
|
||
ori.b #$20,d0
|
||
move.b d0,(a4) ;SCSI-2 command
|
||
move.w 4(a4),8(a4) ;16-bit length + control
|
||
move.l (a4),d0
|
||
andi.l #$001FFFFF,d0
|
||
move.l d0,2(a4) ;32-bit LBA
|
||
clr.b 1(a4)
|
||
bra.b .SendCDB
|
||
.ModeCmd
|
||
ori.b #$40,d0
|
||
move.b d0,(a4) ;SCSI-2 command
|
||
move.w 4(a4),8(a4) ;16-bit length + control
|
||
clr.w 4(a4)
|
||
|
||
;*************** Send the CDB *************************************************
|
||
|
||
.SendCDB
|
||
bsr.w SendPacket ;Send CDB's 12 bytes
|
||
beq.w .Error ;An error has occured
|
||
|
||
move.l scsi_Data(a2),a0 ;A0: data address
|
||
moveq #0,d1
|
||
|
||
;*************** Initialize the data transfer *********************************
|
||
|
||
.Loop
|
||
bsr.w WaitBusySlow ;Wait for BUSY == 0
|
||
beq.w .Error ;Time-out elapsed : error
|
||
btst #ATAPIB_DATAREQ,d0 ;Some data to transfer ?
|
||
beq.b .NoData ;No, skip
|
||
move.b atapi_Reason(a5),d0 ;"Interrupt Reason Register"
|
||
btst #ATAPIB_COD,d0 ;Ready to transfer data ?
|
||
bne.w .Error ;No, error
|
||
move.b atapi_ByteCntH(a5),d1
|
||
lsl.w #8,d1
|
||
move.b atapi_ByteCntL(a5),d1 ;D1.w : Number of bytes to transfer
|
||
move.l d1,d2
|
||
addq.l #1,d1
|
||
lsr.l #1,d1
|
||
subq.w #1,d1
|
||
btst #ATAPIB_IO,d0 ;Transfer direction
|
||
bne.b .ReadLoop ;Bit set : read
|
||
|
||
;*************** Write data to the ATA bus ************************************
|
||
|
||
.WriteLoop
|
||
move.w (a0)+,(a5) ;Reading one word from memory to the ATA bus
|
||
dbra d1,.WriteLoop ;Loop
|
||
add.l d2,scsi_Actual(a2)
|
||
bra.b .Loop ;Loop
|
||
|
||
;*************** Read data from the ATA bus ***********************************
|
||
|
||
.ReadLoop
|
||
move.w (a5),(a0)+ ;Reading one word from the ATA bus to memory
|
||
dbra d1,.ReadLoop ;Loop
|
||
add.l d2,scsi_Actual(a2)
|
||
bra.b .Loop ;Loop
|
||
|
||
;*************** End of the command *******************************************
|
||
|
||
.NoData
|
||
btst #ATAPIB_CHECK,atapi_Status(a5) ;Check condition ?
|
||
beq.w .End ;No, exit
|
||
move.b #2,scsi_Status(a2) ;Yes, set the bit
|
||
|
||
move.w #SCSI_REQUESTSENSE,(a4)+ ;ATAPI command "Request Sense"
|
||
clr.w (a4)+
|
||
clr.l (a4)+
|
||
clr.l (a4) ;We clear the CDB
|
||
subq.l #8,a4 ;Restore A4
|
||
|
||
move.l scsi_SenseData(a2),a0 ;A0: data address
|
||
move.b scsi_Flags(a2),d0 ;D0: Flags
|
||
btst #SCSIB_AUTOSENSE,d0 ;Extended auto-sense ?
|
||
bne.b .ExtSense ;Yes
|
||
btst #SCSIB_OLDAUTOSENSE,d0 ;Old auto-sense ?
|
||
bne.b .OldSense ;Yes
|
||
bra.b .NoSense ;No auto-sense
|
||
|
||
;*************** Old Auto-Sense ***********************************************
|
||
|
||
.OldSense
|
||
move.w #$7000,(a0)+
|
||
move.b atapi_Error(a5),d0
|
||
lsr.b #4,d0
|
||
move.b d0,(a0)+
|
||
clr.b (a0)+
|
||
move.w #4,scsi_SenseActual(a2)
|
||
; cmpi.b #6,d0
|
||
; bne.b .End
|
||
|
||
;*************** No Auto-Sense : re-initialize everything *********************
|
||
|
||
.NoSense
|
||
clr.b 4(a4) ;No information returned
|
||
bra.b .SendSense
|
||
|
||
;*************** Extended Auto-Sense ******************************************
|
||
|
||
.ExtSense
|
||
move.b scsi_SenseLength+1(a2),4(a4) ;Returned information's length
|
||
|
||
.SendSense
|
||
bsr.w SendPacket ;Send CDB's 12 bytes
|
||
beq.b .Error ;An error has occured
|
||
|
||
.SenseLoop1
|
||
bsr.w WaitBusySlow ;Wait for BUSY == 0
|
||
beq.b .Error ;Time-out elapsed : error
|
||
btst #ATAPIB_DATAREQ,d0 ;Data to transfer ?
|
||
beq.b .End ;No, exit
|
||
move.b atapi_Reason(a5),d0
|
||
btst #ATAPIB_COD,d0
|
||
bne.b .Error
|
||
btst #ATAPIB_IO,d0
|
||
beq.b .Error
|
||
|
||
moveq #0,d1
|
||
move.b atapi_ByteCntL(a5),d1 ;D1.w: Number of bytes to read
|
||
beq.b .End ;Nothing to read : exit
|
||
move.w d1,scsi_SenseActual(a2)
|
||
addq.w #1,d1
|
||
lsr.w #1,d1
|
||
subq.w #1,d1
|
||
.SenseLoop2
|
||
move.w (a5),(a0)+ ;Reading one word to memory
|
||
dbra d1,.SenseLoop2 ;Loop
|
||
bra.b .SenseLoop1
|
||
|
||
;*************** End of SCSI-2 commands for ATAPI drives **********************
|
||
|
||
.End
|
||
IFD CPU020
|
||
bsr.w UnFreezeCache ;Unfreeze CPU data cache
|
||
ENDC
|
||
|
||
lea 12(sp),sp ;Restore stack
|
||
movem.l (sp)+,a1/a4-a6 ;Restore A1, A4, A5 & A6
|
||
rts ;End
|
||
|
||
.Error
|
||
move.b #5,scsi_Status(a2)
|
||
clr.l scsi_Actual(a2)
|
||
clr.w scsi_SenseActual(a2)
|
||
clr.w scsi_CmdActual(a2)
|
||
bra.b .End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-1 command : blocks read ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : SCSI CDB address
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
scsi_Read6
|
||
move.w scsi_CmdLength(a2),d0 ;CDB size
|
||
cmpi.w #6,d0 ;6-byte CDB ?
|
||
bne.w ScsiInvCmd ;No, invalid command
|
||
move.w d0,scsi_CmdActual(a2) ;Yes
|
||
|
||
move.l (a1)+,d0
|
||
andi.l #$001FFFFF,d0 ;D0: LBA (21 bits)
|
||
moveq #0,d1
|
||
move.b (a1),d1 ;D1: Length (8 bits)
|
||
bne.b .NotNull
|
||
move.w #256,d1 ;Null size : 256 blocks
|
||
.NotNull
|
||
move.l scsi_Data(a2),a0 ;A0: Buffer
|
||
jsr au_ReadJmp(a3) ;Reading blocks
|
||
move.l d1,scsi_Actual(a2) ;D1: Transfer length in bytes
|
||
tst.b d0
|
||
bne.w ScsiError ;SCSI error management
|
||
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-2 command : blocks read ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : SCSI CDB address
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
scsi_Read10
|
||
move.w scsi_CmdLength(a2),d0 ;CDB size
|
||
cmpi.w #10,d0 ;10-byte CDB ?
|
||
bne.w ScsiInvCmd ;No, invalid command
|
||
move.w d0,scsi_CmdActual(a2) ;Yes
|
||
|
||
movem.l 2(a1),d0/d1 ;D0: LBA (32 bits),D1: Length (16 bits)
|
||
lsl.l #8,d1
|
||
clr.w d1
|
||
swap d1
|
||
move.l scsi_Data(a2),a0 ;A0: Buffer
|
||
jsr au_ReadJmp(a3) ;Reading blocks
|
||
move.l d1,scsi_Actual(a2) ;D1: Transfer length in bytes
|
||
tst.b d0
|
||
bne.w ScsiError ;SCSI error management
|
||
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-3 command : blocks read ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : SCSI CDB address
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
scsi_Read12
|
||
move.w scsi_CmdLength(a2),d0 ;CDB size
|
||
cmpi.w #12,d0 ;12-byte CDB ?
|
||
bne.w ScsiInvCmd ;No, invalid command
|
||
move.w d0,scsi_CmdActual(a2) ;Yes
|
||
|
||
movem.l 2(a1),d0/d1 ;D0: LBA (32 bits),D1: Length (32 bits)
|
||
move.l scsi_Data(a2),a0 ;A0: Buffer
|
||
jsr au_ReadJmp(a3) ;Reading blocks
|
||
move.l d1,scsi_Actual(a2) ;D1: Transfer length in bytes
|
||
tst.b d0
|
||
bne.w ScsiError ;SCSI error management
|
||
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-2 command : blocks verify ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : SCSI CDB address
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
scsi_Verify10
|
||
move.w scsi_CmdLength(a2),d0 ;CDB size
|
||
cmpi.w #10,d0 ;10-byte CDB ?
|
||
bne.w ScsiInvCmd ;No, invalid command
|
||
move.w d0,scsi_CmdActual(a2) ;Yes
|
||
|
||
movem.l 2(a1),d0/d1 ;D0: LBA (32 bits),D1: Length (16 bits)
|
||
lsl.l #8,d1
|
||
clr.w d1
|
||
swap d1
|
||
; bsr.w ata_Verify ;Verifying blocks
|
||
beq.w ScsiError ;SCSI error management
|
||
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-3 command : blocks verify ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : SCSI CDB address
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
scsi_Verify12
|
||
move.w scsi_CmdLength(a2),d0 ;CDB size
|
||
cmpi.w #12,d0 ;12-byte CDB ?
|
||
bne.w ScsiInvCmd ;No, invalid command
|
||
move.w d0,scsi_CmdActual(a2) ;Yes
|
||
|
||
movem.l 2(a1),d0/d1 ;D0: LBA (32 bits),D1: Length (32 bits)
|
||
; bsr.w ata_Verify ;Verifying blocks
|
||
beq.w ScsiError ;SCSI error management
|
||
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-1 command : blocks write ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : SCSI CDB address
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
scsi_Write6
|
||
move.w scsi_CmdLength(a2),d0 ;CDB size
|
||
cmpi.w #6,d0 ;6-byte CDB ?
|
||
bne.w ScsiInvCmd ;No, invalid command
|
||
move.w d0,scsi_CmdActual(a2) ;Yes
|
||
|
||
move.l (a1)+,d0
|
||
andi.l #$001FFFFF,d0 ;D0: LBA (21 bits)
|
||
moveq #0,d1
|
||
move.b (a1),d1 ;D1: Length (8 bits)
|
||
bne.b .NotNull
|
||
move.w #256,d1 ;Null length case : 256 blocks
|
||
.NotNull
|
||
move.l scsi_Data(a2),a0 ;A0: Buffer
|
||
jsr au_WriteJmp(a3) ;Writing blocks
|
||
move.l d1,scsi_Actual(a2) ;D1: Transfer length in bytes
|
||
tst.b d0
|
||
bne.w ScsiError ;SCSI error management
|
||
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-2 command : blocks write ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : SCSI CDB address
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
scsi_Write10
|
||
move.w scsi_CmdLength(a2),d0 ;CDB size
|
||
cmpi.w #10,d0 ;10-byte CDB ?
|
||
bne.w ScsiInvCmd ;No, invalid command
|
||
move.w d0,scsi_CmdActual(a2) ;Yes
|
||
|
||
movem.l 2(a1),d0/d1 ;D0: LBA (32 bits),D1: Length (16 bits)
|
||
lsl.l #8,d1
|
||
clr.w d1
|
||
swap d1
|
||
move.l scsi_Data(a2),a0 ;A0: Buffer
|
||
jsr au_WriteJmp(a3) ;Writing blocks
|
||
move.l d1,scsi_Actual(a2) ;D1: Transfer length in bytes
|
||
tst.b d0
|
||
bne.w ScsiError ;SCSI error management
|
||
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-3 command : blocks write ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : SCSI CDB address
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
scsi_Write12
|
||
move.w scsi_CmdLength(a2),d0 ;CDB size
|
||
cmpi.w #12,d0 ;12-byte CDB ?
|
||
bne.w ScsiInvCmd ;No, invalid command
|
||
move.w d0,scsi_CmdActual(a2) ;Yes
|
||
|
||
movem.l 2(a1),d0/d1 ;D0: LBA (32 bits),D1: Length (32 bits)
|
||
move.l scsi_Data(a2),a0 ;A0: Buffer
|
||
jsr au_WriteJmp(a3) ;Writing blocks
|
||
move.l d1,scsi_Actual(a2) ;D1: Transfer length in bytes
|
||
tst.b d0
|
||
bne.w ScsiError ;SCSI error management
|
||
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-1 command : head seek ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : SCSI CDB address
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
scsi_Seek6
|
||
move.w scsi_CmdLength(a2),d0 ;CDB size
|
||
cmpi.w #6,d0 ;6-byte CDB ?
|
||
bne.w ScsiInvCmd ;No, invalid command
|
||
move.w d0,scsi_CmdActual(a2) ;Yes
|
||
|
||
move.l (a1),d0
|
||
andi.l #$001FFFFF,d0 ;D0: LBA (21 bits)
|
||
bsr.w ata_Seek ;Heads movement
|
||
beq.w ScsiError ;SCSI error management
|
||
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-2 command : head seek ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : SCSI CDB address
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
scsi_Seek10
|
||
move.w scsi_CmdLength(a2),d0 ;CDB size
|
||
cmpi.w #10,d0 ;10-byte CDB ?
|
||
bne.w ScsiInvCmd ;No, invalid command
|
||
move.w d0,scsi_CmdActual(a2) ;Yes
|
||
|
||
move.l 2(a1),d0 ;D0: LBA (32 bits)
|
||
bsr.w ata_Seek ;Heads movement
|
||
beq.w ScsiError ;SCSI error management
|
||
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-2 command : disk capacity reading ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : SCSI CDB address
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
scsi_ReadCapacity
|
||
move.w scsi_CmdLength(a2),d0 ;CDB size
|
||
cmpi.w #10,d0 ;10-byte CDB ?
|
||
bne.w ScsiInvCmd ;No, invalid command
|
||
move.w d0,scsi_CmdActual(a2) ;Yes, continue
|
||
|
||
btst #0,8(a1) ;PMI bit set ?
|
||
bne.b .Pmi ;Yes, skip
|
||
tst.l 2(a1) ;LBA not null ?
|
||
bne.b .Error ;Yes, error
|
||
move.l au_Blocks(a3),d0 ;No, D0 : total number of blocks
|
||
bra.b .Cont ;We continue
|
||
.Pmi
|
||
move.l 2(a1),d0 ;D0 : 32-bit LBA
|
||
divu au_SectorsC(a3),d0
|
||
addq.w #1,d0
|
||
mulu au_SectorsC(a3),d0 ;D0 : Next cylinder's LBA
|
||
.Cont
|
||
subq.l #1,d0
|
||
move.l au_SectSize(a3),d1 ;D1 : Block size
|
||
|
||
movem.l d0/d1,-(sp)
|
||
move.l sp,a0 ;A0 : source
|
||
moveq #8,d0 ;8 bytes to copy
|
||
bsr.w CopyScsiResult ;Copy the result
|
||
addq.l #8,sp ;Restore the stack
|
||
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
.Error
|
||
move.w #$0524,au_SenseKey(a3) ;Invalid field in CDB + Illegal request
|
||
bra.w ScsiError ;SCSI error management
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-1 command : Inquiry (auto-detect drives) ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : SCSI CDB address
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
scsi_Inquiry
|
||
move.w scsi_CmdLength(a2),d0 ;CDB size
|
||
cmpi.w #6,d0 ;6-byte CDB ?
|
||
bne.w ScsiInvCmd ;No, invalid command
|
||
move.w d0,scsi_CmdActual(a2) ;Yes
|
||
|
||
lea -56(sp),sp ;56 bytes allocated on the stack
|
||
move.l sp,a0
|
||
move.b au_DevType(a3),(a0)+ ;Device type
|
||
moveq #0,d0
|
||
tst.b au_Removable(a3) ;Removable media ?
|
||
beq.b .NoRemove ;No, skip next line
|
||
bset #7,d0 ;Yes, set bit #7
|
||
.NoRemove
|
||
move.b d0,(a0)+
|
||
moveq #2,d0
|
||
move.b d0,(a0)+ ;SCSI-2 compatible
|
||
move.b d0,(a0)+ ;Normal Inquiry response
|
||
move.b 4(a1),d0
|
||
subq.b #4,d0
|
||
move.b d0,(a0)+ ;Additional size
|
||
clr.b (a0)+
|
||
clr.b (a0)+
|
||
move.b #$88,(a0)+ ;Relative mode & linked commands
|
||
|
||
lea au_ModelID(a3),a1
|
||
moveq #5,d0 ;6 long words to copy
|
||
.IDLoop
|
||
move.l (a1)+,(a0)+
|
||
dbra d0,.IDLoop ;Model identification
|
||
|
||
addq.l #8,a1
|
||
move.l (a1)+,(a0)+ ;Firmware version
|
||
|
||
clr.l (a0)+
|
||
clr.l (a0)+
|
||
movem.l (a1),d0-d2
|
||
movem.l d0-d2,(a0) ;Serial number
|
||
|
||
move.l sp,a0 ;A0 : source
|
||
moveq #56,d0 ;56 bytes to copy
|
||
bsr.w CopyScsiResult ;Copy the result
|
||
lea 56(sp),sp ;Restore the stack
|
||
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-1 command : Test unit ready ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : SCSI CDB address
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
scsi_TestUnitReady
|
||
move.w scsi_CmdLength(a2),d0 ;CDB size
|
||
cmpi.w #6,d0 ;6-byte CDB ?
|
||
bne.w ScsiInvCmd ;No, invalid command
|
||
move.w d0,scsi_CmdActual(a2) ;Yes
|
||
|
||
movem.l a5/a6,-(sp) ;Save A5 & A6
|
||
move.l au_PortAddr(a3),a5 ;A5: IDE interface base address
|
||
move.l au_Device(a3),a6 ;A6: AT-Apollo.device base address
|
||
move.b au_DevMask(a3),ata_DevHead(a5) ;Select the drive
|
||
bsr.w WaitBusy ;Wait for BUSY == 0
|
||
bne.b .Error1 ;Time-out elapsed : error
|
||
btst #ATAB_DEVREADY,ata_Status(a5) ;Check if the drive is ready
|
||
beq.b .Error2 ;Not ready : error
|
||
movem.l (sp)+,a5/a6 ;Restore A5 & A6
|
||
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
.Error1
|
||
move.w #$0205,au_SenseKey(a3) ;Not ready + Logical unit does not respond
|
||
movem.l (sp)+,a5/a6 ;Restore A5 & A6
|
||
bra.w ScsiError ;SCSI error management
|
||
|
||
.Error2
|
||
move.w #$0204,au_SenseKey(a3) ;Not ready + Logical unit not ready
|
||
movem.l (sp)+,a5/a6 ;Restore A5 & A6
|
||
bra.w ScsiError ;SCSI error management
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-1 command : Request sense ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : SCSI CDB address
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
scsi_RequestSense
|
||
move.w #6,scsi_CmdActual(a2) ;6-byte CDB
|
||
move.l scsi_Length(a2),scsi_Actual(a2) ;Size of the returned data
|
||
|
||
lea -18(sp),sp ;18 bytes allocated on the stack
|
||
|
||
moveq #0,d1
|
||
move.w au_SenseKey(a3),d0
|
||
move.b d0,d1
|
||
clr.b d0
|
||
|
||
move.l sp,a0
|
||
move.b #$70,(a0)+ ;Current error
|
||
IFD CPU020
|
||
|
||
move.w d1,(a0)+ ;Sense key
|
||
move.l au_LBASense(a3),(a0)+ ;LBA where the error occured
|
||
|
||
ELSE
|
||
|
||
clr.b (a0)+
|
||
move.b d1,(a0)+
|
||
move.b au_LBASense(a3),(a0)+ ;LBA where the error occured
|
||
move.b au_LBASense+1(a3),(a0)+ ;LBA where the error occured
|
||
move.b au_LBASense+2(a3),(a0)+ ;LBA where the error occured
|
||
move.b au_LBASense+3(a3),(a0)+ ;LBA where the error occured
|
||
|
||
|
||
ENDC
|
||
move.b #10,(a0)+ ;Extra size
|
||
clr.l (a0)+
|
||
move.w d0,(a0)+ ;Additional sense code
|
||
clr.l (a0)+
|
||
|
||
move.l sp,a0 ;A0 : source address
|
||
moveq #18,d0 ;18 bytes to copy
|
||
bsr.w CopyScsiResult ;Copy the result
|
||
|
||
lea 18(sp),sp ;Restore the stack
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-2 command : Mode Sense ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : SCSI CDB address
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
scsi_ModeSense10
|
||
move.w scsi_CmdLength(a2),d0 ;CDB size
|
||
cmpi.w #10,d0 ;10-byte CDB ?
|
||
bne.w ScsiInvCmd ;No, invalid command
|
||
move.w d0,scsi_CmdActual(a2) ;Yes
|
||
|
||
lea -104(sp),sp ;104 bytes allocated on the stack
|
||
move.l sp,a0
|
||
move.w #13,(a0)+ ;Page size : 13 bytes
|
||
clr.l (a0)+ ;Media type, specific parameters
|
||
move.w #8,(a0)+ ;Block descriptor size
|
||
move.l au_Blocks(a3),(a0)+ ;Number of blocks
|
||
move.l au_SectSize(a3),(a0)+ ;Sector size
|
||
move.b 2(a1),d0
|
||
lea 1(sp),a1
|
||
bra.b scsi_MS_Jump
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** SCSI-1 command : Mode Sense ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;A1.l : SCSI CDB address
|
||
;A2.l : SCSICmd structure
|
||
;A3.l : ApolloUnit base address
|
||
|
||
scsi_ModeSense6
|
||
move.w scsi_CmdLength(a2),d0 ;CDB size
|
||
cmpi.w #6,d0 ;6-byte CDB ?
|
||
bne.w ScsiInvCmd ;No, invalid command
|
||
move.w d0,scsi_CmdActual(a2) ;Yes
|
||
|
||
lea -104(sp),sp ;104 bytes allocated on the stack
|
||
move.l sp,a0
|
||
move.b #13,(a0)+ ;Page size : 13 bytes
|
||
clr.b (a0)+ ;Media type, specific parameters
|
||
clr.b (a0)+ ;Specific parameters
|
||
move.b #8,(a0)+ ;Block descriptor size
|
||
move.l au_Blocks(a3),(a0)+ ;Number of blocks
|
||
move.l au_SectSize(a3),(a0)+ ;Sector size
|
||
move.b 2(a1),d0
|
||
move.l sp,a1
|
||
|
||
scsi_MS_Jump
|
||
andi.b #%00111111,d0 ;"Page Code" field
|
||
|
||
subq.b #3,d0 ;$03 : Format device page
|
||
beq.b .Format
|
||
|
||
subq.b #1,d0 ;$04 : Rigid disk geometry page
|
||
beq.b .Geometry
|
||
|
||
subq.b #4,d0 ;$08 : Caching page
|
||
; beq.b .Cache
|
||
|
||
subq.b #1,d0 ;$09 : Peripheral device page
|
||
beq.b .Periph
|
||
|
||
subq.b #4,d0 ;$0D : Power condition page
|
||
beq.b .Power
|
||
|
||
cmpi.b #$32,d0 ;$3F : All pages
|
||
beq.b .All
|
||
|
||
bra.w ScsiInvCmd ;Invalid command
|
||
|
||
.Format
|
||
bsr.b scsi_MS_Format
|
||
bra.b .End
|
||
|
||
.Geometry
|
||
bsr.b scsi_MS_Geometry
|
||
bra.b .End
|
||
|
||
.Cache
|
||
bsr.b scsi_MS_Cache
|
||
bra.b .End
|
||
|
||
.Periph
|
||
bsr.b scsi_MS_Periph
|
||
bra.b .End
|
||
|
||
.Power
|
||
bsr.w scsi_MS_Power
|
||
bra.b .End
|
||
|
||
.All
|
||
bsr.b scsi_MS_Format
|
||
bsr.b scsi_MS_Geometry
|
||
; bsr.b scsi_MS_Cache
|
||
bsr.b scsi_MS_Periph
|
||
bsr.b scsi_MS_Power
|
||
|
||
.End
|
||
moveq #1,d0
|
||
add.b (a1),d0 ;Number of bytes to copy
|
||
move.l sp,a0
|
||
bsr.w CopyScsiResult ;Copy the result
|
||
lea 104(sp),sp ;Restore the stack
|
||
move.l (sp)+,a1 ;Restore A1
|
||
rts ;End
|
||
|
||
scsi_MS_Format
|
||
move.b #$03,(a0)+
|
||
moveq #22,d0 ;22 bytes in the page
|
||
add.b d0,(a1)
|
||
move.b d0,(a0)+
|
||
clr.l (a0)+
|
||
clr.l (a0)+
|
||
clr.b (a0)+
|
||
move.b au_SectorsT(a3),(a0)+ ;Number of sectors per track
|
||
move.w au_SectSize+2(a3),(a0)+ ;Sector size
|
||
move.w #1,(a0)+ ;Interleave
|
||
clr.l (a0)+
|
||
move.b #%10000000,(a0)+ ;Soft format
|
||
clr.b (a0)+
|
||
clr.w (a0)+
|
||
rts
|
||
|
||
scsi_MS_Geometry
|
||
move.b #$04,(a0)+
|
||
moveq #22,d0 ;22 bytes in the page
|
||
add.b d0,(a1)
|
||
move.b d0,(a0)+
|
||
move.w au_Cylinders(a3),d0 ;Number of cylinders
|
||
lsl.l #8,d0
|
||
move.b au_Heads(a3),d0 ;Number of heads
|
||
move.l d0,(a0)+
|
||
clr.w (a0)+
|
||
clr.l (a0)+
|
||
clr.l (a0)+
|
||
clr.l (a0)+
|
||
clr.l (a0)+
|
||
rts
|
||
|
||
scsi_MS_Cache
|
||
move.b #$08,(a0)+
|
||
moveq #18,d0 ;18 bytes in the page
|
||
add.b d0,(a1)
|
||
move.b d0,(a0)+
|
||
rts
|
||
|
||
scsi_MS_Periph
|
||
move.b #$09,(a0)+
|
||
moveq #6,d0 ;6 bytes in the page
|
||
add.b d0,(a1)
|
||
move.b d0,(a0)+
|
||
move.w #3,(a0)+ ;SCSI-2 interface
|
||
clr.l (a0)+
|
||
rts
|
||
|
||
scsi_MS_Power
|
||
move.b #$0D,(a0)+
|
||
moveq #10,d0 ;10 bytes in the page
|
||
add.b d0,(a1)
|
||
move.b d0,(a0)+
|
||
clr.w (a0)+ ;Timers disabled
|
||
clr.l (a0)+ ;Idle timer
|
||
clr.l (a0)+ ;Standby timer
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Copy the result of a SCSI command ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
;Parameters:
|
||
;-----------
|
||
;D0.l : Copy size
|
||
;A0.l : Source address
|
||
;A2.l : SCSICmd structure
|
||
|
||
CopyScsiResult
|
||
cmp.l scsi_Length(a2),d0 ;Greater than the expected size ?
|
||
bls.b .Lower ;No, skip next instruction
|
||
move.l scsi_Length(a2),d0 ;Yes, limit the size
|
||
|
||
.Lower
|
||
move.l d0,scsi_Actual(a2)
|
||
subq.w #1,d0 ;-1 for DBRA
|
||
bcs.b .End ;Null size : exit
|
||
move.l scsi_Data(a2),a1 ;A1 : destination address
|
||
|
||
.CopyLoop
|
||
move.b (a0)+,(a1)+ ;Copy one byte
|
||
dbra d0,.CopyLoop ;Loop
|
||
|
||
.End
|
||
rts
|
||
|
||
;******************************************************************************
|
||
;******** ********
|
||
;******** Debugging routine under PowerVisor v1.43 ********
|
||
;******** ********
|
||
;******************************************************************************
|
||
|
||
IF PVDBG>0
|
||
|
||
PutChProc
|
||
move.b d0,(a3)+
|
||
rts
|
||
|
||
IdentifyCmd
|
||
moveq #0,d0
|
||
move.b (a4),d0
|
||
cmpi.b #$C0,d0
|
||
bcc.b .Unknown
|
||
add.w d0,d0
|
||
add.w d0,d0
|
||
move.l .Map(pc,d0.w),ad_CmdStr(a5)
|
||
rts
|
||
.Unknown
|
||
move.l #CmdXX,ad_CmdStr(a5)
|
||
rts
|
||
.Map
|
||
dc.l Cmd00,Cmd01,CmdXX,Cmd03,CmdXX,CmdXX,CmdXX,CmdXX
|
||
dc.l Cmd08,CmdXX,CmdXX,Cmd0B,CmdXX,CmdXX,CmdXX,CmdXX
|
||
|
||
dc.l CmdXX,CmdXX,Cmd12,CmdXX,CmdXX,Cmd15,Cmd16,Cmd17
|
||
dc.l Cmd18,CmdXX,Cmd1A,Cmd1B,Cmd1C,Cmd1D,Cmd1E,CmdXX
|
||
|
||
dc.l CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,Cmd25,CmdXX,CmdXX
|
||
dc.l Cmd28,CmdXX,CmdXX,Cmd2B,CmdXX,CmdXX,CmdXX,Cmd2F
|
||
|
||
dc.l Cmd30,Cmd31,Cmd32,Cmd33,Cmd34,Cmd35,Cmd36,CmdXX
|
||
dc.l CmdXX,Cmd39,Cmd3A,Cmd3B,Cmd3C,CmdXX,Cmd3E,CmdXX
|
||
|
||
dc.l Cmd40,CmdXX,Cmd42,Cmd43,Cmd44,Cmd45,CmdXX,Cmd47
|
||
dc.l Cmd48,Cmd49,CmdXX,Cmd4B,Cmd4C,Cmd4D,Cmd4E,CmdXX
|
||
|
||
dc.l CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,Cmd55,Cmd56,Cmd57
|
||
dc.l CmdXX,CmdXX,Cmd5A,CmdXX,CmdXX,CmdXX,Cmd5E,Cmd5F
|
||
|
||
dc.l CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX
|
||
dc.l CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX
|
||
|
||
dc.l CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX
|
||
dc.l CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX
|
||
|
||
dc.l CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX
|
||
dc.l CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX
|
||
|
||
dc.l CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX
|
||
dc.l CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX,CmdXX
|
||
|
||
dc.l CmdA0,CmdXX,CmdXX,CmdXX,CmdXX,CmdA5,CmdXX,CmdXX
|
||
dc.l CmdA8,CmdA9,CmdXX,Cmd03,CmdXX,CmdXX,CmdXX,CmdAF
|
||
|
||
dc.l CmdB0,CmdB1,CmdB2,CmdB3,CmdXX,CmdXX,CmdXX,CmdXX
|
||
dc.l CmdXX,CmdB9,CmdBA,CmdBB,CmdBC,CmdBD,CmdBE,CmdXX
|
||
PVName
|
||
dc.b "powervisor.library",0
|
||
Digit
|
||
dc.b "0123456789ABCDEF"
|
||
FormatString1
|
||
dc.b 10,"---- SCSI-2 command : %s ----",10
|
||
dc.b "scsi_Data = $%08lx",10
|
||
dc.b "scsi_Length = %ld",10
|
||
dc.b "scsi_Command = %s",10
|
||
dc.b "scsi_CmdLength = %d",10
|
||
dc.b "scsi_Flags = $%02x",10
|
||
dc.b "scsi_SenseData = $%08lx",10
|
||
dc.b "scsi_SenseLength = %d",10,0
|
||
FormatString2
|
||
dc.b "---- After execution : ----",10
|
||
dc.b "scsi_Actual = %ld",10
|
||
dc.b "scsi_CmdActual = %d",10
|
||
dc.b "scsi_SenseActual = %d",10
|
||
dc.b "scsi_Status = $%02x",10
|
||
dc.b "---- scsi_Data content : ----",10,0
|
||
FormatString3
|
||
dc.b "---- Unit %d ----",10
|
||
dc.b "Old sense : $%02x",10
|
||
dc.b "New sense : $%02x",10
|
||
dc.b "Old change state : %d",10
|
||
dc.b "Old change number : %ld",10,0
|
||
FormatString4
|
||
dc.b "---- Unit %d ----",10
|
||
dc.b "New change state : %d",10
|
||
dc.b "New change number : %ld",10,0
|
||
OutputString
|
||
blk.b 352,0
|
||
CommandString
|
||
blk.b 64,0
|
||
CmdXX
|
||
dc.b "Unknown",0
|
||
Cmd00
|
||
dc.b "Test Unit Ready",0
|
||
Cmd01
|
||
dc.b "Rezero Unit",0
|
||
Cmd03
|
||
dc.b "Request Sense",0
|
||
Cmd08
|
||
dc.b "Read(6)",0
|
||
Cmd0B
|
||
dc.b "Seek(6)",0
|
||
Cmd12
|
||
dc.b "Inquiry",0
|
||
Cmd15
|
||
dc.b "Mode Select(6)",0
|
||
Cmd16
|
||
dc.b "Reserve(6)",0
|
||
Cmd17
|
||
dc.b "Release(6)",0
|
||
Cmd18
|
||
dc.b "Copy",0
|
||
Cmd1A
|
||
dc.b "Mode Sense(6)",0
|
||
Cmd1B
|
||
dc.b "Stop/Start Unit",0
|
||
Cmd1C
|
||
dc.b "Receive Diagnostic Results",0
|
||
Cmd1D
|
||
dc.b "Send Diagnostic",0
|
||
Cmd1E
|
||
dc.b "Prevent/Allow Medium Removal",0
|
||
Cmd25
|
||
dc.b "Read CD-Rom Capacity",0
|
||
Cmd28
|
||
dc.b "Read(10)",0
|
||
Cmd2B
|
||
dc.b "Seek(10)",0
|
||
Cmd2F
|
||
dc.b "Verify(10)",0
|
||
Cmd30
|
||
dc.b "Search Data High(10)",0
|
||
Cmd31
|
||
dc.b "Search Data Equal(10)",0
|
||
Cmd32
|
||
dc.b "Search Data Low(10)",0
|
||
Cmd33
|
||
dc.b "Set Limits(10)",0
|
||
Cmd34
|
||
dc.b "Pre-Fetch",0
|
||
Cmd35
|
||
dc.b "Synchronize Cache",0
|
||
Cmd36
|
||
dc.b "Lock/Unlock Cache",0
|
||
Cmd39
|
||
dc.b "Compare",0
|
||
Cmd3A
|
||
dc.b "Copy And Verify",0
|
||
Cmd3B
|
||
dc.b "Write Buffer",0
|
||
Cmd3C
|
||
dc.b "Read Buffer",0
|
||
Cmd3E
|
||
dc.b "Read Long",0
|
||
Cmd40
|
||
dc.b "Change Definition",0
|
||
Cmd42
|
||
dc.b "Read Sub-channel",0
|
||
Cmd43
|
||
dc.b "Read TOC",0
|
||
Cmd44
|
||
dc.b "Read Header",0
|
||
Cmd45
|
||
dc.b "Play Audio(10)",0
|
||
Cmd47
|
||
dc.b "Play Audio MSF",0
|
||
Cmd48
|
||
dc.b "Play Audio Track Index",0
|
||
Cmd49
|
||
dc.b "Play Track Relative(10)",0
|
||
Cmd4B
|
||
dc.b "Pause/Resume",0
|
||
Cmd4C
|
||
dc.b "Log Select",0
|
||
Cmd4D
|
||
dc.b "Log Sense",0
|
||
Cmd4E
|
||
dc.b "Stop Play/Scan",0
|
||
Cmd55
|
||
dc.b "Mode Select(10)",0
|
||
Cmd56
|
||
dc.b "Reserve(10)",0
|
||
Cmd57
|
||
dc.b "Release(10)",0
|
||
Cmd5A
|
||
dc.b "Mode Sense(10)",0
|
||
Cmd5E
|
||
dc.b "Prin",0
|
||
Cmd5F
|
||
dc.b "Prout",0
|
||
CmdA0
|
||
dc.b "Report LUNs",0
|
||
CmdA5
|
||
dc.b "Play Audio(12)",0
|
||
CmdA8
|
||
dc.b "Read(12)",0
|
||
CmdA9
|
||
dc.b "Play Track Relative(12)",0
|
||
CmdAF
|
||
dc.b "Verify(12)",0
|
||
CmdB0
|
||
dc.b "Search Data High(12)",0
|
||
CmdB1
|
||
dc.b "Search Data Equal(12)",0
|
||
CmdB2
|
||
dc.b "Search Data Low(12)",0
|
||
CmdB3
|
||
dc.b "Set Limits(12)",0
|
||
CmdB9
|
||
dc.b "Read CD MSF",0
|
||
CmdBA
|
||
dc.b "Audio Scan",0
|
||
CmdBB
|
||
dc.b "Set CD-Rom Speed",0
|
||
CmdBC
|
||
dc.b "Play CD",0
|
||
CmdBD
|
||
dc.b "CD Mechanism States",0
|
||
CmdBE
|
||
dc.b "Read CD",0
|
||
even
|
||
CmdPtr
|
||
dc.l 0
|
||
ENDIF
|
||
|
||
EndRomTag
|