Subject: Re: tape drive instrumentation, again
To: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
From: Brett Lymn <blymn@baesystems.com.au>
List: tech-kern
Date: 03/14/2006 23:28:01
On Sun, Mar 12, 2006 at 09:53:37PM +0900, YAMAMOTO Takashi wrote:
> 
> looks good enough to me.
>

cool :)
 
> minor comments:
> 	- use struct member prefixes ("sc_", "nm_"), at least where other
> 	  existing members have it.

done.

> 	- how about having iostat_seek() instead of "seek++"?

yes, that's good.  done.

> 	- use malloc/free rather than MALLOC/FREE
> 	  unless it's in a critical path.

Mmmm the only place I have used MALLOC/FREE is in the nfs code, all
the other mallocs in that function are MALLOC, besides it's in the nfs
mount path which may be important if you are mounting root over nfs :)

> 	- is there any point to update CTL_HW_NAMES?
> 	  i think you can just remove it.

Hmmm will look at this.

> 	- is anyone use _resetstat()?  how about just removing it?

removed.

> 	- please make sysctl_hw_disknames etc static.

done.

> 	- is "#include <sys/lock.h>" in iostat.h necessary?

bah.. will remove it and test the compile.

> 	- can you do whitespace cleanups as another commit?
> 

heh :) Yes, I actually culled a lot of files that I had touched and
then backed out my changes but they still had the whitespace changes
in them - that is an automatic thing I have in emacs to strip bogus
whitespace on file save.  I have fixed this up so there are no white
space changes in the diff now.

========================================================================

Index: sys/arch/acorn32/mainbus/fd.c
===================================================================
RCS file: /cvsroot/src/sys/arch/acorn32/mainbus/fd.c,v
retrieving revision 1.24
diff -u -r1.24 fd.c
--- sys/arch/acorn32/mainbus/fd.c	23 Feb 2006 05:37:46 -0000	1.24
+++ sys/arch/acorn32/mainbus/fd.c	14 Mar 2006 12:47:42 -0000
@@ -1030,7 +1030,7 @@
 		fd->sc_cylin = -1;
 		fdc->sc_state = SEEKWAIT;
 
-		fd->sc_dk.dk_seek++;
+		iostat_seek(fd->sc_dk.dk_stats);
 		disk_busy(&fd->sc_dk);
 
 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
Index: sys/arch/arc/jazz/fd.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arc/jazz/fd.c,v
retrieving revision 1.25
diff -u -r1.25 fd.c
--- sys/arch/arc/jazz/fd.c	23 Feb 2006 05:37:46 -0000	1.25
+++ sys/arch/arc/jazz/fd.c	14 Mar 2006 12:47:43 -0000
@@ -831,7 +831,7 @@
 		fd->sc_cylin = -1;
 		fdc->sc_state = SEEKWAIT;
 
-		fd->sc_dk.dk_seek++;
+		iostat_seek(fd->sc_dk.dk_stats);
 		disk_busy(&fd->sc_dk);
 
 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
Index: sys/arch/atari/dev/hdfd.c
===================================================================
RCS file: /cvsroot/src/sys/arch/atari/dev/hdfd.c,v
retrieving revision 1.49
diff -u -r1.49 hdfd.c
--- sys/arch/atari/dev/hdfd.c	23 Feb 2006 05:37:46 -0000	1.49
+++ sys/arch/atari/dev/hdfd.c	14 Mar 2006 12:47:43 -0000
@@ -1050,7 +1050,7 @@
 		fd->sc_cylin = -1;
 		fdc->sc_state = SEEKWAIT;
 
-		fd->sc_dk.dk_seek++;
+		iostat_seek(fd->sc_dk.dk_stats);
 		disk_busy(&fd->sc_dk);
 
 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
Index: sys/arch/hp300/dev/rd.c
===================================================================
RCS file: /cvsroot/src/sys/arch/hp300/dev/rd.c,v
retrieving revision 1.71
diff -u -r1.71 rd.c
--- sys/arch/hp300/dev/rd.c	25 Feb 2006 02:28:56 -0000	1.71
+++ sys/arch/hp300/dev/rd.c	14 Mar 2006 12:47:44 -0000
@@ -836,7 +836,7 @@
 
 		/* Instrumentation. */
 		disk_busy(&rs->sc_dkdev);
-		rs->sc_dkdev.dk_seek++;
+		iostat_seek(rs->sc_dkdev->dk_stats);
 
 #ifdef DEBUG
 		if (rddebug & RDB_IO)
Index: sys/arch/pdp10/dev/hp.c
===================================================================
RCS file: /cvsroot/src/sys/arch/pdp10/dev/hp.c,v
retrieving revision 1.4
diff -u -r1.4 hp.c
--- sys/arch/pdp10/dev/hp.c	11 Dec 2005 12:18:34 -0000	1.4
+++ sys/arch/pdp10/dev/hp.c	14 Mar 2006 12:47:44 -0000
@@ -265,7 +265,7 @@
 	 * Collect statistics.
 	 */
 	disk_busy(&sc->sc_disk);
-	sc->sc_disk.dk_seek++;
+	iostat_seek(sc->sc_disk.dk_stats);
 
 	bn = bp->b_rawblkno;
 	if (bn) {
Index: sys/arch/sparc/dev/fd.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc/dev/fd.c,v
retrieving revision 1.125
diff -u -r1.125 fd.c
--- sys/arch/sparc/dev/fd.c	23 Feb 2006 05:37:48 -0000	1.125
+++ sys/arch/sparc/dev/fd.c	14 Mar 2006 12:47:44 -0000
@@ -1490,7 +1490,7 @@
 		fdc->sc_state = SEEKWAIT;
 		fdc->sc_nstat = 0;
 
-		fd->sc_dk.dk_seek++;
+		iostat_seek(fd->sc_dk.dk_stats);
 
 		disk_busy(&fd->sc_dk);
 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
Index: sys/arch/vax/mba/hp.c
===================================================================
RCS file: /cvsroot/src/sys/arch/vax/mba/hp.c,v
retrieving revision 1.39
diff -u -r1.39 hp.c
--- sys/arch/vax/mba/hp.c	11 Dec 2005 12:19:35 -0000	1.39
+++ sys/arch/vax/mba/hp.c	14 Mar 2006 12:47:44 -0000
@@ -235,7 +235,7 @@
 	 * Collect statistics.
 	 */
 	disk_busy(&sc->sc_disk);
-	sc->sc_disk.dk_seek++;
+	iostat_seek(sc->sc_disk->dk_stats);
 
 	bn = bp->b_rawblkno;
 	if (bn) {
Index: sys/arch/x68k/dev/fd.c
===================================================================
RCS file: /cvsroot/src/sys/arch/x68k/dev/fd.c,v
retrieving revision 1.68
diff -u -r1.68 fd.c
--- sys/arch/x68k/dev/fd.c	23 Feb 2006 05:37:48 -0000	1.68
+++ sys/arch/x68k/dev/fd.c	14 Mar 2006 12:47:45 -0000
@@ -1109,7 +1109,7 @@
 		fd->sc_cylin = -1;
 		fdc->sc_state = SEEKWAIT;
 
-		fd->sc_dk.dk_seek++;
+		iostat_seek(fd->sc_dk.dk_stats);
 		disk_busy(&fd->sc_dk);
 
 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
Index: sys/conf/files
===================================================================
RCS file: /cvsroot/src/sys/conf/files,v
retrieving revision 1.763
diff -u -r1.763 files
--- sys/conf/files	1 Mar 2006 22:12:09 -0000	1.763
+++ sys/conf/files	14 Mar 2006 12:47:45 -0000
@@ -1242,6 +1242,7 @@
 file	kern/subr_bufq.c
 file	kern/subr_devsw.c
 file	kern/subr_disk.c
+file	kern/subr_iostat.c
 file	kern/subr_evcnt.c
 file	kern/subr_extent.c
 file	kern/subr_log.c
Index: sys/dev/gpib/rd.c
===================================================================
RCS file: /cvsroot/src/sys/dev/gpib/rd.c,v
retrieving revision 1.8
diff -u -r1.8 rd.c
--- sys/dev/gpib/rd.c	25 Feb 2006 02:28:58 -0000	1.8
+++ sys/dev/gpib/rd.c	14 Mar 2006 12:47:47 -0000
@@ -785,7 +785,7 @@
 	    sizeof(sc->sc_ioc)-1) == sizeof(sc->sc_ioc)-1) {
 		/* Instrumentation. */
 		disk_busy(&sc->sc_dk);
-		sc->sc_dk.dk_seek++;
+		iostat_seek(sc->sc_dk.dk_stats);
 		gpibawait(sc->sc_ic);
 		return;
 	}
Index: sys/dev/isa/fd.c
===================================================================
RCS file: /cvsroot/src/sys/dev/isa/fd.c,v
retrieving revision 1.64
diff -u -r1.64 fd.c
--- sys/dev/isa/fd.c	6 Jan 2006 09:21:44 -0000	1.64
+++ sys/dev/isa/fd.c	14 Mar 2006 12:47:47 -0000
@@ -1042,7 +1042,7 @@
 		fd->sc_cylin = -1;
 		fdc->sc_state = SEEKWAIT;
 
-		fd->sc_dk.dk_seek++;
+		iostat_seek(fd->sc_dk.dk_stats);
 		disk_busy(&fd->sc_dk);
 
 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
Index: sys/dev/scsipi/st.c
===================================================================
RCS file: /cvsroot/src/sys/dev/scsipi/st.c,v
retrieving revision 1.186
diff -u -r1.186 st.c
--- sys/dev/scsipi/st.c	11 Dec 2005 12:23:51 -0000	1.186
+++ sys/dev/scsipi/st.c	14 Mar 2006 12:47:49 -0000
@@ -76,7 +76,7 @@
 #include <sys/conf.h>
 #include <sys/kernel.h>
 #include <sys/vnode.h>
-#include <sys/tape.h>
+#include <sys/iostat.h>
 #include <sys/sysctl.h>
 
 #include <dev/scsipi/scsi_spc.h>
@@ -107,9 +107,6 @@
 #define		ST_MOUNT_DELAY		0
 #endif
 
-struct tape *
-drive_attach(char *name);
-
 static dev_type_open(stopen);
 static dev_type_close(stclose);
 static dev_type_read(stread);
@@ -352,14 +349,6 @@
 	stdone
 };
 
-/*
- * A global list of all tape drives attached to the system.  May grow or
- * shrink over time.
- */
-struct  tapelist_head tapelist = TAILQ_HEAD_INITIALIZER(tapelist);
-int     tape_count = 0;             /* number of drives in global tapelist */
-struct simplelock tapelist_slock = SIMPLELOCK_INITIALIZER;
-
 #if	defined(ST_ENABLE_EARLYWARN)
 #define	ST_INIT_FLAGS	ST_EARLYWARN
 #else
@@ -423,8 +412,9 @@
 		    (st->flags & ST_READONLY) ? "protected" : "enabled");
 	}
 
-	st->stats = drive_attach(st->sc_dev.dv_xname);
-	
+	st->stats = iostat_alloc(IOSTAT_TAPE);
+	st->stats->name = st->sc_dev.dv_xname;
+
 #if NRND > 0
 	rnd_attach_source(&st->rnd_source, st->sc_dev.dv_xname,
 			  RND_TYPE_TAPE, 0);
@@ -480,16 +470,7 @@
 	vdevgone(bmaj, mn, mn+STNMINOR-1, VBLK);
 	vdevgone(cmaj, mn, mn+STNMINOR-1, VCHR);
 
-	if (tape_count == 0) {
-		printf("%s detach: tape_count already zero\n",
-		       st->sc_dev.dv_xname);
-	} else {
-		simple_lock(&tapelist_slock);
-		TAILQ_REMOVE(&tapelist, st->stats, link);
-		tape_count--;
-		simple_unlock(&tapelist_slock);
-		free(st->stats, M_DEVBUF);
-	}
+	iostat_free(st->stats);
 
 #if NRND > 0
 	/* Unhook the entropy source. */
@@ -1187,7 +1168,7 @@
 	struct buf *bp;
 	struct scsi_rw_tape cmd;
 	struct scsipi_xfer *xs;
-	int flags, error, s;
+	int flags, error;
 
 	SC_DEBUG(periph, SCSIPI_DB2, ("ststart "));
 	/*
@@ -1224,12 +1205,8 @@
 		if ((bp = BUFQ_PEEK(st->buf_queue)) == NULL)
 			return;
 
-		if (st->stats->busy++ == 0) {
-			s = splclock();
-			st->stats->timestamp = mono_time;
-			splx(s);
-		}
-		
+		iostat_busy(st->stats);
+
 		/*
 		 * only FIXEDBLOCK devices have pending I/O or space operations.
 		 */
@@ -1356,8 +1333,6 @@
 {
 	struct st_softc *st = (void *)xs->xs_periph->periph_dev;
 	struct buf *bp = xs->bp;
-	int s;
-	struct timeval st_time, diff_time;
 
 	if (bp) {
 		bp->b_error = error;
@@ -1370,32 +1345,10 @@
 		else
 			st->flags &= ~ST_WRITTEN;
 
-		if (st->stats->busy-- == 0) {
-			  /* this is not really fatal so we don't panic */
-			printf("%s: busy < 0, Oops.\n", st->stats->name);
-			st->stats->busy = 0;
-		} else {
-			s = splclock();
-			st_time = mono_time;
-			splx(s);
-
-			timersub(&st_time, &st->stats->timestamp, &diff_time);
-			timeradd(&st->stats->time, &diff_time,
-				 &st->stats->time);
+		iostat_unbusy(st->stats, bp->b_bcount,
+			     ((bp->b_flags & B_READ) == B_READ));
+
 
-			st->stats->timestamp = st_time;
-			if (bp->b_bcount > 0) {
-				if ((bp->b_flags & B_READ) == B_WRITE) {
-					st->stats->wbytes += bp->b_bcount;
-					st->stats->wxfer++;
-				} else {
-					st->stats->rbytes += bp->b_bcount;
-					st->stats->rxfer++;
-				}
-			}
-		}
-		
-			
 #if NRND > 0
 		rnd_add_uint32(&st->rnd_source, bp->b_blkno);
 #endif
@@ -2453,156 +2406,3 @@
 	/* Not implemented. */
 	return (ENXIO);
 }
-
-int
-sysctl_hw_tapenames(SYSCTLFN_ARGS)
-{
-	char bf[TAPENAMELEN + 1];
-	char *where = oldp;
-	struct tape *tapep;
-	size_t needed, left, slen;
-	int error, first;
-
-	if (newp != NULL)
-		return (EPERM);
-	if (namelen != 0)
-		return (EINVAL);
-
-	first = 1;
-	error = 0;
-	needed = 0;
-	left = *oldlenp;
-
-	simple_lock(&tapelist_slock);
-	for (tapep = TAILQ_FIRST(&tapelist); tapep != NULL;
-	    tapep = TAILQ_NEXT(tapep, link)) {
-		if (where == NULL)
-			needed += strlen(tapep->name) + 1;
-		else {
-			memset(bf, 0, sizeof(bf));
-			if (first) {
-				strncpy(bf, tapep->name, sizeof(bf));
-				first = 0;
-			} else {
-				bf[0] = ' ';
-				strncpy(bf + 1, tapep->name, sizeof(bf) - 1);
-			}
-			bf[TAPENAMELEN] = '\0';
-			slen = strlen(bf);
-			if (left < slen + 1)
-				break;
-			/* +1 to copy out the trailing NUL byte */
-			error = copyout(bf, where, slen + 1);
-			if (error)
-				break;
-			where += slen;
-			needed += slen;
-			left -= slen;
-		}
-	}
-	simple_unlock(&tapelist_slock);
-	*oldlenp = needed;
-	return (error);
-}
-
-int
-sysctl_hw_tapestats(SYSCTLFN_ARGS)
-{
-	struct tape_sysctl stape;
-	struct tape *tapep;
-	char *where = oldp;
-	size_t tocopy, left;
-	int error;
-
-	if (newp != NULL)
-		return (EPERM);
-
-	tocopy = name[0];
-
-	if (where == NULL) {
-		*oldlenp = tape_count * tocopy;
-		return (0);
-	}
-
-	error = 0;
-	left = *oldlenp;
-	memset(&stape, 0, sizeof(stape));
-	*oldlenp = 0;
-
-	simple_lock(&tapelist_slock);
-	TAILQ_FOREACH(tapep, &tapelist, link) {
-		if (left < tocopy)
-			break;
-		strncpy(stape.name, tapep->name, sizeof(stape.name));
-		stape.xfer = tapep->rxfer + tapep->wxfer;
-		stape.rxfer = tapep->rxfer;
-		stape.wxfer = tapep->wxfer;
-		stape.bytes = tapep->rbytes + tapep->wbytes;
-		stape.rbytes = tapep->rbytes;
-		stape.wbytes = tapep->wbytes;
-		stape.attachtime_sec = tapep->attachtime.tv_sec;
-		stape.attachtime_usec = tapep->attachtime.tv_usec;
-		stape.timestamp_sec = tapep->timestamp.tv_sec;
-		stape.timestamp_usec = tapep->timestamp.tv_usec;
-		stape.time_sec = tapep->time.tv_sec;
-		stape.time_usec = tapep->time.tv_usec;
-		stape.busy = tapep->busy;
-
-		error = copyout(&stape, where, min(tocopy, sizeof(stape)));
-		if (error)
-			break;
-		where += tocopy;
-		*oldlenp += tocopy;
-		left -= tocopy;
-	}
-	simple_unlock(&tapelist_slock);
-	return (error);
-}
-
-struct tape *
-drive_attach(char *name) 
-{
-	struct tape *stats;
-	int s;
-	
-	/* Allocate and initialise statistics */
-	stats = (struct tape *) malloc(sizeof(struct tape), M_DEVBUF,
-					   M_WAITOK);
-	stats->rxfer = stats->wxfer = stats->rbytes = 0;
-	stats->wbytes = stats->busy = 0;
-
-	/*
-	 * Set the attached timestamp.
-	 */
-	s = splclock();
-	stats->attachtime = mono_time;
-	splx(s);
-
-	  /* and clear the utilisation time */
-	timerclear(&stats->time);
-
-	  /* link the tape drive to the tapelist */
-	simple_lock(&tapelist_slock);
-	TAILQ_INSERT_TAIL(&tapelist, stats, link);
-	tape_count++;
-	simple_unlock(&tapelist_slock);
-	stats->name = name;
-
-	return stats;
-}
-
-SYSCTL_SETUP(sysctl_tape_stats_setup, "sysctl tape stats setup")
-{
-	sysctl_createv(clog, 0, NULL, NULL,
-		       CTLFLAG_PERMANENT,
-		       CTLTYPE_STRING, "tapenames",
-		       SYSCTL_DESCR("List of tape devices present"),
-		       sysctl_hw_tapenames, 0, NULL, 0,
-		       CTL_HW, HW_TAPENAMES, CTL_EOL);
-	sysctl_createv(clog, 0, NULL, NULL,
-		       CTLFLAG_PERMANENT,
-		       CTLTYPE_STRUCT, "tapestats",
-		       SYSCTL_DESCR("Statistics on tape drive operation"),
-		       sysctl_hw_tapestats, 0, NULL, 0,
-		       CTL_HW, HW_TAPESTATS, CTL_EOL);
-}
Index: sys/dev/scsipi/stvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/scsipi/stvar.h,v
retrieving revision 1.16
diff -u -r1.16 stvar.h
--- sys/dev/scsipi/stvar.h	11 Dec 2005 12:23:51 -0000	1.16
+++ sys/dev/scsipi/stvar.h	14 Mar 2006 12:47:49 -0000
@@ -150,9 +150,9 @@
 					/* operations */
 	struct callout sc_callout;	/* restarting the queue after */
 					/* transient error */
-	
-	struct tape *stats;		/* statistics for the drive */
-	
+
+	struct io_stats *stats;		/* statistics for the drive */
+
 #if NRND > 0
 	rndsource_element_t	rnd_source;
 #endif
Index: sys/kern/init_sysctl.c
===================================================================
RCS file: /cvsroot/src/sys/kern/init_sysctl.c,v
retrieving revision 1.63
diff -u -r1.63 init_sysctl.c
--- sys/kern/init_sysctl.c	1 Mar 2006 12:38:21 -0000	1.63
+++ sys/kern/init_sysctl.c	14 Mar 2006 12:47:51 -0000
@@ -904,18 +904,6 @@
 		       CTL_HW, HW_PAGESIZE, CTL_EOL);
 	sysctl_createv(clog, 0, NULL, NULL,
 		       CTLFLAG_PERMANENT,
-		       CTLTYPE_STRING, "disknames",
-		       SYSCTL_DESCR("List of disk devices present"),
-		       sysctl_hw_disknames, 0, NULL, 0,
-		       CTL_HW, HW_DISKNAMES, CTL_EOL);
-	sysctl_createv(clog, 0, NULL, NULL,
-		       CTLFLAG_PERMANENT,
-		       CTLTYPE_STRUCT, "diskstats",
-		       SYSCTL_DESCR("Statistics on disk operation"),
-		       sysctl_hw_diskstats, 0, NULL, 0,
-		       CTL_HW, HW_DISKSTATS, CTL_EOL);
-	sysctl_createv(clog, 0, NULL, NULL,
-		       CTLFLAG_PERMANENT,
 		       CTLTYPE_STRING, "machine_arch",
 		       SYSCTL_DESCR("Machine CPU class"),
 		       NULL, 0, machine_arch, 0,
Index: sys/kern/subr_disk.c
===================================================================
RCS file: /cvsroot/src/sys/kern/subr_disk.c,v
retrieving revision 1.73
diff -u -r1.73 subr_disk.c
--- sys/kern/subr_disk.c	26 Dec 2005 18:45:27 -0000	1.73
+++ sys/kern/subr_disk.c	14 Mar 2006 12:47:51 -0000
@@ -89,14 +89,6 @@
 #include <lib/libkern/libkern.h>
 
 /*
- * A global list of all disks attached to the system.  May grow or
- * shrink over time.
- */
-struct	disklist_head disklist = TAILQ_HEAD_INITIALIZER(disklist);
-int	disk_count;		/* number of drives in global disklist */
-struct simplelock disklist_slock = SIMPLELOCK_INITIALIZER;
-
-/*
  * Compute checksum for disk label.
  */
 u_int
@@ -172,27 +164,20 @@
 }
 
 /*
- * Searches the disklist for the disk corresponding to the
+ * Searches the iostatlist for the disk corresponding to the
  * name provided.
  */
 struct disk *
 disk_find(char *name)
 {
-	struct disk *diskp;
+	struct io_stats *stat;
 
-	if ((name == NULL) || (disk_count <= 0))
-		return (NULL);
+	stat = iostat_find(name);
 
-	simple_lock(&disklist_slock);
-	for (diskp = TAILQ_FIRST(&disklist); diskp != NULL;
-	    diskp = TAILQ_NEXT(diskp, dk_link))
-		if (strcmp(diskp->dk_name, name) == 0) {
-			simple_unlock(&disklist_slock);
-			return (diskp);
-		}
-	simple_unlock(&disklist_slock);
+	if ((stat != NULL) && (stat->type == IOSTAT_DISK))
+		return stat->parent;
 
-	return (NULL);
+        return (NULL);
 }
 
 static void
@@ -211,8 +196,6 @@
 static void
 disk_attach0(struct disk *diskp)
 {
-	int s;
-
 	/*
 	 * Allocate and initialize the disklabel structures.  Note that
 	 * it's not safe to sleep here, since we're probably going to be
@@ -228,19 +211,12 @@
 	memset(diskp->dk_cpulabel, 0, sizeof(struct cpu_disklabel));
 
 	/*
-	 * Set the attached timestamp.
+	 * Set up the stats collection.
 	 */
-	s = splclock();
-	diskp->dk_attachtime = mono_time;
-	splx(s);
+	diskp->dk_stats = iostat_alloc(IOSTAT_DISK);
+        diskp->dk_stats->parent = (void *) diskp;
+        diskp->dk_stats->name = diskp->dk_name;
 
-	/*
-	 * Link into the disklist.
-	 */
-	simple_lock(&disklist_slock);
-	TAILQ_INSERT_TAIL(&disklist, diskp, dk_link);
-	disk_count++;
-	simple_unlock(&disklist_slock);
 }
 
 static void
@@ -248,14 +224,9 @@
 {
 
 	/*
-	 * Remove from the disklist.
+	 * Remove from the drivelist.
 	 */
-	if (disk_count == 0)
-		panic("disk_detach: disk_count == 0");
-	simple_lock(&disklist_slock);
-	TAILQ_REMOVE(&disklist, diskp, dk_link);
-	disk_count--;
-	simple_unlock(&disklist_slock);
+        iostat_free(diskp->dk_stats);
 
 	/*
 	 * Free the space used by the disklabel structures.
@@ -316,205 +287,22 @@
 	disk_detach0(diskp);
 }
 
-
 /*
- * Increment a disk's busy counter.  If the counter is going from
- * 0 to 1, set the timestamp.
+ * Mark the disk as busy for metrics collection.
  */
 void
 disk_busy(struct disk *diskp)
 {
-	int s;
-
-	/*
-	 * XXX We'd like to use something as accurate as microtime(),
-	 * but that doesn't depend on the system TOD clock.
-	 */
-	if (diskp->dk_busy++ == 0) {
-		s = splclock();
-		diskp->dk_timestamp = mono_time;
-		splx(s);
-	}
+	iostat_busy(diskp->dk_stats);
 }
 
 /*
- * Decrement a disk's busy counter, increment the byte count, total busy
- * time, and reset the timestamp.
+ * Finished disk operations, gather metrics.
  */
 void
 disk_unbusy(struct disk *diskp, long bcount, int read)
 {
-	int s;
-	struct timeval dv_time, diff_time;
-
-	if (diskp->dk_busy-- == 0) {
-		printf("%s: dk_busy < 0\n", diskp->dk_name);
-		panic("disk_unbusy");
-	}
-
-	s = splclock();
-	dv_time = mono_time;
-	splx(s);
-
-	timersub(&dv_time, &diskp->dk_timestamp, &diff_time);
-	timeradd(&diskp->dk_time, &diff_time, &diskp->dk_time);
-
-	diskp->dk_timestamp = dv_time;
-	if (bcount > 0) {
-		if (read) {
-			diskp->dk_rbytes += bcount;
-			diskp->dk_rxfer++;
-		} else {
-			diskp->dk_wbytes += bcount;
-			diskp->dk_wxfer++;
-		}
-	}
-}
-
-/*
- * Reset the metrics counters on the given disk.  Note that we cannot
- * reset the busy counter, as it may case a panic in disk_unbusy().
- * We also must avoid playing with the timestamp information, as it
- * may skew any pending transfer results.
- */
-void
-disk_resetstat(struct disk *diskp)
-{
-	int s = splbio(), t;
-
-	diskp->dk_rxfer = 0;
-	diskp->dk_rbytes = 0;
-	diskp->dk_wxfer = 0;
-	diskp->dk_wbytes = 0;
-
-	t = splclock();
-	diskp->dk_attachtime = mono_time;
-	splx(t);
-
-	timerclear(&diskp->dk_time);
-
-	splx(s);
-}
-
-int
-sysctl_hw_disknames(SYSCTLFN_ARGS)
-{
-	char bf[DK_DISKNAMELEN + 1];
-	char *where = oldp;
-	struct disk *diskp;
-	size_t needed, left, slen;
-	int error, first;
-
-	if (newp != NULL)
-		return (EPERM);
-	if (namelen != 0)
-		return (EINVAL);
-
-	first = 1;
-	error = 0;
-	needed = 0;
-	left = *oldlenp;
-
-	simple_lock(&disklist_slock);
-	for (diskp = TAILQ_FIRST(&disklist); diskp != NULL;
-	    diskp = TAILQ_NEXT(diskp, dk_link)) {
-		if (where == NULL)
-			needed += strlen(diskp->dk_name) + 1;
-		else {
-			memset(bf, 0, sizeof(bf));
-			if (first) {
-				strncpy(bf, diskp->dk_name, sizeof(bf));
-				first = 0;
-			} else {
-				bf[0] = ' ';
-				strncpy(bf + 1, diskp->dk_name,
-				    sizeof(bf) - 1);
-			}
-			bf[DK_DISKNAMELEN] = '\0';
-			slen = strlen(bf);
-			if (left < slen + 1)
-				break;
-			/* +1 to copy out the trailing NUL byte */
-			error = copyout(bf, where, slen + 1);
-			if (error)
-				break;
-			where += slen;
-			needed += slen;
-			left -= slen;
-		}
-	}
-	simple_unlock(&disklist_slock);
-	*oldlenp = needed;
-	return (error);
-}
-
-int
-sysctl_hw_diskstats(SYSCTLFN_ARGS)
-{
-	struct disk_sysctl sdisk;
-	struct disk *diskp;
-	char *where = oldp;
-	size_t tocopy, left;
-	int error;
-
-	if (newp != NULL)
-		return (EPERM);
-
-	/*
-	 * The original hw.diskstats call was broken and did not require
-	 * the userland to pass in it's size of struct disk_sysctl.  This
-	 * was fixed after NetBSD 1.6 was released, and any applications
-	 * that do not pass in the size are given an error only, unless
-	 * we care about 1.6 compatibility.
-	 */
-	if (namelen == 0)
-#ifdef COMPAT_16
-		tocopy = offsetof(struct disk_sysctl, dk_rxfer);
-#else
-		return (EINVAL);
-#endif
-	else
-		tocopy = name[0];
-
-	if (where == NULL) {
-		*oldlenp = disk_count * tocopy;
-		return (0);
-	}
-
-	error = 0;
-	left = *oldlenp;
-	memset(&sdisk, 0, sizeof(sdisk));
-	*oldlenp = 0;
-
-	simple_lock(&disklist_slock);
-	TAILQ_FOREACH(diskp, &disklist, dk_link) {
-		if (left < tocopy)
-			break;
-		strncpy(sdisk.dk_name, diskp->dk_name, sizeof(sdisk.dk_name));
-		sdisk.dk_xfer = diskp->dk_rxfer + diskp->dk_wxfer;
-		sdisk.dk_rxfer = diskp->dk_rxfer;
-		sdisk.dk_wxfer = diskp->dk_wxfer;
-		sdisk.dk_seek = diskp->dk_seek;
-		sdisk.dk_bytes = diskp->dk_rbytes + diskp->dk_wbytes;
-		sdisk.dk_rbytes = diskp->dk_rbytes;
-		sdisk.dk_wbytes = diskp->dk_wbytes;
-		sdisk.dk_attachtime_sec = diskp->dk_attachtime.tv_sec;
-		sdisk.dk_attachtime_usec = diskp->dk_attachtime.tv_usec;
-		sdisk.dk_timestamp_sec = diskp->dk_timestamp.tv_sec;
-		sdisk.dk_timestamp_usec = diskp->dk_timestamp.tv_usec;
-		sdisk.dk_time_sec = diskp->dk_time.tv_sec;
-		sdisk.dk_time_usec = diskp->dk_time.tv_usec;
-		sdisk.dk_busy = diskp->dk_busy;
-
-		error = copyout(&sdisk, where, min(tocopy, sizeof(sdisk)));
-		if (error)
-			break;
-		where += tocopy;
-		*oldlenp += tocopy;
-		left -= tocopy;
-	}
-	simple_unlock(&disklist_slock);
-	return (error);
+	iostat_unbusy(diskp->dk_stats, bcount, read);
 }
 
 /*
Index: sys/nfs/nfs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/nfs/nfs_vfsops.c,v
retrieving revision 1.152
diff -u -r1.152 nfs_vfsops.c
--- sys/nfs/nfs_vfsops.c	21 Feb 2006 04:32:39 -0000	1.152
+++ sys/nfs/nfs_vfsops.c	14 Mar 2006 12:47:51 -0000
@@ -77,6 +77,12 @@
 extern struct nfsstats nfsstats;
 extern int nfs_ticks;
 
+/*
+ * keep a count of the nfs mounts to generate ficticious drive names
+ * for the per drive stats.
+ */
+unsigned int nfs_mount_count = 0;
+
 MALLOC_DEFINE(M_NFSMNT, "NFS mount", "NFS mount structure");
 
 /*
@@ -800,6 +806,13 @@
 	nmp->nm_vnode = *vpp;
 	VOP_UNLOCK(*vpp, 0);
 
+	nmp->nm_stats = iostat_alloc(IOSTAT_NFS);
+	nmp->nm_stats->parent = nmp;
+	  /* generate a ficticious drive name for the nfs mount */
+	MALLOC(nmp->nm_stats->name, char *, IOSTATNAMELEN, M_NFSMNT, M_WAITOK);
+	snprintf(nmp->nm_stats->name, IOSTATNAMELEN, "nfs%u", nfs_mount_count);
+	nfs_mount_count++;
+
 	return (0);
 bad:
 	nfs_disconnect(nmp);
@@ -869,6 +882,14 @@
 	nmp->nm_iflag |= NFSMNT_DISMNT;
 
 	/*
+	 * Clean up the stats... note that we carefully avoid decrementing
+	 * nfs_mount_count here for good reason - we may not be unmounting
+	 * the last thing mounted.
+	 */
+	FREE(nmp->nm_stats->name, M_NFSMNT);
+	iostat_free(nmp->nm_stats);
+
+	/*
 	 * There are two reference counts to get rid of here
 	 * (see comment in mountnfs()).
 	 */
Index: sys/nfs/nfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/nfs/nfs_vnops.c,v
retrieving revision 1.231
diff -u -r1.231 nfs_vnops.c
--- sys/nfs/nfs_vnops.c	1 Mar 2006 12:38:32 -0000	1.231
+++ sys/nfs/nfs_vnops.c	14 Mar 2006 12:47:52 -0000
@@ -53,6 +53,7 @@
 #include <sys/proc.h>
 #include <sys/mount.h>
 #include <sys/buf.h>
+#include <sys/disk.h>
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
 #include <sys/namei.h>
@@ -1240,7 +1241,7 @@
 	caddr_t bpos, dpos, cp2;
 	struct mbuf *mreq, *mrep, *md, *mb;
 	struct nfsmount *nmp;
-	int error = 0, len, retlen, tsiz, eof;
+	int error = 0, len, retlen, tsiz, eof, byte_count;
 	const int v3 = NFS_ISV3(vp);
 	struct nfsnode *np = VTONFS(vp);
 #ifndef NFS_V2_ONLY
@@ -1254,6 +1255,8 @@
 	tsiz = uiop->uio_resid;
 	if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize)
 		return (EFBIG);
+	iostat_busy(nmp->nm_stats);
+	byte_count = 0; /* count bytes actually transferred */
 	while (tsiz > 0) {
 		nfsstats.rpccnt[NFSPROC_READ]++;
 		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
@@ -1288,6 +1291,7 @@
 		nfsm_mtouio(uiop, retlen);
 		m_freem(mrep);
 		tsiz -= retlen;
+		byte_count += retlen;
 #ifndef NFS_V2_ONLY
 		if (v3) {
 			if (eof || retlen == 0)
@@ -1298,6 +1302,7 @@
 			tsiz = 0;
 	}
 nfsmout:
+	iostat_unbusy(nmp->nm_stats, byte_count, 1);
 	return (error);
 }
 
@@ -1347,7 +1352,7 @@
 	int committed = NFSV3WRITE_FILESYNC;
 	struct nfsnode *np = VTONFS(vp);
 	struct nfs_writerpc_context ctx;
-	int s;
+	int s, byte_count;
 	struct lwp *l = NULL;
 	size_t origresid;
 #ifndef NFS_V2_ONLY
@@ -1376,6 +1381,8 @@
 retry:
 	origresid = uiop->uio_resid;
 	KASSERT(origresid == uiop->uio_iov->iov_len);
+	iostat_busy(nmp->nm_stats);
+	byte_count = 0; /* count of bytes actually written */
 	while (tsiz > 0) {
 		uint32_t datalen; /* data bytes need to be allocated in mbuf */
 		uint32_t backup;
@@ -1508,6 +1515,7 @@
 		if (error)
 			break;
 		tsiz -= len;
+		byte_count += len;
 		if (stalewriteverf) {
 			*stalewriteverfp = TRUE;
 			stalewriteverf = FALSE;
@@ -1528,6 +1536,7 @@
 		}
 	}
 nfsmout:
+	iostat_unbusy(nmp->nm_stats, byte_count, 0);
 	if (pageprotected) {
 		/*
 		 * wait until mbufs go away.
Index: sys/nfs/nfsmount.h
===================================================================
RCS file: /cvsroot/src/sys/nfs/nfsmount.h,v
retrieving revision 1.37
diff -u -r1.37 nfsmount.h
--- sys/nfs/nfsmount.h	11 Dec 2005 12:25:17 -0000	1.37
+++ sys/nfs/nfsmount.h	14 Mar 2006 12:47:52 -0000
@@ -37,6 +37,9 @@
 
 #ifndef _NFS_NFSMOUNT_H_
 #define _NFS_NFSMOUNT_H_
+#ifdef _KERNEL
+#include <sys/disk.h>
+#endif
 
 /*
  * Arguments to mount NFS
@@ -167,6 +170,7 @@
 	int	nm_iflag;		/* internal flags */
 	int	nm_waiters;		/* number of waiting listeners.. */
 	long	nm_wcckludgetime;	/* see nfs_check_wccdata() */
+	struct io_stats *nm_stats;	/* per nfs mount statistics */
 };
 
 /*
Index: sys/sys/Makefile
===================================================================
RCS file: /cvsroot/src/sys/sys/Makefile,v
retrieving revision 1.82
diff -u -r1.82 Makefile
--- sys/sys/Makefile	11 Feb 2006 17:36:41 -0000	1.82
+++ sys/sys/Makefile	14 Mar 2006 12:47:52 -0000
@@ -12,7 +12,7 @@
 	exec_coff.h exec_ecoff.h exec_elf.h exec_script.h extattr.h extent.h \
 	fcntl.h fd_set.h fdio.h featuretest.h file.h filedesc.h filio.h \
 	float_ieee754.h fstypes.h gmon.h gpio.h hash.h \
-	ieee754.h inttypes.h ioccom.h ioctl.h ioctl_compat.h ipc.h \
+	ieee754.h inttypes.h ioccom.h ioctl.h ioctl_compat.h iostat.h ipc.h \
 	joystick.h \
 	kcore.h kgdb.h ksem.h ksyms.h ktrace.h \
 	lkm.h localedef.h lock.h lockf.h lwp.h \
Index: sys/sys/disk.h
===================================================================
RCS file: /cvsroot/src/sys/sys/disk.h,v
retrieving revision 1.33
diff -u -r1.33 disk.h
--- sys/sys/disk.h	26 Dec 2005 18:41:36 -0000	1.33
+++ sys/sys/disk.h	14 Mar 2006 12:47:52 -0000
@@ -90,6 +90,7 @@
 #include <sys/time.h>
 #include <sys/queue.h>
 #include <sys/lock.h>
+#include <sys/iostat.h>
 
 struct buf;
 struct disk;
@@ -209,15 +210,7 @@
 	 * Metrics data; note that some metrics may have no meaning
 	 * on certain types of disks.
 	 */
-	int		dk_busy;	/* busy counter */
-	uint64_t	dk_rxfer;	/* total number of read transfers */
-	uint64_t	dk_wxfer;	/* total number of write transfers */
-	uint64_t	dk_seek;	/* total independent seek operations */
-	uint64_t	dk_rbytes;	/* total bytes read */
-	uint64_t	dk_wbytes;	/* total bytes written */
-	struct timeval	dk_attachtime;	/* time disk was attached */
-	struct timeval	dk_timestamp;	/* timestamp of last unbusy */
-	struct timeval	dk_time;	/* total time spent busy */
+	struct io_stats	*dk_stats;
 
 	struct	dkdriver *dk_driver;	/* pointer to driver */
 
@@ -243,29 +236,6 @@
 	struct cpu_disklabel *dk_cpulabel;
 };
 
-#define	DK_DISKNAMELEN	16
-
-/* The following structure is 64-bit alignment safe */
-struct disk_sysctl {
-	char		dk_name[DK_DISKNAMELEN];
-	int32_t		dk_busy;
-	int32_t		pad;
-	uint64_t	dk_xfer;
-	uint64_t	dk_seek;
-	uint64_t	dk_bytes;
-	uint32_t	dk_attachtime_sec;
-	uint32_t	dk_attachtime_usec;
-	uint32_t	dk_timestamp_sec;
-	uint32_t	dk_timestamp_usec;
-	uint32_t	dk_time_sec;
-	uint32_t	dk_time_usec;
-	/* New separate read/write stats */
-	uint64_t	dk_rxfer;
-	uint64_t	dk_rbytes;
-	uint64_t	dk_wxfer;
-	uint64_t	dk_wbytes;
-};
-
 struct dkdriver {
 	void	(*d_strategy)(struct buf *);
 	void	(*d_minphys)(struct buf *);
@@ -288,11 +258,6 @@
 #define	DK_OPENRAW	5		/* open without label */
 
 /*
- * disklist_head is defined here so that user-land has access to it.
- */
-TAILQ_HEAD(disklist_head, disk);	/* the disklist is a TAILQ */
-
-/*
  * Bad sector lists per fixed disk
  */
 struct disk_badsectors {
@@ -328,10 +293,9 @@
 void	pseudo_disk_init(struct disk *);
 void	pseudo_disk_attach(struct disk *);
 void	pseudo_disk_detach(struct disk *);
-void	disk_busy(struct disk *);
-void	disk_unbusy(struct disk *, long, int);
-void	disk_resetstat(struct disk *);
-struct	disk *disk_find(char *);
+void    disk_busy(struct disk *);
+void    disk_unbusy(struct disk *, long, int);
+struct  disk *disk_find(char *);
 
 int	dkwedge_add(struct dkwedge_info *);
 int	dkwedge_del(struct dkwedge_info *);
Index: sys/sys/sysctl.h
===================================================================
RCS file: /cvsroot/src/sys/sys/sysctl.h,v
retrieving revision 1.152
diff -u -r1.152 sysctl.h
--- sys/sys/sysctl.h	25 Feb 2006 00:58:36 -0000	1.152
+++ sys/sys/sysctl.h	14 Mar 2006 12:47:53 -0000
@@ -703,15 +703,14 @@
 #define	HW_USERMEM	 6		/* int: non-kernel memory (bytes) */
 #define	HW_PAGESIZE	 7		/* int: software page size */
 #define	HW_DISKNAMES	 8		/* string: disk drive names */
-#define	HW_DISKSTATS	 9		/* struct: diskstats[] */
+#define	HW_IOSTATS	 9		/* struct: iostats[] */
 #define	HW_MACHINE_ARCH	10		/* string: machine architecture */
 #define	HW_ALIGNBYTES	11		/* int: ALIGNBYTES for the kernel */
 #define	HW_CNMAGIC	12		/* string: console magic sequence(s) */
 #define	HW_PHYSMEM64	13		/* quad: total memory (bytes) */
 #define	HW_USERMEM64	14		/* quad: non-kernel memory (bytes) */
-#define	HW_TAPENAMES	15		/* string: tape drive names */
-#define	HW_TAPESTATS	16		/* struct: tapestats[] */
-#define	HW_MAXID	16		/* number of valid hw ids */
+#define	HW_IOSTATNAMES	15		/* string: iostat names */
+#define	HW_MAXID	15		/* number of valid hw ids */
 
 #define	CTL_HW_NAMES { \
 	{ 0, 0 }, \
@@ -722,8 +721,8 @@
 	{ "physmem", CTLTYPE_INT }, \
 	{ "usermem", CTLTYPE_INT }, \
 	{ "pagesize", CTLTYPE_INT }, \
-	{ "disknames", CTLTYPE_STRING }, \
-	{ "diskstats", CTLTYPE_STRUCT }, \
+	{ "drivenames", CTLTYPE_STRING }, \
+	{ "drivestats", CTLTYPE_STRUCT }, \
 	{ "machine_arch", CTLTYPE_STRING }, \
 	{ "alignbytes", CTLTYPE_INT }, \
 	{ "cnmagic", CTLTYPE_STRING }, \
@@ -1074,8 +1073,6 @@
  * these helpers are in other files (XXX so should the nodes be) or
  * are used by more than one node
  */
-int	sysctl_hw_disknames(SYSCTLFN_PROTO);
-int	sysctl_hw_diskstats(SYSCTLFN_PROTO);
 int	sysctl_hw_tapenames(SYSCTLFN_PROTO);
 int	sysctl_hw_tapestats(SYSCTLFN_PROTO);
 int	sysctl_kern_vnode(SYSCTLFN_PROTO);
Index: usr.bin/systat/Makefile
===================================================================
RCS file: /cvsroot/src/usr.bin/systat/Makefile,v
retrieving revision 1.31
diff -u -r1.31 Makefile
--- usr.bin/systat/Makefile	7 Aug 2005 12:32:38 -0000	1.31
+++ usr.bin/systat/Makefile	14 Mar 2006 12:47:53 -0000
@@ -11,7 +11,7 @@
 CPPFLAGS+=-I${NETBSDSRCDIR}/usr.bin/vmstat -DSUPPORT_UTMP -DSUPPORT_UTMPX \
 	-I${NETBSDSRCDIR}/usr.bin/who
 CWARNFLAGS+=    -Wno-format-y2k
-SRCS=	bufcache.c cmds.c cmdtab.c disks.c df.c dkstats.c tpstats.c fetch.c \
+SRCS=	bufcache.c cmds.c cmdtab.c disks.c df.c drvstats.c fetch.c \
 	globalcmds.c icmp.c iostat.c ip.c keyboard.c main.c mbufs.c \
 	netcmds.c netstat.c pigs.c ps.c swap.c tcp.c vmstat.c utmpentry.c
 DPADD=	${LIBCURSES} ${LIBM} ${LIBKVM}
Index: usr.bin/systat/disks.c
===================================================================
RCS file: /cvsroot/src/usr.bin/systat/disks.c,v
retrieving revision 1.15
diff -u -r1.15 disks.c
--- usr.bin/systat/disks.c	26 Feb 2005 18:58:45 -0000	1.15
+++ usr.bin/systat/disks.c	14 Mar 2006 12:47:53 -0000
@@ -42,16 +42,16 @@
 
 #include "systat.h"
 #include "extern.h"
-#include "dkstats.h"
+#include "drvstats.h"
 
-static void dkselect(char *args, int truefalse, int selections[]);
+static void drvselect(char *args, int truefalse, int selections[]);
 
 void
 disks_add(char *args)
 {
 
 	if (args)
-		dkselect(args, 1, dk_select);
+		drvselect(args, 1, drv_select);
 }
 
 void
@@ -59,7 +59,7 @@
 {
 
 	if (args)
-		dkselect(args, 0, dk_select);
+		drvselect(args, 0, drv_select);
 }
 
 void
@@ -68,19 +68,19 @@
 	int i;
 
 	if (args) {
-		for (i = 0; i < dk_ndrive; i++)
-			dk_select[i] = 0;
+		for (i = 0; i < ndrive; i++)
+			drv_select[i] = 0;
 		disks_add(args);
 	} else {
 		move(CMDLINE, 0);
 		clrtoeol();
-		for (i = 0; i < dk_ndrive; i++)
+		for (i = 0; i < ndrive; i++)
 			printw("%s ", dr_name[i]);
 	}
 }
 
 static void
-dkselect(char *args, int truefalse, int selections[])
+drvselect(char *args, int truefalse, int selections[])
 {
 	char *cp;
 	int i;
@@ -98,12 +98,12 @@
 			*cp++ = '\0';
 		if (cp - args == 0)
 			break;
-		for (i = 0; i < dk_ndrive; i++)
+		for (i = 0; i < ndrive; i++)
 			if (strcmp(args, dr_name[i]) == 0) {
 				selections[i] = truefalse;
 				break;
 			}
-		if (i >= dk_ndrive)
+		if (i >= ndrive)
 			error("%s: unknown drive", args);
 		args = cp;
 	}
Index: usr.bin/systat/iostat.c
===================================================================
RCS file: /cvsroot/src/usr.bin/systat/iostat.c,v
retrieving revision 1.34
diff -u -r1.34 iostat.c
--- usr.bin/systat/iostat.c	5 Feb 2006 09:58:39 -0000	1.34
+++ usr.bin/systat/iostat.c	14 Mar 2006 12:47:53 -0000
@@ -43,8 +43,7 @@
 
 #include "systat.h"
 #include "extern.h"
-#include "dkstats.h"
-#include "tpstats.h"
+#include "drvstats.h"
 
 static  int linesperregion;
 static  double etime;
@@ -56,7 +55,6 @@
 static void histogram(double, int, double);
 static int numlabels(int);
 static int stats(int, int, int);
-static int tpstats(int, int, int);
 static void stat1(int, int);
 
 
@@ -82,11 +80,9 @@
 initiostat(void)
 {
 
-	dkinit(1);
-	tpinit(1);
+	drvinit(1);
 	cpureadstats();
-	dkreadstats();
-	tpreadstats();
+	drvreadstats();
 	return(1);
 }
 
@@ -96,11 +92,8 @@
 
 	cpureadstats();
 
-	if (dk_ndrive != 0)
-		dkreadstats();
-
-	if (tp_ndrive != 0)
-		tpreadstats();
+	if (ndrive != 0)
+		drvreadstats();
 }
 
 #define	INSET	14
@@ -110,7 +103,7 @@
 {
 	int row;
 
-	if ((dk_ndrive == 0) && (tp_ndrive == 0)) {
+	if (ndrive == 0) {
 		error("No drives defined.");
 		return;
 	}
@@ -136,13 +129,10 @@
 
 #define COLWIDTH	(9 + secs * 5 + 1 + read_write * 9 + 1)
 #define DRIVESPERLINE	((getmaxx(wnd) + 1) / COLWIDTH)
-	for (ndrives = 0, i = 0; i < dk_ndrive; i++)
-		if (cur.dk_select[i])
-			ndrives++;
-	for (i = 0; i < tp_ndrive; i++)
-		if (cur_tape.select[i])
+	for (ndrives = 0, i = 0; i < ndrive; i++)
+		if (cur.select[i])
 			ndrives++;
-	
+
 	regions = howmany(ndrives, DRIVESPERLINE);
 	/*
 	 * Deduct -regions for blank line after each scrolling region.
@@ -155,22 +145,16 @@
 	if (linesperregion < 3)
 		linesperregion = 3;
 	col = 0;
-	for (i = 0; i < (dk_ndrive + tp_ndrive); i++)
-		if (((i < dk_ndrive) && (cur.dk_select[i])) ||
-		    ((i >= dk_ndrive) && (cur_tape.select[i - dk_ndrive]))) {
+	for (i = 0; i < ndrive; i++)
+		if (cur.select[i]) {
 			if (col + COLWIDTH - 1 > getmaxx(wnd)) {
 				col = 0, row += linesperregion + 1;
 				if (row > getmaxy(wnd) - (linesperregion))
 					break;
 			}
 
-			if (i < dk_ndrive)
-				mvwprintw(wnd, row, col + 5, "%s",
-					  cur.dk_name[i]);
-			else
-				mvwprintw(wnd, row, col + 5, "%s",
-					  cur_tape.name[i - dk_ndrive]);
-			
+			mvwprintw(wnd, row, col + 5, "%s", cur.name[i]);
+
 			if (read_write)
 				mvwprintw(wnd, row, col + 11 + secs * 5,
 				    "(write)");
@@ -195,26 +179,12 @@
 	mvwaddstr(wnd, row++, INSET,
 	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
 	linesperregion = 2 + secs + (read_write ? 2 : 0);
-	for (i = 0; i < dk_ndrive; i++)
-		if (cur.dk_select[i]) {
-			if (row > getmaxy(wnd) - linesperregion)
-				break;
-			mvwprintw(wnd, row++, 0, "%7.7s  kBps|",
-			    cur.dk_name[i]);
-			mvwaddstr(wnd, row++, 0, "          tps|");
-			if (read_write) {
-				mvwprintw(wnd, row++, 0, " (write) kBps|");
-				mvwaddstr(wnd, row++, 0, "          tps|");
-			}
-			if (secs)
-				mvwaddstr(wnd, row++, 0, "         msec|");
-		}
-	for (i = 0; i < tp_ndrive; i++)
-		if (cur_tape.select[i]) {
+	for (i = 0; i < ndrive; i++) {
+		if (cur.select[i]) {
 			if (row > getmaxy(wnd) - linesperregion)
 				break;
 			mvwprintw(wnd, row++, 0, "%7.7s  kBps|",
-			    cur_tape.name[i]);
+			    cur.name[i]);
 			mvwaddstr(wnd, row++, 0, "          tps|");
 			if (read_write) {
 				mvwprintw(wnd, row++, 0, " (write) kBps|");
@@ -223,6 +193,8 @@
 			if (secs)
 				mvwaddstr(wnd, row++, 0, "         msec|");
 		}
+	}
+
 	return (row);
 }
 
@@ -231,11 +203,10 @@
 {
 	int i, row, col;
 
-	if (dk_ndrive == 0)
+	if (ndrive == 0)
 		return;
-	dkswap();
 	cpuswap();
-	tpswap();
+	drvswap();
 
 	etime = cur.cp_etime;
 	row = 1;
@@ -247,18 +218,12 @@
 		stat1(row++, i);
 	if (!numbers) {
 		row += 2;
-		for (i = 0; i < dk_ndrive; i++)
-			if (cur.dk_select[i]) {
+		for (i = 0; i < ndrive; i++)
+			if (cur.select[i]) {
 				if (row > getmaxy(wnd) - linesperregion)
 					break;
 				row = stats(row, INSET, i);
 			}
-		for (i = 0; i < tp_ndrive; i++)
-			if (cur_tape.select[i]) {
-				if (row > getmaxy(wnd) - linesperregion)
-					break;
-				row = tpstats(row, INSET, i);
-			}
 		return;
 	}
 	col = 0;
@@ -266,22 +231,8 @@
 	wdeleteln(wnd);
 	wmove(wnd, row + 3, 0);
 	winsertln(wnd);
-	for (i = 0; i < dk_ndrive; i++)
-		if (cur.dk_select[i]) {
-			if (col + COLWIDTH - 1 > getmaxx(wnd)) {
-				col = 0, row += linesperregion + 1;
-				if (row > getmaxy(wnd) - (linesperregion + 1))
-					break;
-				wmove(wnd, row + linesperregion, 0);
-				wdeleteln(wnd);
-				wmove(wnd, row + 3, 0);
-				winsertln(wnd);
-			}
-			(void) stats(row + 3, col, i);
-			col += COLWIDTH;
-		}
-	for (i = 0; i < tp_ndrive; i++)
-		if (cur_tape.select[i]) {
+	for (i = 0; i < ndrive; i++)
+		if (cur.select[i]) {
 			if (col + COLWIDTH - 1 > getmaxx(wnd)) {
 				col = 0, row += linesperregion + 1;
 				if (row > getmaxy(wnd) - (linesperregion + 1))
@@ -303,64 +254,16 @@
 	uint64_t rxfer;
 
 	/* time busy in disk activity */
-	atime = (double)cur.dk_time[dn].tv_sec +
-		((double)cur.dk_time[dn].tv_usec / (double)1000000);
-
-	/* # of k transferred */
-	rwords = cur.dk_rbytes[dn] / 1024.0;
-	wwords = cur.dk_wbytes[dn] / 1024.0;
-	rxfer = cur.dk_rxfer[dn];
-	if (!read_write) {
-		rwords = wwords;
-		rxfer += cur.dk_wxfer[dn];
-	}
-	if (numbers) {
-		mvwprintw(wnd, row, col, "%5.0f%4.0f",
-		    rwords / etime, rxfer / etime);
-		if (secs)
-			wprintw(wnd, "%5.1f", atime / etime);
-		if (read_write)
-			wprintw(wnd, " %5.0f%4.0f",
-			    wwords / etime, cur.dk_wxfer[dn] / etime);
-		return (row);
-	}
-
-	wmove(wnd, row++, col);
-	histogram(rwords / etime, 50, 0.5);
-	wmove(wnd, row++, col);
-	histogram(rxfer / etime, 50, 0.5);
-	if (read_write) {
-		wmove(wnd, row++, col);
-		histogram(wwords / etime, 50, 0.5);
-		wmove(wnd, row++, col);
-		histogram(cur.dk_wxfer[dn] / etime, 50, 0.5);
-	}
-
-	if (secs) {
-		wmove(wnd, row++, col);
-		atime *= 1000;	/* In milliseconds */
-		histogram(atime / etime, 50, 0.5);
-	}
-	return (row);
-}
-
-static int
-tpstats(int row, int col, int dn)
-{
-	double atime, rwords, wwords;
-	uint64_t rxfer;
-
-	/* time busy in disk activity */
-	atime = (double)cur_tape.time[dn].tv_sec +
-		((double)cur_tape.time[dn].tv_usec / (double)1000000);
+	atime = (double)cur.time[dn].tv_sec +
+		((double)cur.time[dn].tv_usec / (double)1000000);
 
 	/* # of k transferred */
-	rwords = cur_tape.rbytes[dn] / 1024.0;
-	wwords = cur_tape.wbytes[dn] / 1024.0;
-	rxfer = cur_tape.rxfer[dn];
+	rwords = cur.rbytes[dn] / 1024.0;
+	wwords = cur.wbytes[dn] / 1024.0;
+	rxfer = cur.rxfer[dn];
 	if (!read_write) {
 		rwords = wwords;
-		rxfer += cur_tape.wxfer[dn];
+		rxfer += cur.wxfer[dn];
 	}
 	if (numbers) {
 		mvwprintw(wnd, row, col, "%5.0f%4.0f",
@@ -369,7 +272,7 @@
 			wprintw(wnd, "%5.1f", atime / etime);
 		if (read_write)
 			wprintw(wnd, " %5.0f%4.0f",
-			    wwords / etime, cur_tape.wxfer[dn] / etime);
+			    wwords / etime, cur.wxfer[dn] / etime);
 		return (row);
 	}
 
@@ -381,7 +284,7 @@
 		wmove(wnd, row++, col);
 		histogram(wwords / etime, 50, 0.5);
 		wmove(wnd, row++, col);
-		histogram(cur_tape.wxfer[dn] / etime, 50, 0.5);
+		histogram(cur.wxfer[dn] / etime, 50, 0.5);
 	}
 
 	if (secs) {
Index: usr.bin/systat/vmstat.c
===================================================================
RCS file: /cvsroot/src/usr.bin/systat/vmstat.c,v
retrieving revision 1.62
diff -u -r1.62 vmstat.c
--- usr.bin/systat/vmstat.c	5 Feb 2006 09:54:50 -0000	1.62
+++ usr.bin/systat/vmstat.c	14 Mar 2006 12:47:53 -0000
@@ -55,8 +55,7 @@
 
 #include "systat.h"
 #include "extern.h"
-#include "dkstats.h"
-#include "tpstats.h"
+#include "drvstats.h"
 #include "utmpentry.h"
 
 static struct Info {
@@ -80,7 +79,6 @@
 static void copyinfo(struct Info *, struct Info *);
 static float cputime(int);
 static void dinfo(int, int, int);
-static void tinfo(int, int, int);
 static void getinfo(struct Info *, enum state);
 static void putint(int, int, int, int);
 static void putfloat(double, int, int, int, int, int);
@@ -221,9 +219,7 @@
 		}
 	}
 	hertz = stathz ? stathz : hz;
-	if (!dkinit(1))
-		return(0);
-	if (!tpinit(1))
+	if (!drvinit(1))
 		return(0);
 
 	/* Old style interrupt counts - deprecated */
@@ -427,8 +423,7 @@
 
 	cpuswap();
 	if (state == TIME) {
-		dkswap();
-		tpswap();
+		drvswap();
 		etime = cur.cp_etime;
 		/* < 5 ticks - ignore this trash */
 		if ((etime * hertz) < 1.0) {
@@ -558,14 +553,9 @@
 	PUTRATE(uvmexp.softs, GENSTATROW + 1, GENSTATCOL + 22, 5);
 	PUTRATE(uvmexp.faults, GENSTATROW + 1, GENSTATCOL + 27, 6);
 	for (l = 0, i = 0, r = DISKROW, c = DISKCOL;
-	     i < (dk_ndrive + tp_ndrive); i++) {
-		if (i < dk_ndrive) {
-			if (!dk_select[i])
-				continue;
-		} else {
-			if (!tp_select[i - dk_ndrive])
-				continue;
-		}
+	     i < ndrive; i++) {
+		if (!drv_select[i])
+			continue;
 
 		if (disk_horiz)
 			c += DISKCOLWIDTH;
@@ -589,10 +579,7 @@
 		}
 		l++;
 
-		if (i < dk_ndrive)
-			dinfo(i, r, c);
-		else
-			tinfo(i - dk_ndrive, r, c);
+		dinfo(i, r, c);
 	}
 	/* blank out if we lost any disks */
 	for (i = l; i < last_disks; i++) {
@@ -751,8 +738,7 @@
 	int i;
 
 	cpureadstats();
-	dkreadstats();
-	tpreadstats();
+	drvreadstats();
 	NREAD(X_NCHSTATS, &stats->nchstats, sizeof stats->nchstats);
 	if (nintr)
 		NREAD(X_INTRCNT, stats->intrcnt, nintr * LONG);
@@ -812,48 +798,20 @@
 	mvprintw(r, c, "%*.*s", DISKCOLWIDTH, DISKCOLWIDTH, dr_name[dn]);
 	ADV;
 
-	putint((int)(cur.dk_seek[dn]/etime+0.5), r, c, DISKCOLWIDTH);
-	ADV;
-	putint((int)((cur.dk_rxfer[dn]+cur.dk_wxfer[dn])/etime+0.5),
-	    r, c, DISKCOLWIDTH);
-	ADV;
-	puthumanint((cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) / etime + 0.5,
-		    r, c, DISKCOLWIDTH);
-	ADV;
-
-	/* time busy in disk activity */
-	atime = cur.dk_time[dn].tv_sec + cur.dk_time[dn].tv_usec / 1000000.0;
-	atime = atime * 100.0 / etime;
-	if (atime >= 100)
-		putint(100, r, c, DISKCOLWIDTH);
-	else
-		putfloat(atime, r, c, DISKCOLWIDTH, 1, 1);
-}
-
-static void
-tinfo(int dn, int r, int c)
-{
-	double atime;
-
-	mvprintw(r, c, "%*.*s", DISKCOLWIDTH, DISKCOLWIDTH, tp_name[dn]);
+	putint((int)(cur.seek[dn]/etime+0.5), r, c, DISKCOLWIDTH);
 	ADV;
-	ADV; /* skip over the seeks column - not relevant for tape drives */
-
-	putint((int)((cur_tape.rxfer[dn]+cur_tape.wxfer[dn])/etime+0.5),
+	putint((int)((cur.rxfer[dn]+cur.wxfer[dn])/etime+0.5),
 	    r, c, DISKCOLWIDTH);
 	ADV;
-	puthumanint((cur_tape.rbytes[dn] + cur_tape.wbytes[dn]) / etime + 0.5,
+	puthumanint((cur.rbytes[dn] + cur.wbytes[dn]) / etime + 0.5,
 		    r, c, DISKCOLWIDTH);
 	ADV;
 
 	/* time busy in disk activity */
-	atime = cur_tape.time[dn].tv_sec + cur_tape.time[dn].tv_usec / 1000000.0;
+	atime = cur.time[dn].tv_sec + cur.time[dn].tv_usec / 1000000.0;
 	atime = atime * 100.0 / etime;
 	if (atime >= 100)
 		putint(100, r, c, DISKCOLWIDTH);
 	else
 		putfloat(atime, r, c, DISKCOLWIDTH, 1, 1);
-#undef ADV
 }
-
-
Index: usr.bin/vmstat/Makefile
===================================================================
RCS file: /cvsroot/src/usr.bin/vmstat/Makefile,v
retrieving revision 1.22
diff -u -r1.22 Makefile
--- usr.bin/vmstat/Makefile	7 Aug 2005 12:23:20 -0000	1.22
+++ usr.bin/vmstat/Makefile	14 Mar 2006 12:47:53 -0000
@@ -4,7 +4,7 @@
 PROG=	vmstat
 WARNS=3
 
-SRCS=	dkstats.c tpstats.c vmstat.c
+SRCS=	drvstats.c vmstat.c
 MAN=	vmstat.1
 DPADD=	${LIBKVM}
 LDADD=	-lkvm
Index: usr.bin/vmstat/vmstat.c
===================================================================
RCS file: /cvsroot/src/usr.bin/vmstat/vmstat.c,v
retrieving revision 1.139
diff -u -r1.139 vmstat.c
--- usr.bin/vmstat/vmstat.c	5 Feb 2006 09:54:50 -0000	1.139
+++ usr.bin/vmstat/vmstat.c	14 Mar 2006 12:47:53 -0000
@@ -132,8 +132,7 @@
 #include <unistd.h>
 #include <util.h>
 
-#include "dkstats.h"
-#include "tpstats.h"
+#include "drvstats.h"
 
 /*
  * General namelist
@@ -252,8 +251,7 @@
 
 void	cpustats(void);
 void	deref_kptr(const void *, void *, size_t, const char *);
-void	dkstats(void);
-void	tpstats(void);
+void	drvstats(void);
 void	doevcnt(int verbose);
 void	dohashstat(int, int, const char *);
 void	dointr(int verbose);
@@ -405,8 +403,7 @@
 	if (todo & VMSTAT) {
 		struct winsize winsize;
 
-		dkinit(0);	/* Initialize disk stats, no disks selected. */
-		tpinit(0);
+		drvinit(0);	/* Initialize disk stats, no disks selected. */
 
 		(void)setgid(getgid()); /* don't need privs anymore */
 
@@ -511,35 +508,21 @@
 		if (isdigit((unsigned char)**argv))
 			break;
 #endif
-		for (i = 0; i < dk_ndrive; i++) {
+		for (i = 0; i < ndrive; i++) {
 			if (strcmp(dr_name[i], *argv))
 				continue;
-			dk_select[i] = 1;
+			drv_select[i] = 1;
 			++ndrives;
 			break;
 		}
-		for (i = 0; i < tp_ndrive; i++) {
-			if (strcmp(tp_name[i], *argv))
-				continue;
-			tp_select[i] = 1;
-			++ndrives;
-			break;
-		}
-	}
-	for (i = 0; i < dk_ndrive && ndrives < 3; i++) {
-		if (dk_select[i])
-			continue;
-		dk_select[i] = 1;
-		++ndrives;
 	}
-	
-	for (i = 0; i < tp_ndrive && ndrives < 3; i++) {
-		if (tp_select[i])
+	for (i = 0; i < ndrive && ndrives < 3; i++) {
+		if (drv_select[i])
 			continue;
-		tp_select[i] = 1;
+		drv_select[i] = 1;
 		++ndrives;
 	}
-	
+
 	return (argv);
 }
 
@@ -645,8 +628,8 @@
 		if (!--hdrcnt)
 			printhdr();
 		/* Read new disk statistics */
-		dkreadstats();
 		cpureadstats();
+		drvreadstats();
 		tkreadstats();
 		kread(namelist, X_UVMEXP, &uvmexp, sizeof(uvmexp));
 		if (memf != NULL) {
@@ -679,8 +662,7 @@
 		    rate(uvmexp.pgswapout - ouvmexp.pgswapout));
 		(void)printf("%4lu ", rate(uvmexp.pdfreed - ouvmexp.pdfreed));
 		(void)printf("%4lu ", rate(uvmexp.pdscans - ouvmexp.pdscans));
-		dkstats();
-		tpstats();
+		drvstats();
 		(void)printf("%4lu %4lu %3lu ",
 		    rate(uvmexp.intrs - ouvmexp.intrs),
 		    rate(uvmexp.syscalls - ouvmexp.syscalls),
@@ -716,8 +698,8 @@
 		    ndrives * 3, "");
 
 	(void)printf(" r b w    avm    fre  flt  re  pi   po   fr   sr ");
-	for (i = 0; i < dk_ndrive; i++)
-		if (dk_select[i])
+	for (i = 0; i < ndrive; i++)
+		if (drv_select[i])
 			(void)printf("%c%c ", dr_name[i][0],
 			    dr_name[i][strlen(dr_name[i]) - 1]);
 	(void)printf("  in   sy  cs us sy id\n");
@@ -884,40 +866,22 @@
 }
 
 void
-dkstats(void)
+drvstats(void)
 {
 	int dn;
 	double etime;
 
 	/* Calculate disk stat deltas. */
-	dkswap();
 	cpuswap();
+	drvswap();
 	tkswap();
 	etime = cur.cp_etime;
 
-	for (dn = 0; dn < dk_ndrive; ++dn) {
-		if (!dk_select[dn])
-			continue;
-		(void)printf("%2.0f ",
-		    (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime);
-	}
-}
-
-void
-tpstats(void)
-{
-	int dn;
-	double etime;
-
-	/* Calculate tape stat deltas. */
-	tpswap();
-	etime = cur.cp_etime;
-
-	for (dn = 0; dn < tp_ndrive; ++dn) {
-		if (!tp_select[dn])
+	for (dn = 0; dn < ndrive; ++dn) {
+		if (!drv_select[dn])
 			continue;
 		(void)printf("%2.0f ",
-		    (cur_tape.rxfer[dn] + cur_tape.wxfer[dn]) / etime);
+		    (cur.rxfer[dn] + cur.wxfer[dn]) / etime);
 	}
 }
 
Index: usr.sbin/iostat/Makefile
===================================================================
RCS file: /cvsroot/src/usr.sbin/iostat/Makefile,v
retrieving revision 1.21
diff -u -r1.21 Makefile
--- usr.sbin/iostat/Makefile	7 Aug 2005 12:34:21 -0000	1.21
+++ usr.sbin/iostat/Makefile	14 Mar 2006 12:47:53 -0000
@@ -11,7 +11,7 @@
 CPPFLAGS+=-I${NETBSDSRCDIR}/usr.bin/vmstat
 
 # dkstats.c pulled in from ../../usr.bin/vmstat
-SRCS=	dkstats.c tpstats.c iostat.c
+SRCS=	drvstats.c iostat.c
 
 DPADD=	${LIBKVM}
 LDADD=	-lkvm
Index: usr.sbin/iostat/iostat.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/iostat/iostat.c,v
retrieving revision 1.48
diff -u -r1.48 iostat.c
--- usr.sbin/iostat/iostat.c	12 Feb 2006 22:11:54 -0000	1.48
+++ usr.sbin/iostat/iostat.c	14 Mar 2006 12:47:53 -0000
@@ -88,8 +88,7 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "dkstats.h"
-#include "tpstats.h"
+#include "drvstats.h"
 
 /* Namelist and memory files. */
 char	*nlistf, *memf;
@@ -110,9 +109,9 @@
 #define	SHOW_STATS_ALL	(SHOW_STATS_1 | SHOW_STATS_2 | SHOW_STATS_X)
 
 static void cpustats(void);
-static void disk_stats(double);
-static void disk_stats2(double);
-static void disk_statsx(double);
+static void drive_stats(double);
+static void drive_stats2(double);
+static void drive_statsx(double);
 static void sig_header(int);
 static volatile int do_header;
 static void header(void);
@@ -194,14 +193,12 @@
 		defdrives -= 9;		/* XXX magic number */
 	defdrives /= 18;		/* XXX magic number */
 
-	dkinit(0);
-	tpinit(0);
+	drvinit(0);
 	cpureadstats();
-	dkreadstats();
-	tpreadstats();
+	drvreadstats();
 	ndrives = selectdrives(argc, argv);
 	if (ndrives == 0) {
-		/* No drives are selected.  No need to show disk stats. */
+		/* No drives are selected.  No need to show drive stats. */
 		todo &= ~SHOW_STATS_ALL;
 		if (todo == 0)
 			errx(1, "no drives");
@@ -226,18 +223,16 @@
 
 		if (!ISSET(todo, SHOW_TOTALS)) {
 			cpuswap();
-			dkswap();
-			tpswap();
+			drvswap();
 		}
-		
+
 		display();
 
 		if (reps >= 0 && --reps <= 0)
 			break;
 		nanosleep(&tv, NULL);
 		cpureadstats();
-		dkreadstats();
-		tpreadstats();
+		drvreadstats();
 	}
 	exit(0);
 }
@@ -271,25 +266,17 @@
 		(void)printf("      tty");
 
 	if (ISSET(todo, SHOW_STATS_1)) {
-		for (i = 0; i < dk_ndrive; i++)
-			if (cur.dk_select[i])
-				(void)printf("        %9.9s ", cur.dk_name[i]);
-		for (i = 0; i < tp_ndrive; i++)
-			if (cur_tape.select[i])
-				(void)printf("        %9.9s ",
-					     cur_tape.name[i]);
+		for (i = 0; i < ndrive; i++)
+			if (cur.select[i])
+				(void)printf("        %9.9s ", cur.name[i]);
 	}
 
 	if (ISSET(todo, SHOW_STATS_2)) {
-		for (i = 0; i < dk_ndrive; i++)
-			if (cur.dk_select[i])
-				(void)printf("        %9.9s ", cur.dk_name[i]);
-		for (i = 0; i < tp_ndrive; i++)
-			if (cur_tape.select[i])
-				(void)printf("        %9.9s ",
-					     cur_tape.name[i]);
+		for (i = 0; i < ndrive; i++)
+			if (cur.select[i])
+				(void)printf("        %9.9s ", cur.name[i]);
 	}
-	
+
 	if (ISSET(todo, SHOW_CPU))
 		(void)printf("            CPU");
 
@@ -300,15 +287,8 @@
 		printf(" tin tout");
 
 	if (ISSET(todo, SHOW_STATS_1)) {
-		for (i = 0; i < dk_ndrive; i++)
-			if (cur.dk_select[i]) {
-				if (ISSET(todo, SHOW_TOTALS))
-					(void)printf("  KB/t  xfr  MB   ");
-				else
-					(void)printf("  KB/t  t/s  MB/s ");
-			}
-		for (i = 0; i < tp_ndrive; i++)
-			if (cur_tape.select[i]) {
+		for (i = 0; i < ndrive; i++)
+			if (cur.select[i]) {
 				if (ISSET(todo, SHOW_TOTALS))
 					(void)printf("  KB/t  xfr  MB   ");
 				else
@@ -317,11 +297,8 @@
 	}
 
 	if (ISSET(todo, SHOW_STATS_2)) {
-		for (i = 0; i < dk_ndrive; i++)
-			if (cur.dk_select[i])
-				(void)printf("    KB   xfr time ");
-		for (i = 0; i < tp_ndrive; i++)
-			if (cur_tape.select[i])
+		for (i = 0; i < ndrive; i++)
+			if (cur.select[i])
 				(void)printf("    KB   xfr time ");
 	}
 
@@ -331,150 +308,33 @@
 }
 
 static void
-disk_stats(double etime)
-{
-	int dn;
-	double atime, mbps;
-
-	for (dn = 0; dn < dk_ndrive; ++dn) {
-		if (!cur.dk_select[dn])
-			continue;
-					/* average Kbytes per transfer. */
-		if (cur.dk_rxfer[dn] + cur.dk_wxfer[dn])
-			mbps = ((cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) /
-			    1024.0) / (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]);
-		else
-			mbps = 0.0;
-		(void)printf(" %5.2f", mbps);
-
-					/* average transfers per second. */
-		(void)printf(" %4.0f",
-		    (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime);
-
-					/* time busy in disk activity */
-		atime = (double)cur.dk_time[dn].tv_sec +
-		    ((double)cur.dk_time[dn].tv_usec / (double)1000000);
-
-					/* Megabytes per second. */
-		if (atime != 0.0)
-			mbps = (cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) /
-			    (double)(1024 * 1024);
-		else
-			mbps = 0;
-		(void)printf(" %5.2f ", mbps / etime);
-	}
-}
-
-static void
-disk_stats2(double etime)
-{
-	int dn;
-	double atime;
-
-	for (dn = 0; dn < dk_ndrive; ++dn) {
-		if (!cur.dk_select[dn])
-			continue;
-
-					/* average kbytes per second. */
-		(void)printf(" %5.0f",
-		    (cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) / 1024.0 / etime);
-
-					/* average transfers per second. */
-		(void)printf(" %5.0f",
-		    (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime);
-
-					/* average time busy in disk activity */
-		atime = (double)cur.dk_time[dn].tv_sec +
-		    ((double)cur.dk_time[dn].tv_usec / (double)1000000);
-		(void)printf(" %4.2f ", atime / etime);
-	}
-}
-
-static void
-disk_statsx(double etime)
-{
-	int dn;
-	double atime, kbps;
-
-	for (dn = 0; dn < dk_ndrive; ++dn) {
-		if (!cur.dk_select[dn])
-			continue;
-
-		(void)printf("%-8.8s", cur.dk_name[dn]);
-
-					/* average read Kbytes per transfer */
-		if (cur.dk_rxfer[dn])
-			kbps = (cur.dk_rbytes[dn] / 1024.0) / cur.dk_rxfer[dn];
-		else
-			kbps = 0.0;
-		(void)printf(" %8.2f", kbps);
-
-					/* average read transfers
-					   (per second) */
-		(void)printf(" %6.0f", cur.dk_rxfer[dn] / etime);
-
-					/* time read busy in disk activity */
-		atime = (double)cur.dk_time[dn].tv_sec +
-		    ((double)cur.dk_time[dn].tv_usec / (double)1000000);
-		(void)printf(" %6.2f", atime / etime);
-
-					/* average read megabytes
-					   (per second) */
-		(void)printf(" %8.2f",
-		    cur.dk_rbytes[dn] / (1024.0 * 1024) / etime);
-
-
-					/* average write Kbytes per transfer */
-		if (cur.dk_wxfer[dn])
-			kbps = (cur.dk_wbytes[dn] / 1024.0) / cur.dk_wxfer[dn];
-		else
-			kbps = 0.0;
-		(void)printf("   %8.2f", kbps);
-
-					/* average write transfers
-					   (per second) */
-		(void)printf(" %6.0f", cur.dk_wxfer[dn] / etime);
-
-					/* time write busy in disk activity */
-		atime = (double)cur.dk_time[dn].tv_sec +
-		    ((double)cur.dk_time[dn].tv_usec / (double)1000000);
-		(void)printf(" %6.2f", atime / etime);
-
-					/* average write megabytes
-					   (per second) */
-		(void)printf(" %8.2f\n",
-		    cur.dk_wbytes[dn] / (1024.0 * 1024) / etime);
-	}
-}
-
-static void
-tape_stats(double etime)
+drive_stats(double etime)
 {
 	int dn;
 	double atime, mbps;
 
-	for (dn = 0; dn < tp_ndrive; ++dn) {
-		if (!cur_tape.select[dn])
+	for (dn = 0; dn < ndrive; ++dn) {
+		if (!cur.select[dn])
 			continue;
 					/* average Kbytes per transfer. */
-		if (cur_tape.rxfer[dn] + cur_tape.wxfer[dn])
-			mbps = ((cur_tape.rbytes[dn] + cur_tape.wbytes[dn]) /
-			    1024.0) / (cur_tape.rxfer[dn] + cur_tape.wxfer[dn]);
+		if (cur.rxfer[dn] + cur.wxfer[dn])
+			mbps = ((cur.rbytes[dn] + cur.wbytes[dn]) /
+			    1024.0) / (cur.rxfer[dn] + cur.wxfer[dn]);
 		else
 			mbps = 0.0;
 		(void)printf(" %5.2f", mbps);
 
 					/* average transfers per second. */
 		(void)printf(" %4.0f",
-		    (cur_tape.rxfer[dn] + cur_tape.wxfer[dn]) / etime);
+		    (cur.rxfer[dn] + cur.wxfer[dn]) / etime);
 
-					/* time busy in disk activity */
-		atime = (double)cur_tape.time[dn].tv_sec +
-		    ((double)cur_tape.time[dn].tv_usec / (double)1000000);
+					/* time busy in drive activity */
+		atime = (double)cur.time[dn].tv_sec +
+		    ((double)cur.time[dn].tv_usec / (double)1000000);
 
 					/* Megabytes per second. */
 		if (atime != 0.0)
-			mbps = (cur_tape.rbytes[dn] + cur_tape.wbytes[dn]) /
+			mbps = (cur.rbytes[dn] + cur.wbytes[dn]) /
 			    (double)(1024 * 1024);
 		else
 			mbps = 0;
@@ -483,84 +343,84 @@
 }
 
 static void
-tape_stats2(double etime)
+drive_stats2(double etime)
 {
 	int dn;
 	double atime;
 
-	for (dn = 0; dn < tp_ndrive; ++dn) {
-		if (!cur_tape.select[dn])
+	for (dn = 0; dn < ndrive; ++dn) {
+		if (!cur.select[dn])
 			continue;
 
 					/* average kbytes per second. */
 		(void)printf(" %5.0f",
-		    (cur_tape.rbytes[dn] + cur_tape.wbytes[dn]) / 1024.0 / etime);
+		    (cur.rbytes[dn] + cur.wbytes[dn]) / 1024.0 / etime);
 
 					/* average transfers per second. */
 		(void)printf(" %5.0f",
-		    (cur_tape.rxfer[dn] + cur_tape.wxfer[dn]) / etime);
+		    (cur.rxfer[dn] + cur.wxfer[dn]) / etime);
 
-					/* average time busy in disk activity */
-		atime = (double)cur_tape.time[dn].tv_sec +
-		    ((double)cur_tape.time[dn].tv_usec / (double)1000000);
+					/* average time busy in drive activity */
+		atime = (double)cur.time[dn].tv_sec +
+		    ((double)cur.time[dn].tv_usec / (double)1000000);
 		(void)printf(" %4.2f ", atime / etime);
 	}
 }
 
 static void
-tape_statsx(double etime)
+drive_statsx(double etime)
 {
 	int dn;
 	double atime, kbps;
 
-	for (dn = 0; dn < tp_ndrive; ++dn) {
-		if (!cur_tape.select[dn])
+	for (dn = 0; dn < ndrive; ++dn) {
+		if (!cur.select[dn])
 			continue;
 
-		(void)printf("%-8.8s", cur_tape.name[dn]);
+		(void)printf("%-8.8s", cur.name[dn]);
 
 					/* average read Kbytes per transfer */
-		if (cur.dk_rxfer[dn])
-			kbps = (cur_tape.rbytes[dn] / 1024.0) / cur_tape.rxfer[dn];
+		if (cur.rxfer[dn])
+			kbps = (cur.rbytes[dn] / 1024.0) / cur.rxfer[dn];
 		else
 			kbps = 0.0;
 		(void)printf(" %8.2f", kbps);
 
 					/* average read transfers
 					   (per second) */
-		(void)printf(" %6.0f", cur_tape.rxfer[dn] / etime);
+		(void)printf(" %6.0f", cur.rxfer[dn] / etime);
 
-					/* time read busy in disk activity */
-		atime = (double)cur_tape.time[dn].tv_sec +
-		    ((double)cur_tape.time[dn].tv_usec / (double)1000000);
+					/* time read busy in drive activity */
+		atime = (double)cur.time[dn].tv_sec +
+		    ((double)cur.time[dn].tv_usec / (double)1000000);
 		(void)printf(" %6.2f", atime / etime);
 
 					/* average read megabytes
 					   (per second) */
 		(void)printf(" %8.2f",
-		    cur_tape.rbytes[dn] / (1024.0 * 1024) / etime);
+		    cur.rbytes[dn] / (1024.0 * 1024) / etime);
 
 
 					/* average write Kbytes per transfer */
-		if (cur_tape.wxfer[dn])
-			kbps = (cur_tape.wbytes[dn] / 1024.0) / cur_tape.wxfer[dn];
+		if (cur.wxfer[dn])
+			kbps = (cur.wbytes[dn] / 1024.0) / cur.wxfer[dn];
 		else
 			kbps = 0.0;
 		(void)printf("   %8.2f", kbps);
 
 					/* average write transfers
 					   (per second) */
-		(void)printf(" %6.0f", cur_tape.wxfer[dn] / etime);
+		(void)printf(" %6.0f", cur.wxfer[dn] / etime);
 
-					/* time write busy in disk activity */
-		atime = (double)cur_tape.time[dn].tv_sec +
-		    ((double)cur_tape.time[dn].tv_usec / (double)1000000);
+					/* time write busy in drive activity */
+		atime = (double)cur.time[dn].tv_sec +
+		    ((double)cur.time[dn].tv_usec / (double)1000000);
 		(void)printf(" %6.2f", atime / etime);
 
 					/* average write megabytes
 					   (per second) */
 		(void)printf(" %8.2f\n",
-		    cur_tape.wbytes[dn] / (1024.0 * 1024) / etime);
+		    cur.wbytes[dn] / (1024.0 * 1024) / etime);
 	}
 }
 
@@ -605,8 +465,7 @@
 		etime = 1.0;
 
 	if (ISSET(todo, SHOW_STATS_X)) {
-		disk_statsx(etime);
-		tape_statsx(etime);
+		drive_statsx(etime);
 		goto out;
 	}
 
@@ -614,16 +473,14 @@
 		printf("%4.0f %4.0f", cur.tk_nin / etime, cur.tk_nout / etime);
 
 	if (ISSET(todo, SHOW_STATS_1)) {
-		disk_stats(etime);
-		tape_stats(etime);
+		drive_stats(etime);
 	}
-	
+
 
 	if (ISSET(todo, SHOW_STATS_2)) {
-		disk_stats2(etime);
-		tape_stats2(etime);
+		drive_stats2(etime);
 	}
-	
+
 
 	if (ISSET(todo, SHOW_CPU))
 		cpustats();
@@ -656,19 +513,13 @@
 			break;
 #endif
 		tried++;
-		for (i = 0; i < dk_ndrive; i++) {
-			if (strcmp(cur.dk_name[i], *argv))
+		for (i = 0; i < ndrive; i++) {
+			if (strcmp(cur.name[i], *argv))
 				continue;
-			cur.dk_select[i] = 1;
-			++ndrives;
-		}
-		
-		for (i = 0; i < tp_ndrive; i++) {
-			if (strcmp(cur_tape.name[i], *argv))
-				continue;
-			cur_tape.select[i] = 1;
+			cur.select[i] = 1;
 			++ndrives;
 		}
+
 	}
 
 	if (ndrives == 0 && tried == 0) {
@@ -677,15 +528,11 @@
 		 * if none specified.
 		 */
 		maxdrives = (ISSET(todo, SHOW_STATS_X) ||
-			     (dk_ndrive + tp_ndrive) < defdrives)
-			? (dk_ndrive + tp_ndrive) : defdrives;
+			     ndrive < defdrives)
+			? (ndrive) : defdrives;
 		for (i = 0; i < maxdrives; i++) {
-			if (i >= dk_ndrive) {
-				cur_tape.select[i - dk_ndrive] = 1;
-			} else {
-				cur.dk_select[i] = 1;
-			}
-			
+			cur.select[i] = 1;
+
 			++ndrives;
 			if (!ISSET(todo, SHOW_STATS_X) && ndrives == defdrives)
 				break;

-- 
Brett Lymn