--- disk-utils/Makefile.~1~     Mon Aug 30 22:34:13 1999
+++ disk-utils/Makefile Mon Aug 30 22:32:24 1999
@@ -16,13 +16,13 @@

SBIN=          mkfs mkswap

-USRBIN=                fdformat setfdprm
+USRBIN=                fdformat setfdprm raw

ETC=           fdprm

ifneq "$(CPU)" "sparc"
# fsck and mkfs will compile, but there is no kernel support on sparc
-MAN8:=$(MAN8) fsck.minix.8 mkfs.8 mkfs.minix.8
+MAN8:=$(MAN8) fsck.minix.8 mkfs.8 mkfs.minix.8 raw.8
SBIN:=$(SBIN) fsck.minix mkfs.minix
endif

--- disk-utils/raw.8.~1~        Mon Aug 30 22:35:02 1999
+++ disk-utils/raw.8    Mon Aug 30 23:00:21 1999
@@ -0,0 +1,87 @@
+.\" -*- nroff -*-
+.TH RAW 8 "Aug 1999" "Version 0.1"
+.SH NAME
+raw \- bind a Linux raw character device
+.SH SYNOPSIS
+.B raw
+.I /dev/raw<N> <major> <minor>
+.PP
+.B raw
+.I /dev/raw<N> /dev/<blockdev>
+.PP
+.B raw
+.B \-q
+.I /dev/raw<N>
+.PP
+.B raw
+.B \-qa
+.SH DESCRIPTION
+.B raw
+is used to bind a Linux raw character device to a block device.  Any
+block device may be used: at the time of binding, the device driver does
+not even have to be accessible (it may be loaded on demand as a kernel
+module later).
+.PP
+.B raw
+is used in two modes: it either sets raw device bindings, or it queries
+existing bindings.  When setting a raw device,
+.I /dev/raw<N>
+is the device name of an existing raw device node in the filesystem.
+The block device to which it is to be bound can be specified either in
+terms of its
+.I major
+and
+.I minor
+device numbers, or as a path name
+.I /dev/<blockdev>
+to an existing block device file.
+.PP
+The bindings already in existance can be queried with the
+.I \-q
+option, with is used either with a raw device filename to query that one
+device, or with the
+.I \-a
+option to query all bound raw devices.
+.PP
+Once bound to a block device, a raw device can be opened, read and
+written, just like the block device it is bound to.  However, the raw
+device does not behave exactly like the block device.  In particular,
+access to the raw device bypasses the kernel's block buffer cache
+entirely: all I/O is done directly to and from the address space of the
+process performing the I/O.  If the underlying block device driver can
+support DMA, then no data copying at all is required to complete the
+I/O.
+.PP
+Because raw I/O involves direct hardware access to a process's memory, a
+few extra restrictions must be observed.  All I/Os must be correctly
+aligned in memory and on disk: they must start at a sector offset on
+disk, they must be an exact number of sectors long, and the data buffer
+in virtual memory must also be aligned to a multiple of the sector
+size.  The sector size is 512 bytes for most devices.
+.SH OPTIONS
+.TP
+.B -q
+Set query mode.
+.B raw
+will query an existing binding instead of setting a new one.
+.TP
+.B -a
+With
+.B -q
+, specifies that all bound raw devices should be queried.
+.TP
+.B -h
+provides a usage summary.
+.SH BUGS
+The Linux
+.B dd
+(1) command does not currently align its buffers correctly, and so
+cannot be used on raw devices.
+.PP
+Raw I/O devices do not maintain cache coherency with the Linux block
+device buffer cache.  If you use raw I/O to overwrite data already in
+the buffer cache, the buffer cache will no longer correspond to the
+contents of the actual storage device underneath.  This is deliberate,
+but is regarded either a bug or a feature depending on who you ask!
+.SH AUTHOR
+Stephen Tweedie ([email protected])
--- disk-utils/raw.c.~2~        Mon Aug 30 22:34:48 1999
+++ disk-utils/raw.c    Mon Aug 30 22:36:18 1999
@@ -0,0 +1,217 @@
+/*
+ * raw.c: User mode tool to bind and query raw character devices.
+ *
+ * Stephen Tweedie, 1999
+ *
+ * This file may be redistributed under the terms of the GNU General
+ * Public License, version 2.
+ *
+ * Copyright Red Hat Software, 1999
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/sysmacros.h>
+#include <linux/raw.h>
+#include <linux/major.h>
+
+
+char * progname;
+int    do_query = 0;
+int    do_query_all = 0;
+
+int    master_fd;
+int    raw_minor;
+
+void open_raw_ctl(void);
+int  query(int minor, int quiet);
+int  bind (int minor, int block_major, int block_minor);
+
+
+static void usage(int err)
+{
+       fprintf(stderr,
+               "Usage:\n"
+               "  %s /dev/rawN <major> <minor>\n"
+               "  %s /dev/rawN /dev/<blockdev>\n"
+               "  %s -q /dev/rawN\n"
+               "  %s -qa\n",
+               progname, progname, progname, progname);
+       exit(err);
+}
+
+
+int main(int argc, char *argv[])
+{
+       char c;
+       char * raw_name;
+       char * block_name;
+       int  err;
+       int  block_major, block_minor;
+       int  i;
+
+       struct stat statbuf;
+
+       progname = argv[0];
+
+       while ((c = getopt(argc, argv, "ahq")) != EOF) {
+               switch (c) {
+               case 'a':
+                       do_query_all = 1;
+                       break;
+               case 'h':
+                       usage(0);
+               case 'q':
+                       do_query = 1;
+                       break;
+               default:
+                       usage(1);
+               }
+       }
+
+       /*
+        * Check for, and open, the master raw device, /dev/raw
+        */
+
+       open_raw_ctl();
+
+       if (do_query_all) {
+               if (optind < argc)
+                       usage(1);
+               for (i=1; i<255; i++)
+                       query(i, 1);
+               exit(0);
+       }
+
+       /*
+        * It's a bind or a single query.  Either way we need a raw device.
+        */
+
+       if (optind >= argc)
+               usage(1);
+       raw_name = argv[optind++];
+
+       err = stat(raw_name, &statbuf);
+       if (err) {
+               fprintf (stderr, "Cannot locate raw device '%s' (%s)\n",
+                        raw_name, strerror(errno));
+               exit(2);
+       }
+
+       if (!S_ISCHR(statbuf.st_mode)) {
+               fprintf (stderr, "raw device '%s' is not a character dev\n",
+                        raw_name);
+               exit(2);
+       }
+       if (major(statbuf.st_rdev) != RAW_MAJOR) {
+               fprintf (stderr, "Device '%s' is not a raw dev\n",
+                        raw_name);
+               exit(2);
+       }
+
+       raw_minor = minor(statbuf.st_rdev);
+
+       if (do_query)
+               return query(raw_minor, 0);
+
+       /*
+        * It's not a query, so we still have some parsing to do.  Have
+        * we been given a block device filename or a major/minor pair?
+        */
+
+       switch (argc - optind) {
+       case 1:
+               block_name = argv[optind];
+               err = stat(block_name, &statbuf);
+               if (err) {
+                       fprintf (stderr,
+                                "Cannot locate block device '%s' (%s)\n",
+                                block_name, strerror(errno));
+                       exit(2);
+               }
+
+               if (!S_ISBLK(statbuf.st_mode)) {
+                       fprintf (stderr, "Device '%s' is not a block dev\n",
+                                block_name);
+                       exit(2);
+               }
+
+               block_major = major(statbuf.st_rdev);
+               block_minor = minor(statbuf.st_rdev);
+               break;
+
+       case 2:
+               block_major = strtol(argv[optind], 0, 0);
+               block_minor = strtol(argv[optind+1], 0, 0);
+               break;
+
+       default:
+               usage(1);
+       }
+
+       return bind(raw_minor, block_major, block_minor);
+       return 0;
+
+}
+
+
+void open_raw_ctl(void)
+{
+       master_fd = open("/dev/raw", O_RDWR, 0);
+       if (master_fd < 0) {
+               fprintf (stderr,
+                        "Cannot open master raw device '/dev/raw' (%s)\n",
+                        strerror(errno));
+               exit(2);
+       }
+}
+
+int query(int minor, int quiet)
+{
+       struct raw_config_request rq;
+       int err;
+
+       rq.raw_minor = minor;
+       err = ioctl(master_fd, RAW_GETBIND, &rq);
+       if (err < 0) {
+               if (quiet && errno == ENODEV)
+                       return 3;
+               fprintf (stderr,
+                        "Error querying raw device (%s)\n",
+                        strerror(errno));
+               exit(3);
+       }
+       if (quiet && !rq.block_major && !rq.block_minor)
+               return 0;
+       printf ("/dev/raw%d:    bound to major %d, minor %d\n",
+               minor, (int) rq.block_major, (int) rq.block_minor);
+       return 0;
+}
+
+int bind(int minor, int block_major, int block_minor)
+{
+       struct raw_config_request rq;
+       int err;
+
+       rq.raw_minor   = minor;
+       rq.block_major = block_major;
+       rq.block_minor = block_minor;
+       err = ioctl(master_fd, RAW_SETBIND, &rq);
+       if (err < 0) {
+               fprintf (stderr,
+                        "Error setting raw device (%s)\n",
+                        strerror(errno));
+               exit(3);
+       }
+       printf ("/dev/raw%d:    bound to major %d, minor %d\n",
+               raw_minor, (int) rq.block_major, (int) rq.block_minor);
+       return 0;
+}
+