Home | History | Annotate | Line # | Download | only in common
promdev.c revision 1.22
      1 /*	$NetBSD: promdev.c,v 1.22 2009/01/12 11:32:44 tsutsui Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1993 Paul Kranenburg
      5  * Copyright (c) 1995 Gordon W. Ross
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *      This product includes software developed by Paul Kranenburg.
     19  * 4. The name of the author may not be used to endorse or promote products
     20  *    derived from this software without specific prior written permission
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 /*
     35  * Note: the `#ifndef BOOTXX' in here serve to queeze the code size
     36  * of the 1st-stage boot program.
     37  */
     38 #include <sys/param.h>
     39 #include <sys/reboot.h>
     40 #include <sys/systm.h>
     41 #include <machine/oldmon.h>
     42 #include <machine/promlib.h>
     43 #include <machine/ctlreg.h>
     44 #include <sparc/sparc/asm.h>
     45 #include <machine/pte.h>
     46 
     47 #include <lib/libsa/stand.h>
     48 #include <lib/libsa/net.h>
     49 #include <lib/libkern/libkern.h>
     50 #include <sparc/stand/common/promdev.h>
     51 
     52 #ifndef BOOTXX
     53 #include <sys/disklabel.h>
     54 #include <dev/sun/disklabel.h>
     55 #include <dev/raidframe/raidframevar.h>
     56 #endif
     57 
     58 /* OBP V0-3 PROM vector */
     59 #define obpvec	((struct promvec *)romp)
     60 
     61 int	obp_close(struct open_file *);
     62 int	obp_strategy(void *, int, daddr_t, size_t, void *, size_t *);
     63 int	obp_v0_strategy(void *, int, daddr_t, size_t, void *, size_t *);
     64 ssize_t	obp_v0_xmit(struct promdata *, void *, size_t);
     65 ssize_t	obp_v0_recv(struct promdata *, void *, size_t);
     66 int	obp_v2_strategy(void *, int, daddr_t, size_t, void *, size_t *);
     67 ssize_t	obp_v2_xmit(struct promdata *, void *, size_t);
     68 ssize_t	obp_v2_recv(struct promdata *, void *, size_t);
     69 int	oldmon_close(struct open_file *);
     70 int	oldmon_strategy(void *, int, daddr_t, size_t, void *, size_t *);
     71 void	oldmon_iclose(struct saioreq *);
     72 int	oldmon_iopen(struct promdata *);
     73 ssize_t	oldmon_xmit(struct promdata *, void *, size_t);
     74 ssize_t	oldmon_recv(struct promdata *, void *, size_t);
     75 
     76 static char	*oldmon_mapin(u_long, int, int);
     77 #ifndef BOOTXX
     78 static char	*mygetpropstring(int, char *);
     79 static int	getdevtype(int, char *);
     80 #endif
     81 
     82 extern struct fs_ops file_system_nfs[];
     83 extern struct fs_ops file_system_ufs[];
     84 
     85 #define null_devopen	(void *)sparc_noop
     86 #define null_devioctl	(void *)sparc_noop
     87 
     88 #if 0
     89 struct devsw devsw[];
     90 int	ndevs = (sizeof(devsw)/sizeof(devsw[0]));
     91 #endif
     92 
     93 struct devsw oldmon_devsw =
     94 	{ "oldmon", oldmon_strategy, null_devopen, oldmon_close, null_devioctl };
     95 struct devsw obp_v0_devsw =
     96 	{ "obp v0", obp_v0_strategy, null_devopen, obp_close, null_devioctl };
     97 struct devsw obp_v2_devsw =
     98 	{ "obp v2", obp_v2_strategy, null_devopen, obp_close, null_devioctl };
     99 
    100 
    101 char	prom_bootdevice[MAX_PROM_PATH];
    102 static int	saveecho;
    103 
    104 #ifndef BOOTXX
    105 static daddr_t doffset = 0;
    106 #endif
    107 
    108 
    109 void
    110 putchar(int c)
    111 {
    112 
    113 	if (c == '\n')
    114 		prom_putchar('\r');
    115 	prom_putchar(c);
    116 }
    117 
    118 void
    119 _rtt(void)
    120 {
    121 
    122 	prom_halt();
    123 }
    124 
    125 int
    126 devopen(struct open_file *f, const char *fname, char **file)
    127 {
    128 	int	error = 0, fd = 0;
    129 	struct	promdata *pd;
    130 #ifndef BOOTXX
    131 	char *partition;
    132 	int part = 0;
    133 	char rawpart[MAX_PROM_PATH];
    134 	struct promdata *disk_pd;
    135 	char buf[DEV_BSIZE];
    136 	struct disklabel *dlp;
    137 	size_t read;
    138 #endif
    139 
    140 	pd = (struct promdata *)alloc(sizeof *pd);
    141 	f->f_devdata = (void *)pd;
    142 
    143 	switch (prom_version()) {
    144 	case PROM_OLDMON:
    145 		error = oldmon_iopen(pd);
    146 #ifndef BOOTXX
    147 		pd->xmit = oldmon_xmit;
    148 		pd->recv = oldmon_recv;
    149 #endif
    150 		f->f_dev = &oldmon_devsw;
    151 		saveecho = *romVectorPtr->echo;
    152 		*romVectorPtr->echo = 0;
    153 		break;
    154 
    155 	case PROM_OBP_V0:
    156 	case PROM_OBP_V2:
    157 	case PROM_OBP_V3:
    158 	case PROM_OPENFIRM:
    159 		if (*prom_bootdevice == '\0') {
    160 			error = ENXIO;
    161 			break;
    162 		}
    163 		fd = prom_open(prom_bootdevice);
    164 		if (fd == 0) {
    165 			error = ENXIO;
    166 			break;
    167 		}
    168 		pd->fd = fd;
    169 		switch (prom_version()) {
    170 		case PROM_OBP_V0:
    171 #ifndef BOOTXX
    172 			pd->xmit = obp_v0_xmit;
    173 			pd->recv = obp_v0_recv;
    174 #endif
    175 			f->f_dev = &obp_v0_devsw;
    176 			break;
    177 		case PROM_OBP_V2:
    178 		case PROM_OBP_V3:
    179 		case PROM_OPENFIRM:
    180 #ifndef BOOTXX
    181 			pd->xmit = obp_v2_xmit;
    182 			pd->recv = obp_v2_recv;
    183 #endif
    184 			f->f_dev = &obp_v2_devsw;
    185 		}
    186 	}
    187 
    188 	if (error) {
    189 		printf("Can't open device `%s'\n", prom_bootdevice);
    190 		return (error);
    191 	}
    192 
    193 #ifdef BOOTXX
    194 	pd->devtype = DT_BLOCK;
    195 #else /* BOOTXX */
    196 	pd->devtype = getdevtype(fd, prom_bootdevice);
    197 	/* Assume type BYTE is a raw device */
    198 	if (pd->devtype != DT_BYTE)
    199 		*file = (char *)fname;
    200 
    201 	if (pd->devtype == DT_NET) {
    202 		nfsys = 1;
    203 		memcpy(file_system, file_system_nfs,
    204 		    sizeof(struct fs_ops) * nfsys);
    205 		if ((error = net_open(pd)) != 0) {
    206 			printf("Can't open NFS network connection on `%s'\n",
    207 				prom_bootdevice);
    208 			return (error);
    209 		}
    210 	} else {
    211 		memcpy(file_system, file_system_ufs,
    212 		    sizeof(struct fs_ops) * nfsys);
    213 
    214 #ifdef NOTDEF_DEBUG
    215 	printf("devopen: Checking disklabel for RAID partition\n");
    216 #endif
    217 
    218 		/*
    219 		 * We need to read from the raw partition (i.e. the
    220 		 * beginning of the disk in order to check the NetBSD
    221 		 * disklabel to see if the boot partition is type RAID.
    222 		 *
    223 		 * For machines with prom_version() == PROM_OLDMON, we
    224 		 * only handle boot from RAID for the first disk partition.
    225 		 */
    226 		disk_pd = (struct promdata *)alloc(sizeof *disk_pd);
    227 		memcpy(disk_pd, pd, sizeof(struct promdata));
    228 		if (prom_version() != PROM_OLDMON) {
    229 			strcpy(rawpart, prom_bootdevice);
    230 			if ((partition = strchr(rawpart, ':')) != '\0' &&
    231 		    	    *++partition >= 'a' &&
    232 			    *partition <= 'a' +  MAXPARTITIONS) {
    233 				part = *partition - 'a';
    234 				*partition = RAW_PART + 'a';
    235 			} else
    236 				strcat(rawpart, ":c");
    237 			if ((disk_pd->fd = prom_open(rawpart)) == 0)
    238 				return 0;
    239 		}
    240 		error = f->f_dev->dv_strategy(disk_pd, F_READ, LABELSECTOR,
    241 		    DEV_BSIZE, &buf, &read);
    242 		if (prom_version() != PROM_OLDMON)
    243 			prom_close(disk_pd->fd);
    244 		if (error || (read != DEV_BSIZE))
    245 			return 0;
    246 #ifdef NOTDEF_DEBUG
    247 		{
    248 			int x = 0;
    249 			char *p = (char *) buf;
    250 
    251 			printf("  Sector %d:\n", LABELSECTOR);
    252 			printf("00000000  ");
    253 			while (x < DEV_BSIZE) {
    254 				if (*p >= 0x00 && *p < 0x10)
    255 					printf("0%x ", *p & 0xff);
    256 				else
    257 					printf("%x ", *p & 0xff);
    258 				x++;
    259 				if (x && !(x % 8))
    260 					printf(" ");
    261 				if (x && !(x % 16)) {
    262 					if(x < 0x100)
    263 						printf("\n000000%x  ", x);
    264 					else
    265 						printf("\n00000%x  ", x);
    266 				}
    267 				p++;
    268 			}
    269 			printf("\n");
    270 		}
    271 #endif
    272 		/* Check for NetBSD disk label. */
    273 		dlp = (struct disklabel *) (buf + LABELOFFSET);
    274 		if (dlp->d_magic == DISKMAGIC && !dkcksum(dlp) &&
    275 		    dlp->d_partitions[part].p_fstype == FS_RAID) {
    276 #ifdef NOTDEF_DEBUG
    277 			printf("devopen: found RAID partition, "
    278 			    "adjusting offset to %d\n", RF_PROTECTED_SECTORS);
    279 #endif
    280 			doffset = RF_PROTECTED_SECTORS;
    281 		}
    282 	}
    283 #endif /* BOOTXX */
    284 	return (0);
    285 }
    286 
    287 
    288 int
    289 obp_v0_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
    290 		void *buf, size_t *rsize)
    291 {
    292 	int	n, error = 0;
    293 	struct	promdata *pd = (struct promdata *)devdata;
    294 	int	fd = pd->fd;
    295 
    296 #ifndef BOOTXX
    297 	dblk += doffset;
    298 #endif
    299 #ifdef DEBUG_PROM
    300 	printf("promstrategy: size=%d dblk=%d\n", size, dblk);
    301 #endif
    302 
    303 #define prom_bread(fd, nblk, dblk, buf) \
    304 		(*obpvec->pv_v0devops.v0_rbdev)(fd, nblk, dblk, buf)
    305 #define prom_bwrite(fd, nblk, dblk, buf) \
    306 		(*obpvec->pv_v0devops.v0_wbdev)(fd, nblk, dblk, buf)
    307 
    308 #ifndef BOOTXX	/* We know it's a block device, so save some space */
    309 	if (pd->devtype != DT_BLOCK) {
    310 		printf("promstrategy: non-block device not supported\n");
    311 		error = EINVAL;
    312 	}
    313 #endif
    314 
    315 	n = (flag == F_READ)
    316 		? prom_bread(fd, btodb(size), dblk, buf)
    317 		: prom_bwrite(fd, btodb(size), dblk, buf);
    318 
    319 	*rsize = dbtob(n);
    320 
    321 #ifdef DEBUG_PROM
    322 	printf("rsize = %x\n", *rsize);
    323 #endif
    324 	return (error);
    325 }
    326 
    327 int
    328 obp_v2_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
    329 		void *buf, size_t *rsize)
    330 {
    331 	int	error = 0;
    332 	struct	promdata *pd = (struct promdata *)devdata;
    333 	int	fd = pd->fd;
    334 
    335 #ifndef BOOTXX
    336 	dblk += doffset;
    337 #endif
    338 #ifdef DEBUG_PROM
    339 	printf("promstrategy: size=%d dblk=%d\n", size, dblk);
    340 #endif
    341 
    342 #ifndef BOOTXX	/* We know it's a block device, so save some space */
    343 	if (pd->devtype == DT_BLOCK)
    344 #endif
    345 		prom_seek(fd, dbtob(dblk));
    346 
    347 	*rsize = (flag == F_READ)
    348 		? prom_read(fd, buf, size)
    349 		: prom_write(fd, buf, size);
    350 
    351 #ifdef DEBUG_PROM
    352 	printf("rsize = %x\n", *rsize);
    353 #endif
    354 	return (error);
    355 }
    356 
    357 /*
    358  * On old-monitor machines, things work differently.
    359  */
    360 int
    361 oldmon_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
    362 		void *buf, size_t *rsize)
    363 {
    364 	struct promdata	*pd = devdata;
    365 	struct saioreq	*si;
    366 	struct om_boottable *ops;
    367 	char	*dmabuf;
    368 	int	si_flag;
    369 	size_t	xcnt;
    370 
    371 	si = pd->si;
    372 	ops = si->si_boottab;
    373 
    374 #ifndef BOOTXX
    375 	dblk += doffset;
    376 #endif
    377 #ifdef DEBUG_PROM
    378 	printf("prom_strategy: size=%d dblk=%d\n", size, dblk);
    379 #endif
    380 
    381 	dmabuf = dvma_mapin(buf, size);
    382 
    383 	si->si_bn = dblk;
    384 	si->si_ma = dmabuf;
    385 	si->si_cc = size;
    386 
    387 	si_flag = (flag == F_READ) ? SAIO_F_READ : SAIO_F_WRITE;
    388 	xcnt = (*ops->b_strategy)(si, si_flag);
    389 	dvma_mapout(dmabuf, size);
    390 
    391 #ifdef DEBUG_PROM
    392 	printf("disk_strategy: xcnt = %x\n", xcnt);
    393 #endif
    394 
    395 	if (xcnt <= 0)
    396 		return (EIO);
    397 
    398 	*rsize = xcnt;
    399 	return (0);
    400 }
    401 
    402 int
    403 obp_close(struct open_file *f)
    404 {
    405 	struct promdata *pd = f->f_devdata;
    406 	register int fd = pd->fd;
    407 
    408 #ifndef BOOTXX
    409 	if (pd->devtype == DT_NET)
    410 		net_close(pd);
    411 #endif
    412 	prom_close(fd);
    413 	return 0;
    414 }
    415 
    416 int
    417 oldmon_close(struct open_file *f)
    418 {
    419 	struct promdata *pd = f->f_devdata;
    420 
    421 #ifndef BOOTXX
    422 	if (pd->devtype == DT_NET)
    423 		net_close(pd);
    424 #endif
    425 	oldmon_iclose(pd->si);
    426 	pd->si = NULL;
    427 	*romVectorPtr->echo = saveecho; /* Hmm, probably must go somewhere else */
    428 	return 0;
    429 }
    430 
    431 #ifndef BOOTXX
    432 ssize_t
    433 obp_v0_xmit(struct promdata *pd, void *buf, size_t len)
    434 {
    435 
    436 	return ((*obpvec->pv_v0devops.v0_wnet)(pd->fd, len, buf));
    437 }
    438 
    439 ssize_t
    440 obp_v2_xmit(struct promdata *pd, void *buf, size_t len)
    441 {
    442 
    443 	return (prom_write(pd->fd, buf, len));
    444 }
    445 
    446 ssize_t
    447 obp_v0_recv(struct promdata *pd, void *buf, size_t len)
    448 {
    449 
    450 	return ((*obpvec->pv_v0devops.v0_rnet)(pd->fd, len, buf));
    451 }
    452 
    453 ssize_t
    454 obp_v2_recv(struct promdata *pd, void *buf, size_t len)
    455 {
    456 	int	n;
    457 
    458 	n = prom_read(pd->fd, buf, len);
    459 
    460 	/* OBP V2 & V3 may return -2 */
    461 	return (n == -2 ? 0 : n);
    462 }
    463 
    464 ssize_t
    465 oldmon_xmit(struct promdata *pd, void *buf, size_t len)
    466 {
    467 	struct saioreq	*si;
    468 	struct saif	*sif;
    469 	char		*dmabuf;
    470 	int		rv;
    471 
    472 	si = pd->si;
    473 	sif = si->si_sif;
    474 	if (sif == NULL) {
    475 		printf("xmit: not a network device\n");
    476 		return (-1);
    477 	}
    478 	dmabuf = dvma_mapin(buf, len);
    479 	rv = sif->sif_xmit(si->si_devdata, dmabuf, len);
    480 	dvma_mapout(dmabuf, len);
    481 
    482 	return (ssize_t)(rv ? -1 : len);
    483 }
    484 
    485 ssize_t
    486 oldmon_recv(struct promdata *pd, void *buf, size_t len)
    487 {
    488 	struct saioreq	*si;
    489 	struct saif	*sif;
    490 	char		*dmabuf;
    491 	int		rv;
    492 
    493 	si = pd->si;
    494 	sif = si->si_sif;
    495 	dmabuf = dvma_mapin(buf, len);
    496 	rv = sif->sif_poll(si->si_devdata, dmabuf);
    497 	dvma_mapout(dmabuf, len);
    498 
    499 	return (ssize_t)rv;
    500 }
    501 
    502 int
    503 getchar(void)
    504 {
    505 
    506 	return (prom_getchar());
    507 }
    508 
    509 satime_t
    510 getsecs(void)
    511 {
    512 
    513 	(void)prom_peekchar();
    514 	return (prom_ticks() / 1000);
    515 }
    516 
    517 /*
    518  * A number of well-known devices on sun4s.
    519  */
    520 static struct dtab {
    521 	char	*name;
    522 	int	type;
    523 } dtab[] = {
    524 	{ "sd",	DT_BLOCK },
    525 	{ "st",	DT_BLOCK },
    526 	{ "xd",	DT_BLOCK },
    527 	{ "xy",	DT_BLOCK },
    528 	{ "fd",	DT_BLOCK },
    529 	{ "le",	DT_NET },
    530 	{ "ie",	DT_NET },
    531 	{ NULL, 0 }
    532 };
    533 
    534 int
    535 getdevtype(int fd, char *name)
    536 {
    537 	struct dtab *dp;
    538 	int node;
    539 	char *cp;
    540 
    541 	switch (prom_version()) {
    542 	case PROM_OLDMON:
    543 	case PROM_OBP_V0:
    544 		for (dp = dtab; dp->name; dp++) {
    545 			if (name[0] == dp->name[0] &&
    546 			    name[1] == dp->name[1])
    547 				return (dp->type);
    548 		}
    549 		break;
    550 
    551 	case PROM_OBP_V2:
    552 	case PROM_OBP_V3:
    553 	case PROM_OPENFIRM:
    554 		node = prom_instance_to_package(fd);
    555 		cp = mygetpropstring(node, "device_type");
    556 		if (strcmp(cp, "block") == 0)
    557 			return (DT_BLOCK);
    558 		else if (strcmp(cp, "network") == 0)
    559 			return (DT_NET);
    560 		else if (strcmp(cp, "byte") == 0)
    561 			return (DT_BYTE);
    562 		break;
    563 	}
    564 	return (0);
    565 }
    566 
    567 /*
    568  * Return a string property.  There is a (small) limit on the length;
    569  * the string is fetched into a static buffer which is overwritten on
    570  * subsequent calls.
    571  */
    572 char *
    573 mygetpropstring(int node, char *name)
    574 {
    575 	int len;
    576 static	char buf[64];
    577 
    578 	len = prom_proplen(node, name);
    579 	if (len > 0)
    580 		_prom_getprop(node, name, buf, len);
    581 	else
    582 		len = 0;
    583 
    584 	buf[len] = '\0';	/* usually unnecessary */
    585 	return (buf);
    586 }
    587 #endif /* BOOTXX */
    588 
    589 /*
    590  * Old monitor routines
    591  */
    592 
    593 struct saioreq prom_si;
    594 static int promdev_inuse;
    595 
    596 int
    597 oldmon_iopen(struct promdata *pd)
    598 {
    599 	struct om_bootparam *bp;
    600 	struct om_boottable *ops;
    601 	struct devinfo *dip;
    602 	struct saioreq *si;
    603 	int	error;
    604 
    605 	if (promdev_inuse)
    606 		return (EMFILE);
    607 
    608 	bp = *romVectorPtr->bootParam;
    609 	ops = bp->bootTable;
    610 	dip = ops->b_devinfo;
    611 
    612 #ifdef DEBUG_PROM
    613 	printf("Boot device type: %s\n", ops->b_desc);
    614 	printf("d_devbytes=%d\n", dip->d_devbytes);
    615 	printf("d_dmabytes=%d\n", dip->d_dmabytes);
    616 	printf("d_localbytes=%d\n", dip->d_localbytes);
    617 	printf("d_stdcount=%d\n", dip->d_stdcount);
    618 	printf("d_stdaddrs[%d]=%x\n", bp->ctlrNum, dip->d_stdaddrs[bp->ctlrNum]);
    619 	printf("d_devtype=%d\n", dip->d_devtype);
    620 	printf("d_maxiobytes=%d\n", dip->d_maxiobytes);
    621 #endif
    622 
    623 	dvma_init();
    624 
    625 	si = &prom_si;
    626 	memset(si, 0, sizeof(*si));
    627 	si->si_boottab = ops;
    628 	si->si_ctlr = bp->ctlrNum;
    629 	si->si_unit = bp->unitNum;
    630 	si->si_boff = bp->partNum;
    631 
    632 	if (si->si_ctlr > dip->d_stdcount)
    633 		return (ECTLR);
    634 
    635 	if (dip->d_devbytes) {
    636 		si->si_devaddr = oldmon_mapin(dip->d_stdaddrs[si->si_ctlr],
    637 			dip->d_devbytes, dip->d_devtype);
    638 #ifdef	DEBUG_PROM
    639 		printf("prom_iopen: devaddr=0x%x pte=0x%x\n",
    640 			si->si_devaddr,
    641 			getpte4((u_long)si->si_devaddr & ~PGOFSET));
    642 #endif
    643 	}
    644 
    645 	if (dip->d_dmabytes) {
    646 		si->si_dmaaddr = dvma_alloc(dip->d_dmabytes);
    647 #ifdef	DEBUG_PROM
    648 		printf("prom_iopen: dmaaddr=0x%x\n", si->si_dmaaddr);
    649 #endif
    650 	}
    651 
    652 	if (dip->d_localbytes) {
    653 		si->si_devdata = alloc(dip->d_localbytes);
    654 #ifdef	DEBUG_PROM
    655 		printf("prom_iopen: devdata=0x%x\n", si->si_devdata);
    656 #endif
    657 	}
    658 
    659 	/* OK, call the PROM device open routine. */
    660 	error = (*ops->b_open)(si);
    661 	if (error != 0) {
    662 		printf("prom_iopen: \"%s\" error=%d\n", ops->b_desc, error);
    663 		return (ENXIO);
    664 	}
    665 #ifdef	DEBUG_PROM
    666 	printf("prom_iopen: succeeded, error=%d\n", error);
    667 #endif
    668 
    669 	pd->si = si;
    670 	promdev_inuse++;
    671 	return (0);
    672 }
    673 
    674 void
    675 oldmon_iclose(struct saioreq *si)
    676 {
    677 	struct om_boottable *ops;
    678 	struct devinfo *dip;
    679 
    680 	if (promdev_inuse == 0)
    681 		return;
    682 
    683 	ops = si->si_boottab;
    684 	dip = ops->b_devinfo;
    685 
    686 	(*ops->b_close)(si);
    687 
    688 	if (si->si_dmaaddr) {
    689 		dvma_free(si->si_dmaaddr, dip->d_dmabytes);
    690 		si->si_dmaaddr = NULL;
    691 	}
    692 
    693 	promdev_inuse = 0;
    694 }
    695 
    696 static struct mapinfo {
    697 	int maptype;
    698 	int pgtype;
    699 	int base;
    700 } oldmon_mapinfo[] = {
    701 #define PG_COMMON	(PG_V|PG_W|PG_S|PG_NC)
    702 	{ MAP_MAINMEM,   PG_OBMEM | PG_COMMON, 0 },
    703 	{ MAP_OBIO,      PG_OBIO  | PG_COMMON, 0 },
    704 	{ MAP_MBMEM,     PG_VME16 | PG_COMMON, 0xFF000000 },
    705 	{ MAP_MBIO,      PG_VME16 | PG_COMMON, 0xFFFF0000 },
    706 	{ MAP_VME16A16D, PG_VME16 | PG_COMMON, 0xFFFF0000 },
    707 	{ MAP_VME16A32D, PG_VME32 | PG_COMMON, 0xFFFF0000 },
    708 	{ MAP_VME24A16D, PG_VME16 | PG_COMMON, 0xFF000000 },
    709 	{ MAP_VME24A32D, PG_VME32 | PG_COMMON, 0xFF000000 },
    710 	{ MAP_VME32A16D, PG_VME16 | PG_COMMON, 0 },
    711 	{ MAP_VME32A32D, PG_VME32 | PG_COMMON, 0 },
    712 };
    713 static int oldmon_mapinfo_cnt =
    714 	sizeof(oldmon_mapinfo) / sizeof(oldmon_mapinfo[0]);
    715 
    716 /* The virtual address we will use for PROM device mappings. */
    717 static u_long prom_devmap = MONSHORTSEG;
    718 
    719 static char *
    720 oldmon_mapin(u_long physaddr, int length, int maptype)
    721 {
    722 	int i, pa, pte, va;
    723 
    724 	if (length > (4*NBPG))
    725 		panic("oldmon_mapin: length=%d", length);
    726 
    727 	for (i = 0; i < oldmon_mapinfo_cnt; i++)
    728 		if (oldmon_mapinfo[i].maptype == maptype)
    729 			goto found;
    730 	panic("oldmon_mapin: invalid maptype %d", maptype);
    731 
    732 found:
    733 	pte = oldmon_mapinfo[i].pgtype;
    734 	pa = oldmon_mapinfo[i].base;
    735 	pa += physaddr;
    736 	pte |= ((pa >> SUN4_PGSHIFT) & PG_PFNUM);
    737 
    738 	va = prom_devmap;
    739 	do {
    740 		setpte4(va, pte);
    741 		va += NBPG;
    742 		pte += 1;
    743 		length -= NBPG;
    744 	} while (length > 0);
    745 	return ((char*)(prom_devmap | (pa & PGOFSET)));
    746 }
    747