/* $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

#ident "$Header: stats_tape.h 1.6 90/07/29 $"

/*
 * stats_tape.h
 *	Tape performance statistics
 */

/* $Log:	stats_tape.h,v $
 */

#ifndef _SYS_STATS_TAPE_H_
/*
 * Guidelines for adding the hooks to gather the statistics
 *
 *  -  struct tape_stats *
 *     tp_alloc_stats(name, unit)
 *	char	*name;
 *	int	unit;
 *
 *	Allocates a tape_stats structure and returns a pointer to it.  Returns
 *	NULL if the allocation fails.  This is typically done during
 *	initialization and the pointer stored in a device-specific structure.
 *
 *	'name' is the prefix for the device (usually the same as what would
 *		appear in the device name).  A real name for this particular
 *		device is constructed from 'name' and 'unit'.
 *	'unit' is the unit number for this particular device.  It is used
 *		along with 'name' in constructing the name for this device.
 *
 *  -  TP_QUEUED_TIME(timep)
 *	ulong *timep;
 *
 *	At each point when a request has been added to the driver queue but
 *	before it has been queued to the device, add a call to
 *	TP_QUEUED_TIME().
 *
 *	'timep' is a pointer to the timestamp when the operation was queued.
 *	This must be stored in the device data structure.
 *
 *  -  TP_Q(tsp)
 *	struct tape_stats *tsp;
 *
 *	TP_Q() updates queue length statistics.
 *	At each point when a request has been added to the driver queue
 *	a call to TP_Q() should be added.  If an attempt to queue the request
 *	to the device is done just after the request has been queued to
 *	the driver, then the call to TP_Q() may be done immediately after
 *	the request has been queued to the device as long as it is done
 *	behind whatever mutex is guarding access to the device.
 *
 *  -  TP_Q_LENGTH(tsp)
 *	struct tape_stats *tsp;
 *
 *	TP_Q_LENGTH return the current length of the Q of pending request
 *	for the specified tape_stats structure.
 *
 *  -  TP_IOSTART_TIME(tsp)
 *	struct tape_stats *tsp;
 *
 *	At the point the device will be making a transition from idle to active,
 *	a call to TP_IOSTART_TIME() must be inserted.  Typically this would
 *	be done in the routine that is queueing the request to the device.
 *	This records the time that this request was started.  Start time for
 *	requests while the device is busy are handled elsewhere.
 *
 *  -  TP_IODONE_TIME(tsp)
 *	struct tape_stats *tsp;
 *
 *	TP_IODONE_TIME() be called at the time a request finishes
 *	and before the next one is started.  It records the time the
 *	request finished for later processing by tp_completion_stats().
 *	This also marks the start time for the next request.  While not
 *	completely accurate as a start time for the next request (consider
 *	multiple requests queued), this provides accurate measures of drive
 *	active time and thus average service time for each request.
 *
 *  -  tp_completion_stats(tsp, nblks, qtime, rw)
 *	struct tape_stats *tsp;
 *	int nblks;
 *	ulong qtime;
 *	int rw;
 *
 *	tp_completion_stats()should be called at the time a request finishes
 *	and may be done after the next request is started.
 *
 *	'nblks' is the number of DEV_BSIZE blocks.
 *	'qtime' is the timestamp when the request was queued.
 *	'rw' is read/write flag, either B_READ or B_WRITE.
 */

/*
 * The tape statistics structure
 */
struct tape_stats {
	char	tp_name[12];		/* name for this drive */
	ushort	tp_qlen;		/* Current queue length */
	ulong	tp_start;		/* time I/O was queued to controller */
	ulong	tp_savedstart;		/* saved start time (used for service */
					/* time calculation)		      */
	ulong	tp_resp[2];		/* cumulative response time */
	ulong	tp_active[2];		/* cumulative active time */
	ulong	tp_cqlen;		/* cumulative Q lengths */
	ulong	tp_misc;		/* other operations */
	ulong	tp_reads;		/* number of reads */
	ulong	tp_writes;		/* number of writes */
	ulong	tp_rdblks;		/* blocks (DEV_BSIZE) read */
	ulong	tp_wtblks;		/* blocks (DEV_BSIZE) written */
};

/*
 * List of arrays of tape statistics structures
 * (To facilitate dynamic allocation.)
 * The number of structures in each array is controlled by tp_arraysize in
 * stats_space.c
 */

struct tape_stats_list {
	struct tape_stats_list *tl_next; /* Next in chain */
	short	tl_num;			/* no. of stat structs in this chunk */
	short	tl_used;		/* no. of structs left in this chunk */
	struct tape_stats *tl_stats;	/* (really larger) array of stats */
};

#ifdef	INKERNEL

/*
 * Queued (at the driver) and I/O start (queued to controller) timestamps
 */
#define TP_QUEUED_TIME(tp)		(*(tp) = *k_usclk)

#define TP_IOSTART_TIME(tsp) { \
	if ((tsp) != NULL) \
		(tsp)->tp_start = *k_usclk; \
}

#define TP_IODONE_TIME(tsp) { \
	if ((tsp) != NULL) { \
		(tsp)->tp_savedstart = (tsp)->tp_start; \
		TP_IOSTART_TIME(tsp); \
	} \
}

/*
 * Update Q length statistics.
 * argument is a pointer to a tape_stats structure
 *
 * TP_Q()
 */

#define	TP_Q(tsp) { \
	if (tsp != NULL) { \
	    (tsp)->tp_qlen++; \
	    (tsp)->tp_cqlen += (tsp)->tp_qlen; \
	} \
}

/*
 * Return current Q length
 * argument is a pointer to a tape_stats structure
 *
 * TP_Q_LENGTH()
 */

#define	TP_Q_LENGTH(tsp) ((tsp == NULL) ? 0 : (tsp)->tp_qlen)

extern ulong volatile *k_usclk;	/* usclk ptr for kernel use */

extern struct tape_stats *tp_alloc_stats();
extern void tp_completion_stats();

#endif	/* INKERNEL */

#define _SYS_STATS_TAPE_H_
#endif /* _SYS_STATS_TAPE_H_ */
