home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0010 - 0019 / ibm0010-0019 / ibm0010.tar / ibm0010 / CDOSDSK4.ZIP / CDOSDSK4.TD0 / XIOS / HDISK.A86 < prev    next >
Encoding:
Text File  |  1989-01-26  |  27.3 KB  |  1,097 lines

  1. ; HDISK.A86
  2. title 'HARD Disk Driver'
  3. pagesize 60+11
  4. ;****************************************
  5. ;*                    *
  6. ;*    HARD DISK ROUTINES        *
  7. ;*    CDOS 6.0 XIOS            *
  8. ;*    DRI OS ENGR, JMB, GMS, JW    *
  9. ;*                    *
  10. ;****************************************
  11. ; Mods:
  12. ; 6.x
  13. ;  5 JAN 89 -- fix to cure problem with hard disk reads on certain - GMS
  14. ;        machines, where the ROS loses a Hard disk INT.
  15. ;  7 NOV 88 -- always check for buggy ROS read errors on all AT's - GMS
  16. ; 22 Jul 88 -- use new dispatcher                - IJ
  17. ; 11 FEB 88 -- if 386 return no extended memory from int 15h     - GMS
  18. ; 6.0
  19. ; 23 JUL 87 -- don't test AT HD DRQ if add-on disk controller     - JW
  20. ; 17 JUL 87 -- converted XIOS to small model             - JW
  21. ; 17 JUL 87 -- Removed last HD_SPT for RLL and IBM ESDI drives     - GMS/JC
  22. ; 23 JUN 87 -- CP/M hd label buffers removed for 6.0         - JW
  23. ; 5.2
  24. ; 28 JAN 87 -- CDOS 386 code added                 - GMS
  25. ; 5.1
  26. ; 18 AUG 86 -- Multiple DOS partion and >32 mg partition support - GMS
  27. ; 12 AUG 86 -- NSEOI to SEOI (thx RH,JF)
  28. ; 22 APR 86 -- test HD DRQ bit on return from ROS to ID AT buffer bug
  29. ; 22 JAN 86 -- lock paged memory around DMA ops.
  30. ; 25 SEP 85 -- dress up error handling for XTs
  31. ; 19 SEP 85 -- change HD DPHS, INIT now allocates ALV and data buffs
  32. ; 17 SEP 85 -- remove previously installed AT POST/WAIT
  33. ;  4 SEP 85 -- insert our own XT hd driver
  34. ;  1 AUG 85 -- move sector buffer location to miss 64K boundary
  35. ;        -- doesn't work...change link line.
  36. ; 27 JUN 85 -- convert mov reg,0 to sub reg,reg if poss.
  37. ; 12 JUN 85 -- update 4.1 ASM86 source to RASM86
  38.  
  39. ; include COPYRITE.TXT
  40.  
  41. nolist
  42. include CDOS.EQU
  43. include XIOS.EQU
  44. include PCHW.EQU
  45. include ASCII.EQU
  46. list
  47. ; These have been included:
  48. ; include PCHW.EQU
  49. ; include CDOS.EQU
  50. ; include XIOS.EQU
  51. ; include ASCII.EQU
  52.  
  53. CGROUP    group    CODE
  54. DGROUP    group    hdata0,hdata1,hdata2,hdata3,hdata4
  55.  
  56. public    hd_dummy_int@
  57. public    pc_read_hd@,    pc_write_hd@,    pc_select_hd@
  58. public    hd_rom@
  59.  
  60. public    hd_rom_ofs$,    hd_rom_seg$,    local_buffer$
  61. public    hd_disk_info$,    hdinf_ptr$
  62. public    hd_init_flag$,    hd_boot_flag$
  63. public    aux_drive$
  64. public    old_int15$,    int15_isr@            ; for INIT.A86
  65. public    hd_timer$,    hd_error$            ; for ISRS.A86
  66.  
  67. if XM
  68. public    xt_driver@,    hd_cmd_blk$            ; XT's only - not 386
  69. public    hd_isr@
  70. endif
  71.  
  72. eject
  73.  
  74.     dseg
  75. extrn    dph_tbl$    :word                ; in HEADER.A86
  76. extrn    num_flop_des$    :byte,    num_hard$    :byte    ; in PUBDATA.A86
  77. extrn    disk_int_off$    :word
  78. extrn    disk_error$    :byte                ; in FLOPPY.A86
  79. extrn    pc_at$        :byte
  80.  
  81.  
  82.     cseg
  83. extrn    sysdat$        :word                ; in HEADER.A86
  84. extrn    flagwait@    :near
  85. extrn    flagset@    :near
  86. extrn    disp_addr$    :dword
  87. extrn    do_disk_error@    :near                ; in FLOPPY.A86
  88. extrn    comp_dma@    :near
  89. if XM
  90. extrn    lock_page@    :near, unlock_page@:near    ; in EMM.A86
  91. endif
  92. eject
  93.  
  94.     cseg
  95.  
  96.  
  97. at_multi_count:
  98. ; Set multi-sector count for PC, XT or AT:
  99. ;  Entry:    bx -> iopb
  100. ;        cl = multi-count
  101. ;  Exit:    cl = max allowable count
  102.  
  103. if 0
  104.     test    pc_at$,01h
  105.      jz    at_multi_done            ; if not AT or clone, then skip
  106.     cmp    IBM_FN[bx],HD_ROS_READ
  107.      jnz    at_multi_done            ; if not read, then skip
  108.  
  109. ; If the machine is an AT with the buggy ROS, leave the multi-count as it
  110. ; is, because our timer isr will know to avoid dispatches if the buggy window
  111. ; has been interrupted.  If AT or clone, but we weren't able to ID the bug
  112. ; string, we must enforce the single-sector i/o to be safe.
  113.  
  114.     test    pc_at$,80h            ; this bit is set in init. 
  115.      jnz    at_multi_done            ; jump if set
  116.                     
  117.     mov    cl,1                ; else one at a time
  118. at_multi_done:
  119. endif
  120.     ret
  121.  
  122.  
  123. hd_rom@:
  124. ; Provides easy access to HDISK ROM.
  125. ; Call with ds:bx--> IBM_iopb structure as defined elsewhere.
  126. ; Returns zero set if succeeds, else non-zero.
  127. ; CALLS:  hd_error_handler
  128.  
  129.     push es ! push si            ; save uda and HDINF_ptr then execute
  130.  
  131.     mov    cx,IBM_XFER_SEG[bx]        ; must lock page if req'd
  132.     mov    dx,IBM_XFER_OFS[bx]
  133.     mov    ax,SECTOR_SIZE            ; 512
  134.     mul    IBM_COUNT[bx]            ; byte
  135. if XM
  136.     cmp    hd_rom_seg$,0F000h        ; do we use an add-on controller?
  137.      jne    do_lock                ; yes, might use DMA
  138.     test    pc_at$,0ffh            ; if AT, no hdisk dmaing
  139.      jnz    skip_lock
  140. do_lock:
  141.     push    bx                ; save pointer
  142.     call    lock_page@            ; will lock if needed
  143.     pop    bx
  144. endif
  145. skip_lock:
  146.     mov    cx,3                ; set auto retry count
  147.  
  148. hd_rom_retry:                    ; inner retry loop
  149.     push cx ! push bx            ; save retry counter & IOPB
  150.     mov    ah,IBM_FN[bx]
  151.     mov    al,IBM_COUNT[bx]        ; load up registers for ROM call
  152.     mov    dh,IBM_HEAD[bx]
  153.     mov    dl,IBM_LUN[bx]
  154.     or    dl,80h
  155.     mov    cx,IBM_CYLINDER[bx]        ; get cylinder (0-1023)
  156.     cmp    cx,int15_cyl            ; same cylinder as last time
  157.      je    hd_rom_noseek            ; yes, should be quick
  158.     mov    use_int15,TRUE            ; else use DEV_WAITFLAG
  159.     mov    int15_cyl,cx            ; and update current cylinder
  160. hd_rom_noseek:
  161.     xchg    ch,cl
  162.     ror cl,1 ! ror cl,1
  163.     and    cl,0c0h
  164.     or    cl,IBM_SECTOR[bx]
  165.     les    bx,IBM_XFER_PTR[bx]
  166.  
  167.     mov    hd_error$,00            ; reset error flag
  168.     mov    hd_timer$,TICKS_PER_SECOND    ; set off our own watchdog
  169.     test    pc_at$,0ffh            ; if not AT increase timer count
  170.     jnz    hd_rom_go
  171.     mov    hd_timer$,TICKS_PER_SECOND*2    ; set off our own watchdog
  172.     
  173. hd_rom_go:
  174.  
  175.     pushf
  176.     callf    hd_rom_entry            ; fake an SWI call to ROM
  177.     mov    hd_timer$,0ffh            ; reset watchdog
  178.     pop bx ! pop cx                ; restore IOPB ptr and retry counter
  179.     pushf
  180.     cmp    hd_error$,0            ; did we force a timeout error
  181.     je    no_timeout    
  182.     popf
  183.     xor    ah,ah
  184.     xchg    ah,hd_error$
  185.     mov    IBM_ERRCODE[bx],ah        ; save error return
  186.     mov    al,0
  187.      jmp    hd_rom01            ; and do error retry
  188. no_timeout:
  189.     popf
  190.     mov    IBM_ERRCODE[bx],ah        ; save error return
  191.     mov    al,0
  192.      jc    hd_rom01            ; and jump if error
  193.  
  194.     cmp    hd_rom_seg$,0F000h        ; do we use an add-on controller?
  195.      jne    hd_rom1                ; yes, don't touch the hardware
  196.  
  197. ;;    cmp    pc_at$,81h            ; buggy ROS?
  198. ;;     jne    hd_rom1                ; jump if no
  199.     test    pc_at$,01            ; always do the check on all AT's
  200.     jz    hd_rom1
  201.      
  202.     push    dx                ; Here if we need to check for
  203.     mov    dx,AT_HD_STATUS            ;  a ROS bug, where pending
  204.     in    al,dx                ;  data is left in the sector
  205.     pop    dx                ;  buffer.
  206.     test    al,AT_HD_DRQ            ; something in sector buffer?
  207.     mov    al,0
  208.      jz    hd_rom1                ; jump if no error
  209.  
  210. ; Here if there was an error...set the retry flag so that instead of the
  211. ;  limited XT driver here in the XIOS, we use ROS to return the correct
  212. ;  error codes.
  213. hd_rom01:
  214.     mov    retry_fl,0ffh            ; indicate to the XT driver
  215.  
  216.     push cx ! push bx            ; reset drive on any error ??
  217.      mov    ah,HD_ROS_RESET1        ; registers are still ok
  218.      pushf
  219.      callf    hd_rom_entry
  220.     pop bx ! pop cx
  221.  
  222. ;;;;    loop    hd_rom_retry            ; then try automatic retries first
  223.     dec    cx
  224.     jz    done_retries
  225.     jmp    hd_rom_retry
  226. done_retries:
  227.     mov    al,IBM_ERRCODE[bx]        ; else get error code back and exit
  228. hd_rom1:
  229.     mov    retry_fl,0            ; reset for next time
  230. if XM
  231.     call    unlock_page@            ; release paged memory
  232. endif
  233.     pop si ! pop es
  234.     or    al,al
  235.      jz    hd_rom_done            ; return if no error
  236.     test    hd_init_flag$,1            ; if during OS initialization,
  237.      jz    hd_rom_done            ;  return error immediately
  238.  
  239.     push bx ! push si
  240.     call    hd_error_handler        ; else report it to operator
  241.     pop si ! pop bx
  242.     cmp    al,'R'
  243.      jmpz    hd_rom@                ; does he wish to try again?
  244.  
  245. hd_rom_done:
  246.     ret                    ; else return to caller
  247.  
  248.  
  249. hd_dummy_int@:
  250. ; Dummy ROM BIOS SWI used by hard disk ROM (always succeeds).
  251. ; CALLS:  NOTHING
  252.  
  253.     sti
  254.     xor    ax,ax
  255.     retf    2
  256.  
  257.  
  258. hd_error_handler:
  259. ; Display hard disk error and gets operator's response.
  260. ;  entry:    al = error code
  261. ;  exit:    al = 00h for ignore
  262. ;             FFh for accept
  263. ;             'R' for retry
  264.  
  265.     mov    disk_error$,al            ; save for sub message
  266.     jmp    do_disk_error@            ; in the floppy code
  267. eject
  268.  
  269. to_ros:
  270.     jmpf    dword ptr disk_int_off$    ; enter ROS through the
  271.                     ;  vector used for HDMAINT and DSKMAINT
  272.     
  273. if XM
  274. xt_driver@:
  275. ;----------
  276. ; Routine to emulate the ROS driver in an XT to allow flagwaits and sets.
  277. ; This code is used when running on an XT.  If the machine is an AT, we
  278. ; use the ROS driver, with the addition of the device-post/wait implementation
  279. ; in int 15h.  (ref. AT Tech. Ref. Manual) (removed 9-17-85)
  280. ; This routine only performs READS and WRITES...all other functions (the
  281. ; only other one called by the HDISK code above seems to be RESET) continue
  282. ; on to the ROS.  To save space, we don't do any error diagnostics, always
  283. ; reporting BAD ADDR MARK on any error. 9-24-85.
  284.  
  285. ; Entry:
  286. ;  Registers setup per ROS hd driver, int 13h.
  287. ; Exit:
  288. ;  With IRET.
  289.  
  290.     test    retry_fl,0ffh        ; are we in the error retry cycle?
  291.      jnz    to_ros            ; if so, use the ROS to return correct
  292.                     ; errors.
  293.     cmp    ah,HD_ROS_READ        ; for us?
  294.      je    for_us            ;  yes, if read
  295.     cmp    ah,HD_ROS_WRITE
  296.      jne    to_ros            ;  or write
  297.  
  298. for_us:
  299. ; We only support 2 drives.
  300. ; Check for drives on a 2nd controller:
  301. ;    and    dl,3            ; get rid of high drive bit
  302. ;    mov    hd_port,HD_PORT_BASE    ; for first 2 drives
  303. ;    test    dl,2            ; if drives 2 or 3, next controller
  304. ;     jz    first
  305. ;    add    hd_port,4        ; for next controller
  306.  
  307. ; Setup COMMAND byte 1:
  308. first:
  309.     and    dl,1            ; for the bit in command byte 1
  310.     push    cx            ; save sector number
  311.     mov    cl,5            ; shift count
  312.     shl    dl,cl
  313.     or    dh,dl            ; put into head number
  314.     mov    hd_cmd_blk$ + 1,dh    ; and into the block
  315.     pop     cx
  316.  
  317. ; COMMAND byte 2:
  318.     dec    cl            ; sectors 0-16, not 1-17
  319.     mov    hd_cmd_blk$ + 2,cl
  320.  
  321. ; COMMAND byte 3:
  322.     mov    hd_cmd_blk$ + 3,ch    ; cylinder number
  323.  
  324. ; COMMAND byte 4:
  325.     mov    hd_cmd_blk$ + 4,al    ; interleave/block count
  326.  
  327. ; COMMAND byte 5:
  328. ;    mov    al,control_byte        ; setup in init
  329. ;    mov    hd_cmd_blk$ + 5,al
  330.  
  331. ; COMMAND byte 0:
  332.     mov    hd_cmd_blk$ + 0,HD_READ_OP
  333.     mov    al,DMA_MODE_READ_C3    ; mode byte for 8237
  334.     cmp    ah,2            ; assumption correct?
  335.      je    hd_1
  336.     mov    hd_cmd_blk$ + 0,HD_WRITE_OP ; write, not read
  337.     mov    al,DMA_MODE_WRITE_C3
  338. hd_1:
  339.  
  340. ; Setup the DMA controller:
  341.     cli
  342.     out    DMA_CBPF,al        ;; init flip/flop
  343.     push bx ! pop bx        ;; delay
  344.     out    DMA_MODE_REG,al        ;; DMA mode (read or write)
  345.  
  346. ; Calculate 20-bit DMA address:
  347.     mov    ax,ES            ;; segment
  348.     mov    cl,4            ;; paras to bytes by shl 4
  349.     rol    ax,cl            ;; hi nibble comes around
  350.     mov    ch,al            ;; save it
  351.     and    al,0F0h            ;; and get rid of it for
  352.     add    ax,bx            ;; the addition of the offset
  353.     adc    ch,0            ;; if carry, bump high 4
  354.  
  355. ; To controller:
  356.     out    DMA_C3_ADDRESS,al    ;; low 8
  357.     mov    al,ah            ;;
  358.     out    DMA_C3_ADDRESS,al    ;; next 8
  359.     mov    al,ch            ;;
  360.     and    al,0Fh            ;;
  361.     out    DMA_PAGE_C3,al        ;; hi 4
  362.  
  363. ; Count?
  364.     mov    al,hd_cmd_blk$+4    ;; get the block count
  365.     shl    al,1            ;; # bytes - 1
  366.     dec    al            ;;
  367.     mov    ah,al            ;;
  368.     mov    al,0ffh            ;;
  369.     out    DMA_C3_COUNT,al        ;;
  370.     mov    al,ah            ;;
  371.     out    DMA_C3_COUNT,al        ;;
  372.     sti                ;;
  373.  
  374. ; Now talk to the hd controller:
  375. ;    mov    dx,hd_port        ; for 1st (or 2nd controller)
  376. ;    add    dx,2            ; port 2
  377.  
  378.     mov    al,3            ; dma and interrupt mask register
  379.  
  380.     mov    dx,HD_PORT_BASE + 2
  381.     out    dx,al            ; w. anything for controller select
  382.  
  383.     inc    dx            ; port 3
  384.     out    dx,al
  385.  
  386. ; Check for controller ready:
  387.     dec dx ! dec dx            ; port 1
  388. wait_busy:
  389.     in    al,dx
  390.     and    al,0Fh
  391.     cmp    al,0Dh            ; checks busy and others
  392.      jne    wait_busy
  393.     
  394. ; Send command to controller:
  395.     cld                ; for lodsb
  396.     mov    cx,HD_CMD_COUNT
  397.     dec    dx            ; port 0
  398.     mov    si,offset hd_cmd_blk$
  399. cmd_lp:
  400.     lodsb
  401.     out    dx,al
  402.     push dx ! pop dx  ;<------------ This delay is not required for
  403.     nop ! nop ! nop ! nop ;<-------- the IBM controller, but it is for
  404.     loop    cmd_lp            ; the MOUNTAIN, and possibly others.
  405.  
  406. ; The IBM XT controller uses up 123 machine cycles between the OUTs in the
  407. ;  loop above.  A push/pop combo is 27.  Put some quick NOPs there so that
  408. ;  some unfortunate can patch them if need be w/ longer instructions.
  409.  
  410. ; Now make sure the DMA controller is unmasked:
  411.     mov    al,DMA_BMSK_C3
  412.     out    DMA_BMSK_REG,al
  413.  
  414. ; and the PIC is free:
  415.     in    al,PIC_MASK
  416.     and    al,not 20h        ; IRQ 5
  417.     out    PIC_MASK,al
  418.  
  419. ; Tell the XIOS hd isr that we are expecting the int:
  420.     mov    hd_int_expected,0ffh
  421.  
  422. ; Now leave until the op is complete:
  423.     mov    dx,HD_FLAG
  424.     call    flagwait@
  425.  
  426. ; Check error:
  427.     mov    dx,hd_port
  428.     in    al,dx            ; End-of-cmd-status is from port 0
  429.     sub    ah,ah            ; assume no error
  430.     test    al,2
  431.      jz    no_err
  432.     call    process_err        ; returns w/ error in AH
  433. no_err:
  434.  
  435. ; Now op is done, turn off ints at the hd. controller for each drive:
  436.     push    ax
  437.     mov    dx,HD_PORT_BASE + 3    ; to int/dma reg
  438.     sub    al,al
  439.     out    dx,al            ; turn 'em off
  440.     add dx,4 ! out dx,al        ; 3rd, 4th drives
  441.     add dx,4 ! out dx,al        ; 5th, 6th drives
  442.     add dx,4 ! out dx,al        ; 7th, 8th drives
  443.  
  444. ; Disable the pic:
  445.     in     al,PIC_MASK
  446.     or    al,20h            ; set IRQ 5 mask
  447.     out    PIC_MASK,al
  448.  
  449.     pop    ax            ; restore error
  450.     cmp    ah,1
  451.     cmc                ; set CF
  452.     iret
  453.  
  454.  
  455. process_err:
  456. ;-----------
  457. ; Entry: DX = port 1
  458. ; Always reports BAD_ADDR_MARK if error.
  459.  
  460.     inc    dx            ; to port 2
  461.     out    dx,al            ; controller select
  462. ; MOUNTAIN:
  463.     nop ! nop ! nop ! nop
  464.  
  465.     inc    dx            ; to port 3
  466.     sub    al,al
  467.     out    dx,al            ; zero to int/dma    
  468.  
  469.     dec dx ! dec dx            ; to port 1
  470. keep_checking:
  471.     in    al,dx
  472.     and    al,0Fh
  473.     cmp    al,0Dh            ; checks busy and others
  474.      jne    keep_checking
  475.  
  476.     mov    hd_cmd_blk$,3        ; Sense status cmd
  477.     mov    cx,HD_CMD_COUNT
  478.     dec    dx            ; port 0
  479.     cld
  480.     mov    si,offset hd_cmd_blk$
  481. ss_lp:
  482.     lodsb
  483.     out    dx,al
  484.     loop    ss_lp
  485.  
  486.     mov    cx,5            ; 4 sense bytes + 1 end-of-cmd-stat
  487. ss_rd_lp:
  488.     inc    dx            ; port 1
  489. ss_wait:
  490.     in    al,dx
  491.     test    al,1            ; R1_REQ
  492.      jz    ss_wait
  493.  
  494.     dec    dx            ; port 0
  495.     in    al,dx
  496.     loop    ss_rd_lp
  497.  
  498. ; We don't really care what kind of an error:
  499. ; call it 02, bad_addr_mark:
  500.     mov    ah,2
  501.     ret
  502. eject
  503.  
  504. hd_isr@:
  505. ;-------
  506. ; Interrupt service routine for XT hard disk:
  507. ; The BDOS only allows one process in the file system at a time.  Therefore,
  508. ; we may with COMPLETE confidence (!) allow the hd isr to share the same
  509. ; stack area and register save area as the floppy controller.
  510.  
  511.     push    ds
  512.     mov    ds,sysdat
  513.     mov    xt_hd_isr_ax,ax            ;; save this reg
  514.  
  515.     mov    al,PIC_OCW_SEOI + HDISK_CHANNEL    ;; specific-end-of-interrupt
  516.     out    PIC_ACK,al            ;;
  517.  
  518.     mov    al,DMA_BMSK_C3 or 4h        ;; mask off the channel
  519.     out    DMA_BMSK_REG,al            ;;
  520.  
  521.     in    al,PIC_MASK            ;;
  522.     or    al,20h                ;; mask IRQ 5 at the PIC
  523.     out    PIC_MASK,al            ;;
  524. if XM
  525.     call    unlock_page@            ;; release paged memory
  526. endif
  527.     sub    al,al                ;;
  528.     xchg    hd_int_expected,al        ;; reset the byte if set
  529.     or    al,al                ;;
  530.  
  531.      jnz    yes_xios_exp            ;; do flag_set/wait if
  532.                         ;;  our XIOS wants it
  533.     mov    ax,xt_hd_isr_ax            ;; else restore reg and
  534.     pop    ds
  535.     iret                    ;;  go back
  536.  
  537. yes_xios_exp:
  538. ; Now tell the OS we're through:
  539. ;    sti
  540.     mov    xt_hd_isr_ss,ss            ;;
  541.     mov    xt_hd_isr_sp,sp            ;;
  542.  
  543.     mov    ss,sysdat$            ;;
  544.     mov    sp,offset xt_hd_isr_stack    ;;
  545.  
  546. ; Store all regs:
  547.     push bx ! push cx ! push dx        ;;
  548.     push si ! push di ! push bp        ;;
  549.     push es                    ;;
  550.  
  551.     mov    dx,HD_FLAG            ;;
  552.     call    flagset@            ;;
  553.  
  554.     pop es                    ;;
  555.     pop bp ! pop di ! pop si        ;;
  556.     pop dx ! pop cx ! pop bx        ;;
  557.  
  558.     mov    ss,xt_hd_isr_ss            ;;
  559.     mov    sp,xt_hd_isr_sp            ;;
  560.     mov    ax,xt_hd_isr_ax            ;;
  561.     jmpf    dispatch_addr$            ;; do a dispatch now
  562. ;#IJ    pop    ds
  563. ;#IJ    jmpf    disp_addr$            ;; do a dispatch now
  564. endif
  565.  
  566. eject
  567.  
  568. int15_isr@:
  569. ;---------
  570. ; DEVICE-WAIT/POST interrupt service routine, used for hard disk flag-waiting
  571. ; if running on an AT:
  572.     push    ds            ;; saver caller's DS
  573.     mov    ds,sysdat$        ;; DS -> SYSDAT
  574.     cmp    ax,9100h        ;; hd device post?
  575.     jne    not_hd
  576.     mov    hd_timer$,TICKS_PER_SECOND    ; reset our watchdog timer
  577.     
  578. not_hd:
  579.     test    use_int15$,TRUE        ;; CDOS flag system used (1st time)
  580.      jz    int15_skip        ;; no, use hard waits in ROS
  581.     cmp    ax,9100h        ;; hd device post?
  582.      je    int15_post        ;; yes, convert to DEV_FLAGSET
  583.     cmp    ax,9000h        ;; hd device wait?
  584.      jne    int15_skip        ;; no, pass down to ROS
  585.  
  586. int15_wait:                ;; wait for hard disk interrupt
  587.     push ax ! push bx ! push cx ! push dx
  588.     push si ! push di ! push bp ! push es
  589.  
  590.     mov    dx,HD_FLAG        ;; wait for hard disk event
  591.     call    flagwait@
  592.  
  593.     pop es ! pop bp ! pop di ! pop si    ;; restore all registers
  594.     pop dx ! pop cx ! pop bx ! pop ax
  595. int15_skip:
  596.     pop    ds            ;; restore caller's DS
  597. if V386
  598.     cmp    ah,88h
  599.     jne    int15_ros
  600.     mov    ax,cs
  601.     push    bp
  602.     mov    bp,sp
  603.     cmp    ax,4[bp]
  604.     pop    bp
  605.     mov    ah,88h            ;; reload
  606.     je    int15_ros        ;; its come from the XIOS goto ROS
  607.     sub    ax,ax            ;; return no extended memory
  608.     sti
  609.     retf    2
  610. int15_ros:
  611. endif
  612.  
  613.     jmpf    old_int15$        ;; now pass it on to ROS
  614.  
  615. int15_post:                ;; signal hard disk interrupt
  616.     mov    int15_ss,ss        ;; switch to local stack
  617.     mov    int15_sp,sp
  618.     mov    ss,sysdat$
  619.     mov    sp,offset int15_tos
  620.  
  621.     push ax ! push bx ! push cx ! push dx
  622.     push si ! push di ! push bp ! push es
  623.  
  624.     mov    dx,HD_FLAG        ;; wake up process waiting for HD
  625.     call    flagset@
  626.     mov    use_int15,FALSE        ;; only do it once per INT 13h
  627.  
  628.     pop es ! pop bp ! pop di ! pop si    ;; restore all registers
  629.     pop dx ! pop cx ! pop bx ! pop ax
  630.  
  631.     mov    ss,int15_ss        ;; back to user stack
  632.     mov    sp,int15_sp
  633.  
  634.     pushf                ;; emulate INT 15 to ROS handler
  635.     callf    old_int15
  636.  
  637.     jmpf    dispatch_addr$        ;; do a dispatch now
  638. ;#IJ    pop    ds            ;; restore caller's DS
  639. ;#IJ    jmpf    disp_addr$        ;; now pass it on to ROS
  640.  
  641. eject
  642.  
  643. old_int15$    rd    1        ; to continue if int 15 not for us
  644.  
  645. ; ***  XT hard disk driver data segment  ***
  646. hdata0    dseg    word
  647.  
  648. ; XT hardware data:
  649. hd_port        dw    HD_PORT_BASE    ; first or 2nd controller
  650. hd_cmd_blk$    db    0,0,0,0,0,0
  651. HD_CMD_COUNT    equ    offset $ - offset hd_cmd_blk$
  652.  
  653. retry_fl    db    0        ; use XT ROS or XIOS driver
  654.  
  655. hd_timer$    db    0ffh        ; Hard disk watchdog timer
  656. hd_error$    db    00h        ; used to fix bug in some ROS's
  657.  
  658. use_int15    db    FALSE        ; TRUE to use DEV_FLAGWAIT/FLAGSET once
  659.  
  660. int15_cyl    dw    0FFFFh        ; cylinder accessed on last int 13h
  661.  
  662. int15_sp    rw    1        ; stack save area for POST
  663. int15_ss    rw    1
  664.  
  665. ; reg save area for int 15 hdisk posting:
  666.         dw    0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
  667.         dw    0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
  668.         dw    0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
  669.         dw    0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
  670.         dw    0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
  671.         dw    0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
  672.         dw    0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
  673.         dw    0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
  674.         dw    0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
  675.         dw    0CCCCH, 0CCCCH, 0CCCCH, 0CCCCH
  676. int15_tos    rw    0
  677.  
  678. if XM
  679. ; Stack switch area for XT hard disk interrupt:
  680.  
  681.         dw    0cccch,0cccch,0cccch,0cccch
  682.         dw    0cccch,0cccch,0cccch,0cccch
  683.         dw    0cccch,0cccch,0cccch,0cccch
  684.         dw    0cccch,0cccch,0cccch,0cccch
  685.  
  686.         dw    0cccch,0cccch,0cccch,0cccch
  687.         dw    0cccch,0cccch,0cccch,0cccch
  688.         dw    0cccch,0cccch,0cccch,0cccch
  689.         dw    0cccch,0cccch,0cccch,0cccch
  690.  
  691.         dw    0cccch,0cccch,0cccch,0cccch
  692.         dw    0cccch,0cccch,0cccch,0cccch
  693.  
  694. xt_hd_isr_stack    rs    0
  695. xt_hd_isr_ss    dw    0
  696. xt_hd_isr_sp    dw    0
  697. xt_hd_isr_ax    dw    0
  698. endif
  699.  
  700. eject
  701.  
  702. ; This block of data is shared by the
  703. ; XT hard disk driver and the FIDDS hooks.
  704.  
  705. aux_drive$    rb    1            ; corrected drive code
  706. aux_code    rb    1            ; select / rw multi-count
  707. aux_track    rw    1
  708. aux_sector    rw    1
  709. aux_dma_o    rw    1
  710. aux_dma_s    rw    1
  711. aux_longword    equ    dword ptr aux_dma_o
  712.  
  713. aux_func    rw    1            ; hd function code
  714. max_sector    rw    1            ; mcnt loop limit
  715. block_byte_cnt    rw    1            ; multi-sector byte counter
  716. block_mcnt    rb    1            ; multi-sectors in this block
  717.  
  718. hd_int_expected db    0            ; =FF if XIOS requested op.
  719.  
  720. hdata1 dseg word
  721.  
  722. hd_init_flag$    db    0            ; set at end of initialization
  723. hd_boot_flag$    db    0            ; temporarily save partition bootfl
  724.  
  725. ; Tables of pertinent information about each possible disk:
  726. ; Each contains an entry defined by data structure HDINF_vector.
  727.  
  728. hdinf_ptr$    dw    0000        ; logical hard disk drive pointer
  729.         dw    0000        ; table into hd_disk_info vectors
  730.         dw    0000        ;  pointers installed in HD_INIT
  731.         dw    0000        ;  hard disk fix ups according to
  732.         dw    0000        ;  DOS partitions found on each drive.
  733.         dw    0000
  734.         dw    0000
  735.         dw    0000
  736.  
  737. hd_disk_info$:
  738.   hd_info0$    db    0,0,0,0,0
  739.         dw    0,0,offset hd_label0
  740.         db    0            ; new pc logged byte!
  741.           db    0            ; save physical drive number
  742.   hd_info1$    db    0,0,0,0,0
  743.         dw    0,0,offset hd_label1
  744.         db    0            ; new pc logged byte!
  745.         db    0            ; save physical drive number
  746. eject
  747.  
  748.  
  749. ; Pointer to ROS interrupt entry for XT hard disk:
  750. hd_rom_ofs$    rw    1
  751. hd_rom_seg$    rw    1
  752. hd_rom_entry equ dword ptr hd_rom_ofs$
  753.  
  754.  
  755. eject
  756.  
  757. ; Funny thing, but the following buffers must not fall on a physical
  758. ; 64K boundary!  Change the link line, or move them around if required
  759. ; and change the names if that works.
  760.  
  761. hdata2    dseg    para                ; paragraph align
  762. ; Leave space for both label structures:
  763.  
  764.                 ; no CP/M label sectors for 6.0
  765. hd_label0    rb    0
  766.  hd_dpb0$    rb    0
  767. hd_label1    rb    0
  768.  hd_dpb1$    rb    0
  769.  
  770. hdata3 dseg    word                ; word align them
  771.  
  772. ; The XT hard disk now shares its buffer with the floppies
  773.  
  774. ; Sector buffer used by read/write routines when requested
  775. ; multi sector I/O operation crosses a 64K page boundary follows.
  776. ; Also used to read floppy size code from track 0 sector 0.
  777.  
  778. local_buffer$    rw    1
  779.  
  780. eject
  781.  
  782. ;************************************************
  783. ;*                        *
  784. ;*      PC MODE HARD DISK DRIVERS        *
  785. ;*                        *
  786. ;************************************************
  787.  
  788.     cseg
  789.  
  790. pc_select_hd@:
  791. ;------------
  792. ; PC DOS mode select hard disk.
  793. ; Logs in volume if first time select and if login succeeds, returns
  794. ; DPH pointer in the usual fashion.
  795.  
  796.     mov    bl,cl
  797.     xor    bh,bh
  798.     call    pc_point_hdinf            ; fix cl and si-->HDINF
  799.     test    HDINF_EXISTS[si],0ffh        ; see if drive exists
  800.      jz    pc_login_err
  801.     shl    bx,1
  802.     mov    ax,dph_tbl$[bx]            ; get drive DPH address    
  803.     jmps    pc_login_ret
  804. pc_login_err:
  805.     sub ax,ax                ; 0 ret if select err
  806. pc_login_ret:
  807.     mov bx,ax
  808.     ret
  809. eject
  810.  
  811. pc_read_hd@:
  812. ;----------
  813. ; PC DOS mode hard disk read routine:
  814.  
  815.     mov    al,HD_ROS_READ
  816.     jmps    pc_read_write_hd        ; ROS read function
  817.  
  818. pc_write_hd@:
  819. ;-----------
  820. ; PC DOS mode hard disk write routine:
  821.  
  822.     mov    al,HD_ROS_WRITE
  823. ;    jmps    pc_read_write_hd        ; ROS write function
  824.  
  825. pc_read_write_hd:                ; common code
  826.  
  827.     cmp    MCNT,0                ; is this a media check?
  828.      jnz    pc_no_check            ; skip if actual read/write
  829.     mov    ax,1                ; else return "not changed"
  830.     ret
  831.  
  832. pc_no_check:
  833.  
  834.     mov    bx,offset pc_hd_rw_iopb
  835.     mov    IBM_FN[bx],al            ; set function in IOPB
  836.     call    iopb_adjust            ; adjust for sector size > 512
  837.     xor    ch,ch
  838.     mov    cl,DRIVE            ; set drive
  839.     mov    di,cx
  840.     shl    di,1
  841.     mov    di,dph_tbl$[di]            ; get drive DPH address    
  842.     add    di,DPH_SIZE            ; DI -> label
  843.         
  844.     call    pc_point_hdinf            ; SI--> drive info
  845. ;    mov    ax,PC_HD_DPH_SIZE
  846. ;    sub    ch,ch
  847. ;    mul    cx
  848. ;    mov    di,(offset pc_hd_dphs)+DPH_SIZE
  849. ;    add    di,ax                ; DI--> label
  850.  
  851.     mov    cl,HDINF_PC_DRIVE[si]        ; get physical drive number
  852.     mov    IBM_LUN[bx],cl            ; PHYS. unit to IOPB
  853.  
  854.     mov    ax,TRACK            ; setup disk address
  855.     mov    dx,SECTOR
  856.     mov    cl,XT_PT_START_SECTOR[di]    ; get sector/cyl offs
  857.     and    cl,03fh                ; UNPACK IBM SECTOR off
  858.     add    dl,cl                ; add to our sector #
  859.     cmp    dl,HDINF_SPT[si]
  860.      jbe    pc_hd_xlate1            ; check for track carry
  861.     sub    dl,HDINF_SPT[si]        ; if found deal with it
  862.     inc    ax
  863. pc_hd_xlate1:
  864.     mov    IBM_SECTOR[bx],dl        ; PHYS. sector to IOPB
  865.     add    al,XT_PT_START_HEAD[di]
  866.     adc    ah,0                ; in case we're uneven
  867.     sub    ch,ch
  868.     mov    cl,HDINF_HEADS[si]        ; divide by # of heads
  869.     cwd
  870.     div    cx                ; track to CYL and HEAD
  871.     mov    cl,XT_PT_START_CYLINDER[di]    ; get cylinder offset
  872.     mov    ch,XT_PT_START_SECTOR[di]
  873.     rol ch,1 ! rol ch,1
  874.     and    ch,3                ; unpack top two bits
  875.     add    ax,cx                ; add offset to cyl #
  876.     mov    IBM_CYLINDER[bx],ax
  877.     mov    IBM_HEAD[bx],dl
  878.  
  879.     mov    ax,DMA_SEG            ; set data xfer address
  880.     mov    IBM_XFER_SEG[bx],ax
  881.     mov    ax,DMA_OFF
  882.     mov    IBM_XFER_OFS[bx],ax
  883.  
  884. ; The following is to get around the AT ROS bug described above:
  885.     mov    cl,MCNT                ; get number of sectors
  886.     mov    pc_rw_count,cl            ; save for our count
  887.     call    at_multi_count            ; return max for AT
  888.     mov    MCNT,cl
  889. pc_rw_hd_again:
  890.  
  891.     call    pc_hd_operation            ; go do it
  892.  
  893.     mov    ah,IBM_ERRCODE[bx]        ; pick up extended err
  894.     or    al,al
  895.      jnz    pc_rw_hd_error            ; if error, exit
  896.  
  897.     mov    al,MCNT
  898.     sub    pc_rw_count,al            ; count down our count
  899.      jnz    pc_rw_hd_again            ;  and repeat til 0
  900.     xor    ax,ax                ; return success
  901.     ret
  902.  
  903. pc_rw_hd_error:
  904.     mov    al,1
  905.     ret
  906.  
  907. pc_point_hdinf:
  908. ; Return SI pointing to HDINF vector for cpm volume # in CL.
  909. ; and CL = physical drive number
  910.     xor    ch,ch
  911.     sub    cl,byte ptr num_flop_des$    ; hard disks start after floppy names
  912.     mov    si,cx
  913.     shl    si,1
  914.     mov     si,hdinf_ptr$[si]
  915.     mov    cl,HDINF_PC_DRIVE[si]        ; get physical drive number
  916.     ret
  917. eject
  918.  
  919. iopb_adjust:    ; adjust IOPB for large sector sizes
  920. ;-----------
  921.     mov    al,DRIVE        ; get physical drive
  922.     cbw
  923.     xchg    ax,di
  924.     shl    di,1            ; DI = drive*2
  925.     mov    di,dph_tbl$[di]        ; DI -> DPH
  926.     mov    di,DPH_DPB[di]        ; DI -> DPB
  927.     mov    ax,TRACK
  928.     mul    PCDPB_SPT[di]
  929.     add    ax,SECTOR
  930.     adc    dx,0            ; AX/DX = logical absolute sector
  931.     mov    cl,PCDPB_PSH[di]
  932.     mov    ch,0
  933.     dec    cx ! dec cx        ; CX = log2 (sectorsize/512)
  934.      jz    iopb_adjust2        ; skip if sector size == 512
  935. iopb_adjust1:
  936.     shl    ax,1            ; double the sector address
  937.     rcl    dx,1
  938.     shl    MCNT,1            ; double the sector count
  939.     loop    iopb_adjust1        ; until sector size adjusted
  940. iopb_adjust2:
  941.     div    PCDPB_SPT[di]        ; now convert to track/sector (##JC##)
  942.     mov    TRACK,ax
  943.     mov    SECTOR,dx
  944.  
  945.     ret
  946.  
  947. eject
  948.  
  949. pc_hd_operation:
  950. ;---------------
  951. ; Perform IO operation described by IOPB (perhaps as several operations)
  952. ; dealing transparently with all dma boundary crossing problems.
  953. ; Note: This routine is required to deal with the proprietary IBM
  954. ;     DMA page register technique (patent pending) used in the PC.
  955.  
  956. ;  ENTRY     BX--> IOPB
  957. ;        DI--> PC_LBL
  958. ;        SI--> HDINF
  959. ;  EXIT:    AL=0 if succeeds, else NZ
  960.  
  961.     mov    dl,MCNT                ; keep # still to xfer in dl
  962.     push    bx
  963.     mov    ax,IBM_XFER_SEG[bx]
  964.     mov    bx,IBM_XFER_OFS[bx]
  965.     call    comp_dma@            ; calculate 20 bit xfer address
  966.     pop    bx                ; ax= # of bytes left in page
  967.  
  968.     push    dx                ; save count
  969.     sub    dx,dx
  970.     div    C_512                ; # of xfers left in page
  971.     pop    dx                ; restore it count
  972.     or    ax,ax
  973.      jz    pc_hd_mid_xfer            ; if 0 start with buffered xfer
  974.     cmp    al,dl
  975.      jnc    pc_hd_last_xfer         ; if all fit, skip buffr'd xfer
  976.     mov    IBM_COUNT[bx],al        ; else transfer as many as fit
  977.     call    pc_hd_do_it
  978.     or    al,al
  979.      jnz    pc_hd_op_err            ; break if error
  980.     sub    dl,IBM_COUNT[bx]         ; how many are still left?
  981.      jz    pc_hd_op_ok            ; - NONE, exit
  982.  
  983. pc_hd_mid_xfer:
  984.     cmp    IBM_FN[bx],HD_ROS_READ
  985.      je    pc_hd_mid_xfer1
  986.     call    pc_hd_to_buffer            ; if write, move data to buff
  987. pc_hd_mid_xfer1:
  988.     push    IBM_XFER_SEG[bx]        ; save xfer address
  989.     push    IBM_XFER_OFS[bx]
  990.  
  991.     mov    ax,local_buffer$
  992.     mov    IBM_XFER_OFS[bx],ax
  993.     mov    IBM_XFER_SEG[bx],ds        ; setup local transfer
  994.     mov    IBM_COUNT[bx],1
  995.     call    pc_hd_do_it
  996.  
  997.     pop    IBM_XFER_OFS[bx]        ; restore transfer ptrs
  998.     pop    IBM_XFER_SEG[bx]
  999.     or    al,al
  1000.      jnz    pc_hd_op_err            ; break if there was an error
  1001.  
  1002.     cmp    IBM_FN[bx],HD_ROS_WRITE
  1003.      je    pc_hd_mid_xfer2
  1004.     call    pc_hd_from_buffer
  1005. pc_hd_mid_xfer2:
  1006.     add    IBM_XFER_OFS[bx],512
  1007.     dec    dl
  1008.      jz    pc_hd_op_ok            ; dec mcnt and exit if done
  1009.  
  1010. pc_hd_last_xfer:
  1011.     mov    IBM_COUNT[bx],dl        ; do one last long direct xfer
  1012.     call    pc_hd_do_it
  1013.     or    al,al
  1014.      jz    pc_hd_op_ok
  1015. pc_hd_op_err:
  1016.     mov    al,0ffh
  1017.     jmps    pc_hd_op_exit
  1018. pc_hd_op_ok:
  1019.     xor    ax,ax
  1020. pc_hd_op_exit:
  1021.     ret
  1022.  
  1023.  
  1024. pc_hd_from_buffer:
  1025. ; Moves 512 bytes from local buffer to user buffer:
  1026.  
  1027.     push si ! push di ! push ds ! push es
  1028.     mov    si,local_buffer$
  1029.     les    di,IBM_XFER_PTR[bx]
  1030. pc_hd_move1:
  1031.     cld
  1032.     mov    cx,256
  1033.     rep    movsw
  1034.     pop es ! pop ds ! pop di ! pop si
  1035.     ret
  1036.  
  1037.  
  1038. pc_hd_to_buffer:
  1039. ; Moves 512 bytes form user buffer to local buffer:
  1040.  
  1041.     push si ! push di ! push ds ! push es
  1042.     push ds ! pop es
  1043.     mov    di,local_buffer$
  1044.     lds    si,IBM_XFER_PTR[bx]
  1045.     jmps    pc_hd_move1
  1046.  
  1047.  
  1048. pc_hd_do_it:
  1049. ; Does transfer and increments IOPB xfer pointer as needed:
  1050.  
  1051.     push bx ! push cx ! push dx
  1052.     call hd_rom@
  1053.     pop dx ! pop cx ! pop bx
  1054.     or    al,al
  1055.      jnz    pc_hd_doit_done
  1056.     push    dx
  1057.     mov    al,IBM_COUNT[bx]
  1058.     add    IBM_SECTOR[bx],al
  1059.     sub    ah,ah
  1060.     mul    C_512
  1061.     add    IBM_XFER_OFS[bx],ax
  1062. hd_do_it_again:
  1063.     mov    al,HDINF_SPT[si]
  1064.     cmp    IBM_SECTOR[bx],al
  1065.      jbe    pc_hd_do_it1
  1066.     sub    IBM_SECTOR[bx],al
  1067.     inc    IBM_HEAD[bx]
  1068.     mov    al,HDINF_HEADS[si]
  1069.     cmp    IBM_HEAD[bx],al
  1070.      jb    hd_do_it_again
  1071.     sub    IBM_HEAD[bx],al
  1072.     inc    IBM_CYLINDER[bx]
  1073.     jmps    hd_do_it_again
  1074. pc_hd_do_it1:
  1075.     pop    dx
  1076.     sub    ax,ax
  1077. pc_hd_doit_done:
  1078.     ret
  1079. eject
  1080.  
  1081. hdata4    dseg    word
  1082.  
  1083. C_512        dw    512        ; constant for word division
  1084. pc_rw_count    rb    1        ; for AT multi-sect. count down
  1085.         rb    1        ; pad for word align
  1086.  
  1087.  
  1088. pc_hd_rw_iopb:
  1089.     db    0,0,0,0                ; fn,err,lun,head
  1090.     dw    0                ; cyl
  1091.     db    0,1                ; sector, count
  1092.     dw    0,0                ; xfer offset/seg
  1093.  
  1094. end
  1095.  
  1096. ; END OF HDISK.A86
  1097.