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 / AHDI603 / DMAREAD.S < prev    next >
Encoding:
Text File  |  2001-02-09  |  55.1 KB  |  1,922 lines

  1. .super
  2. ******************* Revision Control System *****************************
  3. *
  4. * $Author: apratt $
  5. * =======================================================================
  6. *
  7. * $Date: 1991/11/06 22:42:16 $
  8. * =======================================================================
  9. *
  10. * $Locker:  $
  11. * =======================================================================
  12. *
  13. * $Log: dmaread.s,v $
  14. * Revision 1.27  1991/11/06  22:42:16  apratt
  15. * Fixed a BIG OOPS: at qd0 the label 'sdelay' was wrong so that
  16. * the add of _hz_200 to d0 was INSIDE the loop.  Oops.  Fixed.
  17. *
  18. * Revision 1.26  1991/10/15  15:04:18  apratt
  19. * Fixed a bug in the caller of strcmp.
  20. *
  21. * Revision 1.24  1991/09/30  18:04:38  apratt
  22. * Previous version worked very badly.  One theory: Conner says that
  23. * you need a delay between Identify and Init Parameters.  When Minna
  24. * took out the Init Parameters call, she also took out the delay.
  25. * Well, hmm, maybe the delay is required between Identify and
  26. * ANYTHING ELSE.  So it's back.
  27. *
  28. * Revision 1.23  1991/09/30  16:45:06  apratt
  29. * New from Minna: checks both READY and BUSY waiting for the right values.
  30. * Seems some drives set READY before clearing BUSY.  Sigh.
  31. *
  32. * Revision 1.22  1991/09/13  17:45:58  apratt
  33. * Oops - the delay was supposed to be 500us, not 500ms.  Made it
  34. * two ticks, which is btw 5 and 10 ms.
  35. *
  36. * Revision 1.21  1991/09/13  00:46:52  apratt
  37. * Minna added yet another delay: Conner wants 0.5sec between
  38. * power up and the Identify command.
  39. *
  40. * Revision 1.20  1991/09/12  19:56:18  apratt
  41. * Changed to assemble IDE_AT for ALL MACHINES, now that there's no
  42. * distinction at assembly time between ST and STPLUS.
  43. *
  44. * Revision 1.19  1991/09/06  14:50:56  apratt
  45. * Changed all "ifne" to "if" and "ifeq" to "if !" and "endc" to "endif."
  46. *
  47. * Revision 1.18  91/08/21  11:18:56  apratt
  48. * Fixed two oopses: iderdy is now consistently _iderdy,
  49. * and undev is outside IDEAT conditionals.
  50. * Revision 1.17  91/08/20  13:22:25  minna
  51. * Added iderdy() to test if IDE drive is ready before 
  52. * it's being talked to.  If the drive does not become
  53. * ready in 5 sec., it's considered as an unknown device.
  54. * Revision 1.16  91/08/15  16:18:07  apratt
  55. * Added code for IDE to wait until ATASR shows READY before
  56. * doing anything else.  Also changed so IDE_AT is assembled for
  57. * all STPLUS versions; the bus error detection will take care
  58. * of failing out quick on those machines that don't really have
  59. * an IDE bus.
  60. * Revision 1.15  91/08/02  16:21:23  minna
  61. * Added delay between identify() and initparm(),
  62. * and reversed changes made earlier today.
  63. * Revision 1.14  91/08/02  15:07:10  minna
  64. * Added handling of final interrupt after data transfer
  65. * on IDE drive.
  66. * Revision 1.13  91/07/29  12:37:45  minna
  67. * _atread() and _atwrite modified to not use the
  68. * ATSC (sector count register) to count down on
  69. * multiple sectors read or write.  Some vendors
  70. * decrement the register too early.
  71. * To test if the IDE interface exists, instead of
  72. * reading from bAT (the data register), read from
  73. * ATASR (the alternate status register.)
  74. * Revision 1.12  91/03/27  12:36:36  apratt
  75. * Base address of IDE has moved to $F00000.  This code assumes that the base
  76. * address is on a longword boundary.  Added guards against missing IDE bus,
  77. * and against missing ACSI (bus error when accessing DMA chip).  This is
  78. * for prototype PADs only, and may go away soon.
  79. * Changed switches to SCSI and IDE_AT, which are set based on TT and STPAD at
  80. * the top of the file.
  81. * Revision 1.11  91/02/26  17:58:37  minna
  82. * Base address of IDE bus has been moved to $F00000.  Note that this code
  83. * relies on the base address of the IDE bus being on a longword boundary.
  84. * Revision 1.10  90/10/29  15:52:12  minna
  85. * Base address of IDE bus has been moved to $C00040 (long word boundary).
  86. * Revision 1.9  90/10/19  16:05:22  minna
  87. * Added code to handle drives on the IDE-AT bus.
  88. * Revision 1.8  90/08/03  13:22:48  apratt
  89. * TTOS FINAL RELEASE
  90. * Revision 1.7  90/03/06  16:09:16  apratt
  91. * Moved .globl _resetscsi into the TT conditional; otherwise
  92. * MAS thinks it's external, even though it's never used!
  93. * Revision 1.6  90/03/02  17:46:34  apratt
  94. * This rev is the source for the 3/1/90 ROM.
  95. * Revision 1.5  90/03/01  17:27:00  apratt
  96. * Checkin of Minna's changes, including adding better spin-up delays
  97. * and the dmawrite call.
  98. * Revision 1.4  89/09/22  16:42:55  apratt
  99. * THIS VERSION REQUIRES TURBO C'S "MAS" ASSEMBLER
  100. * No functional changes from previous revision, which is the last to
  101. * require Alcyon's AS68 assembler.
  102. * Revision 1.3  89/09/07  16:30:02  apratt
  103. * Added delay after (potentially) resetting ACSI DMA chip; see SLOWACSI
  104. * code in flop.b.
  105. * Revision 1.2  89/08/25  16:49:18  apratt
  106. * Moved lastacstm from text seg to bss.
  107. * Revision 1.1  89/08/25  16:45:32  apratt
  108. * Initial revision
  109. *
  110. * =======================================================================
  111. *
  112. * $Revision: 1.27 $
  113. * =======================================================================
  114. *
  115. * $Source: e:/tos/bios\RCS\dmaread.s,v $
  116. * =======================================================================
  117. *
  118. *************************************************************************
  119.  
  120. * TT and STPAD equates are in switches.s
  121.  
  122. .include "switches.s"
  123.  
  124. * The code you get in assembling this file depends on the switches SCSI and
  125. * IDE_AT.  For now (2/91), only TT has SCSI and all STPLUSes have IDE.
  126. *
  127. * Those STPLUS machines which use these ROMs but don't actually have an IDE
  128. * bus will still get the IDE code, but using it will fail right away
  129. * because it always probes for the IDE bus and returns if it doesn't exist.
  130. *
  131. * As of 9/91 we want One Rom To Rule Them All, so ALL machines have IDE_AT.
  132. *
  133.  
  134. SCSI        =    TT
  135. IDE_AT        =    1    ; Always! (AKP 9/91)
  136.  
  137. SPSCSI        =    SPARROW    ; 1: Sparrow SCSI
  138.  
  139. ;+
  140. ; DMAREAD(), DMAWRITE() - 
  141. ;    New XBIOS calls to read from or write to hard disk on the
  142. ; ACSI, SCSI or IDE-AT bus.  This is a low-level read/write which 
  143. ; does not do a lot of checking.  Amount of data requested on each 
  144. ; ACSI read or write MUST be smaller than or equal to 255 physical
  145. ; (512-byte) sectors.  On SCSI, all I/O are done by handshaking.  
  146. ; Amount of data requested on each IDE-AT read or write MUST be 
  147. ; smaller than or equal to 256 physical (512-byte) sectors.
  148. ;
  149. ; Jul-24-1989    ml.    Started this from AHDI 3.50 of Jul 24 1989.
  150. ; Aug-23-1989    ml.    Added in code to do hand-shake I/O, instead of
  151. ;            DMA.
  152. ; Dec-11-1989    ml.    Adjusted time-outs.
  153. ; Feb-08-1990    ml.    Updated according to corrections made to the
  154. ;            TT driver (DRIVER.PRG v3.63)
  155. ;            Renamed as dmarw() after adding code to handle
  156. ;            writes also.
  157. ; Feb-28-1990    ml.    Split dmarw() to become dmaread() and dmawrite()
  158. ;            as requested by AKP.  Modified time-out handling.
  159. ;            If system was up for less than UPTIME clicks, use
  160. ;            UPTIME as time-out counter rather than the regular
  161. ;            SC?TMOUT value.
  162. ; Mar-02-1990    ml.    Undid (again?!!) modifications made since Feb 28.
  163. ;            Will use regular SC?TMOUT values.  BIOS will keep
  164. ;            calling _dmaread() at boot time until the drive
  165. ;            responses, BIOS' time-out count expires, or when 
  166. ;            Bios receive a quit message from the user.
  167. ; Oct-16-1990    ml.    Added in code to handle drives on the IDE-AT bus
  168. ;            also.  The code comes from DRIVER.PRG v4.50 (dated
  169. ;            Oct 16 1990), and is slightly modified.
  170. ; Oct-29-1990    ml.    Base address of the IDE bus has been moved to
  171. ;            $C00040 (long word boundary).
  172. ; Feb-22-1991    ml.    Base address of the IDE bus has been moved to
  173. ;            $F00000 (long word boundary).
  174. ; Jul-29-1991    ml.    Do not use the IDE Sector Count Register 
  175. ;            to count down mulitiple sectors read or
  176. ;            write.  Some vendors (e.g. Conner and 
  177. ;            Seagate) seem to update this register 
  178. ;            too early, and every now and then, the
  179. ;            last sector of data would remain in the
  180. ;            internal sector buffer.  
  181. ;            
  182. ;            Code in ideread() and idewrite() are modified
  183. ;            not to use the IDE Sector Count Register.
  184. ;
  185. ;            To check if the IDE bus is there, read from
  186. ;            the alternate status register instead of the
  187. ;            data register.
  188. ;
  189. ; Aug-02-1991    ml.    Added handling of final interrupt from the
  190. ;            IDE drive after data transfer. (Routines that 
  191. ;            call readbuf() and wrtbuf() are modified).
  192. ;
  193. ; Aug-02-1991    ml.    Change again!  Conner now says there is no
  194. ;            final interrupt after data transfer, but need
  195. ;            a delay between the identify() and initparm().
  196. ;
  197. ; Aug-15-1991    ml.    Added a check to see if IDE drive is ready before
  198. ;            sending it the identify() command, by testing the
  199. ;            DRDY (driver ready) bit in the Alternate Status
  200. ;            Register.
  201. ;
  202. ; Aug-20-1991    ml.    Added iderdy() to check if an IDE drive is ready
  203. ;            or not, this includes the check for the existence 
  204. ;            of the slave drive (IDE unit 1.)
  205. ;
  206. ; Sep-12-1991    ml.    Added in yet another delay for IDE drive.  Conner
  207. ;            requires a 500us delay before calling identify()
  208. ;            after power on.
  209. ;
  210. ; Sep-24-1991    ml.    In order to accomodate the Conner CP-2024 (2.5"
  211. ;            IDE drive,) the readbuf() and wrtbuf() routines
  212. ;            need to do move.w instead of move.l to transfer
  213. ;            data.  A tower of 8 move.w is used to speed up
  214. ;            the transfer.
  215. ;
  216. ; Sep-25-1991    ml.    Extended time-out (>= 1.5s) for data hand-shake 
  217. ;            to account for slow SCSI devices (e.g. CDAR-505 
  218. ;            CD-ROM.)  The extended time-out is only needed 
  219. ;            between the end of command phase to the beginning 
  220. ;            of data    phase.  The code has the extended time-out 
  221. ;            for every byte of data to be hand-shaken, but this
  222. ;            should not affect performance because it should
  223. ;            not time-out between data bytes.
  224. ;
  225. ;            Modified _resetscsi() to clear the SCSI reset 
  226. ;            interrupt request (should anyone ever want to
  227. ;            use interrupts for watching the 5380) by reading 
  228. ;            from the 5380's reset error/interrupt register.
  229. ;
  230. ; Sep-26-1991    ml.    If a time-out occurs BEYOND the selection phase,
  231. ;            a SCSI RESET is done to clear the SCSI bus from
  232. ;            any odd state.
  233. ;
  234. ;            Deleted code which initializes IDE drive parameters.
  235. ;            Just use parameters returned by _identify().  So,
  236. ;            delay added between _identify() and _initparm() was
  237. ;            also deleted.
  238. ;
  239. ;            To take care of the bigger sector size (2K) of the
  240. ;            CD-ROM, the ACSI DMA counter is always set at the 
  241. ;            maximum of 255 512-byte blocks.  This basically 
  242. ;            disables the DMA counter and let the counter on 
  243. ;            the device determines when the transfer is finished.
  244. ;            This implies the maximum number of sectors that can
  245. ;            be transferred to or from the CD-ROM is 63.  This
  246. ;            limit should be enforced by the caller of _dmaread()
  247. ;            and _dmawrite().
  248. ;
  249. ; Sep-27-1991    ml.    Instead of just checking the ready bit in the IDEASR
  250. ;            in _iderdy(), check the entire byte for the value
  251. ;            0x50 (the ready status.)
  252. ;
  253. ; Sep-30-1991    ml.    Added delay in _fdone() and _qdone() to take care of
  254. ;            slow ACSI devices, for example the laser printer, to
  255. ;            guard against applications which call dmaread() or
  256. ;            dmawrite() on such devices.
  257. ;
  258. ;            Delay that was taken out with the _initparm() is
  259. ;            put back.  Conner drives probably needs that delay
  260. ;            between _identify() and any command!
  261. ;
  262. ; Oct-11-1991    ml.    Special-cased Conner CP2024 when getting current 
  263. ;            drive parameters.  Conner CP2024's current drive
  264. ;            parameters are not stored in the _identify() data.
  265. ;            
  266. ; Nov-06-1991    ml.    Big OOPS!!!  When delay was added in to take care of
  267. ;            slow ACSI devices, the label "sdelay" for the branch
  268. ;            accidentally includes the "add" instruction.  So, it
  269. ;            takes a long time before we exit the loop.
  270. ;-
  271.  
  272. .globl    _dmaread
  273. .globl    _dmawrite
  274.  
  275.  
  276. ; System variables
  277. flock        equ        $43e    ; FIFO lock variable
  278. _hz_200        equ        $4ba    ; system 200hz timer
  279.  
  280. ; For ACSI and SCSI drives
  281. READ        equ        $08        ; opcode for Read sectors
  282. WRITE        equ        $0a        ; opcode for Write sectors
  283. NCMD        equ        6        ; normal command length (6 bytes)
  284. MAXACSI        equ        7        ; highest ACSI unit#
  285. MAXSCSI        equ        15        ; highest SCSI unit#
  286.  
  287. ; For IDE-AT drives
  288. IDEREAD        equ        $20        ; opcode for Read sectors
  289. IDEWRITE    equ        $30        ; opcode for Write sectors
  290. IDENTIFY    equ        $ec        ; opcode for Identify Drive
  291. D_IDENTIFY  equ        2        ; delay between power on and identify() (500us)
  292. D_WORST        equ        2000    ; worst case delay (10s)
  293. IDERDY        equ        1000    ; delay to wait for IDE drive to be ready
  294. MAXIDE        equ        16        ; highest IDE-AT unit# (unit 0 ONLY)
  295.  
  296. ; Error codes to return to BIOS
  297. EUNDEV        equ        (-15)   ; UNknown DEVice
  298. EREADF        equ        (-11)   ; READ Fault
  299. EWRITF        equ        (-10)   ; WRITe Fault
  300.  
  301. ; Offsets for registers addressing on data bus
  302. REGBASE        equ        1        ; most are on odd part of data bus
  303. REGSTEP        equ        2        ; for regs that are on word boundaries
  304. REGLSTEP    equ        4        ; for regs that are on long word boundaries
  305.  
  306.  
  307. ;+
  308. ; Declarations
  309. ;-
  310. .bss
  311. lastacstm:    ds.l    1    ; controller last accessed time
  312. _cmdblk:    ds.b    10    ; command block
  313. rwflag:        ds.b    1    ; 0: read   1: write
  314. .even
  315.  
  316. .if IDE_AT
  317. sbuf:        ds.l    129    ; scratch buffer (must be on long word
  318.                 ;    boundary)
  319. .even
  320.  
  321. .endif
  322.  
  323. .text
  324.  
  325. ;+
  326. ; dmaread() - read from a DMA device.
  327. ; dmawrite() - write to a DMA device.
  328. ;
  329. ; LONG    sectnum        $4(sp).l
  330. ; WORD    count        $8(sp).w
  331. ; BYTE    *buf;        $a(sp).l    $b(sp)=high $c(sp)=mid $d(sp)=low
  332. ; WORD    pdev;        $e(sp).w
  333. ;
  334. ; Returns 0 if successful.
  335. ; Returns a negative number if failure: 
  336. ;    EUNDEV (-15L) if unknown device (bad dev number)
  337. ;    EREADF (-11L) if read failure
  338. ;    EWRITF (-10L) if write failure
  339. ;           (-1L)  if timed-out
  340. ;
  341. ; Comments:
  342. ;    ACSI, SCSI and IDE-AT drives are supported.
  343. ;-
  344.     .globl    _dmaread
  345. _dmaread:
  346.     move.b    #0,rwflag        ; rwflag = 0 => a read
  347.     move.w    #READ,d1        ; d1 = opcode for READ
  348.     bra.b    dmarw
  349.     
  350.     .globl    _dmawrite
  351. _dmawrite:
  352.     move.b    #1,rwflag        ; rwflag = 1 => a write
  353.     move.w    #WRITE,d1        ; d1 = opcode for WRITE
  354.     
  355. dmarw:
  356. .if IDE_AT
  357.     cmpi.w    #MAXIDE,$e(sp)        ; unit# > IDE-AT unit# 16?
  358. .else
  359. .if SCSI|SPSCSI
  360.     cmpi.w    #MAXSCSI,$e(sp)        ; unit# > SCSI unit# 8-15?
  361. .else
  362.     cmpi.w    #MAXACSI,$e(sp)        ; unit# > ACSI unit# 0-7?
  363. .endif
  364. .endif
  365.     bhi    undev            ; if so, return unknow device
  366.  
  367. .if IDE_AT
  368.     cmp.w    #MAXSCSI,$e(sp)        ; an IDE-AT unit?
  369.     bhi    ide0            ; if so, talk IDE-AT
  370. .endif
  371.                     ; else talk ACSI or SCSI
  372.     lea    _cmdblk,a0        ; a0 -> beginning of command block
  373.     move.b    d1,(a0)+        ; byte 0 = opcode
  374.     move.b    5(sp),(a0)+        ; byte 1 = msb of logical block addr
  375.     move.b    6(sp),(a0)+        ; byte 2 = logical block addr
  376.     move.b    7(sp),(a0)+        ; byte 3 = lsb of logical block addr
  377.     move.b    9(sp),(a0)+        ; byte 4 = transfer length (in blocks)
  378.     clr.b    (a0)            ; byte 5 = control byte
  379.     move.w    $e(sp),d0        ; d0 = physical unit number
  380.     moveq    #NCMD,d2        ; d2 = length of command
  381.     movea.l    $a(sp),a0        ; a0 = buffer
  382.     tst.b    rwflag            ; read or write?
  383.     bne.b    rw0            ; it's a write
  384.     bsr    _dorcmd            ; send a receive data command
  385.     bra    rw1
  386. rw0:    bsr    _dowcmd            ; send a write data command
  387.  
  388. .if IDE_AT
  389.     bra    rw1            ; branch will take place for 
  390.                     ;    non-IDE drives
  391. *
  392. * Before doing anything with the IDE bus, make sure it's there.
  393. * (The label noide is before at just because it fits better.)
  394. *
  395.  
  396. noide:    move.l    a1,sp            ; got the bus error on IDEASR;
  397.     move.l    a0,$8            ; restore vector & sp, return EUNDEV
  398.     bra    undev
  399.  
  400. ide0:    move.l    $8,a0
  401.     move.l    sp,a1
  402.     move.l    #noide,$8
  403.     tst.b    IDEASR            ; read a register to probe for IDE bus
  404.     move.l    a1,sp            ; hey! no bus error!
  405.     move.l    a0,$8            ; restore vector & sp and continue.
  406.  
  407.     move.b    $f(sp),d0        ; IDE unit#
  408.     bsr    _iderdy            ; wait for drive to be ready
  409.     beq    undev            ; if drive never gets ready, return
  410.                     ;   with unknown device
  411.                     ; else
  412.     move.l    #D_IDENTIFY,d0        ; delay required by Conner drives
  413.     add.l    _hz_200,d0        ;  between power on and identify()
  414. ide1:    cmp.l    _hz_200,d0
  415.     bcc.b    ide1
  416.  
  417.     pea    sbuf            ; scratch buffer for drive parameters
  418.     move.w    $12(sp),-(sp)        ; IDE unit#
  419.     bsr    _identify        ; identify()
  420.     addq.w    #6,sp            ; clean up stack
  421.     tst.w    d0            ; successful?
  422.     bmi    rwend            ; if timed-out, return
  423.     bne    rw2            ; if error, return with error code
  424.                     ; else can do read or write
  425.     move.l    #D_IDENTIFY,d0        ; delay required by Conner drives
  426.     add.l    _hz_200,d0        ;  between identify() and r/w
  427. ide4:    cmp.l    _hz_200,d0
  428.     bcc.b    ide4
  429.  
  430.     pea    sbuf            ; beginning of _identify() data
  431.     bsr    _gcparm            ; get drive current parameters
  432.     addq    #4,sp            ; clean up stack
  433.  
  434.     move.w    $e(sp),-(sp)        ; physical unit #
  435.     move.l    $c(sp),-(sp)        ; buffer
  436.     move.w    $e(sp),-(sp)        ; count
  437.     move.l    $c(sp),-(sp)        ; logical block address
  438.     move.w    d2,-(sp)        ; # sectors per track
  439.     move.w    d1,-(sp)        ; # data heads
  440.     tst.b    rwflag            ; read or write?
  441.     bne.b    ide2            ; (write)
  442.     bsr    _ideread        ; read sectors
  443.     bra.b    ide3
  444. ide2:    bsr    _idewrite        ; write sectors
  445. ide3:    adda    #16,sp            ; clean up stack
  446. .endif    
  447. rw1:    
  448. .if    SCSI
  449.     move.w    sr,-(sp)        ; go to IPL 7
  450.     ori    #$700,sr        ; no interrupts right now please
  451.     movec    cacr,d1            ; d1 = (cache control register)
  452.     ori.w    #$0808,d1        ; dump both the I and D cache
  453.     movec    d1,cacr            ; update cache control register
  454.     move.w    (sp)+,sr        ; restore interrupt state
  455. .endif
  456.     tst.w    d0            ; successful?
  457.     ble.b    rwend            ; if no error or timed-out, return
  458.                     ; else
  459. rw2:    moveq    #EREADF,d0        ; assume it's a read error
  460.     tst.b    rwflag            ; read or write?
  461.     beq.b    rwend            ; if read, done
  462.     moveq    #EWRITF,d0        ; else, it's a write error
  463. rwend:    rts
  464.  
  465. undev:    moveq    #EUNDEV,d0
  466.     bra.b    rwend
  467.  
  468. ;+++++++++++++++++++++++++++++++;
  469. ;                ;
  470. ;    ACSI and SCSI specific    ;
  471. ;                ;
  472. ;+++++++++++++++++++++++++++++++;
  473.  
  474. ;+
  475. ; dorcmd() - send a command which will receive data from the target
  476. ;
  477. ; Passed:
  478. ;    d0.w = physical unit number
  479. ;    d2.w = command length (NCMD or LCMD)
  480. ;    a0.l = buffer address
  481. ;-
  482. _dorcmd:
  483. .if SCSI
  484.     cmp.w    #MAXACSI,d0        ; unit# > ACSI unit# 0 - 7?
  485.     bls.b    rcacsi            ; if not, it's an ACSI device
  486.     bsr    _rcvscsi        ; else, it's a SCSI device
  487.     rts
  488. .else
  489. .if SPSCSI
  490.     bsr    _rcvspscsi
  491.     rts
  492. .endif
  493. .endif
  494.  
  495. rcacsi:    bsr    _rcvacsi        ; it's an ACSI device
  496.     rts
  497.  
  498.  
  499. ;+
  500. ; dowcmd() - send a command which will write data to the target
  501. ;
  502. ; Passed:
  503. ;    d0.w = physical unit number
  504. ;    d2.w = command length (NCMD or LCMD)
  505. ;    a0.l = buffer address
  506. ;-
  507. _dowcmd:
  508. .if    SCSI
  509.     cmp.w    #MAXACSI,d0        ; unit# > ACSI unit# 0 - 7?
  510.     bls.b    wracsi            ; if not, it's an ACSI device
  511.     bsr    _wrtscsi        ; else, it's a SCSI device
  512.     rts
  513. .else
  514. .if SPSCSI
  515.     bsr    _wrtspscsi
  516.     rts
  517. .endif
  518. .endif
  519. wracsi:    bsr    _wrtacsi        ; it's an ACSI device
  520.     rts
  521.  
  522.     
  523.  
  524. ;+++++++++++++++++++++++++++++++;
  525. ;                ;
  526. ;    ACSI specific        ;
  527. ;                ;
  528. ;+++++++++++++++++++++++++++++++;
  529.  
  530. ;+
  531. ;  Hardware definitions for ACSI
  532. ;-
  533. WDC        equ    $ffff8604
  534. WDL        equ    $ffff8606
  535. WDCWDL        equ    WDC        ; used for long writes
  536. XWDL        equ    WDL-WDC        ; offset from wdc to wdl
  537.  
  538. DMAHI        equ    $ffff8609
  539. DMAMID        equ    DMAHI+2
  540. DMALOW        equ    DMAMID+2
  541. GPIP        equ    $fffffa01
  542.  
  543.  
  544. ;+
  545. ;  Tunable (delay) values for ACSI
  546. ;-
  547. ACLTMOUT    equ    600        ; long time-out (3 s)
  548. ACSTMOUT    equ    20        ; short time-out (100 ms)
  549.  
  550.  
  551. ;+
  552. ; LONG _qdone() - Wait for command byte handshake
  553. ; LONG _fdone() - Wait for operation complete
  554. ; Passed:    nothing
  555. ;
  556. ; Returns:    EQ: no time-out
  557. ;        MI: time-out condition
  558. ;
  559. ; Uses:        D0
  560. ;
  561. ;-
  562. _fdone:    move.l    #ACLTMOUT,d0
  563.     bra.b    qd0
  564.  
  565. _qdone:    move.l    #ACSTMOUT,d0
  566.  
  567. qd0:    move.l    d0,-(sp)        ; save timeout value
  568.     moveq    #2,d0            ; busy-wait delay for slow ACSI
  569.     add.l    _hz_200,d0        ; minimum 20 microsec.
  570. sdelay:    cmp.l    _hz_200,d0
  571.     bge.b    sdelay
  572.     move.l    (sp)+,d0        ; restore timeout value
  573.  
  574.     add.l    _hz_200,d0
  575. qd1:    cmp.l    _hz_200,d0        ; time-out?
  576.     bcs.b    qdq            ; (i give up, return NE)
  577.     btst    #5,GPIP            ; interrupt?
  578.     bne.b    qd1            ; (not yet)
  579.  
  580.     moveq    #0,d0            ; return EQ (no time-out)
  581.     rts
  582.  
  583. qdq:    moveq    #-1,d0
  584.     rts
  585.  
  586.  
  587. ;+
  588. ; Wait for end of SASI command
  589. ;
  590. ; Passed:    d1 value to be written to wdl
  591. ;
  592. ; Returns:    EQ: success (error code in D0.W)
  593. ;        MI: time-out (-1 in D0.W)
  594. ;        NE: failure (SASI error code in D0.W)
  595. ;
  596. ; Uses:        d0
  597. ;-
  598. _endcmd:
  599.     bsr    _fdone            ; wait for operation complete
  600.     bmi.b    endce            ; (timed-out, so complain)
  601.  
  602. .if    SCSI                ; dump D cache
  603.     move.w    sr,-(sp)        ; go to IPL 7
  604.     ori.w    #$700,sr        ; no interrupts right now kudasai
  605.     movec    cacr,d0            ; d0 = (cache control register)
  606.     ori.w    #$800,d0        ; dump the D cache
  607.     movec    d0,cacr            ; update cache control register
  608.     move.w    (sp)+,sr        ; restore interrupt state
  609. .endif
  610.  
  611.     move.w    d1,WDL
  612.     move.w    WDC,d0            ; get the result
  613.     and.w    #$00ff,d0        ; (clean it up) if non-0 should do a
  614.                     ; RequestSense command to learn more
  615. endce:    move.l    _hz_200,lastacstm    ; update controller last accessed time
  616.     addq.l    #2,lastacstm        ; lastacstm = _hz_200 + 2;
  617.     rts                
  618.  
  619.  
  620. ;+
  621. ;  Handle command time-out;
  622. ;  Unlock DMA chip and return completion status;
  623. ;-
  624. _hdone:    move.w    #$80,WDL    ; Landon's code seems to presume we put 
  625.                 ;  $80 there
  626.     sf    flock        ; NOW, signal that we are done
  627.     rts
  628.  
  629.  
  630. ;+
  631. ; delay()
  632. ;    5 - 10ms kludge delay for message byte sent back by controller.
  633. ;-
  634. _delay:    move.l    d0,-(sp)        ; preserve d0
  635.     move.l    lastacstm,d0        ; d0 = controller last accessed time
  636. wait:    cmp.l    _hz_200,d0        ; while (_hz_200 <= lastacstm)
  637.     bcc.b    wait            ;    wait()
  638.     move.l    (sp)+,d0        ; restore d0
  639.     rts
  640.  
  641.  
  642. ;+
  643. ; rcvacsi() - send a ACSI command which receives data from target.
  644. ;
  645. ; Passed:
  646. ;    d0.w = physical unit number
  647. ;    d2.w = command length (NCMD or LCMD)
  648. ;    a0.l = buffer address
  649. ;-
  650. _rcvacsi:
  651.  
  652. * check to see if the ACSI bus actually exists! Needed for prototype PADs
  653.     move.l    $8,a1
  654.     move.l    sp,a2
  655.     move.l    #noacsi,$8
  656.     tst.w    WDL            ; harmless or bus erorr
  657.     move.l    a1,$8            ; no bus error - restore & continue
  658.     move.l    a2,sp
  659.  
  660.     st    flock            ; lock FIFO
  661.     bsr    _delay            ; delay if necessary
  662.     movea.l    #WDC,a1            ; a1 = pointer to DMA chip
  663.  
  664.     bsr    setadma            ; set DMA pointer
  665.     move.w    #$190,XWDL(a1)    ;WDL    ; toggle DMA chip to direction
  666.     bsr    rstdelay        ; delay
  667.     move.w    #$090,XWDL(a1)    ;WDL    ;  for receiving data
  668.     bsr    rstdelay        ; delay
  669.     bsr    setacnt            ; set DMA count
  670.  
  671.     lea    _cmdblk,a0        ; a0 = address of command block
  672.     moveq    #0,d1            ; direction of DMA is IN
  673.     bsr    sblkacsi        ; send the command block
  674. raend:    bra    _hdone            ; cleanup after IRQ
  675.  
  676.  
  677. ;+
  678. ; wrtacsi() - send an ACSI command which will write data to the target
  679. ;
  680. ; Passed:
  681. ;    d0.w = physical unit number
  682. ;    d2.w = command length (NCMD or LCMD)
  683. ;    a0.l = buffer address
  684. ;-
  685. _wrtacsi:
  686.  
  687. * check to see if the ACSI bus actually exists! Needed for prototype PADs
  688.     move.l    $8,a1
  689.     move.l    sp,a2
  690.     move.l    #noacsi,$8
  691.     tst.w    WDC            ; harmless or bus erorr
  692.     move.l    a1,$8            ; no bus error - restore & continue
  693.     move.l    a2,sp
  694.  
  695.     st    flock            ; lock FIFO
  696.     bsr    _delay
  697.     movea.l    #WDC,a1            ; a1 = pointer to DMA chip
  698.  
  699.     bsr    setadma            ; set DMA pointer
  700.     move.w    #$90,XWDL(a1)    ;WDL    ; toggle DMA chip for "send"
  701.     bsr    rstdelay        ; delay 
  702.     move.w    #$190,XWDL(a1)    ;WDL
  703.     bsr    rstdelay        ; delay
  704.     bsr    setacnt            ; set DMA count
  705.     
  706.     move.l    #$0100,d1        ; d1 = direction of DMA is OUT
  707.     bsr    sblkacsi        ; send the command block
  708.  
  709. waend:    bra    _hdone            ; cleanup after IRQ
  710.  
  711. * You get to this label if there is a bus error when probing for
  712. * the ACSI bus: it's meant for prototype PADs, which don't
  713. * have an ACSI DMA chip.
  714.  
  715. noacsi:    moveq.l    #-15,d0            ; return EUNDEV
  716.     move.l    a2,sp
  717.     move.l    a1,$8
  718.     rts
  719.  
  720. ;+
  721. ; sblkacsi() - send command block
  722. ;
  723. ; Passed:
  724. ;    d0.w = physical unit number
  725. ;    d1.l = direction of DMA ($0000 for IN or $0100 for OUT)
  726. ;    d2.w = command length (NCMD or LCMD)
  727. ;    a1.l = pointer to DMA chip
  728. ;
  729. ; Returns:
  730. ;    d0.l =  0 if successful
  731. ;    d0.l = -1 if time-out
  732. ;
  733. ; Trashes:
  734. ;    d0, d1, d2, a2
  735. ;-
  736. sblkacsi:
  737.     move.b    #$88,d1            ; next byte is the opcode
  738.     move.w    d1,XWDL(a1)    ;WDL
  739.  
  740.     move.b    #$8a,d1            ; following bytes are operands
  741.     lea    _cmdblk,a2        ; a2 = address of command block
  742.                     ; integrate unit # into cmd blk
  743.     lsl.b    #5,d0            ; shift unit number into place
  744.     or.b    d0,(a2)            ; first command byte = unit # | opcode
  745.                     ; control byte is sent seperately
  746.     subq.w    #2,d2            ; and dbra likes one less 
  747. sa1:    swap    d1            ; d1.hw = operand
  748.     move.b    (a2)+,d1        ; d1.lw = tells controller next byte
  749.     swap    d1            ;      is an operand
  750.     move.l    d1,(a1)        ;WDCWDL
  751.     bsr    _qdone
  752.     bmi.b    sbaend            ; if time-out, returns
  753.     dbra    d2,sa1            ; else send rest of command block
  754.  
  755.     move.w    d1,XWDL(a1)    ;WDL    ; get ready to send control byte
  756.     move.b    #0,d1            ; signal sending control byte
  757.     swap    d1            ; d1.hw = control byte
  758.     move.b    (a2),d1            ; d1.lw = tells controller it's end
  759.     swap    d1            ;      of command
  760.     move.l    d1,(a1)            ; send it
  761.  
  762.     move.b    #$8a,d1            ; d1 = wdl value
  763.     bsr    _endcmd            ; wait for command completion
  764. sbaend: rts                ; heading home
  765.  
  766.  
  767. ;+
  768. ; setadma() - set the ACSI DMA pointer
  769. ;
  770. ; Passed:
  771. ;    a0.l = buffer address
  772. ;-
  773. setadma:
  774.     move.l    a0,-(sp)        ; move it on stack
  775.     move.b    3(sp),DMALOW        ; set low-byte of address
  776.     move.b    2(sp),DMAMID        ; set mid-byte of address
  777.     move.b    1(sp),DMAHI        ; set high-byte of address
  778.     addq.l    #4,sp            ; clean up stack
  779.     rts
  780.  
  781.  
  782. ;+
  783. ; setacnt() - set the ACSI DMA counter
  784. ;
  785. ; Comments:
  786. ;    26-Sep-1991 ml    DMA counter is always set at the maximum 
  787. ; (255 sectors) to force the use of the device counter.
  788. ;
  789. ; Passed:
  790. ;    a1.l = pointer to DMA chip
  791. ;-
  792. setacnt:
  793.     move.w    #$ff,(a1)        ;WDC    ; set DMA count
  794.     rts
  795.  
  796.  
  797. ;+
  798. ; Rstdelay()
  799. ;    After talking to the DMA chip in a way that may reset it, 
  800. ; we need a 8 8Mhz clocks (ie. 1 microsec) delay, before we can
  801. ; talk to the chip again.
  802. ;-
  803. rstdelay:
  804.     tst.b    GPIP            ; delay for 1 microsec
  805.     tst.b    GPIP            ; this amounts to 16 16Mhz clocks
  806.     tst.b    GPIP
  807.     tst.b    GPIP
  808.     rts
  809.  
  810.  
  811. .if    SCSI
  812.  
  813. ;+++++++++++++++++++++++++++++++;
  814. ;                ;
  815. ;    SCSI specific        ;
  816. ;                ;
  817. ;+++++++++++++++++++++++++++++++;
  818.  
  819. .globl    _resetscsi
  820.  
  821. ; SCSI Interface (NCR 5380) for READ operations
  822. bSCSI    equ    $FFFF8780+REGBASE
  823. SCSIDB    equ    bSCSI+($00*REGSTEP)    ; current SCSI data bus
  824. SCSIICR    equ    bSCSI+($01*REGSTEP)    ; initiator command register
  825. SCSIMR    equ    bSCSI+($02*REGSTEP)    ; mode register
  826. SCSITCR    equ    bSCSI+($03*REGSTEP)    ; target command register
  827. SCSICR    equ    bSCSI+($04*REGSTEP)    ; current SCSI control register
  828. SCSIDSR    equ    bSCSI+($05*REGSTEP)    ; DMA status register
  829. SCSIIDR    equ    bSCSI+($06*REGSTEP)    ; input data register
  830. SCSIREI    equ    bSCSI+($07*REGSTEP)    ; reset error / interrupt
  831.  
  832. ; SCSI Interface (NCR 5380) for WRITE operations
  833. SCSIODR    equ    bSCSI+($00*REGSTEP)    ; output data register
  834. ;SCSIICR    bSCSI+($01*REGSTEP)    ; initiator command register
  835. ;SCSIMR        bSCSI+($02*REGSTEP)    ; mode register
  836. ;SCSITCR    bSCSI+($03*REGSTEP)    ; target command register
  837. SCSIISR    equ    bSCSI+($04*REGSTEP)    ; ID select register
  838. SCSIDS    equ    bSCSI+($05*REGSTEP)    ; start DMA send
  839. SCSIDTR    equ    bSCSI+($06*REGSTEP)    ; start DMS target receive
  840. SCSIDIR    equ    bSCSI+($07*REGSTEP)    ; start DMA initiator receive
  841.  
  842. ; SCSI DMA Controller
  843. SDMACTL        equ    $FFFF8714    ; WORD
  844.  
  845. ;+
  846. ; Tunable (delay) values (in number of _hz_200 ticks) for SCSI
  847. ;-
  848. SCLTMOUT    equ    301        ; long time-out (at least 1.5 s)
  849. SCSTMOUT    equ    51        ; short time-out (at least 250 ms)
  850.  
  851. ;+
  852. ; rcvscsi() - send a SCSI command which receives data back.
  853. ;
  854. ; Passed:
  855. ;    d0.w = physical unit number
  856. ;    d2.w = command length (NCMD or LCMD)
  857. ;    a0.l = buffer address
  858. ;-
  859. _rcvscsi:
  860.     move.l    a0,-(sp)        ; save buffer address
  861.     andi.w    #7,d0            ; mask off the flags to get unit num
  862.     bsr    sblkscsi        ; send command block
  863.     movea.l    (sp)+,a0        ; restore buffer address
  864.     tst.w    d0            ; successful?
  865.     bmi.b    rsend            ; if not successful, return
  866.  
  867.     movea.l    a0,a1            ; a1 -> buffer to read into
  868.     movea.l    #bSCSI,a2        ; a2 -> 5380
  869.     move.b    #1,SCSITCR        ; set data in phase
  870.     move.b    SCSIREI,d0        ; clear potential interrupt
  871.  
  872.     ;+
  873.     ; 25-Sep-91 ml.    The long time-out is used instead of the short
  874.     ;        time-out to accomodate slow SCSI devices.
  875.     ;-
  876. rs0:    bsr    setscltmout        ; set up time-out
  877.     bsr    w4req            ; wait for REQ to come
  878.     bmi.b    rsend            ; if timed out, returns
  879.     btst    #3,5*REGSTEP(a2)    ; still in data in phase?
  880.     beq    w4stat            ; no, go get status
  881.     move.b    (a2),(a1)+        ; read the data byte
  882.     bsr    doack
  883.     bra.b    rs0            ; do next byte
  884. rsend:    bsr    _resetscsi        ; timed-out, reset SCSI bus
  885.     rts
  886.  
  887.  
  888. ;+
  889. ; wrtscsi() - send a SCSI command which will write data to the target
  890. ;
  891. ; Passed:
  892. ;    d0.w = physical unit number
  893. ;    d2.w = command length (NCMD or LCMD)
  894. ;    a0.l = buffer address
  895. ;-
  896. _wrtscsi:
  897.     andi.w    #7,d0            ; mask off the flags to get unit num
  898.     move.l    a0,-(sp)        ; save beginning buffer address
  899.     move.w    d2,-(sp)        ; save command length
  900.     bsr    sblkscsi        ; send command block
  901.     move.w    (sp)+,d2        ; restore command length
  902.     move.l    (sp)+,a0        ; a0 = where DMA ends
  903.     tst.w    d0            ; successful?
  904.     bmi.b    wsend            ; if failure, return
  905.  
  906.     movea.l    a0,a1            ; a1 -> buffer to write from
  907.     movea.l    #bSCSI,a2        ; a2 -> 5380
  908.     move.b    #0,SCSITCR        ; set data out phase
  909.     move.b    SCSIREI,d0        ; clear potential interrupt
  910.  
  911.     ;+
  912.     ; 25-Sep-91 ml.    The long time-out is used instead of the short
  913.     ;        time-out to accomodate slow SCSI devices.
  914.     ;-
  915. ws0:    bsr    setscltmout
  916.     bsr    w4req            ; wait for REQ to come
  917.     bmi.b    wsend            ; if timed out, returns
  918.     btst    #3,5*REGSTEP(a2)    ; still in data out phase?
  919.     beq    w4stat            ; no, go get status
  920.     move.b    (a1)+,(a2)        ; write the data byte
  921.     bsr    doack
  922.     bra.b    ws0            ; do next byte
  923. wsend:    bsr    _resetscsi        ; timed-out, reset SCSI bus
  924.     rts
  925.  
  926.  
  927.  
  928. ;+
  929. ; sblkscsi() - send command block
  930. ;
  931. ; Passed:
  932. ;    d0.w = physical unit number
  933. ;    d2.w = command length (NCMD or LCMD)
  934. ;
  935. ; Returns:
  936. ;    d0.l =  0 if successful
  937. ;    d0.l = -1 if time-out
  938. ;-
  939. sblkscsi:
  940.     move.l    d2,-(sp)        ; save command length
  941.     move.w    d0,-(sp)        ; physical unit #
  942.     bsr    selscsi            ; select the unit
  943.     addq    #2,sp            ; clean up stack
  944.     move.l    (sp)+,d2        ; restore command length
  945.     tst.w    d0            ; selection successful?
  946.     bmi.b    sbsend            ; if timed out, return
  947.                     ; else proceed
  948.     move.b    #2,SCSITCR        ; assert C/D
  949.     move.b    #1,SCSIICR        ; assert data bus
  950.  
  951.     lea    _cmdblk,a1        ; a1 -> command block
  952.     subq.w    #1,d2            ; dbra likes one less
  953.  
  954.     bsr    setscstmout        ; set a short time-out
  955. ss1:    move.b    (a1)+,d0        ; d0.b = byte to be sent
  956.     bsr    hshake            ; write that byte
  957.     tst.w    d0
  958.     bmi.b    sbsend            ; if timed-out, returns
  959.     dbra    d2,ss1            ; until whole command block is sent
  960.     moveq    #0,d0            ; all operations successful
  961. sbsend: rts                ; heading home
  962.  
  963.  
  964. ;+
  965. ; BOOLEAN selscsi(SCSIUnit) 
  966. ; WORD SCSIUnit;
  967. ;-
  968. selscsi:
  969.     bsr    setscstmout        ; set up a short time-out
  970. sels0:    btst    #6,SCSICR        ; STILL busy from last time?
  971.     beq.b    sels1            ; if not, it's available
  972.     cmp.l    (a0),d1            ; time-out?
  973.     bhi.b    sels0            ; not yet, wait some more
  974.     bra.b    sels4            ; else, return error
  975.  
  976. sels1:    move.b    #0,SCSITCR        ; data out phase
  977.     move.b    #0,SCSIISR        ; no interrupt from selection
  978.     move.b    #$0c,SCSIICR        ; assert BSY and SEL
  979. ; set dest SCSI IDs
  980.     clr.w    d0
  981.     move.w    4(sp),d1        ; get the SCSI unit desired
  982.     bset    d1,d0            ; set the appropriate bit
  983.     move.b    d0,SCSIODR        ; (real code would set ours too)
  984.  
  985.     move.b    #$0d,SCSIICR        ; assert BUSY, SEL and data bus
  986.     andi.b    #$FE,SCSIMR        ; clear arbitrate bit
  987.     andi.b    #$F7,SCSIICR        ; clear BUSY
  988.  
  989. * there must be two "deskew delays" here, but that's only 100ns total...
  990. * the following computations take at least that long before we read
  991. * SCSICR again.
  992.  
  993.     bsr    setscstmout        ; use short time-out
  994. sels3:    btst    #6,SCSICR        ; wait for bus to be busy
  995.     bne.b    sels5
  996.     cmp.l    (a0),d1
  997.     bhi.b    sels3
  998.  
  999. sels4:    moveq    #-1,d0            ; time out
  1000.     bra.b    sels6
  1001.     
  1002. sels5:    clr.w    d0            ; selection successful
  1003. sels6:    move.b    #$0,SCSIICR        ; clear SEL and data bus assertion
  1004.     rts
  1005.  
  1006.  
  1007. ;+
  1008. ; w4stat - wait for status byte and message byte.
  1009. ;
  1010. ; Returns:
  1011. ;    d0.l = returned status or time-out error
  1012. ;-
  1013. w4stat:    bsr    setscstmout        ; set up time-out for REQ and ACK
  1014.     move.b    #3,SCSITCR        ; status in phase
  1015.     move.b    SCSIREI,d0        ; clear potential interrupt
  1016.  
  1017.     bsr    w4req            ; wait for status byte
  1018.     bmi.b    wstto            ; if timed-out, handle it
  1019.     moveq    #0,d0            ; clear d0
  1020.     move.b    SCSIDB,d0        ; get the status byte
  1021.     bsr    setscstmout        ; set up time-out for REQ and ACK
  1022.     move.l    d0,-(sp)        ; save the status byte
  1023.     bsr    doack            ; signal that status byte is here
  1024.     tst.w    d0            ; timed-out?
  1025.     beq.b    wst4            ; if not, wait for message byte
  1026.  
  1027. wst3:    addq.l    #4,sp            ; else clean up stack
  1028. wstto:    bsr    _resetscsi        ; timed-out, reset SCSI bus
  1029.     bra.b    wstend            ; and return
  1030.  
  1031. wst4:    bsr    setscstmout        ; set up time-out for REQ and ACK
  1032.     bsr    w4req            ; wait for message byte
  1033.     bmi.b    wst3            ; if timed-out, returns
  1034.  
  1035.     move.b    SCSIDB,d0        ; get and ignore message byte
  1036.     bsr    doack            ; signal that message byte is here
  1037.     tst.w    d0            ; timed-out?
  1038.     bmi.b    wst3            ; if so, return time-out
  1039.     move.l    (sp)+,d0        ; recall the status byte
  1040. wstend:    rts
  1041.  
  1042.  
  1043. ;+
  1044. ; w4req() - wait for REQ to come
  1045. ;
  1046. ; Passed:
  1047. ;    d1.l = expiration time
  1048. ;    a0.l = address of _hz_200
  1049. ;
  1050. ; Returns:
  1051. ;     0 - if successful
  1052. ;    -1 - times out
  1053. ;-
  1054. w4req:
  1055. wr0:    btst    #5,SCSICR        ; waiting for REQ to come
  1056.     bne.b    wr1            ; if REQ comes, done
  1057.     cmp.l    (a0),d1            ; time's up?
  1058.     bhi.b    wr0            ; if not, wait some more
  1059.     moveq    #-1,d0            ; else, returns timed out
  1060.     bra.b    wrend
  1061. wr1:    moveq    #0,d0            ; returns successful
  1062. wrend:    rts
  1063.  
  1064.  
  1065. ;+
  1066. ; doack() - assert ACK
  1067. ;
  1068. ; Passed:
  1069. ;    d1.l = expiration time
  1070. ;    a0.l = address of _hz_200
  1071. ;
  1072. ; Returns:
  1073. ;     0 - if successful
  1074. ;    -1 - times out
  1075. ;-
  1076. doack:    ori.b    #$11,SCSIICR        ; assert ACK (and data bus)
  1077. da0:    btst    #5,SCSICR        ; wait for REQ to go away
  1078.     beq.b    da1            ; if REQ goes away, done
  1079.     cmp.l    (a0),d1            ; time's up?
  1080.     bhi.b    da0            ; if not, wait some more
  1081.     moveq    #-1,d0            ; else returns timed out
  1082.     bra.b    daend
  1083. da1:    moveq    #0,d0            ; returns successful
  1084. daend:    andi.b    #$ef,SCSIICR        ; clear ACK
  1085.     rts
  1086.  
  1087.  
  1088. ;+
  1089. ; hshake() - hand shake a byte over to the controller
  1090. ;
  1091. ; Passed:
  1092. ;    d0.b = byte to be handed over
  1093. ;    d1.l = expiration time
  1094. ;    a0.l = address of _hz_200
  1095. ;
  1096. ; Returns:
  1097. ;    Whatever w4req() or doack() returns, which is:
  1098. ;         0 - if successful
  1099. ;        -1 - times out
  1100. ;-
  1101. hshake:    move.w    d0,-(sp)        ; preserve d0.w
  1102.     bsr    w4req            ; wait for REQ to come
  1103.     bmi.b    hsend            ; if timed out, returns
  1104.     move.b    1(sp),SCSIDB        ; write a byte out to data bus
  1105.     bsr    doack            ; assert ACK
  1106. hsend:    addq.l    #2,sp            ; clean up stack
  1107.     rts
  1108.  
  1109.  
  1110. *+
  1111. * VOID resetscsi();
  1112. *-
  1113.  
  1114. _resetscsi:
  1115.     move.b    #$80,SCSIICR    ; assert RST
  1116.     bsr    setscstmout    ; wait (at least) 250 ms
  1117. rst0:    cmp.l    (a0),d1
  1118.     bhi.b    rst0
  1119.     move.b    #$00,SCSIICR
  1120.     bsr    setscltmout    ; wait (at least) 1000 ms
  1121. rst1:    cmp.l    (a0),d1
  1122.     bhi.b    rst1
  1123.     move.b    SCSIREI,d1    ; clear potential interrupt
  1124.     rts
  1125.  
  1126.  
  1127. ;+
  1128. ; setscstmout - set up a time-out count for the SCSI for SCSTMOUT ticks
  1129. ;
  1130. ; Returns:
  1131. ;    a0.l = address of _hz_200 clock
  1132. ;    d1.l = expiration time
  1133. ;-
  1134. setscstmout:
  1135.     movea.l    #_hz_200,a0    ; a0 -> 200 hz clock
  1136.     move.l    #SCSTMOUT,d1    ; d0 = SCSTMOUT _hz_200 clicks
  1137.     add.l    (a0),d1        ; d0 = curr time + # clicks to wait
  1138.     rts
  1139.  
  1140.  
  1141. ;+
  1142. ; setscltmout - set up a time-out count for the SCSI for SCLTMOUT long
  1143. ;
  1144. ; Returns:
  1145. ;    a0.l = address of _hz_200 clock
  1146. ;    d1.l = expiration time
  1147. ;-
  1148. setscltmout:
  1149.     movea.l    #_hz_200,a0    ; a0 -> 200 hz clock
  1150.     move.l    #SCLTMOUT,d1    ; d0 = SCLTMOUT _hz_200 clicks
  1151.     add.l    (a0),d1        ; d0 = curr time + # clicks to wait
  1152.     rts
  1153.  
  1154. .endif
  1155.  
  1156.  
  1157.  
  1158. .if    SPSCSI
  1159.  
  1160. ;+++++++++++++++++++++++++++++++;
  1161. ;                ;
  1162. ;    SPARROW specific    ;
  1163. ;                ;
  1164. ;+++++++++++++++++++++++++++++++;
  1165.  
  1166. .globl    _resetspscsi
  1167.  
  1168. bSPSCSI        equ    $88    ; base of SCSI bus
  1169.  
  1170. ; SCSI Interface (NCR 5380) for READ operations
  1171. SPSCSIDB    equ    bSPSCSI+0    ; SCSI data bus
  1172. SPSCSIICR    equ    bSPSCSI+1    ; initiator command register
  1173. SPSCSIMR    equ    bSPSCSI+2    ; mode register
  1174. SPSCSITCR    equ    bSPSCSI+3    ; target command register
  1175. SPSCSICR    equ    bSPSCSI+4    ; current SCSI control register
  1176. SPSCSIDSR    equ    bSPSCSI+5    ; DMA status register
  1177. SPSCSIIDR    equ    bSPSCSI+6    ; input data register
  1178. SPSCSIREI    equ    bSPSCSI+7    ; reset error / interrupt
  1179.  
  1180.  
  1181. ; SCSI Interface (NCR 5380) for WRITE operations
  1182. SPSCSIODR    equ    bSPSCSI+0    ; output data register
  1183. ;SPSCSIICR    equ    bSPSCSI+1    ; initiator command register
  1184. ;SPSCSIMR    equ    bSPSCSI+2    ; mode register
  1185. ;SPSCSITCR    equ    bSPSCSI+3    ; target command register
  1186. SPSCSIISR    equ    bSPSCSI+4    ; ID select register
  1187. SPSCSIDS    equ    bSPSCSI+5    ; start DMA send
  1188. SPSCSIDTR    equ    bSPSCSI+6    ; start DMA target receive
  1189. SPSCSIDIR    equ    bSPSCSI+7    ; start DMA initiator receive
  1190.  
  1191.  
  1192. ; Macros to talk to the NCR5380 through the ACSI DMA chip
  1193.  
  1194. .macro    RSCSI    srcreg,dst    ; read from specified register
  1195.     move.w    srcreg,WDL
  1196.     move.w    WDC,dst
  1197. .endm
  1198.  
  1199. .macro    WSCSI    val,dstreg    ; write to specified register
  1200.     move.w    dstreg,WDL
  1201.     move.w    val,WDC
  1202. .endm
  1203.  
  1204. ;+
  1205. ; Tunable (delay) values (in number of _hz_200 ticks) for SCSI
  1206. ;-
  1207. SCLTMOUT    equ    301        ; long time-out (at least 1.5 s)
  1208. SCSTMOUT    equ    51        ; short time-out (at least 250 ms)
  1209.  
  1210. ;+
  1211. ; rcvspscsi() - send a SCSI command which receives data back.
  1212. ;
  1213. ; Passed:
  1214. ;    d0.w = physical unit number
  1215. ;    d1.l = transfer length (in bytes)
  1216. ;    d2.w = command length (NCMD or LCMD)
  1217. ;    a0.l = buffer address
  1218. ;-
  1219.     .globl    _rcvspscsi
  1220. _rcvspscsi:
  1221.     st    flock            ; lock FIFO
  1222.     andi.w    #7,d0            ; mask off the flags to get unit num
  1223.     movem.l    d1-d2/a0,-(sp)        ; save buffer address and cmd length
  1224.     bsr    sblkspscsi        ; send command block
  1225.     movem.l    (sp)+,d1-d2/a0        ; restore buffer address and cmd len
  1226.     tst.w    d0            ; successful?
  1227.     bmi    rspend            ; if not successful, return
  1228.  
  1229.     WSCSI    #0,#SPSCSIICR        ; deassert the data bus
  1230.     WSCSI    #1,#SPSCSITCR        ; set data in phase
  1231.     RSCSI    #SPSCSIREI,d0        ; clear potential interrupt
  1232.  
  1233. rpio:    movea.l    a0,a1            ; a1 -> buffer to read into
  1234. rnxtb:    bsr    setscstmout
  1235.     bsr    w4spreq            ; wait for REQ for data to come
  1236.     bmi    rspend            ; if timed out, returns
  1237.     RSCSI    #SPSCSIDSR,d0        ; still in data in phase?
  1238.     btst    #3,d0            
  1239.     beq    rstat            ; if not, go get status
  1240.     RSCSI    #bSPSCSI,d0        ; else read the next data byte
  1241.     move.b    d0,(a1)+    
  1242.     bsr    dospack
  1243.     bra    rnxtb            ; do next byte
  1244. rstat:    bsr    w4spstat        ; go get status byte
  1245. rspend:    RSCSI    #SPSCSIREI,d1        ; clear potential interrupt
  1246.     bra    _hdone            ; go clean up
  1247.  
  1248.  
  1249.  
  1250. ;+
  1251. ; wrtspscsi() - send a SCSI command which will write data to the target
  1252. ;
  1253. ; Passed:
  1254. ;    d0.w = physical unit number
  1255. ;    d1.l = transfer length (in bytes)
  1256. ;    d2.w = command length (NCMD or LCMD)
  1257. ;    a0.l = buffer address
  1258. ;
  1259. ; Comments: 
  1260. ; 12/04/89 ml
  1261. ;    Bus error occurs when doing a write to the disk that ends at top
  1262. ; of memory.  The DMA counter is decremented when the bytes are written 
  1263. ; from the ping pong buffers to the device, not when bytes are grapped 
  1264. ; from RAM to the ping pong buffers.  Well, AFTER the last 8 bytes are 
  1265. ; read into the ping pong buffers and BEFORE they are written to the 
  1266. ; device, the chip will attempt to read the NEXT 8 bytes into the ping 
  1267. ; pong buffers which results in a bus error because it will be reading 
  1268. ; pass top of memory.  To get around this HARDWARE BUG, the code will 
  1269. ; ALWAYS handshake the last 8 bytes over instead of DMAing them.
  1270. ;
  1271. ; 01/23/90 ml
  1272. ;    A. Pratt said he's willing to move the screen down and sacrifice
  1273. ; 16 bytes of memory.  So, code added on 12/04/89 is commented out.
  1274. ;-
  1275.     .globl    _wrtspscsi
  1276. _wrtspscsi:
  1277.     st    flock            ; lock FIFO
  1278.     andi.w    #7,d0            ; mask off the flags to get unit num
  1279.  
  1280.     movem.l    d1-d2/a0,-(sp)        ; save beginning buffer address
  1281.     bsr    sblkspscsi        ; send command block
  1282.     movem.l    (sp)+,d1-d2/a0        ; a0 = where DMA ends
  1283.     tst.w    d0            ; successful?
  1284.     bmi    wspend            ; if not, go clean up
  1285.  
  1286.     WSCSI    #0,#SPSCSITCR        ; set data out phase
  1287.     RSCSI    #SPSCSIREI,d0        ; clear potential interrupt
  1288.                     ; hand shake data over the bus
  1289. wpio:    movea.l    a0,a1            ; a1 -> buffer to write from
  1290. wnxtb:    bsr    setscstmout
  1291.     bsr    w4spreq            ; wait for REQ for data to come
  1292.     bmi    wspend            ; if timed out, returns
  1293.     RSCSI    #SPSCSIDSR,d0
  1294.     btst    #3,d0            ; still in data out phase?
  1295.     beq    wstat            ; if not, go get status
  1296.     moveq    #0,d0
  1297.     move.b    (a1)+,d0        ; write the next data byte
  1298.     WSCSI    d0,#bSPSCSI
  1299.     bsr    dospack
  1300.     bra    wnxtb            ; do next byte
  1301. wstat:    bsr    w4spstat        ; get status byte
  1302. wspend:    RSCSI    #SPSCSIREI,d1        ; clear potential interrupt
  1303.     bra    _hdone            ; go clean up
  1304.  
  1305.  
  1306.  
  1307. ;+
  1308. ; sblkspscsi() - set DMA pointer and count and send command block
  1309. ;
  1310. ; Passed:
  1311. ;    d0.w = physical unit number
  1312. ;    d1.l = transfer length (in bytes)
  1313. ;    d2.w = command length (NCMD or LCMD)
  1314. ;    a0.l = buffer address
  1315. ;
  1316. ; Returns:
  1317. ;    d0.l =  0 if successful
  1318. ;    d0.l = -1 if timeout
  1319. ;-
  1320. sblkspscsi:
  1321.     movem.l    d1-d2/a0,-(sp)        ; preserve d1, d2 and a0
  1322.     move.w    d0,-(sp)        ; physical unit #
  1323.     bsr    selspscsi        ; select the unit
  1324.     addq.l    #2,sp            ; clean up stack
  1325.     movem.l    (sp)+,d1-d2/a0        ; restore d1, d2 and a0
  1326.     tst.w    d0            ; selection successful?
  1327.     bmi    sbspend            ; if timed out, return
  1328.                     ; else proceed
  1329.     WSCSI    #2,#SPSCSITCR        ; assert C/D
  1330.     WSCSI    #1,#SPSCSIICR        ; assert data bus
  1331.  
  1332.     bsr    setscltmout        ; set up timeout for sending cmdblk
  1333.     lea    _cmdblk,a1        ; a1 -> command block
  1334.     subq.w    #1,d2            ; dbra likes one less
  1335. sbsp0:    move.b    (a1)+,d0        ; d0.b = byte to be sent
  1336.     bsr    sphshake        ; write that byte
  1337.     tst.w    d0
  1338.     bmi    sbspend            ; if timed-out, returns
  1339.     dbra    d2,sbsp0        ; until whole command block is sent
  1340.     moveq    #0,d0            ; all operations successful
  1341. sbspend: rts                ; heading home
  1342.  
  1343.  
  1344. ;+
  1345. ; BOOLEAN selspscsi(SCSIUnit) 
  1346. ; WORD SCSIUnit;
  1347. ;-
  1348. selspscsi:
  1349.     bsr    setscstmout        ; set up a short timeout
  1350. selsp0:    RSCSI    #SPSCSICR,d0
  1351.     btst    #6,d0            ; STILL busy from last time?
  1352.     beq    selsp1            ; if not, it's available
  1353.     cmp.l    (a0),d1            ; timeout?
  1354.     bhi    selsp0            ; not yet, wait some more
  1355.     bra    selsp3            ; else, return error
  1356.  
  1357. selsp1:    WSCSI    #0,#SPSCSITCR        ; data out phase
  1358.     WSCSI    #0,#SPSCSIISR        ; no interrupt from selection
  1359.     WSCSI    #$0c,#SPSCSIICR        ; assert BSY and SEL
  1360. ; set dest SCSI IDs
  1361.     clr.w    d0
  1362.     move.w    4(sp),d1        ; get the SCSI unit desired
  1363.     bset    d1,d0            ; set the appropriate bit
  1364.     WSCSI    d0,#SPSCSIODR        ; (real code would set ours too)
  1365.  
  1366. ;    WSCSI    #$0d,#SPSCSIICR        ; assert BUSY, SEL and data bus
  1367.     WSCSI    #$05,#SPSCSIICR        ; assert SEL and data bus
  1368.     RSCSI    #SPSCSIMR,d0        ; read Mode Register
  1369.     andi.b    #$FE,d0            ; clear arbitrate bit
  1370.     WSCSI    d0,#SPSCSIMR
  1371.     RSCSI    #SPSCSIICR,d0        ; read Initiator Command Register
  1372.     andi.b    #$F7,d0            ; clear BUSY
  1373.     WSCSI    d0,#SPSCSIICR
  1374.     nop                ; 2 deskew delays
  1375.     nop
  1376.  
  1377.     bsr    setscstmout        ; set up for timeout
  1378. selsp2:    RSCSI    #SPSCSICR,d0        ; wait for bus to be busy
  1379.     btst    #6,d0
  1380.     bne    selsp4
  1381.     cmp.l    (a0),d1
  1382.     bhi    selsp2
  1383.  
  1384. selsp3:    moveq    #-1,d0            ; time out
  1385.     bra    selsp5
  1386.     
  1387. selsp4:    clr.w    d0            ; selection successful
  1388. selsp5:    WSCSI    #0,#SPSCSIICR        ; clear SEL and data bus assertion
  1389.     rts
  1390.  
  1391.  
  1392. *+
  1393. * VOID resetspscsi();
  1394. *-
  1395.     .globl    _resetspscsi
  1396. _resetspscsi:
  1397.     WSCSI    #$80,#SPSCSIICR    ; assert RST
  1398.     bsr    setscstmout    ; wait (at least) 250 ms
  1399. rstsp0:    cmp.l    (a0),d1
  1400.     bhi    rstsp0
  1401.     WSCSI    #0,#SPSCSIICR
  1402.     bsr    setscltmout    ; wait (at least) 1000 ms
  1403. rstsp1:    cmp.l    (a0),d1
  1404.     bhi    rstsp1
  1405.     RSCSI    #SPSCSIREI,d0        ; clear potential interrupt
  1406.     rts
  1407.  
  1408.  
  1409. ;+
  1410. ; w4spstat - wait for status byte and message byte.
  1411. ;
  1412. ; Returns:
  1413. ;    d0.l = returned status or timeout error
  1414. ;-
  1415. w4spstat:
  1416.     bsr    setscstmout        ; set up time-out for REQ and ACK
  1417.     WSCSI    #3,#SPSCSITCR        ; status in phase
  1418.     RSCSI    #SPSCSIREI,d0        ; clear potential interrupt
  1419.  
  1420.     bsr    w4spreq            ; wait for status byte
  1421.     bmi    w4spend            ; if timed-out, returns
  1422. gspstat:
  1423.     RSCSI    #SPSCSIDB,d0        ; get the status byte
  1424.     andi.w    #$ff,d0
  1425.     move.l    d0,-(sp)        ; save the status byte
  1426.     bsr    setscstmout        ; set up time-out for REQ and ACK
  1427.     bsr    dospack            ; signal that status byte is here
  1428.     tst.w    d0            ; timed-out?
  1429.     beq    gsp1            ; if not, wait for message byte
  1430.  
  1431. gsp0:    addq.l    #4,sp            ; else clean up stack
  1432.     bra    w4spend            ; and return
  1433.  
  1434. gsp1:    bsr    setscstmout        ; set up timeout for REQ and ACK
  1435.     bsr    w4spreq            ; wait for message byte
  1436.     bmi    gsp0            ; if timed-out, returns
  1437.  
  1438.     RSCSI    #SPSCSIDB,d0        ; get and ignore message byte
  1439.     bsr    dospack            ; signal that message byte is here
  1440.     tst.w    d0            ; timed-out?
  1441.     bmi    gsp0            ; if so, return timeout
  1442.     move.l    (sp)+,d0        ; recall the status byte
  1443. w4spend:
  1444.     rts                ; return
  1445.  
  1446.  
  1447. ;+
  1448. ; w4spreq() - wait for REQ to come during hand shake of non-data bytes
  1449. ;
  1450. ; Passed:
  1451. ;    d1.l = expiration time
  1452. ;    a0.l = address of _hz_200
  1453. ;
  1454. ; Returns:
  1455. ;     0 - if successful
  1456. ;    -1 - times out
  1457. ;-
  1458. w4spreq:
  1459. w4sp0:    RSCSI    #SPSCSICR,d0        ; read Control Register
  1460.     btst    #5,d0            ; waiting for REQ to come
  1461.     bne    w4sp1            ; if REQ comes, done
  1462.     cmp.l    (a0),d1            ; time's up?
  1463.     bhi    w4sp0            ; if not, wait some more
  1464.     moveq    #-1,d0            ; else, returns timed out
  1465.     bra    w4sprend
  1466. w4sp1:    moveq    #0,d0            ; returns successful
  1467. w4sprend:
  1468.     rts
  1469.  
  1470.  
  1471. ;+
  1472. ; dospack() - assert ACK
  1473. ;
  1474. ; Passed:
  1475. ;    d1.l = expiration time
  1476. ;    a0.l = address of _hz_200
  1477. ;
  1478. ; Returns:
  1479. ;     0 - if successful
  1480. ;    -1 - times out
  1481. ;-
  1482. dospack:    
  1483.     RSCSI    #SPSCSIICR,d0        ; read Initiator Command Register
  1484.     ori.b    #$11,d0            ; assert ACK (and data bus)
  1485.     WSCSI    d0,#SPSCSIICR
  1486.     andi.b    #$ef,d0            ; clear ACK
  1487.     WSCSI    d0,#SPSCSIICR
  1488.     moveq    #0,d0
  1489.     rts
  1490.  
  1491.  
  1492. ;+
  1493. ; sphshake() - hand shake a byte over to the controller
  1494. ;
  1495. ; Passed:
  1496. ;    d0.b = byte to be handed over
  1497. ;    d1.l = expiration time
  1498. ;    a0.l = address of _hz_200
  1499. ;
  1500. ; Returns:
  1501. ;    Whatever w4spreq() or dospack() returns, which is:
  1502. ;         0 - if successful
  1503. ;        -1 - times out
  1504. ;-
  1505. sphshake:
  1506.     move.w    d0,-(sp)        ; preserve d0.w
  1507.     bsr    w4spreq            ; wait for REQ to come
  1508.     bmi    hspend            ; if timed out, returns
  1509.     move.w    0(sp),d0
  1510.     WSCSI    d0,#SPSCSIDB        ; write a byte out to data bus
  1511.     bsr    dospack            ; assert ACK
  1512. hspend:    addq.l    #2,sp            ; clean up stack
  1513.     rts
  1514.  
  1515.  
  1516. ;+
  1517. ; setscstmout - set up a time-out count for the SCSI for SCSTMOUT ticks
  1518. ;
  1519. ; Returns:
  1520. ;    a0.l = address of _hz_200 clock
  1521. ;    d1.l = expiration time
  1522. ;-
  1523. setscstmout:
  1524.     movea.l    #_hz_200,a0    ; a0 -> 200 hz clock
  1525.     move.l    #SCSTMOUT,d1    ; d0 = SCSTMOUT _hz_200 clicks
  1526.     add.l    (a0),d1        ; d0 = curr time + # clicks to wait
  1527.     rts
  1528.  
  1529.  
  1530. ;+
  1531. ; setscltmout - set up a time-out count for the SCSI for SCLTMOUT long
  1532. ;
  1533. ; Returns:
  1534. ;    a0.l = address of _hz_200 clock
  1535. ;    d1.l = expiration time
  1536. ;-
  1537. setscltmout:
  1538.     movea.l    #_hz_200,a0    ; a0 -> 200 hz clock
  1539.     move.l    #SCLTMOUT,d1    ; d0 = SCLTMOUT _hz_200 clicks
  1540.     add.l    (a0),d1        ; d0 = curr time + # clicks to wait
  1541.     rts
  1542.  
  1543. .endif
  1544.  
  1545.  
  1546.  
  1547. .if IDE_AT
  1548.  
  1549. ;+++++++++++++++++++++++++++++++;
  1550. ;                ;
  1551. ;    IDE-AT specific        ;
  1552. ;                ;
  1553. ;+++++++++++++++++++++++++++++++;
  1554.  
  1555. ; IDE disk interface I/O locations for Read functions
  1556.  
  1557. bIDE    equ    $FFF00000+REGBASE    ; base address
  1558.  
  1559. IDEDR    equ    bIDE-REGBASE+($00*REGLSTEP); Data Register (16-bit reg)
  1560. IDEER    equ    bIDE+($01*REGLSTEP)    ; Error Register
  1561. IDESC    equ    bIDE+($02*REGLSTEP)    ; Sector Count
  1562. IDESN    equ    bIDE+($03*REGLSTEP)    ; Sector Number
  1563. IDECL    equ    bIDE+($04*REGLSTEP)    ; Cylinder Low
  1564. IDECH    equ    bIDE+($05*REGLSTEP)    ; Cylinder High (2 bits)
  1565. IDESDH    equ    bIDE+($06*REGLSTEP)    ; SDH register
  1566. IDESR    equ    bIDE+($07*REGLSTEP)    ; Status Register
  1567. IDEASR    equ    bIDE+($0E*REGLSTEP)    ; Alternate Status Register
  1568. IDEDAR    equ    bIDE+($0F*REGLSTEP)    ; Drive Address Register
  1569.  
  1570.  
  1571.  
  1572. ; IDE disk interface I/O locations for Write functions
  1573.  
  1574. ;IDEDR    equ    bIDE-REGBASE+($00*REGLSTEP); Data Register (16-bit reg)
  1575. IDEWPR    equ    bIDE+($01*REGLSTEP)    ; Write Precomp Register (not used)
  1576. ;IDESC    equ    bIDE+($02*REGLSTEP)    ; Sector Count
  1577. ;IDESN    equ    bIDE+($03*REGLSTEP)    ; Sector Number
  1578. ;IDECL    equ    bIDE+($04*REGLSTEP)    ; Cylinder Low
  1579. ;IDECH    equ    bIDE+($05*REGLSTEP)    ; Cylinder High (2 bits)
  1580. ;IDESDH    equ    bIDE+($06*REGLSTEP)    ; SDH register
  1581. IDECR    equ    bIDE+($07*REGLSTEP)    ; Command Register
  1582. IDEDOR    equ    bIDE+($0E*REGLSTEP)    ; Digital Output Register
  1583.  
  1584.  
  1585. ; Byte indices into buffer return by the Identify command
  1586.  
  1587. NCYL    equ    2        ; offset to # of fixed cylinders
  1588. NHEAD    equ    6        ; offset to number of heads
  1589. NSPT    equ    12        ; offset to number of sectors/track
  1590. MDLNUM    equ    54        ; offset to model number of drive
  1591. CONMDL    equ    MDLNUM+26    ; offset to Conner's model number
  1592.  
  1593.  
  1594. ; Default drive parameters of Conner Peripherals - CP2024
  1595. CP20NCYL    equ    615    ; # of cylinders
  1596. CP20NHEAD    equ    4    ; # of heads
  1597. CP20NSPT    equ    17    ; # of sectors/track
  1598.  
  1599.  
  1600. ;+
  1601. ; Wait for status to come back
  1602. ;-
  1603. w4int:    move.l    #D_WORST,d0    ; d0 = time-out limit
  1604.     add.l    _hz_200,d0    ; d0 = expiration time
  1605. wi0:    btst.b    #5,GPIP        ; interrupt?
  1606.     beq.b    wi1        ; if so, out of the loop
  1607.     cmp.l    _hz_200,d0    ; time-out?
  1608.     bhi.b    wi0        ; if not, wait some more
  1609.     moveq    #-1,d0        ; else, return time-out
  1610.     bra.b    wi3
  1611. wi1:    moveq    #0,d0        ; clear d0
  1612.     move.b    IDESR,d0    ; d0.b = status returned
  1613.     btst    #0,d0        ; any error?
  1614.     bne.b    wi2        ; if yes, return error code
  1615.     btst    #3,d0        ; else DRQ?
  1616.     bne.b    wi3        ; if so, just return
  1617.     moveq    #0,d0        ; else return OK
  1618.     bra.b    wi3
  1619. wi2:    move.b    IDEER,d0    ; else d0.b = error bits
  1620. wi3:    rts            ; return status or error code
  1621.  
  1622.  
  1623.  
  1624. ;+
  1625. ; ideread() - reads from 1 to 256 sectors as specified in the Task File,
  1626. ;        beginning at the specified sector.
  1627. ;       - sector count equal to 0 requests 256 sectors.
  1628. ;
  1629. ; ideread(nhd, nspt, sectnum, count, buf, pdev)
  1630. ; WORD    nhd;        4(sp).w        ; # of data heads on pdev
  1631. ; WORD    nspt;        6(sp).w        ; # of physical sectors per track
  1632. ; LONG    sectnum;    8(sp).l        ; logical block address
  1633. ; WORD    count;        $c(sp).w    ; # of sectors to read
  1634. ; BYTE    *buf;        $e(sp).l    ; $f(sp)=high $10(sp)=mid $11(sp)=low
  1635. ; WORD    pdev;        $12(sp).w    ; physical device number
  1636. ;-
  1637.     .globl    _ideread
  1638. _ideread:
  1639.     bsr    set_dhcs    ; set physical address
  1640.     move.l    $e(sp),a0    ; a0 -> buffer to read into
  1641.     move.b    $d(sp),IDESC    ; set sector count
  1642.  
  1643.     move.w    $c(sp),d1    ; d1.w = # of sectors to read
  1644.     subq    #1,d1        ; dbra likes one less
  1645.  
  1646.     move.b    #0,IDEDOR    ; enable interrupt
  1647.     move.b    #IDEREAD,IDECR    ; set command code
  1648. ider0:    bsr    w4int        ; wait for interrupt
  1649.     tst.w    d0        ; successful?
  1650.     bmi.b    ider1        ; if timed-out, return
  1651.  
  1652.     btst    #3,d0        ; DRQ?
  1653.     beq.b    ider1        ; if not, return
  1654.  
  1655.     bsr    readbuf        ; fill sector buffer
  1656.     dbra    d1,ider0    ; more to read?
  1657.     moveq    #0,d0        ; everything's fine
  1658. ider1:    rts
  1659.  
  1660.  
  1661. ;+
  1662. ; idewrite() - writes from 1 to 256 sectors as specified in the Task File,
  1663. ;        beginning at the specified sector.
  1664. ;        - sector count equal to 0 requests 256 sectors.
  1665. ;
  1666. ; idewrite(nhd, nspt, sectnum, count, buf, pdev)
  1667. ; WORD    nhd;        4(sp).w        ; # of data heads on pdev
  1668. ; WORD    nspt;        6(sp).w        ; # of physical sectors per track
  1669. ; LONG    sectnum;    8(sp).l        ; logical block address
  1670. ; WORD    count;        $c(sp).w    ; # sectors to read
  1671. ; BYTE    *buf;        $e(sp).l    ; $f(sp)=high $10(sp)=mid $11(sp)=low
  1672. ; WORD    pdev;        $12(sp).w    ; physical device number
  1673. ;-
  1674.     .globl    _idewrite
  1675. _idewrite:    
  1676.     bsr    set_dhcs    ; set physical address
  1677.     move.l    $e(sp),a0    ; a0 -> buffer to write from
  1678.     move.b    $d(sp),IDESC    ; set sector count
  1679.  
  1680.     move.w    $c(sp),d1    ; d1.w = # of sectors to read
  1681.     subq    #1,d1        ; dbra likes one less
  1682.  
  1683.     move.b    #0,IDEDOR    ; enable interrupt
  1684.     move.b    #IDEWRITE,IDECR    ; set command code
  1685. idew0:    btst.b    #3,IDEASR    ; DRQ?
  1686.     beq.b    idew0        ; if not, wait longer
  1687. idew1:    bsr    wrtbuf        ; fill sector buffer
  1688.     bsr    w4int        ; wait for interrupt
  1689.     tst.w    d0        ; successful?
  1690.     bmi.b    idew2        ; if timed-out, return
  1691.     btst    #3,d0        ; DRQ?
  1692.     beq.b    idew2        ; if not, return
  1693.     dbra    d1,idew1    ; else go transfer data
  1694.     moveq    #0,d0        ; everything's fine
  1695. idew2:    rts
  1696.  
  1697.  
  1698. ;+
  1699. ; set_dhcs() - convert a logical block address into a physical address.
  1700. ;         - set drive #, head #, cylinder # and sector # in task file.
  1701. ;
  1702. ; Passed:
  1703. ;    8(sp).w = nhd = # of data heads
  1704. ;    $a(sp).w = nspt = # of physical sectors per track
  1705. ;    $c(sp).l = logical block address
  1706. ;    $16(sp).w = physical unit #
  1707. ;-
  1708. set_dhcs:
  1709.     move.l    $c(sp),d1    ; d1.l = logical block address
  1710.     move.w    8(sp),d2    ; d2.w = # of data heads
  1711.     move.w    $a(sp),d0    ; d0.w = # of physical sectors per track
  1712.     mulu    d0,d2        ; d2.l = # of sectors per cylinder
  1713.                 ;      = # heads * # of sectors per track
  1714.     divu.w    d2,d1        ; d1.w = cylinder #
  1715.                 ;      = log block addr / #spc
  1716.     move.b    d1,IDECL    ; set cylinder low
  1717.     lsr.l    #8,d1        ; d1.b = cylinder high
  1718.     move.b    d1,IDECH    ; set cylinder high
  1719.     lsr.l    #8,d1        ; d1.l = sector # within the cyl
  1720.     divu.w    d0,d1        ; d1.w = head #
  1721.                 ;      = sector # within cyl / #spt
  1722.     move.w    $16(sp),d0    ; d0.w = physical unit #
  1723.     andi.b    #7,d0        ; mask off flags from physical unit #
  1724.     lsl.b    #4,d0        ; shift unit # to place
  1725.     or.b    d0,d1        ; or in drive #
  1726.     move.b    d1,IDESDH    ; set drive and head #
  1727.     swap    d1        ; d1.w = sector # (base 0)
  1728.     addq.w    #1,d1        ;      = sector # + 1 (base 1)
  1729.     move.b    d1,IDESN    ; set sector #
  1730.     rts
  1731.  
  1732. ;+
  1733. ; identify() - allows the Host to receive parameter information from
  1734. ;           the drive.
  1735. ;
  1736. ; identify(pdev, buf)
  1737. ; WORD    pdev;    4(sp).w        ; physical unit #
  1738. ; BYTE    *buf;    6(sp).l        ; buffer to put data
  1739. ;-
  1740.     .globl    _identify
  1741. _identify:
  1742.     move.w    4(sp),d0    ; d0 = physical unit #
  1743.     andi.b    #7,d0        ; mask off flags (if any)
  1744.     lsl.b    #4,d0        ; shift unit # to place
  1745.     move.b    d0,IDESDH    ; set drive #
  1746.     move.l    6(sp),a0    ; a0 -> buffer
  1747.  
  1748.     move.b    #0,IDEDOR    ; enable interrupt
  1749.     move.b    #IDENTIFY,IDECR    ; set command code
  1750.     bsr    w4int        ; wait for interrupt
  1751.     tst.w    d0        ; successful?
  1752.     bmi.b    id0        ; if timed-out, return
  1753.     btst    #3,d0        ; DRQ?
  1754.     beq.b    id0        ; if not, return with error
  1755.  
  1756.     bsr    readbuf        ; read data
  1757.     moveq    #0,d0        ; everything's fine
  1758.  
  1759. id0:    rts 
  1760.  
  1761.  
  1762. ;+
  1763. ; readbuf() - reads 512 bytes (128 longs) of data into sector buffer.
  1764. ;
  1765. ; Passed:
  1766. ;    a0.l = buffer to store data read from sector buffer
  1767. ;-
  1768. readbuf:
  1769.     moveq    #31,d0        ; d0 = (# of words of data to read / 8) - 1
  1770.     lea    IDEDR,a1    ; a1 -> data bus
  1771. rb0:    move.w    (a1),(a0)+    ; read data from bus
  1772.     move.w    (a1),(a0)+    ; read data from bus
  1773.     move.w    (a1),(a0)+    ; read data from bus
  1774.     move.w    (a1),(a0)+    ; read data from bus
  1775.     move.w    (a1),(a0)+    ; read data from bus
  1776.     move.w    (a1),(a0)+    ; read data from bus
  1777.     move.w    (a1),(a0)+    ; read data from bus
  1778.     move.w    (a1),(a0)+    ; read data from bus
  1779.     dbra    d0,rb0        ; repeat until all done
  1780.     rts
  1781.  
  1782.  
  1783. ;+
  1784. ; wrtbuf() - writes 512 bytes (128 longs) of data to sector buffer.
  1785. ;
  1786. ; Passed:
  1787. ;    a0.l = buffer with data to write to sector buffer
  1788. ;-
  1789. wrtbuf:
  1790.     moveq    #31,d0        ; d0 = (# of words of data to read / 8) - 1
  1791.     lea    IDEDR,a1    ; a1 -> data bus
  1792. wb0:    move.w    (a0)+,(a1)    ; write data to bus
  1793.     move.w    (a0)+,(a1)    ; write data to bus
  1794.     move.w    (a0)+,(a1)    ; write data to bus
  1795.     move.w    (a0)+,(a1)    ; write data to bus
  1796.     move.w    (a0)+,(a1)    ; write data to bus
  1797.     move.w    (a0)+,(a1)    ; write data to bus
  1798.     move.w    (a0)+,(a1)    ; write data to bus
  1799.     move.w    (a0)+,(a1)    ; write data to bus
  1800.     dbra    d0,wb0        ; repeat until all done
  1801.     rts
  1802.  
  1803.  
  1804. ;+
  1805. ; _iderdy() - test if the IDE drive is ready
  1806. ;
  1807. ; Passed:
  1808. ;    d0.b = IDE drive unit #
  1809. ;
  1810. ; Returns: 0 - if drive is NOT ready
  1811. ;       1 - if drive is ready
  1812. ;-
  1813.     .globl    _iderdy
  1814. _iderdy:
  1815.     andi.b    #7,d0        ; mask off flags (if any)
  1816.     lsl.b    #4,d0        ; shift unit # to place
  1817.     move.b    d0,IDESDH    ; set drive #
  1818.     move.b    #$50,d1        ; ready status
  1819.     move.l    #IDERDY,d0    ; set up timer
  1820.     add.l    _hz_200,d0
  1821. ir0:    cmp.b    IDEASR,d1    ; is drive ready and not busy?
  1822.     beq.b    ir1        ; if so, return with drive ready
  1823.     cmp.l    _hz_200,d0    ; time-out yet?
  1824.     bcc.b    ir0        ; if not, wait longer
  1825.     moveq    #0,d0        ; else return drive NOT ready
  1826.     rts
  1827. ir1:    moveq    #1,d0        ; else, drive is ready
  1828.     rts
  1829.  
  1830. ;+
  1831. ; gcparm() - get current drive parameters
  1832. ;
  1833. ; gcparm(buf)
  1834. ; char    *buf;    $4(sp).l    /* -> data returned by identify() */
  1835. ;
  1836. ; Returns:
  1837. ;    d0.w = # of default cylinders
  1838. ;    d1.w = # of default heads
  1839. ;    d2.w = # of default sectors per track
  1840. ;-
  1841.     .globl    _gcparm
  1842. _gcparm:
  1843.     move.l    4(sp),a0    ; a0 -> data buffer
  1844.     add.l    #CONMDL,a0    ; a0 -> where Conner model number is
  1845.     move.l    a0,-(sp)
  1846.     pea    cp2024
  1847.     move.w    #6,-(sp)
  1848.     bsr    strcmp        ; compare model# with "CP2024"
  1849.     adda    #10,sp        ; clean up stack
  1850.     tst.w    d0        ; is unit the CP2024 (Kato 20Mb)?
  1851.     bne.b    gcp0        ; if not, handle the normal way
  1852.                 ; else return default values of CP2024
  1853.     move.w    #CP20NCYL,d0    ; d0.w = # of cylinders
  1854.     move.w    #CP20NHEAD,d1    ; d1.w = # of heads
  1855.     move.w    #CP20NSPT,d2    ; d2.w = # of spt
  1856.     bra.b    gcpend
  1857.  
  1858. gcp0:    move.l    4(sp),a0
  1859.     move.w    NCYL(a0),d0    ; d0.w = # of cylinders
  1860.     move.w    NHEAD(a0),d1    ; d1.w = # of heads
  1861.     move.w    NSPT(a0),d2    ; d2.w = # of sectors per track
  1862.  
  1863. gcpend:    rts
  1864.  
  1865.  
  1866.  
  1867. conner:    dc.b    "Conner",0
  1868. .even
  1869. cp2024:    dc.b    "CP2024",0
  1870. .even
  1871.  
  1872.  
  1873. ;+
  1874. ; strcmp() - compare two strings
  1875. ;
  1876. ; Passed:
  1877. ;    4(sp).w  = n (# of bytes to compare)
  1878. ;    6(sp).l  = address of first string
  1879. ;    10(sp).l = address of second string
  1880. ;
  1881. ; Returns:
  1882. ;    d0.w = 0    if first n bytes of the 2 strings are the same
  1883. ;         = non-0    otherwise
  1884. ;-
  1885. strcmp:    movem.l    d1/a0-a1,-(sp)    ; save registers d1, a0 and a1
  1886.     move.w    16(sp),d1    ; d1 = byte count
  1887.     subq.w    #1,d1        ; dbra likes one less
  1888.     move.l    18(sp),a0    ; a0 -> string 1
  1889.     move.l    22(sp),a1    ; a1 -> string 2
  1890.     moveq    #1,d0        ; assume strings are not the same
  1891. str0:    cmpm.b    (a0)+,(a1)+    ; characters the same?
  1892.     bne.b    str1        ; if not, return
  1893.     dbra    d1,str0        ; else compare next character
  1894.     moveq    #0,d0        ; the strings are the same
  1895. str1:    movem.l    (sp)+,d1/a0-a1    ; restore registers d1, a0 and a1
  1896.     rts
  1897.  
  1898.  
  1899. .endif
  1900.  
  1901.  
  1902.