;    File              : $ERROR.A86$
;
;    Description       :
;
;    Original Author   : DIGITAL RESEARCH
;
;    Last Edited By    : $CALDERA$
;
;-----------------------------------------------------------------------;
;    Copyright Work of Caldera, Inc. All Rights Reserved.
;      
;    THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
;    PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
;    ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
;    WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
;    THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
;    HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
;    AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
;    AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
;    COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
;    CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
;    TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
;    CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
;    AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
;    CIVIL LIABILITY.
;-----------------------------------------------------------------------;
;
;    *** Current Edit History ***
;    *** End of Current Edit History ***
;    $Log$
;    ERROR.A86 1.17 94/12/02 11:01:03
;    added logical error entry 
;    ERROR.A86 1.16 93/11/26 15:51:29 
;    Update char_error so ES:SI -> device driver header itself
;    ERROR.A86 1.14 93/09/09 22:36:26
;    Int 21/59 uses error stack (for benefit of Lantastic)
;    ERROR.A86 1.13 93/09/03 20:28:11
;    Add "no critical errors" support (int 21/6C)
;    ENDLOG
;
;	This file contains the Error handling routines for PCMODE
;	When a function encounters an error it jumps to the ERROR_EXIT
;	function which will process the error consistantly. FCB_ERROR_EXIT
;	is a special case of ERROR_EXIT where the error code is not returned
;	directly to the user but is still saved for func59
;

	include pcmode.equ
	include	fdos.def
	include i:msdos.equ
	include i:mserror.equ
	include i:psp.def
	include	i:char.def
	include	i:reqhdr.equ

;
ERR_TBL_CODE	equ	byte ptr 0	; Error Code in Table
ERR_TBL_CLASS	equ	byte ptr 1	; Error Class entry in Table
ERR_TBL_ACTION	equ	byte ptr 2	; Error Action entry in Table
ERR_TBL_LOCUS	equ	byte ptr 3	; Locus entry in table
ERR_TBL_LEN	equ	4		; 4 bytes per entry
;
PCM_CODE	CSEG	BYTE
	extrn	get_dseg:near
	extrn	do_int24:near
	extrn	reload_registers:near
	extrn	return_AX_CLC:near
;
;	*****************************
;	***    DOS Function 59    ***
;	***   Get Extended Error  ***
;	*****************************
;
	Public	func59

func59:
	les	di,error_dev		; Return device driver address
	mov	bh,error_class		; return the Error Class
	mov	bl,error_action		;        the Action Code
	mov	ch,error_locus		;        the Locus Code
	mov	ax,error_code		;        the Error Code
	
	lds	si,int21regs_ptr	; point to user stack
	mov	reg_ES[si],es
	mov	reg_DI[si],di
	mov	reg_BX[si],bx
	mov	reg_CX[si],cx
	push ss ! pop ds
	jmp	return_AX_CLC	

eject
;	On Entry:-	AX == Internal Error Number 
;
;	On Exit:-	None
;	CY set if error should be returned
;	CY clear if it should be ignored
;
	Public	error_exit
error_exit:
	cmp	internal_flag,0			; If this is an internal
	 jnz	error_ret			; do not generate a critical
	call	disk_error			; error
	 jnz	error_r10			; No Error Occured or Ignored
	ret					; in critcal error handler

;
;	Return the error code to the user and DO NOT generate any
;	critical errors.
;
;	On Entry:-	AX == Internal Error Number 
;
;	On Exit:-	None
;
	Public	error_ret
error_ret:
	call	set_error			; the internal error code
error_r10:					; otherwise negate
	les	di,int21regs_ptr
	or	es:reg_FLAGS[di],CARRY_FLAG	; set the "users" carry Flag
	stc					; also set real one
if offset reg_AX EQ 0
	stosw					; save return code
else
	mov	es:reg_AX[di],ax
endif
	ret

;
;	On Entry:-	AX == Internal Error Number 
;
;	On Exit:-	None
;
	Public	fcberror_exit
fcberror_exit:
	call	disk_error		; Process the error code generating
	 jz	fe_e10			;  a critical error is required
	mov	al,0FFh			; on FCB error return AL = FF
fe_e10:
	ret

eject
;	WARNING - may be called from FDOS with DS = SYSDAT
;
;	CHAR_ERROR is called when any character device function generates
;	an error. First CHAR_ERROR sets the correct parameters for Get 
;	Extended Error. Then it generates a Critical Error by calling
;	DO_INT24.
;
;	Entry:-		ES:SI	-> device driver header
;			SS:BX	-> RH_
;			AX	= RH_STATUS
;
;	Exit		AL	Error Action
;
	Public char_error
char_error:
	test	ss:valid_flg,NO_CRIT_ERRORS
	 jz	char_e10
	mov	al,ERR_FAIL		; no critical errors allowed
	ret				;  so just fail things
char_e10:
	push	ds
	push	es
	push	bx
	push	cx
	push	dx
	push	si
	push	di
	push ss ! pop ds		; DS -> our data now
	mov	word ptr error_dev+0,si	; save the device driver address
	mov	word ptr error_dev+2,es	;  and then initialise the FUNC59
	push	es			;  data areas
	and	ax,007Fh		; Mask the Unused Bits
	or	ah,80h+OK_RIF		; Retry/Ignore/Abort/Fail allowable
	cmp	ss:RH_CMD,CMD_OUTPUT	; is this a read or write failure ?
	 jne	char_e20
	inc	ah			; 01 is a Write Failure
char_e20:
	mov	rwmode,ah		;  
	push	ax			; save for int 24
	cbw				; zero AH again
	neg	ax			; convert to an internal error
	add	ax,ED_PROTECT		;  code for set_error
	mov	cl,LOC_CHAR
	call	set_error
	add	ax,ED_PROTECT		; convert to hardware error
	xchg	ax,di			; DI == hardware error
	pop	ax
	pop	es
	call	do_int24		;  execute INT 24
	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	es
	pop	ds
	ret

eject
;
;	DISK_ERROR gains control after any DOS disk based function
;	has been executed which generates an error. First ERROR set the
;	correct parameters for Get Extended Error. Then it determines if
;	the current error should generate a Critical Error and calls 
;	DO_INT24 if TRUE.
;
;
; On Entry:
;	AX	Internal Error Code
;
; On Exit:
;	AX	0 if no error to return (Ignore)
;	AX	DOS Error Code
;	ZF	reflects AX
;
disk_error:
	mov	cl,LOC_CHAR			; assume character device
						; determine if the error is
	test	rwmode,80h			;  caused by a character or
	 jnz	disk_e10			;  block device and set the
	mov	cl,LOC_BLOCK 			;  the critical error locus
disk_e10:
	call	set_error			; record error information
	 jz	disk_e50			; just return a logical error.

	add	ax,ED_PROTECT			; Convert to HardWare Error
	mov	di,ax				; DI == HardWare Error
						; Now get the information
	mov	ah,rwmode			; about the error location

	and	ah,not OK_RIF			; mask the all responses
;	mov	al,valid_flg			; valid flag contains no crit
;	and	al,not NO_CRITICAL_ERRORS	;  errors bit, but if that was
;	or	ah,al				;  set we wouldn't be here
	or	ah,valid_flg			; or in valid responses

	cmp	bx,ED_GENFAIL			; if it's general failure
	 jne	disk_e20			;  we cannot Ignore the error
	and	ah,not OK_IGNORE		;  but must Abort/Fail/Retry
disk_e20:					;  as appropriate

	mov	al,err_drv			; get the failing drive
	mov	error_drive,al			;  and save locally

	les	si,error_dev			; get device driver header

						; are we are a character device
	test	ah,80h				;  as these have handled at a
	 jnz	disk_e40			;  lower level and just need
						;  to be FAILed back to caller

	call	do_int24			; Execute INT 24

	mov	bl,al				; Copy reponse into BL	

	xor	ax,ax				; Assume Ignore Error
	cmp bl,ERR_IGNORE ! jz disk_e50		; Ignore the Error

	cmp bl,ERR_FAIL ! jz disk_e40		; If not FAIL then RETRY
	call	reload_registers		; get back entry registers
	mov	FD_FUNC,ax			; save AX for a moment
	mov	al,ah				; set up function number
	xor	ah,ah				; in AX
	xchg	ax,FD_FUNC			; save for use by FDOS
	xor	ah,ah				; zero AH 'cause it's handy
	mov	sp,retry_sp			; Must be RETRY so reset the
	jmp	retry_off			; STACK and IP

disk_e40:
;
;	When a Critical Error is FAILED then we do the following
;	if (extended error_code <= ED_SHAREFAIL) then
;		ret = ED_ACCESS;
;	else
;		ret = ED_FAIL;
;	extended error_code = ED_FAIL;
;	return(ret);
;
; nb. above proto-code is at the request of ant
;
	mov	ax,-(ED_FAIL)		; always return ED_FAIL in the
	xchg	ax,error_code		;  extended error_code
	cmp	ax,-(ED_SHAREFAIL)	; did we FAIL on sharing conflict ?
	mov	ax,-(ED_ACCESS)		; assume we did and prepare to return
	 jae	disk_e50		;  ED_ACCESS
	mov	al,-(ED_FAIL)		; woops, return ED_FAIL after all
disk_e50:
	or	ax,ax			; NZ if error return required
	ret

eject
;
;	On Entry:-	AX	Internal Error Code
;			CL	Critical Error Locus
;
;	On Exit:-	AX	DOS Error Code
;			BX	Internal Error Code
;			ZF	set on logical error
set_error:
	mov	bx,ax			; by default we return the raw error
	mov	di,offset critical_error; Scan for critical Errors First
	call	scan_error_table	; look for a matching error
	 jc	set_logical_error
	mov	locus,cl		; Save the critical error LOCUS
	cmp	ax,ED_SHAREFAIL		; watch out for SHAREFAIL - the action
	 jne	set_e10			;  depends on the caller
;
; ED_SHAREFAIL will return ED_ACCESS if the result of an attempt to open
; a file in shared mode, otherwise (FCB's and compatibility) it will
; generate a critical error.
;
	mov	bx,ED_GENFAIL		; assume we want a critical error
	cmp	FD_FUNC,MS_X_OPEN	; is it a shared open ?
	 jnz	set_error_data
	test	FD_MODE,0$111$0$000b	;  mode
	 jz	set_error_data
	jmps	set_e30			; return a logical "access denied"

set_e10:
	cmp	ax,ED_LOCKFAIL		; have we a lockfail error ?
	 jne	set_e20
;
; ED_LOCKFAIL returns ED_ACCESS if a lock attempt fails, but a critical error
; on an attempt to read/write a locked region.
;
	cmp	FD_FUNC,FD_LOCK		; was it a result of specific lock
	 je	set_logical_error	;  call ? yes, it's a logical error
	mov	bx,ED_GENFAIL		; no, generate a critical error
	jmps	set_error_data

set_e20:
	test	valid_flg,NO_CRIT_ERRORS
	 jz	set_error_data		; do we allow critical errors ?
	mov	ax,ED_ACCESS		; extended error code is Access Denied
set_e30:
	mov	bx,ED_ACCESS		; return access denied to caller
;	jmps	set_logical_error

set_logical_error:
	xor	di,di
	mov	word ptr error_dev+0,di	; must be a logical error so force
	mov	word ptr error_dev+2,di	;  the ERROR_DEV to 0000:0000
	mov	di,offset logical_error	; scan the Logical error table 
	call	scan_error_table
	cmp	ax,ED_NETACCESS		; if it's a networked access denied
	 jne	set_error_data		;  turn it into ordinary one
	mov	bx,ED_ACCESS		; return a logical "access denied"
;	jmps	set_error_data

set_error_data:
; On Entry:
;	AX = Internal Error Code for extended error
;	BX = Internal Error Code for returned error
;	CS:DI -> error table entry
; On Exit:
;	AX = DOS Error Code
;	BX = Internal Error Code
;	ZF set on logical error
;
	neg	ax
	mov	error_code,ax		; Save the Error Code
	mov	al,cs:ERR_TBL_CLASS[di]
	mov	error_class,al		; Save the Class
	mov	al,cs:ERR_TBL_ACTION[di]
	mov	error_action,al		; Save the Action
	mov	al,cs:ERR_TBL_LOCUS[di]	; Get the Locus
	mov	error_locus,al		; Save the Locus and then check
	test	al,al			; if the function overrides
	 jnz	set_d10			; this value
	mov	al,locus		; Get the Global Locus value
	mov	error_locus,al		; set by the calling function
set_d10:				; and save for FUNC 59
	mov	ax,bx			; Return to the caller with
	neg	ax			; the DOS error code.
	mov	di,word ptr error_dev	; set ZF if logical error
	or	di,word ptr error_dev+2	; error_dev = 0:0
	ret

scan_error_table:
	cmp	cs:ERR_TBL_CODE[di],0
	 je	scan_et10		; Check for the end of the list
	cmp	al,cs:ERR_TBL_CODE[di]
	 je	scan_et20
	add	di,ERR_TBL_LEN
	jmps	scan_error_table
scan_et10:
	stc
scan_et20:
	ret


eject
PCM_RODATA	CSEG	WORD
logical_error	rb	0
;
;	Internal Code	Error Class	Error Action	Error Locus
;	=============	===========	============	===========
   db   ED_FUNCTION,	CLASS_APPLIC,	ACT_ABORT,	00
   db   ED_FILE,	CLASS_LOST,	ACT_USER,	LOC_BLOCK
   db   ED_PATH,	CLASS_LOST,	ACT_USER,	LOC_BLOCK
   db   ED_HANDLE,	CLASS_RESOURCE,	ACT_ABORT,	LOC_UNKNOWN
   db   ED_ACCESS,	CLASS_AUTHOR,	ACT_USER,	00
   db   ED_NETACCESS,	CLASS_AUTHOR,	ACT_USER,	00
   db   ED_H_MATCH,	CLASS_APPLIC,	ACT_ABORT,	LOC_UNKNOWN
   db   ED_DMD,		CLASS_APPLIC,	ACT_TERM,	LOC_MEMORY
   db   ED_MEMORY,	CLASS_RESOURCE,	ACT_ABORT,	LOC_MEMORY
   db   ED_BLOCK,	CLASS_APPLIC,	ACT_ABORT,	LOC_MEMORY
   db   ED_ENVIRON,	CLASS_APPLIC,	ACT_ABORT,	LOC_MEMORY
   db   ED_FORMAT,	CLASS_FORMAT,	ACT_USER,	LOC_UNKNOWN
   db   ED_ACC_CODE,	CLASS_APPLIC,	ACT_ABORT,	LOC_UNKNOWN
   db   ED_DATA,	CLASS_FORMAT,	ACT_ABORT,	LOC_UNKNOWN
   db   ED_DRIVE,	CLASS_LOST,	ACT_USER,	LOC_BLOCK
   db   ED_DIR,		CLASS_AUTHOR,	ACT_USER,	LOC_BLOCK
   db   ED_DEVICE,	CLASS_UNKNOWN,	ACT_USER,	LOC_BLOCK
   db   ED_ROOM,	CLASS_LOST,	ACT_USER,	LOC_BLOCK
   db   ED_EXISTS,	CLASS_EXISTS,	ACT_USER,	LOC_BLOCK
   db   ED_STRUCT,	CLASS_RESOURCE,	ACT_ABORT,	00
   db   ED_PASSWORD,	CLASS_AUTHOR,	ACT_USER,	LOC_UNKNOWN
   db   ED_MAKE,	CLASS_RESOURCE,	ACT_ABORT,	LOC_BLOCK
;; db   ED_NET,		CLASS_FORMAT,	ACT_USER,	LOC_NET
   db   ED_ASSIGN,	CLASS_EXISTS,	ACT_USER,	LOC_NET
   db   ED_PARAM,	CLASS_FORMAT,	ACT_USER,	LOC_UNKNOWN
   db   ED_FAIL,	CLASS_UNKNOWN,	ACT_ABORT,	LOC_UNKNOWN
   db   ED_SHAREFAIL,	CLASS_LOCKED,	ACT_DELAY,	LOC_BLOCK
   db   ED_LOCKFAIL,	CLASS_LOCKED,	ACT_DELAY,	LOC_BLOCK
   db   ED_NOLOCKS,	CLASS_RESOURCE,	ACT_ABORT,	LOC_MEMORY
   db   00,		CLASS_SYSTEM,	ACT_TERM,	LOC_UNKNOWN

critical_error	rb	0
;
;	Internal Code	Error Class	Error Action	Error Locus
;	=============	===========	============	===========
   db   ED_PROTECT,	CLASS_MEDIA,	ACT_URETRY,	LOC_BLOCK
   db   ED_BADUNIT,	CLASS_INTERNAL,	ACT_TERM,	LOC_UNKNOWN
   db   ED_NOTREADY,	CLASS_HARDWARE,	ACT_URETRY,	00
   db   ED_BADCMD,	CLASS_INTERNAL,	ACT_TERM,	LOC_UNKNOWN
   db   ED_BADDATA,	CLASS_MEDIA,	ACT_ABORT,	LOC_BLOCK
   db   ED_BADSEEK,	CLASS_HARDWARE,	ACT_RETRY,	LOC_BLOCK
   db   ED_BADMEDIA,	CLASS_MEDIA,	ACT_URETRY,	LOC_BLOCK
   db   ED_RNF,		CLASS_MEDIA,	ACT_ABORT,	LOC_BLOCK
   db   ED_NOPAPER,	CLASS_TEMP,	ACT_URETRY,	LOC_CHAR
   db   ED_WRFAIL,	CLASS_HARDWARE,	ACT_ABORT,	00
   db   ED_RDFAIL,	CLASS_HARDWARE,	ACT_ABORT,	00
   db   ED_GENFAIL,	CLASS_UNKNOWN,	ACT_ABORT,	00
   db   ED_SHAREFAIL,	CLASS_LOCKED,	ACT_DELAY,	LOC_BLOCK
   db   ED_LOCKFAIL,	CLASS_LOCKED,	ACT_DELAY,	LOC_BLOCK
   db   ED_NOFCBS,	CLASS_APPLIC,	ACT_ABORT,	LOC_UNKNOWN

default_error	rb	0
   db   00,		CLASS_SYSTEM,	ACT_TERM,	LOC_UNKNOWN

PCMODE_DATA	DSEG	WORD
	extrn	indos_flag:byte
	extrn	internal_flag:byte
	extrn	int21regs_ptr:dword
	extrn	current_psp:word
	extrn	retry_off:word, retry_sp:word
	extrn	valid_flg:byte
	extrn	error_locus:byte	; Error Locus
	extrn	error_code:word		; DOS format error Code
	extrn	error_action:byte	; Error Action Code
	extrn	error_class:byte	; Error Class
	extrn	error_dev:dword		; Failing Device Header
	extrn	error_drive:byte	; Failing Disk Drive
	extrn	err_drv:byte
	extrn	locus:byte
	extrn	rwmode:byte
end
