page ,132 .lall ; TFORMAT - Format hard disk drive with Teletek Controller. ; Created 3-31-85 by Don Tarbell. ; Changed 5-1-85 by Don Tarbell for more than one drive. ; Changed 9-3-85 by Don Tarbell to run on PC-DOS. ; 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. data 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 equ's. cr equ 0dh ; carriage-return. lf equ 0ah ; line-feed. dos equ 21h ; pc-dos function call interrupt. ; ************ stack area ************ stack segment para stack 'stack' db 10 dup('stack') stack ends ; *********** end of stack area ****** ; ************** working area ********************* workarea segment ; Messages. openmsg db cr,lf,cr,lf db cr,lf,' Teletek Hard Disk Controller Format Program' db cr,lf,' Copyright (c) 1985 by Tarbell Electronics' db cr,lf,' Last changed 9-2-85' db cr,lf db cr,lf,' No. Manufacturer and Model No.' db cr,lf,' -- --------------------------------------' db cr,lf,0 nitmsg db cr,lf db cr,lf,'Entry not in table.' db cr,lf,0 formsg db cr,lf db cr,lf,'Formatting ',0 eofmsg db cr,lf db cr,lf,'End of Formatting Operation' db cr,lf,0 keymsg db cr,lf,'WARNING: This program erases the hard disk.' db cr,lf db cr,lf,'Enter a number, or period (.) to exit: ',0 exmsg db cr,lf db cr,lf,'Exiting back to operating system...' db cr,lf,0 ; bios stack area. tmpsp dw 0 dw 40 dup(?) ; 20 levels. tmp_tos dw 0 ; 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. cyl dw ? ; number of cylinders per drive. heads db ? ; number of heads (tracks per cylinder). dw 512 ; number of bytes per logical sector. stepdly dw ? ; step rate delay. db 0f8h ; cylinder settling delay constant. headdly db ? ; cylinder settling delay (in ms). db 0 ; reserved. db 0 ; reserved. lowcurr dw ? ; low current boundry cylinder. ; Keyboard buffer. keybuf db 5,0,0,0,0,0,0 ; Command buffer. mwop db 0 ; command byte. option db 0 ; 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 errbuf db nerbyts dup(?) ; error buffer. yes db 'YES' ; data to send for format operation. ; these flags control the hard disk drivers. mvdat db 0 ; move data flag. cerr db 0 ; offset strobe mask. chkmsk db 0 ; offset head number. chghd db 0 ; head change flag. mapptr dw 0 ; map buffer index. mapbuf db 80h ; must be 80h for first access. db 40h dup(?) ; space just in case. mwtab dw 4 dup(?) ; track table. ; Hard disk drive characteristic table. ; Each hard disk has an entry of 7 fields: ; 1. Manufacturer ; 2. Model Number ; 3. Number of cylinders ; 4. Cylinder to reduce write current. ; 5. Number of heads. ; 6. Step delay (2 bytes - see manual) ; 7. Head settle delay (in milliseconds) hdctab db 'Computer Memories, Inc.',0,'CMI-19',0 dw 306,128 ; cylinders, low current cylinder. db 6,0f8h,5,2 ; heads, step delay, settle delay. db 'Rotating Memory Systems',0,'RMS-12',0 dw 156,77 db 8,0f8h,5,2 db 'Miniscribe',0,'3012',0 dw 612,77 db 2,0,0,1 db 'Rodime',0,'20',0 dw 320,132 db 6,0,0,1 db 'Atasi',0,'33',0 dw 512,0 db 8,0,0,1 db 'Quantum',0,'540',0 dw 512,128 db 8,0,0,1 db 'Otari',0,'C-519',0 dw 306,0 db 6,0,0,1 dw 0 ; end of hard disk characteristic table. workarea ends ; *************** end of work area ******************* ; *********** code area ************** cseg segment para public 'code' ; START - Main program starts here. start proc far assume cs:cseg, ds:workarea, ss:stack, es:nothing ; set segment registers. push ds ; save return segment adr. mov ax,0 ; put zero onto stack. push ax mov ax,workarea ; ds = work area. mov ds,ax ; print opening message and table. mov si,offset openmsg ; si = opening message offset. call prtmsg ; print it. mov si,offset hdctab ; si = hard disk char. table offset. mov cl,1 ; initialize counter = 1. loop: call prtspc ; print 2 spaces. call prtbcd ; print bcd number in cl. call prtspc ; print 2 spaces. call prtmsg ; print manufacturer. call prtspc ; print 2 spaces. call prtmsg ; print model number. call crlf ; print carriage-return/line-feed. mov al,cl ; increment counter. add al,1 daa mov cl,al add si,8 ; si = offset of next entry. cmp word ptr [si],0 ; are we at end of table? jne loop ; loop back for next one if not. ; get selection from keyboard. getstr: mov si,offset keymsg ; print keyboard input message. call prtmsg mov dx,offset keybuf ; dx = keyboard buffer offset. mov ah,0ah ; ah = buffered keyboard input code. push ds ; save data segment. int dos ; read string from keyboard. pop ds ; restore data segment. ; convert selection in keyboard buffer to binary. cld ; direction = increment. mov si,offset keybuf+1 ; si = keyboard buffer offset. mov cl,[si] ; cl = number of characters entered. cmp cl,0 ; were there any characters? jne get1 ; hop if so. mov si,offset nitmsg ; print not-in-table message. call prtmsg jmp getstr ; read string from keybaord again. get1: cld inc si ; si = first character offset. lodsb ; al = first character. cmp al,'.' ; was it a period? je exit ; exit if so. sub al,30h ; al = binary number from 0-9. dec cl ; decrement character counter. jz got ; hop if zero. got: ; find offset of entry selected (in al). cld ; direction = increment. mov cl,al ; cx = entry number. mov si,offset hdctab ; si = start of table. loop2: dec cl ; are we there yet? jz there ; hop out if so. cmp word ptr [si],0 ; end of table? je endtab ; hop out if so. loop3: lodsb ; al = character. cmp al,0 ; is it a zero? jne loop3 ; loop if not. loop4: lodsb ; al = character. cmp al,0 ; is it a zero? jne loop4 ; loop if not. add si,8 ; move to next entry. jmp loop2 ; loop until found. ; exit from format program. exit: mov si,offset exmsg ; print exit message. call prtmsg jmp endprog ; exit with return. ; end of table reached, must not be in there. endtab: mov si,offset nitmsg ; not-in-table message. call prtmsg jmp start ; print formatting [manufacturer] [model number]. there: push si ; save string pointer. mov si,offset formsg ; formatting message. call prtmsg pop si ; restore string pointer. call prtmsg ; print manufacturer. call prtspc ; print spaces. call prtmsg ; print model number. call crlf ; print crlf. ; transfer characteristics into work area. cld lodsw ; ax = number of cylinders. mov cyl,ax lodsw ; ax = low current cylinder. mov lowcurr,ax lodsb ; al = number of heads. mov heads,al lodsw ; ax = step rate delay. mov stepdly,ax lodsb ; al = head settle delay. mov headdly,al ; format the disk. cld ; set auto to increment. call mwreset ; reset controller. jc start2 ; hop if error. mov mwop,47h ; operation = format. mov option,1 mov hrddsk,0 ; drive = 0. mov cx,3 ; 3 bytes in command. call cmndphas ; send the command. jc start2 ; hop if error. mov al,0 ; al = code for write. call dataphas ; send "YES" to controller. jc start2 ; hop if error. call statphas ; get status. jc start2 ; hop if error. mov si,offset eofmsg ; end-of-format message. call prtmsg start2: jmp start ; print menu again. ; PRTBCD - Print bcd number in cl. prtbcd proc near push ax ; save ax. mov al,cl ; al = bcd number. shr al,1 ; move left nibble to right. shr al,1 shr al,1 shr al,1 add al,'0' ; make al an ascii char. cmp al,'0' ; is it a zero? jne prtbcd2 ; hop if not. mov al,' ' ; print space instead of zero. prtbcd2: call conout ; print al. mov al,cl ; al = bcd number. and al,0fh ; look at only right nibble. add al,30h ; make al an ascii char. call conout ; print al. pop ax ; restore ax. ret prtbcd endp ; CRLF - Print carriage-return/line-feed. crlf proc near push ax ; save ax. mov al,cr ; al = carriage-return. call conout ; print it. mov al,lf ; al = line-feed. call conout ; print it. pop ax ; restore ax. ret crlf endp ; PRTSPC - Print 2 spaces. prtspc proc near push ax ; save ax. mov al,' ' ; al = space. call conout ; print space. call conout ; print space. pop ax ; restore ax. ret prtspc endp ; PRTMSG - Print message at offset in si. prtmsg proc near lodsb ; al = next character. cmp al,0 ; is it terminator? je prtmsgx ; exit if so. call conout ; else print charactr in al. jmp prtmsg ; get another character. prtmsgx: ret prtmsg endp ; CONOUT - Print character in al on console. conout proc near push ax ; save registers. push cx push si push ds ; save data segment. mov dl,al ; dl = character to print. mov ah,2 ; ah = direct console i/o code. int dos ; call dos to print it. pop ds ; restore data segment. pop si ; restore regsiters. pop cx pop ax ret conout endp ; ; reset the controller and setup the default parameters. ; mwreset proc near out reset,al ;send reset pulse to controller. out clear,al ; clear any pending ctlr interrupt. in al,status ; release the reset signal. mov cx,0f000h ; delay at least 40 microseconds. dloop: loop dloop ; 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 ; are both busy and ready set? jz move6 ; hop if so. 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,data ; 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 data,al ; send init data to controller. loop movel ; decrement cx, loop if not zero. mov al,0 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 out intrupt,al ; interrupt controller. clc ; clear error flag. ret ; return from mwreset. mwreset endp ; do the operation specified by mwop. mwrdwr proc near mov cx,ncdbyts ; cx = number of command bytes. 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). mwrdwr endp ; Wait for request. wait proc near 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 wait endp ; Command Phase. ; Entry: cx = number of command bytes. cmndphas proc near 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 si,offset mwop ; si = command buffer address. cmndlp: lodsb ; al = command byte. out data,al ; send to controller. loop cmndlp ; dec cx, loop till zero. mov al,0 out intrupt,al ; interrupt the controller. call wait ; wait for controller request. clc ; clear error flag. ret cmndphas endp ; Data Phase. dataphas proc near 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. stc ; set error flag. ret ; abort data phase. data1: mov al,0 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,3 ; cx = byte count for transfer. mov di,offset yes ; di = address of "YES". cmp al,0 ; is it a write? je mwrite ; hop if so. ; transfer 3 bytes from controller to hstbuf. mwread: in al,data ; al = a data byte. mov [di],al ; put byte into buffer. inc di ; bump buffer pointer. loop mwread ; dec cx, loop until zero. jmp mwexit ; exit routine. ; transfer 512 bytes from hstbuf to controller. mwrite: mov al,[di] ; al = byte from buffer. inc di ; bump buffer pointer. out data,al ; put byte into controller. loop mwrite ; dec cx, loop until zero. ; stop controller and wait for next request. mwexit: mov al,0 out intrupt,al ; interrupt controller. call wait ; wait for request and reset. clc ; clear error flag. ret dataphas endp ; status phase. ; returns with carry set if error. statphas proc near 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. jz stat2 ; hop if not. stat1: stc ; set error flag. stat2: mov al,0 out intrupt,al ; interrupt the controller. ret statphas endp ; geterr - get error code bits. geterr proc near 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,data ; al = error code byte. mov [bx],al ; put into buffer. inc bx ; bump buffer pointer. loop geterl ; dec cx, loop till zero. ret geterr endp endprog: ret start endp cseg ends end start