home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / diskutil / dskwatch.asm < prev    next >
Assembly Source File  |  1994-03-04  |  7KB  |  137 lines

  1. Comment "
  2.  
  3.    Resident program to report intermittant disk I/O errors, before DOS
  4.    reports them after trying 5 times.  Error handling remains with DOS.
  5.  
  6.    Errors reported:
  7.         No Response     No response from disk
  8.         Failed Seek     Could not locate data
  9.         NEC Error       Controller error
  10.         Bad CRC Seen    Circular Redundancy Check error
  11.         DMA overrun     CPU too busy to allow data on bus (unusual)
  12.         Impos Sector    NEC tried to read non existent sector
  13.         No Addr Mark    No address mark on disk
  14.         W Protected     Write protected disk
  15.         Err Unknown     Severe problem; NEC does not know what happened
  16.  
  17.    Note: some copy protected disks will show disk errors, which are part of
  18.    the scheme.
  19.  
  20.    Author Steve Holzner, as published in PC Magazine Vol. 4 No. 12, p. 263.
  21.  
  22.    To produce a .com file
  23.       [m]asm dskwatch
  24.       link   dskwatch   (Ignore missing stack segment warning.)
  25.       exe2bin dskwatch.exe dskwatch.com
  26.  
  27.    Program may be invoked in autoexec.bat for a permanent watchdog.  Once
  28.    started, can only be removed by re-booting.
  29. "
  30.  
  31. INTERRUPTS      SEGMENT AT 0H  ;This is where the disk interrupt
  32.         ORG     13H*4          ;holds the address of its service routine
  33. DISK_INT        LABEL   DWORD
  34. INTERRUPTS      ENDS
  35.  
  36. SCREEN  SEGMENT AT 0B000H     ;A dummy segment to use as the Extra Segment
  37. SCREEN  ENDS                  ; so we can write to the screen
  38.  
  39. CODE_SEG        SEGMENT
  40.         ASSUME  CS:CODE_SEG
  41.         ORG     100H          ;ORG = 100H to make this into a .COM file
  42. FIRST:  JMP     LOAD_WATCH    ;First time through jump to initialize routine
  43.  
  44.         MSG_PART_1      DB    'Disk Error: ' ;Here are the error messages
  45.         MSG_PART_2      DB    'No response Failed Seek NEC Error   '
  46.                         DB    'Bad CRC SeenDMA Overrun Impos Sector'
  47.                         DB    'No Addr MarkW. ProtectedErr Unknown '
  48.         FIRST_POSITION  DW    ?              ;Position of 1st char on screen
  49.         FLAGS           DW    ?
  50.         SCREEN_SEG_OFFSET     DW      0      ;0 for mono, 8000H for graphics
  51.         OLD_DISK_INT          DD      ?      ;Location of old disk interrupt
  52.         RET_ADDR              LABEL DWORD    ;Used in fooling around with
  53.         RET_ADDR_WORD         DW 2 DUP(?)    ; stack.
  54.  
  55. DISK_WATCH      PROC    FAR          ;The Disk interrupt will now come here
  56.         ASSUME  CS:CODE_SEG
  57.         PUSHF                   ;First, call old disk interrupt
  58.         CALL    OLD_DISK_INT
  59.         PUSHF                   ;Save the flags in memory location "FLAGS"
  60.         POP     FLAGS           ; (cunning name)
  61.         JC      ERROR           ;If there was an error, carry flag will have
  62.         JMP     FIN             ; been set by Disk interrupt
  63. ERROR:  PUSH    AX              ;AH has the status of the error
  64.         PUSH    CX              ;Push all used registers for politeness
  65.         PUSH    DX
  66.         PUSH    DI
  67.         PUSH    SI
  68.         PUSH    ES
  69.         LEA     SI,MSG_PART_1   ;Always print "Disk Error: " part.
  70.         ASSUME  ES:SCREEN             ;Use screen as extra segment
  71.         MOV     DX,SCREEN
  72.         MOV     ES,DX
  73.         MOV     DI,SCREEN_SEG_OFFSET  ;DI will be pointer to screen position
  74.         ADD     DI,FIRST_POSITION     ;Add to point to desired area on screen
  75.         CALL    WRITE_TO_SCREEN  ;This writes 12 characters from [SI] to [DI]
  76.         MOV     DH,80H                ;Initialize for later comparisons
  77.         MOV     CX,7                  ;Loop seven times
  78. E_LOOP: CMP     AH,DH                 ;Are error code and DH the same?
  79.         JE      E_FOUND               ;If yes, Error has been found
  80.         ADD     SI,12                 ;Point to next error message
  81.         SHR     DH,1                  ;Divide DH by 2
  82.         LOOP    E_LOOP                ;Keep going until matched    DH=0
  83.         CMP     AH,3                  ;Error code not even number; 3 perhaps?
  84.         JE      E_FOUND               ;If yes, have found the error
  85.         ADD     SI,12                 ;Err unknown; unknown error returned
  86. E_FOUND:CALL    WRITE_TO_SCREEN       ;Write the error message to screen
  87.         POP     ES                    ;Having done Pushes, here are the Pops
  88.         POP     SI
  89.         POP     DI
  90.         POP     DX
  91.         POP     CX
  92.         POP     AX
  93. FIN:    POP     RET_ADDR_WORD         ;Fooling with the stack.  We want to
  94.         POP     RET_ADDR_WORD[2]      ;preserve the flags but the old flags
  95.         ADD     SP,2                  ;are still on the stack.  First remove
  96.         PUSH    FLAGS                 ;return address, then flags. Fill flags
  97.         POPF                          ;from "FLAGS", return to correct addr.
  98.         JMP     RET_ADDR
  99. DISK_WATCH      ENDP
  100.  
  101. WRITE_TO_SCREEN PROC    NEAR      ;Puts 12 characters on the screen
  102.         MOV     CX,12             ;Loop 12 times
  103. W_LOOP: MOVS    ES:BYTE PTR[DI],CS:[SI] ;Move to the screen
  104.         MOV     AL,7              ;Move screen attribute into screen buffer
  105.         MOV     ES:[DI],AL
  106.         INC     DI                ;Point to next byte in screenbuffer
  107.         LOOP    W_LOOP            ;Keep going until done
  108.         RET                       ;Exeunt
  109. WRITE_TO_SCREEN ENDP
  110.  
  111. LOAD_WATCH      PROC    NEAR      ;This procedure initializes everything
  112.         ASSUME  DS:INTERRUPTS     ;The data segment will be the Interrupt area
  113.         MOV     AX,INTERRUPTS
  114.         MOV     DS,AX
  115.  
  116.         MOV     AX,DISK_INT         ;Get the old interrupt service routine
  117.         MOV     OLD_DISK_INT,AX     ;address and put it into our location
  118.         MOV     AX,DISK_INT[2]      ;OLD_DISK_INT so we can call it.
  119.         MOV     OLD_DISK_INT[2],AX
  120.  
  121.         MOV     DISK_INT,OFFSET DISK_WATCH  ;Now load the address of Dsk Watch
  122.         MOV     DISK_INT[2],CS              ; routine into the Disk interrupt
  123.  
  124.         MOV     AH,15                  ;Ask for service 15 of INT 10H
  125.         INT     10H                    ;This tells us how display is set
  126.         SUB     AH,25                  ;Move to twenty-five placed before edge
  127.         SHL     AH,1                   ;Mult by two (char & attribute bytes)
  128.         MOV     BYTE PTR FIRST_POSITION,AH      ;Set screen cursor
  129.         TEST    AL,4                   ;Is it a monochrome display?
  130.         JNZ     EXIT                   ;Yes - jump out
  131.         MOV     SCREEN_SEG_OFFSET,8000H ;No - set up for graphics display
  132. EXIT:   MOV     DX,OFFSET LOAD_WATCH   ;Set up everything but this program to
  133.         INT     27H                    ;stay resident and attach itself to DOS
  134. LOAD_WATCH      ENDP
  135.         CODE_SEG        ENDS
  136.         END     FIRST   ;END "FIRST" so 8088 will go to FIRST first
  137.