 lib environment
 lib bfhdr
 lib dtab
 lib macdefs
 data
 sttl SASI 5" Winchester Drivers
 pag
 name windrvr
 global winint,windvn,winclose,winopen,winsto
 global wincop,winccl,wincsp,wincio,wincrd,wincwr

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

*
* SASI 5" Winchester drivers
*

*
* driver equates and addresses
*
SASITDR equ $00 Test Drive Ready
SASIREC equ $01 Recalibrate (reseek to 0)
SASIRSS equ $03 Request Sense Status
SASIFDR equ $04 Format Drive
SASIFTR equ $06 Format Track
SASIRDS equ $08 Read Sector
SASIWRS equ $0A Write Sector
SASIIDC equ $0C Initialize Drive Characteristics
OMTIIDC equ $C2 OMTI Assign disk parameters
SASIRDG equ $E0 Internal RAM Diagnostic
SASIDDG equ $E3 Drive Diagnostic
SASICID equ $E4 Controller Internal Diagnostic
SASI_FD equ 17 Format Drive (special count)
SASI_FT equ 17*2 Format Track

*
* Interleave factors for different controllers
*
OMTI_ILF  equ 2
XEBEC_ILF equ 8
*
winesw fdb 0 SASI Error Status Word
winsbf rzb 4 SASI Sense Status Buffer
winirs fcb 0 SASI Controller RESET
winopt fcb 0,0 win open table
windtyp fdb win_DC0,win_DC1 drive characteristics tables
win_DC0 rzb 11 Drive Characteristics tables
win_DC1 rzb 11
win_DCn fcb $ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff,$ff
winotyp fdb win_DCn previous drive type
windrv fdb $FFFF current drive select for SASI
wintmp fcb 0 space to "read" device size
winsdn fdb 0 saved device #
BDtable fdb 0 Block Device Table address
winswpt fdb 0 swap table pointer
*
win_omti fcb 0 XEBEC/OMTI controller flag
*
*  SASI Command Block (DCB)
*
SASIcmd fcb 0 Xebec S1410 Command
SASIlun fcb 0 Drive Select
SASIadr fcb 0,0 Sector Address
SASIcnt fcb 0 Sector Count
SASIctl fcb 0 Control Flags
*
* disk controller definitions
*
SASIBSY equ %00001000
SASIREQ equ %00000001 Controller Request Data

*
* Device parameters control block - OMTI 20C Controller
*
DP_TABLE  equ *
DP_width  fcb 0 Step Pulse Width
DP_period fcb 0 Time between pulses
DP_mode   fcb 0 Stepping mode (0->buffered)
DP_heads  fcb 0 Number of heads (-1)
DP_cyls   fdb 0 Number of cylinders (-1)
DP_wsi    fcb 0 Write Precomp cylinder
DP_type   fcb 0 Drive type
DP_sectrk fcb 0 Sectors/Track
          fcb 0 ** Filler **
*
* Seek table - Used to translate Xebec seeks to OMTI
*
seek_tbl equ *
 fcb $09,$3C 0
 fcb $09,$3C 1
 fcb $09,$3C 2
 fcb $09,$3C 3
 fcb $02,$04 4
 fcb $02,$00 5
 fcb $02,$00 6
 fcb $02,$00 7

*
* Test for XEBEC/OMTI controller
*
 global win_test
win_test
 lda #SASICID run Controller Diagnostic
 sta SASIcmd
 lda #1 no IRQ/DMA
 lbsr wincn
 lbsr winst
 beq 99f if no error, assume XEBEC controller
 lda #1
 sta win_omti
 sta unidt set flag for FORMAT
99 rts

*
* open the win disk drive - insure the device is online, etc.
*
winopen
 std winsdn save device #
 lbsr windvn drive select
 tst winopt,x already open?
 beq winop1 no - go do open
 inc winopt,x yes - bump open count
 lbra winrts all done
winop1 inc winopt,x set open status
 lda #8 set up default device characteristics = ST-506
 ldb winsdn+1
 subb #WINminor
 lbsr cpy_DCT
 pshs x save device offset
 ldx #1 read SIR
 ldy #0
 ldd winsdn restore device #
 lda #WINmajor make sure block read
 jsr rdbuf
 lda bfflag,y get flags
 bita #BFERR error?
 bne winop8 yes - return error
 pshs y save buffer pointer
 ldx 0,s get buffer header
 ldy #wintmp no - read drive type
 ldu #sdenf from "density" byte in SIR
 ldd #1
 jsr cpybts
 lda wintmp check for DCT index/data in SIR
 cmpa #$FF
 bne 10f
 ldx 0,s it is - read actual table from SIR
 ldd winsdn compute table address
 subb #WINminor
 aslb
 ldy #windtyp
 ldy b,y
 ldu #swinc
 ldd #11
 jsr cpybts
 bra 20f
10 lda wintmp pick up size field
 cmpa #MAXDCT legal DCT index?
 bls 15f yes - jump (OK)
 lda #8 no - assume ST-506
15 ldb winsdn+1 compute table address
 subb #WINminor
 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 windrv
 rts device opened OK
winop8 jsr freebf release buffer
 puls x restore device index
winop9 lda #EIO indicate device offline
 sta uerror stuff into user error flag
 clr winopt,x clear open status
winrts 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 #windtyp
 ldy b,y
 ldu winotyp 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 windrv
 puls d,x,y,u,pc return

*
*  Set up controller - XEBEC SA1410
*
winidc tst win_omti using OMTI controller?
 lbne omtiidc
 pshs d,x,y save registers
 cmpx windrv same drive as last operation?
 lbeq winid9 yes - exit
 tfr x,d -- compute table index
 leay d,x 2*X
 ldy windtyp,y
 pshs y save it
 ldx winotyp 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 winid9 exit - no need to reconfigure
15 ldy 0,s no match - copy table
 ldx winotyp
 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 X_prt_dct
 endif
 lda 8,y set up control byte = seek rate/imbedded servo info
 anda #$0F
 ora 9,y
 sta SASIctl
 lda #SASIIDC Initialize Drive Characteristics
 sta SASIcmd
 lda #1 no DMA/IRQ
 lbsr wincn send command
winid2 lbsr winwt wait for READY
 bitb #$14 wait for REQ=1, I/O=0, C/D=0
 bne winid2
 puls x restore device characteristics table
 lda #8
winid3 lbsr winwt wait for READY
 ldb ,x+
 stb SASI_DATA
 deca done?
 bne winid3
 lbsr winst wait for end of command and check status
 beq winid9
 pshs d,x
 ldx #00f
 jsr Pdata
 lda winsbf get error code
 jsr Phex
 bra 99f
00 fcc $d,'XEBEC Error on IDC: ',0
99 puls d,x
winid9
 ldx 2,s restore drive index
 stx windrv no - remember drive #
 puls d,x,y,pc
 if PRT_DCT
*
X_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

*
*  Set up controller
*
omtiidc pshs d,x,y save registers
 cmpx windrv same drive as last operation?
 lbeq omtiid9 yes - exit
 tfr x,d -- compute table index
 leay d,x 2*X
 ldy windtyp,y
 pshs y save it
 ldx winotyp 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 omtiid9 exit - no need to reconfigure
15 ldy 0,s no match - copy table
 ldx winotyp
 ldb #11
17 lda ,y+
 sta ,x+
 decb
 bne 17b
*-- Reformat info for OMTI Assign Disk Parameters command
 puls y restore table address
 ldd ,y++ get # cylinders
 subd #1
 std DP_cyls
 lda ,y+ get # heads
 deca
 sta DP_heads
 ldd ,y++ Reduced write
 ldd ,y++ Write precomp
 anda #$03
 stb DP_wsi
 sta DP_type
 tst ,y+ skip burst length
 lda ,y+ get seek rate
 anda #$07
 lsla
 ldx #seek_tbl
 leax a,x
 lda ,x+
 sta DP_width
 lda ,x+
 sta DP_period
 lda ,y+ get imbedded servo indicator
 beq 18f
 lda #%00110000
 ora DP_type
 sta DP_type
18
 if PRT_DCT
 ldx 2,s restore original drive #
 bsr O_prt_dct
 endif
 lda #OMTIIDC Initialize Drive Characteristics
 sta SASIcmd
 lda #1 no DMA/IRQ
 lbsr wincn send command
omtiid2 lbsr winwt wait for READY
 bitb #$14 wait for REQ=1, I/O=0, C/D=0
 bne omtiid2
 lda #10
 ldx #DP_TABLE
omtiid3 lbsr winwt wait for READY
 ldb ,x+
 stb SASI_DATA
 deca done?
 bne omtiid3
 lbsr winst wait for end of command and check status
 beq omtiid9
 pshs d,x
 ldx #00f
 jsr Pdata
 lda winsbf get error code
 jsr Phex
 bra 99f
00 fcc $d,'SASI Error on IDC: ',0
99 puls d,x
omtiid9
 ldx 2,s restore drive index
 stx windrv no - remember drive #
 puls d,x,y,pc
 if PRT_DCT
*
O_prt_dct pshs d,x,y,u
 ldx #00f
 jsr Pdata
 lda 2+1,s
 jsr Phex
 ldx #01f
 jsr Pdata
 ldb #10
 ldy #DP_TABLE
0 lda ,y+
 jsr Phex
 jsr Pspace
 decb
 bne 0b
 puls d,x,y,u,pc
00 fcc $d,'OMTI DCT - Unit: ',0
01 fcc ', Table: ',0
 endif

*
* win close
*
winclose
 bsr windvn set up drive
 dec winopt,x clear open status
 bpl wincl0
 clr winopt,x
wincl0
 rts return
*
* windvn - select SASI drive
*   (B) - minor device #
*   return with (X) - device index
*
windvn
 cmpb #WINminor+1 check device number
 lbhi winer0 go set error
 subb #WINminor compute relative drive #
 clra set up device index
 tfr d,x
 rts
*
* windvnx - select SASI drive & set up LUN in command
*   (B) - minor device #
*   return with (X) - device index
*
windvnx bsr windvn set up registers
 tstb
 beq windv0
 ldb #$20 select drive #1
windv0 stb SASIlun set command byte
 rts
*
* wincn - set up SASI command and send to Xebec
*    A - DMA/IRQ select mask
*
wincn pshs d
 tst winirs Has interface been RESET?
 bne wincn0 yes - don't do it again
 lda #$80 no - send RESET code
 sta SASI_CSR
 clr SASI_CSR
 inc winirs
wincn0
 lda 0,s restore DMA/IRQ mask
 bita #$60 test DMA/IRQ bits
 beq wincn1
 ldb SASIlun
 orb bfblch,y set up block #
 stb SASIlun
 ldd bfblck,y
 std SASIadr
 lda bfxadr,y get memory address
 sta SASI_ADR
 ldd bfadr,y
 std SASI_ADR+1
 bra wincn2
wincn1 ldd #0 clean up DCB
 std SASIadr
 sta SASIcnt
wincn2 lda 0,s restore DMA/IRQ mask
 sta SASI_CSR set up DMA/IRQ selection
 ldb #XEBEC_ILF block count (interleave factor)
 tst win_omti is this an OMTI controller?
 beq 00f
 ldb #OMTI_ILF yes - use interleave for OMTI
00 lda SASIcmd test for Format Command
 cmpa #SASIFDR
 beq wincn3
 cmpa #SASIFTR Format Track
 beq wincn3
 ldb #1 set block count
wincn3 stb SASIcnt
 ldx #SASIcmd set up to send command
 lda #6 send 6 bytes
wincn4 lbsr winwt wait for READY
 ldb ,x+ get next byte
 stb SASI_DATA send to controller
 deca done?
 bne wincn4
 puls d,pc
*
* winst - wait for operation complete & get status
*
winst
 lda SASI_CSR wait for command completion
 bpl winst
winst0
 lbsr winwt get command status
 lda SASI_DATA
 pshs a
 lbsr winwt
 ldb SASI_DATA
 puls a
 bita #2 error bit set?
 beq winst9 no - exit
 std winesw save error status word
 lda #SASIRSS Request Sense Status
 sta SASIcmd
 lda #1 no DMA/IRQ
 lbsr wincn send command
 ldx #winsbf Sense Buffer
 lda #4
winst1 bsr winwt wait for READY
 ldb SASI_DATA get data
 stb ,x+
 deca done?
 bne winst1
 lbsr winwt get command status
 lda SASI_DATA
 lbsr winwt
 ldb SASI_DATA
 if PRT_ERR
 bsr rpt_err
 endif
 lda winsbf check for soft errors
 anda #$7F
 cmpa #$18 ECC Correctable error code
winst9 rts return
 if PRT_ERR
*
rpt_err pshs d,x,y,u
 ldx #00f
 jsr Pdata
 ldx #winsbf
 ldb #4
0 lda ,x+
 jsr Phex
 jsr Pspace
 decb
 bne 0b
 puls d,x,y,u,pc
00 fcc $d,'SASI Error: ',0
 endif
*
*  Wait for Xebec to request data
*
winwt ldb SASI_CSR test READY
 bitb #1
 beq winwt 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,'SASI I/O, Device = ',0
01 fcc ', Flags = ',0
02 fcc ', Block = ',0
 endif
*
* fire up SASI operation to initiate transfer
*
winsto stx BDtable
 if PRT_REQ
 bsr prt_bh print buffer header
 endif
 ldb bfdvn+1,y get drive #
 lbsr windvnx select drive
 lbsr winidc set up device characteristics if needed
 lda bfblch,y check block number range
 cmpa #$0f
 lbhi winer 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 winswp
 ldb bfflag,y get buffer flags
 bitb #BFRWF are we reading?
 beq winwrt go do write
 lda #SASIRDS set Read Sector Command
 bra winrw go perform I/O
*
* set up for write command
*
winwrt bitb #BFSPC special i/o
 beq winwr9 jump if write
 ldd bfxfc,y get transfer count
 cmpd #512 is it regular block transfer?
 beq winwr9 yes - normal write
 cmpd #SASI_FD special count for Format Disk command
 beq winwr1
 cmpd #SASI_FT special count for Format Track command
 lbne winer bad I/O
 lda #SASIFTR set Format Track command
 bra winrw go do operation
winwr1 lda #SASIFDR Format Drive command
 bra winrw
winwr9 lda #SASIWRS set Write Sector
winrw sta SASIcmd set up command
 lda #$41 set up IRQ
 ldb SASIcmd DMA required?
 cmpb #SASIFTR
 beq winrw0
 cmpb #SASIFDR
 beq winrw0
 ora #$20 set for DMA transfer
winrw0 lbsr wincn send command
 inc windt+dtbusy mark device busy
 rts
*
* take care of SASI swap request
*
winswp
 lda #4 set SWAP activity code
 sta windt+dtbusy
 ldd bfadr,y get swap table pointer
 std winswpt
 lda bfflag,y check direction
 bita #BFRWF Read/Write?
 beq winsw0 jump for Write
 lda #SASIRDS set Read Sector opcode
 bra winsw1
winsw0 lda #SASIWRS Write Sector opcode
winsw1 sta SASIcmd set up command
 ldb SASIlun set up block #
 orb bfblch,y
 stb SASIlun
 ldd bfblck,y
 std SASIadr
 lda #8 do 4K at a time
 sta SASIcnt
 bra winsc2 go do operation
*
* winsc - Continue SWAP request
*
winsc0 ldd SASIadr update block address
 addd #8
 std SASIadr
 bcc winsc1
 inc SASIlun
winsc1 lda [winswpt] end of list?
 cmpa DSKTRM
 lbeq winin4 go to next request
*
*  set up and send SWAP command
*
winsc2
 ldx winswpt pick up SWAP table pointer
 lda ,x+ get descriptor for next segment
 stx winswpt save new pointer
 cmpa DSKTRM end of list?
 lbeq winin4 yes - end of operation
 pshs a compute physical address
 lsra
 lsra
 lsra
 lsra
 sta SASI_ADR Set up DMA address
 puls a
 eora DATsense
 asla
 asla
 asla
 asla
 clrb
 std SASI_ADR+1
 lda #$61 set up for DMA/IRQ
 sta SASI_CSR
 if PRT_SWP
 bsr prt_cx
 endif
 ldx #SASIcmd send SWAP command
 lda #6
winsw2 lbsr winwt wait for Xebec READY
 ldb ,x+ get next byte
 stb SASI_DATA send to Xebec
 deca done?
 bne winsw2
 rts all done
 if PRT_SWP
*
prt_cx pshs d,x,y,u
 ldx #00f
 jsr Pdata
 ldx winswpt
 lda ,-x
 jsr Phex
 ldx #SASIcmd
 ldb #6
0 lda ,x+
 jsr Phex
 jsr Pspace
 decb
 bne 0b
 puls d,x,y,u,pc
00 fcc $d,'SASI SWAP - Page: ',0
01 fcc ', Command: ',0
 endif
*
*  Interrupt handler for Xebec S1410 Controller
*
*
winint
 ldb SASI_CSR get status
 lbsr winst0 get status
 bne winer jump if error
 ldy windt+dtqfl get first transaction
 beq 99f jump if no transaction
 lda bfdvn+1,y check for SASI transaction
 cmpa #WINminor
 blo 99f
 cmpa #WINminor+3
 bhi 99f
 lda windt+dtbusy check for SWAP in progress
 beq 99f exit if no operation actually in progress
 cmpa #4
 lbeq winsc0 continue SWAP
winin4 ldy windt+dtqfl get transaction
 beq 99f jump if no transaction
 clr windt+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
*
winer0 leas 2,s clean up stack
winer ldy windt+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 windt+dtbusy clear status
 bra winin4
 sttl SASI 5" Winchester Character Drivers
 pag

*
* Character drivers for win hard disk.
*

*
* open
*

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


*
* close
*
winccl jmp winclose same as block

*
*  ttyset/ttyget entry
*    ttyget - return most recent device status
*
wincsp cmpx #0 ttyget?
 beq wincsp4 no - do ttyset
wincsp0 ldy #winesw
 lda #6
wincsp1 ldb ,y+ pick up characters
 stb ,x+
 deca done?
 bne wincsp1
 rts
wincsp4 subb #WINminor
 aslb
 ldy #windtyp
 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 windrv
 rts

*
* read
*

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

*
* write
*

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

*
* do character io
*

wincio jmp fchio same as floppies

*
* configure win character header
*

wincnf std bfdvn,y set up device number
 ldd uicnt get transfer count
 std bfxfc,y set in header
 cmpd #512 is it valid?
 beq wincnf0
 cmpd #SASI_FT special counts for Format
 beq wincnf0
 cmpd #SASI_FD
 bne wincerr error?
wincnf0 jmp fchcn2 same as floppies

wincerr lda #EIO set error
 sta uerror
 rts return
