Comment " Resident program to report intermittant disk I/O errors, before DOS reports them after trying 5 times. Error handling remains with DOS. Errors reported: No Response No response from disk Failed Seek Could not locate data NEC Error Controller error Bad CRC Seen Circular Redundancy Check error DMA overrun CPU too busy to allow data on bus (unusual) Impos Sector NEC tried to read non existent sector No Addr Mark No address mark on disk W Protected Write protected disk Err Unknown Severe problem; NEC does not know what happened Note: some copy protected disks will show disk errors, which are part of the scheme. Author Steve Holzner, as published in PC Magazine Vol. 4 No. 12, p. 263. To produce a .com file [m]asm dskwatch link dskwatch (Ignore missing stack segment warning.) exe2bin dskwatch.exe dskwatch.com Program may be invoked in autoexec.bat for a permanent watchdog. Once started, can only be removed by re-booting. " INTERRUPTS SEGMENT AT 0H ;This is where the disk interrupt ORG 13H*4 ;holds the address of its service routine DISK_INT LABEL DWORD INTERRUPTS ENDS SCREEN SEGMENT AT 0B000H ;A dummy segment to use as the Extra Segment SCREEN ENDS ; so we can write to the screen CODE_SEG SEGMENT ASSUME CS:CODE_SEG ORG 100H ;ORG = 100H to make this into a .COM file FIRST: JMP LOAD_WATCH ;First time through jump to initialize routine MSG_PART_1 DB 'Disk Error: ' ;Here are the error messages MSG_PART_2 DB 'No response Failed Seek NEC Error ' DB 'Bad CRC SeenDMA Overrun Impos Sector' DB 'No Addr MarkW. ProtectedErr Unknown ' FIRST_POSITION DW ? ;Position of 1st char on screen FLAGS DW ? SCREEN_SEG_OFFSET DW 0 ;0 for mono, 8000H for graphics OLD_DISK_INT DD ? ;Location of old disk interrupt RET_ADDR LABEL DWORD ;Used in fooling around with RET_ADDR_WORD DW 2 DUP(?) ; stack. DISK_WATCH PROC FAR ;The Disk interrupt will now come here ASSUME CS:CODE_SEG PUSHF ;First, call old disk interrupt CALL OLD_DISK_INT PUSHF ;Save the flags in memory location "FLAGS" POP FLAGS ; (cunning name) JC ERROR ;If there was an error, carry flag will have JMP FIN ; been set by Disk interrupt ERROR: PUSH AX ;AH has the status of the error PUSH CX ;Push all used registers for politeness PUSH DX PUSH DI PUSH SI PUSH ES LEA SI,MSG_PART_1 ;Always print "Disk Error: " part. ASSUME ES:SCREEN ;Use screen as extra segment MOV DX,SCREEN MOV ES,DX MOV DI,SCREEN_SEG_OFFSET ;DI will be pointer to screen position ADD DI,FIRST_POSITION ;Add to point to desired area on screen CALL WRITE_TO_SCREEN ;This writes 12 characters from [SI] to [DI] MOV DH,80H ;Initialize for later comparisons MOV CX,7 ;Loop seven times E_LOOP: CMP AH,DH ;Are error code and DH the same? JE E_FOUND ;If yes, Error has been found ADD SI,12 ;Point to next error message SHR DH,1 ;Divide DH by 2 LOOP E_LOOP ;Keep going until matched DH=0 CMP AH,3 ;Error code not even number; 3 perhaps? JE E_FOUND ;If yes, have found the error ADD SI,12 ;Err unknown; unknown error returned E_FOUND:CALL WRITE_TO_SCREEN ;Write the error message to screen POP ES ;Having done Pushes, here are the Pops POP SI POP DI POP DX POP CX POP AX FIN: POP RET_ADDR_WORD ;Fooling with the stack. We want to POP RET_ADDR_WORD[2] ;preserve the flags but the old flags ADD SP,2 ;are still on the stack. First remove PUSH FLAGS ;return address, then flags. Fill flags POPF ;from "FLAGS", return to correct addr. JMP RET_ADDR DISK_WATCH ENDP WRITE_TO_SCREEN PROC NEAR ;Puts 12 characters on the screen MOV CX,12 ;Loop 12 times W_LOOP: MOVS ES:BYTE PTR[DI],CS:[SI] ;Move to the screen MOV AL,7 ;Move screen attribute into screen buffer MOV ES:[DI],AL INC DI ;Point to next byte in screenbuffer LOOP W_LOOP ;Keep going until done RET ;Exeunt WRITE_TO_SCREEN ENDP LOAD_WATCH PROC NEAR ;This procedure initializes everything ASSUME DS:INTERRUPTS ;The data segment will be the Interrupt area MOV AX,INTERRUPTS MOV DS,AX MOV AX,DISK_INT ;Get the old interrupt service routine MOV OLD_DISK_INT,AX ;address and put it into our location MOV AX,DISK_INT[2] ;OLD_DISK_INT so we can call it. MOV OLD_DISK_INT[2],AX MOV DISK_INT,OFFSET DISK_WATCH ;Now load the address of Dsk Watch MOV DISK_INT[2],CS ; routine into the Disk interrupt MOV AH,15 ;Ask for service 15 of INT 10H INT 10H ;This tells us how display is set SUB AH,25 ;Move to twenty-five placed before edge SHL AH,1 ;Mult by two (char & attribute bytes) MOV BYTE PTR FIRST_POSITION,AH ;Set screen cursor TEST AL,4 ;Is it a monochrome display? JNZ EXIT ;Yes - jump out MOV SCREEN_SEG_OFFSET,8000H ;No - set up for graphics display EXIT: MOV DX,OFFSET LOAD_WATCH ;Set up everything but this program to INT 27H ;stay resident and attach itself to DOS LOAD_WATCH ENDP CODE_SEG ENDS END FIRST ;END "FIRST" so 8088 will go to FIRST first