Subject: Re: Call for review: The New Block/Character Device Switch Configuration Framework
To: None <maekawa@math.sci.kobe-u.ac.jp, matt@3am-software.com>
From: Chris Torek <torek@elf.eng.bsdi.com>
List: tech-kern
Date: 07/01/2001 17:42:28
I still say the Right Answer is to remove the distinction between
block and character device numbers.  Note: this does not mean
"remove the distinction between block and character devices".  I
mean "remove the distinction between their NUMBERS": block device
#17 will then always correspond to a character device #17, and vice
versa.

This works really well.  An inode of type "block device" has a
major and minor number, and an inode of type "character device"
has a major and minor number, and the spec_open() code reads, in
part:

	int maj;
	struct devsw *dev;

	maj = major(dev);
	if ((u_int)maj >= ndevsw || (ds = devsw[maj]) == NULL)
		return ENXIO;

	switch (vp->v_type) {

	case VCHR:
		...
		error = ds->d_open(dev, mode, S_IFCHR, proc);
		...

	case VBLK:
		/*
		 * Character-only devices have no strategy function.
		 * This is what distinguishes them from block-and-char.
		 */
		if (ds->d_strategy == NULL)
			return (ENOTBLK);
		...
		error = ds->d_open(dev, mode, S_IFBLK, proc);
		...
	}

There is not now, and probably never has been, a device that is
"block-only".  Certainly such a thing makes no sense: "blocking"
is simply a behavior imposed upon what would otherwise be a raw
byte stream.

In BSD/OS, we support backwards-compatibility with old (and non-native)
file systems in the ioconf.c.${MACHINE} code.  (This depends on the fact
that our dev_t encoding guarantees dv_makedev(1,0,0) > 65535.)  The
actual code for devcompat() appears below.

This renumbering simplifies the MAKEDEV scripts and completely
eliminates the nasty goof-up of the form: "ok, I just added my new
zonk-disk driver, #75 and 103 -- `mknod /dev/zonk0c b 75 0 2' and
`newfs zonk0c' ... oops, I just wiped everything out because I gave
it block #75 instead of #103, when they are the other way around ..."

Chris

#ifdef COMPAT_DEV
/*
 * Old (and SunOS) block device numbers:
 *	7 =  /dev/sd* = scsi disk	=> 17
 *	10 = /dev/xd* = "xd" disk	=> 42
 *	11 = /dev/st* = scsi tape	=> 18
 *	16 = /dev/floppy		=> 54
 *	17 = "vd_unused" (SunOS)
 *	18 = /dev/sr (SunOS) = our scsi disk
 *	19--21 = "vd_unused" (SunOS)
 *	22--49 = "id" IPI disks (SunOS)
 */

int
devcompat(dev, ty)
	dev_t dev;
	int ty;
{
	int omaj, omin, unit, part;

	/*
	 * Check for new encoding (major(dev) >= 1).  This calls
	 * /dev/console `old' and maps it, but /dev/console is character
	 * device <0,0,0>, and 0 maps to 0.
	 */
	if (major(dev) == 0) {
		omaj = dev >> 8;
		omin = dev & 0xff;
		unit = omin >> 3;
		part = omin & 7;
		if (ty == VBLK) {
			/* Old block numbering */
			switch (omaj) {
			case 7:			/* /dev/sdXX */
				dev = dv_makedev(17, unit, part);
				break;
#ifdef unneeded
			case 10:		/* /dev/xdXX -- no drivers */
				dev = dv_makedev(42, unit, part);
				break;
#endif
			case 11:		/* /dev/stXX */
				dev = makedev(18, omin);	/* ??? */
				break;
			case 16:		/* /dev/floppy */
				dev = dv_makedev(54, unit, part);
				break;
			default:
				dev = NODEV;
				break;
			}
		} else {
			/* Char majors unchanged, but must convert subspecs */
			switch (omaj) {
			case 17:		/* /dev/rsdXX */
#ifdef unneeded
			case 42:		/* /dev/rxdXX */
#endif
			case 54:		/* /dev/floppy */
				dev = dv_makedev(omaj, unit, part);
				break;
			default:
				dev = makedev(omaj, omin);
				break;
			}
		}
	}
	return (dev);
}
#endif /* COMPAT_DEV */