Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / sparc / stand / common / promdev.c
blobfc545560525e2052621f497e505278edeee50332
1 /* $NetBSD: promdev.c,v 1.22 2009/01/12 11:32:44 tsutsui Exp $ */
3 /*
4 * Copyright (c) 1993 Paul Kranenburg
5 * Copyright (c) 1995 Gordon W. Ross
6 * All rights reserved.
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
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.
35 * Note: the `#ifndef BOOTXX' in here serve to queeze the code size
36 * of the 1st-stage boot program.
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>
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>
52 #ifndef BOOTXX
53 #include <sys/disklabel.h>
54 #include <dev/sun/disklabel.h>
55 #include <dev/raidframe/raidframevar.h>
56 #endif
58 /* OBP V0-3 PROM vector */
59 #define obpvec ((struct promvec *)romp)
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);
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
82 extern struct fs_ops file_system_nfs[];
83 extern struct fs_ops file_system_ufs[];
85 #define null_devopen (void *)sparc_noop
86 #define null_devioctl (void *)sparc_noop
88 #if 0
89 struct devsw devsw[];
90 int ndevs = (sizeof(devsw)/sizeof(devsw[0]));
91 #endif
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 };
101 char prom_bootdevice[MAX_PROM_PATH];
102 static int saveecho;
104 #ifndef BOOTXX
105 static daddr_t doffset = 0;
106 #endif
109 void
110 putchar(int c)
113 if (c == '\n')
114 prom_putchar('\r');
115 prom_putchar(c);
118 void
119 _rtt(void)
122 prom_halt();
126 devopen(struct open_file *f, const char *fname, char **file)
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
140 pd = (struct promdata *)alloc(sizeof *pd);
141 f->f_devdata = (void *)pd;
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;
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;
163 fd = prom_open(prom_bootdevice);
164 if (fd == 0) {
165 error = ENXIO;
166 break;
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;
188 if (error) {
189 printf("Can't open device `%s'\n", prom_bootdevice);
190 return (error);
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;
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);
210 } else {
211 memcpy(file_system, file_system_ufs,
212 sizeof(struct fs_ops) * nfsys);
214 #ifdef NOTDEF_DEBUG
215 printf("devopen: Checking disklabel for RAID partition\n");
216 #endif
219 * Don't check disklabel on floppy boot since
220 * reopening it could cause Data Access Exception later.
222 if (strncmp(prom_bootdevice, "fd", 2) == 0 ||
223 strstr(prom_bootdevice, "SUNW,fdtwo") != NULL ||
224 strstr(prom_bootdevice, "fdthree") != NULL)
225 return 0;
228 * We need to read from the raw partition (i.e. the
229 * beginning of the disk in order to check the NetBSD
230 * disklabel to see if the boot partition is type RAID.
232 * For machines with prom_version() == PROM_OLDMON, we
233 * only handle boot from RAID for the first disk partition.
235 disk_pd = (struct promdata *)alloc(sizeof *disk_pd);
236 memcpy(disk_pd, pd, sizeof(struct promdata));
237 if (prom_version() != PROM_OLDMON) {
238 strcpy(rawpart, prom_bootdevice);
239 if ((partition = strchr(rawpart, ':')) != '\0' &&
240 *++partition >= 'a' &&
241 *partition <= 'a' + MAXPARTITIONS) {
242 part = *partition - 'a';
243 *partition = RAW_PART + 'a';
244 } else
245 strcat(rawpart, ":c");
246 if ((disk_pd->fd = prom_open(rawpart)) == 0)
247 return 0;
249 error = f->f_dev->dv_strategy(disk_pd, F_READ, LABELSECTOR,
250 DEV_BSIZE, &buf, &read);
251 if (prom_version() != PROM_OLDMON)
252 prom_close(disk_pd->fd);
253 if (error || (read != DEV_BSIZE))
254 return 0;
255 #ifdef NOTDEF_DEBUG
257 int x = 0;
258 char *p = (char *) buf;
260 printf(" Sector %d:\n", LABELSECTOR);
261 printf("00000000 ");
262 while (x < DEV_BSIZE) {
263 if (*p >= 0x00 && *p < 0x10)
264 printf("0%x ", *p & 0xff);
265 else
266 printf("%x ", *p & 0xff);
267 x++;
268 if (x && !(x % 8))
269 printf(" ");
270 if (x && !(x % 16)) {
271 if(x < 0x100)
272 printf("\n000000%x ", x);
273 else
274 printf("\n00000%x ", x);
276 p++;
278 printf("\n");
280 #endif
281 /* Check for NetBSD disk label. */
282 dlp = (struct disklabel *) (buf + LABELOFFSET);
283 if (dlp->d_magic == DISKMAGIC && !dkcksum(dlp) &&
284 dlp->d_partitions[part].p_fstype == FS_RAID) {
285 #ifdef NOTDEF_DEBUG
286 printf("devopen: found RAID partition, "
287 "adjusting offset to %d\n", RF_PROTECTED_SECTORS);
288 #endif
289 doffset = RF_PROTECTED_SECTORS;
292 #endif /* BOOTXX */
293 return (0);
298 obp_v0_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
299 void *buf, size_t *rsize)
301 int n, error = 0;
302 struct promdata *pd = (struct promdata *)devdata;
303 int fd = pd->fd;
305 #ifndef BOOTXX
306 dblk += doffset;
307 #endif
308 #ifdef DEBUG_PROM
309 printf("promstrategy: size=%d dblk=%d\n", size, dblk);
310 #endif
312 #define prom_bread(fd, nblk, dblk, buf) \
313 (*obpvec->pv_v0devops.v0_rbdev)(fd, nblk, dblk, buf)
314 #define prom_bwrite(fd, nblk, dblk, buf) \
315 (*obpvec->pv_v0devops.v0_wbdev)(fd, nblk, dblk, buf)
317 #ifndef BOOTXX /* We know it's a block device, so save some space */
318 if (pd->devtype != DT_BLOCK) {
319 printf("promstrategy: non-block device not supported\n");
320 error = EINVAL;
322 #endif
324 n = (flag == F_READ)
325 ? prom_bread(fd, btodb(size), dblk, buf)
326 : prom_bwrite(fd, btodb(size), dblk, buf);
328 *rsize = dbtob(n);
330 #ifdef DEBUG_PROM
331 printf("rsize = %x\n", *rsize);
332 #endif
333 return (error);
337 obp_v2_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
338 void *buf, size_t *rsize)
340 int error = 0;
341 struct promdata *pd = (struct promdata *)devdata;
342 int fd = pd->fd;
344 #ifndef BOOTXX
345 dblk += doffset;
346 #endif
347 #ifdef DEBUG_PROM
348 printf("promstrategy: size=%d dblk=%d\n", size, dblk);
349 #endif
351 #ifndef BOOTXX /* We know it's a block device, so save some space */
352 if (pd->devtype == DT_BLOCK)
353 #endif
354 prom_seek(fd, dbtob(dblk));
356 *rsize = (flag == F_READ)
357 ? prom_read(fd, buf, size)
358 : prom_write(fd, buf, size);
360 #ifdef DEBUG_PROM
361 printf("rsize = %x\n", *rsize);
362 #endif
363 return (error);
367 * On old-monitor machines, things work differently.
370 oldmon_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
371 void *buf, size_t *rsize)
373 struct promdata *pd = devdata;
374 struct saioreq *si;
375 struct om_boottable *ops;
376 char *dmabuf;
377 int si_flag;
378 size_t xcnt;
380 si = pd->si;
381 ops = si->si_boottab;
383 #ifndef BOOTXX
384 dblk += doffset;
385 #endif
386 #ifdef DEBUG_PROM
387 printf("prom_strategy: size=%d dblk=%d\n", size, dblk);
388 #endif
390 dmabuf = dvma_mapin(buf, size);
392 si->si_bn = dblk;
393 si->si_ma = dmabuf;
394 si->si_cc = size;
396 si_flag = (flag == F_READ) ? SAIO_F_READ : SAIO_F_WRITE;
397 xcnt = (*ops->b_strategy)(si, si_flag);
398 dvma_mapout(dmabuf, size);
400 #ifdef DEBUG_PROM
401 printf("disk_strategy: xcnt = %x\n", xcnt);
402 #endif
404 if (xcnt <= 0)
405 return (EIO);
407 *rsize = xcnt;
408 return (0);
412 obp_close(struct open_file *f)
414 struct promdata *pd = f->f_devdata;
415 register int fd = pd->fd;
417 #ifndef BOOTXX
418 if (pd->devtype == DT_NET)
419 net_close(pd);
420 #endif
421 prom_close(fd);
422 return 0;
426 oldmon_close(struct open_file *f)
428 struct promdata *pd = f->f_devdata;
430 #ifndef BOOTXX
431 if (pd->devtype == DT_NET)
432 net_close(pd);
433 #endif
434 oldmon_iclose(pd->si);
435 pd->si = NULL;
436 *romVectorPtr->echo = saveecho; /* Hmm, probably must go somewhere else */
437 return 0;
440 #ifndef BOOTXX
441 ssize_t
442 obp_v0_xmit(struct promdata *pd, void *buf, size_t len)
445 return ((*obpvec->pv_v0devops.v0_wnet)(pd->fd, len, buf));
448 ssize_t
449 obp_v2_xmit(struct promdata *pd, void *buf, size_t len)
452 return (prom_write(pd->fd, buf, len));
455 ssize_t
456 obp_v0_recv(struct promdata *pd, void *buf, size_t len)
459 return ((*obpvec->pv_v0devops.v0_rnet)(pd->fd, len, buf));
462 ssize_t
463 obp_v2_recv(struct promdata *pd, void *buf, size_t len)
465 int n;
467 n = prom_read(pd->fd, buf, len);
469 /* OBP V2 & V3 may return -2 */
470 return (n == -2 ? 0 : n);
473 ssize_t
474 oldmon_xmit(struct promdata *pd, void *buf, size_t len)
476 struct saioreq *si;
477 struct saif *sif;
478 char *dmabuf;
479 int rv;
481 si = pd->si;
482 sif = si->si_sif;
483 if (sif == NULL) {
484 printf("xmit: not a network device\n");
485 return (-1);
487 dmabuf = dvma_mapin(buf, len);
488 rv = sif->sif_xmit(si->si_devdata, dmabuf, len);
489 dvma_mapout(dmabuf, len);
491 return (ssize_t)(rv ? -1 : len);
494 ssize_t
495 oldmon_recv(struct promdata *pd, void *buf, size_t len)
497 struct saioreq *si;
498 struct saif *sif;
499 char *dmabuf;
500 int rv;
502 si = pd->si;
503 sif = si->si_sif;
504 dmabuf = dvma_mapin(buf, len);
505 rv = sif->sif_poll(si->si_devdata, dmabuf);
506 dvma_mapout(dmabuf, len);
508 return (ssize_t)rv;
512 getchar(void)
515 return (prom_getchar());
518 satime_t
519 getsecs(void)
522 (void)prom_peekchar();
523 return (prom_ticks() / 1000);
527 * A number of well-known devices on sun4s.
529 static struct dtab {
530 char *name;
531 int type;
532 } dtab[] = {
533 { "sd", DT_BLOCK },
534 { "st", DT_BLOCK },
535 { "xd", DT_BLOCK },
536 { "xy", DT_BLOCK },
537 { "fd", DT_BLOCK },
538 { "le", DT_NET },
539 { "ie", DT_NET },
540 { NULL, 0 }
544 getdevtype(int fd, char *name)
546 struct dtab *dp;
547 int node;
548 char *cp;
550 switch (prom_version()) {
551 case PROM_OLDMON:
552 case PROM_OBP_V0:
553 for (dp = dtab; dp->name; dp++) {
554 if (name[0] == dp->name[0] &&
555 name[1] == dp->name[1])
556 return (dp->type);
558 break;
560 case PROM_OBP_V2:
561 case PROM_OBP_V3:
562 case PROM_OPENFIRM:
563 node = prom_instance_to_package(fd);
564 cp = mygetpropstring(node, "device_type");
565 if (strcmp(cp, "block") == 0)
566 return (DT_BLOCK);
567 else if (strcmp(cp, "network") == 0)
568 return (DT_NET);
569 else if (strcmp(cp, "byte") == 0)
570 return (DT_BYTE);
571 break;
573 return (0);
577 * Return a string property. There is a (small) limit on the length;
578 * the string is fetched into a static buffer which is overwritten on
579 * subsequent calls.
581 char *
582 mygetpropstring(int node, char *name)
584 int len;
585 static char buf[64];
587 len = prom_proplen(node, name);
588 if (len > 0)
589 _prom_getprop(node, name, buf, len);
590 else
591 len = 0;
593 buf[len] = '\0'; /* usually unnecessary */
594 return (buf);
596 #endif /* BOOTXX */
599 * Old monitor routines
602 struct saioreq prom_si;
603 static int promdev_inuse;
606 oldmon_iopen(struct promdata *pd)
608 struct om_bootparam *bp;
609 struct om_boottable *ops;
610 struct devinfo *dip;
611 struct saioreq *si;
612 int error;
614 if (promdev_inuse)
615 return (EMFILE);
617 bp = *romVectorPtr->bootParam;
618 ops = bp->bootTable;
619 dip = ops->b_devinfo;
621 #ifdef DEBUG_PROM
622 printf("Boot device type: %s\n", ops->b_desc);
623 printf("d_devbytes=%d\n", dip->d_devbytes);
624 printf("d_dmabytes=%d\n", dip->d_dmabytes);
625 printf("d_localbytes=%d\n", dip->d_localbytes);
626 printf("d_stdcount=%d\n", dip->d_stdcount);
627 printf("d_stdaddrs[%d]=%x\n", bp->ctlrNum, dip->d_stdaddrs[bp->ctlrNum]);
628 printf("d_devtype=%d\n", dip->d_devtype);
629 printf("d_maxiobytes=%d\n", dip->d_maxiobytes);
630 #endif
632 dvma_init();
634 si = &prom_si;
635 memset(si, 0, sizeof(*si));
636 si->si_boottab = ops;
637 si->si_ctlr = bp->ctlrNum;
638 si->si_unit = bp->unitNum;
639 si->si_boff = bp->partNum;
641 if (si->si_ctlr > dip->d_stdcount)
642 return (ECTLR);
644 if (dip->d_devbytes) {
645 si->si_devaddr = oldmon_mapin(dip->d_stdaddrs[si->si_ctlr],
646 dip->d_devbytes, dip->d_devtype);
647 #ifdef DEBUG_PROM
648 printf("prom_iopen: devaddr=0x%x pte=0x%x\n",
649 si->si_devaddr,
650 getpte4((u_long)si->si_devaddr & ~PGOFSET));
651 #endif
654 if (dip->d_dmabytes) {
655 si->si_dmaaddr = dvma_alloc(dip->d_dmabytes);
656 #ifdef DEBUG_PROM
657 printf("prom_iopen: dmaaddr=0x%x\n", si->si_dmaaddr);
658 #endif
661 if (dip->d_localbytes) {
662 si->si_devdata = alloc(dip->d_localbytes);
663 #ifdef DEBUG_PROM
664 printf("prom_iopen: devdata=0x%x\n", si->si_devdata);
665 #endif
668 /* OK, call the PROM device open routine. */
669 error = (*ops->b_open)(si);
670 if (error != 0) {
671 printf("prom_iopen: \"%s\" error=%d\n", ops->b_desc, error);
672 return (ENXIO);
674 #ifdef DEBUG_PROM
675 printf("prom_iopen: succeeded, error=%d\n", error);
676 #endif
678 pd->si = si;
679 promdev_inuse++;
680 return (0);
683 void
684 oldmon_iclose(struct saioreq *si)
686 struct om_boottable *ops;
687 struct devinfo *dip;
689 if (promdev_inuse == 0)
690 return;
692 ops = si->si_boottab;
693 dip = ops->b_devinfo;
695 (*ops->b_close)(si);
697 if (si->si_dmaaddr) {
698 dvma_free(si->si_dmaaddr, dip->d_dmabytes);
699 si->si_dmaaddr = NULL;
702 promdev_inuse = 0;
705 static struct mapinfo {
706 int maptype;
707 int pgtype;
708 int base;
709 } oldmon_mapinfo[] = {
710 #define PG_COMMON (PG_V|PG_W|PG_S|PG_NC)
711 { MAP_MAINMEM, PG_OBMEM | PG_COMMON, 0 },
712 { MAP_OBIO, PG_OBIO | PG_COMMON, 0 },
713 { MAP_MBMEM, PG_VME16 | PG_COMMON, 0xFF000000 },
714 { MAP_MBIO, PG_VME16 | PG_COMMON, 0xFFFF0000 },
715 { MAP_VME16A16D, PG_VME16 | PG_COMMON, 0xFFFF0000 },
716 { MAP_VME16A32D, PG_VME32 | PG_COMMON, 0xFFFF0000 },
717 { MAP_VME24A16D, PG_VME16 | PG_COMMON, 0xFF000000 },
718 { MAP_VME24A32D, PG_VME32 | PG_COMMON, 0xFF000000 },
719 { MAP_VME32A16D, PG_VME16 | PG_COMMON, 0 },
720 { MAP_VME32A32D, PG_VME32 | PG_COMMON, 0 },
722 static int oldmon_mapinfo_cnt =
723 sizeof(oldmon_mapinfo) / sizeof(oldmon_mapinfo[0]);
725 /* The virtual address we will use for PROM device mappings. */
726 static u_long prom_devmap = MONSHORTSEG;
728 static char *
729 oldmon_mapin(u_long physaddr, int length, int maptype)
731 int i, pa, pte, va;
733 if (length > (4*NBPG))
734 panic("oldmon_mapin: length=%d", length);
736 for (i = 0; i < oldmon_mapinfo_cnt; i++)
737 if (oldmon_mapinfo[i].maptype == maptype)
738 goto found;
739 panic("oldmon_mapin: invalid maptype %d", maptype);
741 found:
742 pte = oldmon_mapinfo[i].pgtype;
743 pa = oldmon_mapinfo[i].base;
744 pa += physaddr;
745 pte |= ((pa >> SUN4_PGSHIFT) & PG_PFNUM);
747 va = prom_devmap;
748 do {
749 setpte4(va, pte);
750 va += NBPG;
751 pte += 1;
752 length -= NBPG;
753 } while (length > 0);
754 return ((char*)(prom_devmap | (pa & PGOFSET)));