Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 86/CONCURRENT/CCPM-86 3.1 SOURCE/D4/XHARD.LIB
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

897 lines
26 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

eject ; Dec 3, 1983
reorg14 equ offset $ ; save for code start
; this module now also includes the FIDDS hooks
;****************************************************************
;* *
;* HARD DISK DATA STRUCTURES *
;* *
;****************************************************************
; GLOBAL CONSTANTS
SLOW_SEEK equ 0 ;if -1, forces 3 ms step rate
IBM_SYS_ID equ 0AA55h ;partition label id word
HD_SYS_ID equ 0DBh ;(yours truly)
HD_VFY_ERR equ 0AAh ;artificial ROS error code
block_size equ 2048 ;remap block size
;also used for dpb phys sector
; XT HARD DISK DATA STRUCTURE DEFINITIONS
DSEG
; This IOPB is used to communicate with the ROS access routine "hd_rom"
; Note:some parameters are not EXACTLY as defined by IBM.
org 0
;IBM_iopb STRUCT
IBM_fn rb 1 ;ibm ROS function code (0 - 14d)
IBM_errcode rb 1 ;what is returned by ROS in AH
IBM_lun rb 1 ;unit number (0h or 1h)
IBM_head rb 1 ;head number only (0 - maxheads)
IBM_cylinder rw 1 ;entire cylinder number (0 - maxcyl)
IBM_sector rb 1 ;sector number only (0 - maxsector)
IBM_count rb 1 ;number of sectors to xfer (1 - 80h)
IBM_xfer_ofs rw 1 ;transfer buffer offset address
IBM_xfer_seg rw 1 ;transfer buffer segment address
IBM_XFER_PTR equ dword ptr ibm_xfer_ofs
HD_IOPB_SIZE equ offset $
;IBM_iopb ENDS
; definition of IBM XT hard disk partition table record
org 0
;XT_PT_record STRUCT
XT_PT_bootfl rb 1 ;80h if bootable
XT_PT_start_head rb 1 ;partition start info
XT_PT_start_sector rb 1 ; high 2 bits of cyl also
XT_PT_start_cylinder rb 1 ; low 8 bits only
XT_PT_system rb 1 ;system indicator (DB for cpm)
XT_PT_end_head rb 1 ;partition end info
XT_PT_end_sector rb 1 ; high 2 bits of cyl also
XT_PT_end_cylinder rb 1 ; low 8 bits only
XT_PT_rel_sect rw 2 ;start in absolute sectors
XT_PT_size rw 2 ;size in sectors
XT_PT_REC_SIZE equ offset $
;XT_PT_record ENDS
; definition of the overall IBM XT hard disk partition sector
org 0
;XTLBL_table STRUCT
XTLBL_code rb 1beh ;contains bootstrap code
XTLBL_part1 rb XT_PT_REC_SIZE ;partition record 1
XTLBL_part2 rb XT_PT_REC_SIZE ;partition record 2
XTLBL_part3 rb XT_PT_REC_SIZE ;partition record 3
XTLBL_part4 rb XT_PT_REC_SIZE ;partition record 4
XTLBL_id rw 1 ;contains signature (0aa55h)
;XTLBL_table ENDS
; This defines the CP/M label for a volume
org 0
;HDLB_label STRUCT
HDLB_chks rw 1 ;checksum
HDLB_id rb 31 ;contains dr copyright
HDLB_pstart rw 1 ;partition start cylinder
HDLB_plength rw 1 ;partition length in cylinders
HDLB_nheads rb 1 ;number of heads
HDLB_ibm_spt rb 1 ;ibm sectors per track
HDLB_cpm_options rb 1 ;lsb = 1 means write verify
HDLB_cpm_nsect rb 1 ;no longer used
HDLB_cpm_dpb: ;DPB
HDLB_cpm_spt rw 1 ;as per usual abbreviations
HDLB_cpm_bsh rb 1
HDLB_cpm_blm rb 1
HDLB_cpm_exm rb 1
HDLB_cpm_dsm rw 1
HDLB_cpm_drm rw 1
HDLB_cpm_al0 rb 1
HDLB_cpm_al1 rb 1
HDLB_cpm_cks rw 1
HDLB_cpm_off rw 1
HDLB_cpm_psh rb 1
HDLB_cpm_prm rb 1
HDLB_cpm_rsvd rw 2 ;for future use
HDLB_cpm_fudge rw 1 ;for cpm_off shift remainder
HDLB_map_ctl: ;remap table begins
HDLB_map_spb rw 1 ;# of ibm sectors per remap block
HDLB_map_max rw 1 ;# total length of table in entries
HDLB_map_cnt rw 1 ;# of currently active entries
HDLB_map_spare_end rw 1 ;last spare cpm relative block number
HDLB_map_table rw 1 ;beginning of remap table entries
HD_LABEL_SIZE equ 512
;HDLB_label ENDS
org 0
; this defines a table entry in the XIOS hard disk information table.
; it stores current status and limit information for the physical disk
;HDINF_vector STRUCT
HDINF_exists rb 1 ;means that hardware exists
HDINF_logged rb 1 ;currently logged in
HDINF_fixed rb 1 ;login indicated it is a fixed drive
HDINF_heads rb 1 ;number of heads (according to ROS)
HDINF_spt rb 1 ;sectors/track (according to ROS)
HDINF_cyl rw 1 ;max cylinders (according to ROS)
HDINF_enddir rw 1 ;last block of dir (in remap units)
HDINF_label_ofs rw 1 ;points to its label buffer
HDINF_SIZE equ offset $
;HDINF_vector ENDS
eject
;****************************************************************
;* *
;* HARD DISK DRIVER ROUTINES *
;* *
;****************************************************************
; These routines hook into M.P. Vano's drivers for CCP/M-86
; version 1.0. Every attempt has been made to mess with
; his code as little as possible. Some changes were made
; for different sector sizes and different dph's, but most
; of it is in the form envisioned by its creator.
; A new parameter HDLB_cpm_fudge has been added to take
; care of a problem arising in disk drives with other than
; a multiple of 4 heads. Grouping tracks in fours to fool
; CP/M into handling 2K physical sectors creates a problem
; in this case. The 2 bit shift of HDLB_cpm_off can relult
; in bits falling on the floor. HDLB_cpm_fudge saves those
; bits, and adds them back when converting to physical
; track number in hd_io:
cseg
org reorg14
; Select hard disk, save spt for multi sector count
select_hd:
sub cl,byte ptr num_flop
mov aux_drive,cl ; save drive code
mov aux_code,dl ; and which select
mov ax,0 ; select function code
call hd_driver ; login and select
test ax,ax ; if bad select
jz sel_hd1 ; then skip sector count
mov si,.8[bx] ; get dpb pointer
mov ax,[si] ; get sectors per track
mov max_sector,ax ; and save for mcnt
mov ax,bx ; restore dph
sel_hd1:
ret
; Hard disk read routine
read_hd:
mov aux_func,2 ; read function code
jmp read_write_hd ; jump to shared code
; Write to hard disk
write_hd:
mov aux_func,4 ; write function code
read_write_hd: ; shared code
call aux_param_set ; set up param block
mov ax,num_flop
sub aux_drive,al ; correct the drive code
rw_hd1:
mov ax,aux_func ; restore function code
call hd_driver
test al,al ; check for errors
jnz rw_hd3 ; skip if bad
dec aux_code ; check multi-count first
jz rw_hd3 ; and skip if done
mov ax,aux_sector ; increment the current
inc ax ; sector (and track if
cmp ax,max_sector ; necessary) for multi
jb rw_hd2 ; sector operations
inc aux_track
sub ax,ax ; reset sector
rw_hd2:
mov aux_sector,ax
add aux_dma_s,128 ; add to seg to avoid overflow
jmps rw_hd1 ; back for another sector
rw_hd3:
ret
; This routine sets up the "aux" parameter block
; It is shared by the FIDDS driver
aux_param_set:
mov al,drive
mov aux_drive,al
mov al,mcnt
mov aux_code,al ; use code for multi-count
mov ax,track
mov aux_track,ax
mov ax,sector
mov aux_sector,ax
mov ax,dma_seg
mov aux_dma_s,ax
mov ax,dma_off
mov aux_dma_o,ax ; save the works
ret
eject
;
; XTCODE.LIB: XT INTERIM XIOS HARD DRIVER CODE MODULE
;
; written for DRI by M.P. Vano
; Vano Associates, Inc.
; 24 May 1983
;
;
; This driver uses the XT ROM BIOS and so cannot relinquish the CPU
; during disk IO operations. This was done at the request of DRI to
; ensure compatibility with the ever-mysterious future plans of IBM.
;
; NOTE that although many data structures and routines of a highly
; general nature are used by this module, the behaviour of this driver
; is not defined except within the frame of reference of the existing
; 4 disk drives set by drive parameters in the XT ROS tables. In
; particular, the use of REMAP blocks of a size other than 2k will not
; succeed unless the XIOS is re-assembled for a different buffer size.
; In addition, binary multiples only are assumed for the ratio of
; CP/M to physical sector sizes supported.
;****************************************************************************
HD_HW_INTERRUPT equ 0dh ;IBM controller interrupt
HD_INTERRUPT equ 13h ;IBM entry point for hard disk
HD_PARMS_INTERRUPT equ 41h ;points to hard disk parms
HD_FD_INTERRUPT equ 40h ;ROS revectors floppy io here
HD_ROS_DATASEG equ 40h
HD_OPTION_ADDR equ 76h ;ibm controller option control
HD_PTR equ dword ptr HD_INTERRUPT * 4
hd_control_byte equ byte ptr HD_ROS_DATA_SEG*16 + HD_OPTION_ADDR
; Hard disk IO calls get vectored here from AUX DISK handler. The entry
; conditions are similar to an ATTACH-A-MATIC except that the aux drive
; parameter pointer is NOT setup.
;
; The GLOBAL XIOS variables AUX_CODE, AUX_TRACK, AUX_DRIVE,AUX_SECTOR
; AUX_LONGWORD must be directly accessed to specify the operation.
; AX has the function to execute as per attach-a-matic usage.
;
; CALLS: hd_seldsk,hd_read,hd_write
hd_driver:
mov hd_function,ax ;save for debug use
push es ! push ds
mov hd_uda,es
mov bx,ax ;save fnc code for jump
mov ax,HDINF_SIZE ;usually correct
mov cl,AUX_DRIVE ! and cl,1 ;keep in index range
mul cl ;si--> info vector[AUX_DRIVE]
mov si,offset hd_disk_info
add si,ax
; stack switch has been deleted here
call hd_fn_table[bx] ;do case(fn)
;
pop ds ! pop es
ret
; function # 0 2 4
hd_fn_table dw hd_seldsk, hd_read, hd_write
; if (!logged_in(info_ptr)) return 0 else return &(dph_array[vol])
; At entry, SI--> info array ptr for that drive and
; external globals AUX_DRIVE and AUX_CODE
; Since AUX_DRIVE is always valid when called, SI's HDINF pointer
; may be trusted.
;
; CALLS: hd_seldsk
hd_seldsk:
call hd_login ;if (!hd_login(info_ptr) return 0)
or al,al
mov ax,0
jz hd_seldsk_ret
mov al,AUX_DRIVE ;else return &dph_array[DPH_SIZE][,vol]
mov ah,dph_size
mul ah
add ax,offset hd_dph0
hd_seldsk_ret:
mov bx,ax
ret
; checks if current hard disk is logged in properly. If it is,
; it returns true. otherwise it tries to log it in and if it can't
; it returns false. The same happens for out of range requests.
; NOTE that this routine is called from INIT also. It takes as input
; the global AUX_DRIVE and the HDINF pointer for that drive in SI.
;
; CALLS: hd_get_partition,hd_read_label,hd_patch_dpb
hd_login:
test HDINF_exists[si],0ffh ;is the hardware there?
jz hd_login_err ;if not, don't go any farther
test HDINF_logged[si],1 ;has it ever been logged-in?
jz hd_log_it_in ; if not, go try to do it
test HDINF_fixed[si],1 ;else don't not be too hasty...
jnz hd_login_ok ; labels on fixed can't change
test AUX_CODE,1 ;even a removable only needs
jnz hd_login_ok ;re-login on first access
;
hd_log_it_in: ;really needs to be logged in
mov HDINF_logged[si],0 ;mark it unlogged
call hd_get_partition ;read IBM's master table
or al,al
jnz hd_login_err ;can't read table or no cp/m
call hd_read_label ;else go look for XIOS label
or al,al ;can't read or doesn't exist
jnz hd_login_err
call hd_patch_dpb ;fix up dpbs for ver 2
hd_login_ok:
mov al,0ffh ! ret ;else tell caller we found it
hd_login_err:
xor al,al ! ret ;return false if we fail
; read partition table into label area and find partition if one exists
; uses cp/m label buffer as temporary bufer
; returns 0 in al if succeeds, else nz
; CALLS: hd_rom
hd_get_partition:
mov bx,offset hd_rd_partition_iopb ;setup iopb
mov al,AUX_DRIVE ;setup fields that vary
mov IBM_lun[bx],al
mov IBM_cylinder[bx],0
mov IBM_sector[bx],1 ;always has label
mov ax,HDINF_label_ofs[si] ;get the correct buffer
mov IBM_xfer_ofs[bx],ax
mov IBM_xfer_seg[bx],ds
call hd_rom ;read partition table
or al,al
jnz hd_get_partition_ret ;oops, disk error.
;
push si
mov si,HDINF_label_ofs[si] ;inspect table
cmp XTLBL_id[si],0aa55h ;is it there at all?
jnz hd_bad_partition
lea si,XTLBL_part1[si] ;scan for cp/m
mov cx,4
hd_partition_hunt:
cmp XT_PT_system[si],HD_SYSID ; is it our magic code?
je hd_partition_found
add si,XT_PT_REC_SIZE ;else keep on looking
loop hd_partition_hunt
jmps hd_bad_partition ;else return the bad news
;
hd_partition_found: ;setup same iopb for label read
mov al,XT_PT_start_cylinder[si] ;adjust the disk address
mov ah,XT_PT_start_sector[si] ;fix up cylinder address
rol ah,1 ! rol ah,1 ! and ah,3
mov IBM_cylinder[bx],ax
mov hd_pstart_cyl,ax ;save to check later
mov IBM_sector[bx],4 ;cp/m label is always here
;
mov al,XT_PT_end_cylinder[si]
mov ah,XT_PT_end_sector[si]
rol ah,1 ! rol ah,1 ! and ah,3
mov hd_pend_cyl,ax ;save to check later
test XT_PT_start_head[si],0ffh ;should start at head 0
jnz hd_bad_partition ;else exit with error
mov al,XT_PT_start_sector[si] ;only 1 or 2 are legal
dec al
and al,not 0c1h ;ignore irrelevant bits
jnz hd_bad_partition
pop si ;else it must be ok
xor al,al
jmps hd_get_partition_ret ;so exit with success code
;
hd_bad_partition:
pop si
mov al,0ffh
hd_get_partition_ret:
ret
; reads cpm label into label area and checks for integrity
; iopb has already been set up by hd_get_partition
; returns 0 in al if succeeds, else nz.,
; CALLS: hd_rom,hd_check_label
hd_read_label:
mov bx,offset hd_rd_partition_iopb ;setup iopb
call hd_rom ;try to read label
or al,al ;disk error?
jnz hd_read_label_ret ;(probably MICROSOFT sabotage)
;
call hd_check_label ;check label's integrity
or al,al
jnz hd_read_label_ret ;label or programmer is strange
;
mov di,HDINF_label_ofs[si] ;update HDINF
mov al,0ffh ;assume fixed disk
cmp HDLB_cpm_cks[di],8000h ;fixed?
je hd_read_label1 ;yep, go ahead
not al ;can't win them all
hd_read_label1:
mov HDINF_fixed[si],al ;set fixed flag as needed
mov HDINF_logged[si],0ffh ;I pronounce thee "logged"
xor al,al
hd_read_label_ret:
ret
; verifies integrity of cp/m label block of disk si--> HDLB pointer of
; returns 0 if succeeds, else nz value in ax
; CALLS: NOTHING
hd_check_label:
push si ! mov si,HDINF_label_ofs[si] ;get pointer to label
;
push si ;checksum it first
mov cx,HD_LABEL_SIZE/2
xor bx,bx ;clear checksum accum.
hd_check_cks:
lodsw
add bx,ax
loop hd_check_cks ;verify its checksum
pop si
jnz hd_check_error ;exit if bad checksum
;
push si ! push es
push ds ! pop es
mov cx,length (hd_idstring) ;check the id string
lea si,HDLB_id[si]
mov di,offset hd_idstring
repe cmpsb
pop es ! pop si
mov ax,0 ! je hd_check_exit ;exit here if id matches
hd_check_error: ;else error
mov ax,-1
hd_check_exit:
pop si
ret
; correct the hard disk dpb's for concurrent version 2.0
; this changes physical sector size from 128 to 2048 bytes
; spt = old spt / 4; psh = 2; prm = 3
hd_patch_dpb:
push si ; save info ptr just in case
mov si,HDINF_label_ofs[si] ; point to label (and dpb's)
mov cl,2 ; for divide by 4
shr HDLB_cpm_spt[si],cl ; for larger physical sectors
mov ax,HDLB_cpm_off[si]
and ax,0003h ; save remainder from shift
mov HDLB_cpm_fudge[si],ax ; for retranslate to physical
mov cl,2
shr HDLB_cpm_off[si],cl ; group tracks by 4's
mov HDLB_cpm_psh[si],4 ; physical sector shift
mov HDLB_cpm_prm[si],15 ; physical sector mask
mov HDLB_map_spb[si],4 ; 512 * 4 = 2k block
pop si
ret
; hard disk physical read
hd_read:
call hd_xlate_request ; do block remap
mov bx,offset hd_rd_iopb ; read parameters
call hd_dma_check ; check for overflow
jc hd_read1 ; if no problem then
jmp hd_dma_io ; read right to dma
hd_read1:
call hd_local_io ; if dma boundary error
or al,al ; read to local first
jnz hd_read2 ; done if error
push es ; if read is good
push si ; then move to dma
mov si,offset hd_local_buf
les di,AUX_LONGWORD
mov cx,block_size/2
rep movsw
pop si
pop es
hd_read2:
ret
; hard disk physical write
hd_write:
call hd_xlate_request ; do block remap
mov bx,offset hd_wr_iopb ; go load iopb and do it
call hd_dma_check ; check for boundary error
jnc hd_write1 ; skip if dma ok
push ds ; if boundary trouble then
push es ; move data to local buffer
push si
mov di,offset hd_local_buf
push ds
pop es ; local destination
lds si,AUX_LONGWORD
mov cx,block_size/2
rep movsw
pop si
pop es
pop ds
call hd_local_io ; write from local buffer
jmps hd_write2 ; skip to error check
hd_write1:
call hd_dma_io
hd_write2:
or al,al
jnz hd_write_exit ; exit here if failed
;
push si
mov si,HDINF_label_ofs[si]
test HDLB_cpm_options[si],1
pop si
jz hd_write_exit ;no, just exit (al still valid)
;
mov bx,offset hd_vfy_iopb ;else run verify cycle
mov IBM_fn[bx],2 ;IBM read opcode
call hd_local_io
or al,al ;did read-after-write fail?
jnz hd_write_exit ;yes, no point in comparing
;
mov IBM_fn[bx],4 ;fake verify opcode for msgs
push es ;else compare buffers
push si
les di,AUX_LONGWORD ;dma segment:offset
mov si,offset hd_local_buf
mov cx,block_size/2
repe cmpsw
pop si
pop es
mov al,0 ;assume success
je hd_write_exit ;if matched, exit
mov IBM_errcode[bx],HD_VFY_ERR ;else fake a physical error
call hd_error_handler ;and see what operator wants
cmp al,'R' ;retry?
je hd_write ;yep, go back to the top
hd_write_exit:
ret
; translate global AUX_TRACK,AUX_SECTOR and hd_disk into remapped units
; and finds alternate block if that block is in remap table
; (updates global variables hd_req_block, hd_req_sec)
; CALLS: NOTHING
hd_xlate_request:
push si
mov si,HDINF_label_ofs[si] ;get label for this disk
;
mov ax,AUX_TRACK ;ax=CPM_TRACK-cpm_offset
sub ax,HDLB_cpm_off[si]
mul HDLB_cpm_spt[si] ; * cpm_spt
add ax,AUX_SECTOR ; + CPM_SECTOR
;
; using 2k physical sectors, ax now equals logical block number
;
mov cx,HDLB_map_cnt[si] ;see if that block is in table
jcxz hd_no_remap ;(skip if table is empty)
push es ! mov dx,ds ! mov es,dx
cld ! lea di,HDLB_map_table[si] ;by scanning table
repne scasw
pop es
jne hd_noremap ;no, leave block number alone
inc cx ! sub cx,HDLB_map_cnt[si] ;else calculate replacement
mov ax,HDLB_map_spare_end[si]
add ax,cx
hd_noremap:
mov hd_req_block,ax ;update parameter and exit
pop si
ret
; check dma addresses for boundary errors. set carry if bad
hd_dma_check:
mov ax,AUX_DMA_S ; get segment
mov cl,4 ; convert to offset
shl ax,cl ; ignoring ms nibble
add ax,AUX_DMA_O ; add in segment
add ax,block_size ; set carry on overflow
ret
; entry point for read or write. transfers to and from dma buffers
hd_dma_io:
mov ax,AUX_DMA_O
mov IBM_xfer_ofs[bx],ax ; save offset
mov ax,AUX_DMA_S
mov IBM_xfer_seg[bx],ax ; save segment
jmps hd_io
; entry point for local read or write
hd_local_io:
mov IBM_xfer_ofs[bx],offset hd_local_buf
mov IBM_xfer_seg[bx],ds ; local segment
; jmps hd_io ; fall through
; fills in the volume,head and cyl fields in passed IBM_IOPB from
; current request using CURRENT HDINF pointer and executes rom operation
; CALLS: hd_rom
hd_io:
push si
mov si,HDINF_label_ofs[si]
mov al,AUX_DRIVE
mov IBM_lun[bx],al
mov ax,hd_req_block ;back to IBM format
;
mul HDLB_map_spb[si] ;ibm_block=(block * remap_spb)
;
mov ch,0 ;for full divide
mov cl,HDLB_ibm_spt[si] ;ibm_rel_track=ibm_block/ibm_spt
xor dx,dx ! div cx ;CAUTION!! 16 bit result
;
inc dl ;save remainder as ibm sector
mov IBM_sector[bx],dl ; (except they start with 1)
;
mov dx,HDLB_cpm_off[si] ;get fake track offset
shl dx,1 ; and change it back to physical
shl dx,1 ; track number
add ax,dx ;correct offset
add ax,HDLB_cpm_fudge[si] ;remainder from offset shift
;
mov cl,HDLB_nheads[si] ;ibm_cyl= ibm_track/nheads
xor dx,dx ! div cx ;CAUTION!! 16 bit result
mov IBM_cylinder[bx],ax
mov IBM_head[bx],dl ;ibm_head=ibm_track % nheads
pop si
; jmps hd_rom ;fall through
; 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
hd_rom:
push es ! push si ;save uda and HDINF_ptr then execute
mov cx,3 ;set 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 ;Next ANSI hard disk command standard!
mov cx,IBM_cylinder[bx] ; SCRewed-Up Microcomputer
xchg ch,cl ; Parameter Interface - SCRUMPI ?
ror cl,1 ! ror cl,1 ; (SERIOUSLY now, why would anyone do
and cl,0c0h ; something this way?)
or cl,IBM_sector[bx]
les bx,IBM_XFER_PTR[bx]
pushf ! callf HD_ROM_ENTRY ;fake an SWI call to ROM
pop bx ! pop cx ;restore IOPB ptr and retry counter
mov IBM_errcode[bx],ah ;save error return
mov al,0 ! jnc hd_rom1 ;and exit if no error
;
push cx ! push bx ! ;reset drive on any error ??
mov ah,0dh ;registers are still ok
pushf ! callf HD_ROM_ENTRY
pop bx ! pop cx
loop hd_rom_retry ;then try automatic retries first
;
mov al,IBM_errcode[bx] ;else get error code back and exit
hd_rom1: ;result shold be in al here
pop si ! pop es
or al,al ! jz hd_rom_done ;return if no error
test hd_init_flag,1 ;if during MPM initialization,
jz hd_rom_done ; return error immediately
call hd_error_handler ;else report it to operator
cmp al,'R' ! jz hd_rom ;does he wish to try more?
hd_rom_done:
ret ;else return to caller
; dummy ROM BIOS SWI used by hard disk ROM (always succeeds)
; CALLS: NOTHING
hd_dummy_int:
sti ! xor ax,ax ! retf 2
; Display hard disk error and gets operator's response.
; entry: al = error code
; exit: al = 00h for ignore
; FFh for accept
; 'R' for retry
hd_error_handler:
mov disk_error,al ; save for sub message
jmp do_disk_error ; in the floppy code
eject
;********************************************************
;* *
;* FIELD INSTALLABLE DEVICE DRIVER HOOKS *
;* *
;********************************************************
; FIDDS select disk
sel_fid:
mov aux_drive,cl ; save drive number
mov aux_code,dl ; and select code
sub ax,ax ; ax = 0 for select
jmps fidds_go ; interrupt away
read_fid:
call aux_param_set ; drive, track, sect, etc.
mov ax,2 ; ax = 2 for read
jmps fidds_go ; interrupt away
write_fid:
call aux_param_set ; same as for read
mov ax,4 ; ax = 4 for write
; jmps fidds_go ; interrupt away
; FIDDS take off point
fidds_go:
mov ax,num_flop
add ax,num_hard ; calc fidds offset
sub aux_drive,al ; zero base the drive code
mov dx,ds ; dx:bx -> param block
mov bx,offset aux_drive
int fidds_interrupt ; see you later...
ret
; Dummy FIDDS interrupt routine for non-disks
i_dummy_fidds:
sub ax,ax ; zero for no select
iret
; Interrupt to return the lowest numbered unused system
; flag to FIDDS, to be used for a flagwait to eternity.
i_fidds_flag:
;
mov al,0 ;; FORCE THE ZERO FLAG, FIDDS NOT SUPPORTED
mov cs:top_flag,al ;; AND MAKE SURE IT STAYS THAT WAY
;
; mov al,cs:top_flag ; get the next available
;
test al,al ; if it's zero,
jz i_f_flag_done ; then forget it
inc al ; increment to the next
cmp al,cs:n_flags ; if we've gone too far
jb i_f_flag_ok ; then reset to zero
mov al,0
i_f_flag_ok:
mov cs:top_flag,al ; for next time
i_f_flag_done:
iret
top_flag db last_flag ; used by i_fidds_flag
eject
reorg_hard_data equ offset $
dseg
org reorg_hard_data
; *** XT hard disk driver data segment ***
; 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 ; for mcnt loops
; general information variables
hd_ndisks db 0 ;amount of IRON found only!
hd_uda dw 0 ;stores UDA at entry to hd routines
hd_init_flag db 0 ;set at end of initialization
hd_pstart_cyl dw 0 ;used to cross-check labels
hd_pend_cyl dw 0 ; for consistency with each other
hd_function dw 0 ;used fo debug trace info only
; desired block buffer contents
; hd_req_vol is global AUX_DRIVE
hd_req_block dw 0 ;requested BLOCK / physical sector
; tables of pertinent information about each possible disk
; each contains an entry defined by data structure HDINF_vector
hd_disk_info:
hd_info0 db 0,0,0,0,0
dw 0,0,offset hd_label0
hd_info1 db 0,0,0,0,0
dw 0,0,offset hd_label1
; iopbs used to do ROM BIOS IO
; CAUTION: these are only templates, it is the user's responsibility
; to make sure they are FULLY filled in with meaningful information
hd_wr_iopb db 3,0,0,0 ;fn,err,lun,head
dw 0 ;cylinder
db 0,4 ;sector,count
dw 0,0 ;xfer offset,seg
hd_rd_iopb db 2,0,0,0 ;fn,err,lun,head
dw 0 ;cylinder
db 0,4 ;sector,count
dw 0,0 ;xfer offset,seg
hd_vfy_iopb db 2,0,0,0 ;fn,err,lun,head
dw 0 ;cylinder
db 0,4 ;sector,count
dw 0,0 ;xfer offset,seg
hd_rd_partition_iopb db 2,0,0,0 ;fn,err,lun,head
dw 0 ;cylinder
db 0,1 ;sector,count
dw 0,0 ;xfer offset,seg
; string used to verify label authenticity
hd_idstring db '(C) 1983 DIGITAL RESEARCH, INC.'
; 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
org offset $+1 and 0fffeh ;word align it
; allocation vectors, etc. for XT hard disks
hd_dph0 dw 0,0,0,0,HD_DPB_INIT
dw 0,0ffffh,0ffffh,0ffffh,0ffffh
hd_dph1 dw 0,0,0,0,HD_DPB_INIT
dw 0,0ffffh,0ffffh,0ffffh,0ffffh
dph_size equ 20
; this is a dummy dpb which is used by genccpm for
; dph allocation, check vector, and hash table calculations
HD_DPB_INIT dw 11h ; spt
db 05h ; bsh 4k blocks
db 1Fh ; blm "
db 01h ; exm
dw 0A20h ; dsm 10 meg maximum
dw 03FFh ; drm
dw 0FFFFh ; al0 and al1
dw 8000h ; cks fixed disk
dw 01h ; off
db 04h ; psh
db 0Fh ; phm
org offset $+15 and 0fff0h ;align them
; leave space for both label structures
hd_label0 rb 512
hd_label1 rb 512
HD_DPB0 equ byte ptr hd_label0 + offset HDLB_cpm_dpb
HD_DPB1 equ byte ptr hd_label1 + offset HDLB_cpm_dpb
org offset $+1 and 0fffeh ;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.
; Also used to read floppy size code from track 0 sector 0.
hd_local_buf rb 0
local_buffer rb bytes_per_sector - 1
floppy_type rb 1
rest_of_buf rb block_size - bytes_per_sector