aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-02-07 12:57:40 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-02-07 12:57:40 +0000
commitb40d827331b9fd3a97bbd33389c2626ba55fee19 (patch)
tree764eb223d5a0160231bcdfca093f10b2db0d8c42
parent7aa51b7949660007cdf82cd56e16df87703f9319 (diff)
parent6a0d02c731cd40fc4a716eb472e7297618fc77eb (diff)
downloadsrc-b40d827331b9fd3a97bbd33389c2626ba55fee19.tar.gz
src-b40d827331b9fd3a97bbd33389c2626ba55fee19.zip
Merging ^/head r278298 through r278350.
Notes
Notes: svn path=/projects/clang360-import/; revision=278351
-rw-r--r--contrib/mdocml/lib.in1
-rwxr-xr-xetc/rc.d/jail2
-rwxr-xr-xetc/rc.d/routing5
-rw-r--r--lib/Makefile1
-rw-r--r--lib/csu/powerpc64/Makefile4
-rw-r--r--lib/libc/gen/disklabel.c23
-rw-r--r--lib/libc/stdlib/tdelete.c9
-rw-r--r--lib/libdevctl/Makefile8
-rw-r--r--lib/libdevctl/devctl.3295
-rw-r--r--lib/libdevctl/devctl.c124
-rw-r--r--lib/libdevctl/devctl.h42
-rw-r--r--lib/libdevinfo/devinfo.h2
-rw-r--r--lib/libnetgraph/debug.c29
-rw-r--r--lib/libthr/thread/thr_barrier.c5
-rw-r--r--lib/msun/src/s_scalbln.c28
-rw-r--r--share/man/man4/witness.426
-rw-r--r--share/mk/bsd.libnames.mk1
-rw-r--r--share/mk/src.libnames.mk1
-rw-r--r--sys/amd64/amd64/mp_machdep.c30
-rw-r--r--sys/arm/broadcom/bcm2835/files.bcm283518
-rw-r--r--sys/arm/conf/RPI-B5
-rw-r--r--sys/boot/amd64/boot1.efi/fat.tmpl.bz2.uu29
-rwxr-xr-xsys/boot/amd64/boot1.efi/generate-fat.sh2
-rw-r--r--sys/boot/forth/beastie.4th11
-rw-r--r--sys/boot/forth/brand.4th3
-rw-r--r--sys/cam/ctl/ctl_frontend_iscsi.c39
-rw-r--r--sys/cam/ctl/ctl_ioctl.h16
-rw-r--r--sys/conf/files2
-rw-r--r--sys/conf/kern.pre.mk2
-rw-r--r--sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h4
-rw-r--r--sys/dev/acpica/acpi.c30
-rw-r--r--sys/dev/cxgbe/if_cxl.c44
-rw-r--r--sys/dev/cxgbe/t4_main.c7
-rw-r--r--sys/dev/ipmi/ipmi.c104
-rw-r--r--sys/dev/ipmi/ipmi_kcs.c20
-rw-r--r--sys/dev/ipmi/ipmi_smic.c24
-rw-r--r--sys/dev/ipmi/ipmi_ssif.c17
-rw-r--r--sys/dev/ipmi/ipmivars.h15
-rw-r--r--sys/dev/pci/pci.c59
-rw-r--r--sys/i386/i386/mp_machdep.c30
-rw-r--r--sys/kern/subr_bus.c272
-rw-r--r--sys/kern/subr_hints.c28
-rw-r--r--sys/modules/Makefile2
-rw-r--r--sys/modules/cxgbe/Makefile1
-rw-r--r--sys/modules/cxgbe/if_cxl/Makefile11
-rw-r--r--sys/modules/dtb/rpi/Makefile5
-rw-r--r--sys/sys/bus.h63
-rw-r--r--sys/x86/x86/local_apic.c28
-rw-r--r--tools/tools/makeroot/makeroot.83
-rwxr-xr-xtools/tools/makeroot/makeroot.sh12
-rw-r--r--usr.bin/ktrdump/ktrdump.812
-rw-r--r--usr.bin/ktrdump/ktrdump.c18
-rw-r--r--usr.sbin/Makefile1
-rw-r--r--usr.sbin/ctladm/ctladm.c13
-rw-r--r--usr.sbin/ctld/ctl.conf.511
-rw-r--r--usr.sbin/ctld/ctld.c172
-rw-r--r--usr.sbin/ctld/ctld.h41
-rw-r--r--usr.sbin/ctld/discovery.c41
-rw-r--r--usr.sbin/ctld/kernel.c122
-rw-r--r--usr.sbin/ctld/login.c42
-rw-r--r--usr.sbin/ctld/parse.y64
-rw-r--r--usr.sbin/ctld/token.l1
-rw-r--r--usr.sbin/devctl/Makefile9
-rw-r--r--usr.sbin/devctl/devctl.8137
-rw-r--r--usr.sbin/devctl/devctl.c282
-rw-r--r--usr.sbin/devinfo/devinfo.c4
-rw-r--r--usr.sbin/freebsd-update/freebsd-update.sh9
-rw-r--r--usr.sbin/jail/command.c32
-rw-r--r--usr.sbin/jail/config.c1
-rw-r--r--usr.sbin/jail/jail.89
-rw-r--r--usr.sbin/jail/jail.c2
-rw-r--r--usr.sbin/jail/jailp.h1
72 files changed, 2239 insertions, 327 deletions
diff --git a/contrib/mdocml/lib.in b/contrib/mdocml/lib.in
index a5522ef7034f..a1ce062f75fc 100644
--- a/contrib/mdocml/lib.in
+++ b/contrib/mdocml/lib.in
@@ -41,6 +41,7 @@ LINE("libcrypt", "Crypt Library (libcrypt, \\-lcrypt)")
LINE("libcurses", "Curses Library (libcurses, \\-lcurses)")
LINE("libcuse", "Userland Character Device Library (libcuse, \\-lcuse)")
LINE("libdevattr", "Device attribute and event library (libdevattr, \\-ldevattr)")
+LINE("libdevctl", "Device Control Library (libdevctl, \\-ldevctl)")
LINE("libdevinfo", "Device and Resource Information Utility Library (libdevinfo, \\-ldevinfo)")
LINE("libdevstat", "Device Statistics Library (libdevstat, \\-ldevstat)")
LINE("libdisk", "Interface to Slice and Partition Labels Library (libdisk, \\-ldisk)")
diff --git a/etc/rc.d/jail b/etc/rc.d/jail
index 0b886fd56b59..393e35526574 100755
--- a/etc/rc.d/jail
+++ b/etc/rc.d/jail
@@ -28,7 +28,7 @@ extra_commands="config console status"
need_dad_wait=
-# extact_var jail name param num defval
+# extract_var jail name param num defval
# Extract value from ${jail_$jail_$name} or ${jail_$name} and
# set it to $param. If not defined, $defval is used.
# When $num is [0-9]*, ${jail_$jail_$name$num} are looked up and
diff --git a/etc/rc.d/routing b/etc/rc.d/routing
index b38147153b0a..7a3c1ab4c2e7 100755
--- a/etc/rc.d/routing
+++ b/etc/rc.d/routing
@@ -165,13 +165,14 @@ static_inet()
static_inet6()
{
- local _action _if _skip fibmod fibs
+ local _action _if _skip fibmod fibs allfibs
_action=$1
_if=$2
# get the number of FIBs supported.
fibs=$((`${SYSCTL_N} net.fibs` - 1))
- if [ "$fibs" -gt 0 ]; then
+ allfibs=`${SYSCTL_N} net.add_addr_allfibs`
+ if [ "$fibs" -gt 0 ] && [ "$allfibs" -ne 0 ]; then
fibmod="-fib 0-$fibs"
else
fibmod=
diff --git a/lib/Makefile b/lib/Makefile
index c00af75f70b4..fdab45351e55 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -41,6 +41,7 @@ SUBDIR= ${SUBDIR_ORDERED} \
${_libcom_err} \
libcompat \
libcrypt \
+ libdevctl \
libdevinfo \
libdevstat \
libdpv \
diff --git a/lib/csu/powerpc64/Makefile b/lib/csu/powerpc64/Makefile
index dd6e9fb2b501..1c93355b7c48 100644
--- a/lib/csu/powerpc64/Makefile
+++ b/lib/csu/powerpc64/Makefile
@@ -9,6 +9,10 @@ CFLAGS+= -I${.CURDIR}/../common \
-I${.CURDIR}/../../libc/include \
-mlongcall
+# XXX: See the log for r232932 as to why the above -mlongcall is needed. Since
+# clang doesn't support -mlongcall, and testing shows a clang linked with a
+# clang-built csu segfaults, this must currently be compiled with gcc. Once
+# clang supports -mlongcall, or we get a fixed ld, this can be revisited.
CC:= gcc
COMPILER_TYPE:= gcc
diff --git a/lib/libc/gen/disklabel.c b/lib/libc/gen/disklabel.c
index bd15a47318e0..8780573d1c5d 100644
--- a/lib/libc/gen/disklabel.c
+++ b/lib/libc/gen/disklabel.c
@@ -85,10 +85,13 @@ getdiskbyname(const char *name)
cq++, cp++;
*cq = '\0';
- if (cgetstr(buf, "ty", &cq) > 0 && strcmp(cq, "removable") == 0)
- dp->d_flags |= D_REMOVABLE;
- else if (cq && strcmp(cq, "simulated") == 0)
- dp->d_flags |= D_RAMDISK;
+ if (cgetstr(buf, "ty", &cq) > 0) {
+ if (strcmp(cq, "removable") == 0)
+ dp->d_flags |= D_REMOVABLE;
+ else if (cq && strcmp(cq, "simulated") == 0)
+ dp->d_flags |= D_RAMDISK;
+ free(cq);
+ }
if (cgetcap(buf, "sf", ':') != NULL)
dp->d_flags |= D_BADSECT;
@@ -100,9 +103,10 @@ getdiskbyname(const char *name)
getnumdflt(dp->d_nsectors, "ns", 0);
getnumdflt(dp->d_ncylinders, "nc", 0);
- if (cgetstr(buf, "dt", &cq) > 0)
+ if (cgetstr(buf, "dt", &cq) > 0) {
dp->d_type = gettype(cq, dktypenames);
- else
+ free(cq);
+ } else
getnumdflt(dp->d_type, "dt", 0);
getnumdflt(dp->d_secpercyl, "sc", dp->d_nsectors * dp->d_ntracks);
getnumdflt(dp->d_secperunit, "su", dp->d_secpercyl * dp->d_ncylinders);
@@ -140,8 +144,11 @@ getdiskbyname(const char *name)
pp->p_frag = 8;
}
getnumdflt(pp->p_fstype, ptype, 0);
- if (pp->p_fstype == 0 && cgetstr(buf, ptype, &cq) > 0)
- pp->p_fstype = gettype(cq, fstypenames);
+ if (pp->p_fstype == 0)
+ if (cgetstr(buf, ptype, &cq) >= 0) {
+ pp->p_fstype = gettype(cq, fstypenames);
+ free(cq);
+ }
max = p;
}
}
diff --git a/lib/libc/stdlib/tdelete.c b/lib/libc/stdlib/tdelete.c
index c83afb8cf3f1..bef187e81a2d 100644
--- a/lib/libc/stdlib/tdelete.c
+++ b/lib/libc/stdlib/tdelete.c
@@ -14,7 +14,7 @@
#include <sys/cdefs.h>
#if 0
#if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: tdelete.c,v 1.2 1999/09/16 11:45:37 lukem Exp $");
+__RCSID("$NetBSD: tdelete.c,v 1.6 2012/06/25 22:32:45 abs Exp $");
#endif /* LIBC_SCCS and not lint */
#endif
__FBSDID("$FreeBSD$");
@@ -25,9 +25,9 @@ __FBSDID("$FreeBSD$");
/*
- * delete node with given key
+ * find a node with given key
*
- * vkey: key to be deleted
+ * vkey: key to be found
* vrootp: address of the root of the tree
* compar: function to carry out node comparisons
*/
@@ -65,7 +65,8 @@ tdelete(const void * __restrict vkey, void ** __restrict vrootp,
q->rlink = (*rootp)->rlink;
}
}
- free(*rootp); /* D4: Free node */
+ if (p != *rootp)
+ free(*rootp); /* D4: Free node */
*rootp = q; /* link parent to new node */
return p;
}
diff --git a/lib/libdevctl/Makefile b/lib/libdevctl/Makefile
new file mode 100644
index 000000000000..74687ecc2bd2
--- /dev/null
+++ b/lib/libdevctl/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+LIB= devctl
+SRCS= devctl.c
+INCS= devctl.h
+MAN= devctl.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libdevctl/devctl.3 b/lib/libdevctl/devctl.3
new file mode 100644
index 000000000000..be869f9d9868
--- /dev/null
+++ b/lib/libdevctl/devctl.3
@@ -0,0 +1,295 @@
+.\"
+.\" Copyright (c) 2014 John Baldwin <jhb@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
+.\"
+.Dd December 26, 2014
+.Dt DEVCTL 3
+.Os
+.Sh NAME
+.Nm devctl ,
+.Nm devctl_attach ,
+.Nm devctl_detach ,
+.Nm devctl_disable ,
+.Nm devctl_enable ,
+.Nm devctl_resume ,
+.Nm devctl_suspend
+.Nd device control library
+.Sh LIBRARY
+.Lb libdevctl
+.Sh SYNOPSIS
+.In devctl.h
+.Ft int
+.Fn devctl_attach "const char *device"
+.Ft int
+.Fn devctl_detach "const char *device" "bool force"
+.Ft int
+.Fn devctl_disable "const char *device" "bool force_detach"
+.Ft int
+.Fn devctl_enable "const char *device"
+.Ft int
+.Fn devctl_resume "const char *device"
+.Ft int
+.Fn devctl_suspend "const char *device"
+.Ft int
+.Fn devctl_set_driver "const char *device" "const char *driver" "bool force"
+.Sh DESCRIPTION
+The
+.Nm
+library adjusts the state of devices in the kernel's internal device
+hierarchy.
+Each control operation accepts a
+.Fa device
+argument that identifies the device to adjust.
+The
+.Fa device
+may be specified as either the name of an existing device or as a
+bus-specific address.
+The following bus-specific address formats are currently supported:
+.Bl -tag -offset indent
+.It Sy pci Ns Fa domain Ns : Ns Fa bus Ns : Ns Fa slot Ns : Ns Fa function
+A PCI device with the specified
+.Fa domain ,
+.Fa bus ,
+.Fa slot ,
+and
+.Fa function .
+.It Sy pci Ns Fa bus Ns : Ns Fa slot Ns : Ns Fa function
+A PCI device in domain zero with the specified
+.Fa bus ,
+.Fa slot ,
+and
+.Fa function .
+.It Fa handle
+A device with an ACPI handle of
+.Fa handle .
+The handle must be specified as an absolute path and must begin with a
+.Dq \e .
+.El
+.Pp
+The
+.Fn devctl_attach
+function probes a device and attaches a suitable device driver if one is
+found.
+.Pp
+The
+.Fn devctl_detach
+function detaches a device from its current device driver.
+The device is left detached until either a new driver for its parent
+bus is loaded or the device is explicitly probed via
+.Fn devctl_attach .
+If
+.Fa force
+is true,
+the current device driver will be detached even if the device is busy.
+.Pp
+The
+.Fn devctl_disable
+function disables a device.
+If the device is currently attached to a device driver,
+the device driver will be detached from the device,
+but the device will retain its current name.
+If
+.Fa force_detach
+is true,
+the current device driver will be detached even if the device is busy.
+The device will remain disabled and detached until it is explicitly enabled
+via
+.Fn devctl_enable .
+.Pp
+The
+.Fn devctl_enable
+function re-enables a disabled device.
+The device will probe and attach if a suitable device driver is found.
+.Pp
+The
+.Fn devctl_suspend
+function suspends a device.
+This may include placing the device in a reduced power state,
+but any device driver currently attached to the device will remain attached.
+.Pp
+The
+.Fn devctl_resume
+function resumes a suspended device to a fully working state.
+.Pp
+The
+.Fn devctl_set_driver
+function attaches a device driver named
+.Fa driver
+to a device.
+If the device is already attached and
+.Fa force
+is false,
+the request will fail.
+If the device is already attached and
+.Fa force
+is true,
+the device will be detached from its current device driver before it is
+attached to the new device driver.
+.Sh RETURN VALUES
+.Rv -std devctl_attach devctl_detach devctl_disable devctl_enable \
+devctl_suspend devctl_resume devctl_set_driver
+.Sh ERRORS
+In addition to specific errors noted below,
+all of the
+.Nm
+functions may fail for any of the errors described in
+.Xr open 2
+as well as:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The device name is too long.
+.It Bq Er ENOENT
+No existing device matches the specified name or location.
+.It Bq Er EPERM
+The current process is not permitted to adjust the state of
+.Fa device .
+.El
+.Pp
+The
+.Fn devctl_attach
+function may fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The device is already attached.
+.It Bq Er ENOMEM
+An internal memory allocation request failed.
+.It Bq Er ENXIO
+The device is disabled.
+.It Bq Er ENXIO
+No suitable driver for the device could be found,
+or the driver failed to attach.
+.El
+.Pp
+The
+.Fn devctl_detach
+function may fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The current device driver for
+.Fa device
+is busy and cannot detach at this time.
+Note that some drivers may return this even if
+.Fa force
+is true.
+.It Bq Er ENXIO
+The device is not attached to a driver.
+.It Bq Er ENXIO
+The current device driver for
+.Fa device
+does not support detaching.
+.El
+.Pp
+The
+.Fn devctl_enable
+function may fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The device is already enabled.
+.It Bq Er ENOMEM
+An internal memory allocation request failed.
+.It Bq Er ENXIO
+No suitable driver for the device could be found,
+or the driver failed to attach.
+.El
+.Pp
+The
+.Fn devctl_disable
+function may fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The current device driver for
+.Fa device
+is busy and cannot detach at this time.
+Note that some drivers may return this even if
+.Fa force_detach
+is true.
+.It Bq Er ENXIO
+The device is already disabled.
+.It Bq Er ENXIO
+The current device driver for
+.Fa device
+does not support detaching.
+.El
+.Pp
+The
+.Fn devctl_suspend
+function may fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The device is already suspended.
+.It Bq Er EINVAL
+The device to be suspended is the root bus device.
+.El
+.Pp
+The
+.Fn devctl_resume
+function may fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The device is not suspended.
+.It Bq Er EINVAL
+The device to be resumed is the root bus device.
+.El
+.Pp
+The
+.Fn devctl_set_driver
+function may fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The device is currently attached to a device driver and
+.Fa force
+is false.
+.It Bq Er EBUSY
+The current device driver for
+.Fa device
+is busy and cannot detach at this time.
+.It Bq Er EFAULT
+The
+.Fa driver
+argument points outside the process' allocated address space.
+.It Bq Er ENOENT
+No device driver with the requested name exists.
+.It Bq Er ENOMEM
+An internal memory allocation request failed.
+.It Bq Er ENXIO
+The device is disabled.
+.It Bq Er ENXIO
+The new device driver failed to attach.
+.El
+.Sh SEE ALSO
+.Xr devinfo 3 ,
+.Xr devstat 3 ,
+.Xr devctl 8
+.Sh HISTORY
+The
+.Nm
+library first appeared in
+.Fx 11.0 .
+.Sh BUGS
+If a device is suspended individually via
+.Fn devctl_suspend
+and the entire machine is subsequently suspended,
+the device will be resumed when the machine resumes.
diff --git a/lib/libdevctl/devctl.c b/lib/libdevctl/devctl.c
new file mode 100644
index 000000000000..7be431e9bf53
--- /dev/null
+++ b/lib/libdevctl/devctl.c
@@ -0,0 +1,124 @@
+/*-
+ * Copyright (c) 2014 John Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/bus.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include "devctl.h"
+
+static int
+devctl_request(u_long cmd, struct devreq *req)
+{
+ static int devctl2_fd = -1;
+
+ if (devctl2_fd == -1) {
+ devctl2_fd = open("/dev/devctl2", O_RDONLY);
+ if (devctl2_fd == -1)
+ return (-1);
+ }
+ return (ioctl(devctl2_fd, cmd, req));
+}
+
+static int
+devctl_simple_request(u_long cmd, const char *name, int flags)
+{
+ struct devreq req;
+
+ memset(&req, 0, sizeof(req));
+ if (strlcpy(req.dr_name, name, sizeof(req.dr_name)) >=
+ sizeof(req.dr_name)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ req.dr_flags = flags;
+ return (devctl_request(cmd, &req));
+}
+
+int
+devctl_attach(const char *device)
+{
+
+ return (devctl_simple_request(DEV_ATTACH, device, 0));
+}
+
+int
+devctl_detach(const char *device, bool force)
+{
+
+ return (devctl_simple_request(DEV_DETACH, device, force ?
+ DEVF_FORCE_DETACH : 0));
+}
+
+int
+devctl_enable(const char *device)
+{
+
+ return (devctl_simple_request(DEV_ENABLE, device, 0));
+}
+
+int
+devctl_disable(const char *device, bool force_detach)
+{
+
+ return (devctl_simple_request(DEV_DISABLE, device, force_detach ?
+ DEVF_FORCE_DETACH : 0));
+}
+
+int
+devctl_suspend(const char *device)
+{
+
+ return (devctl_simple_request(DEV_SUSPEND, device, 0));
+}
+
+int
+devctl_resume(const char *device)
+{
+
+ return (devctl_simple_request(DEV_RESUME, device, 0));
+}
+
+int
+devctl_set_driver(const char *device, const char *driver, bool force)
+{
+ struct devreq req;
+
+ memset(&req, 0, sizeof(req));
+ if (strlcpy(req.dr_name, device, sizeof(req.dr_name)) >=
+ sizeof(req.dr_name)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ req.dr_data = __DECONST(char *, driver);
+ if (force)
+ req.dr_flags |= DEVF_SET_DRIVER_DETACH;
+ return (devctl_request(DEV_SET_DRIVER, &req));
+}
diff --git a/lib/libdevctl/devctl.h b/lib/libdevctl/devctl.h
new file mode 100644
index 000000000000..f773b11dd43a
--- /dev/null
+++ b/lib/libdevctl/devctl.h
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2014 John Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
+ */
+
+#ifndef __DEVCTL_H__
+#define __DEVCTL_H__
+
+#include <stdbool.h>
+
+int devctl_attach(const char *device);
+int devctl_detach(const char *device, bool force);
+int devctl_enable(const char *device);
+int devctl_disable(const char *device, bool force_detach);
+int devctl_suspend(const char *device);
+int devctl_resume(const char *device);
+int devctl_set_driver(const char *device, const char *driver, bool force);
+
+#endif /* !__DEVCTL_H__ */
diff --git a/lib/libdevinfo/devinfo.h b/lib/libdevinfo/devinfo.h
index c8990a6f0d13..b0b8cec49f36 100644
--- a/lib/libdevinfo/devinfo.h
+++ b/lib/libdevinfo/devinfo.h
@@ -50,7 +50,7 @@ struct devinfo_dev {
char *dd_location; /* Where bus thinks dev at */
uint32_t dd_devflags; /* API flags */
uint16_t dd_flags; /* internal dev flags */
- devinfo_state_t dd_state; /* attacement state of dev */
+ devinfo_state_t dd_state; /* attachment state of dev */
};
struct devinfo_rman {
diff --git a/lib/libnetgraph/debug.c b/lib/libnetgraph/debug.c
index 6d0579faef6e..f44504140b8b 100644
--- a/lib/libnetgraph/debug.c
+++ b/lib/libnetgraph/debug.c
@@ -62,12 +62,15 @@ __FBSDID("$FreeBSD$");
#include <netgraph/ng_atmllc.h>
#include <netgraph/ng_bpf.h>
#include <netgraph/ng_bridge.h>
+#include <netgraph/ng_car.h>
#include <netgraph/ng_cisco.h>
+#include <netgraph/ng_deflate.h>
#include <netgraph/ng_device.h>
#include <netgraph/ng_echo.h>
#include <netgraph/ng_eiface.h>
#include <netgraph/ng_etf.h>
#include <netgraph/ng_ether.h>
+#include <netgraph/ng_ether_echo.h>
#include <netgraph/ng_frame_relay.h>
#include <netgraph/ng_gif.h>
#include <netgraph/ng_gif_demux.h>
@@ -81,15 +84,20 @@ __FBSDID("$FreeBSD$");
#include <netgraph/ng_lmi.h>
#include <netgraph/ng_mppc.h>
#include <netgraph/ng_nat.h>
+#include <netgraph/netflow/ng_netflow.h>
#include <netgraph/ng_one2many.h>
+#include <netgraph/ng_patch.h>
+#include <netgraph/ng_pipe.h>
#include <netgraph/ng_ppp.h>
#include <netgraph/ng_pppoe.h>
#include <netgraph/ng_pptpgre.h>
+#include <netgraph/ng_pred1.h>
#include <netgraph/ng_rfc1490.h>
#include <netgraph/ng_socket.h>
#include <netgraph/ng_source.h>
#include <netgraph/ng_split.h>
#include <netgraph/ng_sppp.h>
+#include <netgraph/ng_tag.h>
#include <netgraph/ng_tcpmss.h>
#include <netgraph/ng_tee.h>
#include <netgraph/ng_tty.h>
@@ -129,12 +137,15 @@ static const struct ng_cookie cookies[] = {
COOKIE(ATMLLC),
COOKIE(BPF),
COOKIE(BRIDGE),
+ COOKIE(CAR),
COOKIE(CISCO),
+ COOKIE(DEFLATE),
COOKIE(DEVICE),
COOKIE(ECHO),
COOKIE(EIFACE),
COOKIE(ETF),
COOKIE(ETHER),
+ COOKIE(ETHER_ECHO),
COOKIE(FRAMERELAY),
COOKIE(GIF),
COOKIE(GIF_DEMUX),
@@ -149,15 +160,20 @@ static const struct ng_cookie cookies[] = {
COOKIE(LMI),
COOKIE(MPPC),
COOKIE(NAT),
+ COOKIE(NETFLOW),
COOKIE(ONE2MANY),
+ COOKIE(PATCH),
+ COOKIE(PIPE),
COOKIE(PPP),
COOKIE(PPPOE),
COOKIE(PPTPGRE),
+ COOKIE(PRED1),
COOKIE(RFC1490),
COOKIE(SOCKET),
COOKIE(SOURCE),
COOKIE(SPLIT),
COOKIE(SPPP),
+ COOKIE(TAG),
COOKIE(TCPMSS),
COOKIE(TEE),
COOKIE(TTY),
@@ -181,9 +197,8 @@ NgSetDebug(int level)
{
int old = _gNgDebugLevel;
- if (level < 0)
- level = old;
- _gNgDebugLevel = level;
+ if (level >= 0)
+ _gNgDebugLevel = level;
return (old);
}
@@ -225,10 +240,10 @@ _NgDebugMsg(const struct ng_mesg *msg, const char *path)
/* Display header stuff */
NGLOGX("NG_MESG :");
NGLOGX(" vers %d", msg->header.version);
- NGLOGX(" arglen %d", msg->header.arglen);
- NGLOGX(" flags %ld", msg->header.flags);
- NGLOGX(" token %lu", (u_long)msg->header.token);
- NGLOGX(" cookie %s (%d)",
+ NGLOGX(" arglen %u", msg->header.arglen);
+ NGLOGX(" flags %x", msg->header.flags);
+ NGLOGX(" token %u", msg->header.token);
+ NGLOGX(" cookie %s (%u)",
NgCookie(msg->header.typecookie), msg->header.typecookie);
/* At lower debugging levels, skip ASCII translation */
diff --git a/lib/libthr/thread/thr_barrier.c b/lib/libthr/thread/thr_barrier.c
index 86f880efac1d..10b634608241 100644
--- a/lib/libthr/thread/thr_barrier.c
+++ b/lib/libthr/thread/thr_barrier.c
@@ -86,16 +86,13 @@ _pthread_barrier_init(pthread_barrier_t *barrier,
if (barrier == NULL || count <= 0)
return (EINVAL);
- bar = malloc(sizeof(struct pthread_barrier));
+ bar = calloc(1, sizeof(struct pthread_barrier));
if (bar == NULL)
return (ENOMEM);
_thr_umutex_init(&bar->b_lock);
_thr_ucond_init(&bar->b_cv);
- bar->b_cycle = 0;
- bar->b_waiters = 0;
bar->b_count = count;
- bar->b_refcount = 0;
*barrier = bar;
return (0);
diff --git a/lib/msun/src/s_scalbln.c b/lib/msun/src/s_scalbln.c
index dcf2c789ec32..5e4e42e9dcf0 100644
--- a/lib/msun/src/s_scalbln.c
+++ b/lib/msun/src/s_scalbln.c
@@ -27,38 +27,28 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <limits.h>
#include <math.h>
+#define NMAX 65536
+#define NMIN -65536
+
double
-scalbln (double x, long n)
+scalbln(double x, long n)
{
- int in;
- in = (int)n;
- if (in != n)
- in = (n > 0) ? INT_MAX: INT_MIN;
- return (scalbn(x, in));
+ return (scalbn(x, (n > NMAX) ? NMAX : (n < NMIN) ? NMIN : (int)n));
}
float
-scalblnf (float x, long n)
+scalblnf(float x, long n)
{
- int in;
- in = (int)n;
- if (in != n)
- in = (n > 0) ? INT_MAX: INT_MIN;
- return (scalbnf(x, in));
+ return (scalbnf(x, (n > NMAX) ? NMAX : (n < NMIN) ? NMIN : (int)n));
}
long double
-scalblnl (long double x, long n)
+scalblnl(long double x, long n)
{
- int in;
- in = (int)n;
- if (in != n)
- in = (n > 0) ? INT_MAX: INT_MIN;
- return (scalbnl(x, in));
+ return (scalbnl(x, (n > NMAX) ? NMAX : (n < NMIN) ? NMIN : (int)n));
}
diff --git a/share/man/man4/witness.4 b/share/man/man4/witness.4
index ffd9f8fe0c14..14f2646350a7 100644
--- a/share/man/man4/witness.4
+++ b/share/man/man4/witness.4
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 30, 2012
+.Dd February 6, 2015
.Dt WITNESS 4
.Os
.Sh NAME
@@ -32,7 +32,9 @@
.Nd lock validation facility
.Sh SYNOPSIS
.Cd options WITNESS
+.Cd options WITNESS_COUNT
.Cd options WITNESS_KDB
+.Cd options WITNESS_NO_VNODE
.Cd options WITNESS_SKIPSPIN
.Sh DESCRIPTION
The
@@ -56,6 +58,28 @@ does not recurse on a non-recursive lock,
or attempt an upgrade on a shared lock held by another thread.
If any of these checks fail, then the kernel will panic.
.Pp
+The
+.Dv WITNESS_COUNT
+kernel option controls the maximum number of
+.Xr witness 4
+entries that are tracked in the kernel.
+The maximum number of entries can be queried via the
+.Va debug.witness.count
+sysctl.
+It can also be set from the
+.Xr loader 8
+via the
+.Va debug.witness.count
+environment variable.
+.Pp
+The
+.Dv WITNESS_NO_VNODE
+kernel option tells
+.Xr witness 4
+to ignore locking issues between
+.Xr vnode 9
+objects.
+.Pp
The flag that controls whether or not the kernel debugger is entered when a
lock order violation is detected can be set in a variety of ways.
By default, the flag is off, but if the
diff --git a/share/mk/bsd.libnames.mk b/share/mk/bsd.libnames.mk
index 00f0a0adf0cf..d84747e45767 100644
--- a/share/mk/bsd.libnames.mk
+++ b/share/mk/bsd.libnames.mk
@@ -39,6 +39,7 @@ LIBCRYPT?= ${DESTDIR}${LIBDIR}/libcrypt.a
LIBCRYPTO?= ${DESTDIR}${LIBDIR}/libcrypto.a
LIBCTF?= ${DESTDIR}${LIBDIR}/libctf.a
LIBCURSES?= ${DESTDIR}${LIBDIR}/libcurses.a
+LIBDEVCTL?= ${DESTDIR}${LIBDIR}/libdevctl.a
LIBDEVINFO?= ${DESTDIR}${LIBDIR}/libdevinfo.a
LIBDEVSTAT?= ${DESTDIR}${LIBDIR}/libdevstat.a
LIBDIALOG?= ${DESTDIR}${LIBDIR}/libdialog.a
diff --git a/share/mk/src.libnames.mk b/share/mk/src.libnames.mk
index b8570ed6b5bc..a6880892caac 100644
--- a/share/mk/src.libnames.mk
+++ b/share/mk/src.libnames.mk
@@ -72,6 +72,7 @@ _LIBRARIES= \
ctf \
cuse \
cxxrt \
+ devctl \
devinfo \
devstat \
dialog \
diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c
index 3184f1325374..91b5c9f002e3 100644
--- a/sys/amd64/amd64/mp_machdep.c
+++ b/sys/amd64/amd64/mp_machdep.c
@@ -1065,14 +1065,27 @@ ipi_startup(int apic_id, int vector)
{
/*
+ * This attempts to follow the algorithm described in the
+ * Intel Multiprocessor Specification v1.4 in section B.4.
+ * For each IPI, we allow the local APIC ~20us to deliver the
+ * IPI. If that times out, we panic.
+ */
+
+ /*
* first we do an INIT IPI: this INIT IPI might be run, resetting
* and running the target CPU. OR this INIT IPI might be latched (P5
* bug), CPU waiting for STARTUP IPI. OR this INIT IPI might be
* ignored.
*/
- lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
+ lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_LEVEL |
APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT, apic_id);
- lapic_ipi_wait(-1);
+ lapic_ipi_wait(20);
+
+ /* Explicitly deassert the INIT IPI. */
+ lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_LEVEL |
+ APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT,
+ apic_id);
+
DELAY(10000); /* wait ~10mS */
/*
@@ -1084,9 +1097,11 @@ ipi_startup(int apic_id, int vector)
* will run.
*/
lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
- APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
+ APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
vector, apic_id);
- lapic_ipi_wait(-1);
+ if (!lapic_ipi_wait(20))
+ panic("Failed to deliver first STARTUP IPI to APIC %d",
+ apic_id);
DELAY(200); /* wait ~200uS */
/*
@@ -1096,9 +1111,12 @@ ipi_startup(int apic_id, int vector)
* recognized after hardware RESET or INIT IPI.
*/
lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
- APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
+ APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
vector, apic_id);
- lapic_ipi_wait(-1);
+ if (!lapic_ipi_wait(20))
+ panic("Failed to deliver second STARTUP IPI to APIC %d",
+ apic_id);
+
DELAY(200); /* wait ~200uS */
}
diff --git a/sys/arm/broadcom/bcm2835/files.bcm2835 b/sys/arm/broadcom/bcm2835/files.bcm2835
index 95bb9c519cf6..416fb4adb7e2 100644
--- a/sys/arm/broadcom/bcm2835/files.bcm2835
+++ b/sys/arm/broadcom/bcm2835/files.bcm2835
@@ -29,21 +29,21 @@ dev/mbox/mbox_if.m standard
dev/ofw/ofw_cpu.c standard
# VideoCore driver
-contrib/vchiq/interface/compat/vchi_bsd.c standard \
+contrib/vchiq/interface/compat/vchi_bsd.c optional vchiq \
compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq"
-contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c standard \
+contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c optional vchiq \
compile-with "${NORMAL_C} -Wno-unused -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq"
-contrib/vchiq/interface/vchiq_arm/vchiq_arm.c standard \
+contrib/vchiq/interface/vchiq_arm/vchiq_arm.c optional vchiq \
compile-with "${NORMAL_C} -Wno-unused -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq"
-contrib/vchiq/interface/vchiq_arm/vchiq_connected.c standard \
+contrib/vchiq/interface/vchiq_arm/vchiq_connected.c optional vchiq \
compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq"
-contrib/vchiq/interface/vchiq_arm/vchiq_core.c standard \
+contrib/vchiq/interface/vchiq_arm/vchiq_core.c optional vchiq \
compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq"
-contrib/vchiq/interface/vchiq_arm/vchiq_kern_lib.c standard \
+contrib/vchiq/interface/vchiq_arm/vchiq_kern_lib.c optional vchiq \
compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq"
-contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c standard \
+contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c optional vchiq \
compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq"
-contrib/vchiq/interface/vchiq_arm/vchiq_shim.c standard \
+contrib/vchiq/interface/vchiq_arm/vchiq_shim.c optional vchiq \
compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq"
-contrib/vchiq/interface/vchiq_arm/vchiq_util.c standard \
+contrib/vchiq/interface/vchiq_arm/vchiq_util.c optional vchiq \
compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq"
diff --git a/sys/arm/conf/RPI-B b/sys/arm/conf/RPI-B
index 0b886dd0582e..41566efecc6c 100644
--- a/sys/arm/conf/RPI-B
+++ b/sys/arm/conf/RPI-B
@@ -129,9 +129,12 @@ device smsc
device spibus
device bcm2835_spi
+device vchiq
+
# Flattened Device Tree
options FDT # Configure using FDT/DTB data
# Note: DTB is normally loaded and modified by RPi boot loader, then
# handed to kernel via U-Boot and ubldr.
#options FDT_DTB_STATIC
-makeoptions FDT_DTS_FILE=rpi.dts
+#makeoptions FDT_DTS_FILE=rpi.dts
+makeoptions MODULES_EXTRA=dtb/rpi
diff --git a/sys/boot/amd64/boot1.efi/fat.tmpl.bz2.uu b/sys/boot/amd64/boot1.efi/fat.tmpl.bz2.uu
index 52ed67a468cb..c9044eece9a6 100644
--- a/sys/boot/amd64/boot1.efi/fat.tmpl.bz2.uu
+++ b/sys/boot/amd64/boot1.efi/fat.tmpl.bz2.uu
@@ -2,20 +2,19 @@ FAT template boot filesystem created by generate-fat.sh
DO NOT EDIT
$FreeBSD$
begin 644 fat.tmpl.bz2
-M0EIH.3%!62936=AO?&0`&J9____[ZZKJJ_^N_ZO^Z_^[OO_\`5`(0!0&#$D"
-M0$)$2&(<P`(\K5,M9"5%&DQ---,FAH,0```T````R-!HQ`&30`-&"#)ID$JF
-M1)[U4_5-&@`T```#0&AH````````````(,F`$P`!,`1IA&````"9-,308`1@
-M````!))!BDVI/U0`]0R>H:`81HT#)D!H-#U`T#31IH-&(``R8$9_I)6[MY/,
-M(H=/()+4&!(3V0"20C3J5$L5@2`219,"T6JI,@0"2*2\=LAD6=>N6<O!'F<.
-MQ2`;9$.P]202R&N9I3BX[E0;C7/9BF'`((K?M1ZK0B2Q;BLJ9!(`21P&1:;B
-MDD)S!-L5BL5BL/173`@@M!!!!!X@BQ0@@@@@@CJ"A!!!"!`TWD!B!`@0($"J
-M9(E`B,1(D2)$B;V]S&-,&#!@P8,'1\*$+59`:41,';;/)32*G*Q52N![20F8
-M9CCYSB#!2=[EG.),$:P,>(8QSW'U+N42P^'5X@7X``23=EA``#Z,O)^-VTX@
-M`+E!=,&6PV11C:*D8K#^<%FTG-%!@PR72@\ZU0B<D6I$FT/1\<A#/`;ET5$)
-MKT-MBW97\J.P/H0ADE"(EBN6";@5#$2#!(\F/E8M+!8-A-S"+$U5[\J>F1Y]
-MF-FPGL2L>4QCU&O/>89^#H$6^<;&WKC9W52KUX."CM6+GD;(=1!MUD,,?Y[]
-MTLAG0];,:B^]M%BH0J1":_C-*2I9R3AS#,&0>$RCY'T/R?HR!?'5$MILQ:!"
-M+;10A*!&^<(_/8>D8<CDN9]HO)OH13W(Q())?'R2WTV9*G_4T<=Y!'1+'9,(
-J1-/V<ME.&9Q3LKI2S$(`$D,``'_=FF*).\[A.)#4HU1=R13A0D-AO?&0
+M0EIH.3%!629362AK*D(`&I+____[ZZKJZ_^N_ZO^Z_Z_OJ[L`4`!7I0$#&$"
+M0$!$3&(<P`(;J*C:0E0E#30&AH`T````9#0```9````#)ZF0:,-3U/409,`)
+M@`"8`C3",````$R:8F@P`C`````"24U,D>I-DTU,)ZAZ0VA-!M0T'J`>H#"9
+M'I#0-H&HQI&0&3&FH>H>*`JHHU3V]1%/4/2``T#0`!H``#0`````#1H,@``6
+M'1&G'&@?$6[T#A)?X8$A160"20BO#")0J4TB1*4GXF$B4I,&>43+=_?K=#3*
+M6]<E0HE`UBF?(J%8BRF#?8OQ2'D)`)(EL2;F4.'R>R"ZNKJZI,9*68E8*E2Q
+M4J5*E3'(1830A"$(12A-"<(0A#]VD)H0A"$,>I0FA"$(0I\>P^=F5:M6K5JU
+M:DI3:64UN;[7%5B]Y-^\]@_K@B:N\/,5F%&H<\G#IXQXAEFC&D?![6%0'6MR
+MX1@@%FC"FD`M7,/SXFNG:2`'-0<-C$8^+$N.7M1B,^6)9,DV9,0A\OL<:C"L
+ML1V&,<\9YRB>XV#BG")'6NKRK^("UF2XO?_L!#29">MGDF$R3).!PX&%E,4C
+M''=(FL1.`_3?CN@-IB2PI3!FF\<8X.X@D,>CA90I)#M$XRPNDFJELL<3=1?8
+M2B7\5Z64,!7Z;EEBW-MXN-4IJ@W$462]-*\YCR,-B,5[W?=3&L/U>SX,WV#\
+M\B`:I"'0Z)5"$1B.E)(K[5I4RS`%R$>Y\D0NR*,;<9CZ:^V3P(I?D<D#!UC)
+D^M-HEE3SAN-8O0FQ$(`$(DF`?ZQ]'U2F_XNY(IPH2!0UE2$`
`
end
diff --git a/sys/boot/amd64/boot1.efi/generate-fat.sh b/sys/boot/amd64/boot1.efi/generate-fat.sh
index e8f9cdedd4b5..04d0ed25bf88 100755
--- a/sys/boot/amd64/boot1.efi/generate-fat.sh
+++ b/sys/boot/amd64/boot1.efi/generate-fat.sh
@@ -20,7 +20,7 @@ OUTPUT_FILE=fat.tmpl
dd if=/dev/zero of=$OUTPUT_FILE bs=512 count=$FAT_SIZE
DEVICE=`mdconfig -a -f $OUTPUT_FILE`
-newfs_msdos -F 12 $DEVICE
+newfs_msdos -F 12 -L EFI $DEVICE
mkdir stub
mount -t msdosfs /dev/$DEVICE stub
diff --git a/sys/boot/forth/beastie.4th b/sys/boot/forth/beastie.4th
index 6512d739c271..8d2424408bbc 100644
--- a/sys/boot/forth/beastie.4th
+++ b/sys/boot/forth/beastie.4th
@@ -89,7 +89,7 @@ variable logoY
0 25 at-xy
;
-: fbsdbw-logo ( x y -- ) \ "FreeBSD" logo in B/W (12 rows x 21 columns)
+: fbsdbw-logo ( x y -- ) \ "FreeBSD" logo in B/W (13 rows x 21 columns)
\ We used to use the beastie himself as our default... until the
\ eventual complaint derided his reign of the advanced boot-menu.
@@ -106,16 +106,17 @@ variable logoY
5 + swap 6 + swap
2dup at-xy ." ______" 1+
- 2dup at-xy ." | ____|" 1+
- 2dup at-xy ." | |__ _ __ ___ ___ " 1+
- 2dup at-xy ." | __|| '__/ _ \/ _ \" 1+
- 2dup at-xy ." | | | | | __/ __/" 1+
+ 2dup at-xy ." | ____| __ ___ ___ " 1+
+ 2dup at-xy ." | |__ | '__/ _ \/ _ \" 1+
+ 2dup at-xy ." | __|| | | __/ __/" 1+
+ 2dup at-xy ." | | | | | | |" 1+
2dup at-xy ." |_| |_| \___|\___|" 1+
2dup at-xy ." ____ _____ _____" 1+
2dup at-xy ." | _ \ / ____| __ \" 1+
2dup at-xy ." | |_) | (___ | | | |" 1+
2dup at-xy ." | _ < \___ \| | | |" 1+
2dup at-xy ." | |_) |____) | |__| |" 1+
+ 2dup at-xy ." | | | |" 1+
at-xy ." |____/|_____/|_____/"
\ Put the cursor back at the bottom
diff --git a/sys/boot/forth/brand.4th b/sys/boot/forth/brand.4th
index 3dda97cc3e2f..28d3c5c1d26f 100644
--- a/sys/boot/forth/brand.4th
+++ b/sys/boot/forth/brand.4th
@@ -33,13 +33,14 @@ variable brandY
2 brandX !
1 brandY !
-: fbsd-logo ( x y -- ) \ "FreeBSD" [wide] logo in B/W (6 rows x 42 columns)
+: fbsd-logo ( x y -- ) \ "FreeBSD" [wide] logo in B/W (7 rows x 42 columns)
2dup at-xy ." ______ ____ _____ _____ " 1+
2dup at-xy ." | ____| | _ \ / ____| __ \ " 1+
2dup at-xy ." | |___ _ __ ___ ___ | |_) | (___ | | | |" 1+
2dup at-xy ." | ___| '__/ _ \/ _ \| _ < \___ \| | | |" 1+
2dup at-xy ." | | | | | __/ __/| |_) |____) | |__| |" 1+
+ 2dup at-xy ." | | | | | | || | | |" 1+
at-xy ." |_| |_| \___|\___||____/|_____/|_____/ "
\ Put the cursor back at the bottom
diff --git a/sys/cam/ctl/ctl_frontend_iscsi.c b/sys/cam/ctl/ctl_frontend_iscsi.c
index 817f9ffbdb96..4b8b4923d304 100644
--- a/sys/cam/ctl/ctl_frontend_iscsi.c
+++ b/sys/cam/ctl/ctl_frontend_iscsi.c
@@ -1222,7 +1222,7 @@ cfiscsi_session_unregister_initiator(struct cfiscsi_session *cs)
}
static struct cfiscsi_session *
-cfiscsi_session_new(struct cfiscsi_softc *softc)
+cfiscsi_session_new(struct cfiscsi_softc *softc, const char *offload)
{
struct cfiscsi_session *cs;
int error;
@@ -1242,7 +1242,11 @@ cfiscsi_session_new(struct cfiscsi_softc *softc)
cv_init(&cs->cs_login_cv, "cfiscsi_login");
#endif
- cs->cs_conn = icl_new_conn(NULL, "cfiscsi", &cs->cs_lock);
+ cs->cs_conn = icl_new_conn(offload, "cfiscsi", &cs->cs_lock);
+ if (cs->cs_conn == NULL) {
+ free(cs, M_CFISCSI);
+ return (NULL);
+ }
cs->cs_conn->ic_receive = cfiscsi_receive_callback;
cs->cs_conn->ic_error = cfiscsi_error_callback;
cs->cs_conn->ic_prv0 = cs;
@@ -1325,7 +1329,7 @@ cfiscsi_accept(struct socket *so, struct sockaddr *sa, int portal_id)
{
struct cfiscsi_session *cs;
- cs = cfiscsi_session_new(&cfiscsi_softc);
+ cs = cfiscsi_session_new(&cfiscsi_softc, NULL);
if (cs == NULL) {
CFISCSI_WARN("failed to create session");
return;
@@ -1469,7 +1473,7 @@ cfiscsi_ioctl_handoff(struct ctl_iscsi *ci)
mtx_unlock(&cfiscsi_softc.lock);
} else {
#endif
- cs = cfiscsi_session_new(softc);
+ cs = cfiscsi_session_new(softc, cihp->offload);
if (cs == NULL) {
ci->status = CTL_ISCSI_ERROR;
snprintf(ci->error_str, sizeof(ci->error_str),
@@ -1620,6 +1624,7 @@ cfiscsi_ioctl_list(struct ctl_iscsi *ci)
"<max_data_segment_length>%zd</max_data_segment_length>"
"<immediate_data>%d</immediate_data>"
"<iser>%d</iser>"
+ "<offload>%s</offload>"
"</connection>\n",
cs->cs_id,
cs->cs_initiator_name, cs->cs_initiator_addr, cs->cs_initiator_alias,
@@ -1629,7 +1634,8 @@ cfiscsi_ioctl_list(struct ctl_iscsi *ci)
cs->cs_conn->ic_data_crc32c ? "CRC32C" : "None",
cs->cs_max_data_segment_length,
cs->cs_immediate_data,
- cs->cs_conn->ic_iser);
+ cs->cs_conn->ic_iser,
+ cs->cs_conn->ic_offload);
if (error != 0)
break;
}
@@ -1749,6 +1755,26 @@ cfiscsi_ioctl_logout(struct ctl_iscsi *ci)
ci->status = CTL_ISCSI_OK;
}
+static void
+cfiscsi_ioctl_limits(struct ctl_iscsi *ci)
+{
+ struct ctl_iscsi_limits_params *cilp;
+ int error;
+
+ cilp = (struct ctl_iscsi_limits_params *)&(ci->data);
+
+ error = icl_limits(cilp->offload, &cilp->data_segment_limit);
+ if (error != 0) {
+ ci->status = CTL_ISCSI_ERROR;
+ snprintf(ci->error_str, sizeof(ci->error_str),
+ "%s: icl_limits failed with error %d",
+ __func__, error);
+ return;
+ }
+
+ ci->status = CTL_ISCSI_OK;
+}
+
#ifdef ICL_KERNEL_PROXY
static void
cfiscsi_ioctl_listen(struct ctl_iscsi *ci)
@@ -2176,6 +2202,9 @@ cfiscsi_ioctl(struct cdev *dev,
case CTL_ISCSI_LOGOUT:
cfiscsi_ioctl_logout(ci);
break;
+ case CTL_ISCSI_LIMITS:
+ cfiscsi_ioctl_limits(ci);
+ break;
#ifdef ICL_KERNEL_PROXY
case CTL_ISCSI_LISTEN:
cfiscsi_ioctl_listen(ci);
diff --git a/sys/cam/ctl/ctl_ioctl.h b/sys/cam/ctl/ctl_ioctl.h
index 532953fb7fab..c7a3c2938400 100644
--- a/sys/cam/ctl/ctl_ioctl.h
+++ b/sys/cam/ctl/ctl_ioctl.h
@@ -657,6 +657,7 @@ typedef enum {
CTL_ISCSI_LIST,
CTL_ISCSI_LOGOUT,
CTL_ISCSI_TERMINATE,
+ CTL_ISCSI_LIMITS,
#if defined(ICL_KERNEL_PROXY) || 1
/*
* We actually need those in all cases, but leave the ICL_KERNEL_PROXY,
@@ -677,6 +678,7 @@ typedef enum {
#define CTL_ISCSI_NAME_LEN 224 /* 223 bytes, by RFC 3720, + '\0' */
#define CTL_ISCSI_ADDR_LEN 47 /* INET6_ADDRSTRLEN + '\0' */
#define CTL_ISCSI_ALIAS_LEN 128 /* Arbitrary. */
+#define CTL_ISCSI_OFFLOAD_LEN 8 /* Arbitrary. */
struct ctl_iscsi_handoff_params {
char initiator_name[CTL_ISCSI_NAME_LEN];
@@ -698,11 +700,12 @@ struct ctl_iscsi_handoff_params {
uint32_t max_burst_length;
uint32_t first_burst_length;
uint32_t immediate_data;
+ char offload[CTL_ISCSI_OFFLOAD_LEN];
#ifdef ICL_KERNEL_PROXY
int connection_id;
- int spare[3];
+ int spare[1];
#else
- int spare[4];
+ int spare[2];
#endif
};
@@ -733,6 +736,14 @@ struct ctl_iscsi_terminate_params {
int spare[4];
};
+struct ctl_iscsi_limits_params {
+ char offload[CTL_ISCSI_OFFLOAD_LEN];
+ /* passed to kernel */
+ size_t data_segment_limit;
+ /* passed to userland */
+ int spare[4];
+};
+
#ifdef ICL_KERNEL_PROXY
struct ctl_iscsi_listen_params {
int iser;
@@ -780,6 +791,7 @@ union ctl_iscsi_data {
struct ctl_iscsi_list_params list;
struct ctl_iscsi_logout_params logout;
struct ctl_iscsi_terminate_params terminate;
+ struct ctl_iscsi_limits_params limits;
#ifdef ICL_KERNEL_PROXY
struct ctl_iscsi_listen_params listen;
struct ctl_iscsi_accept_params accept;
diff --git a/sys/conf/files b/sys/conf/files
index 97bbe5914762..e10fd5e44173 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3193,7 +3193,7 @@ libkern/jenkins_hash.c standard
libkern/murmur3_32.c standard
libkern/mcount.c optional profiling-routine
libkern/memcchr.c standard
-libkern/memchr.c optional fdt | gdb
+libkern/memchr.c standard
libkern/memcmp.c standard
libkern/memmem.c optional gdb
libkern/qsort.c standard
diff --git a/sys/conf/kern.pre.mk b/sys/conf/kern.pre.mk
index cf60a770de43..f0e57361d3a5 100644
--- a/sys/conf/kern.pre.mk
+++ b/sys/conf/kern.pre.mk
@@ -174,7 +174,7 @@ SYSTEM_OBJS= locore.o ${MDOBJS} ${OBJS}
SYSTEM_OBJS+= ${SYSTEM_CFILES:.c=.o}
SYSTEM_OBJS+= hack.So
SYSTEM_LD= @${LD} -Bdynamic -T ${LDSCRIPT} ${_LDFLAGS} --no-warn-mismatch \
- -warn-common -export-dynamic -dynamic-linker /red/herring \
+ --warn-common --export-dynamic --dynamic-linker /red/herring \
-o ${.TARGET} -X ${SYSTEM_OBJS} vers.o
SYSTEM_LD_TAIL= @${OBJCOPY} --strip-symbol gcc2_compiled. ${.TARGET} ; \
${SIZE} ${.TARGET} ; chmod 755 ${.TARGET}
diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h
index 30c55a077ffe..f16ef6b12fcb 100644
--- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h
+++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h
@@ -317,12 +317,12 @@ typedef struct {
/* Support for multiple INIs */
struct ar9300_ini_array {
- u_int32_t *ia_array;
+ const u_int32_t *ia_array;
u_int32_t ia_rows;
u_int32_t ia_columns;
};
#define INIT_INI_ARRAY(iniarray, array, rows, columns) do { \
- (iniarray)->ia_array = (u_int32_t *)(array); \
+ (iniarray)->ia_array = (const u_int32_t *)(array); \
(iniarray)->ia_rows = (rows); \
(iniarray)->ia_columns = (columns); \
} while (0)
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index a4732c47a647..bf2cc5498b43 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -101,6 +101,7 @@ int acpi_quirks;
/* Supported sleep states. */
static BOOLEAN acpi_sleep_states[ACPI_S_STATE_COUNT];
+static void acpi_lookup(void *arg, const char *name, device_t *dev);
static int acpi_modevent(struct module *mod, int event, void *junk);
static int acpi_probe(device_t dev);
static int acpi_attach(device_t dev);
@@ -671,8 +672,10 @@ acpi_attach(device_t dev)
/* Register ACPI again to pass the correct argument of pm_func. */
power_pm_register(POWER_PM_TYPE_ACPI, acpi_pm_func, sc);
- if (!acpi_disabled("bus"))
+ if (!acpi_disabled("bus")) {
+ EVENTHANDLER_REGISTER(dev_lookup, acpi_lookup, NULL, 1000);
acpi_probe_children(dev);
+ }
/* Update all GPEs and enable runtime GPEs. */
status = AcpiUpdateAllGpes();
@@ -3401,6 +3404,31 @@ acpi_disabled(char *subsys)
return (0);
}
+static void
+acpi_lookup(void *arg, const char *name, device_t *dev)
+{
+ ACPI_HANDLE handle;
+
+ if (*dev != NULL)
+ return;
+
+ /*
+ * Allow any handle name that is specified as an absolute path and
+ * starts with '\'. We could restrict this to \_SB and friends,
+ * but see acpi_probe_children() for notes on why we scan the entire
+ * namespace for devices.
+ *
+ * XXX: The pathname argument to AcpiGetHandle() should be fixed to
+ * be const.
+ */
+ if (name[0] != '\\')
+ return;
+ if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, __DECONST(char *, name),
+ &handle)))
+ return;
+ *dev = acpi_get_device(handle);
+}
+
/*
* Control interface.
*
diff --git a/sys/dev/cxgbe/if_cxl.c b/sys/dev/cxgbe/if_cxl.c
new file mode 100644
index 000000000000..2b498dc5c449
--- /dev/null
+++ b/sys/dev/cxgbe/if_cxl.c
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2015 Chelsio Communications, Inc.
+ * All rights reserved.
+ * Written by: Navdeep Parhar <np@FreeBSD.org>
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+static int
+mod_event(module_t mod, int cmd, void *arg)
+{
+
+ return (0);
+}
+static moduledata_t if_cxl_mod = {"if_cxl", mod_event};
+DECLARE_MODULE(if_cxl, if_cxl_mod, SI_SUB_EXEC, SI_ORDER_ANY);
+MODULE_VERSION(if_cxl, 1);
+MODULE_DEPEND(if_cxl, cxl, 1, 1, 1);
diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c
index 7f59e840de27..e2f3c594df4b 100644
--- a/sys/dev/cxgbe/t4_main.c
+++ b/sys/dev/cxgbe/t4_main.c
@@ -8215,7 +8215,12 @@ toe_capability(struct port_info *pi, int enable)
return (ENODEV);
if (enable) {
- if (!(sc->flags & FULL_INIT_DONE)) {
+ /*
+ * We need the port's queues around so that we're able to send
+ * and receive CPLs to/from the TOE even if the ifnet for this
+ * port has never been UP'd administratively.
+ */
+ if (!(pi->flags & PORT_INIT_DONE)) {
rc = cxgbe_init_synchronized(pi);
if (rc)
return (rc);
diff --git a/sys/dev/ipmi/ipmi.c b/sys/dev/ipmi/ipmi.c
index 5e30770cb669..a1edbf64524b 100644
--- a/sys/dev/ipmi/ipmi.c
+++ b/sys/dev/ipmi/ipmi.c
@@ -49,6 +49,23 @@ __FBSDID("$FreeBSD$");
#include <dev/ipmi/ipmivars.h>
#endif
+/*
+ * Driver request structures are allocated on the stack via alloca() to
+ * avoid calling malloc(), especially for the watchdog handler.
+ * To avoid too much stack growth, a previously allocated structure can
+ * be reused via IPMI_INIT_DRIVER_REQUEST(), but the caller should ensure
+ * that there is adequate reply/request space in the original allocation.
+ */
+#define IPMI_INIT_DRIVER_REQUEST(req, addr, cmd, reqlen, replylen) \
+ bzero((req), sizeof(struct ipmi_request)); \
+ ipmi_init_request((req), NULL, 0, (addr), (cmd), (reqlen), (replylen))
+
+#define IPMI_ALLOC_DRIVER_REQUEST(req, addr, cmd, reqlen, replylen) \
+ (req) = __builtin_alloca(sizeof(struct ipmi_request) + \
+ (reqlen) + (replylen)); \
+ IPMI_INIT_DRIVER_REQUEST((req), (addr), (cmd), (reqlen), \
+ (replylen))
+
#ifdef IPMB
static int ipmi_ipmb_checksum(u_char, int);
static int ipmi_ipmb_send_message(device_t, u_char, u_char, u_char,
@@ -181,8 +198,8 @@ ipmi_dtor(void *arg)
*/
dev->ipmi_closing = 1;
while (dev->ipmi_requests > 0) {
- msleep(&dev->ipmi_requests, &sc->ipmi_lock, PWAIT,
- "ipmidrain", 0);
+ msleep(&dev->ipmi_requests, &sc->ipmi_requests_lock,
+ PWAIT, "ipmidrain", 0);
ipmi_purge_completed_requests(dev);
}
}
@@ -215,7 +232,7 @@ ipmi_ipmb_send_message(device_t dev, u_char channel, u_char netfn,
u_char slave_addr = 0x52;
int error;
- req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
+ IPMI_ALLOC_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
IPMI_SEND_MSG, data_len + 8, 0);
req->ir_request[0] = channel;
req->ir_request[1] = slave_addr;
@@ -231,7 +248,6 @@ ipmi_ipmb_send_message(device_t dev, u_char channel, u_char netfn,
ipmi_submit_driver_request(sc, req);
error = req->ir_error;
- ipmi_free_request(req);
return (error);
}
@@ -243,7 +259,7 @@ ipmi_handle_attn(struct ipmi_softc *sc)
int error;
device_printf(sc->ipmi_dev, "BMC has a message\n");
- req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
+ IPMI_ALLOC_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
IPMI_GET_MSG_FLAGS, 0, 1);
ipmi_submit_driver_request(sc, req);
@@ -257,9 +273,7 @@ ipmi_handle_attn(struct ipmi_softc *sc)
"watchdog about to go off");
}
if (req->ir_reply[0] & IPMI_MSG_AVAILABLE) {
- ipmi_free_request(req);
-
- req = ipmi_alloc_driver_request(
+ IPMI_ALLOC_DRIVER_REQUEST(req,
IPMI_ADDR(IPMI_APP_REQUEST, 0), IPMI_GET_MSG, 0,
16);
@@ -268,7 +282,6 @@ ipmi_handle_attn(struct ipmi_softc *sc)
}
}
error = req->ir_error;
- ipmi_free_request(req);
return (error);
}
@@ -478,15 +491,11 @@ ipmi_ioctl(struct cdev *cdev, u_long cmd, caddr_t data,
* Request management.
*/
-/* Allocate a new request with request and reply buffers. */
-struct ipmi_request *
-ipmi_alloc_request(struct ipmi_device *dev, long msgid, uint8_t addr,
- uint8_t command, size_t requestlen, size_t replylen)
+static __inline void
+ipmi_init_request(struct ipmi_request *req, struct ipmi_device *dev, long msgid,
+ uint8_t addr, uint8_t command, size_t requestlen, size_t replylen)
{
- struct ipmi_request *req;
- req = malloc(sizeof(struct ipmi_request) + requestlen + replylen,
- M_IPMI, M_WAITOK | M_ZERO);
req->ir_owner = dev;
req->ir_msgid = msgid;
req->ir_addr = addr;
@@ -499,6 +508,18 @@ ipmi_alloc_request(struct ipmi_device *dev, long msgid, uint8_t addr,
req->ir_reply = (char *)&req[1] + requestlen;
req->ir_replybuflen = replylen;
}
+}
+
+/* Allocate a new request with request and reply buffers. */
+struct ipmi_request *
+ipmi_alloc_request(struct ipmi_device *dev, long msgid, uint8_t addr,
+ uint8_t command, size_t requestlen, size_t replylen)
+{
+ struct ipmi_request *req;
+
+ req = malloc(sizeof(struct ipmi_request) + requestlen + replylen,
+ M_IPMI, M_WAITOK | M_ZERO);
+ ipmi_init_request(req, dev, msgid, addr, command, requestlen, replylen);
return (req);
}
@@ -533,21 +554,13 @@ ipmi_complete_request(struct ipmi_softc *sc, struct ipmi_request *req)
}
}
-/* Enqueue an internal driver request and wait until it is completed. */
+/* Perform an internal driver request. */
int
ipmi_submit_driver_request(struct ipmi_softc *sc, struct ipmi_request *req,
int timo)
{
- int error;
- IPMI_LOCK(sc);
- error = sc->ipmi_enqueue_request(sc, req);
- if (error == 0)
- error = msleep(req, &sc->ipmi_lock, 0, "ipmireq", timo);
- if (error == 0)
- error = req->ir_error;
- IPMI_UNLOCK(sc);
- return (error);
+ return (sc->ipmi_driver_request(sc, req, timo));
}
/*
@@ -564,7 +577,7 @@ ipmi_dequeue_request(struct ipmi_softc *sc)
IPMI_LOCK_ASSERT(sc);
while (!sc->ipmi_detaching && TAILQ_EMPTY(&sc->ipmi_pending_requests))
- cv_wait(&sc->ipmi_request_added, &sc->ipmi_lock);
+ cv_wait(&sc->ipmi_request_added, &sc->ipmi_requests_lock);
if (sc->ipmi_detaching)
return (NULL);
@@ -598,7 +611,7 @@ ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec)
if (sec > 0xffff / 10)
return (EINVAL);
- req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
+ IPMI_ALLOC_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
IPMI_SET_WDOG, 6, 0);
if (sec) {
@@ -622,9 +635,7 @@ ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec)
if (error)
device_printf(sc->ipmi_dev, "Failed to set watchdog\n");
else if (sec) {
- ipmi_free_request(req);
-
- req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
+ IPMI_INIT_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
IPMI_RESET_WDOG, 0, 0);
error = ipmi_submit_driver_request(sc, req, 0);
@@ -633,7 +644,6 @@ ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec)
"Failed to reset watchdog\n");
}
- ipmi_free_request(req);
return (error);
/*
dump_watchdog(sc);
@@ -680,7 +690,8 @@ ipmi_startup(void *arg)
dev = sc->ipmi_dev;
/* Initialize interface-independent state. */
- mtx_init(&sc->ipmi_lock, device_get_nameunit(dev), "ipmi", MTX_DEF);
+ mtx_init(&sc->ipmi_requests_lock, "ipmi requests", NULL, MTX_DEF);
+ mtx_init(&sc->ipmi_io_lock, "ipmi io", NULL, MTX_DEF);
cv_init(&sc->ipmi_request_added, "ipmireq");
TAILQ_INIT(&sc->ipmi_pending_requests);
@@ -693,28 +704,24 @@ ipmi_startup(void *arg)
}
/* Send a GET_DEVICE_ID request. */
- req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
+ IPMI_ALLOC_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
IPMI_GET_DEVICE_ID, 0, 15);
error = ipmi_submit_driver_request(sc, req, MAX_TIMEOUT);
if (error == EWOULDBLOCK) {
device_printf(dev, "Timed out waiting for GET_DEVICE_ID\n");
- ipmi_free_request(req);
return;
} else if (error) {
device_printf(dev, "Failed GET_DEVICE_ID: %d\n", error);
- ipmi_free_request(req);
return;
} else if (req->ir_compcode != 0) {
device_printf(dev,
"Bad completion code for GET_DEVICE_ID: %d\n",
req->ir_compcode);
- ipmi_free_request(req);
return;
} else if (req->ir_replylen < 5) {
device_printf(dev, "Short reply for GET_DEVICE_ID: %d\n",
req->ir_replylen);
- ipmi_free_request(req);
return;
}
@@ -724,9 +731,7 @@ ipmi_startup(void *arg)
req->ir_reply[2] & 0x7f, req->ir_reply[3] >> 4, req->ir_reply[3] & 0x0f,
req->ir_reply[4] & 0x0f, req->ir_reply[4] >> 4);
- ipmi_free_request(req);
-
- req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
+ IPMI_INIT_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
IPMI_CLEAR_FLAGS, 1, 0);
ipmi_submit_driver_request(sc, req, 0);
@@ -738,25 +743,21 @@ ipmi_startup(void *arg)
if (req->ir_compcode == 0xc1) {
device_printf(dev, "Clear flags illegal\n");
}
- ipmi_free_request(req);
for (i = 0; i < 8; i++) {
- req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
+ IPMI_INIT_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
IPMI_GET_CHANNEL_INFO, 1, 0);
req->ir_request[0] = i;
ipmi_submit_driver_request(sc, req, 0);
- if (req->ir_compcode != 0) {
- ipmi_free_request(req);
+ if (req->ir_compcode != 0)
break;
- }
- ipmi_free_request(req);
}
device_printf(dev, "Number of channels %d\n", i);
/* probe for watchdog */
- req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
+ IPMI_INIT_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
IPMI_GET_WDOG, 0, 0);
ipmi_submit_driver_request(sc, req, 0);
@@ -767,7 +768,6 @@ ipmi_startup(void *arg)
sc->ipmi_watchdog_tag = EVENTHANDLER_REGISTER(watchdog_list,
ipmi_wd_event, sc, 0);
}
- ipmi_free_request(req);
sc->ipmi_cdev = make_dev(&ipmi_cdevsw, device_get_unit(dev),
UID_ROOT, GID_OPERATOR, 0660, "ipmi%d", device_get_unit(dev));
@@ -834,14 +834,16 @@ ipmi_detach(device_t dev)
sc->ipmi_detaching = 1;
if (sc->ipmi_kthread) {
cv_broadcast(&sc->ipmi_request_added);
- msleep(sc->ipmi_kthread, &sc->ipmi_lock, 0, "ipmi_wait", 0);
+ msleep(sc->ipmi_kthread, &sc->ipmi_requests_lock, 0,
+ "ipmi_wait", 0);
}
IPMI_UNLOCK(sc);
if (sc->ipmi_irq)
bus_teardown_intr(dev, sc->ipmi_irq_res, sc->ipmi_irq);
ipmi_release_resources(dev);
- mtx_destroy(&sc->ipmi_lock);
+ mtx_destroy(&sc->ipmi_io_lock);
+ mtx_destroy(&sc->ipmi_requests_lock);
return (0);
}
diff --git a/sys/dev/ipmi/ipmi_kcs.c b/sys/dev/ipmi/ipmi_kcs.c
index eb5884a86b57..1c586467667b 100644
--- a/sys/dev/ipmi/ipmi_kcs.c
+++ b/sys/dev/ipmi/ipmi_kcs.c
@@ -321,6 +321,8 @@ kcs_polled_request(struct ipmi_softc *sc, struct ipmi_request *req)
u_char *cp, data;
int i, state;
+ IPMI_IO_LOCK(sc);
+
/* Send the request. */
if (!kcs_start_write(sc)) {
device_printf(sc->ipmi_dev, "KCS: Failed to start write\n");
@@ -444,6 +446,7 @@ kcs_polled_request(struct ipmi_softc *sc, struct ipmi_request *req)
}
i++;
}
+ IPMI_IO_UNLOCK(sc);
req->ir_replylen = i;
#ifdef KCS_DEBUG
device_printf(sc->ipmi_dev, "KCS: READ finished (%d bytes)\n", i);
@@ -457,6 +460,7 @@ kcs_polled_request(struct ipmi_softc *sc, struct ipmi_request *req)
return (1);
fail:
kcs_error(sc);
+ IPMI_IO_UNLOCK(sc);
return (0);
}
@@ -492,6 +496,21 @@ kcs_startup(struct ipmi_softc *sc)
device_get_nameunit(sc->ipmi_dev)));
}
+static int
+kcs_driver_request(struct ipmi_softc *sc, struct ipmi_request *req, int timo)
+{
+ int i, ok;
+
+ ok = 0;
+ for (i = 0; i < 3 && !ok; i++)
+ ok = kcs_polled_request(sc, req);
+ if (ok)
+ req->ir_error = 0;
+ else
+ req->ir_error = EIO;
+ return (req->ir_error);
+}
+
int
ipmi_kcs_attach(struct ipmi_softc *sc)
{
@@ -500,6 +519,7 @@ ipmi_kcs_attach(struct ipmi_softc *sc)
/* Setup function pointers. */
sc->ipmi_startup = kcs_startup;
sc->ipmi_enqueue_request = ipmi_polled_enqueue_request;
+ sc->ipmi_driver_request = kcs_driver_request;
/* See if we can talk to the controller. */
status = INB(sc, KCS_CTL_STS);
diff --git a/sys/dev/ipmi/ipmi_smic.c b/sys/dev/ipmi/ipmi_smic.c
index c79c86d574fb..4e26553e98e7 100644
--- a/sys/dev/ipmi/ipmi_smic.c
+++ b/sys/dev/ipmi/ipmi_smic.c
@@ -364,8 +364,11 @@ smic_loop(void *arg)
while ((req = ipmi_dequeue_request(sc)) != NULL) {
IPMI_UNLOCK(sc);
ok = 0;
- for (i = 0; i < 3 && !ok; i++)
+ for (i = 0; i < 3 && !ok; i++) {
+ IPMI_IO_LOCK(sc);
ok = smic_polled_request(sc, req);
+ IPMI_IO_UNLOCK(sc);
+ }
if (ok)
req->ir_error = 0;
else
@@ -385,6 +388,24 @@ smic_startup(struct ipmi_softc *sc)
"%s: smic", device_get_nameunit(sc->ipmi_dev)));
}
+static int
+smic_driver_request(struct ipmi_softc *sc, struct ipmi_request *req, int timo)
+{
+ int i, ok;
+
+ ok = 0;
+ for (i = 0; i < 3 && !ok; i++) {
+ IPMI_IO_LOCK(sc);
+ ok = smic_polled_request(sc, req);
+ IPMI_IO_UNLOCK(sc);
+ }
+ if (ok)
+ req->ir_error = 0;
+ else
+ req->ir_error = EIO;
+ return (req->ir_error);
+}
+
int
ipmi_smic_attach(struct ipmi_softc *sc)
{
@@ -393,6 +414,7 @@ ipmi_smic_attach(struct ipmi_softc *sc)
/* Setup function pointers. */
sc->ipmi_startup = smic_startup;
sc->ipmi_enqueue_request = ipmi_polled_enqueue_request;
+ sc->ipmi_driver_request = smic_driver_request;
/* See if we can talk to the controller. */
flags = INB(sc, SMIC_FLAGS);
diff --git a/sys/dev/ipmi/ipmi_ssif.c b/sys/dev/ipmi/ipmi_ssif.c
index 2256de16e7ef..e5d5d3aa8cdd 100644
--- a/sys/dev/ipmi/ipmi_ssif.c
+++ b/sys/dev/ipmi/ipmi_ssif.c
@@ -359,6 +359,22 @@ ssif_startup(struct ipmi_softc *sc)
"%s: ssif", device_get_nameunit(sc->ipmi_dev)));
}
+static int
+ssif_driver_request(struct ipmi_softc *sc, struct ipmi_request *req, int timo)
+{
+ int error;
+
+ IPMI_LOCK(sc);
+ error = ipmi_polled_enqueue_request(sc, req);
+ if (error == 0)
+ error = msleep(req, &sc->ipmi_requests_lock, 0, "ipmireq",
+ timo);
+ if (error == 0)
+ error = req->ir_error;
+ IPMI_UNLOCK(sc);
+ return (error);
+}
+
int
ipmi_ssif_attach(struct ipmi_softc *sc, device_t smbus, int smbus_address)
{
@@ -370,6 +386,7 @@ ipmi_ssif_attach(struct ipmi_softc *sc, device_t smbus, int smbus_address)
/* Setup function pointers. */
sc->ipmi_startup = ssif_startup;
sc->ipmi_enqueue_request = ipmi_polled_enqueue_request;
+ sc->ipmi_driver_request = ssif_driver_request;
return (0);
}
diff --git a/sys/dev/ipmi/ipmivars.h b/sys/dev/ipmi/ipmivars.h
index 8e9e130d3ca7..9d7dc3220893 100644
--- a/sys/dev/ipmi/ipmivars.h
+++ b/sys/dev/ipmi/ipmivars.h
@@ -95,6 +95,7 @@ struct ipmi_softc {
} _iface;
int ipmi_io_rid;
int ipmi_io_type;
+ struct mtx ipmi_io_lock;
struct resource *ipmi_io_res[MAX_RES];
int ipmi_io_spacing;
int ipmi_irq_rid;
@@ -107,12 +108,13 @@ struct ipmi_softc {
eventhandler_tag ipmi_watchdog_tag;
int ipmi_watchdog_active;
struct intr_config_hook ipmi_ich;
- struct mtx ipmi_lock;
+ struct mtx ipmi_requests_lock;
struct cv ipmi_request_added;
struct proc *ipmi_kthread;
driver_intr_t *ipmi_intr;
int (*ipmi_startup)(struct ipmi_softc *);
int (*ipmi_enqueue_request)(struct ipmi_softc *, struct ipmi_request *);
+ int (*ipmi_driver_request)(struct ipmi_softc *, struct ipmi_request *, int);
};
#define ipmi_ssif_smbus_address _iface.ssif.smbus_address
@@ -183,12 +185,13 @@ struct ipmi_ipmb {
#define IPMI_ADDR(netfn, lun) ((netfn) << 2 | (lun))
#define IPMI_REPLY_ADDR(addr) ((addr) + 0x4)
-#define IPMI_LOCK(sc) mtx_lock(&(sc)->ipmi_lock)
-#define IPMI_UNLOCK(sc) mtx_unlock(&(sc)->ipmi_lock)
-#define IPMI_LOCK_ASSERT(sc) mtx_assert(&(sc)->ipmi_lock, MA_OWNED)
+#define IPMI_LOCK(sc) mtx_lock(&(sc)->ipmi_requests_lock)
+#define IPMI_UNLOCK(sc) mtx_unlock(&(sc)->ipmi_requests_lock)
+#define IPMI_LOCK_ASSERT(sc) mtx_assert(&(sc)->ipmi_requests_lock, MA_OWNED)
-#define ipmi_alloc_driver_request(addr, cmd, reqlen, replylen) \
- ipmi_alloc_request(NULL, 0, (addr), (cmd), (reqlen), (replylen))
+#define IPMI_IO_LOCK(sc) mtx_lock(&(sc)->ipmi_io_lock)
+#define IPMI_IO_UNLOCK(sc) mtx_unlock(&(sc)->ipmi_io_lock)
+#define IPMI_IO_LOCK_ASSERT(sc) mtx_assert(&(sc)->ipmi_io_lock, MA_OWNED)
#if __FreeBSD_version < 601105
#define bus_read_1(r, o) \
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 8f87851da6ac..263904bc1783 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/module.h>
+#include <sys/limits.h>
#include <sys/linker.h>
#include <sys/fcntl.h>
#include <sys/conf.h>
@@ -4824,8 +4825,8 @@ pci_child_location_str_method(device_t dev, device_t child, char *buf,
size_t buflen)
{
- snprintf(buf, buflen, "slot=%d function=%d", pci_get_slot(child),
- pci_get_function(child));
+ snprintf(buf, buflen, "pci%d:%d:%d:%d", pci_get_domain(child),
+ pci_get_bus(child), pci_get_slot(child), pci_get_function(child));
return (0);
}
@@ -4855,10 +4856,60 @@ pci_assign_interrupt_method(device_t dev, device_t child)
cfg->intpin));
}
+static void
+pci_lookup(void *arg, const char *name, device_t *dev)
+{
+ long val;
+ char *end;
+ int domain, bus, slot, func;
+
+ if (*dev != NULL)
+ return;
+
+ /*
+ * Accept pciconf-style selectors of either pciD:B:S:F or
+ * pciB:S:F. In the latter case, the domain is assumed to
+ * be zero.
+ */
+ if (strncmp(name, "pci", 3) != 0)
+ return;
+ val = strtol(name + 3, &end, 10);
+ if (val < 0 || val > INT_MAX || *end != ':')
+ return;
+ domain = val;
+ val = strtol(end + 1, &end, 10);
+ if (val < 0 || val > INT_MAX || *end != ':')
+ return;
+ bus = val;
+ val = strtol(end + 1, &end, 10);
+ if (val < 0 || val > INT_MAX)
+ return;
+ slot = val;
+ if (*end == ':') {
+ val = strtol(end + 1, &end, 10);
+ if (val < 0 || val > INT_MAX || *end != '\0')
+ return;
+ func = val;
+ } else if (*end == '\0') {
+ func = slot;
+ slot = bus;
+ bus = domain;
+ domain = 0;
+ } else
+ return;
+
+ if (domain > PCI_DOMAINMAX || bus > PCI_BUSMAX || slot > PCI_SLOTMAX ||
+ func > PCIE_ARI_FUNCMAX || (slot != 0 && func > PCI_FUNCMAX))
+ return;
+
+ *dev = pci_find_dbsf(domain, bus, slot, func);
+}
+
static int
pci_modevent(module_t mod, int what, void *arg)
{
static struct cdev *pci_cdev;
+ static eventhandler_tag tag;
switch (what) {
case MOD_LOAD:
@@ -4867,9 +4918,13 @@ pci_modevent(module_t mod, int what, void *arg)
pci_cdev = make_dev(&pcicdev, 0, UID_ROOT, GID_WHEEL, 0644,
"pci");
pci_load_vendor_data();
+ tag = EVENTHANDLER_REGISTER(dev_lookup, pci_lookup, NULL,
+ 1000);
break;
case MOD_UNLOAD:
+ if (tag != NULL)
+ EVENTHANDLER_DEREGISTER(dev_lookup, tag);
destroy_dev(pci_cdev);
break;
}
diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c
index 288be908d1b9..72d3fe94d5dc 100644
--- a/sys/i386/i386/mp_machdep.c
+++ b/sys/i386/i386/mp_machdep.c
@@ -1138,14 +1138,27 @@ ipi_startup(int apic_id, int vector)
{
/*
+ * This attempts to follow the algorithm described in the
+ * Intel Multiprocessor Specification v1.4 in section B.4.
+ * For each IPI, we allow the local APIC ~20us to deliver the
+ * IPI. If that times out, we panic.
+ */
+
+ /*
* first we do an INIT IPI: this INIT IPI might be run, resetting
* and running the target CPU. OR this INIT IPI might be latched (P5
* bug), CPU waiting for STARTUP IPI. OR this INIT IPI might be
* ignored.
*/
- lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
+ lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_LEVEL |
APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT, apic_id);
- lapic_ipi_wait(-1);
+ lapic_ipi_wait(20);
+
+ /* Explicitly deassert the INIT IPI. */
+ lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_LEVEL |
+ APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT,
+ apic_id);
+
DELAY(10000); /* wait ~10mS */
/*
@@ -1157,9 +1170,11 @@ ipi_startup(int apic_id, int vector)
* will run.
*/
lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
- APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
+ APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
vector, apic_id);
- lapic_ipi_wait(-1);
+ if (!lapic_ipi_wait(20))
+ panic("Failed to deliver first STARTUP IPI to APIC %d",
+ apic_id);
DELAY(200); /* wait ~200uS */
/*
@@ -1169,9 +1184,12 @@ ipi_startup(int apic_id, int vector)
* recognized after hardware RESET or INIT IPI.
*/
lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
- APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
+ APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
vector, apic_id);
- lapic_ipi_wait(-1);
+ if (!lapic_ipi_wait(20))
+ panic("Failed to deliver second STARTUP IPI to APIC %d",
+ apic_id);
+
DELAY(200); /* wait ~200uS */
}
diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c
index a875e4b77aff..1c7b21ca7d9e 100644
--- a/sys/kern/subr_bus.c
+++ b/sys/kern/subr_bus.c
@@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/poll.h>
+#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/condvar.h>
#include <sys/queue.h>
@@ -128,15 +129,6 @@ struct device {
device_state_t state; /**< current device state */
uint32_t devflags; /**< api level flags for device_get_flags() */
u_int flags; /**< internal device flags */
-#define DF_ENABLED 0x01 /* device should be probed/attached */
-#define DF_FIXEDCLASS 0x02 /* devclass specified at create time */
-#define DF_WILDCARD 0x04 /* unit was originally wildcard */
-#define DF_DESCMALLOCED 0x08 /* description was malloced */
-#define DF_QUIET 0x10 /* don't print verbose attach message */
-#define DF_DONENOMATCH 0x20 /* don't execute DEVICE_NOMATCH again */
-#define DF_EXTERNALSOFTC 0x40 /* softc not allocated by us */
-#define DF_REBID 0x80 /* Can rebid after attach */
-#define DF_SUSPENDED 0x100 /* Device is suspended. */
u_int order; /**< order from device_add_child_ordered() */
void *ivars; /**< instance variables */
void *softc; /**< current driver's variables */
@@ -148,6 +140,8 @@ struct device {
static MALLOC_DEFINE(M_BUS, "bus", "Bus data structures");
static MALLOC_DEFINE(M_BUS_SC, "bus-sc", "Bus data structures, softc");
+static void devctl2_init(void);
+
#ifdef BUS_DEBUG
static int bus_debug = 1;
@@ -432,6 +426,7 @@ devinit(void)
cv_init(&devsoftc.cv, "dev cv");
TAILQ_INIT(&devsoftc.devq);
knlist_init_mtx(&devsoftc.sel.si_note, &devsoftc.mtx);
+ devctl2_init();
}
static int
@@ -2648,6 +2643,15 @@ device_is_attached(device_t dev)
}
/**
+ * @brief Return non-zero if the device is currently suspended.
+ */
+int
+device_is_suspended(device_t dev)
+{
+ return ((dev->flags & DF_SUSPENDED) != 0);
+}
+
+/**
* @brief Set the devclass of a device
* @see devclass_add_device().
*/
@@ -5031,3 +5035,253 @@ bus_free_resource(device_t dev, int type, struct resource *r)
return (0);
return (bus_release_resource(dev, type, rman_get_rid(r), r));
}
+
+/*
+ * /dev/devctl2 implementation. The existing /dev/devctl device has
+ * implicit semantics on open, so it could not be reused for this.
+ * Another option would be to call this /dev/bus?
+ */
+static int
+find_device(struct devreq *req, device_t *devp)
+{
+ device_t dev;
+
+ /*
+ * First, ensure that the name is nul terminated.
+ */
+ if (memchr(req->dr_name, '\0', sizeof(req->dr_name)) == NULL)
+ return (EINVAL);
+
+ /*
+ * Second, try to find an attached device whose name matches
+ * 'name'.
+ */
+ TAILQ_FOREACH(dev, &bus_data_devices, devlink) {
+ if (dev->nameunit != NULL &&
+ strcmp(dev->nameunit, req->dr_name) == 0) {
+ *devp = dev;
+ return (0);
+ }
+ }
+
+ /* Finally, give device enumerators a chance. */
+ dev = NULL;
+ EVENTHANDLER_INVOKE(dev_lookup, req->dr_name, &dev);
+ if (dev == NULL)
+ return (ENOENT);
+ *devp = dev;
+ return (0);
+}
+
+static bool
+driver_exists(struct device *bus, const char *driver)
+{
+ devclass_t dc;
+
+ for (dc = bus->devclass; dc != NULL; dc = dc->parent) {
+ if (devclass_find_driver_internal(dc, driver) != NULL)
+ return (true);
+ }
+ return (false);
+}
+
+static int
+devctl2_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
+ struct thread *td)
+{
+ struct devreq *req;
+ device_t dev;
+ int error, old;
+
+ /* Locate the device to control. */
+ mtx_lock(&Giant);
+ req = (struct devreq *)data;
+ switch (cmd) {
+ case DEV_ATTACH:
+ case DEV_DETACH:
+ case DEV_ENABLE:
+ case DEV_DISABLE:
+ case DEV_SUSPEND:
+ case DEV_RESUME:
+ case DEV_SET_DRIVER:
+ error = priv_check(td, PRIV_DRIVER);
+ if (error == 0)
+ error = find_device(req, &dev);
+ break;
+ default:
+ error = ENOTTY;
+ break;
+ }
+ if (error) {
+ mtx_unlock(&Giant);
+ return (error);
+ }
+
+ /* Perform the requested operation. */
+ switch (cmd) {
+ case DEV_ATTACH:
+ if (device_is_attached(dev) && (dev->flags & DF_REBID) == 0)
+ error = EBUSY;
+ else if (!device_is_enabled(dev))
+ error = ENXIO;
+ else
+ error = device_probe_and_attach(dev);
+ break;
+ case DEV_DETACH:
+ if (!device_is_attached(dev)) {
+ error = ENXIO;
+ break;
+ }
+ if (!(req->dr_flags & DEVF_FORCE_DETACH)) {
+ error = device_quiesce(dev);
+ if (error)
+ break;
+ }
+ error = device_detach(dev);
+ break;
+ case DEV_ENABLE:
+ if (device_is_enabled(dev)) {
+ error = EBUSY;
+ break;
+ }
+
+ /*
+ * If the device has been probed but not attached (e.g.
+ * when it has been disabled by a loader hint), just
+ * attach the device rather than doing a full probe.
+ */
+ device_enable(dev);
+ if (device_is_alive(dev)) {
+ /*
+ * If the device was disabled via a hint, clear
+ * the hint.
+ */
+ if (resource_disabled(dev->driver->name, dev->unit))
+ resource_unset_value(dev->driver->name,
+ dev->unit, "disabled");
+ error = device_attach(dev);
+ } else
+ error = device_probe_and_attach(dev);
+ break;
+ case DEV_DISABLE:
+ if (!device_is_enabled(dev)) {
+ error = ENXIO;
+ break;
+ }
+
+ if (!(req->dr_flags & DEVF_FORCE_DETACH)) {
+ error = device_quiesce(dev);
+ if (error)
+ break;
+ }
+
+ /*
+ * Force DF_FIXEDCLASS on around detach to preserve
+ * the existing name.
+ */
+ old = dev->flags;
+ dev->flags |= DF_FIXEDCLASS;
+ error = device_detach(dev);
+ if (!(old & DF_FIXEDCLASS))
+ dev->flags &= ~DF_FIXEDCLASS;
+ if (error == 0)
+ device_disable(dev);
+ break;
+ case DEV_SUSPEND:
+ if (device_is_suspended(dev)) {
+ error = EBUSY;
+ break;
+ }
+ if (device_get_parent(dev) == NULL) {
+ error = EINVAL;
+ break;
+ }
+ error = BUS_SUSPEND_CHILD(device_get_parent(dev), dev);
+ break;
+ case DEV_RESUME:
+ if (!device_is_suspended(dev)) {
+ error = EINVAL;
+ break;
+ }
+ if (device_get_parent(dev) == NULL) {
+ error = EINVAL;
+ break;
+ }
+ error = BUS_RESUME_CHILD(device_get_parent(dev), dev);
+ break;
+ case DEV_SET_DRIVER: {
+ devclass_t dc;
+ char driver[128];
+
+ error = copyinstr(req->dr_data, driver, sizeof(driver), NULL);
+ if (error)
+ break;
+ if (driver[0] == '\0') {
+ error = EINVAL;
+ break;
+ }
+ if (dev->devclass != NULL &&
+ strcmp(driver, dev->devclass->name) == 0)
+ /* XXX: Could possibly force DF_FIXEDCLASS on? */
+ break;
+
+ /*
+ * Scan drivers for this device's bus looking for at
+ * least one matching driver.
+ */
+ if (dev->parent == NULL) {
+ error = EINVAL;
+ break;
+ }
+ if (!driver_exists(dev->parent, driver)) {
+ error = ENOENT;
+ break;
+ }
+ dc = devclass_create(driver);
+ if (dc == NULL) {
+ error = ENOMEM;
+ break;
+ }
+
+ /* Detach device if necessary. */
+ if (device_is_attached(dev)) {
+ if (req->dr_flags & DEVF_SET_DRIVER_DETACH)
+ error = device_detach(dev);
+ else
+ error = EBUSY;
+ if (error)
+ break;
+ }
+
+ /* Clear any previously-fixed device class and unit. */
+ if (dev->flags & DF_FIXEDCLASS)
+ devclass_delete_device(dev->devclass, dev);
+ dev->flags |= DF_WILDCARD;
+ dev->unit = -1;
+
+ /* Force the new device class. */
+ error = devclass_add_device(dc, dev);
+ if (error)
+ break;
+ dev->flags |= DF_FIXEDCLASS;
+ error = device_probe_and_attach(dev);
+ break;
+ }
+ }
+ mtx_unlock(&Giant);
+ return (error);
+}
+
+static struct cdevsw devctl2_cdevsw = {
+ .d_version = D_VERSION,
+ .d_ioctl = devctl2_ioctl,
+ .d_name = "devctl2",
+};
+
+static void
+devctl2_init(void)
+{
+
+ make_dev_credf(MAKEDEV_ETERNAL, &devctl2_cdevsw, 0, NULL,
+ UID_ROOT, GID_WHEEL, 0600, "devctl2");
+}
diff --git a/sys/kern/subr_hints.c b/sys/kern/subr_hints.c
index 25838ee34136..00cfbf1bfb88 100644
--- a/sys/kern/subr_hints.c
+++ b/sys/kern/subr_hints.c
@@ -461,3 +461,31 @@ resource_disabled(const char *name, int unit)
return (0);
return (value);
}
+
+/*
+ * Clear a value associated with a device by removing it from
+ * the kernel environment. This only removes a hint for an
+ * exact unit.
+ */
+int
+resource_unset_value(const char *name, int unit, const char *resname)
+{
+ char varname[128];
+ const char *retname, *retvalue;
+ int error, line;
+ size_t len;
+
+ line = 0;
+ error = resource_find(&line, NULL, name, &unit, resname, NULL,
+ &retname, NULL, NULL, NULL, NULL, &retvalue);
+ if (error)
+ return (error);
+
+ retname -= strlen("hint.");
+ len = retvalue - retname - 1;
+ if (len > sizeof(varname) - 1)
+ return (ENAMETOOLONG);
+ memcpy(varname, retname, len);
+ varname[len] = '\0';
+ return (kern_unsetenv(varname));
+}
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 7498dab0792a..7f917d6e5c6a 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -735,6 +735,8 @@ _zfs= zfs
.endif
+SUBDIR+=${MODULES_EXTRA}
+
.for reject in ${WITHOUT_MODULES}
SUBDIR:= ${SUBDIR:N${reject}}
.endfor
diff --git a/sys/modules/cxgbe/Makefile b/sys/modules/cxgbe/Makefile
index f7862b5cd722..a46850c1afcf 100644
--- a/sys/modules/cxgbe/Makefile
+++ b/sys/modules/cxgbe/Makefile
@@ -6,6 +6,7 @@ SYSDIR?=${.CURDIR}/../..
.include "${SYSDIR}/conf/kern.opts.mk"
SUBDIR= if_cxgbe
+SUBDIR+= if_cxl
SUBDIR+= t4_firmware
SUBDIR+= t5_firmware
SUBDIR+= ${_tom}
diff --git a/sys/modules/cxgbe/if_cxl/Makefile b/sys/modules/cxgbe/if_cxl/Makefile
new file mode 100644
index 000000000000..ec4ff1ed1802
--- /dev/null
+++ b/sys/modules/cxgbe/if_cxl/Makefile
@@ -0,0 +1,11 @@
+#
+# $FreeBSD$
+#
+
+CXGBE= ${.CURDIR}/../../../dev/cxgbe
+.PATH: ${CXGBE}
+
+KMOD= if_cxl
+SRCS= if_cxl.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/dtb/rpi/Makefile b/sys/modules/dtb/rpi/Makefile
new file mode 100644
index 000000000000..9ea76638bd52
--- /dev/null
+++ b/sys/modules/dtb/rpi/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD$
+# DTS files for the Raspberry Pi-B
+DTS=rpi.dts
+
+.include <bsd.dtb.mk>
diff --git a/sys/sys/bus.h b/sys/sys/bus.h
index b15a5568200b..d6dc53585eba 100644
--- a/sys/sys/bus.h
+++ b/sys/sys/bus.h
@@ -31,6 +31,7 @@
#include <machine/_limits.h>
#include <sys/_bus_dma.h>
+#include <sys/ioccom.h>
/**
* @defgroup NEWBUS newbus - a generic framework for managing devices
@@ -70,14 +71,61 @@ struct u_device {
char dv_pnpinfo[128]; /**< @brief Plug and play info */
char dv_location[128]; /**< @brief Where is the device? */
uint32_t dv_devflags; /**< @brief API Flags for device */
- uint16_t dv_flags; /**< @brief flags for dev date */
+ uint16_t dv_flags; /**< @brief flags for dev state */
device_state_t dv_state; /**< @brief State of attachment */
/* XXX more driver info? */
};
+/* Flags exported via dv_flags. */
+#define DF_ENABLED 0x01 /* device should be probed/attached */
+#define DF_FIXEDCLASS 0x02 /* devclass specified at create time */
+#define DF_WILDCARD 0x04 /* unit was originally wildcard */
+#define DF_DESCMALLOCED 0x08 /* description was malloced */
+#define DF_QUIET 0x10 /* don't print verbose attach message */
+#define DF_DONENOMATCH 0x20 /* don't execute DEVICE_NOMATCH again */
+#define DF_EXTERNALSOFTC 0x40 /* softc not allocated by us */
+#define DF_REBID 0x80 /* Can rebid after attach */
+#define DF_SUSPENDED 0x100 /* Device is suspended. */
+
+/**
+ * @brief Device request structure used for ioctl's.
+ *
+ * Used for ioctl's on /dev/devctl2. All device ioctl's
+ * must have parameter definitions which begin with dr_name.
+ */
+struct devreq_buffer {
+ void *buffer;
+ size_t length;
+};
+
+struct devreq {
+ char dr_name[128];
+ int dr_flags; /* request-specific flags */
+ union {
+ struct devreq_buffer dru_buffer;
+ void *dru_data;
+ } dr_dru;
+#define dr_buffer dr_dru.dru_buffer /* variable-sized buffer */
+#define dr_data dr_dru.dru_data /* fixed-size buffer */
+};
+
+#define DEV_ATTACH _IOW('D', 1, struct devreq)
+#define DEV_DETACH _IOW('D', 2, struct devreq)
+#define DEV_ENABLE _IOW('D', 3, struct devreq)
+#define DEV_DISABLE _IOW('D', 4, struct devreq)
+#define DEV_SUSPEND _IOW('D', 5, struct devreq)
+#define DEV_RESUME _IOW('D', 6, struct devreq)
+#define DEV_SET_DRIVER _IOW('D', 7, struct devreq)
+
+/* Flags for DEV_DETACH and DEV_DISABLE. */
+#define DEVF_FORCE_DETACH 0x0000001
+
+/* Flags for DEV_SET_DRIVER. */
+#define DEVF_SET_DRIVER_DETACH 0x0000001 /* Detach existing driver. */
+
#ifdef _KERNEL
-#include <sys/queue.h>
+#include <sys/eventhandler.h>
#include <sys/kobj.h>
/**
@@ -94,6 +142,14 @@ void devctl_queue_data_f(char *__data, int __flags);
void devctl_queue_data(char *__data);
/**
+ * Device name parsers. Hook to allow device enumerators to map
+ * scheme-specific names to a device.
+ */
+typedef void (*dev_lookup_fn)(void *arg, const char *name,
+ device_t *result);
+EVENTHANDLER_DECLARE(dev_lookup, dev_lookup_fn);
+
+/**
* @brief A device driver (included mainly for compatibility with
* FreeBSD 4.x).
*/
@@ -454,6 +510,7 @@ struct sysctl_oid *device_get_sysctl_tree(device_t dev);
int device_is_alive(device_t dev); /* did probe succeed? */
int device_is_attached(device_t dev); /* did attach succeed? */
int device_is_enabled(device_t dev);
+int device_is_suspended(device_t dev);
int device_is_quiet(device_t dev);
int device_print_prettyname(device_t dev);
int device_printf(device_t dev, const char *, ...) __printflike(2, 3);
@@ -517,6 +574,8 @@ int resource_set_long(const char *name, int unit, const char *resname,
long value);
int resource_set_string(const char *name, int unit, const char *resname,
const char *value);
+int resource_unset_value(const char *name, int unit, const char *resname);
+
/*
* Functions for maintaining and checking consistency of
* bus information exported to userspace.
diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c
index e3228ce34952..080822b29fd4 100644
--- a/sys/x86/x86/local_apic.c
+++ b/sys/x86/x86/local_apic.c
@@ -1452,22 +1452,22 @@ SYSINIT(apic_setup_io, SI_SUB_INTR, SI_ORDER_THIRD, apic_setup_io, NULL);
static int
native_lapic_ipi_wait(int delay)
{
- int x, incr;
+ int x;
/*
- * Wait delay loops for IPI to be sent. This is highly bogus
- * since this is sensitive to CPU clock speed. If delay is
+ * Wait delay microseconds for IPI to be sent. If delay is
* -1, we wait forever.
*/
if (delay == -1) {
- incr = 0;
- delay = 1;
- } else
- incr = 1;
- for (x = 0; x < delay; x += incr) {
+ while ((lapic->icr_lo & APIC_DELSTAT_MASK) != APIC_DELSTAT_IDLE)
+ ia32_pause();
+ return (1);
+ }
+
+ for (x = 0; x < delay; x += 5) {
if ((lapic->icr_lo & APIC_DELSTAT_MASK) == APIC_DELSTAT_IDLE)
return (1);
- ia32_pause();
+ DELAY(5);
}
return (0);
}
@@ -1501,9 +1501,9 @@ native_lapic_ipi_raw(register_t icrlo, u_int dest)
intr_restore(saveintr);
}
-#define BEFORE_SPIN 1000000
+#define BEFORE_SPIN 50000
#ifdef DETECT_DEADLOCK
-#define AFTER_SPIN 1000
+#define AFTER_SPIN 50
#endif
static void
@@ -1514,7 +1514,7 @@ native_lapic_ipi_vectored(u_int vector, int dest)
KASSERT((vector & ~APIC_VECTOR_MASK) == 0,
("%s: invalid vector %d", __func__, vector));
- icrlo = APIC_DESTMODE_PHY | APIC_TRIGMOD_EDGE;
+ icrlo = APIC_DESTMODE_PHY | APIC_TRIGMOD_EDGE | APIC_LEVEL_ASSERT;
/*
* IPI_STOP_HARD is just a "fake" vector used to send a NMI.
@@ -1522,9 +1522,9 @@ native_lapic_ipi_vectored(u_int vector, int dest)
* the vector.
*/
if (vector == IPI_STOP_HARD)
- icrlo |= APIC_DELMODE_NMI | APIC_LEVEL_ASSERT;
+ icrlo |= APIC_DELMODE_NMI;
else
- icrlo |= vector | APIC_DELMODE_FIXED | APIC_LEVEL_DEASSERT;
+ icrlo |= vector | APIC_DELMODE_FIXED;
destfield = 0;
switch (dest) {
case APIC_IPI_DEST_SELF:
diff --git a/tools/tools/makeroot/makeroot.8 b/tools/tools/makeroot/makeroot.8
index 379187c910dd..0ba3fdcad05c 100644
--- a/tools/tools/makeroot/makeroot.8
+++ b/tools/tools/makeroot/makeroot.8
@@ -41,6 +41,7 @@
.Op Fl e Ar extras-manifest
.Op Fl f Ar filelist
.Op Fl k Ar keydir Op Fl K Ar user
+.Op Fl l Ar label
.Op Fl p Ar master.passwd Op Fl g Ar group
.Op Fl s Ar size
.Ar image-file
@@ -94,6 +95,8 @@ If no
.Fl K
argument is supplied then the files will be installed in the root user's
directory.
+.It Fl l Ar label
+Set the file system volume label.
.It Fl p Ar master.passwd Op Fl g Ar group
Install an alternate
.Ar master.passwd
diff --git a/tools/tools/makeroot/makeroot.sh b/tools/tools/makeroot/makeroot.sh
index 1ef376b3c13b..a1e669766bf0 100755
--- a/tools/tools/makeroot/makeroot.sh
+++ b/tools/tools/makeroot/makeroot.sh
@@ -75,7 +75,7 @@ KEYDIR=
KEYUSERS=
PASSWD=
-while getopts "B:de:f:g:K:k:p:s:" opt; do
+while getopts "B:de:f:g:K:k:l:p:s:" opt; do
case "$opt" in
B) BFLAG="-B ${OPTARG}" ;;
d) DEBUG=1 ;;
@@ -84,6 +84,7 @@ while getopts "B:de:f:g:K:k:p:s:" opt; do
g) GROUP="${OPTARG}" ;;
K) KEYUSERS="${KEYUSERS} ${OPTARG}" ;;
k) KEYDIR="${OPTARG}" ;;
+ l) LABEL="${OPTARG}" ;;
p) PASSWD="${OPTARG}" ;;
s) SIZE="${OPTARG}" ;;
*) usage ;;
@@ -165,13 +166,15 @@ if [ -n "${FILELIST}" ]; then
awk '
!/ type=/ { file = $1 }
/ type=/ { if ($1 == file) {print} }' >> ${manifest}
-else
+elif [ -n "${EXTRAS}" ]; then
# Start with all the files in BSDROOT/METALOG except those in
# one of the EXTRAS manifests.
grep -h type=file ${EXTRAS} | cut -d' ' -f1 | \
sort -u ${BSDROOT}/METALOG - | awk '
!/ type=/ { file = $1 }
/ type=/ { if ($1 != file) {print} }' >> ${manifest}
+else
+ sort -u ${BSDROOT}/METALOG >> ${manifest}
fi
# For each extras file, add contents keys relative to the directory the
@@ -228,9 +231,12 @@ if [ -n "${KEYDIR}" ]; then
done
fi
+if [ -n "${LABEL}" ]; then
+LABELFLAG="-o label=${LABEL}"
+fi
if [ -n "${SIZE}" ]; then
SIZEFLAG="-s ${SIZE}"
fi
cd ${BSDROOT}; makefs ${DUPFLAG} -N ${DBDIR} ${SIZEFLAG} ${BFLAG} \
- -t ffs -f 256 ${IMGFILE} ${manifest}
+ -t ffs ${LABELFLAG} -f 256 ${IMGFILE} ${manifest}
diff --git a/usr.bin/ktrdump/ktrdump.8 b/usr.bin/ktrdump/ktrdump.8
index 697e418479fb..8dade5598ea2 100644
--- a/usr.bin/ktrdump/ktrdump.8
+++ b/usr.bin/ktrdump/ktrdump.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 8, 2005
+.Dd February 6, 2015
.Dt KTRDUMP 8
.Os
.Sh NAME
@@ -34,9 +34,9 @@
.Sh SYNOPSIS
.Nm
.Op Fl cfqrtH
-.Op Fl e Ar execfile
.Op Fl i Ar ktrfile
-.Op Fl m Ar corefile
+.Op Fl M Ar core
+.Op Fl N Ar system
.Op Fl o Ar outfile
.Sh DESCRIPTION
The
@@ -44,7 +44,7 @@ The
utility is used to dump the contents of the kernel ktr trace buffer.
.Pp
The following options are available:
-.Bl -tag -width ".Fl e Ar execfile"
+.Bl -tag -width ".Fl i Ar ktrfile"
.It Fl c
Print the CPU number that each entry was logged from.
.It Fl f
@@ -61,11 +61,11 @@ Print the thread ID for each entry.
File containing saved ktr trace events; for more information see the
.Xr ktr 4
manual page.
-.It Fl e Ar execfile
+.It Fl N Ar system
The kernel image to resolve symbols from.
The default is the value returned via
.Xr getbootfile 3 .
-.It Fl m Ar corefile
+.It Fl M Ar core
The core file or memory image to read from.
The default is
.Pa /dev/mem .
diff --git a/usr.bin/ktrdump/ktrdump.c b/usr.bin/ktrdump/ktrdump.c
index 11e78e92bf8b..84ab3a837fba 100644
--- a/usr.bin/ktrdump/ktrdump.c
+++ b/usr.bin/ktrdump/ktrdump.c
@@ -46,7 +46,7 @@ __FBSDID("$FreeBSD$");
#define SBUFLEN 128
#define USAGE \
- "usage: ktrdump [-cfqrtH] [-e execfile] [-i ktrfile] [-m corefile] [-o outfile]\n"
+ "usage: ktrdump [-cfqrtH] [-i ktrfile] [-M core] [-N system] [-o outfile]\n"
static void usage(void);
@@ -59,9 +59,9 @@ static struct nlist nl[] = {
};
static int cflag;
-static int eflag;
static int fflag;
-static int mflag;
+static int Mflag;
+static int Nflag;
static int qflag;
static int rflag;
static int tflag;
@@ -103,16 +103,17 @@ main(int ac, char **av)
* Parse commandline arguments.
*/
out = stdout;
- while ((c = getopt(ac, av, "cfqrtHe:i:m:o:")) != -1)
+ while ((c = getopt(ac, av, "cfqrtHe:i:m:M:N:o:")) != -1)
switch (c) {
case 'c':
cflag = 1;
break;
+ case 'N':
case 'e':
if (strlcpy(execfile, optarg, sizeof(execfile))
>= sizeof(execfile))
errx(1, "%s: File name too long", optarg);
- eflag = 1;
+ Nflag = 1;
break;
case 'f':
fflag = 1;
@@ -122,11 +123,12 @@ main(int ac, char **av)
if ((in = open(optarg, O_RDONLY)) == -1)
err(1, "%s", optarg);
break;
+ case 'M':
case 'm':
if (strlcpy(corefile, optarg, sizeof(corefile))
>= sizeof(corefile))
errx(1, "%s: File name too long", optarg);
- mflag = 1;
+ Mflag = 1;
break;
case 'o':
if ((out = fopen(optarg, "w")) == NULL)
@@ -157,8 +159,8 @@ main(int ac, char **av)
* Open our execfile and corefile, resolve needed symbols and read in
* the trace buffer.
*/
- if ((kd = kvm_openfiles(eflag ? execfile : NULL,
- mflag ? corefile : NULL, NULL, O_RDONLY, errbuf)) == NULL)
+ if ((kd = kvm_openfiles(Nflag ? execfile : NULL,
+ Mflag ? corefile : NULL, NULL, O_RDONLY, errbuf)) == NULL)
errx(1, "%s", errbuf);
if (kvm_nlist(kd, nl) != 0 ||
kvm_read(kd, nl[0].n_value, &version, sizeof(version)) == -1)
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index 918678b8cbb1..30d843dfbd59 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -19,6 +19,7 @@ SUBDIR= adduser \
ctld \
daemon \
dconschat \
+ devctl \
devinfo \
digictl \
diskinfo \
diff --git a/usr.sbin/ctladm/ctladm.c b/usr.sbin/ctladm/ctladm.c
index f2e933a77cc1..aefba042aa54 100644
--- a/usr.sbin/ctladm/ctladm.c
+++ b/usr.sbin/ctladm/ctladm.c
@@ -3439,6 +3439,7 @@ struct cctl_islist_conn {
char *header_digest;
char *data_digest;
char *max_data_segment_length;;
+ char *offload;;
int immediate_data;
int iser;
STAILQ_ENTRY(cctl_islist_conn) links;
@@ -3552,6 +3553,9 @@ cctl_islist_end_element(void *user_data, const char *name)
} else if (strcmp(name, "max_data_segment_length") == 0) {
cur_conn->max_data_segment_length = str;
str = NULL;
+ } else if (strcmp(name, "offload") == 0) {
+ cur_conn->offload = str;
+ str = NULL;
} else if (strcmp(name, "immediate_data") == 0) {
cur_conn->immediate_data = atoi(str);
} else if (strcmp(name, "iser") == 0) {
@@ -3559,8 +3563,12 @@ cctl_islist_end_element(void *user_data, const char *name)
} else if (strcmp(name, "connection") == 0) {
islist->cur_conn = NULL;
} else if (strcmp(name, "ctlislist") == 0) {
- } else
- errx(1, "unknown element %s", name);
+ /* Nothing. */
+ } else {
+ /*
+ * Unknown element; ignore it for forward compatiblity.
+ */
+ }
free(str);
}
@@ -3668,6 +3676,7 @@ retry:
printf("DataSegmentLen: %s\n", conn->max_data_segment_length);
printf("ImmediateData: %s\n", conn->immediate_data ? "Yes" : "No");
printf("iSER (RDMA): %s\n", conn->iser ? "Yes" : "No");
+ printf("Offload driver: %s\n", conn->offload);
printf("\n");
}
} else {
diff --git a/usr.sbin/ctld/ctl.conf.5 b/usr.sbin/ctld/ctl.conf.5
index 789161f90bb8..404699829920 100644
--- a/usr.sbin/ctld/ctl.conf.5
+++ b/usr.sbin/ctld/ctl.conf.5
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 1, 2015
+.Dd February 6, 2015
.Dt CTL.CONF 5
.Os
.Sh NAME
@@ -66,7 +66,7 @@ file is:
.No target Ar name {
.Dl auth-group Ar name
-.Dl portal-group Ar name
+.Dl portal-group Ar name Op Ar agname
.Dl lun Ar number Ar name
.Dl lun Ar number No {
.Dl path Ar path
@@ -310,12 +310,17 @@ This clause is mutually exclusive with
.Sy auth-group ;
one cannot use
both in a single target.
-.It Ic portal-group Ar name
+.It Ic offload Ar driver
+Define iSCSI hardware offload driver to use for this target.
+.It Ic portal-group Ar name Op Ar agname
Assign a previously defined portal group to the target.
The default portal group is
.Qq Ar default ,
which makes the target available
on TCP port 3260 on all configured IPv4 and IPv6 addresses.
+Optional second argument specifies auth group name for connections
+to this specific portal group.
+If second argument is not specified, target auth group is used.
.It Ic redirect Aq Ar address
IPv4 or IPv6 address to redirect initiators to.
When configured, all initiators attempting to connect to this target
diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c
index c19b55a4c1d6..dd864b95d286 100644
--- a/usr.sbin/ctld/ctld.c
+++ b/usr.sbin/ctld/ctld.c
@@ -91,6 +91,7 @@ conf_new(void)
TAILQ_INIT(&conf->conf_luns);
TAILQ_INIT(&conf->conf_targets);
TAILQ_INIT(&conf->conf_auth_groups);
+ TAILQ_INIT(&conf->conf_ports);
TAILQ_INIT(&conf->conf_portal_groups);
TAILQ_INIT(&conf->conf_isns);
@@ -124,6 +125,7 @@ conf_delete(struct conf *conf)
portal_group_delete(pg);
TAILQ_FOREACH_SAFE(is, &conf->conf_isns, i_next, istmp)
isns_delete(is);
+ assert(TAILQ_EMPTY(&conf->conf_ports));
free(conf->conf_pidfile_path);
free(conf);
}
@@ -609,6 +611,7 @@ portal_group_new(struct conf *conf, const char *name)
log_err(1, "calloc");
pg->pg_name = checked_strdup(name);
TAILQ_INIT(&pg->pg_portals);
+ TAILQ_INIT(&pg->pg_ports);
pg->pg_conf = conf;
pg->pg_tag = 0; /* Assigned later in conf_apply(). */
TAILQ_INSERT_TAIL(&conf->conf_portal_groups, pg, pg_next);
@@ -620,7 +623,10 @@ void
portal_group_delete(struct portal_group *pg)
{
struct portal *portal, *tmp;
+ struct port *port, *tport;
+ TAILQ_FOREACH_SAFE(port, &pg->pg_ports, p_pgs, tport)
+ port_delete(port);
TAILQ_REMOVE(&pg->pg_conf->conf_portal_groups, pg, pg_next);
TAILQ_FOREACH_SAFE(portal, &pg->pg_portals, p_next, tmp)
@@ -784,6 +790,7 @@ isns_do_register(struct isns *isns, int s, const char *hostname)
struct target *target;
struct portal *portal;
struct portal_group *pg;
+ struct port *port;
struct isns_req *req;
int res = 0;
uint32_t error;
@@ -807,11 +814,14 @@ isns_do_register(struct isns *isns, int s, const char *hostname)
isns_req_add_32(req, 33, 1); /* 1 -- Target*/
if (target->t_alias != NULL)
isns_req_add_str(req, 34, target->t_alias);
- pg = target->t_portal_group;
- isns_req_add_32(req, 51, pg->pg_tag);
- TAILQ_FOREACH(portal, &pg->pg_portals, p_next) {
- isns_req_add_addr(req, 49, portal->p_ai);
- isns_req_add_port(req, 50, portal->p_ai);
+ TAILQ_FOREACH(port, &target->t_ports, p_ts) {
+ if ((pg = port->p_portal_group) == NULL)
+ continue;
+ isns_req_add_32(req, 51, pg->pg_tag);
+ TAILQ_FOREACH(portal, &pg->pg_portals, p_next) {
+ isns_req_add_addr(req, 49, portal->p_ai);
+ isns_req_add_port(req, 50, portal->p_ai);
+ }
}
}
res = isns_req_send(s, req);
@@ -1123,6 +1133,68 @@ valid_iscsi_name(const char *name)
return (true);
}
+struct port *
+port_new(struct conf *conf, struct target *target, struct portal_group *pg)
+{
+ struct port *port;
+
+ port = calloc(1, sizeof(*port));
+ if (port == NULL)
+ log_err(1, "calloc");
+ asprintf(&port->p_name, "%s-%s", pg->pg_name, target->t_name);
+ if (port_find(conf, port->p_name) != NULL) {
+ log_warnx("duplicate port \"%s\"", port->p_name);
+ free(port);
+ return (NULL);
+ }
+ port->p_conf = conf;
+ TAILQ_INSERT_TAIL(&conf->conf_ports, port, p_next);
+ TAILQ_INSERT_TAIL(&target->t_ports, port, p_ts);
+ port->p_target = target;
+ TAILQ_INSERT_TAIL(&pg->pg_ports, port, p_pgs);
+ port->p_portal_group = pg;
+ return (port);
+}
+
+struct port *
+port_find(const struct conf *conf, const char *name)
+{
+ struct port *port;
+
+ TAILQ_FOREACH(port, &conf->conf_ports, p_next) {
+ if (strcasecmp(port->p_name, name) == 0)
+ return (port);
+ }
+
+ return (NULL);
+}
+
+struct port *
+port_find_in_pg(const struct portal_group *pg, const char *target)
+{
+ struct port *port;
+
+ TAILQ_FOREACH(port, &pg->pg_ports, p_pgs) {
+ if (strcasecmp(port->p_target->t_name, target) == 0)
+ return (port);
+ }
+
+ return (NULL);
+}
+
+void
+port_delete(struct port *port)
+{
+
+ if (port->p_portal_group)
+ TAILQ_REMOVE(&port->p_portal_group->pg_ports, port, p_pgs);
+ if (port->p_target)
+ TAILQ_REMOVE(&port->p_target->t_ports, port, p_ts);
+ TAILQ_REMOVE(&port->p_conf->conf_ports, port, p_next);
+ free(port->p_name);
+ free(port);
+}
+
struct target *
target_new(struct conf *conf, const char *name)
{
@@ -1151,6 +1223,7 @@ target_new(struct conf *conf, const char *name)
targ->t_name[i] = tolower(targ->t_name[i]);
targ->t_conf = conf;
+ TAILQ_INIT(&targ->t_ports);
TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next);
return (targ);
@@ -1159,7 +1232,10 @@ target_new(struct conf *conf, const char *name)
void
target_delete(struct target *targ)
{
+ struct port *port, *tport;
+ TAILQ_FOREACH_SAFE(port, &targ->t_ports, p_ts, tport)
+ port_delete(port);
TAILQ_REMOVE(&targ->t_conf->conf_targets, targ, t_next);
free(targ->t_name);
@@ -1196,11 +1272,20 @@ target_set_redirection(struct target *target, const char *addr)
return (0);
}
-void
-target_set_ctl_port(struct target *target, uint32_t value)
+int
+target_set_offload(struct target *target, const char *offload)
{
- target->t_ctl_port = value;
+ if (target->t_offload != NULL) {
+ log_warnx("cannot set offload to \"%s\" for "
+ "target \"%s\"; already defined",
+ offload, target->t_name);
+ return (1);
+ }
+
+ target->t_offload = checked_strdup(offload);
+
+ return (0);
}
struct lun *
@@ -1445,6 +1530,8 @@ conf_print(struct conf *conf)
fprintf(stderr, "target %s {\n", targ->t_name);
if (targ->t_alias != NULL)
fprintf(stderr, "\t alias %s\n", targ->t_alias);
+ if (targ->t_offload != NULL)
+ fprintf(stderr, "\t offload %s\n", targ->t_offload);
fprintf(stderr, "}\n");
}
}
@@ -1508,6 +1595,7 @@ conf_verify(struct conf *conf)
{
struct auth_group *ag;
struct portal_group *pg;
+ struct port *port;
struct target *targ;
struct lun *lun;
bool found;
@@ -1527,10 +1615,10 @@ conf_verify(struct conf *conf)
"default");
assert(targ->t_auth_group != NULL);
}
- if (targ->t_portal_group == NULL) {
- targ->t_portal_group = portal_group_find(conf,
- "default");
- assert(targ->t_portal_group != NULL);
+ if (TAILQ_EMPTY(&targ->t_ports)) {
+ pg = portal_group_find(conf, "default");
+ assert(pg != NULL);
+ port_new(conf, targ, pg);
}
found = false;
for (i = 0; i < MAX_LUNS; i++) {
@@ -1558,20 +1646,14 @@ conf_verify(struct conf *conf)
if (pg->pg_discovery_filter == PG_FILTER_UNKNOWN)
pg->pg_discovery_filter = PG_FILTER_NONE;
- TAILQ_FOREACH(targ, &conf->conf_targets, t_next) {
- if (targ->t_portal_group == pg)
- break;
- }
- if (pg->pg_redirection != NULL) {
- if (targ != NULL) {
+ if (!TAILQ_EMPTY(&pg->pg_ports)) {
+ if (pg->pg_redirection != NULL) {
log_debugx("portal-group \"%s\" assigned "
- "to target \"%s\", but configured "
+ "to target, but configured "
"for redirection",
- pg->pg_name, targ->t_name);
+ pg->pg_name);
}
pg->pg_unassigned = false;
- } else if (targ != NULL) {
- pg->pg_unassigned = false;
} else {
if (strcmp(pg->pg_name, "default") != 0)
log_warnx("portal-group \"%s\" not assigned "
@@ -1592,6 +1674,12 @@ conf_verify(struct conf *conf)
break;
}
}
+ TAILQ_FOREACH(port, &conf->conf_ports, p_next) {
+ if (port->p_auth_group == ag) {
+ found = true;
+ break;
+ }
+ }
TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) {
if (pg->pg_discovery_auth_group == ag) {
found = true;
@@ -1613,10 +1701,10 @@ conf_verify(struct conf *conf)
static int
conf_apply(struct conf *oldconf, struct conf *newconf)
{
- struct target *oldtarg, *newtarg, *tmptarg;
struct lun *oldlun, *newlun, *tmplun;
struct portal_group *oldpg, *newpg;
struct portal *oldp, *newp;
+ struct port *oldport, *newport, *tmpport;
struct isns *oldns, *newns;
pid_t otherpid;
int changed, cumulated_error = 0, error, sockbuf;
@@ -1684,17 +1772,17 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
* really happen, so leave it as it is for now.
*/
/*
- * First, remove any targets present in the old configuration
+ * First, remove any ports present in the old configuration
* and missing in the new one.
*/
- TAILQ_FOREACH_SAFE(oldtarg, &oldconf->conf_targets, t_next, tmptarg) {
- newtarg = target_find(newconf, oldtarg->t_name);
- if (newtarg != NULL)
+ TAILQ_FOREACH_SAFE(oldport, &oldconf->conf_ports, p_next, tmpport) {
+ newport = port_find(newconf, oldport->p_name);
+ if (newport != NULL)
continue;
- error = kernel_port_remove(oldtarg);
+ error = kernel_port_remove(oldport);
if (error != 0) {
- log_warnx("failed to remove target %s",
- oldtarg->t_name);
+ log_warnx("failed to remove port %s",
+ oldport->p_name);
/*
* XXX: Uncomment after fixing the root cause.
*
@@ -1809,21 +1897,21 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
}
/*
- * Now add new targets or modify existing ones.
+ * Now add new ports or modify existing ones.
*/
- TAILQ_FOREACH(newtarg, &newconf->conf_targets, t_next) {
- oldtarg = target_find(oldconf, newtarg->t_name);
-
- if (oldtarg == NULL)
- error = kernel_port_add(newtarg);
- else {
- target_set_ctl_port(newtarg, oldtarg->t_ctl_port);
- error = kernel_port_update(newtarg);
+ TAILQ_FOREACH(newport, &newconf->conf_ports, p_next) {
+ oldport = port_find(oldconf, newport->p_name);
+
+ if (oldport == NULL) {
+ error = kernel_port_add(newport);
+ } else {
+ newport->p_ctl_port = oldport->p_ctl_port;
+ error = kernel_port_update(newport);
}
if (error != 0) {
- log_warnx("failed to %s target %s",
- (oldtarg == NULL) ? "add" : "update",
- newtarg->t_name);
+ log_warnx("failed to %s port %s",
+ (oldport == NULL) ? "add" : "update",
+ newport->p_name);
/*
* XXX: Uncomment after fixing the root cause.
*
diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h
index 251351d9b663..395b0144ae55 100644
--- a/usr.sbin/ctld/ctld.h
+++ b/usr.sbin/ctld/ctld.h
@@ -119,11 +119,25 @@ struct portal_group {
int pg_discovery_filter;
bool pg_unassigned;
TAILQ_HEAD(, portal) pg_portals;
+ TAILQ_HEAD(, port) pg_ports;
char *pg_redirection;
uint16_t pg_tag;
};
+struct port {
+ TAILQ_ENTRY(port) p_next;
+ TAILQ_ENTRY(port) p_pgs;
+ TAILQ_ENTRY(port) p_ts;
+ struct conf *p_conf;
+ char *p_name;
+ struct auth_group *p_auth_group;
+ struct portal_group *p_portal_group;
+ struct target *p_target;
+
+ uint32_t p_ctl_port;
+};
+
struct lun_option {
TAILQ_ENTRY(lun_option) lo_next;
struct lun *lo_lun;
@@ -152,12 +166,11 @@ struct target {
struct conf *t_conf;
struct lun *t_luns[MAX_LUNS];
struct auth_group *t_auth_group;
- struct portal_group *t_portal_group;
+ TAILQ_HEAD(, port) t_ports;
char *t_name;
char *t_alias;
+ char *t_offload;
char *t_redirection;
-
- uint32_t t_ctl_port;
};
struct isns {
@@ -172,6 +185,7 @@ struct conf {
TAILQ_HEAD(, lun) conf_luns;
TAILQ_HEAD(, target) conf_targets;
TAILQ_HEAD(, auth_group) conf_auth_groups;
+ TAILQ_HEAD(, port) conf_ports;
TAILQ_HEAD(, portal_group) conf_portal_groups;
TAILQ_HEAD(, isns) conf_isns;
int conf_isns_period;
@@ -199,6 +213,7 @@ struct conf {
struct connection {
struct portal *conn_portal;
+ struct port *conn_port;
struct target *conn_target;
int conn_socket;
int conn_session_type;
@@ -209,6 +224,7 @@ struct connection {
struct sockaddr_storage conn_initiator_sa;
uint32_t conn_cmdsn;
uint32_t conn_statsn;
+ size_t conn_data_segment_limit;
size_t conn_max_data_segment_length;
size_t conn_max_burst_length;
int conn_immediate_data;
@@ -317,14 +333,21 @@ void isns_register(struct isns *isns, struct isns *oldisns);
void isns_check(struct isns *isns);
void isns_deregister(struct isns *isns);
+struct port *port_new(struct conf *conf, struct target *target,
+ struct portal_group *pg);
+struct port *port_find(const struct conf *conf, const char *name);
+struct port *port_find_in_pg(const struct portal_group *pg,
+ const char *target);
+void port_delete(struct port *port);
+
struct target *target_new(struct conf *conf, const char *name);
void target_delete(struct target *target);
struct target *target_find(struct conf *conf,
const char *name);
int target_set_redirection(struct target *target,
const char *addr);
-void target_set_ctl_port(struct target *target,
- uint32_t value);
+int target_set_offload(struct target *target,
+ const char *offload);
struct lun *lun_new(struct conf *conf, const char *name);
void lun_delete(struct lun *lun);
@@ -351,9 +374,11 @@ int kernel_lun_add(struct lun *lun);
int kernel_lun_resize(struct lun *lun);
int kernel_lun_remove(struct lun *lun);
void kernel_handoff(struct connection *conn);
-int kernel_port_add(struct target *targ);
-int kernel_port_update(struct target *targ);
-int kernel_port_remove(struct target *targ);
+void kernel_limits(const char *offload,
+ size_t *max_data_segment_length);
+int kernel_port_add(struct port *port);
+int kernel_port_update(struct port *port);
+int kernel_port_remove(struct port *port);
void kernel_capsicate(void);
#ifdef ICL_KERNEL_PROXY
diff --git a/usr.sbin/ctld/discovery.c b/usr.sbin/ctld/discovery.c
index b370e0be5867..88ca64c96ba7 100644
--- a/usr.sbin/ctld/discovery.c
+++ b/usr.sbin/ctld/discovery.c
@@ -162,6 +162,7 @@ logout_new_response(struct pdu *request)
static void
discovery_add_target(struct keys *response_keys, const struct target *targ)
{
+ struct port *port;
struct portal *portal;
char *buf;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
@@ -169,7 +170,10 @@ discovery_add_target(struct keys *response_keys, const struct target *targ)
int ret;
keys_add(response_keys, "TargetName", targ->t_name);
- TAILQ_FOREACH(portal, &targ->t_portal_group->pg_portals, p_next) {
+ TAILQ_FOREACH(port, &targ->t_ports, p_ts) {
+ if (port->p_portal_group == NULL)
+ continue;
+ TAILQ_FOREACH(portal, &port->p_portal_group->pg_portals, p_next) {
ai = portal->p_ai;
ret = getnameinfo(ai->ai_addr, ai->ai_addrlen,
hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
@@ -183,13 +187,13 @@ discovery_add_target(struct keys *response_keys, const struct target *targ)
if (strcmp(hbuf, "0.0.0.0") == 0)
continue;
ret = asprintf(&buf, "%s:%s,%d", hbuf, sbuf,
- targ->t_portal_group->pg_tag);
+ port->p_portal_group->pg_tag);
break;
case AF_INET6:
if (strcmp(hbuf, "::") == 0)
continue;
ret = asprintf(&buf, "[%s]:%s,%d", hbuf, sbuf,
- targ->t_portal_group->pg_tag);
+ port->p_portal_group->pg_tag);
break;
default:
continue;
@@ -198,19 +202,24 @@ discovery_add_target(struct keys *response_keys, const struct target *targ)
log_err(1, "asprintf");
keys_add(response_keys, "TargetAddress", buf);
free(buf);
+ }
}
}
static bool
discovery_target_filtered_out(const struct connection *conn,
- const struct target *targ)
+ const struct port *port)
{
const struct auth_group *ag;
const struct portal_group *pg;
+ const struct target *targ;
const struct auth *auth;
int error;
- ag = targ->t_auth_group;
+ targ = port->p_target;
+ ag = port->p_auth_group;
+ if (ag == NULL)
+ ag = targ->t_auth_group;
pg = conn->conn_portal->p_portal_group;
assert(pg->pg_discovery_auth_group != PG_FILTER_UNKNOWN);
@@ -265,8 +274,8 @@ discovery(struct connection *conn)
{
struct pdu *request, *response;
struct keys *request_keys, *response_keys;
+ const struct port *port;
const struct portal_group *pg;
- const struct target *targ;
const char *send_targets;
pg = conn->conn_portal->p_portal_group;
@@ -284,29 +293,23 @@ discovery(struct connection *conn)
response_keys = keys_new();
if (strcmp(send_targets, "All") == 0) {
- TAILQ_FOREACH(targ, &pg->pg_conf->conf_targets, t_next) {
- if (targ->t_portal_group != pg) {
- log_debugx("not returning target \"%s\"; "
- "belongs to a different portal group",
- targ->t_name);
- continue;
- }
- if (discovery_target_filtered_out(conn, targ)) {
+ TAILQ_FOREACH(port, &pg->pg_ports, p_pgs) {
+ if (discovery_target_filtered_out(conn, port)) {
/* Ignore this target. */
continue;
}
- discovery_add_target(response_keys, targ);
+ discovery_add_target(response_keys, port->p_target);
}
} else {
- targ = target_find(pg->pg_conf, send_targets);
- if (targ == NULL) {
+ port = port_find_in_pg(pg, send_targets);
+ if (port == NULL) {
log_debugx("initiator requested information on unknown "
"target \"%s\"; returning nothing", send_targets);
} else {
- if (discovery_target_filtered_out(conn, targ)) {
+ if (discovery_target_filtered_out(conn, port)) {
/* Ignore this target. */
} else {
- discovery_add_target(response_keys, targ);
+ discovery_add_target(response_keys, port->p_target);
}
}
}
diff --git a/usr.sbin/ctld/kernel.c b/usr.sbin/ctld/kernel.c
index 0c5d2ce07306..47dc56aa3be3 100644
--- a/usr.sbin/ctld/kernel.c
+++ b/usr.sbin/ctld/kernel.c
@@ -121,9 +121,10 @@ struct cctl_lun {
struct cctl_port {
uint32_t port_id;
- int cfiscsi_status;
+ int cfiscsi_state;
char *cfiscsi_target;
uint16_t cfiscsi_portal_group_tag;
+ char *ctld_portal_group_name;
STAILQ_HEAD(,cctl_lun_nv) attr_list;
STAILQ_ENTRY(cctl_port) links;
};
@@ -332,10 +333,13 @@ cctl_end_pelement(void *user_data, const char *name)
if (strcmp(name, "cfiscsi_target") == 0) {
cur_port->cfiscsi_target = str;
str = NULL;
- } else if (strcmp(name, "cfiscsi_status") == 0) {
- cur_port->cfiscsi_status = strtoul(str, NULL, 0);
+ } else if (strcmp(name, "cfiscsi_state") == 0) {
+ cur_port->cfiscsi_state = strtoul(str, NULL, 0);
} else if (strcmp(name, "cfiscsi_portal_group_tag") == 0) {
cur_port->cfiscsi_portal_group_tag = strtoul(str, NULL, 0);
+ } else if (strcmp(name, "ctld_portal_group_name") == 0) {
+ cur_port->ctld_portal_group_name = str;
+ str = NULL;
} else if (strcmp(name, "targ_port") == 0) {
devlist->cur_port = NULL;
} else if (strcmp(name, "ctlportlist") == 0) {
@@ -373,6 +377,8 @@ conf_new_from_kernel(void)
{
struct conf *conf = NULL;
struct target *targ;
+ struct portal_group *pg;
+ struct port *cp;
struct lun *cl;
struct lun_option *lo;
struct ctl_lun_list list;
@@ -496,9 +502,9 @@ retry_port:
"ignoring", (uintmax_t)port->port_id);
continue;
}
- if (port->cfiscsi_status != 1) {
+ if (port->cfiscsi_state != 1) {
log_debugx("CTL port %ju is not active (%d); ignoring",
- (uintmax_t)port->port_id, port->cfiscsi_status);
+ (uintmax_t)port->port_id, port->cfiscsi_state);
continue;
}
@@ -514,6 +520,28 @@ retry_port:
continue;
}
}
+
+ if (port->ctld_portal_group_name == NULL)
+ continue;
+ pg = portal_group_find(conf, port->ctld_portal_group_name);
+ if (pg == NULL) {
+#if 0
+ log_debugx("found new kernel portal group %s for CTL port %ld",
+ port->ctld_portal_group_name, port->port_id);
+#endif
+ pg = portal_group_new(conf, port->ctld_portal_group_name);
+ if (pg == NULL) {
+ log_warnx("portal_group_new failed");
+ continue;
+ }
+ }
+ pg->pg_tag = port->cfiscsi_portal_group_tag;
+ cp = port_new(conf, targ, pg);
+ if (cp == NULL) {
+ log_warnx("port_new failed");
+ continue;
+ }
+ cp->p_ctl_port = port->port_id;
}
STAILQ_FOREACH(lun, &devlist.lun_list, links) {
@@ -771,6 +799,10 @@ kernel_handoff(struct connection *conn)
sizeof(req.data.handoff.initiator_isid));
strlcpy(req.data.handoff.target_name,
conn->conn_target->t_name, sizeof(req.data.handoff.target_name));
+ if (conn->conn_target->t_offload != NULL) {
+ strlcpy(req.data.handoff.offload,
+ conn->conn_target->t_offload, sizeof(req.data.handoff.offload));
+ }
#ifdef ICL_KERNEL_PROXY
if (proxy_mode)
req.data.handoff.connection_id = conn->conn_socket;
@@ -803,33 +835,68 @@ kernel_handoff(struct connection *conn)
}
}
+void
+kernel_limits(const char *offload, size_t *max_data_segment_length)
+{
+ struct ctl_iscsi req;
+
+ bzero(&req, sizeof(req));
+
+ req.type = CTL_ISCSI_LIMITS;
+ if (offload != NULL) {
+ strlcpy(req.data.limits.offload, offload,
+ sizeof(req.data.limits.offload));
+ }
+
+ if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
+ log_err(1, "error issuing CTL_ISCSI ioctl; "
+ "dropping connection");
+ }
+
+ if (req.status != CTL_ISCSI_OK) {
+ log_errx(1, "error returned from CTL iSCSI limits request: "
+ "%s; dropping connection", req.error_str);
+ }
+
+ *max_data_segment_length = req.data.limits.data_segment_limit;
+ if (offload != NULL) {
+ log_debugx("MaxRecvDataSegment kernel limit for offload "
+ "\"%s\" is %zd", offload, *max_data_segment_length);
+ } else {
+ log_debugx("MaxRecvDataSegment kernel limit is %zd",
+ *max_data_segment_length);
+ }
+}
+
int
-kernel_port_add(struct target *targ)
+kernel_port_add(struct port *port)
{
struct ctl_port_entry entry;
struct ctl_req req;
struct ctl_lun_map lm;
+ struct target *targ = port->p_target;
+ struct portal_group *pg = port->p_portal_group;
char tagstr[16];
- int error, i;
+ int error, i, n;
/* Create iSCSI port. */
bzero(&req, sizeof(req));
strlcpy(req.driver, "iscsi", sizeof(req.driver));
req.reqtype = CTL_REQ_CREATE;
- req.num_args = 4;
req.args = malloc(req.num_args * sizeof(*req.args));
- req.args[0].namelen = sizeof("port_id");
- req.args[0].name = __DECONST(char *, "port_id");
- req.args[0].vallen = sizeof(targ->t_ctl_port);
- req.args[0].value = &targ->t_ctl_port;
- req.args[0].flags = CTL_BEARG_WR;
- str_arg(&req.args[1], "cfiscsi_target", targ->t_name);
- snprintf(tagstr, sizeof(tagstr), "%d", targ->t_portal_group->pg_tag);
- str_arg(&req.args[2], "cfiscsi_portal_group_tag", tagstr);
+ n = 0;
+ req.args[n].namelen = sizeof("port_id");
+ req.args[n].name = __DECONST(char *, "port_id");
+ req.args[n].vallen = sizeof(port->p_ctl_port);
+ req.args[n].value = &port->p_ctl_port;
+ req.args[n++].flags = CTL_BEARG_WR;
+ str_arg(&req.args[n++], "cfiscsi_target", targ->t_name);
+ snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag);
+ str_arg(&req.args[n++], "cfiscsi_portal_group_tag", tagstr);
if (targ->t_alias)
- str_arg(&req.args[3], "cfiscsi_target_alias", targ->t_alias);
- else
- req.num_args--;
+ str_arg(&req.args[n++], "cfiscsi_target_alias", targ->t_alias);
+ str_arg(&req.args[n++], "ctld_portal_group_name", pg->pg_name);
+ req.num_args = n;
error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
free(req.args);
if (error != 0) {
@@ -848,7 +915,7 @@ kernel_port_add(struct target *targ)
}
/* Explicitly enable mapping to block any access except allowed. */
- lm.port = targ->t_ctl_port;
+ lm.port = port->p_ctl_port;
lm.plun = UINT32_MAX;
lm.lun = 0;
error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
@@ -859,7 +926,7 @@ kernel_port_add(struct target *targ)
for (i = 0; i < MAX_LUNS; i++) {
if (targ->t_luns[i] == NULL)
continue;
- lm.port = targ->t_ctl_port;
+ lm.port = port->p_ctl_port;
lm.plun = i;
lm.lun = targ->t_luns[i]->l_ctl_lun;
error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
@@ -869,7 +936,7 @@ kernel_port_add(struct target *targ)
/* Enable port */
bzero(&entry, sizeof(entry));
- entry.targ_port = targ->t_ctl_port;
+ entry.targ_port = port->p_ctl_port;
error = ioctl(ctl_fd, CTL_ENABLE_PORT, &entry);
if (error != 0) {
log_warn("CTL_ENABLE_PORT ioctl failed");
@@ -880,14 +947,15 @@ kernel_port_add(struct target *targ)
}
int
-kernel_port_update(struct target *targ)
+kernel_port_update(struct port *port)
{
struct ctl_lun_map lm;
+ struct target *targ = port->p_target;
int error, i;
/* Map configured LUNs and unmap others */
for (i = 0; i < MAX_LUNS; i++) {
- lm.port = targ->t_ctl_port;
+ lm.port = port->p_ctl_port;
lm.plun = i;
if (targ->t_luns[i] == NULL)
lm.lun = UINT32_MAX;
@@ -901,10 +969,12 @@ kernel_port_update(struct target *targ)
}
int
-kernel_port_remove(struct target *targ)
+kernel_port_remove(struct port *port)
{
struct ctl_req req;
char tagstr[16];
+ struct target *targ = port->p_target;
+ struct portal_group *pg = port->p_portal_group;
int error;
bzero(&req, sizeof(req));
@@ -913,7 +983,7 @@ kernel_port_remove(struct target *targ)
req.num_args = 2;
req.args = malloc(req.num_args * sizeof(*req.args));
str_arg(&req.args[0], "cfiscsi_target", targ->t_name);
- snprintf(tagstr, sizeof(tagstr), "%d", targ->t_portal_group->pg_tag);
+ snprintf(tagstr, sizeof(tagstr), "%d", pg->pg_tag);
str_arg(&req.args[1], "cfiscsi_portal_group_tag", tagstr);
error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
diff --git a/usr.sbin/ctld/login.c b/usr.sbin/ctld/login.c
index 5358e4b979a1..11d97cfae793 100644
--- a/usr.sbin/ctld/login.c
+++ b/usr.sbin/ctld/login.c
@@ -453,7 +453,8 @@ static void
login_negotiate_key(struct pdu *request, const char *name,
const char *value, bool skipped_security, struct keys *response_keys)
{
- int which, tmp;
+ int which;
+ size_t tmp;
struct connection *conn;
conn = request->pdu_connection;
@@ -552,13 +553,13 @@ login_negotiate_key(struct pdu *request, const char *name,
log_errx(1, "received invalid "
"MaxRecvDataSegmentLength");
}
- if (tmp > MAX_DATA_SEGMENT_LENGTH) {
+ if (tmp > conn->conn_data_segment_limit) {
log_debugx("capping MaxRecvDataSegmentLength "
- "from %d to %d", tmp, MAX_DATA_SEGMENT_LENGTH);
- tmp = MAX_DATA_SEGMENT_LENGTH;
+ "from %zd to %zd", tmp, conn->conn_data_segment_limit);
+ tmp = conn->conn_data_segment_limit;
}
conn->conn_max_data_segment_length = tmp;
- keys_add_int(response_keys, name, MAX_DATA_SEGMENT_LENGTH);
+ keys_add_int(response_keys, name, tmp);
} else if (strcmp(name, "MaxBurstLength") == 0) {
tmp = strtoul(value, NULL, 10);
if (tmp <= 0) {
@@ -566,7 +567,7 @@ login_negotiate_key(struct pdu *request, const char *name,
log_errx(1, "received invalid MaxBurstLength");
}
if (tmp > MAX_BURST_LENGTH) {
- log_debugx("capping MaxBurstLength from %d to %d",
+ log_debugx("capping MaxBurstLength from %zd to %d",
tmp, MAX_BURST_LENGTH);
tmp = MAX_BURST_LENGTH;
}
@@ -579,10 +580,10 @@ login_negotiate_key(struct pdu *request, const char *name,
log_errx(1, "received invalid "
"FirstBurstLength");
}
- if (tmp > MAX_DATA_SEGMENT_LENGTH) {
- log_debugx("capping FirstBurstLength from %d to %d",
- tmp, MAX_DATA_SEGMENT_LENGTH);
- tmp = MAX_DATA_SEGMENT_LENGTH;
+ if (tmp > conn->conn_data_segment_limit) {
+ log_debugx("capping FirstBurstLength from %zd to %zd",
+ tmp, conn->conn_data_segment_limit);
+ tmp = conn->conn_data_segment_limit;
}
/*
* We don't pass the value to the kernel; it only enforces
@@ -680,6 +681,18 @@ login_negotiate(struct connection *conn, struct pdu *request)
int i;
bool redirected, skipped_security;
+ if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
+ /*
+ * Query the kernel for MaxDataSegmentLength it can handle.
+ * In case of offload, it depends on hardware capabilities.
+ */
+ assert(conn->conn_target != NULL);
+ kernel_limits(conn->conn_target->t_offload,
+ &conn->conn_data_segment_limit);
+ } else {
+ conn->conn_data_segment_limit = MAX_DATA_SEGMENT_LENGTH;
+ }
+
if (request == NULL) {
log_debugx("beginning operational parameter negotiation; "
"waiting for Login PDU");
@@ -827,19 +840,22 @@ login(struct connection *conn)
log_errx(1, "received Login PDU without TargetName");
}
- conn->conn_target = target_find(pg->pg_conf, target_name);
- if (conn->conn_target == NULL) {
+ conn->conn_port = port_find_in_pg(pg, target_name);
+ if (conn->conn_port == NULL) {
login_send_error(request, 0x02, 0x03);
log_errx(1, "requested target \"%s\" not found",
target_name);
}
+ conn->conn_target = conn->conn_port->p_target;
}
/*
* At this point we know what kind of authentication we need.
*/
if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
- ag = conn->conn_target->t_auth_group;
+ ag = conn->conn_port->p_auth_group;
+ if (ag == NULL)
+ ag = conn->conn_target->t_auth_group;
if (ag->ag_name != NULL) {
log_debugx("initiator requests to connect "
"to target \"%s\"; auth-group \"%s\"",
diff --git a/usr.sbin/ctld/parse.y b/usr.sbin/ctld/parse.y
index fead2ea8a258..5eaffe4e324a 100644
--- a/usr.sbin/ctld/parse.y
+++ b/usr.sbin/ctld/parse.y
@@ -60,7 +60,7 @@ extern void yyrestart(FILE *);
%token ALIAS AUTH_GROUP AUTH_TYPE BACKEND BLOCKSIZE CHAP CHAP_MUTUAL
%token CLOSING_BRACKET DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP DISCOVERY_FILTER
%token INITIATOR_NAME INITIATOR_PORTAL ISNS_SERVER ISNS_PERIOD ISNS_TIMEOUT
-%token LISTEN LISTEN_ISER LUN MAXPROC OPENING_BRACKET OPTION
+%token LISTEN LISTEN_ISER LUN MAXPROC OFFLOAD OPENING_BRACKET OPTION
%token PATH PIDFILE PORTAL_GROUP REDIRECT SEMICOLON SERIAL SIZE STR
%token TARGET TIMEOUT
@@ -463,6 +463,8 @@ target_entry:
|
target_initiator_portal
|
+ target_offload
+ |
target_portal_group
|
target_redirect
@@ -652,21 +654,69 @@ target_initiator_portal: INITIATOR_PORTAL STR
}
;
-target_portal_group: PORTAL_GROUP STR
+target_offload: OFFLOAD STR
{
- if (target->t_portal_group != NULL) {
- log_warnx("portal-group for target \"%s\" "
- "specified more than once", target->t_name);
+ int error;
+
+ error = target_set_offload(target, $2);
+ free($2);
+ if (error != 0)
+ return (1);
+ }
+ ;
+
+target_portal_group: PORTAL_GROUP STR STR
+ {
+ struct portal_group *tpg;
+ struct auth_group *tag;
+ struct port *tp;
+
+ tpg = portal_group_find(conf, $2);
+ if (tpg == NULL) {
+ log_warnx("unknown portal-group \"%s\" for target "
+ "\"%s\"", $2, target->t_name);
free($2);
+ free($3);
return (1);
}
- target->t_portal_group = portal_group_find(conf, $2);
- if (target->t_portal_group == NULL) {
+ tag = auth_group_find(conf, $3);
+ if (tag == NULL) {
+ log_warnx("unknown auth-group \"%s\" for target "
+ "\"%s\"", $3, target->t_name);
+ free($2);
+ free($3);
+ return (1);
+ }
+ tp = port_new(conf, target, tpg);
+ if (tp == NULL) {
+ log_warnx("can't link portal-group \"%s\" to target "
+ "\"%s\"", $2, target->t_name);
+ free($2);
+ return (1);
+ }
+ tp->p_auth_group = tag;
+ free($2);
+ free($3);
+ }
+ | PORTAL_GROUP STR
+ {
+ struct portal_group *tpg;
+ struct port *tp;
+
+ tpg = portal_group_find(conf, $2);
+ if (tpg == NULL) {
log_warnx("unknown portal-group \"%s\" for target "
"\"%s\"", $2, target->t_name);
free($2);
return (1);
}
+ tp = port_new(conf, target, tpg);
+ if (tp == NULL) {
+ log_warnx("can't link portal-group \"%s\" to target "
+ "\"%s\"", $2, target->t_name);
+ free($2);
+ return (1);
+ }
free($2);
}
;
diff --git a/usr.sbin/ctld/token.l b/usr.sbin/ctld/token.l
index d4bf823b8b08..fd274983f447 100644
--- a/usr.sbin/ctld/token.l
+++ b/usr.sbin/ctld/token.l
@@ -65,6 +65,7 @@ listen { return LISTEN; }
listen-iser { return LISTEN_ISER; }
lun { return LUN; }
maxproc { return MAXPROC; }
+offload { return OFFLOAD; }
option { return OPTION; }
path { return PATH; }
pidfile { return PIDFILE; }
diff --git a/usr.sbin/devctl/Makefile b/usr.sbin/devctl/Makefile
new file mode 100644
index 000000000000..5a6e19d761a3
--- /dev/null
+++ b/usr.sbin/devctl/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+PROG= devctl
+MAN= devctl.8
+MAN=
+
+LIBADD= devctl
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/devctl/devctl.8 b/usr.sbin/devctl/devctl.8
new file mode 100644
index 000000000000..77c803a7af29
--- /dev/null
+++ b/usr.sbin/devctl/devctl.8
@@ -0,0 +1,137 @@
+.\"
+.\" Copyright (c) 2015 John Baldwin <jhb@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
+.\"
+.Dd February 5, 2015
+.Dt DEVCTL 8
+.Os
+.Sh NAME
+.Nm devctl
+.Nd device control utility
+.Sh SYNOPSIS
+.Nm
+.Cm attach
+.Ar device
+.Nm
+.Cm detach
+.Op Fl f
+.Ar device
+.Nm
+.Cm disable
+.Op Fl f
+.Ar device
+.Nm
+.Cm enable
+.Ar device
+.Nm
+.Cm suspend
+.Ar device
+.Nm
+.Cm resume
+.Ar device
+.Nm
+.Cm set driver
+.Op Fl f
+.Ar device driver
+.Sh DESCRIPTION
+The
+.Nm
+utility adjusts the state of individual devices in the kernel's
+internal device hierarchy.
+Each invocation of
+.Nm
+consists of a single command followed by command-specific arguments.
+Each command operates on a single device specified via the
+.Ar device
+argument.
+The
+.Ar device
+may be specified either as the name of an existing device or as a
+bus-specific address.
+More details on supported address formats can be found in
+.Xr devctl 3 .
+.Pp
+The following commands are supported:
+.Bl -tag -width indent
+.It Cm attach Ar device
+Force the kernel to re-probe the device.
+If a suitable driver is found,
+it is attached to the device.
+.It Xo Cm detach
+.Op Fl f
+.Ar device
+.Xc
+Detach the device from its current device driver.
+If the
+.Fl f
+flag is specified,
+the device driver will be detached even if the device is busy.
+.It Xo Cm disable
+.Op Fl f
+.Ar device
+.Xc
+Disable a device.
+If the device is currently attached to a device driver,
+the device driver will be detached from the device,
+but the device will retain its current name.
+If the
+.Fl f
+flag is specified,
+the device driver will be detached even if the device is busy.
+.It Cm enable Ar device
+Enable a device.
+The device will probe and attach if a suitable device driver is found.
+Note that this can re-enable a device disabled at boot time via a
+loader tunable.
+.It Cm suspend Ar device
+Suspend a device.
+This may include placing the device in a reduced power state.
+.It Cm resume device
+Resume a suspended device to a fully working state.
+.It Xo Cm set driver
+.Op Fl f
+.Ar device driver
+.Xc
+Force the device to use a device driver named
+.Ar driver .
+If the device is already attached to a device driver and the
+.Fl f
+flag is specified,
+the device will be detached from its current device driver before it is
+attached to the new device driver.
+If the device is already attached to a device driver and the
+.Fl f
+flag is not specified,
+the device will not be changed.
+.El
+.Sh SEE ALSO
+.Xr devctl 3 ,
+.Xr devinfo 8
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 11.0 .
diff --git a/usr.sbin/devctl/devctl.c b/usr.sbin/devctl/devctl.c
new file mode 100644
index 000000000000..076c6503885e
--- /dev/null
+++ b/usr.sbin/devctl/devctl.c
@@ -0,0 +1,282 @@
+/*-
+ * Copyright (c) 2014 John Baldwin <jhb@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/linker_set.h>
+#include <devctl.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+struct devctl_command {
+ const char *name;
+ int (*handler)(int ac, char **av);
+};
+
+#define DEVCTL_DATASET(name) devctl_ ## name ## _table
+
+#define DEVCTL_COMMAND(set, name, function) \
+ static struct devctl_command function ## _devctl_command = \
+ { #name, function }; \
+ DATA_SET(DEVCTL_DATASET(set), function ## _devctl_command)
+
+#define DEVCTL_TABLE(set, name) \
+ SET_DECLARE(DEVCTL_DATASET(name), struct devctl_command); \
+ \
+ static int \
+ devctl_ ## name ## _table_handler(int ac, char **av) \
+ { \
+ return (devctl_table_handler(SET_BEGIN(DEVCTL_DATASET(name)), \
+ SET_LIMIT(DEVCTL_DATASET(name)), ac, av)); \
+ } \
+ DEVCTL_COMMAND(set, name, devctl_ ## name ## _table_handler)
+
+static int devctl_table_handler(struct devctl_command **start,
+ struct devctl_command **end, int ac, char **av);
+
+SET_DECLARE(DEVCTL_DATASET(top), struct devctl_command);
+
+DEVCTL_TABLE(top, set);
+
+static void
+usage(void)
+{
+ fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
+ "usage: devctl attach device",
+ " devctl detach [-f] device",
+ " devctl disable [-f] device",
+ " devctl enable device",
+ " devctl suspend device",
+ " devctl resume device",
+ " devctl set driver [-f] device driver");
+ exit(1);
+}
+
+static int
+devctl_table_handler(struct devctl_command **start,
+ struct devctl_command **end, int ac, char **av)
+{
+ struct devctl_command **cmd;
+
+ if (ac < 2) {
+ warnx("The %s command requires a sub-command.", av[0]);
+ return (EINVAL);
+ }
+ for (cmd = start; cmd < end; cmd++) {
+ if (strcmp((*cmd)->name, av[1]) == 0)
+ return ((*cmd)->handler(ac - 1, av + 1));
+ }
+
+ warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
+ return (ENOENT);
+}
+
+static int
+help(int ac __unused, char **av __unused)
+{
+
+ usage();
+ return (0);
+}
+DEVCTL_COMMAND(top, help, help);
+
+static int
+attach(int ac, char **av)
+{
+
+ if (ac != 2)
+ usage();
+ if (devctl_attach(av[1]) < 0)
+ err(1, "Failed to attach %s", av[1]);
+ return (0);
+}
+DEVCTL_COMMAND(top, attach, attach);
+
+static void
+detach_usage(void)
+{
+
+ fprintf(stderr, "usage: devctl detach [-f] device\n");
+ exit(1);
+}
+
+static int
+detach(int ac, char **av)
+{
+ bool force;
+ int ch;
+
+ force = false;
+ while ((ch = getopt(ac, av, "f")) != -1)
+ switch (ch) {
+ case 'f':
+ force = true;
+ break;
+ default:
+ detach_usage();
+ }
+ ac -= optind;
+ av += optind;
+
+ if (ac != 1)
+ detach_usage();
+ if (devctl_detach(av[0], force) < 0)
+ err(1, "Failed to detach %s", av[0]);
+ return (0);
+}
+DEVCTL_COMMAND(top, detach, detach);
+
+static void
+disable_usage(void)
+{
+
+ fprintf(stderr, "usage: devctl disable [-f] device\n");
+ exit(1);
+}
+
+static int
+disable(int ac, char **av)
+{
+ bool force;
+ int ch;
+
+ force = false;
+ while ((ch = getopt(ac, av, "f")) != -1)
+ switch (ch) {
+ case 'f':
+ force = true;
+ break;
+ default:
+ disable_usage();
+ }
+ ac -= optind;
+ av += optind;
+
+ if (ac != 1)
+ disable_usage();
+ if (devctl_disable(av[0], force) < 0)
+ err(1, "Failed to disable %s", av[0]);
+ return (0);
+}
+DEVCTL_COMMAND(top, disable, disable);
+
+static int
+enable(int ac, char **av)
+{
+
+ if (ac != 2)
+ usage();
+ if (devctl_enable(av[1]) < 0)
+ err(1, "Failed to enable %s", av[1]);
+ return (0);
+}
+DEVCTL_COMMAND(top, enable, enable);
+
+static int
+suspend(int ac, char **av)
+{
+
+ if (ac != 2)
+ usage();
+ if (devctl_suspend(av[1]) < 0)
+ err(1, "Failed to suspend %s", av[1]);
+ return (0);
+}
+DEVCTL_COMMAND(top, suspend, suspend);
+
+static int
+resume(int ac, char **av)
+{
+
+ if (ac != 2)
+ usage();
+ if (devctl_resume(av[1]) < 0)
+ err(1, "Failed to resume %s", av[1]);
+ return (0);
+}
+DEVCTL_COMMAND(top, resume, resume);
+
+static void
+set_driver_usage(void)
+{
+
+ fprintf(stderr, "usage: devctl set driver [-f] device driver\n");
+ exit(1);
+}
+
+static int
+set_driver(int ac, char **av)
+{
+ bool force;
+ int ch;
+
+ force = false;
+ while ((ch = getopt(ac, av, "f")) != -1)
+ switch (ch) {
+ case 'f':
+ force = true;
+ break;
+ default:
+ set_driver_usage();
+ }
+ ac -= optind;
+ av += optind;
+
+ if (ac != 2)
+ set_driver_usage();
+ if (devctl_set_driver(av[0], av[1], force) < 0)
+ err(1, "Failed to set %s driver to %s", av[0], av[1]);
+ return (0);
+}
+DEVCTL_COMMAND(set, driver, set_driver);
+
+int
+main(int ac, char *av[])
+{
+ struct devctl_command **cmd;
+
+ if (ac == 1)
+ usage();
+ ac--;
+ av++;
+
+ SET_FOREACH(cmd, DEVCTL_DATASET(top)) {
+ if (strcmp((*cmd)->name, av[0]) == 0) {
+ if ((*cmd)->handler(ac, av) != 0)
+ return (1);
+ else
+ return (0);
+ }
+ }
+ warnx("Unknown command %s.", av[0]);
+ return (1);
+}
diff --git a/usr.sbin/devinfo/devinfo.c b/usr.sbin/devinfo/devinfo.c
index 32d2932b4676..40f2b0b42eba 100644
--- a/usr.sbin/devinfo/devinfo.c
+++ b/usr.sbin/devinfo/devinfo.c
@@ -146,6 +146,10 @@ print_device(struct devinfo_dev *dev, void *arg)
printf(" pnpinfo %s", dev->dd_pnpinfo);
if (vflag && *dev->dd_location)
printf(" at %s", dev->dd_location);
+ if (!(dev->dd_flags & DF_ENABLED))
+ printf(" (disabled)");
+ else if (dev->dd_flags & DF_SUSPENDED)
+ printf(" (suspended)");
printf("\n");
if (rflag) {
ia.indent = indent + 4;
diff --git a/usr.sbin/freebsd-update/freebsd-update.sh b/usr.sbin/freebsd-update/freebsd-update.sh
index 4979c0148257..3b784c810f7c 100644
--- a/usr.sbin/freebsd-update/freebsd-update.sh
+++ b/usr.sbin/freebsd-update/freebsd-update.sh
@@ -2828,18 +2828,27 @@ Kernel updates have been installed. Please reboot and run
grep -E '^[^|]+\|d\|' > INDEX-NEW
install_from_index INDEX-NEW || return 1
+ # Install new runtime linker
+ grep -vE '^/boot/' $1/INDEX-NEW |
+ grep -vE '^[^|]+\|d\|' |
+ grep -E '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' > INDEX-NEW
+ install_from_index INDEX-NEW || return 1
+
# Install new shared libraries next
grep -vE '^/boot/' $1/INDEX-NEW |
grep -vE '^[^|]+\|d\|' |
+ grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
install_from_index INDEX-NEW || return 1
# Deal with everything else
grep -vE '^/boot/' $1/INDEX-OLD |
grep -vE '^[^|]+\|d\|' |
+ grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-OLD
grep -vE '^/boot/' $1/INDEX-NEW |
grep -vE '^[^|]+\|d\|' |
+ grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
install_from_index INDEX-NEW || return 1
install_delete INDEX-OLD INDEX-NEW || return 1
diff --git a/usr.sbin/jail/command.c b/usr.sbin/jail/command.c
index 6fefe414be67..f6f9db3a9fe2 100644
--- a/usr.sbin/jail/command.c
+++ b/usr.sbin/jail/command.c
@@ -112,6 +112,12 @@ next_command(struct cfjail *j)
if (!bool_param(j->intparams[IP_MOUNT_FDESCFS]))
continue;
j->comstring = &dummystring;
+ break;
+ case IP_MOUNT_PROCFS:
+ if (!bool_param(j->intparams[IP_MOUNT_PROCFS]))
+ continue;
+ j->comstring = &dummystring;
+ break;
case IP__OP:
case IP_STOP_TIMEOUT:
j->comstring = &dummystring;
@@ -528,6 +534,32 @@ run_command(struct cfjail *j)
}
break;
+ case IP_MOUNT_PROCFS:
+ argv = alloca(7 * sizeof(char *));
+ path = string_param(j->intparams[KP_PATH]);
+ if (path == NULL) {
+ jail_warnx(j, "mount.procfs: no path");
+ return -1;
+ }
+ devpath = alloca(strlen(path) + 6);
+ sprintf(devpath, "%s/proc", path);
+ if (check_path(j, "mount.procfs", devpath, 0,
+ down ? "procfs" : NULL) < 0)
+ return -1;
+ if (down) {
+ argv[0] = "/sbin/umount";
+ argv[1] = devpath;
+ argv[2] = NULL;
+ } else {
+ argv[0] = _PATH_MOUNT;
+ argv[1] = "-t";
+ argv[2] = "procfs";
+ argv[3] = ".";
+ argv[4] = devpath;
+ argv[5] = NULL;
+ }
+ break;
+
case IP_COMMAND:
if (j->name != NULL)
goto default_command;
diff --git a/usr.sbin/jail/config.c b/usr.sbin/jail/config.c
index cd02a500c544..582020965136 100644
--- a/usr.sbin/jail/config.c
+++ b/usr.sbin/jail/config.c
@@ -84,6 +84,7 @@ static const struct ipspec intparams[] = {
[IP_MOUNT] = {"mount", PF_INTERNAL | PF_REV},
[IP_MOUNT_DEVFS] = {"mount.devfs", PF_INTERNAL | PF_BOOL},
[IP_MOUNT_FDESCFS] = {"mount.fdescfs", PF_INTERNAL | PF_BOOL},
+ [IP_MOUNT_PROCFS] = {"mount.procfs", PF_INTERNAL | PF_BOOL},
[IP_MOUNT_FSTAB] = {"mount.fstab", PF_INTERNAL},
[IP_STOP_TIMEOUT] = {"stop.timeout", PF_INTERNAL | PF_INT},
[IP_VNET_INTERFACE] = {"vnet.interface", PF_INTERNAL},
diff --git a/usr.sbin/jail/jail.8 b/usr.sbin/jail/jail.8
index d580c2553dbf..bc5886a5a01f 100644
--- a/usr.sbin/jail/jail.8
+++ b/usr.sbin/jail/jail.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 28, 2015
+.Dd February 6, 2015
.Dt JAIL 8
.Os
.Sh NAME
@@ -753,6 +753,12 @@ Mount a
filesystem on the chrooted
.Pa /dev/fd
directory.
+.It Va mount.procfs
+Mount a
+.Xr procfs 5
+filesystem on the chrooted
+.Pa /proc
+directory.
.It Va allow.dying
Allow making changes to a
.Va dying
@@ -1207,6 +1213,7 @@ environment of the first jail.
.Xr jls 8 ,
.Xr mount 8 ,
.Xr named 8 ,
+.Xr procfs 5 ,
.Xr reboot 8 ,
.Xr rpcbind 8 ,
.Xr sendmail 8 ,
diff --git a/usr.sbin/jail/jail.c b/usr.sbin/jail/jail.c
index b8f57793d868..e42afa41f875 100644
--- a/usr.sbin/jail/jail.c
+++ b/usr.sbin/jail/jail.c
@@ -93,6 +93,7 @@ static const enum intparam startcommands[] = {
IP__MOUNT_FROM_FSTAB,
IP_MOUNT_DEVFS,
IP_MOUNT_FDESCFS,
+ IP_MOUNT_PROCFS,
IP_EXEC_PRESTART,
IP__OP,
IP_VNET_INTERFACE,
@@ -109,6 +110,7 @@ static const enum intparam stopcommands[] = {
IP_STOP_TIMEOUT,
IP__OP,
IP_EXEC_POSTSTOP,
+ IP_MOUNT_PROCFS,
IP_MOUNT_FDESCFS,
IP_MOUNT_DEVFS,
IP__MOUNT_FROM_FSTAB,
diff --git a/usr.sbin/jail/jailp.h b/usr.sbin/jail/jailp.h
index 3f893920ab21..bfefca56c10b 100644
--- a/usr.sbin/jail/jailp.h
+++ b/usr.sbin/jail/jailp.h
@@ -96,6 +96,7 @@ enum intparam {
IP_MOUNT, /* Mount points in fstab(5) form */
IP_MOUNT_DEVFS, /* Mount /dev under prison root */
IP_MOUNT_FDESCFS, /* Mount /dev/fd under prison root */
+ IP_MOUNT_PROCFS, /* Mount /proc under prison root */
IP_MOUNT_FSTAB, /* A standard fstab(5) file */
IP_STOP_TIMEOUT, /* Time to wait after sending SIGTERM */
IP_VNET_INTERFACE, /* Assign interface(s) to vnet jail */