1 ; SCCSID = @(#)disk3.asm 1.3 85/07/26
2 ; SCCSID = @(#)disk3.asm 1.3 85/07/26
3 TITLE DISK3
- Disk utility routines
5 ; Low level Read and write routines for local SFT I/O on files and devs
12 ; AN000 version 4.00 Jan. 1988
16 ; get the appropriate segment definitions
21 CODE SEGMENT BYTE PUBLIC 'CODE'
22 ASSUME
SS:DOSGROUP
,CS:DOSGROUP
35 i_need SecClusPos
,BYTE
39 i_need SecPos
,DWORD ;F.C. >32mb ;AN000;
46 i_need ValSec
,WORD ;F.C. >32mb ;AN000;
50 I_need FSeek_drive
,BYTE ; DOS 4.00 ;AN000;
51 I_need FSeek_firclus
,WORD ; DOS 4.00 ;AN000;
52 I_need FSeek_logclus
,WORD ; DOS 4.00 ;AN000;
53 I_need HIGH_SECTOR
,WORD ;F.C. >32mb ;AN000;
54 I_need HIGH_SECTOR_TEMP
,WORD ;F.C. >32mb ;AN000;
55 I_need EXTERR
,WORD ; DOS 4.00 ;AN000;
56 I_need EXTERR_LOCUS
,BYTE ; DOS 4.00 ;AN000;
57 I_need EXTERR_ACTION
,BYTE ; DOS 4.00 ;AN000;
58 I_need EXTERR_CLASS
,BYTE ; DOS 4.00 ;AN000;
59 I_need EXITHOLD
,DWORD ; DOS 4.00 ;AN000;
60 I_need DISK_FULL
,BYTE ; DOS 4.00 ;AN000;
61 I_need SC_DRIVE
,BYTE ; DOS 4.00 ;AN000;
62 I_need SC_CACHE_COUNT
,WORD ; DOS 4.00 ;AN000;
63 I_need ThisDRV
,BYTE ; DOS 4.00 ;AN000;
64 I_need User_In_AX
,WORD ; DOS 4.00 ;AN000;
65 I_need DOS34_FLAG
,WORD ; DOS 4.00 ;AN000;
66 I_need FIRST_BUFF_ADDR
,WORD ; DOS 4.00 ;AN000;
70 EXTRN RESTORE_MAP
:NEAR
71 EXTRN SAVE_USER_MAP
:NEAR
72 EXTRN RESTORE_USER_MAP
:NEAR
73 i_need BUF_EMS_SAFE_FLAG
,BYTE
74 i_need BUF_EMS_MODE
,BYTE
79 Break <DISKWRITE
-- PERFORM USER DISK WRITE
>
87 ; CX = No. of bytes read
89 ; SFT offset and cluster pointers updated
95 procedure DISKWRITE
,NEAR
96 DOSAssume
CS,<DS>,"DiskWrite"
99 Assert ISSFT
,<ES,DI>,"DiskWrite"
100 PUSH ES:[DI.sf_firclus
] ; set up 1st cluster # for FastSeek
103 invoke CHECK_WRITE_LOCK
;IFS. check write lock ;AN000;
104 JNC WRITE_OK
;IFS. lock check ok ;AN000;
111 AND ES:[DI.sf_flags
],NOT (sf_close_nodate
OR devid_file_clean
)
112 ; Mark file as dirty, clear no date on close
114 Assert ISDPB
,<ES,BP>,"DiskWrite/WriteOk"
115 MOV AL,ES:[BP.dpb_drive
] ; set up drive # for FastSeek
116 MOV [FSeek_drive
],AL ; 11/5/86 DOS 4.00
119 MOV AX,WORD PTR [BYTPOS
]
120 MOV DX,WORD PTR [BYTPOS
+2]
121 JCXZ WRTEOFJ
;Make the file length = sf_position
123 ADC DX,0 ; AX:DX=byte after last byte accessed
125 ; Make sure divide won't overflow
127 MOV BX,ES:[BP.dpb_sector_size
]
128 ; CMP DX,BX ;F.C. >32mb 16 bit sector check ;AN000;
129 ; JAE WrtErr ;F.C. >32mb ;AN000;
131 CALL DIV32
;F.C. perform 32 bit divide ;AN000;
132 MOV BX,AX ; Save last full sector
135 SUB AX,1 ; AX must be zero base indexed ;AC000;
136 SBB [HIGH_SECTOR
],0 ;F.C. >32mb ;AN000;
138 PUSH [HIGH_SECTOR
] ;F.C. >32mb ;AN000;
139 CALL SHR32
;F.C. >32mb ;AN000;
140 POP [HIGH_SECTOR
] ;F.C. >32mb ;AN000;
142 ; SHR AX,CL ; Last cluster to be accessed
144 PUSH DX ; Save the size of the "tail"
147 Assert ISSFT
,<ES,DI>,"DiskWrite/CalClus"
148 MOV AX,WORD PTR ES:[DI.sf_size
]
149 MOV DX,WORD PTR ES:[DI.sf_size
+2]
154 PUSH AX ;F.C. >32mb ;AN000;
155 MOV AX,DX ;F.C. >32mb ;AN000;
156 XOR DX,DX ;F.C. >32mb ;AN000;
157 DIV ES:[BP.dpb_sector_size
] ;F.C. >32mb ;AN000;
158 MOV [HIGH_SECTOR_TEMP
],AX ;F.C. >32mb ;AN000;
159 POP AX ;F.C. >32mb ;AN000;
161 DIV ES:[BP.dpb_sector_size
]
162 MOV CX,AX ; Save last full sector of current file
165 ADD AX,1 ; Round up if any remainder ;AC000;
166 ADC [HIGH_SECTOR_TEMP
],0 ;F.C. >32mb ;AN000;
168 PUSH [HIGH_SECTOR_TEMP
] ;F.C. >32mb ;AN000;
169 POP WORD PTR [VALSEC
+2] ;F.C. >32mb ;AN000;
170 MOV WORD PTR [VALSEC
],AX ;Number of sectors that have been written
172 MOV WORD PTR [GROWCNT
],AX
173 MOV WORD PTR [GROWCNT
+2],AX
176 MOV DI,[HIGH_SECTOR
] ;F.C. >32mb ;AN000;
177 CMP DI,[HIGH_SECTOR_TEMP
] ;F.C. >32mb ;AN000;
178 JB NOGROW
;F.C. >32mb ;AN000;
179 JZ lowsec
;F.C. >32mb ;AN000;
180 SUB BX,CX ;F.C. >32mb ;AN000;
181 SBB DI,[HIGH_SECTOR_TEMP
] ;F.C. >32mb di:bx no. of sectors ;AN000;
182 JMP yesgrow
;F.C. >32mb ;AN000;
185 SUB BX,CX ; Number of full sectors
191 MUL ES:[BP.dpb_sector_size
] ; Bytes of full sector growth
192 MOV [HIGH_SECTOR
],DX ;F.C. >32mb save dx ;AN000;
193 MOV [HIGH_SECTOR_TEMP
],AX ;F.C. >32mb save ax ;AN000;
194 MOV AX,DI ;F.C. >32mb ;AN000;
195 MUL ES:[BP.dpb_sector_size
] ;F.C. >32mb do higher word multiply ;AN000;
196 ADD AX,[HIGH_SECTOR
] ;F.C. >32mb add lower value ;AN000;
197 MOV DX,AX ;F.C. >32mb DX:AX is the result of ;AN000;
198 MOV AX,[HIGH_SECTOR_TEMP
] ;F.C. >32mb a 32 bit multiply ;AN000;
200 SUB AX,CX ; Take off current "tail"
201 SBB DX,0 ; 32-bit extension
202 ADD AX,BX ; Add on new "tail"
203 ADC DX,0 ; ripple tim's head off
211 MOV [FSeek_logclus
],DX ; delete EOF (FFFFH)
213 invoke FastSeek_Truncate
;
219 DOSAssume
CS,<DS>,"DiskWrite/WrtErr"
222 MOV AH,0FH ;MS. write/data/fail/abort ;AN000;
224 MOV AL,[THISDRV
] ;MS. ;AN000;
225 CALL File_Handle_Fail_Error
;MS. issue disk full I24
226 MOV CX,0 ;No bytes transferred
227 ; XOR CX,CX ; will be deleted
229 Assert ISSFT
,<ES,DI>,"DiskWrite/WrtErr"
243 MOV WORD PTR [GROWCNT
],AX
244 MOV WORD PTR [GROWCNT
+2],DX
247 MOV CX,[CLUSNUM
] ; First cluster accessed
253 MOV [FSeek_logclus
],AX ; set up last position
254 SUB AX,DX ; Last cluster minus current cluster
255 JZ DOWRT
; If we have last clus, we must have first
256 JCXZ HAVSTART
; See if no more data
257 PUSH CX ; No. of clusters short of first
261 CMP [CLUSNUM
],0 ;FS. null file ;AN000;
262 JZ NULL_FILE
;FS. yes ;AN000;
263 MOV [FSeek_logclus
],DX ;FS. delete EOF (FFFFH) ;AN000;
264 INC [FSeek_logclus
] ;FS. ;AN000;
265 invoke FastSeek_Truncate
;FS. ;AN000;
277 MOV [FSeek_logclus
],DX ;
278 ADD [FSeek_logclus
],CX ; set up last position
296 ADD WORD PTR [SECPOS
],AX
297 ADC WORD PTR [SECPOS
+2],0 ;F.C. >32mb ;AN000;
302 MOV BYTE PTR [TRANS
],1 ; A transfer is taking place
315 Assert ISDPB
,<ES,BP>,"DiskWrite/WrtLp"
316 MOV AL,ES:[BP.dpb_drive
]
317 MOV [SC_DRIVE
],AL ;LB. save it for INVALIDATE_SC ;AN000;
319 PUSH [HIGH_SECTOR
] ;LB. ;AN000;
320 SCANNEXT: ;LB. ;AN000;
321 invoke GETCURHEAD
;LB. ;AN000;
323 NEXTBUFF: ; Search for buffers
324 CMP [SC_CACHE_COUNT
],0 ;LB. SC support ? ;AN000;
325 JZ nosc
;LB. no ;AN000;
326 PUSH AX ;LB. save reg ;AN000;
327 PUSH CX ;LB. save reg ;AN000;
328 PUSH DX ;LB. save reg ;AN000;
329 invoke INVALIDATE_SC
;LB. invalidate SC ;AN000;
330 POP DX ;LB. save reg ;AN000;
331 POP CX ;LB. save reg ;AN000;
332 POP AX ;LB. save reg ;AN000;
334 CALL BUFF_RANGE_CHECK
;F.C. >32mb ;AN000;
335 JNC inrange2
;F.C. >32mb ;AN000;
336 mov DI,[DI.buf_next
] ;LB. get next buffer 1/19/88 ;AN000;
337 JMP DONEXTBUFF
;LB. ;AN000;
339 TEST [DI.buf_flags
],buf_dirty
;LB. if dirty ;AN000;
340 JZ not_dirty
;LB. ;AN000;
341 invoke DEC_DIRTY_COUNT
;LB. then decrement dirty count ;AN000;
343 MOV WORD PTR [DI.buf_ID
],(buf_visit
SHL 8) OR 0FFH ; Free the buffer, it is being over written
346 CMP DI,[FIRST_BUFF_ADDR
] ;LB. end of chain ;AN000;
347 JNZ NEXTBUFF
;LB. no ;AN000;
348 ADD DX,1 ;LB. next sector number ;AN000;
349 ADC [HIGH_SECTOR
],0 ;LB. ;AN000;
350 LOOP SCANNEXT
;LB. check again ;AN000;
351 POP [HIGH_SECTOR
] ;LB. ;AN000;
352 POP CX ;LB. get count back ;AN000;
356 MOV DS,WORD PTR [DMAADD
+2]
357 MOV [ALLOWED
],allowed_RETRY
+ allowed_FAIL
+ allowed_IGNORE
361 cmp [BUF_EMS_MODE
], -1
364 call restore_user_map
373 cmp [BUF_EMS_MODE
], -1
387 INC [LASTPOS
] ; We'll be using next cluster
402 Assert ISSFT
,<ES,DI>,"DiskWrite/FinWrt"
403 MOV AX,WORD PTR [GROWCNT
]
404 MOV CX,WORD PTR [GROWCNT
+2]
409 ADD WORD PTR ES:[DI.sf_size
],AX
410 ADC WORD PTR ES:[DI.sf_size
+2],CX
412 ; Make sure that all other SFT's see this growth also.
421 transfer SETCLUS
; ES:DI already points to SFT
424 transfer SET_ACC_ERR_DS
434 MOV BX,ES:[BP.dpb_sector_size
] ;F.C. >32mb ;AN000;
435 CALL DIV32
;F.C. >32mb ;AN000;
436 POP BX ;F.C. >32mb ;AN000;
437 CALL SHR32
;F.C. >32mb ;AN000;
446 MOV [FSeek_logclus
],DX ; truncate clusters starting from DX
447 invoke FastSeek_Truncate
451 JC WRTERRJ
;;;;;;;;; disk full
454 Assert ISSFT
,<ES,DI>,"DiskWrite/update"
455 MOV AX,WORD PTR [BYTPOS
]
456 MOV WORD PTR ES:[DI.sf_size
],AX
457 MOV AX,WORD PTR [BYTPOS
+2]
458 MOV WORD PTR ES:[DI.sf_size
+2],AX
460 ; Make sure that all other SFT's see this growth also.
472 ;;;;;;;;;;;;;;;; 7/18/86
485 Assert ISSFT
,<ES,DI>,"DiskWrite/KillFil"
486 MOV ES:[DI.sf_cluspos
],BX
487 MOV ES:[DI.sf_lstclus
],BX
488 XCHG BX,ES:[DI.sf_firclus
]
491 invoke Delete_FSeek
; delete fastseek entry
495 ;; 10/23/86 FastOpen update
496 PUSH ES ; since first cluster # is 0
497 PUSH BP ; we must delete the old cache entry
501 LES BP,[THISDPB
] ; get current DPB
502 MOV DL,ES:[BP.dpb_drive
] ; get current drive
503 MOV CX,BX ; first cluster #
504 MOV AH,2 ; delete cache entry by drive:firclus
505 invoke FastOpen_Update
; call fastopen
511 ;; 10/23/86 FastOpen update
521 Break <DIV32
-- PERFORM
32 BIT DIVIDE
>
524 ; DX:AX = 32 bit dividend BX= divisor
526 ; Perform 32 bit division
528 ; [HIGH_SECTOR]:AX = quotiend , DX= remainder
531 ASSUME
DS:NOTHING
,ES:NOTHING
534 PUSH AX ;F.C. >32mb ;AN000;
535 MOV AX,DX ;F.C. >32mb ;AN000;
536 XOR DX,DX ;F.C. >32mb ;AN000;
537 DIV BX ;F.C. >32mb ;AN000;
538 MOV [HIGH_SECTOR
],AX ;F.C. >32mb ;AN000;
539 POP AX ;F.C. >32mb ;AN000;
542 DIV BX ; AX=last sector accessed
547 Break <SHR32
-- PERFORM
32 BIT SHIFT RIGHT
>
550 ; [HIGH_SECTOR]:AX = 32 bit sector number
552 ; Perform 32 bit shift right
557 ASSUME
DS:NOTHING
,ES:NOTHING
560 MOV CL,ES:[BP.dpb_cluster_shift
]
562 entry ROTASHFT
;F.C. >32mb ;AN000;
563 OR CX,CX ;F.C. >32mb ;AN000;
564 JZ norota
;F.C. >32mb ;AN000;
566 CLC ;F.C. >32mb ;AN000;
567 RCR [HIGH_SECTOR
],1 ;F.C. >32mb ;AN000;
568 RCR AX,1 ;F.C. >32mb ;AN000;
569 LOOP ROTASHFT2
;F.C. >32mb: ;AN000;
576 ; Issue File Handle Fail INT 24 Critical Error
577 ; Input: Disk_Full=0 ok
579 ; Function: issue critical error for disk full or EOF error
581 ; OutPut: carry clear , no I24
582 ; carry set, fail from I24
584 procedure File_Handle_Fail_Error
,NEAR ;AN000;
585 ASSUME
ES:NOTHING
,DS:NOTHING
;AN000;
587 CMP [DISK_FULL
],0 ;MS. disk full or EOF ;AN000;
588 JZ Fexit
;MS. no ;AN000;
589 TEST [DOS34_FLAG
],Disable_EOF_I24
;MS. check input status ? ;AN000;
590 JNZ Fexit
;MS. yes ;AN000;
592 LES DI,[THISSFT
] ;MS. get current SFT ;AN000;
593 ; LES DI,ES:[DI.sf_DEVPTR];MS. get device header ;AN000;
594 TEST ES:[DI.sf_flags
],Handle_Fail_I24
;MS. gen I24 ? ;AN000;
595 JZ Fexit
;MS. no ;AN000;
596 PUSH DS ;MS. save DS ;AN000;
597 TEST AH,1 ;MS. READ ? ;AN000;
598 JZ readeof
;MS. yes ;AN000;
599 MOV [EXTERR
],error_Handle_Disk_Full
;MS. set extended error ;AN000;
600 JMP SHORT errset
;MS. set extended error ;AN000;
602 MOV [EXTERR
],error_Handle_EOF
;MS. set extended error ;AN000;
604 MOV [EXTERR_CLASS
],errCLASS_OutRes
;MS. set class ;AN000;
605 MOV [EXTERR_ACTION
],errACT_Abort
;MS. set action ;AN000;
606 MOV [EXTERR_LOCUS
],errLOC_Unk
;MS. set locus ;AN000;
607 MOV word ptr [EXITHOLD
+ 2],ES ;MS. save es:bp in exithold ;AN000;
608 MOV word ptr [EXITHOLD
],BP ;MS. ;AN000;
609 TEST ES:[DI.sf_flags
],devid_device
;MS. device ? ;AN000;
610 JNZ chardev2
;MS. yes ;AN000;
611 LDS SI,ES:[DI.sf_DEVPTR
] ;MS. get dpb ;AN000;
612 LDS SI,[SI.dpb_driver_addr
] ;MS. get drive device haeder ;AN000;
613 JMP SHORT doi24
;MS. gen I24 ? ;AN000;
615 LDS SI,ES:[DI.sf_DEVPTR
] ;MS. get chr dev header ;AN000;
617 MOV BP,DS ;MS. bp:si -> device header ;AN000;
618 MOV DI,error_I24_gen_failure
;MS. general error ;AN000;
619 invoke NET_I24_ENTRY
;MS. issue I24 ;AN000;
620 STC ;MS. must be fail ;AN000;
621 POP DS ;MS. restore DS ;AN000;
622 MOV AX,[EXTERR
] ;MS. set error ;AN000;
623 JMP SHORT Fend
;MS. exit ;AN000;
625 CLC ;MS. clear carry ;AN000;
629 EndProc File_Handle_Fail_Error
;AN000;
632 Break <BUFF_RANGE_CHECK
- buffer range checkink
>
635 ; DS:DI -> buffer. AL= drive #
636 ; [HIGH_SECTOR]:DX = sector #
638 ; check if sector is in the buffer
640 ; carry clear= in the range
641 ; set = not in the range
643 procedure BUFF_RANGE_CHECK
,NEAR
644 ASSUME
DS:NOTHING
,ES:NOTHING
646 CMP WORD PTR [DI.buf_sector
],DX ;AN000;
647 JNZ DONEXTBUFF2
; not this sector ;F.C. >32mb ;AN000;
648 MOV SI,[HIGH_SECTOR
] ;F.C. >32mb ;AN000;
649 CMP WORD PTR [DI.buf_sector
+2],SI ;F.C. >32mb ;AN000;
650 JNZ DONEXTBUFF2
; Not for this drive
652 JZ secfound
; Buffer has the sector ;AN000;
658 EndProc BUFF_RANGE_CHECK