On Tue, Oct 04, 2016 at 08:08:32PM +0000, Miod Vallat wrote: > The sgi boot blocks use the PROM (ARCBios or ARCS) for its I/O routines. > When using a disk-based path, these routines are using the partition > table found in the ``volume header''. > > In order to be able to use 16 partitions per disk, the OpenBSD port only > claims one volume header partition, #0, as the OpenBSD area, and puts > its own label in there. > > Unfortunately, this means that `sd0a', the OpenBSD partition on which > the kernel is found, may not actually start at the same location as the > volume header partition #0, even though this is the case in most setups. > > When reinstalling an O2 some time ago, I did not pay attention to this > during install: > > Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout? [a] c > [...] > Label editor (enter '?' for help at any prompt) > > p > OpenBSD area: 0-17773524; size: 17773524; free: 0 > # size offset fstype [fsize bsize cpg] > a: 17770389 3135 4.2BSD 1024 8192 16 > c: 17773524 0 unused > p: 3135 0 unknown > > d a > > a > partition: [a] > offset: [3135] > size: [17770389] 400M > Rounding size to cylinder (3360 sectors): 816705 > FS type: [4.2BSD] > mount point: [none] / > Rounding offset to bsize (32 sectors): 3136 > Rounding size to bsize (32 sectors): 816704 > > And `sd0a' ended up starting one sector after the beginning of the > volume header partition #0. > > Of course, rebooting afterwards did not work as expected: > > OpenBSD/sgi-IP32 ARCBios boot version 1.7 > arg 0: pci(0)scsi(0)disk(1)rdisk(0)partition(8)/boot > arg 1: OSLoadOptions=auto > arg 2: ConsoleIn=serial(0) > arg 3: ConsoleOut=serial(0) > arg 4: SystemPartition=pci(0)scsi(0)disk(1)rdisk(0)partition(8) > arg 5: OSLoader=boot > arg 6: OSLoadPartition=pci(0)scsi(0)disk(1)rdisk(0)partition(0) > arg 7: OSLoadFilename=bsd > Boot: pci(0)scsi(0)disk(1)rdisk(0)partition(0)bsd > cannot open pci(0)scsi(0)disk(1)rdisk(0)partition(0)/etc/random.seed: > Invalid argument > open pci(0)scsi(0)disk(1)rdisk(0)partition(0)bsd: Invalid argument > Boot FAILED! > > The proper way to fix this is to make the boot blocks read the real > OpenBSD label instead of assuming sd0a spans volume header partition #0 > in all cases. > > This is achieved by the diff below, which will attempt to use the raw > disk device (volume header partition #10, equivalent to sd0c) for disk > accesses and will read both the volume header (to know where the OpenBSD > disklabel lies) and then the OpenBSD label (to know where sd0a really > is). > > Of course, this has to cope with the two valid disk syntaxes (true > ARCBios used on older sgi systems, and ARCS dksc() syntax used on Origin > and later systems). > > This diff has been tested on O2 (IP32) and Origin 350 (IP27). It is > written in a conservative way, in order to revert to the existing > behaviour if anything fails (invalid volume header, no OpenBSD label > yet...) and should not cause any regression. > > Note that network boots are not affected by these changes.
I tested this also on Octane (IP30), and it works fine. The diff is now committed. Thanks! > Index: Makefile32.inc > =================================================================== > RCS file: /OpenBSD/src/sys/arch/sgi/stand/Makefile32.inc,v > retrieving revision 1.5 > diff -u -p -r1.5 Makefile32.inc > --- Makefile32.inc 19 Oct 2012 13:51:59 -0000 1.5 > +++ Makefile32.inc 30 Sep 2016 09:19:15 -0000 > @@ -18,6 +18,7 @@ AS+= -32 > LD?= ld > LD+= -m elf32btsmip > LIBSA_CPPFLAGS= > +CFLAGS+= -DLIBSA_LONGLONG_PRINTF > .endif > > ### Figure out what to use for libsa and libz > Index: boot/Makefile > =================================================================== > RCS file: /OpenBSD/src/sys/arch/sgi/stand/boot/Makefile,v > retrieving revision 1.16 > diff -u -p -r1.16 Makefile > --- boot/Makefile 30 Jul 2016 03:25:49 -0000 1.16 > +++ boot/Makefile 30 Sep 2016 09:19:15 -0000 > @@ -13,14 +13,14 @@ AFLAGS+= ${SAABI} > > S= ${.CURDIR}/../../../.. > SRCS= start.S arcbios.c boot.c conf.c diskio.c filesystem.c \ > - netfs.c netio.c strchr.c strstr.c > + netfs.c netio.c strstr.c > > .PATH: ${S}/lib/libsa > SRCS+= loadfile.c > > .PATH: ${S}/lib/libkern/arch/mips64 ${S}/lib/libkern > -SRCS+= strlcpy.c memcpy.c strlen.c strrchr.c strlcat.c > strncmp.c \ > - strcmp.S > +SRCS+= memcpy.c strchr.c strcmp.S strlcat.c strlcpy.c strlen.c > \ > + strncmp.c strrchr.c > > CLEANFILES+= machine mips64 > > Index: boot/diskio.c > =================================================================== > RCS file: /OpenBSD/src/sys/arch/sgi/stand/boot/diskio.c,v > retrieving revision 1.10 > diff -u -p -r1.10 diskio.c > --- boot/diskio.c 30 Sep 2015 22:45:57 -0000 1.10 > +++ boot/diskio.c 30 Sep 2016 09:19:15 -0000 > @@ -1,6 +1,21 @@ > /* $OpenBSD: diskio.c,v 1.10 2015/09/30 22:45:57 krw Exp $ */ > > /* > + * Copyright (c) 2016 Miodrag Vallat. > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > +/* > * Copyright (c) 2000 Opsycon AB (www.opsycon.se) > * Copyright (c) 2000 Rtmx, Inc (www.rtmx.com) > * > @@ -33,11 +48,15 @@ > * > */ > > -#include <stand.h> > #include <sys/param.h> > +#include <lib/libkern/libkern.h> > +#include <stand.h> > + > #include <sys/disklabel.h> > #include <mips64/arcbios.h> > > +char *strstr(char *, const char *); /* strstr.c */ > + > struct dio_softc { > int sc_fd; /* PROM file ID */ > int sc_part; /* Disk partition number. */ > @@ -50,18 +69,20 @@ diostrategy(void *devdata, int rw, daddr > { > struct dio_softc *sc = (struct dio_softc *)devdata; > struct partition *pp = &sc->sc_label.d_partitions[sc->sc_part]; > + uint64_t blkoffset; > arc_quad_t offset; > long result; > > - offset.hi = 0; > - offset.lo = (pp->p_offset + bn) * DEV_BSIZE; > - > - if ((Bios_Seek(sc->sc_fd, &offset, 0) < 0) || > - (Bios_Read(sc->sc_fd, addr, reqcnt, &result) < 0)) > - return (EIO); > + blkoffset = (DL_GETPOFFSET(pp) + bn) * DEV_BSIZE; > + offset.hi = blkoffset >> 32; > + offset.lo = blkoffset; > + > + if (Bios_Seek(sc->sc_fd, &offset, 0) < 0 || > + Bios_Read(sc->sc_fd, addr, reqcnt, &result) < 0) > + return EIO; > > *cnt = result; > - return (0); > + return 0; > } > > int > @@ -69,11 +90,18 @@ dioopen(struct open_file *f, ...) > { > char *ctlr; > int partition; > - > struct dio_softc *sc; > struct disklabel *lp; > + struct sgilabel *sl; > long fd; > + /* XXX getdisklabel() assumes DEV_BSIZE bytes available */ > + char buf[DEV_BSIZE + LABELOFFSET]; > + arc_quad_t offset; > + daddr_t native_offset; > + long result; > va_list ap; > + char rawctlr[1 + MAXPATHLEN]; > + char *partptr; > > va_start(ap, f); > ctlr = va_arg(ap, char *); > @@ -81,26 +109,130 @@ dioopen(struct open_file *f, ...) > va_end(ap); > > if (partition >= MAXPARTITIONS) > - return (ENXIO); > + return ENXIO; > > - if (Bios_Open(ctlr, 0, &fd) < 0) > - return (ENXIO); > + /* > + * If booting from disk, `ctlr` is something like > + * whatever()partition(0) > + * or > + * dksc(whatever,0) > + * where 0 is the volume header #0 partition, which is the > + * OpenBSD area, where the OpenBSD disklabel can be found. > + * > + * However, the OpenBSD `a' partition, where the kernel is to be > + * found, may not start at the same offset. > + * > + * In order to be able to correctly load any file from the OpenBSD > + * partitions, we need to access the volume header partition table > + * and the OpenBSD label. > + * > + * Therefore, make sure we replace `partition(*)' with `partition(10)' > + * before reaching ARCBios, in order to access the raw disk. > + * > + * We could use partition #8 and use the value of SystemPartition in > + * the environment to avoid doing this, but this would prevent us > + * from being able to boot from a different disk than the one > + * pointed to by SystemPartition. > + */ > + > + strlcpy(rawctlr, ctlr, sizeof rawctlr); > + partptr = strstr(rawctlr, "partition("); > + if (partptr != NULL) { > + strlcpy(partptr, "partition(10)", > + sizeof rawctlr - (partptr - rawctlr)); > + } else { > + if ((partptr = strstr(rawctlr, "dksc(")) != NULL) { > + partptr = strstr(partptr, ",0)"); > + if (partptr != NULL && partptr[3] == '\0') > + strlcpy(partptr, ",10)", > + sizeof rawctlr - (partptr - rawctlr)); > + } > + } > + > + sl = NULL; /* no volume header found yet */ > + if (partptr != NULL) { > + if (Bios_Open(rawctlr, 0, &fd) < 0) > + return ENXIO; > + > + /* > + * Read the volume header. > + */ > + offset.hi = offset.lo = 0; > + if (Bios_Seek(fd, &offset, 0) < 0 || > + Bios_Read(fd, buf, DEV_BSIZE, &result) < 0 || > + result != DEV_BSIZE) > + return EIO; > + > + sl = (struct sgilabel *)buf; > + if (sl->magic != SGILABEL_MAGIC) { > +#ifdef DEBUG > + printf("Invalid volume header magic %x\n", sl->magic); > +#endif > + Bios_Close(fd); > + sl = NULL; > + } > + } > + > + if (sl == NULL) { > + if (Bios_Open(ctlr, 0, &fd) < 0) > + return ENXIO; > + } > > sc = alloc(sizeof(struct dio_softc)); > bzero(sc, sizeof(struct dio_softc)); > f->f_devdata = (void *)sc; > + lp = &sc->sc_label; > > sc->sc_fd = fd; > sc->sc_part = partition; > > - lp = &sc->sc_label; > - lp->d_secsize = DEV_BSIZE; > - lp->d_secpercyl = 1; > - lp->d_npartitions = MAXPARTITIONS; > - lp->d_partitions[partition].p_offset = 0; > - lp->d_partitions[0].p_size = 0x7fff0000; > + if (sl != NULL) { > + native_offset = sl->partitions[0].first; > + } else { > + /* > + * We could not read the volume header, or there isn't any. > + * Stick to the device we were given, and assume the > + * OpenBSD disklabel can be found at the beginning. > + */ > + native_offset = 0; > + } > + > + /* > + * Read the native OpenBSD label. > + */ > +#ifdef DEBUG > + printf("OpenBSD label @%lld\n", native_offset + LABELSECTOR); > +#endif > + offset.hi = ((native_offset + LABELSECTOR) * DEV_BSIZE) >> 32; > + offset.lo = (native_offset + LABELSECTOR) * DEV_BSIZE; > + > + if (Bios_Seek(fd, &offset, 0) < 0 || > + Bios_Read(fd, buf, DEV_BSIZE, &result) < 0 || > + result != DEV_BSIZE) > + return EIO; > + > + if (getdisklabel(buf + LABELOFFSET, lp) == NULL) { > +#ifdef DEBUG > + printf("Found native disklabel, " > + "partition %c starts at %lld\n", > + 'a' + partition, > + DL_GETPOFFSET(&lp->d_partitions[partition])); > +#endif > + } else { > + /* > + * Assume the OpenBSD partition spans the whole device. > + */ > +#ifdef DEBUG > + printf("No native disklabel found\n"); > +#endif > + lp->d_secsize = DEV_BSIZE; > + lp->d_secpercyl = 1; > + lp->d_npartitions = MAXPARTITIONS; > + DL_SETPOFFSET(&lp->d_partitions[partition], native_offset); > + DL_SETPSIZE(&lp->d_partitions[partition], -1ULL); > + } > > - return (0); > + return 0; > } > > int > Index: boot/version > =================================================================== > RCS file: /OpenBSD/src/sys/arch/sgi/stand/boot/version,v > retrieving revision 1.8 > diff -u -p -r1.8 version > --- boot/version 13 Sep 2016 18:27:49 -0000 1.8 > +++ boot/version 30 Sep 2016 09:19:15 -0000 > @@ -34,6 +34,10 @@ No version strings up to 2012 > 1.7 > Loadfile support for .SUNW_ctf section > > +1.8 > + Use the OpenBSD disklabel instead of assuming OpenBSD partition `a` > + starts at the beginning of the volume header partition #0. > + > #endif > > -static const char version[] = "1.7"; > +static const char version[] = "1.8"; >