[comp.sources.misc] Silicon disk driver for BSD UNIX

allbery@ncoast.UUCP (06/16/87)

I've gotten enough requests it's probably worth posting...
					der Mouse

				(mouse@mcgill-vision.uucp)

#! /bin/sh
#
# Shar: Shell Archiver
#
# This archive created Tue Jun 16 15:36:41 1987
# Run this through sh to create:
#	memdisk.doc
#	memdisk.c
#	mdset.c
echo x - memdisk.doc \(5929 characters\)
sed 's/^X//' > memdisk.doc << \SHAR_EOF
Xmemdisk: a silicon disk driver for UNIX.
X	 Currently in use on 4.3BSD, mtXinu 4.3+NFS, and Sunix 3.0.
X
XYou should have received:
X
X	- memdisk.doc (this file)
X	- memdisk.c
X	- mdset.c
X
XYou will need to:
X
X	- Look over the configuration section at the top of memdisk.c
X	   and change the #defines to match the system you will be
X	   using it on.  If none of the possibilities listed quite fit,
X	   you will have to guess.  If you have to guess:
X		For lockout(), try splhigh() first and if that doesn't
X		 work ("loading vmunix"/"Undefined:"/"_splhigh") then
X		 use spl7().
X		For mount.h, try doing "echo ../*/*mount.h" and see if
X		 that helps.
X
X	- Put memdisk.c somewhere; I'll assume it's in
X	   ../local/memdisk.c (that's where we have it).  If you put it
X	   somewhere else, change the filename in the next item to
X	   point to wherever you did put it.
X
X	- Put a line
Xlocal/memdisk.c		optional memdisk
X	   in ../conf/files.YOURSYSTEMNAME.  For example, our
X	   configuration is in ../conf/LARRY and the kernel is built in
X	   ../LARRY; the file with the above line is then
X	   ../conf/files.LARRY (clear enough?).
X
X	- Put a line
Xpseudo-device	memdisk		1
X	   in ../conf/YOURSYSTEMNAME.  The 1 specifies how many silicon
X	   disk devices you want to configure in; you may want to
X	   increase it.
X
X	- Edit conf.c.  This file is in ../vax for VAX and MicroVAX
X	   configurations and seems to be in ../sun (rather than
X	   ../machine, which is a link to sun2 or sun3 depending on
X	   which sort of Sun you have) for Suns.  You will need to
X	   insert the following, somewhere early (before both cdevsw[]
X	   and bdevsw[]).
X#include "memdisk.h"
X#if NMEMDISK > 0
Xextern int memdiskopen();
Xextern int memdiskstrategy();
Xextern int memdiskread();
Xextern int memdiskwrite();
Xextern int memdiskioctl();
Xextern int memdiskdump();
Xextern int memdisksize();
X#else
X#define memdiskopen nodev
X#define memdiskstrategy nodev
X#define memdiskread nodev
X#define memdiskwrite nodev
X#define memdiskioctl nodev
X#define memdiskdump nodev
X#define memdisksize nodev
X#endif
X	   Now you need to add a device to each of bdevsw[] and
X	   cdevsw[].  The bdevsw entry should look like
X	{ memdiskopen,	nulldev,	memdiskstrategy,memdiskdump,	/* 10 */
X	  memdisksize,	0 },
X	   (the 10 should be changed to whatever number you choose to
X	   put it at).  The cdevsw entry should look like
X    {
X	memdiskopen,	nulldev,	memdiskread,	memdiskwrite,	/* 34 */
X	memdiskioctl,	nulldev,	nodev,		0,
X	seltrue,	0,
X    },
X	   again, with the 34 changed to whatever is appropriate.
X
X	- add a #define to ../h/ioctl.h:
X#define LIOC_MEM_SET	_IOW(l,0,int)			/* start/stop disk */
X
XYou can now re-run config and rebuild your kernel.  If you get
Xcomplaints when trying to rebuild your kernel about "Don't know how to
Xmake ../h/mount.h" (or ../ufs/ufsmount.h, or ../ufs/mount.h), then try
Xtaking the ones it complains about right out of memdisk.c and redoing
Xthe make depend.
X
XIf I haven't forgotten anything (:-), it should run fine.  Test the new
Xkernel.  When you are satisfied that adding the memdisk driver hasn't
Xbroken anything else, you can try it out:
X
X	- Create entries in /dev.  We use /dev/mdisk0 and /dev/rmdisk0
X	   (just 0 since we have just one configured in - if we had
X	   two, they'd be mdisk0/rmdisk0 and mdisk1/rmdisk1).
X
X	- Compile mdset.c; put the binary wherever you feel
X	   appropriate.  As with any disk drive, the /dev entries
X	   should be mode xx0, probably mode 600 is best, unless you
X	   wouldn't mind entrusting all your users with your root
X	   password.  Mdset must be able to open the raw device
X	   /dev/rmdisk0 (or rmdisk1, or 2, or...) in order to function.
X
X	- Run mdset to allocate memory to the disk.  When the system is
X	   booted, no memory is allocated to the disk.  Mdset takes two
X	   arguments.  The first argument must be the disk unit number
X	   (the trailing number on the /dev entry), the second must be
X	   the number of bytes of memory to allocate to the disk and
X	   must be a multiple of 512 (the usual sector size for a
X	   disk).  The second argument can have a trailing k or m to
X	   indicate kilo- or mega- bytes (eg, 512k indicates a half-meg
X	   disk).  If mdset runs and doesn't crash the system, the
X	   silicon drive should now have some memory allocated to it.
X	   You can now run mkfs (or newfs, if you give it a size) to
X	   create a filesystem on the disk, then you can put whatever
X	   you want there.  Note that the size argument to mkfs is the
X	   number of sectors, ie, the number of bytes divided by 512.
X	   If you use the k abbreviation, the number to pass to mkfs
X	   will be twice the number before the k; if you use m, the
X	   mkfs size will be 2048 times the number before the m.
X
XFor example, suppose we want to allocate a half-meg to /tmp:
X
X# mdset 0 512k
X
XIf the driver can't get the memory, it will produce a message
Xmdset: cannot set size for /dev/rmdisk0: <message>
Xwhere <message> is one of the standard error messages (see intro(2)),
Xmost likely "Not enough core".
X
XNow the disk has memory, but the contents of the memory are basically
Xrandom.  So we make a filesystem:
X
X# /etc/mkfs /dev/rmdisk0 1024
X....mkfs messages....
X
XNow sync the disk just to be safe.  It works just as well to run fsck
Xon it, I find; but if you do neither, I have had it crash mysteriously
Xsometimes (I suspect that some critical filesystem data, like
Xsuperblocks, is still waiting to be written to the disk, because the
Xmkfs used /dev/rmdisk0 instead of /dev/mdisk0).
X
X# sync
X
XNow we can mount it somewhere:
X
X# /etc/mount /dev/mdisk0 /tmp
X
XAnd away we go!  Note that you do not want to put anything on a silicon
Xdrive that is both important and difficult to recreate, because every
Xtime the machine goes down, everything on a silicon drive is lost.
X/tmp is a reasonable thing to put on a silicon drive; a read-only copy
Xof something that gets used heavily could also be a win.
X
X					der Mouse
X
X				(mouse@mcgill-vision.uucp)
SHAR_EOF
if test 5929 -ne "`wc -c memdisk.doc`"
then
echo shar: error transmitting memdisk.doc \(should have been 5929 characters\)
fi
echo x - memdisk.c \(4858 characters\)
sed 's/^X//' > memdisk.c << \SHAR_EOF
X/*
X * Silicon disk driver.
X *
X * Copyright 1987 by Mike Parker.
X * You may do anything you like with this as long as you don't:
X *	- claim you wrote any part of it that you didn't (ie, you may
X *	   of course claim any modifications you've made, but not any
X *	   of my code); nor
X *	- change or delete this copyright notice.
X * Note also that I do not take any responsibility for anything this code
X * may do.  I have tried to make it useful but I can't promise anything.
X *
X * If you find any bugs I'd appreciate hearing about them, especially
X * if you also fix them.  Write to mouse@mcgill-vision.uucp.
X */
X
X/* Configuration. */
X
X/* What spl... do we use for total lockout?  (We assume splx() un-locks.) */
X#define lockout() splhigh() /* works on 4.3BSD derivatives for the VAX */
X/* #define lockout() spl7() /* works on Sun UNIX 3.0 */
X
X/* Where is mount.h? */
X#define UFS_UFSMOUNT /* ../ufs/ufsmount.h: works on mtXinu 4.3+NFS */
X/* #define H_MOUNT /* ../h/mount.h: works on 4.3 */
X/* #define UFS_MOUNT /* ../ufs/mount.h: works on Sun UNIX 3.0 */
X
X#include "memdisk.h"
X
X#if NMEMDISK > 0
X
X#include "../h/param.h"
X#include "../h/systm.h"
X#include "../h/ioctl.h"
X#include "../h/buf.h"
X#include "../h/conf.h"
X#include "../h/time.h"
X#include "../h/kernel.h"
X#include "../h/errno.h"
X#ifdef UFS_UFS_MOUNT
X#include "../ufs/ufsmount.h"
X#endif
X#ifdef H_MOUNT
X#include "../h/mount.h"
X#endif
X#ifdef UFS_MOUNT
X#include "../ufs/mount.h"
X#endif
X
Xint max_md_size = (2048+512) * 1024; /* 2.5Mb */
X
Xstatic struct memdiskinfo {
X	 int busy;
X	 int live;
X	 int unit;
X	 int nbytes;
X	 char *data; } memdiskinfo[NMEMDISK];
Xstatic int didinit = 0;
X
X#define OKUNIT(u) (((u)>=0)&&((u)<NMEMDISK))
X#define LIVEUNIT(u) (OKUNIT(u)&&memdiskinfo[u].live)
X
Xmemdiskopen(dev,flag)
Xdev_t dev;
Xint flag;
X{
X int unit;
X int s;
X
X#ifdef lint
X flag = flag;
X#endif
X unit = minor(dev);
X if (! OKUNIT(unit))
X  { return(ENXIO);
X  }
X s = lockout();
X if (! didinit)
X  { for (unit=0;unit<NMEMDISK;unit++)
X     { register struct memdiskinfo *mdi;
X       mdi = &memdiskinfo[unit];
X       mdi->busy = 0;
X       mdi->live = 0;
X       mdi->unit = unit;
X     }
X    didinit = 1;
X  }
X splx(s);
X return(0);
X}
X
Xmemdiskstrategy(bp)
Xstruct buf *bp;
X{
X int unit;
X register struct memdiskinfo *mdi;
X int off;
X int nblk;
X int s;
X
X unit = minor(bp->b_dev);
X if (! LIVEUNIT(unit))
X  { bp->b_flags |= B_ERROR;
X    iodone(bp);
X    return;
X  }
X mdi = &memdiskinfo[unit];
X s = lockout();
X if (mdi->busy)
X  { splx(s);
X    bp->b_flags |= B_ERROR;
X    iodone(bp);
X    return;
X  }
X off = dbtob(bp->b_blkno);
X if ( (off < 0) ||
X      (off+bp->b_bcount > mdi->nbytes) )
X  { splx(s);
X    bp->b_flags |= B_ERROR;
X    iodone(bp);
X    return;
X  }
X if (bp->b_flags & B_READ)
X  { bcopy(mdi->data+off,bp->b_un.b_addr,bp->b_bcount);
X  }
X else
X  { bcopy(bp->b_un.b_addr,mdi->data+off,bp->b_bcount);
X  }
X splx(s);
X iodone(bp);
X}
X
Xmemdiskread(dev,uio)
Xdev_t dev;
Xstruct uio *uio;
X{
X static struct buf b[NMEMDISK];
X int unit = minor(dev);
X
X if (! LIVEUNIT(unit))
X  { return(ENXIO);
X  }
X return(physio(memdiskstrategy,&b[unit],dev,B_READ,minphys,uio));
X}
X
Xmemdiskwrite(dev,uio)
Xdev_t dev;
Xstruct uio *uio;
X{
X static struct buf b[NMEMDISK];
X int unit = minor(dev);
X
X if (! LIVEUNIT(unit))
X  { return(ENXIO);
X  }
X return(physio(memdiskstrategy,&b[unit],dev,B_WRITE,minphys,uio));
X}
X
Xmemdiskioctl(dev,cmd,data,flag)
Xdev_t dev;
Xint cmd;
Xcaddr_t data;
Xint flag;
X{
X int unit;
X int rv;
X int nb;
X struct memdiskinfo *mdi;
X int s;
X
X unit = minor(dev);
X#ifdef lint
X flag = flag;
X#endif
X if (! OKUNIT(unit))
X  { return(ENXIO);
X  }
X mdi = &memdiskinfo[unit];
X rv = 0;
X switch (cmd)
X  { case LIOC_MEM_SET:
X       nb = * (int *) data;
X       if ( (nb < 0) ||
X	    (nb != dbtob(btodb(nb))) ||
X	    (nb > max_md_size) )
X	{ rv = EINVAL;
X	  break;
X	}
X       if (unit_mounted(unit))
X	{ rv = EBUSY;
X	  break;
X	}
X       s = lockout();
X       if (mdi->busy)
X	{ splx(s);
X	  return(EALREADY);
X	}
X       mdi->busy = 1;
X       splx(s);
X       if (mdi->live)
X	{ wmemfree(mdi->data,mdi->nbytes);
X	  mdi->live = 0;
X	}
X       if (nb > 0)
X	{ mdi->nbytes = nb;
X	  mdi->data = wmemall(memall,nb);
X	  if (mdi->data == 0)
X	   { rv = ENOMEM;
X	   }
X	  else
X	   { mdi->live = 1;
X	   }
X	}
X       mdi->busy = 0;
X       break;
X    default:
X       rv = ENOTTY;
X       break;
X  }
X return(rv);
X}
X
Xmemdiskdump()
X{
X return(ENXIO);
X}
X
Xmemdisksize(dev)
Xdev_t dev;
X{
X int unit = minor(dev);
X
X if (! LIVEUNIT(unit))
X  { return(-1);
X  }
X return(btodb(memdiskinfo[unit].nbytes));
X}
X
Xstatic int unit_mounted(unit)
Xint unit;
X{
X struct mount *mp;
X int s;
X dev_t dev;
X
X s = spl4(); /* as long as ipl > 0, (u)mounts can't happen */
X for (mp= &mounttab[0];mp<&mounttab[NMOUNT];mp++)
X  { if (mp->m_bufp != NULL)
X     { dev = mp->m_dev;
X       if ( (bdevsw[major(dev)].d_strategy == memdiskstrategy) &&
X	    (minor(dev) == unit) )
X	{ splx(s);
X	  return(1);
X	}
X     }
X  }
X splx(s);
X return(0);
X}
X
X#endif
SHAR_EOF
if test 4858 -ne "`wc -c memdisk.c`"
then
echo shar: error transmitting memdisk.c \(should have been 4858 characters\)
fi
echo x - mdset.c \(1367 characters\)
sed 's/^X//' > mdset.c << \SHAR_EOF
X#include <stdio.h>
X#include <sys/file.h>
X#include <sys/ioctl.h>
X
Xchar **argvec;
X
X/* usage: mdset <unit> <size> */
X/* size can have suffix k or m */
X/* assumes /dev/[r]mdisk%d naming scheme */
X
Xint mdfd;
Xchar mdname[64];
X
Xint geti(s)
Xregister char *s;
X{
X register int i;
X
X i = 0;
X for (;*s;s++)
X  { switch (*s)
X     { case '0': case '1': case '2': case '3': case '4':
X       case '5': case '6': case '7': case '8': case '9':
X	  i = (i * 10) + (*s - '0');
X	  break;
X       case 'm': case 'M':
X	  i *= 1024;
X	  /* fall through */
X       case 'k': case 'K':
X	  i *= 1024;
X	  break;
X       default:
X	  return(-1);
X     }
X  }
X return(i);
X}
X
Xmain(ac,av)
Xint ac;
Xchar **av;
X{
X int unit;
X int size;
X
X argvec = av;
X if (ac != 3)
X  { fprintf(stderr,"Usage: %s unit size\n",argvec[0]);
X    exit(1);
X  }
X unit = geti(av[1]);
X size = geti(av[2]);
X if (unit < 0)
X  { fprintf(stderr,"%s: bad number `%s'\n",argvec[0],av[1]);
X    exit(1);
X  }
X if (size < 0)
X  { fprintf(stderr,"%s: bad number `%s'\n",argvec[0],av[2]);
X    exit(1);
X  }
X sprintf(mdname,"/dev/rmdisk%d",unit);
X mdfd = open(mdname,O_RDWR,0);
X if (mdfd < 0)
X  { fprintf(stderr,"%s: cannot open %s: ",argvec[0],mdname);
X    perror((char *)0);
X    exit(1);
X  }
X if (ioctl(mdfd,LIOC_MEM_SET,&size) < 0)
X  { fprintf(stderr,"%s: cannot set size for %s: ",argvec[0],mdname);
X    perror((char *)0);
X    exit(1);
X  }
X exit(0);
X}
SHAR_EOF
if test 1367 -ne "`wc -c mdset.c`"
then
echo shar: error transmitting mdset.c \(should have been 1367 characters\)
fi
exit 0
# end of shell archive