home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 12: Textmags & Docs / nf_archive_12.iso / MAGS / SOURCES / ATARI_SRC.ZIP / atari source / AHDI / TESTSPAR / DRIVER.S < prev    next >
Encoding:
Text File  |  2001-02-09  |  79.4 KB  |  2,492 lines

  1. ; July 31 1992 v6.00'
  2.  
  3. ;------------------------------------------------------------------------
  4. ;                                    :
  5. ;    AHDI Hard Disk Driver for the Atari ST, TT and ST Book        :
  6. ;    Copyright 1985-1991 Atari Corp.                    :
  7. ;    All Rights Reserved                        :
  8. ;                                    :
  9. ;------------------------------------------------------------------------
  10.  
  11.  
  12. ;+
  13. ; Conditional Assembly Switches
  14. ;-
  15. ospool        equ    1        ; increase size of OS pool for ROM
  16.  
  17.  
  18. ;
  19. ;+
  20. ; Edit History
  21. ;
  22. ;
  23. ; 22-May-1989    ml    Started this from ahdi 3.00
  24. ;            Files created for this driver:
  25. ;            ACSI.S        Low-level driver for ACSI.
  26. ;            CMDBLK.S    Builds packets for command blocks.
  27. ;            DOIT.S        Sends packets out to SCSI or ACSI.
  28. ;            DRIVER.S    This file.
  29. ;            SCSI.S        Low-level driver for SCSI.
  30. ;
  31. ; 25-May-1989    ml    Eliminated pread(), use _ahdi_rw() in physical mode
  32. ;            instead.
  33. ;
  34. ; 06-Jun-1989    ml    Created INSTALL.S for driver installation.
  35. ;
  36. ; 11-Jul-1989    ml    Rwabs() now handles DMA to fast RAM on ACSI side
  37. ;            also.  If no extra RAM was reserved for fast RAM
  38. ;            transferred, _dskbufp is used for the transfer.
  39. ;            (This is going to be really slow!!!)
  40. ;
  41. ; 19-Jul-1989    ml    If there is cache on CPU, Rwabs() reads will
  42. ;            flush both the I and D cache.
  43. ;
  44. ; 06-Sep-1989    ml    Use _FRB (in the cookie jar) for fast RAM transfer,
  45. ;            assuming _FRB WILL be there if there is fast RAM on
  46. ;            the machine.
  47. ;
  48. ; 20-Feb-1990    ml 3.64    Fixed bug in return code when doing ACSI odd transfer.
  49. ;            When successful, 0 should be returned.
  50. ;
  51. ; 02-Mar-1990    ml 3.65    Took out wait loop for SCSI 0 to be ready.
  52. ;            (modified file: install.s)
  53. ;
  54. ; 05-Mar-1990    ml 3.66    Added more checks for I/O to ACSI and SCSI non-
  55. ;            accessible memory.  _FRB will be used if it exists.
  56. ;            If _FRB doesn't exist, _dskbuf will used (which
  57. ;            means I/O could be "really" slow).  (_do_rw())
  58. ;
  59. ;            _FRB is being looked for when it's needed for the
  60. ;            first time, not at boot time.  (Applications can
  61. ;            add the _FRB when they are executed.)
  62. ;
  63. ; 08-Mar-1990    ml    Added SCFRDMA flag in defs.h to make SCSI DMA to 
  64. ;            fast RAM conditional assembly.
  65. ;            (modified file: driver.s)
  66. ;
  67. ; 15-Mar-1990    ml    Added DEBUG flag in defs.h to make debugging code
  68. ;            conditional assembly.
  69. ;
  70. ; 09-Apr-1990    ml 3.67    Added a "read" from WDL after toggling the ACSI DMA
  71. ;            chip to point the MMU to the correct direction.
  72. ;            (modified file: acsi.s)
  73. ;
  74. ; 10-Apr-1990    ml    Put up banner at beginning and end of loading driver
  75. ;            (requested by jwt), instead of just at the end.
  76. ;            (Printing of banner moved to install.s)
  77. ;
  78. ; 17-Apr-1990    ml    Added ODMA flag in defs.h to make the klutch of 
  79. ;            making byte counter bigger than # bytes requested
  80. ;            when receiving data from SCSI conditional assembly.
  81. ;            (modified file: scsi.s)
  82. ;
  83. ; 20-Apr-1990    ml    Added RDWDL flag in defs.h to make the "extra read"
  84. ;            added on 09-Apr-1990 conditional assembly.  (When
  85. ;            writing to ACSI, first 32 bytes are always FF's!!
  86. ;            Wondering why...)
  87. ;            (modified file: acsi.s)
  88. ;
  89. ; 30-Jul-1990    ml 4.00    Final for TT release. 
  90. ;            (Vectored-interrupts code not included)
  91. ;
  92. ; 31-Jul-1990    ml     Vectored-interrupt code included as conditional
  93. ;            assembly.
  94. ;
  95. ; 29-Oct-1990    ml 4.01    BUG!!!  Getcookie() module provided by AKP has a
  96. ;            variable declared in the bss.  This bss will be
  97. ;            clobbered when the driver adds GEMDOS buffers and
  98. ;            OS pool.  When getcookie() was called, and access 
  99. ;            the bss, it clobbered whatever was using its space
  100. ;            at the time.
  101. ;            Fixed in cookie.s by changing moving the variable
  102. ;            from the bss to the text segment.
  103. ;            (modified file: cookie.s)
  104. ;
  105. ; 26-Nov-1990    ml 4.02    BUG!!  From 3.00 through 4.01, when Rwabs() is called
  106. ;            in raw mode, it ignored media change completely.
  107. ;            This created problems with cartridge swapping on the 
  108. ;            removable drives.  If Getbpb(), on a logical drive 
  109. ;            that has not been accessed on the previous cartridge,
  110. ;            is called right after a cartridge swap, Getbpb() will
  111. ;            call Rwabs() in raw mode to read the partition map of
  112. ;            the physical unit concerned.  This Rwabs() call will
  113. ;            get the media change error from the controller and 
  114. ;            ignores it without setting any mcflg of the physical
  115. ;            unit.  Now when Mediach(), on a logical drive that was
  116. ;            accessed on the previous cartridge, is called, the 
  117. ;            driver will return media not change!
  118. ;            In version 4.02, Rwabs() still does not return media
  119. ;            change error when called in raw mode, but will 
  120. ;            remember it  by setting the mcflgs of the physical 
  121. ;            unit concerned to maybe changed.
  122. ;
  123. ; 02-Apr-1991    ml 4.03    BUG!!  At boot time, 
  124. ;                move.l    #(i_sasi1-i_sasi),tokeep 
  125. ;            is used to find number of bytes of code to keep.  
  126. ;            In pre-4.00 AHDI, this works just fine because both 
  127. ;            i_sasi1 and i_sasi are in the same file.  But, since 
  128. ;            3.00, i_sasi1 has been moved to the file INSTALL.S, 
  129. ;            thus external.  Madmac did not complain that the 
  130. ;            expression #(i_sasi1-i_sasi) is not valid anymore.  
  131. ;            Instead it assembles the code as
  132. ;                move.l    #i_sasi1,tokeep
  133. ;            This is bad, because it depends of where the driver 
  134. ;            is being loaded, the driver may end up hogging large
  135. ;            amount of memory that it is not using.  This is now
  136. ;            fixed by calculating the amount at run time.
  137. ;                move.l    #i_sasi1,tokeep 
  138. ;                subi.l    #i_sasi,tokeep
  139. ;            (modified file: driver.s)
  140. ;
  141. ; 04-Apr-1991    ml    Some SCSI drives will recalibrate every so often.
  142. ;            While recalibrating, the drive still accepts the
  143. ;            command block, but delays the transfer of data to 
  144. ;            after the recalibration.  So, timeout for the data
  145. ;            transfer should include the amount of time spent 
  146. ;            on recalibration.  The worst case we know of is
  147. ;            the Fujisu drives which takes 4 seconds.  So, the 
  148. ;            default for recalibration time is set to 4 seconds.
  149. ;            (modified files: driver.s, scsi.s)
  150. ;
  151. ; 08-Aug-1991    ml    BUG!!  When the eject button on the MEGAFILE 44 is
  152. ;            pressed without actually changing the cartridge, the
  153. ;            driver still thinks there is a media change.  The
  154. ;            driver complains that the FAT checksum is different
  155. ;            from what's been recorded.
  156. ;
  157. ;            The cause:
  158. ;                When _ahdi_rw() is called in physical mode, the
  159. ;            variable sizr should not be set.  First, it is not
  160. ;            necessary to set it, because the variable is not
  161. ;            used at all when in physical mode.  Secondly, the
  162. ;            setting of the variable overwrites its value which
  163. ;            may have been set by the logical mode _ahdi_rw() that
  164. ;            calls _ahdi_rw() recursively in physical mode!
  165. ;            (modified file: driver.s)
  166. ;
  167. ; 14-Aug-1991    ml 4.60    Folded v4.59, which handles the IDE drives, into 
  168. ;            v4.03.
  169. ;            (added files: ide.s, ide.h, blitter.h)
  170. ;            (modified files: driver.s, install.s, defs.h)
  171. ;            
  172. ; 19-Aug-1991    ml    Modified errcode() so that it returns a BIOS
  173. ;            error code instead of the controller error code.
  174. ;            It now handles error for ACSI, SCSI and IDE drives.
  175. ;
  176. ; 20-Aug-1991    ml    Optimized code by eliminating as many mulu's
  177. ;            and divu's as possible.
  178. ;            (modified files: driver.s install.s, acsi.s)
  179. ;
  180. ; 21-Aug-1991    ml    Modified the ACSI-accessible RAM boundary check
  181. ;            in _do_rw().  The boundary is at 4Mb for STs,
  182. ;            at 10Mb for TTs.
  183. ;            (modified files: driver.s, install.s, defs.h)
  184. ;
  185. ; 30-Aug-1991    ml    Eliminated the requirement that physical units 
  186. ;            connected to the system must have consecutive
  187. ;            physical unit numbers.  The flag how2scan tells
  188. ;            the driver how to scan the physical units.  If set,
  189. ;            the driver will scan the physical units as specified
  190. ;            by the flags to be explained later.  If how2scan is
  191. ;            not set, the driver will do the scanning the default
  192. ;            way, which is, consecutively.  Acsi2scan, scsi2scan
  193. ;            and ide2scan are flags introduced to tell the driver
  194. ;            which physical units to scan at boot time.  Each bit
  195. ;            in the flags corresponds to one physical unit.
  196. ;            acsi2scan: bit 0..7 corresponds to ACSI unit 0..7
  197. ;            scsi2scan: bit 0..7 corresponds to SCSI unit 0..7
  198. ;            ide2scan:  bit 0..1 corresponds to IDE  unit 0..1
  199. ;            Acsi2scan, scsi2scan and ide2scan are defaulted to
  200. ;            0xff, which tells the driver to scan all units.
  201. ;            (modified files: driver.s install.s)
  202. ;
  203. ; 06-Sep-1991    ml    Added boot-time-messages to show information of the
  204. ;            device being scanned.
  205. ;            (modified files: install.s)
  206. ;
  207. ; 13-Sep-1991    ml    Decision has been made that there will only be ONE
  208. ;            IDE drive connected to the controller at the current
  209. ;            IDE bus address.  So, code that was written to take
  210. ;            care of IDE unit 1 was eliminated.
  211. ;            (modified files: driver.s install.s)
  212. ;
  213. ; 16-Sep-1991    ml    Check if driver is running on ST Book.  If so, do
  214. ;            NOT use BLiTTER for IDE hard disk data transfer.
  215. ;            (modified files: driver.s install.s)
  216. ;
  217. ; 17-Sep-1991    ml    Added a flag, called ideinit, for programs (e.g. 
  218. ;            Slavik's POWER.PRG) to set to let the driver know 
  219. ;            that it needs to reinitialize the IDE drive.
  220. ;            Initializing the drive involves doing an identify(),
  221. ;            an initparm(), and reset of the drive's internal 
  222. ;            spin down counter.
  223. ;            (modified files: driver.s)
  224. ;
  225. ; 18-Sep-1991    ml    Assuming that an IDE drive will boot up in a mode as
  226. ;            specified by the parameters returned by the Identify
  227. ;            command, there is no need to do the Initparm command
  228. ;            at boot time.  There is also no need to reinitialize 
  229. ;            the drive after a shut down.  So changes added yes-
  230. ;            terday are deleted.
  231. ;            (modified files: driver.s install.s)
  232. ;
  233. ; 24-Sep-1991    ml 5.00a Wrapped up driver for ST Book and STE+.  To show 
  234. ;            info of ACSI devices at boot time, delay must be 
  235. ;            added to take care of the slow ones (e.g. laser 
  236. ;            printer.)
  237. ;            (modified files: acsi.s driver.s install.s)
  238. ;
  239. ; 01-Oct-1991    ml 5.00    First preliminary release for ST Book.
  240. ;
  241. ; 07-Oct-1991    ml    Changes made to _rcvacsi() in calculating # of 
  242. ;            times to send the command.  Refer to comments in
  243. ;            acsi.s.
  244. ;            (modified file: acsi.s)
  245. ;
  246. ; 11-Oct-1991    ml    Special-cased Conner CP2024 in finding current
  247. ;            drive parameters of IDE drives.
  248. ;            (modified files: ide.s install.s)
  249. ;            
  250. ; 22-Oct-1991    ml    Added in check for command line arguements.  If
  251. ;            there is any, do NOT print any messages on the
  252. ;            screen.
  253. ;            (modified files: driver.s install.s)
  254. ;
  255. ; 25-Nov-1991    ml 5.0a    Modified SCSI code to use the ACSI DMA chip.  This
  256. ;            limits the number of sectors that can be transferred
  257. ;            per command to the ACSI limit of 254 sectors.
  258. ;            (added files: spscsi.h spscsi.s)
  259. ;            (modified files: driver.s install.s)
  260. ;
  261. ; 10-Dec-1991    ml 5.0b    Fixed a couple of bugs.  Added memory boundary checks
  262. ;            for Sparrow.  Changed the way to test for IDE bus, 
  263. ;            access 0xf00010 instead of 0xf00000 (for now.)
  264. ;            (modified files: spscsi.s driver.s install.s)
  265. ;
  266. ; 12-Feb-1992    ml 5.0c    Modified _do_rw() to use the 14-bit counter on the
  267. ;            ACSI DMA chip of the Sparrow.
  268. ;            Modified _rcvspscsi() to utilize the "flush" bit in
  269. ;            the ACSI Mode Register.  This is not really needed
  270. ;            because the driver was doing programmed I/O for 
  271. ;            transfers fewer than 512 bytes.
  272. ;            (modified files: driver.s spscsi.s)
  273. ;
  274. ; 14-Feb-1992    ml    Added safety check in _resetspscsi().
  275. ;            (modified file: spscsi.s)
  276. ;
  277. ; 26-Feb-1992    ml 5.0d    Bug!  Modified check_dev() to support non-consecutive 
  278. ;            unit numbers.
  279. ;
  280. ; 03-Mar-1992    ml    Test if an IDE drive exists before sending it a 
  281. ;            command (even IDE bus exists.)
  282. ;            (modified file: driver.s ide.s install.s)
  283. ; 14-Apr-1992    ml    Slow down IDE non-BLiT transfers
  284. ;            (modified file: driver.s ide.s install.s)
  285. ; 31-Jul-1992    ml 6.00    Released version of the Falcon 030 driver.
  286. ;-
  287.  
  288.  
  289. .include    "defs.h"
  290. .include    "error.h"
  291. .include    "sysvar.h"
  292. .include    "68030.s"
  293. .include    "mfp.h"
  294. .include    "scsi.h"
  295. .include    "spscsi.h"
  296.  
  297.  
  298. .extern _untrdy
  299. .extern _rqsense
  300. .extern _hread
  301. .extern _hwrite
  302. .extern _xtdread
  303. .extern _xtdwrt
  304. .extern _ideread
  305. .extern _idewrite
  306. .extern _awto
  307. .extern    idexst
  308.  
  309. .extern    prnstr
  310.  
  311. .extern    i_sasi1
  312. .extern    _getcookie
  313. .extern    _drvxst
  314.  
  315. ;
  316. ;+
  317. ; Entry points:
  318. ;
  319. ;    +0   GEMDOS entry point (double-click, or \AUTO folder on floppy)
  320. ;    +4   Boot entry point (from driver file off of C:)
  321. ;    +8   Reserved for future use
  322. ;    +$C  $F0AD magic number
  323. ;    +$E  version number
  324. ;    +$12 # chunks of ospool to add
  325. ;    +$14 # of sqnpart entries that follows
  326. ;    +$16 first sqnpart entry
  327. ;
  328. ; if bootloaded, d0 = # bytes allocated by boot code.
  329. ;-
  330. i_sasi:    bra    gboot            ; GEMDOS entry-point
  331.     bra    iboot            ; Boot entry-point
  332.     bra    iboot            ; (unused, reserved)
  333.  
  334.  
  335. ;+
  336. ;  Patchable variables
  337. ;-
  338. ; Published since v3.00
  339. magicnum:    dc.w    $f0ad        ; magic number to signify the
  340.                     ;  existence of  patchable variables
  341. vernum:        dc.w    $0500        ; AHDI version number
  342. numchunks:    dc.w    128        ; # chunks of memory to add to ospool
  343.         .globl    defbigsect
  344. defbigsect:    dc.w    512        ; default size of a big sector
  345. numsqnpart:    dc.w    MAXACSI        ; number of sqnpart entries to follow
  346.         .globl    defsqnpart    ; default # of logical drives
  347. defsqnpart:    dcb.b    MAXACSI,1    ;  reserved for removable ACSI units
  348. acsiidle:    dc.l    0        ; default idle time limit for ACSI
  349.                     ;  unit 0 (in # of _hz_200 ticks)
  350.  
  351. ; Published since v4.00:
  352. numsqcnpart:    dc.w    MAXSCSI        ; number of sqcnpart entries to follow
  353.         .globl    defsqcnpart    ; default # of logical drives
  354. defsqcnpart:    dcb.b    MAXSCSI,1    ;  reserved for removable SCSI units
  355.         .globl    scxltmout    
  356. scxltmout:    dc.l    12001        ; SCSI extra long-timeout (>1 min)
  357.         .globl    slwsclto    
  358. slwsclto:    dc.l    5000        ; SCSI stunit() long-timeout (>25s)
  359.         .globl    slwscsto    
  360. slwscsto:    dc.l    42        ; SCSI stunit() short-timeout (>205ms)
  361.         .globl    scltmout    
  362. scltmout:    dc.l    201        ; SCSI long-timeout (>1000 ms)
  363.         .globl    scstmout    
  364. scstmout:    dc.l    51        ; SCSI short-timeout (>500 ms)
  365.  
  366. ; Published since v4.03:
  367.         .globl    rcaltm    
  368. rcaltm:        dc.l    801        ; time for drive recalibration (>4s)
  369.  
  370. ; Published since v5.00:
  371.         .globl    ideidle        ; default idle time limit for IDE-IDE
  372. ideidle:    dc.w    0        ;  unit 0 (in 5 second increments)
  373.         .globl    how2scan    ; if set, scan physical units as
  374. how2scan:    dc.b    0        ;  specified by acsi/scsi/ide2scan
  375.         .globl    acsi2scan    ; bit mask of ACSI physical units
  376. acsi2scan:    dc.b    $ff        ;   to be scanned at boot time
  377.         .globl    scsi2scan    ; bit mask of SCSI physical units
  378. scsi2scan:    dc.b    $ff        ;   to be scanned at boot time
  379.         .globl    ide2scan    ; bit mask of IDE physical units
  380. ide2scan:    dc.b    $01        ;   to be scanned at boot time
  381.  
  382. ;+
  383. ; For Debugging 
  384.         .globl    badcombo    ; 
  385. badcombo:    dc.b    1        ; 1: combo is bad, don't use BLiTTER
  386. ;-
  387. .even
  388.  
  389.  
  390. ;+
  391. ; GEMDOS entry;
  392. ;   find amount of memory availble and store in d0.l
  393. ;-
  394. gboot:    movea.l    4(sp),a2        ; a2 -> basepage
  395.     move.b    $80(a2),silence        ; set flag for printing messages
  396.     move.l    4(a2),d0        ; d0 = available memory
  397.     sub.l    (a2),d0            ;    = p_hitpa - p_lowtpa - basepage
  398.     sub.l    #$0100,d0
  399.     bra    i_sasi1            ; (continue with normal initialization)
  400.  
  401.  
  402. ;+
  403. ;  Boot entry;
  404. ;    set "bootloaded", record base address from boot loader, 
  405. ;    and continue with normal boot process.
  406. ;-
  407. iboot:    st    bootloaded        ; boot entry-point, set flag
  408.     sub.l    #$1c,d0            ; memory available -= file header
  409.     move.l    a2,baseaddr        ; install base address
  410.                     ; a2 = beginning addr of this block
  411.     bra    i_sasi1            ; (continue with normal initialization)
  412.  
  413.  
  414. ;
  415. ;+
  416. ; Driver State
  417. ;-
  418.         dc.b    13,'AHDI : July 31 1992 v6.00'
  419.         dc.b    13,10,$bd,'Atari Corp.'
  420.         dc.b    ' 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992'
  421.         dc.b    13,10,0,$1A
  422. .even
  423.  
  424. ;*****  Beginning Of Published Variables  *****
  425.  
  426.         .globl    puns
  427. puns:        dc.w    0        ; # of physical units on user's system
  428.  
  429. dummy1:        dcb.b    2,-1        ; dummy pun entries for A and B
  430.         .globl    pun
  431. pun:        dcb.b    MAXLOG,0    ; physical unit table
  432. .even
  433.  
  434. dummy2:        dcb.l    2,0        ; dummy start entries for A and B
  435.         .globl    start
  436. start:        dcb.l    MAXLOG,0    ; partition start table
  437.  
  438.         .globl    cookie        ; *** DON'T CHANGE ***
  439. cookie:        dc.l    $41484449    ; cookie = 'AHDI'
  440.  
  441.         .globl    cookptr
  442. cookptr:    dc.l    0        ; pointer to cookie
  443.  
  444. versn:        dc.w    $0600        ; version number: MMmm
  445.  
  446.         .globl    maxssz
  447. maxssz:        dc.w    512        ; maximum sector size allowed
  448.  
  449. acsisd:        dc.l    0        ; idle time limit to spin down ACSI 
  450.                     ; unit 0 (applicable to STACY ONLY)
  451.         .globl    idesd        ; idle time limit to spin down
  452. idesd:        dc.w    0        ; IDE unit 0 
  453.  
  454.         dcb.w    29,0        ; reserved for future use
  455.  
  456. ;*****  End Of Published Variables  *****
  457.  
  458.         .globl    numacsi
  459. numacsi:    dc.w    0        ; number of ACSI drives
  460.  
  461.         .globl    numscsi
  462. numscsi:    dc.w    0        ; number of SCSI drives
  463.  
  464.     .globl    mcflgs
  465. mcflgs:    dcb.b    MAXLOG,2        ; media change flag table
  466.     .globl    xst
  467. xst:    dcb.b    MAXLOG,1        ; drive existence flag table
  468.     .globl    idedp
  469. idedp:    dcb.b    IDEDPLEN,0        ; IDE drive parameters table
  470. bpbs:    dcb.b    BPBLEN,0        ; a bpb 
  471. serno:    dcb.b    MAXLOG*SERLEN,0        ; serial number table
  472.     .globl    sratio
  473. sratio:    dcb.b    MAXLOG,1        ; log sect size : phys sect size tbl
  474. fatsum:    dcb.b    MAXLOG<<FATLEN,0    ; FAT checksum table
  475. fatst:    dcb.w    MAXLOG,0        ; starting sector # of last FAT
  476. fatend:    dcb.w    MAXLOG,0        ; ending sector # of last FAT
  477.  
  478.         .globl    bootloaded
  479. bootloaded:    dc.w    0        ; nonzero if loaded from boot sector
  480.         .globl    memalloc
  481. memalloc:    dc.l    0        ; total memory available if bootloaded
  482. baseaddr:    dc.l    0        ; -> base addr of .PRG file
  483. tokeep:        dc.l    0        ; amount memory to keep
  484.  
  485.         .globl    machine        ; value of _MCH
  486. machine:    dc.l    0        ; high word is machine type
  487.  
  488.         .globl    cpun
  489. cpun:        dc.w    0        ; current physical unit
  490.         .globl    npart
  491. npart:        dc.w    0        ; number of partitions found
  492. bfat:        dc.w    0        ; 0: 12-bit FAT; 1: 16-bit FAT
  493.  
  494. strec:        dc.l    0        ; starting sector to read/write
  495. endrec:        dc.l    0        ; last sector to read/write
  496. stbuf:        dc.l    0        ; starting address of buffer
  497.         .globl    embscsi
  498. embscsi:    dc.b    0        ; 1: embedded SCSI drive
  499.  
  500. frbbuf:        dc.l    0        ; pointer to _FRB
  501.  
  502. _retries:    dc.w    NRETRIES    ; number of retries to do
  503. retrycnt:    dc.w    1        ; retry counter
  504.  
  505.         .globl    o_bpb
  506. o_bpb:        dc.l    1        ; old bpb vector
  507.         .globl    o_rw
  508. o_rw:        dc.l    1        ; old rwabs vector
  509.         .globl    o_mediach
  510. o_mediach:    dc.l    1        ; old media change vector
  511.  
  512.         .globl    sendata
  513. sendata:    dcb.b    32,0        ; buffer for sense data
  514.  
  515. lastmdctm:    dc.l    0        ; time media change was last called
  516.         .globl    pbuf
  517. pbuf:        dc.l    0        ; ptr to start of root sector image
  518. fsiz:        dc.w    0        ; FAT size in sectors
  519. fatrec:        dc.w    0        ; 2nd FAT starting sector
  520.         .globl    sizr
  521. sizr:        dc.w    1        ; ratio of log : phys sector size
  522. cstart:        dc.l    0        ; current dev's starting sector
  523. temp:        dc.l    0        ; temporary storage
  524.         .globl    savssp
  525. savssp:        dc.l    1        ; (saved SSP)
  526.         .globl    _cachexst
  527. _cachexst:    dc.b    0        ; 0: no cache    1: with cache
  528.         .globl    _useblit
  529. _useblit:    dc.b    0        ; 0: don't BLiT IDE hard disk data
  530.         .globl    ext
  531. ext:        dc.b    0        ; if =0, not processing ext partition
  532.         .globl    extrt
  533. extrt:        dc.l    0        ; starting sector of ext DOS partition
  534.         .globl    extvol
  535. extvol:        dc.l    0        ; offset wrt ext DOS partition
  536. pbpb:        dc.w    0        ; partition # for dev
  537.         .globl    silence
  538. silence:    dc.b    0        ; 0: print messages
  539.         .globl    _spscsixst    
  540. _spscsixst:    dc.b    0        ; 0: no Sparrow SCSI
  541. .even
  542.  
  543.  
  544. ;
  545. ;+
  546. ; Front End
  547. ;-
  548.  
  549. ;+
  550. ;  Return pointer to BPB (or NULL)
  551. ;
  552. ;    Synopsis:    LONG hbpb(dev)
  553. ;        WORD dev;    4(sp).w
  554. ;-
  555.     .globl    hbpb
  556. hbpb:    move.w    4(sp),d0        ; d0 = devno
  557.     clr    d1            ; d1 = 0, physical op not possible
  558.     movea.l    o_bpb,a0        ; a0 -> pass-through vector
  559.     lea    _sasi_bpb(pc),a1    ; a1 -> our handler
  560.     bra.s    check_dev        ; do it
  561.  
  562.  
  563. ;+
  564. ;  Read or write logical sectors
  565. ;
  566. ;    Synopsis:    LONG hrw(rw, buf, count, recno, dev)
  567. ;        WORD rw;    $4(sp).w
  568. ;        char *buf;    $6(sp).l
  569. ;        WORD count;    $a(sp).w
  570. ;        WORD recno;    $c(sp).w
  571. ;        WORD dev;    $e(sp).w
  572. ;-
  573.     .globl    hrw
  574. hrw:    move.w    $e(sp),d0        ; d0 = devno
  575.     move.w    4(sp),d1        ; d1 includes physical device flag
  576.     movea.l    o_rw,a0            ; a0 -> pass-through vector
  577.     lea    _sasi_rw(pc),a1        ; a1 -> our handler
  578.     bra.s    check_dev        ; do it
  579.  
  580.  
  581. ;+
  582. ;  Check for media change
  583. ;
  584. ;    Synopsis:    LONG hmediach(dev)
  585. ;        WORD dev;    4(sp).w
  586. ;-
  587.     .globl    hmediach
  588. hmediach:
  589.     move.w    4(sp),d0        ; d0 = devno
  590.     clr    d1            ; physical operation not possible
  591.     movea.l    o_mediach,a0        ; a0 -> pass-through vector
  592.     lea    _sasi_mediach(pc),a1    ; a1 -> our handler
  593.  
  594.  
  595. ;+
  596. ;  check_dev - use handler, or pass vector through
  597. ;
  598. ;  Passed:    d0.w = device#
  599. ;        d1, bit 3  1=physical operation
  600. ;        a0 ->  old handler
  601. ;        a1 ->  new handler
  602. ;        a5 ->  $0000 (zero-page ptr)
  603. ;
  604. ;  Jumps-to:    (a1) if dev in range for this handler
  605. ;        (a0) otherwise
  606. ;-
  607. check_dev:
  608.     subq    #2,d0            ; lowest device is 2 (unit 0 or C:)
  609.     bmi.s    chkd_f            ; if lower, not one of ours
  610.  
  611.     btst    #3,d1            ; is this a physical unit operation?
  612.     beq.s    chkd_a            ; if not, go check against pun
  613.                     ; else check existence of phys unit
  614.     cmp.w    #ACSIUNT,d0        ; an ACSI unit?
  615.     bgt.s    chkd_sc            ; if not, try SCSI
  616.     tst.w    numacsi            ; any ACSI unit connected?
  617.     bne.s    chkd_s            ; if so, it's one of ours
  618. chkd_sc:                ; else
  619.     cmp.w    #SCSIUNT,d0        ; an SCSI unit?
  620.     bgt.s    chkd_ide        ; if not, try IDE
  621.     tst.w    numscsi            ; any SCSI unit connected?
  622.     bne.s    chkd_s            ; if so, it's one of ours
  623. chkd_ide:                ; else
  624.     cmp.w    #IDEUNT,d0        ; an IDE unit?
  625.     bgt.s    chkd_f            ; if not, not one of ours
  626.     move.w    puns,d1            ; d1.w = number of valid IDE units
  627.     sub.w    numacsi,d1        ;      = total -  #ACSI - #SCSI
  628.     sub.w    numscsi,d1
  629.     tst.w    d1            ; any IDE unit connected?
  630.     bne.s    chkd_s            ; if so, it IS one of of ours
  631.     bra.s    chkd_f            ; else not one of ours
  632.  
  633. chkd_a:    
  634.  
  635. ;+
  636. ; Aug-08-91 ml.    Added upper bound check for logical device #
  637. ;
  638.     cmp.w    #MAXLOG,d0        ; if logical device # >= MAXLOG
  639.     bge.s    chkd_f            ; it's not one of ours
  640. ;-
  641.     lea    pun,a2            ; pointer to pun map
  642.     tst.b    0(a2,d0.w)        ; must be positive for a real unit
  643.     bmi.s    chkd_f
  644. chkd_s:    movea.l    a1,a0            ; yes -- follow success vector
  645. chkd_f:    jmp    (a0)            ; do it
  646.  
  647.  
  648. ;
  649. ;+
  650. ; Medium-Level Driver
  651. ;-
  652.  
  653. ;+
  654. ; Return BPB for logical device
  655. ;
  656. ; Synopsis:    LONG _sasi_bpb(dev)
  657. ;        WORD dev;    $4(sp).w
  658. ;
  659. ; Returns:    NULL, or a pointer to the BPB buffer
  660. ;
  661. ; 10-21-88    ml.    I am not making a special case for non-removable
  662. ;            hard disk, because if a program uses Allan's
  663. ;            program to force a media change, the program 
  664. ;            should be getting the "Real" AND "New" BPB.
  665. ;            (The old (v1.7 and before) AHDI only index into
  666. ;            the bpbs table and return the pointer, without
  667. ;            actually go and read the boot sector of the dev.)
  668. ;-
  669. _sasi_bpb:
  670.     subq.w    #2,4(sp)        ; dev # excluding drv A and B
  671.     move.w    4(sp),d1        ; d1 = device number
  672.     lea    pun,a0            ; a0 -> pun table
  673.     adda.w    d1,a0            ; a0 -> pun @ dev's entry
  674.     moveq    #0,d2            ; coerce byte to word
  675.     move.b    (a0),d2            ; d2.w = pun that dev belongs to
  676.     move.w    d2,cpun            ; cpun = pun(dev)
  677.  
  678.     lea    xst,a1            ; a1 -> drive existence table
  679.     tst.b    (a1,d1.w)        ; does drive exist?
  680.     bne.s    bpbgo            ; if it does, go on normally
  681.                     ; else, see if it really doesn't exist
  682.     movem.l    d1/a0,-(sp)        ; save registers
  683.     move.w    d2,-(sp)        ; physical unit number
  684.     bsr    _untrdy            ; verify by doing test unit ready
  685.     addq.l    #2,sp            ; cleanup stack
  686.     movem.l    (sp)+,d1/a0        ; restore registers
  687.     tst.w    d0            ; return good status?
  688.     beq    badbpb            ; if yes, ie. medium has not changed
  689.                     ; therefore, dev still doesn't exist
  690.     moveq    #1,d0            ; else medium may have changed
  691.     bsr    s_mc_xst        ; set mcflgs and xst flags to 1's
  692.                     ; and go try to get BPB
  693. bpbgo:    move.l    _dskbufp,pbuf        ; pbuf -> 2nd half of 1K disk buf
  694.     add.l    #512,pbuf
  695.  
  696. bpb00:    move.l    a0,-(sp)        ; save ptr to pun(dev)
  697.     move.w    cpun,-(sp)        ; physical unit number
  698.     addq.w    #2,(sp)            ; unit # including A: and B:
  699.     clr.w    -(sp)            ; from sector 0
  700.     move.w    #1,-(sp)        ; read in 1 sector
  701.     move.l    pbuf,-(sp)        ; buffer to read into
  702.     move.w    #$a,-(sp)        ; in phys mode/ignore media change
  703.     bsr    _ahdi_rw        ; ahdi_rw($a, pbuf, 1, 0, cpun)
  704.     adda    #12,sp
  705.     movea.l    (sp)+,a0        ; restore ptr to pun(dev)
  706.     tst    d0            ; read successful?
  707.     beq.s    bpb0            ; if yes, go on normally
  708.                     ; else call up error handler
  709. bpberr:    move.l    a0,-(sp)        ; save ptr to pun(dev)
  710.     move.w    8(sp),d1        ; a0 = drive # excluding A: and B:
  711.     bsr    critic            ; call up critical error handler
  712.     move.l    (sp)+,a0        ; restore ptr to pun(dev)
  713.     cmpi.l    #CRITRETRY,d0        ; retry?
  714.     beq.s    bpb00            ; if so, go and try again
  715.     bra    badbpb            ; else return no BPB
  716.  
  717. bpb0:    move.w    cpun,d2            ; d2 = physical unit number of dev
  718.     move.w    #0,pbpb            ; pbpb = partition # dev corresponds
  719. bpb1:    cmp.b    -(a0),d2        ; pun that dev belongs to == (a0)?
  720.     bne.s    bpb2
  721.     addq.w    #1,pbpb
  722.     bra.s    bpb1
  723.  
  724. bpb2:    move.w    #MAXNPART,d1        ; do #MAXNPART times
  725.     movea.l    pbuf,a0            ; a0 -> beginning of root sector
  726.     cmpi.w    #SIG,DOSSIG(a0)        ; is root sector in DOS format?
  727.     bne.s    bpb3            ; if not, assume it's in GEMDOS format
  728.     bsr    dosbpb            ; else, handle it the DOS way
  729.     bra.s    bpb4            ; else, go get the bpb
  730. bpb3:    move.w    #1,bfat            ; 16 bit FAT always for GEMDOS
  731.     bsr    gembpb            ; handle it the GEMDOS way
  732. bpb4:    tst.w    d0            ; successful?
  733.     beq.s    bpbnf            ; if =0, no valid BPB found
  734.     bpl.s    bpb5            ; if +ive, valid BPB found
  735.     bra.s    badbpb            ; else no BPB found
  736.                     ; partition not found
  737. bpbnf:    lea    xst,a0            ; a0 -> drive existence table
  738.     move.w    4(sp),d0        ; d0 = dev number
  739.     clr.b    (a0,d0.w)        ; dev definitely does not exist
  740.     lea    mcflgs,a0        ; a0 -> mcflgs table
  741.     move.b    #2,(a0,d0.w)        ; set as medium has changed
  742.     bra.s    badbpb            ; can't find such a partition
  743.  
  744. bpb5:    move.l    d1,-(sp)        ; start_sector
  745.     move.w    8(sp),-(sp)        ; dev number
  746.     bsr    getbpb            ; getbpb(dev, start_sector)
  747.     addq.l    #6,sp            ; clean up stack
  748.     tst.l    d0            ; getbpb successful?
  749.     bpl.s    retbpb            ; if so, return ptr to bpb
  750. badbpb:    moveq    #0,d0            ; return no bpb found
  751. retbpb:    rts
  752.  
  753.  
  754. ;
  755. ;+
  756. ; dosbpb - find the DOS partition that corresponds to the requested
  757. ;       logical drive
  758. ; Passed:
  759. ;    a0 = buffer address for root sector
  760. ;    d1 = number of entries in partition map
  761. ;
  762. ; Assumed:
  763. ;    pbpbs = partition being looked for
  764. ;
  765. ; Returns:
  766. ;    d0.b = 0        if partition not found
  767. ;         = negative #    some kind of error
  768. ;         = positive #    system indicator of the partition
  769. ;    d1.l = starting sector of the partition (if it is found)
  770. ;-
  771. dosbpb:    adda.w    #DOSPM,a0        ; a0 -> partition map
  772. dbpb0:    movem.l    d1/a0,-(sp)        ; save count and offset
  773.     sf    ext            ; not dealing with ext partition
  774.     bsr    fdpart            ; find a partition
  775.     tst.b    d0            ; found any?
  776.     beq.s    dbpba            ; not a valid partition
  777.     cmpi.b    #5,d0            ; extended partition?
  778.     bne.s    dbpb1            ; if not, it's a regular partition
  779.     st    ext            ; else, it's an extended partition
  780.     move.l    #0,extvol        ; offset from start of partition = 0
  781.     move.l    d1,extrt        ; starting sector # of ext partition
  782. dbpbx:    bsr    fdnxt            ; find next logical drive
  783.     tst.b    d0            ; found any?
  784.     beq.s    dbpba            ; no logical drive found
  785.     bmi.s    dbpb2            ; error returned
  786.     cmpi.b    #5,d0            ; extended volume?
  787.     beq.s    dbpbx            ; if so, go find next logical drive
  788. dbpb1:    subq.w    #1,pbpb            ; partition that we want?
  789.     bpl.s    dbpb3            ; if not, continue the search
  790. dbpb2:    addq.l    #8,sp            ; else clean up stack
  791.     move.w    #0,bfat            ; assume partition has 12-bit fat
  792.     cmpi.b    #1,d0            ; 12-bit fat?
  793.     beq.s    dbpb22            ; if so, return
  794.     move.w    #1,bfat            ; else bflag = 1 for 16-bit fat
  795. dbpb22:    bra.s    dbpbr            ; and return
  796. dbpb3:    tst.b    ext            ; clun is in ext partition?
  797.     bne.s    dbpbx            ; if so, go find next ext vol
  798. dbpba:    movem.l    (sp)+,d1/a0        ; restore count and offset
  799.     adda    #16,a0            ; index to next entry in pmap
  800.     dbra    d1,dbpb0
  801.     moveq    #0,d0            ; partition not found!
  802. dbpbr:    rts
  803.  
  804.     
  805. ;+
  806. ; fdpart - find a DOS partition.
  807. ;
  808. ; Passed:
  809. ;    a0 = address to partition entry
  810. ;
  811. ; Returns:
  812. ;    d0.b = 0        partition is not valid
  813. ;         = positive    #    partition is a valid partition
  814. ;           (this is the system indicator of the partition)
  815. ;    d1.l = starting sector # of a valid partition (if d0.b = 1 or 4)
  816. ;         = starting sector # of extended partition (if d0.b = 5)
  817. ;-
  818.     .globl    fdpart
  819. fdpart:    tst.l    12(a0)            ; partition's size?
  820.     beq.s    fdp0            ; if =0, not valid
  821.  
  822.     move.b    4(a0),d0        ; d0 = system indicator
  823.     beq.s    fdpr            ; if =0, not valid
  824.  
  825.     cmpi.b    #4,d0            ; if =4, valid
  826.     beq.s    fdp1
  827.  
  828.     cmpi.b    #1,d0            ; if =1, valid
  829.     beq.s    fdp1
  830.  
  831.     cmpi.b    #5,d0            ; if =5, valid
  832.     beq.s    fdp1
  833.  
  834. fdp0:    moveq    #0,d0            ; else, not valid
  835.     bra.s    fdpr
  836.  
  837. fdp1:    move.l    8(a0),d1        ; d1.l = swapped starting sector #
  838.     ror.w    #8,d1            ; swap hi and lo byte of high word
  839.     swap    d1            ; swap hi and lo word
  840.     ror.w    #8,d1            ; swap hi and lo byte of low word
  841. fdpr:    rts
  842.  
  843.  
  844. ;+
  845. ; fdnxt - find a logical drive in the extended DOS partition
  846. ;
  847. ; Passed:
  848. ;    d0.b = (= 5 if a new extended volume was found)
  849. ;           (= 0 if nxtdrv was successful for last logical drive found)
  850. ;    d1.l = starting sector # of this extended volume
  851. ;    d2.b = count down for logical drive entries (if d0.b != 5)
  852. ;    a0.l = address of partition entry to be checked (if d0.b != 5)
  853. ;
  854. ; Assumes:
  855. ;    cpun = current physical unit #
  856. ;    extrt = starting sector # of extended DOS partition
  857. ;    extvol = offset from start of extended DOS partition (in sectors)
  858. ;
  859. ; Returns:
  860. ;    d0.b = 0        no logical drive found
  861. ;         = positive #    valid logical drive found
  862. ;           (this is the system indicator of the logical drive)
  863. ;         = negative #    error occured
  864. ;    d1.l = starting sector # of the logical drive (if d0.b = 1 or 4)
  865. ;         = starting sector # of next extended volume (if d0.b = 5)
  866. ;-
  867.     .globl    fdnxt
  868. fdnxt:    cmpi.b    #5,d0        ; new extended volume found?
  869.     bne.s    fdnxt0        ; if not, search for one
  870.     move.l    d1,-(sp)    ; from beginning of extended volume
  871.     move.w    cpun,-(sp)    ; physical unit number
  872.     addq.w    #2,(sp)        ; unit # including A: and B:
  873.     move.w    #-1,-(sp)    ; using a long sector number
  874.     move.w    #1,-(sp)    ; read in 1 sector
  875.     move.l    _dskbufp,-(sp)    ; buffer to read into
  876.     move.w    #$a,-(sp)    ; read in physical mode/ignore media change
  877.     bsr    _ahdi_rw    ; ahdi_rw($a, buf, 1, -1, cpun, lsectno)
  878.     adda    #16,sp        ; cleanup stack
  879.     tst.w    d0        ; read successful?
  880.     bne    fdnxtr        ; if not, return
  881.     
  882.     movea.l    _dskbufp,a0    ; else, 
  883.     cmpi.w    #SIG,DOSSIG(a0)    ; boot record valid?
  884.     bne.s    fdnxtr        ; if not, return no drive found
  885.                 ; (d0 already set by ahdi_rw)
  886.     adda.w    #DOSPM-16,a0    ; a0 -> 1st entry in log drive map
  887.     move.w    #MAXNPART+1,d2    ; d2 = count for # of log drive entries
  888.  
  889. fdnxt0:    subq.w    #1,d2        ; more entries to search?
  890.     bmi.s    fdnxt1        ; if not, return
  891.  
  892.     adda    #16,a0        ; a0 -> entry to be examined
  893.     tst.l    12(a0)        ; partition size's?
  894.     beq.s    fdnxt0        ; if =0, not valid
  895.  
  896.     move.b    4(a0),d0    ; d0 = system indicator
  897.     beq.s    fdnxt0        ; if =0, not valid
  898.  
  899.     move.l    8(a0),d1    ; d1.l = logical start sector of drv or vol
  900.     beq.s    fdnxt0        ; if =0, not valid
  901.     ror.w    #8,d1        ; swap hi and lo byte of high word
  902.     swap    d1        ; swap hi and lo word
  903.     ror.w    #8,d1        ; swap hi and lo byte of low word
  904.  
  905.     cmpi.b    #4,d0        ; if =4,
  906.     beq.s    fdnxt2        ; valid logical drive found
  907.  
  908.     cmpi.b    #1,d0        ; if =1,
  909.     beq.s    fdnxt2        ; valid logical drive found
  910.  
  911.     cmpi.b    #5,d0        ; if =5, valid ptr to next ext volume
  912.     bne.s    fdnxt0        ; else, not valid
  913.     move.l    d1, extvol    ; offset of ext vol from start of ext DOS
  914.     bra.s    fdnxt3
  915.  
  916. fdnxt1:    moveq    #0,d0        ; return no drive found
  917.     bra.s    fdnxtr
  918.  
  919. fdnxt2:    add.l    extvol,d1    ; d1 = start sector wrt beginning of ext DOS
  920. fdnxt3:    add.l    extrt,d1    ; d1 = start sector wrt beginning of disk
  921. fdnxtr:    rts
  922.  
  923.  
  924. ;
  925. ;+
  926. ; gembpb - find the GEMDOS partition that corresponds to the requested
  927. ;       logical drive.
  928. ; Passed:
  929. ;    a0 = buffer address for root sector
  930. ;    d1 = number of entries in partition map
  931. ;
  932. ; Assumed:
  933. ;    pbpbs = partition being looked for
  934. ;
  935. ; Returns:
  936. ;    d0.b = 0        if partition not found
  937. ;         = negative #    some kind of error
  938. ;         = positive #    system indicator of the partition
  939. ;    d1.l = starting sector of the partition (if it is found)
  940. ;-
  941. gembpb:    adda.w    #HDSIZ,a0        ; a0 -> hard disk size
  942.     tst.l    (a0)+            ; size? (a0 -> start of pmap)
  943.     beq.s    gbpb4            ; if =0, no drive will exist
  944. gbpb0:    movem.l    d1/a0,-(sp)        ; save count and offset
  945.     sf    ext            ; not dealing with ext partition
  946.     bsr    fgpart            ; find partitions
  947.     tst.b    d0            ; found any?
  948.     beq.s    gbpba            ; not a valid partition
  949.     cmpi.b    #'X',d0            ; extended partition?
  950.     bne.s    gbpb1            ; if not, it's a regular partition
  951.     st    ext            ; else, it's an extended partition
  952.     move.l    #0,extvol        ; offset from start of partition = 0
  953.     move.l    d1,extrt        ; starting sector # of ext partition
  954. gbpbx:    bsr    fgnxt            ; find next logical drive
  955.     tst.b    d0            ; found any?
  956.     beq.s    gbpba            ; no logical drive found
  957.     bmi.s    gbpb2            ; error returned
  958.     cmpi.b    #'X',d0            ; extended volume?
  959.     beq.s    gbpbx            ; if so, go find next logical drive
  960. gbpb1:    subq.w    #1,pbpb            ; partition that we want?
  961.     bpl.s    gbpb3            ; if not, continue the search
  962. gbpb2:    addq.l    #8,sp            ; else BINGO!  Clean up stack
  963.     bra.s    gbpbr            ; and return
  964. gbpb3:    tst.b    ext            ; clun is in ext partition?
  965.     bne.s    gbpbx            ; if so, go find next ext vol
  966. gbpba:    movem.l    (sp)+,d1/a0        ; restore count and offset
  967.     adda    #12,a0            ; index to next entry in pmap
  968.     dbra    d1,gbpb0
  969. gbpb4:    moveq    #0,d0            ; partition not found!
  970. gbpbr:    rts
  971.  
  972.  
  973. ;+
  974. ; fgpart - find a GEMDOS partition.
  975. ;
  976. ; Passed:
  977. ;    a0 = address to partition entry
  978. ;
  979. ; Returns:
  980. ;    d0.b = 0        partition is not valid
  981. ;         = positive    #    partition is a valid partition
  982. ;           (this is the first byte in p_id of the partition)
  983. ;    d1.l = starting sector # of a valid partition (if d0.b = 'G' or 'B')
  984. ;         = starting sector # of extended partition (if d0.b = 'X')
  985. ;-
  986.     .globl    fgpart
  987. fgpart:    tst.b    (a0)            ; check the valid partition flag
  988.     beq.s    fgp2            ; if =0, not valid
  989.  
  990.     tst.l    8(a0)            ; partition's size?
  991.     beq.s    fgp2            ; if =0, not valid
  992.  
  993.     cmpi.b    #'G',1(a0)        ; must find GEM as type
  994.     bne.s    fgp0            ; for REGULAR partition
  995.     cmpi.b    #'E',2(a0)        ; (ie., partition < 16Mb)
  996.     bne.s    fgp0
  997.     cmpi.b    #'M',3(a0)
  998.     beq.s    fgp3
  999.  
  1000. fgp0:    cmpi.b    #'B',1(a0)        ; must find BGM as type
  1001.     bne.s    fgp1            ; for BIG partition
  1002.     cmpi.b    #'G',2(a0)        ; (ie., partition >= 16Mb)
  1003.     bne.s    fgp1
  1004.     cmpi.b    #'M',3(a0)
  1005.     beq.s    fgp3
  1006.  
  1007. fgp1:    cmpi.b    #'X',1(a0)        ; or find XGM as type
  1008.     bne.s    fgp2            ; for EXTENDED GEMDOS 
  1009.     cmpi.b    #'G',2(a0)        ; partition
  1010.     bne.s    fgp2            ; (ie., partition with
  1011.     cmpi.b    #'M',3(a0)        ;  a linked list of
  1012.     beq.s    fgp3            ;  logical drives)
  1013.  
  1014. fgp2:    moveq    #0,d0            ; else, not valid
  1015.     bra.s    fgpr
  1016.  
  1017. fgp3:    move.l    4(a0),d1        ; d1.l = starting sector #
  1018.     move.b    1(a0),d0        ; d0.b = first byte of p_id
  1019. fgpr:    rts
  1020.  
  1021.  
  1022. ;+
  1023. ; fgnxt - find a logical drive in the extended GEMDOS partition
  1024. ;
  1025. ; Passed:
  1026. ;    d0.b = (= 'X' if a new extended volume was found)
  1027. ;           (= 0 if nxtdrv was successful for last logical drive found)
  1028. ;    d1.l = starting sector # of this extended volume
  1029. ;    d2.b = count down for logical drive entries (if d0.b != 'X')
  1030. ;    a0.l = address of partition entry to be checked (if d0.b != 'X')
  1031. ;
  1032. ; Assumes:
  1033. ;    cpun = current physical unit #
  1034. ;    extrt = starting sector # of extended GEMDOS partition
  1035. ;    extvol = offset from start of extended GEMDOS partition (in sectors)
  1036. ;
  1037. ; Returns:
  1038. ;    d0.b = 0        no logical drive found
  1039. ;         = positive #    valid logical drive found
  1040. ;           (this is the first byte of p_id of the logical drive)
  1041. ;         = negative #    error occured
  1042. ;    d1.l = starting sector # of the logical drive (if d0.b = 'G' or 'B')
  1043. ;         = starting sector # of next extended volume (if d0.b = 'X')
  1044. ;-
  1045.     .globl    fgnxt
  1046. fgnxt:    cmpi.b    #'X',d0        ; new extended volume found?
  1047.     bne.s    fgnxt0        ; if not, search for one
  1048.     move.l    d1,-(sp)    ; from beginning of extended volume
  1049.     move.w    cpun,-(sp)    ; physical unit number
  1050.     addq.w    #2,(sp)        ; unit # including A: and B:
  1051.     move.w    #-1,-(sp)    ; using a long sector number
  1052.     move.w    #1,-(sp)    ; read in 1 sector
  1053.     move.l    _dskbufp,-(sp)    ; buffer to read into
  1054.     move.w    #$a,-(sp)    ; read in physical mode/ignore media change
  1055.     bsr    _ahdi_rw    ; ahdi_rw($a, buf, 1, -1, cpun, lsectno)
  1056.     adda    #16,sp        ; cleanup stack
  1057.     tst.w    d0        ; read successful?
  1058.     bne    fgnxtr        ; if not, return error
  1059.  
  1060.     movea.l    _dskbufp,a0    ; a0 -> partition map
  1061.     adda.w    #HDSIZ+4-12,a0    ; a0 -> 1st entry in log drive map
  1062.     move.w    #MAXNPART+1,d2    ; d2 = count for # of log drive entries
  1063.  
  1064. fgnxt0:    subq.w    #1,d2        ; more entries to search?
  1065.     bmi.s    fgnxt3        ; if not, return
  1066.  
  1067.     adda    #12,a0        ; a0 -> entry to be examined
  1068.     tst.l    8(a0)        ; partition size's?
  1069.     beq.s    fgnxt0        ; if =0, not valid.  Try next entry
  1070.  
  1071.     tst.b    (a0)        ; check the valid partition flag
  1072.     beq.s    fgnxt0        ; if =0, not valid.  Try next entry
  1073.  
  1074.     move.l    4(a0),d1    ; d1.l = logical start sector of drv or vol
  1075.  
  1076.     cmpi.b    #'G',1(a0)    ; must find GEM as type
  1077.     bne.s    fgnxt1        ; for REGULAR partition
  1078.     cmpi.b    #'E',2(a0)    ; (ie., partition < 16Mb)
  1079.     bne.s    fgnxt1
  1080.     cmpi.b    #'M',3(a0)
  1081.     beq.s    fgnxt4
  1082.  
  1083. fgnxt1:    cmpi.b    #'B',1(a0)    ; must find BGM as type
  1084.     bne.s    fgnxt2        ; for BIG partition
  1085.     cmpi.b    #'G',2(a0)    ; (ie., partition >= 16Mb)
  1086.     bne.s    fgnxt2
  1087.     cmpi.b    #'M',3(a0)
  1088.     beq.s    fgnxt4
  1089.  
  1090. fgnxt2:    cmpi.b    #'X',1(a0)    ; or find XGM as type
  1091.     bne.s    fgnxt3        ; for EXTENDED GEMDOS 
  1092.     cmpi.b    #'G',2(a0)    ; partition
  1093.     bne.s    fgnxt3        ; (ie., partition with
  1094.     cmpi.b    #'M',3(a0)    ;  a linked list of
  1095.     bne.s    fgnxt0        ;  logical drives)
  1096.  
  1097.     move.l    d1, extvol    ; offset of ext vol from start of ext GEMDOS
  1098.     bra.s    fgnxt5
  1099.  
  1100. fgnxt3:    moveq    #0,d0        ; return no drive found
  1101.     bra.s    fgnxtr
  1102.  
  1103. fgnxt4:    add.l    extvol,d1    ; d1 = start sector wrt beginning of ext DOS
  1104. fgnxt5:    add.l    extrt,d1    ; d1 = start sector wrt beginning of disk
  1105.     move.b    1(a0),d0    ; d0.b = first byte of p_id
  1106. fgnxtr:    rts
  1107.  
  1108.  
  1109. ;
  1110. ;+
  1111. ; getbpb(dev, sectorno)
  1112. ; WORD dev;        4(sp).w
  1113. ; LONG sectorno;    6(sp).l
  1114. ;
  1115. ; Assume -
  1116. ;    cpun contains physical unit number of dev
  1117. ;-
  1118. getbpb:    move.l    $6(sp),-(sp)    ; sector # of boot sector
  1119.     move.w    cpun,-(sp)    ; physical unit
  1120.     addq.w    #2,(sp)        ; unit # including A: and B:
  1121.     move.w    #-1,-(sp)    ; using a long sector number
  1122.     move.w    #1,-(sp)    ; 1 sector
  1123.     move.l    _dskbufp,-(sp)    ; buffer
  1124.     move.w    #$a,-(sp)    ; read in physical mode/ignore media change
  1125.     bsr    _ahdi_rw    ; ahdi_rw(8, buf, 1, -1, cpun, lsectno)
  1126.     adda    #16,sp        ; clean up stack
  1127.     tst.w    d0        ; successful?
  1128.     beq.s    getb0        ; if so, go on normally
  1129.                 ; else let user retry
  1130. getb9:    move.w    4(sp),d1    ; d1 = drive # excluding A: and B:
  1131.     bsr    critic
  1132.     cmpi.l    #CRITRETRY,d0    ; retry?
  1133.     bne    getb7        ; if not, return
  1134.     bra.s    getbpb        ; else read again
  1135.  
  1136. getb0:    movea.l    _dskbufp,a0    ; a0 -> boot sector image
  1137.     movea.l    #bpbs,a2    ; a2 -> bpb
  1138.  
  1139.     move.w    #$0b,d0
  1140.     bsr    getlhw
  1141.     cmp.w    maxssz,d0    ; is sector size too big?
  1142.     bhi    getb7        ; if it is, can't handle it
  1143.     move.w    d0,(a2)+    ; =byt/sec
  1144.     beq    getb7        ; if =0, bad data
  1145.     move.w    d0,d1        ; d1 = logical sector size
  1146.     moveq    #9,d2        ; d0.b = (log : phys) sector size ratio
  1147.     lsr.w    d2,d0        ;      = logical sector size / 512
  1148.     move.w    d0,sizr        ; save the ratio
  1149.  
  1150.     clr.w    d0
  1151.     move.b    $d(a0),d0
  1152.     move.w    d0,(a2)+    ; = #sectors/cluster
  1153.     beq    getb7        ; if =0, bad data
  1154.  
  1155.     mulu    d1,d0
  1156.     move    d0,(a2)+    ; = #bytes/cluster
  1157.  
  1158.     moveq    #$11,d0
  1159.     bsr    getlhw        ; number of directory entries
  1160.     tst    d0        ; num o' entries ?= 0
  1161.     beq    getb7        ; if so, bad data
  1162.      lsl.l    #5,d0        ; size root dir = (32 * num entries) bytes
  1163.     divu    d1,d0        ; number of sectors required
  1164.     move.l    d0,d1
  1165.     swap    d1
  1166.     tst    d1
  1167.     beq.s    getb1
  1168.     addq    #1,d0        ; round up
  1169. getb1:    move    d0,(a2)+    ; =rdlen
  1170.     move    d0,d2
  1171.  
  1172.     move    #$16,d0
  1173.     bsr    getlhw
  1174.     move    d0,(a2)+    ; =FATsize
  1175.     beq    getb7        ; if =0, bad data
  1176.     move    d0,d1
  1177.     move    d0,fsiz        ; save FAT size
  1178.  
  1179.     move    #$e,d0
  1180.     bsr    getlhw        ; number of reserved sectors
  1181.     add    d1,d0
  1182.     move    d0,(a2)+    ; =2nd FAT start
  1183.     move    d0,fatrec    ; save 2nd FAT start 
  1184.  
  1185.     add    d1,d0        ; plus size of second fat
  1186.     add    d2,d0        ; plus rdlen
  1187.     move    d0,(a2)+    ; = data start
  1188.     move    d0,d2        ; save start of data
  1189.  
  1190.     move    #$13,d0
  1191.     bsr    getlhw        ; number of sectors on media
  1192.     sub    d2,d0        ; subtract # used by FATs,dir,boot
  1193.     beq    getb7        ; if =0, bad data
  1194.     clr.l    d1
  1195.     move    d0,d1
  1196.     clr    d0
  1197.     move.b    $d(a0),d0    ; number of sectors/cluster
  1198.     divu    d0,d1        ; rounding down
  1199.     move    d1,(a2)+    ; =number of clusters
  1200.     move    bfat,(a2)    ; =flags, 12 or 16 bit fats
  1201.  
  1202.     move.w    sizr,d2        ; d2 = current sector size ratio
  1203.     lea    sratio,a1    ; a1 -> sector size ratio table
  1204.     move.w    4(sp),d0    ; d0 = drive number
  1205.     move.b    d2,(a1,d0.w)    ; update sector size ratio in table
  1206.  
  1207.     btst.b    #6,cpun+1    ; is unit removable?
  1208.     beq    getb6        ; if not, can skip the fat checksum
  1209.  
  1210.     lea    serno,a1    ; a1 -> table of serial #s
  1211.     mulu.w    #SERLEN,d0    ; dev# * SERLEN to index into table
  1212.     adda.l    d0,a1        ; a1 -> serial # of dev
  1213.     move.w    #SERLEN-1,d1    ; length of serial # - 1
  1214. getb2:    move.b    $8(a0,d1.w),(a1,d1.w)    ; update serial # of dev
  1215.     dbra    d1,getb2
  1216.  
  1217.     lea    fatsum,a2    ; a2 -> FAT check sum table
  1218.     moveq    #0,d0        ; coerce to long
  1219.     move.w    4(sp),d0    ; d0 = dev number
  1220.     lsl.l    #FATLEN,d0    ; d0 << FATLEN = to index into table
  1221.     adda.l    d0,a2        ; a2 -> FAT check sum tbl of dev
  1222.  
  1223.     move.w    fatrec,d0    ; d0 = log starting sector of 2nd FAT
  1224.     mulu    d2,d0        ; (in 512-byte sectors)
  1225.     movea.l    $6(sp),a1    ; a1 = starting sector of drive
  1226.     adda.l    d0,a1        ; a1 = phys starting sector of 2nd FAT
  1227.  
  1228.     move.w    fsiz,d1        ; d1 = # FAT sectors to read
  1229.     subq.l    #1,d1        ;    = FAT size - 1
  1230.  
  1231. getb3:    move.w    sizr,d2        ; d2 = count per FAT sector
  1232.     subq.w    #1,d2
  1233.      clr.l    temp        ; initialize the sum
  1234. getb4:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers
  1235.     move.l    a1,-(sp)    ; from sector a1
  1236.     move.w    cpun,-(sp)    ; physical unit
  1237.     addq.w    #2,(sp)        ; unit # including A: and B:
  1238.     move.w    #-1,-(sp)    ; using a long sector number
  1239.     move.w    #1,-(sp)    ; read 1 phys sector
  1240.     move.l    a0,-(sp)    ; buffer (in _dskbufp)
  1241.     move.w    #$a,-(sp)    ; read in physical mode/ignore media change
  1242.     bsr    _ahdi_rw    ; ahdi_rw($a, buf, 1, -1, cpun, lsecno)
  1243.     adda    #16,sp        ; clean up stack
  1244.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers
  1245.     tst.w    d0        ; read successful?
  1246.     beq    getb5        ; if so, go on normally
  1247.                 ; else let user retry
  1248. getba:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers
  1249.     move.w    24(sp),d1    ; d1 = drive # excluding A: and B:
  1250.     bsr    critic        ; critical error handler
  1251.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers
  1252.     cmpi.l    #CRITRETRY,d0    ; retry?
  1253.     beq.s    getb4        ; if so, try again
  1254.     bra    getb7        ; else return
  1255.  
  1256. getb5:    bsr    bsum        ; add up values in the sector
  1257.     addq    #1,a1        ; get ready for next sector
  1258.     dbra    d2,getb4    ; until one logical FAT sector is done
  1259.  
  1260.     bsr    csum        ; find the checksum
  1261.     move.b    d0,(a2)+    ; update checksum for this FAT sector
  1262.     dbra    d1,getb3    ; until all sectors are checked
  1263.  
  1264. getb6:    move.w    $4(sp),d0    ; d0 = dev number
  1265.     lea    mcflgs,a0    ; load address of mcflgs table
  1266.     clr.b    (a0,d0.w)    ; clear mcflg for dev
  1267.  
  1268.     lea    xst,a0        ; a0 -> drive existence table
  1269.     move.b    #2,(a0,d0.w)    ; dev definitely exists
  1270.  
  1271.     lea    fatst,a0    ; a0 -> FAT start sector table
  1272.     asl.w    #1,d0        ; offset = dev# * 2 (tbl of words)
  1273.     move    fatrec,(a0,d0.w); update FAT starting sect#
  1274.  
  1275.     lea    fatend,a0    ; a0 -> FAT end sector table
  1276.     move.w    fatrec,d1    ; d1 = fatend(dev)
  1277.     add.w    fsiz,d1        ;    = fatrec + fsiz - 1
  1278.     subq.w    #1,d1    
  1279.     move.w    d1,(a0,d0.w)    ; fatend(dev) = fatrec + fsiz - 1
  1280.  
  1281.     lea    start,a0    ; a0 -> beginning of start table
  1282.     asl.w    #1,d0        ; offset = dev# * 2 * 2 (tbl of longs)
  1283.     move.l    $6(sp),(a0,d0.w); update starting sect# of dev
  1284.  
  1285.     move.l    #bpbs,d0    ; no errors, return ptr to BPB
  1286.     bra.s    getb8        ; return
  1287.  
  1288. getb7:    moveq    #-1,d0        ; error
  1289. getb8:    rts
  1290.  
  1291.  
  1292. ;+
  1293. ; WORD getlhw(d0=offset)
  1294. ; returns word (low,high) from 0(D0,A0)
  1295. ;-
  1296.     .globl    getlhw
  1297. getlhw:    move    d1,-(sp)    ; preserve d1
  1298.     move.b    1(a0,d0.w),d1
  1299.     lsl.w    #8,d1
  1300.     move.b    0(a0,d0.w),d1
  1301.     move    d1,d0
  1302.     move    (sp)+,d1
  1303.     rts
  1304.  
  1305.  
  1306. ;+
  1307. ; bsum
  1308. ;
  1309. ; Passed:
  1310. ;    a0 = starting address of buffer to be summed
  1311. ;    temp.l = current sum
  1312. ;
  1313. ; Function:
  1314. ;      - sum up 512 bytes of a buffer 4 bytes at a time
  1315. ;    - save the sum in temp.l
  1316. ;
  1317. ; Algorithm for check summing the FAT:
  1318. ;    - add up bytes in the buffer 4 bytes at a time    (in bsum)
  1319. ;    - if the sum is non-zero, XOR the high word     (in csum)
  1320. ;      with the low word of the 4-byte result
  1321. ;    - now take this 2-byte result, and XOR its high    (in csum)
  1322. ;      byte with its low byte to get the final 1-byte
  1323. ;      result
  1324. ;-
  1325. bsum:    movem.l    d1/a0,-(sp)        ; save d1, a0
  1326.     move.l    temp,d0            ; d0 = current sum
  1327.     move    #127,d1            ; count
  1328. bsum0:    add.l    (a0)+,d0        ; add 4 bytes to sum
  1329.     dbra    d1,bsum0        ; until all bytes are added
  1330.     move.l    d0,temp            ; temp.l = new sum
  1331.     movem.l    (sp)+,d1/a0        ; restore d1, a0
  1332.     rts
  1333.  
  1334.  
  1335. ;+
  1336. ; csum
  1337. ; (a) XOR the high word with the low word of temp.l
  1338. ; (b) then XOR the high byte with the low byte of result of (a)
  1339. ;
  1340. ; Returns:
  1341. ;    d0.b = checksum
  1342. ;-
  1343. csum:    move.w    temp+2,d0        ; d0.w = low word of result
  1344.     eor.w    d0,temp            ; exclusive-or low and high word
  1345.     move.b    temp+1,d0        ; d0.b = low byte of xor-ed result
  1346.     eor.b    d0,temp            ; exclusive-or low and high byte
  1347.     move.b    temp,d0
  1348.     rts                ; d0.b = checksum
  1349.  
  1350.  
  1351. ;
  1352. ;+
  1353. ;  Read/Write sectors
  1354. ;
  1355. ;    Synopsis:    _ahdi_rw(rw, buf, count, recno, dev, lrecno)
  1356. ;        WORD rw        4(sp).w        ; non-zero -> write
  1357. ;        char *buf    6(sp).l
  1358. ;        WORD count    $a(sp).w
  1359. ;        WORD recno    $c(sp).w
  1360. ;        WORD dev    $e(sp).w
  1361. ;        LONG lrecno    $10(sp).l    ; optional
  1362. ;-
  1363.  
  1364. ; stack frame offsets
  1365. xrw    equ    8
  1366. xbuf    equ    10
  1367. xcount    equ    14
  1368. xrecno    equ    16
  1369. xdev    equ    18
  1370. xlrecno    equ    20
  1371.  
  1372.     .globl    _sasi_rw
  1373.     .globl    _ahdi_rw
  1374. _sasi_rw:
  1375. _ahdi_rw:
  1376.     link    a6,#0            ; create a frame pointer
  1377.     subq.w    #2,xdev(a6)        ; drive # excluding A: and B:
  1378.  
  1379.     move.w    xdev(a6),d0        ; d0 = device number
  1380.     btst.b    #3,xrw+1(a6)        ; is this a physical operation?
  1381.     beq.s    getcpun            ; if not, find physical unit number
  1382.     move.w    d0,cpun            ; else, dev# passed is phys unit #
  1383. ;+
  1384. ;  Aug-08-91    ml. The following line trashed the sizr set up
  1385. ;            by the logical mode rwabs() which calls the
  1386. ;            physical mode rwabs() recursively.
  1387. ;    move.w    #1,sizr            ; sector size ratio = 1
  1388. ;-
  1389.  
  1390.     bra    ahrw1            ; go start the r/w
  1391. getcpun:                ; map log -> phys unit number
  1392.     lea    pun,a0            ; a0 -> pun table
  1393.     move.b    (a0,d0.w),cpun+1    ; cpun = pun of dev
  1394.     
  1395.     lea    sratio,a0        ; a0 -> sector size ratio table
  1396.     move.b    (a0,d0.w),sizr+1    ; sizr = current sector size ratio
  1397.                     ;     (coerced to word)
  1398.     lea    start,a0        ; a0 -> start table
  1399.     move.w    d0,d1            ; d1 = drive #
  1400.     add.w    d1,d1            ; d1*2*2 (index into tbl of longs)
  1401.     add.w    d1,d1
  1402.     move.l    (a0,d1.w),cstart    ; cstart = dev starting sector
  1403.  
  1404.     btst.b    #1,xrw+1(a6)        ; ignore media change?
  1405.     bne    ahrw1            ; if yes, go ahead and do r/w
  1406.                     ; else check for media change
  1407.     lea    mcflgs,a0        ; a0 -> mcflgs of drive
  1408.     move.b    (a0,d0.w),d0        ; d0 = mcflg of dev
  1409.     beq    ahrw1            ; if media not changed, go do r/w
  1410.  
  1411.     cmpi.b    #2,d0            ; is media definitely changed?
  1412.     beq    retmc            ; if yes, return media has changed
  1413.                     ; else, check if media has changed
  1414.                     ; try to read dev's boot sector
  1415. chkmc:    move.l    cstart,-(sp)        ; dev starting sector
  1416.     move.w    cpun,-(sp)        ; physical unit number
  1417.     addq.w    #2,(sp)            ; unit # including A: and B:
  1418.     move.w    #-1,-(sp)        ; using a long sector number
  1419.     move.w    #1,-(sp)        ; 1 sector
  1420.     move.l    _dskbufp,-(sp)        ; buffer
  1421.     move.w    #$a,-(sp)        ; phys mode and no media change error
  1422.     bsr    _ahdi_rw        ; ahdi_rw($a, buf, 1, -1, cpun, sectno)
  1423.     adda    #16,sp            ; clean up stack
  1424.     tst.w    d0            ; read successful?
  1425.     beq.s    chkser            ; yes, go check serial number
  1426.  
  1427.     move.w    xdev(a6),d1        ; device number
  1428.     bsr    critic            ; call critical error handler
  1429.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1430.     beq.s    chkmc            ; if yes, go back and try it
  1431.     bra    ahrw7            ; else return
  1432.  
  1433. chkser:    lea    serno,a1        ; a1 -> serial #s table
  1434.     move.w    xdev(a6),d0        ; d0 = dev number
  1435.     mulu.w    #SERLEN,d0        ; *SERLEN for index into table
  1436.     adda.l    d0,a1            ; a1 -> serial # of dev
  1437.  
  1438.     move.l    _dskbufp,a2        ; a2 -> boot sector
  1439.     addq.w    #8,a2            ; a2 -> serial # in boot sector
  1440.      move.w    #SERLEN-1,d0        ; d0 = count for comparison
  1441. cmpser:    cmpm.b    (a2)+,(a1)+        ; serial # read ?= serial # recorded
  1442.     bne    ismc            ; if not, media has changed
  1443.     dbra    d0,cmpser        ; compare next byte of serial #
  1444.                     ; serial # hasn't changed, try FAT
  1445.     moveq    #0,d1            ; coerce to long
  1446.     move.w    xdev(a6),d1        ; d0 = dev number
  1447.     lea    fatsum,a1        ; a1 -> fat checksum table
  1448.     lsl.l    #FATLEN,d1        ; d1.w = index into table
  1449.     adda.l    d1,a1            ; a1 -> fat checksum of dev
  1450.  
  1451.     add.w    d0,d0            ; d0*2 = index into table of words
  1452.     lea    fatst,a2        ; a2 -> FAT start table
  1453.     move.w    (a2,d0.w),fatrec    ; fatrec = fatst(dev)
  1454.  
  1455.     lea    fatend,a2        ; a2 -> FAT end table
  1456.     move.w    (a2,d0.w),d1        ; d1 = counter to scan FAT table
  1457.     sub.w    fatrec,d1        ;    = fatend(dev) - fatst(dev)
  1458.  
  1459.     movea.l    cstart,a2        ; a2 = start sector of dev
  1460.     move.w    fatrec,d2        ; d2 = fatst(dev)
  1461.     mulu    sizr,d2            ; d2 = fatst(dev) in 512-byte sector
  1462.     adda.l    d2,a2            ; a2 = phys start sector of 2nd FAT
  1463.  
  1464.     movea.l    _dskbufp,a0        ; a0 -> dskbuf
  1465. cmpfat:    move.w    sizr,d2            ; d2 = # reads per FAT sector
  1466.     subq.w    #1,d2            ; d2 - 1 = counter
  1467.     clr.l    temp            ; initialize sum
  1468. cfat0:    movem.l    d1-d2/a0-a2,-(sp)    ; save d1, d2, a0, a1, a2
  1469.                     ; try to read this FAT sector
  1470.     move.l    a2,-(sp)        ; at sector a2
  1471.     move.w    cpun,-(sp)        ; physical unit number
  1472.     addq.w    #2,(sp)            ; unit # including A: and B:
  1473.     move.w    #-1,-(sp)        ; using a long sector number
  1474.     move.w    #1,-(sp)        ; 1 sector
  1475.     move.l    a0,-(sp)        ; buffer
  1476.     move.w    #$a,-(sp)        ; phys mode and no media change error
  1477.     bsr    _ahdi_rw        ; ahdi_rw($a, buf, 1, -1, cpun, sectno)
  1478.     adda    #16,sp            ; clean up stack
  1479.     movem.l    (sp)+,d1-d2/a0-a2    ; restore d1, d2, a0, a1, a2
  1480.     tst.w    d0            ; read successful?
  1481.     beq.s    chkfat            ; if yes, go check sum FAT sectors
  1482.                     ; else assume it's read error
  1483.     movem.l    d1-d2/a0-a2,-(sp)    ; save registers d1, d2, a0, a2
  1484.     move.w    xdev(a6),d1        ; drive number
  1485.     bsr    critic
  1486.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers d1, d2, a0, a2
  1487.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1488.     beq.s    cfat0            ; if yes, go back and try it
  1489.     bra    ahrw7            ; else return
  1490.  
  1491. chkfat:    bsr    bsum            ; if ok, sum the sector
  1492.     addq    #1,a2            ; ready for try next sector
  1493.     dbra    d2,cfat0        ; until one FAT sector is summed
  1494.  
  1495.     bsr    csum            ; find the checksum
  1496.     cmp.b    (a1)+,d0        ; checksum recorded ?= checksum found
  1497.     bne    ismc            ; if not, media has changed
  1498.     dbra    d1,cmpfat        ; until all sectors are checked
  1499.  
  1500.     lea    mcflgs,a0        ; a0 -> mcflgs table
  1501.     adda.w    xdev(a6),a0        ; a0 -> mcflg of drive
  1502.     clr.b    (a0)            ; clear mcflg for dev
  1503.  
  1504. ahrw1:    tst.w    xcount(a6)        ; any sector to r/w?
  1505.     beq    ahrw6            ; if =0, done
  1506.  
  1507.     cmpi.w    #-1,xrecno(a6)        ; does recno = -1?
  1508.     bne.s    ahrw2            ; if not, we have a word record #
  1509.     movea.l    xlrecno(a6),a1        ; a1.l = start record #
  1510.     bra.s    ahrw3
  1511. ahrw2:    moveq    #0,d0            ; coerce to long
  1512.     move.w    xrecno(a6),d0        ; d0.l = recno
  1513.     movea.l    d0,a1            ; a1.l = start record #
  1514.  
  1515. ahrw3:    move.l    a1,strec        ; save first sector to r/w
  1516.     move.l    a1,d1            ; d1.l = starting sector to r/w
  1517.     moveq    #0,d2            ; coerce to long
  1518.     move.w    xcount(a6),d2        ; d2.l = #sectors to r/w
  1519.     adda.l    d2,a1            ; a1.l = last sector to r/w
  1520.     subq.l    #1,a1            ;      = first sector + count - 1
  1521.     move.l    a1,endrec        ; save last sector to r/w
  1522.     move.l    xbuf(a6),stbuf        ; save starting buffer address
  1523.  
  1524.     btst.b    #3,xrw+1(a6)        ; physical operation?
  1525.     bne.s    ahrw4            ; if so, ready to r/w
  1526.                     ; else log -> phys sector mapping
  1527.     mulu    sizr,d1            ; d1.l    = phys start sector to r/w
  1528.     add.l    cstart,d1        ;    = dev start sect + sect #
  1529.     mulu    sizr,d2            ; d2.l = # phys 512-byte sects to r/w
  1530.  
  1531. ahrw4:    move.w    xdev(a6),-(sp)        ; device # (excluding A: and B:)
  1532.     move.l    d1,-(sp)        ; starting sector
  1533.     move.l    d2,-(sp)        ; count (in sectors)
  1534.     move.l    xbuf(a6),-(sp)        ; buffer
  1535.     move.w    xrw(a6),-(sp)        ; read write flag
  1536.     bsr    _do_rw            ; do the read or write
  1537.     adda    #16,sp            ; clean up stack
  1538.     tst.l    d0            ; successful?
  1539.     beq.s    chkwr            ; if so, go on to wrap up
  1540.  
  1541.     cmpi.l    #E_CHNG,d0        ; media change detected?
  1542.     bne    ahrw7            ; if not, give up
  1543.     btst.b    #3,xrw+1(a6)        ; is this a physical operation?
  1544.     bne    ahrw7            ; if so, return media change error
  1545.     bra    chkmc            ; and go check if media has changed 
  1546.                     ; check if wrote to boot sector
  1547. chkwr:    move.w    xrw(a6),d0        ; d0 = r/w and flags word
  1548.     btst    #0,d0            ; read or write?
  1549.     beq    ahrw6            ; if read, done
  1550.     btst.b    #6,cpun+1        ; is drive removable?
  1551.     beq    ahrw6            ; if not, done
  1552.     btst    #3,d0            ; was it a physical operation?
  1553.     bne    ahrw6            ; if it was, done
  1554.     tst.l    strec            ; wrote to boot sector?
  1555.     bne.s    wrfat            ; if not, check if wrote to FATs
  1556.     lea    mcflgs,a0        ; else, a0 -> mcflgs table
  1557.     adda.w    xdev(a6),a0        ; a0 -> dev's mcflg
  1558.     move.b    #2,(a0)            ; assume medium has changed
  1559.                     ; check if wrote to FATs
  1560. wrfat:    lea    fatend,a0        ; a0 -> fatend table
  1561.     move.w    xdev(a6),d0        ; d0 = device number
  1562.     add.w    d0,d0            ; d0*2 = index into table of words
  1563.     moveq    #0,d1            ; coerce to long
  1564.     move.w    (a0,d0.w),d1        ; d1 = last sector of last FAT
  1565.     cmp.l    strec,d1        ; wrote beyond the last FAT?
  1566.     blt    ahrw6            ; if so, done
  1567.  
  1568.     lea    fatst,a0        ; a0 -> fatst table
  1569.     moveq    #0,d2            ; coerce to long
  1570.     move.w    (a0,d0.w),d2        ; d2 = first sector of last FAT
  1571.     cmp.l    endrec,d2        ; wrote before the last FAT?
  1572.     bgt    ahrw6            ; if so, done
  1573.                     ; else update FAT sector checksums
  1574.     move.l    stbuf,a0        ; a0 -> buffer w/ written data
  1575.     lea    fatsum,a1        ; a1 -> start of fatsum table
  1576.     moveq    #0,d0            ; coerce to long
  1577.     move.w    xdev(a6),d0        ; d0 = dev number
  1578.     lsl.l    #FATLEN,d0        ; d0 = offset to dev's FAT chksum
  1579.     adda.l    d0,a1            ; a1 -> dev's first FAT chksum
  1580.     move.l    strec,d0        ; d0 = first sector wrote to
  1581.     sub.l    d2,d0            ; d0 = strec - start(last FAT)
  1582.     beq.s    wrfat2            ; if strec = start(last FAT), 
  1583.                     ;     no adjustments needed
  1584.      blt.s    wrfat1            ; if strec < start(last FAT)
  1585.                     ;     begin from start(last FAT)
  1586.     move.l    strec,d2        ; else begin from strec
  1587.     adda.l    d0,a1            ; a1 -> fatsum to be updated
  1588.     bra.s    wrfat2
  1589.  
  1590. wrfat1:    neg.l    d0            ; d0 = index into stbuf
  1591.     asl.l    #8,d0            ;    = (start(last FAT) - strec)*512
  1592.     add.l    d0,d0
  1593.     adda.l    d0,a0            ; a0 -> addr of buf for update
  1594.  
  1595. wrfat2:    cmp.l    endrec,d1        ; if end(last FAT) <= endrec
  1596.     ble.s    wrfat3            ;     stop at end(last FAT)
  1597.     move.l    endrec,d1        ; else stop at endrec
  1598.  
  1599. wrfat3:    sub    d2,d1            ; d1 = # sectors to be processed
  1600. wrfat4:    move.w    sizr,d2            ; d2 = # phys sect per log sect
  1601.     subq.w    #1,d2            ; dbra likes one less
  1602.     clr.l    temp            ; initialize sum
  1603. wrfat5:    bsr    bsum            ; sum up one 512-byte sector
  1604.     adda.l    #512,a0            ; point to next 512 bytes
  1605.     dbra    d2,wrfat5        ; until one logical sector is done
  1606.     bsr    csum            ; obtain checksum
  1607.     move.b    d0,(a1)+        ; record new fat checksum
  1608.     dbra    d1,wrfat4        ; do until all are updated
  1609.  
  1610. ahrw6:    clr.l    d0            ; got here with no errors!
  1611.     bra.s    ahrw7
  1612.  
  1613. ismc:    lea    mcflgs,a0        ; a0 -> mcflgs table
  1614.     adda.w    xdev(a6),a0        ; a0 -> dev's mcflg
  1615.     move.b    #2,(a0)            ; set mcflg for dev to has changed
  1616.     lea    xst,a0            ; a0 -> drive existence table
  1617.     adda.w    xdev(a6),a0        ; a0 -> xst flag of dev
  1618.     move.b    #2,(a0)            ; assume dev exists
  1619. retmc:    move.l    #E_CHNG,d0        ; yes, return media change error
  1620.  
  1621. ahrw7:    btst.b    #0,xrw+1(a6)        ; read or write?
  1622.     bne.s    ahrwd            ; if write, done
  1623.     tst.b    _cachexst        ; does a cache exist?
  1624.     beq.s    ahrwd            ; if not, done
  1625.                     ; else dump the cache
  1626.     move.l    d0,-(sp)        ; save the status
  1627.     move    sr,-(sp)        ; go to IPL 7
  1628.     ori    #$700,sr        ; no interrupts right now kudasai
  1629.     movecacrd0            ; d0 = (cache control register)
  1630.     ori.w    #$808,d0        ; dump both the D and I cache
  1631.     moved0cacr            ; update cache control register
  1632.     move    (sp)+,sr        ; restore interrupt state
  1633.     move.l    (sp)+,d0        ; restore the return value
  1634.  
  1635. ahrwd:    unlk    a6
  1636.     rts
  1637.  
  1638.  
  1639. ;+
  1640. ; smove() - Copy unaligned sectors (this is *supposed* to be slow!)
  1641. ;
  1642. ; Passed:
  1643. ;    d0 = # of sectors to be moved
  1644. ;    d1 = size of operation    (0 - byte; 2 - long;)
  1645. ;    a2 -> source buffer
  1646. ;    a1 -> dest buffer
  1647. ;
  1648. ; Trashes: d0, a1, a2
  1649. ;-
  1650. smove:    move.w    d1,-(sp)        ; save size of operation
  1651.     neg.w    d1            ; d0 = count
  1652.     addi.w    #9,d1            ;    = (# sectors * 512) >> op size
  1653.     asl.w    d1,d0            ;
  1654.     subq.w    #1,d0            ; dbra likes one less
  1655.     move.w    (sp)+,d1        ; restore operation size
  1656.     bne.s    smove2            ; if non-zero, use move longs
  1657.  
  1658. smove1:    move.b    (a2)+,(a1)+
  1659.     dbra    d0,smove1
  1660.     rts
  1661.  
  1662. smove2:    move.l    (a2)+,(a1)+
  1663.     dbra    d0,smove2
  1664.     rts
  1665.  
  1666.  
  1667. ;
  1668. ;+
  1669. ; _do_rw - called to read/write no more than 128K to an even boundary
  1670. ;
  1671. ; Passed:
  1672. ;    rw    4(sp).w        ; non-zero -> write
  1673. ;    buf    6(sp).l
  1674. ;    count    $a(sp).l    ; in # phys (512-byte) sectors
  1675. ;    recno    $e(sp).l    ; physical starting sector for r/w
  1676. ;    dev    $12(sp).w    ; log dev # exluding A: and B:
  1677. ;
  1678. ; Assumes:
  1679. ;    cpun = current physical unit to r/w
  1680. ;    if in logical mode, cstart = physical starting sector # of curr dev
  1681. ;
  1682. ; Mar-05-1990 ml.
  1683. ;    All I/O to ACSI and SCSI non-accessible memory will be done by
  1684. ; using the fast ram buffer (if there is one) or the diskbuf as an inter-
  1685. ; mediate stop for the transfer.
  1686. ;
  1687. ; Mar-07-1990 ml.
  1688. ;    Do not have to take care of cases when Rwabs() is supplied with
  1689. ; a buffer that would cross different kinds of memory.
  1690. ; ("It's deadly!" said AKP. :) )
  1691. ;
  1692. ; Aug-19-1991 ml.
  1693. ;    On the TT, ACSI accessible RAM upper limit is 10Mb instead of
  1694. ; 4Mb.
  1695. ;
  1696. ; ACSI accessible memory: (on ST)   $00000000 -> $003fffff
  1697. ;                    $ff000000 -> $ff3fffff
  1698. ;              (on TT)   $00000000 -> $009fffff
  1699. ;                    $ff000000 -> $ff9fffff
  1700. ; SCSI non-accessible memory
  1701. ; on the TT:                $c0000000 -> $fcffffff
  1702. ;                    $fe000000 -> $feffffff
  1703. ;-
  1704. yrw    equ    $8
  1705. ybuf    equ    $a
  1706. ycount    equ    $e
  1707. yrecno    equ    $12
  1708. ydev    equ    $16
  1709.  
  1710. ; Memory that ACSI _can_ DMA to
  1711. STDUAL    equ    $003fffff    ; upper limit of dual-purpose RAM on an ST
  1712. STCMPIH    equ    $ff3fffff    ; upper limit of compatible image on an ST
  1713. TTDUAL    equ    $009fffff    ; upper limit of dual-purpose RAM on a TT
  1714. TTCMPIH    equ    $ff9fffff    ; upper limit of compatible image on a TT
  1715. SPDUAL    equ    $00dfffff    ; upper limit of dual-purpose RAM on a Sparrow
  1716. SPCMPIH    equ    $ffdfffff    ; upper limit of compatible image on a Sparrow
  1717. CMPIL    equ    $ff000000    ; lower limit of compatible image for all
  1718.  
  1719. ; Memory that SCSI _cannot_ DMA to (non-DW)
  1720. A32D16L    equ    $c0000000    ; lower limit of A32:D16 Memory/Peripherals
  1721. A32D16H    equ    $fcffffff    ; upper limit of A32:D16 Memory/Peripherals 
  1722. VA24D16    equ    $fe000000    ; lower limit of VMEbus A24:D16
  1723. VA16D16    equ    $feffffff    ; upper limit of VMEbus    A16:D16
  1724.  
  1725. ; Cookies
  1726. _FRB    equ    $5f465242        ; _FRB
  1727.  
  1728. _do_rw:    link    a6,#0            ; create a frame pointer
  1729.     move.l    ycount(a6),d2        ; d2.l = # sectors requested to r/w
  1730.      movea.l    ybuf(a6),a1        ; a1.l = buffer addr to r/w
  1731.     btst.b    #4,cpun+1        ; talking IDE?
  1732.     bne    atrw0            ; if yes, go for it
  1733.     btst.b    #3,cpun+1        ; else talking SCSI?
  1734.     beq.s    acrw0            ; if not, talking ACSI
  1735.     tst.b    _spscsixst        ; if so, talking Sparrow SCSI?
  1736.     beq    scrw0            ; if not, it's regular SCSI
  1737.                     ; else, it's Sparrow SCSI
  1738.     cmp.l    #MAXSPSECTS,d2        ; more than one DMAful?
  1739.     bls.s    acrw1            ; if not, go check boundary
  1740.     move.l    #MAXSPSECTS,d2        ; else set count to r/w only 1 DMAful
  1741.     bra.s    acrw1
  1742.  
  1743. acrw0:    cmp.l    #MAXACSECTS,d2        ; more than one DMAful?
  1744.     bls.s    acrw1            ; if not, go check boundary
  1745.     move.l    #MAXACSECTS,d2        ; else set count to r/w only 1 DMAful
  1746. acrw1:    btst.b    #0,ybuf+3(a6)        ; buffer on odd boundary?
  1747.     bne.s    itrw0            ; if so, do intermediate transfer
  1748.  
  1749.     cmpi.l    #TT,machine        ; is driver running on a TT?
  1750.     bne.s    acrw2            ; if not, go on
  1751.                     ; else check against TT limits
  1752.     cmpa.l    #TTDUAL,a1        ; buf within ACSI accessible memory?
  1753.     bls    rw1            ; if so, go ahead with the I/O
  1754.     cmpa.l    #CMPIL,a1        ; else, do intermediate transfer
  1755.     bcs.s    itrw0
  1756.     cmpa.l    #TTCMPIH,a1
  1757.     bls    rw1
  1758.     bra    itrw0
  1759.     
  1760. acrw2:    cmpi.l    #SPARROW,machine    ; is driver running on a Sparrow?
  1761.     bne.s    acrw3            ; if not, assume it's an ST or STE
  1762.  
  1763.     cmpa.l    #SPDUAL,a1        ; buf within ACSI accessible memory?
  1764.     bls    rw1            ; if so, go ahead with the I/O
  1765.     cmpa.l    #CMPIL,a1        ; else, do intermediate transfer
  1766.     bcs.s    itrw0
  1767.     cmpa.l    #SPCMPIH,a1
  1768.     bls    rw1
  1769.     bra.s    itrw0
  1770.                     ; driver is running on ST or STE
  1771. acrw3:    cmpa.l    #STDUAL,a1        ; buf within ACSI accessible memory?
  1772.     bls    rw1            ; if so, go ahead with the I/O
  1773.     cmpa.l    #CMPIL,a1        ; else, do intermediate transfer
  1774.     bcs.s    itrw0
  1775.     cmpa.l    #STCMPIH,a1
  1776.     bls    rw1
  1777.                     ; doing intermediate transfer
  1778. itrw0:    moveq    #0,d1            ; assume moving 1 byte at a time
  1779.     btst.b    #0,ybuf+3(a6)        ; odd boundary?
  1780.     bne.s    itrw1            ; if so, assumption ok
  1781.     moveq    #2,d1            ; else move 1 long at a time
  1782.  
  1783. itrw1:    tst.l    frbbuf            ; is there a fast RAM buffer?
  1784.     bne.s    itrw2            ; if there is one, use it
  1785.                     ; else look for _FRB
  1786.     move.l    d1,-(sp)        ; save d1
  1787.     move.l    #frbbuf,-(sp)        ; pointer to fast RAM buffer
  1788.     move.l    #_FRB,-(sp)        ; looking for _FRB cookie
  1789.     bsr    _getcookie        ; 
  1790.     addq.w    #8,sp            ; clean up stack
  1791.     move.l    (sp)+,d1        ; restore d1
  1792.     tst.w    d0            ; found _FRB?
  1793.     bne.s    itrw2            ; if so, use it
  1794.                     ; else use dskbuf
  1795.     movea.l    _dskbufp,a1        ; a1 -> dskbuf
  1796.     cmpi.w    #2,d2            ; can only do 2 at a time tops
  1797.     bls.s    itrw3
  1798.     move.w    #2,d2
  1799.     bra.s    itrw3
  1800.  
  1801. itrw2:    movea.l    frbbuf,a1        ; use the Fast RAM Buffer
  1802.     cmpi.w    #RAMRSV,d2        ; can only do RAMRSV at a time tops
  1803.     bls.s    itrw3
  1804.     move.w    #RAMRSV,d2
  1805.  
  1806. itrw3:    btst.b    #0,yrw+1(a6)        ; is this a read?
  1807.     beq.s    rw1            ; if so, go fill buffer from disk
  1808.                     ; else fill buffer here
  1809.     move.l    a1,-(sp)        ; preserve a1 = dest
  1810.     movea.l    ybuf(a6),a2        ; a2 = source
  1811.     move.w    d2,d0            ; # sectors to be moved
  1812.     bsr    smove            ; move sectors from a2 to a1
  1813.     movea.l    (sp)+,a1        ; restore a1.l = dest
  1814.     bra.s    rw1            ; go do the r/w
  1815.  
  1816. scrw0:    cmpi.l    #MAXSCSECTS,d2        ; more than one SCSI DMAful?
  1817.     bls.s    scrw1            ; if not, ready to r/w
  1818.     move.l    #MAXSCSECTS,d2        ; r/w only one SCSI DMAful?
  1819.  
  1820. scrw1:    
  1821.  
  1822. .if    SCDMA                ; if doing SCSI DMA
  1823. .if    !SCFRDMA            ; if no SCSI DMA to fast RAM
  1824.     cmpi.b    #$01,ybuf(a6)        ; is destination buffer in fast RAM?
  1825.     beq    itrw0            ; if so, do intermediate transfer
  1826. .endif    ;!SCFRDMA
  1827.  
  1828.     cmpa.l    #A32D16L,a1        ; buf in SCSI non-accessible
  1829.     bcs.s    rw1            ;  memory?
  1830.     cmpa.l    #A32D16H,a1        ; if so, do intermediate transfer
  1831.     bls    itrw0            ; else, go ahead with the I/O
  1832.     cmpa.l    #VA24D16,a1
  1833.     bcs.s    rw1
  1834.     cmpa.l    #VA16D16,a1
  1835.     bls    itrw0
  1836. .endif    ;SCDMA
  1837.  
  1838.     bra.s    rw1
  1839.  
  1840. atrw0:    cmp.l    #MAXIDESECTS,d2        ; more than one IDE gulp?
  1841.     bls.s    atrw1            ; if not, check boundary
  1842.     move.l    #MAXIDESECTS,d2        ; else, r/w only one IDE gulp
  1843. atrw1:    btst.b    #0,ybuf+3(a6)        ; buffer on odd boundary?
  1844.     bne    itrw0            ; if so, do intermediate transfer
  1845.                     ; else ready for r/w
  1846. rw0:    movea.l    ybuf(a6),a1        ; a1 = buffer address for r/w
  1847. rw1:    move.w    _retries,retrycnt    ; setup retry counter
  1848.  
  1849.     btst.b    #2,yrw+1(a6)        ; are retries disabled?
  1850.     beq.s    rw2            ; no, act normally
  1851.     move.w    #0,retrycnt        ; yes, so set retrycnt to zero
  1852.  
  1853. rw2:    movem.l    d1-d2/a1,-(sp)        ; preserve d1, d2 and a1
  1854.     move.w    cpun,-(sp)        ; dev.w
  1855.     move.l    a1,-(sp)        ; buf.l
  1856.     move.w    d2,-(sp)        ; count.w
  1857.     move.l    yrecno(a6),-(sp)    ; sect.L
  1858.  
  1859.     btst.b    #4,cpun+1        ; talking IDE?
  1860.     bne.s    rwide            ; if so, do IDE r/w
  1861.                     ; else it's ACSI or SCSI
  1862.     cmpi.l    #MAXACSECTS,d2        ; more than hr/w can handle?
  1863.     bhi.s    rw4            ; if so, use extended call (SCSI only)
  1864.     btst.b    #0,yrw+1(a6)        ; read or write?
  1865.     bne.s    rw3            ; (write)
  1866.     bsr    _hread            ; read sectors
  1867.     bra    rw6
  1868. rw3:    bsr    _hwrite            ; write sectors
  1869.     bra.s    rw6
  1870. rw4:    btst.b    #0,yrw+1(a6)        ; read or write?
  1871.     bne.s    rw5            ; (write)
  1872.     bsr    _xtdread        ; read sectors
  1873.     bra.s    rw6
  1874. rw5:    bsr    _xtdwrt            ; write sectors
  1875.     bra.s    rw6
  1876.  
  1877. rwide:    lea    idedp,a0        ; a0 -> drive param structure
  1878.     move.w    2(a0),-(sp)        ; # physical sectors per track
  1879.     move.w    (a0),-(sp)        ; # data heads
  1880.     btst.b    #0,yrw+1(a6)        ; read or write?
  1881.     bne.s    rwide2            ; (write)
  1882.     bsr    _ideread        ; read sectors
  1883.     bra.s    rwide3
  1884. rwide2:    bsr    _idewrite        ; write sectors
  1885. rwide3:    addq    #4,sp            ; (cleanup stack)
  1886. rw6:    adda    #12,sp            ; (cleanup stack)
  1887.     movem.l    (sp)+,d1-d2/a1        ; restore d1, d2 and a1
  1888.     tst.l    d0            ; errors?
  1889.     beq    rwf            ; no error --> successful
  1890.     bmi.s    rw9            ; timed out --> retry
  1891.  
  1892.     movem.l    d1-d2/a1,-(sp)        ; preserve d1, d2 and a1
  1893.     move.w    yrw(a6),-(sp)        ; rwflag
  1894.     bsr    errcode            ; find error code
  1895.     addq    #2,sp            ; clean up stack
  1896.     movem.l    (sp)+,d1-d2/a1        ; restore d1, d2 and a1
  1897.  
  1898.     cmpi.l    #E_CHNG,d0        ; media change detected?
  1899.     bne.s    rw7            ; if not, fine
  1900.                     ; else record media may be changed
  1901.     move.b    #1,d0            ; d0.b = 1 (may be changed)
  1902.     bsr    s_mc_xst        ; set mcflgs and xst flags for all dev
  1903.  
  1904.     btst.b    #1,yrw+1(a6)        ; ignore media change?
  1905.     bne    rw2            ; if so, retry operation
  1906.     bra    rwr            ; else return
  1907.     
  1908. rw7:    cmpi.l    #EWRPRO,d0        ; write protect error?
  1909.     beq.s    rwa            ; if so, return error
  1910.     cmpi.l    #EDRVNR,d0        ; drive not ready?
  1911.     beq.s    rwa            ; if so, return error
  1912.  
  1913. rw9:    subq.w    #1,retrycnt        ; drop retry count and retry
  1914.     bpl    rw2
  1915.  
  1916. rwa:    btst.b    #3,yrw+1(a6)        ; is this a physical operation?
  1917.     bne    rwr            ; if so, exit
  1918.                     ; else call critical error handler
  1919.     movem.l    d1-d2/a1,-(sp)        ; preserve d1, d2 and a1
  1920.     move.w    ydev(a6),d1        ; d1 = drive number
  1921. rwe:    bsr    critic
  1922.     movem.l    (sp)+,d1-d2/a1        ; restore d1, d2 and a1
  1923.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1924.     beq    rw2            ; if yes, go retry
  1925.     bra.s    rwr            ; else, head home
  1926.  
  1927. rwf:    lea    rw0,a0            ; exec of next r/w starts at rw0
  1928.     cmpa.l    ybuf(a6),a1        ; was alternate buffer used?
  1929.     beq.s    rw10            ; if not, go on to next r/w
  1930.                     ; else take care of transfer
  1931.     lea    itrw3,a0        ; exec of next r/w starts at itrw3
  1932.     btst.b    #0,yrw+1(a6)        ; was it a write?
  1933.     bne.s    rw10            ; if it was, go on to next write
  1934.                     ; else move data to supplied buffer
  1935.     move.l    a1,-(sp)        ; save address of alternate buffer
  1936.     movea.l    a1,a2            ; a2 = address of alternate buffer
  1937.     movea.l    ybuf(a6),a1        ; a1 = address of supplied buffer
  1938.     move.w    d2,d0            ; d0 = # of sectors to move
  1939.     bsr    smove            ; move data from alt buf to sup buf
  1940.     move.l    (sp)+,a1        ; restore address of alternate buffer
  1941.  
  1942. rw10:    sub.l    d2,ycount(a6)        ; ycount(a6) = # sects left to be done
  1943.     beq.s    rwd            ; if no more left, done
  1944.                     ; else get ready for next r/w
  1945.     add.l    d2,yrecno(a6)        ; yrecno(a6) = next starting sector
  1946.     move.l    d2,d0            ; d0 = # bytes done
  1947.     asl.l    #8,d0            ;    = # sectors done * 512
  1948.     add.l    d0,d0            ; 
  1949.     add.l    d0,ybuf(a6)        ; buf += (sectors_done * sector size)
  1950.     cmp.l    ycount(a6),d2        ; amount to r/w > amount doable?
  1951.     bls.s    rw11            ; if so, r/w amount doable
  1952.     move.l    ycount(a6),d2        ; else r/w all of it
  1953. rw11:    jmp    (a0)            ; go on to next r/w
  1954.  
  1955. rwd:    moveq    #0,d0            ; got here with no errors!
  1956. rwr:    unlk    a6            ; head home
  1957.     rts
  1958.  
  1959.  
  1960. ;
  1961. ;+
  1962. ; Check for media change on hard disk
  1963. ; Synopsis:    _sasi_mediach(dev)
  1964. ;        WORD dev;        4(sp).w
  1965. ;
  1966. ; Returns:    0L - media definitely has not changed
  1967. ;        1L - media _may_ have changed
  1968. ;        2L - media definitely has changed
  1969. ;
  1970. ; Uses:        d0, d1, a0, a1
  1971. ;
  1972. ; Comments:
  1973. ; Apr-4-1989    ml.    Add in grace period between _sasi_mediach()s.
  1974. ;            If _sasi_mediach() was called less than 1 s
  1975. ;            (200 _hz_200 clock ticks) ago, and medium was 
  1976. ;            not changed then, assume medium still has not 
  1977. ;            changed.
  1978. ;-
  1979. _sasi_mediach:
  1980.     subq.w    #2,4(sp)        ; dev # excluding drv A and B
  1981.     move.w    4(sp),d1        ; d1 = current drive
  1982.     lea    mcflgs,a0        ; a0 = pointer to mcflgs
  1983.     moveq    #0,d0            ; d0 = mcflg for current drive
  1984.     move.b    (a0,d1.w),d0    
  1985.     tst.b    d0            ; has medium changed?
  1986.     bne.s    decided            ; if yes or maybe, return result
  1987.                     ; else verify that it has not
  1988.     move.l    lastmdctm,d2        ; time media change was last called
  1989.     cmp.l    _hz_200,d2        ; while (_hz_200 <= lastmdctm)
  1990.     bcc.s    decided            ;    assume medium not changed
  1991.  
  1992.     lea    pun,a1            ; ptr to beginning of pun table
  1993.     move.b    (a1,d1.w),cpun+1    ; cpun = pun current drive belongs to
  1994.  
  1995.     btst.b    #6,cpun+1        ; is pun removable?
  1996.     beq.s    notchngd        ; if not, medium has not changed
  1997.  
  1998.     move.w    cpun,-(sp)        ; physical unit number
  1999.     bsr    _untrdy            ; verify by doing test unit ready
  2000.     addq.l    #2,sp
  2001.     move.l    _hz_200,lastmdctm    ; update time for last _sasi_mediach()
  2002.     addi.l    #200,lastmdctm        ; 
  2003.     tst.w    d0            ; return good status?
  2004.     beq.s    notchngd        ; if yes, return medium not changed
  2005.     moveq    #1,d0            ; else return medium may have changed
  2006.     bsr    s_mc_xst        ; set mcflgs and xst flags to 1's
  2007.     bra.s    decided
  2008. notchngd:
  2009.     moveq    #0,d0            ; return medium has not changed
  2010. decided:
  2011.     rts
  2012.  
  2013.  
  2014. ;+
  2015. ; s_mc_xst - set mcflgs and drive existence flags 
  2016. ;         for drives belonging to the current
  2017. ;         physical unit to value passed
  2018. ;
  2019. ; Passed:    d0.b - value to set to
  2020. ;-
  2021. s_mc_xst:
  2022.     movem.l    d1-d2/a0-a2,-(sp) ; save registers
  2023.     lea    pun,a0        ; a0 -> pun table
  2024.     lea    mcflgs,a1    ; a1 -> mcflgs table
  2025.     lea    xst,a2        ; a2 -> drive existence table
  2026.     move.w    cpun,d1        ; d1 = current physical unit #
  2027.     moveq    #0,d2        ; d2 = logical drive #; index into tables
  2028. set0:    btst.b    #7,(a0,d2.w)    ; a valid logical drive?
  2029.     bne.s    setr        ; if not, done
  2030.     cmp.b    (a0,d2.w),d1    ; else, does it belong to this physical unit?
  2031.     bne.s    set1        ; if not, move on to next logical drive
  2032.     move.b    d0,(a1,d2.w)    ; else change its mcflg to value passed
  2033.     move.b    d0,(a2,d2.w)    ; and change its xst to value passed
  2034. set1:    addq.w    #1,d2        ; try next one in forward direction
  2035.     cmp.w    #MAXLOG,d2    ; all units checked?
  2036.     blt.s    set0        ; if not, go on
  2037. setr:    movem.l    (sp)+,d1-d2/a0-a2 ; else restore registers
  2038.     rts            ; and return
  2039.  
  2040.  
  2041. ;
  2042. ;+
  2043. ; Resident Installer
  2044. ;-
  2045.     .globl    i_sasi6
  2046. i_sasi6:
  2047.     tst.b    idexst        ; IDE bus exists?
  2048.     beq.s    calcmem        ; if not, go calculate memory size
  2049.     cmpi.l    #SPARROW,machine    ; is driver running on a Sparrow?
  2050.     beq.s    calcmem
  2051. ;    move.b    #$10,d0        ; does IDE #0 exists?
  2052. ;    bsr    _drvxst
  2053. ;    beq.s    calcmem        ; if not, go calculate memory size
  2054.                 ; else
  2055.     move.w    ideidle,idesd    ; init current IDE spin down timeout
  2056.     beq.s    calcmem        ; if 0, don't set it
  2057.     move.w    ideidle,-(sp)    ; else set default time out
  2058.     move.w    #$10,-(sp)    ; IDE unit #0
  2059.     bsr    _awto        ; set up idle time out
  2060.     addq    #4,sp        ; clean up stack
  2061.  
  2062. ;+
  2063. ; 02-Apr-1991    ml.    The following is illegal, because i_sasi1 is 
  2064. ;            external.
  2065. ;    move.l    #(i_sasi1-i_sasi),tokeep ; at least keep this much
  2066. ;-
  2067. calcmem:
  2068.     move.l    #i_sasi1,tokeep ; tokeep = amount of code to be kept
  2069.     subi.l    #i_sasi,tokeep
  2070.     cmpi.w    #512,maxssz    ; maxssz > 512 bytes?
  2071.     bls.s    nboot1        ; if not, no need to replace GEMDOS buffers
  2072.                 ; else check if there is enough memory for
  2073. chkmem:    bsr    chklstmem    ;   new GEMDOS buffer lists
  2074.     tst.l    d0        ; enough?
  2075.     bpl.s    okbig        ; if so, build the list
  2076.     move.w    defbigsect,d0    ; d0 = minimum big sector
  2077.     cmp.w    maxssz,d0    ; is maxssz >= minimum big sector?
  2078.     bcc.s    regsect        ; if so, give up
  2079.     move.w    d0,maxssz    ; else try minimum big sector
  2080.     bra.s    chkmem
  2081. regsect:
  2082.     move.w    #512,maxssz    ; will not handle big sectors
  2083.     bra.s    nboot1
  2084.  
  2085. okbig:    move.l    d1,tokeep    ; update amount of memory to be kept
  2086.     lea    i_sasi1,a0    ; a0 -> beginning of new buffer lists
  2087.     moveq    #3,d1        ; d1 = count = 4 buffers - 1
  2088.     bsr    list_init    ; initialize the buffer list
  2089.     clr.l    (a0,d0.w)    ; cut 1 list of 4 buffers to 2 lists of 2
  2090.     move.l    a0,_bufl    ; _bufl[0] -> 1st new buffer list
  2091.     add.l    d0,d0        ; d0 = offset to beginning of 2nd buffer list
  2092.     adda.l    d0,a0        ; a0 = head of 2nd buffer list
  2093.     move.l  a0,_bufl+4    ; _bufl[1] -> 2nd new buffer list
  2094.  
  2095. nboot1:    bsr    pool_install    ; attempt to install more OS pool
  2096.     add.l    d0,tokeep    ; update amount of memory to be kept
  2097.  
  2098. ;+
  2099. ; Aug-15-91    ml. Check for existence of _FRB when needed instead of
  2100. ;            at boot time.
  2101. ;
  2102. ;    clr.l    frbbuf        ; assume no _FRB
  2103. ;    move.l    #frbbuf,-(sp)    ; pointer to fast RAM buffer
  2104. ;    move.l    #$5f465242,-(sp)    ; cookie "_FRB"
  2105. ;    bsr    _getcookie    ; try to find _FRB in cookie jar
  2106. ;    addq.w    #8,sp        ; clean up stack
  2107. ;-
  2108.  
  2109.     move.l    _hz_200,lastmdctm   ; initialize media change time
  2110.     tst.w    bootloaded    ; if bootloaded, then already in super mode
  2111.     bne.s    nboot2        ; (already there)
  2112.     move.l    savssp,-(sp)    ; become a mild mannered user process
  2113.     move.w    #$20,-(sp)    ; Super(savssp)
  2114.     trap    #1
  2115.     addq.w    #6,sp
  2116.  
  2117. ;+
  2118. ; Terminate and stay resident;
  2119. ; installed driver under GEMDOS.
  2120. ;-
  2121.     move.l    tokeep,d0    ; compute value for Ptermres()
  2122.     add.l    #$0100,d0    ; for basepage
  2123.     move.l    d0,-(sp)    ; save D0
  2124.     movea.l    #msg_nbl,a0    ; print not bootloaded message
  2125.     bsr    prnstr
  2126.     move.l    (sp)+,d0
  2127.     move.w    #0,-(sp)    ; exit code
  2128.     move.l    d0,-(sp)
  2129.     move.w    #$31,-(sp)    ; terminate and stay resident
  2130.     trap    #1        ; should never come back...
  2131.     illegal
  2132.  
  2133.  
  2134. ;+
  2135. ;  Return to TOS ROMs
  2136. ;    - set default boot device to C:
  2137. ;    - Print silly message
  2138. ;    - Mshrink() memory that was alloc'd to us
  2139. ;    - set magic# in D7 for TOS ROMs
  2140. ;    - RTS back to ROMs
  2141. ;-
  2142. nboot2:    move.l    tokeep,d0    ; compute value for Mshrink
  2143.     add.l    #$1c,d0        ; for file header
  2144.     move.l    d0,-(sp)    ; save D0
  2145.     movea.l    #msg_bl,a0    ; print bootloaded message
  2146.     bsr    prnstr
  2147.  
  2148.     move.w    d4,d1        ; physical unit # in d4.w?
  2149.     bpl.s    bd0        ; if so, good
  2150.                 ; else it's in hi 3 bits of d7.b
  2151.     move.b    d7,d1        ; d1.b = physical unit # boot loaded from
  2152.     lsr.b    #5,d1        ;      = xxx00000 >> 5
  2153. bd0:    lea    pun,a0        ; a0 -> pun table
  2154.     moveq    #0,d2        ; d2 = boot dev
  2155. bd1:    move.b    (a0,d2.w),d0    ; d0.b = unit #
  2156.     andi.b    #$1f,d0        ; mask out flags
  2157.     cmp.b    d0,d1        ; d2 belongs to physical unit booted from?
  2158.     beq.s    bd2        ; if yes, set (d2) as boot device
  2159.     addq.w    #1,d2        ; else try next logical unit
  2160.     bra.s    bd1
  2161. bd2:    addq.w    #2,d2        ; offset for drive A and B
  2162.     move.w    d2,_bootdev    ; set default boot device to (d2)
  2163.  
  2164.     move.l    baseaddr,-(sp)
  2165.     clr.w    -(sp)
  2166.     move.w    #$4a,-(sp)    ; Mshrink(...)
  2167.     trap    #1
  2168.     adda    #12,sp        ; (cleanup stack)
  2169.  
  2170.     move.w    _bootdev,-(sp)    ; set boot dev as default drive
  2171.     move.w    #$e,-(sp)    ; Dsetdrv(_bootdev)
  2172.     trap    #1
  2173.     addq.w    #4,sp        ; cleanup stack
  2174.  
  2175.     move.l    #rootpath,-(sp)    ; set root as current directory
  2176.     move.w    #$3b,-(sp)    ; Dsetpath('\')
  2177.     trap    #1
  2178.     addq.w    #6,sp        ; cleanup stack
  2179. ;
  2180. ;    move.l    _sysbase,a0    ; get the system header address
  2181. ;    move.l    $18(a0),d0    ; d0.l = MMDDYYYY of ROM date
  2182. ;    swap    d0        ; d0.l = YYYYMMDD of ROM date
  2183. ;    cmp.l    #CHKDATE,d0    ; does this version of ROM need bootstop?
  2184. ;    bcs.s    stopall        ; yup, if OS is built before 4/22/87
  2185. ;    move.b    puns+1,d7    ; else prevent processed units from booting
  2186. ;    subq.b    #1,d7        ; unit # = # of units - 1
  2187. ;    lsl.b    #5,d7
  2188. ;    rts            ; return to TOS ROMs
  2189. ;
  2190. ; Stop ANY subsequent boot after the hard disk boot -- FOR NOW!!
  2191. ;
  2192.  
  2193. stopall:
  2194.     move.b    #$100-$20,d7    ; prevent any other unit from booting
  2195.     rts            ; return to TOS ROMs
  2196.  
  2197. rootpath:
  2198.     dc.b    '\\',0
  2199. msg_bl:
  2200.     dc.b    '-----------------------',13,10
  2201.     dc.b    'BOOTLOADED',13,10,0
  2202. msg_nbl:
  2203.     dc.b    '-----------------------',13,10
  2204.     dc.b    'NOT Bootloaded',13,10,0
  2205. .even
  2206.  
  2207.  
  2208. ;+
  2209. ; list_init - Initialize a GEMDOS buffer list (BCBs are contiguous)
  2210. ;
  2211. ; Passed:
  2212. ;     a0.l = head of buffer list            (not changed)
  2213. ;    d0.l = size of each BCB (including data block)    (not changed)
  2214. ;    d1.w = count
  2215. ;         = number of buffers to be installed to the list - 1
  2216. ;
  2217. ; Uses:
  2218. ;    d1, a1
  2219. ;-
  2220. list_init:
  2221.     move.l    a0,-(sp)    ; save head of buffer list
  2222. lin0:    movea.l    a0,a1        ; a1 -> next BCB
  2223.     adda.l    d0,a1        ;    -> curr BCB + size of BCB
  2224.     move.l    a1,(a0)        ; b_link -> next BCB
  2225.     move.w    #-1,4(a0)    ; b_neg1 = -1
  2226.     adda.w    #BCBLEN,a0    ; a0 -> BCB data block
  2227.     move.l    a0,-4(a0)    ; b_bufr -> b_space
  2228.     movea.l    a1,a0
  2229.     dbra    d1,lin0
  2230.     suba.l    d0,a0        ; a0 -> last BCB
  2231.     clr.l    (a0)        ; lastBCB.b_link = NULL
  2232.     move.l    (sp)+,a0    ; restore head of buffer list
  2233.     rts
  2234.  
  2235.  
  2236. ;+
  2237. ; chklstmem - check if enough memory is allocated to replace GEMDOS
  2238. ;        buffer lists
  2239. ;
  2240. ; Returns:
  2241. ;    d0.l = size of each BCB (including data block)
  2242. ;         or -1 if not enough memory is allocated
  2243. ;    d1.l = new amount of memory to be kept if enough is allocated
  2244. ;
  2245. ; Uses:
  2246. ;    d0, d1
  2247. ;-
  2248. chklstmem:
  2249.     moveq    #BCBLEN,d0    ; d0.l = size of each BCB (inc. data block)
  2250.     add.w    maxssz,d0    ;      = BCB header len + data block size
  2251.     move.l    d0,d1        ; d1.l = d0.l * 4 
  2252.     lsl.l    #2,d1        ;      = total size of buffer lists
  2253.     add.l    tokeep,d1    ; d1.l = size needed
  2254.     cmp.l    memalloc,d1    ; enough memory allocated?
  2255.     bls.s    chk0        ; if so return
  2256.     moveq    #-1,d0        ; else return error
  2257. chk0:    rts
  2258.  
  2259.  
  2260. ;
  2261. ;+
  2262. ; critic - call up the critical error handler.
  2263. ;
  2264. ; Passed:
  2265. ;    d0.w = error code
  2266. ;    d1.w = drive # excluding A: and B:
  2267. ;
  2268. ; Uses:
  2269. ;    d0, d1, a0
  2270. ;
  2271. ; Returns:
  2272. ;    d0.l = whatever returned by the critical handler
  2273. ;        (magic RETRY code or something)
  2274. ;-
  2275. critic:    addq.w    #2,d1            ; drive # including A: and B:
  2276.     move.w    d1,-(sp)        ; drive #
  2277.     move.w    d0,-(sp)        ; error code
  2278.     movea.l    etv_critic,a0        ; a0 = address of error handler
  2279.     jsr    (a0)            ; critic_handler(error, drive)
  2280.     addq.l    #4,sp            ; clean up stack
  2281.     rts                ; return
  2282.  
  2283.  
  2284. ;+
  2285. ; errcode - For ACSI or SCSI drives, find error code for previous 
  2286. ;        Check Condition Status, and translate controller error
  2287. ;        code into BIOS error code.
  2288. ;      - For IDE-IDE drives, test for error bits, and translate
  2289. ;        error bits into BIOS error code.
  2290. ;
  2291. ; Passed:
  2292. ;    d0.b    = value of Status register (IDE drive ONLY)
  2293. ;    4(sp).w    = rwflag (bit 0 not set -> read; bit 0 set -> write)
  2294. ;
  2295. ; Assumed:
  2296. ;    cpun = current physical unit number
  2297. ;
  2298. ; Returns:
  2299. ;    d0.l = BIOS error code
  2300. ;
  2301. ; Sep-13-1989    ml. For non-extended request sense, ask for 0 byte.
  2302. ;            (0 is default to return 4 bytes.)
  2303. ; Aug-19-1991    ml. Moved translation of controller error code into
  2304. ;            BIOS error code from _ahdi_rw() to here.
  2305. ;-
  2306.     .globl    errcode
  2307. errcode:
  2308.     btst.b    #4,cpun+1        ; an IDE unit?
  2309.     bne.s    ideerr            ; if so, handle it the IDE way
  2310.                     ; else it's ACSI or SCSI
  2311.     moveq    #22,d1            ; assume requesting extended sense
  2312.     move.w    cpun,d0            ; d0 = physical unit number
  2313.     btst    #3,d0            ; a SCSI unit?
  2314.     bne.s    err0            ; if so, ready to request
  2315.     andi.w    #07,d0            ; else mask off other flags
  2316.     btst.b    d0,embscsi        ; an embedded SCSI unit using ACSI?
  2317.     bne.s    err0            ; if so, request extended sense
  2318.     moveq    #0,d1            ; else request non-extended sense
  2319. err0:    lea    sendata,a0        ; a0 -> sense data buffer
  2320.     movem.l    d1/a0,-(sp)        ; save data len and buffer address
  2321.     move.l    a0,-(sp)        ; sense data buffer
  2322.     move.w    d1,-(sp)        ; data length (in bytes)
  2323.     move.w    d0,-(sp)        ; physical unit number
  2324.     bsr    _rqsense        ; find out error code
  2325.     addq.l    #8,sp            ; clean up stack
  2326.     movem.l    (sp)+,d1/a0        ; restore d1 and a0
  2327.     tst.w    d0            ; successful?
  2328.     beq.s    err1            ; if not, return
  2329.     moveq    #-1,d0            ; error occurred
  2330.     rts
  2331. err1:    cmpi.w    #4,d1            ; extended or non-extended?
  2332.     bgt.s    err2            ; if extended, go get code
  2333.     move.b    (a0),d1            ; else byte 0 = error code
  2334.     andi.b    #$7f,d1            ; mask off valid bit
  2335.     bra.s    err3
  2336. err2:    move.b    12(a0),d1        ; else byte 12 = error code
  2337.  
  2338. err3:    cmpi.b    #MDMCHGD,d1        ; is it media change detected?
  2339.     bne.s    err4            ; if not, check further
  2340.     move.l    #E_CHNG,d0        ; else return media change error
  2341.     bra.s    errend
  2342.  
  2343. err4:    cmpi.b    #WRTPRTD,d1        ; is it write protect error?
  2344.     bne.s    err5            ; if not, check further
  2345.     move.l    #EWRPRO,d0        ; else return write protect error
  2346.     bra.s    errend
  2347.  
  2348. err5:    cmpi.b    #DRVNRDY,d1        ; is it drive not ready?
  2349.     bne.s    err7            ; if not, assume read or write fault
  2350. err6:    move.l    #EDRVNR,d0        ; else return drive not ready error
  2351.     bra.s    errend
  2352.  
  2353. err7:    btst.b    #0,5(sp)        ; read or write?
  2354.     bne.s    errw            ; (write)
  2355.     move.l    #EREADF,d0        ; return read fault
  2356.     bra.s    errend
  2357.  
  2358. ideerr:    btst    #DRDY,d0        ; is IDE drive not ready?
  2359.     beq.s    err6            ; if so, return drive not ready
  2360.  
  2361.     btst    #DWF,d0            ; is it write fault error?
  2362.     bne.s    err7            ; if not, assume read or write fault
  2363. errw:    move.l    #EWRITF,d0        ; else return write fault error
  2364. errend:    rts
  2365.  
  2366.  
  2367.  
  2368.  
  2369. ;
  2370. ;+
  2371. ; OS Pool Expansion
  2372. ;-
  2373.  
  2374. .if ospool
  2375. ;+
  2376. ;  Wire more pool into various ROM releases.
  2377. ;
  2378. ;    Passed:    nothing
  2379. ;    Returns:    D0 = #bytes extra used
  2380. ;-
  2381. pool_install:
  2382.     move.l    _sysbase,a3        ; a3 -> base of OS
  2383.  
  2384. ; make sure we're in ROM,
  2385. ; then get address of RAM location to patch:
  2386.  
  2387.     cmp.l    #$800000,a3        ; better be ROM
  2388.     blt    notrom
  2389.     lea    pool_tab(pc),a0        ; a0 -> table to match
  2390. pi_lp:    move.l    (a0)+,d1        ; d1 = date to match
  2391.     beq    badrom            ; (forget it, end of list)
  2392.     move.l    (a0)+,a2        ; a2 -> _root address for that date
  2393.     cmp.l    $18(a3),d1        ; match dates?
  2394.     bne.s    pi_lp            ; (no -- try again)
  2395.  
  2396.     move.w    numchunks,d0        ; d0 = amount of BSS to be used
  2397.     mulu    #chunksiz,d0        ;    = # chunks * size of a chunk
  2398.     move.l    d0,d1            ; d1 = total memory needed
  2399.     add.l    tokeep,d1        ;    = already keeping + extra OS pool
  2400.     cmp.l    memalloc,d1        ; enough is allocated?
  2401.     bgt.s    bdrom2            ; if not, don't add any
  2402.                     ; else install more OS pool
  2403.     movea.l    #i_sasi+2,a0        ; a0 -> base of first buffer
  2404.     adda.l    tokeep,a0        ;    = start of file + already keeping
  2405.     move.l    a0,-(sp)        ; save base of first buffer
  2406.     move.w    numchunks,d1        ; d0 = count-1
  2407.     subq.w    #1,d1
  2408. pin_1:    lea    chunksiz(a0),a1        ; a1 -> next buffer
  2409.     move.l    a1,(a0)            ; buffer -> next one
  2410.     move.w    #chunkno,-2(a0)        ; install chunksiz
  2411.     move.l    a1,a0            ; a0 -> next buffer
  2412.     dbra    d1,pin_1        ; (do some more)
  2413.  
  2414.     sub.w    #chunksiz,a0        ; a0 -> last block
  2415.     move.l    chunkno*4(a2),(a0)    ; last block -> first in root
  2416.     move.l    (sp)+,chunkno*4(a2)     ; root -> first of ours
  2417.     rts                ; return OK
  2418.  
  2419. ;+
  2420. ;  Print warning messages
  2421. ;  about bogus versions of the
  2422. ;  operating system.  Assume that
  2423. ;  every OS past 1-May-1986 has the
  2424. ;  pool fix installed.
  2425. ;
  2426. ;-
  2427. ok_date    =    %0000110010100001    ; 1-May-1986
  2428. notrom:    lea    m_notrom(pc),a0        ; ram-based system (5/29!)
  2429.     bra.s    bdrom1
  2430. badrom:    lea    m_badrom(pc),a0        ; illegal ROM system
  2431. bdrom1:    cmp.w    #ok_date,$1e(a3)    ; if ok_date <= os_dosdate(a3) 
  2432.     bcc    bdrom2            ; then don't print anything
  2433.  
  2434.     move.l    a0,-(sp)        ; print nasty message
  2435.     move.w    #9,-(sp)
  2436.     trap    #1
  2437.     addq.l    #6,sp
  2438.  
  2439. ; print msg and wait for RETURN
  2440.     pea    keymsg(pc)
  2441.     move.w    #9,-(sp)
  2442.     trap    #1
  2443.     addq.l    #6,sp
  2444.  
  2445. bdrom3:    move.w    #2,-(sp)        ; wait for [RETURN]
  2446.     move.w    #2,-(sp)
  2447.     trap    #13
  2448.     addq.l    #4,sp
  2449.     cmp.w    #13,d0
  2450.     bne    bdrom3
  2451.  
  2452. bdrom2:    moveq    #0,d0            ; 0 extra bytes used
  2453.     rts
  2454.  
  2455. keymsg:    dc.b    'Hard disk driver not loaded; hit RETURN',13,10
  2456.     dc.b    'key to continue:',13,10
  2457.     dc.b    0
  2458.  
  2459. m_notrom:
  2460.     dc.b    '*** WARNING ***',13,10,7
  2461.     dc.b    'This hard disk driver may not work with',13,10,7
  2462.     dc.b    'a disk-based version of TOS; files on',13,10,7
  2463.     dc.b    'your hard disk may be damaged.',13,10,7
  2464.     dc.b    13,10,7
  2465.     dc.b    0
  2466.  
  2467. m_badrom:
  2468.     dc.b    '*** WARNING ***',13,10,7
  2469.     dc.b    'You are using an unofficial ROM release',13,10,7
  2470.     dc.b    'of the operating system.  This driver',13,10,7
  2471.     dc.b    'may not work correctly with it.  Files',13,10,7
  2472.     dc.b    'on your hard disk may be damaged.',13,10,7
  2473.     dc.b    13,10,7
  2474.     dc.b    0
  2475.     even
  2476.  
  2477.  
  2478. ;+
  2479. ;  Table of ROM release dates / _root addresses
  2480. ;  update these for new ROM releases that need the patch.
  2481. ;
  2482. ;-
  2483. pool_tab:
  2484.     dc.l    $11201985,$56fa        ; USA and UK, 20-Nov-1985
  2485.     dc.l    $02061986,$56fa        ; Germany, 6-Feb-1986
  2486.     dc.l    $04241986,$56fa        ; France, 24-Apr-1986
  2487.     dc.l    0            ; end of list
  2488.  
  2489. .endif
  2490.  
  2491.  
  2492.