
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Program:	load_block_counter.mar
;	Author:		Billy Bitsenbites (Bruce Ellis)
;	Date written:	Sometime in January 1986
;	
;	Synopsis:	This guy prompts for a disk device name
;			and looks up its UCB address.  He 
;			then allocates a chunk of nonpaged pool
;			and copies the monitoring code into the
;			allocated pool.  To get the code activated
;			he saves the start i/o address from the
;			DDT and moves the address of the code
;			in pool to the start i/o address in the
;			DDT.  When the start i/o entry point
;			is entered, the code has the address of the 
;			IRP passed to it in R3.  He checks for 
;			paging, swapping, and split i/os.  He also
;			counts the number of read, writes and the 
;			size of each.
;
;	Modifications:
;		BAE 9/24/87:	Add code to count the split i/os.
;		BAE 5/90:	Update synchronization for V5.
;
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^





	.library	/sys$library:lib.mlb/
	.link		/sys$system:sys.stb/
	$ddtdef
	$ucbdef
	$irpdef
	$ipldef
header=12				;12 byte header for the pool
devnam:	.long	15			;storage for the disk device name
	.address	10$
10$:	.blkb	15
dev_prompt:				;Prompt for device name
	.ascid	/enter disk to be monitored:/
l_adr:	.address	l_s
	.address	l_e
	.entry	load_block_ctr,^m<>
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Get device name to monitor
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	pushal	devnam			;pass the length address
	pushal	dev_prompt		;pass the prompt
	pushal	devnam			;address of desc. to store device name
	calls	#3,g^lib$get_input	;Get the device name
	blbs	r0,lab1
	$exit_s	r0
lab1:	$lkwset_s	inadr=l_adr	;lock code running at high ipl
	blbs	r0,lab2
	$exit_s	r0
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Load the code to monitor disk activity
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lab2:	$cmkrnl_s	routin=kernel_setup
	ret
;***********************************************************************
;	Kernel mode setup code
;***********************************************************************
	.entry	kernel_setup,^m<r2,r3,r4,r5>
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Grab a write mutex on the i/o database
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	moval	g^ioc$gl_mutex,r0	;Grab a write mutex on the 
	jsb	g^sch$lockw		; i/o database (Note this code
					; assumes that the change mode
					; dispatcher has set up R44 to point
					; to the PCB)
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Search	for ucb address of this device
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	moval	devnam,r1		;Pass the address of the device name
					; descriptor.
	jsb	g^ioc$searchdev		;Search the i/o database for the UCB
	blbs	r0,no_dev_error		;If error scram
					; of the device (r1<-UCB address)
	pushl	r0			;save status
	brw	dev_error
no_dev_error:
	pushl	r1			;Save the ucb address
	movl	#code_len+header,r1	;else grab a chunk of pool to 
	jsb	g^exe$alononpaged	; load the code into
	blbs	r0,no_pool_error	;on error scram
	pushl	r0			;save error status
	brb	pool_error
no_pool_error:
	movzwl	r1,8(r2)		;init the size field for deallocation
	movl	r2,g^exe$gl_sitespec	;save the pointer to pool
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Copy the code into pool
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	pushr	#^m<r0,r1,r2,r3,r4,r5>	
	movc3	#code_len,pool_code_start,12(r2)
	popr	#^m<r0,r1,r2,r3,r4,r5>
	popl	r1			;restore the ucb address
l_s:	forklock	ucb$b_flck(r1)	;Synch with driver at Fork ipl
	movl	ucb$l_ddt(r1),r5	;get the driver dispatch table address
	movl	ddt$l_start(r5),header(r2)	;save actual start i/o
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	reset the start i/o to point to our code
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	moval	get_block_info-pool_code_start+header(r2),ddt$l_start(r5)
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Save the unit number of the disk
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	movzwl	ucb$w_unit(r1),unit-pool_code_start+header(r2)
	forkunlock	lock=ucb$b_flck(r1),newipl=#ipl$_astdel
l_e:	pushl	#ss$_normal		;set success status
dev_error:
pool_error:
	moval	g^ioc$gl_mutex,r0	;Free up the mutex on the io database
	movl	g^ctl$gl_pcb,r4	;
	jsb	g^sch$unlock		;get status
	popl	r0
	ret

;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Pool code to check each i/o request processed by
;	the start i/o routine
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^	
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


pool_code_start:
saved_start:	.blkl	1
read_count:	.long	0
read_lengths:	.long	0[129]
write_count:	.long	0
write_lengths:	.long	0[129]
paging_ios:	.long	0
swap_ios:	.long	0
unit:		.long	0
splits:		.long	0
get_block_info:
	pushr	#^m<r2>
	cmpw	unit,ucb$w_unit(r5)		;this the unit to be monitored?
	beql	ours				;
	brw	exit				;if not scram
ours:	bbc	#irp$v_pagio,irp$w_sts(r3),no_page	;Paging i/o?
	incl	paging_ios				;if so increment count
no_page:
	bbc	#irp$v_swapio,irp$w_sts(r3),no_swap	;Swapping i/o?
	incl	swap_ios				;if so increment count
no_swap:
	extzv	#io$v_fcode,#io$s_fcode,irp$w_func(r3),r2	;get function
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Check for reads
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	cmpb	#io$_readvblk,r2	;Read virtual?
	beql	handle_reads	
	cmpb	#io$_readlblk,r2	;Read logical?
	beql	handle_reads	
	cmpb	#io$_readpblk,r2	;Read physical?
	beql	handle_reads	
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Check for writes
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	cmpb	#io$_writevblk,r2	;Write virtual?
	beql	handle_writes		
	cmpb	#io$_writelblk,r2	;Write logical?
	beql	handle_writes	
	cmpb	#io$_writepblk,r2	;Write physical?
	beql	handle_writes	
	brw	exit

handle_reads:
	incl	read_count		;increment read count
	movl	irp$l_bcnt(r3),r2	;determine the size
	divl2	#512,r2			;Compute the size in blocks
	cmpl	r2,#127			;if > 127 blocks note in 127
	blequ	ok1
	movl	#128,r2	
ok1:	incl	read_lengths[r2]	;increment size counter
	brw	check_splits
handle_writes:	
	incl	write_count		;increment write count
	movl	irp$l_bcnt(r3),r2	;determine the size
	divl2	#512,r2			;Compute size in blocks
	cmpl	r2,#127			;if > 127 then set to 127
	blequ	ok2
	movl	#128,r2
ok2:	incl	write_lengths[r2]	;increment write size counter
check_splits:
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	If not a virtual i/o then it cannot be a split i/o.
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	bbc	#irp$v_virtual,irp$w_sts(r3),exit
	tstl	irp$l_abcnt(r3)		;If accumulated byte count
					; is 0 this is either not a split
					; i/o or it is the first pass 
					; prior to the split so skip it.
	beql	exit
	incl	splits			; else increment split count
exit:	popr	#^m<r2>
	jmp	@saved_start		;Goto driver start i/o routine
pool_code_end:
code_len = pool_code_end-pool_code_start	;amount of pool to allocate

	.end	load_block_ctr

==

[figure 21]

;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Program:	dump_block_counts
;	Author:		Billy Bitsenbites (Bruce Ellis)
;	Date written:	Sometime in January
;
;	Synopsis:	This guy dumps the block counts
;			monitored by the load_block_counter 
;			program.
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	.macro	check	?l
	blbs	r0,l
	$exit_s	r0
l:
	.endm	check
	.library	/sys$library:lib.mlb/
	.link	/sys$system:sys.stb/
long=4
base=12
c_off=base
saved_start=c_off
c_off=c_off+long	
read_count=c_off
c_off=c_off+long	
read_lengths=c_off
c_off=c_off+<long*129>	
write_count=c_off
c_off=c_off+long	
write_lengths=c_off
c_off=c_off+<long*129>	
paging_ios=c_off
c_off=c_off+long	
swap_ios=c_off
c_off=c_off+long	
splits=c_off+<long>
c_off=c_off+<2*long>

data:	.blkb	c_off		;Data returned from block counter

general_fmt:
	.ascid  -
	/Read:!10UL Writes:!10UL Paging ios:!10UL Swapping ios:!5UL/
split_fmt:
	.ascid	/Split ios on this disk: !10UL/
line_fmt:
	.ascid	/!AD:!10UL!10UL!10UL!10UL!10UL/
pre_list:
	.ascii	/   0 -   4/
pre_len=.-pre_list
	.ascii	/   5 -   9/
	.ascii	/  10 -  14/
	.ascii	/  15 -  19/
	.ascii	/  20 -  24/
	.ascii	/  25 -  29/
	.ascii	/  30 -  34/
	.ascii	/  35 -  39/
	.ascii	/  40 -  44/
	.ascii	/  45 -  49/
	.ascii	/  50 -  54/
	.ascii	/  55 -  59/
	.ascii	/  60 -  64/
	.ascii	/  65 -  69/
	.ascii	/  70 -  75/
	.ascii	/  75 -  79/
	.ascii	/  80 -  85/
	.ascii	/  85 -  89/
	.ascii	/  90 -  94/
	.ascii	/  95 -  99/
	.ascii	/ 100 - 104/
	.ascii	/ 105 - 109/
	.ascii	/ 110 - 114/
	.ascii	/ 115 - 119/
	.ascii	/ 120 - 124/
	.ascii	/ 125 - 128+/
buffer:	.long	80
	.address	10$
10$:	.blkb	80
nlines=25
read_header:
	.ascid	/Breakdown of Reads by block size:/
write_header:
	.ascid	/Breakdown of writes by block size:/
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Program to format and dump block counts
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	.entry	dump_block_counts,^m<>
	$cmkrnl_s	routin=return_counts
	check	
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Format and spill general information
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	$fao_s	ctrstr=general_fmt,outbuf=buffer,outlen=buffer,-
		p1=data+read_count-
		p2=data+write_count,p3=data+paging_ios,p4=swap_ios
	check
	pushal	buffer
	calls	#1,g^lib$put_output
	check
	movl	#80,buffer
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Format and spill split io information
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	$fao_s	ctrstr=split_fmt,outbuf=buffer,outlen=buffer,-
		p1=data+splits
	check
	pushal	buffer
	calls	#1,g^lib$put_output
	check
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Format and spill read header
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	movl	#80,buffer
	pushal	read_header
	calls	#1,g^lib$put_output
	check
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Format and spill each line of read information 
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	movl	#nlines,r5
	moval	pre_list,r3
	moval	data+read_lengths,r2
dump_read:
	$fao_s	ctrstr=line_fmt,outbuf=buffer,outlen=buffer,p1=#10-
		p2=r3,p3=(r2),p4=4(r2),p5=8(r2),p6=12(r2),p7=16(r2)
	check
	pushal	buffer
	calls	#1,g^lib$put_output
	check
	addl	#pre_len,r3
	addl	#4*5,r2
	movl	#80,buffer
	sobgtr	r5,dump_read
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Format and spill last line of read information 
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	$fao_s	ctrstr=line_fmt,outbuf=buffer,outlen=buffer,p1=#10-
		p2=r3,p3=(r2),p4=4(r2),p5=8(r2),p6=#0,p7=#0
	check
	pushal	buffer
	calls	#1,g^lib$put_output
	check
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Format and spill write header
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	pushal	write_header
	calls	#1,g^lib$put_output
	check
	movl	#nlines,r5
	moval	pre_list,r3
	moval	data+write_lengths,r2
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Format and spill each line of write information 
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
dump_write:
	$fao_s	ctrstr=line_fmt,outbuf=buffer,outlen=buffer,p1=#10-
		p2=r3,p3=(r2),p4=4(r2),p5=8(r2),p6=12(r2),p7=16(r2)
	check
	pushal	buffer
	calls	#1,g^lib$put_output
	check
	addl	#pre_len,r3
	addl	#4*5,r2
	movl	#80,buffer
	sobgtr	r5,dump_write
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Format and spill last line of write information 
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	$fao_s	ctrstr=line_fmt,outbuf=buffer,outlen=buffer,p1=#10-
		p2=r3,p3=(r2),p4=4(r2),p5=8(r2),p6=#0,p7=#0
	check
	pushal	buffer
	calls	#1,g^lib$put_output
	check
	ret


;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Return block counter information
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	.entry	return_counts,^m<r2,r3,r4,r5>
	movl	g^exe$gl_sitespec,r2	;Check to see if block counter 
	beql	accvio			; is loaded.
	movc3	#c_off,(r2),data	;copy the data up from pool
	movl	#ss$_normal,r0
exit:	ret				;fini
accvio:	movl	#ss$_accvio,r0
	brb	exit
	

	.end	dump_block_counts


==

[figure 22]

;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Program:	Unload_block_counter
;	Author:		Billy Bitsenbites (Bruce Ellis)
;	Synopsis:	Cleans up after disk monitor.
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	.library	/sys$library:lib.mlb/
	.link		/sys$system:sys.stb/
	$ddtdef
	$ucbdef
	$irpdef
header=12
devnam:	.long	15
	.address	10$
10$:	.blkb	15
dev_prompt:
	.ascid	/enter disk to be unmonitored:/
	.entry	unload_block_ctr,^m<>
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Get device name to unload monitor for
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	pushal	devnam
	pushal	dev_prompt
	pushal	devnam
	calls	#3,g^lib$get_input
	blbs	r0,lab
	$exit_s	r0
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	UNLoad the code to monitor disk activity
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lab:	$cmkrnl_s	routin=kernel_setup
	ret
;***********************************************************************
;	Kernel mode setup code
;***********************************************************************
	.entry	kernel_setup,^m<r2,r3,r4,r5>
	tstl	g^exe$gl_sitespec	;if not loaded scram
	bneq	cont
	movl	#ss$_accvio,r0
	ret
cont:
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Grab a write mutex on the i/o database
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	moval	g^ioc$gl_mutex,r0
	jsb	g^sch$lockw
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Search	for ucb address of this device
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	moval	devnam,r1
	jsb	g^ioc$searchdev
	blbs	r0,no_dev_error		;If error scram
	pushl	r0
	brb	dev_error
no_dev_error:
	movl	g^exe$gl_sitespec,r0	;save the pointer to pool
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	reset the start i/o to point to original and deallocate code 
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	movl	ucb$l_ddt(r1),r5	;get the driver dispatch table address
	movl	header(r0),ddt$l_start(r5)	;save actual start i/o
	jsb	g^exe$deanonpaged	;give up the pool
	clrl	g^exe$gl_sitespec	;mark the sitespec as unused
	pushl	#ss$_normal
dev_error:
	moval	g^ioc$gl_mutex,r0	;Free up the mutex on the io database
	movl	g^ctl$gl_pcb,r4
	jsb	g^sch$unlock
	popl	r0
	ret
	.end	unload_block_ctr

