summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorJoel Sing <jsing@cvs.openbsd.org>2010-03-26 16:51:00 +0000
committerJoel Sing <jsing@cvs.openbsd.org>2010-03-26 16:51:00 +0000
commit0eed1f02202c01ba55015b01f6998293613e7d6d (patch)
tree7ab45f683f864896ace7c1a9abbbd66a4f0f1dfc /sys/dev
parent5c0668aeb3664e3654a9fa92c8bd300d21ec81e3 (diff)
Add an ioctl to softraid to allow the boot block and boot loader to be
installed on a softraid volume. This is work in progress but can continue in tree. ok marco@
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/biovar.h14
-rw-r--r--sys/dev/softraid.c157
2 files changed, 169 insertions, 2 deletions
diff --git a/sys/dev/biovar.h b/sys/dev/biovar.h
index 2448903a74d..e5ff86850aa 100644
--- a/sys/dev/biovar.h
+++ b/sys/dev/biovar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: biovar.h,v 1.37 2009/12/31 14:00:45 jsing Exp $ */
+/* $OpenBSD: biovar.h,v 1.38 2010/03/26 16:50:59 jsing Exp $ */
/*
* Copyright (c) 2002 Niklas Hallqvist. All rights reserved.
@@ -184,6 +184,7 @@ struct bioc_createraid {
#define BIOC_SCFORCE 0x01 /* do not assemble, force create */
#define BIOC_SCDEVT 0x02 /* dev_t array or string in dev_list */
#define BIOC_SCNOAUTOASSEMBLE 0x04 /* do not assemble during autoconf */
+#define BIOC_SCBOOTABLE 0x08 /* device is bootable */
u_int32_t bc_opaque_size;
u_int32_t bc_opaque_flags;
#define BIOC_SOINVALID 0x00 /* no opaque pointer */
@@ -212,6 +213,16 @@ struct bioc_discipline {
void *bd_data;
};
+#define BIOCINSTALLBOOT _IOWR('B', 40, struct bioc_installboot)
+struct bioc_installboot {
+ void *bb_cookie;
+ char bb_dev[16];
+ void *bb_bootblk;
+ void *bb_bootldr;
+ u_int32_t bb_bootblk_size;
+ u_int32_t bb_bootldr_size;
+};
+
/* kernel and userspace defines */
#define BIOC_INQ 0x0001
#define BIOC_DISK 0x0002
@@ -222,6 +233,7 @@ struct bioc_discipline {
#define BIOC_CREATERAID 0x0040
#define BIOC_DELETERAID 0x0080
#define BIOC_DISCIPLINE 0x0100
+#define BIOC_INSTALLBOOT 0x0200
/* user space defines */
#define BIOC_DEVLIST 0x10000
diff --git a/sys/dev/softraid.c b/sys/dev/softraid.c
index b83bfc495be..202c1584601 100644
--- a/sys/dev/softraid.c
+++ b/sys/dev/softraid.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: softraid.c,v 1.196 2010/03/26 11:20:34 jsing Exp $ */
+/* $OpenBSD: softraid.c,v 1.197 2010/03/26 16:50:59 jsing Exp $ */
/*
* Copyright (c) 2007, 2008, 2009 Marco Peereboom <marco@peereboom.us>
* Copyright (c) 2008 Chris Kuethe <ckuethe@openbsd.org>
@@ -105,6 +105,8 @@ int sr_ioctl_deleteraid(struct sr_softc *,
struct bioc_deleteraid *);
int sr_ioctl_discipline(struct sr_softc *,
struct bioc_discipline *);
+int sr_ioctl_installboot(struct sr_softc *,
+ struct bioc_installboot *);
void sr_chunks_unwind(struct sr_softc *,
struct sr_chunk_head *);
void sr_discipline_free(struct sr_discipline *);
@@ -2030,6 +2032,10 @@ sr_ioctl(struct device *dev, u_long cmd, caddr_t addr)
rv = sr_ioctl_discipline(sc, (struct bioc_discipline *)addr);
break;
+ case BIOCINSTALLBOOT:
+ rv = sr_ioctl_installboot(sc, (struct bioc_installboot *)addr);
+ break;
+
default:
DNPRINTF(SR_D_IOCTL, "invalid ioctl\n");
rv = ENOTTY;
@@ -3097,6 +3103,155 @@ sr_ioctl_discipline(struct sr_softc *sc, struct bioc_discipline *bd)
return (rv);
}
+int
+sr_ioctl_installboot(struct sr_softc *sc, struct bioc_installboot *bb)
+{
+ void *bootblk = NULL, *bootldr = NULL;
+ struct sr_discipline *sd = NULL;
+ struct sr_chunk *chunk;
+ struct buf b;
+ u_int32_t bbs, bls;
+ int rv = EINVAL;
+ int i;
+
+ DNPRINTF(SR_D_IOCTL, "%s: sr_ioctl_installboot %s\n", DEVNAME(sc),
+ bb->bb_dev);
+
+ for (i = 0; i < SR_MAXSCSIBUS; i++)
+ if (sc->sc_dis[i]) {
+ if (!strncmp(sc->sc_dis[i]->sd_meta->ssd_devname,
+ bb->bb_dev,
+ sizeof(sc->sc_dis[i]->sd_meta->ssd_devname))) {
+ sd = sc->sc_dis[i];
+ break;
+ }
+ }
+
+ if (sd == NULL)
+ goto done;
+
+ if (bb->bb_bootblk_size > SR_BOOT_BLOCKS_SIZE * 512)
+ goto done;
+
+ if (bb->bb_bootldr_size > SR_BOOT_LOADER_SIZE * 512)
+ goto done;
+
+ /* Copy in boot block. */
+ bbs = howmany(bb->bb_bootblk_size, DEV_BSIZE) * DEV_BSIZE;
+ bootblk = malloc(bbs, M_DEVBUF, M_WAITOK | M_ZERO);
+ if (copyin(bb->bb_bootblk, bootblk, bb->bb_bootblk_size) != 0)
+ goto done;
+
+ /* Copy in boot loader. */
+ bls = howmany(bb->bb_bootldr_size, DEV_BSIZE) * DEV_BSIZE;
+ bootldr = malloc(bls, M_DEVBUF, M_WAITOK | M_ZERO);
+ if (copyin(bb->bb_bootldr, bootldr, bb->bb_bootldr_size) != 0)
+ goto done;
+
+ /* Save boot block and boot loader to each chunk. */
+ for (i = 0; i < sd->sd_meta->ssdi.ssd_chunk_no; i++) {
+
+ chunk = sd->sd_vol.sv_chunks[i];
+
+ /* Save boot blocks. */
+ DNPRINTF(SR_D_IOCTL,
+ "sr_ioctl_installboot: saving boot block to %s "
+ "(%u bytes)\n", chunk->src_devname, bbs);
+
+ bzero(&b, sizeof(b));
+ b.b_flags = B_WRITE | B_PHYS;
+ b.b_blkno = SR_BOOT_BLOCKS_OFFSET;
+ b.b_bcount = bbs;
+ b.b_bufsize = bbs;
+ b.b_resid = bbs;
+ b.b_data = bootblk;
+ b.b_error = 0;
+ b.b_proc = curproc;
+ b.b_dev = chunk->src_dev_mm;
+ b.b_vp = NULL;
+ b.b_iodone = NULL;
+ if (bdevvp(chunk->src_dev_mm, &b.b_vp)) {
+ printf("%s: sr_ioctl_installboot: vnode allocation "
+ "failed\n", DEVNAME(sc));
+ goto done;
+ }
+ if ((b.b_flags & B_READ) == 0)
+ b.b_vp->v_numoutput++;
+ LIST_INIT(&b.b_dep);
+ VOP_STRATEGY(&b);
+ biowait(&b);
+ vput(b.b_vp);
+
+ if (b.b_flags & B_ERROR) {
+ printf("%s: 0x%x i/o error on block %llu while "
+ "writing boot block %d\n", DEVNAME(sc),
+ chunk->src_dev_mm, b.b_blkno, b.b_error);
+ goto done;
+ }
+
+ /* Save boot loader.*/
+ DNPRINTF(SR_D_IOCTL,
+ "sr_ioctl_installboot: saving boot loader to %s "
+ "(%u bytes)\n", chunk->src_devname, bls);
+
+ bzero(&b, sizeof(b));
+ b.b_flags = B_WRITE | B_PHYS;
+ b.b_blkno = SR_BOOT_LOADER_OFFSET;
+ b.b_bcount = bls;
+ b.b_bufsize = bls;
+ b.b_resid = bls;
+ b.b_data = bootldr;
+ b.b_error = 0;
+ b.b_proc = curproc;
+ b.b_dev = chunk->src_dev_mm;
+ b.b_vp = NULL;
+ b.b_iodone = NULL;
+ if (bdevvp(chunk->src_dev_mm, &b.b_vp)) {
+ printf("%s: sr_ioctl_installboot: vnode alocation "
+ "failed\n", DEVNAME(sc));
+ goto done;
+ }
+ if ((b.b_flags & B_READ) == 0)
+ b.b_vp->v_numoutput++;
+ LIST_INIT(&b.b_dep);
+ VOP_STRATEGY(&b);
+ biowait(&b);
+ vput(b.b_vp);
+
+ if (b.b_flags & B_ERROR) {
+ printf("%s: 0x%x i/o error on block %llu while "
+ "writing boot blocks %d\n", DEVNAME(sc),
+ chunk->src_dev_mm, b.b_blkno, b.b_error);
+ goto done;
+ }
+
+ }
+
+ /* XXX - Install boot block on disk - MD code. */
+
+ /* Save boot details in metadata. */
+ sd->sd_meta->ssdi.ssd_flags |= BIOC_SCBOOTABLE;
+
+ /* XXX - Store size of boot block/loader in optional metadata. */
+
+ /* Save metadata. */
+ if (sr_meta_save(sd, SR_META_DIRTY)) {
+ printf("%s: could not save metadata to %s\n",
+ DEVNAME(sc), chunk->src_devname);
+ goto done;
+ }
+
+ rv = 0;
+
+done:
+ if (bootblk)
+ free(bootblk, M_DEVBUF);
+ if (bootldr)
+ free(bootldr, M_DEVBUF);
+
+ return (rv);
+}
+
void
sr_chunks_unwind(struct sr_softc *sc, struct sr_chunk_head *cl)
{