/*
 * 5799-WZQ (C) COPYRIGHT = NONE
 * LICENSED MATERIALS - PROPERTY OF IBM
 */
/* $Header:swap.c 12.0$ */
/* $ACIS:swap.c 12.0$ */
/* $Source: /ibm/acis/usr/src/ucb/systat/RCS/swap.c,v $ */

#ifndef lint
static char *rcsid = "$Header:swap.c 12.0$";
#endif

/*
 * Copyright (c) 1980 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 */

#ifndef lint
static char sccsid[] = "@(#)swap.c	5.3 (Berkeley) 4/12/86";
#endif not lint

#ifdef VFS
/* @(#)swap.c	1.3 87/09/01 3.2/4.3NFSSRC */
#endif VFS

#include "systat.h"
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/text.h>
#include <sys/conf.h>
#include <sys/vmmac.h>
#include <machine/pte.h>

WINDOW *
openswap()
{

	return (subwin(stdscr, LINES-5-1, 0, 5, 0));
}

closeswap(w)
	WINDOW *w;
{

	if (w == NULL)
		return;
	wclear(w);
	wrefresh(w);
	delwin(w);
}

int	dmmin;
int	dmmax;
int	dmtext;
int	nswdev;
int	maxswapdev;
#define	MAXSWAPDEV	4
short	buckets[MAXSWAPDEV][NDMAP];
struct	swdevt *swdevt;
int	colwidth;

#ifdef ibm032
#define REDSIZE CLSIZE*2		/* red zone size plus reserved page */
struct userx
{
	char userfill[UPAGES*NBPG-sizeof (struct user)];
	struct user user;
};

extern union {
	struct	userx userx;
        char    upages[UPAGES][NBPG];
} user;
#define u       user.userx.user
#else
extern union {
        struct  user user;
        char    upages[UPAGES][NBPG];
} user;
#define u       user.user
#endif ibm032

showswap()
{
        register int i, j;
	register struct proc *pp;
	register struct text *xp;
	register int row;
	register int ts;
	register swblk_t *dp;
	register int bucket;

	if (xtext == 0)
		return;
	for (xp = xtext; xp < &xtext[ntext]; xp++) {
#ifdef VFS
		if (xp->x_vptr == NULL)
#else VFS
		if (xp->x_iptr == NULL)
#endif VFS
			continue;
		ts = ctod(xp->x_size);
		dp = xp->x_daddr;
		for (i = 0; i < ts; i += dmtext) {
			j = ts - i;
			if (j > dmtext)
				j = dmtext;
#define	swatodev(addr)	(((addr) / dmmax) % nswdev)
			if ((bucket=swatodev(*dp))< maxswapdev)
				buckets[bucket][dmtoindex(j)]++;
			dp++;
		}
#ifdef VFS
		if ((xp->x_flag & XPAGV) && xp->x_ptdaddr)
#else VFS
		if ((xp->x_flag & XPAGI) && xp->x_ptdaddr)
#endif VFS
			if ((bucket=swatodev(xp->x_ptdaddr))< maxswapdev)
				buckets[bucket]
				    [dmtoindex(ctod(ctopt(xp->x_size)))]++;
	}
	row = swapdisplay(2, dmtext, 'X');
	if (kprocp == NULL)
		return;
        for (i = 0, pp = kprocp; i < nproc; i++, pp++) {
		if (pp->p_stat == 0 || pp->p_stat == SZOMB)
			continue;
		if (pp->p_flag & SSYS)
			continue;
		if (getu(pp) == 0)
			continue;
		vsacct(&u.u_dmap);
		vsacct(&u.u_smap);
#ifdef notdef
		if ((pp->p_flag & SLOAD) == 0)
			vusize(pp);
#endif
        }
	(void) swapdisplay(1+row, dmmax, 'X');
}

#define	OFFSET	5			/* left hand column */

swapdisplay(baserow, dmbound, c)
	int baserow, dmbound;
	char c;
{
	register int i, j, k, row;
	register short *pb;
	char buf[10];

	for (row = baserow, i = dmmin; i <= dmbound; i *= 2, row++) {
		for (j = 0; j < maxswapdev; j++) {
			pb = &buckets[j][row - baserow];
			wmove(wnd, row, OFFSET + j * (1 + colwidth));
			k = MIN(*pb, colwidth);
			if (*pb > colwidth) {
				sprintf(buf, " %d", *pb);
				k -= strlen(buf);
				while (k--)
					waddch(wnd, c);
				waddstr(wnd, buf);
			} else {
				while (k--)
					waddch(wnd, c);
				k = MAX(colwidth - *pb, 0);
				while (k--)
					waddch(wnd, ' ');
			}
			*pb = 0;
		}
	}
	return (row);
}

vsacct(dmp)
	register struct dmap *dmp;
{
	register swblk_t *ip;
	register int blk = dmmin, index = 0;
	register int bucket;

	for (ip = dmp->dm_map; dmp->dm_alloc > 0; ip++) {
		if (ip - dmp->dm_map >= NDMAP) {
			error("vsacct NDMAP");
			break;
		}
		if (*ip == 0)
			error("vsacct *ip == 0");
		if ((bucket=swatodev(*ip))< maxswapdev)
			buckets[bucket][index]++;
		dmp->dm_alloc -= blk;
		if (blk < dmmax) {
			blk *= 2;
			index++;
		}
	}
}

dmtoindex(dm)
	int dm;
{
	register int i, j;

	for (j = 0, i = dmmin; i <= dmmax; i *= 2, j++)
		if (dm <= i)
			return (j);
	error("dmtoindex(%d)", dm);
	return (NDMAP - 1);
}

static struct nlist nlst[] = {
#define X_PROC          0
        { "_proc" },
#define X_NPROC         1
        { "_nproc" },
#define X_USRPTMAP      2
        { "_Usrptmap" },
#define X_USRPT         3
        { "_usrpt" },
#define X_NSWAP         4
        { "_nswap" },
#define X_DMMIN         5
        { "_dmmin" },
#define X_DMMAX         6
        { "_dmmax" },
#define	X_DMTEXT	7
	{ "_dmtext" },
#define X_NSWDEV        8
        { "_nswdev" },
#define	X_SWDEVT	9
	{ "_swdevt" },
#define	X_NTEXT		10
	{ "_ntext" },
#define	X_TEXT		11
	{ "_text" },
        { "" }
};

initswap()
{

	if (nlst[X_PROC].n_type == 0) {
		nlist("/vmunix", nlst);
		if (nlst[X_PROC].n_type == 0) {
			error("namelist on /vmunix failed");
			return(0);
		}
	}
        if (nswdev == 0) {
                dmmin = getw(nlst[X_DMMIN].n_value);
                dmmax = getw(nlst[X_DMMAX].n_value);
                dmtext = getw(nlst[X_DMTEXT].n_value);
                nswdev = getw(nlst[X_NSWDEV].n_value);
/*
		if (nswdev > MAXSWAPDEV)
			nswdev = MAXSWAPDEV;
*/
/*
 * This is a kludge; we really should allocate buckets dynamically,
 * based on the real number of swap devices
 */
		maxswapdev = (nswdev > MAXSWAPDEV)? MAXSWAPDEV : nswdev;
		swdevt = (struct swdevt *)calloc(nswdev, sizeof (*swdevt));
		klseek(kmem, nlst[X_SWDEVT].n_value, L_SET);
		read(kmem, swdevt, nswdev * sizeof (struct swdevt));
		ntext = getw(nlst[X_NTEXT].n_value);
		textp = getw(nlst[X_TEXT].n_value);
        }
        if (procp == NULL) {
                procp = getw(nlst[X_PROC].n_value);
                nproc = getw(nlst[X_NPROC].n_value);
        }
	if (xtext == NULL)
		xtext = (struct text *)calloc(ntext, sizeof (struct text));
	if (kprocp == NULL)
                kprocp = (struct proc *)calloc(nproc, sizeof (struct proc));
        if (usrpt != NULL)
                return(1);
	usrpt = (struct pte *)nlst[X_USRPT].n_value;
	Usrptma = (struct pte *)nlst[X_USRPTMAP].n_value;
	if (pt == NULL)
		pt = (struct p_times *)malloc(nproc * sizeof (struct p_times));
	return(1);
}

fetchswap()
{

	if (nlst[X_PROC].n_type == 0)
		return;
	if (kprocp == NULL) {
                kprocp = (struct proc *)malloc(sizeof (*kprocp) * nproc);
		if (kprocp == NULL)
			return;
	}
        lseek(kmem, procp, L_SET);
        if (read(kmem, kprocp, sizeof (struct proc) * nproc) !=
	    sizeof (struct proc) * nproc) {
		error("couldn't read proc table");
		return;
	}
	if (xtext == NULL) {
		xtext = (struct text *)calloc(ntext, sizeof (struct text));
		if (xtext == NULL)
			return;
	}
	lseek(kmem, textp, L_SET);
	if (read(kmem, xtext, ntext * sizeof (struct text)) !=
	    sizeof (struct text) * ntext)
		error("couldn't read text table");
}

#ifdef vax
char	*devnames[] =
     { "hp", "ht", "up", "rk", "sw", "tm", "ts", "mt", "tu", "ra", "ut",
       "rb", "rx", "rl" };
#endif

#ifdef ibm032
char	*devnames[] =
     { "", "hd", "ud", "fd", "sw", "st", "vd", "scsi", "", "" };
#endif

labelswap()
{
	register int row;

	if (maxswapdev == 0) {
		error("Don't know how many swap devices.\n");
		return;
	}
	colwidth = (COLS - OFFSET - (maxswapdev - 1)) / maxswapdev;
	row = swaplabel(0, dmtext, 1);
	(void) swaplabel(row, dmmax, 0);
}

swaplabel(row, dmbound, donames)
	register int row;
	int dmbound, donames;
{
	register int i, j;

	for (i = 0; i < maxswapdev; i++) {
		if (donames)
			mvwprintw(wnd,
			    row, OFFSET + i*(1 + colwidth) + (colwidth - 3)/2,
			    "%s%d", devnames[major(swdevt[i].sw_dev)],
			        minor(swdevt[i].sw_dev) >> 3);
		for (j = 0; j + 5 < colwidth; j += 5)
			mvwprintw(wnd, row + donames,
			    OFFSET + i*(1 + colwidth) + j, "/%-2d  ", j);
	}
	row += 1 + donames;
	for (j = 0, i = dmmin; i <= dmbound; i *= 2, j++, row++) {
		int k;

		mvwprintw(wnd, row, 0, "%4d|", i);
		for (k = 1; k < maxswapdev; k++)
			mvwaddch(wnd, row, OFFSET + k*(1 + colwidth) - 1, '|');
	}
	return (row);
}
