	.TITLE log - LOG messages for scli
	.IDENT /1.24/

.REM |
*+	log - LOG messages for scli

	File:log.mac
	Version: 1.24
	Author:
	Last Edit: 27-DEC-1985 11:19:08 
	Last Update: 27-Dec-1985 11:39:14 
		     Log errors using smsg$ instead of rpoi of mcr


*-
|

	.LIBRARY /LB:[1,1]GLMAC.MLB/
	.MCALL push,pop,return
	.mcall	qiow$s,dir$,alun$s,gtim$s,smsg$
	.mcall	qio$,qiow$,astx$s,mrkt$,wtse$,cmkt$
	.mcall	rpoi$

	.SBTTL LOCAL DATA

	.psect ldat,d,lcl,con
;
; use this psect for scratch storage - it is not guaranteed to be saved
; across calls to the module
;
;@MARK@

;
; fake r5 argument list for internal  error reporting
;   -- allows us to report our own errors (or at least try!)
errs:	.word	0		; internal error flags
	; bits:   
	er.ssm = 1 	; smsg error
	er.cot = 2	; cot error
	er.p2 = 4	; 1 -> on loop-back pass
;
; point r5 at erlst, then loop back to start
;
erlst:	.word	0	; put number of args here
	.word	9.	; internal error code
	.word	ercod	; 
	.word	nump	; 
erpl:	.blkw	3	; space for params

ercod:	.word	0	; put internal error code here
nump:	.word	0	; put number extra params here

smsp0:	.word	0		; holds sms error dsw
cotp0:	.word	0		; holds cot error dsw
cotp1:	.word	0		; holds cot iosb word 1
cotp2:	.word	0		; holds cot iosb word 2
savr5:	.word	0	; saved original return address
;
; end of internal error stuff
;

msgnum:	.word	0		; message number
argblk:	.blkw	10		; ten words for $edmsg arguments
buf0:	.ascii	/SSM /		; for rpoi
buff:	.blkb	134.		; buffer for building output
buflen:	.word	0		; length of buffer
	;
	; NOTE: max buffer length for the RPOI flavor of SSM logging
	;	is 72. plus the SSM prefix!
	; 

	.psect data,d,gbl,con
;
; use this psect for module-specific data which must be retained across
; calls to the module
;

;
; be sure to include the message definition file
;
	.include /logmsg.mac/

	.psect dpbs d,rw,lcl,con
;
; this psect contains the static dpbs
;
rpoi:	rpoi$ MCR...,,,1,1,,buf0,,,TT,0
smsg:	smsg$ sm.ser,buff		; system service message
cqio:	qio$ io.wvb,2,2,,cotp1,qast,<buff,0,40>	; lun 2 QIO
cqiok:	qio$ io.kil,2,10		; kill io on lun 2
mrkt:	mrkt$ ,15.,2,mtast		; 15 second wait
canmt:	cmkt$ ,mtast			; cancel mrkt
wtse:	wtse$ 2				; wait for efn 2

	.PSECT
; code goes in the blank psect

	.SBTTL LOG - Log messages 

.REM |
	LOG logs messages to the error logging file (via SMSG$)
	and/or to the console (CO). 

	For testing, if logtt3 is defined (just before entry point), 
	logs all messages in raw form to LUN #3, which is hardcoded
	to TT3. 

	Messages are identified by number. A variable number of 
	parameters are required depending upon the message. 
	For message numbers, required parameters, see module
	LOGMSG.MAC. Message number is a pass-by-value. All of
	the variable params are pass by reference. 

	CALL
		call r5,log,<msg,params>
		msg = message number (messages defined above)
		params = parameters dependant upon message number
			 see individual message definition above

	INPUT
		params on r5 stack

	OUTPUT
		message formatted and logged as indicated by flags word
		in message database (defined above)

	REGS
		preserved

	CALLS
		uses $EDMSG from SYSLIB to format messages
|

;;;	logtt3 = 0	; define for test mode dump to tt3:

LOG::	
	push	<r0,r1,r2>
	clr	errs		; no errors yet
10$:	; this is return-entry point for 'calling ourselves'
;
; all messages share a fixed preamble, consisting of "SECURE:" and
; the date-time. Set this up now in buff
;
; bypassed because both COT and Errlog timestamp messages
; we may need to put back in, if we must work to CO: (vs cot)
; with timestamps.
;;	gtim$s #argblk		; get date and time in argblk
;;	bcc	200$		; br if no error
;;
;;	mov	#argblk, r0	; if error, clear out date-time
;;	mov	#8., r1		; word count
;;100$:	clr	(r0)+		; clear out date-time
;;	sob	r1, 100$

200$:	mov	#buff, r0	; set up for first $edmsg
	mov	#premsg, r1	; ... control string
	mov	#argblk, r2	; ... argument block
	.globl	$edmsg
	call	$edmsg		; format the preamble
	mov	r1, buflen	; save first length
;***** NOTE *****
;* from here on, preserve r0, it is the buffer pointer!
;****************

;
; now, pull off the arguments. the first argument is the number
; of remaining arguments. The only required arg is the message
; number. 
; 
	mov	(r5)+, r1	; r1=number of args
	mov	(r5)+, msgnum	; get message number (always present)
	dec	r1		; count remaining args
	beq	350$		; br if none
;	
; copy remaining args to the arg block - all but msgnum are
; 	pass by reference
;
	mov	#argblk, r2
300$:	mov	@(r5)+, (r2)+	; copy an arg
	sob	r1, 300$	; copy remaining args
;
; obtain control string (msgx:) from message number
;
350$:	mov	msgnum, r1
	dec	r1		; table starts at "1"
	asl	r1		; make offset
	add	#msgtbl, r1	; point into table
	cmp	#msgtnd, r1	; off end?
	blos	400$		; yes - br to illegal msg
	mov	(r1), r1	; pick up pointer to control string
	br	500$		; and join common code

	; 
	; illegal message code just fakes out an internal error,
	; and loops back to log that. The error number is 1.
	; 
400$:	mov	#msg9, r1	; point to 'internal error'
	mov	#argblk, r2	; point to argblk
	mov	#1, (r2)	; stuff error number
	mov	#1, 2(r2)	; one more param
	mov	msgnum, 4(r2)	; bad message number
				; and fall thru to format code
	mov	#9., msgnum	; now working on different message
;
; r0,r1 now set for $edmsg
;
500$:	mov	#argblk, r2	; complete setup
	call	$edmsg		; format remainder of message
	add	r1, buflen	; total up length
;
; now examine control byte, and send the thing out
;
	mov	#msgflg, r2	; point to flag byte table
	add	msgnum, r2	; offset into table
	dec	r2		; back off 
	bitb	#ms.cot, (r2)	; output to co?
	beq	1000$		; no - br
;*** do it to co
	mov	#cqio, r1	; point to qio dpb
	mov	buflen, <q.iopl+2>(r1)	; stuff length
	dir$	#cqio		; execute qio
	bcc	510$		; no dir err - continue
	bit	#er.p2, errs	; on second pass?
	bne	1000$		; yes - abandon ship
	bis	#er.cot, errs	; remember error
	mov	$dsw, cotp0	; save dsw
	br	1000$		; and abandon attempt

510$:	dir$	#mrkt		; set timeout
	bcc	530$		; better not fail!
	mov	$dsw, r0	; crash and burn
	mov	#2, r1
	iot
530$:	dir$	#wtse		; wait for efn - ignore errors


1000$:	bitb	#ms.ssm, (r2)  ; output to error logging?
	beq	2000$		; no - br
;*** do it to ssm 
	mov	buflen,<smsg+s.mdbl>	; stuff buffer length
	dir$	#smsg		; do it
	bcc	2000$		; branch if directive okay
	br	1030$		; dir failed, go to error handling code
;
; THE ABOVE SMSG$ CODE REQUIRES THAT SCLI BE PRIVELEGED (PR0).
;
; Rather than do that, we can get to the error logger via the
; MCR SSM command, using rpoi.  Since MCR is a CLI, we are unable
; to pass the connection beyond MCR, thus we cannot tell when
; SSM/ERRLOG is completed.  Use of this method may result in
; errors not being logged (giving "task active" messsages on console).
; We cannot setup a wait, since we would then expose ourselves to 
; cracking during the waiting period when a cli shutdown message
; was issued.
;
; try using rpoi of mcr for the ssm
;*****NOT USING RPOI OF MCR AT THIS TIME
;
;	cmp	#72., buflen	; check for buffer overflow	
;	bhis	1010$		; ok - br
;	mov	#72., <rpoi+r.pobl>	; stuff in what we can
;	br	1020$		; and join common code
;1010$:	mov	buflen, <rpoi+r.pobl>	; stuff in buffer length
;	add	#4, <rpoi+r.pobl>	; bump for /SSM /
;1020$:	dir$	#rpoi		; do it
;	bcc	2000$		; no err - br
;
; set up to report our own error
;
1030$:	bit	#er.p2, errs	; on pass 2 already?
	bne	2000$		; yes - don't try again
	mov	$dsw, smsp0	; save DSW
	bis	#1, errs	; flag error
2000$:
	.if df logtt3		; if test dump 
	alun$s #3,#"TT,#3	; force lun 3 to tt3: for test
				; don't sweat errors
	qiow$s #IO.WVB,#3,#3,,,,<#buff,buflen,#40>	; dump it out
				; don't sweat errors
	.endc	; logtt3
;
; LOG is not really re-entrant, since it uses fixed local data
; However, it should be OK to call ourselves (ONCE!) in order
; to report internal errors. The idea is that, by this point in
; the code, we are done with the scratch database, so a call to
; ourselves is OK. Note, we carefully keep track of this activity,
; to prevent an infinite error loop. 
;
; at this point, the r5 stack is cleaned up (points to the return
; address) and r0-r2 are still saved. 
;
3000$:	tst	errs		; internal errors?
;*****
;* INTERNAL ERROR REPORTING DISABLED
;****
	BR	5000$		; 
	beq	5000$		; no - br
	bit	#er.p2, errs	; on second pass?
	beq	3100$		; yes - br
	mov	r5, savr5	; save return link
	bis	#er.p2, errs	; show on second pass

3100$:	mov	#erpl, r5	; point param lst
	bit	#er.ssm, errs	; ssm error?
	beq	4000$		; no - br
	bic	#er.ssm, errs	; show done ssm 
	mov	#2, ercod	; set internal error number
	mov	#smsp0, (r5)	; point to parameter
	mov	#1, nump	; set number extra params
	mov	#erlst, r5	; set to fake arg list
	mov	#5, (r5)	; set num args
	jmp	10$		; loop back		

4000$:	bit	#er.cot, errs	; console error?
	beq	4700$		; no - br	
	mov	#erpl, r5	; point to param list
	bic	#er.cot, errs	; show done cot
	mov	#3, ercod	; show internal error number
	mov	#3, nump	; show number extra params
	mov	#cotp0, (r5)+	; stuff param addresses
	mov	#cotp1, (r5)+	; ...
	mov	#cotp2, (r5)+	;  ...
	mov	#erlst, r5	; set to fake arg list
	mov	#7, (r5)	; set num args
	jmp	10$		; and loop back
4700$:	mov	savr5, r5	; restore return address
5000$:	pop	<r2,r1,r0>
	return	r5


	.SBTTL qast

.REM |
	AST service routine for QIO completion. 
	When this one fires, cancel the mark-time.
	
|

qast:
	tst	(sp)+	; clean stack
	dir$	#canmt	; cancel mark-time
	cmpb	#is.suc, cotp1	; io success?
	beq	10$		; y- br
	bit	#er.p2, errs	; on second pass?
	bne	10$		; yes - don't log another
	bis	#er.cot, errs	; set cot error
10$:
	astx$s

	.SBTTL mtast

.REM |
	This is the mark-time AST service routine.
	When it fires, the output qio has timed-out.
	Kill the qio, then exit. 
	
|

mtast:
	tst	(sp)+			; clean stack
	dir$	#cqiok			; kill outstanding IO
	astx$s

	.end



