1 /* $NetBSD: promdev.c,v 1.22 2009/01/12 11:32:44 tsutsui Exp $ */
4 * Copyright (c) 1993 Paul Kranenburg
5 * Copyright (c) 1995 Gordon W. Ross
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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>
53 #include <sys/disklabel.h>
54 #include <dev/sun/disklabel.h>
55 #include <dev/raidframe/raidframevar.h>
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);
78 static char *mygetpropstring(int, char *);
79 static int getdevtype(int, char *);
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
90 int ndevs
= (sizeof(devsw
)/sizeof(devsw
[0]));
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
];
105 static daddr_t doffset
= 0;
126 devopen(struct open_file
*f
, const char *fname
, char **file
)
128 int error
= 0, fd
= 0;
133 char rawpart
[MAX_PROM_PATH
];
134 struct promdata
*disk_pd
;
136 struct disklabel
*dlp
;
140 pd
= (struct promdata
*)alloc(sizeof *pd
);
141 f
->f_devdata
= (void *)pd
;
143 switch (prom_version()) {
145 error
= oldmon_iopen(pd
);
147 pd
->xmit
= oldmon_xmit
;
148 pd
->recv
= oldmon_recv
;
150 f
->f_dev
= &oldmon_devsw
;
151 saveecho
= *romVectorPtr
->echo
;
152 *romVectorPtr
->echo
= 0;
159 if (*prom_bootdevice
== '\0') {
163 fd
= prom_open(prom_bootdevice
);
169 switch (prom_version()) {
172 pd
->xmit
= obp_v0_xmit
;
173 pd
->recv
= obp_v0_recv
;
175 f
->f_dev
= &obp_v0_devsw
;
181 pd
->xmit
= obp_v2_xmit
;
182 pd
->recv
= obp_v2_recv
;
184 f
->f_dev
= &obp_v2_devsw
;
189 printf("Can't open device `%s'\n", prom_bootdevice
);
194 pd
->devtype
= DT_BLOCK
;
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
) {
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",
211 memcpy(file_system
, file_system_ufs
,
212 sizeof(struct fs_ops
) * nfsys
);
215 printf("devopen: Checking disklabel for RAID partition\n");
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
)
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';
245 strcat(rawpart
, ":c");
246 if ((disk_pd
->fd
= prom_open(rawpart
)) == 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
))
258 char *p
= (char *) buf
;
260 printf(" Sector %d:\n", LABELSECTOR
);
262 while (x
< DEV_BSIZE
) {
263 if (*p
>= 0x00 && *p
< 0x10)
264 printf("0%x ", *p
& 0xff);
266 printf("%x ", *p
& 0xff);
270 if (x
&& !(x
% 16)) {
272 printf("\n000000%x ", x
);
274 printf("\n00000%x ", x
);
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
) {
286 printf("devopen: found RAID partition, "
287 "adjusting offset to %d\n", RF_PROTECTED_SECTORS
);
289 doffset
= RF_PROTECTED_SECTORS
;
298 obp_v0_strategy(void *devdata
, int flag
, daddr_t dblk
, size_t size
,
299 void *buf
, size_t *rsize
)
302 struct promdata
*pd
= (struct promdata
*)devdata
;
309 printf("promstrategy: size=%d dblk=%d\n", size
, dblk
);
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");
325 ? prom_bread(fd
, btodb(size
), dblk
, buf
)
326 : prom_bwrite(fd
, btodb(size
), dblk
, buf
);
331 printf("rsize = %x\n", *rsize
);
337 obp_v2_strategy(void *devdata
, int flag
, daddr_t dblk
, size_t size
,
338 void *buf
, size_t *rsize
)
341 struct promdata
*pd
= (struct promdata
*)devdata
;
348 printf("promstrategy: size=%d dblk=%d\n", size
, dblk
);
351 #ifndef BOOTXX /* We know it's a block device, so save some space */
352 if (pd
->devtype
== DT_BLOCK
)
354 prom_seek(fd
, dbtob(dblk
));
356 *rsize
= (flag
== F_READ
)
357 ? prom_read(fd
, buf
, size
)
358 : prom_write(fd
, buf
, size
);
361 printf("rsize = %x\n", *rsize
);
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
;
375 struct om_boottable
*ops
;
381 ops
= si
->si_boottab
;
387 printf("prom_strategy: size=%d dblk=%d\n", size
, dblk
);
390 dmabuf
= dvma_mapin(buf
, 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
);
401 printf("disk_strategy: xcnt = %x\n", xcnt
);
412 obp_close(struct open_file
*f
)
414 struct promdata
*pd
= f
->f_devdata
;
415 register int fd
= pd
->fd
;
418 if (pd
->devtype
== DT_NET
)
426 oldmon_close(struct open_file
*f
)
428 struct promdata
*pd
= f
->f_devdata
;
431 if (pd
->devtype
== DT_NET
)
434 oldmon_iclose(pd
->si
);
436 *romVectorPtr
->echo
= saveecho
; /* Hmm, probably must go somewhere else */
442 obp_v0_xmit(struct promdata
*pd
, void *buf
, size_t len
)
445 return ((*obpvec
->pv_v0devops
.v0_wnet
)(pd
->fd
, len
, buf
));
449 obp_v2_xmit(struct promdata
*pd
, void *buf
, size_t len
)
452 return (prom_write(pd
->fd
, buf
, len
));
456 obp_v0_recv(struct promdata
*pd
, void *buf
, size_t len
)
459 return ((*obpvec
->pv_v0devops
.v0_rnet
)(pd
->fd
, len
, buf
));
463 obp_v2_recv(struct promdata
*pd
, void *buf
, size_t len
)
467 n
= prom_read(pd
->fd
, buf
, len
);
469 /* OBP V2 & V3 may return -2 */
470 return (n
== -2 ? 0 : n
);
474 oldmon_xmit(struct promdata
*pd
, void *buf
, size_t len
)
484 printf("xmit: not a network device\n");
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
);
495 oldmon_recv(struct promdata
*pd
, void *buf
, size_t len
)
504 dmabuf
= dvma_mapin(buf
, len
);
505 rv
= sif
->sif_poll(si
->si_devdata
, dmabuf
);
506 dvma_mapout(dmabuf
, len
);
515 return (prom_getchar());
522 (void)prom_peekchar();
523 return (prom_ticks() / 1000);
527 * A number of well-known devices on sun4s.
544 getdevtype(int fd
, char *name
)
550 switch (prom_version()) {
553 for (dp
= dtab
; dp
->name
; dp
++) {
554 if (name
[0] == dp
->name
[0] &&
555 name
[1] == dp
->name
[1])
563 node
= prom_instance_to_package(fd
);
564 cp
= mygetpropstring(node
, "device_type");
565 if (strcmp(cp
, "block") == 0)
567 else if (strcmp(cp
, "network") == 0)
569 else if (strcmp(cp
, "byte") == 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
582 mygetpropstring(int node
, char *name
)
587 len
= prom_proplen(node
, name
);
589 _prom_getprop(node
, name
, buf
, len
);
593 buf
[len
] = '\0'; /* usually unnecessary */
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
;
617 bp
= *romVectorPtr
->bootParam
;
619 dip
= ops
->b_devinfo
;
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
);
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
)
644 if (dip
->d_devbytes
) {
645 si
->si_devaddr
= oldmon_mapin(dip
->d_stdaddrs
[si
->si_ctlr
],
646 dip
->d_devbytes
, dip
->d_devtype
);
648 printf("prom_iopen: devaddr=0x%x pte=0x%x\n",
650 getpte4((u_long
)si
->si_devaddr
& ~PGOFSET
));
654 if (dip
->d_dmabytes
) {
655 si
->si_dmaaddr
= dvma_alloc(dip
->d_dmabytes
);
657 printf("prom_iopen: dmaaddr=0x%x\n", si
->si_dmaaddr
);
661 if (dip
->d_localbytes
) {
662 si
->si_devdata
= alloc(dip
->d_localbytes
);
664 printf("prom_iopen: devdata=0x%x\n", si
->si_devdata
);
668 /* OK, call the PROM device open routine. */
669 error
= (*ops
->b_open
)(si
);
671 printf("prom_iopen: \"%s\" error=%d\n", ops
->b_desc
, error
);
675 printf("prom_iopen: succeeded, error=%d\n", error
);
684 oldmon_iclose(struct saioreq
*si
)
686 struct om_boottable
*ops
;
689 if (promdev_inuse
== 0)
692 ops
= si
->si_boottab
;
693 dip
= ops
->b_devinfo
;
697 if (si
->si_dmaaddr
) {
698 dvma_free(si
->si_dmaaddr
, dip
->d_dmabytes
);
699 si
->si_dmaaddr
= NULL
;
705 static struct mapinfo
{
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
;
729 oldmon_mapin(u_long physaddr
, int length
, int maptype
)
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
)
739 panic("oldmon_mapin: invalid maptype %d", maptype
);
742 pte
= oldmon_mapinfo
[i
].pgtype
;
743 pa
= oldmon_mapinfo
[i
].base
;
745 pte
|= ((pa
>> SUN4_PGSHIFT
) & PG_PFNUM
);
753 } while (length
> 0);
754 return ((char*)(prom_devmap
| (pa
& PGOFSET
)));