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 / TTDRIVER / 4.03 / DRIVER.S < prev    next >
Encoding:
Text File  |  2001-02-09  |  67.2 KB  |  2,168 lines

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