changeset 2590:17d43fd29ee2

Integration of SuperDriver
author boisy
date Thu, 22 Dec 2011 18:23:47 +0000
parents e134044fd755
children f026e5eecfb0
files defs/ide.d defs/rbsuper.d defs/scsi.d level1/cmds/scsiquery.asm level1/coco/modules/makefile level1/modules/boot_ide.asm level1/modules/boot_scsi.asm level1/modules/llide.asm level1/modules/llscsi.asm level1/modules/rbdesc.asm level1/modules/rbsuper.asm level1/modules/superdesc.asm level2/coco3/modules/makefile
diffstat 13 files changed, 4331 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/defs/ide.d	Thu Dec 22 18:23:47 2011 +0000
@@ -0,0 +1,55 @@
+********************************************************************
+* ide.d - IDE definitions
+*
+* $Id$
+*
+* (C) 2004 Boisy G. Pitre - Licensed to Cloud-9
+*
+* Edt/Rev  YYYY/MM/DD  Modified by
+* Comment
+* ------------------------------------------------------------------
+*          2005/12/11  Boisy G. Pitre
+* Moved IDE base addresses and I/O offsets to here.
+
+*
+* ATAPI Commands
+*
+A$READ2        EQU       $A8
+A$WRITE2       EQU       $AA
+A$READ         EQU       $28
+A$WRITE        EQU       $2A
+A$STOP         EQU       $1B
+
+*
+* ATA Commands
+*
+S$READ         EQU       $20
+S$WRITE        EQU       $30
+
+*
+* IDE Registers
+*
+DataReg        EQU       0                   Data (1st 8 bits, non-latched)
+ErrorReg       EQU       1                   Error # when read
+Features       EQU       1                   Features when write
+SectCnt        EQU       2                   Sector count
+SectNum        EQU       3                   Sector #
+CylLow         EQU       4                   Low byte of cylinder
+CylHigh        EQU       5                   High byte of cylinder
+DevHead        EQU       6                   Device/Head
+Status         EQU       7                   Status when read
+Command        EQU       7                   Command when write
+Latch          EQU       8                   Latch (2nd 8 bits of 16 bit word)
+
+BusyBit        EQU       %10000000           BUSY=1 
+DrdyBit        EQU       %01000000           drive ready=1 
+DscBit         EQU       %00010000           seek finished=1 
+DrqBit         EQU       %00001000           data requested=1 
+ErrBit         EQU       %00000001           error_reg has it 
+RdyTrk         EQU       %01010000           ready & over track 
+RdyDrq         EQU       %01011000           ready w/ data 
+
+**** IDE Interface Definitions
+               IFNE      IDE
+SDAddr         SET       $FF50
+               ENDC      
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/defs/rbsuper.d	Thu Dec 22 18:23:47 2011 +0000
@@ -0,0 +1,79 @@
+********************************************************************
+* rbsuper.d - rbsuper definitions
+*
+* $Id$
+*
+* (C) 2004 Boisy G. Pitre - Licensed to Cloud-9
+*
+* These definitions make up the static storage environment for the
+* rbsuper driver.  Low level drivers share these variables with
+* rbsuper, and also have an area reserved exclusively for their use.
+*
+* Edt/Rev  YYYY/MM/DD  Modified by
+* Comment
+* ------------------------------------------------------------------
+*          2004/04/10  Boisy G. Pitre
+* Created.
+*
+*          2005/11/27  Boisy G. Pitre
+* Moved SCSI base addresses and I/O offsets to here.
+*
+*          2005/12/13  Boisy G. Pitre
+* Employed a "trick" whereby driver's U is pointed UOFFSET bytes
+* into the static storage for faster, smaller code generation.
+*
+*          2005/12/13  Boisy G. Pitre
+* Rearranged order of driver statics for smaller code size
+
+* Interface Address
+SDAddr         SET       $FF00
+SDMPI          SET       $FF
+
+*
+* IT.DNS Definitions for all Low Level Drivers
+*
+DNS.HDB        EQU       %00001000
+
+*
+* IT.DNS Definitions for Low Level SCSI Driver
+*
+DNS.TURBO      EQU       %00010000
+
+maxcache       SET       2048
+DrvCount       EQU       8
+llreserve      EQU       64
+
+UOFFSET        EQU       DRVBEG+(DRVMEM*DrvCount)
+
+               ORG       0
+V.LLSema       RMB       1                   low-level semaphore variable
+V.LastDrv      RMB       1                   last drive to access cache
+V.PhysSect     RMB       3                   physical (HW) sector
+V.LogSect      RMB       3                   logical (256 byte) sector
+V.SectSize     RMB       1                   sector size
+V.SectCnt      RMB       1                   number of hw sectors to read from interface
+V.Log2Phys     RMB       1                   number of logical (256) byte sectors to 1 physical sector
+V.CchAddr      RMB       2                   address of cache in system memory
+V.CchSize      RMB       2                   size of cache in bytes
+V.CchPSpot     RMB       2                   pointer to target physical sector in cache
+V.CchLSpot     RMB       2                   pointer to target logical sector in cache
+V.CchDirty     RMB       1                   cache dirty flag (0 = cache is stable, !0 = cache is dirty)
+V.CchBase      RMB       3                   logical sector at start of cache
+V.HDBDrive     RMB       1                   IT.STP (used as HDB-DOS drive number if HDB-DOS partition)
+V.HDBPart      RMB       1                   HDB-DOS partition flag (0 = not HDB-DOS partition, !0 = is)
+V.SSCache      RMB       DrvCount            sector size cache table for each drive
+V.LLAddr       RMB       2                   low level module address
+V.LLInit       RMB       2                   low level init entry point
+V.LLRead       RMB       2                   low level read entry point
+V.LLWrite      RMB       2                   low level write entry point
+V.LLGtSt       RMB       2                   low level getstat entry point
+V.LLStSt       RMB       2                   low level setstat entry point
+V.LLTerm       RMB       2                   low level term entry point
+* Low Level Driver Memory starts here
+V.LLMem        EQU       .                   start of low level driver memory
+               RMB       llreserve           reserved area... low level driver uses this as it wants
+V.LLMemSz      EQU       .-V.LLMem
+* Note: we trick rbsuper to so that it thinks its static storage starts at
+* zero when it really starts beyond DRVBEG+(DRVMEM*DrvCount).
+               RMB       UOFFSET
+V.RBSuper      EQU       .                   end of RBSuper's (and ll driver's) memory requirements
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/defs/scsi.d	Thu Dec 22 18:23:47 2011 +0000
@@ -0,0 +1,99 @@
+********************************************************************
+* scsi.d - SCSI definitions
+*
+* $Id$
+*
+* (C) 2004 Boisy G. Pitre - Licensed to Cloud-9
+*
+* Edt/Rev  YYYY/MM/DD  Modified by
+* Comment
+* ------------------------------------------------------------------
+*          2005/12/11  Boisy G. Pitre
+* Moved SCSI base addresses and I/O offsets to here.
+
+
+*
+* SCSI Packet Command Bytes
+*
+S$REZERO       EQU       $01
+S$REQSEN       EQU       $03
+S$FORMAT       EQU       $04
+S$READ         EQU       $08
+S$WRITE        EQU       $0A
+S$SEEK         EQU       $0B
+S$MODSEL       EQU       $15
+S$UNIT         EQU       $1B
+S$RCAP         EQU       $25
+S$READEX       EQU       $28
+S$WRITEX       EQU       $2A
+
+*
+* SCSI Status Codes
+*
+X$ERROR        EQU       $02
+X$BUSY         EQU       $08
+
+**** Cloud-9 TC^3 Controller Definitions
+               IFNE      TC3+SB
+SCSIDATA       EQU       0
+SCSISTAT       EQU       1
+SCSISEL        EQU       1
+SCSIRST        EQU       1                   INVALID, but not used
+
+REQ            EQU       $01
+BUSY           EQU       $02
+MSG            EQU       $04
+CMD            EQU       $08
+INOUT          EQU       $10
+
+               IFNE      SB
+SDAddr         SET       $FF1E
+               ELSE
+SDAddr         SET       $FF74
+               ENDC      
+
+               ENDC      
+
+**** Ken-Ton/LR-Tech Controller Definitions
+               IFNE      KTLR
+SCSIDATA       EQU       0
+SCSISTAT       EQU       1
+SCSISEL        EQU       2
+SCSIRST        EQU       3
+
+REQ            EQU       $01
+BUSY           EQU       $02
+MSG            EQU       $04
+CMD            EQU       $08
+INOUT          EQU       $10
+ACK            EQU       $20
+SEL            EQU       $40
+RST            EQU       $80
+
+SDAddr         SET       $FF74
+               ENDC      
+
+**** Disto 4-N-1/HD-II Controller Definitions
+               IFNE      D4N1+HDII
+SDMPI          SET       $02
+
+* Disto SCSI Controller Definitions
+SCSIDATA       EQU       0
+SCSISTAT       EQU       -2
+SCSISEL        EQU       -1
+SCSIRST        EQU       -2
+
+SEL            EQU       $00
+BUSY           EQU       $01
+ACK            EQU       $02
+MSG            EQU       $04
+INOUT          EQU       $20
+CMD            EQU       $40
+REQ            EQU       $80
+
+               IFNE      D4N1
+SDAddr         SET       $FF5B
+               ELSE      
+SDAddr         SET       $FF53
+               ENDC      
+               ENDC      
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/level1/cmds/scsiquery.asm	Thu Dec 22 18:23:47 2011 +0000
@@ -0,0 +1,269 @@
+********************************************************************
+* scsiquery - Get info on SCSI device through SS.DCmd call
+*
+* $Id$
+*
+* Edt/Rev  YYYY/MM/DD  Modified by
+* Comment
+* ------------------------------------------------------------------
+*   1      2008/01/21  Boisy G. Pitre
+* Created while on the FPSO Kikeh in the South China Sea.
+
+               nam       scsiquery
+               ttl       Get info on SCSI device through the SS.DCmd call
+
+               ifp1      
+               use       defsfile
+               use       scfdefs
+               endc      
+
+tylg           set       Prgrm+Objct
+atrv           set       ReEnt+rev
+rev            set       $00
+edition        set       1
+
+               mod       eom,name,tylg,atrv,start,size
+
+               org       0
+code           rmb       1
+lsn            rmb       3
+left           rmb       2
+path           rmb       1
+numbuf         rmb       16
+txbuff         rmb       2048                to accomodate CD-ROM sector sizes
+               rmb       200
+size           equ       .
+
+StartM         fcc       /SCSI Inquiry Utility/
+cr             fcb       C$CR
+VID            fcc       /Vendor ID  : /
+VIDL           equ       *-VID
+PID            fcc       /Product ID : /
+PIDL           equ       *-PID
+RLV            fcc       /Revision   : /
+RLVL           equ       *-RLV
+LBA            fcc       /Blocks     : /
+LBAL           equ       *-LBA
+BSZ            fcc       /Block Size : /
+BSZL           equ       *-BSZ
+
+InquiryUnit    fcb       $12,$00,$00,$00,96,$00
+ReadCapacity   fcb       $25,$00,$00,$00,$00,$00,$00,$00,$00,$00
+
+name           fcs       /scsiquery/
+               fcb       edition
+
+start                    
+               leay      txbuff,u
+               ldd       #$2060
+l@             sta       ,y+
+               decb      
+               bne       l@
+               leay      txbuff,u
+
+l@             lda       ,x+
+               cmpa      #C$CR
+               beq       ok@
+               cmpa      #C$SPAC
+               beq       ok@
+               sta       ,y+
+               bra       l@
+ok@            ldd       #'@*256+C$CR
+               std       ,y
+               leax      txbuff,u
+
+               lda       #READ.
+               os9       I$Open
+               lbcs      exit
+               sta       path,u
+
+               leax      StartM,pcr
+               lda       #1
+               ldy       #100
+               os9       I$WritLn
+
+* Do INQUIRY
+               leax      txbuff,u
+               leay      InquiryUnit,pcr
+               lda       path,u
+               ldb       #SS.DCmd
+               os9       I$SetStt
+               lbcs      exit
+
+* Show Vendor ID
+               leax      VID,pcr
+               ldy       #VIDL
+               lda       #1
+               os9       I$WritLn
+
+               leax      txbuff+8,u
+               ldy       #15-8+1
+               lda       #1
+               os9       I$Write
+               leax      cr,pcr
+               ldy       #1
+               os9       I$WritLn
+
+* Show Product ID
+               leax      PID,pcr
+               ldy       #PIDL
+               lda       #1
+               os9       I$WritLn
+
+               leax      txbuff+16,u
+               ldy       #31-16+1
+               lda       #1
+               os9       I$Write
+               leax      cr,pcr
+               ldy       #1
+               os9       I$WritLn
+
+* Show Revision Level
+               leax      RLV,pcr
+               ldy       #RLVL
+               lda       #1
+               os9       I$WritLn
+
+               leax      txbuff+32,u
+               ldy       #35-32+1
+               lda       #1
+               os9       I$Write
+               leax      cr,pcr
+               ldy       #1
+               os9       I$WritLn
+
+* Do READ CAPACITY
+               leax      txbuff,u
+               leay      ReadCapacity,pcr
+               lda       path,u
+               ldb       #SS.DCmd
+               os9       I$SetStt
+               bcs       exit
+
+* Show Number of Blocks
+               leax      LBA,pcr
+               ldy       #LBAL
+               lda       #1
+               os9       I$WritLn
+
+               leax      txbuff,u
+               leay      numbuf,u
+               bsr       itoa
+               lda       #1
+               os9       I$Write
+			   
+               leax      cr,pcr
+               ldy       #1
+               os9       I$WritLn
+
+* Show Block Size
+               leax      BSZ,pcr
+               ldy       #BSZL
+               lda       #1
+               os9       I$WritLn
+
+               leax      txbuff+4,u
+               leay      numbuf,u
+               bsr       itoa
+               lda       #1
+               os9       I$Write
+			   
+               leax      cr,pcr
+               ldy       #1
+               os9       I$WritLn
+
+exitok         clrb      
+exit           os9       F$Exit
+
+* Entry:
+* X = address of 32 bit value
+* Y = address of buffer to hold number
+* Exit:
+* X = address of buffer holding number
+* Y = length of number string in bytes
+itoa           pshs      u,y
+               tfr       y,u
+               ldb       #10                 max number of numbers (10^9)
+               pshs      b                   save count on stack
+               leay      Base,pcr            point to base of numbers
+s@             lda       #$30                put #'0
+               sta       ,u                  at U
+s1@            bsr       Sub32               ,X=,X-,Y
+               inc       ,u
+               bcc       s1@                 if X>0, continue
+               bsr       Add32               add back in
+               dec       ,u+
+               dec       ,s                  decrement counter
+               beq       done@
+               lda       ,s
+               cmpa      #$09
+               beq       comma@
+               cmpa      #$06
+               beq       comma@
+               cmpa      #$03
+               bne       s2@
+comma@         ldb       #',
+               stb       ,u+
+s2@            leay      4,y                 point to next
+               bra       s@
+done@          leas      1,s
+* 1,234,567,890
+               ldb       #14                 length of string with commas + 1
+               ldx       ,s++                get pointer to buffer
+a@             decb      
+               beq       ex@
+               lda       ,x+                 get byte
+               cmpa      #'0
+               beq       a@
+               cmpa      #',
+               beq       a@
+               clra      
+               tfr       d,y                 transfer count into Y
+v@             leax      -1,x
+               puls      u,pc
+ex@            ldy       #0001
+               bra       v@
+
+* Entry:
+* X = address of 32 bit minuend
+* Y = address of 32 bit subtrahend
+* Exit:
+* X = address of 32 bit difference
+Sub32          ldd       2,x
+               subd      2,y
+               std       2,x
+               ldd       ,x
+               sbcb      1,y
+               sbca      ,y
+               std       ,x
+               rts       
+
+
+* Entry:
+* X = address of 32 bit number
+* Y = address of 32 bit number
+* Exit:
+* X = address of 32 bit sum
+Add32          ldd       2,x
+               addd      2,y
+               std       2,x
+               ldd       ,x
+               adcb      1,y
+               adca      ,y
+               std       ,x
+               rts       
+
+Base           fcb       $3B,$9A,$CA,$00     1,000,000,000
+               fcb       $05,$F5,$E1,$00     100,000,000
+               fcb       $00,$98,$96,$80     10,000,000
+               fcb       $00,$0f,$42,$40     1,000,000
+               fcb       $00,$01,$86,$a0     100,000
+               fcb       $00,$00,$27,$10     10,000
+               fcb       $00,$00,$03,$e8     1,000
+               fcb       $00,$00,$00,$64     100
+               fcb       $00,$00,$00,$0a     10
+               fcb       $00,$00,$00,$01     1
+
+               emod      
+eom            equ       *
+               end       
--- a/level1/coco/modules/makefile	Tue Oct 04 15:11:45 2011 +0000
+++ b/level1/coco/modules/makefile	Thu Dec 22 18:23:47 2011 +0000
@@ -15,12 +15,15 @@
 CLOCKSOFT       = -aRTCSoft=1
 CLOCKMESSEMU    = -aRTCMessEmu=1
 CLOCKJVEMU      = -aRTCJVEmu=1
+TC3FLAGS        = $(AFLAGS) -aTC3=1 $(FLAGS)
+IDEFLAGS        = $(AFLAGS) -aIDE=1 $(FLAGS)
 
 DEPENDS		= ./makefile
 TPB		= $(3RDPARTY)/booters
 
 BOOTERS		= boot_1773_6ms boot_1773_30ms \
-		boot_burke boot_rampak boot_wd1002 boot_dw3 boot_dw3_coco1
+		boot_burke boot_rampak boot_wd1002 boot_dw3 boot_dw3_coco1 \
+		boot_tc3 boot_ide
 BOOTTRACK	= rel $(BOOTERS)
 KERNEL		= krn krnp2 wbug
 SYSMODS		= ioman init sysgo_dd sysgo_h0
@@ -35,7 +38,11 @@
 		ddd0_35s.dd d0_35s.dd d1_35s.dd d2_35s.dd d3_35s.dd \
 		ddd0_40d.dd d0_40d.dd d1_40d.dd d2_40d.dd \
 		ddd0_80d.dd d0_80d.dd d1_80d.dd d2_80d.dd \
-		ddx0.dd x0.dd x1.dd x2.dd x3.dd
+		ddx0.dd x0.dd x1.dd x2.dd x3.dd \
+		rbsuper.dr lltc3.dr llide.dr \
+		ddi0_ide.dd i0_ide.dd i1_ide.dd ih_ide.dd \
+		dds0_tc3.dd s0_tc3.dd s1_tc3.dd s2_tc3.dd s3_tc3.dd s4_tc3.dd \
+                s5_tc3.dd s6_tc3.dd sh_tc3.dd
 
 SCF		= scf.mn \
 		sc6551.dr vrn.dr scbbp.dr scbbt.dr scdwp.dr sspak.dr vtio.dr \
@@ -58,7 +65,19 @@
 
 all:	$(ALLOBJS)
 
+# Kernel
+krn krnp2:
+	$(CD) kernel; make $@
+	$(CP) kernel/$@ .
+
 # Special cases
+# TC^3 SCSI Booter
+boot_tc3: boot_scsi.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS)
+
+# SuperIDE/Glenside IDE Booter
+boot_ide: boot_ide.asm
+	$(AS) $(ASOUT)$@ $< $(IDEFLAGS)
 
 # DriveWire 3
 boot_dw3_coco1: boot_dw3.asm
@@ -67,11 +86,6 @@
 dw3_coco1.sb: dw3.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aBAUD38400=1
 
-# Kernel
-krn krnp2:
-	$(CD) kernel; make $@
-	$(CP) kernel/$@ .
-
 boot_1773_6ms:	boot_1773.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aDNum=0 -aSTEP=0
 
@@ -84,18 +98,13 @@
 rb1773_scii_ff58.dr:	rb1773.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aSCII=1 -aSCIIALT=1
 
-# Clocks
-clock_60hz: clock.asm
-	$(AS) $(AFLAGS) $(ASOUT)$@ $< -aPwrLnFrq=60
+# TC^3 SCSI Driver
+lltc3.dr: llscsi.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS)
 
-clock_50hz: clock.asm
-	$(AS) $(AFLAGS) $(ASOUT)$@ $< -aPwrLnFrq=50
-
-clock2_bnb: clock2_ds1315.asm
-	$(AS) $(AFLAGS) $(ASOUT)$@ $< -aBNB=1
-
-clock2_cloud9: clock2_ds1315.asm
-	$(AS) $(AFLAGS) $(ASOUT)$@ $< -aCLOUD9=1
+# IDE Driver
+llide.dr: llide.asm
+	$(AS) $(ASOUT)$@ $< $(IDEFLAGS)
 
 # Floppy descriptors
 SSDD35		= -aCyls=35 -aSides=1 -aSectTrk=18 -aSectTrk0=18 \
@@ -209,6 +218,47 @@
 x3.dd: dwdesc.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aDNum=3
 
+# TC^3 SCSI Descriptors
+dds0_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(ID0) -aDD=1
+
+s0_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(ID0) $(SCSI_HD)
+
+s1_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(ID1) $(SCSI_HD)
+
+s2_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(ID2) $(SCSI_HD)
+
+s3_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(ID3) $(SCSI_HD)
+
+s4_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(ID4) $(SCSI_HD)
+
+s5_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(ID5) $(SCSI_HD)
+
+s6_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(ID6) $(SCSI_HD)
+
+sh_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(HDBDOS)
+
+# IDE Descriptors
+ddi0_ide.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(IDEFLAGS) $(MASTER) -aDD=1
+
+i0_ide.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(IDEFLAGS) $(MASTER)
+
+i1_ide.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(IDEFLAGS) $(SLAVE)
+
+ih_ide.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(IDEFLAGS) $(HDBDOS)
+
 # RFM descriptors
 ddy0.dd: rfmdesc.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aDD=1 -aDNum=0
@@ -234,6 +284,19 @@
 sysgo_h0: sysgo.asm
 	$(AS) $(AFLAGS) $(ASOUT)$@ $<
 
+# Clocks
+clock_60hz: clock.asm
+	$(AS) $(AFLAGS) $(ASOUT)$@ $< -aPwrLnFrq=60
+
+clock_50hz: clock.asm
+	$(AS) $(AFLAGS) $(ASOUT)$@ $< -aPwrLnFrq=50
+
+clock2_bnb: clock2_ds1315.asm
+	$(AS) $(AFLAGS) $(ASOUT)$@ $< -aBNB=1
+
+clock2_cloud9: clock2_ds1315.asm
+	$(AS) $(AFLAGS) $(ASOUT)$@ $< -aCLOUD9=1
+
 clean:
 	$(CD) kernel; make $@
 	$(RM) $(ALLOBJS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/level1/modules/boot_ide.asm	Thu Dec 22 18:23:47 2011 +0000
@@ -0,0 +1,248 @@
+********************************************************************
+* Boot - IDE Boot Module
+*
+* $Id$
+*
+* Edt/Rev  YYYY/MM/DD  Modified by
+* Comment
+* ------------------------------------------------------------------
+*   ?      1994/06/25  Alan DeKok
+* Diassembled.
+*
+*   6      1999/08/17  Paul T. Barton
+* Redone for IDE.
+*
+*   7      2002/06/27  Boisy G. Pitre
+* Added use of LSN bits 23-16.
+*
+*   7r1    2004/05/12  Boisy G. Pitre
+* Optimized, made toG wait on !BUSY and DRDY, added slowdown POKE
+* for Fujitsu 128MB CF (may be temporary)
+*
+*   8      2004/07/29  Boisy G. Pitre
+* Now detects CHS/LBA mode to work with ALL IDE drives.
+*
+*   9      2005/10/13  Boisy G. Pitre
+* Support for fragmented bootfiles added.
+
+               NAM       Boot                
+               TTL       IDE Boot Module     
+
+               IFP1      
+               USE       defsfile
+               USE       ide.d
+               ENDC      
+
+tylg           SET       Systm+Objct
+atrv           SET       ReEnt+rev
+rev            SET       $00
+edition        SET       9
+
+* Disassembled 94/06/25 11:37:47 by Alan DeKok 
+* ReDone by Paul T. Barton 99/08/17, for IDE 
+
+               MOD       eom,name,tylg,atrv,start,size
+
+* on-stack static storage
+               ORG       0
+cyls           RMB       2
+sides          RMB       1
+sects          RMB       2
+mode           RMB       1
+seglist        RMB       2                   pointer to segment list
+blockloc       RMB       2                   pointer to memory requested
+blockimg       RMB       2                   duplicate of the above
+bootloc        RMB       3                   sector pointer; not byte pointer
+bootsize       RMB       2                   size in bytes
+LSN0Ptr        RMB       2                   LSN0 pointer (used by boot_common.asm)
+size           EQU       .
+
+name           FCS       /Boot/
+               FCB       edition
+
+* Common booter-required defines
+LSN24BIT       EQU       1
+FLOPPY         EQU       0
+
+               USE       boot_common.asm
+
+* HWInit - Initialize the device
+*   Entry: Y = hardware address
+*   Exit:  Carry Clear = OK, Set = Error
+*          B = error (Carry Set)
+HWInit         ldb       Address+2,pcr
+               bne       slave@
+               lda       #%10100000
+               FCB       $8C
+slave@         lda       #%10110000
+               sta       mode,u
+               stb       DevHead,y           select device
+a@             tst       Status,y            wait for BSY to clear
+               bmi       a@
+               lda       #$EC
+               sta       Command,y
+b@             tst       Status,y
+               bmi       b@
+* Harvest C/H/S values.
+               ldb       DataReg,y           ignore bytes 0-1
+               ldb       DataReg,y           bytes 2-3 = no. of cylinders
+               lda       Latch,y
+               std       cyls,u              save cylinders in our private static area
+               ldb       DataReg,y           ignore bytes 4-5
+               ldb       DataReg,y           bytes 6-7 = no. of heads
+               stb       sides,u             save sides on stack (B)
+               ldb       DataReg,y           ignore bytes 8-9
+               ldb       DataReg,y           ignore bytes 10-11
+               ldb       DataReg,y           bytes 12-13 = no. of sectors/track
+               lda       Latch,y
+               std       sects,u             save sectors/track on stack (Y)
+* Throw away the next 42 (48-7) words
+               ldb       #43
+l@             tst       DataReg,y
+               lda       Latch,y
+               decb      
+               bne       l@
+* A holds byte with LBA bit
+               anda      #%00000010          LBA drive?
+               beq       nope@
+               ldb       mode,u
+               orb       #%01000000
+               stb       mode,u
+nope@          ldb       #256-50
+o@             tst       DataReg,y
+               decb      
+               bne       o@
+HWTerm         clrb      
+               rts       
+
+* HWRead - Read a 256 byte sector from the device
+*   Entry: Y = hardware address
+*          B = bits 23-16 of LSN
+*          X = bits 15-0  of LSN
+*	   blockloc,u = ptr to 256 byte sector
+*   Exit:  X = ptr to data (i.e. ptr in blockloc,u)
+HWRead                   
+               pshs      x,b
+b@             tst       Status,y
+               bmi       b@                  if =1 then loop 
+               lda       mode,u
+               sta       DevHead,y           0L0d/0hhh device=CHS 
+r@             ldb       Status,y            is IDE ready for commands? 
+               andb      #BusyBit+DrdyBit    ready ? 
+               cmpb      #DrdyBit
+               bne       r@                  loop until Drdy=1 and Busy=0
+               ldb       #$01                only one at a time 
+               stb       SectCnt,y           only one at a time 
+               anda      #%01000000
+               beq       chs@                branch if mode
+               lda       ,s                  get bits 23-16
+               sta       CylHigh,y
+               ldd       1,s                 get bits 15-0
+               stb       SectNum,y
+               sta       CylLow,y
+               bra       DoCmd
+chs@                     
+* Compute proper C:H:S value
+               lda       sides,u             get device's head
+               ldb       sects+1,u           and sector
+               mul                           multiply H*S
+* Note, there is a chance here that if the product is zero, we could loop forever
+*         beq   ZeroProd
+               pshs      d                   save product of H*S
+               ldd       1+2,s               get bits 15-0 of LSN
+               ldx       #-1                 start Y at -1
+               inc       0+2,s               increment physical sector
+* Here we are doing physLSN/(H*S) to get cylinder for physLSN
+a@             leax      1,x                 increment count to compensate
+               subd      ,s                  subtract (H*S) from physLSN
+               bhs       a@                  if D>=0 then continue
+               dec       0+2,s               decrement phys sector bits 23-16
+               bne       a@                  if not zero, continue divide
+               addd      ,s++                add in (H*S) to make non-negative
+               pshs      d                   X now holds cylinder, save D on stack
+               tfr       x,d
+               exg       a,b                 swap
+               std       CylLow,y            store computed cylinder in HW
+               puls      d                   restore saved cylinder
+* Now we will compute the sector/head value
+               ldx       #-1
+c@             leax      1,x
+               subb      sects+1,u
+               sbca      #0
+               bcc       c@
+               addb      sects+1,u
+               incb                          add 1 to B, which is sector
+               stb       SectNum,y           store computed sector in HW
+               tfr       x,d
+               orb       DevHead,y           OR in with value written earlier
+               stb       DevHead,y
+DoCmd          lda       #S$READ             read one sector 
+               sta       Command,y           finish process 
+
+Blk2           lda       Status,y            is IDE ready to send? 
+               anda      #DrqBit             DRQ, data request 
+               beq       Blk2                loop while DRQ =0 
+
+               ldx       blockloc,u
+               clr       ,s
+BlkLp                    
+               lda       DataReg,y           A <- IDE 
+               ldb       Latch,y
+               std       ,x++                into RAM 
+               inc       ,s
+               bpl       BlkLp               go get the rest 
+b@             lda       DataReg,y           read remaining 256 bytes
+               dec       ,s
+               bne       b@
+
+               leax      -256,x
+               stx       1,s
+               lda       Status,y            check for error-bit 
+               clrb      
+               puls      b,x,pc
+
+
+
+* ------------------------------------------ 
+
+*Init           
+*         pshs  d,y
+*         ldy   <Address,pcr
+*         bsr   ChkBusy    could be spinning up... 
+*         lda   #Diagnos   hits all drives 
+*         sta   Command,y   ./ 
+*         bsr   ChkBusy    wait 'til both done 
+*         clrb             no errors 
+*         puls  d,y,pc
+
+* Entry: A = number to show
+* Destroys D
+*Num
+* tfr a,b
+* lsra
+* lsra
+* lsra
+* lsra
+* bsr  x@
+* andb  #$0F
+* tfr b,a
+*x@
+* adda  #'0
+* cmpa  #'9
+* ble   s@
+* adda  #$7
+*s@ jsr   <D.BtBug
+* rts
+
+               IFGT      Level-1
+Pad            FILL      $39,$1D0-3-2-1-*
+               ENDC      
+
+Address        FDB       SDAddr
+WhchDriv       FCB       0                   Drive to use (0 = master, 1 = slave)
+
+
+               EMOD      
+eom            EQU       *
+               END       
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/level1/modules/boot_scsi.asm	Thu Dec 22 18:23:47 2011 +0000
@@ -0,0 +1,284 @@
+********************************************************************
+* Boot - SCSI Boot Module
+*
+* $Id$
+*
+* This module allows booting from a hard drive that uses HDB-DOS
+* and is controlled by a TC^3, Ken-Ton or Disto SCSI controller.
+*
+* It was later modified to handle hard drives with sector sizes
+* larger than 256 bytes, and works on both 256 byte and larger drives,
+* so it should totally replace the old SCSI boot module.
+*
+* Instructions followed by +++ in the comment field were added for this fix.
+*
+* Edt/Rev  YYYY/MM/DD  Modified by
+* Comment
+* ------------------------------------------------------------------
+*   1      ????/??/??  Roger Krupski
+* Original Roger Krupski distribution version
+*
+*   1r1    1996/??/??  Boisy G. Pitre
+* Added code to allow booting from any sector size hard drive
+*
+*   1r2    2002/05/01  Boisy G. Pitre
+* Merged Ken-Ton and TC^3 module source
+*
+*   1r3    2002/07/22  Boisy G. Pitre
+* Outputs '.' for each sector read when booting under NitrOS-9
+*
+*   2      2004/07/30  Boisy G. Pitre
+* SCSI ID 0-7 now modifiable at end of module as well as base address
+*
+*   3      2005/10/09  Boisy G. Pitre
+* Fixed stupid mistake where SCSIDATA was set to base address.  Now
+* baseaddr is the base address set at the end of the module and SCSIDATA
+* is 0 for the data offset.
+* Also SCSI-3 compatible SCSI IDs (with hi-bit set) are now sent to bus which
+* causes the booter to work with IBM-DPES31080 and other newer hard drives.
+* Fragmented bootfiles are now supported.
+*
+*   4      2008/02/17  Boisy G. Pitre
+* Message phase code was broken, now fixed and the booter now works.
+
+               NAM       Boot                
+               TTL       SCSI Boot Module    
+
+               IFP1      
+               USE       defsfile
+               USE       rbsuper.d
+               USE       scsi.d
+               ENDC      
+
+tylg           SET       Systm+Objct
+atrv           SET       ReEnt+rev
+rev            SET       0
+edition        SET       4
+
+               MOD       eom,name,tylg,atrv,start,size
+
+SCSIEX         EQU       1
+
+* Data equates; subroutines must keep data in stack
+               IFNE      SCSIEX
+v$cmd          RMB       1
+v$extra        RMB       1
+v$addr0        RMB       1
+v$addr1        RMB       1
+v$addr2        RMB       1
+v$addr3        RMB       1
+v$resv         RMB       1
+v$blks0        RMB       1
+v$blks1        RMB       1
+v$ctrl         RMB       1
+               ELSE
+v$cmd          RMB       1
+v$addr0        RMB       1
+v$addr1        RMB       2
+v$blks         RMB       1
+v$opts         RMB       1
+			   ENDC
+seglist        RMB       2                   pointer to segment list
+blockloc       RMB       2                   pointer to memory requested
+blockimg       RMB       2                   duplicate of the above
+bootloc        RMB       3                   sector pointer; not byte pointer
+bootsize       RMB       2                   size in bytes
+LSN0Ptr        RMB       2                   LSN0 pointer (used by boot_common.asm)
+size           EQU       .
+
+name           FCS       /Boot/
+               FCB       edition
+
+* Common booter-required defines
+LSN24BIT       EQU       1
+FLOPPY         EQU       0
+
+
+               USE       boot_common.asm
+
+************************************************************
+************************************************************
+*              Hardware-Specific Booter Area               *
+************************************************************
+************************************************************                         
+
+* HWInit - Initialize the device
+*   Entry: Y = hardware address
+*   Exit:  Carry Clear = OK, Set = Error
+*          B = error (Carry Set)
+HWInit                   
+               clr       >$FF40              stop the disk motors
+               IFNE      D4N1+HDII
+               leax      CntlSlot,pcr
+               lda       ,x
+               sta       MPI.Slct
+               ENDC      
+               ldd       #S$SEEK*256
+               ldx       #0
+               bsr       setup
+               IFEQ      SCSIEX
+			   clr       v$blks,u
+			   ENDC
+               bra       command
+			
+* Sets up the SCSI packet to send
+* Destroys B
+setup          sta       v$cmd,u
+               IFNE      SCSIEX
+			   clr       v$extra,u
+               clr       v$addr0,u
+               stb       v$addr1,u
+               stx       v$addr2,u
+               clr       v$resv,u
+               clr       v$blks0,u
+               ldb       #1
+               stb       v$blks1,u
+               clr       v$ctrl,u
+               ELSE
+               stb       v$addr0,u
+               stx       v$addr1,u
+               ldb       #1
+               stb       v$blks,u
+               clr       v$opts,u
+			   ENDC
+               rts
+
+scsival        FCB       $80+1,$80+2,$80+4,$80+8,$80+16,$80+32,$80+64,$80
+
+* SCSI Wake-Up Routine
+* Destroys: X
+wakeup         ldx       #0                  load X with 0 (counter)
+* Step 1: Wait for BUSY+SEL to be clear
+wake           lda       SCSISTAT,y          obtain SCSI status byte
+               bita      #BUSY               BUSY clear?
+               beq       wake1               branch if so
+               leax      -1,x                else count down
+               bne       wake                and try again if not timed out
+               bra       wake4               else branch to timeout
+* Step 2: Put our SCSI ID on the bus
+wake1          bsr       wake3               small delay
+               lda       WhichDrv,pcr        get SCSI ID
+               leax      <scsival,pcr        point to SCSI value table
+               lda       a,x                 get appropriate bitmask
+               sta       SCSIDATA,y          put on SCSI bus
+               bsr       wake3               small delay
+               sta       SCSISEL,y           and select
+               ldx       #0                  load X with 0 (counter)
+wake2          lda       SCSISTAT,y          obtain SCSI status byte
+               bita      #BUSY               BUSY set?
+               bne       wake3               if so, exit without error
+               leax      -1,x                else count down
+               bne       wake2               and try again if not timed out
+wake4          comb                          set carry
+               ldb       #E$NotRdy           and load error
+wake3          rts                           then return
+
+
+* HWRead - Read a 256 byte sector from the device
+*   Entry: Y = hardware address
+*          B = bits 23-16 of LSN
+*          X = bits 15-0  of LSN
+*          blockloc,u = ptr to 256 byte sector
+*   Exit:  X = ptr to data (i.e. ptr in blockloc,u)
+HWRead         lda       #S$READEX
+               bsr       setup
+* SCSI Send Command Routine
+command        bsr       wakeup              tell SCSI we want the bus
+               bcs       wake3              return immediately if error
+               leax      v$cmd,u
+               bsr       SCSISend
+               bcs       command
+               bsr       Wait4REQ
+               bita      #CMD
+               bne       getsta
+               ldx       blockloc,u
+               bsr       read
+getsta         bsr       Wait4REQ
+               lda       SCSIDATA,y
+               anda      #%00001111
+               pshs      a
+               bsr       Wait4REQ
+               clra      
+               sta       SCSIDATA,y
+               puls      a
+               bita      #X$BUSY
+               bne       command
+               bita      #X$ERROR
+               beq       HWTerm
+reterr         comb      
+               ldb       #E$Unit
+               rts       
+
+* HWTerm - Terminate the device
+*   Entry: Y = hardware address
+*   Exit:  Carry Clear = OK, Set = Error
+*          B = error (Carry Set)
+HWTerm         clrb      
+               rts       
+
+SCSISend       bsr       Wait4REQ
+               bita      #CMD
+               beq       HWTerm
+               bita      #INOUT
+               bne       ckmsg
+               lda       ,x+
+               sta       SCSIDATA,y
+               bra       SCSISend
+ckmsg          bita      #MSG                MESSAGE IN (target->initiator)
+			   beq       HWTerm
+               lda       SCSIDATA,y          extended message?
+               deca      
+*
+* MESSAGE IN phase code
+*
+               bne       SCSISend
+               ldb       SCSIDATA,y          get extended message length
+l@             tst       SCSIDATA,y          read extended message
+               decb      
+               bne       l@
+               bra       reterr              return with carry set
+			   
+Wait4REQ
+loop@          lda       SCSISTAT,y
+               bita      #REQ
+               beq       loop@
+               rts
+
+* Patch to allow booting from sector sizes > 256 bytes - BGP 08/16/97
+* We ignore any bytes beyond byte 256, but continue to read them from
+* the SCSIDATA until the CMD bit is set.
+read                     
+* next 2 lines added
+               clrb                          +++ use B as counter
+read2                    
+               bsr       Wait4REQ
+               bita      #CMD
+               bne       HWTerm
+               lda       SCSIDATA,y
+               sta       ,x+
+* next line commented out and next 8 lines added
+* bra read
+               incb                          +++
+               bne       read2               +++
+               leax      -256,x
+read3                    
+               bsr       Wait4REQ            +++
+               bita      #CMD                +++
+               bne       HWTerm              +++
+               lda       SCSIDATA,y          +++
+               bra       read3               +++
+
+
+               IFGT      Level-1
+* Fillers to get to $1D0
+Pad            FILL      $39,$1D0-3-1-2-1-*
+               ENDC      
+
+* The default SCSI ID is here
+CntlSlot       FCB       SDMPI
+Address        FDB       SDAddr
+WhichDrv       FCB       0
+
+               EMOD      
+eom            EQU       *
+               END       
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/level1/modules/llide.asm	Thu Dec 22 18:23:47 2011 +0000
@@ -0,0 +1,1098 @@
+*******************************************************************
+* llide - Low-level IDE driver
+*
+* $Id$
+*
+* This low level driver works with both ATA and ATAPI devices.
+*
+* The type of device (ATA or ATAPI) is automatically detected
+* by the 'IOSetup' routine.  Additionally, an ATA device is
+* further detected as either an LBA or CHS device.
+*
+* Since only two physical drives are allowed (master/slave),
+* there is a two entry "per drive static storage" that indicates
+* if a drive has been initialized, its type (ATAPI or ATA, LBA or
+* CHS), and if ATA, its geometry.
+*
+* Edt/Rev  YYYY/MM/DD  Modified by
+* Comment
+* ------------------------------------------------------------------
+*     1    2004/04/08  Boisy G. Pitre
+* Created.
+*
+*     2    2005/07/23  Christopher R. Hawks
+* Fixes for persnickity ATAPI CDROMs.
+*
+*     3    2005/08/21  Christopher R. Hawks
+* More fixes.
+*
+*     4    2005/12/13  Boisy G. Pitre
+* Moved SS.VarSect code into RBSuper for performance
+
+               NAM       llide               
+               TTL       Low-level IDE driver
+
+               IFP1      
+               USE       defsfile
+               USE       rbsuper.d
+               USE       ide.d
+               ENDC      
+
+tylg           SET       Sbrtn+Objct
+atrv           SET       ReEnt+rev
+rev            SET       4
+
+
+RW12           SET       0                   Use READ12/WRITE12 ATAPI commands (1 = yes)
+WAITTIME       SET       10                  BUSY wait time (in approximate seconds)
+
+*
+* Status Register Flip/Mask Values
+*
+NBUSYDRDY      EQU       (BusyBit|DrdyBit)*256+(DrdyBit)
+NBUSY          EQU       (BusyBit)*256+$00
+NBUSYDRQ       EQU       (BusyBit|DrqBit)*256+(DrqBit)
+NBUSYNDRQ      EQU       (BusyBit|DrqBit)*256+$00
+
+               MOD       eom,name,tylg,atrv,start,0
+
+               IFNE      RW12
+READCODE       EQU       A$READ2
+WRITCODE       EQU       A$WRITE2
+               ELSE      
+READCODE       EQU       A$READ
+WRITCODE       EQU       A$WRITE
+               ENDC      
+
+NumRetries     EQU       8
+
+* Low-level driver static memory area
+               ORG       V.LLMem
+* Master static storage
+V.Master       RMB       1                   status byte (ATAPI or ATA (CHS or LBA))
+               RMB       2                   Cylinders (CHS) or Bits 31-16 of LBA
+               RMB       1                   Sides (CHS) or Bits 15-8 of LBA
+               RMB       2                   Sectors (CHS) or Bits 7-0 of LBA
+* Slave drive static storage
+V.Slave        RMB       1
+               RMB       2
+               RMB       1
+               RMB       2
+* ATAPI Command Packet
+V.ATAPICmd     RMB       18
+V.SnsData      EQU       V.ATAPICmd          Sense Data is shared with ATAPI command block
+* The following values are for device 0 and 1 respectively:
+* Bit 0 = device inited (0 = false, 1 = true)
+* Bit 1 = device type (0 = ATA, 1 = ATAPI)
+* Bit 2 = device mode (0 = CHS, 1 = LBA)
+V.CurStat      RMB       1
+V.Retries      RMB       1
+V.WhichDv      RMB       1                   contains devhead selection (made by IOSetup)
+V.PhySct       RMB       3                   local copy of physical sector passed (V.PhySct)
+V.SctCnt       RMB       1                   local copy of physical sector passed (V.SectCnt)
+V.Sectors      RMB       1                   number of sectors (harvested directly from drive query)
+V.CurDTbl      RMB       2
+V.ATAVct       RMB       2
+
+
+name           FCS       /llide/
+
+start          bra       ll_init
+               nop       
+               lbra      ll_read
+               lbra      ll_write
+               lbra      ll_getstat
+               lbra      ll_setstat
+
+* ll_init - Low level init routine
+*
+* Entry:
+*    Y  = address of device descriptor
+*    U  = address of low level device memory area
+*
+* Exit:
+*    CC = carry set on error
+*    B  = error code
+*
+* Note: This routine is called ONCE: for the first device
+* IT IS NOT CALLED PER DEVICE!
+*
+ll_init                  
+*         clrb
+*         rts             
+
+
+* ll_term - Low level term routine
+*
+* Entry:
+*    Y  = address of device descriptor
+*    U  = address of device memory area
+*
+* Exit:
+*    CC = carry set on error
+*    B  = error code
+*
+* Note: This routine is called ONCE: for the last device
+* IT IS NOT CALLED PER DEVICE!
+*
+ll_term                  
+               clrb      
+               rts       
+
+
+* Entry:   Y = address of per-drive static storage
+ATADSize                 
+               pshs      y,x,b               make room for space on stack (and save id byte)
+* Determine if we are dealing with LBA or CHS
+               bitb      #$04                LBA?
+               bne       lba@
+* Here we pull CHS values
+chs@                     
+               ldd       1,y                 get cylinders
+               std       1,s
+               lda       3,y                 get sides
+               sta       ,s                  save sides on stack (B)
+               ldd       4,y                 get sectors
+               std       3,s                 save sectors/track on stack (Y)
+               bra       m@
+* Here we pull LBA values at words 60-61
+lba@                     
+               clr       ,s                  clear flag indicating LBA mdoe (B)
+               ldd       3,y                 get bits 15-0
+               std       3,s                 save bits 15-0 on stack (Y)
+               ldd       1,y                 get bits 31-16
+               std       1,s                 save bits 31-16 (X)
+m@             lda       #$02                512 bytes/sector
+ex@            puls      b,x,y,pc
+
+
+* SSDSize - Get a disk medium's size
+*
+* GetStat Call SS.DSize:
+*
+* Entry: B = SS.DSize
+* Exit:  Carry = 1; error with code in B
+*        Carry = 0:
+*          IF B = 0
+*            A = Sector Size (1 = 256, 2 = 512, 4 = 1024, 8 = 2048)
+*            X = Number of Sectors (bits 31-16)
+*            Y = Number of Sectors (Bits 15-0)
+*          IF B != 0
+*            A = Sector Size (1 = 256, 2 = 512, 4 = 1024, 8 = 2048)
+*            X = Number of Logical Cylinders
+*            B = Number of Logical Sides
+*            Y = Number of Logical Sectors/Track
+*  
+SSDSize        pshs      u,y
+               bsr       DSize
+               bcs       ex@
+               ldu       ,s                  get path desc in U
+               ldu       PD.RGS,u
+               std       R$D,u
+               stx       R$X,u
+               sty       R$Y,u
+               clrb      
+ex@            puls      y,u,pc
+
+DSize          lbsr      IOSetup
+               bcs       ex@
+* Determine if this device is ATAPI or ATA
+               bitb      #$02                ATAPI?
+               lbeq      ATADSize            no, it's ATA
+* Note - for ATAPI version of SS.DSize, we use the obsolete
+* READ CAPACITY call because it works on CD-ROMs, as opposed to
+* READ FORMAT CAPACITIES.
+ATAPIDSize               
+               lbsr      ATAPIPreSend        prepare packet
+* Populate packet buffer with STOP code and Eject
+*         ldd   #$230C		ATAPI READ FORMAT CAPACITIES Code
+               lda       #$25                ATAPI READ CAPACITY Code
+               sta       V.ATAPICmd,u        write it
+*         stb   V.ATAPICmd+8,u	and allocation length
+* Send to data port
+               bsr       ATAPISend           send command
+               bcs       ex@
+* Read 8 bytes of format capacity data
+*         ldb   #6
+               ldb       #4
+               pshs      b
+               leay      V.SnsData,u
+read@          lda       DataReg,x
+               ldb       Latch,x
+               std       ,y++
+               dec       ,s
+               bne       read@
+               puls      b
+               ldx       V.SnsData+0,u
+               ldy       V.SnsData+2,u
+               leay      1,y
+               bcc       b@
+               leax      1,x
+b@             lda       V.SnsData+6,u
+               clrb      
+ex@            rts       
+
+*         ldy   PD.RGS,y
+*         ldd   V.SnsData+0,u	get bits 31-16
+*         std   R$X,y
+*         ldd   V.SnsData+2,u	get bits 15-0
+*         addd  #$0001		add 1
+*         std   R$Y,y
+*         bcc   b@
+*         ldd   R$X,y
+*         addd  #$0001
+*         std   R$X,y
+*b@       lda   V.SnsData+6,u	get bits 15-8 of block size
+*         sta   R$A,y
+*         clr   R$B,y		signal that this is LBA mode
+*         clrb
+*ex@      rts        
+
+
+* ll_getstat - Low level GetStat routine
+*
+* Entry:
+*    Y  = address of path descriptor
+*    U  = address of device memory area
+*
+* Exit:
+*    CC = carry set on error
+*    B  = error code
+*
+ll_getstat               
+               ldx       PD.RGS,y
+               lda       R$B,x
+               cmpa      #SS.DSize
+               beq       SSDSize
+               ldb       #E$UnkSvc
+               coma      
+ex1            rts       
+
+
+* StopUnit - Park a drive
+*
+* ATA   Devices: This is a No-Op.
+* ATAPI Devices: A STOP UNIT command is issued to the device.
+*                (ejects media on ATAPI removable devices)
+StopUnit       lbsr      IOSetup
+               bcs       ex1
+* Determine if this device is ATAPI or ATA
+               bitb      #$02                ATAPI?
+               beq       ex1                 no, ignore...
+               lbsr      ATAPIPreSend        prepare packet
+* Populate packet buffer with STOP code and Eject
+ok@            ldd       #A$STOP*256+$02     ATAPI STOP Code and Eject byte
+               sta       V.ATAPICmd,u        write it and RSV to zero
+               stb       V.ATAPICmd+4,u
+* Send to data port
+               bra       ATAPISend           send command
+
+
+* ll_setstat - Low level SetStat routine
+*
+* Entry:
+*    Y  = address of path descriptor
+*    U  = address of device memory area
+*
+* Exit:
+*    CC = carry set on error
+*    B  = error code
+*
+ll_setstat               
+               ldx       PD.RGS,y
+               lda       R$B,x
+               cmpa      #SS.SQD
+               beq       StopUnit
+               IFNE      0
+               cmpa      #SS.DCmd
+               bne       n@
+               pshs      x                  save pointer to caller registers
+               bsr       DCmd               call DCmd
+               puls      x                  get pointer to caller registers
+               sta       R$A,x              save status byte in A
+               ENDC
+n@             clrb      
+ssex           rts       
+
+
+               IFNE    0
+BadType        comb
+               ldb     #E$BTyp
+               rts
+
+* Entry:
+*    X   = caller regs
+*    Y   = path descriptor
+*
+*    R$B = SS.DCmd
+*    R$X = Transfer buffer
+*    R$Y = ATAPI command packet
+DCmd                     
+               pshs      y
+               os9       F$ID                get the user ID of the calling process
+               cmpy      #$0000              is it 0 (superuser)?
+               puls      y
+               bne       noperms             no, don't allow the call
+               lbsr      IOSetup
+** SS.DCmd only works with ATAPI devices.
+               bitb      #$02                ATAPI?
+               beq       BadType             branch if not
+               ldy       R$X,x               get caller's transfer buffer
+               sty       V.UTxBuf,u          save off in mem for later
+               ldx       R$Y,x               get ptr to caller's command buffer
+               IFGT      Level-1
+               ldy       D.Proc              get current process ptr
+               lda       P$Task,y            get task # for current process
+               ldb       D.SysTsk            get system task #
+               ldy       #ATAPIPkLn          max size of ATAPI command
+               pshs      u                   save on stack
+               leau      V.ATAPICmd,u        point to ATAPI command buffer in our statics
+               os9       F$Move              copy from caller to temporary task
+               puls      u
+               bcs       ex                  error copying, exit
+               ELSE      
+               ldb       #ATAPIPkLn
+               leay      V.ATAPICmd,u
+cl@            lda       ,x+
+               sta       ,y+
+               decb      
+               bne       cl@
+               ENDC      
+               ldy       V.PORT-UOFFSET,u    get hw address (because we overwrite Y earlier)
+*               inc       V.OS9Err,u          we want real errors returned
+               inc       V.CchDirty,u        and make cache dirty
+*               leax      retry@,pcr
+*               stx       V.RetryVct,u
+retry@         lbsr      ATAPISend
+               bcs       ex
+               IFGT      Level-1
+               ldx       D.Proc              get current process ptr
+               ldb       P$Task,x            get task # for current process
+               ENDC      
+               ldx       V.UTxBuf,u
+
+msgloop@       lbsr      Wait4REQ            wait for REQ to be asserted
+               bita      #CMD                command phase?
+               lbne      PostXfr             yes, return
+io@            bita      #INOUT              data coming in or going out?
+               bne       in@                 branch if coming in...
+               IFGT      Level-1
+               os9       F$LDABX
+               leax      1,x
+               ELSE      
+               lda       ,x+
+               ENDC      
+               sta       SCSIDATA,y
+               bra       msgloop@
+in@            lda       SCSIDATA,y
+               IFGT      Level-1
+               os9       F$STABX
+               leax      1,x
+               ELSE      
+               sta       ,x+
+               ENDC      
+               bra       msgloop@
+               ENDC
+
+* ATAPISend - Sends the command packet to the device
+*
+* Entry:   X = HW address
+*          V.WhichDv = DevHead device selection value
+* Exit:    Carry = 1; error code in B
+*          Carry = 0; command successfully sent
+ATAPISend                
+* First, select the device and wait for /BUSY
+               lda       V.WhichDv,u
+               sta       DevHead,x           select device
+* ATAPI says we wait for !BUSY
+               ldd       #NBUSYDRDY          wait for NBUSY and DEVREADY too - CRH
+               lbsr      StatusWait          wait for proper condition
+               bcs       timeout             branch if error
+               lda       #NumRetries         get retry count
+               sta       V.Retries,u         and save
+retry@                   
+               clr       Features,x          clear feature byte
+               clr       SectCnt,x           clear TAG field
+               ldd       #$FFFF              maximum read in PIO mode
+               std       CylLow,x
+               lda       #$A0                ATAPI PACKET CODE
+               sta       Command,x           write it to device
+* Check for error
+               ldd       #NBUSYDRQ           /BUSY and DRQ
+               lbsr      StatusWait          wait for proper condition
+               bcs       ex@                 branch if error
+* Send to data port
+               lda       #6                  packet size / 2
+               pshs      a,y
+               leay      V.ATAPICmd,u
+l@             ldd       ,y++
+               stb       Latch,x
+               sta       DataReg,x
+               dec       ,s
+               bne       l@
+               puls      a,y
+* Added by CRH - Some drives require that we wait for much more than
+* 400ns.  Hence this code forces a slow-down and checks the status
+* to see if things are ok.
+               clrb      
+slow@          decb                          CRH wait for much more than 400ns
+               bne       slow@
+               lda       Status,x            CRH Sometimes error on first try
+               lsra      
+               bcc       ok@
+               dec       V.Retries,u
+               bne       retry@
+* As per ATA/ATAPI-6 spec (T13/1410D Revision 3A), page 161, we wait for /BUSY
+* and DRQ after sending a command
+* That IS NOT the case when sending START/STOP unit commands, so we don't check
+* for DRQ.
+ok@            ldd       #NBUSY              /BUSY
+               lbsr      StatusWait          wait for proper condition
+               bcs       ex@                 branch if error
+               lda       #A$STOP             CRH see above
+               cmpa      V.ATAPICmd,u
+               beq       nodata@
+               ldd       #NBUSYDRQ           /BUSY and DRQ
+               lbsr      StatusWait          wait for proper condition
+               bcs       ex@                 branch if error
+nodata@        lsra                          shift in CHECK CONDITION bit
+               bcc       ex@                 branch if ok
+* Note: if the device returns error, DRQ won't be set...
+err@           lbsr      HandleSenseKey      go check sense key
+               bcs       ex@
+ret@           dec       V.Retries,u         else retry until terminal
+               bne       retry@              continue retrying
+timeout        comb                          set carry
+               ldb       #E$DevBsy+4         SHOULD BE AN E$TimeOut ERROR!
+ex@            rts       
+
+* Prepare the ATAPI Packet
+ATAPIPreSend             
+               pshs      x
+* Clear 12 byte packet.
+               leax      V.ATAPICmd,u
+               ldb       #12
+c@             clr       ,x+
+               decb      
+               bne       c@
+ex@            puls      x,pc
+
+
+** ATAPI REQUEST SENSE Command
+** Should only be called for ATAPI devices
+*ReqSense 
+*         bsr    ATAPIPreSend	prepare packet
+** Populate packet buffer with REQUEST SENSE
+*         ldd   #$0312		ATAPI REQUEST SENSE Code and allocation length byte
+*         sta   V.ATAPICmd,u
+*         stb   V.ATAPICmd+4,u
+** Send to data port
+*         lbsr  ATAPISend	send command
+*         lda   Status,x		get status code
+*         lsra			shift in CHECK CONDITION bit
+*         bcs   ex@		branch if ok
+** Read 18 bytes of sense data
+*         ldb   #$12
+*         pshs  y,b
+*         leay  V.SnsData,u
+*read@    lda   DataReg,x 
+*         ldb   Latch,x   
+*         std   ,y++      
+*         dec   ,s        
+*         bne   read@     
+*         puls  b,y,pc
+*ex@      rts
+
+
+* IOSetup - Sets up the device for I/O
+*
+* The device is selected (master or slave), then the device is
+* checked for previous initialization.
+*
+* If the device has not been initialized, it is queried for its
+* mode (ATAPI/ATA, LBA or CHS) and size.  That information is
+* saved in the driver's static storage for later use by other
+* routines.
+*
+* Entry:  Y = path descriptor pointer
+*         U = static memory pointer
+* Exit:   B = status byte for device
+*         X = HW address
+*         Y = pointer to current device table
+IOSetup        ldx       V.PORT-UOFFSET,u    get hw address
+               lda       PD.DNS,y            get device ID bit
+               lsra                          shift device ID into carry
+               bcs       slave@
+               lda       #%10100000          master byte
+               leay      V.Master,u
+               bra       t@
+slave@         lda       #%10110000          slave byte
+               leay      V.Slave,u           else point to slave status byte
+t@             sty       V.CurDTbl,u
+               sta       V.WhichDv,u         save for later
+* Select the device -- on power-up, the status register is usually 0
+               sta       DevHead,x           select device
+* According to page 320 of the ATA/ATAPI-6 document, we must wait for BOTH
+* BUSY and DRQ to be clear before proceeding. (HI2: Device_Select State)
+               ldd       #NBUSYNDRQ          /BUSY and /DRQ
+               lbsr      StatusWait          wait for proper condition
+               lbcs      ex@                 branch if error
+* Determine if this device has already been initialized
+               tst       ,y                  test device's stat byte
+               lbne      initdone            if not zero, init already done
+* Here we must initialize the device by IDENTIFYING it.
+* First, try sending the ATA IDENTIFY DRIVE code
+               lda       #$EC                ATA identify command
+               sta       Command,x           write it
+               ldd       #NBUSY              /BUSY
+               lbsr      StatusWait          wait for proper condition
+               lbcs      ex@                 branch if error
+* Check if there's an error
+               lsra                          shift error bit into carry
+               bcc       ATAIdent            if no error, then probably ATA
+* If here, we got an error sending $EC, so try ATAPI's $A1
+               lda       #$A1
+               sta       Command,x
+               clrb      
+slow@          decb                          CRH wait for much more than 400ns
+               bne       slow@
+               ldd       #NBUSY
+               lbsr      StatusWait          wait for proper condition
+               bcs       ex@                 branch if error
+               lsra                          shift error bit into carry
+               bcs       timeout             if not error, we're ok
+               ldd       #NBUSYDRQ
+               lbsr      StatusWait          wait for proper condition
+               lbcs      ex@                 branch if error
+* Here, we have identified an ATAPI device.
+ATAPIIdent               
+               ldb       #$03                ATAPI
+               stb       ,y
+* We flush the ATAPI data but don't reference it
+dread@         ldb       DataReg,x           CRH flush ALL bytes
+*         ldb   Latch,x 	but save time by not reading latch
+               lda       Status,x
+               anda      #8
+               bne       dread@
+               bra       initdone
+* ATAIdent - process an ATA device
+* This routine is called by IOSetup when it deduces that the device
+* being queried is an ATA device.  This device is called ONCE -- the
+* first time the device is accessed.
+* This routine will set up our per-drive static storage to indicate that
+* it is an ATA device.  It will also determine if it is an LBA or CHS mode
+* device, and save the appropriate CHS or LBA sector values.
+ATAIdent                 
+               ldd       #NBUSYDRDY          /BUSY and DRDY
+               lbsr      StatusWait          wait for proper condition
+               bcs       ex@                 branch if error
+* Harvest C/H/S and LBA sector values.
+               ldb       DataReg,x           ignore bytes 0-1
+               ldb       DataReg,x           bytes 2-3 = no. of cylinders
+               lda       Latch,x
+               std       1,y                 save cylinders in our private static area
+               ldb       DataReg,x           ignore bytes 4-5
+               ldb       DataReg,x           bytes 6-7 = no. of heads
+               lda       Latch,x
+               stb       3,y                 save sides on stack (B)
+               ldb       DataReg,x           ignore bytes 8-9
+               ldb       DataReg,x           ignore bytes 10-11
+               ldb       DataReg,x           bytes 12-13 = no. of sectors/track
+               lda       Latch,x
+               std       4,y                 save sectors/track on stack (Y)
+* Throw away the next 42 (7-48) words
+               ldb       #43
+l@             tst       DataReg,x
+               lda       Latch,x
+               decb      
+               bne       l@
+* A holds byte with LBA bit
+               incb                          B was 0, now 1
+               anda      #%00000010          LBA allowed on this drive?
+               beq       nope@
+               orb       #$04                set LBA mode
+               stb       ,y                  save updated status byte
+* Since we're LBA mode, get the number of LBA sectors in words 60-61
+               ldb       #10                 skip to the LBA sectors (words 60-61)
+more@          tst       DataReg,x           simply read the data register like this...
+               decb      
+               bne       more@
+               ldb       DataReg,x           get word 60
+               lda       Latch,x
+               std       3,y
+               ldb       DataReg,x           and 61
+               lda       Latch,x
+               std       1,y
+               lda       #256-61             how many words we have left
+               bra       left@               go on.
+nope@          stb       ,y                  save updated status byte
+* Read remaining 256-50 words
+               lda       #256-50
+left@          ldb       DataReg,x
+               deca      
+               bne       left@
+initdone       ldb       ,y                  get status byte of drive
+               clra                          clear carry
+ex@            rts       
+
+
+* ATAPI Write Routine -- Independent of ATA Read
+ATAPIWrite               
+               lbsr      ATAPIPreSend        prepare packet
+* Populate packet buffer with WRITE code and sector information
+again@         ldb       V.PhySct,u          get bits 23-16 of sector
+               stb       V.ATAPICmd+3,u
+               ldd       V.PhySct+1,u        get bits 15-0 of sector
+               std       V.ATAPICmd+4,u
+               ldd       #WRITCODE*256+$01   ATAPI WRITE Code and transfer length
+               sta       V.ATAPICmd,u        write it
+               IFNE      RW12
+               stb       V.ATAPICmd+9,u      write to byte 9
+               ELSE      
+               stb       V.ATAPICmd+8,u      write to byte 8
+               ENDC      
+* Send to data port
+               lbsr      ATAPISend           send command
+               bcs       ex@
+* Shift data from device
+o@             pshs      d
+               lda       V.Log2Phys,u
+               sta       1,s                 set up our logical sector counter
+inc@           clr       ,s                  set up our byte counter
+wr@            ldd       ,y++
+               stb       Latch,x
+               sta       DataReg,x
+               inc       ,s
+               bpl       wr@
+               dec       1,s
+               bne       inc@
+               puls      d
+* Increment physical sector
+               inc       V.PhySct+2,u
+               bcc       go@
+               inc       V.PhySct+1,u
+               bcc       go@
+               inc       V.PhySct,u
+go@            dec       V.SctCnt,u          decrement # of hw sectors to read
+               bne       again@              if not zero, do it again
+               ldd       #NBUSY              /BUSY
+               lbsr      StatusWait          wait for proper condition
+               bcs       ex@                 branch if error
+               lsra                          error bit set?
+               bcc       ex@                 yep...
+               bsr       HandleSenseKey
+ex@            puls      x,pc
+
+
+
+* ATAPI Read Routine -- Independent of ATA Read
+ATAPIRead                
+               ldy       V.CchPSpot,u        get pointer to spot in cache to put sector
+               lbsr      ATAPIPreSend        do command packet setup stuff
+* Populate packet buffer with READ code and sector information
+again@         ldb       V.PhySct,u          get,u bits 23-16 of sector
+               stb       V.ATAPICmd+3,u
+               ldd       V.PhySct+1,u        get bits 15-0 of sector
+               std       V.ATAPICmd+4,u
+               ldd       #READCODE*256+$01   ATAPI Read Code and transfer length
+               sta       V.ATAPICmd,u        write it and RSV to zero
+               IFNE      RW12
+               stb       V.ATAPICmd+9,u      write to byte 9
+               ELSE      
+               stb       V.ATAPICmd+8,u      write to byte 8
+               ENDC      
+* Send to data port
+               lbsr      ATAPISend           send command
+               bcs       ex@
+* Shift data from device
+o@             pshs      d
+               lda       V.Log2Phys,u
+               sta       1,s                 set up our logical sector counter
+inc@           clr       ,s                  set up our byte counter
+read@          lda       DataReg,x
+               ldb       Latch,x
+               std       ,y++
+               inc       ,s
+               bpl       read@
+               dec       1,s
+               bne       inc@
+               puls      d
+* Increment physical sector
+               inc       V.PhySct+2,u
+               bcc       go@
+               inc       V.PhySct+1,u
+               bcc       go@
+               inc       V.PhySct,u
+go@            dec       V.SctCnt,u          decrement # of hw sectors to read
+               bne       again@              if not zero, do it again
+               ldd       #NBUSY              /BUSY
+               lbsr      StatusWait          wait for proper condition
+               bcs       ex@                 branch if error
+               lsra                          error bit set?
+               bcc       ex@                 nope...
+               bsr       HandleSenseKey
+ex@            puls      x,pc
+
+
+* Handle ATAPI Sense Key
+* If the resulting error in the look-up table is zero,
+* we return with carry clear
+* Returns: B =  0 (carry clear, no error)
+*          B != 1 (carry set, error)
+HandleSenseKey           
+               pshs      x,a
+               ldb       ErrorReg,x          get error register value
+               lsrb                          shift sense key into place
+               lsrb      
+               lsrb      
+               lsrb      
+               leax      SenseMap,pcr        point to Sense Key Map
+               clra                          clear carry
+               ldb       b,x                 get appropriate error
+               beq       ok@                 if error is zero, return ok
+               coma                          set carry
+ok@            puls      a,x,pc
+
+* ll_read - Low level read routine
+*
+* Entry:
+*    Registers:
+*      Y  = address of path descriptor
+*      U  = address of device memory area
+*    Static Variables of interest:
+*      V.PhySct = starting physical sector to read from
+*      V.SectCnt  = number of physical sectors to read
+*      V.SectSize = physical sector size (0=256,1=512,2=1024,3=2048)
+*      V.CchPSpot = address where physical sector(s) will go
+*
+* Exit:
+*    All registers may be modified
+*    Static variables may NOT be modified
+ll_read                  
+               pshs      x                   make some space on the stack
+               lbsr      IOSetup             initialize the device
+               lbcs      ex@
+* Copy V.PhySct and V.SectCnt to our local copy
+* since we cannot modify them.
+               lda       V.PhysSect,u
+               ldy       V.PhysSect+1,u
+               sta       V.PhySct,u
+               sty       V.PhySct+1,u
+               lda       V.SectCnt,u
+               sta       V.SctCnt,u
+               bitb      #$02                ATAPI device?
+               lbne      ATAPIRead           yes, go do it
+* ATA Read Routine
+ATARead                  
+* stb   V.CurStat,u	save status of current drive
+               bitb      #$04                LBA drive?
+               bne       lba@                branch if so
+               leay      DoCHS,pcr           else point Y to CHS routine
+               bra       skip@
+lba@           leay      DoLBA,pcr
+skip@          sty       V.ATAVct,u          save pointer
+               ldy       V.CchPSpot,u        get pointer to spot in cache to put sector
+loop@                    
+               ldd       #NBUSY              /BUSY
+               bsr       StatusWait          wait for proper condition
+               bcs       ex@                 branch if error
+               jsr       [V.ATAVct,u]        do proper ATA preparation
+               bcs       ex@                 branch if error
+cont@          lda       #$01
+               sta       SectCnt,x           store it
+               lda       #S$READ
+               sta       Command,x
+               ldd       #NBUSY              /BUSY
+               bsr       StatusWait          wait for proper condition
+               bcs       ex@                 branch if error
+               lsra                          error bit set?
+               bcc       w@                  branch if not
+               lbsr      ATAError
+               bra       ex@
+w@             ldd       #NBUSYDRQ           /BUSY and DRQ
+               bsr       StatusWait          wait for proper condition
+               bcs       ex@                 branch if error
+               lda       V.Log2Phys,u
+               sta       1,s                 set up our logical sector counter
+inc@           clr       ,s                  set up our byte counter
+read@          lda       DataReg,x
+               ldb       Latch,x
+               std       ,y++
+               inc       ,s
+               bpl       read@
+               dec       1,s
+               bne       inc@
+* Increment physical sector
+               inc       V.PhySct+2,u
+               bcc       go@
+               inc       V.PhySct+1,u
+               bcc       go@
+               inc       V.PhySct,u
+go@            dec       V.SctCnt,u          decrement # of hw sectors to read
+               bne       loop@               if not zero, do it again
+               clrb      
+ex@            puls      x,pc
+
+
+*
+* Convert LSN to LBA values
+*
+* Entry:  V.PhySct = bits 23-0 of LSN
+*         X      = ptr to hardware
+*
+* Exit:   CHS values placed directly in HW
+*
+DoLBA          lda       V.WhichDv,u         get devhead value populated by IOSetup (CHS mode)
+               ora       #%01000000          OR in LBA bit
+               sta       DevHead,x
+               ldd       #NBUSYNDRQ          /BUSY and /DRQ
+               bsr       StatusWait
+               bcs       ex@
+               ldb       V.PhySct,u          get bits 23-16 of sector
+               stb       CylHigh,x           store it
+               ldd       V.PhySct+1,u        get bits 15-0 of sector
+               stb       SectNum,x           store it
+               sta       CylLow,x
+ex@            rts       
+
+
+* Wait for a set of conditions in the status register to be TRUE
+* This yields a delay of about 4 seconds.
+*
+* Entry: X = HW address
+*        A = flip (if bit set, that bit is tested)
+*        B = mask (result must match this byte)
+* Exit:  A = status
+StatusWait               
+               pshs      y,b,a
+               IFEQ      Level-1
+               ldb       #WAITTIME/2
+               ldy       #$0000
+               ELSE      
+               ldb       #WAITTIME
+               ldy       #$0000
+               ENDC      
+l@             lda       Status,x
+               anda      ,s                  apply flip
+               cmpa      1,s                 compare to mask
+               bne       dec@                branch if not equal (not what we want)
+               clrb                          clear carry
+               bra       ok@
+dec@           leay      -1,y                count down
+               bne       l@
+               decb                          decrement bits 23-16
+               bpl       l@                  if >=0, keep going
+err@           comb                          set carry
+               ldb       #E$DevBsy
+ok@            leas      2,s
+               lda       Status,x            get status again
+               puls      y,pc
+
+* Wait for 1 tick (1/60 second)
+*Delay1Tk
+*         pshs  x
+*         IFGT  Level-1
+*         ldx   D.Proc		get proc descriptor
+*         cmpx  D.SysPrc	system?
+*         beq   hw@		yep, system cannot sleep
+*         ENDC
+*         ldx   D.AProcQ	get active proc queue
+*         beq   hw@		if empty, do hard wait
+*         ldx   #1
+*         os9   F$Sleep		give up worst case: 1 tick (1/60 second)
+*         puls  x,pc		return to caller
+** In case we can't sleep... do a hard 1/60 second delay
+*hw@ 
+*         IFEQ  Level-1
+*         ldx   #$E52E/2		(5) (4)
+*         ELSE
+*         ldx   #$E52E		(5) (4)
+*         ENDC
+*w@       leax  -1,x		(4+) (4+)
+*         bne   w@		(3) (3)
+*         puls  x,pc		return to caller
+*
+
+
+* ll_write - Low level write routine
+*
+* Entry:
+*    Registers:
+*      Y  = address of path descriptor
+*      U  = address of device memory area
+*    Static Variables of interest:
+*      V.PhySct = starting physical sector to write to
+*      V.SectCnt  = number of physical sectors to write
+*      V.SectSize = physical sector size (0=256,1=512,2=1024,3=2048)
+*      V.CchPSpot = address of data to write to device
+*
+* Exit:
+*    All registers may be modified
+*    Static variables may NOT be modified
+ll_write                 
+               pshs      x                   make some space on the stack
+               lbsr      IOSetup             initialize the device
+               lbcs      ex@
+* Copy V.PhySct to our local copy
+               lda       V.PhysSect,u
+               ldy       V.PhysSect+1,u
+               sta       V.PhySct,u
+               sty       V.PhySct+1,u
+               lda       V.SectCnt,u
+               sta       V.SctCnt,u
+*
+               ldy       V.CchPSpot,u        get pointer to spot in cache where physical sector is
+               bitb      #$02                ATAPI device?
+               lbne      ATAPIWrite          yes, go do it
+* ATA Write Routine
+ATAWrite       stb       V.CurStat,u         save status of current drive
+loop@                    
+               ldd       #NBUSY              /BUSY
+               bsr       StatusWait          wait for proper condition
+               bcs       ex@                 branch if ok
+* Check for LBA mode
+               ldb       V.CurStat,u         get status of current drive
+               bitb      #$04                LBA bit set?
+               bne       lba@                branch if so
+* Here, we use CHS
+               bsr       DoCHS
+               bcs       ex@
+               bra       cont@
+lba@           lbsr      DoLBA
+cont@          lda       #$01
+               sta       SectCnt,x           store it
+               lda       #S$WRITE
+               sta       Command,x
+               ldd       #NBUSY              /BUSY
+               bsr       StatusWait          wait for proper condition
+               bcs       ex@                 branch if ok
+               lsra                          error bit set?
+               bcc       g@                  branch if not
+               lbsr      ATAError
+               bra       ex@
+g@             ldd       #NBUSYDRQ           /BUSY and DRQ
+               lbsr      StatusWait          wait for proper condition
+               bcs       ex@                 branch if ok
+again@         lda       V.Log2Phys,u
+               sta       1,s                 set up our sector counter
+inc@           clr       ,s                  set up our byte counter
+wr@            ldd       ,y++
+               stb       Latch,x
+               sta       DataReg,x
+               inc       ,s
+               bpl       wr@
+               dec       1,s
+               bne       inc@
+* Increment physical sector
+               inc       V.PhySct+2,u
+               bcc       go@
+               inc       V.PhySct+1,u
+               bcc       go@
+               inc       V.PhySct,u
+go@                      
+               dec       V.SctCnt,u          decrement # of hw sectors to read
+               bne       loop@               if not zero, do it again
+               clrb      
+ex@            puls      x,pc
+
+*
+* Convert LSN to C/H/S values and write to IDE hardware
+*
+* Entry:  V.PhySct = bits 23-0 of LSN
+*         X      = ptr to hardware
+*
+* Exit:   CHS values placed directly in HW
+*
+DoCHS                    
+* Select device
+               lda       V.WhichDv,u         get devhead value made by IOSetup (already CHS)
+               sta       DevHead,x
+               ldd       #NBUSYNDRQ          /BUSY and /DRQ
+               lbsr      StatusWait          wait for proper condition
+               bcc       start@              branch if ok
+               rts       
+* Start computation
+start@         pshs      y                   save original Y
+               ldy       V.CurDTbl,u
+               lda       3,y                 get device's head
+               ldb       5,y                 and sector
+               stb       V.Sectors,u
+               mul                           multiply H*S
+               beq       ZeroProd            if zero, error out
+               pshs      d                   save product of H*S
+               ldd       V.PhySct+1,u        get bits 15-0 of LSN
+               ldy       #-1                 start Y at -1
+               inc       V.PhySct,u          increment physical sector
+* Here we are doing physLSN/(H*S) to get cylinder for physLSN
+a@             leay      1,y                 increment count to compensate
+               subd      ,s                  subtract (H*S) from physLSN
+               bhs       a@                  if D>=0 then continue
+               dec       V.PhySct,u          decrement phys sector bits 23-16
+               bne       a@                  if not zero, continue divide
+               addd      ,s++                add in (H*S) to make non-negative
+               pshs      d                   D now holds cylinder, save on stack 
+               tfr       y,d                 Y now holds cylinder value
+               exg       a,b                 swap
+               std       CylLow,x            store computed cylinder in HW
+               puls      d                   restore saved cylinder
+* Now we will compute the sector/head value
+               ldy       #-1
+b@             leay      1,y
+               subb      V.Sectors,u
+               sbca      #0
+               bcc       b@
+               addb      V.Sectors,u
+               incb                          add 1 to B, which is sector
+               stb       SectNum,x           store computed sector in HW
+               tfr       y,d
+               orb       DevHead,x           OR in with value written earlier
+               stb       DevHead,x
+               clrb      
+               puls      y,pc
+ZeroProd       ldb       #E$Sect
+               coma      
+               puls      y,pc
+
+* ATAError - Checks the ATA error register and maps
+*            to a NitrOS-9 error message.
+*
+* Called if the error bit in the status register is set.
+ATAError                 
+               lda       ErrorReg,x
+               ldb       #7
+l@             lsra      
+               bcs       LookUp
+               decb      
+               bne       l@
+LookUp         leax      Errs,pcr
+x@             ldb       b,x
+               coma      
+               rts       
+
+* This is the ATAPI Sense Key -> NitrOS-9 Error Table
+* The Sense Key Table is on page 50 of the ATAPI Removable
+* Rewritable Specification, Revision 1.3 Proposed.
+* If an error number is zero, then no error is returned.
+SenseMap       FCB       0                   sense key 0 (NO SENSE)
+               FCB       0                   sense key 1 (RECOVERED ERROR)
+               FCB       E$NotRdy            sense key 2 (NOT READY)
+               FCB       E$Sect              sense key 3 (MEDIUM ERROR)
+               FCB       E$Unit              sense key 4 (HARDWARE ERROR)
+               FCB       E$IllArg            sense key 5 (ILLEGAL REQUEST)
+               FCB       0                   sense key 6 (UNIT ATTENTION)
+               FCB       E$WP                sense key 7 (DATA PROTECT)
+               FCB       0                   sense key 8 (BLANK CHECK)
+               FCB       0                   sense key 9 (VENDOR SPECIFIC)
+               FCB       0                   sense key A (RESERVED)
+               FCB       1                   sense key B (ABORTED COMMAND)
+               FCB       0                   sense key C (RESERVED)
+               FCB       0                   sense key D (VOLUME OVERFLOW)
+               FCB       0                   sense key E (MISCOMPARE)
+               FCB       0                   sense key F (RESERVED)
+
+* ERROR REG Bit   0      1     2       3       4        5      6     7
+Errs           FCB       E$Unit,E$CRC,E$UnkSvc,E$Sect,E$UnkSvc,E$DIDC,E$Seek,E$Sect
+
+               EMOD      
+eom            EQU       *
+               END       
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/level1/modules/llscsi.asm	Thu Dec 22 18:23:47 2011 +0000
@@ -0,0 +1,970 @@
+********************************************************************
+* llscsi - Low-level SCSI driver
+*
+* $Id$
+*
+* Drives tested with this driver:
+* -------------------------------
+* Conner DCP30200 Hard Drive - Sends out a SDTR message immediately,
+*   which confused the driver.  The driver now handles the receipt
+*   of SCSI messages from the target.
+*
+* IBM DPES-31080 Hard Drive - Works, but seizes the bus if a
+*   device ID is referenced on the bus that doesn't exist.
+*
+* Sony CDU415 2X CD-ROM - Works fine.
+*
+* Toshiba XM-4101BME 12X CD-ROM - Works fine.
+*
+* NOTE: A full dsave from the Sony to the IBM was done on 300+ MB
+* of data (RTSI RBF CD-ROM) on June 7, 2004 with no problems.
+*
+*
+* Edt/Rev  YYYY/MM/DD  Modified by
+* Comment
+* ------------------------------------------------------------------
+*          2004/04/??  Boisy G. Pitre
+* Created.
+*
+*          2004/??/??  Boisy G. Pitre
+* RELEASED WITH SUPERDRIVERS 1.0
+*
+*          2005/12/02  Boisy G. Pitre
+* Now detects MESSAGE IN phase and reads in message codes (ignoring
+* the data).  The Conner DCP30200 Hard Drive sends out a SDTR message
+* immediately, which confused the driver.  The driver now handles the
+* receipt of messages from the target.
+*
+*          2005/12/11  Boisy G. Pitre
+* Added SS.SQD and SS.DCmd support.
+*
+*          2005/12/13  Boisy G. Pitre
+* Moved SS.VarSect code into RBSuper for performance.
+*
+*          2006/03/22  Boisy G. Pitre
+* Moved SS.VarSect code into RBSuper for performance.
+*
+*          2008/01/21  Boisy G. Pitre
+* Fixed issue in DCmd where Y was not being saved when os9 F$ID was being called.
+
+               NAM       llscsi              
+               TTL       Low-level SCSI driver
+
+               IFP1      
+               USE       defsfile
+               USE       rbsuper.d
+               USE       scsi.d
+               ENDC      
+
+tylg           SET       Sbrtn+Objct
+atrv           SET       ReEnt+rev
+rev            SET       0
+
+
+*
+* SCSI Delay Constants
+*
+               IFGT      Level-1
+BUSYDELAY      EQU       $FFFF
+               ELSE      
+BUSYDELAY      EQU       $FFFF/2
+               ENDC      
+NUMTRIES       EQU       8
+
+               MOD       eom,name,tylg,atrv,start,0
+
+               ORG       V.LLMem
+* Low-level driver static memory area
+* SCSI Command Packet
+* SCSI packet length is 14 bytes
+V.SCSICMD      RMB       1
+V.SCSILUN      RMB       1
+V.SCSIPrm0     RMB       1
+V.SCSIPrm1     RMB       1
+V.SCSIPrm2     RMB       1
+V.SCSIPrm3     RMB       1
+V.SCSIPrm4     RMB       1
+V.SCSIPrm5     RMB       1
+V.SCSIPrm6     RMB       1
+V.SCSIPrm7     RMB       1
+               RMB       4
+SCSIPkLn       EQU       .-V.SCSICMD
+V.Retries      RMB       1                   SCSI command retry counter   
+V.OS9Err       RMB       1                   (0 = return OS-9 error code, 1 = return SCSI error code)
+V.Turbo        RMB       1                   turbo flag (0 = regular read, 1 = turbo read)
+V.TfrBuf       RMB       2                   transfer buffer pointer
+V.RetryVct     RMB       2                   retry vector
+V.ReadVct      RMB       2                   normal/turbo read vectoor
+V.WriteVct     RMB       2                   normal/turbo write vector
+V.DnsByte      RMB       1                   copy of PD.DNS from last accessed drive
+               IFNE      D4N1+HDII
+V.MPISlot      RMB       1                   MPI slot
+V.MPISave      RMB       1                   contents of original MPI slot
+               ENDC      
+* The Request Sense Packet and Read Capacity return data share the same space
+ReqSnPkt       EQU       .
+V.TxBuf        EQU       .                   used by DSize
+V.R$Err        RMB       2                   SCSI error code return value
+V.UTxBuf       EQU       .
+V.R$Err2       RMB       10
+V.R$AdSns      RMB       1
+ReqPkL         EQU       .-ReqSnPkt          length of packet
+               RMB       3                   makes V.TxBuf 16 bytes
+
+name           FCC       /ll/
+               IFNE      TC3
+               FCS       /tc3/
+               ELSE      
+               IFNE      KTLR
+               FCS       /ktlr/
+               ELSE      
+               IFNE      D4N1+HDII
+               FCS       /disto/
+               ENDC      
+               ENDC      
+               ENDC      
+
+start          bra       ll_init
+               nop       
+               lbra      ll_read
+               lbra      ll_write
+               bra       ll_getstat
+               nop       
+               lbra      ll_setstat
+*         lbra  ll_term   
+
+* ll_term
+*
+* Entry:
+*    Y  = address of device descriptor
+*    U  = address of device memory area
+*
+* Exit:
+*    CC = carry set on error
+*    B  = error code
+*
+ll_term                  
+               clrb      
+               rts       
+
+* ll_init
+*
+* Entry:
+*    Y  = address of device descriptor
+*    U  = address of device memory area
+*
+* Exit:
+*    CC = carry set on error
+*    B  = error code
+*
+ll_init                  
+               IFNE      D4N1+HDII
+* Disto 4-N-1 and HD-II: Get MPI slot select value from descriptor
+* and save it in our static storage.
+               lda       IT.MPI,y
+               anda      #$0F                preserve *SCS bits only
+               sta       V.MPISlot,u
+               ENDC      
+               clrb      
+               rts       
+
+
+* ll_getstat
+*
+* Entry:
+*    Y  = address of path descriptor
+*    U  = address of device memory area
+*
+* Exit:
+*    CC = carry set on error
+*    B  = error code
+*
+ll_getstat               
+               ldx       PD.RGS,y
+               lda       R$B,x
+               cmpa      #SS.DSize
+               beq       SSDSize
+               ldb       #E$UnkSvc
+               coma      
+               rts       
+
+
+* SS.DSize - Return size information about a device
+*
+* Entry: B = SS.DSize
+* Exit:  Carry = 1; error with code in B
+*        Carry = 0:
+*          IF B = 0
+*            A = Sector Size (1 = 256, 2 = 512, 4 = 1024, 8 = 2048)
+*            X = Number of Sectors (bits 31-16)
+*            Y = Number of Sectors (Bits 15-0)
+*          IF B != 0
+*            A = Sector Size (1 = 256, 2 = 512, 4 = 1024, 8 = 2048)
+*            X = Number of Logical Cylinders
+*            B = Number of Logical Sides
+*            Y = Number of Logical Sectors/Track
+*
+SSDSize                  
+               pshs      u,y
+               bsr       DSize
+               bcs       ex@
+               ldu       ,s                  get path desc in U
+               ldu       PD.RGS,u
+               std       R$D,u
+               stx       R$X,u
+               sty       R$Y,u
+               clrb      
+ex@            puls      y,u,pc
+
+* DSize - Get SCSI disk size
+*
+* Exit:  Carry = 1; error with code in B
+*        Carry = 0:
+*          IF B = 0
+*            A = Sector Size (1 = 256, 2 = 512, 4 = 1024, 8 = 2048)
+*            X = Number of Sectors (bits 31-16)
+*            Y = Number of Sectors (Bits 15-0)
+*          IF B != 0
+*            A = Sector Size (1 = 256, 2 = 512, 4 = 1024, 8 = 2048)
+*            X = Number of Logical Cylinders
+*            B = Number of Logical Sides
+*            Y = Number of Logical Sectors/Track
+DSize          lbsr      SCSIPrep            do SCSI prep stuff
+               lda       #S$RCAP
+               sta       V.SCSICMD,u
+               leax      V.TxBuf,u
+               stx       V.TfrBuf,u
+               IFNE      D4N1+HDII
+               lbsr      MPIIn
+               ENDC      
+               lbsr      SCSIXfer
+               bcs       ex@
+               ldd       V.TxBuf+2,u         get bits 15-0 of block count
+               addd      #$0001              add 1 to count
+               std       V.TxBuf+2,u         resave
+               bcc       b@
+               ldd       V.TxBuf,u           get bits 31-16
+               addd      #$0001              add 1
+               std       V.TxBuf,u           resave
+b@             lda       V.TxBuf+6,u
+               clrb      
+               ldx       V.TxBuf,u
+               ldy       V.TxBuf+2,u
+ex@                      
+               IFNE      D4N1+HDII
+               lbra      MPIOut
+               ELSE      
+               rts       
+               ENDC      
+
+
+* ll_setstat
+*
+* Entry:
+*    Y  = address of path descriptor
+*    U  = address of device memory area
+*
+* Exit:
+*    CC = carry set on error
+*    B  = error code
+*
+ll_setstat               
+               ldx       PD.RGS,y
+               lda       R$B,x
+               cmpa      #SS.SQD
+               beq       StopUnit
+               cmpa      #SS.DCmd
+               bne       n@
+               pshs      x                  save pointer to caller registers
+               bsr       DCmd               call DCmd
+               puls      x                  get pointer to caller registers
+               sta       R$A,x              save status byte in A
+n@             clrb      
+ex             rts       
+
+* Entry:
+*    R$B = SS.SQD 
+StopUnit                    
+               lbsr      SCSIPrep            do SCSI prep stuff
+               lda       #S$UNIT
+               sta       V.SCSICMD,u
+               clr       V.SCSIPrm2,u        we want to STOP unit
+s@                       
+               IFNE      D4N1+HDII
+               lbsr      MPIIn
+               ENDC      
+               lbra      SCSIXfer
+
+noperms        comb
+               ldb       #E$FNA
+               rts
+               
+* Entry:
+*    X   = caller regs
+*    Y   = path descriptor
+*
+*    R$B = SS.DCmd
+*    R$X = Transfer buffer
+*    R$Y = SCSI command packet
+DCmd                     
+* Fixed bug where Y was not being saved when doing os9 F$ID
+               pshs      y
+               os9       F$ID                get the user ID of the calling process
+               cmpy      #$0000              is it 0 (superuser)?
+               puls      y
+               bne       noperms             no, don't allow the call
+               lbsr      SCSIPrep
+               ldy       R$X,x               get caller's transfer buffer
+               sty       V.UTxBuf,u          save off in mem for later
+               ldx       R$Y,x               get ptr to caller's SCSI command buffer
+               IFGT      Level-1
+               ldy       D.Proc              get current process ptr
+               lda       P$Task,y            get task # for current process
+               ldb       D.SysTsk            get system task #
+               ldy       #SCSIPkLn           max size of SCSI command
+               pshs      u                   save on stack
+               leau      V.SCSICMD,u         point to SCSI command buffer in our statics
+               os9       F$Move              copy from caller to temporary task
+               puls      u
+               bcs       ex                  error copying, exit
+               ELSE      
+               ldb       #SCSIPkLn
+               leay      V.SCSICMD,u
+cl@            lda       ,x+
+               sta       ,y+
+               decb      
+               bne       cl@
+               ENDC      
+               ldy       V.PORT-UOFFSET,u    get hw address (because we overwrite Y earlier)
+               IFNE      D4N1+HDII
+               lbsr      MPIIn
+               ENDC      
+               inc       V.OS9Err,u          we want real SCSI errors returned
+               inc       V.CchDirty,u        and make cache dirty
+               leax      retry@,pcr
+               stx       V.RetryVct,u
+retry@         lbsr      SCSISend
+               IFNE      D4N1+HDII
+               lbcs      MPIOut
+               ELSE      
+               bcs       ex
+               ENDC      
+               IFGT      Level-1
+               ldx       D.Proc              get current process ptr
+               ldb       P$Task,x            get task # for current process
+               ENDC      
+               ldx       V.UTxBuf,u
+
+msgloop@       lbsr      Wait4REQ            wait for REQ to be asserted
+               bita      #CMD                command phase?
+               lbne      PostXfr             yes, return
+io@            bita      #INOUT              data coming in or going out?
+               bne       in@                 branch if coming in...
+               IFGT      Level-1
+               os9       F$LDABX
+               leax      1,x
+               ELSE      
+               lda       ,x+
+               ENDC      
+               sta       SCSIDATA,y
+               bra       msgloop@
+in@            lda       SCSIDATA,y
+               IFGT      Level-1
+               os9       F$STABX
+               leax      1,x
+               ELSE      
+               sta       ,x+
+               ENDC      
+               bra       msgloop@
+
+
+* ll_read
+*
+* Entry:
+*    Y  = address of path descriptor
+*    U  = address of device memory area
+*
+* Static memory referenced:
+*    V.CchPSpot     = address of spot in cache where physical sector data will go
+*    sectsize       = sector size (0=256,1=512,2=1024,3=2048)
+*    V.SectCnt      = sectors to read
+*    V.PhysSect = physical sector to start read from
+ll_read                  
+               IFNE      D4N1+HDII
+               lbsr      MPIIn
+               ENDC      
+               IFNE      SIZEMATTERS
+               bsr       SCSIPrep            do SCSI prep stuff
+               bsr       MakeRead            make read command packet
+               ldx       V.CchPSpot,u
+               stx       V.TfrBuf,u
+               lbra      SCSIXfer
+               ELSE      
+               leax      SCSIReadRetry,pcr
+               stx       V.RetryVct,u
+               lbsr      SCSIPrep            do SCSI prep stuff
+               lbsr      MakeRead            make read command packet
+SCSIReadRetry            
+               lbsr      SCSISend
+               bcs       mpiex
+               bita      #CMD
+               lbne      PostXfr
+               ldb       V.SectCnt,u
+               pshs      b
+* Set up appropriate read call (regular or turbo)
+               tst       V.Turbo,u
+               beq       reg@
+               leax      TurboRead,pcr
+               bra       do@
+reg@           leax      RegRead256,pcr
+do@            stx       V.ReadVct,u
+               ldx       V.CchPSpot,u        get pointer to physical sector in cache for data in
+again@                   
+               ldb       V.Log2Phys,u
+               pshs      b
+loop@                    
+               jsr       [V.ReadVct,u]
+               dec       ,s
+               bne       loop@
+               puls      b
+               dec       ,s
+               bne       again@
+               puls      a
+               lbra      PostXfr
+mpiex                    
+               IFNE      D4N1+HDII
+               lbra      MPIOut
+               ELSE      
+               rts       
+               ENDC      
+
+TurboRead                
+               IFNE      H6309
+
+* 6309 Turbo READ
+               ldw       #256
+               orcc      #IntMasks           we have to mask interrupts for Level 1
+               tfm       y,x+                do the transfer
+               andcc     #^IntMasks          we have to unmask interrupts for Level 1
+               lbsr      DeauxDeaux
+               rts       
+
+               ELSE      
+
+* 6809 Turbo READ
+               lda       #16
+               pshs      a
+l2@            lda       SCSIDATA,y
+               ldb       SCSIDATA,y
+               std       ,x
+               lda       SCSIDATA,y
+               ldb       SCSIDATA,y
+               std       $02,x
+               lda       SCSIDATA,y
+               ldb       SCSIDATA,y
+               std       $04,x
+               lda       SCSIDATA,y
+               ldb       SCSIDATA,y
+               std       $06,x
+               lda       SCSIDATA,y
+               ldb       SCSIDATA,y
+               std       $08,x
+               lda       SCSIDATA,y
+               ldb       SCSIDATA,y
+               std       $0A,x
+               lda       SCSIDATA,y
+               ldb       SCSIDATA,y
+               std       $0C,x
+               lda       SCSIDATA,y
+               ldb       SCSIDATA,y
+               std       $0E,x
+               leax      16,x
+               dec       ,s                  decrement counter
+               bne       l2@
+               puls      a,pc
+               ENDC      
+
+RegRead256               
+               clrb      
+*         
+* "Non-Turbo" Read Data from controller
+*         
+* Passed:  B = bytes to read
+*          X = Address of buffer
+*          Y = Controller Address
+* 
+RegRead                  
+* We wait for REQ in an infinite, faster loop here
+               lda       SCSISTAT,y          get SCSI status byte
+               bita      #REQ                REQ?
+               beq       RegRead
+               lda       SCSIDATA,y
+               sta       ,x+
+               decb      
+               bne       RegRead
+               rts       
+
+
+               ENDC      
+
+
+* Make Read/Write Packet
+* Entry:
+*    A = SCSI command
+*    V.PhysSect = 3 byte physical sector to read/write
+MakeWrite      lda       #S$WRITEX
+               fcb       $8C                 skip next two bytes
+MakeRead       lda       #S$READEX
+MakeRW         sta       V.SCSICMD,u         put passed SCSI command
+               lda       V.SectCnt,u         'V.SectCnt' logical blocks
+* Make SCSI Read/Write 6 byte CDB here
+*               sta       V.SCSIPrm2,u
+*               lda       V.PhysSect,u
+*               sta       V.SCSILUN,u
+*               ldd       V.PhysSect+1,u
+*               std       V.SCSIPrm0,u
+*               rts
+* Make SCSI Read/Write Extended 10 byte CDB here
+               sta       V.SCSIPrm6,u
+               lda       V.PhysSect,u
+               sta       V.SCSIPrm1,u
+               ldd       V.PhysSect+1,u
+               std       V.SCSIPrm2,u
+               rts       
+
+* Prep for SCSI transfer
+* Preserves all regs
+* Entry: Y = path descriptor
+* Exit:  Y = hardware address
+SCSIPrep       pshs      x,d
+               leax      V.SCSICMD,u
+               ldb       #SCSIPkLn
+l@             clr       ,x+
+               decb      
+               bne       l@
+               ldb       PD.DNS,y            and DNS byte
+               stb       V.DnsByte,u         save in our statics
+               andb      #DNS.TURBO          mask out all but turbo bit
+               stb       V.Turbo,u           and save state
+               lda       #NUMTRIES           get retry count
+               sta       V.Retries,u         and reset retry counter
+               clr       V.OS9Err,u          we want real SCSI errors returned
+               ldy       V.PORT-UOFFSET,u    get hw address
+               puls      x,d,pc
+
+* Check Transfer Status
+* This routine is passed the address of another routine to call in case
+* the device is busy or there is an error returned.
+*
+* Passed:  V.RetryVct,u = address of routine to call if SCSI device is busy
+PostXfr        lbsr      GetStatB            get transfer status byte
+               bita      #X$BUSY             device BUSY?
+               bne       retry@              attempt a retry if so...
+chkerr@        bita      #X$ERROR            error?
+               beq       ok@                 branch if not...
+* Error occurred.. retry
+retry@         dec       V.Retries,u         decrement retry count
+               bne       jmp@                try again if not at end
+               IFNE      D4N1+HDII
+               lbsr      SCSIErr
+               lbra      MPIOut
+               ELSE      
+               lbra      SCSIErr
+               ENDC      
+jmp@           jmp       [V.RetryVct,u]
+ok@            clrb      
+               IFNE      D4N1+HDII
+               lbra      MPIOut
+               ELSE      
+               rts       
+               ENDC      
+
+
+* ll_write
+*
+* Entry:
+*    Y  = address of path descriptor
+*    U  = address of device memory area
+*
+* Static memory referenced:
+*    V.CchPSpot     = address of spot in cache where physical sector data is
+*    sectsize       = sector size (0=256,1=512,2=1024,3=2048)
+*    V.SectCnt      = sectors to read
+*    V.PhysSect     = physical sector to start read from
+ll_write                 
+               IFNE      D4N1+HDII
+               lbsr      MPIIn
+               ENDC      
+               IFNE      SIZEMATTERS
+               bsr       SCSIPrep            do SCSI prep stuff
+               bsr       MakeWrite           make read command packet
+               ldx       V.CchPSpot,u
+               stx       V.TfrBuf,u
+               ELSE      
+               leax      SCSIWriteRetry,pcr
+               stx       V.RetryVct,u
+               bsr       SCSIPrep            do SCSI prep stuff
+               lbsr      MakeWrite
+SCSIWriteRetry lbsr      SCSISend
+               lbcs      mpiex
+               bita      #CMD
+               bne       PostXfr
+               ldb       V.SectCnt,u
+               pshs      b
+* Set up appropriate write call (regular or turbo)
+               tst       V.Turbo,u
+               beq       reg@
+               leax      TurboWrite,pcr
+               bra       do@
+reg@           leax      RegWrite,pcr
+do@            stx       V.WriteVct,u
+               ldx       V.CchPSpot,u
+again@         ldb       V.Log2Phys,u
+               pshs      b
+loop@          jsr       [V.WriteVct,u]
+               dec       ,s
+               bne       loop@
+               puls      b
+               dec       ,s
+               bne       again@
+               puls      a
+               bra       PostXfr
+
+TurboWrite               
+               IFNE      H6309
+
+* 6309 Turbo WRITE
+loop@          orcc      #IntMasks           we have to mask interrupts for Level 1
+               ldw       #256
+               tfm       x+,y
+               andcc     #^IntMasks          we have to unmask interrupts for Level 1
+               lbsr      DeauxDeaux
+               rts       
+
+               ELSE      
+
+* 6809 Turbo WRITE
+               lda       #16
+               pshs      a
+l2@            ldd       ,x
+               sta       SCSIDATA,y
+               stb       SCSIDATA,y
+               ldd       $02,x
+               sta       SCSIDATA,y
+               stb       SCSIDATA,y
+               ldd       $04,x
+               sta       SCSIDATA,y
+               stb       SCSIDATA,y
+               ldd       $06,x
+               sta       SCSIDATA,y
+               stb       SCSIDATA,y
+               ldd       $08,x
+               sta       SCSIDATA,y
+               stb       SCSIDATA,y
+               ldd       $0A,x
+               sta       SCSIDATA,y
+               stb       SCSIDATA,y
+               ldd       $0C,x
+               sta       SCSIDATA,y
+               stb       SCSIDATA,y
+               ldd       $0E,x
+               sta       SCSIDATA,y
+               stb       SCSIDATA,y
+               leax      16,x
+               dec       ,s                  decrement counter
+               bne       l2@
+               puls      a,pc
+
+               ENDC      
+
+*
+* "Non-Turbo" Write Data to controller
+*
+* Passed:  X = Address of data to write
+*          Y = Controller Address
+*
+RegWrite       clrb      
+loop@          lda       SCSISTAT,y
+               bita      #REQ
+               beq       loop@
+               lda       ,x+
+               sta       SCSIDATA,y
+               decb      
+               bne       loop@
+               rts       
+
+               ENDC      
+
+               IFNE      D4N1+HDII
+* Disto 4-N-1/HD-II: Map in MPI HERE
+MPIIn          pshs      cc,a
+               lda       MPI.Slct            get MPI value
+               sta       V.MPISave,u         save off in our statics
+               anda      #$F0                preserve CTS slot bits (%1111000)
+               ora       V.MPISlot,u         OR in MPI slot of our HW
+MPIWrite       sta       MPI.Slct            write out to MPI
+               puls      a,cc,pc
+
+MPIOut         pshs      cc,a
+               lda       V.MPISave,u
+               bra       MPIWrite
+               ENDC      
+
+
+* SCSIXfer
+*
+* Entry:
+*    Y  = hardware address
+*    U  = address of device memory area
+*
+* Static memory referenced:
+*    V.TfrBuf,u      = address of transfer/receive buffer               
+SCSIXfer       leax      retry@,pcr
+               stx       V.RetryVct,u
+retry@         bsr       SCSISend
+               bcs       sr@
+               ldx       V.TfrBuf,u
+tfr@           lbsr      Wait4REQ            wait for REQ to be asserted
+               bita      #CMD
+               lbne      PostXfr             COMMAND phase...
+* If here, we're in DATA PHASE
+               bita      #INOUT              data coming in or going out?
+               bne       in@                 branch if coming in...
+out@           lda       ,x+
+               sta       SCSIDATA,y
+               bra       tfr@
+in@            lda       SCSIDATA,y
+               sta       ,x+
+               bra       tfr@
+sr@            rts       
+
+
+* Give up timeslice several times unless this is the system
+DeauxDeaux     pshs      x
+               IFGT      Level-1
+               ldx       D.Proc              get proc descriptor
+               cmpx      D.SysPrc            system?
+               beq       WaitDone            yep, system cannot sleep
+               ENDC      
+*               ldx       D.AProcQ            get active proc queue
+*               beq       WaitDone            if empty, return
+*               ldx       #$0001
+*               os9       F$Sleep             give up timeslice
+*               ldx       D.AProcQ            get active proc queue
+*               beq       WaitDone            if empty, return
+               ldx       #$0001
+               os9       F$Sleep             give up timeslice
+WaitDone       puls      x,pc                return to caller
+
+* Get Status Byte from SCSI controller
+* Exit: A = status byte
+GetStatB       bsr       Wait4REQ
+               lda       SCSIDATA,y
+               pshs      a
+               bsr       Wait4REQ
+               clr       SCSIDATA,y
+               puls      pc,a
+
+* SCSI ID table with hi-bit set for SCSI-3 compliance
+IDTBL          FCB       $80+1,$80+2,$80+4,$80+8,$80+16,$80+32,$80+64,128
+
+*
+* SCSI Packet Send Routine
+* 
+* Sets LUN for SCSI Packet, then sends command packet to controller
+*
+* Passed:  Y = Device Address
+*
+* Returns: A = SCSI Status byte
+*
+* Destroys: X
+*
+SCSISend       ldb       V.SCSILUN,u         get SCSI LUN
+               andb      #%00011111          mask out LUN
+               stb       V.SCSILUN,u
+               ldb       V.DnsByte,u         get DNS byte
+               andb      #%11100000          get SCSI LUN from byte
+               orb       V.SCSILUN,u         OR with SCSI LUN byte
+               stb       V.SCSILUN,u         save off
+               ldd       #BUSY*256           we want /BUSY
+               bsr       StatusWait
+               bcs       ex4
+* BUSY is clear, put initiator/target IDs on bus
+               lda       V.DnsByte,u         get DNS byte
+               anda      #$07                mask out all but SCSI IDs
+               leax      IDTBL,pcr           point to device ID table
+               lda       a,x                 get ID value
+               sta       SCSIDATA,y          write out to controller
+               sta       SCSISEL,y           here too...
+               ldd       #BUSY*256+BUSY      we want BUSY
+               bsr       StatusWait
+               bcs       ex4
+* BUSY is set
+* Here we send the packet to the controller.
+chkok@         leax      V.SCSICMD,u         point X to SCSI command packet
+tfrloop@       bsr       Wait4REQ            wait for REQ
+               bita      #CMD                SCSI CMD bit set?
+               beq       ex4                 branch if not...
+               bita      #INOUT              INOUT set?
+               bne       ckmsg@              branch if target->initiator
+               lda       ,x+                 get byte from SCSI CMD packet
+               sta       SCSIDATA,y          write to controller
+               bra       tfrloop@
+ckmsg@         bita      #MSG                MESSAGE IN (target->initiator)
+               beq       ex4
+*
+* MESSAGE IN phase code
+*
+MSGIn          lda       SCSIDATA,y          extended message?
+               deca      
+               bne       SCSISend            nope, restart target initiation
+               ldb       SCSIDATA,y          get extended message length
+* Note: We ignore extended messages
+l@             tst       SCSIDATA,y          read extended message data
+               decb      
+               bne       l@
+               bra       SCSISend            message read, restart target initiation
+ex4            rts       
+
+*
+* Loop until REQ bit is set
+*
+* Passed:   Y = Device Address
+*
+* Returns:  A = SCSI Status byte
+*
+Wait4REQ                 
+loop@          lda       SCSISTAT,y          get SCSI status byte
+               bita      #REQ                REQ?
+               beq       sleep@              +
+               rts                           +
+sleep@         lbsr      DeauxDeaux
+               bra       loop@
+
+* Wait for a set of conditions in the status register to be TRUE
+* This yields a delay of about 5 seconds.
+*
+* Entry: Y = HW address
+*        A = flip (if bit set, that bit is tested)
+*        B = mask (result must match this byte)
+StatusWait               
+               pshs      x,d
+               IFEQ      Level-1
+               ldb       #$02
+               ldx       #$0000
+               ELSE      
+               ldb       #$04
+               ldx       #$0000
+               ENDC      
+l@             lda       SCSISTAT,y
+               anda      ,s                  apply flip
+               cmpa      1,s                 compare to mask
+               bne       dec@                branch if not equal (not what we want)
+               lda       SCSISTAT,y
+               clrb                          clear carry
+               bra       ok@
+dec@           leax      -1,x                count down
+               bne       l@
+               decb                          decrement bits 23-16
+               bpl       l@                  if >=0, keep going
+               comb                          set carry
+               ldb       #E$NotRdy
+ok@            leas      2,s
+               puls      x,pc
+
+*
+* Send a REQSENSE message to the SCSI controller
+*
+SndMSG         lbsr      Wait4REQ            wait for REQ to be asserted
+               bita      #CMD                command phase?
+               bne       ex4                 yes, return
+               beq       INorOUT             no, check for in/out
+               rts       
+INorOUT        bita      #INOUT              data coming in or going out?
+               bne       ComingIn            branch if coming in...
+               lda       ,x+
+               sta       SCSIDATA,y
+               bra       SndMSG
+ComingIn       lda       SCSIDATA,y
+               sta       ,x+
+               bra       SndMSG
+
+
+* SCSIErr - Attemps a REQUEST SENSE to find a SCSI error
+*
+* Entry:
+*    Y  = address of hardware
+*    U  = address of device memory area
+*
+* Exit:
+*    CC = carry set
+*    B  = error code
+*
+SCSIErr        lda       #S$REQSEN           REQUEST SENSE command
+               sta       V.SCSICMD,u
+               clra      
+               clrb      
+               sta       V.SCSILUN,u
+               std       V.SCSIPrm0,u
+               lda       #ReqPkL             set allocation length
+               std       V.SCSIPrm2,u
+               lbsr      SCSISend            send command
+               bcs       ex4                 branch if error
+               leax      V.R$Err,u           point to return data buffer
+               bsr       SndMSG              get response data
+               lbsr      GetStatB
+               clra      
+               pshs      a
+               lda       V.R$Err,u           get error code
+               anda      #$7F                wipe out hi bit
+               cmpa      #$70                "current" error?
+               bne       L05A3               branch if not...
+               lda       V.R$Err2,u          get more detailed error
+               anda      #%00001111
+               sta       ,s                  save off stack
+               lda       V.R$AdSns,u         get additional sense code
+L05A3          tst       V.OS9Err,u          send OS-9 error?
+L05A7          beq       L05AD               branch if so...
+               tfr       a,b                 else put SCSI error in B
+               clr       V.OS9Err,u          and clear SCSI error flag
+               bra       ErrErr              and return with error
+* Walk error table to find OS-9 error
+L05AD          leax      >ErrTbl,pcr
+               ldb       #E$Unit
+L05B3          tst       ,x
+               beq       ErrErr
+               cmpa      ,x++
+               blt       L05B3
+               ldb       -1,x
+ErrErr         coma      
+               puls      pc,a
+
+
+
+* Error Table - Maps SCSI errors to OS-9 errors
+* This table is contructed so that gaps are actually continuations of
+* the previous entry.  For example, $14 maps to E$Seek, and so does $15 and
+* $16.
+ErrTbl         FCB       $01,E$NotRdy
+               FCB       $02,E$Seek
+               FCB       $03,E$Write
+               FCB       $04,E$NotRdy
+               FCB       $06,E$Seek
+               FCB       $10,E$CRC
+               FCB       $11,E$Read
+               FCB       $14,E$Seek
+               FCB       $17,E$CRC
+               FCB       $19,E$IllArg
+               FCB       $1C,E$Read
+               FCB       $1E,E$CRC
+               FCB       $20,E$IllCmd
+               FCB       $21,E$Sect
+               FCB       $25,E$IllArg
+               FCB       $29,E$NotRdy
+               FCB       $00
+
+
+               EMOD      
+eom            EQU       *
+               END       
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/level1/modules/rbdesc.asm	Thu Dec 22 18:23:47 2011 +0000
@@ -0,0 +1,71 @@
+********************************************************************
+* rbdesc - Device Descriptor Template
+*
+* $Id$
+*
+* Edt/Rev  YYYY/MM/DD  Modified by
+* Comment
+* ------------------------------------------------------------------
+
+         nam   rbdesc
+         ttl   Device Descriptor Template
+
+* Disassembled 98/08/23 17:09:41 by Disasm v1.6 (C) 1988 by RML
+
+         ifp1  
+         use   defsfile
+         endc  
+
+tylg     set   Devic+Objct
+atrv     set   ReEnt+rev
+rev      set   $00
+
+DNum     set   0
+         IFNE  D35
+Type     set   TYP.CCF+TYP.3
+         ELSE
+Type     set   TYP.CCF+TYP.5
+         ENDC
+Density  set   DNS.MFM
+Step     set   STP.6ms
+Cyls     set   35
+Sides    set   1
+Verify   set   1
+SectTrk  set   18
+SectTrk0 set   18
+Interlv  set   3
+SAS      set   8
+
+         mod   eom,name,tylg,atrv,mgrnam,drvnam
+
+         fcb   DIR.!SHARE.!PEXEC.!PWRIT.!PREAD.!EXEC.!UPDAT. mode byte
+         fcb   HW.Page    extended controller address
+         fdb   $FF40      physical controller address
+         fcb   initsize-*-1 initalization table size
+         fcb   DT.RBF     device type:0=scf,1=rbf,2=pipe,3=scf
+         fcb   DNum       drive number
+         fcb   Step       step rate
+         fcb   Type       drive device type
+         fcb   Density    media density:0=single,1=double
+         fdb   Cyls       number of cylinders (tracks)
+         fcb   Sides      number of sides
+         fcb   Verify     verify disk writes:0=on
+         fdb   SectTrk    # of sectors per track
+         fdb   SectTrk0   # of sectors per track (track 0)
+         fcb   Interlv    sector interleave factor
+         fcb   SAS        minimum size of sector allocation
+initsize equ   *
+
+         IFNE  DD
+name     fcs   /DD/
+         ELSE
+name     fcs   /RTST/
+         fcb   '0+DNum+$80
+         ENDC
+mgrnam   fcs   /RBF/
+drvnam   fcs   /rbtest/
+
+         emod  
+eom      equ   *
+         end   
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/level1/modules/rbsuper.asm	Thu Dec 22 18:23:47 2011 +0000
@@ -0,0 +1,791 @@
+********************************************************************
+* rbsuper - RBF Super Caching Device Driver
+*
+* $Id$
+*
+* (C) 2004 Boisy G. Pitre - Licensed to Cloud-9
+*
+* RBSuper is the framework for a new type of RBF device driver -- one
+* that fetches native-size, or PHYSICAL sectors.  A physical sector is
+* a sector that is sized to its device.  For example, all IDE drives and
+* pretty much all SCSI drives have 512 byte sectors; CD-ROMs have 2048
+* byte sectors.
+*
+* As a high-level driver, this module is responsible for managing
+* the cache, verifying writes, etc.
+*
+* The actual reading and writing of sectors is performed by the
+* low-level driver, which can be designed for any device.
+*
+* Conditionals:
+*   H6309 - if set, assembles for 6309
+*   USECS - if set, uses critical section code (slows down driver)
+*   HDBDOS - if set, adds code to handle HDB-DOS partitions
+*
+* Edt/Rev  YYYY/MM/DD  Modified by
+* Comment
+* ------------------------------------------------------------------
+*          2004/04/10  Boisy G. Pitre
+* Created due to Mark's constant harping about a NitrOS-9 driver for
+* the SuperIDE Interface.  Here ya go, Marlette.
+*
+*          2005/12/12  Boisy G. Pitre
+* The SS.VarSect call has been moved from the low level driver to rbsuper
+* for efficiency.  Also it no longer calls SS.DSize every time it is called.
+* Instead, it only calls it the first time, then caches the sector size value
+* and returns that value on subsequent calls.
+*
+*          2005/12/13  Boisy G. Pitre
+* Employed a trick to "shift" the idea of where the driver's static
+* data starts at the start of each entry point.  This saves about 200
+* bytes of memory.
+*
+* 1        2006/08/20  Boisy G. Pitre
+* Fixed bug where linking to a non-existent module in Init would cause a crash
+* because IOMan calls the Term routine when Init returns an error.  Added a simple
+* one line test in Term to see if a value was non-zero which would indicate if Init
+*
+* 2        2008/02/05  Boisy G. Pitre
+* Fixed bug where DNS HDB flag was being pulled from PD.TYP byte instead of PD.DNS.
+*
+* 3        2011/12/22  Boisy G. Pitre
+* Made a "fast path" for 256 byte sector devices to read/write directly into PD.BUF
+* instead of using the cache, for performance reasons.
+* Conditionalized critical section code since it may not be needed, and affects performance.
+
+               NAM       rbsuper             
+               TTL       RBF Super Caching Device Driver
+
+               IFP1      
+               USE       defsfile
+               USE       rbsuper.d
+               ENDC      
+
+tylg           SET       Drivr+Objct
+atrv           SET       ReEnt+rev
+rev            SET       0
+edition        SET       2
+
+               MOD       eom,name,tylg,atrv,start,V.RBSuper
+
+               FCB       DIR.+SHARE.+PEXEC.+PREAD.+PWRIT.+EXEC.+UPDAT.
+
+name           FCS       /RBSuper/
+               FCB       edition
+
+start          lbra      Init
+               bra       Read
+               nop       
+               lbra      Write
+               lbra      GetStat
+               lbra      SetStat
+
+*
+* Term
+*
+* Entry:
+*    U  = address of device memory area
+* 
+* Exit:
+*    CC = carry set on error
+*    B  = error code
+* 
+Term           leau      UOFFSET,u
+* Free memory allocated for cache
+               lda       V.CchSize,u         get cache size into A
+* Note, the next line fixes a bug where the system would crash when F$Link in Init failed.
+* If it fails, V.CchSize will never get set, and since it is set to 0 initally, we assume
+* that init failed if V.CchSize is 0 and thus we simply return.
+               beq       ret@
+               tfr       u,x                 move statics ptr into X for safety
+               ldu       V.CchAddr,u         and load U with cache address
+               beq       nofree@
+               os9       F$SRtMem            return cache memory to system
+nofree@        tfr       x,u                 and restore statics ptr
+* Call low-level driver term
+               ldx       V.LLTerm,u
+               lbsr      LLCall
+* Unlink low-level driver
+               IFGT      Level-1
+               ldx       D.Proc              get curr proc ptr
+               ldd       D.SysPrc            get system process desc ptr
+               std       D.Proc              and make current proc
+               ENDC      
+               ldu       V.LLAddr,u          get the address of the low-level module
+               os9       F$Unlink            unlink it
+               IFGT      Level-1
+               stx       D.Proc              restore
+               ENDC      
+ret@           rts                           return
+
+*
+* Read
+*
+* Entry:
+*    B  = MSB of the disk's LSN
+*    X  = LSB of the disk's LSN
+*    Y  = address of path descriptor
+*    U  = address of device memory area
+*
+* Exit:
+*    CC = carry set on error
+*    B  = error code
+*
+Read           leau      UOFFSET,u
+               cmpx      #$0000              LSN 0?
+               bne       ReadSect            branch if not
+               tstb                          LSN 0?
+               bne       ReadSect            branch if not
+               bsr       ReadSect            else read LSN0
+               bcs       bye                 if error, return
+* Code to deal with copying LSN0
+               leax      DRVBEG-UOFFSET,u    point X to start of drive table
+               ldb       PD.DRV,y            get drive number
+lsn@           beq       CopyLSN0            branch if zero
+               leax      DRVMEM,x            else increase X by drive table size
+               decb                          decrement drive number
+               bra       lsn@                branch to loop
+
+* X = drive table pointer for PD.DRV
+* Copy DD.SIZ bytes (LSN0) from buffer to drive table
+CopyLSN0       EQU       *
+               ldu       PD.BUF,y
+               IFNE      H6309
+               ldw       #DD.SIZ
+               tfm       u+,x+
+               ELSE      
+               ldb       #DD.SIZ
+CpyLSNLp       pulu      a                   one cycle less than lda ,u+
+               sta       ,x+
+               decb      
+               bne       CpyLSNLp
+               ENDC      
+rret           rts       
+
+               IFNE      HDBDOS
+* For HDB-DOS, we must add in drive number
+* First, multiply drive number in descriptor by $276 (630 sectors),
+* then, add the product to the PSect
+ComputeHDB               
+               IFNE      H6309
+               clra      
+               ldb       V.HDBDrive,u
+               muld      #$0276
+               addw      V.PhysSect+1,u
+               stw       V.PhysSect+1,u
+               adcb      V.PhysSect,u
+               stb       V.PhysSect,u
+               ELSE      
+               leas      -4,s                make a stack to store product of $276 * DriveNum
+               lda       V.HDBDrive,u        get drive number
+               ldb       #$76
+               mul       
+               std       2,s
+               lda       V.HDBDrive,u
+               ldb       #$02
+               mul       
+               std       ,s
+               clrb      
+               lda       1,s
+               addd      2,s
+               std       2,s
+               bcc       f@
+               inc       ,s
+f@             lda       ,s
+               sta       1,s
+               ldd       2,s
+               addd      V.PhysSect+1,u
+               std       V.PhysSect+1,u
+               lda       1,s
+               adca      V.PhysSect,u
+               sta       V.PhysSect,u
+               leas      4,s
+               ENDC      
+               ENDC      
+bye            rts       
+
+* 256 byte sector device: setup for low level driver to put 256 byte sector directly into PD.BUF
+Read256
+               lbsr      Log2Phys
+* We may not have to do this (and disturb the cache as a result)
+*               lda       PD.DRV,y            get current drive number
+*               sta       V.LastDrv,u         and make this the current drive
+               lda       #1
+               sta       V.SectCnt,u
+               ldx       PD.BUF,y             put address of PD.BUF directly into cache spot
+               stx       V.CchPSpot,u
+* Call low-level driver read
+               ldx       V.LLRead,u
+               lbra      LLCall
+
+* Read Sector
+*
+* The sector will be read from either the cache or the controller.
+* A cache "hit" is verified by two methods:
+* 1. Comparing the drive number of the drive for the current path to
+*    the drive number of the last path -- if they match, we *MAY*
+*    have a cache hit.  If not, we fill the cache
+* 2. If #1 matches, then we know the current drive and the last drive
+*    are the same.  We then check the logical sector to see if it is
+*    in the cache.
+*
+* Entry:
+*    Y = address of path descriptor
+*    U = address of device memory area
+*    B = Sector bits 23-16
+*    X = Sector bits 15-0
+*
+ReadSect       bsr       PreXfr              to pre-transfer stuff
+               bcs       bye                 branch if error
+               IFNE      HDBDOS
+               tst       V.HDBPart,u         HDB-DOS partition?
+               beq       NotHDB
+* This is the HDB-DOS partition "read" code path.
+* As an HDB-DOS partition, we are interested ONLY in reading the first 256 bytes
+* regardless of the size of the cache.
+               lda       V.SectSize,u        get sector size (0=256,1=512,2=1024,etc)
+               leax      SCTTBL,pcr
+               lda       a,x
+               sta       V.Log2Phys,u        set logical sectors per phys
+               lda       #$01                get sector count
+               sta       V.SectCnt,u         and store it
+               sta       V.CchDirty,u        the cache will ALWAYS be dirty in HDB-DOS mode
+               lda       V.LogSect,u         get logical sector stored earlier
+               sta       V.PhysSect,u        save off logical sector as physical one
+               ldd       V.LogSect+1,u       get logical sector stored earlier
+               std       V.PhysSect+1,u      save off logical sector as physical sector
+               lbsr      AddSectorOffset     add in partition offset and HDB-DOS drive
+               bsr       ComputeHDB          and compute HDB-DOS offset
+* Set up the pointer to the buffer
+               ldx       V.CchAddr,u         get address of cache
+               stx       V.CchPSpot,u        save in current sector pointer
+* Call low-level driver
+               ldx       V.LLRead,u
+               lbsr      LLCall
+               bcs       bye
+               ldx       V.CchAddr,u         get cache pointer which holds HDB-DOS sector
+               bra       CopyXToPDBUF
+               ENDC      
+NotHDB
+* New: Dec 20, 2011
+* Fast path opportunity: if sector size is 256 bytes, call LLRead right into PD.BUF
+               tst       V.SectSize,u        (0=256 byte sector device)
+               beq       Read256 
+               bsr       ValidateCache
+               bcs       ex@
+* Copy appropriate 256 byte sector from V.CchAddr to PD.BUF,y
+               lda       V.CchSize,u         get hi byte of cache size
+               deca      
+               anda      V.LogSect+2,u
+               clrb      
+               ldx       V.CchAddr,u
+               leax      d,x
+CopyXToPDBUF   pshs      y
+               ldy       PD.BUF,y
+               IFNE      H6309
+               ldw       #256
+               tfm       x+,y+
+               clrb      
+               puls      y,pc
+               ELSE      
+               clr       ,-s
+next@          ldd       ,x++
+               std       ,y++
+               inc       ,s
+               bpl       next@
+               clrb      
+               puls      a,y,pc
+               ENDC      
+ex@            rts       
+
+* ValidateCache
+*
+* Check if the cache is coherent (i.e. contains requested sector).
+* If the cache is NOT coherent, it calls 'FillCache' to fill it.
+ValidateCache            
+* We must determine if the currently requested sector is already in cache.
+* First, is this drive the same as the last drive that accessed the cache?
+* If not, then we need to fill the cache with sectors from the current drive.
+               tst       V.CchDirty,u        has cache been initialized?
+               bne       nomatch             branch if not
+               lda       PD.DRV,y            get current drive
+               cmpa      V.LastDrv,u         save as last drive to access cache?
+               bne       nomatch             if not, fill cache
+* Same drive as last access... is this sector in cache?
+               ldb       V.LogSect,u         save off logical sector
+               cmpb      V.CchBase,u         compare bits 23-16
+               bne       nomatch             branch if not the same
+               lda       V.LogSect+1,u       save off logical sector
+               ldb       V.CchSize,u         get hi byte of cache size
+               decb                          decrement (e.g. 8=7,4=3,2=1,1=0)
+               comb                          invert (e.g. 7=$F8,3=$FC,1=$FE,0=$FF)
+               andb      V.LogSect+2,u       mask out cached sectors
+               cmpd      V.CchBase+1,u       same as what's in cache?
+               beq       exok@               YES, WE HAVE A CACHE HIT!!!
+nomatch        bra       FillCache           no, we must fil the cache
+*
+* PreXfr
+*
+* Called at read/write to gather info from path descriptor and
+* device descriptor.
+PreXfr         stb       V.LogSect,u         save off logical sector
+               stx       V.LogSect+1,u       save off logical sector
+               lda       PD.STP,y            get possible HDB-DOS drive number
+               sta       V.HDBDrive,u        save off in our statics
+               lda       PD.TYP,y
+               anda      #TYPH.SSM           lob off all but sector size bits
+* SmartCache - check if our current cache can accommodate this sector size
+               cmpa      V.SectSize,u        do we need to expand?
+               bls       no@                 branch if not
+* Yes, we need to free our current cache mem and alloc more
+               pshs      a,u                 save regs
+               ldd       V.CchSize,u         get current cache size
+               ldu       V.CchAddr,u         and cache pointer
+               beq       nofree@
+               os9       F$SRtMem            return that memory
+nofree@        puls      a,u                 restore regs
+               lbsr      ExpandCache         go expand cache
+               bcs       ex@                 and branch if error
+               sta       V.SectSize,u        save new sector size
+no@
+               lda       PD.DNS,y            get DNS byte
+               anda      #DNS.HDB            isolate HDB-DOS flag
+               sta       V.HDBPart,u         and save state
+exok@          clrb                          clear carry
+               rts                           return
+ex@            clr       V.SectSize,u        clear sector size to force realloc
+               orcc      #Carry              set carry (indicates error)
+               rts                           return
+
+* FillCache
+*
+* Fill the cache with sectors from the device.
+*
+* Destroys: A, B, X
+FillCache                
+               lda       V.LogSect,u         get logical sector bits 23-16
+               sta       V.CchBase,u         save as cached base
+               lda       V.LogSect+1,u       save off logical sector
+               ldb       V.CchSize,u         get hi byte of cache size (1, 2, 4 or 8)
+               decb                          decrement (e.g. 8=7,4=3,2=1,1=0)
+               comb                          invert (e.g. 7=$F8,3=$FC,1=$FE,0=$FF)
+               andb      V.LogSect+2,u       mask out cached sectors
+               std       V.CchBase+1,u       save as cached base
+               lbsr      Log2Phys            convert logical sectors to physical
+               lda       PD.DRV,y            get current drive number
+               sta       V.LastDrv,u         and make this the currently cached drive
+* Set up the transfer
+               ldb       V.CchSize,u         get upper 8 bits of cache size
+               lda       V.SectSize,u        get sector size (0=256,1=512,2=1024,etc)
+               leax      SCTTBL,pcr
+               lda       a,x
+               sta       V.Log2Phys,u
+               lda       V.SectSize,u        get sector size (0=256,1=512,2=1024,etc)
+               beq       ok@
+lsr@           lsrb                          divide by 2
+               deca                          decrement
+               bne       lsr@                else divide again
+ok@            stb       V.SectCnt,u         save sector count
+               decb      
+               comb      
+               andb      V.PhysSect+2,u
+               stb       V.PhysSect+2,u
+* Set up the pointer to the buffer
+               ldx       V.CchAddr,u         get pointer to big buffer
+               stx       V.CchPSpot,u        save in current sector pointer
+* Call low-level driver read
+               ldx       V.LLRead,u
+               bsr       LLCall
+               bcs       ex@
+               clr       V.CchDirty,u        cache is no longer dirty
+               clrb      
+               rts       
+ex@            stb       V.CchDirty,u        store error code as dirty flag
+               rts       
+
+
+SCTTBL         FCB       256/256
+               FCB       512/256
+               FCB       1024/256
+               FCB       2048/256
+
+* GetStat/SetStat
+*
+* Entry:
+*    R$B = function code
+*    Y   = address of path descriptor
+*    U   = address of device memory area
+*
+* Exit:
+*    CC = carry set on error
+*    B  = error code
+*
+SetStat        leau      UOFFSET,u
+               ldx       V.LLStSt,u
+               bra       LLCall
+
+SSVarSect      ldb       PD.DRV,y            get drive number
+               leax      V.SSCache,u         point to sector size cache table
+               abx       
+               lda       ,x                  get sector size
+               bne       go2@                if not zero, use that value
+               pshs      x
+               ldx       PD.RGS,y
+               pshs      x
+               leas      -R$Size,s
+               sts       PD.RGS,y
+               lda       #SS.DSize
+               sta       R$B,s
+               bsr       gs2                 make a call to low level driver's SS.DSize
+* Be sure that no instructions from here to the bcs modify carry
+               lda       R$A,s
+               leas      R$Size,s
+               puls      x
+               stx       PD.RGS,y
+               puls      x
+               bcs       ex@
+               cmpa      #8                  2048 byte sector?
+               beq       go@
+               lsra                          else shift right
+               FCB       $8C                 skip next two bytes (cmpx...)
+go@            lda       #3
+               sta       ,x                  save newly acquired value off into cached size table
+go2@           pshs      a
+               lda       PD.TYP,y
+               anda      #^TYPH.SSM
+               ora       ,s+
+* Boisy's Notes 3/27/06:
+* Notice that we save the true sector size of the device in the PD.TYP byte of
+* the path descriptor EACH TIME SS.VarSect is called.  This is important,
+* because it alleviates the user from having to set this value in the device
+* descriptor in a situation where the device being accessed has a larger sector
+* size than what is in the device descriptor.
+*
+* Note that the value in the device descriptor IS used to initially determine
+* the size of the cache at INIT time since we haven't even talked to the
+* controller at that time yet to query it for its size.
+*               sta       PD.TYP,y            and in path descriptor
+               clrb      
+ex@            rts       
+
+
+GetStat        leau      UOFFSET,u
+               ldx       PD.RGS,y            get registers
+               ldb       R$B,x               get caller's B
+               cmpb      #SS.VarSect
+               beq       SSVarSect
+
+gs2            ldx       V.LLGtSt,u
+
+* Entry: Y = path desc ptr
+*        U = statics ptr
+*        X = address of routine to call
+LLCall
+               IFEQ      USECS-1
+               pshs      a                   preserve A for duration of csacq_wait
+               lda       #255                wait the maximum number of counts
+               bsr       csacq_wait          acquire the critical section
+               tsta                          test A for zero
+               puls      a                   restore A
+               beq       cserr               return if A was zero (semaphore wasn't acquired)
+               ENDC
+               pshs      u,y                 save U and Y
+               jsr       ,x                  call low level routine
+               puls      y,u                 restore U and Y
+
+               IFEQ      USECS-1
+* Critical Section Release - clear the critial section to zero, allowing others to use it
+csrel          pshs      cc                  preserve CC
+               clr       V.LLSema,u          clear critical section
+               puls      cc,pc               restore CC and return
+cserr          comb                          set the carry
+               ldb       #111                and load B with error indicating a semaphore timeout
+               ENDC
+               rts       
+
+               IFEQ      USECS-1
+* Critical Section Acquire With Wait
+*
+* Entry:
+*    A = number of times to check before giving up
+*
+* Exit:
+*    A = status (>0 = Critical section acquired, 0 = Critical section not acquired)
+*
+csacq_wait     pshs      cc                  save CC on stack
+               orcc      #IntMasks           mask interrupts
+               tst       V.LLSema,u          does someone already have the critical section?
+               bne       w@                  if so, then branch
+               inc       V.LLSema,u          else claim critical section (0->1)
+e@             puls      cc,pc               restore CC and return
+w@             deca                          decrement our timeout counter
+               beq       e@                  if zero, we've timed out, return
+               puls      cc                  give interrupts a chance to breathe
+               IFGT      Level-1
+* Give up timeslice unless this is the system
+               pshs      x
+               ldx       D.Proc              get proc descriptor
+               cmpx      D.SysPrc            system?
+               beq       wd@                 yep, system cannot sleep
+*               ldx       D.AProcQ            get active proc queue
+*               beq       wd@                 if empty, return
+               ldx       #$0001
+               os9       F$Sleep             give up timeslice
+wd@            puls      x                   return to caller
+               ENDC      
+               bra       csacq_wait          and try again
+               ENDC
+
+
+* Log2Phys - Convert logical sector to physical sector
+*
+* Stores V.PhysSect,u from V.LogSect,u based on V.SectSize,u
+* Also adds IT.SOFF1-IT.SOFF3 to V.PhysSect,u for partitioning.
+* Results are placed in V.PhysSect,u
+Log2Phys       lda       V.LogSect,u
+               sta       V.PhysSect,u
+               ldd       V.LogSect+1,u
+               std       V.PhysSect+1,u
+               lda       V.SectSize,u
+               beq       AddSectorOffset
+DivBy2         lsr       V.PhysSect,u
+               ror       V.PhysSect+1,u
+               ror       V.PhysSect+2,u
+               deca      
+               bne       DivBy2
+* This routine adds the 3 byte sector offset in the
+* device descriptor to the physical sector.
+AddSectorOffset           
+               ldx       PD.DEV,y
+               ldx       V$DESC,x
+               ldd       IT.SOFF2,x
+               addd      V.PhysSect+1,u
+               std       V.PhysSect+1,u
+               lda       IT.SOFF1,x
+               adca      V.PhysSect,u
+               sta       V.PhysSect,u
+logex          rts       
+
+
+* 256 byte sector device: setup for low level driver to put 256 byte sector directly into PD.BUF
+Write256
+               bsr      Log2Phys
+* We may not have to do this (and disturb the cache as a result)
+*               lda       PD.DRV,y            get current drive number
+*               sta       V.LastDrv,u         and make this the current drive
+               lda       #1
+               sta       V.SectCnt,u
+               ldx       PD.BUF,y             put address of PD.BUF directly into cache spot
+               stx       V.CchPSpot,u
+* Call low-level driver read
+               ldx       V.LLWrite,u
+               bra       LLCall
+
+* Write
+*
+* Entry:
+*    B  = MSB of the disk's LSN
+*    X  = LSB of the disk's LSN
+*    Y  = address of path descriptor
+*    U  = address of device memory area
+*
+* Exit:
+*    CC = carry set on error
+*    B  = error code
+*
+Write          leau      UOFFSET,u
+               lbsr      PreXfr              to pre-transfer stuff
+               bcs       logex               branch if error
+               IFNE      HDBDOS
+               lda       V.HDBPart,u         HDB-DOS partition?
+               beq       h@
+* HDB-DOS partition code path
+               sta       V.CchDirty,u        cache is dirty
+               lda       V.SectSize,u        get sector size (0=256,1=512,2=1024,3=2048)
+               leax      SCTTBL,pcr
+               lda       a,x
+               sta       V.Log2Phys,u        set logical sectors per phys
+               lda       V.LogSect,u
+               sta       V.PhysSect,u
+               ldd       V.LogSect+1,u
+               std       V.PhysSect+1,u
+               bsr       AddSectorOffset     add in partition offset and HDB-DOS drive
+               lbsr      ComputeHDB          and compute HDB-DOS offset
+               ldx       PD.BUF,y            get path desc buffer
+               stx       V.CchPSpot,u        we write directly from PD.BUF
+               bra       writeit
+               ENDC      
+* New: Dec 20, 2011
+* Fast path opportunity: if sector size is 256 bytes, call LLRead right into PD.BUF
+h@
+               tst       V.SectSize,u        (0=256 byte sector device)
+               beq       Write256
+               lbsr      ValidateCache
+               bcs       logex
+* Copy appropriate 256 byte sector from PD.BUF,y to V.CchAddr,u
+* Determine where in the cache we copy this 256 byte sector
+               bsr       Log2Phys            compute physical sector from logical sector
+               lda       V.CchSize,u         get hi byte of cache size
+               deca      
+               anda      V.LogSect+2,u
+               clrb      
+               ldx       V.CchAddr,u
+               leax      d,x
+               stx       V.CchLSpot,u        save for possible verify later
+               pshs      y                   save path desc for now
+               ldy       PD.BUF,y
+               IFNE      H6309
+               ldw       #256
+               tfm       y+,x+
+               puls      y
+               ELSE      
+               clr       ,-s
+loop@          ldd       ,y++
+               std       ,x++
+               inc       ,s
+               bpl       loop@
+               puls      a,y
+               ENDC      
+* Now that sector is copied, determine where in cache we start
+               lda       V.LogSect+2,u       get logical sector bits 7-0
+               leax      MASKTBL,pcr         point to base of cache
+               ldb       V.SectSize,u        get sector size in B
+               anda      b,x
+               pshs      a
+               lda       V.CchSize,u         get upper 8 bits of cache size
+               deca      
+               anda      ,s+
+               clrb      
+               ldx       V.CchAddr,u         point to base of cache
+               leax      d,x
+               stx       V.CchPSpot,u
+* Call low-level driver write routine
+writeit        lda       #$01
+               sta       V.SectCnt,u
+               ldx       V.LLWrite,u
+               lbsr      LLCall
+* If verify flag is on, read back and compare
+               tst       PD.VFY,y            verify flag set?
+               bne       ex@                 if so, we don't verify -- just exit
+* Read back physical sector into cache
+               tst       V.HDBPart,u         HDB-DOS partition?
+               beq       o@
+* If in HDB-DOS mode, we simply place the base address of the cache into 
+* V.CchPSpot... and V.CchLSpot for later verify
+               ldx       V.CchAddr,u
+               stx       V.CchPSpot,u
+               stx       V.CchLSpot,u
+o@             lda       #$01
+               sta       V.SectCnt,u
+               ldx       V.LLRead,u
+               lbsr      LLCall
+* Now compare PD.BUF to sector in cache just re-read         
+               ldx       V.CchLSpot,u        get spot in cache where 256 byte sector is.
+               ldy       PD.BUF,y            get pointer to buffer
+               clra      
+a@             ldb       ,x+                 get byte in cache
+               cmpb      ,y+                 compare against byte in PD.BUF
+               bne       err@
+               deca      
+               bne       a@
+ex@            clrb      
+               rts       
+err@           comb      
+               ldb       #E$Write
+               stb       V.CchDirty,u        make cache dirty due to error
+               rts       
+
+*
+* Init
+*
+* Entry:
+*    Y  = address of device descriptor
+*    U  = address of device memory area
+*
+* Exit:
+*    CC = carry set on error
+*    B  = error code
+*
+Init           pshs      y                   save device descriptor ptr on stack
+               ldb       #DrvCount           get maximum drives supported
+               stb       V.NDRV,u            save in our device memory
+               leax      DRVBEG,u            point X to the drive tables
+               lda       #$FF
+* Invalidate V.NDRV drive tables
+drvx           sta       DD.TOT,x
+               sta       DD.TOT+1,x
+               sta       DD.TOT+2,x
+               leax      DRVMEM,x            point to next drive table
+               decb                          decrement counter
+               bne       drvx                if not zero, continue
+* Link to low-level driver
+               ldd       IT.LLDRV,y          point to name in descriptor
+               leax      d,y                 point to name in descriptor
+               pshs      u
+               IFGT      Level-1
+               ldd       D.Proc              get curr proc ptr
+               pshs      d                   save on stack
+               ldd       D.SysPrc            get system process desc ptr
+               std       D.Proc              and make current proc
+               ENDC      
+               lda       #Sbrtn+Objct
+               os9       F$Link              link to it
+               IFGT      Level-1
+               puls      x                   get curr proc ptr
+               stx       D.Proc              restore
+               ENDC      
+               tfr       u,x                 transfer module address to X
+               puls      u                   restore U
+               leau      UOFFSET,u
+               bcs       ret@
+               stx       V.LLAddr,u          else save module address
+* setup entry points to low-level module
+               leax      V.LLInit,u
+               lda       #6                  number of entry points
+l@             sty       ,x++
+               leay      3,y
+               deca      
+               bne       l@
+* Call low-level driver init
+               ldy       ,s                  grab path desc ptr
+               ldx       V.LLInit,u
+               lbsr      LLCall
+               bcc       r@
+ret@           puls      y,pc
+* Allocate cache memory
+r@             lda       IT.TYP,y            get type byte
+               anda      #TYPH.SSM           mask out all but sector size
+* Added Dec 20, 2011: save off to V.SectSize (never got initialized until now!)
+               sta       V.SectSize,u        clear out V.SectSize
+               puls      y
+* Fall through to ExpandCache
+
+* Entry: A = cache size to expand to (1 = 512, 2 = 1024, 3 = 2048)
+* Exit:  D is destroyed
+* Note: any previously allocated cache memory must have been
+* freed before this call!
+* 
+ExpandCache              
+               pshs      a,x
+               leax      CCHTBL,pcr
+               lda       a,x                 get 1, 2, 4 or 8 
+               sta       V.CchDirty,u        make cache dirty since we will expand it
+               clrb      
+               std       V.CchSize,u         save cache size (256, 512, 1024 or 2048)
+               tfr       u,x
+               os9       F$SRqMem            allocate cache memory
+               stu       V.CchAddr,x         save cache ptr
+               tfr       x,u                 restore mem pointer
+ex@            puls      a,x,pc
+
+
+CCHTBL         FCB       256/256
+               FCB       512/256
+               FCB       1024/256
+               FCB       2048/256
+
+MASKTBL        FCB       $07,$06,$04,$00
+
+               EMOD      
+eom            EQU       *
+               END       
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/level1/modules/superdesc.asm	Thu Dec 22 18:23:47 2011 +0000
@@ -0,0 +1,206 @@
+********************************************************************
+* SuperDesc - Super Driver Device Descriptor Template
+*
+* $Id$
+*
+* RBSuper Defined Offsets
+*
+* IT.STP (offset $14)
+*  Bit Meaning
+*  --- ---------------------------------------------------------------
+*  7-0 HDB-DOS Drive Number (useful only if HDB-DOS bit set in IT.DNS)
+* 
+* IT.TYP (offset $15)
+*  Bit Meaning
+*  --- ---------------------------------------------------------------
+*  7   Hard Disk:  1 = hard disk
+*  6   Fudge LSN0: 0 = OS-9 disk, 1 = non-OS-9 disk
+*  5   Undefined
+*  4   Drive Size Query (1 = yes, 0 = no)
+*  2-3 Undefined
+*  0-1 Sector Size (0 = 256, 1 = 512, 2 = 1024, 3 = 2048)
+* 
+* IT.DNS (offset $16) for SCSI Low Level Driver
+*  Bit Meaning
+*  --- ---------------------------------------------------------------
+*  5-7 SCSI Logical Unit Number of drive (0-7) (ignored if bit 3 is 1)
+*  4   Turbo Mode:  1 = use accelerated handshaking, 0 = standard
+*  3   HDB-DOS Partition Flag
+*  0-2 SCSI ID of the drive or controller (0-7)
+* 
+* IT.DNS (offset $16) for IDE Low Level Driver
+*  Bit Meaning
+*  --- ---------------------------------------------------------------
+*  4-7 Undefined
+*  3   HDB-DOS Partition Flag
+*  1-2 Undefined
+*  0   IDE ID (0 = master, 1 = slave)
+*
+* Edt/Rev  YYYY/MM/DD  Modified by
+* Comment
+* ------------------------------------------------------------------
+*   0      2004/04/08  Boisy G. Pitre
+* Created.
+*
+*   0      2005/11/27  Boisy G. Pitre
+* Added IT.MPI value to descriptor.
+*
+*   0      2005/12/08  Boisy G. Pitre
+* Reserved two bits in IT.TYP for llscsi.
+
+               NAM       SuperDesc
+               TTL       Super Driver Device Descriptor Template
+
+* Super Driver specific fields
+ITDRV          SET       $00
+ITSTP          SET       $00
+ITTYP          SET       $81
+ITDNS          SET       $00
+
+ITSOFS1        SET       $00
+ITSOFS2        SET       $00
+ITSOFS3        SET       $00
+
+* Geometry for an EZ-135
+Sides          SET       $40
+Cyls           SET       $007f
+SectTrk        SET       $0020
+SectTrk0       SET       $0020
+Interlv        SET       $01
+SAS            SET       $08
+
+               IFP1      
+               USE       defsfile
+               USE       rbsuper.d
+               IFNE      IDE
+               USE       ide.d
+               ELSE
+               USE       scsi.d
+               ENDC      
+               ENDC      
+
+tylg           SET       Devic+Objct
+atrv           SET       ReEnt+rev
+rev            SET       $09
+
+               MOD       eom,name,tylg,atrv,mgrnam,drvnam
+
+               IFNE      CDROM
+               FCB       DIR.+SHARE.+PEXEC.+PREAD.+EXEC.+READ.
+               ELSE      
+               FCB       DIR.+SHARE.+PEXEC.+PREAD.+PWRIT.+EXEC.+UPDAT.
+               ENDC      
+               FCB       HW.PAGE             extended controller address
+               FDB       SDAddr              physical controller address
+               FCB       initsize-*-1        initilization table size
+               FCB       DT.RBF              device type:0=scf,1=rbf,2=pipe,3=scf
+               FCB       ITDRV               drive number
+               FCB       ITSTP               step rate
+               FCB       ITTYP               drive device type
+               FCB       ITDNS               media density
+               FDB       Cyls                number of cylinders (tracks)
+               FCB       Sides               number of sides
+               FCB       $01                 verify disk writes:0=on
+               FDB       SectTrk             # of sectors per track
+               FDB       SectTrk0            # of sectors per track (track 0)
+               FCB       Interlv             sector interleave factor
+               FCB       SAS                 minimum size of sector allocation
+               FCB       0                   IT.TFM
+               FDB       0                   IT.Exten
+               FCB       0                   IT.STOff
+* Super Driver specific additions to the device descriptor go here
+* NOTE: These do NOT get copied into the path descriptor; they
+*       cannot due to the fact that there is simply NO ROOM in
+*       the path descriptor to do so.  The driver must access
+*       these values directly from the descriptor.
+               FCB       ITSOFS1             (IT.WPC)
+               FCB       ITSOFS2             (IT.OFS)
+               FCB       ITSOFS3
+initsize       EQU       *
+               FDB       lldrv               (IT.RWC)
+               FCB       SDMPI               (IT.MPI)
+
+               IFNE      NULL
+name           FCC       /NULL/
+               FCB       ITDRV+$B0
+               ELSE      
+               IFNE      DD
+name           FCS       /DD/
+               ELSE      
+               IFNE      DRIVEWIRE
+name           FCC       /X/
+               IFNE      HB
+               FCS       /H/
+               ELSE      
+               FCB       ITDRV+$B0
+               ENDC      
+               ELSE      
+               IFNE      IDE
+name           FCC       /I/
+               IFNE      HB
+               FCS       /H/
+               ELSE      
+               FCB       ITDRV+$B0
+               ENDC      
+               ELSE      
+               IFNE      SD
+name           FCC       /SD/
+               IFNE      HB
+               FCS       /H/
+               ELSE      
+               FCB       ITDRV+$B0
+               ENDC      
+               ELSE      
+name           FCC       /S/
+               IFNE      HB
+               FCS       /H/
+               ELSE      
+               FCB       ITDRV+$B0
+               ENDC      
+               ENDC      
+               ENDC      
+               ENDC      
+               ENDC      
+               ENDC      
+
+mgrnam         FCS       /RBF/
+drvnam         FCS       /rbsuper/
+lldrv          EQU       *
+               IFNE      NULL
+               FCS       /llnull/
+               FCB       0
+               ELSE      
+               IFNE      DRIVEWIRE
+               FCS       /lldw/
+               FCB       0,0,0
+               ELSE      
+               IFNE      TC3+SB
+               FCS       /lltc3/
+               FCB       0,0
+               ELSE      
+               IFNE      KTLR
+               FCS       /llktlr/
+               FCB       0
+               ELSE      
+               IFNE      HDII+D4N1
+               FCS       /lldisto/
+               ELSE      
+               IFNE      IDE
+               FCS       /llide/
+               FCB       0,0
+               ELSE      
+               IFNE      SD
+               FCS       /llsd/
+               FCB       0,0,0
+               ENDC      
+               ENDC      
+               ENDC      
+               ENDC      
+               ENDC      
+               ENDC      
+               ENDC      
+
+
+               EMOD      
+eom            EQU       *
+               END       
--- a/level2/coco3/modules/makefile	Tue Oct 04 15:11:45 2011 +0000
+++ b/level2/coco3/modules/makefile	Thu Dec 22 18:23:47 2011 +0000
@@ -15,12 +15,15 @@
 CLOCKSOFT       = -aRTCSoft=1
 CLOCKMESSEMU    = -aRTCMessEmu=1
 CLOCKJVEMU      = -aRTCJVEmu=1
+TC3FLAGS        = $(AFLAGS) -aTC3=1 $(FLAGS)
+IDEFLAGS        = $(AFLAGS) -aIDE=1 $(FLAGS)
 
 DEPENDS		= ./makefile
-TPB		= ../../3rdparty/booters
+TPB		= $(3RDPARTY)/booters
 
 BOOTERS		= boot_1773_6ms boot_1773_30ms \
-		 boot_burke boot_rampak boot_wd1002 boot_dw3 boot_dw3_becker
+		 boot_burke boot_rampak boot_wd1002 boot_dw3 boot_dw3_becker \
+		boot_tc3 boot_ide
 BOOTTRACK	= rel_32 rel_40 rel_80 rel_32_50hz rel_40_50hz rel_80_50hz $(BOOTERS) krn
 KERNEL		= krnp2 krnp3_perr krnp4_regdump
 SYSMODS		= ioman init sysgo_h0 sysgo_dd
@@ -38,8 +41,11 @@
 		ddd0_35s.dd ddd0_40d.dd ddd0_80d.dd \
 		rammer.dr r0_8k.dd r0_96k.dd r0_128k.dd r0_192k.dd \
 		ddr0_8k.dd ddr0_96k.dd ddr0_128k.dd ddr0_192k.dd md.dd \
-		ddx0.dd x0.dd x1.dd x2.dd x3.dd
-		
+		ddx0.dd x0.dd x1.dd x2.dd x3.dd \
+		rbsuper.dr lltc3.dr llide.dr \
+		ddi0_ide.dd i0_ide.dd i1_ide.dd ih_ide.dd \
+		dds0_tc3.dd s0_tc3.dd s1_tc3.dd s2_tc3.dd s3_tc3.dd s4_tc3.dd \
+		s5_tc3.dd s6_tc3.dd sh_tc3.dd
 
 SCF		= scf.mn \
 		vtio.dr vrn.dr scbbp.dr scbbt.dr scdwp.dr sspak.dr sc6551.dr \
@@ -86,21 +92,40 @@
 	$(CP) kernel/$@ .
 
 # Special cases
+# TC^3 SCSI Booter
+boot_tc3: boot_scsi.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS)
+
+# SuperIDE/Glenside IDE Booter
+boot_ide: boot_ide.asm
+	$(AS) $(ASOUT)$@ $< $(IDEFLAGS)
+
+# DriveWire 3 Becker Booter
 boot_dw3_becker: boot_dw3.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aBECKER=1
 
+# DriveWire 3 Becker Submodule
 dw3_becker.sb: dw3.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aBECKER=1
 
+# CoGrf/CoVDG Modules
 cogrf.io: cowin.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aCoGrf=1
 
+covdg.io: covdg.asm
+	$(AS) $(AFLAGS) $(ASOUT)$@ $< -aCOCO2=1
+
+covdg_small.io: covdg.asm
+	$(AS) $(AFLAGS) $(ASOUT)$@ $<
+
+# Disto SC-II Drivers
 rb1773_scii_ff74.dr:    rb1773.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aSCII=1
                                                                             
 rb1773_scii_ff58.dr:    rb1773.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aSCII=1 -aSCIIALT=1
                                                                             
+# REL Modules
 rel_32: rel.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aWidth=32
 
@@ -119,18 +144,28 @@
 rel_80_50hz: rel.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aWidth=80 -aTkPerSec=50
 
+# Floppy Booters
 boot_1773_6ms: boot_1773.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aSTEP=0
 
 boot_1773_30ms: boot_1773.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aSTEP=3
 
+# SysGo Modules
 sysgo_dd: sysgo.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aDD=1
 	
 sysgo_h0: sysgo.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS)
 	
+# TC^3 SCSI Driver
+lltc3.dr: llscsi.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS)
+
+# IDE Driver
+llide.dr: llide.asm
+	$(AS) $(ASOUT)$@ $< $(IDEFLAGS)
+
 # Floppy descriptors
 SSDD35		= -aCyls=35 -aSides=1 -aSectTrk=18 -aSectTrk0=18 \
 		-aInterlv=3 -aSAS=8 -aDensity=1
@@ -268,6 +303,47 @@
 x3.dd: dwdesc.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aDNum=3
 
+# TC^3 SCSI Descriptors
+dds0_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(ID0) -aDD=1
+
+s0_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(ID0) $(SCSI_HD)
+
+s1_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(ID1) $(SCSI_HD)
+
+s2_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(ID2) $(SCSI_HD)
+
+s3_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(ID3) $(SCSI_HD)
+
+s4_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(ID4) $(SCSI_HD)
+
+s5_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(ID5) $(SCSI_HD)
+
+s6_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(ID6) $(SCSI_HD)
+
+sh_tc3.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(TC3FLAGS) $(HDBDOS)
+
+# IDE Descriptors
+ddi0_ide.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(IDEFLAGS) $(MASTER) -aDD=1
+
+i0_ide.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(IDEFLAGS) $(MASTER)
+
+i1_ide.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(IDEFLAGS) $(SLAVE)
+
+ih_ide.dd: superdesc.asm
+	$(AS) $(ASOUT)$@ $< $(IDEFLAGS) $(HDBDOS)
+
 # RFM descriptors
 ddy0.dd: rfmdesc.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aDD=1 -aDNum=0
@@ -284,13 +360,6 @@
 y3.dd: rfmdesc.asm
 	$(AS) $< $(ASOUT)$@ $(AFLAGS) -aDNum=3
 
-# VDGInt Modules
-covdg.io: covdg.asm
-	$(AS) $(AFLAGS) $(ASOUT)$@ $< -aCOCO2=1
-
-covdg_small.io: covdg.asm
-	$(AS) $(AFLAGS) $(ASOUT)$@ $<
-
 # Clocks
 clock_60hz: clock.asm
 	$(AS) $(AFLAGS) $(ASOUT)$@ $< -aPwrLnFrq=60