1 ; SCCSID = @(#)disk2.asm 1.3 85/06/19
2 ; SCCSID = @(#)disk2.asm 1.3 85/06/19
3 TITLE DISK2
- Disk utility routines
5 ; Low level Read and write routines for local SFT I/O on files and devs
14 ; WRITE_LOCK_VIOLATION
24 ; AN000 version 4.00 Jan. 1988
28 ; get the appropriate segment definitions
33 CODE SEGMENT BYTE PUBLIC 'CODE'
34 ASSUME
SS:DOSGROUP
,CS:DOSGROUP
49 i_need SecClusPos
,BYTE
54 i_need SecPos
,DWORD ; DOS 4.00 >32mb ;AN000;
62 i_need CALLVIDRW
,DWORD
66 i_need DISK_FULL
,BYTE ; disk full flag for ran blk wrt
67 i_need FSeek_drive
,BYTE ; DOS 4.00 ;AN000;
68 i_need FSeek_firclus
,WORD ; DOS 4.00 ;AN000;
69 i_need HIGH_SECTOR
,WORD ; F.C. >32mb ;AN000;
70 i_need TEMP_VAR2
,WORD ; LB. ;AN000;
71 i_need TEMP_VAR
,WORD ; LB. ;AN000;
72 i_need IFS_DRIVER_ERR
,WORD ; LB. ;AN000;
73 i_need CurHashEntry
,DWORD ; DOS 4.00 current Hash entry ;AN000;
74 i_need BUF_HASH_PTR
,DWORD ; DOS 4.00 Hash table pointer ;AN000;
75 i_need BUF_HASH_COUNT
,WORD ; DOS 4.00 Hash table entries ;AN000;
76 i_need LastBuffer
,DWORD
77 i_need FIRST_BUFF_ADDR
,WORD ; first buffer address ;AN000;
81 EXTRN RESTORE_MAP
:NEAR
82 EXTRN SAVE_USER_MAP
:NEAR
83 EXTRN RESTORE_USER_MAP
:NEAR
84 i_need BUF_EMS_SAFE_FLAG
,BYTE
85 i_need BUF_EMS_MODE
,BYTE
90 Break <DSKREAD
-- PHYSICAL DISK READ
>
93 ; DS:BX = Transfer addr
94 ; CX = Number of sectors
95 ; [HIGH_SECTOR] = Absolute record number (HIGH)
96 ; DX = Absolute record number (LOW)
97 ; ES:BP = Base of drive parameters
99 ; Call BIOS to perform disk read
102 ; CX = Number of sectors unsuccessfully transfered
103 ; AX = Status word as returned by BIOS (error code in AL if error)
104 ; Zero set if OK (from BIOS) (carry clear)
105 ; Zero clear if error (carry clear)
106 ; SI Destroyed, others preserved
108 procedure DskRead
,NEAR
109 ASSUME
DS:NOTHING
,ES:NOTHING
111 Assert ISDPB
,<ES,BP>,"DskRead"
113 MOV AH,ES:[BP.dpb_media
]
114 MOV AL,ES:[BP.dpb_UNIT
]
120 Break <DWRITE
-- SEE ABOUT WRITING
>
123 ; DS:BX = Transfer address
124 ; CX = Number of sectors
125 ; [HIGH_SECTOR] = Absolute record number (HIGH)
126 ; DX = Absolute record number (LOW)
127 ; ES:BP = Base of drive parameters
128 ; [ALLOWED] must be set in case HARDERR called
130 ; Calls BIOS to perform disk write. If BIOS reports
131 ; errors, will call HARDERRRW for further action.
133 ; Carry set if error (currently, user FAILed to I 24)
134 ; BP preserved. All other registers destroyed.
137 ASSUME
DS:NOTHING
,ES:NOTHING
139 Assert ISDPB
,<ES,BP>,"DWrite"
142 MOV BYTE PTR [READOP
],1
144 CMP AL,1 ; Check for retry
146 CMP AL,3 ; Check for FAIL
153 Break <DSKWRITE
-- PHYSICAL DISK WRITE
>
156 ; DS:BX = Transfer addr
157 ; CX = Number of sectors
158 ; DX = Absolute record number (LOW)
159 ; [HIGH_SECTOR] = Absolute record number (HIGH)
160 ; ES:BP = Base of drive parameters
162 ; Call BIOS to perform disk read
165 ; CX = Number of sectors unsuccessfully transfered
166 ; AX = Status word as returned by BIOS (error code in AL if error)
167 ; Zero set if OK (from BIOS) (carry clear)
168 ; Zero clear if error (carry clear)
169 ; SI Destroyed, others preserved
172 ASSUME
DS:NOTHING
,ES:NOTHING
174 Assert ISDPB
,<ES,BP>,"DskWrite"
176 MOV AH,ES:[BP.dpb_media
]
177 MOV AL,ES:[BP.dpb_UNIT
]
183 POP DS ; DS:BP points to DPB
185 LDS SI,DS:[BP.dpb_driver_addr
]
187 MOV DS,CX ; Restore DS
190 MOV CX,[CALLSCNT
] ; Number of sectors transferred
193 NEG CX ; Number of sectors not transferred
194 MOV AX,[DEVCALL
.REQSTAT
]
195 MOV [IFS_DRIVER_ERR
],AX ;IFS. save it for IFS ;AN000;
202 Break <HardErrRW
- map extended errors
and call harderr
>
205 ; AX is error code from read or write
206 ; Other registers set as per HARDERR
208 ; Checks the error code for special extended
209 ; errors and maps them if needed. Then invokes
213 ; AX may be modified prior to call to HARDERR.
214 ; No other registers altered.
216 procedure HARDERRRW
,near
217 ASSUME
DS:NOTHING
,ES:NOTHING
219 CMP AL,error_I24_wrong_disk
220 JNZ DO_ERR
; Nothing to do
223 LDS SI,[CALLVIDRW
] ; Get pointer from dev
224 MOV WORD PTR [EXTERRPT
+2],DS ; Set ext err pointer
225 MOV WORD PTR [EXTERRPT
],SI
234 Break <SETUP
-- SETUP A DISK READ
OR WRITE
FROM USER
>
237 ; ES:DI point to SFT (value also in THISSFT)
238 ; [DMAADD] contains transfer address
240 ; WARNING Stack must be clean, two ret addrs on stack, 1st of caller,
241 ; 2nd of caller of caller.
244 ; [THISDPB] = Base of drive parameters if file
245 ; = Pointer to device header if device or NET
246 ; ES:DI Points to SFT
247 ; [NEXTADD] = Displacement of disk transfer within segment
248 ; [TRANS] = 0 (No transfers yet)
249 ; [BYTPOS] = Byte position in file
251 ; The following fields are relevant to local files (not devices) only:
253 ; [SECPOS] = Position of first sector (local files only)
254 ; [BYTSECPOS] = Byte position in first sector (local files only)
255 ; [CLUSNUM] = First cluster (local files only)
256 ; [SECCLUSPOS] = Sector within first cluster (local files only)
257 ; [THISDRV] = Physical unit number (local files only)
259 ; RETURNS ONE LEVEL UP WITH:
262 ; IF AN ERROR IS DETECTED
263 ; All other registers destroyed
266 DOSAssume
CS,<DS>,"SetUp"
269 Assert ISSFT
,<ES,DI>,"SetUp"
270 LDS SI,ES:[DI.sf_devptr
]
272 MOV WORD PTR [THISDPB
+2],DS
274 MOV WORD PTR [THISDPB
],SI
275 MOV BX,WORD PTR [DMAADD
]
276 MOV [NEXTADD
],BX ;Set NEXTADD to start of Xaddr
277 MOV BYTE PTR [TRANS
],0 ;No transferes
278 MOV AX,WORD PTR ES:[DI.sf_Position
]
279 MOV DX,WORD PTR ES:[DI.sf_Position
+2]
280 MOV WORD PTR [BYTPOS
+2],DX ;Set it
281 MOV WORD PTR [BYTPOS
],AX
282 TEST ES:[DI.sf_flags
],sf_isnet
+ devid_device
283 JNZ NOSETSTUFF
;Following not done on devs or NET
285 LES BP,[THISDPB
] ;Point at the DPB
286 Assert ISDPB
,<ES,BP>,"Setup"
287 MOV BL,ES:[BP.dpb_drive
]
288 MOV [THISDRV
],BL ;Set THISDRV
289 MOV BX,ES:[BP.dpb_sector_size
]
290 ; CMP DX,BX ; See if divide will overflow
291 ; JNC EOFERR ; for 16 bit sector
293 invoke DIV32
; F.C. >32mb ;AN000;
294 MOV WORD PTR [SECPOS
],AX ; F.C. >32mb ;AN000;
295 MOV BX,[HIGH_SECTOR
] ; F.C. >32mb ;AN000;
296 MOV WORD PTR [SECPOS
+2],BX ; F.C. >32mb ;AN000;
300 AND AL,ES:[BP.dpb_cluster_mask
]
302 MOV AX,CX ; Save byte count
303 ; MOV CL,ES:[BP.dpb_cluster_shift]
304 PUSH WORD PTR [SECPOS
+2] ; F.C. >32mb ;AN000;
305 POP [HIGH_SECTOR
] ; F.C. >32mb ;AN000;
306 PUSH AX ; F.C. >32mb save ax ;AN000;
307 MOV AX,DX ; F.C. >32mb ax=dx ;AN000;
308 invoke SHR32
; F.C. >32mb shift ax ;AN000;
309 MOV DX,AX ; F.C. >32mb dx=ax ;AN000;
310 POP AX ; F.C. >32mb restore dx ;AN000;
313 CMP DX,ES:[BP.dpb_max_cluster
] ;>32mb if > disk size ;AN000; ;AN000;
314 JA EOFERR
;>32mb then EOF ;AN000; ;AN000;
317 POP ES ; ES:DI point to SFT
318 MOV CX,AX ; Put byte count back in CX
320 MOV AX,CX ; Need it in AX too
321 ADD AX,WORD PTR [DMAADD
] ; See if it will fit in one segment
322 JNC OK
; Must be less than 64K
323 MOV AX,WORD PTR [DMAADD
]
324 NEG AX ; Amount of room left in segment (know
325 ; less than 64K since max value of CX
330 MOV CX,AX ; Can do this much
331 JCXZ NOROOM
; Silly user gave Xaddr of FFFF in segment
336 POP ES ; ES:DI point to SFT
337 XOR CX,CX ; No bytes read
339 ; MOV BYTE PTR [DISK_FULL],1 ; set disk full flag
342 POP BX ; Kill return address
344 return
; RETURN TO CALLER OF CALLER
347 Break <BREAKDOWN
-- CUT A USER READ
OR WRITE
INTO PIECES
>
350 ; CX = Length of disk transfer in bytes
351 ; ES:BP = Base of drive parameters
352 ; [BYTSECPOS] = Byte position witin first sector
354 ; [BYTCNT1] = Bytes to transfer in first sector
355 ; [SECCNT] = No. of whole sectors to transfer
356 ; [BYTCNT2] = Bytes to transfer in last sector
357 ; AX, BX, DX destroyed. No other registers affected.
359 procedure BREAKDOWN
,near
360 DOSAssume
CS,<DS>,"BreakDown"
363 Assert ISDPB
,<ES,BP>,"BreakDown"
367 JZ SAVFIR
; Partial first sector?
368 SUB AX,ES:[BP.dpb_sector_size
]
369 NEG AX ; Max number of bytes left in first sector
370 SUB BX,AX ; Subtract from total length
372 ADD AX,BX ; Don't use all of the rest of the sector
373 XOR BX,BX ; And no bytes are left
378 DIV ES:[BP.dpb_sector_size
] ; How many whole sectors?
380 MOV [BYTCNT2
],DX ; Bytes remaining for last sector
382 retnz
; NOT (BYTCNT1 = BYTCNT2 = 0)
385 MOV AX,ES:[BP.dpb_sector_size
] ; Buffer EXACT one sector I/O
387 MOV [SECCNT
],DX ; DX = 0
392 ; ES:DI points to SFT. This entry used by NET_READ
393 ; Carry set if to return error (CX=0,AX=error_sharing_violation).
395 ; ES:DI,DS,CX preserved
397 procedure READ_LOCK_VIOLATION
,NEAR
398 DOSAssume
CS,<DS>,"Read_Lock_Violation"
401 Assert ISSFT
,<ES,DI>,"ReadLockViolation"
405 TEST ES:[DI.sf_mode
],sf_isfcb
408 MOV CL,BYTE PTR ES:[DI.sf_mode
]
410 CMP CL,sharing_compat
414 invoke LOCK_VIOLATION
415 retnc
; User wants Retrys
417 XOR CX,CX ;No bytes transferred
418 MOV AX,error_lock_violation
422 EndProc READ_LOCK_VIOLATION
424 ; Same as READ_LOCK_VIOLATION except for READOP.
425 ; This entry used by NET_WRITE
426 procedure WRITE_LOCK_VIOLATION
,NEAR
427 DOSAssume
CS,<DS>,"Write_Lock_Violation"
429 Assert ISSFT
,<ES,DI>,"WriteLockViolation"
434 EndProc WRITE_LOCK_VIOLATION
437 Break <DISKREAD
-- PERFORM USER DISK READ
>
445 ; CX = No. of bytes read
447 ; SFT offset and cluster pointers updated
453 procedure DISKREAD
,NEAR
454 DOSAssume
CS,<DS>,"DiskRead"
457 Assert ISSFT
,<ES,DI>,"DISKREAD"
458 PUSH ES:[DI.sf_firclus
] ; set up 1st cluster # for FastSeek
459 POP [FSeek_firclus
] ; 11/5/86
461 MOV AX,WORD PTR ES:[DI.sf_size
]
462 MOV BX,WORD PTR ES:[DI.sf_size
+2]
463 SUB AX,WORD PTR [BYTPOS
]
464 SBB BX,WORD PTR [BYTPOS
+2]
465 JB RDERR
;Read starts past EOF
466 JNZ ENUF
;More than 64k to EOF
468 JZ RDERR
;Read starts at EOF
471 MOV CX,AX ;Limit read to up til EOF
473 invoke CHECK_READ_LOCK
;IFS. check read lock ;AN000;
474 JNC Read_Ok
; There are no locks
479 Assert ISDPB
,<ES,BP>,"DISKREAD/ReadOK"
480 MOV AL,ES:[BP.dpb_drive
] ; set up drive # for FastSeek
481 MOV [FSeek_drive
],AL ; 11/5/86 ;AN000;
486 ;------------------------------------------------------------------------
488 JC SET_ACC_ERR_DS
; fix to take care of I24 fail
489 ; migrated from 330a - HKN
491 ;------------------------------------------------------------------------
495 MOV [DISK_FULL
],1 ;MS. EOF detection ;AN000;
496 MOV AH,0EH ;MS. read/data/fail ;AN000;
507 ASSUME
DS:NOTHING
,ES:NOTHING
511 DOSAssume
CS,<DS>,"SET_ACC_ERR"
514 MOV AX,error_access_denied
530 MOV BYTE PTR [TRANS
],1 ; A transfer is taking place
541 MOV [ALLOWED
],allowed_RETRY
+ allowed_FAIL
+ allowed_IGNORE
542 MOV DS,WORD PTR [DMAADD
+2]
546 invoke SET_RQ_SC_PARMS
;LB. do this for SC ;AN000;
550 cmp [BUF_EMS_SAFE_FLAG
], 1
553 call restore_user_map
562 cmp [BUF_EMS_SAFE_FLAG
], 1
575 MOV [TEMP_VAR
],BX ;LB. save sector count ;AN000;
576 MOV [TEMP_VAR2
],DX ;LB. 1st sector ;AN000;
578 ;;;;;;; invoke GETCURHEAD ;LB. get buffer header ;AN000;
579 PUSH DX ;LB. save regs ;AN000;
583 ; MOV DX,[HIGH_SECTOR] ;LB. HASH(sector#) and get entry # ;AN000;
584 XOR DX,DX ;LB. to avoid divide overflow ;AN000;
585 DIV [BUF_HASH_COUNT
] ;LB. get remainder ;AN000;
586 ADD DX,DX ;LB. 8 bytes per entry ;AN000;
587 ADD DX,DX ;LB. ;AN000;
588 ADD DX,DX ;LB. times 8 ;AN000;
590 LDS DI,[BUF_HASH_PTR
] ;LB. get Hash Table addr ;AN000;
591 ADD DI,DX ;LB position to entry ;AN000;
592 CMP [DI.Dirty_Count
],0 ;LB dirty hash entry ? ;AN000;
593 JNZ yesdirty
;LB yes and map it ;AN000;
599 JMP SHORT end_scan
;LB. ;AN000;
605 MOV WORD PTR [CurHashEntry
+2],DS ;LB. update current Hash entry ptr ;AN000;
606 MOV WORD PTR [CurHashEntry
],DI ;LB. ;AN000;
607 MOV WORD PTR [LASTBUFFER
],-1 ;LB. invalidate last buffer ;AN000;
608 MOV BX,[DI.EMS_PAGE_NUM
] ;LB. logical page ;AN000;
611 LDS DI,[DI.BUFFER_BUCKET
] ;LB. ds:di is 1st buffer addr ;AN000;
612 MOV [FIRST_BUFF_ADDR
],DI ;LB. save first buff addr 1/19/88 ;AN000;
613 invoke SET_MAP_PAGE
;LB. activate handle if EMS there ;AN000;
617 push di ; save hash ptr
619 LDS DI,[DI.BUFFER_BUCKET
] ;ds:di is 1st buffer addr
620 POP AX ; Recall transfer address
622 PUSH DI ; Save search environment
623 PUSH DX ; F.C. no need for high sector, <64K
626 MOV DX,[TEMP_VAR2
] ;LB. get 1st sector #
627 SUB DX,WORD PTR [DI.buf_sector
] ; How far into transfer?
631 MOV CX,ES:[BP.dpb_sector_size
]
633 ADD DI,AX ; Put the buffer here
640 invoke SET_MAP_PAGE
;LB. activate handle if EMS there ;AN000;
641 pop di ; restore hash ptr.
643 LDS DI,[DI.BUFFER_BUCKET
] ;LB. ds:di is 1st buffer addr ;AN000;
644 MOV [FIRST_BUFF_ADDR
],DI ;LB. save first buff addr 1/19/88 ;AN000;
652 Assert ISDPB
,<ES,BP>,"DISKREAD/RdLp"
653 MOV AL,ES:[BP.dpb_drive
]
654 NXTBUF: ; Must see if one of these sectors is buffered
655 invoke BUFF_RANGE_CHECK
;F.C. >32mb
656 JNC inrange
;LB. ;AN000;
657 mov DI,[DI.buf_next
] ;LB. get next buffer 1/19/88 ;AN000;
658 JMP DONXTBUF
;LB. ;AN000;
660 TEST [DI.buf_flags
],buf_dirty
661 JZ CLBUFF
; Buffer is clean, so OK
662 ; A sector has been read in when a dirty copy of it is in a buffer
663 ; The buffered sector must now be read into the right place
664 POP AX ; Recall transfer address
666 PUSH DI ; Save search environment
667 PUSH DX ; F.C. no need for high sector, <64K
669 MOV DX,[TEMP_VAR2
] ;LB. get 1st sector #
670 SUB DX,WORD PTR [DI.buf_sector
] ; How far into transfer?
675 MOV CX,ES:[BP.dpb_sector_size
]
677 ADD DI,AX ; Put the buffer here
681 MOV ES,WORD PTR [DMAADD
+2]
689 MOV AL,ES:[BP.dpb_drive
]
690 invoke SCANPLACE
;LB. done with this chain ;AN000;
691 JMP SHORT end_scan
;LB. ;AN000;
695 CMP DI,[FIRST_BUFF_ADDR
] ;LB. end of buffers ;AN000;
698 ADD DX,1 ;LB. next sector # ;AN000;
699 ADC [HIGH_SECTOR
],0 ;LB. ;AN000;
700 DEC [TEMP_VAR
] ;LB. decrement count ;AN000;
701 JZ SCAN_DONE
;LB. scan next sector ;AN000;
702 JMP SCAN_NEXT
;LB. scan next sector ;AN000;
709 invoke IsEOF
; test for eof on fat size
712 INC [LASTPOS
] ; We'll be using next cluster
728 ; [NEXTADD],[CLUSNUM],[LASTPOS] set to determine transfer size
729 ; and set cluster fields
731 ; Update [THISSFT] based on the transfer
733 ; sf_position, sf_lstclus, and sf_cluspos updated
734 ; ES:DI points to [THISSFT]
735 ; CX No. of bytes transferred
739 DOSAssume
CS,<DS>,"SetSFT"
744 ; Same as SETSFT except ES:DI already points to SFT
746 DOSAssume
CS,<DS>,"SetClus"
749 Assert ISSFT
,<ES,DI>,"SetClus"
751 SUB CX,WORD PTR [DMAADD
] ; Number of bytes transfered
752 TEST ES:[DI.sf_flags
],devid_device
753 JNZ ADDREC
; don't set clusters if device
755 MOV ES:[DI.sf_lstclus
],AX
757 MOV ES:[DI.sf_cluspos
],AX
760 ; ES:DI points to SFT
761 ; CX is No. Bytes transferred
763 ; Update the SFT offset based on the transfer
765 ; sf_position updated to point to first byte after transfer
766 ; ES:DI points to SFT
767 ; CX No. of bytes transferred
771 DOSAssume
CS,<DS>,"AddRec"
774 Assert ISSFT
,<ES,DI>,"AddRec"
775 JCXZ RET28
; If no records read, don't change position
776 ADD WORD PTR ES:[DI.sf_position
],CX ; Update current position
777 ADC WORD PTR ES:[DI.sf_position
+2],0