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 / ACSC / AHDI.S < prev    next >
Encoding:
Text File  |  2001-02-09  |  91.4 KB  |  3,069 lines

  1.  
  2. ; Jun 16 1989 v3.01'
  3.  
  4. ;------------------------------------------------------------------------
  5. ;                                    :
  6. ;    AHDI Hard Disk Driver for the Atari ST                :
  7. ;    Copyright 1985,1986,1987,1988,1989 Atari Corp.            :
  8. ;    All Rights Reserved                        :
  9. ;                                    :
  10. ;------------------------------------------------------------------------
  11.  
  12.  
  13. ;----------------
  14. ;
  15. ;  Conditional Assembly Switches
  16. ;
  17. format        equ    0        ; Format code
  18. mdsense        equ    0        ; Mode Sense code
  19. ospool        equ    1        ; increase size of OS pool for ROM
  20.  
  21.  
  22. ;
  23. ;-------------------- Edit History ------------------------
  24.  
  25. ;------------------
  26. ;                                    :
  27. ;  9-Apr-1985 lmd    Hacked it up.  "Gee, it seems to work ..."    :
  28. ; 14-Apr-1985 lmd    linked with BIOS (***FOR NOW***)        :
  29. ; 20-Apr-1985 lmd    hacked for WD controller (now, wired...)    :
  30. ; 24-Jun-1985 jwt    hacked for Adaptec, new kludge board        :
  31. ; 01-Jul-1985 jwt    seems to work, add more formatting and more    :
  32. ;             detailed error reporting            :
  33. ; 22-Jul-1985 jwt    change timing of wdc/wdl at start of command,    :
  34. ;             added extra move.w $8a,wdl to change A1    :
  35. ; 23-Jul-1985 jwt    use a move.l instruction for all wdc/wdl write    :
  36. ;             pairs since it changes A1 quickly enough that    :
  37. ;             the (old) DMA chip does not incorrectly    :
  38. ;             generate two chip selects            :
  39. ; 26-Sep-1985 jwt v0.05    support multiple ACSI devices            :
  40. ;            separate timeouts for command packet and    :
  41. ;             operation                    :
  42. ; 01-Oct-1985 jwt v0.06    added some AUXout serial debug messages        :
  43. ;            was responding to one more drive than was there    :
  44. ; 07-Oct-1985 jwt v0.07    added support for multiple partitions/drive    :
  45. ; 11-Oct-1985 jwt v0.08 added delay loop after pread for completion    :
  46. ;             byte                        :
  47. ; 19-Oct-1985 jwt v0.09    remove format and simple commands from resident :
  48. ;             part                        :
  49. ;            conditional assembly for default size        :
  50. ;            added count parameter to pread            :
  51. ; 22-Oct-1985 jwt v0.10    make certain qdone returns d0=-1 on timeout    :
  52. ;            add bits to read/write flag for:        :
  53. ;             retry disable (bit 2)                :
  54. ;             physical unit operation (bit 3)        :
  55. ;            add pun_ptr to TOS global variables        :
  56. ; 24-Oct-1985 jwt v0.11    add critical error call on errors        :
  57. ; 30-Jan-1986 lmd v0.12    increase OS pool by 128 chunks for ROM release    :
  58. ;             of 11/20/85                    :
  59. ;          jwt    stay resident if any physical units found    :
  60. ;             rather than if any GEM partitions found    :
  61. ; 05-Feb-1986 jwt    call critical error handler on errors unless    :
  62. ;             no-retry bit is set                :
  63. ;            conditional assembly format code        :
  64. ;            remove transfer only to even byte boundary    :
  65. ;             restriction                    :
  66. ;            remove transfer less than 128K restriction    :
  67. ;            check for 0 length transfer            :
  68. ; 06-Feb-1986 jwt v0.13    use register based accesses for wdc and wdl    :
  69. ; 25-Mar-1986 lmd v0.14 Enforce .005 (200th) sec delay between        :
  70. ;             successive calls to _do_rw().  SCSI adapter    :
  71. ;             board eats the controller's completion byte,    :
  72. ;             so we have to delay for it.            :
  73. ; 24-Apr-1986 lmd v1.1    Hack pool_install code to increase pool for    :
  74. ;             other ROM releases of the system.        :
  75. ; 24-Apr-1986 lmd v1.4    Print nasty messages for old disk-based and    :
  76. ;             unauthorized ROM-based systems.        :
  77. ; 23-Jun-1987 lmd v1.5  Fix date-check in nasty-OS-message code; wrong    :
  78. ;             offset into the OS header (now $1e).        :
  79. ; 06-Nov-1987 akp v1.7    Added procedure findpackages and call to it.    :
  80. ; 10-Nov-1987 akp    Changed source to MADMAC format.        :
  81. ;            Removed format flag from top of file.        :
  82. ; 24-Nov-1987 akp    Really made v1.7 work.                :
  83. ; 19-Feb-1988 ml    Added format and mode sense code for use in     :
  84. ;             HDX  (It's conditional, code will only be    :
  85. ;             included for ahdi.prg, and not shdriver.sys).    :
  86. ; 26-May-1988 ml    Added request sense code for use in HDX 3.0    :
  87. ;             for SR444 (Syquest drive).            :
  88. ; ??-Aug-1988 ml  v2.0    Attempted to add code for removable media.    :
  89. ; 07-Sep-1988 ml    Found out that shouldn't move code around too    :
  90. ;             much.  Labels i_sasi and i_sasi1 are used to    :
  91. ;             determine which part of this program will be    :
  92. ;             reserved at Ptermres().  All text and data to    :
  93. ;             be reserved should appear between these two    :
  94. ;             labels.                    :
  95. ; 31-Oct-1988 ml    It seemed to work well.  Now AHDI can handle    :
  96. ;             both removable and non-removable hard disks.    :
  97. ;            It can handle hard disks partitioned in    GEMDOS    :
  98. ;             format or MSDOS 3.x format.              :
  99. ;            Code for executing programs in the AUTO folder     :
  100. ;             and packages in RAM, and code for bringing up    :
  101. ;             AES have been deleted.  Instead, AHDI returns    :
  102. ;             to TOS ROMs and let them handle those tasks.    :
  103. ; 01-Dec-1988 ml    Modified _sasi_rw so that it will look for a     :
  104. ;             LONG record number after the device number, if :
  105. ;             the WORD record number == -1.  This allows the    :
  106. ;             caller of Rwabs to address pass 32Mb.        :
  107. ;             Though the underlying routine is the same, the    :
  108. ;             caller has to call Lrwabs from the high level,    :
  109. ;             not Rwabs for this to work.            :
  110. ; 02-Dec-1988 ml    Modified the way we check whether we should jam    :
  111. ;             d7 for further boot before returning to TOS    :
  112. ;             ROMs.  The system build date is being checked    :
  113. ;             instead of the OS version number.  This is    :
  114. ;             necessary because there seems to be confusion    :
  115. ;             about version numbers of some released ROMS.    :
  116. ; 05-Dec-1988 ml    If OS wasn't built before 4/22/1987, when     :
  117. ;             returning to TOS ROMs, jam d7 with the last     :
  118. ;             unit that was processed, instead of magic #.    :
  119. ; 08-Dec-1988 ml    If ospool code is included, make sure 'poolbuf'    :
  120. ;             is the last label in the program to be kept.    :
  121. ;             The code uses the memory after that label as    :
  122. ;             a buffer.  Whatever is after 'poolbuf' will be :
  123. ;             overwritten.                    :
  124. ; 04-Jan-1989 ml    Modified to handle more than 4 partitions per    :
  125. ;             physical unit.  The method used is the same as    :
  126. ;             used in MSDOS 3.3 (ie., by implementing a     :
  127. ;             linked list of logical drives).  There is a     :
  128. ;             type of partition called the EXTENDED GEMDOS    :
  129. ;             PARTITION which is head of the linked list.    :
  130. ;             This new type of partition is specified by the    :
  131. ;             value "XGM" in the p_id field of the partition    :
  132. ;             map.                        :
  133. ; 22-Feb-1989 ml v2.07a    Modified _fdone() and _qdone() to use 200 hz    :
  134. ;             clock for timeout loop.  This would keep the    :
  135. ;             timeout constant over different machines.    :
  136. ; 02-Mar-1989 ml v2.08a Moved pbuf up with regular declarations.  It    :
  137. ;             should stay resident.  Added a cookie pointer    :
  138. ;             for people to check if they have gotten this    :
  139. ;             new version of ahdi.                :
  140. ; 03-Mar-1989 ml    Changed cookie to 'AHDI'.  It will stay that     :
  141. ;             way.  Added version #, a long, right after    :
  142. ;             cookie ptr.                      :
  143. ;             Example: 19890208                :
  144. ;                 1989 - year 1989;            :
  145. ;                 02 - major version #;            :
  146. ;                 08 - minor version #;            :
  147. ; 06-Mar-1989 ml     Enforced 0.005 sec delay between driver calls.    :
  148. ;             Delay only when neccessary before 1st command    :
  149. ;             byte is sent, and update timer when command is    :
  150. ;             done.  New routine _delay().  Update timer     :
  151. ;             code is added in _endcmd().            :
  152. ; 07-Mar-1989 ml    More optimization done on low-level driver.    :
  153. ;             Use registers instead of wdlwdc when accessing    :
  154. ;             DMA registers, etc...                :
  155. ; 09-Mar-1989 ml    Forced driver to stay around even when no drive    :
  156. ;             is found.                    :
  157. ;            Made number of drive to reserve for each ACSI     :
  158. ;             Syquest drive patchable.            :
  159. ;             Magic number $f0ad is used to denote a version    :
  160. ;             with patchable variables.            :
  161. ;             Version number (same as one after the cookie    :
  162. ;             pointer) is stored after magic # $f0ad.    :
  163. ; 10-Mar-1989 ml    Made number of memory chunks to add to ospool    :
  164. ;             patchable.                    :
  165. ; 13-Mar-1989 ml v2.09a    If there is no cartridge in a Syquest drive,    :
  166. ;             return drive not ready, and pass to critical    :
  167. ;             error handler.                    :
  168. ; 29-Mar-1989 ml v2.10a Verion number is now a word, MMmm.        :
  169. ;             (MM - major #; mm - minor #)            :
  170. ;            Added in checks to see if enough memory is    :
  171. ;             allocated for ospool installation and big    :
  172. ;             GEMDOS buffer lists.                :
  173. ; 30-Mar-1989 ml    If there is not enough memory for big GEMDOS    :
  174. ;             buffer lists, make maximum sector size = 512.    :
  175. ;             This guarantees that the regular partitions     :
  176. ;             are still accessible.                :
  177. ;            If there is not enough memory to install amount    :
  178. ;             of OS pool requested. NONE would be installed. :
  179. ;            Variable 'poolbuf' is gone.            :
  180. ; 04-Apr-1989 ml    Sped up media change.  Refer to comments at    :
  181. ;             _sasi_mediach.                    :
  182. ; 11-Apr-1989 ml v3.00    Made version # consistent with HDX and HINSTALL.:
  183. ; 15-May-1989 ml    Initialize sendata buffer to be all 0's every    :
  184. ;             time before _inquiry() is called.        :
  185. ;            Fixed the bug for Dsetpath() (move.l #rootpath    :
  186. ;             instead of move.l rootpath).            :
  187. ; 16-Jun-1989 ml v3.01    Fixed the bug for odd boundary's write.  Should    :
  188. ;             have preserved a1.l since smove() trashes it.    :
  189. ;------------------------------------------------------------------------
  190.  
  191.  
  192. ;
  193. ;------------  Equates and Declarations--------------
  194.  
  195. etv_critic    equ    $404        ; critical error handoff vector
  196. phystop        equ    $42e        ; physical top of memory
  197. flock        equ    $43e        ; FIFO lock variable
  198. _bootdev    equ    $446        ; default boot device
  199. hdv_init    equ    $46a        ; hdv_init()    ** UNUSED **
  200. hdv_bpb        equ    $472        ; hdv_bpb(dev)
  201. hdv_rw        equ    $476        ; hdv_rw(rw, buf, count, recno, dev)
  202. hdv_boot    equ    $47a        ; hdv_boot()    ** UNUSED **
  203. hdv_mediach    equ    $47e        ; hdv_mediach(dev)
  204. _bufl        equ    $4b2        ; 2 buffer-list headers
  205. _hz_200        equ    $4ba        ; system 200hz timer
  206. _drvbits    equ    $4c2        ; block device bitVector
  207. _dskbufp    equ    $4c6        ; pointer to common disk buffer
  208. _sysbase    equ    $4f2        ; -> base of OS
  209. pun_ptr        equ    $516        ; number of physical units
  210.  
  211. ;+
  212. ; Restraints 
  213. ;-
  214. MAXUNITS    equ    14        ; max # of log units w/o drv A & B
  215. MAXACSI        equ    8        ; maximum number of ACSI devices
  216. MAXSECTORS    equ    254        ; maximum no. of sectors at one gulp
  217.  
  218. ;+
  219. ; Offsets to ...
  220. ;-
  221. DOSPM        equ    $1be        ; MSDOS boot sect's partition map
  222. DOSSIG        equ    $1fe        ; MSDOS boot sect's signature
  223. HDSIZ        equ    $1c2        ; offset to GEMDOS root sect's 
  224.                     ; hard disk size
  225.  
  226. ;+
  227. ; Constants and Variables
  228. ;-
  229. SIG        equ    $55aa        ; signature for valid MSDOS boot sects
  230. NRETRIES    equ    3        ; #retries-1
  231. MAXNPART    equ    3        ; #partition entries in root sect - 1
  232. BPBLEN        equ    18        ; length of bpb entry in bytes
  233. FATLEN        equ    64        ; max fat size = 64 sectors
  234.                     ; (for 16Mb drive, 2 spc, 512 bps)
  235. SERLEN        equ    3        ; length of a serial # in bytes
  236. CHKDATE        equ    $04221987    ; ROM date for bootstop checking
  237.  
  238. ;+
  239. ; BIOS error codes
  240. ;-
  241. EDRVNR        equ    -2        ; driver not ready
  242. EWRITF        equ    -10        ; write fault
  243. EREADF        equ    -11        ; read fault
  244. EWRPRO        equ    -13        ; write on write-protected media
  245. E_CHNG        equ    -14        ; media change detected
  246. CRITRETRY    equ    $00010000    ; "retry" return code
  247.  
  248. ;+
  249. ; SCSI error codes
  250. ;-
  251. DRVNRDY        equ    $4        ; drive not ready
  252. WRTPRTD        equ    $27        ; write on write-protected media
  253. MDMCHGD        equ    $28        ; media change detected
  254.  
  255. ;+
  256. ; Number of bytes per Buffer Control Block (excluding the data block itself)
  257. ;
  258. ; struct_bcb {
  259. ;     struct_bcb    *b_link;    /* 4 bytes */
  260. ;    int        b_neg1;        /* 2 bytes */
  261. ;    int        b_private[5];    /* 10 bytes */
  262. ;    char        *b_bufr;    /* 4 bytes */
  263. ; };
  264. ;
  265. ; For GEMDOS buffer lists.
  266. ;-
  267. BCBLEN        equ    20
  268.  
  269. ;+
  270. ; for extension of os pool
  271. ;-
  272. chunksiz    equ     66        ; #bytes/chunk
  273. chunkno        equ     4        ; chunk# (4 16-byte chunks)
  274.  
  275.  
  276. ;
  277. ;----------------
  278. ;
  279. ;  Entry points:
  280. ;
  281. ;    +0   GEMDOS entry point (double-click, or \AUTO folder on floppy)
  282. ;    +4   Boot entry point (from driver file off of C:)
  283. ;    +8   Reserved for future use
  284. ;    +$C  $F0AD magic number
  285. ;    +$E  version number
  286. ;    +$12 # chunks of ospool to add
  287. ;    +$14 # of sqnpart entries that follows
  288. ;    +$16 first sqnpart entry
  289. ;
  290. ;  if bootloaded, d0 = # bytes allocated by boot code.
  291. ;
  292. i_sasi:    bra    gboot            ; GEMDOS entry-point
  293.     bra    iboot            ; Boot entry-point
  294.     bra    iboot            ; (unused, reserved)
  295.  
  296.  
  297. ;----------------
  298. ;
  299. ;  Patchable variables
  300. ;
  301. magicnum:    dc.w    $f0ad        ; wasn't here in previous releases
  302. vernum:        dc.w    $0301        ; version number
  303. numchunks:    dc.w    128        ; # chunks of ospool to add
  304. minbigsect:    dc.w    512        ; minimum size of a big sector
  305. numsqnpart:    dc.w    MAXACSI        ; number of sqnpart entries to follow
  306. minsqnpart:    dcb.b    MAXACSI,1    ; minimum # drives for removable unit
  307. .even
  308.  
  309. ;----------------
  310. ;
  311. ;  GEMDOS entry;
  312. ;    find amount of memory availble and store in d0.l
  313. ;
  314. gboot:    movea.l    4(sp),a2        ; a2 -> basepage
  315.     move.l    4(a2),d0        ; d0 = available memory
  316.     sub.l    (a2),d0            ;    = p_hitpa - p_lowtpa - basepage
  317.     sub.l    #$0100,d0
  318.     bra    i_sasi1            ; (continue with normal initialization)
  319.  
  320.  
  321. ;----------------
  322. ;
  323. ;  Boot entry;
  324. ;    set "bootloaded", record base address from boot loader, 
  325. ;    and continue with normal boot process.
  326. ;
  327. iboot:    st    bootloaded        ; boot entry-point, set flag
  328.     sub.l    #$1c,d0            ; memory available -= file header
  329.     move.l    a2,baseaddr        ; install base address
  330.                     ; a2 = beginning addr of this block
  331.     bra    i_sasi1            ; (continue with normal initialization)
  332.  
  333.  
  334. ;
  335. ;--------------- Driver State --------------------
  336.  
  337.         dc.b    13,'AHDI : Jun 16 1989 v3.01'
  338.         dc.b    13,10,$bd,'Atari Corp. 1985, 1986, 1987, 1988, 1989'
  339.         dc.b    13,10,0,$1A
  340. .even
  341.  
  342. _puns:
  343. puns:        dc.w    0        ; # of physical units on user's system
  344.  
  345. dummy1:        dcb.b    2,-1        ; dummy pun entries for A and B
  346. _pun:
  347. pun:        dcb.b    MAXUNITS,0    ; physical unit table
  348. .even
  349.  
  350. dummy2:        dcb.l    2,0        ; dummy start entries for A and B
  351. _partstart:
  352. start:        dcb.l    MAXUNITS,0    ; partition start table
  353.  
  354. _cookie:                ; *** DON'T CHANGE ***
  355. cookie:        dc.l    $41484449    ; cookie = 'AHDI'
  356.  
  357. _cookptr:
  358. cookptr:    dc.l    0        ; pointer to cookie
  359.  
  360. _versn:
  361. versn:        dc.w    $0301        ; version number: MMmm
  362.  
  363. _maxssz:
  364. maxssz:        dc.w    512        ; maximum sector size allowed
  365.         dcb.l    16,0        ; reserved for future use
  366.  
  367. bpbs:    dcb.b    BPBLEN,0        ; a bpb 
  368. mcflgs:    dcb.b    MAXUNITS,2        ; media change flag table
  369. xst:    dcb.b    MAXUNITS,1        ; drive existence flag table
  370. serno:    dcb.b    MAXUNITS*SERLEN,0    ; serial number table
  371. sratio:    dcb.b    MAXUNITS,1        ; log sect size : phys sect size tbl
  372. fatsum:    dcb.b    MAXUNITS*FATLEN,0    ; FAT checksum table
  373. fatst:    dcb.w    MAXUNITS,0        ; starting sector # of last FAT
  374. fatend:    dcb.w    MAXUNITS,0        ; ending sector # of last FAT
  375.  
  376. bootloaded:    dc.w    0        ; nonzero if loaded from boot sector
  377. memalloc:    dc.l    0        ; total memory available if bootloaded
  378. baseaddr:    dc.l    0        ; -> base addr of .PRG file
  379. tokeep:        dc.l    0        ; amount memory to keep
  380. preadret:    dc.w    0        ; return code from pread
  381.  
  382. cpun:        dc.w    0        ; current physical unit
  383. npart:        dc.w    0        ; number of partitions found
  384. bfat:        dc.w    0        ; 0: 12-bit FAT; 1: 16-bit FAT
  385.  
  386. strec:        dc.l    0        ; starting sector to read/write
  387. endrec:        dc.l    0        ; last sector to read/write
  388. stbuf:        dc.l    0        ; starting address of buffer
  389. rmbits:        dc.b    0        ; bit map - 1: unit is removable
  390. scsi:        dc.b    0        ; bit map - 1: embedded SCSI drive
  391.  
  392. _retries:    dc.w    NRETRIES    ; number of retries to do
  393. retrycnt:    dc.w    1        ; retry counter
  394.  
  395. o_bpb:        dc.l    1
  396. o_rw:        dc.l    1
  397. o_mediach:    dc.l    1
  398.  
  399. sendata:    dcb.b    16,0        ; buffer for request sense
  400.  
  401. lastacstm:    dc.l    0        ; controller last accessed time
  402. lastmdctm:    dc.l    0        ; time media change was last called
  403. pbuf:        dc.l    0        ; ptr to start of root sector image
  404. fsiz:        dc.w    0        ; FAT size in sectors
  405. fatrec:        dc.w    0        ; 2nd FAT starting sector
  406. sizr:        dc.w    1        ; ratio of log : phys sector size
  407. temp:        dc.l    0        ; temporary storage
  408. savssp:        dc.l    1        ; (saved SSP)
  409. mcrw:        dc.b    0        ; if TRUE, r/w returns media change
  410. ext:        dc.b    0        ; if =0, not processing ext partition
  411.  
  412. extrt:        dc.l    0        ; starting sector of ext DOS partition
  413. extvol:        dc.l    0        ; offset wrt ext DOS partition
  414. pbpb:        dc.w    0        ; partition # for dev
  415. .even
  416.  
  417.  
  418. ;
  419. ;------------------ Front End ------------------
  420.  
  421. ;----------------
  422. ;
  423. ;  Return pointer to BPB (or NULL)
  424. ;
  425. ;    Synopsis:    LONG hbpb(dev)
  426. ;        WORD dev;    4(sp).w
  427. ;
  428. hbpb:    move.w    4(sp),d0        ; d0 = devno
  429.     clr    d1            ; d1 = 0, physical op not possible
  430.     movea.l    o_bpb,a0        ; a0 -> pass-through vector
  431.     lea    _sasi_bpb(pc),a1    ; a1 -> our handler
  432.     bra.s    check_dev        ; do it
  433.  
  434.  
  435. ;----------------
  436. ;
  437. ;  Read or write logical sectors
  438. ;
  439. ;    Synopsis:    LONG rw(rw, buf, count, recno, dev)
  440. ;        WORD rw;    $4(sp).w
  441. ;        char *buf;    $6(sp).l
  442. ;        WORD count;    $a(sp).w
  443. ;        WORD recno;    $c(sp).w
  444. ;        WORD dev;    $e(sp).w
  445. ;
  446. hrw:    move.w    $e(sp),d0        ; d0 = devno
  447.     move.w    4(sp),d1        ; d1 includes physical device flag
  448.     movea.l    o_rw,a0            ; a0 -> pass-through vector
  449.     lea    _sasi_rw(pc),a1        ; a1 -> our handler
  450.     bra.s    check_dev        ; do it
  451.  
  452.  
  453. ;----------------
  454. ;
  455. ;  Check for media change
  456. ;
  457. ;    Synopsis:    LONG mediach(dev)
  458. ;        WORD dev;    4(sp).W
  459. ;
  460. hmediach:
  461.     move.w    4(sp),d0        ; d0 = devno
  462.     clr    d1            ; physical operation not possible
  463.     movea.l    o_mediach,a0        ; a0 -> pass-through vector
  464.     lea    _sasi_mediach(pc),a1    ; a1 -> our handler
  465.  
  466.  
  467. ;----------------
  468. ;
  469. ;  check_dev - use handler, or pass vector through
  470. ;
  471. ;  Passed:    d0.w = device#
  472. ;        d1, bit 3  1=physical operation
  473. ;        a0 ->  old handler
  474. ;        a1 ->  new handler
  475. ;        a5 ->  $0000 (zero-page ptr)
  476. ;
  477. ;  Jumps-to:    (a1) if dev in range for this handler
  478. ;        (a0) otherwise
  479. ;
  480. check_dev:
  481.     subq    #2,d0            ; lowest device is 2 (unit 0 or C:)
  482.     bmi.s    chkd_f            ; if lower, not one of ours
  483.  
  484.     btst    #3,d1            ; is this a physical unit operation?
  485.     beq.s    chkd_a            ; if not set, go to chkd_a
  486.  
  487.     cmp    puns,d0            ; compare unit num to num units exist
  488.     bge.s    chkd_f            ; if unit num too big, not one of ours
  489.     bra.s    chkd_s            ; else it IS one of of ours
  490.  
  491. chkd_a:    lea    pun,a2            ; pointer to pun map
  492.     tst.b    0(a2,d0.w)        ; must be positive for a real unit
  493.     bmi.s    chkd_f
  494. chkd_s:    movea.l    a1,a0            ; yes -- follow success vector
  495. chkd_f:    jmp    (a0)            ; do it
  496.  
  497.  
  498. ;
  499. ;------------------ Medium-Level Driver ----------------
  500.  
  501. ;----------------
  502. ;
  503. ;  Return BPB for logical device
  504. ;
  505. ;    Synopsis:    LONG _sasi_bpb(dev)
  506. ;        WORD dev;    $4(sp).w
  507. ;
  508. ;    Returns:    NULL, or a pointer to the BPB buffer
  509. ;
  510. ; 10-21-88    ml.    I am not making a special case for non-removable
  511. ;            hard disk, because if a program uses Allan's
  512. ;            program to force a media change, the program 
  513. ;            should be getting the "Real" AND "New" BPB.
  514. ;            (The old (v1.7 and before) AHDI only index into
  515. ;            the bpbs table and return the pointer, without
  516. ;            actually go and read the boot sector of the dev.)
  517. ;
  518. _sasi_bpb:
  519.     subq.w    #2,4(sp)        ; dev # excluding drv A and B
  520. bpbst:    move.w    4(sp),d1        ; d1 = device number
  521.     lea    pun,a0            ; a0 = ptr to pun table
  522.     adda.w    d1,a0            ; a0 = ptr to pun @ dev's entry
  523.     clr.w    d2            ; coerce byte to word
  524.     move.b    (a0),d2            ; d2.w = pun that dev belongs to
  525.  
  526.     lea    xst,a1            ; a0 = ptr to drive existence table
  527.     tst.b    (a1,d1.w)        ; does drive exist?
  528.     bne.s    bpbgo            ; if it does, go on normally
  529.                     ; else, see if it really doesn't exist
  530.     movem.w    d1-d2,-(sp)        ; else save registers
  531.     move.w    d2,-(sp)        ; physical unit number
  532.     bsr    testunit        ; verify by doing test unit ready
  533.     addq.l    #2,sp            ; cleanup stack
  534.     movem.w    (sp)+,d1-d2        ; restore registers
  535.     tst.w    d0            ; return good status?
  536.     beq    badbpb            ; if yes, ie. medium has not changed
  537.                     ; therefore, dev still doesn't exist
  538.     moveq    #1,d0            ; else medium may have changed
  539.     bsr    s_mc_xst        ; set mcflgs and xst flags to 1's
  540.     bra.s    bpbst            ; restart procedure
  541.  
  542. bpbgo:    move.w    d2,cpun            ; cpun = pun(dev)
  543.     move.l    _dskbufp,pbuf        ; pbuf = ptr to 2nd half of 1K disk buf
  544.     add.l    #512,pbuf
  545.  
  546. bpb00:    move.l    a0,-(sp)        ; save ptr to pun(dev)
  547.     move.w    #1,-(sp)        ; return media change if detected
  548.     move.w    cpun,-(sp)        ; physical unit number
  549.     move.l    pbuf,-(sp)        ; buffer to read into
  550.     move.w    #1,-(sp)        ; read in 1 sector
  551.     clr.l    -(sp)            ; from sector 0
  552.     bsr    pread            ; pread(sectno, cnt, buf, phys#, flag)
  553.     adda    #14,sp
  554.     move.l    (sp)+,a0        ; restore ptr to pun(dev)
  555.     tst    d0            ; pread successful?
  556.     beq.s    bpb0            ; if yes, go on normally
  557.  
  558. bpberr:    cmpi.w    #E_CHNG,d0        ; is media change detected?
  559.     beq.s    bpbchg            ; if so, set mcflgs
  560.                     ; else call up error handler
  561.     move.l    a0,-(sp)        ; save ptr to pun(dev)
  562.     move.w    8(sp),d1        ; a0 = drive # excluding A: and B:
  563.     bsr    critic            ; call up critical error handler
  564.     move.l    (sp)+,a0        ; restore ptr to pun(dev)
  565.     cmpi.l    #CRITRETRY,d0        ; retry?
  566.     beq.s    bpb00            ; if so, go and try again
  567.     bra    badbpb            ; else return no BPB
  568.  
  569. bpbchg:    move.b    #1,d0            ; d0.b = media may be changed
  570.     move.w    4(sp),d1        ; d1.w = device number
  571.     move.b    cpun+1,d2        ; d2.b = physical unit number
  572.     bsr    s_mc_xst        ; go set mcflgs and xst flags
  573.     bra    bpbst            ; restart procedure
  574.  
  575. bpb0:    move.w    cpun,d2            ; d2 = physical unit number of dev
  576.     move.w    #0,pbpb            ; pbpb = partition # dev corresponds
  577. bpb1:    cmp.b    -(a0),d2        ; pun that dev belongs to == (a0)?
  578.     bne.s    bpb2
  579.     addq.w    #1,pbpb
  580.     bra.s    bpb1
  581.  
  582. bpb2:    move.w    #MAXNPART,d1        ; do #MAXNPART times
  583.     movea.l    pbuf,a0            ; a0 = ptr to beginning of root sector
  584.     cmpi.w    #SIG,DOSSIG(a0)        ; is root sector in DOS format?
  585.     bne.s    bpb3            ; if not, assume it's in GEMDOS format
  586.     bsr    dosbpb            ; else, handle it the DOS way
  587.     bra.s    bpb4            ; else, go get the bpb
  588. bpb3:    move.w    #1,bfat            ; 16 bit FAT always for GEMDOS
  589.     bsr    gembpb            ; handle it the GEMDOS way
  590. bpb4:    tst.w    d0            ; successful?
  591.     beq.s    bpbnf            ; if =0, no valid BPB found
  592.     bpl.s    bpb5            ; if +ive, valid BPB found
  593.     cmpi.w    #E_CHNG,d0        ; else media changed?
  594.     beq.s    bpbchg            ; if so, restart procedure
  595.     bra.s    badbpb            ; else no BPB found
  596.                     ; partition not found
  597. bpbnf:    lea    xst,a0            ; a0 = ptr to drive existence table
  598.     move.w    4(sp),d0        ; d0 = dev number
  599.     clr.b    (a0,d0.w)        ; dev definitely does not exist
  600.     lea    mcflgs,a0        ; a0 = ptr to mcflgs table
  601.     move.b    #2,(a0,d0.w)        ; set as medium has changed
  602.     bra.s    badbpb            ; can't find such a partition
  603.  
  604. bpb5:    move.l    d1,-(sp)        ; start_sector
  605.     move.w    8(sp),-(sp)        ; dev number
  606.     bsr    getbpb            ; getbpb(dev, start_sector)
  607.     addq.l    #6,sp            ; clean up stack
  608.     tst.l    d0            ; getbpb successful?
  609.     bpl.s    retbpb            ; if so, return ptr to bpb
  610.     cmpi.w    #E_CHNG,d0        ; media changed?
  611.     beq    bpbchg            ; if so, restart procedure
  612. badbpb:    moveq    #0,d0            ; return no bpb found
  613. retbpb:    rts
  614.  
  615.  
  616. ;
  617. ;+
  618. ; dosbpb - find the DOS partition that corresponds to the requested
  619. ;       logical drive
  620. ; Passed:
  621. ;    a0 = buffer address for root sector
  622. ;    d1 = number of entries in partition map
  623. ;
  624. ; Assumed:
  625. ;    pbpbs = partition being looked for
  626. ;
  627. ; Returns:
  628. ;    d0.b = 0        if partition not found
  629. ;         = negative #    some kind of error
  630. ;         = positive #    system indicator of the partition
  631. ;    d1.l = starting sector of the partition (if it is found)
  632. ;-
  633. dosbpb:    adda.w    #DOSPM,a0        ; a0 = ptr to partition map
  634. dbpb0:    movem.l    d1/a0,-(sp)        ; save count and offset
  635.     sf    ext            ; not dealing with ext partition
  636.     bsr    fdpart            ; find a partition
  637.     tst.b    d0            ; found any?
  638.     beq.s    dbpba            ; not a valid partition
  639.     cmpi.b    #5,d0            ; extended partition?
  640.     bne.s    dbpb1            ; if not, it's a regular partition
  641.     st    ext            ; else, it's an extended partition
  642.     move.l    #0,extvol        ; offset from start of partition = 0
  643.     move.l    d1,extrt        ; starting sector # of ext partition
  644. dbpbx:    bsr    fdnxt            ; find next logical drive
  645.     tst.b    d0            ; found any?
  646.     beq.s    dbpba            ; no logical drive found
  647.     bmi.s    dbpb2            ; error returned
  648.     cmpi.b    #5,d0            ; extended volume?
  649.     beq.s    dbpbx            ; if so, go find next logical drive
  650. dbpb1:    subq.w    #1,pbpb            ; partition that we want?
  651.     bpl.s    dbpb3            ; if not, continue the search
  652. dbpb2:    addq.l    #8,sp            ; else clean up stack
  653.     move.w    #0,bfat            ; assume partition has 12-bit fat
  654.     cmpi.b    #1,d0            ; 12-bit fat?
  655.     beq.s    dbpb22            ; if so, return
  656.     move.w    #1,bfat            ; else bflag = 1 for 16-bit fat
  657. dbpb22:    bra.s    dbpbr            ; and return
  658. dbpb3:    tst.b    ext            ; clun is in ext partition?
  659.     bne.s    dbpbx            ; if so, go find next ext vol
  660. dbpba:    movem.l    (sp)+,d1/a0        ; restore count and offset
  661.     adda    #16,a0            ; index to next entry in pmap
  662.     dbra    d1,dbpb0
  663.     moveq    #0,d0            ; partition not found!
  664. dbpbr:    rts
  665.  
  666.     
  667. ;+
  668. ; fdpart - find a DOS partition.
  669. ;
  670. ; Passed:
  671. ;    a0 = address to partition entry
  672. ;
  673. ; Returns:
  674. ;    d0.b = 0        partition is not valid
  675. ;         = positive    #    partition is a valid partition
  676. ;           (this is the system indicator of the partition)
  677. ;    d1.l = starting sector # of a valid partition (if d0.b = 1 or 4)
  678. ;         = starting sector # of extended partition (if d0.b = 5)
  679. ;-
  680. fdpart:    tst.l    12(a0)            ; partition's size?
  681.     beq.s    fdp0            ; if =0, not valid
  682.  
  683.     move.b    4(a0),d0        ; d0 = system indicator
  684.     beq.s    fdpr            ; if =0, not valid
  685.  
  686.     cmpi.b    #4,d0            ; if =4, valid
  687.     beq.s    fdp1
  688.  
  689.     cmpi.b    #1,d0            ; if =1, valid
  690.     beq.s    fdp1
  691.  
  692.     cmpi.b    #5,d0            ; if =5, valid
  693.     beq.s    fdp1
  694.  
  695. fdp0:    moveq    #0,d0            ; else, not valid
  696.     bra.s    fdpr
  697.  
  698. fdp1:    move.l    8(a0),d1        ; d1.l = swapped starting sector #
  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. fdpr:    rts
  703.  
  704.  
  705. ;+
  706. ; fdnxt - find a logical drive in the extended DOS partition
  707. ;
  708. ; Passed:
  709. ;    d0.b = (= 5 if a new extended volume was found)
  710. ;           (= 0 if nxtdrv was successful for last logical drive found)
  711. ;    d1.l = starting sector # of this extended volume
  712. ;    d2.b = count down for logical drive entries (if d0.b != 5)
  713. ;    a0.l = address of partition entry to be checked (if d0.b != 5)
  714. ;
  715. ; Assumes:
  716. ;    cpun = current physical unit #
  717. ;    extrt = starting sector # of extended DOS partition
  718. ;    extvol = offset from start of extended DOS partition (in sectors)
  719. ;
  720. ; Returns:
  721. ;    d0.b = 0        no logical drive found
  722. ;         = positive #    valid logical drive found
  723. ;           (this is the system indicator of the logical drive)
  724. ;         = negative #    error occured
  725. ;    d1.l = starting sector # of the logical drive (if d0.b = 1 or 4)
  726. ;         = starting sector # of next extended volume (if d0.b = 5)
  727. ;-
  728. fdnxt:    cmpi.b    #5,d0        ; new extended volume found?
  729.     bne.s    fdnxt0        ; if not, search for one
  730.     move.w    #1,-(sp)    ; return media change if detected
  731.     move.w    cpun,-(sp)    ; physical unit number
  732.     move.l    _dskbufp,-(sp)    ; buffer to read into
  733.     move.w    #1,-(sp)    ; read in 1 sector
  734.     move.l    d1,-(sp)    ; from beginning of extended volume
  735.     bsr    pread        ; pread(sectno, cnt, buf, phys#, flag)
  736.     adda    #14,sp        ; cleanup stack
  737.     tst.w    d0        ; pread successful?
  738.     bne    fdnxtr        ; if so, return
  739.     
  740.     movea.l    _dskbufp,a0    ; else, 
  741.     cmpi.w    #SIG,DOSSIG(a0)    ; boot record valid?
  742.     bne.s    fdnxtr        ; if not, return no drive found
  743.                 ; (d0 already set by pread)
  744.     adda.w    #DOSPM-16,a0    ; a0 = ptr to 1st entry in log drive map
  745.     move.w    #MAXNPART+1,d2    ; d2 = count for # of log drive entries
  746.  
  747. fdnxt0:    subq.w    #1,d2        ; more entries to search?
  748.     bmi.s    fdnxt1        ; if not, return
  749.  
  750.     adda    #16,a0        ; a0 = ptr to entry to be examined
  751.     tst.l    12(a0)        ; partition size's?
  752.     beq.s    fdnxt0        ; if =0, not valid
  753.  
  754.     move.b    4(a0),d0    ; d0 = system indicator
  755.     beq.s    fdnxt0        ; if =0, not valid
  756.  
  757.     move.l    8(a0),d1    ; d1.l = logical start sector of drv or vol
  758.     beq.s    fdnxt0        ; if =0, not valid
  759.     ror.w    #8,d1        ; swap hi and lo byte of high word
  760.     swap    d1        ; swap hi and lo word
  761.     ror.w    #8,d1        ; swap hi and lo byte of low word
  762.  
  763.     cmpi.b    #4,d0        ; if =4,
  764.     beq.s    fdnxt2        ; valid logical drive found
  765.  
  766.     cmpi.b    #1,d0        ; if =1,
  767.     beq.s    fdnxt2        ; valid logical drive found
  768.  
  769.     cmpi.b    #5,d0        ; if =5, valid ptr to next ext volume
  770.     bne.s    fdnxt0        ; else, not valid
  771.     move.l    d1, extvol    ; offset of ext vol from start of ext DOS
  772.     bra.s    fdnxt3
  773.  
  774. fdnxt1:    moveq    #0,d0        ; return no drive found
  775.     bra.s    fdnxtr
  776.  
  777. fdnxt2:    add.l    extvol,d1    ; d1 = start sector wrt beginning of ext DOS
  778. fdnxt3:    add.l    extrt,d1    ; d1 = start sector wrt beginning of disk
  779. fdnxtr:    rts
  780.  
  781.  
  782. ;
  783. ;+
  784. ; gembpb - find the GEMDOS partition that corresponds to the requested
  785. ;       logical drive.
  786. ; Passed:
  787. ;    a0 = buffer address for root sector
  788. ;    d1 = number of entries in partition map
  789. ;
  790. ; Assumed:
  791. ;    pbpbs = partition being looked for
  792. ;
  793. ; Returns:
  794. ;    d0.b = 0        if partition not found
  795. ;         = negative #    some kind of error
  796. ;         = positive #    system indicator of the partition
  797. ;    d1.l = starting sector of the partition (if it is found)
  798. ;-
  799. gembpb:    adda.w    #HDSIZ,a0        ; a0 = ptr to hard disk size
  800.     tst.l    (a0)+            ; size? (a0 = ptr to start of pmap)
  801.     beq.s    gbpb4            ; if =0, no drive will exist
  802. gbpb0:    movem.l    d1/a0,-(sp)        ; save count and offset
  803.     sf    ext            ; not dealing with ext partition
  804.     bsr    fgpart            ; find partitions
  805.     tst.b    d0            ; found any?
  806.     beq.s    gbpba            ; not a valid partition
  807.     cmpi.b    #'X',d0            ; extended partition?
  808.     bne.s    gbpb1            ; if not, it's a regular partition
  809.     st    ext            ; else, it's an extended partition
  810.     move.l    #0,extvol        ; offset from start of partition = 0
  811.     move.l    d1,extrt        ; starting sector # of ext partition
  812. gbpbx:    bsr    fgnxt            ; find next logical drive
  813.     tst.b    d0            ; found any?
  814.     beq.s    gbpba            ; no logical drive found
  815.     bmi.s    gbpb2            ; error returned
  816.     cmpi.b    #'X',d0            ; extended volume?
  817.     beq.s    gbpbx            ; if so, go find next logical drive
  818. gbpb1:    subq.w    #1,pbpb            ; partition that we want?
  819.     bpl.s    gbpb3            ; if not, continue the search
  820. gbpb2:    addq.l    #8,sp            ; else BINGO!  Clean up stack
  821.     bra.s    gbpbr            ; and return
  822. gbpb3:    tst.b    ext            ; clun is in ext partition?
  823.     bne.s    gbpbx            ; if so, go find next ext vol
  824. gbpba:    movem.l    (sp)+,d1/a0        ; restore count and offset
  825.     adda    #12,a0            ; index to next entry in pmap
  826.     dbra    d1,gbpb0
  827. gbpb4:    moveq    #0,d0            ; partition not found!
  828. gbpbr:    rts
  829.  
  830.  
  831. ;+
  832. ; fgpart - find a GEMDOS partition.
  833. ;
  834. ; Passed:
  835. ;    a0 = address to partition entry
  836. ;
  837. ; Returns:
  838. ;    d0.b = 0        partition is not valid
  839. ;         = positive    #    partition is a valid partition
  840. ;           (this is the first byte in p_id of the partition)
  841. ;    d1.l = starting sector # of a valid partition (if d0.b = 'G' or 'B')
  842. ;         = starting sector # of extended partition (if d0.b = 'X')
  843. ;-
  844. fgpart:    tst.b    (a0)            ; check the valid partition flag
  845.     beq.s    fgp2            ; if =0, not valid
  846.  
  847.     tst.l    8(a0)            ; partition's size?
  848.     beq.s    fgp2            ; if =0, not valid
  849.  
  850.     cmpi.b    #'G',1(a0)        ; must find GEM as type
  851.     bne.s    fgp0            ; for REGULAR partition
  852.     cmpi.b    #'E',2(a0)        ; (ie., partition < 16Mb)
  853.     bne.s    fgp0
  854.     cmpi.b    #'M',3(a0)
  855.     beq.s    fgp3
  856.  
  857. fgp0:    cmpi.b    #'B',1(a0)        ; must find BGM as type
  858.     bne.s    fgp1            ; for BIG partition
  859.     cmpi.b    #'G',2(a0)        ; (ie., partition >= 16Mb)
  860.     bne.s    fgp1
  861.     cmpi.b    #'M',3(a0)
  862.     beq.s    fgp3
  863.  
  864. fgp1:    cmpi.b    #'X',1(a0)        ; or find XGM as type
  865.     bne.s    fgp2            ; for EXTENDED GEMDOS 
  866.     cmpi.b    #'G',2(a0)        ; partition
  867.     bne.s    fgp2            ; (ie., partition with
  868.     cmpi.b    #'M',3(a0)        ;  a linked list of
  869.     beq.s    fgp3            ;  logical drives)
  870.  
  871. fgp2:    moveq    #0,d0            ; else, not valid
  872.     bra.s    fgpr
  873.  
  874. fgp3:    move.l    4(a0),d1        ; d1.l = starting sector #
  875.     move.b    1(a0),d0        ; d0.b = first byte of p_id
  876. fgpr:    rts
  877.  
  878.  
  879. ;+
  880. ; fgnxt - find a logical drive in the extended GEMDOS partition
  881. ;
  882. ; Passed:
  883. ;    d0.b = (= 'X' if a new extended volume was found)
  884. ;           (= 0 if nxtdrv was successful for last logical drive found)
  885. ;    d1.l = starting sector # of this extended volume
  886. ;    d2.b = count down for logical drive entries (if d0.b != 'X')
  887. ;    a0.l = address of partition entry to be checked (if d0.b != 'X')
  888. ;
  889. ; Assumes:
  890. ;    cpun = current physical unit #
  891. ;    extrt = starting sector # of extended GEMDOS partition
  892. ;    extvol = offset from start of extended GEMDOS partition (in sectors)
  893. ;
  894. ; Returns:
  895. ;    d0.b = 0        no logical drive found
  896. ;         = positive #    valid logical drive found
  897. ;           (this is the first byte of p_id of the logical drive)
  898. ;         = negative #    error occured
  899. ;    d1.l = starting sector # of the logical drive (if d0.b = 'G' or 'B')
  900. ;         = starting sector # of next extended volume (if d0.b = 'X')
  901. ;-
  902. fgnxt:    cmpi.b    #'X',d0        ; new extended volume found?
  903.     bne.s    fgnxt0        ; if not, search for one
  904.     move.w    #1,-(sp)    ; return media change if detected
  905.     move.w    cpun,-(sp)    ; physical unit number
  906.     move.l    _dskbufp,-(sp)    ; buffer to read into
  907.     move.w    #1,-(sp)    ; read in 1 sector
  908.     move.l    d1,-(sp)    ; from beginning of extended volume
  909.     bsr    pread        ; pread(sectno, cnt, buf, phys#, flag)
  910.     adda    #14,sp        ; cleanup stack
  911.     tst.w    d0        ; pread successful?
  912.     bne    fgnxtr        ; if not, return error
  913.  
  914.     movea.l    _dskbufp,a0    ; a0 = ptr to partition map
  915.     adda.w    #HDSIZ+4-12,a0    ; a0 = ptr to 1st entry in log drive map
  916.     move.w    #MAXNPART+1,d2    ; d2 = count for # of log drive entries
  917.  
  918. fgnxt0:    subq.w    #1,d2        ; more entries to search?
  919.     bmi.s    fgnxt3        ; if not, return
  920.  
  921.     adda    #12,a0        ; a0 = ptr to entry to be examined
  922.     tst.l    8(a0)        ; partition size's?
  923.     beq.s    fgnxt0        ; if =0, not valid.  Try next entry
  924.  
  925.     tst.b    (a0)        ; check the valid partition flag
  926.     beq.s    fgnxt0        ; if =0, not valid.  Try next entry
  927.  
  928.     move.l    4(a0),d1    ; d1.l = logical start sector of drv or vol
  929.  
  930.     cmpi.b    #'G',1(a0)    ; must find GEM as type
  931.     bne.s    fgnxt1        ; for REGULAR partition
  932.     cmpi.b    #'E',2(a0)    ; (ie., partition < 16Mb)
  933.     bne.s    fgnxt1
  934.     cmpi.b    #'M',3(a0)
  935.     beq.s    fgnxt4
  936.  
  937. fgnxt1:    cmpi.b    #'B',1(a0)    ; must find BGM as type
  938.     bne.s    fgnxt2        ; for BIG partition
  939.     cmpi.b    #'G',2(a0)    ; (ie., partition >= 16Mb)
  940.     bne.s    fgnxt2
  941.     cmpi.b    #'M',3(a0)
  942.     beq.s    fgnxt4
  943.  
  944. fgnxt2:    cmpi.b    #'X',1(a0)    ; or find XGM as type
  945.     bne.s    fgnxt3        ; for EXTENDED GEMDOS 
  946.     cmpi.b    #'G',2(a0)    ; partition
  947.     bne.s    fgnxt3        ; (ie., partition with
  948.     cmpi.b    #'M',3(a0)    ;  a linked list of
  949.     bne.s    fgnxt0        ;  logical drives)
  950.  
  951.     move.l    d1, extvol    ; offset of ext vol from start of ext GEMDOS
  952.     bra.s    fgnxt5
  953.  
  954. fgnxt3:    moveq    #0,d0        ; return no drive found
  955.     bra.s    fgnxtr
  956.  
  957. fgnxt4:    add.l    extvol,d1    ; d1 = start sector wrt beginning of ext DOS
  958. fgnxt5:    add.l    extrt,d1    ; d1 = start sector wrt beginning of disk
  959.     move.b    1(a0),d0    ; d0.b = first byte of p_id
  960. fgnxtr:    rts
  961.  
  962.  
  963. ;
  964. ;--------------
  965. ;
  966. ; getbpb(dev, sectorno)
  967. ; WORD dev;        4(sp).w
  968. ; LONG sectorno;    6(sp).l
  969. ;
  970. ; Assume -
  971. ;    cpun contains physical unit number of dev
  972. ;
  973. getbpb:    move.w    #1,-(sp)        ; return media change if detected
  974.     move.w    cpun,-(sp)        ; physical unit
  975.     move.l    _dskbufp,-(sp)        ; buffer
  976.     move.w    #1,-(sp)        ; 1 sector
  977.     move.l    $10(sp),-(sp)        ; sector # of boot sector
  978.     bsr    pread            ; pread(bootsect, 1, buf, phys#, flag)
  979.     adda    #14,sp            ; clean up stack
  980.     tst.w    d0            ; any trouble reading?
  981.     beq.s    getb0            ; if no, go on normally
  982.     cmpi.w    #EREADF,d0        ; was it a read error?
  983.     beq.s    getb9            ; if it is, retry
  984.     cmpi.w    #EDRVNR,d0        ; was it drive not ready?
  985.     bne    getb8            ; if not, return
  986.                     ; else let user retry
  987. getb9:    move.w    4(sp),d1        ; d1 = drive # excluding A: and B:
  988.     bsr    critic
  989.     cmpi.l    #CRITRETRY,d0        ; retry?
  990.     bne    getb7            ; if not, return
  991.     bra.s    getbpb            ; else read again
  992.  
  993. getb0:    movea.l    _dskbufp,a0        ; a0 = ptr to boot sector image
  994.     movea.l    #bpbs,a2        ; a2 = ptr to bpb
  995.  
  996.     move.w    #$0b,d0
  997.     bsr    getlhw
  998.     cmp.w    maxssz,d0        ; is sector size too big?
  999.     bhi    getb7            ; if it is, can't handle it
  1000.     move.w    d0,(a2)+        ; =byt/sec
  1001.     beq    getb7            ; if =0, bad data
  1002.     move.w    d0,d1
  1003.     divu    #512,d0            ; d0.b = ratio log : phys sector size
  1004.     move.w    d0,sizr            ; save the ratio
  1005.  
  1006.     clr.w    d0
  1007.     move.b    $d(a0),d0
  1008.     move.w    d0,(a2)+        ; =sec/cluster
  1009.     beq    getb7            ; if =0, bad data
  1010.  
  1011.     mulu    d1,d0
  1012.     move    d0,(a2)+        ; =byt/cluster
  1013.  
  1014.     move    #$11,d0
  1015.     bsr    getlhw            ; number of directory entries
  1016.     tst    d0            ; num o' entries ?= 0
  1017.     beq    getb7            ; if so, bad data
  1018.     mulu    #32,d0            ; size of each entry
  1019.     divu    d1,d0            ; number of sectors required
  1020.     move.l    d0,d1
  1021.     swap    d1
  1022.     tst    d1
  1023.     beq.s    getb1
  1024.     addq    #1,d0            ; round up
  1025. getb1:    move    d0,(a2)+        ; =rdlen
  1026.     move    d0,d2
  1027.  
  1028.     move    #$16,d0
  1029.     bsr    getlhw
  1030.     move    d0,(a2)+        ; =FATsize
  1031.     beq    getb7            ; if =0, bad data
  1032.     move    d0,d1
  1033.     move    d0,fsiz            ; save FAT size
  1034.  
  1035.     move    #$e,d0
  1036.     bsr    getlhw            ; number of reserved sectors
  1037.     add    d1,d0
  1038.     move    d0,(a2)+        ; =2nd FAT start
  1039.     move    d0,fatrec        ; save 2nd FAT start 
  1040.  
  1041.     add    d1,d0            ; plus size of second fat
  1042.     add    d2,d0            ; plus rdlen
  1043.     move    d0,(a2)+        ; = data start
  1044.     move    d0,d2            ; save start of data
  1045.  
  1046.     move    #$13,d0
  1047.     bsr    getlhw            ; number of sectors on media
  1048.     sub    d2,d0            ; subtract # used by FATs,dir,boot
  1049.     beq    getb7            ; if =0, bad data
  1050.     clr.l    d1
  1051.     move    d0,d1
  1052.     clr    d0
  1053.     move.b    $d(a0),d0        ; number of sectors/cluster
  1054.     divu    d0,d1            ; rounding down
  1055.     move    d1,(a2)+        ; =number of clusters
  1056.     move    bfat,(a2)        ; =flags, 12 or 16 bit fats
  1057.  
  1058.     move.w    sizr,d2            ; d2 = current sector size ratio
  1059.     lea    sratio,a1        ; a1 = ptr to sector size ratio table
  1060.     move.w    4(sp),d0        ; d0 = drive number
  1061.     move.b    d2,(a1,d0.w)        ; update sector size ratio in table
  1062.  
  1063.     move.w    cpun,d1            ; d1 = physical unit #
  1064.     btst.b    d1,rmbits        ; is unit removable?
  1065.     beq    getb6            ; if not, can skip the fat checksum
  1066.  
  1067.     lea    serno,a1        ; a1 = ptr to table of serial #s
  1068.     mulu.w    #SERLEN,d0        ; dev# * SERLEN to index into table
  1069.     adda.l    d0,a1            ; a1 = ptr to serial # of dev
  1070.     move.w    #SERLEN-1,d1        ; length of serial # - 1
  1071. getb2:    move.b    $8(a0,d1.w),(a1,d1.w)    ; update serial # of dev
  1072.     dbra    d1,getb2
  1073.  
  1074.     lea    fatsum,a2        ; a2 = ptr to FAT check sum table
  1075.     move.w    4(sp),d0        ; d0 = dev number
  1076.     mulu    #FATLEN,d0        ; d0*FATLEN = to index into table
  1077.     adda.l    d0,a2            ; a2 = ptr to FAT check sum tbl of dev
  1078.  
  1079.     move.w    fatrec,d0        ; d0 = log starting sector of 2nd FAT
  1080.     mulu    d2,d0            ; (in 512-byte sectors)
  1081.     movea.l    $6(sp),a1        ; a1 = starting sector of drive
  1082.     adda.l    d0,a1            ; a1 = phys starting sector of 2nd FAT
  1083.  
  1084.     move.w    fsiz,d1            ; d1 = # FAT sectors to read
  1085.     subq.l    #1,d1            ;    = FAT size - 1
  1086.  
  1087. getb3:    move.w    sizr,d2            ; d2 = count per FAT sector
  1088.     subq.w    #1,d2
  1089.      clr.l    temp            ; initialize the sum
  1090. getb4:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers
  1091.     move.w    #1,-(sp)        ; return media change if detected
  1092.     move.w    cpun,-(sp)        ; physical unit
  1093.     move.l    a0,-(sp)        ; buffer (in _dskbufp)
  1094.     move.w    #1,-(sp)        ; read 1 phys sector
  1095.     move.l    a1,-(sp)        ; from sector a1
  1096.     bsr    pread            ; pread()
  1097.     adda    #14,sp            ; clean up stack
  1098.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers
  1099.     tst.w    d0            ; pread successful?
  1100.     beq    getb5            ; if so, go on normally
  1101.     cmpi.w    #EREADF,d0        ; read error?
  1102.     beq.s    getba            ; if so, retry
  1103.     cmpi.w    #EDRVNR,d0        ; drive not ready?
  1104.     bne    getb8            ; if not, return
  1105.  
  1106. getba:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers
  1107.     move.w    24(sp),d1        ; d1 = drive # excluding A: and B:
  1108.     bsr    critic            ; critical error handler
  1109.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers
  1110.     cmpi.l    #CRITRETRY,d0        ; retry?
  1111.     beq.s    getb4            ; if so, try again
  1112.     bra    getb7            ; else return
  1113.  
  1114. getb5:    bsr    bsum            ; add up values in the sector
  1115.     addq    #1,a1            ; get ready for next sector
  1116.     dbra    d2,getb4        ; until one logical FAT sector is done
  1117.  
  1118.     bsr    csum            ; find the checksum
  1119.     move.b    d0,(a2)+        ; update checksum for this FAT sector
  1120.     dbra    d1,getb3        ; until all sectors are checked
  1121.  
  1122. getb6:    move.w    $4(sp),d0        ; d0 = dev number
  1123.     lea    mcflgs,a0        ; load address of mcflgs table
  1124.     clr.b    (a0,d0.w)        ; clear mcflg for dev
  1125.  
  1126.     lea    xst,a0            ; a0 = ptr to drive existence table
  1127.     move.b    #2,(a0,d0.w)        ; dev definitely exists
  1128.  
  1129.     lea    fatst,a0        ; a0 = ptr to FAT start sector table
  1130.     asl.w    #1,d0            ; offset = dev# * 2 (tbl of words)
  1131.     move    fatrec,(a0,d0.w)    ; update FAT starting sect#
  1132.  
  1133.     lea    fatend,a0        ; a0 = ptr to FAT end sector table
  1134.     move.w    fatrec,d1        ; d1 = fatend(dev)
  1135.     add.w    fsiz,d1            ;    = fatrec + fsiz - 1
  1136.     subq.w    #1,d1    
  1137.     move.w    d1,(a0,d0.w)        ; fatend(dev) = fatrec + fsiz - 1
  1138.  
  1139.     lea    start,a0        ; a0 = ptr to beginning of start table
  1140.     asl.w    #1,d0            ; offset = dev# * 2 * 2 (tbl of longs)
  1141.     move.l    $6(sp),(a0,d0.w)    ; update starting sect# of dev
  1142.  
  1143.     move.l    #bpbs,d0        ; no errors, return ptr to BPB
  1144.     bra.s    getb8            ; return
  1145.  
  1146. getb7:    moveq    #-1,d0            ; error
  1147. getb8:    rts
  1148.  
  1149.  
  1150. ;+
  1151. ; WORD getlhw(d0=offset)
  1152. ; returns word (low,high) from 0(D0,A0)
  1153. ;-
  1154.  
  1155. getlhw:    move    d1,-(sp)        ; preserve d1
  1156.     move.b    1(a0,d0.w),d1
  1157.     lsl.w    #8,d1
  1158.     move.b    0(a0,d0.w),d1
  1159.     move    d1,d0
  1160.     move    (sp)+,d1
  1161.     rts
  1162.  
  1163.  
  1164. ;+
  1165. ; bsum
  1166. ;
  1167. ; Passed:
  1168. ;    a0 = starting address of buffer to be summed
  1169. ;    temp.l = current sum
  1170. ;
  1171. ; Function:
  1172. ;      - sum up 512 bytes of a buffer 4 bytes at a time
  1173. ;    - save the sum in temp.l
  1174. ;
  1175. ; Algorithm for check summing the FAT:
  1176. ;    - add up bytes in the buffer 4 bytes at a time    (in bsum)
  1177. ;    - if the sum is non-zero, EOR the high word     (in csum)
  1178. ;      with the low word of the 4-byte result
  1179. ;    - now take this 2-byte result, and EOR its high    (in csum)
  1180. ;      byte with its low byte to get the final 1-byte
  1181. ;      result
  1182. ;-
  1183. bsum:    movem.l    d1/a0,-(sp)        ; save d1, a0
  1184.     move.l    temp,d0            ; d0 = current sum
  1185.     move    #127,d1            ; count
  1186. bsum0:    add.l    (a0)+,d0        ; add 4 bytes to sum
  1187.     dbra    d1,bsum0        ; until all bytes are added
  1188.     move.l    d0,temp            ; temp.l = new sum
  1189.     movem.l    (sp)+,d1/a0        ; restore d1, a0
  1190.     rts
  1191.  
  1192.  
  1193. ;+
  1194. ; csum
  1195. ; (a) EOR the high word with the low word of temp.l
  1196. ; (b) then EOR the high byte with the low byte of result of (a)
  1197. ;
  1198. ; Returns:
  1199. ;    d0.b = checksum
  1200. ;-
  1201. csum:    move.w    temp+2,d0        ; d0.w = low word of result
  1202.     eor.w    d0,temp            ; exclusive-or low and high word
  1203.     move.b    temp+1,d0        ; d0.b = low byte of xor-ed result
  1204.     eor.b    d0,temp            ; exclusive-or low and high byte
  1205.     move.b    temp,d0
  1206.     rts                ; d0.b = checksum
  1207.  
  1208.  
  1209. ;
  1210. ;----------------
  1211. ;
  1212. ;  Read/Write sectors
  1213. ;
  1214. ;    Synopsis:    _ahdi_rw(rw, buf, count, recno, dev, lrecno)
  1215. ;        WORD rw        4(sp).w        ; non-zero -> write
  1216. ;        char buf    6(sp).l
  1217. ;        WORD count    $a(sp).w
  1218. ;        WORD recno    $c(sp).w
  1219. ;        WORD dev    $e(sp).w
  1220. ;        WORD lrecno    $10(sp).l    ; optional
  1221. ;-
  1222.  
  1223. ; stack frame offsets
  1224. xrw    equ    8
  1225. xbuf    equ    10
  1226. xcount    equ    14
  1227. xrecno    equ    16
  1228. xdev    equ    18
  1229. xlrecno    equ    20
  1230.  
  1231. _sasi_rw:
  1232. _ahdi_rw:
  1233.     link    a6,#0            ; create a frame pointer
  1234.     subq.w    #2,xdev(a6)        ; drive # excluding A: and B:
  1235.     move.w    xrw(a6),d0        ; r/w and flags word
  1236.     andi.b    #$a,d0            ; phys op?  ignore media change?
  1237.     bne    ahrw1            ; yes, go ahead and do r/w
  1238.                     ; else check for media change
  1239.     lea    sratio,a1        ; a1 = ptr to sector size ratio table
  1240.     adda.w    xdev(a6),a1        ; a1 = ptr to dev's sector size ratio
  1241.     move.b    (a1),sizr+1        ; sizr = current sector size ratio
  1242.                     ;     (coerced to word)
  1243.     lea    mcflgs,a0        ; a0 = ptr to mcflgs of drive
  1244.     adda.w    xdev(a6),a0        ; a0 = ptr to dev's mcflg
  1245.     move.b    (a0),d0            ; d0 = mcflg of dev
  1246.     beq    ahrw1            ; if media definitely not, go do r/w
  1247.  
  1248.     cmpi.b    #2,d0            ; is media definitely changed?
  1249.     beq    retmc            ; if yes, return media has changed
  1250.  
  1251.     sf    mcrw            ; mcrw = FALSE
  1252.     lea    pun,a1            ; a1 = ptr to pun table
  1253.     adda.w    xdev(a6),a1        ; a1 = ptr to pun dev belongs to
  1254.     move.b    (a1),cpun+1        ; cpun = pun of dev
  1255.  
  1256. chkmc:    lea    start,a1        ; a1 = ptr to start table
  1257.     move.w    xdev(a6),d0        ; d0 = drive #
  1258.     add.w    d0,d0            ; d0*2*2 (index into tbl of longs)
  1259.     add.w    d0,d0
  1260.     movea.l    (a1,d0.w),a1        ; a1 = dev starting sector
  1261.  
  1262.     move.w    #1,-(sp)        ; return media change if detected
  1263.     move.w    cpun,-(sp)        ; physical unit number
  1264.     move.l    _dskbufp,-(sp)        ; buffer
  1265.     move.w    #1,-(sp)        ; 1 sector
  1266.     move.l    a1,-(sp)        ; dev starting sector
  1267.     bsr    pread            ; try to read dev's boot sector
  1268.     adda    #14,sp            ; clean up stack
  1269.     tst.w    d0            ; pread successful?
  1270.     beq.s    chkser            ; yes, go check serial number
  1271.  
  1272.     cmpi.w    #E_CHNG,d0        ; media change detected?
  1273.     bne.s    rderr1            ; if not, assume it's read error
  1274.  
  1275. mcchg:    move.b    #1,d0            ; d0.b = 1 (may be changed)
  1276.     move.w    xdev(a6),d1        ; d1.w = drive # excluding A: and B:
  1277.     move.b    cpun+1,d2        ; d2.b = physical unit number
  1278.     bsr    s_mc_xst        ; set mcflgs and xst flags for all dev
  1279.     bra.s    chkmc            ; then try again
  1280.  
  1281. rderr1:    move.w    xdev(a6),d1        ; device number
  1282.     bsr    critic            ; call critical error handler
  1283.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1284.     beq.s    chkmc            ; if yes, go back and try it
  1285.     bra    ahrw7            ; else return
  1286.  
  1287. chkser:    lea    serno,a1        ; a1 = ptr to serial #s table
  1288.     move.w    xdev(a6),d0        ; d0 = dev number
  1289.     mulu.w    #SERLEN,d0        ; *SERLEN for index into table
  1290.     adda.l    d0,a1            ; a1 = ptr to serial # of dev
  1291.  
  1292.     move.l    _dskbufp,a2        ; a2 = ptr to buffer
  1293.     addq.w    #8,a2            ; a2 = ptr to serial # read
  1294.      move.w    #SERLEN-1,d0        ; d0 = count for comparison
  1295. cmpser:    cmpm.b    (a2)+,(a1)+        ; serial # read ?= serial # recorded
  1296.     bne    ismc            ; no, media has changed
  1297.     dbra    d0,cmpser        ; compare next byte of serial #
  1298.                     ; serial # hasn't changed, try FAT
  1299.     move.w    xdev(a6),d0        ; d0 = dev number
  1300.     lea    fatsum,a1        ; a1 = ptr to fat checksum table
  1301.     move.w    #FATLEN,d1        ; d1.w = index into table
  1302.     mulu    d0,d1
  1303.     adda.l    d1,a1            ; a1 = ptr to fat checksum of dev
  1304.  
  1305.     add.w    d0,d0            ; d0*2 = index into table of words
  1306.     lea    fatst,a2        ; a2 = ptr to FAT start table
  1307.     move.w    (a2,d0.w),fatrec    ; fatrec = fatst(dev)
  1308.  
  1309.     lea    fatend,a2        ; a2 = ptr to FAT end table
  1310.     move.w    (a2,d0.w),d1        ; d1 = counter to scan FAT table
  1311.     sub.w    fatrec,d1        ;    = fatend(dev) - fatst(dev)
  1312.  
  1313.     lea    start,a2        ; a2 = ptr to start table
  1314.     add.w    d0,d0            ; d0*2*2 = index into table of longs
  1315.     movea.l    (a2,d0.w),a2        ; a2 = start sector of dev
  1316.     move.w    fatrec,d2        ; d2 = fatst(dev)
  1317.     mulu    sizr,d2            ; d2 = fatst(dev) in 512-byte sector
  1318.     adda.l    d2,a2            ; a2 = phys start sector of 2nd FAT
  1319.  
  1320.     movea.l    _dskbufp,a0        ; a0 = ptr to buffer
  1321. cmpfat:    move.w    sizr,d2            ; d2 = # reads per FAT sector
  1322.     subq.w    #1,d2            ; d2 - 1 = counter
  1323.     clr.l    temp            ; initialize sum
  1324. cfat0:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers d1, d2, a0, a1, a2
  1325.     move.w    #1,-(sp)        ; return media change if detected
  1326.     move.w    cpun,-(sp)        ; physical unit number
  1327.     move.l    a0,-(sp)        ; buffer
  1328.     move.w    #1,-(sp)        ; 1 sector
  1329.     move.l    a2,-(sp)        ; at sector a2
  1330.     bsr    pread            ; try to read this FAT sector
  1331.     adda    #14,sp            ; clean up stack
  1332.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers d1, a0, a1, a2
  1333.     tst.w    d0            ; pread successful?
  1334.     beq.s    chkfat            ; if yes, go check sum FAT sectors
  1335.                     ; else check if it's media change
  1336.     cmpi.w    #E_CHNG,d0        ; media change detected?
  1337.     beq    mcchg            ; if so, go test media change again
  1338.                     ; else assume it's read error
  1339.     movem.l    d1-d2/a0-a2,-(sp)    ; save registers d1, d2, a0, a2
  1340.     move.w    xdev(a6),d1        ; drive number
  1341.     bsr    critic
  1342.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers d1, d2, a0, a2
  1343.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1344.     beq.s    cfat0            ; if yes, go back and try it
  1345.     bra    ahrw7            ; else return
  1346.  
  1347. chkfat:    bsr    bsum            ; if ok, sum the sector
  1348.     addq    #1,a2            ; ready for try next sector
  1349.     dbra    d2,cfat0        ; until one FAT sector is summed
  1350.  
  1351.     bsr    csum            ; find the checksum
  1352.     cmp.b    (a1)+,d0        ; checksum recorded ?= checksum found
  1353.     bne    ismc            ; if no match, media has changed
  1354.     dbra    d1,cmpfat        ; until all sectors are checked
  1355.  
  1356.     lea    mcflgs,a0        ; a0 = ptr to mcflgs table
  1357.     adda.w    xdev(a6),a0        ; a0 = ptr to mcflg of drive
  1358.     clr.b    (a0)            ; clear mcflg for dev
  1359.  
  1360. ahrw1:    tst.w    xcount(a6)        ; any sector to r/w?
  1361.     beq    ahrw6            ; if =0, done
  1362.  
  1363.     cmpi.w    #-1,xrecno(a6)        ; does recno = -1?
  1364.     bne.s    ahrw9            ; if not, we have a word record #
  1365.     move.l    xlrecno(a6),a1        ; a1.l = start record #
  1366.     bra.s    ahrwa
  1367. ahrw9:    moveq    #0,d0            ; coerce to long
  1368.     move.w    xrecno(a6),d0        ; d0.l = recno
  1369.     movea.l    d0,a1            ; a1.l = start record #
  1370.  
  1371. ahrwa:    move.l    a1,strec        ; save first sector to r/w
  1372.     moveq    #0,d1            ; coerce to long
  1373.     move.w    xcount(a6),d1        ; d1.l = #sectors to r/w
  1374.     adda.l    d1,a1            ; a1.l = last sector to r/w
  1375.     subq.w    #1,a1            ;      = first sector + count - 1
  1376.     move.l    a1,endrec        ; save last sector to r/w
  1377.     move.l    xbuf(a6),stbuf        ; save starting buffer address
  1378.  
  1379.     move.l    strec,d1        ; d1.l = starting sector to r/w
  1380.     moveq    #0,d2            ; clear d2
  1381.     move.w    xcount(a6),d2        ; d2.l = # sectors to r/w
  1382.     btst.b    #3,xrw+1(a6)        ; physical operation?
  1383.     bne.s    ahrwb            ; if so, go on
  1384.                     ; else log -> phys sector mapping
  1385.     mulu    sizr,d1            ; d1.l = phys start sector to r/w
  1386.     mulu    sizr,d2            ; d2.l = # phys 512-byte sects to r/w
  1387.  
  1388. ahrwb:    move.l    xbuf(a6),a1        ; a1.l = buffer addr to r/w
  1389.     cmpi.l    #MAXSECTORS,d2        ; more than one DMAfull?
  1390.     bhi.s    ahrwc            ; if not, do only one DMAfull
  1391.     move.w    d2,xcount(a6)        ; else xcount(a6) = # sects requested
  1392.     bra.s    ahrw2
  1393. ahrwc:    move.w    #MAXSECTORS,xcount(a6)    ; xcount(a6) = 1 DMAfull of sects
  1394. ahrw2:    btst    #0,xbuf+3(a6)        ; an odd boundary?
  1395.     beq.s    ahrw4            ; no, so do normally
  1396.  
  1397.     cmpi.w    #2,xcount(a6)        ; can only do 2 at a time tops this way
  1398.     bls.s    ahrw3
  1399.     move.w    #2,xcount(a6)
  1400.  
  1401. ahrw3:    move.l    _dskbufp,a1        ; use the bios buffer for this transfer
  1402.  
  1403.     btst    #0,xrw+1(a6)        ; is this a write?
  1404.     beq.s    ahrw4            ; no, so go fill buffer from disk
  1405.  
  1406.     move.l    a1,-(sp)        ; preserve a1 = dest
  1407.     movea.l    xbuf(a6),a2        ; a2.l = source
  1408.     move.w    xcount(a6),-(sp)    ; # sectors to be moved
  1409.     bsr    smove            ; move sectors from a2 to a1
  1410.     addq.l    #2,sp            ; clean up stack
  1411.     movea.l    (sp)+,a1        ; restore a1 = dest buffer address
  1412.  
  1413. ahrw4:    movem.l    d1-d2,-(sp)        ; save total count and start sector
  1414.     move.w    xdev(a6),-(sp)
  1415.     move.l    d1,-(sp)
  1416.     move.w    xcount(a6),-(sp)    ; count
  1417.     move.l    a1,-(sp)        ; buffer
  1418.     move.w    xrw(a6),-(sp)
  1419.     bsr    _do_rw
  1420.     adda    #14,sp
  1421.     movem.l    (sp)+,d1-d2        ; restore total count and start sector
  1422.     tst.l    d0            ; any errors there?
  1423.     beq.s    ahrw8            ; no, go on normally
  1424.  
  1425.     cmpi.l    #E_CHNG,d0        ; media change detected?
  1426.     bne    ahrw7            ; if not, give up
  1427.     st    mcrw            ; else it's mc returned when r/w
  1428.     bra    mcchg            ; and go check if media has changed
  1429.  
  1430. ahrw8:    btst    #0,xbuf+3(a6)        ; on odd boundary?
  1431.     beq.s    ahrw5            ; if not, go on normally
  1432.     btst    #0,xrw+1(a6)        ; was it a read?
  1433.     bne.s    ahrw5            ; if it wasn't, go on normally
  1434.                     ; else
  1435.     movea.l    xbuf(a6),a1        ; must move data read to desired dest
  1436.     movea.l    _dskbufp,a2        ; from dskbuf
  1437.     move.w    xcount(a6),-(sp)    ; # of sectors to move
  1438.     bsr    smove
  1439.     addq.l    #2,sp            ; clean up stack
  1440.  
  1441. ahrw5:    moveq    #0,d0            ; clear d0
  1442.     move.w    xcount(a6),d0        ; #sectors we did
  1443.     sub.l    d0,d2            ; #sectors left to do
  1444.     add.l    d0,d1            ; next starting sector to r/w
  1445.     asl.l    #8,d0            ; d0 = #bytes we did
  1446.     add.l    d0,d0            ;    = #sectors * 512
  1447.     add.l    d0,xbuf(a6)        ; buf += (sectors_done * sector size)
  1448.     tst.l    d2            ; anything left to r/w?
  1449.     bne    ahrwb            ; if so, continue
  1450.                     ; check if wrote to boot sector
  1451. chkwr:    move.w    xrw(a6),d0        ; d0 = r/w and flags word
  1452.     btst    #0,d0            ; was it a write?
  1453.     beq    ahrw6            ; if not, done
  1454.     btst    #3,d0            ; was it a physical operation?
  1455.     bne    ahrw6            ; if it was, done
  1456.     btst    #1,d0            ; ignore media change?
  1457.     bne.s    wrfat            ; if so, update FAT chksums if appl.
  1458.     tst.l    strec            ; wrote to boot sector?
  1459.     bne.s    wrfat            ; if not, update FAT chksums if appl.
  1460.     lea    mcflgs,a0        ; else, a0 = ptr to mcflgs table
  1461.     adda.w    xdev(a6),a0        ; a0 = ptr to dev's mcflg
  1462.     move.b    #2,(a0)            ; assume medium has changed
  1463.  
  1464. wrfat:    moveq    #0,d0            ; clear d0
  1465.     move.b    cpun+1,d0        ; d0.b = pun of dev
  1466.     btst.b    d0,rmbits        ; is drive removable?
  1467.     beq    ahrw6            ; if not, done
  1468.                     ; else check if wrote to FATs
  1469.     lea    fatend,a0        ; a0 = ptr to fatend table
  1470.     move.w    xdev(a6),d0        ; d0 = device number
  1471.     add.w    d0,d0            ; d0*2 = index into table of words
  1472.     moveq    #0,d1            ; coerce to long
  1473.     move.w    (a0,d0.w),d1        ; d1 = last FAT's ending sector
  1474.     cmp.l    strec,d1        ; wrote beyond the last FAT?
  1475.     blt    ahrw6            ; if so, done
  1476.  
  1477.     lea    fatst,a0        ; a0 = ptr to fatst table
  1478.     moveq    #0,d2            ; coerce to long
  1479.     move.w    (a0,d0.w),d2        ; d2 = last FAT's starting sector
  1480.     cmp.l    endrec,d2        ; wrote before the last FAT?
  1481.     bgt    ahrw6            ; if so, done
  1482.                     ; else update FAT sector checksums
  1483.     move.l    stbuf,a0        ; a0 = ptr to buffer w/ written data
  1484.     lea    fatsum,a1        ; a1 = ptr to start of fatsum table
  1485.     move.w    xdev(a6),d0        ; d0 = dev number
  1486.     mulu.w    #FATLEN,d0        ; d0 = offset to dev's FAT chksum
  1487.     adda.l    d0,a1            ; a1 = ptr to dev's first FAT chksum
  1488.     move.l    strec,d0        ; d0 = first sector wrote to
  1489.     sub.l    d2,d0            ; d0 = strec - start(last FAT)
  1490.     beq.s    wrfat2            ; if strec = start(last FAT), 
  1491.                     ;     no adjustments needed
  1492.      blt.s    wrfat1            ; if strec < start(last FAT)
  1493.                     ;     begin from start(last FAT)
  1494.     move.l    strec,d2        ; else begin from strec
  1495.     adda.l    d0,a1            ; a1 = ptr to fatsum to be updated
  1496.     bra.s    wrfat2
  1497.  
  1498. wrfat1:    neg.l    d0            ; d0 = index into stbuf
  1499.     asl.l    #8,d0            ;    = (start(last FAT) - strec)*512
  1500.     add.l    d0,d0
  1501.     adda.l    d0,a0            ; a0 = pt to addr of buf for update
  1502.  
  1503. wrfat2:    cmp.l    endrec,d1        ; if end(last FAT) <= endrec
  1504.     ble.s    wrfat3            ;     stop at end(last FAT)
  1505.     move.l    endrec,d1        ; else stop at endrec
  1506.  
  1507. wrfat3:    sub    d2,d1            ; d1 = # sectors to be processed
  1508. wrfat4:    move.w    sizr,d2            ; d2 = # phys sect per log sect
  1509.     subq.w    #1,d2            ; dbra likes one less
  1510.     clr.l    temp            ; initialize sum
  1511. wrfat5:    bsr    bsum            ; sum up one 512-byte sector
  1512.     adda.l    #512,a0            ; point to next 512 bytes
  1513.     dbra    d2,wrfat5        ; until one logical sector is done
  1514.     bsr    csum            ; obtain checksum
  1515.     move.b    d0,(a1)+        ; record new fat checksum
  1516.     dbra    d1,wrfat4        ; do until all are updated
  1517.  
  1518. ahrw6:    clr.l    d0            ; got here with no errors!
  1519.     bra.s    ahrw7
  1520.  
  1521. ismc:    tst.b    mcrw            ; media change returned by r/w?
  1522.     beq    onemc            ; no, only dev has changed
  1523.     move.b    #2,d0            ; d0.b = value to set to
  1524.     move.w    xdev(a6),d1        ; d1.w = dev number
  1525.     move.b    cpun+1,d2        ; d2.b = physical unit number
  1526.     bsr    s_mc_xst        ; set mcflgs and xst flags for devs
  1527.     bra.s    retmc            ; return media change detected
  1528.  
  1529. onemc:    lea    mcflgs,a0        ; a0 = ptr to mcflgs table
  1530.     adda.w    xdev(a6),a0        ; a0 = ptr to dev's mcflg
  1531.     move.b    #2,(a0)            ; set mcflg for dev to has changed
  1532.     lea    xst,a0            ; a0 = ptr to drive existence table
  1533.     adda.w    xdev(a6),a0        ; a0 = ptr to xst flag of dev
  1534.     move.b    #2,(a0)            ; assume dev exists
  1535.  
  1536. retmc:    move.l    #E_CHNG,d0        ; yes, return media change error
  1537. ahrw7:    unlk    a6
  1538.     rts
  1539.  
  1540.  
  1541. ;----------------
  1542. ;
  1543. ;  Copy unaligned sectors
  1544. ;  (this is *supposed* to be slow!)
  1545. ;
  1546. ;    Passed:    4(sp).w    = # of sectors (known to be 1 or 2)
  1547. ;        a2    -> source sector
  1548. ;        a1    -> dest buffer (oddly aligned)
  1549. ;
  1550. smove:    move.w    4(sp),d0        ; d0 = # 512-byte sectors to move
  1551.     asl.w    #8,d0            ; d0 * 512 = # bytes to move
  1552.     add.w    d0,d0
  1553.     subq.w    #1,d0            ; dbra likes one less
  1554. smove1:    move.b    (a2)+,(a1)+
  1555.     dbra    d0,smove1
  1556.     rts
  1557.  
  1558.  
  1559. ;
  1560. ;+
  1561. ; _do_rw - called to read/write no more than 128K to an even boundary
  1562. ;
  1563. ; Passed:    dev    $10(sp).W
  1564. ;        recno    $c(sp).L
  1565. ;        count    $a(sp).W
  1566. ;        buf    6(sp).L
  1567. ;        rw    4(sp).W        ; non-zero -> write
  1568. ;
  1569. ;-
  1570. _do_rw:
  1571.     move.w    d3,-(sp)        ; preserve d3
  1572.  
  1573. sasrw0:    move.w    _retries,retrycnt    ; setup retry counter
  1574.  
  1575.     move.w    6(sp),d3        ; rw
  1576.     btst    #2,d3            ; are retries disabled?
  1577.     beq.s    sasrw1            ; no, act normally
  1578.     move.w    #0,retrycnt        ; yes, so set retrycnt to zero
  1579.  
  1580. sasrw1:    lea    2(sp),a1        ; frame pointer
  1581.     move.l    $c(a1),d0        ; sect.L
  1582.     move.w    4(a1),d3        ; rw
  1583.  
  1584.     btst    #3,d3            ; physical unit operation
  1585.     beq.s    sasrw2            ; no, so do log->phys mapping
  1586.  
  1587.     move    $10(a1),cpun        ; get unit number
  1588.     bra.s    sasrw3            ; and use that as the physical unit
  1589.  
  1590. sasrw2:    clr    d2            ; coerce byte to word
  1591.     move.w    $10(a1),d1        ; get device
  1592.      lea    pun,a2
  1593.     move.b    (a2,d1.w),cpun+1    ; get physical unit number
  1594. sasrw3:    move.w    cpun,-(sp)        ; dev
  1595.     move.l    6(a1),-(sp)        ; buf
  1596.     move.w    $a(a1),-(sp)        ; count
  1597.  
  1598.     btst    #3,d3            ; physical operation?
  1599.     bne.s    sasrw4            ; yes, so no offset
  1600.  
  1601.     add.w    d1,d1            ; d1*2*2 = index into table of longs
  1602.     add.w    d1,d1
  1603.     lea    start,a2
  1604.     add.l    (a2,d1.w),d0        ; adjust sector number
  1605.  
  1606. sasrw4:    move.l    d0,-(sp)        ; sect
  1607.     btst    #0,d3            ; read or write?
  1608.     bne.s    sasrw5            ; (write)
  1609.     bsr    _hread            ; read sectors
  1610.     bra.s    sasrw6
  1611. sasrw5:    bsr    _hwrite            ; write sectors
  1612. sasrw6:    adda    #12,sp            ; (cleanup stack)
  1613.     tst.l    d0            ; errors?
  1614.     beq    sasrwr            ; no -- success
  1615.  
  1616.     bsr    errcode            ; find error code
  1617.     cmpi.b    #MDMCHGD,d0        ; media change detected?
  1618.     beq.s    sasrw7
  1619.     cmpi.b    #WRTPRTD,d0        ; write on write-protected media?
  1620.     beq.s    sasrw9
  1621.     cmpi.b    #DRVNRDY,d0        ; drive not ready?
  1622.     beq.s    sasrwe
  1623.  
  1624.     subq.w    #1,retrycnt        ; drop retry count and retry
  1625.     bpl    sasrw1
  1626.  
  1627.     move    6(sp),d1        ; get r/w and flags word
  1628.     move.l    #EREADF,d0        ; read error code
  1629.     btst    #0,d1            ; is it a write?
  1630.     beq.s    sasrwa
  1631.     move.l    #EWRITF,d0        ; write error code
  1632.     bra.s    sasrwa
  1633.  
  1634. sasrw7:    move.w    6(sp),d1        ; get r/w and flags word
  1635.     andi.b    #$a,d1            ; no media change/physical operation?
  1636.     beq.s    sasrw8            ; if not, return media change
  1637.     move.b    #1,d0            ; d0.b = medium may have changed
  1638.     move.w    $12(a6),d1        ; d1.w = dev number
  1639.     move.b    cpun+1,d2        ; d2.b = physical unit number
  1640.     bsr    s_mc_xst        ; set mcflgs and xst flags for dev
  1641.     bra    sasrw0            ; start all over
  1642.     
  1643. sasrw8:    move.l    #E_CHNG,d0        ; media change detected
  1644.     bra.s    sasrwr            ; return
  1645.  
  1646. sasrw9:    move.l    #EWRPRO,d0        ; write on write-protected media
  1647.     bra.s    sasrwf
  1648.  
  1649. sasrwe:    move.l    #EDRVNR,d0        ; drive not ready
  1650. sasrwf:    move.w    6(sp),d1        ; get r/w and flags word
  1651.  
  1652. sasrwa:    btst    #3,d1            ; is this a physical operation?
  1653.     beq.s    sasrwc            ; no, call critical error handler
  1654.                     ; else find 1st drive of current unit
  1655.     lea    pun,a0            ; a0 = ptr to pun table
  1656.     move.w    cpun,d2            ; d1 = current pun
  1657.     moveq    #0,d1            ; d2 = index into pun table
  1658. sasrwb:    cmp.b    (a0,d1.w),d2        ; 1st drive of unit?
  1659.     beq.s    sasrwd            ; if so, get drive number 
  1660.     addq.w    #1,d1            ; else, get next drive number
  1661.     cmpi.w    #MAXUNITS,d1        ; reach end of pun table?
  1662.     bge.s    sasrwr            ; if so, forget it
  1663.     bra.s    sasrwb            ; else try this next drive
  1664.  
  1665. sasrwc:    move.w    $12(sp),d1        ; d1 = drive number
  1666. sasrwd:    bsr    critic
  1667.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1668.     beq    sasrw0            ; if yes, go retry
  1669.  
  1670. sasrwr:    move.w    (sp)+,d3        ; remember to restore d3
  1671.     rts
  1672.  
  1673.  
  1674. ;
  1675. ;----------------
  1676. ;
  1677. ; Check for media change on hard disk
  1678. ; Synopsis:    _sasi_mediach(dev)
  1679. ;        WORD dev;        4(sp).w
  1680. ;
  1681. ; Returns:    0L - media definitely has not changed
  1682. ;        1L - media _may_ have changed
  1683. ;        2L - media definitely has changed
  1684. ;
  1685. ; Uses:        d0, d1, a0, a1
  1686. ;
  1687. ; Comments:
  1688. ; Apr-4-1989    ml.    Add in grace period between _sasi_mediach()s.
  1689. ;            If _sasi_mediach() was called less than 1 s
  1690. ;            (200 _hz_200 clock ticks) ago, and medium was 
  1691. ;            not changed then, assume medium still has not 
  1692. ;            changed.
  1693. ;
  1694. _sasi_mediach:
  1695.     subq.w    #2,4(sp)        ; dev # excluding drv A and B
  1696.     move.w    4(sp),d1        ; d1 = current drive
  1697.     lea    mcflgs,a0        ; a0 = pointer to mcflgs
  1698.     moveq    #0,d0            ; d0 = mcflg for current drive
  1699.     move.b    (a0,d1.w),d0    
  1700.     tst.b    d0            ; has medium changed?
  1701.     bne.s    decided            ; if yes or maybe, return result
  1702.                     ; else verify that it has not
  1703.     move.l    lastmdctm,d2        ; time media change was last called
  1704.     cmp.l    _hz_200,d2        ; while (_hz_200 <= lastmdctm)
  1705.     bcc.s    decided            ;    assume medium not changed
  1706.  
  1707.     lea    pun,a1            ; ptr to beginning of pun table
  1708.     clr.w    d2            ; coerce byte to word
  1709.     move.b    (a1,d1.w),d2        ; d2 = pun current drive belongs to
  1710.  
  1711.     btst.b    d2,rmbits        ; is pun removable?
  1712.     beq.s    notchngd        ; if not, medium has not changed
  1713.  
  1714.     movem.w    d1-d2,-(sp)        ; else save registers
  1715.     move.w    d2,-(sp)        ; physical unit number
  1716.     bsr    testunit        ; verify by doing test unit ready
  1717.     addq.l    #2,sp
  1718.     movem.w    (sp)+,d1-d2        ; restore registers
  1719.     move.l    _hz_200,lastmdctm    ; update time for last _sasi_mediach()
  1720.     addi.l    #200,lastmdctm        ; 
  1721.     tst.w    d0            ; return good status?
  1722.     beq.s    notchngd        ; if yes, return medium not changed
  1723.     moveq    #1,d0            ; else return medium may have changed
  1724.     bsr    s_mc_xst        ; set mcflgs and xst flags to 1's
  1725.     bra.s    decided
  1726. notchngd:
  1727.     moveq    #0,d0            ; return medium has not changed
  1728. decided:
  1729.     rts
  1730.  
  1731.  
  1732. ;+
  1733. ; s_mc_xst - set mcflgs and drive existence flags 
  1734. ;         for drives belonging to a physical unit 
  1735. ;         to value passed
  1736. ;
  1737. ; Passed:    d0.b - value to set to
  1738. ;         d1.w - dev number
  1739. ;        d2.b - physical unit #
  1740. ;-
  1741. s_mc_xst:
  1742.     movem.l    a0-a2,-(sp)    ; save registers
  1743.     move.w    d1,-(sp)    ; save dev number
  1744.     lea    mcflgs,a0    ; a0 = ptr to mcflgs table
  1745.     lea    pun,a1        ; a1 = ptr to pun table
  1746.     lea    xst,a2        ; a2 = ptr to drive existence table
  1747. back:    cmp.b    (a1,d1.w),d2    ; does this drive belongs to this physical unit?
  1748.     bne.s    oppdir        ; if not, try opposition direction
  1749.     move.b    d0,(a0,d1.w)    ; else change its mcflg to value passed
  1750.     move.b    d0,(a2,d1.w)    ; and change its xst to value passed
  1751.     dbra    d1,back        ; try next one in backward direction
  1752. oppdir:    move.w    (sp)+,d1    ; get device number again
  1753. forth:    addq.w    #1,d1        ; try next one in forward direction
  1754.     cmp.w    #MAXUNITS,d1    ; all units checked?
  1755.     bge.s    setr        ; if yes, get ready to return
  1756.     cmp.b    (a1,d1.w),d2    ; does this drive belongs to this physical unit?
  1757.     bne.s    setr        ; if not, get ready to return
  1758.     move.b    d0,(a0,d1.w)    ; else change its mcflg to value passed
  1759.     move.b    d0,(a2,d1.w)    ; and change its xst to value passed
  1760.     bra.s    forth        ; continue to search
  1761. setr:    movem.l    (sp)+,a0-a2    ; restore registers
  1762.     rts
  1763.  
  1764.  
  1765. ;
  1766. ;--------------------- Low-Level Driver -------------------
  1767.  
  1768. ;----------------
  1769. ;
  1770. ;  Hardware definitions
  1771. ;
  1772. wdc        equ    $ffff8604
  1773. wdl        equ    $ffff8606
  1774. wdcwdl        equ    wdc        ; used for long writes
  1775. xwdl        equ    wdl-wdc        ; offset from wdc to wdl
  1776.  
  1777. dmahi        equ    $ffff8609
  1778. dmamid        equ    dmahi+2
  1779. dmalow        equ    dmamid+2
  1780. gpip        equ    $fffffa01
  1781.  
  1782.  
  1783. ;----------------
  1784. ;
  1785. ;  Tunable (delay) values (in number of _hz_200 ticks) for ACSI
  1786. ;
  1787. ltimeout        equ    600        ; long-timeout (3 S)
  1788. stimeout        equ    20        ; short-timeout (100 mS)
  1789.  
  1790.  
  1791. ;----------------
  1792. ;
  1793. ; LONG _qdone() - Wait for command byte handshake
  1794. ; LONG _fdone() - Wait for operation complete
  1795. ; Passed:    nothing
  1796. ;
  1797. ; Returns:    EQ: no timeout
  1798. ;        MI: timeout condition
  1799. ;
  1800. ; Uses:        D0
  1801. ;
  1802. ;
  1803. ;-
  1804. _fdone:    move.l    _hz_200,d0
  1805.     add.l    #ltimeout,d0
  1806.     bra.s    qd1
  1807.  
  1808. _qdone:    move.l    _hz_200,d0
  1809.     add.l    #stimeout,d0
  1810.  
  1811. qd1:    cmp.l    _hz_200,d0        ; timeout?
  1812.     bcs.s    qdq            ; (i give up, return NE)
  1813.     btst    #5,gpip            ; interrupt?
  1814.     bne.s    qd1            ; (not yet)
  1815.  
  1816.     moveq    #0,d0            ; return EQ (no timeout)
  1817.     rts
  1818.  
  1819. qdq:    moveq    #-1,d0
  1820.     rts
  1821.  
  1822.  
  1823. ;----------------
  1824. ;
  1825. ; Wait for end of SASI command
  1826. ;
  1827. ; Passed:    d0 value to be written to wdl
  1828. ;
  1829. ; Returns:    EQ: success (error code in D0.W)
  1830. ;        MI: timeout (-1 in D0.W)
  1831. ;        NE: failure (SASI error code in D0.W)
  1832. ;
  1833. ; Uses:        d0,d1
  1834. ;-
  1835. _endcmd: move    d0,d1            ; preserve wdl value
  1836.  
  1837.     bsr    _fdone            ; wait for operation complete
  1838.     bmi.s    endce            ; (timed-out, so complain)
  1839.  
  1840.     move.w    d1,wdl
  1841.     move.w    wdc,d0            ; get the result
  1842.     and.w    #$00ff,d0        ; (clean it up), if non-zero should
  1843.                     ; do a ReadSense command to learn more
  1844. endce:    move.l    _hz_200,lastacstm    ; update controller last accessed time
  1845.     addq.l    #2,lastacstm        ; lastacstm = _hz_200 + 2;
  1846.     rts                
  1847.  
  1848.  
  1849. ;+
  1850. ;  Handle command timeout;
  1851. ;  Unlock DMA chip and return completion status;
  1852. ;-
  1853. _hto:    moveq    #-1,d0        ; indicate timeout
  1854. _hdone:    move.w    #$80,wdl    ; Landon's code seems to presume we
  1855.     tst.w    wdc
  1856.     clr    flock        ; NOW, signal that we are done
  1857.     rts
  1858.  
  1859.  
  1860. ;+
  1861. ; delay()
  1862. ;    5 - 10ms kludge delay for message byte sent back by controller.
  1863. ;-
  1864. _delay:    move.l    lastacstm,d0        ; d0 = controller last accessed time
  1865. wait:    cmp.l    _hz_200,d0        ; while (_hz_200 <= lastacstm)
  1866.     bcc.s    wait            ;    wait()
  1867.     rts
  1868.  
  1869.  
  1870. ;
  1871. ;-----------------
  1872. ;
  1873. ; _hread(sectno, count, buf, dev)
  1874. ; LONG sectno;         4(sp)
  1875. ; WORD count;         8(sp)
  1876. ; LONG buf;        $a(sp)    $b=high, $c=mid, $d=low
  1877. ; WORD dev;        $e(sp)
  1878. ;
  1879. ; Returns:    -1 on timeout
  1880. ;        0 on success
  1881. ;        nonzero on error
  1882. ;
  1883. ;-
  1884. _hread:    bsr    _delay
  1885.     movea.l    #wdc,a0            ; pointer to DMA chip
  1886.     st    flock            ; lock FIFO
  1887.  
  1888.     move    #$88,xwdl(a0)    ;wdl
  1889.     clr.l    d0
  1890.     move.w    $0e(sp),d0        ; get unit number
  1891.     lsl.w    #5,d0
  1892.     swap    d0
  1893.     ori.l    #$0008008a,d0        ; 08 wdc, 8a wdl
  1894.     move.l    d0,(a0)     ;wdcwdl
  1895.  
  1896.     move.l    $a(sp),-(sp)        ; set DMA address
  1897.     bsr    _setdma
  1898.     addq.l    #4,sp
  1899.  
  1900.     bsr    _setss            ; set sector and size
  1901.     bmi    _hto
  1902.  
  1903.     move.w    #$190,xwdl(a0)    ;wdl
  1904.     move.w    #$90,xwdl(a0)    ;wdl
  1905.     move.w    8(sp),(a0)     ;wdc    ; write sector count to DMA chip
  1906.     move.w    #$8a,xwdl(a0)    ;wdl
  1907.     move.l    #$00000000,(a0) ;wdcwdl    ; control byte  0 wdc 0 wdl
  1908.  
  1909.     move.w    #$8a,d0
  1910.     bsr    _endcmd
  1911.  
  1912. hrx:    bra    _hdone            ; cleanup after IRQ
  1913.  
  1914.  
  1915. ;
  1916. ;----------------
  1917. ;
  1918. ; _hwrite(sectno, count, buf, dev)
  1919. ; LONG sectno;         4(sp)
  1920. ; WORD count;         8(sp)
  1921. ; LONG buf;        $a(sp)    $b=high, $c=mid, $d=low
  1922. ; WORD dev;        $e(sp)
  1923. ;
  1924. ;-
  1925. _hwrite:
  1926.     bsr    _delay
  1927.     movea.l    #wdc,a0            ; pointer to DMA chip
  1928.     st    flock            ; lock FIFO
  1929.  
  1930.     move.l    $a(sp),-(sp)        ; set DMA address
  1931.     bsr    _setdma
  1932.     addq.l    #4,sp
  1933.  
  1934.     move.w    #$88,xwdl(a0)    ;wdl
  1935.     clr.l    d0
  1936.     move.w    $0e(sp),d0        ; get unit number
  1937.     lsl.w    #5,d0
  1938.     swap    d0
  1939.     ori.l    #$000a008a,d0        ; 0a wdc 8a wdl
  1940.     move.l    d0,(a0)     ;wdcwdl
  1941.  
  1942.     bsr    _setss
  1943.     bmi    _hto
  1944.  
  1945.     move.w    #$90,xwdl(a0)    ;wdl
  1946.     move.w    #$190,xwdl(a0)    ;wdl
  1947.     move.w    8(sp),(a0)     ;wdc    ; sector count for DMA chip's benefit
  1948.     move.w    #$18a,xwdl(a0)
  1949.     move.l    #$00000100,(a0) ;wdcwdl
  1950.  
  1951.     move.w    #$18a,d0
  1952.     bsr    _endcmd
  1953.  
  1954. hwx:    bra    _hdone            ; cleanup after IRQ
  1955.  
  1956.  
  1957. ;
  1958. ;----------------
  1959. ;
  1960. ; Set DMA address
  1961. ;
  1962. ; void _setdma(addr)
  1963. ; LONG addr;
  1964. ;-
  1965. _setdma:
  1966.     move.b    7(sp),dmalow
  1967.     move.b    6(sp),dmamid
  1968.     move.b    5(sp),dmahi
  1969.     rts
  1970.  
  1971.  
  1972. ;----------------
  1973. ;
  1974. ; Set sector number and number of sectors
  1975. ;
  1976. _setss:    move.w    #$8a,xwdl(a0)
  1977.  
  1978.     bsr    _qdone            ; wait for controller to take command
  1979.     bmi    setsse
  1980.  
  1981.     move.b    9(sp),d0        ; construct sector#
  1982.     swap    d0
  1983.     move.w    #$008a,d0
  1984.     move.l    d0,(a0)     ;wdcwdl    ; write MSB sector# + devno
  1985.     bsr    _qdone
  1986.     bmi    setsse
  1987.  
  1988.     move.b    10(sp),d0        ; write MidSB sector#
  1989.     swap    d0
  1990.     move.w    #$008a,d0
  1991.     move.l    d0,(a0)     ;wdcwdl
  1992.     bsr    _qdone
  1993.     bmi    setsse
  1994.  
  1995.     move.b    11(sp),d0        ; write LSB sector#
  1996.     swap    d0
  1997.     move.w    #$008a,d0
  1998.     move.l    d0,(a0)     ;wdcwdl
  1999.     bsr    _qdone
  2000.     bmi    setsse
  2001.  
  2002.     move.w    12(sp),d0        ; write sector count
  2003.     swap    d0
  2004.     move.w    #$008a,d0
  2005.     move.l    d0,(a0)     ;wdcwdl
  2006.     bsr    _qdone
  2007.  
  2008. setsse:    rts
  2009.  
  2010.  
  2011. ;
  2012. ;----------------
  2013. ;
  2014. ;  _inquiry - get device-specific parameters
  2015. ;
  2016. ;    Synopsis:    LONG _inquiry(physunit#, parms)
  2017. ;        WORD physunit#;            4(sp).W
  2018. ;        char *parms;            6(sp).L
  2019. ;
  2020. ; Old driver uses these two lines which do NOT do 
  2021. ; "d0 = (dev << 5) << 16" because the hi word of
  2022. ; D0 before the swap (lo word after) is garbage.
  2023. ;    lsl.b    #5,d0
  2024. ;    swap    d0
  2025. ;-
  2026. _inquiry:
  2027.     bsr    _delay
  2028.     st    flock            ; lock FIFO
  2029.     move.l    6(sp),-(sp)        ; -> parameter block address
  2030.     bsr    _setdma            ; set DMA there
  2031.     addq.l    #4,sp
  2032.     movea.l    #wdc,a0            ; pointer to DMA chip
  2033. ; write command and phyunit#
  2034.     move.w    #$88,xwdl(a0)    ;wdl
  2035.     move.w    4(sp),d0        ; d0 = (physunit# << 5) << 16
  2036.     moveq    #21,d1
  2037.     lsl.l    d1,d0            
  2038.     or.l    #$0012008a,d0        ; write physunit# + Inquiry + FIFO bits
  2039.     move.l    d0,(a0)        ;wdcwdl    ; inquiry+physunit# wdc 8a wdl (byte 0)
  2040.     bsr    _qdone
  2041.     bmi    inq
  2042.  
  2043.     move.l    #$8a,d1            ; d1 = byte to be sent
  2044.     move.l    d1,(a0)        ;wdcwdl    ; byte 1
  2045.     bsr    _qdone
  2046.     bmi    inq
  2047.  
  2048.     move.l    d1,(a0)        ;wdcwdl    ; byte 2
  2049.     bsr    _qdone
  2050.     bmi    inq
  2051.  
  2052.     move.l    d1,(a0)        ;wdcwdl    ; byte 3
  2053.     bsr    _qdone
  2054.     bmi    inq
  2055.  
  2056.     move.l    #$0010008a,(a0)    ;wdcwdl    ; 16 byte of parameters (byte 4)
  2057.     bsr    _qdone
  2058.     bmi    inq
  2059.  
  2060.     move.w    #$190,xwdl(a0)    ;wdl    ; reset the DMA chip
  2061.     move.w    #$90,xwdl(a0)    ;wdl
  2062.     move.w    #$01,(a0)    ;wdc    ; 1 sector of DMA (actually less)
  2063.     move.w    #$8a,xwdl(a0)    ;wdl
  2064.     move.l    #0,(a0)        ;wdcwdl    ; byte 5 (control byte)
  2065.     move.w    #$8a,d0            ; wdl value
  2066.     bsr    _endcmd            ; wait for command completion
  2067. inq:    bra    _hdone
  2068.  
  2069.  
  2070. ;
  2071. ;---------------
  2072. ;
  2073. ;  LONG _rq_sense() - get non-extended sense data from target
  2074. ;  LONG _rq_xsense() - get extended sense data from target
  2075. ;
  2076. ;  Passed:
  2077. ;    WORD physunit#;            4(sp).W        $6(sp).w
  2078. ;    char data[];            6(sp).L        $8(sp).l
  2079. ;
  2080. ;  Returns:
  2081. ;        0 : OK
  2082. ;    non-0 : ERROR
  2083. ;
  2084. _rq_sense:
  2085.     moveq    #3,d2            ; do it 4 times
  2086.     move.w    #0,-(sp)        ; request 4 bytes of sense data
  2087.     bra.s    rq0
  2088. _rq_xsense:
  2089.     moveq    #0,d2            ; do it one time
  2090.     move.w    #16,-(sp)        ; request 16 bytes of sense data
  2091. rq0:    bsr    _delay            ; kludge delay
  2092.     movea.l    #wdc,a0
  2093.     st    flock            ; lock FIFO
  2094.     move.l    8(sp),-(sp)        ; -> sense data buffer address
  2095.     bsr    _setdma            ; set DMA there
  2096.     addq.l    #4,sp
  2097.  
  2098.      move.w    #$190,xwdl(a0)    ;wdl    ; reset the DMA chip
  2099.     move.w    #$90,xwdl(a0)    ;wdl
  2100.     move.w    #$01,(a0)    ;wdc    ; 1 sector of DMA (actually less)
  2101.  
  2102.     moveq    #0,d0
  2103. rq1:    move.w    #$88,xwdl(a0)    ;wdl
  2104.     move.w    6(sp),d0        ; d0 = (dev << 5) << 16
  2105.     lsl.b    #5,d0
  2106.     swap    d0            ; in upper word
  2107.     or.l    #$0003008a,d0        ; write dev#+Request Sense+FIFO bits
  2108.     move.l    d0,(a0)        ;wdcwdl    ; rqsense+dev wdc 8a wdl (byte 0)
  2109.     bsr    _qdone
  2110.     bmi.s    wdq1
  2111.  
  2112.     move.l    #$8a,d1        ; byte to be sent
  2113.     move.l    d1,(a0)        ;wdcwdl    ; byte 1
  2114.     bsr    _qdone
  2115.     bmi.s    wdq1
  2116.  
  2117.     move.l    d1,(a0)        ;wdcwdl    ; byte 2
  2118.     bsr    _qdone
  2119.     bmi.s    wdq1
  2120.  
  2121.     move.l    d1,(a0)        ;wdcwdl    ; byte 3
  2122.     bsr    _qdone
  2123.     bmi.s    wdq1
  2124.  
  2125.     move.w    (sp),d0            ; # bytes of sense data requested
  2126.     swap    d0
  2127.     or.l    d1,d0
  2128.     move.l    d0,(a0)        ;wdcwdl    ; byte 4
  2129.     bsr    _qdone
  2130.     bmi.s    wdq1
  2131.  
  2132.     move.w    #$8a,xwdl(a0)    ;wdl
  2133.     move.l    #0,(a0)        ;wdcwdl    ; byte 5 (control byte)
  2134.     move.w    #$8a,d0            ; wdl value
  2135.     bsr    _endcmd            ; wait for command completion
  2136.     tst.w    d0
  2137.     bmi.s    wdq1
  2138.     dbra    d2,rq1            ; go back until done
  2139. wdq1:    addq.l    #2,sp            ; clean up stack
  2140.     bra    _hdone
  2141.  
  2142.  
  2143. ;
  2144. ;----------------
  2145. ;
  2146. ;  testunit - Test Unit Ready
  2147. ;
  2148. ;    Synopsis:    LONG testunit(dev)
  2149. ;        WORD dev;        4(sp).W
  2150. ;
  2151. ;    Uses:  d0, d1, and a0
  2152. ;-
  2153. tst:    dc.b    0    ; format command + devno (upper 3 bits)
  2154.     dc.b    0    ; (unused)
  2155.     dc.b    0    ; (unused)
  2156.     dc.b    0    ; (unused)
  2157.     dc.b    0    ; (unused)
  2158.     dc.b    0    ; (unused)
  2159. .even
  2160.  
  2161. testunit:
  2162.     bsr    _delay
  2163.     move.w    4(sp),d0        ; set dev#
  2164.     lsl.b    #5,d0            ; up 5 bits, fill in 0s
  2165.     move.b    d0,tst            ; stuff into command frame
  2166.     lea    tst(pc),a0        ; pick up pointer to the command block
  2167.     clr.w    d0
  2168.     st    flock            ; lock FIFO
  2169.     move.w    #$88,wdl
  2170.     move.b    (a0)+,d0        ; get the command byte
  2171.     swap    d0
  2172.     move.w    #$8a,d0
  2173.     move.l    d0,wdc            ; byte wdc 8a wdl
  2174.  
  2175.     moveq    #(5-1),d1        ; write remaining 5 bytes of command
  2176. tst1:    bsr    _qdone
  2177.     bmi    _hto
  2178.     move.b    (a0)+,d0        ; next byte of command
  2179.     swap    d0
  2180.     move.w    #$8a,d0
  2181.     move.l    d0,wdcwdl
  2182.     dbra    d1,tst1
  2183.     bsr    _endcmd            ; wait for command completion
  2184.     bra    _hdone            ; cleanup after IRQ
  2185.  
  2186.  
  2187. ;
  2188. ;---------------- Resident Installer -------------------
  2189.  
  2190. isasi5:    move.l    #(i_sasi1-i_sasi),tokeep ; at least keep this much
  2191.  
  2192.     cmpi.w    #512,maxssz    ; maxssz > 512 bytes?
  2193.     bls.s    nboot0        ; if not, don't need to replace GEMDOS buffers
  2194.                 ; else check if there is enough memory for
  2195. chkmem:    bsr    chklstmem    ;   new GEMDOS buffer lists
  2196.     tst.l    d0        ; enough?
  2197.     bpl.s    okbig        ; if so, build the list
  2198.     move.w    minbigsect,d0    ; d0 = minimum big sector
  2199.     cmp.w    maxssz,d0    ; is maxssz >= minimum big sector?
  2200.     bcc.s    regsect        ; if so, give up
  2201.     move.w    d0,maxssz    ; else try minimum big sector
  2202.     bra.s    chkmem
  2203. regsect:
  2204.     move.w    #512,maxssz    ; else, cannot handle big sectors
  2205.     bra.s    nboot0
  2206.  
  2207. okbig:    move.l    d1,tokeep    ; update amout of memory to be kept
  2208.     lea    i_sasi1,a0    ; a0 = ptr to beginning of new buffer lists
  2209.     moveq    #3,d1        ; d1 = count = 4 buffers - 1
  2210.     bsr    list_init    ; initialize the buffer list
  2211.     clr.l    (a0,d0.w)    ; cut 1 list of 4 buffers to 2 lists of 2
  2212.     move.l    a0,_bufl    ; _bufl[0] -> 1st new buffer list
  2213.     add.l    d0,d0        ; d0 = offset to beginning of 2nd buffer list
  2214.     adda.l    d0,a0        ; a0 = head of 2nd buffer list
  2215.     move.l  a0,_bufl+4    ; _bufl[1] -> 2nd new buffer list
  2216.  
  2217. nboot0:    bsr    pool_install    ; attempt to install more OS pool
  2218.     tst.w    bootloaded    ; if bootloaded, then already in super mode
  2219.     bne.s    nboot1        ; (already there)
  2220.     move.l    d0,-(sp)    ; save size of installed pool
  2221.     move.l    savssp,-(sp)    ; become a mild mannered user process
  2222.     move.w    #$20,-(sp)    ; Super(savssp)
  2223.     trap    #1
  2224.     addq.l    #6,sp
  2225.     move.l    (sp)+,d0    ; restore size of installed pool
  2226.  
  2227. nboot1:    add.l    tokeep,d0    ; compute value for Ptermres() or Mshrink
  2228.     tst.w    bootloaded    ; exit to GEMDOS?
  2229.     beq    nboot2        ; (yes -- not boot loaded)
  2230.  
  2231. ;+
  2232. ;  Return to TOS ROMs
  2233. ;    - set default boot device to C:
  2234. ;    - Print silly message
  2235. ;    - Mshrink() memory that was alloc'd to us
  2236. ;    - set magic# in D7 for TOS ROMs
  2237. ;    - RTS back to ROMs
  2238. ;-
  2239.     add.l    #$1c,d0        ; for file header
  2240.     move.l    d0,-(sp)    ; save D0
  2241.     pea    msg_loaded(pc)    ; print announcement
  2242.     move.w    #9,-(sp)
  2243.     trap    #1
  2244.     addq.l    #6,sp
  2245.     move.l    (sp)+,d0
  2246.  
  2247.     move.b    d7,d1        ; d1.b = physical unit # boot loaded from
  2248.     lsr.b    #5,d1        ;      = xxx00000 >> 5
  2249.     lea    pun,a0        ; a0 = ptr to pun table
  2250.     move.w    #0,d2        ; d2 = boot dev
  2251. bd1:    cmp.b    (a0,d2.w),d1    ; d2 belongs to physical unit booted from?
  2252.     beq    bd2        ; if yes, set (d2) as boot device
  2253.     addq.w    #1,d2        ; else try next logical unit
  2254.     bra.s    bd1
  2255. bd2:    addq.w    #2,d2        ; offset for drive A and B
  2256.     move.w    d2,_bootdev    ; set default boot device to (d2)
  2257.  
  2258.     move.l    d0,-(sp)
  2259.     move.l    baseaddr,-(sp)
  2260.     clr.w    -(sp)
  2261.     move.w    #$4a,-(sp)    ; Mshrink(...)
  2262.     trap    #1
  2263.     adda    #12,sp        ; (cleanup stack)
  2264.  
  2265.     move.w    _bootdev,-(sp)    ; set boot dev as default drive
  2266.     move.w    #$e,-(sp)    ; Dsetdrv(_bootdev)
  2267.     trap    #1
  2268.     addq.l    #4,sp        ; cleanup stack
  2269.  
  2270.     move.l    #rootpath,-(sp)    ; set root as current directory
  2271.     move.w    #$3b,-(sp)    ; Dsetpath('\')
  2272.     trap    #1
  2273.     addq.l    #6,sp        ; cleanup stack
  2274.  
  2275.     movea.l    _sysbase,a0    ; get the system header address
  2276.     move.l    $18(a0),d0    ; d0.l = MMDDYYYY of ROM date
  2277.     cmp.l    #CHKDATE,d0    ; does this version of ROM need bootstop?
  2278.     bcs.s    stopall        ; yup, if OS is built before 4/22/87
  2279.     move.b    puns+1,d7    ; else prevent processed units from booting
  2280.     subq.b    #1,d7        ; unit # = # of units - 1
  2281.     lsl.b    #5,d7
  2282.     rts            ; return to TOS ROMs
  2283.  
  2284. stopall:
  2285.     move.b    #$100-$20,d7    ; prevent any other unit from booting
  2286.     rts            ; return to TOS ROMs
  2287.  
  2288. rootpath:
  2289.     dc.b    '\\',0
  2290. msg_loaded:
  2291.     dc.b    '----------------------',13,10
  2292.     dc.b    'Atari Hard Disk Driver',13,10
  2293.     dc.b    'AHDI v3.01 Jun-16-1989',13,10
  2294.     dc.b    '----------------------',13,10
  2295.     dc.b    0
  2296. .even
  2297.  
  2298. ;
  2299. ;  Terminate and stay resident;
  2300. ;  installed driver under GEMDOS.
  2301. ;
  2302. nboot2:    add.l    #$0100,d0    ; for basepage
  2303.     move.w    #0,-(sp)    ; exit code
  2304.     move.l    d0,-(sp)
  2305.     move.w    #$31,-(sp)    ; terminate and stay resident
  2306.     trap    #1        ; should never come back...
  2307.     illegal
  2308.  
  2309.  
  2310.  
  2311. ;+
  2312. ; list_init - Initialize a GEMDOS buffer list (BCBs are contiguous)
  2313. ;
  2314. ; Passed:
  2315. ;     a0.l = head of buffer list            (not changed)
  2316. ;    d0.l = size of each BCB (including data block)    (not changed)
  2317. ;    d1.w = count
  2318. ;         = number of buffers to be installed to the list - 1
  2319. ;
  2320. ; Uses:
  2321. ;    d1, a1
  2322. ;-
  2323. list_init:
  2324.     move.l    a0,-(sp)    ; save head of buffer list
  2325. lin0:    movea.l    a0,a1        ; a1 = ptr to next BCB
  2326.     adda.l    d0,a1        ;    = ptr to curr BCB + size of BCB
  2327.     move.l    a1,(a0)        ; b_link -> next BCB
  2328.     move.w    #-1,4(a0)    ; b_neg1 = -1
  2329.     adda.w    #BCBLEN,a0    ; a0 = ptr to BCB data block
  2330.     move.l    a0,-4(a0)    ; b_bufr -> b_space
  2331.     movea.l    a1,a0
  2332.     dbra    d1,lin0
  2333.     suba.l    d0,a0        ; a0 = ptr to last BCB
  2334.     clr.l    (a0)        ; lastBCB.b_link = NULL
  2335.     move.l    (sp)+,a0    ; restore head of buffer list
  2336.     rts
  2337.  
  2338.  
  2339. ;+
  2340. ; chklstmem - check if enough memory is allocated to replace GEMDOS
  2341. ;        buffer lists
  2342. ;
  2343. ; Returns:
  2344. ;    d0.l = size of each BCB (including data block)
  2345. ;         or -1 if not enough memory is allocated
  2346. ;
  2347. ; Uses:
  2348. ;    d0, d1
  2349. ;-
  2350. chklstmem:
  2351.     moveq    #BCBLEN,d0    ; d0.l = size of each BCB (inc. data block)
  2352.     add.w    maxssz,d0    ;      = BCB header len + data block size
  2353.     move.l    d0,d1        ; d1.l = d0.l * 4 
  2354.     lsl.l    #2,d1        ;      = total size of buffer lists
  2355.     add.l    tokeep,d1    ; d1.l = size needed
  2356.     cmp.l    memalloc,d1    ; enough memory allocated?
  2357.     bls.s    chk0        ; if so return
  2358.     moveq    #-1,d0        ; else return error
  2359. chk0:    rts
  2360.  
  2361.  
  2362. ;
  2363. ;+
  2364. ; pread(sectno, cnt, buf, physunit, flag)
  2365. ; LONG sectno;
  2366. ; BYTE *buf; (word aligned)
  2367. ; WORD cnt,physunit,flag;
  2368. ;
  2369. ; Passed:    flag.w            $10(sp)    
  2370. ;        dev.w        $a(a0)    $e(sp)
  2371. ;        &buf.l        $6(a0)    $a(sp)
  2372. ;        cnt.w        $4(a0)    $8(sp)
  2373. ;        sectno.l    $0(a0)    $4(sp)
  2374. ;
  2375. ; flag = 1 -- return media change if detected
  2376. ; flag = 0 -- ignore media change
  2377. ;
  2378. ; Returns:    -1 if we could not read it
  2379. ;            (may not exist)
  2380. ;-
  2381. _pread:
  2382. pread:    move    _retries,retrycnt
  2383. pread1:    lea    4(sp),a0        ; frame pointer
  2384.     move.w    $a(a0),-(sp)        ; push physical unit number
  2385.     move.l    $6(a0),-(sp)        ; buffer address
  2386.     move.w    $4(a0),-(sp)        ; number to read
  2387.     move.l    (a0),-(sp)        ; sector number
  2388.     bsr    _hread            ; hread()
  2389.     adda    #12,sp            ; clean up stack
  2390.     tst.w    d0            ; read successful
  2391.     beq    pread8            ; if so, return
  2392.     bmi.s    pread9            ; timeout, does not exist
  2393.                     ; else, it's check condition status
  2394.     move.w    $e(sp),cpun        ; cpun = current physical unit #
  2395.     bsr    errcode            ; find error code
  2396.  
  2397.     cmpi.b    #DRVNRDY,d0        ; drive not ready?
  2398.     beq.s    preadd            ; if so, return drive not ready
  2399.  
  2400.     tst.w    $10(sp)            ; ignore media change?
  2401.     beq.s    preadc            ; if so, next try
  2402.                     ; else see if it's media change error
  2403.     cmpi.b    #MDMCHGD,d0        ; media change detected?
  2404.     beq.s    pread7            ; if so, return media change
  2405.  
  2406. preadc:    subq    #1,retrycnt        ; else try try again
  2407.     bpl    pread1
  2408.  
  2409. pread9:    moveq    #EREADF,d0        ; read error
  2410.     rts
  2411.  
  2412. pread7:    moveq    #E_CHNG,d0        ; return media change detected
  2413.     rts
  2414.  
  2415. preadd:    moveq    #EDRVNR,d0        ; drive not ready
  2416.     rts
  2417.  
  2418. pread8:    clr.l    d0            ; flag no errors
  2419.     rts
  2420.  
  2421.  
  2422. ;
  2423. ;+
  2424. ; critic - call up the critical error handler.
  2425. ;
  2426. ; Passed:
  2427. ;    d0.w = error code
  2428. ;    d1.w = drive # excluding A: and B:
  2429. ;
  2430. ; Uses:
  2431. ;    d0, d1, a0
  2432. ;
  2433. ; Returns:
  2434. ;    d0.l = whatever returned by the critical handler
  2435. ;        (magic RETRY code or something)
  2436. ;-
  2437. critic:    addq.w    #2,d1            ; drive # including A: and B:
  2438.     move.w    d1,-(sp)        ; drive #
  2439.     move.w    d0,-(sp)        ; error code
  2440.     movea.l    etv_critic,a0        ; a0 = address of error handler
  2441.     jsr    (a0)            ; critic_handler(error, drive)
  2442.     addq.l    #4,sp            ; clean up stack
  2443.     rts                ; return
  2444.  
  2445.  
  2446. ;+
  2447. ; errcode - find error code for previous Check Condition Status
  2448. ;
  2449. ; Assumed:
  2450. ;    cpun = current physical unit number
  2451. ;
  2452. ; Returns:
  2453. ;    d0.b = error code    (aka additional sense code)
  2454. ;-
  2455. errcode:
  2456.     move.w    cpun,d0            ; d0 = physical unit number
  2457.     move.l    #sendata,-(sp)        ; sense data buffer
  2458.     move.w    d0,-(sp)        ; physical unit number
  2459.     btst.b    d0,scsi            ; embedded SCSI unit?
  2460.     beq.s    err0            ; if not, request non-extended sense
  2461.     bsr    _rq_xsense        ; else request extended sense
  2462.     tst.w    d0            ; successful?
  2463.     bne.s    err1            ; if not, return
  2464.     movea.l    2(sp),a0        ; a0 -> sense data buffer
  2465.     move.b    12(a0),d0        ; else d0.b = error code
  2466.     bra.s    err2            ; and return
  2467. err0:    bsr    _rq_sense        ; find out error code
  2468.     tst.w    d0            ; successful?
  2469.     bne.s    err1            ; if not, return
  2470.     movea.l    2(sp),a0        ; a0 -> sense data buffer
  2471.     move.b    (a0),d0            ; else d0.b = error code
  2472.     andi.b    #$7f,d0            ; mask valid bit
  2473.     bra.s    err2            ; and return
  2474. err1:    moveq    #-1,d0            ; error occurred
  2475. err2:    addq.l    #6,sp            ; cleanup stack
  2476.     rts
  2477.  
  2478.  
  2479. ;
  2480. ;----------------- OS Pool Expansion ------------------
  2481.  
  2482. .if ospool
  2483. ;---------------
  2484. ;
  2485. ;  Wire more pool into various ROM releases.
  2486. ;
  2487. ;    Passed:    nothing
  2488. ;    Returns:    D0 = #bytes extra used
  2489. ;
  2490. ;-
  2491. pool_install:
  2492.     move.l    _sysbase,a3        ; a3 -> base of OS
  2493.  
  2494. ; make sure we're in ROM,
  2495. ; then get address of RAM location to patch:
  2496.  
  2497.     cmp.l    #$800000,a3        ; better be ROM
  2498.     blt    notrom
  2499.     lea    pool_tab(pc),a0        ; a0 -> table to match
  2500. pi_lp:    move.l    (a0)+,d1        ; d1 = date to match
  2501.     beq    badrom            ; (forget it, end of list)
  2502.     move.l    (a0)+,a2        ; a2 -> _root address for that date
  2503.     cmp.l    $18(a3),d1        ; match dates?
  2504.     bne.s    pi_lp            ; (no -- try again)
  2505.  
  2506.     move.w    numchunks,d0        ; d0 = amount of BSS to be used
  2507.     mulu    #chunksiz,d0        ;    = # chunks * size of a chunk
  2508.     move.l    d0,d1            ; d1 = total memory needed
  2509.     add.l    tokeep,d1        ;    = already keeping + extra OS pool
  2510.     cmp.l    memalloc,d1        ; enough is allocated?
  2511.     bgt.s    bdrom2            ; if not, don't add any
  2512.                     ; else install more OS pool
  2513.     movea.l    #i_sasi+2,a0        ; a0 -> base of first buffer
  2514.     adda.l    tokeep,a0        ;    = start of file + already keeping
  2515.     move.l    a0,-(sp)        ; save base of first buffer
  2516.     move.w    numchunks,d1        ; d0 = count-1
  2517.     subq.w    #1,d1
  2518. pin_1:    lea    chunksiz(a0),a1        ; a1 -> next buffer
  2519.     move.l    a1,(a0)            ; buffer -> next one
  2520.     move.w    #chunkno,-2(a0)        ; install chunksiz
  2521.     move.l    a1,a0            ; a0 -> next buffer
  2522.     dbra    d1,pin_1        ; (do some more)
  2523.  
  2524.     sub.w    #chunksiz,a0        ; a0 -> last block
  2525.     move.l    chunkno*4(a2),(a0)    ; last block -> first in root
  2526.     move.l    (sp)+,chunkno*4(a2)     ; root -> first of ours
  2527.     rts                ; return OK
  2528.  
  2529. ;+
  2530. ;  Print warning messages
  2531. ;  about bogus versions of the
  2532. ;  operating system.  Assume that
  2533. ;  every OS past 1-May-1986 has the
  2534. ;  pool fix installed.
  2535. ;
  2536. ;-
  2537. ok_date    =    %0000110010100001    ; 1-May-1986
  2538. notrom:    lea    m_notrom(pc),a0        ; ram-based system (5/29!)
  2539.     bra.s    bdrom1
  2540. badrom:    lea    m_badrom(pc),a0        ; illegal ROM system
  2541. bdrom1:    cmp.w    #ok_date,$1e(a3)    ; if ok_date <= os_dosdate(a3) 
  2542.     bcc    bdrom2            ; then don't print anything
  2543.  
  2544.     move.l    a0,-(sp)        ; print nasty message
  2545.     move.w    #9,-(sp)
  2546.     trap    #1
  2547.     addq.l    #6,sp
  2548.  
  2549. ; print msg and wait for RETURN
  2550.     pea    keymsg(pc)
  2551.     move.w    #9,-(sp)
  2552.     trap    #1
  2553.     addq.l    #6,sp
  2554.  
  2555. bdrom3:    move.w    #2,-(sp)        ; wait for [RETURN]
  2556.     move.w    #2,-(sp)
  2557.     trap    #13
  2558.     addq.l    #4,sp
  2559.     cmp.w    #13,d0
  2560.     bne    bdrom3
  2561.  
  2562. bdrom2:    moveq    #0,d0            ; 0 extra bytes used
  2563.     rts
  2564.  
  2565. keymsg:    dc.b    'Hard disk driver not loaded; hit RETURN',13,10
  2566.     dc.b    'key to continue:',13,10
  2567.     dc.b    0
  2568.  
  2569. m_notrom:
  2570.     dc.b    '*** WARNING ***',13,10,7
  2571.     dc.b    'This hard disk driver may not work with',13,10,7
  2572.     dc.b    'a disk-based version of TOS; files on',13,10,7
  2573.     dc.b    'your hard disk may be damaged.',13,10,7
  2574.     dc.b    13,10,7
  2575.     dc.b    0
  2576.  
  2577. m_badrom:
  2578.     dc.b    '*** WARNING ***',13,10,7
  2579.     dc.b    'You are using an unofficial ROM release',13,10,7
  2580.     dc.b    'of the operating system.  This driver',13,10,7
  2581.     dc.b    'may not work correctly with it.  Files',13,10,7
  2582.     dc.b    'on your hard disk may be damaged.',13,10,7
  2583.     dc.b    13,10,7
  2584.     dc.b    0
  2585.     even
  2586.  
  2587.  
  2588. ;+
  2589. ;  Table of ROM release dates / _root addresses
  2590. ;  update these for new ROM releases that need the patch.
  2591. ;
  2592. ;-
  2593. pool_tab:
  2594.     dc.l    $11201985,$56fa        ; USA and UK, 20-Nov-1985
  2595.     dc.l    $02061986,$56fa        ; Germany, 6-Feb-1986
  2596.     dc.l    $04241986,$56fa        ; France, 24-Apr-1986
  2597.     dc.l    0            ; end of list
  2598.  
  2599. .endif
  2600.  
  2601.  
  2602. ;
  2603. ;------------------ Driver Installation -----------------
  2604.  
  2605. ;----------------
  2606. ;
  2607. ;  Driver Installation
  2608. ;
  2609. i_sasi1:
  2610.     move.l    d0,memalloc        ; record amount of memory available
  2611.     tst.w    bootloaded        ; if boot-loaded, don't Super()
  2612.     bne    nboot3
  2613.     clr.l    -(sp)            ; it's a bird...
  2614.     move.w    #$20,-(sp)        ;    ... it's a plane ...
  2615.     trap    #1            ;      ... no, its:
  2616.     addq.l    #6,sp            ; SOOUPERUSER!
  2617.     move.l    d0,savssp        ; "Faster than a prefetched opcode..."
  2618.  
  2619. nboot3:    move    #MAXUNITS-1,d1
  2620.     moveq    #-1,d0            ; a bad pun
  2621.     lea    pun,a0
  2622. i_sasi2:
  2623.     move.b    d0,(a0)+        ; initialize all puns to be bad
  2624.     dbra    d1,i_sasi2
  2625.  
  2626.     move    #0,clun            ; cur log unit# excluding drive A & B
  2627.     move.l    #4,cdbit        ; current drive bit
  2628.     move    #0,cpun            ; current physical unit number
  2629.     move    #0,puns            ; no physical units found
  2630.     move    minbigsect,maxssz    ; initialize maximum sector size
  2631.  
  2632.     move.l    _dskbufp,pbuf        ; pbuf = buffer address of
  2633.     add.l    #512,pbuf        ;     root sector image
  2634. i_sasi3:
  2635.     clr.w    -(sp)            ; ignore media change
  2636.     move.w    cpun,-(sp)        ; physical unit number
  2637.     move.l    pbuf,-(sp)        ; buffer
  2638.     move.w    #1,-(sp)        ; 1 sector
  2639.     move.l    #0,-(sp)        ; sectno = 0; root sector
  2640.     bsr    pread            ; pread()
  2641.     adda    #14,sp
  2642.     move.w    d0,preadret        ; save pread return code
  2643.  
  2644.     movea.l    #sendata,a0        ; a0 = address of sense data buffer
  2645.     clr.l    (a0)            ; fill buffer with 0's
  2646.     clr.l    4(a0)
  2647.     clr.l    8(a0)
  2648.     clr.l    $c(a0)
  2649.     move.l    a0,-(sp)        ; buffer for data inquired
  2650.     move.w    cpun,-(sp)        ; current physical unit
  2651.     bsr    _inquiry        ; inquiry(physunit, buf)
  2652.     addq.l    #6,sp            ; clean up stack
  2653.     tst.w    d0            ; Inquiry successful?
  2654.     bne.s    chkret            ; if not, unit isn't a SCSI device
  2655.                     ; else unit is a SCSI device
  2656.     movea.l    #sendata,a0        ; a0 = address of sense data
  2657.     tst.b    (a0)            ; is unit a hard drive?
  2658.     bne.s    i_sasi4            ; if not, end of chain
  2659.     move.w    cpun,d1            ; else d1 = physical unit #
  2660.     bset.b    d1,scsi            ; mark unit as embedded scsi
  2661.     btst.b    #7,1(a0)        ; removable drive?
  2662.     beq.s    chkret            ; if not removable, was read ok?
  2663.     bset.b    d1,rmbits        ; else mark unit as removable
  2664.     bra.s    found1
  2665. chkret:    tst.w    preadret        ; was pread successful?
  2666.     bne.s    i_sasi4            ; if not, not an ACSI unit, return
  2667. found1:    addq    #1,puns            ; else found a physical unit
  2668.     bsr    ppu            ; find out how it is partitioned
  2669.     tst.w    d0            ; ppu successful?
  2670.     beq.s    nxtpun            ; go on normally
  2671.                     ; else find out what's wrong
  2672.     cmpi.w    #E_CHNG,d0        ; media changed?
  2673.     beq    i_sasi3            ; if so, retry this unit
  2674.                     ; else try next physical unit
  2675. nxtpun:    addq.w    #1,cpun            ; next physical unit
  2676.     cmpi.w    #MAXACSI,cpun        ; last one yet?
  2677.     bne    i_sasi3            ; if not, continue
  2678.  
  2679. i_sasi4:
  2680.     clr.l    a5            ; zeropage ptr
  2681.     move.l    hdv_bpb(a5),o_bpb
  2682.     move.l    hdv_rw(a5),o_rw
  2683.     move.l    hdv_mediach(a5),o_mediach
  2684.  
  2685.     move.l    #hbpb,hdv_bpb(a5)    ; install our new ones
  2686.     move.l    #hrw,hdv_rw(a5)
  2687.     move.l    #hmediach,hdv_mediach(a5)
  2688.     move.l    #_puns,pun_ptr(a5)
  2689.  
  2690.     move.l    #_cookie,cookptr    ; initialize cookie pointer
  2691.     bra    isasi5            ; must get back into resident part
  2692.  
  2693.  
  2694. ;
  2695. ;-----------------
  2696. ;
  2697. ; Partition physical unit
  2698. ;
  2699. ;
  2700. ppu:    move.w    #0,npart        ; no partition found for cpun yet
  2701.     move.w    cpun,d1            ; is cpun removable?
  2702.     btst.b  d1,rmbits        ;
  2703.     beq.s    ppu0            ; if not, go on normally
  2704.                     ; else, it's a syquest unit
  2705.     tst.w    preadret        ; is there a cartridge in there?
  2706.     bne.s    squnit            ; if not, go reserve #drv letters
  2707.                     ; else find the partitions
  2708. ppu0:    moveq    #MAXNPART,d1        ; d1 = # partition entries to check
  2709.     movea.l    pbuf,a0            ; a0 = ptr to root sector image
  2710.     cmpi.w    #SIG,DOSSIG(a0)        ; is root sector in DOS format?
  2711.     bne.s    ppu1            ; if not, assume it's in ST format
  2712.     bsr    dosppu            ; else, handle it the DOS way
  2713.     bra.s    ppu2
  2714. ppu1:    bsr    gemppu
  2715. ppu2:    tst.w    d0            ; successful?
  2716.     bne.s    ppud            ; if not, return
  2717.  
  2718.     lea    minsqnpart,a0        ; a0 = addr of least # of drives
  2719.     move.w    cpun,d1            ; d1 = unit #
  2720.     move.b    (a0,d1.w),d1        ; d0 = least # of drives requested
  2721.     sub.w    npart,d1        ; enough drives being set up?
  2722.     bls.s    ppud            ; if so, done
  2723.                     ; else see if it's removable
  2724.     move.w    cpun,d0            ; d0 = unit #
  2725.     btst.b    d0,rmbits        ; is cpun removable?
  2726.     beq.s    ppud            ; if not, done
  2727.     bra.s    sq0            ; else, set up the rest
  2728.  
  2729. squnit:    lea    minsqnpart,a0        ; a0 = addr of least # of drives
  2730.     move.w    cpun,d1            ; d1 = unit #
  2731.     move.b    (a0,d1.w),d1        ; d0 = least # of drives requested
  2732. sq0:    subq.w    #1,d1
  2733. ppu3:    move.w    d1,-(sp)        ; save count
  2734.     bsr    nxtd0
  2735.     move.w    (sp)+,d1        ; restore count
  2736.     tst.w    d0            ; a valid unit?
  2737.     bmi.s    ppud            ; if not, return
  2738.     dbra    d1,ppu3
  2739. ppud:    rts
  2740.  
  2741.  
  2742. ;
  2743. ;+
  2744. ; dosppu - find the DOS partitions of the drive and set up
  2745. ;       appropiate data structures.
  2746. ; Passed:
  2747. ;    a0 = buffer address for root sector
  2748. ;    d1 = number of entries in partition map
  2749. ;
  2750. ; Returns:
  2751. ;    d0 = 0            if no error
  2752. ;       = negative #        if error found
  2753. ;-
  2754. dosppu:    adda.w    #DOSPM,a0        ; a0 = ptr to partition map
  2755. dppu0:    movem.l    d1/a0,-(sp)        ; save count and offset
  2756.     sf    ext            ; not dealing with ext partition
  2757.     bsr    fdpart            ; find partitions
  2758.     tst.b    d0            ; found any?
  2759.     beq.s    dppua            ; not a valid partition
  2760.     cmpi.b    #5,d0            ; extended partition?
  2761.     bne.s    dppu1            ; if not, it's a regular partition
  2762.     st    ext            ; else, it's an extended partition
  2763.     move.l    #0,extvol        ; offset from start of partition = 0
  2764.     move.l    d1,extrt        ; starting sector # of ext partition
  2765. dppux:    bsr    fdnxt            ; find next logical drive
  2766.     tst.b    d0            ; found any?
  2767.     beq.s    dppua            ; no logical drive found
  2768.     bmi.s    dppu2            ; error returned
  2769.     cmpi.b    #5,d0            ; extended volume?
  2770.     beq.s    dppux            ; if so, go find next logical drive
  2771. dppu1:    movem.l    d1-d2/a0,-(sp)        ; save registers
  2772.     bsr    nxtdrv            ; general set up for clun
  2773.     movem.l    (sp)+,d1-d2/a0        ; restore registers
  2774.     tst.w    d0            ; set up successful?
  2775.     beq.s    dppu3            ; if successful, continue
  2776. dppu2:    addq.l    #8,sp            ; else clean up stack
  2777.     bra.s    dppur            ; and return
  2778. dppu3:    tst.b    ext            ; clun is in ext partition?
  2779.     bne.s    dppux            ; if so, go find next ext vol
  2780. dppua:    movem.l    (sp)+,d1/a0        ; restore count and offset
  2781.     adda    #16,a0            ; index to next entry in pmap
  2782.     dbra    d1,dppu0
  2783.     moveq    #0,d0            ; get here with no error!
  2784. dppur:    rts
  2785.  
  2786.  
  2787. ;
  2788. ;+
  2789. ; gemppu - find the GEMDOS partitions of the drive and set up
  2790. ;       appropiate data structures.
  2791. ; Passed:
  2792. ;    a0 = buffer address for root sector
  2793. ;    d1 = number of entries in partition map
  2794. ;
  2795. ; Returns:
  2796. ;    d0 = 0            if no error
  2797. ;       = negative #        if error found
  2798. ;-
  2799. gemppu:    adda.w    #HDSIZ,a0        ; a0 = ptr to hard disk size
  2800.     tst.l    (a0)+            ; size? (a0 = ptr to start of pmap)
  2801.     beq.s    gppu4            ; if =0, no drive will exist
  2802. gppu0:    movem.l    d1/a0,-(sp)        ; save count and offset
  2803.     sf    ext            ; not dealing with ext partition
  2804.     bsr    fgpart            ; find partitions
  2805.     tst.b    d0            ; found any?
  2806.     beq.s    gppua            ; not a valid partition
  2807.     cmpi.b    #'X',d0            ; extended partition?
  2808.     bne.s    gppu1            ; if not, it's a regular partition
  2809.     st    ext            ; else, it's an extended partition
  2810.     move.l    #0,extvol        ; offset from start of partition = 0
  2811.     move.l    d1,extrt        ; starting sector # of ext partition
  2812. gppux:    bsr    fgnxt            ; find next logical drive
  2813.     tst.b    d0            ; found any?
  2814.     beq.s    gppua            ; no logical drive found
  2815.     bmi.s    gppu2            ; error returned
  2816.     cmpi.b    #'X',d0            ; extended volume?
  2817.     beq.s    gppux            ; if so, go find next logical drive
  2818. gppu1:    movem.l    d1-d2/a0,-(sp)        ; save registers
  2819.     bsr    nxtdrv            ; general set up for clun
  2820.     movem.l    (sp)+,d1-d2/a0        ; restore registers
  2821.     tst.w    d0            ; set up successful?
  2822.     beq.s    gppu3            ; if so, continue
  2823. gppu2:    addq.l    #8,sp            ; else clean up stack
  2824.     bra.s    gppur            ; and return
  2825. gppu3:    tst.b    ext            ; clun is in ext partition?
  2826.     bne.s    gppux            ; if so, go find next ext vol
  2827. gppua:    movem.l    (sp)+,d1/a0        ; restore count and offset
  2828.     adda    #12,a0            ; index to next entry in pmap
  2829.     dbra    d1,gppu0
  2830. gppu4:    moveq    #0,d0            ; get here with no error!
  2831. gppur:    rts
  2832.  
  2833.  
  2834. ;
  2835. ;+
  2836. ; nxtdrv    (of clun, cdbit)
  2837. ;
  2838. ; Passed:
  2839. ;    d1.l = starting sector # of clun
  2840. ; Returns:
  2841. ;    d0 = 0            if successful
  2842. ;       = negative #        if error occurred
  2843. ;-
  2844. nxtdrv:    cmpi    #MAXUNITS,clun        ; have we already hit maximum?
  2845.     bge    nxtd9            ; yes, so signal error
  2846.  
  2847.     move.w    #1,-(sp)        ; return media change if detected
  2848.     move.w    cpun,-(sp)        ; physical unit number
  2849.     move.l    #sbuf,-(sp)        ; buffer address
  2850.     move.w    #1,-(sp)        ; 1 sector
  2851.     move.l    d1,-(sp)        ; logical sector 0 of clun
  2852.     bsr    pread            ; pread(sectno, cnt, buf, phys#, flag)
  2853.     adda    #14,sp            ; clean up stack
  2854.     tst.w    d0            ; pread successful?
  2855.     bne    nxtr            ; if not, return with error code
  2856.  
  2857.     move.l    #sbuf,a0        ; a0 = addr of boot sector image
  2858.     moveq    #$b,d0            ; d0 = offset for bytes per sector
  2859.     bsr    getlhw
  2860.     tst.w    d0            ; bytes per sector = 0?
  2861.     beq.s    nxtd1            ; if so, assume ratio to be 1
  2862.  
  2863.     cmp.w    maxssz,d0        ; max sect size >= curr sect size?
  2864.     bls.s    nxtd00            ; if so, continue
  2865.     move.w    d0,maxssz        ; else max sect size = curr sect size
  2866. nxtd00:    divu    #512,d0            ; d0 = sector size ratio
  2867.     move.w    d0,sizr            ; sizr = sector size ratio
  2868.     bra.s    nxtd2            ; go on
  2869.  
  2870. nxtd0:    cmpi    #MAXUNITS,clun        ; have we already hit maximum?
  2871.     bge    nxtd9            ; yes, so signal error
  2872.  
  2873. nxtd1:    move.w    #1,sizr            ; sector size ratio assumes to be 1
  2874.  
  2875. nxtd2:    move.l    cdbit,d1        ; get the bit to turn on
  2876.     move.l    _drvbits,d0        ; tell TOS we have the drive
  2877.     or.l    d1,d0
  2878.     move.l    d0,_drvbits
  2879.  
  2880.     asl.l    #1,d1            ; put in the next bit to turn on
  2881.     move.l    d1,cdbit
  2882.  
  2883.     move    clun,d0            ; d0 = dev number
  2884.     lea    pun,a0            ; a0 = ptr to pun table
  2885.     move.b    cpun+1,(a0,d0.w)    ; clun belongs to cpun
  2886.  
  2887.     lea    sratio,a0        ; a0 = ptr to sector size ratio table
  2888.     move.b    sizr+1,(a0,d0.w)    ; save sector ratio of clun
  2889.  
  2890.     lea    xst,a0            ; a0 = ptr to drive existence table
  2891.     move.b    #1,(a0,d0.w)        ; clun may exist
  2892.  
  2893.     lea    mcflgs,a0        ; a0 = ptr to mcflgs table
  2894.     move.b    #2,(a0,d0.w)        ; clun is definitely changed
  2895.  
  2896.     addq    #1,clun            ; clun = next possible lun
  2897.     addq    #1,npart        ; one more partition found
  2898.     moveq    #0,d0            ; gets here with no error
  2899.     bra.s    nxtr
  2900.  
  2901. nxtd9:    moveq    #-1,d0            ; error!
  2902. nxtr:    rts
  2903.  
  2904.  
  2905. ;
  2906. .if    format
  2907. ;----------------
  2908. ;
  2909. ;  Parameter Block
  2910. ;
  2911. acfmt:    dc.b    4    ; format command + devno (upper 3 bits)
  2912.     dc.b    0    ; (unused)
  2913.     dc.b    0    ; (unused) data pattern
  2914. ac_in:    dc.b    0,0    ; interleave factor MSB, LSB
  2915.     dc.b    0    ; reserved
  2916. .even
  2917.  
  2918. ;---------------
  2919. ;
  2920. ;  _doformat - format hard disk
  2921. ;
  2922. ;    Synopsis:    LONG _doformat(dev, interlv)
  2923. ;        WORD dev;            4(sp).W
  2924. ;        WORD interlv;            6(sp).W
  2925. ;
  2926. _doformat:
  2927.     move.w    4(sp),d0        ; set dev#
  2928.     lsl.b    #5,d0            ; up 5 bits, fill in 0s
  2929.     or.b    #4,d0            ; OR-in with FORMAT command
  2930.     move.b    d0,acfmt        ; stuff into command frame
  2931.     move.b    6(sp),ac_in        ; set interleave
  2932.     move.b    7(sp),ac_in+1
  2933.  
  2934.     lea    acfmt(pc),a0        ; pick up pointer to the command block
  2935.     clr.w    d0
  2936.     st    flock            ; lock FIFO
  2937.     move.w    #$88,wdl
  2938.     move.b    (a0)+,d0        ; get the command byte
  2939.     swap    d0
  2940.     move.w    #$8a,d0
  2941.     move.l    d0,wdc            ; byte wdc 8a wdl
  2942.  
  2943.     moveq    #(5-1),d1        ; write remaining 5 bytes of command
  2944. fmt1:    bsr    _qdone
  2945.     bmi    _hto
  2946.     move.b    (a0)+,d0        ; next byte of command
  2947.     swap    d0
  2948.     move.w    #$8a,d0
  2949.     move.l    d0,wdcwdl
  2950.     dbra    d1,fmt1
  2951.     bsr    _endcmd            ; wait for command completion
  2952.     bra    _hdone            ; cleanup after IRQ
  2953.  
  2954.  
  2955. ;
  2956. ;----------------
  2957. ;
  2958. ;  _mode_set - set hard disk format parameters
  2959. ;
  2960. ;    Synopsis:    LONG _mode_set(dev, len, parms)
  2961. ;        WORD dev;            4(sp).W
  2962. ;        WORD len;            6(sp).W
  2963. ;        char *parms;            8(sp).L
  2964. ;
  2965. _mode_set:
  2966.     st    flock            ; lock FIFO
  2967.     move.l    8(sp),-(sp)        ; -> parameter block address
  2968.     bsr    _setdma            ; set DMA there
  2969.     addq.l    #4,sp
  2970.  
  2971. ; write command and dev#
  2972.     move.w    #$88,wdl
  2973.     move.w    4(sp),d0        ; d0 = (dev << 5) << 16
  2974.     lsl.b    #5,d0
  2975.     swap    d0            ; in upper word
  2976.     or.l    #$0015008a,d0        ; write dev# + ModeSelect + FIFO bits
  2977.     move.l    d0,wdcwdl        ; mdsel+dev wdc 8a wdl (byte 0)
  2978.     bsr    _qdone
  2979.     bmi    wdx
  2980.  
  2981.     move.l    #$0000008a,wdcwdl    ; byte 1
  2982.     bsr    _qdone
  2983.     bmi    wdx
  2984.  
  2985.     move.l    #$0000008a,wdcwdl    ; byte 2
  2986.     bsr    _qdone
  2987.     bmi    wdx
  2988.  
  2989.     move.l    #$0000008a,wdcwdl    ; byte 3
  2990.     bsr    _qdone
  2991.     bmi    wdx
  2992.  
  2993.     move.w    6(sp),d0        ; # bytes of parameter
  2994.     swap    d0            ; in upper word
  2995.     or.l    #$0000008a,d0
  2996.     move.l    d0,wdcwdl        ; byte 4
  2997.     bsr    _qdone
  2998.     bmi    wdx
  2999.  
  3000.     move.w    #$90,wdl        ; reset the DMA chip
  3001.     move.w    #$190,wdl
  3002.     move.w    #$01,wdc        ; 1 sector of DMA (actually less)
  3003.     move.w    #$18a,wdl
  3004.     move.l    #$00000100,wdcwdl    ; byte 5 (control byte)
  3005.     move.w    #$18a,d0        ; wdl value
  3006.     bsr    _endcmd            ; wait for command completion
  3007. wdx:    bra    _hdone
  3008.  
  3009. .endif  ; format
  3010.  
  3011.   
  3012. .if    mdsense
  3013. ;----------------
  3014. ;
  3015. ;  _md_sense - get hard disk format parameters
  3016. ;
  3017. ;    Synopsis:    LONG _md_sense(dev, parms)
  3018. ;        WORD dev;            4(sp).W
  3019. ;        char *parms;            6(sp).L
  3020. ;
  3021. _md_sense:
  3022.     st    flock            ; lock FIFO
  3023.     move.l    6(sp),-(sp)        ; -> parameter block address
  3024.     bsr    _setdma            ; set DMA there
  3025.     addq.l    #4,sp
  3026.  
  3027. ; write command and dev#
  3028.     move.w    #$88,wdl
  3029.     move.w    4(sp),d0        ; d0 = (dev << 5) << 16
  3030.     lsl.b    #5,d0
  3031.     swap    d0            ; in upper word
  3032.     or.l    #$001a008a,d0        ; write dev# + ModeSense + FIFO bits
  3033.     move.l    d0,wdcwdl        ; mdsense+dev wdc 8a wdl (byte 0)
  3034.     bsr    _qdone
  3035.     bmi    wdx1
  3036.  
  3037.     move.l    #$0000008a,wdcwdl    ; byte 1
  3038.     bsr    _qdone
  3039.     bmi    wdx1
  3040.  
  3041.     move.l    #$0000008a,wdcwdl    ; byte 2
  3042.     bsr    _qdone
  3043.     bmi    wdx1
  3044.  
  3045.     move.l    #$0000008a,wdcwdl    ; byte 3
  3046.     bsr    _qdone
  3047.     bmi    wdx1
  3048.  
  3049.     move.l    #$0016008a,wdcwdl    ; 22 bytes of parameters (byte 4)
  3050.     bsr    _qdone
  3051.     bmi    wdx1
  3052.  
  3053.     move.w    #$190,wdl        ; reset the DMA chip
  3054.     move.w    #$90,wdl
  3055.     move.w    #$01,wdc        ; 1 sector of DMA (actually less)
  3056.     move.w    #$8a,wdl
  3057.     move.l    #0,wdcwdl        ; byte 5 (control byte)
  3058.     move.w    #$8a,d0            ; wdl value
  3059.     bsr    _endcmd            ; wait for command completion
  3060. wdx1:    bra    _hdone
  3061.  
  3062. .endif  ; mdsense
  3063.  
  3064.     bss
  3065. clun:    ds.w    1            ; current logical unit
  3066. cdbit:    ds.l    1            ; current drive bit
  3067. sbuf:    ds.b    512            ; temporary buffer for i/o
  3068.     end
  3069.