 lib environment
 lib bfhdr
 lib dtab
 lib macdefs
 data
 sttl CMI 5" Winchester Drivers
 pag
 name cmidrvr
 global cmiint,cmidvn,cmiclose,cmiopen,cmisto
 global cdcop,cdccl,cdcsp,cdcio,cdcrd,cdcwr

PRT_DCT set 0 Print DCT when initializing
PRT_ERR set 0 Print I/O Errors
PRT_REQ set 0 Print I/O Requests
PRT_SWP set 0 Print Swap transactions

*
* CMI 5" Winchester drivers
*

*
* driver equates and addresses
*
CMITDR equ $00 Test Drive Ready
CMIREC equ $01 Recalibrate (reseek to 0)
CMIRSS equ $03 Request Sense Status
CMIFDR equ $04 Format Drive
CMIFTR equ $06 Format Track
CMIRDS equ $08 Read Sector
CMIWRS equ $0A Write Sector
CMIIDC equ $0C Initialize Drive Characteristics
CMIRDG equ $E0 Internal RAM Diagnostic
CMIDDG equ $E3 Drive Diagnostic
CMICID equ $E4 Controller Internal Diagnostic
CMI_FD equ 17 Format Drive (special count)
CMI_FT equ 17*2 Format Track
*
cmiesw fdb 0 CMI Error Status Word
cmisbf rzb 4 CMI Sense Status Buffer
cmiirs fcb 0 CMI Controller RESET
cmiopt fcb 0,0 cmi open table
cmidtyp fdb cmi_DC0,cmi_DC1 drive characteristics tables
cmi_DC0 rzb 11 Drive Characteristics tables
cmi_DC1 rzb 11
cmi_DCn fcb $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
cmiotyp fdb cmi_DCn previous drive type
cmidrv fdb $FFFF current drive select for CMI
cmitmp fcb 0 space to "read" device size
cmisdn fdb 0 saved device #
BDtable fdb 0 Block Device Table address
cmiswpt fdb 0 swap table pointer
*
*  Xebec Command Block (DCB)
*
CMIcmd fcb 0 Xebec S1410 Command
CMIlun fcb 0 Drive Select
CMIadr fcb 0,0 Sector Address
CMIcnt fcb 0 Sector Count
CMIctl fcb 4 Control Flags (constant)
*
* disk controller definitions
*
CMIBSY equ %00001000
CMIREQ equ %00000001 Controller Request Data
*
* open the cmi disk drive - insure the device is online, etc.
*
cmiopen
 std cmisdn save device #
 lbsr cmidvn drive select
 tst cmiopt,x already open?
 beq cmiop1 no - go do open
 inc cmiopt,x yes - bump open count
 lbra cmirts all done
cmiop1 inc cmiopt,x set open status
 lda #8 set up default device characteristics = ST-506
 ldb cmisdn+1
 subb #CMIminor
 lbsr cpy_DCT

 if 0 *** Can't do this here !! ***

 lda #CMITDR Test for Drive Ready
 sta CMIcmd
 lda #1 No DMA or IRQ
 lbsr cmicn set up and send command
 lbsr cmist get status of command
 lbne cmiop9 jump if error detected
 lda #CMIRDG run RAM diagnostics
 sta CMIcmd
 lda #1 no DMA/IRQ needed
 lbsr cmicn run command
 lbsr cmist test status
 lbne cmiop9
 lda #CMICID run Controller Diagnostic
 sta CMIcmd
 lda #1 no IRQ/DMA
 lbsr cmicn
 lbsr cmist
 lbne cmiop9
 endif

 pshs x save device offset
 ldx #1 read SIR
 ldy #0
 ldd cmisdn restore device #
 lda #CMImajor make sure block read
 jsr rdbuf
 lda bfflag,y get flags
 bita #BFERR error?
 bne cmiop8 yes - return error
 pshs y save buffer pointer
 ldx 0,s get buffer header
 ldy #cmitmp no - read drive type
 ldu #sdenf from "density" byte in SIR
 ldd #1
 jsr cpybts
 lda cmitmp check for DCT index/data in SIR
 cmpa #$FF
 bne 10f
 ldx 0,s it is - read actual table from SIR
 ldd cmisdn compute table address
 subb #CMIminor
 aslb
 ldy #cmidtyp
 ldy b,y
 ldu #swinc
 ldd #11
 jsr cpybts
 bra 20f
10 lda cmitmp pick up size field
 cmpa #MAXDCT legal DCT index?
 bls 15f yes - jump (OK)
 lda #8 no - assume ST-506
15 ldb cmisdn+1 compute table address
 subb #CMIminor
 jsr cpy_DCT copy device table
20 puls y restore buffer pointer
 jsr freebf free buffer
 puls x
 ldx #$FFFF force controller to be reconfigured
 stx cmidrv
 rts device opened OK
cmiop8 jsr freebf release buffer
 puls x restore device index
cmiop9 lda #EIO indicate device offline
 sta uerror stuff into user error flag
 clr cmiopt,x clear open status
cmirts rts return
*
* Copy a device characteristics table from
* the "Winchesters" table to the internal
* drive type table
*    A - Drive type index
*    B - Relative device number (minor)
*
cpy_DCT pshs d,x,y,u
 aslb
 ldy #cmidtyp
 ldy b,y
 ldu cmiotyp reset "old" known configuration
 ldx #MW_DCT compute device characteristics table
 leax a,x
 asla A*8
 asla
 asla
 leax a,x offset*9
 ldb #9
17 lda ,x+ copy table
 sta ,y+
 clr ,u+
 decb
 bne 17b
 clr ,y+ ** filler **
 clr ,y+
 ldx #$FFFF force controller to be reconfigured
 stx cmidrv
 puls d,x,y,u,pc return
*
*  Set up controller
*
cmiidc pshs d,x,y save registers
 cmpx cmidrv same drive as last operation?
 lbeq cmiid9 yes - exit
 tfr x,d -- compute table index
 leay d,x 2*X
 ldy cmidtyp,y
 pshs y save it
 ldx cmiotyp compare with last table sent
 ldb #11
10 lda ,x+
 cmpa ,y+
 bne 15f jump if not the same
 decb
 bne 10b continue
 puls y clean up stack
 lbra cmiid9 exit - no need to reconfigure
15 ldy 0,s no match - copy table
 ldx cmiotyp
 ldb #11
17 lda ,y+
 sta ,x+
 decb
 bne 17b
 ldy 0,s restore table address
 if PRT_DCT
 ldx 2,s -- get actual drive pointer
 bsr prt_dct
 endif
 lda 8,y set up control byte = seek rate/imbedded servo info
 anda #$0F
 ora 9,y
 sta CMIctl
 lda #CMIIDC Initialize Drive Characteristics
 sta CMIcmd
 lda #1 no DMA/IRQ
 lbsr cmicn send command
cmiid2 lbsr cmiwt wait for READY
 bitb #$14 wait for REQ=1, I/O=0, C/D=0
 bne cmiid2
 puls x restore device characteristics table
 lda #8
cmiid3 lbsr cmiwt wait for READY
 ldb ,x+
 stb XBCCOM
 deca done?
 bne cmiid3
 lbsr cmist wait for end of command and check status
 beq cmiid9
 pshs d,x
 ldx #00f
 jsr Pdata
 lda cmisbf get error code
 jsr Phex
 bra 99f
00 fcc $d,'XEBEC Error on IDC: ',0
99 puls d,x
cmiid9
 ldx 2,s restore drive index
 stx cmidrv no - remember drive #
 puls d,x,y,pc
 if PRT_DCT
*
prt_dct pshs d,x,y,u
 ldx #00f
 jsr Pdata
 lda 2+1,s
 jsr Phex
 ldx #01f
 jsr Pdata
 ldb #10
0 lda ,y+
 jsr Phex
 jsr Pspace
 decb
 bne 0b
 puls d,x,y,u,pc
00 fcc $d,'XEBEC DCT - Unit: ',0
01 fcc ', Table: ',0
 endif
*
* cmi close
*
cmiclose
 bsr cmidvn set up drive
 dec cmiopt,x clear open status
 bpl cmicl0
 clr cmiopt,x
cmicl0
 rts return
*
* cmidvn - select CMI drive
*   (B) - minor device #
*   return with (X) - device index
*
cmidvn
 cmpb #CMIminor+1 check device number
 lbhi cmier0 go set error
 subb #CMIminor compute relative drive #
 clra set up device index
 tfr d,x
 rts
*
* cmidvnx - select CMI drive & set up LUN in command
*   (B) - minor device #
*   return with (X) - device index
*
cmidvnx bsr cmidvn set up registers
 tstb
 beq cmidv0
 ldb #$20 select drive #1
cmidv0 stb CMIlun set command byte
 rts
*
* cmicn - set up CMI command and send to Xebec
*    A - DMA/IRQ select mask
*
cmicn pshs d
 tst cmiirs Has interface been RESET?
 bne cmicn0 yes - don't do it again
 lda #$80 no - send RESET code
 sta CMICMD
 clr CMICMD
 inc cmiirs
cmicn0
 lda 0,s restore DMA/IRQ mask
 bita #$60 test DMA/IRQ bits
 beq cmicn1
 ldb CMIlun
 orb bfblch,y set up block #
 stb CMIlun
 ldd bfblck,y
 std CMIadr
 lda bfxadr,y get memory address
 sta CMIADR
 ldd bfadr,y
 std CMIADR+1
 bra cmicn2
cmicn1 ldd #0 clean up DCB
 std CMIadr
 sta CMIcnt
cmicn2 lda 0,s restore DMA/IRQ mask
 sta CMICMD set up DMA/IRQ selection
 ldb #8 block count (interleave factor)
 lda CMIcmd test for Format Command
 cmpa #CMIFDR
 beq cmicn3
 cmpa #CMIFTR Format Track
 beq cmicn3
 ldb #1 set block count
cmicn3 stb CMIcnt
 ldx #CMIcmd set up to send command
 lda #6 send 6 bytes
cmicn4 lbsr cmiwt wait for READY
 ldb ,x+ get next byte
 stb XBCCOM send to controller
 deca done?
 bne cmicn4
 puls d,pc
*
* cmist - wait for operation complete & get status
*
cmist
 lda CMICMD wait for command completion
 bpl cmist
cmist0
 lbsr cmiwt get command status
 lda XBCCOM
 pshs a
 lbsr cmiwt
 ldb XBCCOM
 puls a
 bita #2 error bit set?
 beq cmist9 no - exit
 std cmiesw save error status word
 lda #CMIRSS Request Sense Status
 sta CMIcmd
 lda #1 no DMA/IRQ
 lbsr cmicn send command
 ldx #cmisbf Sense Buffer
 lda #4
cmist1 bsr cmiwt wait for READY
 ldb XBCCOM get data
 stb ,x+
 deca done?
 bne cmist1
 lbsr cmiwt get command status
 lda XBCCOM
 lbsr cmiwt
 ldb XBCCOM
 if PRT_ERR
 bsr rpt_err
 endif
 lda cmisbf check for soft errors
 anda #$7F
 cmpa #$18 ECC Correctable error code
cmist9 rts return
 if PRT_ERR
*
rpt_err pshs d,x,y,u
 ldx #00f
 jsr Pdata
 ldx #cmisbf
 ldb #4
0 lda ,x+
 jsr Phex
 jsr Pspace
 decb
 bne 0b
 puls d,x,y,u,pc
00 fcc $d,'XEBEC Error: ',0
 endif
*
*  Wait for Xebec to request data
*
cmiwt ldb CMICMD test READY
 bitb #1
 beq cmiwt wait until READY
 rts

 if PRT_REQ
prt_bh pshs d,x,y,u
 ldx #00f
 jsr Pdata
 ldd bfdvn,y
 bsr phex2
 ldx #01f
 jsr Pdata
 lda bfflag,y
 jsr Phex
 ldx #02f
 jsr Pdata
 lda bfblch,y
 jsr Phex
 ldd bfblck,y
 bsr phex2
 puls d,x,y,u,pc
*
phex2 pshs d
 jsr Phex
 lda 1,s
 jsr Phex
 puls d,pc
*
00 fcc $d,'CMI I/O, Device = ',0
01 fcc ', Flags = ',0
02 fcc ', Block = ',0
 endif
*
* fire up CMI operation to initiate transfer
*
cmisto stx BDtable
 if PRT_REQ
 bsr prt_bh print buffer header
 endif
 ldb bfdvn+1,y get drive #
 lbsr cmidvnx select drive
 lbsr cmiidc set up device characteristics if needed
 lda bfblch,y check block number range
 cmpa #$0f
 lbhi cmier if too big - error
*
* decide whether we are doing a read or write (or swap)
*
 ldd bfxfc,y get transfer count
 cmpd #16 special value for swap?
 ble cmiswp
 ldb bfflag,y get buffer flags
 bitb #BFRWF are we reading?
 beq cmiwrt go do write
 lda #CMIRDS set Read Sector Command
 bra cmirw go perform I/O
*
* set up for write command
*
cmiwrt bitb #BFSPC special i/o
 beq cmiwr9 jump if write
 ldd bfxfc,y get transfer count
 cmpd #512 is it regular block transfer?
 beq cmiwr9 yes - normal write
 cmpd #CMI_FD special count for Format Disk command
 beq cmiwr1
 cmpd #CMI_FT special count for Format Track command
 lbne cmier bad I/O
 lda #CMIFTR set Format Track command
 bra cmirw go do operation
cmiwr1 lda #CMIFDR Format Drive command
 bra cmirw
cmiwr9 lda #CMIWRS set Write Sector
cmirw sta CMIcmd set up command
 lda #$41 set up IRQ
 ldb CMIcmd DMA required?
 cmpb #CMIFTR
 beq cmirw0
 cmpb #CMIFDR
 beq cmirw0
 ora #$20 set for DMA transfer
cmirw0 lbsr cmicn send command
 inc cmidt+dtbusy mark device busy
 rts
*
* take care of CMI swap request
*
cmiswp
 lda #4 set SWAP activity code
 sta cmidt+dtbusy
 ldd bfadr,y get swap table pointer
 std cmiswpt
 lda bfflag,y check direction
 bita #BFRWF Read/Write?
 beq cmisw0 jump for Write
 lda #CMIRDS set Read Sector opcode
 bra cmisw1
cmisw0 lda #CMIWRS Write Sector opcode
cmisw1 sta CMIcmd set up command
 ldb CMIlun set up block #
 orb bfblch,y
 stb CMIlun
 ldd bfblck,y
 std CMIadr
 lda #8 do 4K at a time
 sta CMIcnt
 bra cmisc2 go do operation
*
* cmisc - Continue SWAP request
*
cmisc0 ldd CMIadr update block address
 addd #8
 std CMIadr
 bcc cmisc1
 inc CMIlun
cmisc1 lda [cmiswpt] end of list?
 cmpa DSKTRM
 lbeq cmiin4 go to next request
*
*  set up and send SWAP command
*
cmisc2
 ldx cmiswpt pick up SWAP table pointer
 lda ,x+ get descriptor for next segment
 stx cmiswpt save new pointer
 cmpa DSKTRM end of list?
 lbeq cmiin4 yes - end of operation
 pshs a compute physical address
 lsra
 lsra
 lsra
 lsra
 sta CMIADR Set up DMA address
 puls a
 eora DATsense
 asla
 asla
 asla
 asla
 clrb
 std CMIADR+1
 lda #$61 set up for DMA/IRQ
 sta CMICMD
 if PRT_SWP
 bsr prt_cx
 endif
 ldx #CMIcmd send SWAP command
 lda #6
cmisw2 lbsr cmiwt wait for Xebec READY
 ldb ,x+ get next byte
 stb XBCCOM send to Xebec
 deca done?
 bne cmisw2
 rts all done
 if PRT_SWP
*
prt_cx pshs d,x,y,u
 ldx #00f
 jsr Pdata
 ldx cmiswpt
 lda ,-x
 jsr Phex
 ldx #CMIcmd
 ldb #6
0 lda ,x+
 jsr Phex
 jsr Pspace
 decb
 bne 0b
 puls d,x,y,u,pc
00 fcc $d,'CMI SWAP - Page: ',0
01 fcc ', Command: ',0
 endif
*
*  Interrupt handler for Xebec S1410 Controller
*
*
cmiint
 ldb CMICMD get status
 lbsr cmist0 get status
 bne cmier jump if error
 ldy cmidt+dtqfl get first transaction
 beq 99f jump if no transaction
 lda bfdvn+1,y check for CMI transaction
 cmpa #CMIminor
 blo 99f
 cmpa #CMIminor+3
 bhi 99f
 lda cmidt+dtbusy check for SWAP in progress
 beq 99f exit if no operation actually in progress
 cmpa #4
 lbeq cmisc0 continue SWAP
cmiin4 ldy cmidt+dtqfl get transaction
 beq 99f jump if no transaction
 clr cmidt+dtbusy set not busy
 ldx BDtable restore Block Device Table address
 jmp BDioend end of operation
*
99 rts *** Spontaneous interrupt ***

*
* error routine - give up forever
*
cmier0 leas 2,s clean up stack
cmier ldy cmidt+dtqfl get transaction
 beq 10f jump if none present
 lda bfflag,y get buffer flag
 ora #BFERR indicate failure
 sta bfflag,y stuff back in el flago
10 clr cmidt+dtbusy clear status
 bra cmiin4
 sttl CMI 5" Winchester Character Drivers
 pag

*
* Character drivers for cmi hard disk.
*

*
* open
*

cdcop cmpb #CMIminor+1 check for legal drive #
 bhi cdcop9 jump on error
 subb #CMIminor compute relative drive #
 clra
 tfr d,x
 tst cmiopt,x check open status
 bne cdcop2
 lda #8 assume ST-506 drive
 jsr cpy_DCT
cdcop2 inc cmiopt,x bump open count
 rts
cdcop9 lda #EBARG bad argument
 sta uerror
 rts


*
* close
*
cdccl jmp cmiclose same as block

*
*  ttyset/ttyget entry
*    ttyget - return most recent device status
*
cdcsp cmpx #0 ttyget?
 beq cdcsp4 no - do ttyset
cdcsp0 ldy #cmiesw
 lda #6
cdcsp1 ldb ,y+ pick up characters
 stb ,x+
 deca done?
 bne cdcsp1
 rts
cdcsp4 subb #CMIminor
 aslb
 ldy #cmidtyp
 ldy b,y
 lda #11 copy device table
 ldx usarg2 get table address
10 pshs y,a save registers
 jsr gtubyt get next byte
 puls a,y
 stb ,y+ place in table
 leax 1,x bump source pointer
 deca done?
 bne 10b
 ldd #$FFFF force reconfigure of controller
 std cmidrv
 rts

*
* read
*

cdcrd pshs d save device number
 jsr fchgb get buffer header
 puls d reset dev number
 bsr cdcnf go configure header
 tst uerror any errors?
 beq cdcrd4
 jsr frechbf release buffer
 rts error return
cdcrd4 pshs a save task info
 orb #BFRWF set read mode
 stb bfflag,y save in buffer
 bra cdcio go do it

*
* write
*

cdcwr pshs d save device number
 jsr fchgb get buffer header
 puls d
 bsr cdcnf configure buffer
 tst uerror any errors?
 beq cdcwr4
 jsr frechbf release buffer
 rts error return
cdcwr4 pshs a save task status

*
* do character io
*

cdcio jmp fchio same as floppies

*
* configure cmi character header
*

cdcnf std bfdvn,y set up device number
 ldd uicnt get transfer count
 std bfxfc,y set in header
 cmpd #512 is it valid?
 beq cdcnf0
 cmpd #CMI_FT special counts for Format
 beq cdcnf0
 cmpd #CMI_FD
 bne cdcerr error?
cdcnf0 jmp fchcn2 same as floppies

cdcerr lda #EIO set error
 sta uerror
 rts return
