; ******** BEGINNING of TELETEK HARD DISK CONTROLLER DRIVER *********** ; PC-DOS I/O Drivers for Teletek HDC Hard Disk Controller. ; Changed 6-2-85 by Don Tarbell for PC-DOS. ; Last changed 10-25-85 by Don Tarbell. ; Teletek controller constants ioport equ 30h ; base i/o port. status equ ioport+0 ; read = get controller status reset equ ioport+0 ; write = reset controller. hdata equ ioport+1 ; rd/wt = get/put controller FIFO data. intrupt equ ioport+2 ; write = interrput controller. clear equ ioport+3 ; write = clear interrupt from controller. ncdbyts equ 7 ; number of command bytes. ninbyts equ 16 ; number of initialization bytes. nerbyts equ 26 ; number of error bytes. ; status port bits. request equ 80h ; controller requests service from bus master. busy equ 40h ; a command is in progress on the controller. ready equ 20h ; controller is ready for service by master. error equ 10h ; errors have occurred on the controller. ; commands. cclrbf equ 04h ; clear hd/ctc buffers. dmaread equ 4ah ; read a record (logical sector). dmawrit equ 4bh ; write a record (logical sector). ; misc. rtcnt equ 10 ; retry count. ; bios stack area. tmpsp dw 40 DUP(?) ; 20 levels. tmp_tos label word ; top of stack. ; Teletek HD/CTC Initialization Data. initdat db 0 ; interrupt vector. db 00000000b ; options (verify, phsy trk, deblocking) db 1 ; number of physical drives on line. incyl dw 100 ; number of cylinders per drive. inhpc db 2 ; number of heads (tracks per cylinder). inbps dw 512 ; number of bytes per logical sector. db 00 ; setp rate delay constant. db 0 ; step rate in milliseconds. inhd db 0f8h ; cylinder settling delay constant. db 5 ; cylinder settling time, in ms. db 0 ; reserved. db 0 ; reserved. inwlc dw 50 ; low current boundry cylinder. ; Command buffer. mwop db 0 ; command byte. option db 1 ; options byte. hrddsk db 0 ; drive number. cylind dw 0 ; cylinder. mwhead db 0 ; head. mwsectr db 0 ; sector. ; Teletek hard disk controller messages. msg1 db cr,lf,'Load Aborted -- ',0 msg3 db 'HD/CTC Board Does Not Respond.',cr,lf,0 msg4 db 'HD/CTC Board Failed Self Test.',cr,lf,0 msg5 db 'Check Hard Disk Drive(s).',cr,lf,0 opnmsg db cr,lf,'Teletek Hard Disk Controller' db cr,lf,'Driver of 10-25-85' db cr,lf,'Copyright (c) 1985 Tarbell Electronics' db cr,lf,cr,lf,0 errbuf db nerbyts dup(?) ; error buffer. ; local scratch storage. twtab dw 4 dup(?) ; track table. ; hard disk parameter table (read from disk). twptab equ $ ; starting address. twbps dw 512 ; bytes per sector. twspa db 2 ; sectors per allocation unit. twnrs dw ? ; number of reserved sectors. db 2 ; number of fat's. twnde dw ? ; number of directory entries. twtns dw ? ; total number of sectors. db 0f8h ; hard disk media descriptor. twnsf dw ? ; number of sectors for each fat. twspt dw 16 ; sectors per track. twhpc dw ? ; number of heads. twhidn dw ? ; number of hidden sectors. dw 5 dup(?) ; reserved for ibm. twcyl dw ? ; number of cylinders. twwpc dw ? ; cylinder to start write precomp. twwlc dw ? ; cylinder to start write low current. twsd dw ? ; step delay. twrsd dw ? ; recalibrate step delay. twhd dw ? ; head settle delay. twss dw 3 ; sector size code (3 shown for 512). twdrv db 32 dup(?) ; place for drive manufact. and model. dw 5 dup(?) ; reserved for Tarbell additions. dw 5 dup(?) ; reserved for Dealer additions. dw 5 dup(?) ; reserved for end user additions. twptabe equ $ ; end of table marker. twbuf db 512 dup(?) ; 512-byte buffer. ; ; Initialize Teletek Hard disk interface. ; mapper proc near cld mov si,offset opnmsg ; print opening message. call prtmsg call twreset ; reset controller. ; read sector 0, head 0, cylinder 0, drive 0. mov ah,1 ; ah = read code. mov cl,0 ; cl = drive number. push ds ; es = ds. pop es mov di,offset twbuf ; es:di = buffer address. mov bx,0 ; bx = cylinder 0. mov dx,0 ; dx = sector 0. call findalt ; read the sector. ; transfer parameters to local table. mov di,offset twptab ; destination = twptab. mov si,offset twbuf+11 ; source = first useful buffer stuff. mov cx,offset twptabe-twptab ; cx = length of table. rep movsb ; move the parameters. ; move some parameters from local table to initialization buffer. mov ax,twcyl ; incyl = twcyl (number of cyliders). mov incyl,ax mov ax,twhpc ; inhpc = twhpc (number of heads). mov inhpc,al mov ax,twwlc ; inwlc = twwlc (low wrt current cyl). mov inwlc,ax mov ax,twhd ; inhd = twhd (head settle delay). mov word ptr inhd,ax ; print drive manufacturer and model number and reset again. mov si,offset twdrv ; di = mfr and model string. call prtmsg ; print it. call twreset ; reset controller using new values. mov si,offset twbuf ; return address of buffer. ret mapper endp ; Common Teletek hard disk read/write routine. ; Transfers one sector only. ; Entry: ah = 1 for read, 2 for write. ; cl = drive number ; es:di = transfer address. ; bx = cylinder number. ; dx = sector number. findalt proc near cld ; set auto = increment. ; put parameters into command buffer. mov al,dmaread ; al = code for read. cmp ah,1 ; is it a read? je setcmd ; hop if so. mov al,dmawrit ; al = code for write. setcmd: mov mwop,al ; put command into buffer. mov hrddsk,cl ; hrddsk = physical drive number. mov cylind,bx ; cylind = cylinder number. mov ax,dx ; ax = sector requested. mov bl,byte ptr twspt ; bl = sectors per track. div bl ; dx = head number, ax = sector. mov mwhead,al ; mwhead = physical head number. mov mwsectr,ah ; mwsectr = physical sector number. rwsect: mov al,rtcnt ;get number of retries. mov byte ptr ercnt,al retry: call mwrdwr ; read or write a sector. mov al,0 jc l_3 ; hop if error. ret ; return. l_3: dec ercnt ; decrement error count. jnz retry stc ; set carry for error return. ret ; return with error. ; ; reset the controller and setup the default parameters. ; twreset: out reset,al ;send reset pulse to controller. out clear,al ; clear any pending ctlr interrupt. in al,status ; release the reset signal. call hdelay ; delay at least 40 microseconds. ; verify that controller request signal is off. mov bx,0 move3: in al,status ; get status byte. test al,request ; check request signal. jz move4 ; until request signal turned off. dec bx jnz move3 ; or until waited long enough. ; if request signal never turned off. mov si,offset msg1 ; print "Load Aborted' call prtmsg mov si,offset msg3 ; print "HD/CTC Board Does Not Resp." call prtmsg jmp mwierr ; abort. ; request signal has turned off. move4: mov ch,busy ; set up mask byte in ch. or ch,ready mov bx,0 ; bx = time-out counter. move5: in al,status ; get status byte. and al,ch ; mask out request and error bits. cmp al,ch ; see if both busy and ready high. jz move6 ; exit if both are high. dec bx jnz move5 ; or until waited long enough. ; if never got busy and ready together. mov si,offset msg1 ; print "load aborted". call prtmsg mov si,offset msg3 ; print "HD/CTC does not respond". call prtmsg jmp mwierr ; abort. ; if got busy and ready together. move6: in al,status ; if controller error. test al,error jz move7 ; then mov si,offset msg1 ; print "Load aborted". call prtmsg mov si,offset msg4 ; print "HD/CTC failed self-test". call prtmsg jmp mwierr ; abort. ; no controller error. move7: in al,hdata ; read firmware version letter. mov si,offset initdat ; point to initialization data. mov cx,ninbyts ; number bytes initialization data. movel: lodsb ; al = byte of init data. out hdata,al ; send init data to controller. loop movel ; decrement cx, loop if not zero. mov al,0 ; this isn't documented. out intrupt,al ; interrupt controller. call wait ; wait for controller request. ; check for controller error. in al,status ; if controller error, test al,error jz move9 ; then mov si,offset msg1 ; print "load aborted". call prtmsg call geterr ; get error bytes from controller. mov si,offset msg5 ; print "check drives". call prtmsg jmp mwierr ; abort. ; if no errors. move9: mov al,0 ; works better. out intrupt,al ; interrupt controller. ret ; return from mwreset. ; do the operation specified by mwop. mwrdwr: call cmndphas ; do command phase. mov al,1 ; i/o direction = in. cmp mwop,dmaread ; is it a read operation? je mwtran ; hop if so. mov al,0 ; else i/o direction = out. mwtran: call dataphas ; transfer data. call statphas ; check for any errors. cmp al,0 ; were there any errors? je mwiret ; return if not. mwierr: stc ; set carry for error indicator. mwiret: ret ;return no error (carry reset). ; Wait for request. wait: in al,status ; get unit status. test al,request ; test request bit. jz wait ; until request comes in. out clear,al ; clear the request line. ret ; Command Phase. cmndphas: cmnd1: in al,status test al,busy ; is it busy? jnz cmnd1 ; poll for not busy. test al,ready ; is it ready? jz cmnd1 ; poll for ready. mov cx,ncdbyts ; cx = number of command bytes. mov si,offset mwop ; si = command buffer address. cmndlp: lodsb ; al = command byte. out hdata,al ; send to controller. loop cmndlp ; dec cx, loop till zero. mov al,0 ; let's try this. out intrupt,al ; interrupt the controller. call wait ; wait for controller request. ret ; Data Phase. dataphas: push ax ; save i/o direction. in al,status ; al = status. test al,error ; any errors? jz data1 ; hop if not. pop ax ; correct stack. ret ; abort data phase. data1: mov al,0 ; other things don't always work. out intrupt,al ; interrupt the controller. data2: in al,status ; al = status. test al,ready ; is it ready? jz data2 ; wait till it is. pop ax ; ax = 0 for write, else read. mov cx,512 ; cx = byte count for transfer. cmp al,0 ; is it a write? je mwrite ; hop if so. ; transfer 512 bytes from controller to es:di. mwread: in al,hdata ; al = a data byte. mov es:[di],al ; put byte into buffer. inc di ; bump buffer pointer. jnz mwr1 ; hop if no overflow. mov bx,es ; else increment segment by 64k. add bx,1000h mov es,bx mwr1: loop mwread ; dec cx, loop until zero. jmp mwexit ; exit routine. ; transfer 512 bytes from es:di to controller. mwrite: mov al,es:[di] ; al = byte from buffer. inc di ; bump buffer pointer. jnz mwr2 ; hop if no overflow. mov bx,es ; else increment segment by 64k. add bx,1000h mov es,bx mwr2: out hdata,al ; put byte into controller. loop mwrite ; dec cx, loop until zero. ; stop controller and wait for next request. mwexit: mov al,0 ; we tried lots of things. out intrupt,al ; interrupt controller. call wait ; wait for request and reset. ret ; status phase. ; exit with al = 0 if no errors. statphas: in al,status ; al = status. test al,error ; look at error bits. mov al,0 jz stat2 ; hop if no errors. call geterr ; get error bytes from controller. mov al,errbuf ; al = first byte. test al,1 ; if fatal errors. mov al,1 ; then set error flag. jnz stat1 ; else xor al,al ; reset error flag. stat1: stat2: mov al,0 ; other things can act wierd. out intrupt,al ; interrupt the controller. ret ; geterr - get error code bits. geterr: mov al,0 out intrupt,al ; interrupt the controller. geter1: in al,status ; al = status. test al,ready ; poll-wait for controller ready. jz geter1 ; loop until ready. mov bx,offset errbuf ; bx = error buffer adr. mov cx,nerbyts ; cx = number of error bytes. geterl: in al,hdata ; al = error code byte. mov [bx],al ; put into buffer. inc bx ; bump buffer pointer. loop geterl ; dec cx, loop till zero. ret ; delay. hdelay: push cx ; save cx. mov cx,128 ; initialize counter. hdloop: loop hdloop ; decrement cx till zero. pop cx ; restore cx. ret findalt endp ; ************ END OF TELETEK HDC HARD DISK DRIVER ***************