changeset 89:2727056db0d3

Updated to Curtis Boyle's latest IDE driver, works with L1 and L2
author boisy
date Thu, 27 Jun 2002 18:10:41 +0000
parents 93d2c224fa1f
children 6aa54d3691e5
files 3rdparty/drivers/ide/ccide.asm 3rdparty/drivers/ide/defsfile 3rdparty/drivers/ide/h0_ide.asm
diffstat 3 files changed, 1133 insertions(+), 201 deletions(-) [+]
line wrap: on
line diff
--- a/3rdparty/drivers/ide/ccide.asm	Sat Jun 01 09:15:08 2002 +0000
+++ b/3rdparty/drivers/ide/ccide.asm	Thu Jun 27 18:10:41 2002 +0000
@@ -1,4 +1,71 @@
+* NOTE: Currently, will return RAW error #'s from drive (see ATA bit flags
+*   in error register). After driver finalized, switch back to OS9 error
+*   codes.
+* NOTE 2: drvrbusy checks are done even before hardware access, because
+*  some variables are shared in the driver memory, and if a 2nd request
+*  comes in in the middle of it, the vars might be changed at a dangerous
+*  time. Note if you have two IDE controllers: since they get separate driver
+*  memory from each other, that both controllers CAN be active at the same
+*  time.
+* BIG NOTE ON OLDER ATA-1 DRIVES!!!
+* SOME DRIVES (MY MINISCRIBE 8051A INCLUDED) HAVE A TRANSLATION MODE THAT
+* _IS_BUILT_INTO_THE_IDE_ROM_ITSELF! THE BAD PART IS, THE "IDENTIFY DRIVE"
+* COMMAND _DOES_NOT_ TAKE THIS INTO CONSIDERATION, BUT RETURNS THE "NATIVE"
+* DRIVE SPECS FOR CYLINDERS, HEADS & SECTORS PER TRACK. TO GET THE FULL
+* CAPACITY OF THE DRIVE, WITHOUT ERRORS, YOU _MUST_ SET YOUR DEVICE
+* DESCRIPTOR BASED ON THE HARDWARE _TRANSLATED_ SETTINGS, _NOT_ THE _NATIVE_
+* SETTINGS (DESCRIBED IN THE IDENTIFY DRIVE COMMAND)! AS A REAL WORLD
+* EXAMPLE, ON MY MINISCRIBE 8051A:
+*   Drives "Native"  mode (as well as the Identify Drive command) returns:
+*     745 cylinders, 4 heads & 28 sectors/cylinder.
+*  HOWEVER, the "Translation" mode (which is checked off on the sticker on
+*    the drive itself from the manufacturer), says:
+*    Translated: 5 heads, 17 sectors. At this point, you will have to figure
+*      out the # of cylinders, by computing the # of sectors TOTAL for the
+*      drive in it's native mode (745*4*28 in the above example, or 83,440
+*      sectors), and then dividing that value by (# of sectors/track * # of
+*      heads) in the translation mode, and rounding down. In the above case,
+*      83,440/(5*17)=981.647, so use 981 (which in hex is $03d5).
+* Therefore, the proper device descriptor for this drive is:
+*  cyl=3d5 sid=5 sct=22 t0s=22  (Actually, t0s is ignored by CCIDE)
+*    The sct=22 is because the value is hexidecimal (it means 34 sectors/
+*    track), and is double the 17 I mentioned above because OS9 sectors are
+*    half the size of IDE sectors (256 bytes vs. 512 bytes). If this drive
+*    had been shipped in "Native" mode, it would use the following:
+*  cyl=2E9 sid=4 sct=38 t0s=38, which is what the IDENTIFY DRIVE command
+*    reports.
+* You can verify the highest cylinder # by setting the OFS in the descriptor
+*   to what you think is the highest cylinder # (total # of cylinders-1 ...
+*   remember that CHS cylinder numbers start at 0!), and then try to read
+*   enough sectors to cover the whole track. If you go one past that value,
+*   you should start getting errors if you have the right cylinder count.
+* This is kind of a dumb system, but I assume it had something to do with
+* IBM PC BIOS in the early days of IDE.
+*A LITTLE LATER, WHEN THE DRIVER IS STABLE, MAY WANT TO ADD ANOTHER BIT FLAG
+*  TO DRIVEFLG, SET UP BY A FIRST TIME READ: 8 BIT ACCEPTED. THEN, USE THE 8
+*  BIT TRANSFER MODE IF POSSIBLE (LIKE I DID WITH LBA). THIS SHOULD ALLOW
+*  MUCH FASTER SECTOR ACCESS ON A NITROS9 SYSTEM, AND IT WOULD BE INTERESTING
+*  TO SEE HOW MANY DRIVES ACCEPT THAT MODE (SUPPOSED TO RETURN AN 'ABORTED'
+*  FLAG IF IT DOES NOT).
+* NOTE: RBF WILL ASSIGN NEW DEVICE MEM (,U PTR) TO _EACH_ CONTROLLER ON IT'S
+*   OWN, BASED ON THE BASE ADDRESS FROM THE DEVICE DESCRIPTOR. THEREFORE,
+*   CCIDE SHOULD BE SET UP FOR _2_ DRIVES MAX (PER CONTROLLER), AND LET RBF
+*   TAKE CARE OF MULTIPLE CONTROLLERS.
+*    The exception to this is when using partitions; since they will have a
+*    separate descriptor for each partition, they will need a separate drive
+*    table entry. Each table entry is $26 (38) bytes each, so it is not a lot.
+*    Should make the device table fill up the rest of a 256 byte page (with
+*    all other variables allocated), since OS9 will force System RAM pages to
+*    even multiples of 256 anyways. Once full 8k block caching is implemented,
+*    some of the two 256 byte sector buffers currently in system RAM could be
+*    reused for more drive table entries as well. With current system RAM
+*    requirements in driver, this would allow 5 device table entries without
+*    taking any more system RAM then it is already. These can be shared in
+*    whatever combination you need for your (up to) 2 physical drives.
+* ALSO, RBF CALLS THE INIT ROUTINE ONLY ONCE PER _DRIVER_, NOT DRIVE!
 ********************************************************************
+* DO NOT FORGET TO SET H6309 FLAG IN DEFSFILE APPROPRIATELY FOR 6809 VS.
+*   6309 CODE WHEN ASSEMBLING!!
 * CCIDE - IDE device driver for CoCo
 *
 * $Id$
@@ -8,8 +75,11 @@
 *  Disassembled (OK, so I didn't have the source version at first!)
 *     by Eddie Kuns, ATA specs followed carefully and sector buffering
 *     on writes handled more carefully
-*
-*  This driver uses 16-bit transfers *only*
+* This driver uses 16-bit transfers *only*
+* Check with Glenside - can we switch to 16 bit only, so there is less to
+*   maintain? With the cacheing stuff, the speed is fairly decent, although
+*   some 6309 optomizations are still possible (cache copies, drive table
+*   copies, hardware divide for CHS translation, etc.)
 *
 * Ed.    Comments                                       Who YY/MM/DD
 * ------------------------------------------------------------------
@@ -17,32 +87,141 @@
 *        Added comments from 8 bit driver               BGP 99/05/07
 * 6      Driver now gets address from descriptor, made  BGP 99/05/10
 *        minor optimizations, added symbols
+* 7      Change to use real 16 bits                     LCB 99/09/06
+*        partitions (both LBA & CHS)                     to 99/10/31
+*        better error reporting
+*        slightly optomized read
+*        Half sector & LSN0 caches for current drive
+*        Auto-sense/run LBA & CHS modes
+*        Full CHS calculations (up to 4096 cylinders)
+*          for ATA-1 old drive compatibility
+* 8      Attempted to add support for removable media   LCB 00/05/27
+*         commands (Door Lock/Unlock, Acknowledge Media  to 00/??/??
+*         Change)
+*        Attempt 'generic' ATA command system call
+* Constants - change if needed
+* NUMDRIVE is LOGICAL drives (partitions), NOT physical drives-use 5,11,etc
+* 5=768 byte data area, 11=1024 byte data area
+NUMDRIVE equ   11       Max. # of device descriptors per controller address
+MAXWAIT  equ   60*5     Max. # clock ticks to give up on read/write (5 sec)
+HDSclPwr equ   2048     Set to 2048 as start ^2 cylinder (CHS translate)
 
-* Maximum number of drives to support
-NUMDRIVE equ   4
+* New definitions in Device Descriptor
+PartOfs  equ   $26      2 byte partition offset
+
+* Definitions for DD.DNS
+PhysDriv equ   %00000001  Physical drive # (0=Master, 1=Slave)
+ForceCHS equ   %00000010  Force driver to use CHS mode
+
+* New GetStat/SetStat calls:
+* SS.DrInf call shares call # with SS.ScInf from NitrOS9 WindInt (info)
+SS.DrInf equ   $8f      Drive info call (see routine for parms)
+* Subcall #'s fro SS.DrInf (Y register on entry)
+ATAIdent equ   0        ATA (handles ATAPI & plain ATA)
+
+* IDE & ATAPI Commands (ATAPI stuff not implemented yet, and LBA is mandatory)
+ReadRtry equ   $20      Read sector with retry
+WritRtry equ   $30      Write sector with retry
+Diagnost equ   $90      Execute drive diagnostic
+Identify equ   $EC      Identify drive command
+DoorLock equ   $DE      Lock drive
+DoorUnLk equ   $DF      Unlock (eject) drive
+AckMdChg equ   $DB      Acknowledge media change
+
+PIIdent  equ   $A1      Identify ATAPI drive command
 
+* IDE Status Register
+Busy     equ   %10000000 Drive busy (1=busy)
+DrvReady equ   %01000000 Drive ready (1=ready to accept command)
+WriteFlt equ   %00100000 Drive Write Fault (1=Write fault?)
+SeekDone equ   %00010000 Seek Complete (1=Seek complete)
+DataReq  equ   %00001000 Data Request (1=drive ready for read/write data)
+CorrData equ   %00000100 Corrected Data (1=correctable data error was done)
+Index    equ   %00000010 1=1 disk revolution completed
+ErrorFnd equ   %00000001 1=Error detected - see error register
+
+* IDE hardware offsets
+DataReg  equ   0         Data (1st 8 bits, non-latched)
+Error    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)
+
+* Special flags (Mini extra drive table - 1 byte per drive) - starts at
+*    DriveFlg,u
+* These are set by inquiring the drive, NOT from the descriptor
+* Should add a GETSTAT to allow user to access these for any drive
+Unused   equ   %10000000  Entry is un-initialized
+DrvMode  equ   %00000001  0=CHS mode, 1=LBA mode
+ATAPI    equ   %00000010  0=Device is ATA,1=Device is ATAPI
+Remove   equ   %00000100  0=Fixed Drive, 1=Removable media
+ReadOnly equ   %00001000  0=Read & write allowed, 1=Read only (CD-ROM)
+*                           Could also use to write-protect hard drive
          nam   CCIDE
          ttl   IDE device driver for CoCo
 
          ifp1
          use   defsfile
-         use   rbfdefs
          endc
 
 tylg     set   Drivr+Objct   
 atrv     set   ReEnt+rev
 rev      set   $01
-edition  equ   6
+edition  equ   8
 
          mod   eom,name,tylg,atrv,start,size
 
+* NOTE: OS9 WILL ALWAYS ASSIGN DRIVER MEM SPACE ON AN EVEN 256 BYTE PAGE,
+*   SO TAKE ADVANTAGE OF "EXTRA" SPACE!
+
          org   0
          rmb   DRVBEG+(DRVMEM*NUMDRIVE)
 * Start of driver-specific statics
+SlpCntr  rmb   2           # ticks left before we give up on a read/write
+PhysDrv  rmb   1           Physical drive # (for quick lookup)
+DriveFlg rmb   NUMDRIVE    1 byte per drive (bit flags)
 OS9LSN   rmb   3           LSN of current OS-9 256-byte sector
-Counter  rmb   1
+* IDE spec can handle 28 bits (4 bits of 4th byte) for LBA mode. Since OS9
+*   can't get that high anyways, we only work with 3, and then use the offset
+*   partition value to bump it up beyond the 4 GB mark.
+OS9PSN   rmb   3           PSN of current OS9 sector (512 byte)
+DrivMask rmb   1           Drive # (0 or 1) for IDE (in proper bit position)
 idecmd   rmb   1           1 byte IDE command code
-         rmb   20
+identcmd rmb   1           1 byte IDE Identify drive code
+
+* Following flag is because the IDE interface can NOT access a 2nd drive
+*   while the 1st drive is completing a read or write. Because of shared
+*   device memory variables, this flag is set even on cached entries.
+drvrbusy rmb   1           Driver busy flag (0=not busy)
+
+* Following for CHS mode drives only!
+Head     rmb   1           Head # (s/b base 0)
+Cylinder rmb   2           Cylinder #
+CHSSect  rmb   1           CHS mode sector #
+CHSSPT   rmb   2           CHS mode sectors/track
+
+* Buffer/cache variables
+LSN0Flag rmb   1           $FF=Not LSN0, $00=LSN0
+Sect0Drv rmb   1           Drive # of LSN0 currently buffered ($FF=none)
+Sect0Ofs rmb   2           Offset value for current LSN0 buffered drive
+TempHalf rmb   3           Temp spot to hold other half calculation
+HalfDrv  rmb   1           Drive # of HalfBuff buffered ($FF=none)
+HalfOfs  rmb   2           Offset value for drive for current cached sector
+HalfSct  rmb   3           OS9 sector # of half sector not asked for
+TempOfs  rmb   2           Temporary copy of partition offset
+
+* NOTE: When 8k block buffering is added, move both of these to that block.
+*   Of course, if removable media, re-read LSN0 physically every time. At that
+*   time, we should make tables here instead (32 entries per drive up to the
+*   maximum # of drives) of LSN #'s buffered (3 bytes/entry).
+Sect0    rmb   256         Buffer for LSN0
+HalfBuff rmb   256         Buffer for other half of 512 byte phys. sector
 size     equ   .
 
          fcb   $FF         mode byte
@@ -50,224 +229,968 @@
 name     fcs   /CCIDE/     module name
          fcb   edition     module edition
 
+* INIT - appears to only be called on 1ST try on ANY IDE device IF link counts
+*   are 0.
+* Y = address of path descriptor (but 
+* U = address of driver memory (ie, of V.PAGE)
+* Inits the drive table, and the DriveFlg table
+Init     ldd   #$8000+NUMDRIVE Flag that special drive flags are all unused
+         leax  DriveFlg,u
+DrvFlgLp sta   ,x+
+         decb
+         bne   DrvFlgLp
+GoInit   leax  DRVBEG,u      Point to start of drive tables
+         ldd   #$FF00+NUMDRIVE
+         stb   V.NDRV,u      Max # of drives
+         sta   Sect0Drv,u    Flag that no LSN0 is buffered
+         sta   HalfDrv,u     Flag that we have no half sector buffered
+NextDrv  sta   DD.TOT,x      Set Total # of sectors to illegal value
+         sta   V.TRAK,x      Non 0, so 1st seek can read Track 0
+         leax  DRVMEM,x      Point to next drive
+         decb                Dec # of drives left
+         bne   NextDrv       Still more, init them too
+         clrb                No error & return
+         rts
+
+* Do drive diagnostic (use CHS mode) - Do not worry about ATAPI at this point
+* Entry: U=driver mem ptr
+*        Y=path descriptor
+*        B=Identify command
+* Exit:  CC clear - drive ready to send info
+*        CC set   - error from drive, B contains raw error register
+* TRASHES X - does timeout (CHECK - WILL SOME DRIVES TAKE TOO LONG?)
+* This is called by INIT, and should also be called by a GETSTAT at some
+*  point.
+Ident    pshs  y             Save path descriptor
+         stb   identcmd,u    Save which Ident we are doing
+         ldy   V.PORT,u      Get IDE controller address
+DoIdent  lda   DrivMask,u    Get drive # requested
+         ora   #%10100000    Mask in head 0 & CHS mode
+         std   DevHead,y     Send drive/head to controller, and IDENTIFY
+* Note, if person booting from ROM, drive may not have spun up yet. See if
+*   we can check some sort of status or error flag that indicates drive is
+*   still firing up, if this is a problem.
+         ldx   #$a000        Arbitrary amount of time to give up
+WaitIdnt lda   Status,y      Get Status register
+         bmi   NoErr         Busy, drop counter
+         bita  #ErrorFnd     Error?
+         beq   NoErr         No, continue
+         ldb   Error,y       Get error code
+         bra   BadIdent
+
+NoErr    cmpa  #DrvReady+SeekDone+DataReq Drive ready to send Identify data?
+         beq   GotIdent      Yep, exit out
+         leax  -1,x          Drop timer
+         bne   WaitIdnt      Keep trying
+         ldb   #E$NotRdy     Timed out, device not ready error
+BadIdent coma                Flag error
+         puls  y,pc          Restore path descriptor & return
+
+GotIdent clrb                No error
+         puls  y,pc          Restore path descriptor & return
+
+* Send Identify drive command (ATA or ATAPI - see identcmd,u), update DriveFlg
+*   table
+* PLEASE NOTE: The 2 identify commands are mutually exclusive; it will fail
+*  with an 'Aborted' error if the wrong Identify is used.
+*  UNLIKE A NORMAL READ OF A SECTOR, THE INFORMATION CONTAINED IN THE IDENTIFY
+*  DRIVE COMMAND IS ALL IN INTEL ORDER WORD (16 BITS)
+* Entry: Y=Ptr to path descriptor
+*        U=Ptr to driver memory
+* X IS DESTROYED!
+* Exit:  CC=0 if DriveFlg properly updated
+*          & A=DriveFlg value from update entry in table
+*        CC=1, B=error if Identify Drive failed
+*        DriveFlg,u - the proper flags for the specified controller/drive are
+*                     updated
+*        Sect0 contains 1st 256 bytes, HalfBuff contains 2nd half
+IdentDrv lbsr  WaitDrv       Wait for IDE to be ready
+         ldb   #Identify
+         bsr   Ident         Send identify drive command to controller
+         bcc   DoInfo        Worked, Do info
+         bitb  #%00000100    Error, Aborted Flag set?
+         beq   ExitIdnt      No, exit with other error
+         ldb   #PIIdent      Try ATAPI identify
+         bsr   Ident
+         bcs   ExitIdnt      That didn't work either, abort
+DoInfo   leax  Sect0,u       Point to buffer
+* NOTE: INIT routine only gets called when the DRIVER is Initing...not every
+*   device. Hence, READ/WRITE must check the DriveFlg settings and make sure
+*   the hi bit is clear for the drive it is using, to indicate that it HAS
+*   been set properly from an Identify Drive command.
+* Read in 1st 256 bytes of Identify Drive buffer, parse out info we need
+*   for our special flag table
+         lbsr  Read256       Generic 256 byte copy from IDE routine
+         ldb   #$FF          Since we made it this far, flag that HalfBuff
+         stb   HalfDrv,u       & Sect0Drv are now bogus
+         stb   Sect0Drv,u
+         clra                Set current flags to all off
+         leax  Sect0,u       Point to start of buffer again
+         ldb   ,x            Get general config low byte
+         andb  #%10000000    Removable cartridge bit set?
+         beq   CheckLBA      No, check LBA mode
+         ora   #Remove       Set removable media flag
+CheckLBA ldb   99,x          Get LBA mode byte
+         andb  #%00000010    LBA allowed on this drive?
+         beq   ChkATAPI      No
+         ora   #DrvMode      Yes, set LBA flag
+ChkATAPI ldb   identcmd,u    Get Identify drive command type
+         cmpb  #PIIdent      ATAPI?
+         bne   SetFlg        No, set drive flags
+         ora   #ATAPI        Set ATAPI flag
+SetFlg   ldb   PD.DNS,y      Get special settings flags
+         bitb  #ForceCHS     Force CHS mode on?
+         beq   LeavAlon      No
+         anda  #^DrvMode     Yes, force to CHS mode
+LeavAlon ldb   PD.DRV,y      Get Logical drive #
+         leax  DriveFlg,u    Point to drive flags table
+         sta   b,x           Save flags
+         pshs  a             Save for exit
+         leax  HalfBuff,u    Point to 2nd buffer
+         lbsr  Read256       Identify info part 2
+         lbsr  WaitOK        Make sure drive finished command
+         puls  a             Restore flags byte
+ExitIdnt rts                 No error, return
+
+* Entry: U=driver memory ptr
+*        Y=path descriptor ptr
+GetStat  ldx   PD.RGS,y      Get ptr to callers register stack
+         lda   R$B,x         Get function code
+         cmpa  #SS.DrInf     Drive info command?
+         bne   NextGet       No, try next
+         ldd   R$Y,x         Get sub-function type
+         beq   GoodFunc
+         comb                Only sub-functions 0 allowed for IDE
+         ifeq  Level-2
+         ldb   #E$IllArg
+         else
+         ldb   #167
+         endc
+ExitGet  rts
+
+GoodFunc pshs  x,y,u         Preserve regs
+         bsr   IdentDrv      Get either ATA or ATAPI Identify info
+         bcc   GotInfo       Something wrong, return
+         puls  x,y,u,pc      Restore regs, return with error
+
+GotInfo  leay  Sect0,u       Point to start of 512 byte buffer
+         ldx   #256          # of two byte entries in buffer
+SwapLoop ldd   ,y            Swap all words to Motorola order
+         exg   a,b
+         std   ,y++
+         leax  -1,x
+         bne   SwapLoop
+         leay  Sect0,u       Point to start of buffer again
+         ldx   114,y         Get Current Capacity, swap to Motorola
+         ldd   116,y
+         stx   116,y
+         std   114,y
+         ldx   120,y         Get LBA sector count, swap to Motorola
+         ldd   122,y
+         stx   122,y
+         std   120,y
+         ifeq  Level-2
+         lda   <D.SysTsk     Get system task #
+         ldx   <D.Proc       Get user task ptr
+         ldb   P$Task,x      Get user's task #
+         leax  Sect0,u       Point to source buffer
+         ldu   ,s            Get ptr to PD.RGS
+         ldu   R$X,u         Get Destination ptr
+         ldy   #512          Move 512 bytes to caller
+         os9   F$Move
+         else
+         endc
+         puls  x,y,u         Restore regs to normal
+         bcc   SetUserR      No error, set exit registers for caller
+         rts
+
+SetUserR ldd   #512          # of bytes returned=512 (Callers Y)
+         std   R$Y,x
+         clrb                Device type=ATA
+         lda   identcmd,u    Get which Identify Drive command worked
+         cmpa  #PIIdent      ATAPI?
+         bne   SaveType      No, save ATA as type
+         incb
+SaveType lda   PD.DRV,y      Get logical drive #
+         leay  DriveFlg,u    Point to drive flag table
+         lda   a,y           Get drive flags
+         std   R$D,x         Save drive flags & device type
+         clrb
+         rts
+
+NextGet  comb
+         ldb   #E$UnkSvc
+         rts
+
+SetStat  clrb
+         rts
+
 start    lbra  Init
-         lbra  FRead
+         lbra  Read
          lbra  FWrite
          lbra  GetStat
          lbra  SetStat
-         lbra  Term
-*
-* INIT
-*
-* Y = address of path descriptor
-* U = address of device memory (ie, of V.PAGE)
-*
-Init     ldx   #$1500        delay loop value
-         ldy   V.PORT,u
-RdyIni1  tst   7,y           Wait for drive ready
-         bpl   GoInit
-         leax  -1,x
-         bne   RdyIni1
-         lbeq  ENotRdy       Timed out ... give up on drive
+         clrb               Term routine (does nothing)
+         rts
+
+NotBsy   lda   #$FF
+         sta   drvrbusy,u
+         rts
+
+* Checks if driver is busy, retries & possibly sleeps if it is.
+* Set's driver to busy again when done.
+* A reg is destroyed, all others are preserved
+ChekBusy lda   #64            # of fast retries for driver
+BsyTst   tst   drvrbusy,u     Is current driver/controller already in use?
+         beq   NotBsy         No, continue
+         deca
+         bne   BsyTst         Try up to 64 times
+         pshs  x              Otherwise, sleep a tick & try again
+         ldx   #1
+         os9   F$Sleep
+         puls  x
+         bra   ChekBusy
 
-GoInit   ldd   #$AF20        Drive is ready -- initialize
-* For IDE command $91, DrvHd reg = 101xhhhh binary
-         sta   6,y           $10 heads       (x=0-master/1-slave; hhhh=#heads)
-         stb   2,y           $20 sectors/track
-         lda   #$91 
-         sta   7,y           Give drive the Init Drive Parameters IDE command
-RdyIni2  tst   7,y
-         bmi   RdyIni2       Wait *forever* until drive is ready
+* Save OS9 LSN & Physical PSN (not including any partition offset)
+* Also saves sector # of other half that is buffered
+* Will have to add check later for ATAPI stuff, up to 2048 bytes/sector
+*   for CD ROM
+* Entry: U=ptr to driver mem
+*        B:X=OS9 LSN
+* Exit:  B:X=OS9 LSN
+*      OS9PSN updated (512 byte Physical sector # that IDE needs)
+*      TempHalf updated to cached LSN # (Use HalfDrv to figure out if legit
+*        or not)
+*      TempOfs updated to current partition offset
+*      Zero flag set if LSN0 was requested (also saved at LSN0Flag,u)
+*      PhysDrv set to physical drive #
+SavLSN   pshs  b,x          Save work copy of LSN
+         lda   PD.DNS,y     Make copy of physical drive #
+         anda  #PhysDriv
+         sta   PhysDrv,u
+         clra               Flag: LSN0
+         stb   OS9LSN,u     Save OS-9 LSN
+         beq   dox          Could be LSN0
+         inca               Not LSN0
+dox      stx   OS9LSN+1,u
+         beq   doPSN        Is LSN0
+         inca               Not LSN0
+doPSN    sta   LSN0Flag,u   Save LSN0 flag (0=Yes, anything else, no)
+         stb   OS9PSN,u     Save OS-9 PSN
+         stx   OS9PSN+1,u
+         lsr   OS9PSN,u     Divide LSN by 2 for PSN (512 bytes/sector)
+         ror   OS9PSN+1,u
+         ror   OS9PSN+2,u
+         bcc   Even         Even sector requested, half will be odd (+1)
+* Subtract 1 from current LSN
+         ldd   1,s
+         subd  #1
+         std   1,s
+         ldb   ,s
+         sbcb  #0
+         bra   SaveExit
 
-* Initialize drive table (only first is inited here)
-         leax  DRVBEG,u
-         lda   #1
-         sta   V.NDRV,u
-         lda   #$FF
-         sta   DD.TOT+2,x
-         sta   V.TRAK,x
-
-GetStat
-SetStat
-Term     clrb
+* Add 1 to current LSN
+Even     ldd   1,s
+         addd  #1
+         std   1,s
+         ldb   ,s
+         adcb  #0
+SaveExit ldx   1,s
+         stb   TempHalf,u   Save buffered sector #
+         stx   TempHalf+1,u
+         leas  3,s          Eat temp stack
+         ldx   PD.DEV,y     Get ptr to device table entry
+         ldx   V$DESC,x     Get device descriptor ptr
+         ldx   PartOfs,x    Get partition offset value
+         stx   TempOfs,u    Save copy of it
+         ldb   OS9LSN,u     Restore LSN
+         ldx   OS9LSN+1,u
+         lda   LSN0Flag,u   Set CC bits for LSN0 compare
          rts
 
-SavLSN   stb   OS9LSN,u     Save OS-9 LSN
-         stx   OS9LSN+1,u
-         rts   
-*
 * READ
-*
-* Y = address of path descriptor
-* U = address of device memory (ie, of V.PAGE)
-* B = MSB of OS-9 disk LSN
-* X = LSB of OS-9 disk LSN
-*
-FRead    bsr   SavLSN
-         ldb   #$20
-         lbsr  SetIDE
-         bcs   Ret
-         ldx   PD.BUF,y
-         lda   #$20
-         sta   Counter,u
-         pshs  y
-         ldy   V.PORT,u
-ReadLp   lda   ,y
-         ldb   ,y
-         std   ,x++
-         lda   ,y
-         ldb   ,y
-         std   ,x++
-         lda   ,y
-         ldb   ,y
-         std   ,x++
+* Entry: Y = address of path descriptor
+*        U = address of device memory (ie, of V.PAGE)
+*        B = MSB of OS-9 disk LSN
+*        X = LSB of OS-9 disk LSN
+* Eventually change LSN stuff to use a bit from descriptor as to whether
+*   buffered LSN0 or not. (After that, add in for general 8k block buffering
+*   or not).
+* Later, add check for DriveFlg that sees if device has removable media. If
+*   not, and caching for each logical drive is done, keep PERMANENT copy of
+*   LSN0 at all times, and just copy it when requested (WRITE will update copy
+*   if new LSN0 is written).
+* MAKE SURE WRITE ROUTINE UPDATES CACHING STUFF CORRECTLY!
+Read     lbsr  ChekBusy       Wait for driver to be unbusy
+         bsr   SavLSN         Save LSN/PSN, PartOfs & HalfSect info
+         bne   NotLSN0        Not LSN0, skip ahead
+* Theoretically, following REM'ed out lines will handle removable media:
+*         lda   DriveFlg,u     Get drive flag settings
+*         bita  #Remove        Removable media?
+*         bne   NotLSN0        Yes, LSN0 may change from disk swap
+
+* LSN0 - 1st see if buffered
+         lda   PhysDrv,u      Get requested physical drive #
+         cmpa  Sect0Drv,u     Same drive in LSN0 cache?
+         bne   PhysRead       No, go physically read off of drive
+         ldx   TempOfs,u      Get copy of partition offset
+         cmpx  Sect0Ofs,u     Same as cached LSN0 offset?
+         bne   PhysRead       No, physically read the sector
+* LSN0 buffered goes here - later add check against DriveFlg with removable
+*   media bit - if non-removable, copy from cache, otherwise to physical read
+         leax  Sect0,u        Point to LSN0 cache
+         bra   CopyBuff       Copy to caller's PD.BUF, exit from there
+
+* Not LSN0 - see if normal sector is currently cached.
+* Entry: B:X=LSN
+NotLSN0  cmpb  HalfSct,u      Same as cached sector?
+         bne   PhysRead
+         cmpx  HalfSct+1,u    Same as cached sector?
+         bne   PhysRead
+         lda   PhysDrv,u      Same drive as cached?
+         cmpa  HalfDrv,u
+         bne   PhysRead       No, need physical read of sector
+         ldd   TempOfs,u      Get current request's Partition offset
+         cmpd  HalfOfs,u      Same as cached?
+         bne   PhysRead       No, physical read of sector
+* Non-LSN0 sector is cached - if removable drive, force physical read unless
+*   we somehow monitor disk swaps (some media require Eject commands)
+         leax  HalfBuff,u     Point to cached sector
+* Copy sector from cache buffer to caller's buffer
+* Entry: X=Ptr to cache buffer (either Sect0, or HalfBuff)
+CopyBuff clrb                 256 counter
+         ldy   PD.BUF,y       Point to caller's buffer
+CpyLoop  lda   ,x+            Copy it
+         sta   ,y+
+         decb
+         bne   CpyLoop
+         clr   drvrbusy,u     Flag driver not busy
+         rts
+
+* Not buffered in any way - physical read required - update cache tags AFTER
+*   read, or flag with $FF if failed.
+* Entry: Y=Ptr to path descriptor
+*        U=Driver mem
+PhysRead lbsr  InitRead       Tell IDE to read sector
+         bcc   DoRead         No error, do read
+FlagBad  lda   #$FF           If IDE can't even initiate read, flag both
+         sta   Sect0Drv,u     LSN0 and HalfBuff as bad
+         sta   HalfDrv,u
+         lbra  RprtErr
+
+* Entry: Y=path dsc. ptr
+*        U=Driver mem ptr
+DoRead   lda   OS9LSN+2,u     Get LSB of OS9 sector #
+         lsra                 Shift 1/2 512 sector flag out
+         bcs   DoOdd          Odd sector, buffer even one 1st
+         ldx   PD.BUF,y       Get pointer to caller's buffer
+         bsr   Read256        Copy 1st half of HD sector there
+         leax  HalfBuff,u     Point to cache buffer
+         bsr   Read256        Copy 2nd half of HD sector there
+         bra   FinRead        Finish the Read command on IDE
+
+* Copy to cache 1st (Odd sector # request)
+DoOdd    leax  HalfBuff,u   Point to cache buffer
+         bsr   Read256      1st half goes there
+         ldx   PD.BUF,y     Get pointer to caller's buffer
+         bsr   Read256      2nd half goes there
+FinRead  lbsr  WaitOK       Wait for drive to complete command
+         bcc   DoneRead     No error, exit
+         lbra  RprtErr      Exit with error
+
+* Update HalfSct vars to whatever is in TempHalf
+GoodCach ldd   TempHalf,u     Copy Buffered LSN to HalfSct
+         std   HalfSct,u
+         lda   TempHalf+2,u
+         sta   HalfSct+2,u
+         ldd   TempOfs,u      Get partition offset
+         std   HalfOfs,u      Save it
+         lda   PhysDrv,u      Copy drive # to HalfDrv
+         sta   HalfDrv,u
+         rts
+
+* Entry: Read command complete on IDE.
+*   Y=ptr to path descriptor
+*   U=ptr to driver mem
+DoneRead bsr   GoodCach       Update HalfSct stuff with Temp stuff
+         ldb   LSN0Flag,u     Was this LSN0?
+         bne   GoodExit       No, leave
+* LSN0 just physically read - update drive table
+* CHANGE EVENTUALLY TO CHECK IF NON-REMOVABLE MEDIA; IF IT IS, DON'T BOTHER
+*   WITH THESE CHECKS!
+         sta   Sect0Drv,u     Save which drive LSN0 is buffered
+         ldd   TempOfs,u      Restore partition offset again
+         std   Sect0Ofs,u     Save for LSN0
+         leax  Sect0,u        Point to LSN0 buffer
+         clrb                 256 counter
+         pshs  y              Save path dsc. ptr
+         ldy   PD.BUF,y       Point to caller's buffer
+LSN0Loop lda   ,y+            Copy LSN0 from callers buffer to LSN0 cache
+         sta   ,x+
+         decb
+         bne   LSN0Loop
+         puls  y              Restore path dsc. ptr
+         leax  Sect0,u        Point to LSN0 cache again
+CopyTbl1 lbsr  CpyDrvTb       Copy LSN0 stuff to drive table
+GoodExit clr   drvrbusy,u     No error & return
+         rts
+
+* Initiate the 512 byte READ sequence
+* Entry: U=Driver mem ptr
+*        Y=Path dsc. ptr (?)
+* Exit:  CC=0 if no error
+*        CC=1 if error
+*            B=Error code
+InitRead ldb   #ReadRtry      Read sector (with retry) IDE command
+         lbra  SetIDE         Send to IDE, return from there (w or w/o err)
+
+* Copy 256 bytes of data from IDE controller (after READ, etc.)
+* Entry: X=ptr to 256 byte destination buffer
+*        U=ptr to driver memory
+* Exit: 256 bytes copied
+*        B is destroyed, A=0
+*        Y is preserved
+Read256  lda   #$20           # of loops (of 8 bytes)
+         pshs  y,a            Save y & counter
+         ldy   V.PORT,u       Get ptr to IDE controller for this drive
+ReadLp   lda   ,y             Get 16 bits of data, and save in buffer, 8
+         ldb   Latch,y          times
+         std   ,x
          lda   ,y
-         ldb   ,y
-         std   ,x++
-         dec   Counter,u
-         bne   ReadLp
-         puls  y
-
-         ldx   OS9LSN+1,u     Is this LSN 0?
-         bne   NotLSN0
-         ldb   OS9LSN,u
-         bne   NotLSN0
-         ldx   PD.BUF,y
+         ldb   Latch,y
+         std   2,x
+         lda   ,y
+         ldb   Latch,y
+         std   4,x
+         lda   ,y
+         ldb   Latch,y
+         std   6,x
+         leax  8,x            Bump ptr up
+         dec   ,s             Done all bytes?
+         bne   ReadLp         No, keep going
+         puls  a,y,pc         Restore Y & return
 
-         pshs  y            Yes, it is LSN 0
-         lda   #DD.SIZ      Copy useful information to our LSN 0 buffer
-         leay  DRVBEG,u
-LSN0Cp   ldb   ,x+
-         stb   ,y+
-         deca  
-         bne   LSN0Cp
-         puls  y            Done with LSN 0 stuff
-
-NotLSN0  bsr   WaitOK       Wait for drive to complete command
-         bcc   Ret 
-         lbra  ReadErr
-Ret      rts
-
-*
-* WRITE
-*
+* WRITE - Can use cache data, or preread sector
 * Y = address of path descriptor
 * U = address of device memory (ie, of V.PAGE)
 * B = MSB of OS-9 disk LSN
 * X = LSB of OS-9 disk LSN
-*
-FWrite   lbsr  SavLSN       Save LSN info
-*
-*  *** HACK *** Read the 2 sectors into our buffer first
-*
-         ldb   #$30         IDE Read w/ Retry command
-         lbsr  SetIDE       Setup IDE command registers
-         bcs   ReadDone
-         pshs  y
-         ldx   PD.BUF,y
-         lda   #$20
-         sta   Counter,u
-         ldy   V.PORT,u
-HackLp   ldd   ,x++
+* 1st , see if other half is buffered in HalfBuff
+FWrite   lbsr  ChekBusy     Wait for driver to be unbusy
+         lbsr  SavLSN       Save LSN info, set LSN0Flag for later
+         ldb   TempHalf,u   Get OS9 LSN of 'other half' of 512 byte sector
+         cmpb  HalfSct,u    Same MSB of buffered sector #?
+         bne   ChkLSN1      No, check if LSN1
+         ldx   TempHalf+1,u LSW of 'other half'
+         cmpx  HalfSct+1,u  Same as LSW of buffered sector #?
+         bne   ChkLsn1      No, check if LSN1
+         ldd   HalfOfs,u    Same partition as buffered sector's drive?
+         cmpd  TempOfs,u
+         bne   ChkLsn1      No, check if LSN1
+         lda   PhysDrv,u    Same physical drive as buffered sector's drive?
+         cmpa  HalfDrv,u    Same as buffered sector's drive?
+         bne   ChkLsn1      No, check is LSN1
+* Buffered sector IS the other half of current write sector...no preread nec-
+*   essary.
+         lbsr  InitWrit     Send Write command to IDE, setup mode, etc.
+         bcc   GoodWrit     No problems, continue with Write
+         lbra  FlagBad      Flag caches as bad, exit with error
+
+* See if request is for LSN1, in which case we may have LSN0 buffered
+ChkLSN1  ldb   OS9LSN,u     Get MSB of sector to write
+         bne   PreRead      Not 0, need physical preread
+         ldx   OS9LSN+1,u   Get LSW of sector to write
+         cmpx  #1           LSN=1?
+         bne   PreRead      Not LSN1, need to preread sector
+         lda   PhysDrv,u    Get physical drive #
+         cmpa  Sect0Drv,u   Same as buffered LSN0?
+         bne   PreRead      No, need physical preread
+         ldd   TempOfs,u    Get partition offset of requested sector
+         cmpd  Sect0Ofs,u   Same as buffered?
+         bne   PreRead
+* We have LSN0 buffered for an LSN1 write
+         lbsr  InitWrit     Send Write to IDE
+         bcc   ContWrt1     Successful, continue
+         lbra  RprtErr
+
+ContWrt1 leax  Sect0,u      Point to buffered Sector 0
+         bsr   Write256     Write to IDE
+         ldx   PD.BUF,y     Get ptr to caller's LSN1 buffer
+         bsr   Write256     Write to IDE
+         bra   FinWrite     Complete the write command
+
+* Nothing buffered, pre-read sector in so we have other half to write.
+* Note that OS9PSN is already set to the correct physical sector.
+PreRead  lbsr  InitRead     Send Read command to IDE
+         bcc   GotPreRd     No problem, continue
+         lbra  FlagBad      Flag caches as bad; exit with error
+
+GotPreRd lda   OS9LSN+2,u   Get least sig. byte of LSN to write
+         lsra               Odd or even sector?
+         bcc   ReadOdd      Even write sector requested
+* Odd write requested
+         leax  HalfBuff,u   Point to 1/2 sector cache
+         lbsr  Read256      Read it in
+         bsr   Eat256       Bleed off other half (not needed)
+         bra   FinPre
+
+* Even sector to write - buffer odd one
+ReadOdd  bsr   Eat256       Bleed 1st half
+         leax  HalfBuff,u   Read in 2nd half
+         lbsr  Read256
+FinPre   lbsr  WaitOK       Get OK from controller
+         bcc   DonePre      Good, continue
+BadExit  lbra  RprtErr      Error, exit with it
+
+DonePre  lbsr  GoodCach     Update HalfSct stuff only
+         lbsr  InitWrit     Initialize Write command
+         bcs   BadExit
+* Now, onto the write
+GoodWrit ldb   OS9LSN+2,u   Get least sig. byte of LSN
+         lsrb               Odd or even sector to write?
+         bcs   BuffWOdd     Write fully buffered Odd
+* We are writing even portion, odd is in cache
+         ldx   PD.BUF,y     Get ptr to caller's 256 byte buffer
+         bsr   Write256     Write to IDE
+         leax  HalfBuff,u   Point to cached sector
+         bsr   Write256     Write to IDE
+         bra   FinWrite
+
+BuffWOdd leax  HalfBuff,u   Point to cached sector
+         bsr   Write256     Write to IDE
+         ldx   PD.BUF,y     Point to caller's 256 byte buffer
+         bsr   Write256     Write to IDE
+FinWrite lbsr  WaitOK       Wait for IDE to be done command
+         bcc   DoneWrit     No error, done writing
+         lbra  RprtErr      Error, exit with it
+
+* Write 256 bytes from ,x to IDE
+* Entry: X=ptr to 256 buffer to write
+*        U=driver mem ptr
+* Exit: 256 bytes written
+*        B is destroyed, A=0
+*        X=end of buffer+1
+*        Y is preserved
+Write256 lda   #$20         # of 8 byte loops
+         pshs  y,a          Save Y & loop counter
+         ldy   V.PORT,u     Get IDE base address
+WritLp   ldd   ,x           Copy 256 bytes from buffer to IDE
+         stb   Latch,y
          sta   ,y
-         stb   ,y
-         ldd   ,x++
+         ldd   2,x
+         stb   Latch,y
          sta   ,y
-         stb   ,y
-         ldd   ,x++
+         ldd   4,x
+         stb   Latch,y
          sta   ,y
-         stb   ,y
-         ldd   ,x++
+         ldd   6,x
+         stb   Latch,y
          sta   ,y
-         stb   ,y
-         dec   Counter,u
-         bne   HackLp
-         puls  y
-         bsr   WaitOK       Wait for drive to finish command
-         bcc   ReadDone      
-         lbsr  WriteErr
-ReadDone rts
-*
+         leax  8,x
+         dec   ,s
+         bne   WritLp
+         puls  a,y,pc       Restore regs & return
+
+* Eat 256 bytes from IDE (hopefully, triggering latch will skip having to
+*  read even bytes)
+* Entry: U=driver memory ptr
+*        Y=Path descriptor ptr
+* Exit: 256 bytes bled off of sector buffer on IDE
+* All regs preserved
+Eat256   pshs  d,x          Save regs
+         ldb   #$20         32 loops
+         ldx   V.PORT,u     Get pointer to IDE
+EatLp    lda   ,x           Read seems to be a pre-trigger
+         lda   ,x           Eat each 16 bit trigger byte
+         lda   ,x
+         lda   ,x
+         decb
+         bne   EatLp
+         puls  d,x,pc       Restore regs & return
+
+* Write command to IDE completed successfully
+* Update cache (copy PD.BUF to Cache if even sector, so a sequential
+*   write will have the 1st half cached, or leave current cache alone if
+*   odd). Also, check if LSN0. If it is, copy to LSN0 cache, updating
+*   vars, and copy drive table info
+DoneWrit ldb   LSN0Flag,u   Was it sector 0?
+         beq   WritLSN0     Yes, special processing for that
+         ldb   OS9LSN+2,u   Get LSB of sector #
+         lsrb               Odd/Even?
+         bcc   CpyCache     Even, copy to Cache
+* Odd sector written, leave cache as is
+         clr   drvrbusy,u   Exit without error
+         rts
+
+* Copy PD.BUF sector to HalfBuff cache, update cache tags
+CpyCache lda   PhysDrv,u    Set cache vars for PD.BUF sector
+         sta   HalfDrv,u
+         ldd   TempOfs,u
+         std   HalfOfs,u
+         ldd   OS9LSN,u
+         std   HalfSct,u
+         lda   OS9LSN+2,u
+         sta   HalfSct+2,u
+         leax  HalfBuff,u   Point to 1/2 sector cache
+CachBuff clrb
+         ldy   PD.BUF,y     Get ptr to callers buffer
+CachLp   lda   ,y+          Copy even sector to cache (in case of sequential
+         sta   ,x+            writes)
+         decb
+         bne   CachLp
+         clr   drvrbusy,u
+         rts
+
+* We wrote LSN0 - 1st, update LSN0 cache tags, then copy PD.BUF to Sect0,
+*   then update drive table entry.
+* Entry: U=drive mem ptr
+*        Y=path dsc. ptr
+WritLSN0 lda   PhysDrv,u    Copy cache tag stuff for Sect0 cache
+         sta   Sect0Drv,u
+         ldd   TempOfs,u
+         std   Sect0Ofs,u
+         leax  Sect0,u      Point to LSN0 cache
+         bsr   CachBuff     Copy from PD.BUF to Sect0 buff
+         leax  Sect0,u      Point to LSN0 cache again
+         clr   drvrbusy,u
+         lbra  CpyDrvTb     Copy info to drive table, exit from there
+
+* Initialize Write sequence to IDE
+* Entry: U=driver mem ptr
+*        Y=Ptr to path descriptor
+* Exits back to calling routine. CC=0 if command ready on controller
+*  CC=1, B=Raw IDE error code if command failed
+InitWrit ldb   #WritRtry    IDE Write w/ Retry command
+         bra   SetIDE       Send to IDE, return from there w or w/o error
+
 * After read or write, check drive status
-*   Return value = CC, true=error, false=OK
-*
-WaitOK   ldy   V.PORT,u     Is DRQ still true?  Just one check necessary
-         tst   7,y         If it is, sector isn't fully transferred
-         bmi   WaitOK      
-         lda   #$01        Wait *forever* for drive ready
-         bita  7,y
-         bne   CmdErr
-         clrb              Nope -- clear CC
-         rts   
-CmdErr   comb              Yep  -- set CC
-         rts   
+* Exit: CC=0, command ok, CC=1, Error from IDE (B=Raw error code)
+*   X=Ptr to hardware address
+WaitOK   ldx   V.PORT,u    Get status register
+WaitLp   tst   Status,x    Still busy, wait till unbusy
+         bmi   WaitLp
+         lda   #ErrorFnd   Check Error flag
+         bita  Status,x    Error from controller?
+         bne   RprtErr     Yes, go get error
+         clrb              No, exit without error
+         rts
+
+* Entry: B=Error code from IDE
+RprtErr  lsrb
+         bcc   ChkTk0
+SctrExit ldb   #E$Sect     Bad sector # for Addres Mark Not Found
+         bra   ExitErr
+
+ChkTk0   lsrb
+         bcc   ChkMdChg
+SeekExit ldb   #E$Seek     Seek error for Track 0 not found
+         bra   ExitErr
+
+ChkMdChg lsrb
+         bcc   ChkAbrt
+MdChExit ldb   #E$DIDC     Media changed error
+         bra   ExitErr
+
+ChkAbrt  lsrb
+         bcc   ChkIdnf
+         ldb   #E$UnkSvc   Unknown service error for aborted command
+         bra   ExitErr
+
+ChkIdnf  lsrb
+         bcs   SctrExit    Sector error for ID not found
+         lsrb
+         bcs   MdChExit    Media changed error for Media Change
+         lsrb
+         bcc   ChkBBK
+         ldb   #E$CRC      CRC Error for Uncorrectable data
+         bra   ExitErr
+
+ChkBBK   lsrb
+         bcs   ReadExit    Read error for Bad Block Detected
+* Error flag set, but no error condition
+         lbra  ENotRdy     Assume drive not ready
+
+ReadExit ldb   #E$Read
+ExitErr  clr   drvrbusy,u  Flag driver not busy
+         coma              Set carry & exit
+         rts
+
+BadUnit  ldb   #E$Unit
+         bra   ExitErr
+
+CmdErr   ldb   Error,x     Get Error register
+         bra   RprtErr
 
-*
-* Setup IDE read or write operation
-*
-* B  = IDE command code
-*
+* Send IDE command (read or write)
+* Entry: B  = IDE command code
+*        Y = address of path descriptor
+*        U = address of device memory (ie, of V.PAGE)
 * trashes D and X
-*
-SetIDE   stb   idecmd,u
-         pshs  y
-         ldx   #$A000
-CmdLp1   ldy   V.PORT,u
-         tst   7,y
-         bpl   SetRdy       Should go to ChkDRDY ?????
-         leax  -1,x
-         bne   CmdLp1
-         puls  y
+* Exit: CC=0 if command exited with data ready on controller
+*       CC=1, B=error if problem.
+SetIDE   stb   idecmd,u     Save copy of IDE command
+         ldb   PD.DRV,y     Get logical drive #
+         cmpb  #NUMDRIVE    Within range?
+         bhs   BadUnit      No, exit with error
+         leax  DriveFlg,u   Point to special drive flags table
+         lda   b,x          Get flags for our drive
+         bpl   TblReady     Properly initialized, figure out mode
+         lbsr  IdentDrv     NOT Initialized, get mode info
+         bcs   CmdErr       Error doing IDENTIFY DRIVE command, exit
+TblReady anda  #DrvMode     Just need CHS/LBA mode for now
+         bne   DoLBA        LBA mode, go do
+* Do CHS mode
+         ldd   PD.SCT,y     Get # of OS9 (256) sectors/track
+         lsra               Convert to 512 byte sectors/track
+         rorb
+         std   CHSSPT,u     Save for Calc routine
+         ldx   PD.DTB,y     Get pointer to device table
+         lbsr  CalcCHS      Go calculate cyl/head/sector stuff
+         bcs   CmdErr       Error calculating, exit
+         lbsr  WaitDrv      Go wait for the drive (preserves y)
+         bcs   CmdErr       Error waiting for drive, exit
+* Do sector #, then Drive/Head, then Cyl, then sector count, then command
+         pshs  y            Save path descriptor ptr
+         ldy   V.PORT,u     Get IDE hardware address
+         lda   CHSSect,u    Get IDE sector #
+         sta   SectNum,y    Save to controller
+         lda   Head,u       Get IDE head #
+         ora   #%10100000   Set CHS mode
+         ora   DrivMask,u   Merge drive #
+         sta   DevHead,y    Save to controller
+         ldd   Cylinder,u   Get 16 bit cylinder # (4095 max)
+         addd  TempOfs,u    Add partition offset cylinder
+         bcs   SeekErr      If it overflowed, SEEK error
+         sta   CylHigh,y    Save to controller
+         stb   CylLow,y
+         bra   SendCmd      Send sector count & IDE command
+
+* Do LBA mode IDE command here
+DoLBA    bsr   WaitDrv      Wait for controller to be ready
+         pshs  y            Save path descriptor ptr
+         ldy   V.PORT,u     Get IDE hardware address
+* Copy LBA sector # to controller, including device/head (LBA 24-27)
+         ldd   OS9PSN+1,u   Get bits 0-15 of PSN
+         stb   SectNum,y    Save bits 0-7
+         sta   CylLow,y     Save bit 8-15
+         clra
+         ldb   OS9PSN,u     D=PSN bits 16-23 (24 & up set to 0 for OS9)
+         addd  TempOfs,u    Add partition offset cylinder
+         cmpa  #$0f         Overflow past LBA bits?
+         bhi   SeekErr      Yes, SEEK error
+         stb   CylHigh,y    Save bits 16-23
+         ora   #%11100000   Set LBA mode
+         ora   DrivMask,u   Merge drive #
+         sta   DevHead,y    Save to controller
+* Send sector count (1) & command to controller, get results
+SendCmd  ldx   #MAXWAIT     Get # 1/60th sec. ticks to wait on drive
+         stx   SlpCntr,u    Save it for sleep routine (if needed)
+         ldd   #$0140       Sector count to 1, fast retry to 64 tries
+         sta   SectCnt,y    Send to controller
+         lda   idecmd,u     Get command to send
+         sta   Command,y    Send to controller
+CmdLp    lda   Status,y     Get status of drive command
+         bmi   CmdLp        IDE still busy, no other bits are valid
+         bita  #ErrorFnd    Not busy anymore, is there an error?
+         bne   TransErr     Yes, figure out what (don't forget to PULS Y!)
+         bita  #DataReq     Is data ready for us yet?
+         bne   CmdDone      Yes, exit
+         decb               Dec counter
+         bne   CmdLp        Keep trying
+         ldx   SlpCntr,u    Get sleep tick counter
+         leax  -1,x         Drop it by one
+         beq   NoWay        Done count, give up with device not ready error
+         stx   SlpCntr,u    Save new sleep counter
+         ldx   #1           Fast retry didn't work, sleep a tick
+         os9   F$Sleep
+         ldb   #$40         64 fast retries again
+         bra   CmdLp        Try again
+
+SeekErr  lbsr  SeekExit     Seek error & exit
+         puls  y,pc
+
+NoWay    puls  y
          bra   ENotRdy
 
-SetRdy   ldy   V.PORT,u      Drive is ready -- calculate HCS from LSN
-         lda   OS9LSN+2,u  Sector first
-         anda  #$1F
-         adda  #$01
-         sta   3,y          Store calculated sector number
-         ldd   OS9LSN+1,u  Drive number next
-         rolb  
-         rola  
-         rolb  
-         rola  
-         rolb  
-         rola  
-         anda  #$0F
-         ora   #$A0
-         sta   6,y          Store calculated drive number
-         ldd   OS9LSN,u    Last, the cylinder number (2-bytes)
-         rora  
-         rorb  
-         anda  #$7F
-         sta   5,y          Store calculated CylHi
-         stb   4,y          Store calculated CylLo
-         lda   #$01
-         sta   2,y          Sector count = 1
-         ldb   idecmd,u
-         stb   7,y          Lastly, push the command to the drive
-         ldb   #$40
-         lda   #$08         Wait for Drive ready
-CmdLp2   bita  7,y
-         bne   CmdDone
-         decb  
-         bne   CmdLp2
-         ldx   #$0001       If we time out, sleep 1 tick, then loop *forever*
-         os9   F$Sleep
-CmdLp3   bita  7,y
-         beq   CmdLp3
-CmdDone  puls  y
-         clrb               All right, drive ready -- return
-         rts   
+TransErr lbsr  CmdErr       Get error code
+         puls  y,pc         Exit with it, restore path dsc. ptr
+
+CmdDone  clrb               Command complete, return with no error
+         puls  y,pc         Restore path dsc. ptr
 
-ENotRdy  comb
+* Wait for IDE controller to be ready
+* Entry: Y=path dsc. ptr
+*        U=driver mem ptr
+* Exit: CC=0 - controller ready for command
+*       CC=1 - Error message in B
+*       DrivMask,u - contains drive # bit ready for IDE masking
+* PRESERVES X&Y
+WaitDrv  pshs  x,y           Preserve regs
+         ldx   #$A000        (1/2 to 1/3 second busy check)
+         lda   PD.DNS,y      Get physical drive #
+         anda  #PhysDriv     No bad drive # possible
+         lsla                Move drive # into proper bit for Drive/head
+         lsla
+         lsla
+         lsla
+         sta   DrivMask,u    Save drive mask for IDE
+         ldy   V.PORT,u      Get controller address for drive selected
+RdyIni1  tst   Status,y      IDE busy?
+         bpl   IDEReady      No, return
+         leax  -1,x          Dec counter
+         bne   RdyIni1       Try again
+         puls  x,y           Restore regs
+ENotRdy  clr   drvrbusy,u
+         comb                Tried too long; give up with error
          ldb   #E$NotRdy
          rts
-WriteErr comb
-         ldb   #E$Write
+
+IDEReady puls  x,y           Restore regs
+         clrb                IDE ready, return
          rts
-ReadErr  comb
-         ldb   #E$Read
-         rts
+
+* Copy LSN0 stuff into drive table
+* Entry: X=ptr to 256 byte buffer containing LSN0 Sector.
+* Exit: X,D is destroyed
+CpyDrvTb pshs  y              Save path desc. ptr
+         ldb   PD.DRV,y       Get LOGICAL drive #
+         lda   #DRVMEM        Copy useful information to our LSN 0 buffer
+         mul                  Point to proper entry in drive table
+         leay  DRVBEG,u
+         leay  d,y
+         lda   #DD.SIZ
+LSN0Cp   ldb   ,x+
+         stb   ,y+
+         deca  
+         bne   LSN0Cp
+         puls  y,pc           Restore path desc. ptr & return
+
+* Notes: PhysSN is the physical sector number to send to the controller,
+* not the LSN...so it must be translated from the LSN (for IDE, divide by
+* 2, unless using ATAPI CDROM, in which case divide by 8).
+* Note that the head returned from this routine is base 0, so that the
+* lowest head # returned would be 0 (for the first head). This matches
+* the IDE spec (which can also only go up to 16 heads).
+* The cylinder returned is also base 0, same as IDE.
+* The sector returned is base 0, but IDE needs base 1.
+* Vars used from elsewhere - OS9PSN,u   - Physical (IDE 512) sector #
+*                          - Head,u     - IDE head #
+*                          - Cylinder,u - IDE Cylinder #
+*                          - CHSSect,u  - IDE sector (512) #
+*                          - CHSSPT,u   - IDE (512 byte) sctrs/track)
+
+* LSN division routine variable definitions: all on temp stack
+           org   0
+S.SclPwr   rmb   2              scale power
+S.SclAmt   rmb   3              scale amount
+S.Cyl      rmb   2              cylinder number
+S.PSN      rmb   3              physical sector number (work copy)
+S.Head     rmb   1              head number
+S.Frame    equ   .              size of stack frame
+
+* Entry:   U=ptr to driver data area
+*          Y=Ptr to path descriptor
+*          X=Ptr to current drives' entry in drive table (DD.TOT, etc.)
+*   OS9PSN,u-  Three byte Physical (512 byte) sector #)
+* Exit:    U=ptr to driver data area
+*          Y=ptr to path descriptor
+*          X=Drive table ptr
+*     Head,u=Head # in CHS mode
+* Cylinder,u=Cylinder # in CHS mode
+*  CHSSect,u=Sector # in CHS mode
+* CC=0, no error, above 3 vars. are legit
+* CC=1, error, error return in B
+CalcCHS    leas  -S.Frame,s     make room for LSN division variables
+           ldb   OS9PSN,u
+           stb   S.PSN,s        initialize PSN MSB
+           ldd   OS9PSN+1,u
+           std   S.PSN+1,s      initialize PSN LSBs
+           ldd   #$0000
+           sta   S.Head,s       initialize head number
+           std   S.Cyl,s        initialize cylinder number
+           ldd   S.PSN+1,s      get PSN LSBs
+           subd  CHSSPT,u       less sectors/track
+           bhs   NotTrk0
+           tst   S.PSN,s        PSN MSB = 0?
+           beq   DivDone        yes, sector in track 0, go save info
+           dec   S.PSN,s        PSN MSB less 1
+NotTrk0    std   S.PSN+1,s      save remaining PSN LSBs
+           inc   S.Head,s       set to next head (1)
+           inc   V.TRAK+1,x     mark track as non-0 for SetUpWD
+           ldb   CHSSPT+1,u     get IDE sectors per track
+           lda   PD.SID,y       Get # of disk heads
+           deca                 less track 0
+           mul                  calculate sectors remaining in cylinder 0
+           std   S.SclPwr,s     save it temporarily
+           ldd   S.PSN+1,s      get remaining PSN LSBs
+           subd  S.SclPwr,s     less sectors remaining in cylinder 0
+           bhs   NotCyl0
+           tst   S.PSN,s        remaining PSN MSB = 0?
+           beq   CalcHead       sector in cylinder 0, go get head number
+           dec   S.PSN,s        remaining PSN MSB less 1
+NotCyl0    std   S.PSN+1,s      save remaining PSN LSBs
+           inc   S.Cyl+1,s      set cylinder to 1
+           clr   S.Head,s       reset head number to 0
+           lda   PD.SID,y       get disk sides
+           ldb   CHSSPT+1,u     get sectors per track
+NrmlDiv    clr   S.SclAmt+2,s   initialize scale amount LSB
+           lsla                 HD prescale = heads x 8
+           lsla                   This is the max we can do with a 16 head
+           lsla                   drive, using 8 bit MUL.
+           mul                  calculate scale amount MSBs
+           std   S.SclAmt,s     save scale amount MSBs
+           ldd   #HDSclPwr      Set hard drive scale power
+           std   S.SclPwr,s     save scale power
+DivLoop    lda   S.PSN,s        get remaining PSN MSB
+           cmpa  S.SclAmt,s     remaining PSN > scale amount?
+           blo   DivLoop1       no, go set up next scale amount & power
+           bhi   DivLoop2       yes, go do subtraction
+           ldd   S.PSN+1,s      get remaining PSN LSBs
+           subd  S.SclAmt+1,s   remaining PSN >= scale amount?
+           blo   DivLoop1       no, go set up next scale amount & power
+           std   S.PSN+1,s      save remaining PSN LSBs
+           bra   DivLoop3
+
+DivLoop2   ldd   S.PSN+1,s      get remaining PSN LSBs
+           subd  S.SclAmt+1,s   less scale amount LSBs
+           std   S.PSN+1,s      save remaining PSN LSBs
+DivLoop3   lda   S.PSN,s        get remaining PSN MSB
+           sbca  S.SclAmt,s     less scale amount MSB and borrow (if any)
+           sta   S.PSN,s        save remaining PSN MSB
+           ldd   S.Cyl,s        get cylinder number
+           addd  S.SclPwr,s     add scale power
+           std   S.Cyl,s        save cylinder number
+DivLoop1   lsr   S.SclAmt,s     * divide scale amount by two
+           ror   S.SclAmt+1,s
+           ror   S.SclAmt+2,s
+           lsr   S.SclPwr,s     * divide scale power by two
+           ror   S.SclPwr+1,s
+           bcc   DivLoop
+CalcHead   ldd   S.PSN+1,s      get remaining PSN LSBs
+NextHead   subd  CHSSPT,u       less sectors per track (head)
+           blo   DivDone        underflow, go save info
+           std   S.PSN+1,s      save remaining PSN LSBs
+           inc   S.Head,s       increment head number
+           bra   NextHead
+
+DivDone    ldd   S.Cyl,s        get cylinder number
+           cmpd  PD.CYL,y       cylinder number OK?
+           bhs   LSNErrSF       no, go return error
+           std   Cylinder,u
+           lda   S.PSN+2,s      get sector number (remaining PSN LSB)
+           inca                 IDE needs base 1
+           sta   CHSSect,u
+           ldb   S.Head,s       get head number
+           stb   Head,u
+           leas  S.Frame,s      restore stack pointer
+           clrb
+           rts
+
+LSNErrSF   leas  S.Frame,s      restore stack pointer
+LSNErr     comb
+           ldb   #E$Sect        Exit with Bad sector # error
+           rts
 
          emod
 eom      equ   *
--- a/3rdparty/drivers/ide/defsfile	Sat Jun 01 09:15:08 2002 +0000
+++ b/3rdparty/drivers/ide/defsfile	Thu Jun 27 18:10:41 2002 +0000
@@ -1,4 +1,4 @@
     use os9defs
-*    use rbfdefs
-    use    systype
+    use rbfdefs
+    use systype
 
--- a/3rdparty/drivers/ide/h0_ide.asm	Sat Jun 01 09:15:08 2002 +0000
+++ b/3rdparty/drivers/ide/h0_ide.asm	Thu Jun 27 18:10:41 2002 +0000
@@ -11,7 +11,6 @@
 
          ifp1  
          use   defsfile
-         use   rbfdefs
          endc  
 
 dnum     equ   0
@@ -39,6 +38,16 @@
          fcb   26         sector interleave factor
          fcb   8          minimum size of sector allocation
 initsize equ   *
+* Additional space for Curtis' new driver
+         fcb   0
+         fcb   0
+         fcb   0
+         fcb   0
+         fcb   0
+         fcb   0
+         fcb   0
+         fcb   0
+         fcb   0
 
 name     fcc   /H/
          fcb   176+dnum