page ,132 .lall ; FORMAT PROGRAM FOR MORROW HARD DISK CONTROLLER ON PC-DOS. ; Note: This first version only sets up boot, fat's, and directory. ; Changes by Don Tarbell: ; 09-14-85: created from MORHDC.LIB of 9-11-85. ; 10-06-85: got running. ; 10-20-85: more work on it. ; Equates. hdrtmax equ 2 ; hard disk retry maximum. badsiz equ 64 ; # of bad sector entries allowed. hdskrt equ 3 ; hard disk retry count. ; Morrow Controller Commands. dmaread equ 0 ; read sector. dmawrit equ 1 ; write sector. dmarhed equ 2 ; find a sector. dmawhed equ 3 ; write headers (format track). dmalcon equ 4 ; load disk parameters. dmassta equ 5 ; sense disk drive status. dmanop equ 6 ; null controller operation. reset equ 54h ; reset controller. attn equ 55h ; send a controller attention. chan equ 50h ; default channel address. stepout equ 10h ; step direction out. stepin equ 0 ; step direction in. band1 equ 40h ; no precomp, high current. band2 equ 0c0h ; precomp, high current. band3 equ 80h ; precomp, low current. track0 equ 1 ; track zero status. wflt equ 2 ; write fault from drive. dready equ 4 ; drive ready. sekcmp equ 8 ; seek complete. ;ASCII Equates. cr equ 0dh ; carriage-return. lf equ 0ah ; line-feed. ; System Equates. dos equ 21h ; bdos interrupt number. stack segment para stack 'stack' db 10 dup('stack') stack ends ; START OF DATA SEGMENT. workarea segment page public 'data' ; Messages. openmsg db cr,lf db cr,lf,' Morrow Hard Disk Controller Format Program' db cr,lf,' Copyright (c) 1985 by Tarbell Electronics' db cr,lf,' Last changed 10-20-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 rsmsg db cr,lf,'How many sectors do you want reserved before' db cr,lf,'the start of the file allocation tables?' db cr,lf,'The default is one cylinder, or ',0 kbimsg db ': ',0 dirmsg db cr,lf db cr,lf,'What is the maximum number of directory entries' db cr,lf,'that you want. This determines the maximum number' db cr,lf,'of files you can have on the disk. A large number' db cr,lf,'takes up extra disk space and slows down directory' db cr,lf,'accesses. The maximum number is ',0 di2msg db cr,lf,'The default number is ',0 exmsg db cr,lf db cr,lf,'Exiting back to operating system...' db cr,lf,0 ; Keyboard buffer. keybuf db 10,0,0,0,0,0,0 ; Hard disk drive characteristic table. ; Each hard disk has an entry of 9 fields: ; 1. Manufacturer ; 2. Model Number ; 3. Number of cylinders ; 4. Cylinder to start write premonpensation ; 5. Cylinder to reduce write current ; 6. Number of heads ; 7. Step rate ; 8. Step rate during recalibration ; 9. Head Settle delay hdctab db 'Computer Memories, Inc.',0,'CM5206',0 dw 306,128,128 db 2,2,60,1 db 'Computer Memories, Inc.',0,'CM5412',0 dw 306,128,128 db 4,2,60,1 db 'Computer Memories, Inc.',0,'CM5619',0 dw 306,128,128 ; cylinders, precomp, low current. db 6,2,60,1 ; heads, step delay, step recal, settle delay. db 'RMS',0,'RMS-512',0 dw 156,77,77 db 8,1,30,2 db 'Miniscribe',0,'3012',0 dw 612,128,77 db 2,0,30,0 db 'Rodime',0,'20',0 dw 320,0,132 db 6,0,30,0 db 'Atasi',0,'33',0 dw 512,320,0 db 5,0,30,0 db 'Quantum',0,'540',0 dw 512,256,128 db 8,0,30,0 db 'Otari',0,'C-507',0 dw 306,128,0 db 2,0,60,0 db 'Otari',0,'C-514',0 dw 306,128,0 db 4,0,60,0 db 'Otari',0,'C-519',0 dw 306,128,0 db 6,0,60,0 db 'Otari',0,'C-526',0 dw 306,128,0 db 8,0,60,0 dw 0 ; end of hard disk characteristic table. ; Morrow 5-inch Winchester Controller Scratch Area. ; track address table for 4 physical drives. mwtab dw 0ffffh ; initialize to dw 0ffffh ; (way out on the end of disk.) dw 0ffffh dw 0ffffh mwop db 0 mwhead db 0 ; currently selected head. mwsectr db 0 ; currently selected sector. dmachan equ (offset $) ; command channel area. dmasel0 db 0 ; drive select. dmastep dw 0 ; relative step counter. dmasel1 db 0 ; head select. dmadma dw 0 ; dma address. extdma db 0 ; extended address. dmarg0 db 0 ; first argument. dmarg1 db 0 ; second argument. dmarg2 db 0 ; third argument. dmarg3 db 0 ; fourth argument. dmaop db 0 ; operation code. dmastat db 0 ; controller status byte. dmalnk dw 0 ; link adr to next cmd ch. db 0 ; extended address of link. badmap db badsiz*9 dup(?) ; bad sector map. db 0ffh ; end marker. mwiflg db 0 ; bad map initialization flag. ; these flags control the hard disk drivers. hrdsec db 0 ; logical sector number. hrdtrk dw 0 ; cylinder number. hrddsk db 0 ; hard disk drive number (0-3). 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. hdrtct db 0 ; retry counter. mapmsg db cr,lf,'Badmap overflow on ' mapmsgdrive db 0,':',0 badptr dw (offset badmap) ;pointer to next bad map entry. ; hard disk parameter table. mwptab equ $ mwjmp db 3 dup(?) ; jump to boot (unused). mwid db 'Tarbell',0 ; oem name. mwbps dw 512 ; bytes per sector. mwspa db 2 ; sectors per allocation unit. mwnrs dw ? ; number of reserved sectors. db 2 ; number of fats. mwnde dw ? ; number of directory entries. mwtns dw ? ; total number of sectors. db 0f8h ; hard disk media descriptor (f8). mwnsf dw ? ; number of sectors occupied by each fat. mwspt dw 17 ; sectors per track. mwhpc dw ? ; number of heads. mwhidn dw ? ; number of hidden sectors. dw 5 dup(?) ; reserved for IBM. mwcyl dw ? ; number of cylinders. mwwpc dw ? ; cylinder to start write precompensation. mwwlc dw ? ; cylinder to start write low current. mwsd dw ? ; step delay. mwrsd dw ? ; recalibrate step delay. mwhd dw ? ; head settle delay. mwss dw 3 ; sector size code (3 shown for 512). mwdrv db 32 dup(?) ; place for drive manufacturer and model. dw 5 dup(?) ; reserved for Tarbell additions. dw 5 dup(?) ; reserved for Dealer additions. dw 5 dup(?) ; reserved for End User additions. mwptabe equ $ ; end of table. mwbuf db 512 dup(?) ; 512-byte buffer. ; intermediate calculations. (not part of above table) mwspc dw ? ; sectors per cylinder. fatctr db ? ; file allocation table counter. sector dw ? ; sector number from 0 to total on disk. workarea ends ; END OF DATA SEGMENT. ;------------------------------------------------------------------------ ; START OF CODE SEGMENT. cseg segment para public 'code' ; MAIN PROGRAM ENTRY POINT. 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,10 ; 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. mov ah,10 ; multiply number by 10. mul ah mov ah,al ; save in ah. lodsb ; al = 2nd character. sub al,30h ; al = binary number from 0-9. add al,ah ; al = binary number from 0-99. 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,10 ; 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. mov di,offset mwdrv ; di = mfr & model place in table. call patmsg ; print and transfer manufacturer. dec di ; write over terminator (0). call patspc ; print spaces. call patmsg ; print and transfer model number. call crlf ; print crlf. ; transfer characteristics into work area. cld lodsw ; ax = number of cylinders. mov mwcyl,ax lodsw ; ax = write precomp cylinder. mov mwwpc,ax lodsw ; ax = low current cylinder. mov mwwlc,ax lodsb ; al = number of heads. mov ah,0 mov mwhpc,ax lodsb ; al = step rate delay. mov mwsd,ax lodsb ; al = step rate during recal. mov mwrsd,ax lodsb ; al = head settle delay. mov mwhd,ax ; get number of reserved sectors from operator. mov si,offset rsmsg ; ask about reserved sectors. call prtmsg mov al,byte ptr mwspt ; al = sectors per track. mov ah,byte ptr mwhpc ; ah = number of heads. mul ah ; ax = sectors per cylinder. mov mwspc,ax ; save it. call prtdec ; print default reserved sectors. call getbin ; get binary from keyboard. mov mwnrs,ax ; set reserved sectors. mov mwhidn,ax ; use same number for hidden. ; get number of directory entries from operator. mov si,offset dirmsg ; ask operator about directory. call prtmsg mov ax,mwcyl ; ax = total number of cylinders. mov bx,mwspc ; bx = sectors per cylinder. mov dx,0 ; dx = upper word of answer. mul bx ; dx,ax = total sectors on disk. cmp dx,0 ; over maximum? je set2 ; hop if not. mov ax,0ffffh ; set to maximum if exceeded. set2: mov mwtns,ax ; save total sectors. mov dx,0 ; dx = upper part of numerator. mov bl,mwspa ; divide by sectors per alloc unit. mov bh,0 div bx ; ax = maximum directory entries. call prtdec ; print maximum directory entries. mov si,offset di2msg ; print default message. call prtmsg mov dx,0 ; dx = upper part of numerator. mov bx,4 ; divide maximum by 4 for default. div bx ; ax = default directory entries. call prtdec ; print default to operator. call getbin ; get binary from keyboard. mov mwnde,ax ; set number of directory entires. ; figure size of file allocation tables (fat's). mov ax,mwtns ; ax = total number of sectors. sub ax,mwnrs ; subtract reserved sectors. mov cl,9 ; divide by 2 and 256. shr ax,cl inc ax ; add one. mov mwnsf,ax ; set number of sectors per fat. ; move hard disk to cylinder 0, read map of bad sectors. call mapper ; put info into disk buffer. mov si,offset mwptab ; move table into buffer. mov di,offset mwbuf mov cx,offset mwptabe-mwptab push ds ; es = ds. pop es cld rep movsb ; write boot sector to cylinder 0, head 0, sector 0. mov dmaop,dmawrit ; set operation = write. mov dx,(offset mwbuf) ; figure 20-bit address of mwbuf. call fndact mov dmadma,dx ; set dma address. mov extdma,al mov mwsectr,0 ; set sector = 0. mov mwhead,0 ; set head = 0. call rwsect ; write the sector. ; write file allocation tables to disk. mov fatctr,2 ; initialize fat counter. mov ax,mwnrs ; ax = number of reserved sectors. mov sector,ax ; sector = starting sector number. fatlp: call zerbuf ; zero out buffer. mov di,offset mwbuf ; di = offset of buffer. mov al,0f8h ; al = fixed disk code. stosb ; write it to buffer. mov ax,0ffffh ; ax = first bytes of fat. stosw ; write to buffer. stosb ; and one more ff. call wrtsec ; write sector to disk. inc sector ; increment sector number. call zerbuf ; zero out buffer. mov cx,mwnsf ; cx = number of sectors per fat. dec cx ; allow for first one already written. fatlp2: call wrtsec ; write out sectors with zeroes. inc sector ; increment sector number. loop fatlp2 ; dec cx, loop back if not zero. dec fatctr ; are both fat's written yet? jnz fatlp ; do another one if not. ; initialize directory on disk. mov cx,mwnde ; cx = number of directory entries. shr cx,1 ; divide by 512, multiply by 32. shr cx,1 shr cx,1 shr cx,1 inc cx ; just in case it was not mult of 16. dirlp: call wrtsec ; write out sector with zeroes. inc sector ; increment sector number. loop dirlp ; dec cx, loop back if not zero. ; print end-of-format message and loop back for another. mov si,offset eofmsg ; end-of-format message. call prtmsg start2: jmp start ; print menu again. endprog: ret start endp ; WRTSEC - Write sector in mwbuf to disk. ; Entry: SECTOR variable has sector number 0-size of disk. wrtsec proc near push cx ; save cx. mov ax,ds ; es = ds. mov es,ax mov di,offset mwbuf ; es:di = transfer address. mov bx,mwspc ; bx = sectors per cylinder. mov ax,sector ; ax = sector number. mov dx,0 ; numerator is dx and ax. div bx ; dx = sector number. mov bx,ax ; bx = cylinder number. mov cl,0 ; cl = drive number. mov ah,2 ; ah = code for write sector. call findalt ; write sector. pop cx ; restore cx. ret ; return from wrtsec. wrtsec endp ; ZERBUF - Write all zeroes (0) to buffer mwbuf. zerbuf proc near mov di,offset mwbuf ; di = buffer address. push ds ; es = ds. pop es mov ax,0 ; ax = word to write. mov cx,256 ; cx = number of words to write. cld ; direction = forward. rep stosw ; write zeroes to buffer. ret ; return from zerbuf. zerbuf endp ; GETBIN - Get string from keyboard and convert to binary in ax. ; If only a return, leave ax unchanged. getbin proc near mov si,offset kbimsg ; print " : ". call prtmsg call getkb ; get string from keyboard. jz getbinx ; exit if only a return. call asbin ; convert string to binary in ax. getbinx: ret ; return from getbin. getbin endp ; ASBIN - Convert ASCII at [si] to binary in ax. asbin proc near push bx ; save bx. mov bx,0 ; bx = accumulator. asbinl: lodsb ; al = ASCII character. mov ah,0 ; clear upper ax. add bx,ax ; add ax to accumulator. dec cl ; any more characters? jz asbinx ; exit if not. mov ax,bx ; ax = accumulator. mov bl,10 ; bl = multiplier. mul bl ; multiply by 10. mov bx,ax ; put back in bx. jmp asbinl ; loop back till done. asbinx: mov ax,bx ; ax = final answer. pop bx ; restore bx ret ; return from asbin. asbin endp ; GETKB - Get a string from keyboard into buffer. getkb proc near push ds ; save ds. push ax ; save ax. mov dx,offset keybuf ; dx = keyboard buffer offset. mov ah,10 ; ah = code to read keyboard. int dos ; call disk operating system. mov si,offset keybuf+1 ; si = byte count offset. mov cl,[si] ; cl = byte count. inc si ; si = address of first character. cmp cl,0 ; set Z flag if byte count=0. cld ; direction = forward. pop ax ; restore ax. pop ds ; restore ds. ret ; return from getkb. getkb endp ; PRTDEC - Print decimal number in ax. ; preserve ax. prtdec proc near mov cx,ax ; cx = number to print. prtdel: push dx ; save value on stack. mov dx,-1 ; this becomes number/radix. prtdes: sub cx,10 ; subtract 10. inc dx ; inc remainder. jnc prtdes ; loop till carry out. add cx,10 ; add radix back in. xchg dx,cx ; switch new/current. test cx,cx ; test for zero remainder. jz prtdex ; exit if done. call prtdel ; build bcd digits recursively. prtdex: push ax ; save ax. mov al,dl ; get bcd value. add al,'0' ; add ascii bias. call conout ; print the digit. pop ax ; restore ax. pop dx ; recover next bcd value. ret ; return from prtdec and prtdel. prtdec endp ; 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 ; PATSPC - Print and transfer 2 spaces. patspc proc near push ax push ds ; es = ds. pop es mov al,' ' ; al = space. cld ; transfer 2 spaces to table at di. stosb stosb call conout ; print 2 spaces. call conout pop ax ret patspc 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 ; PATMSG - Print and transfer message at si. patmsg proc near push ax push ds ; es = ds. pop es patmsgl: lodsb ; al = next character. stosb ; put character at [di]. cmp al,0 ; is it terminator? je patmsgx ; exit if so. call conout ; else print character in al. jmp patmsgl ; get another character. patmsgx: pop ax ; restore ax. ret patmsg endp ; PRTMSG - Print message at offset in si. prtmsg proc near push ax ; save ax. prtmsgl: lodsb ; al = next character. cmp al,0 ; is it terminator? je prtmsgx ; exit if so. call conout ; else print charactr in al. jmp prtmsgl ; get another character. prtmsgx: pop ax ; restore ax. 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 ; MAPPER ; Log in Morrow Hard disk interface drive. ; Read bad sector map from track 0, head 2, first sector. ; entry: cl = physical hard disk drive number from 0-3. ; exit: cf (carry flag) set if error, ercode = status. ; mapper proc near mov hrddsk,0 ; save drive number. ; clear bad map table to all zeroes unless done already. mov cx,badsiz*9 ; cx = bad map size. mov di,offset badmap ; di = starting address. mov ax,ds ; es = ds. mov es,ax mov al,0 ; put zeroes in it. cld ; forward direction. rep stosb ; clear out bad map. mwrest: call mwhome ;do a restore. jnc mwnoer ; hop if no error. mwyerr: jmp mwerr ; hop if error. mwnoer: mov cx,0 ; track zero. call mwseek ; seek to zero. jc mwyerr ; hop if error in seek. mov al,dmaread ; setup for read. mov byte ptr dmaop,al mov dx,(offset mwbuf) ; get buffer addr. call fndact ; figure physical addr. mov word ptr dmadma,dx ; physical addr a00-a15. mov byte ptr extdma,al ; physical addr a16-a19. mov al,0 mov byte ptr mwsectr,al ; sector 0 for badmap. mov al,2 ; head 2. mov byte ptr mwhead,al call rwsect ; go read the sector. jc mwerr ; exit if read error. mov bx,word ptr badptr ; pick up bad map pointer. mov si, (offset mwbuf) ; start at beginning of buffer. bad1: mov al,[si] ; pick up an entry from buffer. or al,al jz bade ; all done. mov al,[bx] ; pick up entry from bad map table. inc al jz overflo ; bad map overflow. mov al,byte ptr hrddsk ; put drive in table. mov [bx],al inc bx mov cx,8 xchg bx,si ;ldir ; move rest of info into table. ldir: mov al,[bx] ; get a byte. mov [si],al ; put a byte. inc bx ; bump pointers. inc si loop ldir ; dec cx, loop back till zero. xchg bx,si jmp bad1 bade: mov word ptr badptr,bx ;restore new bad map pointer. mapex: clc ; no error flag. ret overflo: mov al,hrddsk ; al = drive letter. add al,'A' ; make ascii. mov byte ptr mapmsgdrive,al mov bx,(offset mapmsg) call prtmsg ; common error return routine. mwerr: mov cl,hrddsk ; cl = drive number. mov bx,hrdtrk ; bx = cylinder number. mov dh,mwhead ; dh = head number. mov dl,mwsectr ; dl = sector number. mov al,dmastat ; al = error status. or al,al ; clear zero flag. stc ; set error flag. ret ; fndact - Find actual (physical) address of an operand. ; Enter with offset in dx. ; Return with al=a16-19, dx=a00-a15 of physical address. fndact: mov ax,ds ; get base of segment. mov cl,4 ; shift count. rol ax,cl ; shift segment left 4. mov cl,al ; save shifted out top 4 bits. and cl,0fh ; mask for top 4 bits only. and ax,0fff0h add dx,ax ; add shifted segment to offset. mov al,0 ; clear. adc al,cl ; add top 4 & carry. ret ; al=a16-a19, dx=a00-a15. mapper endp ; Common Morrow hard disk read/write routine. ; Entry: es:di = transfer address ; cl = logical drive number (starting at 0) ; bx = cylinder number (starting at 0) ; dx = sector number (starting at 0) ; ah = 1 for read, 2 for write ; Exit: carry set if error. ; al = controller status if error. findalt proc near cld ; set auto = increment. ; set physical hard disk drive number. mov hrddsk,cl ; set hard disk drive number. ; set operation code and cylinder number. dec ah ; read = 0, write =1. mov mwop,ah ; set morrow winchester operation. mov hrdtrk,bx ; hrdtrk = cylinder number. mov hrdsec,dl ; hrdsec = sector requested. ; (head number figured later) ; figure physical address for data. mov ax,es ; ax = segment. mov cl,4 ; cl = shift count. rol ax,cl ; rotate segment left 4. mov cl,al ; cl = top 4 bits. and cl,0fh and ax,0fff0h ; ax without rotated bits. add di,ax ; di = a00-a15 of address. mov al,0 ; clear. adc al,cl ; al = a16-a19, di = a00-a15. mov dmadma,di ; dmadma = a00-a15. mov extdma,al ; extdma = a16-a19. ; read or write the sector requested. io_srt: call mwtran ; read or write the data. jc io_the ; hop if error. ret io_the: jmp mwerr ; handler error above. ; Common Morrow hard disk read/write routine. mwtran: mov cl,hrddsk ; get hard disk number. mov bx,(offset badmap) ;get badmap address. all: mov dx,word ptr badptr ;get bad map pointer. or al,al ;clear carry. xchg bx,dx sub bx,dx jz alt2 ;if the end. xchg bx,dx ; swap back. push bx ; save pointer. mov al,cl ;get drive #. cmp al,[bx] ;check it. jnz altmis ;nope. inc bx ;bump to track. mov al,byte ptr hrdtrk ;get lsb track. cmp al,[bx] ;check it. jnz altmis ;nope. inc bx ;bumpt to msb. mov al,byte ptr hrdtrk+1 ;get msb track. cmp al,[bx] ;check it. jnz altmis inc bx mov al,[bx] ;get map sector. dec al ; make sectors start at 0. mov ch,al ;put in b. mov al,byte ptr hrdsec ;get sector. cmp al,ch ;check it. jnz altmis ; the current sector was found in badmap, so seek to alternate. inc bx ;alternate found. inc bx ;bump to alternate. mov cl,[bx] ;get lsb alternate track. inc bx mov ch,[bx] ;get msb alternate track. push bx ;save bx. call mwseek ;do the seek. pop bx ;restore bx. jc alte ; exit if seek error. inc bx mov al,byte ptr mwop ;get the operation. mov byte ptr dmaop,al ;tell the controller. mov al,[bx] ;get the alternate sector. dec al ; make sectors start at 0. pop bx ;make stack right. jmp altfnd ;calculate head and do it. altmis: pop bx ;restore bx add bx,9 ; offset to next badmap entry. jmp all ;look some more. alte: pop bx ; make stack right. ret ; jump here if no alternate found. alt2: mov cx,word ptr hrdtrk call mwseek ;do the seek. jc mwexit ; exit if seek error. mov al,byte ptr mwop ;get the operation. mov byte ptr dmaop,al ;tell the controller. mov al,byte ptr hrdsec ;get the requested sector. ; jump here if an alternate is found. altfnd: mov cl,al ;put in c. mov dh,0 ;clear head counter. seclp: sub al,byte ptr mwspt ;subtract out a heads worth. jb secfnd ;jump if found. inc dh ;else bump to next head. mov cl,al ;update sector count. jmp seclp ;and do it again. secfnd: mov al,dh ;get head. mov byte ptr mwhead,al ;save it. mov al,cl ;get sector. mov byte ptr mwsectr,al ;save it also. rwsect: mov hdrtct,hdrtmax ; initialize retry counter. retry: call mwrdwr ;go to it. jnc mwexit ; exit if good read. dec hdrtct ; decrement error counter. jnz retry ; loop back till zero. stc ; set error (carry) flag. mwexit: ret ; ; these are the low level drivers for the morrow controller. ; reset the controller and do a home on hrddsk. mwhome: call mwreset ;reset controller. jc mwexit ; exit if error during reset. mov bx,(offset dmarg1) ;load arguments. mov al,byte ptr mwrsd ; al = recal step delay. mov byte ptr [bx],al ;load step delay (slow). inc bx mov al,byte ptr mwhd ; al = head settle delay. mov byte ptr [bx],al ;head settle delay. call mwissue ;do load constants again. jc mwexit ; exit if error during load constants. call mwptr ;get pointer to current cyl no. mov word ptr [bx],0 ; set up fake at cylinder 0. mov cx,2 ;seek in 2 cylinders. call mwseek jc mwexit ; exit if error during seek. call mwptr ;get pointer again. mov cx,mwcyl ; cx = number of cylinders. add cx,100 mov word ptr [bx],cx ; maximum head travel. mov cx,0 ;seek to cylinder 0. call mwseek ;recal slowly. jc mwexit ; exit if error during seek. jmp mwreset ;back to fast stepping mode. ; seek hrddsk to the track in cx. mwseek: call mwptr ;get track pointer. mov dx,[bx] ; dx = old track number. mov [bx],cx ; store new track number. mov word ptr dmarg0,cx ; set command channel cyl no. mov al,dh inc al mov bx,0ffffh jnz mwskip0 mov cl,stepout jmp mwskip mwskip0: mov bx,cx ; bx=new track, dx = old track. sub bx,dx ; bx = new track - old track. mov cl,stepout ; cl = step out code. jc mwsout ; hop if new track smaller. mov cl,stepin ; else cl = code to step in. jmp mwskip mwsout: call mwnegh1 mwskip: mov dmastep,bx ; save step count. mov al,hrddsk ; al = physical hard disk number. or al,cl mov dmasel0,al ; put it into command channel. mov al,dmanop ;no-operation command for channel. call mwprep ;step to proper track. mov dmastep,0 ; clear step counter. ret ; ; reset the controller and setup the default parameters. ; mwreset: out reset,al ;send reset pulse to controller. mov dx,(offset dmasel0) ;get command channel address. call fndact ;convert to physical address. push ds ;save data segment register. mov cx,0 ;put zero into DS register. mov ds,cx cli ; disable interrupts during startup. mov di,chan ; di = channel starting point. mov cx,[di] ; cx = contents of 50h,51h. mov [di],dx ; put in channel address low. mov ah,2[di] ; ah = contents of 52h. mov 2[di],ah ; put in channel address high. pop ds mov word ptr dmalnk,dx ;put link at end of channel. mov byte ptr dmalnk+2,al mov bx,(offset dmarg1) ;load arguments. mov al,byte ptr mwsd ; al = step delay. mov byte ptr [bx],al ;load step delay. inc bx mov al,byte ptr mwhd ; al = head settle delay. mov byte ptr [bx],al ;head settle delay. inc bx mov al,byte ptr mwss ; al = sector size code. mov byte ptr [bx],al ;sector size code. inc bx mov byte ptr [bx],dmalcon ;load constants command. call mwissue ; do load constants. push ds ; save data segment. mov dx,0 ; ds = 0. mov ds,dx mov di,chan ; di = starting channel addres. mov [di],cx ; restore whatever was at 50,51. mov 2[di],ah ; restore whatever was at 52. sti ; re-enable interrupts. pop ds ret ; ; do the opration specified by a register. ; mwprep: mov byte ptr dmaop,al ;save command channel op code. ; do the operation specified by dmaop. mwrdwr: mov cl,band1 mov bx,word ptr dmarg0 mov dx,mwwpc ; dx = write precomp cylinder. call mwhlcde jb mwpreps mov cl,band2 mov dx,mwwlc ; dx = write low current cyl. call mwhlcde jb mwpreps mov cl,band3 ;cylinder > low_current. mwpreps: mov al,byte ptr mwhead ;load head address. mov byte ptr dmarg2,al not al ;negative logic for controller. and al,7 ;3 bits of head select. rol al,1 ;shove over to bits 2-4. rol al,1 or al,cl ;add on low current and precomp. mov cl,al mov al,byte ptr hrddsk ;load drive address. or al,cl ;slap in drive bits. mov byte ptr dmasel1,al ;save in cmd channel head sel. mov al,byte ptr mwsectr ;load sector address. mov byte ptr dmarg3,al ; start the controller running and wait for completion. mwissue: mov dmastat,0 ; initialize status to busy. out attn,al ;start controller. mwwtlp: mov al,dmastat ; al = status of transfer. cmp al,0 ; is controller still busy? jz mwwtlp ; loop back if so. cmp al,0ffh ;test for successful operation. jz mwiret ; hop if successful completion. stc ; set carry for error indicator. mwiret: ret ;return no error (carry reset). ; return with bx pointing to the track word for hrddsk. mwptr: mov dl,byte ptr hrddsk ;get track address. shl dl,1 mov dh,0 mov bx,(offset mwtab) add bx,dx ret mwnegh1: mov al,bh not al mov bh,al mov al,bl not al mov bl,al inc bx ret mwhlmde: xchg bx,dx call mwnegh1 xchg bx,dx add bx,dx ret mwhlcde: mov al,bh cmp al,dh jz l_6 ret l_6: mov al,bl cmp al,dl ret l_7 equ $ findalt endp cseg ends end start