Files
Arquivotheca.SunOS-4.1.4/sys/sundev/rd.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

488 lines
13 KiB
C

#ifndef lint
static char sccsid[] = "@(#)rd.c 1.1 94/10/31 Copyr 1983 Sun Micro";
#endif
/*
* RAM pseudo-device to let data live in real memory. In its present form
* it is meant to hold a root file system. When first accessed, it will
* prompt at the console for the name of a local block device. It will
* then copy a 4.2 file system from that device into a dynamically
* allocated chunk of memory sized to fit that file system.
*/
#include "rd.h"
#if NRD > 0
#include <sys/param.h> /* Includes <sys/types.h> */
#include <sys/errno.h>
#include <sys/buf.h>
#include <sys/file.h>
#include <sys/kmem_alloc.h>
#include <ufs/fs.h>
#include <sundev/mbvar.h>
#include <sys/user.h>
#include <sys/conf.h>
#include <sys/uio.h>
#include <sys/ioccom.h>
#include <sys/mtio.h>
#include <sys/vnode.h>
#include <vm/page.h>
#ifdef sun4c /* and anyone else doing programmed IO of boot devices? */
#include <machine/clock.h>
#endif
#include <sun/dklabel.h>
#ifdef sun3 /* XXX sun3e HACK */
#include <machine/cpu.h>
#endif sun3
#ifdef RAMDISK_PRELOADED
#include <mon/sunromvec.h>
#ifndef MUNIXFS_SIZE
/*
* HARDCODE (yecch!) numbers from sundist/Makefile
* XXX ought to have a included config file in both Makefiles
*/
#if defined(sun4) || defined(sun4c) || defined(sun4m)
#define MUNIXFS_SIZE 4096
#elif defined(sun3) || defined(sun3x)
#define MUNIXFS_SIZE 3072
#endif
#endif /* not MUNIXFS_SIZE */
int ramdiskispreloaded = 0;
/*
* space for filesys, aligned at word, as well as force into data segment.
* also init'd with its size, so stamprd.c can check it.
*/
int ramdisk0[(DEV_BSIZE * MUNIXFS_SIZE) / sizeof (int)] =
{ ((int)(DEV_BSIZE * MUNIXFS_SIZE)), 0, 2 };
#endif RAMDISK_PRELOADED
extern char *strncpy();
/* UNITIALIZED matches value of unitialized data structure */
typedef enum { UNINITIALIZED = 0, INITIALIZED, FAILED } rdstate_t;
typedef struct {
caddr_t data;
u_int size;
rdstate_t state;
} ramdisk_t;
ramdisk_t rd[NRD];
off_t rd_offset = 0; /* offset in disk blocks */
extern int loadramdiskfile;
#ifndef OPENPROMS
/* This structure exists because swapgeneric.c:getchardev() wants to see it. */
struct mb_driver rddriver = {
0, /* probe: see if a driver is really there */
0, /* slave: see if a slave is there */
0, /* attach: setup driver for a slave */
0, /* go: routine to start transfer */
0, /* done: routine to finish transfer */
0, /* poll: polling interrupt routine */
0, /* size: mount of memory space needed */
"rd", /* dname: name of a device */
0, /* dinfo: backpointers to mbdinit structs */
"rd", /* cname: name of a controller */
0, /* cinfo: backpointers to mbcinit structs */
MDR_PSEUDO, /* flags: Mainbus usage flags */
0, /* link: interrupt routine linked list */
};
#else !OPENPROMS
/*
* This is a pseudo-device that needs to be initialized properly,
* and only at the proper time. Unfortunately, at the time of this
* writing, we don't yet have a clever way to do this worked out,
* so the hacks that are present in ../sun/swapgeneric.c will
* have to suffice.
*
*/
#endif !OPENPROMS
#define TAPEBLOCK(x) ((daddr_t)(((x)*(BLKDEV_IOSIZE/DEV_BSIZE))))
static int fnumber = -1;
ramdisk_t *
ramdisk(dev)
dev_t dev;
{
register ramdisk_t *rdp;
dev_t cdev, bdev; /* get ram disk data from here */
char devname[128]; /* name gets copied back to this char array */
extern u_int max_page_get, total_pages;
u_int save_max_page_get;
struct cdevsw *dp;
int e;
#ifdef sun4c /* and anyone else doing programmed IO of boot devices? */
int savedmonclock;
#endif
rdp = &rd[minor(dev)];
if (rdp < &rd[NRD] && rdp->state != UNINITIALIZED)
return (rdp->state == INITIALIZED ? rdp : (ramdisk_t *)0);
else if (rdp >= &rd[NRD])
return ((ramdisk_t *)0);
#ifdef RAMDISK_PRELOADED
if ((minor(dev) == 0) && ramdiskispreloaded) {
if (rdp->state == INITIALIZED)
return (rdp);
rdp->data = (caddr_t)ramdisk0;
rdp->size = DEV_BSIZE * MUNIXFS_SIZE;
rdp->state = INITIALIZED;
printf("rd0: using preloaded munixfs\n");
#ifdef OPENPROMS
/* XXX OPENBOOT warning! */
/* XXX: devname is limitted to 2 char name */
(void) prom_get_boot_dev_name(rdp->data, 3);
rdp->data[2] = prom_get_boot_dev_unit() + '0';
rdp->data[3] = prom_get_boot_dev_part() + 'a';
rdp->data[4] = (char)0;
#else OPENPROMS
rdp->data[0] = (*romp->v_bootparam)->bp_dev[0];
rdp->data[1] = (*romp->v_bootparam)->bp_dev[1];
rdp->data[2] = '0' + (*romp->v_bootparam)->bp_unit;
/* XXX NOTE: do this - OR - just say NO to PRE-loaded non OPENPROM machines */
/* XXX #ifndef OPENPROM (kinda - Campus PROMS too) *XXX*/
/* XXX rdp->data[2] = INSCRUTABLE_TRANSLATION(rdp->data[2]); *XXX*/
/* XXX #endif *XXX*/
rdp->data[3] = 'a' + (*romp->v_bootparam)->bp_part;
rdp->data[4] = '\0';
#endif OPENPROMS
return (rdp);
}
#endif RAMDISK_PRELOADED
retry:
/* initialize the ramdisk from something */
(void)bzero(devname, sizeof (devname));
getchardev("Initialize ram disk from", devname, &fnumber, &cdev, &bdev);
#ifdef sun4c /* and anyone else doing programmed IO of boot devices? */
/*
* as to why this HACK is here: the problem is that the proms
* use level 14 interrupts to poll the keyboard every 10 ms, and lock
* out the floppy - which always gets overruns and we can't load the
* ramdisk. Choices: (a) fix proms to use keyboard interrupts instead
* [-too much code to do so quickly], (b) put DMA on floppy chip
* [-WAY too late for that], (c) add a bunch of code to fd.c to do
* reads by wait with spl15 and knowing that its at MUNIX and loading
* ramdisk [-will hang system, too much code to do so quickly], or
* (d) bump the monitor's clock down in either rd.c or fd.c.
* since the problem could be generic (for similar PIO devices) -AND-
* rd.c/swapgeneric.c are the dumping place for HACKS, it goes here.
*/
/* if "fd" or other similar semi-fast PIO device... */
if (devname[0] == 'f' && devname[1] == 'd') {
/* slow down the monitor clock to 2 seconds */
savedmonclock = COUNTER->limit14;
COUNTER->limit14 = (2 * 1000000) << CTR_USEC_SHIFT;
} else
#endif
/*
* if cdrom, it can't understand partitions, so
* we teach the ramdisk drive how to read the disk label.
* we also have to strip out the partition number.
* we don't optimize for sd, as we want to test this!
*/
if (devname[0] == 's' && ((devname[1] == 'd') || (devname[1] == 'r'))) {
struct vnode *vp;
dev_t part;
struct dk_label dkl; /* is 512 bytes (better be!) */
part = minor(bdev) & 0x7; /* 8 partitions! */
bdev = bdev & ~(0x7); /* force to partition "a" */
if (bdevsw[major(bdev)].d_open(bdev, FREAD, u.u_cred) != 0) {
printf("rd: can't open sr bdev of: %s\n", devname);
goto outnull;
}
vp = bdevvp(bdev);
if (rd_readidev(vp, (daddr_t)0, (caddr_t)&dkl, 512)) {
printf("rd: can't read sr label on: %s\n", devname);
goto outnull;
}
/* now set rd_offset (in DEV_BSIZE units) */
rd_offset = btodb(loadramdiskfile) +
(dkl.dkl_map[part].dkl_cylno *
(dkl.dkl_nsect * dkl.dkl_nhead));
printf("rd: rd_offset of \"%s\" is %d\n", devname, rd_offset);
goto opened;
}
/* fnumber != -1 return from getchardev() means TAPE (& tape ONLY!) */
if ((fnumber > 0) && (major(cdev) != major(-1))) {
struct mtop op;
#ifdef sun3 /* XXX sun3e HACK */
if ((cpu == CPU_SUN3_E) && (devname[0] == 's') &&
(devname[1] =='t')) {
cdev |= MT_DENSITY2; /* force to QIC-24 */
bdev |= MT_DENSITY2;
}
#endif sun3
dp = &cdevsw[major(cdev)];
if ((*dp->d_open)(cdev, FREAD, u.u_cred) != 0)
goto outnull;
op.mt_op = MTFSF;
op.mt_count = fnumber;
if ((*dp->d_ioctl)(cdev, MTIOCTOP, &op, 0) != 0)
goto outnull;
} else {
if (bdevsw[major(bdev)].d_open(bdev, FREAD, u.u_cred) != 0)
goto outnull;
}
opened:
/* read the 4.2 file system in a semi-portable fashion */
/* ignore the usual allocation limits */
save_max_page_get = max_page_get; /* save arbitrary limits */
max_page_get = total_pages;
if ((e = rd_readdata(bdev, rdp)) != 0) {
struct vnode *vp;
(void)printf(
"ramdisk: error %d, try another tape file # or floppy disk\n", e);
(*dp->d_close)(bdev);
vp = bdevvp(bdev);
binval(vp);
goto retry;
} else
rdp->state = INITIALIZED;
max_page_get = save_max_page_get; /* restore arbitrary limits */
if ((fnumber > 0) && (major(cdev) != major(-1)))
(*dp->d_close)(cdev);
else {
if (bdevsw[major(bdev)].d_close(bdev, FREAD, u.u_cred) != 0)
rdp->state = FAILED;
}
/*
* whew: we got here ok, now lets stuff the 1st block of the ramdisk
* (if unit 0) with where loading from (as Unix devname).
* useful for munixfs extract of miniroot
*/
if (rdp == &rd[0])
(void)strncpy(rdp->data, devname, sizeof (devname));
outnull: /* if rdp->state != INITIALIZED, we'll return null */
#ifdef sun4c /* and anyone else doing programmed IO of boot devices? */
if (devname[0] == 'f' && devname[1] == 'd') {
/* restore the monitor clock */
COUNTER->limit14 = savedmonclock;
}
#endif
return (rdp->state == INITIALIZED ? rdp : (ramdisk_t *)0);
}
/*
* rd_readidev - read from the initializing device
*/
rd_readidev(vp, bno, base, len)
struct vnode *vp;
daddr_t bno;
caddr_t base;
int len;
{
struct buf *tp;
int e;
bno += rd_offset;
tp = bread(vp, bno, len);
if ((e = geterror(tp)) == 0)
bcopy(tp->b_un.b_addr, base, (u_int)len);
brelse(tp);
return (e);
}
rd_readdata(dev, rdp)
dev_t dev;
register ramdisk_t *rdp;
{
register caddr_t data;
register int maxblock, chunk, i;
int bsize, nblocks;
int e;
struct vnode *vp;
vp = bdevvp(dev);
rdp->size = (u_int)(BBSIZE + SBSIZE);
if ((data = new_kmem_alloc(rdp->size, KMEM_NOSLEEP)) == 0)
return (1);
/*
* Egregious hack for tapes here. xt driver attempts
* to position you. This doesn't work for a variety of reasons.
* The st driver ignores you. The ar tape device pisses on you.
* So, we will hack these reads to always be the right blkno
* for tape devices. We will also assume 8k records. Sorry. (mjacob).
*/
if (fnumber < 0) {
if ((e = rd_readidev(vp, BBLOCK, data, BBSIZE)) != 0)
return (e);
if ((e = rd_readidev(vp, SBLOCK, data+BBSIZE, SBSIZE)) != 0)
return (e);
} else {
if ((e = rd_readidev(vp, TAPEBLOCK(0), data, BBSIZE)) != 0)
return (e);
if ((e = rd_readidev(vp, TAPEBLOCK(1), data+BBSIZE, SBSIZE))
!= 0)
return (e);
}
if (((struct fs *)(data+dbtob(SBLOCK)))->fs_magic != FS_MAGIC) {
(void)printf("rd: bad magic number\n");
return (1);
}
bsize = ((struct fs *)(data+dbtob(SBLOCK)))->fs_bsize;
/* calculate number of fs blocks */
nblocks = ((struct fs *)(data+dbtob(SBLOCK)))->fs_size
* ((struct fs *)(data+dbtob(SBLOCK)))->fs_fsize
/ bsize;
(void)printf("rd: reading %d, %d byte blocks: ", nblocks, bsize);
/*
* allocate space for the rest of the ram disk and transfer
* the data read so far into it.
*/
rdp->size = (u_int)(nblocks * bsize);
#ifdef RAMDISK_PRELOADED
/* just use existing space if big enuff */
if ((rdp == &rd[0]) && (ramdisk0[0] >= rdp->size)) {
rdp->data = (caddr_t)ramdisk0;
printf("rd0: using preloaded munixfs space\n");
} else
#endif RAMDISK_PRELOADED
if ((rdp->data = new_kmem_alloc(rdp->size, KMEM_NOSLEEP)) == 0) {
kmem_free(data, BBSIZE + SBSIZE);
return (1);
}
bcopy(data, rdp->data, BBSIZE + SBSIZE);
kmem_free(data, BBSIZE + SBSIZE);
data = rdp->data;
/* read in the rest of the file system a fs block at a time */
maxblock = NSPB((struct fs *)(data+dbtob(SBLOCK))) * nblocks;
chunk = btodb(bsize);
if (fnumber < 0) {
for (i = SBLOCK + btodb(SBSIZE); i < maxblock; i += chunk) {
if ((e = rd_readidev(vp, (daddr_t)i, data+dbtob(i),
bsize)) != 0)
return (e);
(void)printf(".");
}
} else {
int j = 2;
bsize = BBSIZE; /* force it to first read's size */
chunk = btodb(bsize);
for (i = SBLOCK + btodb(SBSIZE); i < maxblock; i += chunk, j++){
if ((e = rd_readidev(vp, TAPEBLOCK(j), data+dbtob(i),
bsize)) != 0)
return (e);
(void)printf(".");
}
}
(void)printf("done\n");
return (0); /* OK */
}
/*ARGSUSED*/
rdopen(dev, wrtflag)
dev_t dev;
int wrtflag;
{
if (!ramdisk(dev))
return (ENXIO);
return (minor(dev) >= NRD ? ENXIO : 0);
}
rdsize(dev)
dev_t dev;
{
register ramdisk_t *rdp;
if ((rdp = ramdisk(dev)) == (ramdisk_t *)0)
return (-1);
else
return (btodb(rdp->size));
}
#include <sys/uio.h>
rdread(dev, uio)
dev_t dev;
register struct uio *uio;
{
register ramdisk_t *rdp;
if ((rdp = ramdisk(dev)) == (ramdisk_t *)0 ||
(unsigned) uio->uio_offset > rdp->size)
return (EINVAL);
return (uiomove(rdp->data + uio->uio_offset,
(int)(MIN(uio->uio_resid, rdp->size - uio->uio_offset)),
UIO_READ, uio));
}
rdwrite(dev, uio)
dev_t dev;
register struct uio *uio;
{
register ramdisk_t *rdp;
if ((rdp = ramdisk(dev)) == (ramdisk_t *)0 ||
((unsigned) uio->uio_offset > rdp->size))
return (EINVAL);
return (uiomove(rdp->data + uio->uio_offset,
(int)(MIN(uio->uio_resid, rdp->size - uio->uio_offset)),
UIO_WRITE, uio));
}
rdstrategy(bp)
register struct buf *bp;
{
register ramdisk_t *rdp;
register long offset = dbtob(bp->b_blkno);
if ((rdp = ramdisk(bp->b_dev)) == (ramdisk_t *)0 ||
(u_long) offset > rdp->size) {
bp->b_error = EINVAL;
bp->b_flags |= B_ERROR;
} else {
caddr_t raddr;
unsigned nbytes;
raddr = rdp->data + offset;
nbytes = MIN(bp->b_bcount, rdp->size - offset);
if (bp->b_flags & B_PAGEIO)
bp_mapin(bp);
if (bp->b_flags & B_READ)
bcopy(raddr, bp->b_un.b_addr, nbytes);
else
bcopy(bp->b_un.b_addr, raddr, nbytes);
bp->b_resid = bp->b_bcount - nbytes;
}
iodone(bp);
}
#endif