PAGE ,132 ; TITLE MSDISK - BIOS %OUT ...MSDISK.ASM ;============================================================================== ;REVISION HISTORY: ;AN000 - New for DOS Version 4.00 - J.K. ;AC000 - Changed for DOS Version 4.00 - J.K. ;AN00x - PTM number for DOS Version 4.00 - J.K. ;============================================================================== ;AN001; d24 Multi Track enable/disable command in CONFIG.SYS 6/27/87 J.K. ;AN002; d9 Double word MOV instruction 7/1/87 J.K. ;AN003: d25 Change DASD ERP to that recommended by Storage systems 7/28/87 J.K. ;AN004; D113 Disable I/O access to unformatted media 9/03/87 J.K. ;AN005; P985 Allow I/O access to unformatted media 9/14/87 J.K. ;AN006; P1535 Disallow I/O access to unformatted media. 10/15/87 J.K. ; (Give the user to control this - Generic IOCTL subfunction 64h/44h ;AN007; p2828 Do not retry for multi-track format request 12/08/87 J.K. ;AC008; p3197 Should reset change line after BPB set in BDS table 01/21/88 J.K. ;AN009; p3349 Should retry at hard file timeout error 02/03/88 J.K. ;AN010; p4696 ECC error handler should cover PC ATs for CMC disks 05/04/88 J.K. ;AN011; p5034 Possible virgin hard file problem with direct INT 13 06/03/88 J.K. ;AN012; P5049 Attempt to write at DISK BASE table in ROM BIOS 06/06/88 J.K. ;AN013; P5055 Diskcopy fails (Regression of P5049) 06/09/88 J.K. ;============================================================================== ;for testing, set itest to 1. So as MSBIO1.ASM. itest=0 EXTRN NUMERR:ABS ;MSDATA INCLUDE MSGROUP.INC ;DEFINE CODE SEGMENT INCLUDE MSEQU.INC INCLUDE PUSHPOP.INC INCLUDE MSMACRO.INC INCLUDE DEVSYM.INC INCLUDE MSDSKPR.INC include biostruc.inc EXTRN INT2F_DISK:FAR ;MSBIO2 EXTRN MEDIACHECK:NEAR ;96TPI EXTRN HASCHANGE:NEAR ;96TPI EXTRN MEDIA_SET_VID:NEAR ;96TPI EXTRN HIDENSITY:NEAR ;96TPI EXTRN CHECKLATCHIO:NEAR ;96TPI EXTRN CHECKIO:NEAR ;96TPI EXTRN SET_CHANGED_DL:NEAR ;96TPI EXTRN SET_VOLUME_ID:NEAR ;MSVOLID EXTRN SWPDSK:NEAR ;MSBIO2 EXTRN CMDERR:NEAR ;MSBIO1 EXTRN STRATEGY:NEAR ;MSBIO1 EXTRN ERR$CNT:NEAR ;MSBIO1 EXTRN DSK$IN:NEAR ;MSBIO1 EXTRN EXIT:NEAR ;MSBIO1 EXTRN BUS$EXIT:NEAR ;MSBIO1 EXTRN ERR$EXIT:NEAR ;MSBIO1 extrn ResetChanged:near ;AN000; MS96TPI ;DATA EXTRN OLD13:DWORD ;MSBIO2 EXTRN PTRSAV:DWORD ;MSBIO1 EXTRN COM1DEV:WORD ;MSAUX EXTRN DAYCNT:WORD ;MSCLOCK EXTRN TIM_DRV:BYTE ;MSDATA EXTRN ACCESSCOUNT:BYTE ;MSDATA EXTRN SM92:BYTE ;MSDATA EXTRN DISKSECTOR:BYTE ;MSDATA EXTRN MEDIABYTE:BYTE ;MSDATA EXTRN SECPERCLUSINSECTOR:BYTE ;MSDATA EXTRN BPB_IN_SECTOR:WORD ;MSDATA EXTRN DISKSECTOR:BYTE ;MSDATA EXTRN STEP_DRV:BYTE ;MSDATA EXTRN START_BDS:WORD ;MSDATA EXTRN PHYS_DRV:BYTE ;MSDATA EXTRN WRTVERIFY:WORD ;MSDATA EXTRN FSETOWNER:BYTE ;MSDATA EXTRN SINGLE:BYTE ;MSDATA EXTRN RFLAG:BYTE ;MSDATA EXTRN MEDBYT:BYTE ;MSDATA EXTRN SPSAV:WORD ;MSDATA EXTRN SECCNT:WORD ;MSDATA EXTRN DPT:DWORD ;MSDATA EXTRN CURSEC:BYTE,CURHD:BYTE ;MSDATA EXTRN CURTRK:WORD ;MSDATA EXTRN EOT:BYTE ;MSDATA EXTRN MOTORSTARTUP:BYTE,SETTLECURRENT:BYTE,SETTLESLOW:BYTE ;MSDATA EXTRN CURHD:BYTE ;MSDATA EXTRN LSTERR:BYTE ;MSDATA EXTRN ERRIN:BYTE,ERROUT:BYTE ;MSDATA EXTRN PREVOPER:WORD ;MSDATA EXTRN ORIG13:DWORD ;MSDATA EXTRN FLAGBITS:WORD ;MSDATA EXTRN NUMBER_OF_SEC:BYTE ;MSDATA EXTRN FHAVE96:BYTE ;MSDATA EXTRN NEW_ROM:BYTE ;MSDATA EXTRN FORMT_EOT:BYTE,HDNUM:BYTE,TRKNUM:WORD,GAP_PATCH:BYTE ;MSDATA EXTRN NEXT2F_13:WORD ;MSDATA extrn Save_head_sttl:byte ;msbdata extrn Secrete_Code:word ;msbdata J.K. 11/7/86 Secrete code for DOS 3.3 MSBIO extrn Ext_Boot_Sig:byte ;AN000; msbdata extrn Boot_Serial_L:word ;AN000; msbdata extrn Boot_Serial_H:word ;AN000; msbdata extrn Boot_Volume_Label:byte ;AN000; msbdata extrn Boot_System_ID:byte ;AN000; msbdata extrn Model_Byte:Byte ;MSBIO2 extrn Secondary_Model_Byte:Byte ;MSBIO2 ;----------------------------------------------------------------- ; ; DISK INTERFACE ROUTINES ; ; DEVICE ATTRIBUTE BITS: ; BIT 6 - GET/SET MAP FOR LOGICAL DRIVES AND GENERIC IOCTL. ; MAXERR = 5 LSTDRV = 504H ; SOME FLOPPIES DO NOT HAVE CHANGELINE. AS A RESULT, MEDIA-CHECK WOULD ; NORMALLY RETURN I-DON'T-KNOW, THE DOS WOULD CONTINUALLY REREAD THE FAT, AND ; DISCARD CACHED DATA. WE OPTIMIZE THIS BY IMPLEMENTING A LOGICAL DOOR- ; LATCH: IT IS PHYSICALLY IMPOSSIBLE TO CHANGE A DISK IN UNDER 2 SECONDS. WE ; RETAIN THE TIME OF THE LAST SUCCESSFUL DISK OPERATION AND COMPARE IT WITH ; THE CURRENT TIME DURING MEDIA-CHECK. IF < 2 SECONDS AND AT LEAST 1 TIMER ; TICK HAS PASSED, THE WE SAY NO CHANGE. IF > 2 SECONDS THEN WE SAY I- ; DON'T-KNOW. FINALLY, SINCE WE CANNOT TRUST THE TIMER TO BE ALWAYS ; AVAILABLE, WE RECORD THE NUMBER OF MEDIA CHECKS THAT HAVE OCCURRED WHEN NO ; APPARENT TIME HAS ELAPSED. WHILE THIS NUMBER IS < A GIVEN THRESHOLD, WE SAY ; NO CHANGE. WHEN IT EXCEEDS THAT THRESHOLD, WE SAY I-DON'T-KNOW AND RESET ; THE COUNTER TO 0. WHEN WE STORE THE TIME OF LAST SUCCESSFUL ACCESS, IF WE ; SEE THAT TIME HAS PASSED TOO, WE RESET THE COUNTER. ; ACCESSMAX = 5 ; ; DUE TO VARIOUS BOGOSITIES, WE NEED TO CONTINUALLY ADJUST WHAT THE HEAD ; SETTLE TIME IS. THE FOLLOWING ALGORITHM IS USED: ; ; GET THE CURRENT HEAD SETTLE VALUE. ; IF IT IS 0, THEN ; SET SLOW = 15 ; ELSE ; SET SLOW = VALUE ; ... ;********************************************* ;************ OLD ALGORITHM ****************** ;* IF WE ARE SEEKING AND WRITING THEN ;* USE SLOW ;* ELSE ;* USE FAST ;********************************************* ;*********** IBM'S REQUESTED LOGIC *********** ; IF WE ARE SEEKING AND WRITING AND NOT ON AN AT THEN ; USE SLOW ; ELSE ; USE FAST ; ... ; RESTORE CURRENT HEAD SETTLE VALUE ; Set_ID_Flag db 0 ;AN000; If 1, GETBP routine will set the ;Vol_Serial and FileSys_ID in BDS table ;from the media Boot record, if it is > DOS 4.00 ;formatted one. Then Set_ID_flag will be set to 2 ;to signal that volume_label is set from the extended ;boot record and do not set it from the root ;directory as done in SET_VOLUME_ID routine. ;For the old version, Vol_Serial ;will be set to -1, and FileSys_ID will be set ;to "FAT12 " if it is a floppy. public Fat_12_ID Fat_12_ID DB "FAT12 ",0 ;AN000; Default System ID for floppy. public Fat_16_ID Fat_16_ID DB "FAT16 ",0 ;AN000; public Vol_No_Name Vol_No_Name db "NO NAME ",0 ;AN000; public Temp_H Temp_H dw 0 ;AN000; Temporary for 32 bit calculation. public Start_Sec_H Start_Sec_H dw 0 ;AN000; Starting sector number high word. ;Used as an input to DISKIO subroutine. Saved_Word dw 0 ;AN000; Tempory saving place for a word. ;--------------------------------------- ;J.K. 6/29/87 For Multi-track MULTRK_ON EQU 10000000B ;User spcified Mutitrack=on, or System turns ; it on after handling CONFIG.SYS file as a ; default value, if MulTrk_flag = MULTRK_OFF1. MULTRK_OFF1 EQU 00000000B ;initial value. No "Multitrack=" command entered. MULTRK_OFF2 EQU 00000001B ;User specified Multitrack=off. public MulTrk_Flag MulTrk_Flag dw 0 ;AN001; ;J.K. 6/29/87 End of Multi-track definition. ;--------------------------------------------------------------------- public EC35_Flag EC35_Flag db 0 ; flags for electrically compatible 3.5 inch disk drives (mrw 4/88) ;--------------------------------------------------------------------- VRetry_Cnt dw 0 ;AN003; Soft_ECC_Cnt dw 0 ;AN003; ;--------------------------------------------------------------------- MultiTrk_Format_Flag db 0 ;AN007;Testing. If 1, then Multi track format request ;--------------------------------------------------------------------- ; ; IF ID IS F9, HAVE A 96TPI DISK ELSE ; IF BIT 2 IS 0 THEN MEDIA IS NOT REMOVABLE AND COULD NOT HAVE CHANGED ; OTHERWISE IF WITHIN 2 SECS OF LAST DISK OPERATION MEDIA COULD NOT ; HAVE CHANGED, OTHERWISE DONT KNOW IF MEDIA HAS CHANGED ; PUBLIC MEDIA$CHK MEDIA$CHK PROC NEAR MESSAGE FTESTDISK,<"DISK MEDIA CHECK "> MNUM FTESTDISK,AX MESSAGE FTESTDISK, CALL SETDRIVE cmp cs:Secrete_Code, 'jk' ;J.K.11/7/86 Secrete code for DOS 3.3 IBMBIO. jne media$done ;J.K.11/7/86 ; FOR NON-REMOVABLE DISKS ONLY RETURN CHANGED IF CHANGED BY FORMAT, OTHERWISE ; RETURN 'NOT CHANGED'. MOV SI,1 ; ASSUME NO CHANGE TEST WORD PTR [DI].FLAGS,FCHANGED_BY_FORMAT JZ WEARENOTFAKINGIT AND WORD PTR [DI].FLAGS,NOT FCHANGED_BY_FORMAT ; RESET FLAG ; IF MEDIA HAS BEEN CHANGED BY FORMAT, WE MUST ASK THE ROM. CANNOT RELY ON THE ; 2 SECOND TIME CHECK. MOV CS:[TIM_DRV],-1 ; ENSURE THAT WE ASK THE ROM IF MEDIA ; HAS CHANGED TEST WORD PTR [DI].FLAGS,FNON_REMOVABLE JZ WEHAVEAFLOPPY MOV SI,-1 ; INDICATE MEDIA CHANGED JMP SHORT MEDIA$DONE ; ; WE NEED TO RETURN 'NOT CHANGED' IF WE HAVE A HARD FILE. ; WEARENOTFAKINGIT: TEST WORD PTR [DI].FLAGS,FNON_REMOVABLE JNZ MEDIA$DONE WEHAVEAFLOPPY: XOR SI,SI ; PRESUME "I DON'T KNOW" ; ; IF WE HAVE A FLOPPY WITH CHANGELINE SUPPORT, WE ASK THE ROM TO DETERMINE IF ; MEDIA HAS CHANGED. WE DO NOT PERFORM THE 2 SECOND CHECK FOR THESE DRIVES. ;----------------------------------------| ; WARNING: DO NOT CHANGE THE FOLLOWING. ;| ; IT GETS PATCHED IN MSINIT ;| PUBLIC MEDIA_PATCH ;| MEDIA_PATCH: ;| CALL MEDIACHECK ;| JC ERR$EXITJ ;| CALL HASCHANGE ;| JNZ MEDIA$DONE ;| ;----------------------------------------| ; IF WE COME HERE, WE HAVE A FLOPPY WITH NO CHANGELINE SUPPORT MOV SI,1 ; PRESUME NO CHANGE MOV AL,CS:[TIM_DRV] ; LAST DRIVE ACCESSED CMP AL,BYTE PTR [DI].DRIVENUM ;IS DRIVE OF LAST ACCESS THE SAME? JNZ MEDIA$UNK ; NO, THEN "I DON'T KNOW" ; ; CHECK TO SEE IF THIS DRIVE HAS BEEN ACCESSED IN THE LAST 2 SECONDS. CALL CHECK_TIME_OF_ACCESS ; SETS SI CORRECTLY JMP SHORT MEDIA$DONE MEDIA$UNK: DEC SI ; RETURN "I DON'T KNOW" ; ; SI NOW CONTAINS THE CORRECT VALUE FOR MEDIA CHANGE. CLEAN UP THE LEFT OVERS ; MEDIA$DONE: LES BX,CS:[PTRSAV] ; GET ORIGINAL PACKET MOV WORD PTR ES:[BX].TRANS,SI OR SI,SI JS INIT_PATCH JMP EXIT MEDIA$CHK ENDP ;----------------------------------------| ; WARNING: DO NOT CHANGE THE FOLLOWING. ;| ; IT GETS PATCHED IN MSINIT ;| PUBLIC INIT_PATCH ;| INIT_PATCH PROC NEAR ;| CALL MEDIA_SET_VID ;| ;----------------------------------------| MOV CS:[TIM_DRV],-1 ; MAKE SURE WE ASK ROM FOR MEDIA CHECK VOLIDOK: JMP EXIT INIT_PATCH ENDP ERR$EXITJ PROC NEAR MESSAGE FTESTCOM,<"ERR$EXITJ: "> MNUM FTESTCOM,AX MESSAGE FTESTCOM,<" == "> CALL MAPERROR MNUM FTESTCOM,AX MESSAGE FTESTCOM, JMP ERR$EXIT ERR$EXITJ ENDP ; ; PERFORM A CHECK ON THE TIME PASSED SINCE THE LAST ACCESS FOR THIS PHYSICEL ; DRIVE. ; WE ARE ACCESSING THE SAME DRIVE. IF THE TIME OF LAST SUCCESSFUL ACCESS WAS ; LESS THAN 2 SECONDS AGO, THEN WE MAY PRESUME THAT THE DISK WAS NOT CHANGED. ; RETURNS IN SI: ; 0 - IF TIME OF LAST ACCESS WAS >= 2 SECONDS ; 1 - IF TIME WAS < 2 SECONDS (I.E NO MEDIA CHANGE ASSUMED) ; REGISTERS AFFECTED AX,CX,DX, FLAGS. ; CHECK_TIME_OF_ACCESS PROC NEAR PUBLIC CHECK_TIME_OF_ACCESS MOV SI,1 ; PRESUME NO CHANGE. ;SB33014************************************************************* xor AH,AH ; set command to read time int 1Ah ; call rom-bios clock routine ;SB33014************************************************************* ; ; NOW THAT WE ARE READING THE TIME, WE MUST MAKE SURE THAT WE DO NOT LOSE A ; DATE WRAP. THE ROM WILL RETURN THE VALUE ONLY ONCE, SO WE NEED TO NOTE THIS ; FACT. ; SHR AL,1 ADC CS:[DAYCNT],0 ; ADD IT IN TO OUR REMEMBERED DAY COUNT ; ; COMPUTE ELAPSED TIME ; MOV AX,WORD PTR DS:[DI].TIM_LO ; GET STORED TIME SUB DX,AX MOV AX,WORD PTR DS:[DI].TIM_HI SBB CX,AX ; ; CX:DX IS THE ELAPSED TIME ; JNZ TIMECHECK_UNK ; CX <> 0 => > 1 HOUR OR DX,DX ; TIME MUST PASS JNZ TIMEPASSED ; YES, EXAMINE MAX VALUE ; ; NO NOTICEABLE TIME HAS PASSED. WE CANNOT TRUST THE COUNTER TO BE ALWAYS ; AVAILABLE AS THERE ARE BOGUS PROGRAMS THAT GO AND REPROGRAM THE THING. WE ; KEEP A COUNT OF THE NUMBER OF MEDIA CHECKS THAT WE'VE SEEN THAT DO NOT HAVE ; ANY TIME PASSING. IF WE EXCEED A GIVE THRESHOLD, WE GIVE UP ON THE TIMER. ; INC BYTE PTR CS:ACCESSCOUNT CMP BYTE PTR CS:ACCESSCOUNT,ACCESSMAX JB TIMECHECK_RET ; IF COUNT IS LESS THAN THRESHOLD, OK DEC BYTE PTR CS:ACCESSCOUNT ; DON'T LET THE COUNT WRAP JMP SHORT TIMECHECK_UNK ; "I DON'T KNOW" IF MEDIA CHANGED ; ; 18.2 TICS PER SECOND. ; TIMEPASSED: CMP DX,18 * 2 ; MIN ELAPSED TIME? JBE TIMECHECK_RET ; YES, PRESUME NO CHANGE ; ; EVERYTHING INDICATES THAT WE DO NOT KNOW WHAT HAS HAPPENED. ; TIMECHECK_UNK: DEC SI ; PRESUME I DON'T KNOW TIMECHECK_RET: RET CHECK_TIME_OF_ACCESS ENDP ERR$EXITJ2: JMP ERR$EXITJ ; ; BUILD A VALID BPB FOR THE DISK IN THE DRIVE. ; PUBLIC GET$BPB GET$BPB PROC NEAR MESSAGE FTESTDISK,<"DISK BUILD BPB "> MNUM FTESTDISK,AX MESSAGE FTESTDISK, MOV AH,BYTE PTR ES:[DI] ;GET FAT ID BYTE READ BY DOS CALL SETDRIVE ; GET THE CORRECT BDS FOR THE DRIVE TEST WORD PTR [DI].FLAGS,FNON_REMOVABLE JNZ ALREADY_GOTBPB ; NO NEED TO BUILD FOR FIXED DISKS ;J.K. Let's set the default value for VOLID,Vol_Serial,FileSys_ID in BDS table call Clear_IDs ;AN000; mov cs:[Set_ID_Flag],1 ;AN000; Indicate to set system id in BDS CALL GETBP ;BUILD A BPB IF NECESSARY. JC ERR$EXITJ2 ;AN000; If error, Set_ID_flag is set to 0 already. cmp cs:[Set_ID_Flag],2 ;AN000; Already, volume_Label set from Boot record mov cs:[Set_ID_Flag],0 ;AN000; to BDS table? je Already_GotBPB ;AN000; Then do not set it again from Root directory. ;AN000; Otherwise, conventional Boot record. GET$BPB ENDP ;----------------------------------------| ; WARNING: DO NOT CHANGE THE FOLLOWING. ;| ; IT GETS PATCHED IN MSINIT ;| PUBLIC SET_PATCH ;| SET_PATCH PROC NEAR ;| CALL SET_VOLUME_ID ;| ;----------------------------------------| MESSAGE FTESTDISK,<"SET VOLUME ID"> MNUM FTESTDISK,DI MESSAGE FTESTDISK,<" "> MNUM FTESTDISK,DS MESSAGE FTESTDISK, ALREADY_GOTBPB: ADD DI,BYTEPERSEC ; RETURN THE BPB THAT IS IN THE CURRENT BDS PUBLIC SETPTRSAV SETPTRSAV: ; RETURN POINT FOR DSK$INIT LES BX,CS:[PTRSAV] MOV ES:[BX].MEDIA,AH MOV ES:[BX].COUNT,DI MOV ES:[BX].COUNT+2,DS JMP EXIT SET_PATCH ENDP ;J.K. Clear IDs in BDS table. Only applied for Floppies. ;Input: DS:DI -> BDS table ;Output: VOLID set to "NO NAME " ; VOL_SERIAL set to 0. ; FileSys_ID set to "FAT12 " or "FAT16 " ; depending on the flag FATSIZE in BDS. ;All registers saved. public Clear_IDs Clear_IDs proc near ;AN000; push ds ;AN000; push di ;AN000; push es ;AN000; push si ;AN000; push cx ;AN000; push ds ;AN000; pop es ;AN000; es -> bds push cs ;AN000; pop ds ;AN000; ds = cs mov cx, 0 ;AN000; no serial number mov word ptr es:[di.VOL_SERIAL],cx ;AN000; mov word ptr es:[di.VOL_SERIAL]+2,cx ;AN000; mov cx, BOOT_VOLUME_LABEL_SIZE ;AN000; =11 mov si, offset VOL_NO_NAME ;AN000; push di ;AN000; save BDS pointer add di, VOLID ;AN000; points to VOLID field rep movsb ;AN000; pop di ;AN000; restore BDS pointer test es:[di.FATSIZ], FBIG ;AN000; jnz CI_BigFat ;AN000; small fat mov si, offset FAT_12_ID ;AN000; jmp CI_Filesys ;AN000; CI_BigFat: ;AN000; mov si, offset FAT_16_ID ;AN000; big fat CI_Filesys: ;AN000; mov cx, BOOT_SYSTEM_ID_SIZE ;AN000; =8 add di, FILESYS_ID ;AN000; points to FILESYS_ID field rep movsb ;AN000; pop cx ;AN000; pop si ;AN000; pop es ;AN000; pop di ;AN000; pop ds ;AN000; ret ;AN000; Clear_IDs endp ;AN000; ; GETBP - RETURN BPB FROM THE DRIVE SPECIFIED BY THE BDS. ; IF THE RETURN_FAKE_BPB FLAG IS SET, THEN IT DOES NOTHING. ; NOTE THAT WE NEVER COME HERE FOR FIXED DISKS. ; FOR ALL OTHER CASES, ; - IT READS BOOT SECTOR TO PULL OUT THE BPB ; - IF NO VALID BPB IS FOUND, IT THEN READS THE FAT SECTOR, ; TO GET THE FAT ID BYTE TO BUILD THE BPB FROM THERE. ; ; INPUTS: DS:DI POINT TO CORRECT BDS. ; ; OUTPUTS: FILLS IN BPB IN CURRENT BDS IF VALID BPB OR FAT ID ON DISK. ; CARRY SET, AND AL=7 IF INVALID DISK. ; CARRY SET AND ERROR CODE IN AL IF OTHER ERROR. ; If failed to recognize the Boot Record, then will set the ; Set_ID_Flag to 0. ; J.K. This routine will only work for a floppy diskette. ; For a fixed disk, it will just return. PUBLIC GETBP GETBP PROC NEAR ; IF RETURNING FAKE BPB THEN RETURN BPB AS IS. TEST WORD PTR [DI].FLAGS,RETURN_FAKE_BPB OR FNON_REMOVABLE JZ GETBP1 JMP GETRET_EXIT GETBP1: MESSAGE FTESTDISK,<"BUILDING BPB FROM SCRATCH",CR,LF> SAVEREG ; ; ATTEMPT TO READ IN BOOT SECTOR AND DETERMINE BPB. ; WE ASSUME THAT THE 2.X AND GREATER DOS DISKS ALL HAVE A VALID BOOT SECTOR. ; RDBOOT: CALL READBOOTSEC JC GETBP_ERR_RET_brdg ; CARRY SET IF THERE WAS ERROR. CMP BX,0 ; BX IS 0 IF BOOT SECTOR IS VALID. JNZ DOFATBPB CALL MOVBPB ; MOVE BPB INTO REGISTERS. JMP HAS1 Getbp_err_ret_brdg: jmp Getbp_err_ret ; ; WE HAVE A 1.X DISKETTE. ; IN THIS CASE READ IN THE FAT ID BYTE AND FILL IN BPB FROM THERE. ; DOFATBPB: CALL READFAT ; PUTS MEDIA DESCRIPTOR BYTE IN AH JC GETBP_ERR_RET_Brdg ;----------------------------------------| ; WARNING: DO NOT CHANGE THE FOLLOWING. ;| ; IT GETS PATCHED IN MSINIT ;| PUBLIC GETBP1_PATCH ;| GETBP1_PATCH: ;| CALL HIDENSITY ;| ;----------------------------------------| ;TEST FOR A VALID 3.5" MEDIUM CMP [DI].FORMFACTOR,FFSMALL JNZ IS_FLOPPY CMP AH,0F9H ; IS IT A VALID FAT ID BYTE FOR 3.5" ? JNZ GOT_UNKNOWN_MEDIUM MOV BX,OFFSET SM92 ; POINTER TO CORRECT BPB PUSH CS POP ES ASSUME ES:CODE ;J.K. DS points to segment of BDS. The following should be modified ;J.K. to get spf,csec,spa,spt correctly. It had been wrong if DRIVER.SYS ;J.K. is loaded since the BDS is inside the driver.sys. MOV AL,es:[BX.SPF] MOV CX,es:[BX.CSEC] MOV DX,WORD PTR es:[BX.SPA] MOV BX,WORD PTR es:[BX.SPT] JMP SHORT HAS1 ; MUST BE A 5.25" FLOPPY IF WE COME HERE IS_FLOPPY: MOV CL,AH ;SAVE MEDIA AND CL,0F8H ;NORMALIZE CMP CL,0F8H ;COMPARE WITH GOOD MEDIA BYTE JNZ GOT_UNKNOWN_MEDIUM GOODID: MOV AL,1 ;SET NUMBER OF FAT SECTORS MOV BX,64*256+8 ;SET DIR ENTRIES AND SECTOR MAX MOV CX,40*8 ;SET SIZE OF DRIVE MOV DX,01*256+1 ;SET HEAD LIMIT AND SEC/ALL UNIT TEST AH,00000010B ;TEST FOR 8 OR 9 SECTOR JNZ HAS8 ;NZ = HAS 8 SECTORS INC AL ;INC NUMBER OF FAT SECTORS INC BL ;INC SECTOR MAX ADD CX,40 ;INCREASE SIZE HAS8: TEST AH,00000001B ;TEST FOR 1 OR 2 HEADS JZ HAS1 ;Z = 1 HEAD ADD CX,CX ;DOUBLE SIZE OF DISK MOV BH,112 ;INCREASE NUMBER OF DIRECTORY ENTRIES INC DH ;INC SEC/ALL UNIT INC DL ;INC HEAD LIMIT HAS1: PUBLIC HAS1 MOV BYTE PTR DS:[DI].SECPERCLUS,DH MOV BYTE PTR DS:[DI].CDIR,BH MOV WORD PTR DS:[DI].DRVLIM,CX MOV BYTE PTR DS:[DI].MEDIAD,AH MOV BYTE PTR DS:[DI].CSECFAT,AL MOV BYTE PTR DS:[DI].SECLIM,BL MOV BYTE PTR DS:[DI].HDLIM,DL ;SB34DISK001******************************************************************* ;SB the HIDSEC_H field and DRVLIM_L field and the ;SB DRVLIM_H fields need to be set to 0 since this code here is for floppies ;SB 3 LOCS mov word ptr ds:[di].HIDSEC_H,0 mov word ptr ds:[di].HIDSEC_L,0 mov word ptr ds:[di].DRVLIM_H,0 ;SB34DISK001******************************************************************* GETRET: POP BX RESTOREREG ASSUME ES:NOTHING GETRET_EXIT: RET GETBP_ERR_RET: ;J.K. Before doing anything else, set Set_ID_Flag to 0. mov cs:Set_ID_Flag, 0 ;AN000; CALL MAPERROR JMP SHORT GETRET ; ; WE HAVE A 3.5" DISKETTE FOR WHICH WE CANNOT BUILD A BPB. WE DO NOT ASSUME ANY ; TYPE OF BPB FOR THIS MEDIUM. ; GOT_UNKNOWN_MEDIUM: mov cs:Set_ID_Flag, 0 ;AN000; MOV AL,ERROR_UNKNOWN_MEDIA STC JMP SHORT GETRET GETBP ENDP BPBTYPE STRUC SPF DB ? SPT DB ? CDIRE DB ? CSEC DW ? SPA DB ? CHEAD DB ? BPBTYPE ENDS ; ; READ IN THE BOOT SECTOR. SET CARRY IF ERROR IN READING SECTOR. ; BX IS SET TO 1 IF THE BOOT SECTOR IS INVALID, OTHERWISE IT IS 0. ; READBOOTSEC PROC NEAR MOV DH,0 ;HEAD 0 MOV CX,0001 ;CYLINDER 0, SECTOR 1 CALL READ_SECTOR JC ERR_RET XOR BX,BX ; ASSUME VALID BOOT SECTOR. ;******************************************************************************* ; PUT A SANITY CHECK FOR THE BOOT SECTOR IN HERE TO DETECT BOOT SECTORS THAT ; DO NOT HAVE VALID BPBS. ; WE EXAMINE THE FIRST TWO BYTES - THEY MUST CONTAIN A LONG JUMP (69H) OR A ; SHORT JUMP (EBH) FOLLOWED BY A NOP (90H), OR A SHORT JUMP (E9H). ; IF THIS TEST IS PASSED, WE FURTHER CHECK BY EXAMINING THE SIGNATURE AT ; THE END OF THE BOOT SECTOR FOR THE WORD AA55H. ; IF THE SIGNATURE IS NOT PRESENT, WE EXAMINE THE MEDIA DESCRIPTOR BYTE TO ; SEE IF IT IS VALID. ;J.K. 10/15/86 DCR00012. For DOS 3.3, this logic is modified a little bit. ; We are not going to check Signature. Instead we are going to sanity ; check the media byte in BPB regardless of the validity of signature. ; This is to save the already developed commercial products that have ; good jump instruction and signature but with the false BPB informations ; that will crash the diskette drive operation. (For example, Symphony diskette). ;****************************************************************************** CMP BYTE PTR CS:[DISKSECTOR],069H ; IS IT A DIRECT JUMP? JE Check_bpb_MediaByte ; DON'T NEED TO FIND A NOP CMP BYTE PTR CS:[DISKSECTOR],0E9H ; DOS 2.0 JUMP? JE Check_bpb_MediaByte ; NO NEED FOR NOP CMP BYTE PTR CS:[DISKSECTOR],0EBH ; HOW ABOUT A SHORT JUMP. JNE INVALIDBOOTSEC CMP BYTE PTR CS:[DISKSECTOR]+2,090H ; IS NEXT ONE A NOP? JNE INVALIDBOOTSEC ;J.K. 10/15/86 Don't have to perform the following signature check since ; we need to check the media byte even with the good signatured diskette. ;CHECK_SIGNATURE: ; CMP WORD PTR CS:[DISKSECTOR+1FEH],0AA55H ; SEE IF NON-IBM DISK OR 1.X ; ; MEDIA. ; JZ CHECKSINGLESIDED ; GO SEE IF SINGLE SIDED MEDIUM. MAY ; ; NEED SOME SPECIAL HANDLING ; ; CHECK FOR NON-IBM DISKS WHICH DO NOT HAVE THE SIGNATURE AA55 AT THE ; END OF THE BOOT SECTOR, BUT STILL HAVE A VALID BOOT SECTOR. THIS IS DONE ; BY EXAMINING THE MEDIA DESCRIPTOR IN THE BOOT SECTOR. ; Check_bpb_MediaByte: MOV AL,BYTE PTR CS:MEDIABYTE AND AL,0F0H CMP AL,0F0H ; ALLOW FOR STRANGE MEDIA JNZ INVALIDBOOTSEC ; ; THERE WERE SOME (APPARENTLY A LOT OF THEM) DISKETTES THAT HAD BEEN FORMATTED ; UNDER DOS 3.1 AND EARLIER VERSIONS WHICH HAVE INVALID BPBS IN THEIR BOOT ; SECTORS. THESE ARE SPECIFICALLY DISKETTES THAT WERE FORMATTED IN DRIVES ; WITH ONE HEAD, OR WHOSE SIDE 0 WAS BAD. THESE CONTAIN BPBS IN THE BOOT ; SECTOR THAT HAVE THE SEC/CLUS FIELD SET TO 2 INSTEAD OF 1, AS IS STANDARD ; IN DOS. IN ORDER TO SUPPORT THEM, WE HAVE TO INTRODUCE A "HACK" THAT WILL ; HELP OUR BUILD BPB ROUTINE TO RECOGNISE THESE SPECIFIC CASES, AND TO ; SET UP OUT COPY OF THE BPB ACCORDINGLY. ; WE DO THIS BY CHECKING TO SEE IF THE BOOT SECTOR IS OFF A DISKETTE THAT ; IS SINGLE-SIDED AND IS A PRE-DOS 3.20 DISKETTE. IF IT IS, WE SET THE ; SEC/CLUS FIELD TO 1. IF NOT, WE CARRY ON AS NORMAL. CHECKSINGLESIDED: MOV AL,BYTE PTR CS:MEDIABYTE TEST AL,0001H ; IS LOW BIT SET? - INDICATES DOUBLE SIDED JNZ GOODDSK CMP WORD PTR CS:[DISKSECTOR+8],"." SHL 8 + "3" JNZ MUSTBEEARLIER CMP BYTE PTR CS:[DISKSECTOR+10],"2" JAE GOODDSK ; WE MUST HAVE A PRE-3.20 DISKETTE. SET THE SEC/CLUS FIELD TO 1 MUSTBEEARLIER: MOV BYTE PTR CS:[SECPERCLUSINSECTOR],1 JMP SHORT GOODDSK ;****************************************************************************** INVALIDBOOTSEC: INC BX ; INDICATE THAT BOOT SECTOR INVALID GOODDSK: ; CARRY ALREADY RESET CLC RET ERR_RET: ; CARRY IS ALREADY SET ON ENTRY HERE MESSAGE FTESTDISK,<"ERROR IN READBOOT",CR,LF> RET READBOOTSEC ENDP ; MOVES THE BPB READ FROM THE BOOT SECTOR INTO REGISTERS FOR USE BY ; GETBP ROUTINE AT HAS1 ;J.K.- ; If the Set_ID_Flag is 1, and if an extended Boot Record, then set Volume ; Serial Number, Volume Label, File System ID in BDS according to ; the BOOT reocrd. After that, this routine will set the Set_ID_Flag to 2 ; to signal that VOLUME Label is set already from the Extended BOOT record ; (so, don't set it again by calling "SET_VOLUME_ID" routine which uses ; the volume label in the root directory. MOVBPB PROC NEAR SAVEREG PUSH CS POP DS MOV DI,OFFSET BPB_IN_SECTOR MOV DH,BYTE PTR [DI].SECALL ;SECTORS PER UNIT MOV BH,BYTE PTR [DI].DIRNUM ;NUMBER OF DIRECTORY ENTRIES MOV CX,WORD PTR [DI].SECNUM ;SIZE OF DRIVE MOV AH,BYTE PTR [DI].FATID ;MEDIA DESCRIPTOR MOV AL,BYTE PTR [DI].FATSIZE ;NUMBER OF FAT SECTORS MOV BL,BYTE PTR [DI].SLIM ;SECTORS PER TRACK MOV DL,BYTE PTR [DI].HLIM ;NUMBER OF HEADS RESTOREREG cmp cs:[Set_ID_Flag], 1 ;AC008 called by GET$BPB? jne MovBPB_Ret ;AC008 call Mov_Media_IDs ;AC008 jc MovBPB_Conv ;AC008 Conventional boot record? mov cs:[Set_ID_Flag],2 ;AC008 signals that Volume ID is set. MovBPB_Conv: ;AC008 cmp cs:fHave96, 1 ;AC008 jne MovBPB_Ret ;AC008 call ResetChanged ;AC008 Reset Flags in BDS to NOT fCHANGED. MovBPB_Ret: ;AC008 clc ;AC008 ret ;AC008 MOVBPB ENDP ;AC008 ; public Mov_Media_IDs Mov_Media_IDs Proc near ;AN000; ;copy the boot_serial number, Volume id, and Filesystem id from the ;***Extended Boot record*** in cs:DiskSector to the BDS table pointed ;by DS:DI. ;In.) DS:DI -> BDS ; CS:DiskSector = Valid extended boot record. ;Out.) Vol_Serial, Volid and System_Id in BDS are set according to ; the boot record information. ; Carry flag set if not an extended BPB. ; All registers saved except the flag. cmp cs:[Ext_Boot_Sig], EXT_BOOT_SIGNATURE ;AN000; = 41 jne MMI_Not_Ext ;AN000; push cx ;AN000; mov cx, cs:[Boot_Serial_L] ;AN000; mov word ptr ds:[di.VOL_SERIAL],cx ;AN000; mov cx, cs:[Boot_Serial_H] ;AN000; mov word ptr ds:[di.VOL_SERIAL+2],cx ;AN000; push ds ;AN000; Save regs. push di ;AN000; push es ;AN000; push si ;AN000; push ds ;AN000; ds-> cs, es-> bds pop es ;AN000; push cs ;AN000; pop ds ;AN000; mov cx, BOOT_VOLUME_LABEL_SIZE ;AN000; mov si, offset Boot_Volume_Label;AN000; push di add di, VOLID ;AN000; rep movsb ;AN000; pop di mov cx, BOOT_SYSTEM_ID_SIZE ;AN000; =8 mov si, offset Boot_System_ID ;AN000; add di, FILESYS_ID ;AN000; rep movsb ;AN000; pop si ;AN000; pop es ;AN000; pop di ;AN000; pop ds ;AN000; pop cx ;AN000; clc ;AN000; MMI_Ret: ;AN000; ret ;AN000; MMI_Not_Ext: ;AN000; stc ;AN000; ret ;AN000; Mov_Media_IDs endp ;AN000; ; READ IN THE FAT SECTOR AND GET THE MEDIA BYTE FROM IT. ; INPUT : AL CONTAINS LOGICAL DRIVE. ; OUTPUT: ; CARRY SET IF AN ERROR OCCURS, AX CONTAINS ERROR CODE. ; OTHERWISE, AH CONTAINS MEDIA BYTE ON EXIT. AL IS PRESERVED. READFAT PROC NEAR PUSH AX ; PRESERVE LOGICAL DRIVE IN AL MOV DH,0 ; HEAD 0 MOV CX,0002 ; CYLINDER 0, SECTOR 2 CALL READ_SECTOR ; CS:BX POINTS TO FAT SECTOR JC BAD_FAT_RET POP AX ; RESET LOGICAL DRIVE MOV AH,BYTE PTR CS:[BX] ; MEDIA BYTE RET BAD_FAT_RET: ; CARRY SET ON ENTRY MESSAGE FTESTDISK,<"ERROR IN FAT READ",CR,LF> POP CX ; CLEAR STACK RET READFAT ENDP ; READ A SINGLE SECTOR INTO THE TEMP BUFFER. ; PERFORM THREE RETRIES IN CASE OF ERROR. ; INPUTS: DRIVE HAS PHYSICAL DRIVE TO USE ; CX HAS SECTOR AND CYLINDER ; DH HAS HEAD ; OUTPUTS: CARRY CLEAR ; CS:BX POINT TO SECTOR ; CARRY SET ; AX HAS ROM ERROR CODE ; REGISTERS ES AND BP ARE PRESERVED. READ_SECTOR PROC NEAR PUBLIC READ_SECTOR PUSH BP MOV BP,3 ; MAKE 3 ATTEMPTS PUSH ES ;SB33015***************************************************************** mov DL, byte ptr ds:[di].DriveNum ;SB;3.30* mov BX, offset DiskSector ; Get ES:BX to point to buffer ;SB;3.30* push CS ; get the segment right ;SB;3.30* pop ES ; now ES:BX is correct ;SB;3.30* ;SB33015***************************************************************** RD_RET: ;SB33016***************************************************************** mov AX, 0201h ; number of sectors to 1 (AL=1);SB;3.30* int 13h ; call rom-bios disk routines ;SB;3.30* ;SB33016***************************************************************** JNC OKRET2 Rd_rty: CALL AGAIN ; RESET DISK, DECREMENT BP, PRESERVE AX jz Err_RD_RET test word ptr ds:[di].flags,fNon_Removable JNZ RD_RET cmp cs:[Media_Set_For_Format], 0 ;AN012; jne Rd_Skip1_DPT ;AN012; push ds ;J.K. 11/7/86 For retry, set the head settle time push ax ;to 0Fh. PTM845. lds si,cs:DPT mov al, ds:[si].disk_head_sttl mov cs:[save_head_sttl],al mov byte ptr ds:[si].disk_head_sttl, NormSettle pop ax pop ds Rd_Skip1_DPT: ;AN012; ;SB33017***************************************************************** ; SET CMD TO READ (AH=2) AND ;SB ;3.30 MOV AX, 0201h ; NUM OF SECTORS TO 1 (AL=1) ;SB ;3.30 INT 13h ; CALL ROM-BIOS DISK ROUTINES ;SB ;3.30 ;SB33017***************************************************************** pushf ;AN012; cmp cs:[Media_Set_For_Format], 0 ;AN012; jne Rd_Skip2_DPT ;AN012; push ds push ax lds si,cs:DPT mov al, cs:[save_head_sttl] mov byte ptr ds:[si].disk_head_sttl, al pop ax pop ds Rd_Skip2_DPT: ;AN012; popf ;AN012; jnc OKRET2 jmp Rd_rty ERR_RD_RET: MOV DL,-1 ; MAKE SURE WE ASK ROM IF MEDIA HAS CHANGED STC ; RETURN ERROR ; UPDATE INFORMATION PERTAINING TO LAST DRIVE ACCESSED, TIME OF ACCESS, LAST ; TRACK ACCESSED IN THAT DRIVE. OKRET2: MOV CS:[STEP_DRV],DL ; SET UP FOR HEAD SETTLE LOGIC IN DISK. MOV CS:[TIM_DRV],DL ;SAVE DRIVE LAST ACCESSED MOV BYTE PTR [DI].TRACK,CH ; SAVE LAST TRACK ACCESSED ON THIS DRIVE PUSHF ; PRESERVE FLAGS IN CASE ERROR OCCURRED CALL SET_TIM POPF ; RESTORE FLAGS POP ES POP BP RET READ_SECTOR ENDP ;----------------------------------------------------------- ; ; DISK REMOVABLE ROUTINE ARR 2.41 ; DSK$REM PROC NEAR ;ARR 2.41 PUBLIC DSK$REM MESSAGE FTESTDISK,<"DISK REMOVABLE "> MNUM FTESTDISK,AX MESSAGE FTESTDISK, ; AL IS UNIT # CALL SETDRIVE ; GET BDS FOR THIS DRIVE TEST WORD PTR [DI].FLAGS,FNON_REMOVABLE JNZ NON_REM JMP EXIT NON_REM: JMP BUS$EXIT ;ARR 2.41 DSK$REM ENDP ; SETDRIVE SCANS THROUGH THE DATA STRUCTURE OF BDSS, AND RETURNS A POINTER TO ; THE ONE THAT BELONGS TO THE DRIVE SPECIFIED. CARRY IS SET IF NONE EXISTS FOR ; THE DRIVE. ; IF THE BYTE [PHYS_DRV] IS 0 THEN ; ON ENTRY, AL CONTAINS THE LOGICAL DRIVE NUMBER. ; ON EXIT, DS:DI POINTS TO CORRECT BDS FOR THE DRIVE IF CARRY CLEAR. ; ELSE IF THE BYTE [PHYS_DRV] IS 1 THEN (ONLY USED FOR FIXED DISKS WHEN AN ECC ; ERROR OCCURS) ; ON ENTRY, DL CONTAINS THE PYHSICAL DRIVE NUMBER. ; ON EXIT, DS:DI POINTS TO CORRECT BDS FOR THE DRIVE IF CARRY CLEAR. PUBLIC SETDRIVE SETDRIVE PROC NEAR MESSAGE FTESTDISK,<"SETDRIVE",CR,LF> PUSH BX PUSH CS POP DS ASSUME DS:CODE ; ASSUME FIRST BDS IS IN THIS SEGMENT MOV DI,WORD PTR START_BDS SCAN_LOOP: CMP BYTE PTR CS:[PHYS_DRV],1 ; DOES AL HAVE PHYSICAL DRIVE? JB USE_LOGICAL_DRV CMP BYTE PTR [DI].DRIVENUM,AL JE SETDRV JMP SHORT GET_NXT_BDS USE_LOGICAL_DRV: CMP BYTE PTR [DI].DRIVELET,AL JE SETDRV GET_NXT_BDS: MOV BX,WORD PTR [DI].LINK+2 ; GO TO NEXT BDS MOV DI,WORD PTR [DI].LINK MOV DS,BX ASSUME DS:NOTHING CMP DI,-1 JNZ SCAN_LOOP STC SETDRV: POP BX RET SETDRIVE ENDP ;----------------------------------------------------------- ; ; DISK I/O ROUTINES ; DSK$WRITV PROC NEAR PUBLIC DSK$WRITV MESSAGE FTESTDISK,<"DISK WRITE WITH VERIFY "> MNUM FTESTDISK,AX MESSAGE FTESTDISK,<" "> MNUM FTESTDISK,DX MESSAGE FTESTDISK,<" FOR "> MNUM FTESTDISK,CX MESSAGE FTESTDISK, MOV CS:[WRTVERIFY],103H JMP SHORT DSK$CL DSK$WRIT: PUBLIC DSK$WRIT MESSAGE FTESTDISK,<"DISK WRITE "> MNUM FTESTDISK,AX MESSAGE FTESTDISK,<" "> MNUM FTESTDISK,DX MESSAGE FTESTDISK,<" FOR "> MNUM FTESTDISK,CX MESSAGE FTESTDISK, MOV CS:[WRTVERIFY],ROMWRITE DSK$CL: CALL DISKIO DSK$IO: JC DSKBAD JMP EXIT DSKBAD: JMP ERR$CNT DSK$WRITV ENDP DSK$READ PROC NEAR PUBLIC DSK$READ MESSAGE FTESTDISK,<"DISK READ "> MNUM FTESTDISK,AX MESSAGE FTESTDISK,<" "> MNUM FTESTDISK,DX MESSAGE FTESTDISK,<" FOR "> MNUM FTESTDISK,CX MESSAGE FTESTDISK, CALL DISKRD JMP DSK$IO DSK$READ ENDP ; MISCELLANEOUS ODD JUMP ROUTINES. MOVED OUT OF MAINLINE FOR SPEED. ; IF WE HAVE A SYSTEM WHERE WE HAVE VIRTUAL DRIVES, WE NEED TO PROMPT THE ; USER TO PLACE THE CORRECT DISK IN THE DRIVE. CHECKSINGLE PROC NEAR PUBLIC CHECKSINGLE PUSH AX PUSH BX MOV BX,WORD PTR DS:[DI].FLAGS ; IF HARD DRIVE, CANNOT CHANGE DISK. ; IF CURRENT OWNER OF PHYSICAL DRIVE, NO NEED TO CHANGE DISKETTE. TEST BL,FNON_REMOVABLE OR FI_OWN_PHYSICAL JNZ SINGLERET TEST BL,FI_AM_MULT ; IS THERE A DRIVE SHARING THIS ; PHYSICAL DRIVE? JZ SINGLERET ; LOOK FOR THE PREVIOUS OWNER OF THIS PHYSICAL DRIVE AND RESET ITS OWNERSHIP ; FLAG. MOV AL,DS:[DI].DRIVENUM ; GET PHYSICAL DRIVE NUMBER PUSH DS ; PRESERVE POINTER TO CURRENT BDS PUSH DI PUSH CS POP DS ASSUME DS:CODE MOV DI,OFFSET START_BDS SCAN_LIST: MOV BX,WORD PTR [DI].LINK+2 ; GO TO NEXT BDS MOV DI,WORD PTR [DI].LINK MOV DS,BX ASSUME DS:NOTHING CMP DI,-1 ; END OF LIST? JZ SINGLE_ERR_RET ; MUST BE ERROR CMP BYTE PTR [DI].DRIVENUM,AL JNZ SCAN_LIST CHECK_OWN: MOV BX,WORD PTR [DI].FLAGS TEST BL,FI_OWN_PHYSICAL JZ SCAN_LIST XOR BL,FI_OWN_PHYSICAL ; RESET OWNERSHIP FLAG MOV WORD PTR DS:[DI].FLAGS,BX POP DI ; RESTORE POINTER TO CURRENT BDS POP DS XOR BX,BX OR BL,FI_OWN_PHYSICAL ; ESTABLISH CURRENT BDS AS OWNER OR WORD PTR [DI].FLAGS,BX ; ; WE EXAMINE THE FSETOWNER FLAG. IF IT IS SET, THEN WE ARE USING THE CODE IN ; CHECKSINGLE TO JUST SET THE OWNER OF A DRIVE. WE MUST NOT ISSUE THE PROMPT ; IN THIS CASE. ; CMP BYTE PTR CS:[FSETOWNER],1 JZ SINGLERET ; TO SUPPORT "BACKWARD" COMPATIBILITY WITH IBM'S "SINGLE DRIVE STATUS BYTE" ; WE NOW CHECK TO SEE IF WE ARE IN A SINGLE DRIVE SYSTEM AND THE APPLICATION ; HAS "CLEVERLY" DIDDLED THE SDSB CMP CS:[SINGLE],2 ; IF (SINGLE_DRIVE_SYSTEM) JNE SHORT IGNORE_SDSB SAVEREG ; THEN MOV AL,DS:[DI].DRIVELET ; IF (CURR_DRV == REQ_DRV) MOV AH,AL XOR DI,DI MOV DS,DI XCHG AL,DS:BYTE PTR LSTDRV ; THEN SWAP(CURR_DRV,REQ_DRV) CMP AH,AL ; ELSE RESTOREREG ; SWAP(CURR_DRV,REQ_DRV) JE SINGLERET ; ISSUE SWAP_DSK_MSG IGNORE_SDSB: CALL SWPDSK ; ASK USER FOR CORRECT DISK SINGLERET: POP BX POP AX RET SINGLE_ERR_RET: STC POP DI ; RESTORE CURRENT BDS POP DS JMP SHORT SINGLERET BADDRIVE: MOV AL,8 ;Sector not found jmp short BadDrive_Ret ;AN004;AN005;AN006; UnformattedDrive: ;AN004;AN005;AN006; mov al,7 ;AN004;Unknown media;AN005;AN006; BadDrive_Ret: STC IORET: RET BOGUSSETTLE: MOV AL,NORMSETTLE ; SOMEONE HAS DIDDLED THE SETTLE JMP GOTSLOWSETTLE CHECKSINGLE ENDP ;------------------------------------------------------------ ; ; DISK I/O HANDLER ; ; AL = DRIVE NUMBER (0-6) ; AH = MEDIA DESCRIPTOR ; CX = SECTOR COUNT ; DX = FIRST SECTOR (low) ; [Start_Sec_H] = FIRST SECTOR (high) ;J.K. 32 bit calculation. ; DS = CS ; ES:DI = TRANSFER ADDRESS ; [RFLAG]=OPERATION (2=READ, 3=WRITE) ; [VERIFY]=1 FOR VERIFY AFTER WRITE ; ; IF SUCCESSFUL CARRY FLAG = 0 ; ELSE CF=1 AND AL CONTAINS ERROR CODE ; PUBLIC DISKRD DISKRD PROC NEAR MOV CS:[RFLAG],ROMREAD DISKIO: MOV BX,DI ; ES:BX = TRANSFER ADDRESS CALL SETDRIVE ; MAP LOGICAL AND PHYSICAL MOV AL,BYTE PTR DS:[DI].MEDIAD MOV CS:MEDBYT,AL ; PRESERVE MEDIA BYTE FOR DRIVE FOR USE ; IN DETERMINING MEDIA CHANGE. JCXZ IORET ;SB34DISK006****************************************************************** ;SB See if the Media is formatted or not by checking the flags field in ;SB in the BDS. If it is unformatted we cannot allow I/O, so we should ;SB go to the error exit at label UnformattedDrive. 2LOCS test word ptr ds:[di].FLAGS, UNFORMATTED_MEDIA jnz UnformattedDrive ;SB34DISK006****************************************************************** mov cs:[SECCNT],CX ;save sector count MOV CS:[SPSAV],SP ; SAVE SP ; ENSURE THAT WE ARE TRYING TO ACCESS VALID SECTORS ON THE DRIVE ; mov ax,dx ;AN000; save DX to AX xor si,si ;AN000; add dx,cx ;AN000; adc si,0 ;AN000; cmp [di].DrvLim, 0 ;AN000; Is this drive > 32 bit sector ? je Sanity32 ;AN000; cmp si,0 ;AN000; jne BADDRIVE ;AN000; cmp dx, [di].DrvLim ;AN000; ja BADDRIVE ;AN000; jmp short SanityOK ;AN000; Sanity32: ;AN000; add si, cs:[Start_Sec_H] ;AN000; cmp si, [di].DrvLim_H ;AN000; jb SanityOK ;AN000; ja BADDRIVE ;AN000; cmp dx, [di].DrvLim_L ;AN000; ja BADDRIVE ;AN000; SanityOK: ;AN000; mov dx,cs:[Start_Sec_H] ;AN000; add ax,word ptr [di].HIDSEC_L ;AN000; adc dx,word ptr [di].Hidsec_H ;AN000; ;J.K. Now DX;AX have the physical first sector. ;Since the following procedures is going to destroy AX, let's ;save it temporarily to SAVED_WORD. mov cs:[Saved_Word], ax ;AN000; Save the sector number (low) ; MOV SI,DX ; ADD SI,CX ; ADD DX,WORD PTR [DI].HIDSEC ; ADD IN THE HIDDEN SECTORS ; CMP SI,WORD PTR [DI].DRVLIM ; COMPARE AGAINST DRIVE MAX ; JA BADDRIVE ; SET UP POINTER TO DISK BASE TABLE IN [DPT]. WE CANNOT ASSUME THAT IOSETUP ; WILL DO IT BECAUSE WE WILL SKIP THE SET UP STUFF WITH HARD DISKS. PUSH DS XOR AX,AX MOV DS,AX LDS SI,DWORD PTR DS:[DSKADR]; CURRENT DISK PARM TABLE MOV WORD PTR CS:DPT,SI MOV WORD PTR CS:DPT+2,DS POP DS TEST WORD PTR [DI].FLAGS,FNON_REMOVABLE JNZ SKIP_SETUP CALL CHECKSINGLE ; ; CHECK TO SEE IF WE HAVE PREVIOUSLY NOTED A CHANGE LINE. THE ROUTINE ; RETURNS IF EVERYTHING IS OK. OTHERWISE, IT POPS OFF THE STACK AND RETURNS ; THE PROPER ERROR CODE. ; ;----------------------------------------| ; WARNING: DO NOT CHANGE THE FOLLOWING. ;| ; IT GETS PATCHED IN MSINIT ;| PUBLIC DISKIO_PATCH ;| DISKIO_PATCH: ;| CALL CHECKLATCHIO ;| ;----------------------------------------| ; ; SET UP TABLES AND VARIABLES FOR I/O CALL IOSETUP ; ; NOW THE SETTLE VALUES ARE CORRECT FOR THE FOLLOWING CODE ; SKIP_SETUP: ;J.K. 32 bit sector calculation. ; DX;[Saved_Word] = starting sector number. mov ax,dx ;AN000; xor dx,dx ;AN000; DIV WORD PTR [DI].SECLIM ;DIVIDE BY SEC PER TRACK mov cs:[Temp_H],ax ;AN000; mov ax, cs:[Saved_Word] ;AN000; Restore the lower word div word ptr [di].SecLim ;AN000; ;Now, [Temp_H],AX = track #, DX = sector INC DL ;Sector number is 1 based. MOV CS:[CURSEC],DL ;SAVE CURRENT SECTOR MOV CX,WORD PTR [DI].HDLIM ;GET NUMBER OF HEADS push ax ;AN000; XOR DX,DX ;DIVIDE TRACKS BY HEADS PER CYLINDER mov ax, cs:[Temp_H] ;AN000; DIV CX mov cs:[Temp_H],ax ;AN000; pop ax ;AN000; div cx ;AN000; ;Now, [Temp_H],AX = cyliner #, DX = head cmp cs:[Temp_H],0 ;AN000; ja BADDRIVE_brdg ;AN000; cmp AX, 1024 ;AN000; 2**10 currently maxium for track #. ja BADDRIVE_brdg ;AN000; MOV CS:[CURHD],DL ;SAVE CURRENT HEAD MOV CS:[CURTRK],AX ;SAVE CURRENT TRACK ; ; WE ARE NOW SET UP FOR THE I/O. NORMALLY, WE CONSIDER THE DMA BOUNDARY ; VIOLATIONS HERE. NOT TRUE. WE PERFORM THE OPERATION AS IF EVERYTHING IS ; SYMMETRIC; LET THE INT 13 HANDLER WORRY ABOUT THE DMA VIOLATIONS. ; MOV AX, CS:[SECCNT] CALL BLOCK CALL DONE RET DISKRD ENDP ; BADDRIVE_Brdg:jmp Baddrive ; ; SET THE DRIVE-LAST-ACCESSED FLAG FOR DISKETTE ONLY. WE KNOW THAT THE HARD ; DISK WILL NOT BE REMOVED. ; DS:DI -> CURRENT BDS. ; AX,CX,SI ARE DESTROYED. ; PUBLIC IOSETUP IOSETUP PROC NEAR MOV AL,[DI].DRIVENUM MOV CS:[TIM_DRV],AL ; SAVE DRIVE LETTER ; ; DETERMINE PROPER HEAD SETTLE VALUES ; cmp cs:[Media_Set_For_Format], 0 ;AN012; jne Skip_DPT_Setting ;AN012; MOV CX,DS LDS SI,DWORD PTR CS:[DPT] ; GET POINTER TO DISK BASE TABLE MOV AL,CS:[EOT] MOV [SI].DISK_EOT,AL ; BUMP FOR US MOV AL,[SI].DISK_MOTOR_STRT ; PRESERVE OLD MOTOR START TIME MOV CS:MOTORSTARTUP,AL ; ; FOR 3.5" DRIVES, BOTH EXTERNAL AS WELL AS ON THE K09, WE NEED TO SET THE ; MOTOR START TIME TO 4. THIS CHECKING FOR EVERY I/O IS GOING TO AFFECT ; PERFORMANCE ACROSS THE BOARD, BUT IS NECESSARY!! - RS ; PUSH ES MOV ES,CX ; ES:DI -> TO CURRENT BDS CMP BYTE PTR ES:[DI].FORMFACTOR,FFSMALL JNZ MOTOR_START_OK MOV AL,4 XCHG AL,[SI].DISK_MOTOR_STRT MOTOR_START_OK: POP ES ; ; DS:SI NOW POINTS TO DISK PARAMETER TABLE. GET CURRENT SETTLE AND SET FAST ; SETTLE ; XOR AL,AL INC AL ; IBM WANTS FAST SETTLE TO BE 1 - RS. XCHG AL,[SI].DISK_HEAD_STTL ; GET SETTLE AND SET UP FOR FAST MOV CS:SETTLECURRENT,AL MOV AL,NORMSETTLE ; SOMEONE HAS DIDDLED THE SETTLE GOTSLOWSETTLE: MOV DS,CX MOV CS:SETTLESLOW,AL Skip_DPT_Setting: ;AN012; RET ; ; SET TIME OF LAST ACCESS, AND RESET DEFAULT VALUES IN THE DPT. ; DONE: TEST WORD PTR [DI].FLAGS,FNON_REMOVABLE JNZ RETZ ; DO NOT SET FOR NON-REMOVABLE MEDIA CALL SET_TIM ; SET TIME OF LAST ACCESS FOR DRIVE ; ; RESTORE HEAD SETTLE AND EOT VALUES ; DIDDLEBACK: pushf ;AN013;Save flag cmp cs:[Media_Set_For_Format], 0 ;AN012; jne NoDiddleBack ;AN012; PUSH AX MOV DX,DS MOV AL,CS:SETTLECURRENT MOV AH,CS:MOTORSTARTUP LDS SI,CS:DPT ; MOV [SI].DISK_EOT,9 ;J.K. 4/25/86. Should not change the EOT value ;of diskbase to 9. This cause a problem ;with 1.44M diskette in Polaris when the user ;issue INT 13 with the default system ;diskbase. mov [si].DISK_EOT,9 ;J.K. 11/5/86. For compatibility reason, return ;back to set it to 9 ( PTM826 ). MOV [SI].DISK_HEAD_STTL,AL MOV [SI].DISK_SECTOR_SIZ,2 MOV [SI].DISK_MOTOR_STRT,AH MOV DS,DX POP AX NoDiddleBack: ;AN013; popf ;AN013;Restore flag RETZ: RET ;READ THE NUMBER OF SECTORS SPECIFIED IN AX, HANDLING TRACK BOUNDARIES ;DS:DI -> BDS FOR THIS DRIVE BLOCK: OR AX,AX ;SEE IF ANY SECTORS TO READ JZ RETZ ;Fixed disk will not be restricted to the track-by-track basis. -J.K.4/10/86 test word ptr [di].Flags, fNon_Removable ;J.K. Fixed disk? jz BLOCK_FLOPPY ;J.K. ;SB34DISK002***************************************************************** ;SB Check to see if multi track operation is allowed. If not ;SB we have to go to the block_floppy below to break up the operation. ;SB 2 LOCS test word ptr CS:MulTrk_Flag, MulTrk_ON jz BLOCK_FLOPPY ;SB34DISK002***************************************************************** call DISK ;J.K. xor ax,ax RET ;J.K. BLOCK_FLOPPY: ;J.K.4/10/86 ; ; READ AT MOST 1 TRACK WORTH. PERFORM MINIMIZATION AT SECTOR / TRACK ; MOV CL,BYTE PTR [DI].SECLIM INC CL SUB CL,CS:CURSEC ; LEEAC 3.20 ADD SEGMENT OVERRIDE XOR CH,CH CMP AX,CX JAE GOTMIN MOV CX,AX GOTMIN: ; ; AX IS THE REQUESTED NUMBER OF SECTORS TO READ ; CX IS THE NUMBER THAT WE CAN DO ON THIS TRACK ; PUSH AX PUSH CX MOV AX,CX ; AL IS NUMBER OF SECTORS TO READ CALL DISK POP CX POP AX ; ; CX IS THE NUMBER OF SECTORS JUST TRANSFERRED ; SUB AX,CX ; REDUCE SECTORS-REMAINING BY LAST I/O SHL CL,1 ADD BH,CL ; ADJUST TRANSFER ADDRESS JMP BLOCK IOSETUP ENDP DskErr_Brdg: jmp DskErr ;AN003; ; ;PERFORM DISK I/O WITH RETRIES ; AL = NUMBER OF SECTORS (1-8, ALL ON ONE TRACK) ; DI POINT TO DRIVE PARAMETERS ; ES:BX = TRANSFER ADDRESS (MUST NOT CROSS A 64K PHYSICAL BOUNDARY) ; [RFLAG] = 2 IF READ, 3 IF WRITE ; [VERIFY] = 0 FOR NORMAL, 1 FOR VERIFY AFTER WRITE PUBLIC DISK DISK PROC NEAR MOV BP,MAXERR ; SET UP RETRY COUNT mov cs:VRetry_Cnt, BP ;AN003;Verify op. retry cnt for Write-Verify. mov cs:Soft_ECC_Cnt, BP ;AN003;Soft ECC error retry count. MOV AH,CS:RFLAG ;GET READ/WRITE INDICATOR RETRY: PUSH AX MOV DX,CS:[CURTRK] ;LOAD CURRENT CYLINDER test word ptr [di].FLAGS, fNon_Removable ;Fixed disk? - J.K. 4/7/86 jz DISK_NOT_MINI ;no, skip this. - J.K. 4/7/86 cmp [di].IsMini, 1 ;Is this a mini disk? - J.K. 4/7/86 jnz DISK_NOT_MINI ;No. continue to next.- J.K. 4/7/86 add dx, [di].Hidden_Trks ;else add hidden trks.- J.K. 4/7/86 DISK_NOT_MINI: ;J.K. 4/7/86 ROR DH,1 ROR DH,1 OR DH,CS:[CURSEC] MOV CX,DX XCHG CH,CL ; CL = SECTOR, CH = CYLINDER MOV DH,BYTE PTR CS:[CURHD] ; LOAD CURRENT HEAD NUMBER AND MOV DL,BYTE PTR [DI].DRIVENUM ; PHYSICAL DRIVE NUMBER CMP BYTE PTR [DI].FORMFACTOR,FFHARDFILE JZ DO_FAST ; HARD FILES USE FAST SPEED ; IF WE HAVE [STEP_DRV] SET TO -1, WE USE THE SLOW SETTLE TIME. ; THIS HELPS WHEN WE HAVE JUST DONE A RESED DISK OPERATION AND THE HEAD HAS ; BEEN MOVED TO ANOTHER CYLINDER - THE PROBLEM CROPS UP WITH 3.5" DRIVES. CMP CS:[STEP_DRV],-1 JZ DO_WRITEJ CMP AH,ROMREAD ; ARR 2.20 JE DO_FAST CMP AH, ROMVERIFY JE DO_FAST DO_WRITEJ: ; READS ALWAYS FAST, UNLESS WE HAVE JUST DONE A DISK RESET OPERATION JMP DO_WRITE ; ARR 2.20 READS ALWAYS FAST DO_FAST: ; ARR 2.20 CALL FASTSPEED ; MZ 2.21 CHANGE SETTLE MODE TESTERR: ; MZ 2.21 JC DSKERR_brdg ; SET DRIVE AND TRACK OF LAST ACCESS MOV CS:[STEP_DRV],DL ; ARR 2.20 SET DRIVE MOV BYTE PTR [DI].TRACK,CH ; ARR 2.20 SAVE TRACK NO_SET: CMP CS:WRTVERIFY,103H ; CHECK FOR WRITE AND VERIFY JZ DOVERIFY NOVERIFY: POP AX ;SB34DISK003***************************************************************** ;SB Check the flags word in the BDS to see if the drive is non removable ;SB If not we needn't do anything special ;SB If it is a hard disk then check to see if multi-track operation ;SB is specified. If specified we don't have to calculate for the next ;SB track since we are already done. So we can go to the exit of this ;SB routine. 5 LOCS test word ptr [di].FLAGS, fNON_REMOVABLE jz ITS_REMOVABLE test CS:MulTrk_Flag, MulTrk_ON jnz DISK_RET ITS_REMOVABLE: ;SB34DISK003***************************************************************** AND CL,03FH ; ELIMINATE CYLINDER BITS FROM SECTOR XOR AH,AH SUB CS:[SECCNT],AX ; REDUCE COUNT OF SECTORS TO GO ADD CL,AL ; NEXT SECTOR MOV CS:[CURSEC],CL CMP CL,BYTE PTR [DI].SECLIM ; SEE IF SECTOR/TRACK LIMIT REACHED JBE DISK_RET NEXTTRACK: MOV CS:[CURSEC],1 ; START WITH FIRST SECTOR OF NEXT TRACK MOV DH,CS:[CURHD] INC DH CMP DH,BYTE PTR [DI].HDLIM JB NOXOR XOR DH,DH INC CS:[CURTRK] ;NEXT TRACK NOXOR: MOV CS:[CURHD],DH DISK_RET: CLC ; LEEAC RET DISK ENDP ; THE REQUEST IS FOR WRITE. DETERMINE IF WE ARE TALKING ABOUT THE SAME ; TRACK AND DRIVE. IF SO, USE THE FAST SPEED. DO_WRITE PROC NEAR CMP DL,CS:[STEP_DRV] ; ARR 2.20 JNZ DO_NORM ; WE HAVE CHANGED DRIVES CMP CH,BYTE PTR [DI].TRACK ; ARR 2.20 JZ DO_FAST ; WE ARE STILL ON THE SAME TRACK DO_NORM: CALL NORMSPEED JMP SHORT TESTERR ; MZ 2.21 TEST FOR ERROR DO_WRITE ENDP ; ; WE HAVE A VERIFY REQUEST ALSO. GET STATE INFO AND GO VERIFY ; DOVERIFY PROC NEAR POP AX ; RESTORE SECTOR COUNT PUSH AX MOV AH,ROMVERIFY ; REQUEST VERIFY CALL FASTSPEED ; MZ 2.21 CHANGE SETTLE MODE JNC NOVERIFY ;SB34DISK004************************************************************** ;SB check the error returned in AH to see if it is a SOFT ECC error. ;SB If it is not we needn't do anything special. If it is a SOFT ;SB ECC error then decrement the SOFT_ECC_CNT error retry count. If ;SB this retry count becomes 0 then we just ignore the error and go to ;SB No_verify but if we can still try then we call the routine to reset ;SB the disk and go to DSKerr1 to retry the operation. 6 LOCS cmp ah,11h ;SOFT ECC error ? jnz Not_SoftECC_Err dec SOFT_ECC_CNT jz NoVerify ;no more retry call ResetDisk ;reset disk jmp DskErr1 ;retry ;SB34DISK004************************************************************** Not_SoftECC_Err: ;AN003;Other error. call ResetDisk ;AN003; dec VRetry_Cnt ;AN003; jmp DskErr0 ;AN003; DOVERIFY ENDP ; ; NEED TO SPECIAL CASE THE CHANGE-LINE ERROR AH=06H. IF WE GET THIS, WE ; NEED TO RETURN IT. ; ;----------------------------------------| ; WARNING: DO NOT CHANGE THE FOLLOWING. ;| ; IT GETS PATCHED IN MSINIT ;| PUBLIC DSKERR ;| DSKERR PROC NEAR ;| CALL CHECKIO ;| ;---------------------------------------;| cmp cs:MultiTrk_Format_Flag, 1 ;AN007;Multi trk format request? jne DoChkAgain ;AN007; mov bp, 1 ;AN007;No more retry. mov cs:MultiTrk_Format_Flag, 0 ;AN007;Clear the flag. DoChkAgain: ;AN007; CALL AGAIN DskErr0: ;AN003; JZ HARDERR test word ptr [di].FLAGS, fNon_Removable ;AN009; jnz Skip_TimeOut_Chk ;AN009; CMP AH,80H ;TIMEOUT? JZ HARDERR ;*** Skip_TimeOut_Chk: ;AN009; cmp ah, 0cch ;AN003;Write Fault error? jz Write_Fault_Err ;AN003; Then, don't retry. mov cs:Soft_ECC_Cnt, MAXERR ;AN003;Set Soft_ECC_Cnt back to MAXERR DSKERR1: POP AX ;RESTORE SECTOR COUNT JMP RETRY Write_Fault_Err: ;AN003; mov bp, 1 ;AN003;Just retry only once for Write Fault error. jmp DskErr1 ;AN003; HARDERR: PUBLIC HARDERR CALL MAPERROR HARDERR2: ; FOR ROUTINES THAT CALL MAPERROR THEMSELVES PUBLIC HARDERR2 MOV CS:[TIM_DRV],-1 ;FORCE A MEDIA CHECK THROUGH ROM MOV CX,CS:SECCNT ;GET COUNT OF SECTORS TO GO MOV SP,CS:[SPSAV] ;RECOVER ENTRY STACK POINTER ; ; SINCE WE ARE PERFORMING A NON-LOCAL GOTO, RESTORE THE DISK PARAMETERS ; MEDBYT_OK: CALL DIDDLEBACK RET ;AND RETURN DSKERR ENDP ; ; CHANGE SETTLE VALUE FROM SETTLECURRENT TO WHATEVER IS APPROPRIATE ; NOTE THAT THIS ROUTINE IS NEVER CALLED FOR A FIXED DISK. ; NORMSPEED PROC NEAR cmp cs:[Media_Set_For_Format], 0 ;AN012; jne FASTSPEED ;AN012; PUSH DS PUSH AX MOV AL,CS:SETTLESLOW LDS SI,CS:DPT ; CURRENT DISK PARM TABLE MOV [SI].DISK_HEAD_STTL,AL POP AX POP DS CALL FASTSPEED PUSH DS LDS SI,CS:DPT MOV [SI].DISK_HEAD_STTL,1 ; 1 IS FAST SETTLE VALUE POP DS RET NORMSPEED ENDP FASTSPEED PROC NEAR ; ; IF THE DRIVE HAS BEEN MARKED AS TOO BIG (I.E. STARTING SECTOR OF THE ; PARTITION IS > 16 BITS, THEN ALWAYS RETURN DRIVE NOT READY. ; TEST BYTE PTR [DI].FATSIZ,FTOOBIG IF iTEST JZ READY JMP NOTREADY READY: ELSE JNZ NOTREADY ENDIF MESSAGE FTESTINIT,<"<"> MNUM FTESTINIT,AX MESSAGE FTESTINIT,<","> MNUM FTESTINIT,ES MESSAGE FTESTINIT,<":"> MNUM FTESTINIT MESSAGE FTESTINIT,<","> MNUM FTESTINIT,CX MESSAGE FTESTINIT,<","> MNUM FTESTINIT,DX MESSAGE FTESTINIT,<">"> INT 13H DEATH: RET NOTREADY: STC MOV AH,80H JMP DEATH FASTSPEED ENDP ; MAP ERROR RETURNED BY ROM IN AH INTO CORRESPONDING CODE TO BE RETURNED TO ; DOS IN AL. ; MAPERROR PROC NEAR PUBLIC MAPERROR PUSH CX ; SAVE CX PUSH CS POP ES ;MAKE ES THE LOCAL SEGMENT MOV AL,AH ;PUT ERROR CODE IN AL MOV CS:[LSTERR],AL ;TERMINATE LIST WITH ERROR CODE MOV CX,NUMERR ;NUMBER OF POSSIBLE ERROR CONDITIONS MOV DI,OFFSET ERRIN ;POINT TO ERROR CONDITIONS REPNE SCASB MOV AL,CS:[DI + NUMERR - 1] ;GET TRANSLATION POP CX ; RESTORE CX STC ;FLAG ERROR CONDITION RET MAPERROR ENDP ; SET THE TIME OF LAST ACCESS FOR THIS DRIVE. THIS IS DONE ONLY FOR REMOVABLE ; MEDIA. PUBLIC SET_TIM SET_TIM PROC NEAR PUSH AX ;SB33018****************************************************************** xor AH, AH ; set command to get time ;SB;3.30* int 1Ah ; call rom-bios timer function ;SB;3.30* ;SB33018****************************************************************** OR AL,AL JZ NOROLL3 INC CS:[DAYCNT] ; CATCH ROLLOVER NOROLL3: ; WE HAVE THE NEW TIME. IF WE SEE THAT THE TIME HAS PASSED, THEN WE RESET ; THE THRESHOLD COUNTER... CMP DX,WORD PTR [DI].TIM_LO JNZ SETACCESS CMP CX,WORD PTR [DI].TIM_HI JZ DONE_SET SETACCESS: MOV BYTE PTR CS:[ACCESSCOUNT],0 MOV WORD PTR [DI].TIM_LO,DX ;SAVE IT MOV WORD PTR [DI].TIM_HI,CX DONE_SET: CLC POP AX RET SET_TIM ENDP ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING ; ; THIS IS THE TRUE INT 13 HANDLER. WE PARSE THE REQUEST TO SEE IF THERE IS ; A DMA VIOLATION. IF SO, DEPENDING ON THE FUNCTION, WE: ; READ/WRITE BREAK THE REQUEST INTO THREE PIECES AND MOVE THE MIDDLE ONE ; INTO OUR INTERNAL BUFFER. ; FORMAT COPY THE FORMAT TABLE INTO THE BUFFER ; VERIFY POINT THE TRANSFER ADDRESS INTO THE BUFFER ; ; THIS IS THE BIGGEST BOGOSITY OF ALL. THE IBM CONTROLLER DOES NOT HANDLE ; OPERATIONS THAT CROSS PHYSICAL 64K BOUNDARIES. IN THESE CASES, WE COPY ; THE OFFENDING SECTOR INTO THE BUFFER BELOW AND DO THE I/O FROM THERE. ; INT13FRAME STRUC OLDBP DW ? OLDAX DW ? OLDBX DW ? OLDCX DW ? OLDDX DW ? OLDDD DD ? OLDF DW ? INT13FRAME ENDS ;J.K. 1/30/87 To handle the ps2_30 machine INT 13h, AH = 8 Problem. ;Save Registers here. Save_AX DW ? Save_BX DW ? Save_CX DW ? Save_DX DW ? Save_DI DW ? Save_SI DW ? Save_BP DW ? Save_DS DW ? Save_ES DW ? Prev_DX DW ? Save_Flag DW ? ; ENTRY CONDITIONS: ; AH = FUNCTION ; AL = NUMBER OF SECTORS ; ES:BX = DMA ADDRESS ; CX = PACKED TRACK AND SECTOR ; DX = HEAD AND DRIVE ; OUTPUT CONDITIONS: ; NO DMA VIOLATION. ; PUBLIC BLOCK13 BLOCK13 PROC FAR ; ; LET THE OPPERATION PROCEED. IF THERE IS A DMA VIOLATION, THEN WE DO THINGS. ; MOV CS:PREVOPER,AX ; SAVE REQUEST PUSHF CMP AH,ROMFORMAT JNZ NOT_FORMAT ; SET CHANGED BY FORMAT BIT FOR ALL LOGICAL DRIVES USING THIS PHYSICAL DRIVE ;---------------------------------------------------------| ; WARNING: DO NOT CHANGE THE FOLLOWING. ; IT GETS PATCHED IN AT INIT TIME | PUBLIC CHANGED_PATCH CHANGED_PATCH: MOV WORD PTR CS:[FLAGBITS],FCHANGED_BY_FORMAT+FCHANGED CALL SET_CHANGED_DL ; INDICATE THAT MEDIA CHANGED BY FORMAT ; | ;---------------------------------------------------------| NOT_FORMAT: test dl, 80h ; floppy or hard disk? jnz not_floppy ; if hard, skip this nonsense cmp cs:EC35_Flag, 0 ; any electrically compat. drives? jz not_floppy ; no; proceed unhindered SAVEREG mov cl, dl ; turn drive number into bit map: mov al, 1 ; assume drive 0 shl al, cl ; shift over correct number of times test al, cs:EC35_Flag ; is THIS drive an electrically compatible 3.5 incher? jz not_EC35 ; no; don't change anything mov bl, dl ; which drive was it? xor bh, bh ; need only one byte of index push es ; need a segment register mov ax, 40h ; the machine state byte is in the... mov es, ax ; ...segment at 40h mov byte ptr es:[90h+bx], 93H ; establish drive type as: (360k disk in 360k drive, no double-stepping, 250 kbs transfer rate) pop es ; fix up register again not_EC35: RESTOREREG not_floppy: cmp cs:[model_byte], mdl_ps2_30 ; is this a ps2/30? jne not_ps2_30 ; if not, just do normal call cmp ah, 8 ;J.K. 1/30/87 Read Driver Parm ? je ps2_30_Problem ;J.K. 1/30/87 cmp ah, 15h je ps2_30_Problem not_ps2_30: CALL ORIG13 ; SIMULATE INT 13 JC GOTERR13_br ; ERROR? RET 2 ; NO, RETURN AND CLEAR FLAGS GOTERR13_br: jmp Goterr13 ;J.K.1/30/87 ps2_30 machine has some problem with AH=8h(Read Drive Parm), Int 13h. ;This function does not reset the common buses after the execution. ;To solve this problem, when we detect AH=8h, then we will save the result and ;will issue AH=1 (Read Status) call to reset the buses. ps2_30_Problem: ;J.K. 1/30/87; ps2_30 = PS2 Model 30. mov cs:Prev_DX, DX ;save orignal drive number call Orig13 ;Do "Read drive parm" mov cs:Save_AX, AX ;Save registers,flag mov cs:Save_BX, BX mov cs:Save_CX, CX mov cs:Save_DX, DX mov cs:Save_DI, DI mov cs:Save_SI, SI mov cs:Save_BP, BP mov cs:Save_DS, DS mov cs:Save_ES, ES pushf pop cs:Save_Flag mov dx, cs:Prev_DX ;restore orignal drive pushf mov ah, 1 ;Read Status. call Orig13 ;Reset the bus as a side effect of this call. mov AX, cs:Save_AX ;restore registers,flag mov BX, cs:Save_BX mov CX, cs:Save_CX mov DX, cs:Save_DX mov DI, cs:Save_DI mov SI, cs:Save_SI mov BP, cs:Save_BP mov DS, cs:Save_DS mov ES, cs:Save_ES push cs:Save_Flag popf jc GotErr13 ;AH=8 had been an error? ret 2 ; ; SOME KIND OF ERROR OCCURRED. SEE IF IT IS DMA VIOLATION ; GOTERR13: PUSHF cmp ah, 09h ;AN011; DMA error? je Chk_ValidMedia_ERR13 ;AN011; cmp ah, 11h ;AN011; ECC error? je Chk_ValidMedia_ERR13 ;AN011; jmp Skip_Ecc_Check ;AN011; Other error. Just return back. Chk_ValidMedia_ERR13: ;AN011;If SetDrive fails, then just push ds ;AN011; return back to INT 13h caller, push di ;AN011; without performing ECC, DMA push ax ;AN011; error handling. mov byte ptr cs:[Phys_Drv], 1 ;AN011; mov al, dl ;AN011; call SetDrive ;AN011; mov byte ptr cs:[Phys_Drv], 0 ;AN011; pop ax ;AN011; pop di ;AN011; pop ds ;AN011; jc Skip_Ecc_Check ;AN011; ; TEST OF BIT PATTERN 08H LET OTHER ERRORS BE PASSED AS DMA ERRORS - PTR 32D0519 ; TEST AH,08H ; DMA BIT CMP AH, 09H ; DMA ERROR CODE JNZ CHECK_ECC JMP GOTDMAERR CHECK_ECC: ;J.K. AN003; Soft ECC bug is only applied to PC1 and PC-XT. So, we will enforce ;this ECC error handler for them. Also, since CMC hardfiles in PC AT also ;generate a lot of unnecessary ECC errors, we will still cover PC ATs as ;it is done in the earlier version of MSBIO. ;During Format/Verify operation, we are going to consider any Soft Ecc as a ;hard error. ;SB34DISK005***************************************************************** ;SB See if the machine we are operating on is a PC, XT or AT by checking ;SB the model byte. The soft ECC bug is only on these machines and if ;SB the machine we are operating on is not one of these three then we ;SB needn't do anything special. If we are operating one these however ;SB we check to see if the error occured during format by checking ;SB media_set_for_format. If it did occur during format we cannot do ;SB anything but if not during format then check to see if the error ;SB returned in AH is the SOFT_ECC error and if so go to OK11 since ;SB the error can be ignored. 6 LOCS cmp cs:[Media_Set_For_Format], 1 ; formatting? je Skip_Ecc_Check cmp cs:[Model_Byte], 0FEh ; PC or XT? jae Go_Chk_Ecc cmp cs:[Model_Byte], 0FBh ; XT? je Go_Chk_Ecc cmp cs:[Model_Byte], 0FCh jne Skip_Ecc_Check cmp cs:[Secondary_Model_Byte], 2 ; AT? ja Skip_Ecc_Check Go_Chk_Ecc: ; for PC, XT, AT CMP AH,11H JZ OK11 Skip_Ecc_Check: ;AN003; Just return back to INT 13h caller. ;SB34DISK005***************************************************************** POPF RET 2 ; ; WE HAVE AN ERROR STATUS 11H. THIS INDICATES AN ECC-CORRECTED ERROR. NOTE ; THAT THIS INDICATES THAT THE DATA IS PROBABLY CORRECT BUT NOT CERTAINLY ; CORRECT. THE ROMS ON PC-1S AND PC_XTS HAVE A 'BUG' IN THAT IF AN ECC ERROR ; OCCURS FOR A MULTI-SECTOR READ, ONLY THE SECTORS UP TO THE ONE WHERE THE ; ERROR OCCURRED ARE READ IN. WE HAVE NO WAY OF KNOWING HOW MANY WERE READ IN ; THIS CASE, SO WE REDO THE OPERATION, READING ONE SECTOR AT A TIME. IF WE ; GET AN ECC ERROR ON READING ONE SECTOR, WE IGNORE THE ERROR BECAUSE THE ; SECTOR HAS BEEN READ IN. ; PUBLIC OK11 OK11: ; POPF ;J.K. 8/29/86 Here, it is better reset the system. So, we are going to ;call Orig13 again xor ah, ah call Orig13 ;reset. Don't care about the result MOV AX,CS:[PREVOPER] ; RETRIEVE REQUEST ; ; THIS WILL PROVIDE A TERMINATION POINT. ; CMP AL,1 ; IF REQUEST FOR ONE SECTOR, ASSUME OK JNZ ECC_ERR_HANDLE XOR AH,AH ; CLEAR CARRY TOO! RET 2 PUBLIC ECC_ERR_HANDLE ECC_ERR_HANDLE: SAVEREG MOV CS:[NUMBER_OF_SEC],AL LOOP_ECC: MOV AX,CS:[PREVOPER] MOV AL,1 ; REQUEST FOR ONE SECTOR ONLY ; ; WE DO READS ONE SECTOR AT A TIME. THIS ENSURES THAT WE WILL EVENTUALLY ; FINISH THE REQUEST SINCE ECC ERRORS ON ONE SECTOR DO READ IN THAT SECTOR. ; ; WE NEED TO PUT IN SOME "INTELLIGENCE" INTO THE ECC HANDLER TO HANDLE READS ; THAT ATTEMPT TO READ MORE SECTORS THAN ARE AVAILABLE ON A PARTICULAR ; TRACK. ; WE CALL CHECK_WRAP TO SET UP THE SECTOR #, HEAD # AND CYLINDER # FOR ; THIS REQUEST. ; AT THIS POINT, ALL REGISTERS ARE SET UP FOR THE CALL TO ORIG13, EXCEPT ; THAT THERE MAY BE A STARTING SECTOR NUMBER THAT IS BIGGER THAN THE NUMBER ; OF SECTORS ON A TRACK. ; CALL CHECK_WRAP ; GET CORRECT PARAMETERS FOR INT 13 PUSHF CALL ORIG13 JNC OK11_OP CMP AH,11H ; ONLY ALLOW ECC ERRORS JNZ OK11_EXIT_err ;J.K. 8/26/86 Other error? mov ah, 0 ;J.K. ECC error. Reset the system again. pushf call Orig13 xor ax, ax ; clear the error code so that if this ; was the last sector, no error code ; will be returned for the corrected ; read. (clear carry too.) OK11_OP: DEC CS:[NUMBER_OF_SEC] JZ OK11_EXIT ; ALL DONE? INC CL ; ADVANCE SECTOR NUMBER INC BH ; ADD 200H TO ADDRESS INC BH JMP SHORT LOOP_ECC OK11_EXIT_err: stc ;J.K. 8/28/86 Set carry bit again. OK11_EXIT: RESTOREREG RET 2 ; ; WE TRULY HAVE A DMA VIOLATION. RESTORE REGISTER AX AND RETRY THE ; OPERATION AS BEST WE CAN. ; GOTDMAERR: POP AX ; CLEAN UP STACK MOV AX,CS:PREVOPER STI CMP AH,ROMREAD ; SAVE USER FLAGS JB INTDONE CMP AH,ROMVERIFY JZ INTVERIFY CMP AH,ROMFORMAT JZ INTFORMAT JA INTDONE ; ; WE ARE DOING A READ/WRITE CALL. CHECK FOR DMA PROBLEMS ; SAVEREG PUSH BP MOV BP,SP MOV DX,ES ; CHECK FOR 64K BOUNDARY ERROR SHL DX,1 SHL DX,1 SHL DX,1 SHL DX,1 ; SEGMENT CONVERTED TO ABSOLUTE ADDRESS ADD DX,BX ; COMBINE WITH OFFSET ADD DX,511 ; SIMULATE A TRANSFER ; ; IF CARRY IS SET, THEN WE ARE WITHIN 512 BYTES OF THE END OF THE SEGMENT. ; WE SKIP THE FIRST TRANSFER AND PERFORM THE REMAINING BUFFERING AND TRANSFER ; JNC NO_SKIP_FIRST MOV DH,BYTE PTR [BP.OLDDX+1] ; SET UP HEAD NUMBER JMP BUFFER ;J.K. 4/10/86 ; JMP SHORT BUFFER ; ; DX IS THE PHYSICAL 16 BITS OF START OF TRANSFER. COMPUTE REMAINING ; SECTORS IN SEGMENT. ; NO_SKIP_FIRST: SHR DH,1 ; DH = NUMBER OF SECTORS BEFORE ADDRESS MOV AH,128 ; AH = MAX NUMBER OF SECTORS IN SEGMENT SUB AH,DH ; ; AH IS NOW THE NUMBER OF SECTORS THAT WE CAN SUCCESSFULLY WRITE IN THIS ; SEGMENT. IF THIS NUMBER IS ABOVE OR EQUAL TO THE REQUESTED NUMBER, THEN WE ; CONTINUE THE OPERATION AS NORMAL. OTHERWISE, WE BREAK IT INTO PIECES. ; CMP AH,AL ; CAN WE FIT IT IN? JB DOBLOCK ; NO, PERFORM BLOCKING. ; ; YES, THE REQUEST FITS. LET IT HAPPEN ; MOV DH,BYTE PTR [BP.OLDDX+1] ; SET UP HEAD NUMBER CALL DOINT JMP BAD13 ; ; VERIFY THE GIVEN SECTORS. PLACE THE BUFFER POINTER INTO OUR SPACE. ; INTVERIFY: SAVEREG PUSH CS POP ES DOSIMPLE: MOV BX,OFFSET DISKSECTOR PUSHF CALL ORIG13 RESTOREREG RET 2 ; ; FORMAT OPERATION. COPY THE PARAMETER TABLE INTO MEMORY ; INTFORMAT: SAVEREG SAVEREG PUSH ES PUSH CS POP ES POP DS MOV SI,BX MOV DI,OFFSET DISKSECTOR CALL MOVE RESTOREREG JMP DOSIMPLE ; ; INLINE CONTINUATION OF OPERATION ; INTDONE: JMP ORIG13 ; ; We can't fit the request into the entire block. Perform the operation on ; the first block. ; ; DoBlock is modified to correctly handle multi-sector disk I/O. -J.K. 4/10/86 ; Old DoBlock had added the number of sectors I/Oed (Ah in Old DoBlock) after ; the DoInt call to CL. Observing only the lower 6 bits of CL(=max. 64) can ; represent a starting sector, if AH was big, then CL would be clobbered. ; By the way, we still are going to use CL for this purpose since Checkwrap ; routine will use it as an input. To prevent CL from being clobbered, a ; safe number of sectors should be calculated like "63 - # of sectors/track". ; DoBlock will handle the first block of requested sectors within the ; boundary of this safe value. - J.K. 2/28/86 DoBlock: ;Try to get the # of sectors/track from BDS via Rom drive number. ;For any mini disks installed, here we have to pray that they have the ;same # of sector/track as the main DOS partition disk drive. Message ftestDisk,<"!!!DMA DoBlock!!!"> mov dx, word ptr [bp.olddx] ;set head # push di push ds push ax ;AH - # of sectors before DMA boundary ;AL - User requeseted # of sectors for I/O. mov byte ptr CS:[phys_drv],1 mov al, dl call SetDrive ;get BDS pointer for this DISK. pop ax mov byte ptr CS:[phys_drv],0 test word ptr [DI].Flags, fNon_Removable ;don't have to worry jnz DoBlockHard ;about floppies. They are track by track operation. mov al, ah ;set al = ah for floppies jmp short DoBlockCont DoBlockHard: push cx xor cx, cx mov cx, [DI].SecLim ;# of sectors/track mov ch, 63 sub ch, cl mov al, ch xchg ah, al ;now ah - safe # of sectors ;al - # of sectors before DMA boundary pop cx DoBlockCont: pop ds pop di DoBlockContinue: Message ftestDisk,<"%%DMA DoBlock Loop%%"> cmp ah, al ;if safe_# >= #_of_sectors_to_go_before DMA, jae DoBlocklast ;then #_of_sectors_to_go as it is for DoInt. push ax ;save AH, AL mov al, ah ;Otherwise, set al to ah to operate. jmp short DoBlockDoInt ;DoInt will set AH to a proper function in [BP.Oldax] DoBlocklast: mov ah, al push ax ;save AH DoBlockDoInt: ;let AH = AL = # of sectors for this shot CALL DoInt JC BAD13 ;something happened, bye! pop ax SUB BYTE PTR [BP.oldax], AH ;decrement by the successful operation ADD CL,AH ;advance sector number. Safety gauranteed. ADD BH,AH ;advance DMA address ADD BH,AH ;twice for 512 byte sectors. cmp ah, al ;check the previous value je Buffer ;if #_of_sectors_to_go < safe_#, then we are done already. sub al, ah ;otherwise, #_sector_to_go = #_of_sector_to_go - safe_# call Check_Wrap ;get new CX, DH for the next operation. jmp short DoBlockContinue ;handles next sectors left. ;End of modificaion of DoBlock - J.K. 2/28/86 ;The following is the original one. ; PUSH AX ; MOV AL,AH ; get max to operate on ; MOV AH,BYTE PTR [BP.oldax+1]; get function ; mov dh,byte ptr [BP.olddx+1] ; set up head number ; CALL DoInt ; JC Bad13 ; something happened, bye! ; POP AX ; SUB BYTE PTR [BP.oldax],AH ; decrement by the successful operation ; ADD CL,AH ; advance sector number ; ADD BH,AH ; advance DMA address ; ADD BH,AH ; twice for 512 byte sectors. ; ; THE NEXT REQUEST WILL WRAP THE 64K BOUNDARY. IF WE ARE WRITING, THEN COPY ; THE OFFENDING SECTOR INTO OUR SPACE. ; ; ES:BX POINTS TO THE SECTOR ; CX,DX CONTAIN THE CORRECT TRACK/SECTOR/HEAD/DRIVE INFO ; [BP.OLDAX] HAS CORRECT FUNCTION CODE ; BUFFER: PUSH BX MOV AH,BYTE PTR [BP.OLDAX+1] CMP AH,ROMWRITE JNZ DOREAD ; ; COPY THE OFFENDING SECTOR INTO LOCAL BUFFER ; SAVEREG PUSH CS ; EXCHANGE SEGMENT REGISTERS PUSH ES POP DS POP ES MOV DI,OFFSET DISKSECTOR ; WHERE TO MOVE PUSH DI ; SAVE IT MOV SI,BX ; SOURCE CALL MOVE POP BX ; NEW TRANSFER ADDRESS RESTOREREG MOV AL,1 ; SEE IF WE ARE WRAPPING AROUND A TRACK OR HEAD MOV DL,BYTE PTR [BP.OLDDX] ; GET DRIVE NUMBER CALL CHECK_WRAP ; SETS UP REGISTERS IF WRAP-AROUND ; ; AH IS FUNCTION ; AL IS 1 FOR SINGLE SECTOR TRANSFER ; ES:BX IS LOCAL TRANSFER ADDRES ; CX IS TRACK/SECTOR NUMBER ; DX IS HEAD/DRIVE NUMBER ; SI,DI UNCHANGED ; CALL DOINT RESTOREREG JC BAD13 ; GO CLEAN UP JMP SHORT DOTAIL ; ; READING A SECTOR. DO INT FIRST, THEN MOVE THINGS AROUND ; DOREAD: SAVEREG PUSH CS POP ES MOV BX,OFFSET DISKSECTOR MOV AL,1 ; SEE IF OUR REQUEST WILL WRAP A TRACK OR HEAD BOUNDARY MOV DL,BYTE PTR [BP.OLDDX] ; GET DRIVE NUMBER CALL CHECK_WRAP ; SETS UP REGISTERS IF WRAP-AROUND ; ; AH = FUNCTION ; AL = 1 FOR SINGLE SECTOR ; ES:BX POINTS TO LOCAL BUFFER ; CX, DX ARE TRACK/SECTOR, HEAD/DRIVE ; CALL DOINT RESTOREREG JC BAD13 ; ERROR => CLEAN UP SAVEREG PUSH CS POP DS MOV DI,BX MOV SI,OFFSET DISKSECTOR CALL MOVE RESTOREREG ; ; NOTE THE FACT THAT WE'VE DONE 1 MORE SECTOR ; DOTAIL: POP BX ; RETRIEVE NEW DMA AREA ADD BH,2 ; ADVANCE OVER SECTOR INC CX MOV AL,BYTE PTR [BP.OLDAX] CLC DEC AL JZ BAD13 ; NO MORE I/O ; SEE IF WE WRAP AROUND A TRACK OR HEAD BOUNDARY WITH STARTING SECTOR ; WE ALREADY HAVE THE CORRECT HEAD NUMBER TO PASS TO CHECK_WRAP MOV DL,BYTE PTR [BP.OLDDX] ; GET DRIVE NUMBER CALL CHECK_WRAP ; SETS UP REGISTERS IF WRAP-AROUND CALL DOINT ; ; WE ARE DONE. AX HAS THE FINAL CODE; WE THROW AWAY WHAT WE GOT BEFORE ; BAD13: MOV SP,BP RESTOREREG RET 2 BLOCK13 ENDP PAGE INCLUDE MSIOCTL.INC PAGE ; CHECK_WRAP IS A ROUTINE THAT ADJUSTS THE STARTING SECTOR, STARTING HEAD ; AND STARTING CYLINDER FOR AN INT 13 REQUEST THAT REQUESTS I/O OF A LOT ; OF SECTORS. IT ONLY DOES THIS FOR FIXED DISKS. IT IS USED IN THE SECTIONS ; OF CODE THAT HANDLE ECC ERRORS AND DMA ERRORS. IT IS NECESSARY, BECAUSE ; ORDINARILY THE ROM WOULD TAKE CARE OF WRAPS AROUND HEADS AND CYLINDERS, ; BUT WE BREAK DOWN A REQUEST WHEN WE GET AN ECC OR DMA ERROR INTO SEVERAL ; I/O OF ONE OR MORE SECTORS. IN THIS CASE, WE MAY ALREADY BE BEYOND THE ; NUMBER OF SECTORS ON A TRACK ON THE MEDIUM, AND THE REQUEST WOULD FAIL. ; ; INPUT CONDITIONS: ; ALL REGISTERS SET UP FOR AN INT 13 REQUEST. ; ; OUTPUT: ; DH - CONTAINS STARTING HEAD NUMBER FOR REQUEST ; CX - CONTAINS STARTING SECTOR AND CYLINDER NUMBERS ; (THE ABOVE MAY OR MAY NOT HAVE BEEN CHANGED, AND ARE 0-BASED) ; ALL OTHER REGISTERS PRESERVED. ; PUBLIC CHECK_WRAP CHECK_WRAP: Message ftestDisk,<"Entering Check_Wrap...",cr,lf> SAVEREG MOV BYTE PTR CS:[PHYS_DRV],1; USE PHYSICAL DRIVE IN AL TO GET BDS MOV AL,DL ; AL HAS PHYSICAL DRIVE NUMBER CALL SETDRIVE ; GET POINTER TO BDS FOR DRIVE MOV BYTE PTR CS:[PHYS_DRV],0; RESTORE FLAG TO USE LOGICAL DRIVE JC NO_WRAP ; DO NOTHING IF WRONG PHYSICAL DRIVE TEST WORD PTR [DI].FLAGS,FNON_REMOVABLE JZ NO_WRAP ; NO WRAPPING FOR REMOVABLE MEDIA MOV BX,[DI].SECLIM MOV AX,CX AND AX,003FH ; EXTRACT SECTOR NUMBER CMP AX,BX ; ARE WE GOING TO WRAP? JBE NO_WRAP DIV BL ; AH=NEW SECTOR #, AL=# OF HEAD WRAPS ; WE NEED TO BE CAREFUL HERE. IF THE NEW SECTOR # IS 0, THEN WE ARE ON THE ; LAST SECTOR ON THAT TRACK. OR AH,AH JNZ NOT_ON_BOUND MOV AH,BL ; SET SECTOR=SECLIM IF ON BOUNDARY DEC AL ; ALSO DECREMENT # OF HEAD WRAPS NOT_ON_BOUND: AND CL,0C0H ; ZERO OUT SECTOR # OR CL,AH ; OR IN NEW SECTOR # XOR AH,AH ; AX = # OF HEAD WRAPS INC AX ADD AL,DH ; ADD IN STARTING HEAD # ADC AH,0 ; CATCH ANY CARRY CMP AX,[DI].HDLIM ; ARE WE GOING TO WRAP AROUND A HEAD? JBE NO_WRAP_HEAD ; DO NOT LOSE NEW HEAD NUMBER!! PUSH DX ; PRESERVE DRIVE NUMBER AND HEAD NUMBER XOR DX,DX MOV BX,[DI].HDLIM DIV BX ; DX=NEW HEAD #, AX=# OF CYLINDER WRAPS ; CAREFUL HERE! IF NEW HEAD # IS 0, THEN WE ARE ON THE LAST HEAD. OR DX,DX JNZ NO_HEAD_BOUND MOV DX,BX ; ON BOUNDARY. SET TO HDLIM ; IF WE HAD SOME CYLINDER WRAPS, WE NEED TO REDUCE THEM BY ONE!! OR AX,AX JZ NO_HEAD_BOUND DEC AX ; REDUCE NUMBER OF CYLINDER WRAPS NO_HEAD_BOUND: MOV BH,DL ; BH HAS NEW HEAD NUMBER POP DX ; RESTORE DRIVE NUMBER AND HEAD NUMBER DEC BH ; GET IT 0-BASED MOV DH,BH ; SET UP NEW HEAD NUMBER IN DH MOV BH,CL AND BH,3FH ; PRESERVE SECTOR NUMBER MOV BL,6 XCHG CL,BL SHR BL,CL ; GET MS CYLINDER BITS TO LS END ADD CH,AL ; ADD IN CYLINDER WRAP ADC BL,AH ; ADD IN HIGH BYTE SHL BL,CL ; MOVE UP TO MS END XCHG BL,CL ; RESTORE CYLINDER BITS INTO CL OR CL,BH ; OR IN SECTOR NUMBER NO_WRAP: CLC ; RESET CARRY RESTOREREG RET NO_WRAP_HEAD: MOV DH,AL ; DO NOT LOSE NEW HEAD NUMBER DEC DH ; GET IT 0-BASED JMP SHORT NO_WRAP ; ; INT_2F_13: ; THIS CODE IS CHAINED INTO THE INT_2F INTERRUPT DURING BIOS ; INITIALIZATION. IT ALLOWS THE USER TO CHANGE THE ORIG13 INT_13 VECTOR ; AFTER BOOTING. THIS ALLOWS TESTING AND IMPLEMENTATION OF CUSTOM INT_13 ; HANDLERS, WITHOUT GIVING UP MS-DOS ERROR RECOVERY ; ; ENTRY CONDITIONS ; AH == RESET_INT_13 (13H) ; DS:DX == ADDRESS OF NEW INT_13 HANDLER ; ES:BX == ADDRESS OF NEW INT_13 VECTOR USED BY WARM BOOT ; (INT 19) ; ; EXIT CONDITIONS ; ORIG13 == ADDRESS OF NEW INT_13 HANDLER ; DS:DX == OLD ORIG13 VALUE ; ES:BX == OLD OLD13 VALUE ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING PUBLIC INT_2F_13 INT_2F_13 PROC FAR CMP AH,13H ; IF (INTERRUPT_VALUE != RESET_INT_13) JE CHG_ORIG13 JMP CS:[NEXT2F_13] ; THEN CONTINUE ON INT_2F CHAIN CHG_ORIG13: ; ELSE PUSH WORD PTR CS:[ORIG13] ; SAVE OLD VALUE OF OLD13 AND PUSH WORD PTR CS:[ORIG13 + 2]; ORIG13 SO THAT WE CAN PUSH WORD PTR CS:[OLD13] ; RETURN THEM TO CALLER PUSH WORD PTR CS:[OLD13 + 2] MOV WORD PTR CS:[ORIG13],DX ; ORIG13 := ADDR. OF NEW INT_13 ; VECTOR MOV WORD PTR CS:[ORIG13+2],DS MOV WORD PTR CS:[OLD13],BX ; OLD13 := ADDR. OF NEW ; BOOT_13 VECTOR MOV WORD PTR CS:[OLD13+2],ES POP ES ; ES:BX := OLD OLD13 VECTOR POP BX POP DS ; DS:DX := OLD ORIG13 VECTOR POP DX IRET ; END ELSE INT_2F_13 ENDP MOVE PROC NEAR CLD PUSH CX MOV CX,512/2 ;J.K. Warning!!! Do not change the position of this label. ; The following three bytes will be NOPed out by MSINIT if the system ; does not support the DOUBLE WORD MOV instruction, i.e., (if ; not 386 base machine.) ;---------------------------------------------------------------------------- public DoubleWordMov DoubleWordMov: ;AN002; shr cx, 1 ;AN002;Make it a double word. db 66h ;AN002;Machine code for double word mov ;---------------------------------------------------------------------------- REP MOVSW POP CX RET MOVE ENDP DOINT PROC NEAR MOV DL,BYTE PTR [BP.OLDDX] ; GET PHYSICAL DRIVE NUMBER XOR AH,AH OR AL,AL JZ DOINTDONE MOV AH,BYTE PTR [BP.OLDAX+1] ; GET REQUEST CODE PUSH [BP.OLDF] CALL ORIG13 PUSHF POP [BP.OLDF] DOINTDONE: RET DOINT ENDP CODE ENDS END