From 2d04cacc5322951f187bb17e017c12920ac8ebe2 Mon Sep 17 00:00:00 2001 From: Mark Zbikowski Date: Thu, 25 Apr 2024 21:24:10 +0100 Subject: MZ is back! --- v4.0/src/BIOS/MSDISK.ASM | 2443 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2443 insertions(+) create mode 100644 v4.0/src/BIOS/MSDISK.ASM (limited to 'v4.0/src/BIOS/MSDISK.ASM') diff --git a/v4.0/src/BIOS/MSDISK.ASM b/v4.0/src/BIOS/MSDISK.ASM new file mode 100644 index 0000000..f132e7f --- /dev/null +++ b/v4.0/src/BIOS/MSDISK.ASM @@ -0,0 +1,2443 @@ + 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 -- cgit v1.2.3