1/*	$NetBSD: promdev.c,v 1.25 2010/08/25 20:16:49 christos 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#include <sparc/stand/common/isfloppy.h>
52
53#ifndef BOOTXX
54#include <sys/disklabel.h>
55#include <dev/sun/disklabel.h>
56#include <dev/raidframe/raidframevar.h>
57#endif
58
59/* OBP V0-3 PROM vector */
60#define obpvec	((struct promvec *)romp)
61
62int	obp_close(struct open_file *);
63int	obp_strategy(void *, int, daddr_t, size_t, void *, size_t *);
64int	obp_v0_strategy(void *, int, daddr_t, size_t, void *, size_t *);
65ssize_t	obp_v0_xmit(struct promdata *, void *, size_t);
66ssize_t	obp_v0_recv(struct promdata *, void *, size_t);
67int	obp_v2_strategy(void *, int, daddr_t, size_t, void *, size_t *);
68ssize_t	obp_v2_xmit(struct promdata *, void *, size_t);
69ssize_t	obp_v2_recv(struct promdata *, void *, size_t);
70int	oldmon_close(struct open_file *);
71int	oldmon_strategy(void *, int, daddr_t, size_t, void *, size_t *);
72void	oldmon_iclose(struct saioreq *);
73int	oldmon_iopen(struct promdata *);
74ssize_t	oldmon_xmit(struct promdata *, void *, size_t);
75ssize_t	oldmon_recv(struct promdata *, void *, size_t);
76
77static char	*oldmon_mapin(u_long, int, int);
78#ifndef BOOTXX
79static char	*mygetpropstring(int, char *);
80static int	getdevtype(int, char *);
81#endif
82
83extern struct fs_ops file_system_nfs[];
84extern struct fs_ops file_system_ufs[];
85
86#define null_devopen	(void *)sparc_noop
87#define null_devioctl	(void *)sparc_noop
88
89#if 0
90struct devsw devsw[];
91int	ndevs = (sizeof(devsw)/sizeof(devsw[0]));
92#endif
93
94struct devsw oldmon_devsw =
95	{ "oldmon", oldmon_strategy, null_devopen, oldmon_close, null_devioctl };
96struct devsw obp_v0_devsw =
97	{ "obp v0", obp_v0_strategy, null_devopen, obp_close, null_devioctl };
98struct devsw obp_v2_devsw =
99	{ "obp v2", obp_v2_strategy, null_devopen, obp_close, null_devioctl };
100
101
102char	prom_bootdevice[MAX_PROM_PATH];
103static int	saveecho;
104
105#ifndef BOOTXX
106static daddr_t doffset = 0;
107#endif
108
109void
110putchar(int c)
111{
112
113	if (c == '\n')
114		prom_putchar('\r');
115	prom_putchar(c);
116}
117
118void
119_rtt(void)
120{
121
122	prom_halt();
123}
124
125int
126devopen(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		 * Don't check disklabel on floppy boot since
220		 * reopening it could cause Data Access Exception later.
221		 */
222		if (bootdev_isfloppy(prom_bootdevice))
223			return 0;
224
225		/*
226		 * We need to read from the raw partition (i.e. the
227		 * beginning of the disk in order to check the NetBSD
228		 * disklabel to see if the boot partition is type RAID.
229		 *
230		 * For machines with prom_version() == PROM_OLDMON, we
231		 * only handle boot from RAID for the first disk partition.
232		 */
233		disk_pd = (struct promdata *)alloc(sizeof *disk_pd);
234		memcpy(disk_pd, pd, sizeof(struct promdata));
235		if (prom_version() != PROM_OLDMON) {
236			strcpy(rawpart, prom_bootdevice);
237			if ((partition = strchr(rawpart, ':')) != '\0' &&
238		    	    *++partition >= 'a' &&
239			    *partition <= 'a' +  MAXPARTITIONS) {
240				part = *partition - 'a';
241				*partition = RAW_PART + 'a';
242			} else
243				strcat(rawpart, ":c");
244			if ((disk_pd->fd = prom_open(rawpart)) == 0)
245				return 0;
246		}
247		error = f->f_dev->dv_strategy(disk_pd, F_READ, LABELSECTOR,
248		    DEV_BSIZE, &buf, &read);
249		if (prom_version() != PROM_OLDMON)
250			prom_close(disk_pd->fd);
251		if (error || (read != DEV_BSIZE))
252			return 0;
253#ifdef NOTDEF_DEBUG
254		{
255			int x = 0;
256			char *p = (char *) buf;
257
258			printf("  Sector %d:\n", LABELSECTOR);
259			printf("00000000  ");
260			while (x < DEV_BSIZE) {
261				if (*p >= 0x00 && *p < 0x10)
262					printf("0%x ", *p & 0xff);
263				else
264					printf("%x ", *p & 0xff);
265				x++;
266				if (x && !(x % 8))
267					printf(" ");
268				if (x && !(x % 16)) {
269					if(x < 0x100)
270						printf("\n000000%x  ", x);
271					else
272						printf("\n00000%x  ", x);
273				}
274				p++;
275			}
276			printf("\n");
277		}
278#endif
279		/* Check for NetBSD disk label. */
280		dlp = (struct disklabel *) (buf + LABELOFFSET);
281		if (dlp->d_magic == DISKMAGIC && !dkcksum(dlp) &&
282		    dlp->d_partitions[part].p_fstype == FS_RAID) {
283#ifdef NOTDEF_DEBUG
284			printf("devopen: found RAID partition, "
285			    "adjusting offset to %d\n", RF_PROTECTED_SECTORS);
286#endif
287			doffset = RF_PROTECTED_SECTORS;
288		}
289	}
290#endif /* BOOTXX */
291	return (0);
292}
293
294
295int
296obp_v0_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
297		void *buf, size_t *rsize)
298{
299	int	n, error = 0;
300	struct	promdata *pd = (struct promdata *)devdata;
301	int	fd = pd->fd;
302
303#ifndef BOOTXX
304	dblk += doffset;
305#endif
306#ifdef DEBUG_PROM
307	printf("promstrategy: size=%zd dblk=%d\n", size, (int)dblk);
308#endif
309
310#define prom_bread(fd, nblk, dblk, buf) \
311		(*obpvec->pv_v0devops.v0_rbdev)(fd, nblk, dblk, buf)
312#define prom_bwrite(fd, nblk, dblk, buf) \
313		(*obpvec->pv_v0devops.v0_wbdev)(fd, nblk, dblk, buf)
314
315#ifndef BOOTXX	/* We know it's a block device, so save some space */
316	if (pd->devtype != DT_BLOCK) {
317		printf("promstrategy: non-block device not supported\n");
318		error = EINVAL;
319	}
320#endif
321
322	n = (flag == F_READ)
323		? prom_bread(fd, btodb(size), dblk, buf)
324		: prom_bwrite(fd, btodb(size), dblk, buf);
325
326	*rsize = dbtob(n);
327
328#ifdef DEBUG_PROM
329	printf("rsize = %zx\n", *rsize);
330#endif
331	return (error);
332}
333
334int
335obp_v2_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
336		void *buf, size_t *rsize)
337{
338	int	error = 0;
339	struct	promdata *pd = (struct promdata *)devdata;
340	int	fd = pd->fd;
341
342#ifndef BOOTXX
343	dblk += doffset;
344#endif
345#ifdef DEBUG_PROM
346	printf("promstrategy: size=%zd dblk=%d\n", size, (int)dblk);
347#endif
348
349#ifndef BOOTXX	/* We know it's a block device, so save some space */
350	if (pd->devtype == DT_BLOCK)
351#endif
352		prom_seek(fd, dbtob(dblk));
353
354	*rsize = (flag == F_READ)
355		? prom_read(fd, buf, size)
356		: prom_write(fd, buf, size);
357
358#ifdef DEBUG_PROM
359	printf("rsize = %zx\n", *rsize);
360#endif
361	return (error);
362}
363
364/*
365 * On old-monitor machines, things work differently.
366 */
367int
368oldmon_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
369		void *buf, size_t *rsize)
370{
371	struct promdata	*pd = devdata;
372	struct saioreq	*si;
373	struct om_boottable *ops;
374	char	*dmabuf;
375	int	si_flag;
376	size_t	xcnt;
377
378	si = pd->si;
379	ops = si->si_boottab;
380
381#ifndef BOOTXX
382	dblk += doffset;
383#endif
384#ifdef DEBUG_PROM
385	printf("prom_strategy: size=%zd dblk=%d\n", size, (int)dblk);
386#endif
387
388	dmabuf = dvma_mapin(buf, size);
389
390	si->si_bn = dblk;
391	si->si_ma = dmabuf;
392	si->si_cc = size;
393
394	si_flag = (flag == F_READ) ? SAIO_F_READ : SAIO_F_WRITE;
395	xcnt = (*ops->b_strategy)(si, si_flag);
396	dvma_mapout(dmabuf, size);
397
398#ifdef DEBUG_PROM
399	printf("disk_strategy: xcnt = %zx\n", xcnt);
400#endif
401
402	if (xcnt <= 0)
403		return (EIO);
404
405	*rsize = xcnt;
406	return (0);
407}
408
409int
410obp_close(struct open_file *f)
411{
412	struct promdata *pd = f->f_devdata;
413	register int fd = pd->fd;
414
415#ifndef BOOTXX
416	if (pd->devtype == DT_NET)
417		net_close(pd);
418#endif
419	prom_close(fd);
420	return 0;
421}
422
423int
424oldmon_close(struct open_file *f)
425{
426	struct promdata *pd = f->f_devdata;
427
428#ifndef BOOTXX
429	if (pd->devtype == DT_NET)
430		net_close(pd);
431#endif
432	oldmon_iclose(pd->si);
433	pd->si = NULL;
434	*romVectorPtr->echo = saveecho; /* Hmm, probably must go somewhere else */
435	return 0;
436}
437
438#ifndef BOOTXX
439ssize_t
440obp_v0_xmit(struct promdata *pd, void *buf, size_t len)
441{
442
443	return ((*obpvec->pv_v0devops.v0_wnet)(pd->fd, len, buf));
444}
445
446ssize_t
447obp_v2_xmit(struct promdata *pd, void *buf, size_t len)
448{
449
450	return (prom_write(pd->fd, buf, len));
451}
452
453ssize_t
454obp_v0_recv(struct promdata *pd, void *buf, size_t len)
455{
456
457	return ((*obpvec->pv_v0devops.v0_rnet)(pd->fd, len, buf));
458}
459
460ssize_t
461obp_v2_recv(struct promdata *pd, void *buf, size_t len)
462{
463	int	n;
464
465	n = prom_read(pd->fd, buf, len);
466
467	/* OBP V2 & V3 may return -2 */
468	return (n == -2 ? 0 : n);
469}
470
471ssize_t
472oldmon_xmit(struct promdata *pd, void *buf, size_t len)
473{
474	struct saioreq	*si;
475	struct saif	*sif;
476	char		*dmabuf;
477	int		rv;
478
479	si = pd->si;
480	sif = si->si_sif;
481	if (sif == NULL) {
482		printf("xmit: not a network device\n");
483		return (-1);
484	}
485	dmabuf = dvma_mapin(buf, len);
486	rv = sif->sif_xmit(si->si_devdata, dmabuf, len);
487	dvma_mapout(dmabuf, len);
488
489	return (ssize_t)(rv ? -1 : len);
490}
491
492ssize_t
493oldmon_recv(struct promdata *pd, void *buf, size_t len)
494{
495	struct saioreq	*si;
496	struct saif	*sif;
497	char		*dmabuf;
498	int		rv;
499
500	si = pd->si;
501	sif = si->si_sif;
502	dmabuf = dvma_mapin(buf, len);
503	rv = sif->sif_poll(si->si_devdata, dmabuf);
504	dvma_mapout(dmabuf, len);
505
506	return (ssize_t)rv;
507}
508
509int
510getchar(void)
511{
512
513	return (prom_getchar());
514}
515
516satime_t
517getsecs(void)
518{
519
520	(void)prom_peekchar();
521	return (prom_ticks() / 1000);
522}
523
524/*
525 * A number of well-known devices on sun4s.
526 */
527static struct dtab {
528	char	*name;
529	int	type;
530} dtab[] = {
531	{ "sd",	DT_BLOCK },
532	{ "st",	DT_BLOCK },
533	{ "xd",	DT_BLOCK },
534	{ "xy",	DT_BLOCK },
535	{ "fd",	DT_BLOCK },
536	{ "le",	DT_NET },
537	{ "ie",	DT_NET },
538	{ NULL, 0 }
539};
540
541int
542getdevtype(int fd, char *name)
543{
544	struct dtab *dp;
545	int node;
546	char *cp;
547
548	switch (prom_version()) {
549	case PROM_OLDMON:
550	case PROM_OBP_V0:
551		for (dp = dtab; dp->name; dp++) {
552			if (name[0] == dp->name[0] &&
553			    name[1] == dp->name[1])
554				return (dp->type);
555		}
556		break;
557
558	case PROM_OBP_V2:
559	case PROM_OBP_V3:
560	case PROM_OPENFIRM:
561		node = prom_instance_to_package(fd);
562		cp = mygetpropstring(node, "device_type");
563		if (strcmp(cp, "block") == 0)
564			return (DT_BLOCK);
565		else if (strcmp(cp, "network") == 0)
566			return (DT_NET);
567		else if (strcmp(cp, "byte") == 0)
568			return (DT_BYTE);
569		break;
570	}
571	return (0);
572}
573
574/*
575 * Return a string property.  There is a (small) limit on the length;
576 * the string is fetched into a static buffer which is overwritten on
577 * subsequent calls.
578 */
579char *
580mygetpropstring(int node, char *name)
581{
582	int len;
583static	char buf[64];
584
585	len = prom_proplen(node, name);
586	if (len > 0)
587		_prom_getprop(node, name, buf, len);
588	else
589		len = 0;
590
591	buf[len] = '\0';	/* usually unnecessary */
592	return (buf);
593}
594#endif /* BOOTXX */
595
596/*
597 * Old monitor routines
598 */
599
600struct saioreq prom_si;
601static int promdev_inuse;
602
603int
604oldmon_iopen(struct promdata *pd)
605{
606	struct om_bootparam *bp;
607	struct om_boottable *ops;
608	struct devinfo *dip;
609	struct saioreq *si;
610	int	error;
611
612	if (promdev_inuse)
613		return (EMFILE);
614
615	bp = *romVectorPtr->bootParam;
616	ops = bp->bootTable;
617	dip = ops->b_devinfo;
618
619#ifdef DEBUG_PROM
620	printf("Boot device type: %s\n", ops->b_desc);
621	printf("d_devbytes=%d\n", dip->d_devbytes);
622	printf("d_dmabytes=%d\n", dip->d_dmabytes);
623	printf("d_localbytes=%d\n", dip->d_localbytes);
624	printf("d_stdcount=%d\n", dip->d_stdcount);
625	printf("d_stdaddrs[%d]=%lx\n", bp->ctlrNum, dip->d_stdaddrs[bp->ctlrNum]);
626	printf("d_devtype=%d\n", dip->d_devtype);
627	printf("d_maxiobytes=%d\n", dip->d_maxiobytes);
628#endif
629
630	dvma_init();
631
632	si = &prom_si;
633	memset(si, 0, sizeof(*si));
634	si->si_boottab = ops;
635	si->si_ctlr = bp->ctlrNum;
636	si->si_unit = bp->unitNum;
637	si->si_boff = bp->partNum;
638
639	if (si->si_ctlr > dip->d_stdcount)
640		return (ECTLR);
641
642	if (dip->d_devbytes) {
643		si->si_devaddr = oldmon_mapin(dip->d_stdaddrs[si->si_ctlr],
644			dip->d_devbytes, dip->d_devtype);
645#ifdef	DEBUG_PROM
646		printf("prom_iopen: devaddr=%p pte=0x%x\n",
647			si->si_devaddr,
648			getpte4((u_long)si->si_devaddr & ~PGOFSET));
649#endif
650	}
651
652	if (dip->d_dmabytes) {
653		si->si_dmaaddr = dvma_alloc(dip->d_dmabytes);
654#ifdef	DEBUG_PROM
655		printf("prom_iopen: dmaaddr=%p\n", si->si_dmaaddr);
656#endif
657	}
658
659	if (dip->d_localbytes) {
660		si->si_devdata = alloc(dip->d_localbytes);
661#ifdef	DEBUG_PROM
662		printf("prom_iopen: devdata=%p\n", si->si_devdata);
663#endif
664	}
665
666	/* OK, call the PROM device open routine. */
667	error = (*ops->b_open)(si);
668	if (error != 0) {
669		printf("prom_iopen: \"%s\" error=%d\n", ops->b_desc, error);
670		return (ENXIO);
671	}
672#ifdef	DEBUG_PROM
673	printf("prom_iopen: succeeded, error=%d\n", error);
674#endif
675
676	pd->si = si;
677	promdev_inuse++;
678	return (0);
679}
680
681void
682oldmon_iclose(struct saioreq *si)
683{
684	struct om_boottable *ops;
685	struct devinfo *dip;
686
687	if (promdev_inuse == 0)
688		return;
689
690	ops = si->si_boottab;
691	dip = ops->b_devinfo;
692
693	(*ops->b_close)(si);
694
695	if (si->si_dmaaddr) {
696		dvma_free(si->si_dmaaddr, dip->d_dmabytes);
697		si->si_dmaaddr = NULL;
698	}
699
700	promdev_inuse = 0;
701}
702
703static struct mapinfo {
704	int maptype;
705	int pgtype;
706	int base;
707} oldmon_mapinfo[] = {
708#define PG_COMMON	(PG_V|PG_W|PG_S|PG_NC)
709	{ MAP_MAINMEM,   PG_OBMEM | PG_COMMON, 0 },
710	{ MAP_OBIO,      PG_OBIO  | PG_COMMON, 0 },
711	{ MAP_MBMEM,     PG_VME16 | PG_COMMON, 0xFF000000 },
712	{ MAP_MBIO,      PG_VME16 | PG_COMMON, 0xFFFF0000 },
713	{ MAP_VME16A16D, PG_VME16 | PG_COMMON, 0xFFFF0000 },
714	{ MAP_VME16A32D, PG_VME32 | PG_COMMON, 0xFFFF0000 },
715	{ MAP_VME24A16D, PG_VME16 | PG_COMMON, 0xFF000000 },
716	{ MAP_VME24A32D, PG_VME32 | PG_COMMON, 0xFF000000 },
717	{ MAP_VME32A16D, PG_VME16 | PG_COMMON, 0 },
718	{ MAP_VME32A32D, PG_VME32 | PG_COMMON, 0 },
719};
720static int oldmon_mapinfo_cnt =
721	sizeof(oldmon_mapinfo) / sizeof(oldmon_mapinfo[0]);
722
723/* The virtual address we will use for PROM device mappings. */
724static u_long prom_devmap = MONSHORTSEG;
725
726static char *
727oldmon_mapin(u_long physaddr, int length, int maptype)
728{
729	int i, pa, pte, va;
730
731	if (length > (4*NBPG))
732		panic("oldmon_mapin: length=%d", length);
733
734	for (i = 0; i < oldmon_mapinfo_cnt; i++)
735		if (oldmon_mapinfo[i].maptype == maptype)
736			goto found;
737	panic("oldmon_mapin: invalid maptype %d", maptype);
738
739found:
740	pte = oldmon_mapinfo[i].pgtype;
741	pa = oldmon_mapinfo[i].base;
742	pa += physaddr;
743	pte |= ((pa >> SUN4_PGSHIFT) & PG_PFNUM);
744
745	va = prom_devmap;
746	do {
747		setpte4(va, pte);
748		va += NBPG;
749		pte += 1;
750		length -= NBPG;
751	} while (length > 0);
752	return ((char*)(prom_devmap | (pa & PGOFSET)));
753}
754