home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-01-26 | 27.3 KB | 1,097 lines |
- ; HDISK.A86
- title 'HARD Disk Driver'
- pagesize 60+11
- ;****************************************
- ;* *
- ;* HARD DISK ROUTINES *
- ;* CDOS 6.0 XIOS *
- ;* DRI OS ENGR, JMB, GMS, JW *
- ;* *
- ;****************************************
- ; Mods:
- ; 6.x
- ; 5 JAN 89 -- fix to cure problem with hard disk reads on certain - GMS
- ; machines, where the ROS loses a Hard disk INT.
- ; 7 NOV 88 -- always check for buggy ROS read errors on all AT's - GMS
- ; 22 Jul 88 -- use new dispatcher - IJ
- ; 11 FEB 88 -- if 386 return no extended memory from int 15h - GMS
- ; 6.0
- ; 23 JUL 87 -- don't test AT HD DRQ if add-on disk controller - JW
- ; 17 JUL 87 -- converted XIOS to small model - JW
- ; 17 JUL 87 -- Removed last HD_SPT for RLL and IBM ESDI drives - GMS/JC
- ; 23 JUN 87 -- CP/M hd label buffers removed for 6.0 - JW
- ; 5.2
- ; 28 JAN 87 -- CDOS 386 code added - GMS
- ; 5.1
- ; 18 AUG 86 -- Multiple DOS partion and >32 mg partition support - GMS
- ; 12 AUG 86 -- NSEOI to SEOI (thx RH,JF)
- ; 22 APR 86 -- test HD DRQ bit on return from ROS to ID AT buffer bug
- ; 22 JAN 86 -- lock paged memory around DMA ops.
- ; 25 SEP 85 -- dress up error handling for XTs
- ; 19 SEP 85 -- change HD DPHS, INIT now allocates ALV and data buffs
- ; 17 SEP 85 -- remove previously installed AT POST/WAIT
- ; 4 SEP 85 -- insert our own XT hd driver
- ; 1 AUG 85 -- move sector buffer location to miss 64K boundary
- ; -- doesn't work...change link line.
- ; 27 JUN 85 -- convert mov reg,0 to sub reg,reg if poss.
- ; 12 JUN 85 -- update 4.1 ASM86 source to RASM86
-
- ; include COPYRITE.TXT
-
- nolist
- include CDOS.EQU
- include XIOS.EQU
- include PCHW.EQU
- include ASCII.EQU
- list
- ; These have been included:
- ; include PCHW.EQU
- ; include CDOS.EQU
- ; include XIOS.EQU
- ; include ASCII.EQU
-
- CGROUP group CODE
- DGROUP group hdata0,hdata1,hdata2,hdata3,hdata4
-
- public hd_dummy_int@
- public pc_read_hd@, pc_write_hd@, pc_select_hd@
- public hd_rom@
-
- public hd_rom_ofs$, hd_rom_seg$, local_buffer$
- public hd_disk_info$, hdinf_ptr$
- public hd_init_flag$, hd_boot_flag$
- public aux_drive$
- public old_int15$, int15_isr@ ; for INIT.A86
- public hd_timer$, hd_error$ ; for ISRS.A86
-
- if XM
- public xt_driver@, hd_cmd_blk$ ; XT's only - not 386
- public hd_isr@
- endif
-
- eject
-
- dseg
- extrn dph_tbl$ :word ; in HEADER.A86
- extrn num_flop_des$ :byte, num_hard$ :byte ; in PUBDATA.A86
- extrn disk_int_off$ :word
- extrn disk_error$ :byte ; in FLOPPY.A86
- extrn pc_at$ :byte
-
-
- cseg
- extrn sysdat$ :word ; in HEADER.A86
- extrn flagwait@ :near
- extrn flagset@ :near
- extrn disp_addr$ :dword
- extrn do_disk_error@ :near ; in FLOPPY.A86
- extrn comp_dma@ :near
- if XM
- extrn lock_page@ :near, unlock_page@:near ; in EMM.A86
- endif
- eject
-
- cseg
-
-
- at_multi_count:
- ; Set multi-sector count for PC, XT or AT:
- ; Entry: bx -> iopb
- ; cl = multi-count
- ; Exit: cl = max allowable count
-
- if 0
- test pc_at$,01h
- jz at_multi_done ; if not AT or clone, then skip
- cmp IBM_FN[bx],HD_ROS_READ
- jnz at_multi_done ; if not read, then skip
-
- ; If the machine is an AT with the buggy ROS, leave the multi-count as it
- ; is, because our timer isr will know to avoid dispatches if the buggy window
- ; has been interrupted. If AT or clone, but we weren't able to ID the bug
- ; string, we must enforce the single-sector i/o to be safe.
-
- test pc_at$,80h ; this bit is set in init.
- jnz at_multi_done ; jump if set
-
- mov cl,1 ; else one at a time
- at_multi_done:
- endif
- ret
-
-
- hd_rom@:
- ; Provides easy access to HDISK ROM.
- ; Call with ds:bx--> IBM_iopb structure as defined elsewhere.
- ; Returns zero set if succeeds, else non-zero.
- ; CALLS: hd_error_handler
-
- push es ! push si ; save uda and HDINF_ptr then execute
-
- mov cx,IBM_XFER_SEG[bx] ; must lock page if req'd
- mov dx,IBM_XFER_OFS[bx]
- mov ax,SECTOR_SIZE ; 512
- mul IBM_COUNT[bx] ; byte
- if XM
- cmp hd_rom_seg$,0F000h ; do we use an add-on controller?
- jne do_lock ; yes, might use DMA
- test pc_at$,0ffh ; if AT, no hdisk dmaing
- jnz skip_lock
- do_lock:
- push bx ; save pointer
- call lock_page@ ; will lock if needed
- pop bx
- endif
- skip_lock:
- mov cx,3 ; set auto retry count
-
- hd_rom_retry: ; inner retry loop
- push cx ! push bx ; save retry counter & IOPB
- mov ah,IBM_FN[bx]
- mov al,IBM_COUNT[bx] ; load up registers for ROM call
- mov dh,IBM_HEAD[bx]
- mov dl,IBM_LUN[bx]
- or dl,80h
- mov cx,IBM_CYLINDER[bx] ; get cylinder (0-1023)
- cmp cx,int15_cyl ; same cylinder as last time
- je hd_rom_noseek ; yes, should be quick
- mov use_int15,TRUE ; else use DEV_WAITFLAG
- mov int15_cyl,cx ; and update current cylinder
- hd_rom_noseek:
- xchg ch,cl
- ror cl,1 ! ror cl,1
- and cl,0c0h
- or cl,IBM_SECTOR[bx]
- les bx,IBM_XFER_PTR[bx]
-
- mov hd_error$,00 ; reset error flag
- mov hd_timer$,TICKS_PER_SECOND ; set off our own watchdog
- test pc_at$,0ffh ; if not AT increase timer count
- jnz hd_rom_go
- mov hd_timer$,TICKS_PER_SECOND*2 ; set off our own watchdog
-
- hd_rom_go:
-
- pushf
- callf hd_rom_entry ; fake an SWI call to ROM
- mov hd_timer$,0ffh ; reset watchdog
- pop bx ! pop cx ; restore IOPB ptr and retry counter
- pushf
- cmp hd_error$,0 ; did we force a timeout error
- je no_timeout
- popf
- xor ah,ah
- xchg ah,hd_error$
- mov IBM_ERRCODE[bx],ah ; save error return
- mov al,0
- jmp hd_rom01 ; and do error retry
- no_timeout:
- popf
- mov IBM_ERRCODE[bx],ah ; save error return
- mov al,0
- jc hd_rom01 ; and jump if error
-
- cmp hd_rom_seg$,0F000h ; do we use an add-on controller?
- jne hd_rom1 ; yes, don't touch the hardware
-
- ;; cmp pc_at$,81h ; buggy ROS?
- ;; jne hd_rom1 ; jump if no
- test pc_at$,01 ; always do the check on all AT's
- jz hd_rom1
-
- push dx ; Here if we need to check for
- mov dx,AT_HD_STATUS ; a ROS bug, where pending
- in al,dx ; data is left in the sector
- pop dx ; buffer.
- test al,AT_HD_DRQ ; something in sector buffer?
- mov al,0
- jz hd_rom1 ; jump if no error
-
- ; Here if there was an error...set the retry flag so that instead of the
- ; limited XT driver here in the XIOS, we use ROS to return the correct
- ; error codes.
- hd_rom01:
- mov retry_fl,0ffh ; indicate to the XT driver
-
- push cx ! push bx ; reset drive on any error ??
- mov ah,HD_ROS_RESET1 ; registers are still ok
- pushf
- callf hd_rom_entry
- pop bx ! pop cx
-
- ;;;; loop hd_rom_retry ; then try automatic retries first
- dec cx
- jz done_retries
- jmp hd_rom_retry
- done_retries:
- mov al,IBM_ERRCODE[bx] ; else get error code back and exit
- hd_rom1:
- mov retry_fl,0 ; reset for next time
- if XM
- call unlock_page@ ; release paged memory
- endif
- pop si ! pop es
- or al,al
- jz hd_rom_done ; return if no error
- test hd_init_flag$,1 ; if during OS initialization,
- jz hd_rom_done ; return error immediately
-
- push bx ! push si
- call hd_error_handler ; else report it to operator
- pop si ! pop bx
- cmp al,'R'
- jmpz hd_rom@ ; does he wish to try again?
-
- hd_rom_done:
- ret ; else return to caller
-
-
- hd_dummy_int@:
- ; Dummy ROM BIOS SWI used by hard disk ROM (always succeeds).
- ; CALLS: NOTHING
-
- sti
- xor ax,ax
- retf 2
-
-
- hd_error_handler:
- ; Display hard disk error and gets operator's response.
- ; entry: al = error code
- ; exit: al = 00h for ignore
- ; FFh for accept
- ; 'R' for retry
-
- mov disk_error$,al ; save for sub message
- jmp do_disk_error@ ; in the floppy code
- eject
-
- to_ros:
- jmpf dword ptr disk_int_off$ ; enter ROS through the
- ; vector used for HDMAINT and DSKMAINT
-
- if XM
- xt_driver@:
- ;----------
- ; Routine to emulate the ROS driver in an XT to allow flagwaits and sets.
- ; This code is used when running on an XT. If the machine is an AT, we
- ; use the ROS driver, with the addition of the device-post/wait implementation
- ; in int 15h. (ref. AT Tech. Ref. Manual) (removed 9-17-85)
- ; This routine only performs READS and WRITES...all other functions (the
- ; only other one called by the HDISK code above seems to be RESET) continue
- ; on to the ROS. To save space, we don't do any error diagnostics, always
- ; reporting BAD ADDR MARK on any error. 9-24-85.
-
- ; Entry:
- ; Registers setup per ROS hd driver, int 13h.
- ; Exit:
- ; With IRET.
-
- test retry_fl,0ffh ; are we in the error retry cycle?
- jnz to_ros ; if so, use the ROS to return correct
- ; errors.
- cmp ah,HD_ROS_READ ; for us?
- je for_us ; yes, if read
- cmp ah,HD_ROS_WRITE
- jne to_ros ; or write
-
- for_us:
- ; We only support 2 drives.
- ; Check for drives on a 2nd controller:
- ; and dl,3 ; get rid of high drive bit
- ; mov hd_port,HD_PORT_BASE ; for first 2 drives
- ; test dl,2 ; if drives 2 or 3, next controller
- ; jz first
- ; add hd_port,4 ; for next controller
-
- ; Setup COMMAND byte 1:
- first:
- and dl,1 ; for the bit in command byte 1
- push cx ; save sector number
- mov cl,5 ; shift count
- shl dl,cl
- or dh,dl ; put into head number
- mov hd_cmd_blk$ + 1,dh ; and into the block
- pop cx
-
- ; COMMAND byte 2:
- dec cl ; sectors 0-16, not 1-17
- mov hd_cmd_blk$ + 2,cl
-
- ; COMMAND byte 3:
- mov hd_cmd_blk$ + 3,ch ; cylinder number
-
- ; COMMAND byte 4:
- mov hd_cmd_blk$ + 4,al ; interleave/block count
-
- ; COMMAND byte 5:
- ; mov al,control_byte ; setup in init
- ; mov hd_cmd_blk$ + 5,al
-
- ; COMMAND byte 0:
- mov hd_cmd_blk$ + 0,HD_READ_OP
- mov al,DMA_MODE_READ_C3 ; mode byte for 8237
- cmp ah,2 ; assumption correct?
- je hd_1
- mov hd_cmd_blk$ + 0,HD_WRITE_OP ; write, not read
- mov al,DMA_MODE_WRITE_C3
- hd_1:
-
- ; Setup the DMA controller:
- cli
- out DMA_CBPF,al ;; init flip/flop
- push bx ! pop bx ;; delay
- out DMA_MODE_REG,al ;; DMA mode (read or write)
-
- ; Calculate 20-bit DMA address:
- mov ax,ES ;; segment
- mov cl,4 ;; paras to bytes by shl 4
- rol ax,cl ;; hi nibble comes around
- mov ch,al ;; save it
- and al,0F0h ;; and get rid of it for
- add ax,bx ;; the addition of the offset
- adc ch,0 ;; if carry, bump high 4
-
- ; To controller:
- out DMA_C3_ADDRESS,al ;; low 8
- mov al,ah ;;
- out DMA_C3_ADDRESS,al ;; next 8
- mov al,ch ;;
- and al,0Fh ;;
- out DMA_PAGE_C3,al ;; hi 4
-
- ; Count?
- mov al,hd_cmd_blk$+4 ;; get the block count
- shl al,1 ;; # bytes - 1
- dec al ;;
- mov ah,al ;;
- mov al,0ffh ;;
- out DMA_C3_COUNT,al ;;
- mov al,ah ;;
- out DMA_C3_COUNT,al ;;
- sti ;;
-
- ; Now talk to the hd controller:
- ; mov dx,hd_port ; for 1st (or 2nd controller)
- ; add dx,2 ; port 2
-
- mov al,3 ; dma and interrupt mask register
-
- mov dx,HD_PORT_BASE + 2
- out dx,al ; w. anything for controller select
-
- inc dx ; port 3
- out dx,al
-
- ; Check for controller ready:
- dec dx ! dec dx ; port 1
- wait_busy:
- in al,dx
- and al,0Fh
- cmp al,0Dh ; checks busy and others
- jne wait_busy
-
- ; Send command to controller:
- cld ; for lodsb
- mov cx,HD_CMD_COUNT
- dec dx ; port 0
- mov si,offset hd_cmd_blk$
- cmd_lp:
- lodsb
- out dx,al
- push dx ! pop dx ;<------------ This delay is not required for
- nop ! nop ! nop ! nop ;<-------- the IBM controller, but it is for
- loop cmd_lp ; the MOUNTAIN, and possibly others.
-
- ; The IBM XT controller uses up 123 machine cycles between the OUTs in the
- ; loop above. A push/pop combo is 27. Put some quick NOPs there so that
- ; some unfortunate can patch them if need be w/ longer instructions.
-
- ; Now make sure the DMA controller is unmasked:
- mov al,DMA_BMSK_C3
- out DMA_BMSK_REG,al
-
- ; and the PIC is free:
- in al,PIC_MASK
- and al,not 20h ; IRQ 5
- out PIC_MASK,al
-
- ; Tell the XIOS hd isr that we are expecting the int:
- mov hd_int_expected,0ffh
-
- ; Now leave until the op is complete:
- mov dx,HD_FLAG
- call flagwait@
-
- ; Check error:
- mov dx,hd_port
- in al,dx ; End-of-cmd-status is from port 0
- sub ah,ah ; assume no error
- test al,2
- jz no_err
- call process_err ; returns w/ error in AH
- no_err:
-
- ; Now op is done, turn off ints at the hd. controller for each drive:
- push ax
- mov dx,HD_PORT_BASE + 3 ; to int/dma reg
- sub al,al
- out dx,al ; turn 'em off
- add dx,4 ! out dx,al ; 3rd, 4th drives
- add dx,4 ! out dx,al ; 5th, 6th drives
- add dx,4 ! out dx,al ; 7th, 8th drives
-
- ; Disable the pic:
- in al,PIC_MASK
- or al,20h ; set IRQ 5 mask
- out PIC_MASK,al
-
- pop ax ; restore error
- cmp ah,1
- cmc ; set CF
- iret
-
-
- process_err:
- ;-----------
- ; Entry: DX = port 1
- ; Always reports BAD_ADDR_MARK if error.
-
- inc dx ; to port 2
- out dx,al ; controller select
- ; MOUNTAIN:
- nop ! nop ! nop ! nop
-
- inc dx ; to port 3
- sub al,al
- out dx,al ; zero to int/dma
-
- dec dx ! dec dx ; to port 1
- keep_checking:
- in al,dx
- and al,0Fh
- cmp al,0Dh ; checks busy and others
- jne keep_checking
-
- mov hd_cmd_blk$,3 ; Sense status cmd
- mov cx,HD_CMD_COUNT
- dec dx ; port 0
- cld
- mov si,offset hd_cmd_blk$
- ss_lp:
- lodsb
- out dx,al
- loop ss_lp
-
- mov cx,5 ; 4 sense bytes + 1 end-of-cmd-stat
- ss_rd_lp:
- inc dx ; port 1
- ss_wait:
- in al,dx
- test al,1 ; R1_REQ
- jz ss_wait
-
- dec dx ; port 0
- in al,dx
- loop ss_rd_lp
-
- ; We don't really care what kind of an error:
- ; call it 02, bad_addr_mark:
- mov ah,2
- ret
- eject
-
- hd_isr@:
- ;-------
- ; Interrupt service routine for XT hard disk:
- ; The BDOS only allows one process in the file system at a time. Therefore,
- ; we may with COMPLETE confidence (!) allow the hd isr to share the same
- ; stack area and register save area as the floppy controller.
-
- push ds
- mov ds,sysdat
- mov xt_hd_isr_ax,ax ;; save this reg
-
- mov al,PIC_OCW_SEOI + HDISK_CHANNEL ;; specific-end-of-interrupt
- out PIC_ACK,al ;;
-
- mov al,DMA_BMSK_C3 or 4h ;; mask off the channel
- out DMA_BMSK_REG,al ;;
-
- in al,PIC_MASK ;;
- or al,20h ;; mask IRQ 5 at the PIC
- out PIC_MASK,al ;;
- if XM
- call unlock_page@ ;; release paged memory
- endif
- sub al,al ;;
- xchg hd_int_expected,al ;; reset the byte if set
- or al,al ;;
-
- jnz yes_xios_exp ;; do flag_set/wait if
- ;; our XIOS wants it
- mov ax,xt_hd_isr_ax ;; else restore reg and
- pop ds
- iret ;; go back
-
- yes_xios_exp:
- ; Now tell the OS we're through:
- ; sti
- mov xt_hd_isr_ss,ss ;;
- mov xt_hd_isr_sp,sp ;;
-
- mov ss,sysdat$ ;;
- mov sp,offset xt_hd_isr_stack ;;
-
- ; Store all regs:
- push bx ! push cx ! push dx ;;
- push si ! push di ! push bp ;;
- push es ;;
-
- mov dx,HD_FLAG ;;
- call flagset@ ;;
-
- pop es ;;
- pop bp ! pop di ! pop si ;;
- pop dx ! pop cx ! pop bx ;;
-
- mov ss,xt_hd_isr_ss ;;
- mov sp,xt_hd_isr_sp ;;
- mov ax,xt_hd_isr_ax ;;
- jmpf dispatch_addr$ ;; do a dispatch now
- ;#IJ pop ds
- ;#IJ jmpf disp_addr$ ;; do a dispatch now
- endif
-
- eject
-
- int15_isr@:
- ;---------
- ; DEVICE-WAIT/POST interrupt service routine, used for hard disk flag-waiting
- ; if running on an AT:
- push ds ;; saver caller's DS
- mov ds,sysdat$ ;; DS -> SYSDAT
- cmp ax,9100h ;; hd device post?
- jne not_hd
- mov hd_timer$,TICKS_PER_SECOND ; reset our watchdog timer
-
- not_hd:
- test use_int15$,TRUE ;; CDOS flag system used (1st time)
- jz int15_skip ;; no, use hard waits in ROS
- cmp ax,9100h ;; hd device post?
- je int15_post ;; yes, convert to DEV_FLAGSET
- cmp ax,9000h ;; hd device wait?
- jne int15_skip ;; no, pass down to ROS
-
- int15_wait: ;; wait for hard disk interrupt
- push ax ! push bx ! push cx ! push dx
- push si ! push di ! push bp ! push es
-
- mov dx,HD_FLAG ;; wait for hard disk event
- call flagwait@
-
- pop es ! pop bp ! pop di ! pop si ;; restore all registers
- pop dx ! pop cx ! pop bx ! pop ax
- int15_skip:
- pop ds ;; restore caller's DS
- if V386
- cmp ah,88h
- jne int15_ros
- mov ax,cs
- push bp
- mov bp,sp
- cmp ax,4[bp]
- pop bp
- mov ah,88h ;; reload
- je int15_ros ;; its come from the XIOS goto ROS
- sub ax,ax ;; return no extended memory
- sti
- retf 2
- int15_ros:
- endif
-
- jmpf old_int15$ ;; now pass it on to ROS
-
- int15_post: ;; signal hard disk interrupt
- mov int15_ss,ss ;; switch to local stack
- mov int15_sp,sp
- mov ss,sysdat$
- mov sp,offset int15_tos
-
- push ax ! push bx ! push cx ! push dx
- push si ! push di ! push bp ! push es
-
- mov dx,HD_FLAG ;; wake up process waiting for HD
- call flagset@
- mov use_int15,FALSE ;; only do it once per INT 13h
-
- pop es ! pop bp ! pop di ! pop si ;; restore all registers
- pop dx ! pop cx ! pop bx ! pop ax
-
- mov ss,int15_ss ;; back to user stack
- mov sp,int15_sp
-
- pushf ;; emulate INT 15 to ROS handler
- callf old_int15
-
- jmpf dispatch_addr$ ;; do a dispatch now
- ;#IJ pop ds ;; restore caller's DS
- ;#IJ jmpf disp_addr$ ;; now pass it on to ROS
-
- eject
-
- old_int15$ rd 1 ; to continue if int 15 not for us
-
- ; *** XT hard disk driver data segment ***
- hdata0 dseg word
-
- ; XT hardware data:
- hd_port dw HD_PORT_BASE ; first or 2nd controller
- hd_cmd_blk$ db 0,0,0,0,0,0
- HD_CMD_COUNT equ offset $ - offset hd_cmd_blk$
-
- retry_fl db 0 ; use XT ROS or XIOS driver
-
- hd_timer$ db 0ffh ; Hard disk watchdog timer
- hd_error$ db 00h ; used to fix bug in some ROS's
-
- use_int15 db FALSE ; TRUE to use DEV_FLAGWAIT/FLAGSET once
-
- int15_cyl dw 0FFFFh ; cylinder accessed on last int 13h
-
- int15_sp rw 1 ; stack save area for POST
- int15_ss rw 1
-
- ; reg save area for int 15 hdisk posting:
- dw 0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
- dw 0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
- dw 0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
- dw 0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
- dw 0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
- dw 0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
- dw 0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
- dw 0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
- dw 0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
- dw 0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
- int15_tos rw 0
-
- if XM
- ; Stack switch area for XT hard disk interrupt:
-
- dw 0cccch,0cccch,0cccch,0cccch
- dw 0cccch,0cccch,0cccch,0cccch
- dw 0cccch,0cccch,0cccch,0cccch
- dw 0cccch,0cccch,0cccch,0cccch
-
- dw 0cccch,0cccch,0cccch,0cccch
- dw 0cccch,0cccch,0cccch,0cccch
- dw 0cccch,0cccch,0cccch,0cccch
- dw 0cccch,0cccch,0cccch,0cccch
-
- dw 0cccch,0cccch,0cccch,0cccch
- dw 0cccch,0cccch,0cccch,0cccch
-
- xt_hd_isr_stack rs 0
- xt_hd_isr_ss dw 0
- xt_hd_isr_sp dw 0
- xt_hd_isr_ax dw 0
- endif
-
- eject
-
- ; This block of data is shared by the
- ; XT hard disk driver and the FIDDS hooks.
-
- aux_drive$ rb 1 ; corrected drive code
- aux_code rb 1 ; select / rw multi-count
- aux_track rw 1
- aux_sector rw 1
- aux_dma_o rw 1
- aux_dma_s rw 1
- aux_longword equ dword ptr aux_dma_o
-
- aux_func rw 1 ; hd function code
- max_sector rw 1 ; mcnt loop limit
- block_byte_cnt rw 1 ; multi-sector byte counter
- block_mcnt rb 1 ; multi-sectors in this block
-
- hd_int_expected db 0 ; =FF if XIOS requested op.
-
- hdata1 dseg word
-
- hd_init_flag$ db 0 ; set at end of initialization
- hd_boot_flag$ db 0 ; temporarily save partition bootfl
-
- ; Tables of pertinent information about each possible disk:
- ; Each contains an entry defined by data structure HDINF_vector.
-
- hdinf_ptr$ dw 0000 ; logical hard disk drive pointer
- dw 0000 ; table into hd_disk_info vectors
- dw 0000 ; pointers installed in HD_INIT
- dw 0000 ; hard disk fix ups according to
- dw 0000 ; DOS partitions found on each drive.
- dw 0000
- dw 0000
- dw 0000
-
- hd_disk_info$:
- hd_info0$ db 0,0,0,0,0
- dw 0,0,offset hd_label0
- db 0 ; new pc logged byte!
- db 0 ; save physical drive number
- hd_info1$ db 0,0,0,0,0
- dw 0,0,offset hd_label1
- db 0 ; new pc logged byte!
- db 0 ; save physical drive number
- eject
-
-
- ; Pointer to ROS interrupt entry for XT hard disk:
- hd_rom_ofs$ rw 1
- hd_rom_seg$ rw 1
- hd_rom_entry equ dword ptr hd_rom_ofs$
-
-
- eject
-
- ; Funny thing, but the following buffers must not fall on a physical
- ; 64K boundary! Change the link line, or move them around if required
- ; and change the names if that works.
-
- hdata2 dseg para ; paragraph align
- ; Leave space for both label structures:
-
- ; no CP/M label sectors for 6.0
- hd_label0 rb 0
- hd_dpb0$ rb 0
- hd_label1 rb 0
- hd_dpb1$ rb 0
-
- hdata3 dseg word ; word align them
-
- ; The XT hard disk now shares its buffer with the floppies
-
- ; Sector buffer used by read/write routines when requested
- ; multi sector I/O operation crosses a 64K page boundary follows.
- ; Also used to read floppy size code from track 0 sector 0.
-
- local_buffer$ rw 1
-
- eject
-
- ;************************************************
- ;* *
- ;* PC MODE HARD DISK DRIVERS *
- ;* *
- ;************************************************
-
- cseg
-
- pc_select_hd@:
- ;------------
- ; PC DOS mode select hard disk.
- ; Logs in volume if first time select and if login succeeds, returns
- ; DPH pointer in the usual fashion.
-
- mov bl,cl
- xor bh,bh
- call pc_point_hdinf ; fix cl and si-->HDINF
- test HDINF_EXISTS[si],0ffh ; see if drive exists
- jz pc_login_err
- shl bx,1
- mov ax,dph_tbl$[bx] ; get drive DPH address
- jmps pc_login_ret
- pc_login_err:
- sub ax,ax ; 0 ret if select err
- pc_login_ret:
- mov bx,ax
- ret
- eject
-
- pc_read_hd@:
- ;----------
- ; PC DOS mode hard disk read routine:
-
- mov al,HD_ROS_READ
- jmps pc_read_write_hd ; ROS read function
-
- pc_write_hd@:
- ;-----------
- ; PC DOS mode hard disk write routine:
-
- mov al,HD_ROS_WRITE
- ; jmps pc_read_write_hd ; ROS write function
-
- pc_read_write_hd: ; common code
-
- cmp MCNT,0 ; is this a media check?
- jnz pc_no_check ; skip if actual read/write
- mov ax,1 ; else return "not changed"
- ret
-
- pc_no_check:
-
- mov bx,offset pc_hd_rw_iopb
- mov IBM_FN[bx],al ; set function in IOPB
- call iopb_adjust ; adjust for sector size > 512
- xor ch,ch
- mov cl,DRIVE ; set drive
- mov di,cx
- shl di,1
- mov di,dph_tbl$[di] ; get drive DPH address
- add di,DPH_SIZE ; DI -> label
-
- call pc_point_hdinf ; SI--> drive info
- ; mov ax,PC_HD_DPH_SIZE
- ; sub ch,ch
- ; mul cx
- ; mov di,(offset pc_hd_dphs)+DPH_SIZE
- ; add di,ax ; DI--> label
-
- mov cl,HDINF_PC_DRIVE[si] ; get physical drive number
- mov IBM_LUN[bx],cl ; PHYS. unit to IOPB
-
- mov ax,TRACK ; setup disk address
- mov dx,SECTOR
- mov cl,XT_PT_START_SECTOR[di] ; get sector/cyl offs
- and cl,03fh ; UNPACK IBM SECTOR off
- add dl,cl ; add to our sector #
- cmp dl,HDINF_SPT[si]
- jbe pc_hd_xlate1 ; check for track carry
- sub dl,HDINF_SPT[si] ; if found deal with it
- inc ax
- pc_hd_xlate1:
- mov IBM_SECTOR[bx],dl ; PHYS. sector to IOPB
- add al,XT_PT_START_HEAD[di]
- adc ah,0 ; in case we're uneven
- sub ch,ch
- mov cl,HDINF_HEADS[si] ; divide by # of heads
- cwd
- div cx ; track to CYL and HEAD
- mov cl,XT_PT_START_CYLINDER[di] ; get cylinder offset
- mov ch,XT_PT_START_SECTOR[di]
- rol ch,1 ! rol ch,1
- and ch,3 ; unpack top two bits
- add ax,cx ; add offset to cyl #
- mov IBM_CYLINDER[bx],ax
- mov IBM_HEAD[bx],dl
-
- mov ax,DMA_SEG ; set data xfer address
- mov IBM_XFER_SEG[bx],ax
- mov ax,DMA_OFF
- mov IBM_XFER_OFS[bx],ax
-
- ; The following is to get around the AT ROS bug described above:
- mov cl,MCNT ; get number of sectors
- mov pc_rw_count,cl ; save for our count
- call at_multi_count ; return max for AT
- mov MCNT,cl
- pc_rw_hd_again:
-
- call pc_hd_operation ; go do it
-
- mov ah,IBM_ERRCODE[bx] ; pick up extended err
- or al,al
- jnz pc_rw_hd_error ; if error, exit
-
- mov al,MCNT
- sub pc_rw_count,al ; count down our count
- jnz pc_rw_hd_again ; and repeat til 0
- xor ax,ax ; return success
- ret
-
- pc_rw_hd_error:
- mov al,1
- ret
-
- pc_point_hdinf:
- ; Return SI pointing to HDINF vector for cpm volume # in CL.
- ; and CL = physical drive number
- xor ch,ch
- sub cl,byte ptr num_flop_des$ ; hard disks start after floppy names
- mov si,cx
- shl si,1
- mov si,hdinf_ptr$[si]
- mov cl,HDINF_PC_DRIVE[si] ; get physical drive number
- ret
- eject
-
- iopb_adjust: ; adjust IOPB for large sector sizes
- ;-----------
- mov al,DRIVE ; get physical drive
- cbw
- xchg ax,di
- shl di,1 ; DI = drive*2
- mov di,dph_tbl$[di] ; DI -> DPH
- mov di,DPH_DPB[di] ; DI -> DPB
- mov ax,TRACK
- mul PCDPB_SPT[di]
- add ax,SECTOR
- adc dx,0 ; AX/DX = logical absolute sector
- mov cl,PCDPB_PSH[di]
- mov ch,0
- dec cx ! dec cx ; CX = log2 (sectorsize/512)
- jz iopb_adjust2 ; skip if sector size == 512
- iopb_adjust1:
- shl ax,1 ; double the sector address
- rcl dx,1
- shl MCNT,1 ; double the sector count
- loop iopb_adjust1 ; until sector size adjusted
- iopb_adjust2:
- div PCDPB_SPT[di] ; now convert to track/sector (##JC##)
- mov TRACK,ax
- mov SECTOR,dx
-
- ret
-
- eject
-
- pc_hd_operation:
- ;---------------
- ; Perform IO operation described by IOPB (perhaps as several operations)
- ; dealing transparently with all dma boundary crossing problems.
- ; Note: This routine is required to deal with the proprietary IBM
- ; DMA page register technique (patent pending) used in the PC.
-
- ; ENTRY BX--> IOPB
- ; DI--> PC_LBL
- ; SI--> HDINF
- ; EXIT: AL=0 if succeeds, else NZ
-
- mov dl,MCNT ; keep # still to xfer in dl
- push bx
- mov ax,IBM_XFER_SEG[bx]
- mov bx,IBM_XFER_OFS[bx]
- call comp_dma@ ; calculate 20 bit xfer address
- pop bx ; ax= # of bytes left in page
-
- push dx ; save count
- sub dx,dx
- div C_512 ; # of xfers left in page
- pop dx ; restore it count
- or ax,ax
- jz pc_hd_mid_xfer ; if 0 start with buffered xfer
- cmp al,dl
- jnc pc_hd_last_xfer ; if all fit, skip buffr'd xfer
- mov IBM_COUNT[bx],al ; else transfer as many as fit
- call pc_hd_do_it
- or al,al
- jnz pc_hd_op_err ; break if error
- sub dl,IBM_COUNT[bx] ; how many are still left?
- jz pc_hd_op_ok ; - NONE, exit
-
- pc_hd_mid_xfer:
- cmp IBM_FN[bx],HD_ROS_READ
- je pc_hd_mid_xfer1
- call pc_hd_to_buffer ; if write, move data to buff
- pc_hd_mid_xfer1:
- push IBM_XFER_SEG[bx] ; save xfer address
- push IBM_XFER_OFS[bx]
-
- mov ax,local_buffer$
- mov IBM_XFER_OFS[bx],ax
- mov IBM_XFER_SEG[bx],ds ; setup local transfer
- mov IBM_COUNT[bx],1
- call pc_hd_do_it
-
- pop IBM_XFER_OFS[bx] ; restore transfer ptrs
- pop IBM_XFER_SEG[bx]
- or al,al
- jnz pc_hd_op_err ; break if there was an error
-
- cmp IBM_FN[bx],HD_ROS_WRITE
- je pc_hd_mid_xfer2
- call pc_hd_from_buffer
- pc_hd_mid_xfer2:
- add IBM_XFER_OFS[bx],512
- dec dl
- jz pc_hd_op_ok ; dec mcnt and exit if done
-
- pc_hd_last_xfer:
- mov IBM_COUNT[bx],dl ; do one last long direct xfer
- call pc_hd_do_it
- or al,al
- jz pc_hd_op_ok
- pc_hd_op_err:
- mov al,0ffh
- jmps pc_hd_op_exit
- pc_hd_op_ok:
- xor ax,ax
- pc_hd_op_exit:
- ret
-
-
- pc_hd_from_buffer:
- ; Moves 512 bytes from local buffer to user buffer:
-
- push si ! push di ! push ds ! push es
- mov si,local_buffer$
- les di,IBM_XFER_PTR[bx]
- pc_hd_move1:
- cld
- mov cx,256
- rep movsw
- pop es ! pop ds ! pop di ! pop si
- ret
-
-
- pc_hd_to_buffer:
- ; Moves 512 bytes form user buffer to local buffer:
-
- push si ! push di ! push ds ! push es
- push ds ! pop es
- mov di,local_buffer$
- lds si,IBM_XFER_PTR[bx]
- jmps pc_hd_move1
-
-
- pc_hd_do_it:
- ; Does transfer and increments IOPB xfer pointer as needed:
-
- push bx ! push cx ! push dx
- call hd_rom@
- pop dx ! pop cx ! pop bx
- or al,al
- jnz pc_hd_doit_done
- push dx
- mov al,IBM_COUNT[bx]
- add IBM_SECTOR[bx],al
- sub ah,ah
- mul C_512
- add IBM_XFER_OFS[bx],ax
- hd_do_it_again:
- mov al,HDINF_SPT[si]
- cmp IBM_SECTOR[bx],al
- jbe pc_hd_do_it1
- sub IBM_SECTOR[bx],al
- inc IBM_HEAD[bx]
- mov al,HDINF_HEADS[si]
- cmp IBM_HEAD[bx],al
- jb hd_do_it_again
- sub IBM_HEAD[bx],al
- inc IBM_CYLINDER[bx]
- jmps hd_do_it_again
- pc_hd_do_it1:
- pop dx
- sub ax,ax
- pc_hd_doit_done:
- ret
- eject
-
- hdata4 dseg word
-
- C_512 dw 512 ; constant for word division
- pc_rw_count rb 1 ; for AT multi-sect. count down
- rb 1 ; pad for word align
-
-
- pc_hd_rw_iopb:
- db 0,0,0,0 ; fn,err,lun,head
- dw 0 ; cyl
- db 0,1 ; sector, count
- dw 0,0 ; xfer offset/seg
-
- end
-
- ; END OF HDISK.A86
-