diff --git a/lib/geom/nop/geom_nop.c b/lib/geom/nop/geom_nop.c
index ea7afdce0ca0..346a721d3127 100644
--- a/lib/geom/nop/geom_nop.c
+++ b/lib/geom/nop/geom_nop.c
@@ -43,6 +43,7 @@ uint32_t version = G_NOP_VERSION;
struct g_command class_commands[] = {
{ "create", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
{
+ { 'c', "count_until_fail", "-1", G_TYPE_NUMBER },
{ 'd', "delaymsec", "-1", G_TYPE_NUMBER },
{ 'e', "error", "-1", G_TYPE_NUMBER },
{ 'o', "offset", "0", G_TYPE_NUMBER },
@@ -57,12 +58,14 @@ struct g_command class_commands[] = {
{ 'z', "physpath", G_NOP_PHYSPATH_PASSTHROUGH, G_TYPE_STRING },
G_OPT_SENTINEL
},
- "[-v] [-d delaymsec] [-e error] [-o offset] [-p stripesize] "
- "[-P stripeoffset] [-q rdelayprob] [-r rfailprob] [-s size] "
- "[-S secsize] [-w wfailprob] [-x wdelayprob] [-z physpath] dev ..."
+ "[-v] [-c count_until_fail] [-d delaymsec] [-e error] [-o offset] "
+ "[-p stripesize] [-P stripeoffset] [-q rdelayprob] [-r rfailprob] "
+ "[-s size] [-S secsize] [-w wfailprob] [-x wdelayprob] "
+ "[-z physpath] dev ..."
},
{ "configure", G_FLAG_VERBOSE, NULL,
{
+ { 'c', "count_until_fail", "-1", G_TYPE_NUMBER },
{ 'd', "delaymsec", "-1", G_TYPE_NUMBER },
{ 'e', "error", "-1", G_TYPE_NUMBER },
{ 'q', "rdelayprob", "-1", G_TYPE_NUMBER },
@@ -71,8 +74,9 @@ struct g_command class_commands[] = {
{ 'x', "wdelayprob", "-1", G_TYPE_NUMBER },
G_OPT_SENTINEL
},
- "[-v] [-d delaymsec] [-e error] [-q rdelayprob] [-r rfailprob] "
- "[-w wfailprob] [-x wdelayprob] prov ..."
+ "[-v] [-c count_until_fail] [-d delaymsec] [-e error] "
+ "[-q rdelayprob] [-r rfailprob] [-w wfailprob] [-x wdelayprob] "
+ "prov ..."
},
{ "destroy", G_FLAG_VERBOSE, NULL,
{
diff --git a/lib/geom/nop/gnop.8 b/lib/geom/nop/gnop.8
index ef6c44bc5297..12e609728566 100644
--- a/lib/geom/nop/gnop.8
+++ b/lib/geom/nop/gnop.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 31, 2019
+.Dd September 13, 2019
.Dt GNOP 8
.Os
.Sh NAME
@@ -34,6 +34,7 @@
.Nm
.Cm create
.Op Fl v
+.Op Fl c Ar count_until_fail
.Op Fl d Ar delaymsec
.Op Fl e Ar error
.Op Fl o Ar offset
@@ -50,6 +51,7 @@
.Nm
.Cm configure
.Op Fl v
+.Op Fl c Ar count_until_fail
.Op Fl d Ar delaymsec
.Op Fl e Ar error
.Op Fl q Ar rdelayprob
@@ -118,7 +120,10 @@ See
.El
.Pp
Additional options:
-.Bl -tag -width ".Fl r Ar rfailprob"
+.Bl -tag -width "-c count_until_fail"
+.It Fl c Ar count_until_fail
+Specifies the number of I/O requests to allow before setting the read and write
+failure probabilities to 100%.
.It Fl d Ar delaymsec
Specifies the delay of the requests in milliseconds.
Note that requests will be delayed before they are sent to the backing device.
diff --git a/lib/libc/locale/big5.5 b/lib/libc/locale/big5.5
index 13d0c7b64e53..2daf8b1bb414 100644
--- a/lib/libc/locale/big5.5
+++ b/lib/libc/locale/big5.5
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd August 7, 2003
+.Dd September 12, 2019
.Dt BIG5 5
.Os
.Sh NAME
@@ -37,7 +37,7 @@ encoding for Traditional Chinese text
.Qq BIG5
.Sh DESCRIPTION
.Dq Big Five
-is the de facto standard for encoding Traditional Chinese text.
+is a standard for encoding Traditional Chinese text.
Each character is represented by either one or two bytes.
Characters from the
.Tn ASCII
@@ -49,3 +49,10 @@ the first in the range 0xA1 - 0xFE, the second in the range
.Xr euc 5 ,
.Xr gb18030 5 ,
.Xr utf8 5
+.Sh BUGS
+The range of the second byte overlaps some ASCII characters, including
+0x5C (`\\') and 0x7C (`|') which may cause problems in program execution or
+display.
+Big5 is considered a legacy standard and only preserved for backward
+compatibility reason.
+New documents and systems are suggested using UTF-8 directly.
diff --git a/stand/lua/cli.lua b/stand/lua/cli.lua
index adefabbb3386..b2434faa3ce4 100644
--- a/stand/lua/cli.lua
+++ b/stand/lua/cli.lua
@@ -125,6 +125,10 @@ cli['boot-conf'] = function(...)
core.autoboot(argstr)
end
+cli['reload-conf'] = function(...)
+ config.reload()
+end
+
-- Used for splitting cli varargs into cmd_name and the rest of argv
function cli.arguments(...)
local argv = {...}
diff --git a/stand/lua/cli.lua.8 b/stand/lua/cli.lua.8
index f25a27c01b0b..ac9ed3580448 100644
--- a/stand/lua/cli.lua.8
+++ b/stand/lua/cli.lua.8
@@ -26,7 +26,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 31, 2018
+.Dd September 13, 2019
.Dt CLI.LUA 8
.Os
.Sh NAME
@@ -82,14 +82,27 @@ As of present, the
module by default provides commands for
.Ic autoboot ,
.Ic boot ,
+.Ic boot-conf ,
and
-.Ic boot-conf.
-In all three cases, the
+.Ic reload-conf .
+.Pp
+For
+.Ic autoboot ,
+.Ic boot ,
+and
+.Ic boot-conf ,
+the
.Xr core.lua 8
module will load all ELF modules as-needed before executing the equivalent
built-in loader commands.
All non-kernel arguments to these commands are passed in the same order to the
loader command.
+.Pp
+The
+.Ic reload-conf
+command will reload the configuration from disk.
+This is useful if you have manually changed currdev and would like to easily
+reload the configuration from the new device.
.Ss Exported Functions
The following functions are exported from
.Nm :
diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc
index 5383595b1411..b5ceba0bbd4c 100644
--- a/sys/conf/files.powerpc
+++ b/sys/conf/files.powerpc
@@ -192,6 +192,7 @@ powerpc/powernv/opal_flash.c optional powernv opalflash
powerpc/powernv/opal_hmi.c optional powernv
powerpc/powernv/opal_i2c.c optional iicbus fdt powernv
powerpc/powernv/opal_i2cm.c optional iicbus fdt powernv
+powerpc/powernv/opal_nvram.c optional powernv nvram
powerpc/powernv/opal_pci.c optional powernv pci
powerpc/powernv/opal_sensor.c optional powernv
powerpc/powernv/opalcall.S optional powernv
diff --git a/sys/geom/nop/g_nop.c b/sys/geom/nop/g_nop.c
index 6c7706b52cd3..e8152030f518 100644
--- a/sys/geom/nop/g_nop.c
+++ b/sys/geom/nop/g_nop.c
@@ -195,6 +195,10 @@ g_nop_start(struct bio *bp)
G_NOP_LOGREQ(bp, "Request received.");
mtx_lock(&sc->sc_lock);
+ if (sc->sc_count_until_fail != 0 && --sc->sc_count_until_fail == 0) {
+ sc->sc_rfailprob = 100;
+ sc->sc_wfailprob = 100;
+ }
switch (bp->bio_cmd) {
case BIO_READ:
sc->sc_reads++;
@@ -308,9 +312,10 @@ g_nop_access(struct g_provider *pp, int dr, int dw, int de)
static int
g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp,
- int ioerror, u_int rfailprob, u_int wfailprob, u_int delaymsec, u_int rdelayprob,
- u_int wdelayprob, off_t offset, off_t size, u_int secsize, off_t stripesize,
- off_t stripeoffset, const char *physpath)
+ int ioerror, u_int count_until_fail, u_int rfailprob, u_int wfailprob,
+ u_int delaymsec, u_int rdelayprob, u_int wdelayprob, off_t offset,
+ off_t size, u_int secsize, off_t stripesize, off_t stripeoffset,
+ const char *physpath)
{
struct g_nop_softc *sc;
struct g_geom *gp;
@@ -386,6 +391,7 @@ g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp,
} else
sc->sc_physpath = NULL;
sc->sc_error = ioerror;
+ sc->sc_count_until_fail = count_until_fail;
sc->sc_rfailprob = rfailprob;
sc->sc_wfailprob = wfailprob;
sc->sc_delaymsec = delaymsec;
@@ -491,8 +497,9 @@ static void
g_nop_ctl_create(struct gctl_req *req, struct g_class *mp)
{
struct g_provider *pp;
- intmax_t *error, *rfailprob, *wfailprob, *offset, *secsize, *size,
- *stripesize, *stripeoffset, *delaymsec, *rdelayprob, *wdelayprob;
+ intmax_t *error, *rfailprob, *wfailprob, *count_until_fail, *offset,
+ *secsize, *size, *stripesize, *stripeoffset, *delaymsec,
+ *rdelayprob, *wdelayprob;
const char *name, *physpath;
char param[16];
int i, *nargs;
@@ -558,6 +565,16 @@ g_nop_ctl_create(struct gctl_req *req, struct g_class *mp)
gctl_error(req, "Invalid '%s' argument", "wdelayprob");
return;
}
+ count_until_fail = gctl_get_paraml(req, "count_until_fail",
+ sizeof(*count_until_fail));
+ if (count_until_fail == NULL) {
+ gctl_error(req, "No '%s' argument", "count_until_fail");
+ return;
+ }
+ if (*count_until_fail < -1) {
+ gctl_error(req, "Invalid '%s' argument", "count_until_fail");
+ return;
+ }
offset = gctl_get_paraml(req, "offset", sizeof(*offset));
if (offset == NULL) {
gctl_error(req, "No '%s' argument", "offset");
@@ -622,6 +639,7 @@ g_nop_ctl_create(struct gctl_req *req, struct g_class *mp)
}
if (g_nop_create(req, mp, pp,
*error == -1 ? EIO : (int)*error,
+ *count_until_fail == -1 ? 0 : (u_int)*count_until_fail,
*rfailprob == -1 ? 0 : (u_int)*rfailprob,
*wfailprob == -1 ? 0 : (u_int)*wfailprob,
*delaymsec == -1 ? 1 : (u_int)*delaymsec,
@@ -640,7 +658,8 @@ g_nop_ctl_configure(struct gctl_req *req, struct g_class *mp)
{
struct g_nop_softc *sc;
struct g_provider *pp;
- intmax_t *delaymsec, *error, *rdelayprob, *rfailprob, *wdelayprob, *wfailprob;
+ intmax_t *delaymsec, *error, *rdelayprob, *rfailprob, *wdelayprob,
+ *wfailprob, *count_until_fail;
const char *name;
char param[16];
int i, *nargs;
@@ -661,6 +680,12 @@ g_nop_ctl_configure(struct gctl_req *req, struct g_class *mp)
gctl_error(req, "No '%s' argument", "error");
return;
}
+ count_until_fail = gctl_get_paraml(req, "count_until_fail",
+ sizeof(*count_until_fail));
+ if (count_until_fail == NULL) {
+ gctl_error(req, "No '%s' argument", "count_until_fail");
+ return;
+ }
rfailprob = gctl_get_paraml(req, "rfailprob", sizeof(*rfailprob));
if (rfailprob == NULL) {
gctl_error(req, "No '%s' argument", "rfailprob");
@@ -736,6 +761,8 @@ g_nop_ctl_configure(struct gctl_req *req, struct g_class *mp)
sc->sc_wdelayprob = (u_int)*wdelayprob;
if (*delaymsec != -1)
sc->sc_delaymsec = (u_int)*delaymsec;
+ if (*count_until_fail != -1)
+ sc->sc_count_until_fail = (u_int)*count_until_fail;
}
}
@@ -904,6 +931,8 @@ g_nop_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
sbuf_printf(sb, "%s%u\n", indent,
sc->sc_wdelayprob);
sbuf_printf(sb, "%s%d\n", indent, sc->sc_delaymsec);
+ sbuf_printf(sb, "%s%u\n", indent,
+ sc->sc_count_until_fail);
sbuf_printf(sb, "%s%d\n", indent, sc->sc_error);
sbuf_printf(sb, "%s%ju\n", indent, sc->sc_reads);
sbuf_printf(sb, "%s%ju\n", indent, sc->sc_writes);
diff --git a/sys/geom/nop/g_nop.h b/sys/geom/nop/g_nop.h
index d7649ac1c23f..f65a7544c4ca 100644
--- a/sys/geom/nop/g_nop.h
+++ b/sys/geom/nop/g_nop.h
@@ -62,6 +62,7 @@ struct g_nop_softc {
u_int sc_delaymsec;
u_int sc_rdelayprob;
u_int sc_wdelayprob;
+ u_int sc_count_until_fail;
uintmax_t sc_reads;
uintmax_t sc_writes;
uintmax_t sc_deletes;
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 348244a1f87f..6df84aad6c1e 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -762,10 +762,11 @@ _wi= wi
.if ${MACHINE_ARCH} == "powerpc64"
_ipmi= ipmi
+_nvram= opal_nvram
.endif
.if ${MACHINE_ARCH} == "powerpc64" || ${MACHINE_ARCH} == "powerpc"
# Don't build powermac_nvram for powerpcspe, it's never supported.
-_nvram= powermac_nvram
+_nvram+= powermac_nvram
.endif
.if ${MACHINE_CPUARCH} == "sparc64"
diff --git a/sys/modules/opal_nvram/Makefile b/sys/modules/opal_nvram/Makefile
new file mode 100644
index 000000000000..aca711070fc5
--- /dev/null
+++ b/sys/modules/opal_nvram/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.PATH: ${SRCTOP}/sys/powerpc/powernv
+
+KMOD= opal_nvram
+SRCS= opal_nvram.c
+SRCS+= bus_if.h device_if.h
+SRCS+= ofw_bus_if.h
+
+.include
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
index 6dfe58911955..f55329f54ce4 100644
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -1448,7 +1448,10 @@ ipfw_chk(struct ip_fw_args *args)
do { \
int x = (_len) + T + EHLEN; \
if (mem) { \
- MPASS(pktlen >= x); \
+ if (__predict_false(pktlen < x)) { \
+ unlock; \
+ goto pullup_failed; \
+ } \
p = (char *)args->mem + (_len) + EHLEN; \
} else { \
if (__predict_false((m)->m_len < x)) { \
diff --git a/sys/powerpc/powernv/opal.h b/sys/powerpc/powernv/opal.h
index b519316c066b..b1137ca1ce2e 100644
--- a/sys/powerpc/powernv/opal.h
+++ b/sys/powerpc/powernv/opal.h
@@ -45,6 +45,8 @@ int opal_call(uint64_t token, ...);
#define OPAL_RTC_WRITE 4
#define OPAL_CEC_POWER_DOWN 5
#define OPAL_CEC_REBOOT 6
+#define OPAL_READ_NVRAM 7
+#define OPAL_WRITE_NVRAM 8
#define OPAL_HANDLE_INTERRUPT 9
#define OPAL_POLL_EVENTS 10
#define OPAL_PCI_CONFIG_READ_BYTE 13
diff --git a/sys/powerpc/powernv/opal_hmi.c b/sys/powerpc/powernv/opal_hmi.c
index 13b84ed10d23..998d64f99a09 100644
--- a/sys/powerpc/powernv/opal_hmi.c
+++ b/sys/powerpc/powernv/opal_hmi.c
@@ -81,6 +81,26 @@ opal_hmi_event_handler(void *unused, struct opal_msg *msg)
return;
}
+static int
+opal_hmi_handler2(struct trapframe *frame)
+{
+ uint64_t flags;
+ int err;
+
+ flags = 0;
+ err = opal_call(OPAL_HANDLE_HMI2, vtophys(&flags));
+
+ if (flags & OPAL_HMI_FLAGS_TOD_TB_FAIL)
+ panic("TOD/TB recovery failure");
+
+ if (err == OPAL_SUCCESS)
+ return (0);
+
+ printf("HMI handler failed! OPAL error code: %d\n", err);
+
+ return (-1);
+}
+
static int
opal_hmi_handler(struct trapframe *frame)
{
@@ -88,10 +108,8 @@ opal_hmi_handler(struct trapframe *frame)
err = opal_call(OPAL_HANDLE_HMI);
- if (err == OPAL_SUCCESS) {
- mtspr(SPR_HMER, 0);
+ if (err == OPAL_SUCCESS)
return (0);
- }
printf("HMI handler failed! OPAL error code: %d\n", err);
@@ -105,7 +123,9 @@ opal_setup_hmi(void *data)
if (opal_check() != 0)
return;
- if (opal_call(OPAL_CHECK_TOKEN, OPAL_HANDLE_HMI) == OPAL_TOKEN_PRESENT)
+ if (opal_call(OPAL_CHECK_TOKEN, OPAL_HANDLE_HMI2) == OPAL_TOKEN_PRESENT)
+ hmi_handler = opal_hmi_handler2;
+ else if (opal_call(OPAL_CHECK_TOKEN, OPAL_HANDLE_HMI) == OPAL_TOKEN_PRESENT)
hmi_handler = opal_hmi_handler;
else {
printf("Warning: No OPAL HMI handler found.\n");
diff --git a/sys/powerpc/powernv/opal_nvram.c b/sys/powerpc/powernv/opal_nvram.c
new file mode 100644
index 000000000000..acd81e19e57e
--- /dev/null
+++ b/sys/powerpc/powernv/opal_nvram.c
@@ -0,0 +1,276 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 Justin Hibbits
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "opal.h"
+
+#include
+
+#include
+#include
+
+#define NVRAM_BUFSIZE (65536) /* 64k blocks */
+
+struct opal_nvram_softc {
+ device_t sc_dev;
+ uint32_t sc_size;
+ uint8_t *sc_buf;
+ vm_paddr_t sc_buf_phys;
+
+ struct cdev *sc_cdev;
+ int sc_isopen;
+};
+
+/*
+ * Device interface.
+ */
+static int opal_nvram_probe(device_t);
+static int opal_nvram_attach(device_t);
+static int opal_nvram_detach(device_t);
+
+/*
+ * Driver methods.
+ */
+static device_method_t opal_nvram_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, opal_nvram_probe),
+ DEVMETHOD(device_attach, opal_nvram_attach),
+ DEVMETHOD(device_detach, opal_nvram_detach),
+
+ { 0, 0 }
+};
+
+static driver_t opal_nvram_driver = {
+ "opal_nvram",
+ opal_nvram_methods,
+ sizeof(struct opal_nvram_softc)
+};
+
+static devclass_t opal_nvram_devclass;
+
+DRIVER_MODULE(opal_nvram, opal, opal_nvram_driver, opal_nvram_devclass, 0, 0);
+
+/*
+ * Cdev methods.
+ */
+
+static d_open_t opal_nvram_open;
+static d_close_t opal_nvram_close;
+static d_read_t opal_nvram_read;
+static d_write_t opal_nvram_write;
+static d_ioctl_t opal_nvram_ioctl;
+
+static struct cdevsw opal_nvram_cdevsw = {
+ .d_version = D_VERSION,
+ .d_flags = D_NEEDGIANT,
+ .d_open = opal_nvram_open,
+ .d_close = opal_nvram_close,
+ .d_read = opal_nvram_read,
+ .d_write = opal_nvram_write,
+ .d_ioctl = opal_nvram_ioctl,
+ .d_name = "nvram",
+};
+
+static int
+opal_nvram_probe(device_t dev)
+{
+
+ if (!ofw_bus_is_compatible(dev, "ibm,opal-nvram"))
+ return (ENXIO);
+
+ device_set_desc(dev, "OPAL NVRAM");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+opal_nvram_attach(device_t dev)
+{
+ struct opal_nvram_softc *sc;
+ phandle_t node;
+ int err;
+
+ node = ofw_bus_get_node(dev);
+ sc = device_get_softc(dev);
+
+ sc->sc_dev = dev;
+
+ err = OF_getencprop(node, "#bytes", &sc->sc_size,
+ sizeof(sc->sc_size));
+
+ if (err < 0)
+ return (ENXIO);
+
+ sc->sc_buf = contigmalloc(NVRAM_BUFSIZE, M_DEVBUF, M_WAITOK,
+ 0, BUS_SPACE_MAXADDR, PAGE_SIZE, 0);
+ if (sc->sc_buf == NULL) {
+ device_printf(dev, "No memory for buffer.\n");
+ return (ENXIO);
+ }
+ sc->sc_buf_phys = pmap_kextract((vm_offset_t)sc->sc_buf);
+ sc->sc_cdev = make_dev(&opal_nvram_cdevsw, 0, 0, 0, 0600,
+ "nvram");
+ sc->sc_cdev->si_drv1 = sc;
+
+ return (0);
+}
+
+static int
+opal_nvram_detach(device_t dev)
+{
+ struct opal_nvram_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ if (sc->sc_cdev != NULL)
+ destroy_dev(sc->sc_cdev);
+ if (sc->sc_buf != NULL)
+ contigfree(sc->sc_buf, NVRAM_BUFSIZE, M_DEVBUF);
+
+ return (0);
+}
+
+static int
+opal_nvram_open(struct cdev *dev, int flags, int fmt, struct thread *td)
+{
+ struct opal_nvram_softc *sc = dev->si_drv1;
+
+ if (sc->sc_isopen)
+ return EBUSY;
+ sc->sc_isopen = 1;
+ return (0);
+}
+
+static int
+opal_nvram_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
+{
+ struct opal_nvram_softc *sc = dev->si_drv1;
+
+ sc->sc_isopen = 0;
+ return (0);
+}
+
+static int
+opal_nvram_read(struct cdev *dev, struct uio *uio, int ioflag)
+{
+ struct opal_nvram_softc *sc = dev->si_drv1;
+ int rv, amnt;
+
+ rv = 0;
+ while (uio->uio_resid > 0) {
+ amnt = MIN(uio->uio_resid, sc->sc_size - uio->uio_offset);
+ amnt = MIN(amnt, NVRAM_BUFSIZE);
+ if (amnt == 0)
+ break;
+
+ rv = opal_call(OPAL_READ_NVRAM, sc->sc_buf_phys,
+ amnt, uio->uio_offset);
+ if (rv != OPAL_SUCCESS) {
+ switch (rv) {
+ case OPAL_HARDWARE:
+ rv = EIO;
+ break;
+ case OPAL_PARAMETER:
+ rv = EINVAL;
+ break;
+ }
+ break;
+ }
+ rv = uiomove(sc->sc_buf, amnt, uio);
+ if (rv != 0)
+ break;
+ }
+ return (rv);
+}
+
+static int
+opal_nvram_write(struct cdev *dev, struct uio *uio, int ioflag)
+{
+ off_t offset;
+ int rv, amnt;
+ struct opal_nvram_softc *sc = dev->si_drv1;
+
+ rv = 0;
+ while (uio->uio_resid > 0) {
+ amnt = MIN(uio->uio_resid, sc->sc_size - uio->uio_offset);
+ amnt = MIN(amnt, NVRAM_BUFSIZE);
+ if (amnt == 0) {
+ rv = ENOSPC;
+ break;
+ }
+ offset = uio->uio_offset;
+ rv = uiomove(sc->sc_buf, amnt, uio);
+ if (rv != 0)
+ break;
+ rv = opal_call(OPAL_WRITE_NVRAM, sc->sc_buf_phys, amnt,
+ offset);
+ if (rv != OPAL_SUCCESS) {
+ switch (rv) {
+ case OPAL_HARDWARE:
+ rv = EIO;
+ break;
+ case OPAL_PARAMETER:
+ rv = EINVAL;
+ break;
+ }
+ break;
+ }
+ }
+ return (rv);
+}
+
+static int
+opal_nvram_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
+ struct thread *td)
+{
+ struct opal_nvram_softc *sc = dev->si_drv1;
+
+ switch (cmd) {
+ case DIOCGMEDIASIZE:
+ *(off_t *)data = sc->sc_size;
+ return (0);
+ }
+ return (EINVAL);
+}