;	PAGE ,132 ;
;	TITLE MSDISK - BIOS
	%warning 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 equ 0
	EXTRN NUMERR:ABS		;MSDATA

	%include "ddataseg.nas"
	%include "msequ.mac"
	%include "pushpop.mac"
	%include "devsym.mac"
	%include "msdskpr.mac"
	%include "biostruc.mac"
	%include "entryseg.nas"
	%include "entrysw.mac"
	%include "msgroup.mac"	;DEFINE CODE SEGMENT
	%include "msmacro.mac"
	%include "lmacros2.mac"

	extern biocode_get_ds_dosentry, biocode_get_es_dosentry
	extern biocode_get_ds_dosbiodata
	extern biocode_get_es_dosbiodata

	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	equ	5
LSTDRV	equ	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	equ	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
;


section BIOCODE

	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;


section DOSENTRY

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.

	extern Set_ID_Flag, Saved_Word
	extern VRetry_Cnt, Soft_ECC_Cnt, MultiTrk_Format_Flag

	extern lbapacket
	extern	Temp_H
	extern	Start_Sec_H
	extern	MulTrk_Flag
	extern EC35_Flag


section BIOCODE

       PUBLIC MEDIA$CHK
MEDIA$CHK PROC	NEAR
 assume ds:nothing, es:nothing, ss:nothing
	MESSAGE FTESTDISK,<"DISK MEDIA CHECK ">
	MNUM	FTESTDISK,AX
	MESSAGE FTESTDISK,<CR,LF>
	CALL	SETDRIVE
 assume ds:UPB
	jc DSK$UNKNOWN

	push ds
	call biocode_get_ds_dosentry	; Secrete_Code in DOSENTRY
 assume ds:DOSENTRYGROUP
	cmp word [Secrete_Code], 'kj'	;J.K.11/7/86 Secrete code for DOS 3.3 IBMBIO.	; NASM port swapped text literals
	pop ds
 assume ds:UPB
media$done equ MEDIA$DONE	; NASM port label
	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],~ 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.
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	byte [TIM_DRV],-1 	; ENSURE THAT WE ASK THE ROM IF MEDIA
					; HAS CHANGED
	pop ds
 assume ds:UPB
	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:
 assume ds:UPB, es:nothing, ss:nothing
	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	;|
	call ispatched
	jc @F
	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
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	AL,[TIM_DRV]		; LAST DRIVE ACCESSED
	pop ds
 assume ds:UPB
	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:
	call biocode_get_es_dosentry	; PTRSAV in DOSENTRY
 assume es:DOSENTRYGROUP
	LES	BX,[es:PTRSAV]		; GET ORIGINAL PACKET
 assume es:nothing
	MOV	WORD PTR [ES:BX + TRANS],SI
	test	SI,SI
	JS	INIT_PATCH_before
	JMP	EXIT
MEDIA$CHK ENDP
;----------------------------------------|
; WARNING: DO NOT CHANGE THE FOLLOWING. ;|
;	   IT GETS PATCHED IN MSINIT	;|
INIT_PATCH_before:
	call ispatched
	jc @F
	PUBLIC INIT_PATCH		;|
INIT_PATCH PROC NEAR			;|
	CALL	MEDIA_SET_VID		;|
@@:
;----------------------------------------|
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	byte [TIM_DRV], -1	; MAKE SURE WE ASK ROM FOR MEDIA CHECK
VOLIDOK:
	JMP	EXIT
INIT_PATCH ENDP

ERR$EXITJ PROC NEAR
 assume ds:nothing, es:nothing, ss:nothing

	MESSAGE FTESTCOM,<"ERR$EXITJ: ">
	MNUM	FTESTCOM,AX
	MESSAGE FTESTCOM,<" == ">
	CALL	MAPERROR
	MNUM	FTESTCOM,AX
	MESSAGE FTESTCOM,<CR,LF>
	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
 assume ds:UPB

	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.
;
	push es
	call biocode_get_es_dosbiodata
 assume es:DOSGROUP
	SHR	AL,1
	ADC	word [es:DAYCNT],0		; ADD IT IN TO OUR REMEMBERED DAY COUNT
;
; COMPUTE ELAPSED TIME
;
	MOV	AX,WORD PTR [DI + TIM_LO]   ; GET STORED TIME
	SUB	DX,AX
	MOV	AX,WORD PTR [DI + TIM_HI]
	SBB	CX,AX
;
; CX:DX IS THE ELAPSED TIME
;
	JNZ	TIMECHECK_UNK		; CX <> 0 => > 1 HOUR
	test	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 [es:ACCESSCOUNT]
	CMP	BYTE [es:ACCESSCOUNT],ACCESSMAX
	JB	TIMECHECK_RET		; IF COUNT IS LESS THAN THRESHOLD, OK
	DEC	BYTE [es: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:
	pop es
 assume es:nothing
	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
 assume ds:DOSGROUP, es:nothing, ss:nothing
	MESSAGE FTESTDISK,<"DISK BUILD BPB ">
	MNUM	FTESTDISK,AX
	MESSAGE FTESTDISK,<CR,LF>
	MOV	AH,BYTE PTR [ES:DI]	;GET FAT ID BYTE READ BY DOS
	CALL	SETDRIVE		; GET THE CORRECT BDS FOR THE DRIVE
 assume ds:UPB
	jc DSK$UNKNOWN
	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;
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov	byte [Set_ID_Flag],1	;AN000; Indicate to set system id in BDS
	pop ds
 assume ds:UPB
	CALL	GETBP			;BUILD A BPB IF NECESSARY.
	JC	ERR$EXITJ2		;AN000; If error, Set_ID_flag is set to 0 already.
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	cmp	byte [Set_ID_Flag],2	;AN000; Already, volume_Label set from Boot record
	mov	byte [Set_ID_Flag],0	;AN000;  to BDS table?
	pop ds
 assume ds:UPB
Already_GotBPB equ ALREADY_GOTBPB	; NASM port label
	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	;|
	call ispatched
	jc @F
	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,<CR,LF>

ALREADY_GOTBPB:
	ADD	DI,BYTEPERSEC		; RETURN THE BPB THAT IS IN THE CURRENT BDS

	PUBLIC	SETPTRSAV
SETPTRSAV:				; RETURN POINT FOR DSK$INIT
 assume ds:nothing, es:nothing, ss:nothing
	call biocode_get_es_dosentry	; PTRSAV in DOSENTRY
 assume es:DOSENTRYGROUP
	LES	BX,[es:PTRSAV]
 assume es:nothing
	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;
 assume ds:UPB, es:nothing, ss:nothing
	push	ds			;AN000;
	push	di			;AN000;
	push	es			;AN000;
	push	si			;AN000;
	push	cx			;AN000;

	xor cx, cx			;AN000; no serial number
	mov	word ptr [di + VOL_SERIAL],cx	 ;AN000;
	mov	word ptr [di + VOL_SERIAL + 2],cx ;AN000;

	push	ds			;AN000;
	pop	es			;AN000; es -> bds
 assume es:UPB
	push	cs			;AN000; get => DOSCODE
	pop	ds			;AN000; ds = cs => BIOCODE / DOSCODE
 assume ds:DOSCODEGROUP

	mov	cl, BOOT_VOLUME_LABEL_SIZE	 ;AN000; =11
VOL_NO_NAME equ Vol_No_Name	; NASM port label
	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	byte [es:di + FATSIZ], FBIG		 ;AN000;
	jnz	CI_BigFat			 ;AN000; small fat
FAT_12_ID equ Fat_12_ID	; NASM port label
	mov	si, offset FAT_12_ID		 ;AN000;
	jmp	CI_Filesys			 ;AN000;

CI_BigFat:					 ;AN000;
FAT_16_ID equ Fat_16_ID	; NASM port label
	mov	si, offset FAT_16_ID		 ;AN000; big fat
CI_Filesys:					 ;AN000;
	mov	cl, BOOT_SYSTEM_ID_SIZE		 ;AN000; =8
FILESYS_ID equ FILESYS_Id	; NASM port equate
	add	di, FILESYS_ID			 ;AN000; points to FILESYS_ID field
	rep	movsb				 ;AN000;

	pop	cx				 ;AN000;
	pop	si				 ;AN000;
	pop	es				 ;AN000;
 assume es:nothing
	pop	di				 ;AN000;
	pop	ds				 ;AN000;
 assume ds:UPB
	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
 assume ds:UPB, es:nothing, ss:nothing
; IF RETURNING FAKE BPB THEN RETURN BPB AS IS.
	TEST	WORD PTR [DI + FLAGS],RETURN_FAKE_BPB | FNON_REMOVABLE
	JZ	GETBP1
	JMP	GETRET_EXIT

GETBP1:
	MESSAGE FTESTDISK,<"BUILDING BPB FROM SCRATCH",CR,LF>
	SAVEREG <CX,DX,ES,BX>
;
; 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
 assume es:DOSENTRYGROUP
GETBP_ERR_RET_brdg equ Getbp_err_ret_brdg	; NASM port label
	JC	GETBP_ERR_RET_brdg	; CARRY SET IF THERE WAS ERROR.
	CMP	BX,0			; BX IS 0 IF BOOT SECTOR IS VALID.
	JNZ	DOFATBPB

; 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.

;	CALL	MOVBPB			; MOVE BPB INTO REGISTERS.
;MOVBPB	PROC	NEAR
	mov ax, word [es:BPB_IN_SECTOR + DIRNUM]
	mov word [di + CDIR], ax
	mov ax, word [es:BPB_IN_SECTOR + FATSIZE]
	mov word [di + CSECFAT], ax
	mov ax, word [es:BPB_IN_SECTOR + RESNUM]
	mov word [di + RESSEC], ax
	mov al, byte [es:BPB_IN_SECTOR + FATNUM]
	mov byte [di + CFAT], al

	SAVEREG <DS,DI>
	PUSH	es
	POP	DS
 assume ds:DOSENTRYGROUP
	MOV	DI,OFFSET BPB_IN_SECTOR		; access with ds
	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 <DI,DS>
 assume ds:UPB
	call biocode_get_es_dosbiodata
 assume es:DOSGROUP
	cmp	byte [es: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	byte [es:Set_ID_Flag],2	     ;AC008 signals that Volume ID is set.
MovBPB_Conv:				     ;AC008
fHave96 equ FHAVE96	; NASM port label
	cmp	byte [es:fHave96], 1		     ;AC008
	jne	MovBPB_Ret		     ;AC008
	call	ResetChanged		     ;AC008 Reset Flags in BDS to NOT fCHANGED.
MovBPB_Ret:				     ;AC008
	clc				     ;AC008
;MOVBPB	ENDP				     ;AC008
	JMP	HAS1
	nop	; identicalise

Getbp_err_ret equ GETBP_ERR_RET	; NASM port label
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:
 assume ds:UPB
	CALL	READFAT			; PUTS MEDIA DESCRIPTOR BYTE IN AH
 assume es:DOSENTRYGROUP
GETBP_ERR_RET_Brdg equ Getbp_err_ret_brdg	; NASM port label
	JC	GETBP_ERR_RET_Brdg
;----------------------------------------|
; WARNING: DO NOT CHANGE THE FOLLOWING. ;|
;	   IT GETS PATCHED IN MSINIT	;|
	call ispatched
	jc @F
	PUBLIC GETBP1_PATCH		;|
GETBP1_PATCH:				;|
	CALL	HIDENSITY		;|
@@:
;----------------------------------------|
;TEST FOR A VALID 3.5" MEDIUM
	CMP	byte [DI + FORMFACTOR],FFSMALL
	JNZ	IS_FLOPPY
	CMP	AH,0F9H			; IS IT A VALID FAT ID BYTE FOR 3.5" ?
	jnz short	GOT_UNKNOWN_MEDIUM
	MOV	BX,OFFSET SM92		; POINTER TO CORRECT BPB
	call biocode_get_es_dosbiodata
 assume es:DOSGROUP

;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:
 assume es:DOSENTRYGROUP
	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
 assume es:nothing

	MOV	BYTE PTR [DI + SECPERCLUS],DH
	MOV	BYTE PTR [DI + CDIR],BH
	MOV	WORD PTR [DI + DRVLIM],CX
	MOV	BYTE PTR [DI + MEDIAD],AH
	MOV	BYTE PTR [DI + CSECFAT],AL
	MOV	BYTE PTR [DI + SECLIM],BL
	mov dh, 0
	MOV	word PTR [DI + HDLIM], dx
;SB34DISK001*******************************************************************
;SB	the HIDSEC_H field and HIDSEC_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 [di + HIDSEC_H],0
	mov	word ptr [di + HIDSEC_L],0
	mov	word ptr [di + DRVLIM_H],0

;SB34DISK001*******************************************************************
GETRET:
	POP	BX
	RESTOREREG <ES,DX,CX>
 ASSUME ES:NOTHING

GETRET_EXIT:
	RET

GETBP_ERR_RET:
;J.K. Before doing anything else, set Set_ID_Flag to 0.
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov	byte [Set_ID_Flag], 0	;AN000;
	pop ds
 assume ds:nothing
	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:
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov	byte [Set_ID_Flag], 0	;AN000;
	pop ds
 assume ds:nothing
	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
 assume es:DOSENTRYGROUP
	 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 [es:DISKSECTOR],069H	; IS IT A DIRECT JUMP?
	 JE	Check_bpb_MediaByte		; DON'T NEED TO FIND A NOP
	 CMP	BYTE PTR [es:DISKSECTOR],0E9H	; DOS 2.0 JUMP?
	 JE	Check_bpb_MediaByte		; NO NEED FOR NOP
	 CMP	BYTE PTR [es:DISKSECTOR],0EBH	; HOW ABOUT A SHORT JUMP.
	 JNE	INVALIDBOOTSEC
	 CMP	BYTE PTR [es: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 [es: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 [es: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 [es:MEDIABYTE]
	TEST	AL,0001H	; IS LOW BIT SET? - INDICATES DOUBLE SIDED
	JNZ	GOODDSK
	cmp	BYTE PTR [es:SECPERCLUSINSECTOR], 2
	jne	GOODDSK
	CMP	WORD PTR [es:DISKSECTOR+8],("." << 8) + "2"
	je	MUSTBEEARLIER
	CMP	WORD PTR [es:DISKSECTOR+8],("." << 8) + "3"
	jne	GOODDSK
	CMP	BYTE PTR [es:DISKSECTOR+10],"0"
	jb	GOODDSK
	CMP	BYTE PTR [es:DISKSECTOR+10],"2"
	JAE	GOODDSK

; WE MUST HAVE A PRE-3.20 DISKETTE. SET THE SEC/CLUS FIELD TO 1
MUSTBEEARLIER:
	MOV	BYTE PTR [es: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

;
	public	Mov_Media_IDs
Mov_Media_IDs	Proc	near		    ;AN000;
 assume ds:UPB, es:nothing, ss:nothing
;copy the boot_serial number, Volume id, and Filesystem id from the
;***Extended Boot record*** in DOSENTRY:DiskSector to the BDS table pointed
;by DS:DI.
;In.) DS:DI -> BDS
;     DOSENTRY: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.

	push	es			    ;AN000;
	call biocode_get_es_dosentry	; DISKSECTOR in DOSENTRY
 assume es:DOSENTRYGROUP
	cmp	byte [es:Ext_Boot_Sig], EXT_BOOT_SIGNATURE ;AN000; = 41
	jne	MMI_Not_Ext		    ;AN000;
	push	cx			    ;AN000;
	mov	cx, [es:Boot_Serial_L]	    ;AN000;
	mov	word ptr [di + VOL_SERIAL],cx	 ;AN000;
	mov	cx, [es:Boot_Serial_H]		 ;AN000;
	mov	word ptr [di + VOL_SERIAL+2],cx ;AN000;
	push	ds			    ;AN000; Save regs.
	push	di			    ;AN000;
	push	si			    ;AN000;

	push es
	push ds				; swap es, ds
	pop es				; es => UPB
	pop ds				; ds => DOSENTRY
 assume ds:DOSENTRYGROUP, es:UPB

	mov	cx, BOOT_VOLUME_LABEL_SIZE  ;AN000;
	mov	si, offset Boot_Volume_Label;AN000; access with ds
	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; accexd with ds
	add	di, FILESYS_ID		    ;AN000;
	rep	movsb			    ;AN000;

	pop	si			    ;AN000;
	pop	di			    ;AN000;
	pop	ds			    ;AN000;
 assume ds:UPB
	pop	cx			    ;AN000;
	clc				    ;AN000;
MMI_Ret:				    ;AN000;
	pop	es			    ;AN000;
 assume es:nothing
	ret				    ;AN000;
MMI_Not_Ext:				    ;AN000;
	pop	es			    ;AN000;
 assume es:nothing
	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
 assume ds:nothing, es:nothing, ss:nothing
	PUSH	AX			    ; PRESERVE LOGICAL DRIVE IN AL
	MOV	DH,0			    ; HEAD 0
	MOV	CX,0002 		    ; CYLINDER 0, SECTOR 2
	CALL	READ_SECTOR		    ; es:BX POINTS TO FAT SECTOR
 assume es:DOSENTRYGROUP
	JC	BAD_FAT_RET
	POP	AX			    ; RESET LOGICAL DRIVE
	MOV	AH,BYTE PTR [es: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
;		    es:BX POINT TO SECTOR
;		CARRY SET
;		    AX HAS ROM ERROR CODE
; REGISTERS ES AND BP ARE PRESERVED.
; OUT:		es => DOSENTRY

READ_SECTOR PROC NEAR
	PUBLIC READ_SECTOR
 assume ds:UPB, es:nothing

	PUSH	BP
	MOV	BP,3		; MAKE 3 ATTEMPTS
;SB33015*****************************************************************
DriveNum equ DRIVENUM	; NASM port equate
	mov	DL, byte ptr [di + DriveNum]			       ;SB;3.30*
DiskSector equ DISKSECTOR	; NASM port label
	mov	BX, offset DiskSector	; Get ES:BX to point to buffer ;SB;3.30*
	call biocode_get_es_dosentry	; DISKSECTOR in DOSENTRY
					; now ES:BX is correct	       ;SB;3.30*
 assume es:DOSENTRYGROUP
;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
Err_RD_RET equ ERR_RD_RET	; NASM port label
	jz	Err_RD_RET
flags equ FLAGS	; NASM port equate
fNon_Removable equ FNON_REMOVABLE	; NASM port equate
	test	word ptr [di + flags],fNon_Removable
	JNZ	RD_RET
	push es
	call biocode_get_es_dosbiodata
 assume es:DOSGROUP
Media_Set_For_Format equ MEDIA_SET_FOR_FORMAT	; NASM port label
	cmp	byte [es: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,[es:DPT]
 assume ds:nothing
disk_head_sttl equ DISK_HEAD_STTL	; NASM port equate
	mov	al, [si + disk_head_sttl]
save_head_sttl equ Save_head_sttl	; NASM port label
	mov	[es:save_head_sttl],al
NormSettle equ NORMSETTLE	; NASM port equate
	mov	byte ptr [si + disk_head_sttl], NormSettle
	pop	ax
	pop	ds
 assume ds:UPB
Rd_Skip1_DPT:			;AN012;
	pop es
 assume es:DOSENTRYGROUP
;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*****************************************************************
	push es
	call biocode_get_es_dosbiodata
 assume es:DOSGROUP
	pushf			;AN012;
	cmp	byte [es:Media_Set_For_Format], 0	;AN012;
	jne	Rd_Skip2_DPT	       ;AN012;
	push	ds
	push	ax
	lds	si,[es:DPT]
 assume ds:nothing
	mov	al, [es:save_head_sttl]
	mov	byte ptr [si + disk_head_sttl], al
	pop	ax
	pop	ds
 assume ds:UPB
Rd_Skip2_DPT:			;AN012;
	popf			;AN012;
	pop es
 assume es:DOSENTRYGROUP
	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:
	push es
	call biocode_get_es_dosbiodata
 assume es:DOSGROUP
	MOV	[es:STEP_DRV],DL	; SET UP FOR HEAD SETTLE LOGIC IN DISK.
	MOV	[es: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
 assume es:DOSENTRYGROUP
	POP	BP
	RET
READ_SECTOR ENDP

;-----------------------------------------------------------
;
;		DISK REMOVABLE ROUTINE ARR 2.41
;

DSK$REM PROC	NEAR			;ARR 2.41
	PUBLIC	DSK$REM
 assume ds:DOSGROUP, es:nothing, ss:nothing

	MESSAGE FTESTDISK,<"DISK REMOVABLE ">
	MNUM	FTESTDISK,AX
	MESSAGE FTESTDISK,<CR,LF>
; AL IS UNIT #
	CALL	SETDRIVE		; GET BDS FOR THIS DRIVE
 assume ds:UPB
	jc DSK$UNKNOWN
	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
 assume ds:nothing, es:nothing, ss:nothing
	MESSAGE FTESTDISK,<"SETDRIVE",CR,LF>
	PUSH	BX
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	lds	di, [START_BDS]
 assume ds:UPB
SCAN_LOOP:
	CMP	DI,-1
	je SCAN_NONE
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	CMP	BYTE PTR [PHYS_DRV], 1		; DOES AL HAVE PHYSICAL DRIVE?
	pop ds
 assume ds:UPB
	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:
	lds di, [DI + LINK]			; GO TO NEXT BDS
	jmp SCAN_LOOP

SCAN_NONE:
	STC
SETDRV:
	POP	BX
	RET
SETDRIVE ENDP

;-----------------------------------------------------------
;
;		DISK I/O ROUTINES
;

DSK$WRITV PROC	NEAR
	PUBLIC	DSK$WRITV
 assume ds:nothing, es:nothing, ss:nothing

	MESSAGE FTESTDISK,<"DISK WRITE WITH VERIFY ">
	MNUM	FTESTDISK,AX
	MESSAGE FTESTDISK,<" ">
	MNUM	FTESTDISK,DX
	MESSAGE FTESTDISK,<" FOR ">
	MNUM	FTESTDISK,CX
	MESSAGE FTESTDISK,<CR,LF>
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	word [WRTVERIFY],103H
		; needn't preserve ds, DISKIO overwrites its INP:ds
	JMP	SHORT DSK$CL

DSK$WRIT:
	PUBLIC	DSK$WRIT
 assume ds:nothing, es:nothing, ss:nothing
	MESSAGE FTESTDISK,<"DISK WRITE ">
	MNUM	FTESTDISK,AX
	MESSAGE FTESTDISK,<" ">
	MNUM	FTESTDISK,DX
	MESSAGE FTESTDISK,<" FOR ">
	MNUM	FTESTDISK,CX
	MESSAGE FTESTDISK,<CR,LF>
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	word [WRTVERIFY],ROMWRITE
		; needn't preserve ds, DISKIO overwrites its INP:ds
DSK$CL:
	CALL	DISKIO
DSK$IO:
	JC	DSKBAD
	JMP	EXIT
DSKBAD:
	JMP	ERR$CNT
DSK$WRITV ENDP

DSK$READ PROC	NEAR
	PUBLIC	DSK$READ
 assume ds:nothing, es:nothing, ss:nothing
	MESSAGE FTESTDISK,<"DISK READ ">
	MNUM	FTESTDISK,AX
	MESSAGE FTESTDISK,<" ">
	MNUM	FTESTDISK,DX
	MESSAGE FTESTDISK,<" FOR ">
	MNUM	FTESTDISK,CX
	MESSAGE FTESTDISK,<CR,LF>
	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
 assume ds:UPB, es:nothing, ss:nothing

	PUSH	AX
	MOV	ax,WORD PTR [DI + FLAGS]
 ; IF HARD DRIVE, CANNOT CHANGE DISK.
 ; IF CURRENT OWNER OF PHYSICAL DRIVE, NO NEED TO CHANGE DISKETTE.
	TEST	al,FNON_REMOVABLE | FI_OWN_PHYSICAL
	JNZ	SINGLERET
	TEST	al,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,[DI + DRIVENUM]	; GET PHYSICAL DRIVE NUMBER
	PUSH	DS			; PRESERVE POINTER TO CURRENT BDS
	PUSH	DI
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	DI,OFFSET START_BDS
SCAN_LIST:
	lds di, [di + LINK]		; GO TO NEXT BDS
 assume ds:UPB
	CMP	DI,-1			; END OF LIST?
	je	SINGLE_ERR_RET		; MUST BE ERROR
	CMP	BYTE PTR [DI + DRIVENUM],AL
	jne	SCAN_LIST

CHECK_OWN:
	test byte [DI + FLAGS], FI_OWN_PHYSICAL
	JZ	SCAN_LIST

		; MS-DOS v5 flips these flags before the 2F.4A00 callout
	and byte [DI + FLAGS], ~ FI_OWN_PHYSICAL; RESET OWNERSHIP FLAG
	MOV	ah, [DI + DRIVELET]		; ah = wanted DOS drive letter
	POP	DI			    ; RESTORE POINTER TO CURRENT BDS
	POP	DS
 assume ds:UPB
	or byte [DI + FLAGS], FI_OWN_PHYSICAL		    ; ESTABLISH CURRENT BDS AS OWNER

;
; 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.
;
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	CMP	BYTE PTR [FSETOWNER],1
	pop ds
 assume ds:UPB
	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
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	CMP	byte [SINGLE],2		    ; IF (SINGLE_DRIVE_SYSTEM)
	pop ds
 assume ds:UPB
	JNE	SHORT IGNORE_SDSB
	SAVEREG <DS,DI,AX>		    ;	THEN
	MOV	AL,[DI + DRIVELET]	    ;	  IF (CURR_DRV == REQ_DRV)
	MOV	AH,AL
	XOR	DI,DI
	MOV	DS,DI			; => 0
 assume ds:IVT
	XCHG	AL,BYTE PTR [LSTDRV]	    ;	     THEN SWAP(CURR_DRV,REQ_DRV)
	CMP	AH,AL			    ;	     ELSE
	RESTOREREG <AX,DI,DS>		    ;		  SWAP(CURR_DRV,REQ_DRV)
 assume ds:UPB
	JE	SINGLERET		    ;		  ISSUE SWAP_DSK_MSG

IGNORE_SDSB:
	CALL	SWPDSK			    ;  ASK USER FOR CORRECT DISK
SINGLERET:
	POP	AX
	RET

SINGLE_ERR_RET:
	STC
	POP	DI			    ; RESTORE CURRENT BDS
	POP	DS
 assume ds:UPB
	JMP	SHORT SINGLERET

DISKIO_unknown:
	mov al, 1			; unknown unit
	db __TEST_IMM16			; skip mov al
BADDRIVE:
	MOV	AL,8			;Sector not found
	db __TEST_IMM16			; skip mov al
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.
;	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
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	byte [RFLAG],ROMREAD
		; SETDRIVE overwrites ds, so no need to restore

DISKIO:
	MOV	BX,DI			; ES:BX = TRANSFER ADDRESS
	CALL	SETDRIVE		; MAP LOGICAL AND PHYSICAL
 assume ds:UPB
	jc DISKIO_unknown
	MOV	AL,BYTE PTR [DI + MEDIAD]
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	[MEDBYT],AL		; PRESERVE MEDIA BYTE FOR DRIVE FOR USE
					; IN DETERMINING MEDIA CHANGE.
	pop ds
 assume ds:UPB
	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 [di + FLAGS], UNFORMATTED_MEDIA
	jnz	UnformattedDrive
;SB34DISK006******************************************************************
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov	[SECCNT],CX		;save sector count
	MOV	[SPSAV],SP		; SAVE SP
	add word [SPSAV], 2		; discard ds off the stack
	pop ds
 assume ds:UPB

; 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;
DrvLim equ DRVLIM	; NASM port equate
	cmp	word [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;
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	add	si, [Start_Sec_H]	;AN000;
	pop ds
 assume ds:UPB
DrvLim_H equ DRVLIM_H	; NASM port equate
	cmp	si, [di + DrvLim_H]	;AN000;
	jb	SanityOK		;AN000;
	ja	BADDRIVE		;AN000;
DrvLim_L equ DRVLIM_L	; NASM port equate
	cmp	dx, [di + DrvLim_L]	;AN000;
	ja	BADDRIVE		;AN000;
SanityOK:				;AN000;
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov	dx,[Start_Sec_H]	;AN000;
	pop ds
 assume ds:UPB
	add	ax,word ptr [di + HIDSEC_L]    ;AN000;
Hidsec_H equ HIDSEC_H	; NASM port equate
	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.
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov	[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.
	XOR	AX,AX
	MOV	DS,AX
 assume ds:IVT
	push word [DSKADR + 2]
	mov SI, [DSKADR]	; CURRENT DISK PARM TABLE
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	WORD PTR [DPT],SI
	pop	WORD PTR [DPT+2]
	POP	DS
 assume ds:UPB
	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	;|
	call ispatched
	jc @F
	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.

	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	word [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
	mov cx, dx                      ; cx = high word sector number
	mov ax, [di + SECLIM]           ; ax = number of CHS sectors
	mul word ptr [di + HDLIM]        ; ax = sectors per cylinder (dx == zero)
	mul word ptr [di + Hidden_Trks]   ; dx:ax = how many hidden sectors to add
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	add word ptr [Saved_Word], ax
	pop ds
 assume ds:UPB
	adc dx, cx                      ; add hidden sectors amount matching cyls
DISK_NOT_MINI:
	test word ptr [di + FLAGS], F_LBA
	jnz diskio_lba		; --> (NC)
	call lbatochs_saved_word
	jc BADDRIVE_Brdg
;
; 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.
;
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	AX, [SECCNT]
	pop ds
 assume ds:UPB
	CALL	BLOCK
diskio_done:
	CALL	msbiodisk_DONE
	RET

;
Baddrive equ BADDRIVE	; NASM port label
BADDRIVE_Brdg:jmp Baddrive
;

diskio_lba:
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov ax, word ptr [Saved_Word]
	mov cx, word ptr [SECCNT]
	pop ds
 assume ds:UPB
diskio_lba_loop:
	jcxz diskio_done
	call ishma_lba
	jnc .nothma
	push es
	push bx
	push cx

	 push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	cmp byte [RFLAG], ROMREAD
	je .hma_read
	push es
	push di
	push si
	 push es
	 pop ds
 assume ds:nothing
	mov si, bx
	call biocode_get_es_dosentry
 assume es:DOSENTRYGROUP
	mov di, DISKSECTOR
	call MOVE
	pop si
	pop di
	pop es
 assume es:nothing
.hma_read:
	 pop ds
 assume ds:UPB
	call biocode_get_es_dosentry
 assume es:DOSENTRYGROUP
	mov bx, DISKSECTOR
	mov cx, 1
	call diskio_lba_simple
	pop cx
	pop bx
	pop es
 assume es:nothing

	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	cmp byte [RFLAG], ROMREAD
	pop ds
 assume ds:UPB
	jne .hma_write
	 push ds
	 push si
	 push di
	mov di, bx
	call biocode_get_ds_dosentry
 assume ds:DOSENTRYGROUP
	mov si, DISKSECTOR
	call MOVE
	 pop di
	 pop si
	 pop ds
 assume ds:UPB
.hma_write:
	sub cx, 1
	add bh, 512 / 256
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov ax, word ptr [lbapacket + lpSector]
	mov dx, word ptr [lbapacket + lpSector + 2]
	pop ds
 assume ds:UPB
	add ax, 1
	adc dx, 0
	jmp diskio_lba_loop

.nothma:
	cmp cx, 128
	jb diskio_lba_call_simple
	push cx
	mov cx, 127
	call diskio_lba_simple
	pop cx
	mov ax, es
	add ax, 127 * 512 / 16
	mov es, ax
 assume es:nothing
	sub cx, 127
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov ax, word ptr [lbapacket + lpSector]
	mov dx, word ptr [lbapacket + lpSector + 2]
	pop ds
 assume ds:UPB
	add ax, 127
	adc dx, 0
	jmp diskio_lba_loop

diskio_lba_call_simple:
	call diskio_lba_simple
	jmp diskio_done

diskio_lba_simple:
	mov ch, byte ptr [di + DRIVENUM]
	push ds
	push si
	call lba_packet_setup
 assume ds:DOSGROUP
	MOV	BP,MAXERR		; SET UP RETRY COUNT
	mov	[VRetry_Cnt], BP	;AN003;Verify op. retry cnt for Write-Verify.
	mov	[Soft_ECC_Cnt], BP	;AN003;Soft ECC error retry count.
diskio_lba_retry:
	mov ax, 4000h			; ah will be 42h, 43h, 44h
	or ah, [RFLAG]			; GET READ/WRITE INDICATOR
	 push word ptr [si + lpCount]
	mov dl, ch
	int 13h
	 pop word ptr [si + lpCount]
	jc lba_noverify
	cmp word [WRTVERIFY], 103h	; CHECK FOR WRITE AND VERIFY
	je lba_doverify
	clc
lba_noverify:
	pop si
	pop ds
 assume ds:UPB
	jc diskio_lba_error
	retn

diskio_lba_error:
	call ispatched
	jc @F
	PUBLIC DSKERR_LBA_PATCH
DSKERR_LBA_PATCH:
	CALL CHECKIO
@@:
	CALL	AGAIN
lba_DskErr0:				;AN003;
	JZ	lba_HARDERR
	test	word ptr [di + FLAGS], fNon_Removable	;AN009;
	jnz	lba_Skip_TimeOut_Chk			;AN009;
	CMP	AH,80H			;TIMEOUT?
	JZ	lba_HARDERR		;***
lba_Skip_TimeOut_Chk:			;AN009;
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	cmp	ah, 0cch		;AN003;Write Fault error?
	jz	lba_Write_Fault_Err	;AN003; Then, don't retry.
	mov	word [Soft_ECC_Cnt], MAXERR ;AN003;Set Soft_ECC_Cnt back to MAXERR
lba_DSKERR1:
	pop ds
 assume ds:UPB
	mov ch, byte ptr [di + DRIVENUM]
	push ds
	push si
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov si, offset lbapacket	; access with ds
	JMP	diskio_lba_retry

lba_Write_Fault_Err:			;AN003;
	mov	bp, 1			;AN003;Just retry only once for Write Fault error.
lba_DskErr1 equ lba_DSKERR1	; NASM port label
	jmp	lba_DskErr1		;AN003;

lba_HARDERR:
	jmp HARDERR

lba_doverify:
 assume ds:DOSGROUP
	mov ah, 44h
	 push word ptr [si + lpCount]
	int 13h
	 pop word ptr [si + lpCount]
	jnc lba_noverify

	cmp	ah,11h			; SOFT ECC error ?
	jnz	.Not_SoftECC_Err
		; here NC
	dec	word [SOFT_ECC_CNT]
	jz	lba_noverify		; no more retry --> (NC)
	call	ResetDisk		; reset disk
	pop si
	jmp	lba_DskErr1		; retry

.Not_SoftECC_Err:			;AN003;Other error.
	call	ResetDisk
	dec word [VRetry_Cnt]
	pop si
	pop ds
 assume ds:UPB
	jmp	lba_DskErr0

DISKRD	ENDP


		; INP:	dx:ax = LBA
		;	ds:di -> UPB
		; OUT:	word [DOSDATA:CURTRK] = cylinder
		;	byte [DOSDATA:CURHD] = head
		;	byte [DOSDATA:CURSEC] = sector (1-based)
		;	CY if overflow
		; CHG:	dx, ax, cx
	public lbatochs
lbatochs:
 assume ds:UPB, es:nothing, ss:nothing
	push es
	call biocode_get_es_dosbiodata
 assume es:DOSGROUP
        mov word ptr [es:Saved_Word], ax
        db __TEST_IMM8			; skip push
lbatochs_saved_word:
	push es
 assume ds:UPB, es:nothing, ss:nothing
	call biocode_get_es_dosbiodata
 assume es:DOSGROUP
	xchg	ax, dx			; ax = high word, dx clobbered
	xor	dx,dx			;AN000;
	DIV	WORD PTR [DI + SECLIM]	;DIVIDE BY SEC PER TRACK
	mov	[es:Temp_H],ax		;AN000;
	mov	ax, [es:Saved_Word]	;AN000; Restore the lower word
SecLim equ SECLIM	; NASM port equate
	div	word ptr [di + SecLim]	;AN000;
;Now, [Temp_H],AX = track #, DX = sector
	INC	DL			;Sector number is 1 based.
	MOV	[es: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, [es:Temp_H]		;AN000;
	DIV	CX
	mov	[es:Temp_H],ax		;AN000;
	pop	ax			;AN000;
	div	cx			;AN000;
;Now, [Temp_H],AX = cyliner #, DX = head
	cmp	word [es:Temp_H],0		;AN000;
	ja	lbatochs_cy		;AN000;
	cmp	AX, 1024		;AN000; 2**10 currently maxium for track #.
	jae	lbatochs_cy		;AN000;
	MOV	[es:CURHD],DL		;SAVE CURRENT HEAD
	MOV	[es:CURTRK],AX		;SAVE CURRENT TRACK
	db 0A8h				; test al, imm8 - skip stc and NC

lbatochs_cy:
	stc
	pop es
 assume es:nothing
	ret


		; INP:	es:bx -> transfer address
		;	cl = count
		;	dx:ax = sector number
		; OUT:	ds:si -> LBA packet
		;	ah = 42h
	public lba_packet_setup
lba_packet_setup:
 assume ds:nothing, es:nothing, ss:nothing
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov si, offset lbapacket	; access with ds
	mov byte ptr [si + lpCount], cl
	mov word ptr [si + lpBuffer], bx
	mov word ptr [si + lpBuffer + 2], es
	mov word ptr [si + lpSector + 0], ax
	mov word ptr [si + lpSector + 2], dx
	mov ah, 42h
	retn


; 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
 assume ds:UPB, es:nothing, ss:nothing
	MOV	AL,[DI + DRIVENUM]
	push es
	call biocode_get_es_dosbiodata
 assume es:DOSGROUP
	MOV	[es:TIM_DRV],AL 	; SAVE DRIVE LETTER
;
; DETERMINE PROPER HEAD SETTLE VALUES
;
	cmp	byte [es:Media_Set_For_Format], 0	;AN012;
	jne	Skip_DPT_Setting		;AN012;
	MOV	CX,DS
	LDS	SI,[es:DPT]	; GET POINTER TO DISK BASE TABLE
 assume ds:nothing
	MOV	AL,[es:EOT]
	MOV	[SI + DISK_EOT],AL	; BUMP FOR US
	MOV	AL,[SI + DISK_MOTOR_STRT] ; PRESERVE OLD MOTOR START TIME
	MOV	[es: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
 assume es:UPB
	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
 assume es:DOSGROUP
;
; 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	[es:SETTLECURRENT],AL
	MOV	AL,NORMSETTLE		; SOMEONE HAS DIDDLED THE SETTLE
GOTSLOWSETTLE:
	MOV	DS,CX
 assume ds:UPB
	MOV	[es:SETTLESLOW],AL
Skip_DPT_Setting:			;AN012;
	pop es
 assume es:nothing
	RET
;
; SET TIME OF LAST ACCESS, AND RESET DEFAULT VALUES IN THE DPT.
;
msbiodisk_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:
 assume ds:nothing, es:nothing, ss:nothing
	pushf					;AN013;Save flag
	push es
	call biocode_get_es_dosbiodata
 assume es:DOSGROUP
	cmp	byte [es:Media_Set_For_Format], 0	;AN012;
	jne	NoDiddleBack			;AN012;
	PUSH	AX
	MOV	DX,DS
	MOV	AL,[es:SETTLECURRENT]
	MOV	AH,[es:MOTORSTARTUP]
	LDS	SI,[es:DPT]
 assume ds:nothing
;	 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	byte [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	byte [SI + DISK_SECTOR_SIZ],2
	MOV	[SI + DISK_MOTOR_STRT],AH
	MOV	DS,DX
 assume ds:nothing
	POP	AX
NoDiddleBack:				;AN013;
	pop es
 assume es:nothing
	popf				;AN013;Restore flag
RETZ:
	RET

ishma_lba:
 assume ds:nothing, es:nothing, ss:nothing
	push ax
	push cx
	push bx
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	rol byte [config_bounce_any_lba], 1
	jc ishma_chs.ret		; always bounce -->
	rol byte [config_bounce_uma_lba], 1
	jc ishma_chs.uma
	rol byte [config_bounce_hma_lba], 1
	jmp ishma_chs.none_or_hma

ishma_chs:
 assume ds:nothing, es:nothing, ss:nothing
	push ax
	push cx
	push bx
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	rol byte [config_bounce_any_chs], 1
	jc .ret				; always bounce -->
	rol byte [config_bounce_uma_chs], 1
	jc .uma
	rol byte [config_bounce_hma_chs], 1
.none_or_hma:
	jnc .ret
.hma:
	call .getax
.ret:
	pop ds
 assume ds:nothing
	pop bx
	pop cx
	pop ax
	retn

.uma:
 assume ds:DOSGROUP
	call .getax
	jc @F				; if in HMA, treat as UMA bounce too -->
 extern ENDMEM
	cmp ax, [ENDMEM]		; CY if end < UMA, NC if end >= UMA start
	jz .ret				; if end == UMA start --> (NC)
	cmc				; CY if end > UMA start
	jmp .ret
@@:

.getax:
	mov ax, es
	mov cl, 4
	shr bx, cl
	add ax, bx
	jc @F
	add ax, paras(512)
@@:
	retn

;READ THE NUMBER OF SECTORS SPECIFIED IN AX, HANDLING TRACK BOUNDARIES
;DS:DI -> BDS FOR THIS DRIVE
BLOCK:
 assume ds:UPB, es:nothing, ss:nothing
	test	AX,AX			;SEE IF ANY SECTORS TO READ
	JZ	RETZ	; fixme
	call ishma_chs
	jnc .nothma
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov byte [hma_operation], 0FFh
	pop ds
 assume ds:UPB
	jmp BLOCK_FLOPPY
.nothma:
;Fixed disk will not be restricted to the track-by-track basis. -J.K.4/10/86
Flags equ FLAGS	; NASM port equate
	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
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
MulTrk_ON equ MULTRK_ON	; NASM port equate
	test	word [MulTrk_Flag], MulTrk_ON
	pop ds
 assume ds:UPB
	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
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	SUB	CL,[CURSEC]		; LEEAC 3.20 ADD SEGMENT OVERRIDE
	rol byte [hma_operation], 1
	jnc .nohma
	cmp byte [RFLAG], ROMREAD
	je .hma_read
	push es
	push di
	push si
	 push es
	 pop ds
 assume ds:nothing
	mov si, bx
	call biocode_get_es_dosentry
 assume es:DOSENTRYGROUP
	mov di, DISKSECTOR		; access with es
	call MOVE
	pop si
	pop di
	pop es
 assume es:nothing
.hma_read:
	stc
	mov cl, 1
.nohma:
	pop ds
 assume ds:UPB
	jnc @F
	push es
	push bx
	call biocode_get_es_dosentry
 assume es:DOSENTRYGROUP
	mov bx, DISKSECTOR		; access with es
@@:
 assume es:nothing
	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

	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	rol byte [hma_operation], 1
	jnc .nohma
	not byte [hma_operation]
	cmp byte [RFLAG], ROMREAD
	jne .hma_write
	pop ds
 assume ds:UPB
	pop bx
	pop es
 assume es:nothing
	 push ds
	 push si
	 push di
	mov di, bx
	call biocode_get_ds_dosentry
 assume ds:DOSENTRYGROUP
	mov si, DISKSECTOR		; access with ds
	call MOVE
	 pop di
	 pop si
	 pop ds
 assume ds:UPB
	jmp @F
.hma_write:
	pop ds
 assume ds:UPB
	pop bx
	pop es
 assume es:nothing
	db __TEST_IMM8		; skip pop
.nohma:
	pop ds
 assume ds:UPB
@@:

;
; 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 equ DSKERR	; NASM port label
DskErr_Brdg: jmp DskErr 		;AN003;


		; INP:	variables from lbatochs
		;	ds:di -> UPB
		; OUT:	cx:dx = tuple value
	public chstotuple
chstotuple:
 assume ds:UPB, es:nothing, ss:nothing
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	cx, [CURTRK]		;LOAD CURRENT CYLINDER
	ROR	ch, 1
	ROR	ch, 1

	OR	ch, [CURSEC]
	XCHG	CH,CL			; CL = SECTOR, CH = CYLINDER
	MOV	DH,BYTE PTR [CURHD]	; LOAD CURRENT HEAD NUMBER AND
	pop ds
 assume ds:UPB
	MOV	DL,BYTE PTR [DI + DRIVENUM]  ; PHYSICAL DRIVE NUMBER
	ret

;
;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
 assume ds:UPB, es:nothing, ss:nothing
	MOV	BP,MAXERR		; SET UP RETRY COUNT
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov	[VRetry_Cnt], BP	;AN003;Verify op. retry cnt for Write-Verify.
	mov	[Soft_ECC_Cnt], BP	;AN003;Soft ECC error retry count.
	MOV	AH,[RFLAG]		;GET READ/WRITE INDICATOR
	pop ds
 assume ds:UPB

RETRY:
 assume ds:UPB
	PUSH	AX

	call chstotuple
	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.
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	CMP	byte [STEP_DRV],-1
	pop ds
 assume ds:UPB
	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
	nop	; identicalise
DO_FAST:				; ARR 2.20
	CALL	FASTSPEED		; MZ  2.21 CHANGE SETTLE MODE
TESTERR:				; MZ  2.21
DSKERR_brdg equ DskErr_Brdg	; NASM port label
	JC	DSKERR_brdg
; SET DRIVE AND TRACK OF LAST ACCESS
	MOV	BYTE PTR [DI + TRACK],CH	; ARR 2.20 SAVE TRACK
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	[STEP_DRV],DL	; ARR 2.20 SET DRIVE
	CMP	word [WRTVERIFY],103H	; CHECK FOR WRITE AND VERIFY
	pop ds
 assume ds:UPB
	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

fNON_REMOVABLE equ FNON_REMOVABLE	; NASM port equate
	test	word ptr [di + FLAGS], fNON_REMOVABLE
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	jz	ITS_REMOVABLE
	test	word [MulTrk_Flag], MulTrk_ON
	jnz	DISK_RET
ITS_REMOVABLE:
;SB34DISK003*****************************************************************
	AND	CL,03FH 		; ELIMINATE CYLINDER BITS FROM SECTOR
	XOR	AH,AH
	SUB	[SECCNT],AX		; REDUCE COUNT OF SECTORS TO GO
	ADD	CL,AL			; NEXT SECTOR
	MOV	[CURSEC],CL
	pop ds
 assume ds:UPB
	push ds
	CMP	CL,BYTE PTR [DI + SECLIM] ; SEE IF SECTOR/TRACK LIMIT REACHED
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	JBE	DISK_RET
NEXTTRACK:
	MOV	byte [CURSEC],1		; START WITH FIRST SECTOR OF NEXT TRACK
	MOV	DH,[CURHD]
	INC	DH
	jz nexttrack_xor
	pop ds
 assume ds:UPB
	push ds
	CMP	DH,BYTE PTR [DI + HDLIM]
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	JB	NOXOR
nexttrack_xor:
	XOR	DH,DH
	INC	word [CURTRK]		;NEXT TRACK
NOXOR:
	MOV	[CURHD],DH
DISK_RET:
	pop ds
 assume ds:UPB
	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
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	CMP	DL,[STEP_DRV]	; ARR 2.20
	pop ds
 assume ds:UPB
	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
SOFT_ECC_CNT equ Soft_ECC_Cnt	; NASM port label
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	dec	word [SOFT_ECC_CNT]
	pop ds
 assume ds:UPB
NoVerify equ NOVERIFY	; NASM port label
	jz	NoVerify		;no more retry
ResetDisk equ RESETDISK	; NASM port label
	call	ResetDisk		;reset disk
DskErr1 equ DSKERR1	; NASM port label
	jmp	DskErr1			;retry
	nop	; identicalise

;SB34DISK004**************************************************************

Not_SoftECC_Err:			;AN003;Other error.
	call	ResetDisk		;AN003;
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	dec	word [VRetry_Cnt]		;AN003;
	pop ds
 assume ds:UPB
	jmp	DskErr0 		;AN003;
	nop	; identicalise
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 ispatched
	jc @F
	PUBLIC DSKERR_PATCH
DSKERR_PATCH:
	CALL	CHECKIO 		;|
@@:
;---------------------------------------;|

	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	cmp	byte [MultiTrk_Format_Flag], 1 ;AN007;Multi trk format request?
	jne	DoChkAgain		   ;AN007;
	mov	bp, 1			   ;AN007;No more retry.
	mov	byte [MultiTrk_Format_Flag], 0 ;AN007;Clear the flag.
DoChkAgain:				   ;AN007;
	pop ds
 assume ds:UPB
	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.
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov	word [Soft_ECC_Cnt], MAXERR ;AN003;Set Soft_ECC_Cnt back to MAXERR
	pop ds
 assume ds:UPB
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

	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	pop word [dosbiodata_temp_ds]
	MOV	byte [TIM_DRV],-1	;FORCE A MEDIA CHECK THROUGH ROM
	MOV	CX,[SECCNT]		;GET COUNT OF SECTORS TO GO
	MOV	SP,[SPSAV]		;RECOVER ENTRY STACK POINTER
	mov ds, word [dosbiodata_temp_ds]
 assume ds:UPB
;
; 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
	push es
	call biocode_get_es_dosbiodata
 assume es:DOSGROUP
	cmp	byte [es:Media_Set_For_Format], 0	;AN012;
	jne	FASTSPEED_es			;AN012;
	PUSH	DS
	PUSH	AX
	MOV	AL,[es:SETTLESLOW]
	LDS	SI,[es:DPT]		; CURRENT DISK PARM TABLE
 assume ds:nothing
	MOV	[SI + DISK_HEAD_STTL],AL
	POP	AX
	POP	DS
 assume ds:UPB
	pop es
 assume es:nothing
	CALL	FASTSPEED
	push es
	call biocode_get_es_dosbiodata
 assume es:DOSGROUP
	PUSH	DS
	LDS	SI,[es:DPT]
 assume ds:nothing
	MOV	byte [SI + DISK_HEAD_STTL],1	; 1 IS FAST SETTLE VALUE
	POP	DS
 assume ds:UPB
	pop es
 assume es:nothing
	RET
NORMSPEED ENDP

FASTSPEED_es:
	pop es
 assume es:nothing
FASTSPEED PROC	NEAR
 assume ds:UPB, es:nothing, ss:nothing
;
; 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
	call biocode_get_es_dosbiodata
 assume es:DOSGROUP
					;MAKE ES THE LOCAL SEGMENT
	MOV	AL,AH			;PUT ERROR CODE IN AL
	MOV	[es:LSTERR],AL		;TERMINATE LIST WITH ERROR CODE
	MOV	CX,NUMERR		;NUMBER OF POSSIBLE ERROR CONDITIONS
	MOV	DI,OFFSET ERRIN      ;POINT TO ERROR CONDITIONS ; access with es
	REPNE	SCASB
	MOV	AL,[es: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
 assume ds:UPB, es:nothing, ss:nothing
	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
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	INC	word [DAYCNT]		; CATCH ROLLOVER
	pop ds
 assume ds:UPB
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:
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	BYTE PTR [ACCESSCOUNT],0
	pop ds
 assume ds:UPB
	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	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

section DOSENTRY

	extern Prev_DX, dosbiodata_temp_ds


section BIOCODE

;   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.
;
relocated msdisk_i13
	PUBLIC BLOCK13
BLOCK13 PROC	FAR
;
; LET THE OPPERATION PROCEED.  IF THERE IS A DMA VIOLATION, THEN WE DO THINGS.
;
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	[PREVOPER],AX		; SAVE REQUEST
	pop ds
 assume ds:nothing
	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			  |
	push bx
	MOV	bx,FCHANGED_BY_FORMAT+FCHANGED
	call ispatched
	jc @F
	PUBLIC CHANGED_PATCH
CHANGED_PATCH:
	CALL	SET_CHANGED_DL		; INDICATE THAT MEDIA CHANGED BY FORMAT
@@:
	pop bx
;							  |
;---------------------------------------------------------|
NOT_FORMAT:
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	test	dl, 80h			; floppy or hard disk?
	jnz	not_floppy		; if hard, skip this nonsense
	cmp	byte [EC35_Flag], 0		; any electrically compat. drives?
	jz	not_floppy		; no; proceed unhindered
	SAVEREG	<ax, bx, cx>
	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, [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
	mov	ax, 40h			; the machine state byte is in the...
	push ds
	mov	ds, ax			; ...segment at 40h
 assume ds:BDA
	mov	byte ptr [90h+bx], 93H	; establish drive type as: (360k disk in 360k drive, no double-stepping, 250 kbs transfer rate)
	pop ds
 assume ds:DOSGROUP
.not_EC35:
	RESTOREREG <cx, bx, ax>
not_floppy:
model_byte equ Model_Byte	; NASM port label
	cmp	byte [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:
	pop ds
 assume ds:nothing
	call DOSENTRY:transfer_orig13	; SIMULATE INT 13
	JC	GOTERR13_br		; ERROR?
	jmp Leave13			; NO, RETURN AND CLEAR FLAGS

Goterr13 equ GOTERR13	; NASM port label
GOTERR13_br: jmp Goterr13

section DOSENTRY

	extern transfer_orig13


section BIOCODE

	extern Leave13


;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.
 assume ds:DOSGROUP
	mov	[Prev_DX], DX		;save orignal drive number
	pop ds
 assume ds:nothing
Orig13 equ ORIG13	; NASM port label
	call DOSENTRY:transfer_orig13		;Do "Read drive parm"

	push ax
	push bx
	push cx
	push dx
	push di
	push si
	push bp
	push ds
	push es
	pushf
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov	dx, [Prev_DX]		;restore orignal drive
	mov	ah, 1			;Read Status.
	 pushf
	call DOSENTRY:transfer_orig13	;Reset the bus as a side effect of this call.

	popf
	pop es
 assume es:nothing
	pop ds
 assume ds:nothing
	pop bp
	pop si
	pop di
	pop dx
	pop cx
	pop bx
	pop ax
GotErr13 equ GOTERR13	; NASM port label
	jc	GotErr13		;AH=8 had been an error?
	jmp Leave13

;
; 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.
	nop	; identicalise

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.
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
Phys_Drv equ PHYS_DRV	; NASM port label
	mov	byte ptr [Phys_Drv], 1 ;AN011;
	mov	al, dl			;AN011;
SetDrive equ SETDRIVE	; NASM port label
	call	SetDrive		;AN011;
 assume ds:UPB
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov	byte ptr [Phys_Drv], 0 ;AN011;
	pop	ax			;AN011;
	pop	di			;AN011;
	pop	ds			;AN011;
 assume ds:nothing
	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

	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	cmp	byte [Media_Set_For_Format], 1 ; formatting?
	je	Skip_Ecc_Check_pop
	cmp	byte [Model_Byte], 0FEh	; PC or XT?
	jae	Go_Chk_Ecc
	cmp	byte [Model_Byte], 0FBh	; XT?
	je	Go_Chk_Ecc
	cmp	byte [Model_Byte], 0FCh
	jne	Skip_Ecc_Check
	cmp	byte [Secondary_Model_Byte], 2 ; AT?
	ja	Skip_Ecc_Check
Go_Chk_Ecc:				; for PC, XT, AT
	CMP	AH,11H
	JZ	OK11
Skip_Ecc_Check_pop:
	pop ds
 assume ds:nothing
Skip_Ecc_Check:				;AN003; Just return back to INT 13h caller.

;SB34DISK005*****************************************************************

	POPF
	jmp Leave13
;
; 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:
	pop ds
 assume ds:nothing
;	 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 DOSENTRY:transfer_orig13	;reset. Don't care about the result

	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	AX,[PREVOPER]		; RETRIEVE REQUEST
;
; THIS WILL PROVIDE A TERMINATION POINT.
;
	CMP	AL,1			; IF REQUEST FOR ONE SECTOR, ASSUME OK
	JNZ	ECC_ERR_HANDLE
	pop ds
 assume ds:nothing
	XOR	AH,AH			; CLEAR CARRY TOO!
	jmp Leave13

	PUBLIC ECC_ERR_HANDLE
ECC_ERR_HANDLE:
 assume ds:DOSGROUP
	pop ds
 assume ds:nothing
	SAVEREG <BX,CX,DX>
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	[NUMBER_OF_SEC],AL
LOOP_ECC:
	MOV	AX,[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
	 pop ds
 assume ds:nothing
	PUSHF
	call DOSENTRY:transfer_orig13
	JNC	OK11_OP
	CMP	AH,11H			; ONLY ALLOW ECC ERRORS
	stc				;J.K. 8/28/86 Set carry bit again.
	JNZ	OK11_EXIT_err		;J.K. 8/26/86 Other error? --> (CY)
	mov	ah, 0			;J.K. ECC error. Reset the system again.
	pushf
	call DOSENTRY:transfer_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:
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	DEC	byte [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:
	pop ds
 assume ds:nothing
OK11_EXIT_err:
	RESTOREREG <DX,CX,BX>
	jmp Leave13
;
; WE TRULY HAVE A DMA VIOLATION.  RESTORE REGISTER AX AND RETRY THE
; OPERATION AS BEST WE CAN.
;
GOTDMAERR:
	POP	AX			; CLEAN UP STACK
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	AX,[PREVOPER]
	pop ds
 assume ds:nothing
	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 <DX,CX,BX,AX>
	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?
DOBLOCK equ DoBlock	; NASM port label
	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 <ES,BX>
	call biocode_get_es_dosentry	; DISKSECTOR in DOSENTRY
 assume es:DOSENTRYGROUP
DOSIMPLE:
	MOV	BX,OFFSET DISKSECTOR	; access with es
	PUSHF
	call DOSENTRY:transfer_orig13
	RESTOREREG  <BX,ES>
 assume es:nothing
	jmp Leave13

;
; FORMAT OPERATION.  COPY THE PARAMETER TABLE INTO MEMORY
;
INTFORMAT:
	SAVEREG <ES,BX>
	SAVEREG <SI,DI,DS>
	PUSH	ES
	call biocode_get_es_dosentry	; DISKSECTOR in DOSENTRY
 assume es:DOSENTRYGROUP
	POP	DS
 assume ds:nothing
	MOV	SI,BX
	MOV	DI,OFFSET DISKSECTOR	; access with es
	CALL	MOVE
	RESTOREREG  <DS,DI,SI>
 assume ds:nothing
	JMP	DOSIMPLE
;
; INLINE CONTINUATION OF OPERATION
;
INTDONE:
 assume ds:nothing, es:nothing
	jmp DOSENTRY:transfer_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:
 assume ds:nothing, es:nothing
;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!!!">

olddx equ OLDDX	; NASM port equate
	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.
phys_drv equ PHYS_DRV	; NASM port label
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov	byte ptr [phys_drv],1
	mov	al, dl
	call	SetDrive		;get BDS pointer for this DISK.
 assume ds:UPB
		; fixme: what if not found ?
		; see next jc (questionable)
	pop	ax
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov byte ptr [phys_drv],0
	pop ds
 assume ds:UPB
	jc @F
	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
	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
 assume ds:nothing
	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
DoInt equ DOINT	; NASM port label
	CALL	DoInt
	JC BAD13			;something happened, bye!
	pop	ax
oldax equ OLDAX	; NASM port equate
	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
Buffer equ BUFFER	; NASM port label
	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_#
Check_Wrap equ CHECK_WRAP	; NASM port label
	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 <DS,ES,SI,DI>
	PUSH	ES
	POP	DS			; ds => user buffer
 assume ds:nothing
	call biocode_get_es_dosentry	; DISKSECTOR in DOSENTRY ; es => DOSENTRY
 assume es:DOSENTRYGROUP
	MOV	DI,OFFSET DISKSECTOR	; WHERE TO MOVE ; access with es
	PUSH	DI			; SAVE IT
	MOV	SI,BX			; SOURCE
	CALL	MOVE
	POP	BX			; NEW TRANSFER ADDRESS
	RESTOREREG  <DI,SI>
	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  <ES,DS>
 assume es:nothing, ds:nothing
	JC	BAD13			; GO CLEAN UP
	JMP	SHORT DOTAIL
;
; READING A SECTOR.  DO INT FIRST, THEN MOVE THINGS AROUND
;
.DOREAD:
 assume es:nothing
	SAVEREG <ES,BX>
	call biocode_get_es_dosentry	; DISKSECTOR in DOSENTRY
 assume es:DOSENTRYGROUP
	MOV	BX,OFFSET DISKSECTOR	; access with es
	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  <BX,ES>
 assume es:nothing
	JC	BAD13			; ERROR => CLEAN UP
	SAVEREG <DS,SI,DI>
	call biocode_get_ds_dosentry	; DISKSECTOR in DOSENTRY !
 assume ds:DOSENTRYGROUP
	MOV	DI,BX
	MOV	SI,OFFSET DISKSECTOR	; access with ds
	CALL	MOVE
	RESTOREREG  <DI,SI,DS>
 assume ds:nothing
;
; 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  <BP,BX,BX,CX,DX>
	jmp Leave13
BLOCK13 ENDP
;	PAGE
;=== Push trace listing source: msioctl.nas
	%include "msioctl.nas" ; NASM included file
;=== Pop trace listing source
;	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 <AX,BX,DS,DI>
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	BYTE PTR [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
 assume ds:UPB
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	BYTE PTR [PHYS_DRV],0	; RESTORE FLAG TO USE LOGICAL DRIVE
	pop ds
 assume ds:UPB
	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.
	test	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!!
	test	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 <DI,DS,BX,AX>
 assume ds:nothing
	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


%ifn _RELOCATEDOSCODE
 global i2F
i2F:
%endif
relocated head_i2F	; (destination of the real int 2Fh vector)
relocated set_i13_i2F
 ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
	CMP	AH,13H			; IF (INTERRUPT_VALUE != RESET_INT_13)
 extern relocateddisk_i2F
	jne relocateddisk_i2F		;  THEN CONTINUE ON INT_2F CHAIN
CHG_ORIG13:				;	ELSE
 assume ds:nothing, es:nothing, ss:nothing
	cli
	push ax
	mov ax, ds
	call biocode_get_ds_dosentry	; OLD13, ORIG13 in DOSENTRY !
 assume ds:DOSENTRYGROUP
	PUSH	WORD PTR [ORIG13]	;	   SAVE OLD VALUE OF OLD13 AND
	PUSH	WORD PTR [ORIG13 + 2];	   ORIG13 SO THAT WE CAN

	PUSH	WORD PTR [OLD13]	;	   RETURN THEM TO CALLER
	PUSH	WORD PTR [OLD13 + 2]

	MOV	WORD PTR [ORIG13],DX ;	   ORIG13 := ADDR. OF NEW INT_13
					;				VECTOR
	MOV	WORD PTR [ORIG13+2], ax

	MOV	WORD PTR [OLD13],BX	;	    OLD13 := ADDR. OF NEW
					;			  BOOT_13 VECTOR
	MOV	WORD PTR [OLD13+2],ES

	POP	ES			;	    ES:BX := OLD OLD13 VECTOR
 assume es:nothing
	POP	BX

	POP	DS			;	    DS:DX := OLD ORIG13 VECTOR
 assume ds:nothing
	POP	DX
	pop ax

	IRET				;	END ELSE

INT_2F_13	ENDP

MOVE	PROC	NEAR
	CLD
	PUSH	CX
	MOV	CX,512/2

	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	rol byte [dosbiodata_have_386], 1
	pop ds
 assume ds:nothing
	jnc @F

;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.
	o32			;AN002;Machine code for double word mov
;----------------------------------------------------------------------------
@@:
	REP	MOVSW
	POP	CX
	RET
MOVE ENDP

DOINT	PROC	NEAR
 assume ds:nothing, es:nothing, ss:nothing
	MOV	DL,BYTE PTR [BP + OLDDX]		; GET PHYSICAL DRIVE NUMBER
	XOR	AH,AH
	test	AL,AL
	JZ	DOINTDONE
	MOV	AH,BYTE PTR [BP + OLDAX+1]	; GET REQUEST CODE
	PUSH	word [BP + OLDF]
	call DOSENTRY:transfer_orig13
	PUSHF
	POP	word [BP + OLDF]
DOINTDONE:
	RET
DOINT	ENDP


	global ispatched
ispatched:
 assume ds:nothing
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP
	cmp byte [FHAVE96], 1			; CY if 0
	pop ds
 assume ds:nothing
	retn


usesection DOSBIODATA

 global dosbiodata_have_386
dosbiodata_have_386:	db 0
hma_operation:		db 0

 global config_bounce_hma_chs
 global config_bounce_hma_lba
config_bounce_hma_chs:	db 0
config_bounce_hma_lba:	db 0
 global config_bounce_uma_chs
 global config_bounce_uma_lba
config_bounce_uma_chs:	db 0
config_bounce_uma_lba:	db 0
 global config_bounce_any_chs
 global config_bounce_any_lba
config_bounce_any_chs:	db 0
config_bounce_any_lba:	db 0
