1 /* $NetBSD: ofdev.c,v 1.23 2009/03/18 17:06:47 cegger Exp $ */
4 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5 * Copyright (C) 1995, 1996 TooLs GmbH.
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 TooLs GmbH.
19 * 4. The name of TooLs GmbH 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 TOOLS GMBH ``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 TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * Device I/O routines using Open Firmware
36 #include <sys/param.h>
37 #include <sys/disklabel.h>
39 #include <netinet/in.h>
42 #include <lib/libsa/stand.h>
43 #include <lib/libsa/ufs.h>
44 #include <lib/libsa/cd9660.h>
46 #include <lib/libsa/nfs.h>
47 #include <lib/libsa/tftp.h>
49 #include <lib/libkern/libkern.h>
51 #include <dev/sun/disklabel.h>
52 #include <dev/raidframe/raidframevar.h>
54 #include <machine/promlib.h>
59 extern char bootdev
[];
62 * This is ugly. A path on a sparc machine is something like this:
64 * [device] [-<options] [path] [-options] [otherstuff] [-<more options]
69 filename(char *str
, char *ppart
)
79 for (cp
= str
; *cp
; lp
= cp
) {
80 /* For each component of the path name... */
81 while (*++cp
&& *cp
!= '/');
84 /* ...look whether there is a device with this name */
85 dhandle
= prom_finddevice(str
);
86 DPRINTF(("filename: prom_finddevice(%s) returned %x\n",
91 * if not, lp is the delimiter between device and
92 * path. if the last component was a block device.
94 if (!strcmp(devtype
, "block")) {
95 /* search for arguments */
96 DPRINTF(("filename: hunting for arguments "
102 (cp
[0] == ' ' && (cp
+1) != lp
&&
106 if (cp
>= str
&& *cp
== '-')
107 /* found arguments, make firmware
110 for (cp
= lp
; *--cp
&& *cp
!= ','
113 if (cp
[0] == ':' && cp
[1] >= 'a' &&
114 cp
[1] <= 'a' + MAXPARTITIONS
) {
119 DPRINTF(("filename: found %s\n",lp
));
121 } else if (_prom_getprop(dhandle
, "device_type", devtype
,
125 DPRINTF(("filename: not found\n",lp
));
130 strategy(void *devdata
, int rw
, daddr_t blk
, size_t size
, void *buf
, size_t *rsize
)
132 struct of_dev
*dev
= devdata
;
138 if (dev
->type
!= OFDEV_DISK
)
142 printf("strategy: block %lx, partition offset %lx, blksz %lx\n",
143 (long)blk
, (long)dev
->partoff
, (long)dev
->bsize
);
144 printf("strategy: seek position should be: %lx\n",
145 (long)((blk
+ dev
->partoff
) * dev
->bsize
));
147 pos
= (u_quad_t
)(blk
+ dev
->partoff
) * dev
->bsize
;
151 printf("strategy: seeking to %lx\n", (long)pos
);
153 if (prom_seek(dev
->handle
, pos
) < 0)
156 printf("strategy: reading %lx at %p\n", (long)size
, buf
);
158 n
= prom_read(dev
->handle
, buf
, size
);
170 devclose(struct open_file
*of
)
172 struct of_dev
*op
= of
->f_devdata
;
175 if (op
->type
== OFDEV_NET
)
178 prom_close(op
->handle
);
182 static struct devsw ofdevsw
[1] = {
185 (int (*)(struct open_file
*, ...))nodev
,
189 int ndevs
= sizeof ofdevsw
/ sizeof ofdevsw
[0];
191 #ifdef SPARC_BOOT_UFS
192 static struct fs_ops file_system_ufs
= FS_OPS(ufs
);
194 #ifdef SPARC_BOOT_CD9660
195 static struct fs_ops file_system_cd9660
= FS_OPS(cd9660
);
198 static struct fs_ops file_system_nfs
= FS_OPS(nfs
);
199 static struct fs_ops file_system_tftp
= FS_OPS(tftp
);
202 struct fs_ops file_system
[3];
205 static struct of_dev ofdev
= {
209 char opened_name
[256];
213 get_long(const void *p
)
215 const unsigned char *cp
= p
;
217 return cp
[0] | (cp
[1] << 8) | (cp
[2] << 16) | (cp
[3] << 24);
219 /************************************************************************
221 * The rest of this was taken from arch/sparc64/scsi/sun_disklabel.c
222 * and then substantially rewritten by Gordon W. Ross
224 ************************************************************************/
226 /* What partition types to assume for Sun disklabels: */
231 FS_OTHER
, /* c - whole disk */
240 * Given a SunOS disk label, set lp to a BSD disk label.
241 * Returns NULL on success, else an error string.
243 * The BSD label is cleared out before this is called.
246 disklabel_sun_to_bsd(char *cp
, struct disklabel
*lp
)
248 struct sun_disklabel
*sl
;
249 struct partition
*npp
;
250 struct sun_dkpart
*spp
;
252 u_short cksum
, *sp1
, *sp2
;
254 sl
= (struct sun_disklabel
*)cp
;
256 /* Verify the XOR check. */
258 sp2
= (u_short
*)(sl
+ 1);
263 return("SunOS disk label, bad checksum");
265 /* Format conversion. */
266 lp
->d_magic
= DISKMAGIC
;
267 lp
->d_magic2
= DISKMAGIC
;
268 memcpy(lp
->d_packname
, sl
->sl_text
, sizeof(lp
->d_packname
));
271 lp
->d_nsectors
= sl
->sl_nsectors
;
272 lp
->d_ntracks
= sl
->sl_ntracks
;
273 lp
->d_ncylinders
= sl
->sl_ncylinders
;
275 secpercyl
= sl
->sl_nsectors
* sl
->sl_ntracks
;
276 lp
->d_secpercyl
= secpercyl
;
277 lp
->d_secperunit
= secpercyl
* sl
->sl_ncylinders
;
279 lp
->d_sparespercyl
= sl
->sl_sparespercyl
;
280 lp
->d_acylinders
= sl
->sl_acylinders
;
281 lp
->d_rpm
= sl
->sl_rpm
;
282 lp
->d_interleave
= sl
->sl_interleave
;
284 lp
->d_npartitions
= 8;
285 /* These are as defined in <ufs/ffs/fs.h> */
286 lp
->d_bbsize
= 8192; /* XXX */
287 lp
->d_sbsize
= 8192; /* XXX */
289 for (i
= 0; i
< 8; i
++) {
290 spp
= &sl
->sl_part
[i
];
291 npp
= &lp
->d_partitions
[i
];
292 npp
->p_offset
= spp
->sdkp_cyloffset
* secpercyl
;
293 npp
->p_size
= spp
->sdkp_nsectors
;
294 DPRINTF(("partition %d start %x size %x\n", i
, (int)npp
->p_offset
, (int)npp
->p_size
));
295 if (npp
->p_size
== 0) {
296 npp
->p_fstype
= FS_UNUSED
;
298 npp
->p_fstype
= sun_fstypes
[i
];
299 if (npp
->p_fstype
== FS_BSDFFS
) {
301 * The sun label does not store the FFS fields,
302 * so just set them with default values here.
312 lp
->d_checksum
= dkcksum(lp
);
313 DPRINTF(("disklabel_sun_to_bsd: success!\n"));
318 * Find a valid disklabel.
321 search_label(struct of_dev
*devp
, u_long off
, char *buf
,
322 struct disklabel
*lp
, u_long off0
)
325 struct mbr_partition
*p
;
328 static int recursion
;
330 struct disklabel
*dlp
;
331 struct sun_disklabel
*slp
;
334 /* minimal requirements for archtypal disk label */
335 if (lp
->d_secperunit
== 0)
336 lp
->d_secperunit
= 0x1fffffff;
337 lp
->d_npartitions
= 1;
338 if (lp
->d_partitions
[0].p_size
== 0)
339 lp
->d_partitions
[0].p_size
= 0x1fffffff;
340 lp
->d_partitions
[0].p_offset
= 0;
342 if (strategy(devp
, F_READ
, LABELSECTOR
, DEV_BSIZE
, buf
, &read
)
343 || read
!= DEV_BSIZE
)
344 return ("Cannot read label");
345 /* Check for a NetBSD disk label. */
346 dlp
= (struct disklabel
*) (buf
+ LABELOFFSET
);
347 if (dlp
->d_magic
== DISKMAGIC
) {
349 return ("NetBSD disk label corrupted");
351 DPRINTF(("search_label: found NetBSD label\n"));
355 /* Check for a Sun disk label (for PROM compatibility). */
356 slp
= (struct sun_disklabel
*) buf
;
357 if (slp
->sl_magic
== SUN_DKMAGIC
)
358 return (disklabel_sun_to_bsd(buf
, lp
));
361 memset(buf
, 0, sizeof(buf
));
362 return ("no disk label");
366 devopen(struct open_file
*of
, const char *name
, char **file
)
370 char fname
[256], devname
[256];
373 struct disklabel label
;
375 struct disklabel label
;
376 int handle
, part
, try = 0;
378 char *errmsg
= NULL
, *pp
, savedpart
= 0;
381 if (ofdev
.handle
!= -1)
383 if (of
->f_flags
!= F_READ
)
385 DPRINTF(("devopen: you want %s\n", name
));
387 cp
= filename(fname
, &partition
);
392 if (!cp
|| !b
.buf
[0])
393 strcpy(b
.buf
, DEFAULT_KERNEL
);
395 strcpy(fname
, bootdev
);
396 strcpy(opened_name
, fname
);
398 cp
= opened_name
+ strlen(opened_name
);
403 *file
= opened_name
+ strlen(opened_name
);
405 strcat(opened_name
, "/");
406 strcat(opened_name
, b
.buf
);
407 DPRINTF(("devopen: trying %s\n", fname
));
408 if ((handle
= prom_finddevice(fname
)) == -1)
410 DPRINTF(("devopen: found %s\n", fname
));
411 if (_prom_getprop(handle
, "name", b
.buf
, sizeof b
.buf
) < 0)
413 DPRINTF(("devopen: %s is called %s\n", fname
, b
.buf
));
414 floppyboot
= !strcmp(b
.buf
, "floppy");
415 if (_prom_getprop(handle
, "device_type", b
.buf
, sizeof b
.buf
) < 0)
417 DPRINTF(("devopen: %s is a %s device\n", fname
, b
.buf
));
418 if (!strcmp(b
.buf
, "block")) {
419 pp
= strrchr(fname
, ':');
420 if (pp
&& pp
[1] >= 'a' && pp
[1] <= 'f' && pp
[2] == 0) {
424 handle
= prom_open(fname
);
426 OF_instance_to_path(handle
, devname
,
428 DPRINTF(("real path: %s\n", devname
));
430 pp
= devname
+ strlen(devname
);
431 if (pp
> devname
+ 3) pp
-= 2;
435 pp
= fname
+ strlen(fname
);
440 DPRINTF(("devopen: replacing by whole disk device %s\n",
443 partition
= savedpart
;
447 DPRINTF(("devopen: opening %s\n", fname
));
448 if ((handle
= prom_open(fname
)) == -1) {
449 DPRINTF(("devopen: open of %s failed\n", fname
));
450 if (pp
&& savedpart
) {
464 DPRINTF(("devopen: %s is now open\n", fname
));
465 memset(&ofdev
, 0, sizeof ofdev
);
466 ofdev
.handle
= handle
;
467 if (!strcmp(b
.buf
, "block")) {
468 ofdev
.type
= OFDEV_DISK
;
469 ofdev
.bsize
= DEV_BSIZE
;
470 /* First try to find a disklabel without MBR partitions */
471 DPRINTF(("devopen: trying to read disklabel\n"));
472 if (strategy(&ofdev
, F_READ
,
473 LABELSECTOR
, DEV_BSIZE
, b
.buf
, &read
) != 0
475 || (errmsg
= getdisklabel(b
.buf
, &label
))) {
476 if (errmsg
) printf("devopen: getdisklabel returned %s\n", errmsg
);
477 /* Else try MBR partitions */
478 errmsg
= search_label(&ofdev
, 0, b
.buf
, &label
, 0);
480 printf("devopen: search_label returned %s\n", errmsg
);
483 if (error
&& error
!= ERDLAB
)
487 if (error
== ERDLAB
) {
488 /* No, label, just use complete disk */
490 if (pp
&& savedpart
) {
493 if ((handle
= prom_open(fname
)) == -1) {
494 DPRINTF(("devopen: open of %s failed\n",
498 ofdev
.handle
= handle
;
499 DPRINTF(("devopen: back to original device %s\n",
503 part
= partition
? partition
- 'a' : 0;
504 ofdev
.partoff
= label
.d_partitions
[part
].p_offset
;
505 DPRINTF(("devopen: setting partition %d offset %x\n",
506 part
, ofdev
.partoff
));
507 if (label
.d_partitions
[part
].p_fstype
== FS_RAID
) {
508 ofdev
.partoff
+= RF_PROTECTED_SECTORS
;
509 DPRINTF(("devopen: found RAID partition, "
510 "adjusting offset to %x\n", ofdev
.partoff
));
516 of
->f_devdata
= &ofdev
;
517 #ifdef SPARC_BOOT_UFS
518 memcpy(&file_system
[nfsys
++], &file_system_ufs
, sizeof file_system
[0]);
520 #ifdef SPARC_BOOT_CD9660
521 memcpy(&file_system
[nfsys
++], &file_system_cd9660
,
522 sizeof file_system
[0]);
524 DPRINTF(("devopen: return 0\n"));
528 if (!strcmp(b
.buf
, "network")) {
529 if (error
= net_open(&ofdev
))
532 ofdev
.type
= OFDEV_NET
;
534 of
->f_devdata
= NULL
;
536 if (!strncmp(*file
,"/tftp:",6)) {
538 memcpy(&file_system
[0], &file_system_tftp
, sizeof file_system
[0]);
539 if (net_tftp_bootp(&of
->f_devdata
)) {
544 memcpy(&file_system
[0], &file_system_nfs
, sizeof file_system
[0]);
545 if (error
= net_mountroot()) {
556 DPRINTF(("devopen: error %d, cannot open device\n", error
));