summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Lowe <richlowe@richlowe.net>2022-02-22 18:00:48 -0600
committerRichard Lowe <richlowe@richlowe.net>2022-02-22 18:00:48 -0600
commit3971085411b91c5d82e278443ab68fca1946cb21 (patch)
tree8e6d01d8aea1c3d8179a47b929ff5bfa8b42f752
parent1df45418ec3688847e142a9a2213965459ff39c7 (diff)
parentca783257c986cddcc674ae22916a6766b98a2d36 (diff)
downloadillumos-joyent-3971085411b91c5d82e278443ab68fca1946cb21.tar.gz
Merge branch 'master' of https://github.com/illumos/illumos-gate into man/big-reorg
# Conflicts: # usr/src/cmd/fmthard/fmthard.c # usr/src/cmd/zoneadmd/zcons.c # usr/src/man/man2/chmod.2 # usr/src/man/man2/close.2 # usr/src/man/man2/open.2 # usr/src/man/man3c/grantpt.3c # usr/src/man/man3c/posix_openpt.3c # usr/src/man/man3c/ptsname.3c # usr/src/man/man3c/unlockpt.3c # usr/src/man/man3utempter/utempter_add_record.3utempter # usr/src/man/man4/Makefile # usr/src/man/man4d/ptm.4d # usr/src/man/man4d/pts.4d # usr/src/man/man4d/pty.4d # usr/src/man/man4d/zcons.4d # usr/src/man/man4m/pckt.4m # usr/src/man/man4m/ptem.4m # usr/src/man/man4p/vxlan.7p # usr/src/man/man5/Makefile # usr/src/man/man5/bhyve_config.5 # usr/src/man/man7d/Makefile # usr/src/man/man7p/Makefile # usr/src/man/man8/bhyve.8 # usr/src/man/man8/dladm.8 # usr/src/man/man8/flowadm.8 # usr/src/man/man8/fmthard.8 # usr/src/man/man8/in.rlogind.8 # usr/src/man/man8/in.telnetd.8 # usr/src/man/man8/nvmeadm.8 # usr/src/man/man8/pppd.8 # usr/src/pkg/manifests/SUNWcs.man4d.inc # usr/src/uts/common/io/zcons.c
-rw-r--r--exception_lists/packaging12
-rw-r--r--usr/src/Targetdirs4
-rw-r--r--usr/src/boot/Makefile21
-rw-r--r--usr/src/boot/Makefile.inc (renamed from usr/src/boot/sys/boot/Makefile.inc)5
-rw-r--r--usr/src/boot/Makefile.lib (renamed from usr/src/boot/sys/boot/Makefile.lib)0
-rw-r--r--usr/src/boot/README.loader (renamed from usr/src/boot/sys/boot/README)0
-rw-r--r--usr/src/boot/Readme.txt17
-rw-r--r--usr/src/boot/common/Makefile.inc (renamed from usr/src/boot/sys/boot/common/Makefile.inc)0
-rw-r--r--usr/src/boot/common/bcache.c (renamed from usr/src/boot/sys/boot/common/bcache.c)0
-rw-r--r--usr/src/boot/common/boot.c (renamed from usr/src/boot/sys/boot/common/boot.c)0
-rw-r--r--usr/src/boot/common/bootstrap.h (renamed from usr/src/boot/sys/boot/common/bootstrap.h)0
-rw-r--r--usr/src/boot/common/commands.c (renamed from usr/src/boot/sys/boot/common/commands.c)0
-rw-r--r--usr/src/boot/common/console.c (renamed from usr/src/boot/sys/boot/common/console.c)0
-rw-r--r--usr/src/boot/common/dev_net.c (renamed from usr/src/boot/sys/boot/common/dev_net.c)0
-rw-r--r--usr/src/boot/common/dev_net.h (renamed from usr/src/boot/sys/boot/common/dev_net.h)0
-rw-r--r--usr/src/boot/common/devopen.c (renamed from usr/src/boot/sys/boot/common/devopen.c)0
-rw-r--r--usr/src/boot/common/disk.c (renamed from usr/src/boot/sys/boot/common/disk.c)0
-rw-r--r--usr/src/boot/common/disk.h (renamed from usr/src/boot/sys/boot/common/disk.h)0
-rw-r--r--usr/src/boot/common/gfx_fb.c (renamed from usr/src/boot/sys/boot/common/gfx_fb.c)8
-rw-r--r--usr/src/boot/common/gfx_fb.h (renamed from usr/src/boot/sys/boot/common/gfx_fb.h)0
-rw-r--r--usr/src/boot/common/gpt.c (renamed from usr/src/boot/sys/boot/common/gpt.c)0
-rw-r--r--usr/src/boot/common/gpt.h (renamed from usr/src/boot/sys/boot/common/gpt.h)0
-rw-r--r--usr/src/boot/common/help.common (renamed from usr/src/boot/sys/boot/common/help.common)0
-rw-r--r--usr/src/boot/common/install.c (renamed from usr/src/boot/sys/boot/common/install.c)0
-rw-r--r--usr/src/boot/common/interp.c (renamed from usr/src/boot/sys/boot/common/interp.c)0
-rw-r--r--usr/src/boot/common/interp_backslash.c (renamed from usr/src/boot/sys/boot/common/interp_backslash.c)0
-rw-r--r--usr/src/boot/common/interp_forth.c (renamed from usr/src/boot/sys/boot/common/interp_forth.c)0
-rw-r--r--usr/src/boot/common/interp_parse.c (renamed from usr/src/boot/sys/boot/common/interp_parse.c)0
-rw-r--r--usr/src/boot/common/isapnp.c (renamed from usr/src/boot/sys/boot/common/isapnp.c)0
-rw-r--r--usr/src/boot/common/isapnp.h (renamed from usr/src/boot/sys/boot/common/isapnp.h)0
-rwxr-xr-xusr/src/boot/common/linenoise/LICENSE (renamed from usr/src/boot/sys/boot/common/linenoise/LICENSE)0
-rw-r--r--usr/src/boot/common/linenoise/LICENSE.descrip (renamed from usr/src/boot/sys/boot/common/linenoise/LICENSE.descrip)0
-rwxr-xr-xusr/src/boot/common/linenoise/Makefile (renamed from usr/src/boot/sys/boot/common/linenoise/Makefile)0
-rwxr-xr-xusr/src/boot/common/linenoise/README.markdown (renamed from usr/src/boot/sys/boot/common/linenoise/README.markdown)0
-rwxr-xr-xusr/src/boot/common/linenoise/example.c (renamed from usr/src/boot/sys/boot/common/linenoise/example.c)0
-rwxr-xr-xusr/src/boot/common/linenoise/linenoise.c (renamed from usr/src/boot/sys/boot/common/linenoise/linenoise.c)0
-rwxr-xr-xusr/src/boot/common/linenoise/linenoise.h (renamed from usr/src/boot/sys/boot/common/linenoise/linenoise.h)0
-rw-r--r--usr/src/boot/common/load_elf.c (renamed from usr/src/boot/sys/boot/common/load_elf.c)0
-rw-r--r--usr/src/boot/common/load_elf32.c (renamed from usr/src/boot/sys/boot/common/load_elf32.c)0
-rw-r--r--usr/src/boot/common/load_elf32_obj.c (renamed from usr/src/boot/sys/boot/common/load_elf32_obj.c)0
-rw-r--r--usr/src/boot/common/load_elf64.c (renamed from usr/src/boot/sys/boot/common/load_elf64.c)0
-rw-r--r--usr/src/boot/common/load_elf64_obj.c (renamed from usr/src/boot/sys/boot/common/load_elf64_obj.c)0
-rw-r--r--usr/src/boot/common/load_elf_obj.c (renamed from usr/src/boot/sys/boot/common/load_elf_obj.c)0
-rw-r--r--usr/src/boot/common/ls.c (renamed from usr/src/boot/sys/boot/common/ls.c)0
-rw-r--r--usr/src/boot/common/mb_header.S (renamed from usr/src/boot/sys/boot/common/mb_header.S)0
-rw-r--r--usr/src/boot/common/md.c (renamed from usr/src/boot/sys/boot/common/md.c)0
-rw-r--r--usr/src/boot/common/merge_help.awk (renamed from usr/src/boot/sys/boot/common/merge_help.awk)0
-rw-r--r--usr/src/boot/common/misc.c (renamed from usr/src/boot/sys/boot/common/misc.c)0
-rw-r--r--usr/src/boot/common/module.c (renamed from usr/src/boot/sys/boot/common/module.c)0
-rw-r--r--usr/src/boot/common/multiboot2.c (renamed from usr/src/boot/sys/boot/common/multiboot2.c)0
-rwxr-xr-xusr/src/boot/common/newvers.sh (renamed from usr/src/boot/sys/boot/common/newvers.sh)0
-rw-r--r--usr/src/boot/common/nvstore.c (renamed from usr/src/boot/sys/boot/common/nvstore.c)0
-rw-r--r--usr/src/boot/common/part.c (renamed from usr/src/boot/sys/boot/common/part.c)0
-rw-r--r--usr/src/boot/common/part.h (renamed from usr/src/boot/sys/boot/common/part.h)0
-rw-r--r--usr/src/boot/common/paths.h (renamed from usr/src/boot/sys/boot/common/paths.h)0
-rw-r--r--usr/src/boot/common/pnp.c (renamed from usr/src/boot/sys/boot/common/pnp.c)0
-rw-r--r--usr/src/boot/common/rbx.h (renamed from usr/src/boot/sys/boot/common/rbx.h)0
-rw-r--r--usr/src/boot/common/reloc_elf.c (renamed from usr/src/boot/sys/boot/common/reloc_elf.c)0
-rw-r--r--usr/src/boot/common/reloc_elf32.c (renamed from usr/src/boot/sys/boot/common/reloc_elf32.c)0
-rw-r--r--usr/src/boot/common/reloc_elf64.c (renamed from usr/src/boot/sys/boot/common/reloc_elf64.c)0
-rw-r--r--usr/src/boot/common/self_reloc.c (renamed from usr/src/boot/sys/boot/common/self_reloc.c)0
-rw-r--r--usr/src/boot/common/tem.c (renamed from usr/src/boot/sys/boot/common/tem.c)0
-rw-r--r--usr/src/boot/common/util.c (renamed from usr/src/boot/sys/boot/common/util.c)0
-rw-r--r--usr/src/boot/common/util.h (renamed from usr/src/boot/sys/boot/common/util.h)0
-rw-r--r--usr/src/boot/common/vdisk.c (renamed from usr/src/boot/sys/boot/common/vdisk.c)0
-rw-r--r--usr/src/boot/common/zfs_cmd.c (renamed from usr/src/boot/sys/boot/common/zfs_cmd.c)0
-rw-r--r--usr/src/boot/efi/Makefile (renamed from usr/src/boot/sys/boot/efi/Makefile)0
-rw-r--r--usr/src/boot/efi/Makefile.inc (renamed from usr/src/boot/sys/boot/efi/Makefile.inc)0
-rw-r--r--usr/src/boot/efi/include/Guid/MemoryTypeInformation.h (renamed from usr/src/boot/sys/boot/efi/include/Guid/MemoryTypeInformation.h)0
-rw-r--r--usr/src/boot/efi/include/Guid/MtcVendor.h (renamed from usr/src/boot/sys/boot/efi/include/Guid/MtcVendor.h)0
-rw-r--r--usr/src/boot/efi/include/Guid/ZeroGuid.h (renamed from usr/src/boot/sys/boot/efi/include/Guid/ZeroGuid.h)0
-rw-r--r--usr/src/boot/efi/include/Protocol/EdidActive.h (renamed from usr/src/boot/sys/boot/efi/include/Protocol/EdidActive.h)0
-rw-r--r--usr/src/boot/efi/include/Protocol/EdidDiscovered.h (renamed from usr/src/boot/sys/boot/efi/include/Protocol/EdidDiscovered.h)0
-rw-r--r--usr/src/boot/efi/include/Protocol/EdidOverride.h (renamed from usr/src/boot/sys/boot/efi/include/Protocol/EdidOverride.h)0
-rw-r--r--usr/src/boot/efi/include/README (renamed from usr/src/boot/sys/boot/efi/include/README)0
-rw-r--r--usr/src/boot/efi/include/amd64/efibind.h (renamed from usr/src/boot/sys/boot/efi/include/amd64/efibind.h)0
-rw-r--r--usr/src/boot/efi/include/amd64/pe.h (renamed from usr/src/boot/sys/boot/efi/include/amd64/pe.h)0
-rw-r--r--usr/src/boot/efi/include/arm/efibind.h (renamed from usr/src/boot/sys/boot/efi/include/arm/efibind.h)0
-rw-r--r--usr/src/boot/efi/include/arm64/efibind.h (renamed from usr/src/boot/sys/boot/efi/include/arm64/efibind.h)0
-rw-r--r--usr/src/boot/efi/include/efi.h (renamed from usr/src/boot/sys/boot/efi/include/efi.h)0
-rw-r--r--usr/src/boot/efi/include/efi_driver_utils.h (renamed from usr/src/boot/sys/boot/efi/include/efi_driver_utils.h)0
-rw-r--r--usr/src/boot/efi/include/efi_drivers.h (renamed from usr/src/boot/sys/boot/efi/include/efi_drivers.h)0
-rw-r--r--usr/src/boot/efi/include/efi_nii.h (renamed from usr/src/boot/sys/boot/efi/include/efi_nii.h)0
-rw-r--r--usr/src/boot/efi/include/efiapi.h (renamed from usr/src/boot/sys/boot/efi/include/efiapi.h)0
-rw-r--r--usr/src/boot/efi/include/efichar.h (renamed from usr/src/boot/sys/boot/efi/include/efichar.h)0
-rw-r--r--usr/src/boot/efi/include/eficon.h (renamed from usr/src/boot/sys/boot/efi/include/eficon.h)0
-rw-r--r--usr/src/boot/efi/include/eficonsctl.h (renamed from usr/src/boot/sys/boot/efi/include/eficonsctl.h)0
-rw-r--r--usr/src/boot/efi/include/efidebug.h (renamed from usr/src/boot/sys/boot/efi/include/efidebug.h)0
-rw-r--r--usr/src/boot/efi/include/efidef.h (renamed from usr/src/boot/sys/boot/efi/include/efidef.h)0
-rw-r--r--usr/src/boot/efi/include/efidevp.h (renamed from usr/src/boot/sys/boot/efi/include/efidevp.h)0
-rw-r--r--usr/src/boot/efi/include/efierr.h (renamed from usr/src/boot/sys/boot/efi/include/efierr.h)0
-rw-r--r--usr/src/boot/efi/include/efifpswa.h (renamed from usr/src/boot/sys/boot/efi/include/efifpswa.h)0
-rw-r--r--usr/src/boot/efi/include/efifs.h (renamed from usr/src/boot/sys/boot/efi/include/efifs.h)0
-rw-r--r--usr/src/boot/efi/include/efigop.h (renamed from usr/src/boot/sys/boot/efi/include/efigop.h)0
-rw-r--r--usr/src/boot/efi/include/efigpt.h (renamed from usr/src/boot/sys/boot/efi/include/efigpt.h)0
-rw-r--r--usr/src/boot/efi/include/efiip.h (renamed from usr/src/boot/sys/boot/efi/include/efiip.h)0
-rw-r--r--usr/src/boot/efi/include/efilib.h (renamed from usr/src/boot/sys/boot/efi/include/efilib.h)0
-rw-r--r--usr/src/boot/efi/include/efinet.h (renamed from usr/src/boot/sys/boot/efi/include/efinet.h)0
-rw-r--r--usr/src/boot/efi/include/efipart.h (renamed from usr/src/boot/sys/boot/efi/include/efipart.h)0
-rw-r--r--usr/src/boot/efi/include/efipciio.h (renamed from usr/src/boot/sys/boot/efi/include/efipciio.h)0
-rw-r--r--usr/src/boot/efi/include/efipoint.h (renamed from usr/src/boot/sys/boot/efi/include/efipoint.h)0
-rw-r--r--usr/src/boot/efi/include/efiprot.h (renamed from usr/src/boot/sys/boot/efi/include/efiprot.h)0
-rw-r--r--usr/src/boot/efi/include/efipxebc.h (renamed from usr/src/boot/sys/boot/efi/include/efipxebc.h)0
-rw-r--r--usr/src/boot/efi/include/efiser.h (renamed from usr/src/boot/sys/boot/efi/include/efiser.h)0
-rw-r--r--usr/src/boot/efi/include/efistdarg.h (renamed from usr/src/boot/sys/boot/efi/include/efistdarg.h)0
-rw-r--r--usr/src/boot/efi/include/efitcp.h (renamed from usr/src/boot/sys/boot/efi/include/efitcp.h)0
-rw-r--r--usr/src/boot/efi/include/efiudp.h (renamed from usr/src/boot/sys/boot/efi/include/efiudp.h)0
-rw-r--r--usr/src/boot/efi/include/efiuga.h (renamed from usr/src/boot/sys/boot/efi/include/efiuga.h)0
-rw-r--r--usr/src/boot/efi/include/efizfs.h (renamed from usr/src/boot/sys/boot/efi/include/efizfs.h)0
-rw-r--r--usr/src/boot/efi/include/i386/efibind.h (renamed from usr/src/boot/sys/boot/efi/include/i386/efibind.h)0
-rw-r--r--usr/src/boot/efi/include/i386/pe.h (renamed from usr/src/boot/sys/boot/efi/include/i386/pe.h)0
-rw-r--r--usr/src/boot/efi/libefi/Makefile (renamed from usr/src/boot/sys/boot/efi/libefi/Makefile)0
-rw-r--r--usr/src/boot/efi/libefi/Makefile.com (renamed from usr/src/boot/sys/boot/efi/libefi/Makefile.com)12
-rw-r--r--usr/src/boot/efi/libefi/amd64/Makefile (renamed from usr/src/boot/sys/boot/efi/libefi/amd64/Makefile)0
-rw-r--r--usr/src/boot/efi/libefi/delay.c (renamed from usr/src/boot/sys/boot/efi/libefi/delay.c)0
-rw-r--r--usr/src/boot/efi/libefi/devicename.c (renamed from usr/src/boot/sys/boot/efi/libefi/devicename.c)0
-rw-r--r--usr/src/boot/efi/libefi/devpath.c (renamed from usr/src/boot/sys/boot/efi/libefi/devpath.c)0
-rw-r--r--usr/src/boot/efi/libefi/efi_console.c (renamed from usr/src/boot/sys/boot/efi/libefi/efi_console.c)0
-rw-r--r--usr/src/boot/efi/libefi/efi_driver_utils.c (renamed from usr/src/boot/sys/boot/efi/libefi/efi_driver_utils.c)0
-rw-r--r--usr/src/boot/efi/libefi/efichar.c (renamed from usr/src/boot/sys/boot/efi/libefi/efichar.c)0
-rw-r--r--usr/src/boot/efi/libefi/efienv.c (renamed from usr/src/boot/sys/boot/efi/libefi/efienv.c)0
-rw-r--r--usr/src/boot/efi/libefi/efinet.c (renamed from usr/src/boot/sys/boot/efi/libefi/efinet.c)0
-rw-r--r--usr/src/boot/efi/libefi/efipart.c (renamed from usr/src/boot/sys/boot/efi/libefi/efipart.c)0
-rw-r--r--usr/src/boot/efi/libefi/efizfs.c (renamed from usr/src/boot/sys/boot/efi/libefi/efizfs.c)0
-rw-r--r--usr/src/boot/efi/libefi/env.c (renamed from usr/src/boot/sys/boot/efi/libefi/env.c)0
-rw-r--r--usr/src/boot/efi/libefi/errno.c (renamed from usr/src/boot/sys/boot/efi/libefi/errno.c)0
-rw-r--r--usr/src/boot/efi/libefi/handles.c (renamed from usr/src/boot/sys/boot/efi/libefi/handles.c)0
-rw-r--r--usr/src/boot/efi/libefi/i386/Makefile (renamed from usr/src/boot/sys/boot/efi/libefi/i386/Makefile)0
-rw-r--r--usr/src/boot/efi/libefi/libefi.c (renamed from usr/src/boot/sys/boot/efi/libefi/libefi.c)0
-rw-r--r--usr/src/boot/efi/libefi/time.c (renamed from usr/src/boot/sys/boot/efi/libefi/time.c)0
-rw-r--r--usr/src/boot/efi/libefi/time_event.c (renamed from usr/src/boot/sys/boot/efi/libefi/time_event.c)0
-rw-r--r--usr/src/boot/efi/libefi/wchar.c (renamed from usr/src/boot/sys/boot/efi/libefi/wchar.c)0
-rw-r--r--usr/src/boot/efi/loader/Makefile (renamed from usr/src/boot/sys/boot/efi/loader/Makefile)0
-rw-r--r--usr/src/boot/efi/loader/Makefile.com (renamed from usr/src/boot/sys/boot/efi/loader/Makefile.com)31
-rw-r--r--usr/src/boot/efi/loader/acpi.c (renamed from usr/src/boot/sys/boot/efi/loader/acpi.c)0
-rw-r--r--usr/src/boot/efi/loader/amd64/Makefile (renamed from usr/src/boot/sys/boot/efi/loader/amd64/Makefile)0
-rw-r--r--usr/src/boot/efi/loader/arch/amd64/Makefile.inc (renamed from usr/src/boot/sys/boot/efi/loader/arch/amd64/Makefile.inc)0
-rw-r--r--usr/src/boot/efi/loader/arch/amd64/amd64_tramp.S (renamed from usr/src/boot/sys/boot/efi/loader/arch/amd64/amd64_tramp.S)0
-rw-r--r--usr/src/boot/efi/loader/arch/amd64/elf64_freebsd.c (renamed from usr/src/boot/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c)0
-rw-r--r--usr/src/boot/efi/loader/arch/amd64/exc.S (renamed from usr/src/boot/sys/boot/efi/loader/arch/amd64/exc.S)0
-rw-r--r--usr/src/boot/efi/loader/arch/amd64/ldscript.amd64 (renamed from usr/src/boot/sys/boot/efi/loader/arch/amd64/ldscript.amd64)0
-rw-r--r--usr/src/boot/efi/loader/arch/amd64/multiboot_tramp.S (renamed from usr/src/boot/sys/boot/efi/loader/arch/amd64/multiboot_tramp.S)0
-rw-r--r--usr/src/boot/efi/loader/arch/amd64/start.S (renamed from usr/src/boot/sys/boot/efi/loader/arch/amd64/start.S)0
-rw-r--r--usr/src/boot/efi/loader/arch/amd64/trap.c (renamed from usr/src/boot/sys/boot/efi/loader/arch/amd64/trap.c)0
-rw-r--r--usr/src/boot/efi/loader/arch/arm/Makefile.inc (renamed from usr/src/boot/sys/boot/efi/loader/arch/arm/Makefile.inc)0
-rw-r--r--usr/src/boot/efi/loader/arch/arm/exec.c (renamed from usr/src/boot/sys/boot/efi/loader/arch/arm/exec.c)0
-rw-r--r--usr/src/boot/efi/loader/arch/arm/ldscript.arm (renamed from usr/src/boot/sys/boot/efi/loader/arch/arm/ldscript.arm)0
-rw-r--r--usr/src/boot/efi/loader/arch/arm/start.S (renamed from usr/src/boot/sys/boot/efi/loader/arch/arm/start.S)0
-rw-r--r--usr/src/boot/efi/loader/arch/arm64/Makefile.inc (renamed from usr/src/boot/sys/boot/efi/loader/arch/arm64/Makefile.inc)0
-rw-r--r--usr/src/boot/efi/loader/arch/arm64/exec.c (renamed from usr/src/boot/sys/boot/efi/loader/arch/arm64/exec.c)0
-rw-r--r--usr/src/boot/efi/loader/arch/arm64/ldscript.arm64 (renamed from usr/src/boot/sys/boot/efi/loader/arch/arm64/ldscript.arm64)0
-rw-r--r--usr/src/boot/efi/loader/arch/arm64/start.S (renamed from usr/src/boot/sys/boot/efi/loader/arch/arm64/start.S)0
-rw-r--r--usr/src/boot/efi/loader/arch/i386/Makefile.inc (renamed from usr/src/boot/sys/boot/efi/loader/arch/i386/Makefile.inc)0
-rw-r--r--usr/src/boot/efi/loader/arch/i386/bootinfo.c (renamed from usr/src/boot/sys/boot/efi/loader/arch/i386/bootinfo.c)0
-rw-r--r--usr/src/boot/efi/loader/arch/i386/efimd.c (renamed from usr/src/boot/sys/boot/efi/loader/arch/i386/efimd.c)0
-rw-r--r--usr/src/boot/efi/loader/arch/i386/elf32_freebsd.c (renamed from usr/src/boot/sys/boot/efi/loader/arch/i386/elf32_freebsd.c)0
-rw-r--r--usr/src/boot/efi/loader/arch/i386/exec.c (renamed from usr/src/boot/sys/boot/efi/loader/arch/i386/exec.c)0
-rw-r--r--usr/src/boot/efi/loader/arch/i386/i386_copy.c (renamed from usr/src/boot/sys/boot/efi/loader/arch/i386/i386_copy.c)0
-rw-r--r--usr/src/boot/efi/loader/arch/i386/ldscript.i386 (renamed from usr/src/boot/sys/boot/efi/loader/arch/i386/ldscript.i386)0
-rw-r--r--usr/src/boot/efi/loader/arch/i386/multiboot_tramp.S (renamed from usr/src/boot/sys/boot/efi/loader/arch/i386/multiboot_tramp.S)0
-rw-r--r--usr/src/boot/efi/loader/arch/i386/start.S (renamed from usr/src/boot/sys/boot/efi/loader/arch/i386/start.S)0
-rw-r--r--usr/src/boot/efi/loader/autoload.c (renamed from usr/src/boot/sys/boot/efi/loader/autoload.c)0
-rw-r--r--usr/src/boot/efi/loader/bootinfo.c (renamed from usr/src/boot/sys/boot/efi/loader/bootinfo.c)0
-rw-r--r--usr/src/boot/efi/loader/conf.c (renamed from usr/src/boot/sys/boot/efi/loader/conf.c)0
-rw-r--r--usr/src/boot/efi/loader/copy.c (renamed from usr/src/boot/sys/boot/efi/loader/copy.c)0
-rw-r--r--usr/src/boot/efi/loader/efi_main.c (renamed from usr/src/boot/sys/boot/efi/loader/efi_main.c)0
-rw-r--r--usr/src/boot/efi/loader/efiserialio.c (renamed from usr/src/boot/sys/boot/efi/loader/efiserialio.c)0
-rw-r--r--usr/src/boot/efi/loader/framebuffer.c (renamed from usr/src/boot/sys/boot/efi/loader/framebuffer.c)0
-rw-r--r--usr/src/boot/efi/loader/framebuffer.h (renamed from usr/src/boot/sys/boot/efi/loader/framebuffer.h)0
-rw-r--r--usr/src/boot/efi/loader/i386/Makefile (renamed from usr/src/boot/sys/boot/efi/loader/i386/Makefile)0
-rw-r--r--usr/src/boot/efi/loader/loader_efi.h (renamed from usr/src/boot/sys/boot/efi/loader/loader_efi.h)0
-rw-r--r--usr/src/boot/efi/loader/main.c (renamed from usr/src/boot/sys/boot/efi/loader/main.c)6
-rw-r--r--usr/src/boot/efi/loader/memmap.c (renamed from usr/src/boot/sys/boot/efi/loader/memmap.c)0
-rw-r--r--usr/src/boot/efi/loader/reloc.c (renamed from usr/src/boot/sys/boot/efi/loader/reloc.c)0
-rw-r--r--usr/src/boot/forth/Makefile71
-rw-r--r--usr/src/boot/forth/beadm.4th (renamed from usr/src/boot/sys/boot/forth/beadm.4th)0
-rw-r--r--usr/src/boot/forth/beastie.4th (renamed from usr/src/boot/sys/boot/forth/beastie.4th)0
-rw-r--r--usr/src/boot/forth/brand-fbsd.4th (renamed from usr/src/boot/sys/boot/forth/brand-fbsd.4th)0
-rw-r--r--usr/src/boot/forth/brand-illumos.4th (renamed from usr/src/boot/sys/boot/forth/brand-illumos.4th)0
-rw-r--r--usr/src/boot/forth/brand.4th (renamed from usr/src/boot/sys/boot/forth/brand.4th)0
-rw-r--r--usr/src/boot/forth/check-password.4th (renamed from usr/src/boot/sys/boot/forth/check-password.4th)0
-rw-r--r--usr/src/boot/forth/color.4th (renamed from usr/src/boot/sys/boot/forth/color.4th)0
-rw-r--r--usr/src/boot/forth/delay.4th (renamed from usr/src/boot/sys/boot/forth/delay.4th)0
-rw-r--r--usr/src/boot/forth/efi.4th (renamed from usr/src/boot/sys/boot/forth/efi.4th)0
-rw-r--r--usr/src/boot/forth/frames.4th (renamed from usr/src/boot/sys/boot/forth/frames.4th)0
-rw-r--r--usr/src/boot/forth/illumos-brand.png (renamed from usr/src/boot/sys/boot/forth/illumos-brand.png)bin37587 -> 37587 bytes
-rw-r--r--usr/src/boot/forth/illumos-logo.png (renamed from usr/src/boot/sys/boot/forth/illumos-logo.png)bin11979 -> 11979 bytes
-rw-r--r--usr/src/boot/forth/loader.4th (renamed from usr/src/boot/sys/boot/forth/loader.4th)0
-rw-r--r--usr/src/boot/forth/loader.conf (renamed from usr/src/boot/sys/boot/forth/loader.conf)0
-rw-r--r--usr/src/boot/forth/loader.rc (renamed from usr/src/boot/sys/boot/i386/loader/loader.rc)0
-rw-r--r--usr/src/boot/forth/logo-beastie.4th (renamed from usr/src/boot/sys/boot/forth/logo-beastie.4th)0
-rw-r--r--usr/src/boot/forth/logo-beastiebw.4th (renamed from usr/src/boot/sys/boot/forth/logo-beastiebw.4th)0
-rw-r--r--usr/src/boot/forth/logo-fbsdbw.4th (renamed from usr/src/boot/sys/boot/forth/logo-fbsdbw.4th)0
-rw-r--r--usr/src/boot/forth/logo-illumos.4th (renamed from usr/src/boot/sys/boot/forth/logo-illumos.4th)0
-rw-r--r--usr/src/boot/forth/logo-orb.4th (renamed from usr/src/boot/sys/boot/forth/logo-orb.4th)0
-rw-r--r--usr/src/boot/forth/logo-orbbw.4th (renamed from usr/src/boot/sys/boot/forth/logo-orbbw.4th)0
-rw-r--r--usr/src/boot/forth/menu-commands.4th (renamed from usr/src/boot/sys/boot/forth/menu-commands.4th)0
-rw-r--r--usr/src/boot/forth/menu.4th (renamed from usr/src/boot/sys/boot/forth/menu.4th)0
-rw-r--r--usr/src/boot/forth/menu.rc (renamed from usr/src/boot/sys/boot/forth/menu.rc)0
-rw-r--r--usr/src/boot/forth/menusets.4th (renamed from usr/src/boot/sys/boot/forth/menusets.4th)0
-rw-r--r--usr/src/boot/forth/pcibios.4th (renamed from usr/src/boot/sys/boot/forth/pcibios.4th)0
-rw-r--r--usr/src/boot/forth/pnp.4th (renamed from usr/src/boot/sys/boot/forth/pnp.4th)0
-rw-r--r--usr/src/boot/forth/screen.4th (renamed from usr/src/boot/sys/boot/forth/screen.4th)0
-rw-r--r--usr/src/boot/forth/shortcuts.4th (renamed from usr/src/boot/sys/boot/forth/shortcuts.4th)0
-rw-r--r--usr/src/boot/forth/support.4th (renamed from usr/src/boot/sys/boot/forth/support.4th)0
-rw-r--r--usr/src/boot/forth/version.4th (renamed from usr/src/boot/sys/boot/forth/version.4th)0
-rw-r--r--usr/src/boot/i386/Makefile (renamed from usr/src/boot/sys/boot/i386/Makefile)0
-rw-r--r--usr/src/boot/i386/Makefile.inc (renamed from usr/src/boot/sys/boot/i386/Makefile.inc)4
-rw-r--r--usr/src/boot/i386/boot.ldscript (renamed from usr/src/boot/sys/boot/i386/boot.ldscript)0
-rw-r--r--usr/src/boot/i386/btx/Makefile (renamed from usr/src/boot/sys/boot/i386/btx/Makefile)0
-rw-r--r--usr/src/boot/i386/btx/btx/Makefile (renamed from usr/src/boot/sys/boot/i386/btx/btx/Makefile)2
-rw-r--r--usr/src/boot/i386/btx/btx/btx.S (renamed from usr/src/boot/sys/boot/i386/btx/btx/btx.S)0
-rw-r--r--usr/src/boot/i386/btx/btxldr/Makefile (renamed from usr/src/boot/sys/boot/i386/btx/btxldr/Makefile)2
-rw-r--r--usr/src/boot/i386/btx/btxldr/btxldr.S (renamed from usr/src/boot/sys/boot/i386/btx/btxldr/btxldr.S)0
-rw-r--r--usr/src/boot/i386/btx/lib/Makefile (renamed from usr/src/boot/sys/boot/i386/btx/lib/Makefile)2
-rw-r--r--usr/src/boot/i386/btx/lib/btxcsu.S (renamed from usr/src/boot/sys/boot/i386/btx/lib/btxcsu.S)0
-rw-r--r--usr/src/boot/i386/btx/lib/btxsys.s (renamed from usr/src/boot/sys/boot/i386/btx/lib/btxsys.s)0
-rw-r--r--usr/src/boot/i386/btx/lib/btxv86.h (renamed from usr/src/boot/sys/boot/i386/btx/lib/btxv86.h)0
-rw-r--r--usr/src/boot/i386/btx/lib/btxv86.s (renamed from usr/src/boot/sys/boot/i386/btx/lib/btxv86.s)0
-rw-r--r--usr/src/boot/i386/cdboot/Makefile (renamed from usr/src/boot/sys/boot/i386/cdboot/Makefile)2
-rw-r--r--usr/src/boot/i386/cdboot/cdboot.S (renamed from usr/src/boot/sys/boot/i386/cdboot/cdboot.S)0
-rw-r--r--usr/src/boot/i386/common/bootargs.h (renamed from usr/src/boot/sys/boot/i386/common/bootargs.h)0
-rw-r--r--usr/src/boot/i386/common/cons.c (renamed from usr/src/boot/sys/boot/i386/common/cons.c)0
-rw-r--r--usr/src/boot/i386/common/cons.h (renamed from usr/src/boot/sys/boot/i386/common/cons.h)0
-rw-r--r--usr/src/boot/i386/common/drv.c (renamed from usr/src/boot/sys/boot/i386/common/drv.c)0
-rw-r--r--usr/src/boot/i386/common/drv.h (renamed from usr/src/boot/sys/boot/i386/common/drv.h)0
-rw-r--r--usr/src/boot/i386/common/edd.h (renamed from usr/src/boot/sys/boot/i386/common/edd.h)0
-rw-r--r--usr/src/boot/i386/gptzfsboot/Makefile (renamed from usr/src/boot/sys/boot/i386/gptzfsboot/Makefile)18
-rw-r--r--usr/src/boot/i386/gptzfsboot/gptldr.S (renamed from usr/src/boot/sys/boot/i386/gptzfsboot/gptldr.S)0
-rw-r--r--usr/src/boot/i386/gptzfsboot/lib.h (renamed from usr/src/boot/sys/boot/i386/gptzfsboot/lib.h)0
-rw-r--r--usr/src/boot/i386/gptzfsboot/sio.S (renamed from usr/src/boot/sys/boot/i386/gptzfsboot/sio.S)0
-rw-r--r--usr/src/boot/i386/gptzfsboot/zfsboot.c (renamed from usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c)6
-rw-r--r--usr/src/boot/i386/isoboot/Makefile (renamed from usr/src/boot/sys/boot/i386/isoboot/Makefile)14
-rw-r--r--usr/src/boot/i386/isoboot/cd9660read.c (renamed from usr/src/boot/sys/boot/i386/isoboot/cd9660read.c)0
-rw-r--r--usr/src/boot/i386/isoboot/isoboot.c (renamed from usr/src/boot/sys/boot/i386/isoboot/isoboot.c)0
-rw-r--r--usr/src/boot/i386/libi386/Makefile (renamed from usr/src/boot/sys/boot/i386/libi386/Makefile)29
-rw-r--r--usr/src/boot/i386/libi386/amd64_tramp.S (renamed from usr/src/boot/sys/boot/i386/libi386/amd64_tramp.S)0
-rw-r--r--usr/src/boot/i386/libi386/bio.c (renamed from usr/src/boot/sys/boot/i386/libi386/bio.c)0
-rw-r--r--usr/src/boot/i386/libi386/biosacpi.c (renamed from usr/src/boot/sys/boot/i386/libi386/biosacpi.c)0
-rw-r--r--usr/src/boot/i386/libi386/biosdisk.c (renamed from usr/src/boot/sys/boot/i386/libi386/biosdisk.c)0
-rw-r--r--usr/src/boot/i386/libi386/biosmem.c (renamed from usr/src/boot/sys/boot/i386/libi386/biosmem.c)0
-rw-r--r--usr/src/boot/i386/libi386/biospci.c (renamed from usr/src/boot/sys/boot/i386/libi386/biospci.c)0
-rw-r--r--usr/src/boot/i386/libi386/biospnp.c (renamed from usr/src/boot/sys/boot/i386/libi386/biospnp.c)0
-rw-r--r--usr/src/boot/i386/libi386/biossmap.c (renamed from usr/src/boot/sys/boot/i386/libi386/biossmap.c)0
-rw-r--r--usr/src/boot/i386/libi386/bootinfo.c (renamed from usr/src/boot/sys/boot/i386/libi386/bootinfo.c)0
-rw-r--r--usr/src/boot/i386/libi386/bootinfo32.c (renamed from usr/src/boot/sys/boot/i386/libi386/bootinfo32.c)0
-rw-r--r--usr/src/boot/i386/libi386/bootinfo64.c (renamed from usr/src/boot/sys/boot/i386/libi386/bootinfo64.c)0
-rw-r--r--usr/src/boot/i386/libi386/comconsole.c (renamed from usr/src/boot/sys/boot/i386/libi386/comconsole.c)0
-rw-r--r--usr/src/boot/i386/libi386/cpuid.c (renamed from usr/src/boot/sys/boot/i386/libi386/cpuid.c)0
-rw-r--r--usr/src/boot/i386/libi386/devicename.c (renamed from usr/src/boot/sys/boot/i386/libi386/devicename.c)0
-rw-r--r--usr/src/boot/i386/libi386/elf32_freebsd.c (renamed from usr/src/boot/sys/boot/i386/libi386/elf32_freebsd.c)0
-rw-r--r--usr/src/boot/i386/libi386/elf64_freebsd.c (renamed from usr/src/boot/sys/boot/i386/libi386/elf64_freebsd.c)0
-rw-r--r--usr/src/boot/i386/libi386/i386_copy.c (renamed from usr/src/boot/sys/boot/i386/libi386/i386_copy.c)0
-rw-r--r--usr/src/boot/i386/libi386/i386_module.c (renamed from usr/src/boot/sys/boot/i386/libi386/i386_module.c)0
-rw-r--r--usr/src/boot/i386/libi386/libi386.h (renamed from usr/src/boot/sys/boot/i386/libi386/libi386.h)0
-rw-r--r--usr/src/boot/i386/libi386/linux.c (renamed from usr/src/boot/sys/boot/i386/libi386/linux.c)0
-rw-r--r--usr/src/boot/i386/libi386/linux.h (renamed from usr/src/boot/sys/boot/i386/libi386/linux.h)0
-rw-r--r--usr/src/boot/i386/libi386/multiboot.c (renamed from usr/src/boot/sys/boot/i386/libi386/multiboot.c)0
-rw-r--r--usr/src/boot/i386/libi386/multiboot_tramp.S (renamed from usr/src/boot/sys/boot/i386/libi386/multiboot_tramp.S)0
-rw-r--r--usr/src/boot/i386/libi386/nullconsole.c (renamed from usr/src/boot/sys/boot/i386/libi386/nullconsole.c)0
-rw-r--r--usr/src/boot/i386/libi386/pread.c (renamed from usr/src/boot/sys/boot/i386/libi386/pread.c)0
-rw-r--r--usr/src/boot/i386/libi386/pxe.c (renamed from usr/src/boot/sys/boot/i386/libi386/pxe.c)0
-rw-r--r--usr/src/boot/i386/libi386/pxe.h (renamed from usr/src/boot/sys/boot/i386/libi386/pxe.h)0
-rw-r--r--usr/src/boot/i386/libi386/pxetramp.s (renamed from usr/src/boot/sys/boot/i386/libi386/pxetramp.s)0
-rw-r--r--usr/src/boot/i386/libi386/relocater_tramp.S (renamed from usr/src/boot/sys/boot/i386/libi386/relocater_tramp.S)0
-rw-r--r--usr/src/boot/i386/libi386/spinconsole.c (renamed from usr/src/boot/sys/boot/i386/libi386/spinconsole.c)0
-rw-r--r--usr/src/boot/i386/libi386/time.c (renamed from usr/src/boot/sys/boot/i386/libi386/time.c)0
-rw-r--r--usr/src/boot/i386/libi386/vbe.c (renamed from usr/src/boot/sys/boot/i386/libi386/vbe.c)0
-rw-r--r--usr/src/boot/i386/libi386/vbe.h (renamed from usr/src/boot/sys/boot/i386/libi386/vbe.h)0
-rw-r--r--usr/src/boot/i386/libi386/vidconsole.c (renamed from usr/src/boot/sys/boot/i386/libi386/vidconsole.c)0
-rw-r--r--usr/src/boot/i386/loader/Makefile (renamed from usr/src/boot/sys/boot/i386/loader/Makefile)49
-rw-r--r--usr/src/boot/i386/loader/chain.c (renamed from usr/src/boot/sys/boot/i386/loader/chain.c)0
-rw-r--r--usr/src/boot/i386/loader/conf.c (renamed from usr/src/boot/sys/boot/i386/loader/conf.c)0
-rw-r--r--usr/src/boot/i386/loader/help.i386 (renamed from usr/src/boot/sys/boot/i386/loader/help.i386)0
-rw-r--r--usr/src/boot/i386/loader/ldscript.i386 (renamed from usr/src/boot/sys/boot/i386/loader/ldscript.i386)0
-rw-r--r--usr/src/boot/i386/loader/main.c (renamed from usr/src/boot/sys/boot/i386/loader/main.c)8
-rw-r--r--usr/src/boot/i386/pmbr/Makefile (renamed from usr/src/boot/sys/boot/i386/pmbr/Makefile)2
-rw-r--r--usr/src/boot/i386/pmbr/pmbr.s (renamed from usr/src/boot/sys/boot/i386/pmbr/pmbr.s)0
-rw-r--r--usr/src/boot/i386/pxeldr/Makefile (renamed from usr/src/boot/sys/boot/i386/pxeldr/Makefile)4
-rw-r--r--usr/src/boot/i386/pxeldr/pxeldr.S (renamed from usr/src/boot/sys/boot/i386/pxeldr/pxeldr.S)0
-rw-r--r--usr/src/boot/lib/libstand/mips/_setjmp.S108
-rw-r--r--usr/src/boot/lib/libstand/powerpc/_setjmp.S115
-rw-r--r--usr/src/boot/lib/libstand/powerpc/syncicache.c103
-rw-r--r--usr/src/boot/lib/libstand/sparc64/_setjmp.S94
-rw-r--r--usr/src/boot/libficl/Makefile (renamed from usr/src/boot/sys/boot/libficl/Makefile)0
-rw-r--r--usr/src/boot/libficl/Makefile.com (renamed from usr/src/boot/sys/boot/libficl/Makefile.com)12
-rw-r--r--usr/src/boot/libficl/amd64/Makefile (renamed from usr/src/boot/sys/boot/libficl/amd64/Makefile)2
-rw-r--r--usr/src/boot/libficl/ficllocal.h (renamed from usr/src/boot/sys/boot/libficl/ficllocal.h)0
-rw-r--r--usr/src/boot/libficl/i386/Makefile (renamed from usr/src/boot/sys/boot/libficl/i386/Makefile)2
-rw-r--r--usr/src/boot/libficl/softcore/Makefile (renamed from usr/src/boot/sys/boot/libficl/softcore/Makefile)0
-rw-r--r--usr/src/boot/libsa/Makefile (renamed from usr/src/boot/sys/boot/libstand/Makefile)0
-rw-r--r--usr/src/boot/libsa/Makefile.com (renamed from usr/src/boot/sys/boot/libstand/Makefile.com)17
-rw-r--r--usr/src/boot/libsa/Makefile.inc (renamed from usr/src/boot/lib/libstand/Makefile.inc)48
-rw-r--r--usr/src/boot/libsa/__main.c (renamed from usr/src/boot/lib/libstand/__main.c)0
-rw-r--r--usr/src/boot/libsa/abort.c (renamed from usr/src/boot/lib/libstand/abort.c)0
-rw-r--r--usr/src/boot/libsa/amd64/Makefile (renamed from usr/src/boot/sys/boot/libstand/amd64/Makefile)4
-rw-r--r--usr/src/boot/libsa/amd64/_setjmp.S (renamed from usr/src/boot/lib/libstand/amd64/_setjmp.S)0
-rw-r--r--usr/src/boot/libsa/arp.c (renamed from usr/src/boot/lib/libstand/arp.c)0
-rw-r--r--usr/src/boot/libsa/assert.c (renamed from usr/src/boot/lib/libstand/assert.c)0
-rw-r--r--usr/src/boot/libsa/bcd.c (renamed from usr/src/boot/lib/libstand/bcd.c)0
-rw-r--r--usr/src/boot/libsa/bootp.c (renamed from usr/src/boot/lib/libstand/bootp.c)0
-rw-r--r--usr/src/boot/libsa/bootp.h (renamed from usr/src/boot/lib/libstand/bootp.h)0
-rw-r--r--usr/src/boot/libsa/bootparam.c (renamed from usr/src/boot/lib/libstand/bootparam.c)0
-rw-r--r--usr/src/boot/libsa/bootparam.h (renamed from usr/src/boot/lib/libstand/bootparam.h)0
-rw-r--r--usr/src/boot/libsa/bzipfs.c (renamed from usr/src/boot/lib/libstand/bzipfs.c)0
-rw-r--r--usr/src/boot/libsa/cd9660.c (renamed from usr/src/boot/lib/libstand/cd9660.c)0
-rw-r--r--usr/src/boot/libsa/close.c (renamed from usr/src/boot/lib/libstand/close.c)0
-rw-r--r--usr/src/boot/libsa/closeall.c (renamed from usr/src/boot/lib/libstand/closeall.c)0
-rw-r--r--usr/src/boot/libsa/crypto/Makefile.inc (renamed from usr/src/boot/lib/libstand/crypto/Makefile.inc)0
-rw-r--r--usr/src/boot/libsa/crypto/digest.c (renamed from usr/src/boot/lib/libstand/crypto/digest.c)0
-rw-r--r--usr/src/boot/libsa/crypto/libcrypto.h (renamed from usr/src/boot/lib/libstand/crypto/libcrypto.h)0
-rw-r--r--usr/src/boot/libsa/dev.c (renamed from usr/src/boot/lib/libstand/dev.c)0
-rw-r--r--usr/src/boot/libsa/dosfs.c (renamed from usr/src/boot/lib/libstand/dosfs.c)0
-rw-r--r--usr/src/boot/libsa/dosfs.h (renamed from usr/src/boot/lib/libstand/dosfs.h)0
-rw-r--r--usr/src/boot/libsa/environment.c (renamed from usr/src/boot/lib/libstand/environment.c)0
-rw-r--r--usr/src/boot/libsa/ether.c (renamed from usr/src/boot/lib/libstand/ether.c)0
-rw-r--r--usr/src/boot/libsa/ext2fs.c (renamed from usr/src/boot/lib/libstand/ext2fs.c)0
-rw-r--r--usr/src/boot/libsa/fstat.c (renamed from usr/src/boot/lib/libstand/fstat.c)0
-rw-r--r--usr/src/boot/libsa/getopt.c (renamed from usr/src/boot/lib/libstand/getopt.c)0
-rw-r--r--usr/src/boot/libsa/gets.c (renamed from usr/src/boot/lib/libstand/gets.c)0
-rw-r--r--usr/src/boot/libsa/globals.c (renamed from usr/src/boot/lib/libstand/globals.c)0
-rw-r--r--usr/src/boot/libsa/gzipfs.c (renamed from usr/src/boot/lib/libstand/gzipfs.c)0
-rw-r--r--usr/src/boot/libsa/i386/Makefile (renamed from usr/src/boot/sys/boot/libstand/i386/Makefile)6
-rw-r--r--usr/src/boot/libsa/i386/_setjmp.S (renamed from usr/src/boot/lib/libstand/i386/_setjmp.S)0
-rw-r--r--usr/src/boot/libsa/in_cksum.c (renamed from usr/src/boot/lib/libstand/in_cksum.c)0
-rw-r--r--usr/src/boot/libsa/inet_ntoa.c (renamed from usr/src/boot/lib/libstand/inet_ntoa.c)0
-rw-r--r--usr/src/boot/libsa/ioctl.c (renamed from usr/src/boot/lib/libstand/ioctl.c)0
-rw-r--r--usr/src/boot/libsa/iodesc.h (renamed from usr/src/boot/lib/libstand/iodesc.h)0
-rw-r--r--usr/src/boot/libsa/ip.c (renamed from usr/src/boot/lib/libstand/ip.c)0
-rw-r--r--usr/src/boot/libsa/lseek.c (renamed from usr/src/boot/lib/libstand/lseek.c)0
-rw-r--r--usr/src/boot/libsa/net.c (renamed from usr/src/boot/lib/libstand/net.c)0
-rw-r--r--usr/src/boot/libsa/net.h (renamed from usr/src/boot/lib/libstand/net.h)0
-rw-r--r--usr/src/boot/libsa/netif.c (renamed from usr/src/boot/lib/libstand/netif.c)0
-rw-r--r--usr/src/boot/libsa/netif.h (renamed from usr/src/boot/lib/libstand/netif.h)0
-rw-r--r--usr/src/boot/libsa/nfs.c (renamed from usr/src/boot/lib/libstand/nfs.c)0
-rw-r--r--usr/src/boot/libsa/nfsv2.h (renamed from usr/src/boot/lib/libstand/nfsv2.h)0
-rw-r--r--usr/src/boot/libsa/ntoh.c (renamed from usr/src/boot/lib/libc/net/ntoh.c)0
-rw-r--r--usr/src/boot/libsa/nullfs.c (renamed from usr/src/boot/lib/libstand/nullfs.c)0
-rw-r--r--usr/src/boot/libsa/open.c (renamed from usr/src/boot/lib/libstand/open.c)0
-rw-r--r--usr/src/boot/libsa/pager.c (renamed from usr/src/boot/lib/libstand/pager.c)0
-rw-r--r--usr/src/boot/libsa/panic.c (renamed from usr/src/boot/lib/libstand/panic.c)0
-rw-r--r--usr/src/boot/libsa/pkgfs.c (renamed from usr/src/boot/lib/libstand/pkgfs.c)0
-rw-r--r--usr/src/boot/libsa/printf.c (renamed from usr/src/boot/lib/libstand/printf.c)0
-rw-r--r--usr/src/boot/libsa/qdivrem.c (renamed from usr/src/boot/lib/libstand/qdivrem.c)0
-rw-r--r--usr/src/boot/libsa/quad.h (renamed from usr/src/boot/lib/libstand/quad.h)0
-rw-r--r--usr/src/boot/libsa/random.c (renamed from usr/src/boot/lib/libstand/random.c)0
-rw-r--r--usr/src/boot/libsa/rarp.c (renamed from usr/src/boot/lib/libstand/rarp.c)0
-rw-r--r--usr/src/boot/libsa/read.c (renamed from usr/src/boot/lib/libstand/read.c)0
-rw-r--r--usr/src/boot/libsa/readdir.c (renamed from usr/src/boot/lib/libstand/readdir.c)0
-rw-r--r--usr/src/boot/libsa/rpc.c (renamed from usr/src/boot/lib/libstand/rpc.c)0
-rw-r--r--usr/src/boot/libsa/rpc.h (renamed from usr/src/boot/lib/libstand/rpc.h)0
-rw-r--r--usr/src/boot/libsa/rpcv2.h (renamed from usr/src/boot/lib/libstand/rpcv2.h)0
-rw-r--r--usr/src/boot/libsa/saioctl.h (renamed from usr/src/boot/lib/libstand/saioctl.h)0
-rw-r--r--usr/src/boot/libsa/sbrk.c (renamed from usr/src/boot/lib/libstand/sbrk.c)0
-rw-r--r--usr/src/boot/libsa/smbios.c (renamed from usr/src/boot/sys/boot/i386/libi386/smbios.c)13
-rw-r--r--usr/src/boot/libsa/smbios.h (renamed from usr/src/boot/sys/boot/i386/libi386/smbios.h)4
-rw-r--r--usr/src/boot/libsa/splitfs.c (renamed from usr/src/boot/lib/libstand/splitfs.c)0
-rw-r--r--usr/src/boot/libsa/stand.h (renamed from usr/src/boot/lib/libstand/stand.h)5
-rw-r--r--usr/src/boot/libsa/stat.c (renamed from usr/src/boot/lib/libstand/stat.c)0
-rw-r--r--usr/src/boot/libsa/strcasecmp.c (renamed from usr/src/boot/lib/libstand/strcasecmp.c)0
-rw-r--r--usr/src/boot/libsa/strdup.c (renamed from usr/src/boot/lib/libstand/strdup.c)0
-rw-r--r--usr/src/boot/libsa/strerror.c (renamed from usr/src/boot/lib/libstand/strerror.c)0
-rw-r--r--usr/src/boot/libsa/string/bcmp.c (renamed from usr/src/boot/lib/libc/string/bcmp.c)0
-rw-r--r--usr/src/boot/libsa/string/bcopy.c (renamed from usr/src/boot/lib/libc/string/bcopy.c)0
-rw-r--r--usr/src/boot/libsa/string/bzero.c (renamed from usr/src/boot/lib/libc/string/bzero.c)0
-rw-r--r--usr/src/boot/libsa/string/ffs.c (renamed from usr/src/boot/lib/libc/string/ffs.c)0
-rw-r--r--usr/src/boot/libsa/string/fls.c (renamed from usr/src/boot/lib/libc/string/fls.c)0
-rw-r--r--usr/src/boot/libsa/string/memccpy.c (renamed from usr/src/boot/lib/libc/string/memccpy.c)0
-rw-r--r--usr/src/boot/libsa/string/memchr.c (renamed from usr/src/boot/lib/libc/string/memchr.c)0
-rw-r--r--usr/src/boot/libsa/string/memcmp.c (renamed from usr/src/boot/lib/libc/string/memcmp.c)0
-rw-r--r--usr/src/boot/libsa/string/memcpy.c (renamed from usr/src/boot/lib/libc/string/memcpy.c)0
-rw-r--r--usr/src/boot/libsa/string/memmove.c (renamed from usr/src/boot/lib/libc/string/memmove.c)0
-rw-r--r--usr/src/boot/libsa/string/memset.c (renamed from usr/src/boot/lib/libc/string/memset.c)0
-rw-r--r--usr/src/boot/libsa/string/stpcpy.c (renamed from usr/src/boot/lib/libc/string/stpcpy.c)0
-rw-r--r--usr/src/boot/libsa/string/stpncpy.c (renamed from usr/src/boot/lib/libc/string/stpncpy.c)0
-rw-r--r--usr/src/boot/libsa/string/strcat.c (renamed from usr/src/boot/lib/libc/string/strcat.c)0
-rw-r--r--usr/src/boot/libsa/string/strchr.c (renamed from usr/src/boot/lib/libc/string/strchr.c)0
-rw-r--r--usr/src/boot/libsa/string/strcmp.c (renamed from usr/src/boot/lib/libc/string/strcmp.c)0
-rw-r--r--usr/src/boot/libsa/string/strcpy.c (renamed from usr/src/boot/lib/libc/string/strcpy.c)0
-rw-r--r--usr/src/boot/libsa/string/strcspn.c (renamed from usr/src/boot/lib/libc/string/strcspn.c)0
-rw-r--r--usr/src/boot/libsa/string/strlcat.c (renamed from usr/src/boot/lib/libc/string/strlcat.c)0
-rw-r--r--usr/src/boot/libsa/string/strlcpy.c (renamed from usr/src/boot/lib/libc/string/strlcpy.c)0
-rw-r--r--usr/src/boot/libsa/string/strlen.c (renamed from usr/src/boot/lib/libc/string/strlen.c)0
-rw-r--r--usr/src/boot/libsa/string/strncat.c (renamed from usr/src/boot/lib/libc/string/strncat.c)0
-rw-r--r--usr/src/boot/libsa/string/strncmp.c (renamed from usr/src/boot/lib/libc/string/strncmp.c)0
-rw-r--r--usr/src/boot/libsa/string/strncpy.c (renamed from usr/src/boot/lib/libc/string/strncpy.c)0
-rw-r--r--usr/src/boot/libsa/string/strpbrk.c (renamed from usr/src/boot/lib/libc/string/strpbrk.c)0
-rw-r--r--usr/src/boot/libsa/string/strrchr.c (renamed from usr/src/boot/lib/libc/string/strrchr.c)0
-rw-r--r--usr/src/boot/libsa/string/strsep.c (renamed from usr/src/boot/lib/libc/string/strsep.c)0
-rw-r--r--usr/src/boot/libsa/string/strspn.c (renamed from usr/src/boot/lib/libc/string/strspn.c)0
-rw-r--r--usr/src/boot/libsa/string/strstr.c (renamed from usr/src/boot/lib/libc/string/strstr.c)0
-rw-r--r--usr/src/boot/libsa/string/strtok.c (renamed from usr/src/boot/lib/libc/string/strtok.c)0
-rw-r--r--usr/src/boot/libsa/string/swab.c (renamed from usr/src/boot/lib/libc/string/swab.c)0
-rw-r--r--usr/src/boot/libsa/tftp.c (renamed from usr/src/boot/lib/libstand/tftp.c)0
-rw-r--r--usr/src/boot/libsa/tftp.h (renamed from usr/src/boot/lib/libstand/tftp.h)0
-rw-r--r--usr/src/boot/libsa/twiddle.c (renamed from usr/src/boot/lib/libstand/twiddle.c)0
-rw-r--r--usr/src/boot/libsa/udp.c (renamed from usr/src/boot/lib/libstand/udp.c)0
-rw-r--r--usr/src/boot/libsa/ufs.c (renamed from usr/src/boot/lib/libstand/ufs.c)0
-rw-r--r--usr/src/boot/libsa/uuid/uuid_create_nil.c (renamed from usr/src/boot/lib/libc/uuid/uuid_create_nil.c)0
-rw-r--r--usr/src/boot/libsa/uuid/uuid_equal.c (renamed from usr/src/boot/lib/libc/uuid/uuid_equal.c)0
-rw-r--r--usr/src/boot/libsa/uuid/uuid_is_nil.c (renamed from usr/src/boot/lib/libc/uuid/uuid_is_nil.c)0
-rw-r--r--usr/src/boot/libsa/uuid_from_string.c (renamed from usr/src/boot/lib/libstand/uuid_from_string.c)0
-rw-r--r--usr/src/boot/libsa/uuid_to_string.c (renamed from usr/src/boot/lib/libstand/uuid_to_string.c)0
-rw-r--r--usr/src/boot/libsa/write.c (renamed from usr/src/boot/lib/libstand/write.c)0
-rw-r--r--usr/src/boot/libsa/x86/hypervisor.c (renamed from usr/src/boot/lib/libstand/x86/hypervisor.c)0
-rw-r--r--usr/src/boot/libsa/zalloc.c (renamed from usr/src/boot/lib/libstand/zalloc.c)0
-rw-r--r--usr/src/boot/libsa/zalloc_defs.h (renamed from usr/src/boot/lib/libstand/zalloc_defs.h)0
-rw-r--r--usr/src/boot/libsa/zalloc_malloc.c (renamed from usr/src/boot/lib/libstand/zalloc_malloc.c)0
-rw-r--r--usr/src/boot/libsa/zalloc_mem.h (renamed from usr/src/boot/lib/libstand/zalloc_mem.h)0
-rw-r--r--usr/src/boot/libsa/zalloc_protos.h (renamed from usr/src/boot/lib/libstand/zalloc_protos.h)0
-rw-r--r--usr/src/boot/libsa/zfs/Makefile.inc (renamed from usr/src/boot/lib/libstand/zfs/Makefile.inc)4
-rw-r--r--usr/src/boot/libsa/zfs/devicename_stubs.c (renamed from usr/src/boot/lib/libstand/zfs/devicename_stubs.c)0
-rw-r--r--usr/src/boot/libsa/zfs/gzip.c (renamed from usr/src/boot/lib/libstand/zfs/gzip.c)0
-rw-r--r--usr/src/boot/libsa/zfs/libzfs.h (renamed from usr/src/boot/lib/libstand/zfs/libzfs.h)0
-rw-r--r--usr/src/boot/libsa/zfs/nvlist.c (renamed from usr/src/boot/lib/libstand/zfs/nvlist.c)0
-rw-r--r--usr/src/boot/libsa/zfs/zfs.c (renamed from usr/src/boot/lib/libstand/zfs/zfs.c)0
-rw-r--r--usr/src/boot/libsa/zfs/zfsimpl.c (renamed from usr/src/boot/lib/libstand/zfs/zfsimpl.c)0
-rw-r--r--usr/src/boot/sys/boot/Makefile45
-rw-r--r--usr/src/boot/sys/boot/forth/Makefile.inc28
-rw-r--r--usr/src/boot/sys/boot/forth/loader.rc20
-rw-r--r--usr/src/cmd/Makefile1
-rw-r--r--usr/src/cmd/bhyve/README.sync9
-rw-r--r--usr/src/cmd/bhyve/acpi.c12
-rw-r--r--usr/src/cmd/bhyve/audio.h2
-rw-r--r--usr/src/cmd/bhyve/bhyverun.c12
-rw-r--r--usr/src/cmd/bhyve/block_if.c4
-rw-r--r--usr/src/cmd/bhyve/bootrom.c137
-rw-r--r--usr/src/cmd/bhyve/config.c2
-rw-r--r--usr/src/cmd/bhyve/config.h2
-rw-r--r--usr/src/cmd/bhyve/fwctl.c48
-rw-r--r--usr/src/cmd/bhyve/hda_reg.h26
-rw-r--r--usr/src/cmd/bhyve/mevent.c349
-rw-r--r--usr/src/cmd/bhyve/mevent.h2
-rw-r--r--usr/src/cmd/bhyve/mevent_test.c2
-rw-r--r--usr/src/cmd/bhyve/mptbl.c6
-rw-r--r--usr/src/cmd/bhyve/net_backends.c2
-rw-r--r--usr/src/cmd/bhyve/pci_ahci.c4
-rw-r--r--usr/src/cmd/bhyve/pci_e82545.c48
-rw-r--r--usr/src/cmd/bhyve/pci_emul.c166
-rw-r--r--usr/src/cmd/bhyve/pci_emul.h13
-rw-r--r--usr/src/cmd/bhyve/pci_fbuf.c34
-rw-r--r--usr/src/cmd/bhyve/pci_hda.h2
-rw-r--r--usr/src/cmd/bhyve/pci_lpc.c2
-rw-r--r--usr/src/cmd/bhyve/pci_nvme.c353
-rw-r--r--usr/src/cmd/bhyve/pci_passthru.c239
-rw-r--r--usr/src/cmd/bhyve/pci_virtio_9p.c4
-rw-r--r--usr/src/cmd/bhyve/pci_virtio_block.c31
-rw-r--r--usr/src/cmd/bhyve/pci_virtio_console.c4
-rw-r--r--usr/src/cmd/bhyve/pci_virtio_net.c14
-rw-r--r--usr/src/cmd/bhyve/pci_virtio_scsi.c2
-rw-r--r--usr/src/cmd/bhyve/pci_xhci.c18
-rw-r--r--usr/src/cmd/bhyve/rtc.c2
-rw-r--r--usr/src/cmd/bhyve/smbiostbl.c4
-rw-r--r--usr/src/cmd/bhyve/test/tests/mevent/Makefile9
-rw-r--r--usr/src/cmd/bhyve/test/tests/mevent/mevent.c6
-rw-r--r--usr/src/cmd/bhyve/test/tests/mevent/testlib.h2
-rw-r--r--usr/src/cmd/bhyve/test/tests/mevent/vnode_file.c141
-rw-r--r--usr/src/cmd/bhyve/test/tests/mevent/vnode_zvol.c259
-rw-r--r--usr/src/cmd/bhyve/uart_emul.c2
-rw-r--r--usr/src/cmd/bhyve/usb_mouse.c6
-rw-r--r--usr/src/cmd/bhyvectl/Makefile3
-rw-r--r--usr/src/cmd/bhyvectl/bhyvectl.c100
-rw-r--r--usr/src/cmd/cmd-inet/etc/services6
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/in.ndpd/ndp.xml4
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/in.ripngd/ripng.xml4
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/in.rdisc/rdisc.xml4
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/in.rlogind.c28
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/in.routed/route.xml4
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/in.telnetd.c52
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/routeadm/forwarding.xml4
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/routeadm/legacy-routing.xml4
-rw-r--r--usr/src/cmd/dcs/sparc/sun4u/rdr_messages.c4
-rw-r--r--usr/src/cmd/devfsadm/misc_link.c11
-rw-r--r--usr/src/cmd/dladm/Makefile3
-rw-r--r--usr/src/cmd/dladm/dladm.c831
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithChill.d4
-rw-r--r--usr/src/cmd/enhance/enhance.c136
-rw-r--r--usr/src/cmd/fmthard/Makefile6
-rw-r--r--usr/src/cmd/fmthard/fmthard.c6
-rw-r--r--usr/src/cmd/make/bin/ar.cc50
-rw-r--r--usr/src/cmd/make/bin/doname.cc136
-rw-r--r--usr/src/cmd/make/bin/dosys.cc8
-rw-r--r--usr/src/cmd/make/bin/files.cc34
-rw-r--r--usr/src/cmd/make/bin/implicit.cc48
-rw-r--r--usr/src/cmd/make/bin/macro.cc12
-rw-r--r--usr/src/cmd/make/bin/main.cc82
-rw-r--r--usr/src/cmd/make/bin/misc.cc26
-rw-r--r--usr/src/cmd/make/bin/nse_printdep.cc24
-rw-r--r--usr/src/cmd/make/bin/read.cc42
-rw-r--r--usr/src/cmd/make/bin/read2.cc88
-rw-r--r--usr/src/cmd/make/bin/rep.cc2
-rw-r--r--usr/src/cmd/make/bin/state.cc16
-rw-r--r--usr/src/cmd/make/include/mksh/dosys.h17
-rw-r--r--usr/src/cmd/make/include/mksh/macro.h15
-rw-r--r--usr/src/cmd/make/include/mksh/misc.h46
-rw-r--r--usr/src/cmd/make/include/mksh/read.h8
-rw-r--r--usr/src/cmd/make/include/vroot/args.h59
-rw-r--r--usr/src/cmd/make/include/vroot/vroot.h26
-rw-r--r--usr/src/cmd/make/lib/mksh/macro.cc58
-rw-r--r--usr/src/cmd/make/lib/mksh/misc.cc38
-rw-r--r--usr/src/cmd/make/lib/mksh/read.cc14
-rw-r--r--usr/src/cmd/make/lib/vroot/report.cc22
-rw-r--r--usr/src/cmd/make/lib/vroot/vroot.cc28
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm.c57
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm.h11
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm_dev.c47
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm_print.c76
-rw-r--r--usr/src/cmd/pcieadm/pcieadm_cfgspace.c117
-rw-r--r--usr/src/cmd/pcieadm/pcieadm_devs.c32
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/LDAPAuthentication.rawhlp6
-rw-r--r--usr/src/cmd/ps/Makefile37
-rw-r--r--usr/src/cmd/ps/Makefile.com54
-rw-r--r--usr/src/cmd/ps/amd64/Makefile36
-rw-r--r--usr/src/cmd/ps/i386/Makefile39
-rw-r--r--usr/src/cmd/ps/sparcv9/Makefile39
-rw-r--r--usr/src/cmd/ps/ucbps.c22
-rw-r--r--usr/src/cmd/script/script.c70
-rw-r--r--usr/src/cmd/sgs/ar/common/ar.msg6
-rw-r--r--usr/src/cmd/sgs/ar/common/file.c4
-rw-r--r--usr/src/cmd/sgs/ar/common/main.c4
-rw-r--r--usr/src/cmd/sgs/lex/Makefile.com3
-rw-r--r--usr/src/cmd/sgs/lex/common/sub1.c19
-rw-r--r--usr/src/cmd/sgs/lex/common/sub2.c6
-rw-r--r--usr/src/cmd/sgs/lex/common/sub3.c7
-rw-r--r--usr/src/cmd/sgs/libld/common/libld.msg4
-rw-r--r--usr/src/cmd/sgs/tools/SUNWonld-README3
-rw-r--r--usr/src/cmd/smbsrv/testoplock/tol_main.c17
-rw-r--r--usr/src/cmd/svc/milestone/network-routing-setup.xml2
-rw-r--r--usr/src/cmd/syseventd/modules/zfs_mod/zfs_mod.c31
-rw-r--r--usr/src/cmd/truss/codes.c4
-rw-r--r--usr/src/cmd/ttymon/parms.h17
-rw-r--r--usr/src/cmd/varpd/Makefile64
-rw-r--r--usr/src/cmd/varpd/varpd.c526
-rw-r--r--usr/src/cmd/varpd/varpd.xml67
-rw-r--r--usr/src/cmd/vscan/vscand/vs_main.c2
-rw-r--r--usr/src/cmd/zoneadmd/zcons.c110
-rw-r--r--usr/src/common/core/core_shstrtab.c3
-rw-r--r--usr/src/common/dis/i386/dis_tables.c4
-rw-r--r--usr/src/common/fs/ufsops.c5
-rw-r--r--usr/src/common/util/string.c11
-rw-r--r--usr/src/compat/bhyve/amd64/machine/fpu.h28
-rw-r--r--usr/src/compat/bhyve/amd64/machine/pcb.h21
-rw-r--r--usr/src/data/consfonts/THIRDPARTYLICENSE2
-rw-r--r--usr/src/data/consfonts/THIRDPARTYLICENSE.descrip2
-rw-r--r--usr/src/data/consfonts/ter-u12b.bdf44
-rw-r--r--usr/src/data/consfonts/ter-u12n.bdf44
-rw-r--r--usr/src/data/consfonts/ter-u14b.bdf50
-rw-r--r--usr/src/data/consfonts/ter-u14n.bdf50
-rw-r--r--usr/src/data/consfonts/ter-u14v.bdf50
-rw-r--r--usr/src/data/consfonts/ter-u16b.bdf54
-rw-r--r--usr/src/data/consfonts/ter-u16n.bdf54
-rw-r--r--usr/src/data/consfonts/ter-u16v.bdf54
-rw-r--r--usr/src/data/consfonts/ter-u18b.bdf60
-rw-r--r--usr/src/data/consfonts/ter-u18n.bdf60
-rw-r--r--usr/src/data/consfonts/ter-u20b.bdf64
-rw-r--r--usr/src/data/consfonts/ter-u20n.bdf64
-rw-r--r--usr/src/data/consfonts/ter-u22b.bdf66
-rw-r--r--usr/src/data/consfonts/ter-u22n.bdf66
-rw-r--r--usr/src/data/consfonts/ter-u24b.bdf72
-rw-r--r--usr/src/data/consfonts/ter-u24n.bdf72
-rw-r--r--usr/src/data/consfonts/ter-u28b.bdf80
-rw-r--r--usr/src/data/consfonts/ter-u28n.bdf81
-rw-r--r--usr/src/data/consfonts/ter-u32b.bdf88
-rw-r--r--usr/src/data/consfonts/ter-u32n.bdf88
-rw-r--r--usr/src/data/ucode/Makefile.links4
-rw-r--r--usr/src/data/ucode/README.ucode2
-rw-r--r--usr/src/data/ucode/intel/000306F2-01bin34816 -> 38912 bytes
-rw-r--r--usr/src/data/ucode/intel/000306F4-80bin19456 -> 23552 bytes
-rw-r--r--usr/src/data/ucode/intel/000406E3-40bin105472 -> 105472 bytes
-rw-r--r--usr/src/data/ucode/intel/000406F1-01bin31744 -> 35840 bytes
-rw-r--r--usr/src/data/ucode/intel/00050653-01bin34816 -> 34816 bytes
-rw-r--r--usr/src/data/ucode/intel/00050654-01bin36864 -> 43008 bytes
-rw-r--r--usr/src/data/ucode/intel/00050656-01bin30720 -> 35840 bytes
-rw-r--r--usr/src/data/ucode/intel/00050657-01bin30720 -> 36864 bytes
-rw-r--r--usr/src/data/ucode/intel/0005065B-01bin27648 -> 28672 bytes
-rw-r--r--usr/src/data/ucode/intel/00050663-10bin24576 -> 28672 bytes
-rw-r--r--usr/src/data/ucode/intel/00050664-10bin24576 -> 27648 bytes
-rw-r--r--usr/src/data/ucode/intel/00050665-10bin19456 -> 23552 bytes
-rw-r--r--usr/src/data/ucode/intel/000506C9-01bin17408 -> 17408 bytes
-rw-r--r--usr/src/data/ucode/intel/000506CA-01bin15360 -> 16384 bytes
-rw-r--r--usr/src/data/ucode/intel/000506E3-02bin105472 -> 108544 bytes
-rw-r--r--usr/src/data/ucode/intel/000506F1-01bin11264 -> 11264 bytes
-rw-r--r--usr/src/data/ucode/intel/000606A6-01bin283648 -> 291840 bytes
-rw-r--r--usr/src/data/ucode/intel/000706A1-01bin74752 -> 74752 bytes
-rw-r--r--usr/src/data/ucode/intel/000706A8-01bin75776 -> 75776 bytes
-rw-r--r--usr/src/data/ucode/intel/000706E5-80bin110592 -> 110592 bytes
-rw-r--r--usr/src/data/ucode/intel/00080664-01bin130048 -> 0 bytes
-rw-r--r--usr/src/data/ucode/intel/000806A1-10bin32768 -> 34816 bytes
-rw-r--r--usr/src/data/ucode/intel/000806C1-80bin109568 -> 109568 bytes
-rw-r--r--usr/src/data/ucode/intel/000806C2-02bin94208 -> 96256 bytes
-rw-r--r--usr/src/data/ucode/intel/000806D1-02bin99328 -> 101376 bytes
-rw-r--r--usr/src/data/ucode/intel/000806E9-10bin104448 -> 104448 bytes
-rw-r--r--usr/src/data/ucode/intel/000806E9-40bin104448 -> 104448 bytes
-rw-r--r--usr/src/data/ucode/intel/000806EA-40bin103424 -> 103424 bytes
-rw-r--r--usr/src/data/ucode/intel/000806EB-10bin104448 -> 104448 bytes
-rw-r--r--usr/src/data/ucode/intel/000806EC-04bin104448 -> 104448 bytes
-rw-r--r--usr/src/data/ucode/intel/00090661-01bin19456 -> 20480 bytes
-rw-r--r--usr/src/data/ucode/intel/000906C0-01bin19456 -> 20480 bytes
-rw-r--r--usr/src/data/ucode/intel/000906E9-02bin104448 -> 106496 bytes
-rw-r--r--usr/src/data/ucode/intel/000906EA-02bin102400 -> 102400 bytes
-rw-r--r--usr/src/data/ucode/intel/000906EB-02bin104448 -> 104448 bytes
-rw-r--r--usr/src/data/ucode/intel/000906EC-02bin103424 -> 103424 bytes
-rw-r--r--usr/src/data/ucode/intel/000906ED-02bin103424 -> 103424 bytes
-rw-r--r--usr/src/data/ucode/intel/000A0652-20bin93184 -> 93184 bytes
-rw-r--r--usr/src/data/ucode/intel/000A0653-02bin94208 -> 94208 bytes
-rw-r--r--usr/src/data/ucode/intel/000A0655-02bin94208 -> 94208 bytes
-rw-r--r--usr/src/data/ucode/intel/000A0660-80bin94208 -> 94208 bytes
-rw-r--r--usr/src/data/ucode/intel/000A0661-80bin93184 -> 93184 bytes
-rw-r--r--usr/src/data/ucode/intel/000A0671-02bin100352 -> 102400 bytes
-rw-r--r--usr/src/data/ucode/intel/THIRDPARTYLICENSE2
-rw-r--r--usr/src/lib/Makefile6
-rw-r--r--usr/src/lib/gss_mechs/mech_dh/dh192/fakensl.c6
-rw-r--r--usr/src/lib/gss_mechs/mech_krb5/krb5/rcache/rc_file.c10
-rw-r--r--usr/src/lib/libdladm/Makefile11
-rw-r--r--usr/src/lib/libdladm/Makefile.com8
-rw-r--r--usr/src/lib/libdladm/common/libdladm.c85
-rw-r--r--usr/src/lib/libdladm/common/libdladm.h17
-rw-r--r--usr/src/lib/libdladm/common/libdladm_impl.h7
-rw-r--r--usr/src/lib/libdladm/common/libdloverlay.c885
-rw-r--r--usr/src/lib/libdladm/common/libdloverlay.h107
-rw-r--r--usr/src/lib/libdladm/common/libdlvlan.c2
-rw-r--r--usr/src/lib/libdladm/common/libdlvnic.c11
-rw-r--r--usr/src/lib/libdladm/common/libdlvnic.h3
-rw-r--r--usr/src/lib/libdladm/common/mapfile-vers18
-rw-r--r--usr/src/lib/libfakekernel/Makefile.com2
-rw-r--r--usr/src/lib/libfakekernel/common/printf.c9
-rw-r--r--usr/src/lib/libsldap/common/ns_internal.h2
-rw-r--r--usr/src/lib/libzfs/common/libzfs_pool.c18
-rw-r--r--usr/src/lib/varpd/Makefile33
-rw-r--r--usr/src/lib/varpd/Makefile.plugin19
-rw-r--r--usr/src/lib/varpd/direct/Makefile39
-rw-r--r--usr/src/lib/varpd/direct/Makefile.com35
-rw-r--r--usr/src/lib/varpd/direct/amd64/Makefile19
-rw-r--r--usr/src/lib/varpd/direct/common/libvarpd_direct.c411
-rw-r--r--usr/src/lib/varpd/direct/common/mapfile-vers35
-rw-r--r--usr/src/lib/varpd/direct/i386/Makefile18
-rw-r--r--usr/src/lib/varpd/files/Makefile39
-rw-r--r--usr/src/lib/varpd/files/Makefile.com36
-rw-r--r--usr/src/lib/varpd/files/amd64/Makefile19
-rw-r--r--usr/src/lib/varpd/files/common/libvarpd_files.c605
-rw-r--r--usr/src/lib/varpd/files/common/libvarpd_files_json.c936
-rw-r--r--usr/src/lib/varpd/files/common/libvarpd_files_json.h52
-rw-r--r--usr/src/lib/varpd/files/common/mapfile-vers35
-rw-r--r--usr/src/lib/varpd/files/i386/Makefile18
-rw-r--r--usr/src/lib/varpd/libvarpd/Makefile54
-rw-r--r--usr/src/lib/varpd/libvarpd/Makefile.com48
-rw-r--r--usr/src/lib/varpd/libvarpd/amd64/Makefile19
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd.c345
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd.h77
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_arp.c649
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_client.c626
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_client.h92
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_door.c469
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_impl.h248
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_overlay.c588
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_panic.c53
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_persist.c586
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_plugin.c256
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_prop.c300
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_provider.h417
-rw-r--r--usr/src/lib/varpd/libvarpd/common/libvarpd_util.c91
-rw-r--r--usr/src/lib/varpd/libvarpd/common/mapfile-plugin57
-rw-r--r--usr/src/lib/varpd/libvarpd/common/mapfile-vers113
-rw-r--r--usr/src/lib/varpd/libvarpd/i386/Makefile18
-rw-r--r--usr/src/man/man1/ar.15
-rw-r--r--usr/src/man/man1/ld.14
-rw-r--r--usr/src/man/man2/chmod.212
-rw-r--r--usr/src/man/man2/close.2472
-rw-r--r--usr/src/man/man2/open.21790
-rw-r--r--usr/src/man/man3c/grantpt.3c157
-rw-r--r--usr/src/man/man3c/posix_openpt.3c290
-rw-r--r--usr/src/man/man3c/ptsname.3c127
-rw-r--r--usr/src/man/man3c/unlockpt.3c142
-rw-r--r--usr/src/man/man3cpc/cpc.3cpc3
-rw-r--r--usr/src/man/man3utempter/utempter_add_record.3utempter6
-rw-r--r--usr/src/man/man4/Makefile1
-rw-r--r--usr/src/man/man4d/Makefile4
-rw-r--r--usr/src/man/man4d/amdzen.4d4
-rw-r--r--usr/src/man/man4d/ptm.4d341
-rw-r--r--usr/src/man/man4d/pts.4d112
-rw-r--r--usr/src/man/man4d/pty.4d495
-rw-r--r--usr/src/man/man4d/zcons.4d132
-rw-r--r--usr/src/man/man4m/pckt.4m13
-rw-r--r--usr/src/man/man4m/ptem.4m188
-rw-r--r--usr/src/man/man4p/Makefile6
-rw-r--r--usr/src/man/man4p/vxlan.4p130
-rw-r--r--usr/src/man/man5/Makefile1
-rw-r--r--usr/src/man/man5/bhyve_config.54
-rw-r--r--usr/src/man/man5/overlay_files.5187
-rw-r--r--usr/src/man/man7/Makefile1
-rw-r--r--usr/src/man/man7/overlay.7521
-rw-r--r--usr/src/man/man8/bhyve.832
-rw-r--r--usr/src/man/man8/dladm.8371
-rw-r--r--usr/src/man/man8/flowadm.818
-rw-r--r--usr/src/man/man8/fmthard.8400
-rw-r--r--usr/src/man/man8/in.rlogind.810
-rw-r--r--usr/src/man/man8/in.telnetd.811
-rw-r--r--usr/src/man/man8/nvmeadm.843
-rw-r--r--usr/src/man/man8/pppd.838
-rw-r--r--usr/src/man/man9f/kmem_alloc.9f31
-rw-r--r--usr/src/man/man9f/kmem_cache_create.9f33
-rw-r--r--usr/src/man/man9f/scsi_hba_tgtmap_create.9f10
-rw-r--r--usr/src/man/man9s/scsi_address.9s95
-rw-r--r--usr/src/pkg/manifests/SUNWcs.man4d.inc2
-rw-r--r--usr/src/pkg/manifests/SUNWcs.p5m4
-rw-r--r--usr/src/pkg/manifests/compatibility-ucb.p5m4
-rw-r--r--usr/src/pkg/manifests/driver-cpu-amd-zen.p5m15
-rw-r--r--usr/src/pkg/manifests/driver-storage-smrt.p5m74
-rw-r--r--usr/src/pkg/manifests/system-bhyve-tests.p5m5
-rw-r--r--usr/src/pkg/manifests/system-boot-loader.p5m4
-rw-r--r--usr/src/pkg/manifests/system-kernel-platform.p5m2
-rw-r--r--usr/src/pkg/manifests/system-microcode-intel.p5m7
-rw-r--r--usr/src/pkg/manifests/system-network-overlay.p5m62
-rw-r--r--usr/src/pkg/manifests/system-test-ostest.p5m2
-rw-r--r--usr/src/test/bhyve-tests/runfiles/default.run9
-rw-r--r--usr/src/test/bhyve-tests/tests/vmm/Makefile3
-rw-r--r--usr/src/test/bhyve-tests/tests/vmm/common.c5
-rw-r--r--usr/src/test/bhyve-tests/tests/vmm/common.h2
-rw-r--r--usr/src/test/bhyve-tests/tests/vmm/fpu_getset.c333
-rw-r--r--usr/src/test/bhyve-tests/tests/vmm/mem_partial.c5
-rw-r--r--usr/src/test/bhyve-tests/tests/vmm/mem_seg_map.c5
-rw-r--r--usr/src/test/libc-tests/runfiles/default.run1
-rw-r--r--usr/src/test/os-tests/runfiles/default.run2
-rw-r--r--usr/src/test/os-tests/tests/syscall/Makefile2
-rw-r--r--usr/src/test/os-tests/tests/syscall/fchmodat.c92
-rw-r--r--usr/src/test/util-tests/tests/ar/artest.ksh43
-rw-r--r--usr/src/test/util-tests/tests/ctf/precheck.ksh2
-rw-r--r--usr/src/test/util-tests/tests/dladm/Makefile2
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/pcieadm-priv.ksh35
-rw-r--r--usr/src/tools/scripts/onu.1onbld6
-rw-r--r--usr/src/uts/Makefile.targ3
-rw-r--r--usr/src/uts/Makefile.uts6
-rw-r--r--usr/src/uts/common/Makefile.files19
-rw-r--r--usr/src/uts/common/Makefile.rules12
-rw-r--r--usr/src/uts/common/disp/cpupart.c5
-rw-r--r--usr/src/uts/common/dtrace/dtrace.c15
-rw-r--r--usr/src/uts/common/fs/bootfs/bootfs_vfsops.c2
-rw-r--r--usr/src/uts/common/fs/dev/sdev_ptsops.c23
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_auth.c10
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_fsctl_copychunk.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c2
-rw-r--r--usr/src/uts/common/fs/zfs/zcp.c3
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_dir.c1
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vnops.c88
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_znode.c2
-rw-r--r--usr/src/uts/common/fs/zfs/zio_crypt.c13
-rw-r--r--usr/src/uts/common/inet/ip/ip_attr.c2
-rw-r--r--usr/src/uts/common/inet/udp/udp.c16
-rw-r--r--usr/src/uts/common/io/audio/impl/audio_ddi.c2
-rw-r--r--usr/src/uts/common/io/avintr.c2
-rw-r--r--usr/src/uts/common/io/blkdev/blkdev.c127
-rw-r--r--usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c2
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3.c2
-rw-r--r--usr/src/uts/common/io/dld/dld_drv.c14
-rw-r--r--usr/src/uts/common/io/iwn/if_iwnreg.h14
-rw-r--r--usr/src/uts/common/io/mac/mac_client.c8
-rw-r--r--usr/src/uts/common/io/mac/mac_datapath_setup.c11
-rw-r--r--usr/src/uts/common/io/mac/mac_protect.c4
-rw-r--r--usr/src/uts/common/io/mac/mac_provider.c3
-rw-r--r--usr/src/uts/common/io/mwl/mwl.c43
-rw-r--r--usr/src/uts/common/io/nvme/nvme.c285
-rw-r--r--usr/src/uts/common/io/nvme/nvme_reg.h15
-rw-r--r--usr/src/uts/common/io/nvme/nvme_var.h2
-rw-r--r--usr/src/uts/common/io/overlay/overlay.c2184
-rw-r--r--usr/src/uts/common/io/overlay/overlay.conf16
-rw-r--r--usr/src/uts/common/io/overlay/overlay.mapfile46
-rw-r--r--usr/src/uts/common/io/overlay/overlay_fm.c82
-rw-r--r--usr/src/uts/common/io/overlay/overlay_mux.c363
-rw-r--r--usr/src/uts/common/io/overlay/overlay_plugin.c281
-rw-r--r--usr/src/uts/common/io/overlay/overlay_prop.c122
-rw-r--r--usr/src/uts/common/io/overlay/overlay_target.c1650
-rw-r--r--usr/src/uts/common/io/overlay/plugins/overlay_vxlan.c394
-rw-r--r--usr/src/uts/common/io/ptem.c19
-rw-r--r--usr/src/uts/common/io/ptm.c246
-rw-r--r--usr/src/uts/common/io/ptms_conf.c148
-rw-r--r--usr/src/uts/common/io/pts.c232
-rw-r--r--usr/src/uts/common/io/sata/adapters/ahci/ahci.c2
-rw-r--r--usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_attach.c4
-rw-r--r--usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_sata.c5
-rw-r--r--usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c8
-rw-r--r--usr/src/uts/common/io/scsi/adapters/smrt/smrt.c565
-rw-r--r--usr/src/uts/common/io/scsi/adapters/smrt/smrt.conf16
-rw-r--r--usr/src/uts/common/io/scsi/adapters/smrt/smrt_ciss.c2023
-rw-r--r--usr/src/uts/common/io/scsi/adapters/smrt/smrt_ciss_simple.c282
-rw-r--r--usr/src/uts/common/io/scsi/adapters/smrt/smrt_commands.c362
-rw-r--r--usr/src/uts/common/io/scsi/adapters/smrt/smrt_device.c238
-rw-r--r--usr/src/uts/common/io/scsi/adapters/smrt/smrt_hba.c1457
-rw-r--r--usr/src/uts/common/io/scsi/adapters/smrt/smrt_interrupts.c286
-rw-r--r--usr/src/uts/common/io/scsi/adapters/smrt/smrt_logvol.c367
-rw-r--r--usr/src/uts/common/io/scsi/adapters/smrt/smrt_physical.c612
-rw-r--r--usr/src/uts/common/io/scsi/adapters/smrt/smrt_sata.c160
-rw-r--r--usr/src/uts/common/io/tty_pts.c46
-rw-r--r--usr/src/uts/common/io/tty_pty.c84
-rw-r--r--usr/src/uts/common/io/ufmtest.c2
-rw-r--r--usr/src/uts/common/io/usb/clients/ccid/ccid.c2
-rw-r--r--usr/src/uts/common/io/usb/clients/hid/hid.c212
-rw-r--r--usr/src/uts/common/io/usb/clients/usbecm/usbecm.c2
-rw-r--r--usr/src/uts/common/io/vioblk/vioblk.c118
-rw-r--r--usr/src/uts/common/io/virtio/virtio.h16
-rw-r--r--usr/src/uts/common/io/virtio/virtio_impl.h6
-rw-r--r--usr/src/uts/common/io/virtio/virtio_main.c135
-rw-r--r--usr/src/uts/common/io/zcons.c401
-rw-r--r--usr/src/uts/common/krtld/kobj.c8
-rw-r--r--usr/src/uts/common/netinet/in.h1
-rw-r--r--usr/src/uts/common/os/bio.c1
-rw-r--r--usr/src/uts/common/os/cpu.c2
-rw-r--r--usr/src/uts/common/os/ddi_ufm.c4
-rw-r--r--usr/src/uts/common/os/driver_lyr.c2
-rw-r--r--usr/src/uts/common/os/exacct.c6
-rw-r--r--usr/src/uts/common/os/fio.c4
-rw-r--r--usr/src/uts/common/os/flock.c58
-rw-r--r--usr/src/uts/common/os/fm.c1
-rw-r--r--usr/src/uts/common/os/klpd.c2
-rw-r--r--usr/src/uts/common/os/kmem.c2
-rw-r--r--usr/src/uts/common/os/lgrp.c15
-rw-r--r--usr/src/uts/common/os/log_sysevent.c11
-rw-r--r--usr/src/uts/common/os/mmapobj.c8
-rw-r--r--usr/src/uts/common/os/modctl.c2
-rw-r--r--usr/src/uts/common/os/modsubr.c3
-rw-r--r--usr/src/uts/common/os/panic.c2
-rw-r--r--usr/src/uts/common/os/pool.c10
-rw-r--r--usr/src/uts/common/os/priv.c3
-rw-r--r--usr/src/uts/common/os/rctl.c2
-rw-r--r--usr/src/uts/common/os/sunddi.c6
-rw-r--r--usr/src/uts/common/os/sunmdi.c22
-rw-r--r--usr/src/uts/common/os/sunpm.c7
-rw-r--r--usr/src/uts/common/os/vm_pageout.c2
-rw-r--r--usr/src/uts/common/os/watchpoint.c1
-rw-r--r--usr/src/uts/common/pcmcia/cs/cs_stubs.c27
-rw-r--r--usr/src/uts/common/sys/Makefile11
-rw-r--r--usr/src/uts/common/sys/dld_ioc.h3
-rw-r--r--usr/src/uts/common/sys/dls_mgmt.h7
-rw-r--r--usr/src/uts/common/sys/kmem.h3
-rw-r--r--usr/src/uts/common/sys/mac_client_priv.h1
-rw-r--r--usr/src/uts/common/sys/mac_impl.h1
-rw-r--r--usr/src/uts/common/sys/mac_provider.h3
-rw-r--r--usr/src/uts/common/sys/nvme.h34
-rw-r--r--usr/src/uts/common/sys/overlay.h96
-rw-r--r--usr/src/uts/common/sys/overlay_common.h65
-rw-r--r--usr/src/uts/common/sys/overlay_impl.h205
-rw-r--r--usr/src/uts/common/sys/overlay_plugin.h324
-rw-r--r--usr/src/uts/common/sys/overlay_target.h295
-rw-r--r--usr/src/uts/common/sys/plat/pci_prd.h130
-rw-r--r--usr/src/uts/common/sys/ptms.h63
-rw-r--r--usr/src/uts/common/sys/ptyvar.h12
-rw-r--r--usr/src/uts/common/sys/scsi/adapters/smrt/smrt.h750
-rw-r--r--usr/src/uts/common/sys/scsi/adapters/smrt/smrt_ciss.h345
-rw-r--r--usr/src/uts/common/sys/scsi/adapters/smrt/smrt_scsi.h371
-rw-r--r--usr/src/uts/common/sys/termios.h2
-rw-r--r--usr/src/uts/common/sys/ucode.h5
-rw-r--r--usr/src/uts/common/sys/usb/clients/hid/hidminor.h19
-rw-r--r--usr/src/uts/common/sys/usb/clients/hid/hidvar.h25
-rw-r--r--usr/src/uts/common/sys/zcons.h26
-rw-r--r--usr/src/uts/common/syscall/chmod.c5
-rw-r--r--usr/src/uts/common/syscall/poll.c7
-rw-r--r--usr/src/uts/common/vm/page.h2
-rw-r--r--usr/src/uts/common/vm/page_retire.c3
-rw-r--r--usr/src/uts/common/vm/seg_kmem.c4
-rw-r--r--usr/src/uts/common/vm/seg_map.c2
-rw-r--r--usr/src/uts/common/vm/vm_as.c14
-rw-r--r--usr/src/uts/common/vm/vm_page.c2
-rw-r--r--usr/src/uts/common/vm/vm_pagelist.c48
-rw-r--r--usr/src/uts/i86pc/Makefile.files4
-rw-r--r--usr/src/uts/i86pc/Makefile.i86pc2
-rw-r--r--usr/src/uts/i86pc/boot/boot_console.c1
-rw-r--r--usr/src/uts/i86pc/dboot/dboot_startkern.c7
-rw-r--r--usr/src/uts/i86pc/dboot/dboot_xboot.h4
-rw-r--r--usr/src/uts/i86pc/io/hrtimers.c6
-rw-r--r--usr/src/uts/i86pc/io/pci/mps_table.h (renamed from usr/src/uts/intel/io/pci/mps_table.h)8
-rw-r--r--usr/src/uts/i86pc/io/pci/pci_prd_i86pc.c (renamed from usr/src/uts/intel/io/pci/pci_resource.c)451
-rw-r--r--usr/src/uts/i86pc/io/pci/pcihrt.h (renamed from usr/src/uts/intel/io/pci/pcihrt.h)8
-rw-r--r--usr/src/uts/i86pc/io/vmm/intel/vmx_msr.c1
-rw-r--r--usr/src/uts/i86pc/io/vmm/io/ppt.c13
-rw-r--r--usr/src/uts/i86pc/io/vmm/io/vatpic.c245
-rw-r--r--usr/src/uts/i86pc/io/vmm/io/vlapic.c14
-rw-r--r--usr/src/uts/i86pc/io/vmm/sys/vmm_kernel.h4
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm.c69
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c95
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm_sol_glue.c62
-rw-r--r--usr/src/uts/i86pc/os/cmi_hw.c2
-rw-r--r--usr/src/uts/i86pc/os/cpuid.c13
-rw-r--r--usr/src/uts/i86pc/os/cpuid_subr.c23
-rw-r--r--usr/src/uts/i86pc/os/ddi_impl.c39
-rw-r--r--usr/src/uts/i86pc/os/fakebop.c3
-rw-r--r--usr/src/uts/i86pc/os/hma_fpu.c264
-rw-r--r--usr/src/uts/i86pc/os/lgrpplat.c2
-rw-r--r--usr/src/uts/i86pc/os/mp_startup.c2
-rw-r--r--usr/src/uts/i86pc/os/pci_bios.c21
-rw-r--r--usr/src/uts/i86pc/os/smt.c2
-rw-r--r--usr/src/uts/i86pc/os/startup.c5
-rw-r--r--usr/src/uts/i86pc/os/trap.c5
-rw-r--r--usr/src/uts/i86pc/pci_prd/Makefile66
-rw-r--r--usr/src/uts/i86pc/sys/hma.h38
-rw-r--r--usr/src/uts/i86pc/sys/pci_cfgspace_impl.h11
-rw-r--r--usr/src/uts/i86pc/sys/vmm_dev.h22
-rw-r--r--usr/src/uts/i86pc/unix/Makefile12
-rw-r--r--usr/src/uts/i86pc/vm/hat_i86.c4
-rw-r--r--usr/src/uts/i86pc/vm/vm_machdep.c14
-rw-r--r--usr/src/uts/intel/Makefile.files2
-rw-r--r--usr/src/uts/intel/Makefile.intel7
-rw-r--r--usr/src/uts/intel/genunix/Makefile9
-rw-r--r--usr/src/uts/intel/io/acpica/acpi_enum.c177
-rw-r--r--usr/src/uts/intel/io/amdzen/amdzen.c2
-rw-r--r--usr/src/uts/intel/io/imc/imc.c4
-rw-r--r--usr/src/uts/intel/io/pci/pci_autoconfig.c27
-rw-r--r--usr/src/uts/intel/io/pci/pci_boot.c380
-rw-r--r--usr/src/uts/intel/io/pci/pci_memlist.c4
-rw-r--r--usr/src/uts/intel/os/archdep.c2
-rw-r--r--usr/src/uts/intel/os/cpc_subr.c1
-rw-r--r--usr/src/uts/intel/os/fpu.c43
-rw-r--r--usr/src/uts/intel/os/sundep.c6
-rw-r--r--usr/src/uts/intel/overlay/Makefile46
-rw-r--r--usr/src/uts/intel/pcbe/opteron_pcbe.c3
-rw-r--r--usr/src/uts/intel/pci_autoconfig/Makefile4
-rw-r--r--usr/src/uts/intel/smrt/Makefile64
-rw-r--r--usr/src/uts/intel/sys/fp.h45
-rw-r--r--usr/src/uts/intel/vxlan/Makefile41
917 files changed, 36230 insertions, 6793 deletions
diff --git a/exception_lists/packaging b/exception_lists/packaging
index f5cdbbf189..dc74d6d3bf 100644
--- a/exception_lists/packaging
+++ b/exception_lists/packaging
@@ -400,6 +400,18 @@ usr/include/libidspace.h
# VXLAN
#
usr/include/sys/vxlan.h
+lib/libvarpd.so
+lib/amd64/libvarpd.so
+#
+# Overlay
+#
+usr/include/libdloverlay.h
+usr/include/libvarpd.h
+usr/include/libvarpd_client.h
+usr/include/libvarpd_provider.h
+usr/include/sys/overlay.h
+usr/include/sys/overlay_common.h
+usr/include/sys/overlay_target.h
#
# Private interfaces in libsec
#
diff --git a/usr/src/Targetdirs b/usr/src/Targetdirs
index b78dc9df7f..94ec907b77 100644
--- a/usr/src/Targetdirs
+++ b/usr/src/Targetdirs
@@ -309,6 +309,7 @@ DIRS= \
/usr/lib/mdb/kvm \
/usr/lib/mdb/proc \
/usr/lib/nfs \
+ /usr/lib/varpd \
/usr/net \
/usr/net/servers \
/usr/lib/pool \
@@ -490,6 +491,7 @@ DIRS64= \
/usr/lib/security/$(MACH64) \
/usr/lib/smbsrv/$(MACH64) \
/usr/lib/abi/$(MACH64) \
+ /usr/lib/varpd/$(MACH64) \
/usr/sbin/$(MACH64) \
/usr/ucb/$(MACH64) \
/usr/ucblib/$(MACH64) \
@@ -544,6 +546,7 @@ SYM.DIRS64= \
/usr/lib/lwp/64 \
/usr/lib/secure/64 \
/usr/lib/security/64 \
+ /usr/lib/varpd/64 \
/usr/xpg4/lib/64 \
/var/ld/64 \
/usr/ucblib/64
@@ -647,6 +650,7 @@ $(BUILD64) $(ROOT)/usr/lib/lwp/64:= LINKDEST=$(MACH64)
$(BUILD64) $(ROOT)/usr/lib/link_audit/64:= LINKDEST=$(MACH64)
$(BUILD64) $(ROOT)/usr/lib/secure/64:= LINKDEST=$(MACH64)
$(BUILD64) $(ROOT)/usr/lib/security/64:= LINKDEST=$(MACH64)
+$(BUILD64) $(ROOT)/usr/lib/varpd/64:= LINKDEST=$(MACH64)
$(BUILD64) $(ROOT)/usr/xpg4/lib/64:= LINKDEST=$(MACH64)
$(BUILD64) $(ROOT)/var/ld/64:= LINKDEST=$(MACH64)
$(BUILD64) $(ROOT)/usr/ucblib/64:= LINKDEST=$(MACH64)
diff --git a/usr/src/boot/Makefile b/usr/src/boot/Makefile
index 11d0eea7c2..2152c3a524 100644
--- a/usr/src/boot/Makefile
+++ b/usr/src/boot/Makefile
@@ -15,16 +15,29 @@
.KEEP_STATE:
-include ../Makefile.master
+include $(SRC)/Makefile.master
-SUBDIRS = sys/boot
+INSTDIRS = i386 efi forth
+SUBDIRS = libsa libficl $(INSTDIRS)
all := TARGET = all
-install := TARGET = install
clean := TARGET = clean
clobber := TARGET = clobber
+install := TARGET = install
+
+all clean clobber: $(SUBDIRS)
+
+#
+# The directories in INSTDIRS depend implicitly on SUBDIRS being built already.
+# We use .WAIT instead of explicit dependencies because we only want to make
+# the "install" target in INSTDIRS, not in SUBDIRS.
+#
+# If adding SUBDIRS which are not dependencies of INSTDIRS, "install: all"
+# rules should be added to the Makefiles in those directories.
+#
+install: all .WAIT $(INSTDIRS)
-all install clean clobber: $(SUBDIRS)
+.PARALLEL: libsa libficl
$(SUBDIRS): FRC
@cd $@; pwd; $(MAKE) $(TARGET)
diff --git a/usr/src/boot/sys/boot/Makefile.inc b/usr/src/boot/Makefile.inc
index c6b5320866..495bfab86b 100644
--- a/usr/src/boot/sys/boot/Makefile.inc
+++ b/usr/src/boot/Makefile.inc
@@ -36,9 +36,8 @@ FONT_DIR= $(SRC)/data/consfonts
PNGLITE= $(SRC)/common/pnglite
-BOOTSRC= $(SRC)/boot/sys/boot
-LIBSRC= $(SRC)/boot/lib
-SASRC= $(LIBSRC)/libstand
+BOOTSRC= $(SRC)/boot
+SASRC= $(BOOTSRC)/libsa
CRYPTOSRC= $(SASRC)/crypto
ZFSSRC= $(SASRC)/zfs
ZLIB= $(SRC)/contrib/zlib
diff --git a/usr/src/boot/sys/boot/Makefile.lib b/usr/src/boot/Makefile.lib
index baa97a1513..baa97a1513 100644
--- a/usr/src/boot/sys/boot/Makefile.lib
+++ b/usr/src/boot/Makefile.lib
diff --git a/usr/src/boot/sys/boot/README b/usr/src/boot/README.loader
index 22faea26b8..22faea26b8 100644
--- a/usr/src/boot/sys/boot/README
+++ b/usr/src/boot/README.loader
diff --git a/usr/src/boot/Readme.txt b/usr/src/boot/Readme.txt
index 6fe0768889..8bbbb3e34a 100644
--- a/usr/src/boot/Readme.txt
+++ b/usr/src/boot/Readme.txt
@@ -10,11 +10,8 @@
#
#
-# Copyright 2016 Toomas Soome <tsoome@me.com>
+# Copyright 2022 Toomas Soome <tsoome@me.com>
#
-# Please update the svn revision number on source refresh.
-
-Current snapshot from freebsd revision 296191.
This is source tree snapshot of loader and related parts from
freebsd source.
@@ -26,10 +23,9 @@ containing Makefile and licence notes for build and packaging.
Directories from freebsd userland (freebsd /usr/src tree):
include
-lib
-Directories from freebsd kernel tree, including boot loader itself
-are located in sys subdirectory (freebsd /usr/src/sys tree):
+Directories from freebsd kernel tree are located in sys subdirectory
+(freebsd /usr/src/sys tree):
platform specific include files:
@@ -42,10 +38,7 @@ sys/sys
sys/ufs
zfs boot module import in freebsd:
-sys/cddl
-
-boot loader sources are in:
-sys/boot
+sys/cddl
Note, some of the directories are not 1:1 mapping in this source import,
because of differences of build systems used in illumos and freebsd.
@@ -53,4 +46,4 @@ Also some differences are due to fact, we do not need all the variants of
stage1/stage2 boot blocks which are built in freebsd due to the historical
or technical reasons.
-Mar, 2016
+Feb, 2022
diff --git a/usr/src/boot/sys/boot/common/Makefile.inc b/usr/src/boot/common/Makefile.inc
index bbf81332d2..bbf81332d2 100644
--- a/usr/src/boot/sys/boot/common/Makefile.inc
+++ b/usr/src/boot/common/Makefile.inc
diff --git a/usr/src/boot/sys/boot/common/bcache.c b/usr/src/boot/common/bcache.c
index 5838f02fef..5838f02fef 100644
--- a/usr/src/boot/sys/boot/common/bcache.c
+++ b/usr/src/boot/common/bcache.c
diff --git a/usr/src/boot/sys/boot/common/boot.c b/usr/src/boot/common/boot.c
index db5aae9b92..db5aae9b92 100644
--- a/usr/src/boot/sys/boot/common/boot.c
+++ b/usr/src/boot/common/boot.c
diff --git a/usr/src/boot/sys/boot/common/bootstrap.h b/usr/src/boot/common/bootstrap.h
index 689905ae68..689905ae68 100644
--- a/usr/src/boot/sys/boot/common/bootstrap.h
+++ b/usr/src/boot/common/bootstrap.h
diff --git a/usr/src/boot/sys/boot/common/commands.c b/usr/src/boot/common/commands.c
index 04a2bf591f..04a2bf591f 100644
--- a/usr/src/boot/sys/boot/common/commands.c
+++ b/usr/src/boot/common/commands.c
diff --git a/usr/src/boot/sys/boot/common/console.c b/usr/src/boot/common/console.c
index 0472ae7645..0472ae7645 100644
--- a/usr/src/boot/sys/boot/common/console.c
+++ b/usr/src/boot/common/console.c
diff --git a/usr/src/boot/sys/boot/common/dev_net.c b/usr/src/boot/common/dev_net.c
index a71127c641..a71127c641 100644
--- a/usr/src/boot/sys/boot/common/dev_net.c
+++ b/usr/src/boot/common/dev_net.c
diff --git a/usr/src/boot/sys/boot/common/dev_net.h b/usr/src/boot/common/dev_net.h
index 995b67241d..995b67241d 100644
--- a/usr/src/boot/sys/boot/common/dev_net.h
+++ b/usr/src/boot/common/dev_net.h
diff --git a/usr/src/boot/sys/boot/common/devopen.c b/usr/src/boot/common/devopen.c
index c4aa21c5c6..c4aa21c5c6 100644
--- a/usr/src/boot/sys/boot/common/devopen.c
+++ b/usr/src/boot/common/devopen.c
diff --git a/usr/src/boot/sys/boot/common/disk.c b/usr/src/boot/common/disk.c
index 08912cc4e1..08912cc4e1 100644
--- a/usr/src/boot/sys/boot/common/disk.c
+++ b/usr/src/boot/common/disk.c
diff --git a/usr/src/boot/sys/boot/common/disk.h b/usr/src/boot/common/disk.h
index 81d002314f..81d002314f 100644
--- a/usr/src/boot/sys/boot/common/disk.h
+++ b/usr/src/boot/common/disk.h
diff --git a/usr/src/boot/sys/boot/common/gfx_fb.c b/usr/src/boot/common/gfx_fb.c
index 73dc1579d7..6cb328acbb 100644
--- a/usr/src/boot/sys/boot/common/gfx_fb.c
+++ b/usr/src/boot/common/gfx_fb.c
@@ -141,13 +141,7 @@ static bool insert_font(char *, FONT_FLAGS);
static uint8_t *
gfx_get_fb_address(void)
{
-#if defined(EFI)
- return ((uint8_t *)(uintptr_t)
- gfx_fb.framebuffer_common.framebuffer_addr);
-#else
- return ((uint8_t *)PTOV((uint32_t)
- gfx_fb.framebuffer_common.framebuffer_addr & 0xffffffff));
-#endif
+ return ((uint8_t *)ptov(gfx_fb.framebuffer_common.framebuffer_addr));
}
/*
diff --git a/usr/src/boot/sys/boot/common/gfx_fb.h b/usr/src/boot/common/gfx_fb.h
index 8d20dcf162..8d20dcf162 100644
--- a/usr/src/boot/sys/boot/common/gfx_fb.h
+++ b/usr/src/boot/common/gfx_fb.h
diff --git a/usr/src/boot/sys/boot/common/gpt.c b/usr/src/boot/common/gpt.c
index e63a5419f1..e63a5419f1 100644
--- a/usr/src/boot/sys/boot/common/gpt.c
+++ b/usr/src/boot/common/gpt.c
diff --git a/usr/src/boot/sys/boot/common/gpt.h b/usr/src/boot/common/gpt.h
index afbc3a7abc..afbc3a7abc 100644
--- a/usr/src/boot/sys/boot/common/gpt.h
+++ b/usr/src/boot/common/gpt.h
diff --git a/usr/src/boot/sys/boot/common/help.common b/usr/src/boot/common/help.common
index dca3b09ab9..dca3b09ab9 100644
--- a/usr/src/boot/sys/boot/common/help.common
+++ b/usr/src/boot/common/help.common
diff --git a/usr/src/boot/sys/boot/common/install.c b/usr/src/boot/common/install.c
index 36e7c6484d..36e7c6484d 100644
--- a/usr/src/boot/sys/boot/common/install.c
+++ b/usr/src/boot/common/install.c
diff --git a/usr/src/boot/sys/boot/common/interp.c b/usr/src/boot/common/interp.c
index f69d0460e5..f69d0460e5 100644
--- a/usr/src/boot/sys/boot/common/interp.c
+++ b/usr/src/boot/common/interp.c
diff --git a/usr/src/boot/sys/boot/common/interp_backslash.c b/usr/src/boot/common/interp_backslash.c
index c8d59fa070..c8d59fa070 100644
--- a/usr/src/boot/sys/boot/common/interp_backslash.c
+++ b/usr/src/boot/common/interp_backslash.c
diff --git a/usr/src/boot/sys/boot/common/interp_forth.c b/usr/src/boot/common/interp_forth.c
index 1f3a92bcb4..1f3a92bcb4 100644
--- a/usr/src/boot/sys/boot/common/interp_forth.c
+++ b/usr/src/boot/common/interp_forth.c
diff --git a/usr/src/boot/sys/boot/common/interp_parse.c b/usr/src/boot/common/interp_parse.c
index 11cf11c057..11cf11c057 100644
--- a/usr/src/boot/sys/boot/common/interp_parse.c
+++ b/usr/src/boot/common/interp_parse.c
diff --git a/usr/src/boot/sys/boot/common/isapnp.c b/usr/src/boot/common/isapnp.c
index 438687bc45..438687bc45 100644
--- a/usr/src/boot/sys/boot/common/isapnp.c
+++ b/usr/src/boot/common/isapnp.c
diff --git a/usr/src/boot/sys/boot/common/isapnp.h b/usr/src/boot/common/isapnp.h
index 595cbf0fee..595cbf0fee 100644
--- a/usr/src/boot/sys/boot/common/isapnp.h
+++ b/usr/src/boot/common/isapnp.h
diff --git a/usr/src/boot/sys/boot/common/linenoise/LICENSE b/usr/src/boot/common/linenoise/LICENSE
index 18e814865a..18e814865a 100755
--- a/usr/src/boot/sys/boot/common/linenoise/LICENSE
+++ b/usr/src/boot/common/linenoise/LICENSE
diff --git a/usr/src/boot/sys/boot/common/linenoise/LICENSE.descrip b/usr/src/boot/common/linenoise/LICENSE.descrip
index 2191e517d7..2191e517d7 100644
--- a/usr/src/boot/sys/boot/common/linenoise/LICENSE.descrip
+++ b/usr/src/boot/common/linenoise/LICENSE.descrip
diff --git a/usr/src/boot/sys/boot/common/linenoise/Makefile b/usr/src/boot/common/linenoise/Makefile
index a285410678..a285410678 100755
--- a/usr/src/boot/sys/boot/common/linenoise/Makefile
+++ b/usr/src/boot/common/linenoise/Makefile
diff --git a/usr/src/boot/sys/boot/common/linenoise/README.markdown b/usr/src/boot/common/linenoise/README.markdown
index c845673cd4..c845673cd4 100755
--- a/usr/src/boot/sys/boot/common/linenoise/README.markdown
+++ b/usr/src/boot/common/linenoise/README.markdown
diff --git a/usr/src/boot/sys/boot/common/linenoise/example.c b/usr/src/boot/common/linenoise/example.c
index a2f0936ede..a2f0936ede 100755
--- a/usr/src/boot/sys/boot/common/linenoise/example.c
+++ b/usr/src/boot/common/linenoise/example.c
diff --git a/usr/src/boot/sys/boot/common/linenoise/linenoise.c b/usr/src/boot/common/linenoise/linenoise.c
index e3a72151a4..e3a72151a4 100755
--- a/usr/src/boot/sys/boot/common/linenoise/linenoise.c
+++ b/usr/src/boot/common/linenoise/linenoise.c
diff --git a/usr/src/boot/sys/boot/common/linenoise/linenoise.h b/usr/src/boot/common/linenoise/linenoise.h
index fbb01cfaad..fbb01cfaad 100755
--- a/usr/src/boot/sys/boot/common/linenoise/linenoise.h
+++ b/usr/src/boot/common/linenoise/linenoise.h
diff --git a/usr/src/boot/sys/boot/common/load_elf.c b/usr/src/boot/common/load_elf.c
index b7fc4bea09..b7fc4bea09 100644
--- a/usr/src/boot/sys/boot/common/load_elf.c
+++ b/usr/src/boot/common/load_elf.c
diff --git a/usr/src/boot/sys/boot/common/load_elf32.c b/usr/src/boot/common/load_elf32.c
index 0c9f460d48..0c9f460d48 100644
--- a/usr/src/boot/sys/boot/common/load_elf32.c
+++ b/usr/src/boot/common/load_elf32.c
diff --git a/usr/src/boot/sys/boot/common/load_elf32_obj.c b/usr/src/boot/common/load_elf32_obj.c
index 94b0896188..94b0896188 100644
--- a/usr/src/boot/sys/boot/common/load_elf32_obj.c
+++ b/usr/src/boot/common/load_elf32_obj.c
diff --git a/usr/src/boot/sys/boot/common/load_elf64.c b/usr/src/boot/common/load_elf64.c
index c29e8e3596..c29e8e3596 100644
--- a/usr/src/boot/sys/boot/common/load_elf64.c
+++ b/usr/src/boot/common/load_elf64.c
diff --git a/usr/src/boot/sys/boot/common/load_elf64_obj.c b/usr/src/boot/common/load_elf64_obj.c
index 3c9371ba01..3c9371ba01 100644
--- a/usr/src/boot/sys/boot/common/load_elf64_obj.c
+++ b/usr/src/boot/common/load_elf64_obj.c
diff --git a/usr/src/boot/sys/boot/common/load_elf_obj.c b/usr/src/boot/common/load_elf_obj.c
index f32388e170..f32388e170 100644
--- a/usr/src/boot/sys/boot/common/load_elf_obj.c
+++ b/usr/src/boot/common/load_elf_obj.c
diff --git a/usr/src/boot/sys/boot/common/ls.c b/usr/src/boot/common/ls.c
index 1ca760c7ab..1ca760c7ab 100644
--- a/usr/src/boot/sys/boot/common/ls.c
+++ b/usr/src/boot/common/ls.c
diff --git a/usr/src/boot/sys/boot/common/mb_header.S b/usr/src/boot/common/mb_header.S
index 411d126025..411d126025 100644
--- a/usr/src/boot/sys/boot/common/mb_header.S
+++ b/usr/src/boot/common/mb_header.S
diff --git a/usr/src/boot/sys/boot/common/md.c b/usr/src/boot/common/md.c
index 175833d748..175833d748 100644
--- a/usr/src/boot/sys/boot/common/md.c
+++ b/usr/src/boot/common/md.c
diff --git a/usr/src/boot/sys/boot/common/merge_help.awk b/usr/src/boot/common/merge_help.awk
index 1070f73f1f..1070f73f1f 100644
--- a/usr/src/boot/sys/boot/common/merge_help.awk
+++ b/usr/src/boot/common/merge_help.awk
diff --git a/usr/src/boot/sys/boot/common/misc.c b/usr/src/boot/common/misc.c
index ef21ad4db2..ef21ad4db2 100644
--- a/usr/src/boot/sys/boot/common/misc.c
+++ b/usr/src/boot/common/misc.c
diff --git a/usr/src/boot/sys/boot/common/module.c b/usr/src/boot/common/module.c
index 481c07eb58..481c07eb58 100644
--- a/usr/src/boot/sys/boot/common/module.c
+++ b/usr/src/boot/common/module.c
diff --git a/usr/src/boot/sys/boot/common/multiboot2.c b/usr/src/boot/common/multiboot2.c
index 55af7d0456..55af7d0456 100644
--- a/usr/src/boot/sys/boot/common/multiboot2.c
+++ b/usr/src/boot/common/multiboot2.c
diff --git a/usr/src/boot/sys/boot/common/newvers.sh b/usr/src/boot/common/newvers.sh
index 0cb1b16b76..0cb1b16b76 100755
--- a/usr/src/boot/sys/boot/common/newvers.sh
+++ b/usr/src/boot/common/newvers.sh
diff --git a/usr/src/boot/sys/boot/common/nvstore.c b/usr/src/boot/common/nvstore.c
index b3e6cdbeaa..b3e6cdbeaa 100644
--- a/usr/src/boot/sys/boot/common/nvstore.c
+++ b/usr/src/boot/common/nvstore.c
diff --git a/usr/src/boot/sys/boot/common/part.c b/usr/src/boot/common/part.c
index 084eb38f80..084eb38f80 100644
--- a/usr/src/boot/sys/boot/common/part.c
+++ b/usr/src/boot/common/part.c
diff --git a/usr/src/boot/sys/boot/common/part.h b/usr/src/boot/common/part.h
index bdeddcbd5c..bdeddcbd5c 100644
--- a/usr/src/boot/sys/boot/common/part.h
+++ b/usr/src/boot/common/part.h
diff --git a/usr/src/boot/sys/boot/common/paths.h b/usr/src/boot/common/paths.h
index 3934ef4909..3934ef4909 100644
--- a/usr/src/boot/sys/boot/common/paths.h
+++ b/usr/src/boot/common/paths.h
diff --git a/usr/src/boot/sys/boot/common/pnp.c b/usr/src/boot/common/pnp.c
index 14b0b965f0..14b0b965f0 100644
--- a/usr/src/boot/sys/boot/common/pnp.c
+++ b/usr/src/boot/common/pnp.c
diff --git a/usr/src/boot/sys/boot/common/rbx.h b/usr/src/boot/common/rbx.h
index 5fdb9075b2..5fdb9075b2 100644
--- a/usr/src/boot/sys/boot/common/rbx.h
+++ b/usr/src/boot/common/rbx.h
diff --git a/usr/src/boot/sys/boot/common/reloc_elf.c b/usr/src/boot/common/reloc_elf.c
index 188d259069..188d259069 100644
--- a/usr/src/boot/sys/boot/common/reloc_elf.c
+++ b/usr/src/boot/common/reloc_elf.c
diff --git a/usr/src/boot/sys/boot/common/reloc_elf32.c b/usr/src/boot/common/reloc_elf32.c
index 03d9d73bab..03d9d73bab 100644
--- a/usr/src/boot/sys/boot/common/reloc_elf32.c
+++ b/usr/src/boot/common/reloc_elf32.c
diff --git a/usr/src/boot/sys/boot/common/reloc_elf64.c b/usr/src/boot/common/reloc_elf64.c
index c8dcf2a36b..c8dcf2a36b 100644
--- a/usr/src/boot/sys/boot/common/reloc_elf64.c
+++ b/usr/src/boot/common/reloc_elf64.c
diff --git a/usr/src/boot/sys/boot/common/self_reloc.c b/usr/src/boot/common/self_reloc.c
index f82006078f..f82006078f 100644
--- a/usr/src/boot/sys/boot/common/self_reloc.c
+++ b/usr/src/boot/common/self_reloc.c
diff --git a/usr/src/boot/sys/boot/common/tem.c b/usr/src/boot/common/tem.c
index 2798f2883d..2798f2883d 100644
--- a/usr/src/boot/sys/boot/common/tem.c
+++ b/usr/src/boot/common/tem.c
diff --git a/usr/src/boot/sys/boot/common/util.c b/usr/src/boot/common/util.c
index d73d992105..d73d992105 100644
--- a/usr/src/boot/sys/boot/common/util.c
+++ b/usr/src/boot/common/util.c
diff --git a/usr/src/boot/sys/boot/common/util.h b/usr/src/boot/common/util.h
index 88a99f19f0..88a99f19f0 100644
--- a/usr/src/boot/sys/boot/common/util.h
+++ b/usr/src/boot/common/util.h
diff --git a/usr/src/boot/sys/boot/common/vdisk.c b/usr/src/boot/common/vdisk.c
index bb5b2eb6d1..bb5b2eb6d1 100644
--- a/usr/src/boot/sys/boot/common/vdisk.c
+++ b/usr/src/boot/common/vdisk.c
diff --git a/usr/src/boot/sys/boot/common/zfs_cmd.c b/usr/src/boot/common/zfs_cmd.c
index fd8edd10c3..fd8edd10c3 100644
--- a/usr/src/boot/sys/boot/common/zfs_cmd.c
+++ b/usr/src/boot/common/zfs_cmd.c
diff --git a/usr/src/boot/sys/boot/efi/Makefile b/usr/src/boot/efi/Makefile
index 76032c7603..76032c7603 100644
--- a/usr/src/boot/sys/boot/efi/Makefile
+++ b/usr/src/boot/efi/Makefile
diff --git a/usr/src/boot/sys/boot/efi/Makefile.inc b/usr/src/boot/efi/Makefile.inc
index ad29e53249..ad29e53249 100644
--- a/usr/src/boot/sys/boot/efi/Makefile.inc
+++ b/usr/src/boot/efi/Makefile.inc
diff --git a/usr/src/boot/sys/boot/efi/include/Guid/MemoryTypeInformation.h b/usr/src/boot/efi/include/Guid/MemoryTypeInformation.h
index be9c4b5177..be9c4b5177 100644
--- a/usr/src/boot/sys/boot/efi/include/Guid/MemoryTypeInformation.h
+++ b/usr/src/boot/efi/include/Guid/MemoryTypeInformation.h
diff --git a/usr/src/boot/sys/boot/efi/include/Guid/MtcVendor.h b/usr/src/boot/efi/include/Guid/MtcVendor.h
index 3aa774f554..3aa774f554 100644
--- a/usr/src/boot/sys/boot/efi/include/Guid/MtcVendor.h
+++ b/usr/src/boot/efi/include/Guid/MtcVendor.h
diff --git a/usr/src/boot/sys/boot/efi/include/Guid/ZeroGuid.h b/usr/src/boot/efi/include/Guid/ZeroGuid.h
index 6de8c3821f..6de8c3821f 100644
--- a/usr/src/boot/sys/boot/efi/include/Guid/ZeroGuid.h
+++ b/usr/src/boot/efi/include/Guid/ZeroGuid.h
diff --git a/usr/src/boot/sys/boot/efi/include/Protocol/EdidActive.h b/usr/src/boot/efi/include/Protocol/EdidActive.h
index 1f6ff052a9..1f6ff052a9 100644
--- a/usr/src/boot/sys/boot/efi/include/Protocol/EdidActive.h
+++ b/usr/src/boot/efi/include/Protocol/EdidActive.h
diff --git a/usr/src/boot/sys/boot/efi/include/Protocol/EdidDiscovered.h b/usr/src/boot/efi/include/Protocol/EdidDiscovered.h
index c10b6ee89a..c10b6ee89a 100644
--- a/usr/src/boot/sys/boot/efi/include/Protocol/EdidDiscovered.h
+++ b/usr/src/boot/efi/include/Protocol/EdidDiscovered.h
diff --git a/usr/src/boot/sys/boot/efi/include/Protocol/EdidOverride.h b/usr/src/boot/efi/include/Protocol/EdidOverride.h
index 450c95641f..450c95641f 100644
--- a/usr/src/boot/sys/boot/efi/include/Protocol/EdidOverride.h
+++ b/usr/src/boot/efi/include/Protocol/EdidOverride.h
diff --git a/usr/src/boot/sys/boot/efi/include/README b/usr/src/boot/efi/include/README
index bf821fae7e..bf821fae7e 100644
--- a/usr/src/boot/sys/boot/efi/include/README
+++ b/usr/src/boot/efi/include/README
diff --git a/usr/src/boot/sys/boot/efi/include/amd64/efibind.h b/usr/src/boot/efi/include/amd64/efibind.h
index 4cd25ed54b..4cd25ed54b 100644
--- a/usr/src/boot/sys/boot/efi/include/amd64/efibind.h
+++ b/usr/src/boot/efi/include/amd64/efibind.h
diff --git a/usr/src/boot/sys/boot/efi/include/amd64/pe.h b/usr/src/boot/efi/include/amd64/pe.h
index f8033c55ac..f8033c55ac 100644
--- a/usr/src/boot/sys/boot/efi/include/amd64/pe.h
+++ b/usr/src/boot/efi/include/amd64/pe.h
diff --git a/usr/src/boot/sys/boot/efi/include/arm/efibind.h b/usr/src/boot/efi/include/arm/efibind.h
index 177032adc0..177032adc0 100644
--- a/usr/src/boot/sys/boot/efi/include/arm/efibind.h
+++ b/usr/src/boot/efi/include/arm/efibind.h
diff --git a/usr/src/boot/sys/boot/efi/include/arm64/efibind.h b/usr/src/boot/efi/include/arm64/efibind.h
index 8581643b98..8581643b98 100644
--- a/usr/src/boot/sys/boot/efi/include/arm64/efibind.h
+++ b/usr/src/boot/efi/include/arm64/efibind.h
diff --git a/usr/src/boot/sys/boot/efi/include/efi.h b/usr/src/boot/efi/include/efi.h
index ea4041047b..ea4041047b 100644
--- a/usr/src/boot/sys/boot/efi/include/efi.h
+++ b/usr/src/boot/efi/include/efi.h
diff --git a/usr/src/boot/sys/boot/efi/include/efi_driver_utils.h b/usr/src/boot/efi/include/efi_driver_utils.h
index f030d4e61f..f030d4e61f 100644
--- a/usr/src/boot/sys/boot/efi/include/efi_driver_utils.h
+++ b/usr/src/boot/efi/include/efi_driver_utils.h
diff --git a/usr/src/boot/sys/boot/efi/include/efi_drivers.h b/usr/src/boot/efi/include/efi_drivers.h
index 1a96d669dc..1a96d669dc 100644
--- a/usr/src/boot/sys/boot/efi/include/efi_drivers.h
+++ b/usr/src/boot/efi/include/efi_drivers.h
diff --git a/usr/src/boot/sys/boot/efi/include/efi_nii.h b/usr/src/boot/efi/include/efi_nii.h
index 561cbd46a3..561cbd46a3 100644
--- a/usr/src/boot/sys/boot/efi/include/efi_nii.h
+++ b/usr/src/boot/efi/include/efi_nii.h
diff --git a/usr/src/boot/sys/boot/efi/include/efiapi.h b/usr/src/boot/efi/include/efiapi.h
index 15c3187f5e..15c3187f5e 100644
--- a/usr/src/boot/sys/boot/efi/include/efiapi.h
+++ b/usr/src/boot/efi/include/efiapi.h
diff --git a/usr/src/boot/sys/boot/efi/include/efichar.h b/usr/src/boot/efi/include/efichar.h
index 97ca28bf4f..97ca28bf4f 100644
--- a/usr/src/boot/sys/boot/efi/include/efichar.h
+++ b/usr/src/boot/efi/include/efichar.h
diff --git a/usr/src/boot/sys/boot/efi/include/eficon.h b/usr/src/boot/efi/include/eficon.h
index b5a387cb08..b5a387cb08 100644
--- a/usr/src/boot/sys/boot/efi/include/eficon.h
+++ b/usr/src/boot/efi/include/eficon.h
diff --git a/usr/src/boot/sys/boot/efi/include/eficonsctl.h b/usr/src/boot/efi/include/eficonsctl.h
index 68be3d69f4..68be3d69f4 100644
--- a/usr/src/boot/sys/boot/efi/include/eficonsctl.h
+++ b/usr/src/boot/efi/include/eficonsctl.h
diff --git a/usr/src/boot/sys/boot/efi/include/efidebug.h b/usr/src/boot/efi/include/efidebug.h
index 5576d5f4e4..5576d5f4e4 100644
--- a/usr/src/boot/sys/boot/efi/include/efidebug.h
+++ b/usr/src/boot/efi/include/efidebug.h
diff --git a/usr/src/boot/sys/boot/efi/include/efidef.h b/usr/src/boot/efi/include/efidef.h
index 4c075b0e2e..4c075b0e2e 100644
--- a/usr/src/boot/sys/boot/efi/include/efidef.h
+++ b/usr/src/boot/efi/include/efidef.h
diff --git a/usr/src/boot/sys/boot/efi/include/efidevp.h b/usr/src/boot/efi/include/efidevp.h
index bd8f304922..bd8f304922 100644
--- a/usr/src/boot/sys/boot/efi/include/efidevp.h
+++ b/usr/src/boot/efi/include/efidevp.h
diff --git a/usr/src/boot/sys/boot/efi/include/efierr.h b/usr/src/boot/efi/include/efierr.h
index a8b6557185..a8b6557185 100644
--- a/usr/src/boot/sys/boot/efi/include/efierr.h
+++ b/usr/src/boot/efi/include/efierr.h
diff --git a/usr/src/boot/sys/boot/efi/include/efifpswa.h b/usr/src/boot/efi/include/efifpswa.h
index 21823c5ff6..21823c5ff6 100644
--- a/usr/src/boot/sys/boot/efi/include/efifpswa.h
+++ b/usr/src/boot/efi/include/efifpswa.h
diff --git a/usr/src/boot/sys/boot/efi/include/efifs.h b/usr/src/boot/efi/include/efifs.h
index 58febb66eb..58febb66eb 100644
--- a/usr/src/boot/sys/boot/efi/include/efifs.h
+++ b/usr/src/boot/efi/include/efifs.h
diff --git a/usr/src/boot/sys/boot/efi/include/efigop.h b/usr/src/boot/efi/include/efigop.h
index 104fa6e44b..104fa6e44b 100644
--- a/usr/src/boot/sys/boot/efi/include/efigop.h
+++ b/usr/src/boot/efi/include/efigop.h
diff --git a/usr/src/boot/sys/boot/efi/include/efigpt.h b/usr/src/boot/efi/include/efigpt.h
index ac90a304f7..ac90a304f7 100644
--- a/usr/src/boot/sys/boot/efi/include/efigpt.h
+++ b/usr/src/boot/efi/include/efigpt.h
diff --git a/usr/src/boot/sys/boot/efi/include/efiip.h b/usr/src/boot/efi/include/efiip.h
index 839507964f..839507964f 100644
--- a/usr/src/boot/sys/boot/efi/include/efiip.h
+++ b/usr/src/boot/efi/include/efiip.h
diff --git a/usr/src/boot/sys/boot/efi/include/efilib.h b/usr/src/boot/efi/include/efilib.h
index d1cced2e4d..d1cced2e4d 100644
--- a/usr/src/boot/sys/boot/efi/include/efilib.h
+++ b/usr/src/boot/efi/include/efilib.h
diff --git a/usr/src/boot/sys/boot/efi/include/efinet.h b/usr/src/boot/efi/include/efinet.h
index 3ac58b2431..3ac58b2431 100644
--- a/usr/src/boot/sys/boot/efi/include/efinet.h
+++ b/usr/src/boot/efi/include/efinet.h
diff --git a/usr/src/boot/sys/boot/efi/include/efipart.h b/usr/src/boot/efi/include/efipart.h
index ef1a8709d9..ef1a8709d9 100644
--- a/usr/src/boot/sys/boot/efi/include/efipart.h
+++ b/usr/src/boot/efi/include/efipart.h
diff --git a/usr/src/boot/sys/boot/efi/include/efipciio.h b/usr/src/boot/efi/include/efipciio.h
index b42fa59395..b42fa59395 100644
--- a/usr/src/boot/sys/boot/efi/include/efipciio.h
+++ b/usr/src/boot/efi/include/efipciio.h
diff --git a/usr/src/boot/sys/boot/efi/include/efipoint.h b/usr/src/boot/efi/include/efipoint.h
index 46e92ffd3b..46e92ffd3b 100644
--- a/usr/src/boot/sys/boot/efi/include/efipoint.h
+++ b/usr/src/boot/efi/include/efipoint.h
diff --git a/usr/src/boot/sys/boot/efi/include/efiprot.h b/usr/src/boot/efi/include/efiprot.h
index bd051a0ee1..bd051a0ee1 100644
--- a/usr/src/boot/sys/boot/efi/include/efiprot.h
+++ b/usr/src/boot/efi/include/efiprot.h
diff --git a/usr/src/boot/sys/boot/efi/include/efipxebc.h b/usr/src/boot/efi/include/efipxebc.h
index ba0b2e9b6c..ba0b2e9b6c 100644
--- a/usr/src/boot/sys/boot/efi/include/efipxebc.h
+++ b/usr/src/boot/efi/include/efipxebc.h
diff --git a/usr/src/boot/sys/boot/efi/include/efiser.h b/usr/src/boot/efi/include/efiser.h
index e3d66e203a..e3d66e203a 100644
--- a/usr/src/boot/sys/boot/efi/include/efiser.h
+++ b/usr/src/boot/efi/include/efiser.h
diff --git a/usr/src/boot/sys/boot/efi/include/efistdarg.h b/usr/src/boot/efi/include/efistdarg.h
index 25f5569841..25f5569841 100644
--- a/usr/src/boot/sys/boot/efi/include/efistdarg.h
+++ b/usr/src/boot/efi/include/efistdarg.h
diff --git a/usr/src/boot/sys/boot/efi/include/efitcp.h b/usr/src/boot/efi/include/efitcp.h
index 6c5df7fd94..6c5df7fd94 100644
--- a/usr/src/boot/sys/boot/efi/include/efitcp.h
+++ b/usr/src/boot/efi/include/efitcp.h
diff --git a/usr/src/boot/sys/boot/efi/include/efiudp.h b/usr/src/boot/efi/include/efiudp.h
index 7c8b467eb9..7c8b467eb9 100644
--- a/usr/src/boot/sys/boot/efi/include/efiudp.h
+++ b/usr/src/boot/efi/include/efiudp.h
diff --git a/usr/src/boot/sys/boot/efi/include/efiuga.h b/usr/src/boot/efi/include/efiuga.h
index dce4e044c1..dce4e044c1 100644
--- a/usr/src/boot/sys/boot/efi/include/efiuga.h
+++ b/usr/src/boot/efi/include/efiuga.h
diff --git a/usr/src/boot/sys/boot/efi/include/efizfs.h b/usr/src/boot/efi/include/efizfs.h
index 4fc0ff551f..4fc0ff551f 100644
--- a/usr/src/boot/sys/boot/efi/include/efizfs.h
+++ b/usr/src/boot/efi/include/efizfs.h
diff --git a/usr/src/boot/sys/boot/efi/include/i386/efibind.h b/usr/src/boot/efi/include/i386/efibind.h
index 3bbed66176..3bbed66176 100644
--- a/usr/src/boot/sys/boot/efi/include/i386/efibind.h
+++ b/usr/src/boot/efi/include/i386/efibind.h
diff --git a/usr/src/boot/sys/boot/efi/include/i386/pe.h b/usr/src/boot/efi/include/i386/pe.h
index e2ae25c3dd..e2ae25c3dd 100644
--- a/usr/src/boot/sys/boot/efi/include/i386/pe.h
+++ b/usr/src/boot/efi/include/i386/pe.h
diff --git a/usr/src/boot/sys/boot/efi/libefi/Makefile b/usr/src/boot/efi/libefi/Makefile
index 6ba07bc880..6ba07bc880 100644
--- a/usr/src/boot/sys/boot/efi/libefi/Makefile
+++ b/usr/src/boot/efi/libefi/Makefile
diff --git a/usr/src/boot/sys/boot/efi/libefi/Makefile.com b/usr/src/boot/efi/libefi/Makefile.com
index 5d3285db2c..ae9c3da748 100644
--- a/usr/src/boot/sys/boot/efi/libefi/Makefile.com
+++ b/usr/src/boot/efi/libefi/Makefile.com
@@ -14,7 +14,7 @@
#
include $(SRC)/Makefile.master
-include $(SRC)/boot/sys/boot/Makefile.inc
+include $(SRC)/boot/Makefile.inc
install:
@@ -39,13 +39,13 @@ SRCS += delay.c \
OBJS= $(SRCS:%.c=%.o)
CPPFLAGS += -DEFI
-CPPFLAGS += -I. -I../../../../../include -I../../../..
+CPPFLAGS += -I. -I../../../include -I../../../sys
CPPFLAGS += -I$(SRC)/common/ficl -I../../../libficl
CPPFLAGS += -I../../include
CPPFLAGS += -I../../include/$(MACHINE)
-CPPFLAGS += -I../../../../../lib/libstand
+CPPFLAGS += -I../../../libsa
CPPFLAGS += -I$(ZFSSRC)
-CPPFLAGS += -I../../../../cddl/boot/zfs
+CPPFLAGS += -I../../../sys/cddl/boot/zfs
gfx_fb.o := CPPFLAGS += $(DEFAULT_CONSOLE_COLOR) -I$(LZ4)
pnglite.o := CPPFLAGS += -I$(ZLIB)
@@ -68,11 +68,11 @@ clobber:
machine:
$(RM) machine
- $(SYMLINK) ../../../../$(MACHINE)/include machine
+ $(SYMLINK) ../../../sys/$(MACHINE)/include machine
x86:
$(RM) x86
- $(SYMLINK) ../../../../x86/include x86
+ $(SYMLINK) ../../../sys/x86/include x86
%.o: ../%.c
$(COMPILE.c) $<
diff --git a/usr/src/boot/sys/boot/efi/libefi/amd64/Makefile b/usr/src/boot/efi/libefi/amd64/Makefile
index 6d247f44a5..6d247f44a5 100644
--- a/usr/src/boot/sys/boot/efi/libefi/amd64/Makefile
+++ b/usr/src/boot/efi/libefi/amd64/Makefile
diff --git a/usr/src/boot/sys/boot/efi/libefi/delay.c b/usr/src/boot/efi/libefi/delay.c
index 966eec88e7..966eec88e7 100644
--- a/usr/src/boot/sys/boot/efi/libefi/delay.c
+++ b/usr/src/boot/efi/libefi/delay.c
diff --git a/usr/src/boot/sys/boot/efi/libefi/devicename.c b/usr/src/boot/efi/libefi/devicename.c
index 34062f2f25..34062f2f25 100644
--- a/usr/src/boot/sys/boot/efi/libefi/devicename.c
+++ b/usr/src/boot/efi/libefi/devicename.c
diff --git a/usr/src/boot/sys/boot/efi/libefi/devpath.c b/usr/src/boot/efi/libefi/devpath.c
index 257d49fdd6..257d49fdd6 100644
--- a/usr/src/boot/sys/boot/efi/libefi/devpath.c
+++ b/usr/src/boot/efi/libefi/devpath.c
diff --git a/usr/src/boot/sys/boot/efi/libefi/efi_console.c b/usr/src/boot/efi/libefi/efi_console.c
index cdcc9ee297..cdcc9ee297 100644
--- a/usr/src/boot/sys/boot/efi/libefi/efi_console.c
+++ b/usr/src/boot/efi/libefi/efi_console.c
diff --git a/usr/src/boot/sys/boot/efi/libefi/efi_driver_utils.c b/usr/src/boot/efi/libefi/efi_driver_utils.c
index eeb8930fe3..eeb8930fe3 100644
--- a/usr/src/boot/sys/boot/efi/libefi/efi_driver_utils.c
+++ b/usr/src/boot/efi/libefi/efi_driver_utils.c
diff --git a/usr/src/boot/sys/boot/efi/libefi/efichar.c b/usr/src/boot/efi/libefi/efichar.c
index 3a2a773b81..3a2a773b81 100644
--- a/usr/src/boot/sys/boot/efi/libefi/efichar.c
+++ b/usr/src/boot/efi/libefi/efichar.c
diff --git a/usr/src/boot/sys/boot/efi/libefi/efienv.c b/usr/src/boot/efi/libefi/efienv.c
index 253d525c1a..253d525c1a 100644
--- a/usr/src/boot/sys/boot/efi/libefi/efienv.c
+++ b/usr/src/boot/efi/libefi/efienv.c
diff --git a/usr/src/boot/sys/boot/efi/libefi/efinet.c b/usr/src/boot/efi/libefi/efinet.c
index 2024eb343f..2024eb343f 100644
--- a/usr/src/boot/sys/boot/efi/libefi/efinet.c
+++ b/usr/src/boot/efi/libefi/efinet.c
diff --git a/usr/src/boot/sys/boot/efi/libefi/efipart.c b/usr/src/boot/efi/libefi/efipart.c
index 694dd1d28e..694dd1d28e 100644
--- a/usr/src/boot/sys/boot/efi/libefi/efipart.c
+++ b/usr/src/boot/efi/libefi/efipart.c
diff --git a/usr/src/boot/sys/boot/efi/libefi/efizfs.c b/usr/src/boot/efi/libefi/efizfs.c
index 570a97ecfa..570a97ecfa 100644
--- a/usr/src/boot/sys/boot/efi/libefi/efizfs.c
+++ b/usr/src/boot/efi/libefi/efizfs.c
diff --git a/usr/src/boot/sys/boot/efi/libefi/env.c b/usr/src/boot/efi/libefi/env.c
index eabee1dd07..eabee1dd07 100644
--- a/usr/src/boot/sys/boot/efi/libefi/env.c
+++ b/usr/src/boot/efi/libefi/env.c
diff --git a/usr/src/boot/sys/boot/efi/libefi/errno.c b/usr/src/boot/efi/libefi/errno.c
index c558bc608b..c558bc608b 100644
--- a/usr/src/boot/sys/boot/efi/libefi/errno.c
+++ b/usr/src/boot/efi/libefi/errno.c
diff --git a/usr/src/boot/sys/boot/efi/libefi/handles.c b/usr/src/boot/efi/libefi/handles.c
index 1e4ef6ffbd..1e4ef6ffbd 100644
--- a/usr/src/boot/sys/boot/efi/libefi/handles.c
+++ b/usr/src/boot/efi/libefi/handles.c
diff --git a/usr/src/boot/sys/boot/efi/libefi/i386/Makefile b/usr/src/boot/efi/libefi/i386/Makefile
index 60274fab76..60274fab76 100644
--- a/usr/src/boot/sys/boot/efi/libefi/i386/Makefile
+++ b/usr/src/boot/efi/libefi/i386/Makefile
diff --git a/usr/src/boot/sys/boot/efi/libefi/libefi.c b/usr/src/boot/efi/libefi/libefi.c
index b1af9c040e..b1af9c040e 100644
--- a/usr/src/boot/sys/boot/efi/libefi/libefi.c
+++ b/usr/src/boot/efi/libefi/libefi.c
diff --git a/usr/src/boot/sys/boot/efi/libefi/time.c b/usr/src/boot/efi/libefi/time.c
index c475ed7a41..c475ed7a41 100644
--- a/usr/src/boot/sys/boot/efi/libefi/time.c
+++ b/usr/src/boot/efi/libefi/time.c
diff --git a/usr/src/boot/sys/boot/efi/libefi/time_event.c b/usr/src/boot/efi/libefi/time_event.c
index afb30c1d9e..afb30c1d9e 100644
--- a/usr/src/boot/sys/boot/efi/libefi/time_event.c
+++ b/usr/src/boot/efi/libefi/time_event.c
diff --git a/usr/src/boot/sys/boot/efi/libefi/wchar.c b/usr/src/boot/efi/libefi/wchar.c
index c13922aa9f..c13922aa9f 100644
--- a/usr/src/boot/sys/boot/efi/libefi/wchar.c
+++ b/usr/src/boot/efi/libefi/wchar.c
diff --git a/usr/src/boot/sys/boot/efi/loader/Makefile b/usr/src/boot/efi/loader/Makefile
index f69f4b3c06..f69f4b3c06 100644
--- a/usr/src/boot/sys/boot/efi/loader/Makefile
+++ b/usr/src/boot/efi/loader/Makefile
diff --git a/usr/src/boot/sys/boot/efi/loader/Makefile.com b/usr/src/boot/efi/loader/Makefile.com
index 555cfa0db7..d7ae84091e 100644
--- a/usr/src/boot/sys/boot/efi/loader/Makefile.com
+++ b/usr/src/boot/efi/loader/Makefile.com
@@ -14,7 +14,7 @@
#
include $(SRC)/boot/Makefile.version
-include $(SRC)/boot/sys/boot/Makefile.inc
+include $(SRC)/boot/Makefile.inc
PROG= loader.sym
@@ -35,7 +35,6 @@ SRCS= \
multiboot2.c \
nvstore.c \
self_reloc.c \
- smbios.c \
tem.c \
vers.c
@@ -55,7 +54,6 @@ OBJS= \
multiboot2.o \
nvstore.o \
self_reloc.o \
- smbios.o \
tem.o \
vers.o
@@ -63,8 +61,8 @@ module.o := CPPFLAGS += -I$(CRYPTOSRC)
tem.o := CPPFLAGS += $(DEFAULT_CONSOLE_COLOR)
main.o := CPPFLAGS += -I$(SRC)/uts/common/fs/zfs
-CPPFLAGS += -I../../../../../include -I../../..../
-CPPFLAGS += -I../../../../../lib/libstand
+CPPFLAGS += -I../../../include -I../../../sys
+CPPFLAGS += -I../../../libsa
include ../../Makefile.inc
@@ -73,23 +71,14 @@ include ../arch/$(MACHINE)/Makefile.inc
CPPFLAGS += -I. -I..
CPPFLAGS += -I../../include
CPPFLAGS += -I../../include/$(MACHINE)
-CPPFLAGS += -I../../../..
-CPPFLAGS += -I../../../i386/libi386
CPPFLAGS += -I$(ZFSSRC)
-CPPFLAGS += -I../../../../cddl/boot/zfs
+CPPFLAGS += -I../../../sys/cddl/boot/zfs
CPPFLAGS += -I$(SRC)/uts/intel/sys/acpi
CPPFLAGS += -I$(PNGLITE)
CPPFLAGS += -DNO_PCI -DEFI
-# Export serial numbers, UUID, and asset tag from loader.
-smbios.o := CPPFLAGS += -DSMBIOS_SERIAL_NUMBERS
-# Use little-endian UUID format as defined in SMBIOS 2.6.
-smbios.o := CPPFLAGS += -DSMBIOS_LITTLE_ENDIAN_UUID
-# Use network-endian UUID format for backward compatibility.
-#CPPFLAGS += -DSMBIOS_NETWORK_ENDIAN_UUID
-
-DPLIBSTAND= ../../../libstand/$(MACHINE)/libstand_pics.a
-LIBSTAND= -L../../../libstand/$(MACHINE) -lstand_pics
+DPLIBSA= ../../../libsa/$(MACHINE)/libsa_pics.a
+LIBSA= -L../../../libsa/$(MACHINE) -lsa_pics
BOOT_FORTH= yes
CPPFLAGS += -DBOOT_FORTH
@@ -170,19 +159,19 @@ loader.bin: loader.sym
DPLIBEFI= ../../libefi/$(MACHINE)/libefi.a
LIBEFI= -L../../libefi/$(MACHINE) -lefi
-DPADD= $(DPLIBFICL) $(DPLIBEFI) $(DPLIBSTAND) $(LDSCRIPT)
-LDADD= $(LIBFICL) $(LIBEFI) $(LIBSTAND)
+DPADD= $(DPLIBFICL) $(DPLIBEFI) $(DPLIBSA) $(LDSCRIPT)
+LDADD= $(LIBFICL) $(LIBEFI) $(LIBSA)
loader.sym: $(OBJS) $(DPADD)
$(LD) $(LDFLAGS) -o $@ $(OBJS) $(LDADD)
machine:
$(RM) machine
- $(SYMLINK) ../../../../$(MACHINE)/include machine
+ $(SYMLINK) ../../../sys/$(MACHINE)/include machine
x86:
$(RM) x86
- $(SYMLINK) ../../../../x86/include x86
+ $(SYMLINK) ../../../sys/x86/include x86
clean clobber:
$(RM) $(CLEANFILES) $(OBJS) machine x86
diff --git a/usr/src/boot/sys/boot/efi/loader/acpi.c b/usr/src/boot/efi/loader/acpi.c
index ae25c0c0f6..ae25c0c0f6 100644
--- a/usr/src/boot/sys/boot/efi/loader/acpi.c
+++ b/usr/src/boot/efi/loader/acpi.c
diff --git a/usr/src/boot/sys/boot/efi/loader/amd64/Makefile b/usr/src/boot/efi/loader/amd64/Makefile
index a7894b50ca..a7894b50ca 100644
--- a/usr/src/boot/sys/boot/efi/loader/amd64/Makefile
+++ b/usr/src/boot/efi/loader/amd64/Makefile
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/Makefile.inc b/usr/src/boot/efi/loader/arch/amd64/Makefile.inc
index a4cf7e162d..a4cf7e162d 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/Makefile.inc
+++ b/usr/src/boot/efi/loader/arch/amd64/Makefile.inc
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/amd64_tramp.S b/usr/src/boot/efi/loader/arch/amd64/amd64_tramp.S
index c102d92435..c102d92435 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/amd64_tramp.S
+++ b/usr/src/boot/efi/loader/arch/amd64/amd64_tramp.S
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c b/usr/src/boot/efi/loader/arch/amd64/elf64_freebsd.c
index 7571eb9561..7571eb9561 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c
+++ b/usr/src/boot/efi/loader/arch/amd64/elf64_freebsd.c
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/exc.S b/usr/src/boot/efi/loader/arch/amd64/exc.S
index e52204bd96..e52204bd96 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/exc.S
+++ b/usr/src/boot/efi/loader/arch/amd64/exc.S
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/ldscript.amd64 b/usr/src/boot/efi/loader/arch/amd64/ldscript.amd64
index c37f655e52..c37f655e52 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/ldscript.amd64
+++ b/usr/src/boot/efi/loader/arch/amd64/ldscript.amd64
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/multiboot_tramp.S b/usr/src/boot/efi/loader/arch/amd64/multiboot_tramp.S
index e8ba51324a..e8ba51324a 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/multiboot_tramp.S
+++ b/usr/src/boot/efi/loader/arch/amd64/multiboot_tramp.S
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/start.S b/usr/src/boot/efi/loader/arch/amd64/start.S
index 774ef4fa79..774ef4fa79 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/start.S
+++ b/usr/src/boot/efi/loader/arch/amd64/start.S
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/amd64/trap.c b/usr/src/boot/efi/loader/arch/amd64/trap.c
index 844d759c06..844d759c06 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/amd64/trap.c
+++ b/usr/src/boot/efi/loader/arch/amd64/trap.c
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/arm/Makefile.inc b/usr/src/boot/efi/loader/arch/arm/Makefile.inc
index b2876ca195..b2876ca195 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/arm/Makefile.inc
+++ b/usr/src/boot/efi/loader/arch/arm/Makefile.inc
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/arm/exec.c b/usr/src/boot/efi/loader/arch/arm/exec.c
index 83d3f2b114..83d3f2b114 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/arm/exec.c
+++ b/usr/src/boot/efi/loader/arch/arm/exec.c
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/arm/ldscript.arm b/usr/src/boot/efi/loader/arch/arm/ldscript.arm
index a52af40884..a52af40884 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/arm/ldscript.arm
+++ b/usr/src/boot/efi/loader/arch/arm/ldscript.arm
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/arm/start.S b/usr/src/boot/efi/loader/arch/arm/start.S
index 443de4af1f..443de4af1f 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/arm/start.S
+++ b/usr/src/boot/efi/loader/arch/arm/start.S
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/arm64/Makefile.inc b/usr/src/boot/efi/loader/arch/arm64/Makefile.inc
index d263db956a..d263db956a 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/arm64/Makefile.inc
+++ b/usr/src/boot/efi/loader/arch/arm64/Makefile.inc
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/arm64/exec.c b/usr/src/boot/efi/loader/arch/arm64/exec.c
index a8420b4b64..a8420b4b64 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/arm64/exec.c
+++ b/usr/src/boot/efi/loader/arch/arm64/exec.c
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/arm64/ldscript.arm64 b/usr/src/boot/efi/loader/arch/arm64/ldscript.arm64
index 96da9ba662..96da9ba662 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/arm64/ldscript.arm64
+++ b/usr/src/boot/efi/loader/arch/arm64/ldscript.arm64
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/arm64/start.S b/usr/src/boot/efi/loader/arch/arm64/start.S
index cd9badb05b..cd9badb05b 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/arm64/start.S
+++ b/usr/src/boot/efi/loader/arch/arm64/start.S
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/Makefile.inc b/usr/src/boot/efi/loader/arch/i386/Makefile.inc
index 9290ace4de..9290ace4de 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/i386/Makefile.inc
+++ b/usr/src/boot/efi/loader/arch/i386/Makefile.inc
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/bootinfo.c b/usr/src/boot/efi/loader/arch/i386/bootinfo.c
index cbd6e4ebe9..cbd6e4ebe9 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/i386/bootinfo.c
+++ b/usr/src/boot/efi/loader/arch/i386/bootinfo.c
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/efimd.c b/usr/src/boot/efi/loader/arch/i386/efimd.c
index 41615be905..41615be905 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/i386/efimd.c
+++ b/usr/src/boot/efi/loader/arch/i386/efimd.c
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/elf32_freebsd.c b/usr/src/boot/efi/loader/arch/i386/elf32_freebsd.c
index b3a18d27d3..b3a18d27d3 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/i386/elf32_freebsd.c
+++ b/usr/src/boot/efi/loader/arch/i386/elf32_freebsd.c
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/exec.c b/usr/src/boot/efi/loader/arch/i386/exec.c
index 579f5593b2..579f5593b2 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/i386/exec.c
+++ b/usr/src/boot/efi/loader/arch/i386/exec.c
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/i386_copy.c b/usr/src/boot/efi/loader/arch/i386/i386_copy.c
index 522913f5da..522913f5da 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/i386/i386_copy.c
+++ b/usr/src/boot/efi/loader/arch/i386/i386_copy.c
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/ldscript.i386 b/usr/src/boot/efi/loader/arch/i386/ldscript.i386
index 735fe77158..735fe77158 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/i386/ldscript.i386
+++ b/usr/src/boot/efi/loader/arch/i386/ldscript.i386
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/multiboot_tramp.S b/usr/src/boot/efi/loader/arch/i386/multiboot_tramp.S
index 60be6a378d..60be6a378d 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/i386/multiboot_tramp.S
+++ b/usr/src/boot/efi/loader/arch/i386/multiboot_tramp.S
diff --git a/usr/src/boot/sys/boot/efi/loader/arch/i386/start.S b/usr/src/boot/efi/loader/arch/i386/start.S
index b597f419d4..b597f419d4 100644
--- a/usr/src/boot/sys/boot/efi/loader/arch/i386/start.S
+++ b/usr/src/boot/efi/loader/arch/i386/start.S
diff --git a/usr/src/boot/sys/boot/efi/loader/autoload.c b/usr/src/boot/efi/loader/autoload.c
index c1eb84928e..c1eb84928e 100644
--- a/usr/src/boot/sys/boot/efi/loader/autoload.c
+++ b/usr/src/boot/efi/loader/autoload.c
diff --git a/usr/src/boot/sys/boot/efi/loader/bootinfo.c b/usr/src/boot/efi/loader/bootinfo.c
index 1ede89a303..1ede89a303 100644
--- a/usr/src/boot/sys/boot/efi/loader/bootinfo.c
+++ b/usr/src/boot/efi/loader/bootinfo.c
diff --git a/usr/src/boot/sys/boot/efi/loader/conf.c b/usr/src/boot/efi/loader/conf.c
index d29cbca573..d29cbca573 100644
--- a/usr/src/boot/sys/boot/efi/loader/conf.c
+++ b/usr/src/boot/efi/loader/conf.c
diff --git a/usr/src/boot/sys/boot/efi/loader/copy.c b/usr/src/boot/efi/loader/copy.c
index 491c6787c6..491c6787c6 100644
--- a/usr/src/boot/sys/boot/efi/loader/copy.c
+++ b/usr/src/boot/efi/loader/copy.c
diff --git a/usr/src/boot/sys/boot/efi/loader/efi_main.c b/usr/src/boot/efi/loader/efi_main.c
index 2da79f20b0..2da79f20b0 100644
--- a/usr/src/boot/sys/boot/efi/loader/efi_main.c
+++ b/usr/src/boot/efi/loader/efi_main.c
diff --git a/usr/src/boot/sys/boot/efi/loader/efiserialio.c b/usr/src/boot/efi/loader/efiserialio.c
index 9d22a5b319..9d22a5b319 100644
--- a/usr/src/boot/sys/boot/efi/loader/efiserialio.c
+++ b/usr/src/boot/efi/loader/efiserialio.c
diff --git a/usr/src/boot/sys/boot/efi/loader/framebuffer.c b/usr/src/boot/efi/loader/framebuffer.c
index bd86ea3e43..bd86ea3e43 100644
--- a/usr/src/boot/sys/boot/efi/loader/framebuffer.c
+++ b/usr/src/boot/efi/loader/framebuffer.c
diff --git a/usr/src/boot/sys/boot/efi/loader/framebuffer.h b/usr/src/boot/efi/loader/framebuffer.h
index 2ec9017dc3..2ec9017dc3 100644
--- a/usr/src/boot/sys/boot/efi/loader/framebuffer.h
+++ b/usr/src/boot/efi/loader/framebuffer.h
diff --git a/usr/src/boot/sys/boot/efi/loader/i386/Makefile b/usr/src/boot/efi/loader/i386/Makefile
index b2f086971a..b2f086971a 100644
--- a/usr/src/boot/sys/boot/efi/loader/i386/Makefile
+++ b/usr/src/boot/efi/loader/i386/Makefile
diff --git a/usr/src/boot/sys/boot/efi/loader/loader_efi.h b/usr/src/boot/efi/loader/loader_efi.h
index 77ef65e87a..77ef65e87a 100644
--- a/usr/src/boot/sys/boot/efi/loader/loader_efi.h
+++ b/usr/src/boot/efi/loader/loader_efi.h
diff --git a/usr/src/boot/sys/boot/efi/loader/main.c b/usr/src/boot/efi/loader/main.c
index d8daf4ce7d..82b0936cde 100644
--- a/usr/src/boot/sys/boot/efi/loader/main.c
+++ b/usr/src/boot/efi/loader/main.c
@@ -489,6 +489,12 @@ interactive_interrupt(const char *msg)
return (false);
}
+caddr_t
+ptov(uintptr_t x)
+{
+ return ((caddr_t)x);
+}
+
EFI_STATUS
main(int argc, CHAR16 *argv[])
{
diff --git a/usr/src/boot/sys/boot/efi/loader/memmap.c b/usr/src/boot/efi/loader/memmap.c
index f3545a4d64..f3545a4d64 100644
--- a/usr/src/boot/sys/boot/efi/loader/memmap.c
+++ b/usr/src/boot/efi/loader/memmap.c
diff --git a/usr/src/boot/sys/boot/efi/loader/reloc.c b/usr/src/boot/efi/loader/reloc.c
index 5d03e09dc7..5d03e09dc7 100644
--- a/usr/src/boot/sys/boot/efi/loader/reloc.c
+++ b/usr/src/boot/efi/loader/reloc.c
diff --git a/usr/src/boot/forth/Makefile b/usr/src/boot/forth/Makefile
new file mode 100644
index 0000000000..5de1fc3878
--- /dev/null
+++ b/usr/src/boot/forth/Makefile
@@ -0,0 +1,71 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2022 Toomas Soome <tsoome@me.com>
+#
+include $(SRC)/Makefile.master
+
+ROOT_BOOT= $(ROOT)/boot
+ROOT_BOOT_DEFAULTS= $(ROOT)/boot/defaults
+ROOT_BOOT_FORTH= $(ROOT)/boot/forth
+ROOT_BOOT_CONF= $(ROOT)/boot/conf.d
+ROOTBOOTFILES=$(FILES:%=$(ROOT_BOOT)/%)
+ROOTBOOTFORTH=$(FORTH:%=$(ROOT_BOOT_FORTH)/%)
+ROOTBOOTDEFAULTS=$(DEFFILES:%=$(ROOT_BOOT_DEFAULTS)/%)
+FILEMODE=0444
+
+FORTH = beastie.4th
+FORTH += beadm.4th
+FORTH += brand.4th
+FORTH += brand-illumos.4th
+FORTH += check-password.4th
+FORTH += color.4th
+FORTH += delay.4th
+FORTH += efi.4th
+FORTH += frames.4th
+FORTH += loader.4th
+DEFFILES = loader.conf
+FORTH += logo-beastie.4th
+FORTH += logo-beastiebw.4th
+FORTH += logo-fbsdbw.4th
+FORTH += logo-illumos.4th
+FORTH += logo-orb.4th
+FORTH += logo-orbbw.4th
+FORTH += menu.4th
+FORTH += menu.rc
+FORTH += menu-commands.4th
+FORTH += menusets.4th
+FORTH += pcibios.4th
+FORTH += screen.4th
+FORTH += shortcuts.4th
+FORTH += support.4th
+FORTH += version.4th
+FILES += illumos-logo.png
+FILES += illumos-brand.png
+FILES += loader.rc
+
+all clean clobber:
+
+install: $(ROOT_BOOT_DEFAULTS) $(ROOT_BOOT_FORTH) $(ROOTBOOTFILES) \
+ $(ROOTBOOTDEFAULTS) $(ROOT_BOOT_CONF) $(ROOTBOOTFORTH)
+
+$(ROOT_BOOT)/%: % $(ROOT_BOOT)
+ $(INS.file)
+
+$(ROOT_BOOT_DEFAULTS)/%: % $(ROOT_BOOT_DEFAULTS)
+ $(INS.file)
+
+$(ROOT_BOOT_FORTH)/%: % $(ROOT_BOOT_FORTH)
+ $(INS.file)
+
+$(ROOT_BOOT_DEFAULTS) $(ROOT_BOOT_CONF) $(ROOT_BOOT_FORTH):
+ $(INS.dir)
diff --git a/usr/src/boot/sys/boot/forth/beadm.4th b/usr/src/boot/forth/beadm.4th
index 74e9022634..74e9022634 100644
--- a/usr/src/boot/sys/boot/forth/beadm.4th
+++ b/usr/src/boot/forth/beadm.4th
diff --git a/usr/src/boot/sys/boot/forth/beastie.4th b/usr/src/boot/forth/beastie.4th
index 874e19a9d9..874e19a9d9 100644
--- a/usr/src/boot/sys/boot/forth/beastie.4th
+++ b/usr/src/boot/forth/beastie.4th
diff --git a/usr/src/boot/sys/boot/forth/brand-fbsd.4th b/usr/src/boot/forth/brand-fbsd.4th
index 9cd017f84a..9cd017f84a 100644
--- a/usr/src/boot/sys/boot/forth/brand-fbsd.4th
+++ b/usr/src/boot/forth/brand-fbsd.4th
diff --git a/usr/src/boot/sys/boot/forth/brand-illumos.4th b/usr/src/boot/forth/brand-illumos.4th
index 3122af6ec0..3122af6ec0 100644
--- a/usr/src/boot/sys/boot/forth/brand-illumos.4th
+++ b/usr/src/boot/forth/brand-illumos.4th
diff --git a/usr/src/boot/sys/boot/forth/brand.4th b/usr/src/boot/forth/brand.4th
index c86b955602..c86b955602 100644
--- a/usr/src/boot/sys/boot/forth/brand.4th
+++ b/usr/src/boot/forth/brand.4th
diff --git a/usr/src/boot/sys/boot/forth/check-password.4th b/usr/src/boot/forth/check-password.4th
index f8b7d5a135..f8b7d5a135 100644
--- a/usr/src/boot/sys/boot/forth/check-password.4th
+++ b/usr/src/boot/forth/check-password.4th
diff --git a/usr/src/boot/sys/boot/forth/color.4th b/usr/src/boot/forth/color.4th
index 09b2c39ebf..09b2c39ebf 100644
--- a/usr/src/boot/sys/boot/forth/color.4th
+++ b/usr/src/boot/forth/color.4th
diff --git a/usr/src/boot/sys/boot/forth/delay.4th b/usr/src/boot/forth/delay.4th
index 28cfa5c26e..28cfa5c26e 100644
--- a/usr/src/boot/sys/boot/forth/delay.4th
+++ b/usr/src/boot/forth/delay.4th
diff --git a/usr/src/boot/sys/boot/forth/efi.4th b/usr/src/boot/forth/efi.4th
index 422a32d295..422a32d295 100644
--- a/usr/src/boot/sys/boot/forth/efi.4th
+++ b/usr/src/boot/forth/efi.4th
diff --git a/usr/src/boot/sys/boot/forth/frames.4th b/usr/src/boot/forth/frames.4th
index 4976e4e8e3..4976e4e8e3 100644
--- a/usr/src/boot/sys/boot/forth/frames.4th
+++ b/usr/src/boot/forth/frames.4th
diff --git a/usr/src/boot/sys/boot/forth/illumos-brand.png b/usr/src/boot/forth/illumos-brand.png
index 0679f0d050..0679f0d050 100644
--- a/usr/src/boot/sys/boot/forth/illumos-brand.png
+++ b/usr/src/boot/forth/illumos-brand.png
Binary files differ
diff --git a/usr/src/boot/sys/boot/forth/illumos-logo.png b/usr/src/boot/forth/illumos-logo.png
index 3af7a2f360..3af7a2f360 100644
--- a/usr/src/boot/sys/boot/forth/illumos-logo.png
+++ b/usr/src/boot/forth/illumos-logo.png
Binary files differ
diff --git a/usr/src/boot/sys/boot/forth/loader.4th b/usr/src/boot/forth/loader.4th
index 378c71eead..378c71eead 100644
--- a/usr/src/boot/sys/boot/forth/loader.4th
+++ b/usr/src/boot/forth/loader.4th
diff --git a/usr/src/boot/sys/boot/forth/loader.conf b/usr/src/boot/forth/loader.conf
index 78028c88fe..78028c88fe 100644
--- a/usr/src/boot/sys/boot/forth/loader.conf
+++ b/usr/src/boot/forth/loader.conf
diff --git a/usr/src/boot/sys/boot/i386/loader/loader.rc b/usr/src/boot/forth/loader.rc
index 32f6bf8043..32f6bf8043 100644
--- a/usr/src/boot/sys/boot/i386/loader/loader.rc
+++ b/usr/src/boot/forth/loader.rc
diff --git a/usr/src/boot/sys/boot/forth/logo-beastie.4th b/usr/src/boot/forth/logo-beastie.4th
index 671eb5e496..671eb5e496 100644
--- a/usr/src/boot/sys/boot/forth/logo-beastie.4th
+++ b/usr/src/boot/forth/logo-beastie.4th
diff --git a/usr/src/boot/sys/boot/forth/logo-beastiebw.4th b/usr/src/boot/forth/logo-beastiebw.4th
index 197099cda0..197099cda0 100644
--- a/usr/src/boot/sys/boot/forth/logo-beastiebw.4th
+++ b/usr/src/boot/forth/logo-beastiebw.4th
diff --git a/usr/src/boot/sys/boot/forth/logo-fbsdbw.4th b/usr/src/boot/forth/logo-fbsdbw.4th
index d4a532b78f..d4a532b78f 100644
--- a/usr/src/boot/sys/boot/forth/logo-fbsdbw.4th
+++ b/usr/src/boot/forth/logo-fbsdbw.4th
diff --git a/usr/src/boot/sys/boot/forth/logo-illumos.4th b/usr/src/boot/forth/logo-illumos.4th
index e64895db08..e64895db08 100644
--- a/usr/src/boot/sys/boot/forth/logo-illumos.4th
+++ b/usr/src/boot/forth/logo-illumos.4th
diff --git a/usr/src/boot/sys/boot/forth/logo-orb.4th b/usr/src/boot/forth/logo-orb.4th
index c2a504d1dd..c2a504d1dd 100644
--- a/usr/src/boot/sys/boot/forth/logo-orb.4th
+++ b/usr/src/boot/forth/logo-orb.4th
diff --git a/usr/src/boot/sys/boot/forth/logo-orbbw.4th b/usr/src/boot/forth/logo-orbbw.4th
index 11dc11cabb..11dc11cabb 100644
--- a/usr/src/boot/sys/boot/forth/logo-orbbw.4th
+++ b/usr/src/boot/forth/logo-orbbw.4th
diff --git a/usr/src/boot/sys/boot/forth/menu-commands.4th b/usr/src/boot/forth/menu-commands.4th
index f2a3547aae..f2a3547aae 100644
--- a/usr/src/boot/sys/boot/forth/menu-commands.4th
+++ b/usr/src/boot/forth/menu-commands.4th
diff --git a/usr/src/boot/sys/boot/forth/menu.4th b/usr/src/boot/forth/menu.4th
index 304abb4aeb..304abb4aeb 100644
--- a/usr/src/boot/sys/boot/forth/menu.4th
+++ b/usr/src/boot/forth/menu.4th
diff --git a/usr/src/boot/sys/boot/forth/menu.rc b/usr/src/boot/forth/menu.rc
index 00ab7445c3..00ab7445c3 100644
--- a/usr/src/boot/sys/boot/forth/menu.rc
+++ b/usr/src/boot/forth/menu.rc
diff --git a/usr/src/boot/sys/boot/forth/menusets.4th b/usr/src/boot/forth/menusets.4th
index 3f05f38844..3f05f38844 100644
--- a/usr/src/boot/sys/boot/forth/menusets.4th
+++ b/usr/src/boot/forth/menusets.4th
diff --git a/usr/src/boot/sys/boot/forth/pcibios.4th b/usr/src/boot/forth/pcibios.4th
index 71702dad8a..71702dad8a 100644
--- a/usr/src/boot/sys/boot/forth/pcibios.4th
+++ b/usr/src/boot/forth/pcibios.4th
diff --git a/usr/src/boot/sys/boot/forth/pnp.4th b/usr/src/boot/forth/pnp.4th
index 8be89d8277..8be89d8277 100644
--- a/usr/src/boot/sys/boot/forth/pnp.4th
+++ b/usr/src/boot/forth/pnp.4th
diff --git a/usr/src/boot/sys/boot/forth/screen.4th b/usr/src/boot/forth/screen.4th
index fe5a684002..fe5a684002 100644
--- a/usr/src/boot/sys/boot/forth/screen.4th
+++ b/usr/src/boot/forth/screen.4th
diff --git a/usr/src/boot/sys/boot/forth/shortcuts.4th b/usr/src/boot/forth/shortcuts.4th
index 33a1cf6789..33a1cf6789 100644
--- a/usr/src/boot/sys/boot/forth/shortcuts.4th
+++ b/usr/src/boot/forth/shortcuts.4th
diff --git a/usr/src/boot/sys/boot/forth/support.4th b/usr/src/boot/forth/support.4th
index 2abf48f70b..2abf48f70b 100644
--- a/usr/src/boot/sys/boot/forth/support.4th
+++ b/usr/src/boot/forth/support.4th
diff --git a/usr/src/boot/sys/boot/forth/version.4th b/usr/src/boot/forth/version.4th
index ee1b178c1b..ee1b178c1b 100644
--- a/usr/src/boot/sys/boot/forth/version.4th
+++ b/usr/src/boot/forth/version.4th
diff --git a/usr/src/boot/sys/boot/i386/Makefile b/usr/src/boot/i386/Makefile
index bfcf99270b..bfcf99270b 100644
--- a/usr/src/boot/sys/boot/i386/Makefile
+++ b/usr/src/boot/i386/Makefile
diff --git a/usr/src/boot/sys/boot/i386/Makefile.inc b/usr/src/boot/i386/Makefile.inc
index 028eca2b1c..6deaf96b27 100644
--- a/usr/src/boot/sys/boot/i386/Makefile.inc
+++ b/usr/src/boot/i386/Makefile.inc
@@ -13,7 +13,7 @@
# Copyright 2015 Toomas Soome <tsoome@me.com>
#
-# Common defines for all of /sys/boot/i386/
+# Common defines for all of /i386/
LOADER_ADDRESS=0x200000
CFLAGS += -m32
@@ -21,7 +21,7 @@ CCASFLAGS += -m32
ASFLAGS += --32
# BTX components
-BTXDIR= $(SRC)/boot/sys/boot/i386/btx
+BTXDIR= $(SRC)/boot/i386/btx
BTXLDR= ${BTXDIR}/btxldr/btxldr
BTXKERN= ${BTXDIR}/btx/btx
BTXCRT= ${BTXDIR}/lib/crt0.o
diff --git a/usr/src/boot/sys/boot/i386/boot.ldscript b/usr/src/boot/i386/boot.ldscript
index 5e6b97b197..5e6b97b197 100644
--- a/usr/src/boot/sys/boot/i386/boot.ldscript
+++ b/usr/src/boot/i386/boot.ldscript
diff --git a/usr/src/boot/sys/boot/i386/btx/Makefile b/usr/src/boot/i386/btx/Makefile
index 7ba55cc583..7ba55cc583 100644
--- a/usr/src/boot/sys/boot/i386/btx/Makefile
+++ b/usr/src/boot/i386/btx/Makefile
diff --git a/usr/src/boot/sys/boot/i386/btx/btx/Makefile b/usr/src/boot/i386/btx/btx/Makefile
index da8b3e7d4f..2157bf721e 100644
--- a/usr/src/boot/sys/boot/i386/btx/btx/Makefile
+++ b/usr/src/boot/i386/btx/btx/Makefile
@@ -15,7 +15,7 @@
#
include $(SRC)/Makefile.master
-include $(SRC)/boot/sys/boot/Makefile.inc
+include $(SRC)/boot/Makefile.inc
include ../../Makefile.inc
PROG= btx
diff --git a/usr/src/boot/sys/boot/i386/btx/btx/btx.S b/usr/src/boot/i386/btx/btx/btx.S
index 87d09a5a1e..87d09a5a1e 100644
--- a/usr/src/boot/sys/boot/i386/btx/btx/btx.S
+++ b/usr/src/boot/i386/btx/btx/btx.S
diff --git a/usr/src/boot/sys/boot/i386/btx/btxldr/Makefile b/usr/src/boot/i386/btx/btxldr/Makefile
index c209ba4ab4..408db52b66 100644
--- a/usr/src/boot/sys/boot/i386/btx/btxldr/Makefile
+++ b/usr/src/boot/i386/btx/btxldr/Makefile
@@ -15,7 +15,7 @@
#
include $(SRC)/Makefile.master
-include $(SRC)/boot/sys/boot/Makefile.inc
+include $(SRC)/boot/Makefile.inc
include ../../Makefile.inc
PROG= btxldr
diff --git a/usr/src/boot/sys/boot/i386/btx/btxldr/btxldr.S b/usr/src/boot/i386/btx/btxldr/btxldr.S
index 1a0f5f40ff..1a0f5f40ff 100644
--- a/usr/src/boot/sys/boot/i386/btx/btxldr/btxldr.S
+++ b/usr/src/boot/i386/btx/btxldr/btxldr.S
diff --git a/usr/src/boot/sys/boot/i386/btx/lib/Makefile b/usr/src/boot/i386/btx/lib/Makefile
index 864a519441..5986c0d63f 100644
--- a/usr/src/boot/sys/boot/i386/btx/lib/Makefile
+++ b/usr/src/boot/i386/btx/lib/Makefile
@@ -15,7 +15,7 @@
#
include $(SRC)/Makefile.master
-include $(SRC)/boot/sys/boot/Makefile.inc
+include $(SRC)/boot/Makefile.inc
include ../../Makefile.inc
CPPFLAGS += -I./../../common
diff --git a/usr/src/boot/sys/boot/i386/btx/lib/btxcsu.S b/usr/src/boot/i386/btx/lib/btxcsu.S
index c46f8097db..c46f8097db 100644
--- a/usr/src/boot/sys/boot/i386/btx/lib/btxcsu.S
+++ b/usr/src/boot/i386/btx/lib/btxcsu.S
diff --git a/usr/src/boot/sys/boot/i386/btx/lib/btxsys.s b/usr/src/boot/i386/btx/lib/btxsys.s
index 9c77b4295e..9c77b4295e 100644
--- a/usr/src/boot/sys/boot/i386/btx/lib/btxsys.s
+++ b/usr/src/boot/i386/btx/lib/btxsys.s
diff --git a/usr/src/boot/sys/boot/i386/btx/lib/btxv86.h b/usr/src/boot/i386/btx/lib/btxv86.h
index a3583a04c1..a3583a04c1 100644
--- a/usr/src/boot/sys/boot/i386/btx/lib/btxv86.h
+++ b/usr/src/boot/i386/btx/lib/btxv86.h
diff --git a/usr/src/boot/sys/boot/i386/btx/lib/btxv86.s b/usr/src/boot/i386/btx/lib/btxv86.s
index 0d7d111632..0d7d111632 100644
--- a/usr/src/boot/sys/boot/i386/btx/lib/btxv86.s
+++ b/usr/src/boot/i386/btx/lib/btxv86.s
diff --git a/usr/src/boot/sys/boot/i386/cdboot/Makefile b/usr/src/boot/i386/cdboot/Makefile
index 31e684c922..ac6beb0e41 100644
--- a/usr/src/boot/sys/boot/i386/cdboot/Makefile
+++ b/usr/src/boot/i386/cdboot/Makefile
@@ -15,7 +15,7 @@
#
include $(SRC)/Makefile.master
-include $(SRC)/boot/sys/boot/Makefile.inc
+include $(SRC)/boot/Makefile.inc
include ../Makefile.inc
CPPFLAGS += -I../common
diff --git a/usr/src/boot/sys/boot/i386/cdboot/cdboot.S b/usr/src/boot/i386/cdboot/cdboot.S
index 3ab75c1fb2..3ab75c1fb2 100644
--- a/usr/src/boot/sys/boot/i386/cdboot/cdboot.S
+++ b/usr/src/boot/i386/cdboot/cdboot.S
diff --git a/usr/src/boot/sys/boot/i386/common/bootargs.h b/usr/src/boot/i386/common/bootargs.h
index 0bd446e18e..0bd446e18e 100644
--- a/usr/src/boot/sys/boot/i386/common/bootargs.h
+++ b/usr/src/boot/i386/common/bootargs.h
diff --git a/usr/src/boot/sys/boot/i386/common/cons.c b/usr/src/boot/i386/common/cons.c
index c6b52b032f..c6b52b032f 100644
--- a/usr/src/boot/sys/boot/i386/common/cons.c
+++ b/usr/src/boot/i386/common/cons.c
diff --git a/usr/src/boot/sys/boot/i386/common/cons.h b/usr/src/boot/i386/common/cons.h
index 8add66fa3f..8add66fa3f 100644
--- a/usr/src/boot/sys/boot/i386/common/cons.h
+++ b/usr/src/boot/i386/common/cons.h
diff --git a/usr/src/boot/sys/boot/i386/common/drv.c b/usr/src/boot/i386/common/drv.c
index d21f069dd8..d21f069dd8 100644
--- a/usr/src/boot/sys/boot/i386/common/drv.c
+++ b/usr/src/boot/i386/common/drv.c
diff --git a/usr/src/boot/sys/boot/i386/common/drv.h b/usr/src/boot/i386/common/drv.h
index 8f2f1a8136..8f2f1a8136 100644
--- a/usr/src/boot/sys/boot/i386/common/drv.h
+++ b/usr/src/boot/i386/common/drv.h
diff --git a/usr/src/boot/sys/boot/i386/common/edd.h b/usr/src/boot/i386/common/edd.h
index 0c76e3f2c8..0c76e3f2c8 100644
--- a/usr/src/boot/sys/boot/i386/common/edd.h
+++ b/usr/src/boot/i386/common/edd.h
diff --git a/usr/src/boot/sys/boot/i386/gptzfsboot/Makefile b/usr/src/boot/i386/gptzfsboot/Makefile
index c826966da5..4e457fbaf8 100644
--- a/usr/src/boot/sys/boot/i386/gptzfsboot/Makefile
+++ b/usr/src/boot/i386/gptzfsboot/Makefile
@@ -18,7 +18,7 @@
include $(SRC)/Makefile.master
include $(SRC)/boot/Makefile.version
-include $(SRC)/boot/sys/boot/Makefile.inc
+include $(SRC)/boot/Makefile.inc
PROG= gptzfsboot
MAN= gptzfsboot.8
@@ -38,22 +38,22 @@ CPPFLAGS += -DBOOTPROG=\"gptzfsboot\" \
-DSIOPRT=$(BOOT_COMCONSOLE_PORT) \
-DSIOFMT=$(B2SIOFMT) \
-DSIOSPD=$(BOOT_COMCONSOLE_SPEED) \
- -I../../../../include \
- -I../../../../lib/libstand \
+ -I../../include \
+ -I../../libsa \
-I../../common \
-I../common \
-I$(ZFSSRC) \
- -I../../../cddl/boot/zfs \
+ -I../../sys/cddl/boot/zfs \
-I../btx/lib -I. \
- -I../../.. \
+ -I../../sys \
-I../libi386
LDSCRIPT= ../boot.ldscript
LD_FLAGS= -static -N --gc-sections
LIBI386= -L ../libi386 -li386
-LIBSTAND= -L ../../libstand/$(MACH) -lstand
+LIBSTAND= -L ../../libsa/$(MACH) -lsa
LIBS= $(LIBI386) $(LIBSTAND)
-DPADD= ../libi386/libi386.a ../../libstand/$(MACH)/libstand.a
+DPADD= ../libi386/libi386.a ../../libsa/$(MACH)/libsa.a
include ../Makefile.inc
@@ -97,11 +97,11 @@ gptzfsboot.out: $(BTXCRT) $(OBJS) $(DPADD)
machine:
$(RM) machine
- $(SYMLINK) ../../../i386/include machine
+ $(SYMLINK) ../../sys/i386/include machine
x86:
$(RM) x86
- $(SYMLINK) ../../../x86/include x86
+ $(SYMLINK) ../../sys/x86/include x86
$(OBJS): machine x86
diff --git a/usr/src/boot/sys/boot/i386/gptzfsboot/gptldr.S b/usr/src/boot/i386/gptzfsboot/gptldr.S
index 1b1fd9ba9c..1b1fd9ba9c 100644
--- a/usr/src/boot/sys/boot/i386/gptzfsboot/gptldr.S
+++ b/usr/src/boot/i386/gptzfsboot/gptldr.S
diff --git a/usr/src/boot/sys/boot/i386/gptzfsboot/lib.h b/usr/src/boot/i386/gptzfsboot/lib.h
index d8d3317e5a..d8d3317e5a 100644
--- a/usr/src/boot/sys/boot/i386/gptzfsboot/lib.h
+++ b/usr/src/boot/i386/gptzfsboot/lib.h
diff --git a/usr/src/boot/sys/boot/i386/gptzfsboot/sio.S b/usr/src/boot/i386/gptzfsboot/sio.S
index ca9d0a2406..ca9d0a2406 100644
--- a/usr/src/boot/sys/boot/i386/gptzfsboot/sio.S
+++ b/usr/src/boot/i386/gptzfsboot/sio.S
diff --git a/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c b/usr/src/boot/i386/gptzfsboot/zfsboot.c
index 65141c52fd..37ab14ccd9 100644
--- a/usr/src/boot/sys/boot/i386/gptzfsboot/zfsboot.c
+++ b/usr/src/boot/i386/gptzfsboot/zfsboot.c
@@ -141,6 +141,12 @@ struct fs_ops *file_system[] = {
NULL
};
+caddr_t
+ptov(uintptr_t x)
+{
+ return (PTOV(x));
+}
+
int
main(void)
{
diff --git a/usr/src/boot/sys/boot/i386/isoboot/Makefile b/usr/src/boot/i386/isoboot/Makefile
index 2a0992e5cc..08a803f44e 100644
--- a/usr/src/boot/sys/boot/i386/isoboot/Makefile
+++ b/usr/src/boot/i386/isoboot/Makefile
@@ -15,7 +15,7 @@
include $(SRC)/Makefile.master
include $(SRC)/boot/Makefile.version
-include $(SRC)/boot/sys/boot/Makefile.inc
+include $(SRC)/boot/Makefile.inc
PROG= isoboot
FILEMODE=0444
@@ -33,10 +33,10 @@ CPPFLAGS += -DBOOTPROG=\"isoboot\" \
-DSIOPRT=$(BOOT_COMCONSOLE_PORT) \
-DSIOFMT=$(B2SIOFMT) \
-DSIOSPD=$(BOOT_COMCONSOLE_SPEED) \
- -I../../../../include \
- -I../../../../lib/libstand \
+ -I../../include \
+ -I../../libsa \
-I. \
- -I../../.. \
+ -I../../sys \
-I../common \
-I../btx/lib \
-I../../common \
@@ -44,7 +44,7 @@ CPPFLAGS += -DBOOTPROG=\"isoboot\" \
LDSCRIPT= ../boot.ldscript
LD_FLAGS= -static -N --gc-sections
-LIBSTAND= ../../libstand/$(MACH)/libstand.a
+LIBSTAND= ../../libsa/$(MACH)/libsa.a
gptldr.out := LD_FLAGS += -m elf_i386_sol2
@@ -84,11 +84,11 @@ isoboot.out: $(BTXCRT) $(OBJS)
machine:
$(RM) machine
- $(SYMLINK) ../../../i386/include machine
+ $(SYMLINK) ../../sys/i386/include machine
x86:
$(RM) x86
- $(SYMLINK) ../../../x86/include x86
+ $(SYMLINK) ../../sys/x86/include x86
$(OBJS): machine x86
diff --git a/usr/src/boot/sys/boot/i386/isoboot/cd9660read.c b/usr/src/boot/i386/isoboot/cd9660read.c
index 5a4113421e..5a4113421e 100644
--- a/usr/src/boot/sys/boot/i386/isoboot/cd9660read.c
+++ b/usr/src/boot/i386/isoboot/cd9660read.c
diff --git a/usr/src/boot/sys/boot/i386/isoboot/isoboot.c b/usr/src/boot/i386/isoboot/isoboot.c
index 8e25fd55de..8e25fd55de 100644
--- a/usr/src/boot/sys/boot/i386/isoboot/isoboot.c
+++ b/usr/src/boot/i386/isoboot/isoboot.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/Makefile b/usr/src/boot/i386/libi386/Makefile
index 4b6d501c95..37dbde9d0d 100644
--- a/usr/src/boot/sys/boot/i386/libi386/Makefile
+++ b/usr/src/boot/i386/libi386/Makefile
@@ -15,9 +15,9 @@
#
include $(SRC)/Makefile.master
-include $(SRC)/boot/sys/boot/Makefile.inc
+include $(SRC)/boot/Makefile.inc
-CPPFLAGS += -I../../../../include -I../../..
+CPPFLAGS += -I../../include -I../../sys
CPPFLAGS += -I$(ZFSSRC)
all install: libi386.a
@@ -52,7 +52,6 @@ SRCS= \
pxe.c \
pxetramp.s \
relocater_tramp.S \
- smbios.c \
spinconsole.c \
time.c \
vbe.c \
@@ -85,7 +84,6 @@ OBJS= \
pxe.o \
pxetramp.o \
relocater_tramp.o \
- smbios.o \
spinconsole.o \
time.o \
vbe.o \
@@ -113,13 +111,6 @@ CPPFLAGS += -DCOMSPEED=${BOOT_COMCONSOLE_SPEED}
# Make the disk code more talkative
# CPPFLAGS+= -DDISK_DEBUG
-# Export serial numbers, UUID, and asset tag from loader.
-smbios.o := CPPFLAGS += -DSMBIOS_SERIAL_NUMBERS
-# Use little-endian UUID format as defined in SMBIOS 2.6.
-smbios.o := CPPFLAGS += -DSMBIOS_LITTLE_ENDIAN_UUID
-# Use network-endian UUID format for backward compatibility.
-#CPPFLAGS += -DSMBIOS_NETWORK_ENDIAN_UUID
-
# XXX: make alloca() useable
CPPFLAGS += -Dalloca=__builtin_alloca
@@ -127,14 +118,14 @@ CPPFLAGS += -I$(SRC)/common/ficl -I../../libficl \
-I../../common -I../common \
-I../btx/lib \
-I$(SRC)/uts/intel/sys/acpi \
- -I../../.. -I.
+ -I.
# the location of libstand
-CPPFLAGS += -I../../../../lib/libstand/
+CPPFLAGS += -I../../libsa
-multiboot.o := CPPFLAGS += -I../../../cddl/boot/zfs
-multiboot2.o := CPPFLAGS += -I../../../cddl/boot/zfs
-devicename.o := CPPFLAGS += -I../../../cddl/boot/zfs
-devicename_stubs.o := CPPFLAGS += -I../../../cddl/boot/zfs
+multiboot.o := CPPFLAGS += -I../../sys/cddl/boot/zfs
+multiboot2.o := CPPFLAGS += -I../../sys/cddl/boot/zfs
+devicename.o := CPPFLAGS += -I../../sys/cddl/boot/zfs
+devicename_stubs.o := CPPFLAGS += -I../../sys/cddl/boot/zfs
CLEANFILES += machine x86
@@ -145,11 +136,11 @@ CPPFLAGS += -I$(SRC)/uts/common
machine:
$(RM) machine
- $(SYMLINK) ../../../i386/include machine
+ $(SYMLINK) ../../sys/i386/include machine
x86:
$(RM) x86
- $(SYMLINK) ../../../x86/include x86
+ $(SYMLINK) ../../sys/x86/include x86
$(OBJS): machine x86
diff --git a/usr/src/boot/sys/boot/i386/libi386/amd64_tramp.S b/usr/src/boot/i386/libi386/amd64_tramp.S
index d044c05814..d044c05814 100644
--- a/usr/src/boot/sys/boot/i386/libi386/amd64_tramp.S
+++ b/usr/src/boot/i386/libi386/amd64_tramp.S
diff --git a/usr/src/boot/sys/boot/i386/libi386/bio.c b/usr/src/boot/i386/libi386/bio.c
index 07a330a06c..07a330a06c 100644
--- a/usr/src/boot/sys/boot/i386/libi386/bio.c
+++ b/usr/src/boot/i386/libi386/bio.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/biosacpi.c b/usr/src/boot/i386/libi386/biosacpi.c
index a82862dd3f..a82862dd3f 100644
--- a/usr/src/boot/sys/boot/i386/libi386/biosacpi.c
+++ b/usr/src/boot/i386/libi386/biosacpi.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/biosdisk.c b/usr/src/boot/i386/libi386/biosdisk.c
index 343b8b0df9..343b8b0df9 100644
--- a/usr/src/boot/sys/boot/i386/libi386/biosdisk.c
+++ b/usr/src/boot/i386/libi386/biosdisk.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/biosmem.c b/usr/src/boot/i386/libi386/biosmem.c
index cf13e6016c..cf13e6016c 100644
--- a/usr/src/boot/sys/boot/i386/libi386/biosmem.c
+++ b/usr/src/boot/i386/libi386/biosmem.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/biospci.c b/usr/src/boot/i386/libi386/biospci.c
index 828cc87fa1..828cc87fa1 100644
--- a/usr/src/boot/sys/boot/i386/libi386/biospci.c
+++ b/usr/src/boot/i386/libi386/biospci.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/biospnp.c b/usr/src/boot/i386/libi386/biospnp.c
index df64ba9582..df64ba9582 100644
--- a/usr/src/boot/sys/boot/i386/libi386/biospnp.c
+++ b/usr/src/boot/i386/libi386/biospnp.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/biossmap.c b/usr/src/boot/i386/libi386/biossmap.c
index 26adef0aa8..26adef0aa8 100644
--- a/usr/src/boot/sys/boot/i386/libi386/biossmap.c
+++ b/usr/src/boot/i386/libi386/biossmap.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/bootinfo.c b/usr/src/boot/i386/libi386/bootinfo.c
index a207545258..a207545258 100644
--- a/usr/src/boot/sys/boot/i386/libi386/bootinfo.c
+++ b/usr/src/boot/i386/libi386/bootinfo.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/bootinfo32.c b/usr/src/boot/i386/libi386/bootinfo32.c
index fda7db76ad..fda7db76ad 100644
--- a/usr/src/boot/sys/boot/i386/libi386/bootinfo32.c
+++ b/usr/src/boot/i386/libi386/bootinfo32.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/bootinfo64.c b/usr/src/boot/i386/libi386/bootinfo64.c
index 762f57eb85..762f57eb85 100644
--- a/usr/src/boot/sys/boot/i386/libi386/bootinfo64.c
+++ b/usr/src/boot/i386/libi386/bootinfo64.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/comconsole.c b/usr/src/boot/i386/libi386/comconsole.c
index 4c351d16bf..4c351d16bf 100644
--- a/usr/src/boot/sys/boot/i386/libi386/comconsole.c
+++ b/usr/src/boot/i386/libi386/comconsole.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/cpuid.c b/usr/src/boot/i386/libi386/cpuid.c
index f8116b5b40..f8116b5b40 100644
--- a/usr/src/boot/sys/boot/i386/libi386/cpuid.c
+++ b/usr/src/boot/i386/libi386/cpuid.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/devicename.c b/usr/src/boot/i386/libi386/devicename.c
index e6809109db..e6809109db 100644
--- a/usr/src/boot/sys/boot/i386/libi386/devicename.c
+++ b/usr/src/boot/i386/libi386/devicename.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/elf32_freebsd.c b/usr/src/boot/i386/libi386/elf32_freebsd.c
index 47ccf6722f..47ccf6722f 100644
--- a/usr/src/boot/sys/boot/i386/libi386/elf32_freebsd.c
+++ b/usr/src/boot/i386/libi386/elf32_freebsd.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/elf64_freebsd.c b/usr/src/boot/i386/libi386/elf64_freebsd.c
index aa2dbb2fd8..aa2dbb2fd8 100644
--- a/usr/src/boot/sys/boot/i386/libi386/elf64_freebsd.c
+++ b/usr/src/boot/i386/libi386/elf64_freebsd.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/i386_copy.c b/usr/src/boot/i386/libi386/i386_copy.c
index bcfd475c37..bcfd475c37 100644
--- a/usr/src/boot/sys/boot/i386/libi386/i386_copy.c
+++ b/usr/src/boot/i386/libi386/i386_copy.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/i386_module.c b/usr/src/boot/i386/libi386/i386_module.c
index 78ab61ba9a..78ab61ba9a 100644
--- a/usr/src/boot/sys/boot/i386/libi386/i386_module.c
+++ b/usr/src/boot/i386/libi386/i386_module.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/libi386.h b/usr/src/boot/i386/libi386/libi386.h
index 3f769ee688..3f769ee688 100644
--- a/usr/src/boot/sys/boot/i386/libi386/libi386.h
+++ b/usr/src/boot/i386/libi386/libi386.h
diff --git a/usr/src/boot/sys/boot/i386/libi386/linux.c b/usr/src/boot/i386/libi386/linux.c
index 65fc3e3e98..65fc3e3e98 100644
--- a/usr/src/boot/sys/boot/i386/libi386/linux.c
+++ b/usr/src/boot/i386/libi386/linux.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/linux.h b/usr/src/boot/i386/libi386/linux.h
index 9ca7c3d0de..9ca7c3d0de 100644
--- a/usr/src/boot/sys/boot/i386/libi386/linux.h
+++ b/usr/src/boot/i386/libi386/linux.h
diff --git a/usr/src/boot/sys/boot/i386/libi386/multiboot.c b/usr/src/boot/i386/libi386/multiboot.c
index 0474b62350..0474b62350 100644
--- a/usr/src/boot/sys/boot/i386/libi386/multiboot.c
+++ b/usr/src/boot/i386/libi386/multiboot.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/multiboot_tramp.S b/usr/src/boot/i386/libi386/multiboot_tramp.S
index 452a86bbb8..452a86bbb8 100644
--- a/usr/src/boot/sys/boot/i386/libi386/multiboot_tramp.S
+++ b/usr/src/boot/i386/libi386/multiboot_tramp.S
diff --git a/usr/src/boot/sys/boot/i386/libi386/nullconsole.c b/usr/src/boot/i386/libi386/nullconsole.c
index 55655ab61b..55655ab61b 100644
--- a/usr/src/boot/sys/boot/i386/libi386/nullconsole.c
+++ b/usr/src/boot/i386/libi386/nullconsole.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/pread.c b/usr/src/boot/i386/libi386/pread.c
index 870e254015..870e254015 100644
--- a/usr/src/boot/sys/boot/i386/libi386/pread.c
+++ b/usr/src/boot/i386/libi386/pread.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/pxe.c b/usr/src/boot/i386/libi386/pxe.c
index 49585891bd..49585891bd 100644
--- a/usr/src/boot/sys/boot/i386/libi386/pxe.c
+++ b/usr/src/boot/i386/libi386/pxe.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/pxe.h b/usr/src/boot/i386/libi386/pxe.h
index f4bf388aa8..f4bf388aa8 100644
--- a/usr/src/boot/sys/boot/i386/libi386/pxe.h
+++ b/usr/src/boot/i386/libi386/pxe.h
diff --git a/usr/src/boot/sys/boot/i386/libi386/pxetramp.s b/usr/src/boot/i386/libi386/pxetramp.s
index dcf1441aeb..dcf1441aeb 100644
--- a/usr/src/boot/sys/boot/i386/libi386/pxetramp.s
+++ b/usr/src/boot/i386/libi386/pxetramp.s
diff --git a/usr/src/boot/sys/boot/i386/libi386/relocater_tramp.S b/usr/src/boot/i386/libi386/relocater_tramp.S
index ad36b60873..ad36b60873 100644
--- a/usr/src/boot/sys/boot/i386/libi386/relocater_tramp.S
+++ b/usr/src/boot/i386/libi386/relocater_tramp.S
diff --git a/usr/src/boot/sys/boot/i386/libi386/spinconsole.c b/usr/src/boot/i386/libi386/spinconsole.c
index 8d4be4574f..8d4be4574f 100644
--- a/usr/src/boot/sys/boot/i386/libi386/spinconsole.c
+++ b/usr/src/boot/i386/libi386/spinconsole.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/time.c b/usr/src/boot/i386/libi386/time.c
index e6188d6543..e6188d6543 100644
--- a/usr/src/boot/sys/boot/i386/libi386/time.c
+++ b/usr/src/boot/i386/libi386/time.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/vbe.c b/usr/src/boot/i386/libi386/vbe.c
index 6cf60b5c03..6cf60b5c03 100644
--- a/usr/src/boot/sys/boot/i386/libi386/vbe.c
+++ b/usr/src/boot/i386/libi386/vbe.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/vbe.h b/usr/src/boot/i386/libi386/vbe.h
index e049af1e42..e049af1e42 100644
--- a/usr/src/boot/sys/boot/i386/libi386/vbe.h
+++ b/usr/src/boot/i386/libi386/vbe.h
diff --git a/usr/src/boot/sys/boot/i386/libi386/vidconsole.c b/usr/src/boot/i386/libi386/vidconsole.c
index 490c4571a4..490c4571a4 100644
--- a/usr/src/boot/sys/boot/i386/libi386/vidconsole.c
+++ b/usr/src/boot/i386/libi386/vidconsole.c
diff --git a/usr/src/boot/sys/boot/i386/loader/Makefile b/usr/src/boot/i386/loader/Makefile
index 6ed85969a2..8a124cd603 100644
--- a/usr/src/boot/sys/boot/i386/loader/Makefile
+++ b/usr/src/boot/i386/loader/Makefile
@@ -16,9 +16,9 @@
include $(SRC)/Makefile.master
include $(SRC)/boot/Makefile.version
-include $(SRC)/boot/sys/boot/Makefile.inc
+include $(SRC)/boot/Makefile.inc
-CPPFLAGS += -I../../../../include -I../../..
+CPPFLAGS += -I../../include -I../../sys
CPPFLAGS += -I$(SRC)/uts/intel/sys/acpi
CPPFLAGS += -I$(ZLIB)
LOADER= loader
@@ -31,12 +31,7 @@ DPLIBI386= ../libi386/libi386.a
LIBI386= -L../libi386 -li386
ROOT_BOOT= $(ROOT)/boot
-ROOT_BOOT_DEFAULTS= $(ROOT)/boot/defaults
-ROOT_BOOT_FORTH= $(ROOT)/boot/forth
-ROOT_BOOT_CONF= $(ROOT)/boot/conf.d
ROOTBOOTFILES=$(FILES:%=$(ROOT_BOOT)/%)
-ROOTBOOTFORTH=$(FORTH:%=$(ROOT_BOOT_FORTH)/%)
-ROOTBOOTDEFAULTS=$(DEFFILES:%=$(ROOT_BOOT_DEFAULTS)/%)
FILEMODE=0444
all: $(LOADER) loader.help
@@ -93,9 +88,9 @@ LDSCRIPT= ldscript.i386
LDFLAGS= -static -T $(LDSCRIPT) -N --gc-sections
# i386 standalone support library
-CPPFLAGS += -I.. -I../../../../lib/libstand
-DPLIBSTAND= ../../libstand/$(MACH)/libstand.a
-LIBSTAND= -L../../libstand/$(MACH) -lstand
+CPPFLAGS += -I.. -I../../libsa
+DPLIBSA= ../../libsa/$(MACH)/libsa.a
+LIBSA= -L../../libsa/$(MACH) -lsa
# BTX components
CPPFLAGS += -I../btx/lib
@@ -106,10 +101,10 @@ CPPFLAGS += -I../btx/lib
include ../Makefile.inc
-conf.o := CPPFLAGS += -I../../../cddl/boot/zfs
-multiboot2.o := CPPFLAGS += -I../../../cddl/boot/zfs
-main.o := CPPFLAGS += -I../../../cddl/boot/zfs -I$(SRC)/uts/common/fs/zfs
-zfs_cmd.o := CPPFLAGS += -I../../../cddl/boot/zfs
+conf.o := CPPFLAGS += -I../../sys/cddl/boot/zfs
+multiboot2.o := CPPFLAGS += -I../../sys/cddl/boot/zfs
+main.o := CPPFLAGS += -I../../sys/cddl/boot/zfs -I$(SRC)/uts/common/fs/zfs
+zfs_cmd.o := CPPFLAGS += -I../../sys/cddl/boot/zfs
# For multiboot2.h, must be last, to avoid conflicts
CPPFLAGS += -I$(SRC)/uts/common
@@ -130,26 +125,20 @@ loader.help: ../../common/help.common help.i386
FILES= $(LOADER) loader.help
-include ../../forth/Makefile.inc
-FORTH += pcibios.4th
-
-FILES += loader.rc
-FORTH += menu.rc
-
# XXX crt0.o needs to be first for pxeboot(8) to work
-DPADD= $(DPLIBFICL) $(DPLIBI386) $(DPLIBSTAND)
-LDADD= $(LIBFICL) $(LIBI386) $(LIBSTAND)
+DPADD= $(DPLIBFICL) $(DPLIBI386) $(DPLIBSA)
+LDADD= $(LIBFICL) $(LIBI386) $(LIBSA)
CLEANFILES += machine x86
machine:
$(RM) machine
- $(SYMLINK) ../../../i386/include machine
+ $(SYMLINK) ../../sys/i386/include machine
x86:
$(RM) x86
- $(SYMLINK) ../../../x86/include x86
+ $(SYMLINK) ../../sys/x86/include x86
OBJS= $(SRCS:%.c=%.o)
@@ -162,8 +151,7 @@ clean: clobber
clobber:
$(RM) $(CLEANFILES) $(OBJS)
-install: all $(ROOT_BOOT_DEFAULTS) $(ROOT_BOOT_FORTH) \
- $(ROOTBOOTFILES) $(ROOTBOOTDEFAULTS) $(ROOT_BOOT_CONF) $(ROOTBOOTFORTH)
+install: all $(ROOTBOOTFILES)
%.o: ../../common/%.c
$(COMPILE.c) -o $@ $<
@@ -179,12 +167,3 @@ $(FONT).c: $(FONT_DIR)/$(FONT_SRC)
$(ROOT_BOOT)/%: ../../forth/% $(ROOT_BOOT)
$(INS.file)
-
-$(ROOT_BOOT_DEFAULTS)/%: ../../forth/% $(ROOT_BOOT_DEFAULTS)
- $(INS.file)
-
-$(ROOT_BOOT_FORTH)/%: ../../forth/% $(ROOT_BOOT_FORTH)
- $(INS.file)
-
-$(ROOT_BOOT_DEFAULTS) $(ROOT_BOOT_CONF) $(ROOT_BOOT_FORTH):
- $(INS.dir)
diff --git a/usr/src/boot/sys/boot/i386/loader/chain.c b/usr/src/boot/i386/loader/chain.c
index 2f32a9adf0..2f32a9adf0 100644
--- a/usr/src/boot/sys/boot/i386/loader/chain.c
+++ b/usr/src/boot/i386/loader/chain.c
diff --git a/usr/src/boot/sys/boot/i386/loader/conf.c b/usr/src/boot/i386/loader/conf.c
index d8025b3ef8..d8025b3ef8 100644
--- a/usr/src/boot/sys/boot/i386/loader/conf.c
+++ b/usr/src/boot/i386/loader/conf.c
diff --git a/usr/src/boot/sys/boot/i386/loader/help.i386 b/usr/src/boot/i386/loader/help.i386
index dc285347c3..dc285347c3 100644
--- a/usr/src/boot/sys/boot/i386/loader/help.i386
+++ b/usr/src/boot/i386/loader/help.i386
diff --git a/usr/src/boot/sys/boot/i386/loader/ldscript.i386 b/usr/src/boot/i386/loader/ldscript.i386
index 94f4bb7b07..94f4bb7b07 100644
--- a/usr/src/boot/sys/boot/i386/loader/ldscript.i386
+++ b/usr/src/boot/i386/loader/ldscript.i386
diff --git a/usr/src/boot/sys/boot/i386/loader/main.c b/usr/src/boot/i386/loader/main.c
index 2659bf577d..dc21e0d2b3 100644
--- a/usr/src/boot/sys/boot/i386/loader/main.c
+++ b/usr/src/boot/i386/loader/main.c
@@ -46,7 +46,7 @@
#include "bootstrap.h"
#include "common/bootargs.h"
#include "libi386/libi386.h"
-#include "libi386/smbios.h"
+#include "smbios.h"
#include "btxv86.h"
#include "libzfs.h"
@@ -76,6 +76,12 @@ extern char _end[];
static void *heap_top;
static void *heap_bottom;
+caddr_t
+ptov(uintptr_t x)
+{
+ return (PTOV(x));
+}
+
int
main(void)
{
diff --git a/usr/src/boot/sys/boot/i386/pmbr/Makefile b/usr/src/boot/i386/pmbr/Makefile
index b7905c92f2..dccd6d09f1 100644
--- a/usr/src/boot/sys/boot/i386/pmbr/Makefile
+++ b/usr/src/boot/i386/pmbr/Makefile
@@ -18,7 +18,7 @@
# x86 EFI pmbr build rules
#
include $(SRC)/Makefile.master
-include $(SRC)/boot/sys/boot/Makefile.inc
+include $(SRC)/boot/Makefile.inc
include ../Makefile.inc
PROG= pmbr
diff --git a/usr/src/boot/sys/boot/i386/pmbr/pmbr.s b/usr/src/boot/i386/pmbr/pmbr.s
index 46088cc78c..46088cc78c 100644
--- a/usr/src/boot/sys/boot/i386/pmbr/pmbr.s
+++ b/usr/src/boot/i386/pmbr/pmbr.s
diff --git a/usr/src/boot/sys/boot/i386/pxeldr/Makefile b/usr/src/boot/i386/pxeldr/Makefile
index 15661bdf23..32b6ee2f0c 100644
--- a/usr/src/boot/sys/boot/i386/pxeldr/Makefile
+++ b/usr/src/boot/i386/pxeldr/Makefile
@@ -14,13 +14,13 @@
#
include $(SRC)/Makefile.master
-include $(SRC)/boot/sys/boot/Makefile.inc
+include $(SRC)/boot/Makefile.inc
ROOT_BOOT = $(ROOT)/boot
DD= /usr/bin/dd
-CPPFLAGS += -I../../..
+CPPFLAGS += -I../../sys
CPPFLAGS += -I../common
CCASFLAGS= -Wa,--divide
diff --git a/usr/src/boot/sys/boot/i386/pxeldr/pxeldr.S b/usr/src/boot/i386/pxeldr/pxeldr.S
index ee1e18a1f3..ee1e18a1f3 100644
--- a/usr/src/boot/sys/boot/i386/pxeldr/pxeldr.S
+++ b/usr/src/boot/i386/pxeldr/pxeldr.S
diff --git a/usr/src/boot/lib/libstand/mips/_setjmp.S b/usr/src/boot/lib/libstand/mips/_setjmp.S
deleted file mode 100644
index 0289b0ec92..0000000000
--- a/usr/src/boot/lib/libstand/mips/_setjmp.S
+++ /dev/null
@@ -1,108 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Ralph Campbell.
- *
- * 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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$
- */
-
-#include <machine/regnum.h>
-#include <machine/asm.h>
-
-#if 0
-#if defined(LIBC_SCCS)
- .text
- .asciz "$OpenBSD: _setjmp.S,v 1.6 1996/09/23 21:27:53 imp Exp $"
-#endif /* LIBC_SCCS */
-#endif
-
-/*
- * C library -- _setjmp, _longjmp
- *
- * _longjmp(a,v)
- * will generate a "return(v)" from
- * the last call to
- * _setjmp(a)
- * by restoring registers from the stack,
- * The previous signal state is NOT restored.
- */
-
-LEAF(_setjmp)
- .set noreorder
- REG_LI v0, 0xACEDBADE # sigcontext magic number
- REG_S ra, (2 * SZREG)(a0) # sc_pc = return address
- REG_S v0, (3 * SZREG)(a0) # saved in sc_regs[0]
- REG_S s0, ((S0 + 3) * SZREG)(a0)
- REG_S s1, ((S1 + 3) * SZREG)(a0)
- REG_S s2, ((S2 + 3) * SZREG)(a0)
- REG_S s3, ((S3 + 3) * SZREG)(a0)
- REG_S s4, ((S4 + 3) * SZREG)(a0)
- REG_S s5, ((S5 + 3) * SZREG)(a0)
- REG_S s6, ((S6 + 3) * SZREG)(a0)
- REG_S s7, ((S7 + 3) * SZREG)(a0)
- REG_S sp, ((SP + 3) * SZREG)(a0)
- REG_S s8, ((S8 + 3) * SZREG)(a0)
- j ra
- move v0, zero
-END(_setjmp)
-
-LEAF(_longjmp)
-#ifdef ABICALLS
- subu sp, sp, 32
- .cprestore 16
-#endif
- .set noreorder
- REG_L v0, (3 * SZREG)(a0) # get magic number
- REG_L ra, (2 * SZREG)(a0)
- bne v0, 0xACEDBADE, botch # jump if error
-
- addu sp, sp, 32 # does not matter, sanity
- REG_L s0, ((S0 + 3) * SZREG)(a0)
- REG_L s1, ((S1 + 3) * SZREG)(a0)
- REG_L s2, ((S2 + 3) * SZREG)(a0)
- REG_L s3, ((S3 + 3) * SZREG)(a0)
- REG_L s4, ((S4 + 3) * SZREG)(a0)
- REG_L s5, ((S5 + 3) * SZREG)(a0)
- REG_L s6, ((S6 + 3) * SZREG)(a0)
- REG_L s7, ((S7 + 3) * SZREG)(a0)
- REG_L sp, ((SP + 3) * SZREG)(a0)
- REG_L s8, ((S8 + 3) * SZREG)(a0)
-
- j ra
- move v0, a1
-botch:
- jal _C_LABEL(longjmperror)
- nop
- jal _C_LABEL(abort)
- nop
-END(_longjmp)
diff --git a/usr/src/boot/lib/libstand/powerpc/_setjmp.S b/usr/src/boot/lib/libstand/powerpc/_setjmp.S
deleted file mode 100644
index 7c7c24b123..0000000000
--- a/usr/src/boot/lib/libstand/powerpc/_setjmp.S
+++ /dev/null
@@ -1,115 +0,0 @@
-/* $FreeBSD$ */
-/* from: NetBSD: setjmp.S,v 1.1 1998/01/27 15:13:12 sakamoto Exp $ */
-/* from: OpenBSD: setjmp.S,v 1.2 1996/12/28 06:22:18 rahnds Exp */
-/* kernel version of this file, does not have signal goop */
-/* int setjmp(jmp_buf env) */
-
-#include <machine/asm.h>
-
-#ifdef __powerpc64__
-#define LD_REG ld
-#define ST_REG std
-#define REGWIDTH 8
-#else
-#define LD_REG lwz
-#define ST_REG stw
-#define REGWIDTH 4
-#endif
-
-#define JMP_r1 1*REGWIDTH
-#define JMP_r2 2*REGWIDTH
-#define JMP_r14 3*REGWIDTH
-#define JMP_r15 4*REGWIDTH
-#define JMP_r16 5*REGWIDTH
-#define JMP_r17 6*REGWIDTH
-#define JMP_r18 7*REGWIDTH
-#define JMP_r19 8*REGWIDTH
-#define JMP_r20 9*REGWIDTH
-#define JMP_r21 10*REGWIDTH
-#define JMP_r22 11*REGWIDTH
-#define JMP_r23 12*REGWIDTH
-#define JMP_r24 13*REGWIDTH
-#define JMP_r25 14*REGWIDTH
-#define JMP_r26 15*REGWIDTH
-#define JMP_r27 16*REGWIDTH
-#define JMP_r28 17*REGWIDTH
-#define JMP_r29 18*REGWIDTH
-#define JMP_r30 19*REGWIDTH
-#define JMP_r31 20*REGWIDTH
-#define JMP_lr 21*REGWIDTH
-#define JMP_cr 22*REGWIDTH
-#define JMP_ctr 23*REGWIDTH
-#define JMP_xer 24*REGWIDTH
-#define JMP_sig 25*REGWIDTH
-
-ASENTRY_NOPROF(_setjmp)
- ST_REG 31, JMP_r31(3)
- /* r1, r2, r14-r30 */
- ST_REG 1, JMP_r1 (3)
- ST_REG 2, JMP_r2 (3)
- ST_REG 14, JMP_r14(3)
- ST_REG 15, JMP_r15(3)
- ST_REG 16, JMP_r16(3)
- ST_REG 17, JMP_r17(3)
- ST_REG 18, JMP_r18(3)
- ST_REG 19, JMP_r19(3)
- ST_REG 20, JMP_r20(3)
- ST_REG 21, JMP_r21(3)
- ST_REG 22, JMP_r22(3)
- ST_REG 23, JMP_r23(3)
- ST_REG 24, JMP_r24(3)
- ST_REG 25, JMP_r25(3)
- ST_REG 26, JMP_r26(3)
- ST_REG 27, JMP_r27(3)
- ST_REG 28, JMP_r28(3)
- ST_REG 29, JMP_r29(3)
- ST_REG 30, JMP_r30(3)
- /* cr, lr, ctr, xer */
- mfcr 0
- ST_REG 0, JMP_cr(3)
- mflr 0
- ST_REG 0, JMP_lr(3)
- mfctr 0
- ST_REG 0, JMP_ctr(3)
- mfxer 0
- ST_REG 0, JMP_xer(3)
- /* f14-f31, fpscr */
- li 3, 0
- blr
-
-
-.extern sigsetmask
-ASENTRY_NOPROF(_longjmp)
- LD_REG 31, JMP_r31(3)
- /* r1, r2, r14-r30 */
- LD_REG 1, JMP_r1 (3)
- LD_REG 2, JMP_r2 (3)
- LD_REG 14, JMP_r14(3)
- LD_REG 15, JMP_r15(3)
- LD_REG 16, JMP_r16(3)
- LD_REG 17, JMP_r17(3)
- LD_REG 18, JMP_r18(3)
- LD_REG 19, JMP_r19(3)
- LD_REG 20, JMP_r20(3)
- LD_REG 21, JMP_r21(3)
- LD_REG 22, JMP_r22(3)
- LD_REG 23, JMP_r23(3)
- LD_REG 24, JMP_r24(3)
- LD_REG 25, JMP_r25(3)
- LD_REG 26, JMP_r26(3)
- LD_REG 27, JMP_r27(3)
- LD_REG 28, JMP_r28(3)
- LD_REG 29, JMP_r29(3)
- LD_REG 30, JMP_r30(3)
- /* cr, lr, ctr, xer */
- LD_REG 0, JMP_cr(3)
- mtcr 0
- LD_REG 0, JMP_lr(3)
- mtlr 0
- LD_REG 0, JMP_ctr(3)
- mtctr 0
- LD_REG 0, JMP_xer(3)
- mtxer 0
- /* f14-f31, fpscr */
- mr 3, 4
- blr
diff --git a/usr/src/boot/lib/libstand/powerpc/syncicache.c b/usr/src/boot/lib/libstand/powerpc/syncicache.c
deleted file mode 100644
index 434dcec634..0000000000
--- a/usr/src/boot/lib/libstand/powerpc/syncicache.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*-
- * Copyright (C) 1995-1997, 1999 Wolfgang Solfrank.
- * Copyright (C) 1995-1997, 1999 TooLs GmbH.
- * 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by TooLs GmbH.
- * 4. The name of TooLs GmbH may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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.
- *
- * $NetBSD: syncicache.c,v 1.2 1999/05/05 12:36:40 tsubai Exp $
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <sys/param.h>
-#if defined(_KERNEL) || defined(_STANDALONE)
-#include <sys/time.h>
-#include <sys/proc.h>
-#include <vm/vm.h>
-#endif
-#include <sys/sysctl.h>
-
-#include <machine/cpu.h>
-#include <machine/md_var.h>
-
-#ifdef _STANDALONE
-int cacheline_size = 32;
-#endif
-
-#if !defined(_KERNEL) && !defined(_STANDALONE)
-#include <stdlib.h>
-
-int cacheline_size = 0;
-
-static void getcachelinesize(void);
-
-static void
-getcachelinesize()
-{
- static int cachemib[] = { CTL_MACHDEP, CPU_CACHELINE };
- int clen;
-
- clen = sizeof(cacheline_size);
-
- if (sysctl(cachemib, sizeof(cachemib) / sizeof(cachemib[0]),
- &cacheline_size, &clen, NULL, 0) < 0 || !cacheline_size) {
- abort();
- }
-}
-#endif
-
-void
-__syncicache(void *from, int len)
-{
- int l, off;
- char *p;
-
-#if !defined(_KERNEL) && !defined(_STANDALONE)
- if (!cacheline_size)
- getcachelinesize();
-#endif
-
- off = (u_int)from & (cacheline_size - 1);
- l = len += off;
- p = (char *)from - off;
-
- do {
- __asm __volatile ("dcbst 0,%0" :: "r"(p));
- p += cacheline_size;
- } while ((l -= cacheline_size) > 0);
- __asm __volatile ("sync");
- p = (char *)from - off;
- do {
- __asm __volatile ("icbi 0,%0" :: "r"(p));
- p += cacheline_size;
- } while ((len -= cacheline_size) > 0);
- __asm __volatile ("sync; isync");
-}
-
diff --git a/usr/src/boot/lib/libstand/sparc64/_setjmp.S b/usr/src/boot/lib/libstand/sparc64/_setjmp.S
deleted file mode 100644
index 8df29e6ba7..0000000000
--- a/usr/src/boot/lib/libstand/sparc64/_setjmp.S
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This software was developed by the Computer Systems Engineering group
- * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
- * contributed to Berkeley.
- *
- * 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.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- *
- * $Header: _setjmp.s,v 1.1 91/07/06 16:45:53 torek Exp
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
- .asciz "@(#)_setjmp.s 8.1 (Berkeley) 6/4/93"
-#else
- RCSID("$NetBSD: _setjmp.S,v 1.4 1998/10/08 02:27:59 eeh Exp $")
-#endif
-#endif /* LIBC_SCCS and not lint */
-
-#include <machine/asm.h>
-__FBSDID("$FreeBSD$");
-
-#define _JB_FP 0x0
-#define _JB_PC 0x8
-#define _JB_SP 0x10
-
- .register %g2,#ignore
- .register %g3,#ignore
-
-/*
- * C library -- setjmp, longjmp
- *
- * longjmp(a,v)
- * will generate a "return(v?v:1)" from
- * the last call to
- * setjmp(a)
- * by restoring the previous context.
- */
-
-ENTRY(_setjmp)
- stx %sp, [%o0 + _JB_SP]
- stx %o7, [%o0 + _JB_PC]
- stx %fp, [%o0 + _JB_FP]
- retl
- clr %o0
-END(_setjmp)
-
-ENTRY(_longjmp)
- mov 1, %g1
- movrnz %o1, %o1, %g1
- mov %o0, %g2
- ldx [%g2 + _JB_FP], %g3
-1: cmp %fp, %g3
- bl,a 1b
- restore
- be,a 2f
- ldx [%g2 + _JB_SP], %o0
-
-.Lbotch:
- illtrap
-
-2: cmp %o0, %sp
- bge,a 3f
- mov %o0, %sp
- b,a .Lbotch
- nop
-3: ldx [%g2 + _JB_PC], %o7
- retl
- mov %g1, %o0
-END(_longjmp)
diff --git a/usr/src/boot/sys/boot/libficl/Makefile b/usr/src/boot/libficl/Makefile
index 97b7bb80f0..97b7bb80f0 100644
--- a/usr/src/boot/sys/boot/libficl/Makefile
+++ b/usr/src/boot/libficl/Makefile
diff --git a/usr/src/boot/sys/boot/libficl/Makefile.com b/usr/src/boot/libficl/Makefile.com
index 564403516d..822e5d79fe 100644
--- a/usr/src/boot/sys/boot/libficl/Makefile.com
+++ b/usr/src/boot/libficl/Makefile.com
@@ -13,15 +13,15 @@
# Copyright 2016 Toomas Soome <tsoome@me.com>
#
-include $(SRC)/boot/sys/boot/Makefile.inc
+include $(SRC)/boot/Makefile.inc
FICLDIR= $(SRC)/common/ficl
PNGLITE= $(SRC)/common/pnglite
CPPFLAGS += -I. -I..
-CPPFLAGS += -I../../..
-CPPFLAGS += -I../../../../include
-CPPFLAGS += -I../../../../lib/libstand
+CPPFLAGS += -I../../sys
+CPPFLAGS += -I../../include
+CPPFLAGS += -I../../libsa
CPPFLAGS += -I$(FICLDIR) -I../../common -I$(PNGLITE)
# For multiboot2.h, must be last, to avoid conflicts
@@ -45,11 +45,11 @@ pics/vm.o := CFLAGS += -_gcc=-Wno-clobbered
machine:
$(RM) machine
- $(SYMLINK) ../../../$(MACHINE)/include machine
+ $(SYMLINK) ../../sys/$(MACHINE)/include machine
x86:
$(RM) x86
- $(SYMLINK) ../../../x86/include x86
+ $(SYMLINK) ../../sys/x86/include x86
objs/%.o pics/%.o: ../softcore/%.c $(HEADERS)
$(COMPILE.c) -o $@ $<
diff --git a/usr/src/boot/sys/boot/libficl/amd64/Makefile b/usr/src/boot/libficl/amd64/Makefile
index 2f006575f7..028e60868e 100644
--- a/usr/src/boot/sys/boot/libficl/amd64/Makefile
+++ b/usr/src/boot/libficl/amd64/Makefile
@@ -25,6 +25,6 @@ include ../Makefile.com
CFLAGS += -m64 $(CFLAGS64)
-include $(SRC)/boot/sys/boot/Makefile.lib
+include $(BOOTSRC)/Makefile.lib
FRC:
diff --git a/usr/src/boot/sys/boot/libficl/ficllocal.h b/usr/src/boot/libficl/ficllocal.h
index 964cd79780..964cd79780 100644
--- a/usr/src/boot/sys/boot/libficl/ficllocal.h
+++ b/usr/src/boot/libficl/ficllocal.h
diff --git a/usr/src/boot/sys/boot/libficl/i386/Makefile b/usr/src/boot/libficl/i386/Makefile
index 6ad5f9467d..73d2c963f0 100644
--- a/usr/src/boot/sys/boot/libficl/i386/Makefile
+++ b/usr/src/boot/libficl/i386/Makefile
@@ -26,6 +26,6 @@ include ../Makefile.com
CFLAGS += -m32
-include $(SRC)/boot/sys/boot/Makefile.lib
+include $(BOOTSRC)/Makefile.lib
FRC:
diff --git a/usr/src/boot/sys/boot/libficl/softcore/Makefile b/usr/src/boot/libficl/softcore/Makefile
index 7b42031180..7b42031180 100644
--- a/usr/src/boot/sys/boot/libficl/softcore/Makefile
+++ b/usr/src/boot/libficl/softcore/Makefile
diff --git a/usr/src/boot/sys/boot/libstand/Makefile b/usr/src/boot/libsa/Makefile
index 01b0b02cab..01b0b02cab 100644
--- a/usr/src/boot/sys/boot/libstand/Makefile
+++ b/usr/src/boot/libsa/Makefile
diff --git a/usr/src/boot/sys/boot/libstand/Makefile.com b/usr/src/boot/libsa/Makefile.com
index d282deedaa..3d5291e961 100644
--- a/usr/src/boot/sys/boot/libstand/Makefile.com
+++ b/usr/src/boot/libsa/Makefile.com
@@ -14,10 +14,10 @@
# Copyright 2019 Joyent, Inc.
#
-include $(SRC)/boot/sys/boot/Makefile.inc
+include $(SRC)/boot/Makefile.inc
-CPPFLAGS += -I../../../../include -I$(SASRC)
-CPPFLAGS += -I../../.. -I.
+CPPFLAGS += -I../../include -I$(SASRC)
+CPPFLAGS += -I../../sys -I.
include $(SASRC)/Makefile.inc
include $(CRYPTOSRC)/Makefile.inc
@@ -34,11 +34,11 @@ pics/printf.o := SMOFF += 64bit_shift
machine:
$(RM) machine
- $(SYMLINK) ../../../$(MACHINE)/include machine
+ $(SYMLINK) ../../sys/$(MACHINE)/include machine
x86:
$(RM) x86
- $(SYMLINK) ../../../x86/include x86
+ $(SYMLINK) ../../sys/x86/include x86
pics/%.o objs/%.o: %.c
$(COMPILE.c) -o $@ $<
@@ -46,13 +46,10 @@ pics/%.o objs/%.o: %.c
pics/%.o objs/%.o: $(SASRC)/%.c
$(COMPILE.c) -o $@ $<
-pics/%.o objs/%.o: $(LIBSRC)/libc/net/%.c
+pics/%.o objs/%.o: $(SASRC)/string/%.c
$(COMPILE.c) -o $@ $<
-pics/%.o objs/%.o: $(LIBSRC)/libc/string/%.c
- $(COMPILE.c) -o $@ $<
-
-pics/%.o objs/%.o: $(LIBSRC)/libc/uuid/%.c
+pics/%.o objs/%.o: $(SASRC)/uuid/%.c
$(COMPILE.c) -o $@ $<
pics/%.o objs/%.o: $(ZLIB)/%.c
diff --git a/usr/src/boot/lib/libstand/Makefile.inc b/usr/src/boot/libsa/Makefile.inc
index 2acb9ef490..3ca6522785 100644
--- a/usr/src/boot/lib/libstand/Makefile.inc
+++ b/usr/src/boot/libsa/Makefile.inc
@@ -38,26 +38,26 @@ SRCS += $(SASRC)/strcasecmp.c
OBJECTS += strcasecmp.o
# from libc
-SRCS += $(LIBSRC)/libc/net/ntoh.c
+SRCS += $(SASRC)/ntoh.c
OBJECTS += ntoh.o
# string functions from libc
-SRCS += $(LIBSRC)/libc/string/bcmp.c $(LIBSRC)/libc/string/bcopy.c
-SRCS += $(LIBSRC)/libc/string/bzero.c $(LIBSRC)/libc/string/ffs.c
-SRCS += $(LIBSRC)/libc/string/fls.c $(LIBSRC)/libc/string/memccpy.c
-SRCS += $(LIBSRC)/libc/string/memchr.c $(LIBSRC)/libc/string/memcmp.c
-SRCS += $(LIBSRC)/libc/string/memcpy.c $(LIBSRC)/libc/string/memmove.c
-SRCS += $(LIBSRC)/libc/string/memset.c $(LIBSRC)/libc/string/strcat.c
-SRCS += $(LIBSRC)/libc/string/strchr.c $(LIBSRC)/libc/string/strcmp.c
-SRCS += $(LIBSRC)/libc/string/strcpy.c $(LIBSRC)/libc/string/stpcpy.c
-SRCS += $(LIBSRC)/libc/string/stpncpy.c $(LIBSRC)/libc/string/strcspn.c
-SRCS += $(LIBSRC)/libc/string/strlcat.c $(LIBSRC)/libc/string/strlcpy.c
-SRCS += $(LIBSRC)/libc/string/strlen.c $(LIBSRC)/libc/string/strncat.c
-SRCS += $(LIBSRC)/libc/string/strncmp.c $(LIBSRC)/libc/string/strncpy.c
-SRCS += $(LIBSRC)/libc/string/strpbrk.c $(LIBSRC)/libc/string/strrchr.c
-SRCS += $(LIBSRC)/libc/string/strsep.c $(LIBSRC)/libc/string/strspn.c
-SRCS += $(LIBSRC)/libc/string/strstr.c $(LIBSRC)/libc/string/strtok.c
-SRCS += $(LIBSRC)/libc/string/swab.c
+SRCS += $(SASRC)/string/bcmp.c $(SASRC)/string/bcopy.c
+SRCS += $(SASRC)/string/bzero.c $(SASRC)/string/ffs.c
+SRCS += $(SASRC)/string/fls.c $(SASRC)/string/memccpy.c
+SRCS += $(SASRC)/string/memchr.c $(SASRC)/string/memcmp.c
+SRCS += $(SASRC)/string/memcpy.c $(SASRC)/string/memmove.c
+SRCS += $(SASRC)/string/memset.c $(SASRC)/string/strcat.c
+SRCS += $(SASRC)/string/strchr.c $(SASRC)/string/strcmp.c
+SRCS += $(SASRC)/string/strcpy.c $(SASRC)/string/stpcpy.c
+SRCS += $(SASRC)/string/stpncpy.c $(SASRC)/string/strcspn.c
+SRCS += $(SASRC)/string/strlcat.c $(SASRC)/string/strlcpy.c
+SRCS += $(SASRC)/string/strlen.c $(SASRC)/string/strncat.c
+SRCS += $(SASRC)/string/strncmp.c $(SASRC)/string/strncpy.c
+SRCS += $(SASRC)/string/strpbrk.c $(SASRC)/string/strrchr.c
+SRCS += $(SASRC)/string/strsep.c $(SASRC)/string/strspn.c
+SRCS += $(SASRC)/string/strstr.c $(SASRC)/string/strtok.c
+SRCS += $(SASRC)/string/swab.c
SRCS += $(SASRC)/qdivrem.c
@@ -68,9 +68,9 @@ OBJECTS += bcmp.o bcopy.o bzero.o ffs.o fls.o \
strpbrk.o strrchr.o strsep.o strspn.o strstr.o strtok.o swab.o
# uuid functions from libc
-SRCS += $(LIBSRC)/libc/uuid/uuid_create_nil.c
-SRCS += $(LIBSRC)/libc/uuid/uuid_equal.c
-SRCS += $(LIBSRC)/libc/uuid/uuid_is_nil.c
+SRCS += $(SASRC)/uuid/uuid_create_nil.c
+SRCS += $(SASRC)/uuid/uuid_equal.c
+SRCS += $(SASRC)/uuid/uuid_is_nil.c
SRCS += $(SASRC)/uuid_from_string.c
SRCS += $(SASRC)/uuid_to_string.c
@@ -235,6 +235,14 @@ SRCS += $(SASRC)/closeall.c $(SASRC)/dev.c \
OBJECTS += closeall.o dev.o ioctl.o nullfs.o stat.o fstat.o close.o lseek.o \
open.o read.o write.o readdir.o
+# SMBios routines
+SRCS += smbios.c
+OBJECTS += smbios.o
+# Export serial numbers, UUID, and asset tag from loader.
+# Use little-endian UUID format as defined in SMBIOS 2.6.
+pics/smbios.o := CPPFLAGS += -DSMBIOS_SERIAL_NUMBERS -DSMBIOS_LITTLE_ENDIAN_UUID
+objs/smbios.o := CPPFLAGS += -DSMBIOS_SERIAL_NUMBERS -DSMBIOS_LITTLE_ENDIAN_UUID
+
# network routines
SRCS += $(SASRC)/arp.c $(SASRC)/ether.c $(SASRC)/ip.c \
$(SASRC)/inet_ntoa.c $(SASRC)/in_cksum.c \
diff --git a/usr/src/boot/lib/libstand/__main.c b/usr/src/boot/libsa/__main.c
index e38f33865c..e38f33865c 100644
--- a/usr/src/boot/lib/libstand/__main.c
+++ b/usr/src/boot/libsa/__main.c
diff --git a/usr/src/boot/lib/libstand/abort.c b/usr/src/boot/libsa/abort.c
index 663555a333..663555a333 100644
--- a/usr/src/boot/lib/libstand/abort.c
+++ b/usr/src/boot/libsa/abort.c
diff --git a/usr/src/boot/sys/boot/libstand/amd64/Makefile b/usr/src/boot/libsa/amd64/Makefile
index e79d2deef5..39eaf206e7 100644
--- a/usr/src/boot/sys/boot/libstand/amd64/Makefile
+++ b/usr/src/boot/libsa/amd64/Makefile
@@ -17,7 +17,7 @@
include $(SRC)/Makefile.master
MACHINE= $(MACH64)
-DYNLIB= libstand_pics.a
+DYNLIB= libsa_pics.a
all install: $(DYNLIB)
@@ -44,6 +44,6 @@ pics/%.o: $(SASRC)/amd64/%.S
pics/%.o: $(SASRC)/x86/%.c
$(COMPILE.c) -o $@ $<
-include $(SRC)/boot/sys/boot/Makefile.lib
+include $(BOOTSRC)/Makefile.lib
FRC:
diff --git a/usr/src/boot/lib/libstand/amd64/_setjmp.S b/usr/src/boot/libsa/amd64/_setjmp.S
index 6d9a5fa13f..6d9a5fa13f 100644
--- a/usr/src/boot/lib/libstand/amd64/_setjmp.S
+++ b/usr/src/boot/libsa/amd64/_setjmp.S
diff --git a/usr/src/boot/lib/libstand/arp.c b/usr/src/boot/libsa/arp.c
index d55595d8ff..d55595d8ff 100644
--- a/usr/src/boot/lib/libstand/arp.c
+++ b/usr/src/boot/libsa/arp.c
diff --git a/usr/src/boot/lib/libstand/assert.c b/usr/src/boot/libsa/assert.c
index 7ed70d70ee..7ed70d70ee 100644
--- a/usr/src/boot/lib/libstand/assert.c
+++ b/usr/src/boot/libsa/assert.c
diff --git a/usr/src/boot/lib/libstand/bcd.c b/usr/src/boot/libsa/bcd.c
index 7bd67c9162..7bd67c9162 100644
--- a/usr/src/boot/lib/libstand/bcd.c
+++ b/usr/src/boot/libsa/bcd.c
diff --git a/usr/src/boot/lib/libstand/bootp.c b/usr/src/boot/libsa/bootp.c
index 080e90d7a5..080e90d7a5 100644
--- a/usr/src/boot/lib/libstand/bootp.c
+++ b/usr/src/boot/libsa/bootp.c
diff --git a/usr/src/boot/lib/libstand/bootp.h b/usr/src/boot/libsa/bootp.h
index b26a5cd45c..b26a5cd45c 100644
--- a/usr/src/boot/lib/libstand/bootp.h
+++ b/usr/src/boot/libsa/bootp.h
diff --git a/usr/src/boot/lib/libstand/bootparam.c b/usr/src/boot/libsa/bootparam.c
index 2f86f52257..2f86f52257 100644
--- a/usr/src/boot/lib/libstand/bootparam.c
+++ b/usr/src/boot/libsa/bootparam.c
diff --git a/usr/src/boot/lib/libstand/bootparam.h b/usr/src/boot/libsa/bootparam.h
index 6f0c773a07..6f0c773a07 100644
--- a/usr/src/boot/lib/libstand/bootparam.h
+++ b/usr/src/boot/libsa/bootparam.h
diff --git a/usr/src/boot/lib/libstand/bzipfs.c b/usr/src/boot/libsa/bzipfs.c
index 1c2cc39904..1c2cc39904 100644
--- a/usr/src/boot/lib/libstand/bzipfs.c
+++ b/usr/src/boot/libsa/bzipfs.c
diff --git a/usr/src/boot/lib/libstand/cd9660.c b/usr/src/boot/libsa/cd9660.c
index a17146fce5..a17146fce5 100644
--- a/usr/src/boot/lib/libstand/cd9660.c
+++ b/usr/src/boot/libsa/cd9660.c
diff --git a/usr/src/boot/lib/libstand/close.c b/usr/src/boot/libsa/close.c
index 546dd98600..546dd98600 100644
--- a/usr/src/boot/lib/libstand/close.c
+++ b/usr/src/boot/libsa/close.c
diff --git a/usr/src/boot/lib/libstand/closeall.c b/usr/src/boot/libsa/closeall.c
index 425cd334b7..425cd334b7 100644
--- a/usr/src/boot/lib/libstand/closeall.c
+++ b/usr/src/boot/libsa/closeall.c
diff --git a/usr/src/boot/lib/libstand/crypto/Makefile.inc b/usr/src/boot/libsa/crypto/Makefile.inc
index 3cff3ecdb6..3cff3ecdb6 100644
--- a/usr/src/boot/lib/libstand/crypto/Makefile.inc
+++ b/usr/src/boot/libsa/crypto/Makefile.inc
diff --git a/usr/src/boot/lib/libstand/crypto/digest.c b/usr/src/boot/libsa/crypto/digest.c
index 7a1bd841b1..7a1bd841b1 100644
--- a/usr/src/boot/lib/libstand/crypto/digest.c
+++ b/usr/src/boot/libsa/crypto/digest.c
diff --git a/usr/src/boot/lib/libstand/crypto/libcrypto.h b/usr/src/boot/libsa/crypto/libcrypto.h
index b00373f6ab..b00373f6ab 100644
--- a/usr/src/boot/lib/libstand/crypto/libcrypto.h
+++ b/usr/src/boot/libsa/crypto/libcrypto.h
diff --git a/usr/src/boot/lib/libstand/dev.c b/usr/src/boot/libsa/dev.c
index 89d7867ec6..89d7867ec6 100644
--- a/usr/src/boot/lib/libstand/dev.c
+++ b/usr/src/boot/libsa/dev.c
diff --git a/usr/src/boot/lib/libstand/dosfs.c b/usr/src/boot/libsa/dosfs.c
index d4bc2c9834..d4bc2c9834 100644
--- a/usr/src/boot/lib/libstand/dosfs.c
+++ b/usr/src/boot/libsa/dosfs.c
diff --git a/usr/src/boot/lib/libstand/dosfs.h b/usr/src/boot/libsa/dosfs.h
index 0915c70930..0915c70930 100644
--- a/usr/src/boot/lib/libstand/dosfs.h
+++ b/usr/src/boot/libsa/dosfs.h
diff --git a/usr/src/boot/lib/libstand/environment.c b/usr/src/boot/libsa/environment.c
index d3130d292e..d3130d292e 100644
--- a/usr/src/boot/lib/libstand/environment.c
+++ b/usr/src/boot/libsa/environment.c
diff --git a/usr/src/boot/lib/libstand/ether.c b/usr/src/boot/libsa/ether.c
index 798886ebb4..798886ebb4 100644
--- a/usr/src/boot/lib/libstand/ether.c
+++ b/usr/src/boot/libsa/ether.c
diff --git a/usr/src/boot/lib/libstand/ext2fs.c b/usr/src/boot/libsa/ext2fs.c
index d0b91e0446..d0b91e0446 100644
--- a/usr/src/boot/lib/libstand/ext2fs.c
+++ b/usr/src/boot/libsa/ext2fs.c
diff --git a/usr/src/boot/lib/libstand/fstat.c b/usr/src/boot/libsa/fstat.c
index 44030d085e..44030d085e 100644
--- a/usr/src/boot/lib/libstand/fstat.c
+++ b/usr/src/boot/libsa/fstat.c
diff --git a/usr/src/boot/lib/libstand/getopt.c b/usr/src/boot/libsa/getopt.c
index ead2ee5626..ead2ee5626 100644
--- a/usr/src/boot/lib/libstand/getopt.c
+++ b/usr/src/boot/libsa/getopt.c
diff --git a/usr/src/boot/lib/libstand/gets.c b/usr/src/boot/libsa/gets.c
index 781e161edb..781e161edb 100644
--- a/usr/src/boot/lib/libstand/gets.c
+++ b/usr/src/boot/libsa/gets.c
diff --git a/usr/src/boot/lib/libstand/globals.c b/usr/src/boot/libsa/globals.c
index 81453c3dd0..81453c3dd0 100644
--- a/usr/src/boot/lib/libstand/globals.c
+++ b/usr/src/boot/libsa/globals.c
diff --git a/usr/src/boot/lib/libstand/gzipfs.c b/usr/src/boot/libsa/gzipfs.c
index c6c7b206e6..c6c7b206e6 100644
--- a/usr/src/boot/lib/libstand/gzipfs.c
+++ b/usr/src/boot/libsa/gzipfs.c
diff --git a/usr/src/boot/sys/boot/libstand/i386/Makefile b/usr/src/boot/libsa/i386/Makefile
index 7902d44a86..091c1ab256 100644
--- a/usr/src/boot/sys/boot/libstand/i386/Makefile
+++ b/usr/src/boot/libsa/i386/Makefile
@@ -17,8 +17,8 @@
include $(SRC)/Makefile.master
MACHINE= $(MACH)
-LIBRARY= libstand.a
-DYNLIB= libstand_pics.a
+LIBRARY= libsa.a
+DYNLIB= libsa_pics.a
all install: $(LIBRARY) $(DYNLIB)
@@ -40,6 +40,6 @@ pics/%.o objs/%.o: $(SASRC)/i386/%.S
pics/%.o objs/%.o: $(SASRC)/x86/%.c
$(COMPILE.c) -o $@ $<
-include $(SRC)/boot/sys/boot/Makefile.lib
+include $(BOOTSRC)/Makefile.lib
FRC:
diff --git a/usr/src/boot/lib/libstand/i386/_setjmp.S b/usr/src/boot/libsa/i386/_setjmp.S
index 95b0ea8037..95b0ea8037 100644
--- a/usr/src/boot/lib/libstand/i386/_setjmp.S
+++ b/usr/src/boot/libsa/i386/_setjmp.S
diff --git a/usr/src/boot/lib/libstand/in_cksum.c b/usr/src/boot/libsa/in_cksum.c
index 7551d65dbe..7551d65dbe 100644
--- a/usr/src/boot/lib/libstand/in_cksum.c
+++ b/usr/src/boot/libsa/in_cksum.c
diff --git a/usr/src/boot/lib/libstand/inet_ntoa.c b/usr/src/boot/libsa/inet_ntoa.c
index 7aa01c6124..7aa01c6124 100644
--- a/usr/src/boot/lib/libstand/inet_ntoa.c
+++ b/usr/src/boot/libsa/inet_ntoa.c
diff --git a/usr/src/boot/lib/libstand/ioctl.c b/usr/src/boot/libsa/ioctl.c
index 67c95c77d6..67c95c77d6 100644
--- a/usr/src/boot/lib/libstand/ioctl.c
+++ b/usr/src/boot/libsa/ioctl.c
diff --git a/usr/src/boot/lib/libstand/iodesc.h b/usr/src/boot/libsa/iodesc.h
index 2086c586d2..2086c586d2 100644
--- a/usr/src/boot/lib/libstand/iodesc.h
+++ b/usr/src/boot/libsa/iodesc.h
diff --git a/usr/src/boot/lib/libstand/ip.c b/usr/src/boot/libsa/ip.c
index ab3cd36591..ab3cd36591 100644
--- a/usr/src/boot/lib/libstand/ip.c
+++ b/usr/src/boot/libsa/ip.c
diff --git a/usr/src/boot/lib/libstand/lseek.c b/usr/src/boot/libsa/lseek.c
index eb063394a1..eb063394a1 100644
--- a/usr/src/boot/lib/libstand/lseek.c
+++ b/usr/src/boot/libsa/lseek.c
diff --git a/usr/src/boot/lib/libstand/net.c b/usr/src/boot/libsa/net.c
index eea4b8a9d8..eea4b8a9d8 100644
--- a/usr/src/boot/lib/libstand/net.c
+++ b/usr/src/boot/libsa/net.c
diff --git a/usr/src/boot/lib/libstand/net.h b/usr/src/boot/libsa/net.h
index 93ab8d84e7..93ab8d84e7 100644
--- a/usr/src/boot/lib/libstand/net.h
+++ b/usr/src/boot/libsa/net.h
diff --git a/usr/src/boot/lib/libstand/netif.c b/usr/src/boot/libsa/netif.c
index 74364e9098..74364e9098 100644
--- a/usr/src/boot/lib/libstand/netif.c
+++ b/usr/src/boot/libsa/netif.c
diff --git a/usr/src/boot/lib/libstand/netif.h b/usr/src/boot/libsa/netif.h
index 44165ab0d8..44165ab0d8 100644
--- a/usr/src/boot/lib/libstand/netif.h
+++ b/usr/src/boot/libsa/netif.h
diff --git a/usr/src/boot/lib/libstand/nfs.c b/usr/src/boot/libsa/nfs.c
index f10abf1e26..f10abf1e26 100644
--- a/usr/src/boot/lib/libstand/nfs.c
+++ b/usr/src/boot/libsa/nfs.c
diff --git a/usr/src/boot/lib/libstand/nfsv2.h b/usr/src/boot/libsa/nfsv2.h
index 09b2428b80..09b2428b80 100644
--- a/usr/src/boot/lib/libstand/nfsv2.h
+++ b/usr/src/boot/libsa/nfsv2.h
diff --git a/usr/src/boot/lib/libc/net/ntoh.c b/usr/src/boot/libsa/ntoh.c
index d658c90b68..d658c90b68 100644
--- a/usr/src/boot/lib/libc/net/ntoh.c
+++ b/usr/src/boot/libsa/ntoh.c
diff --git a/usr/src/boot/lib/libstand/nullfs.c b/usr/src/boot/libsa/nullfs.c
index 91fe6efb2c..91fe6efb2c 100644
--- a/usr/src/boot/lib/libstand/nullfs.c
+++ b/usr/src/boot/libsa/nullfs.c
diff --git a/usr/src/boot/lib/libstand/open.c b/usr/src/boot/libsa/open.c
index 6d026f1ca6..6d026f1ca6 100644
--- a/usr/src/boot/lib/libstand/open.c
+++ b/usr/src/boot/libsa/open.c
diff --git a/usr/src/boot/lib/libstand/pager.c b/usr/src/boot/libsa/pager.c
index bbc0c8e0b0..bbc0c8e0b0 100644
--- a/usr/src/boot/lib/libstand/pager.c
+++ b/usr/src/boot/libsa/pager.c
diff --git a/usr/src/boot/lib/libstand/panic.c b/usr/src/boot/libsa/panic.c
index 8a3730ce6b..8a3730ce6b 100644
--- a/usr/src/boot/lib/libstand/panic.c
+++ b/usr/src/boot/libsa/panic.c
diff --git a/usr/src/boot/lib/libstand/pkgfs.c b/usr/src/boot/libsa/pkgfs.c
index fda7f60708..fda7f60708 100644
--- a/usr/src/boot/lib/libstand/pkgfs.c
+++ b/usr/src/boot/libsa/pkgfs.c
diff --git a/usr/src/boot/lib/libstand/printf.c b/usr/src/boot/libsa/printf.c
index 55a1c7aad2..55a1c7aad2 100644
--- a/usr/src/boot/lib/libstand/printf.c
+++ b/usr/src/boot/libsa/printf.c
diff --git a/usr/src/boot/lib/libstand/qdivrem.c b/usr/src/boot/libsa/qdivrem.c
index 294e360488..294e360488 100644
--- a/usr/src/boot/lib/libstand/qdivrem.c
+++ b/usr/src/boot/libsa/qdivrem.c
diff --git a/usr/src/boot/lib/libstand/quad.h b/usr/src/boot/libsa/quad.h
index 26c5d8c2b7..26c5d8c2b7 100644
--- a/usr/src/boot/lib/libstand/quad.h
+++ b/usr/src/boot/libsa/quad.h
diff --git a/usr/src/boot/lib/libstand/random.c b/usr/src/boot/libsa/random.c
index 1547078b42..1547078b42 100644
--- a/usr/src/boot/lib/libstand/random.c
+++ b/usr/src/boot/libsa/random.c
diff --git a/usr/src/boot/lib/libstand/rarp.c b/usr/src/boot/libsa/rarp.c
index f7a624d08c..f7a624d08c 100644
--- a/usr/src/boot/lib/libstand/rarp.c
+++ b/usr/src/boot/libsa/rarp.c
diff --git a/usr/src/boot/lib/libstand/read.c b/usr/src/boot/libsa/read.c
index ebbc082705..ebbc082705 100644
--- a/usr/src/boot/lib/libstand/read.c
+++ b/usr/src/boot/libsa/read.c
diff --git a/usr/src/boot/lib/libstand/readdir.c b/usr/src/boot/libsa/readdir.c
index 6920f5b5fe..6920f5b5fe 100644
--- a/usr/src/boot/lib/libstand/readdir.c
+++ b/usr/src/boot/libsa/readdir.c
diff --git a/usr/src/boot/lib/libstand/rpc.c b/usr/src/boot/libsa/rpc.c
index ed5c9fc5cb..ed5c9fc5cb 100644
--- a/usr/src/boot/lib/libstand/rpc.c
+++ b/usr/src/boot/libsa/rpc.c
diff --git a/usr/src/boot/lib/libstand/rpc.h b/usr/src/boot/libsa/rpc.h
index 5efe832101..5efe832101 100644
--- a/usr/src/boot/lib/libstand/rpc.h
+++ b/usr/src/boot/libsa/rpc.h
diff --git a/usr/src/boot/lib/libstand/rpcv2.h b/usr/src/boot/libsa/rpcv2.h
index 4f1f016333..4f1f016333 100644
--- a/usr/src/boot/lib/libstand/rpcv2.h
+++ b/usr/src/boot/libsa/rpcv2.h
diff --git a/usr/src/boot/lib/libstand/saioctl.h b/usr/src/boot/libsa/saioctl.h
index 5124f86187..5124f86187 100644
--- a/usr/src/boot/lib/libstand/saioctl.h
+++ b/usr/src/boot/libsa/saioctl.h
diff --git a/usr/src/boot/lib/libstand/sbrk.c b/usr/src/boot/libsa/sbrk.c
index fb2dab1d44..fb2dab1d44 100644
--- a/usr/src/boot/lib/libstand/sbrk.c
+++ b/usr/src/boot/libsa/sbrk.c
diff --git a/usr/src/boot/sys/boot/i386/libi386/smbios.c b/usr/src/boot/libsa/smbios.c
index 148c6cf1fe..d3d6433c92 100644
--- a/usr/src/boot/sys/boot/i386/libi386/smbios.c
+++ b/usr/src/boot/libsa/smbios.c
@@ -27,15 +27,8 @@
#include <sys/cdefs.h>
#include <stand.h>
-#include <bootstrap.h>
#include <sys/endian.h>
-#ifdef EFI
-/* In EFI, we don't need PTOV(). */
-#define PTOV(x) (caddr_t)(x)
-#else
-#include "btxv86.h"
-#endif
#include "smbios.h"
/*
@@ -139,7 +132,7 @@ smbios_sigsearch(const caddr_t addr, const uint32_t len)
smbios.minor = SMBIOS_GET8(cp, 0x07);
}
smbios.ver = (smbios.major << 8) | smbios.minor;
- smbios.addr = PTOV(paddr);
+ smbios.addr = ptov(paddr);
return (cp);
}
#ifdef _LP64
@@ -164,7 +157,7 @@ smbios_sigsearch(const caddr_t addr, const uint32_t len)
smbios.length = SMBIOS_GET32(cp, 0x0c);
/* Structure Table Address */
paddr = SMBIOS_GET64(cp, 0x10);
- smbios.addr = PTOV(paddr);
+ smbios.addr = ptov(paddr);
/*
* Calculate upper limit for structure count,
* use size of table header (4 bytes).
@@ -425,7 +418,7 @@ static void
smbios_probe(const caddr_t addr)
{
caddr_t info;
- const caddr_t paddr = addr != NULL ? addr : PTOV(SMBIOS_START);
+ const caddr_t paddr = addr != NULL ? addr : ptov(SMBIOS_START);
if (smbios.probed)
return;
diff --git a/usr/src/boot/sys/boot/i386/libi386/smbios.h b/usr/src/boot/libsa/smbios.h
index 03fc07e293..a39d08e98a 100644
--- a/usr/src/boot/sys/boot/i386/libi386/smbios.h
+++ b/usr/src/boot/libsa/smbios.h
@@ -1,4 +1,4 @@
-/*-
+/*
* Copyright (c) 2015 Rui Paulo <rpaulo@FreeBSD.org>
* All rights reserved.
*
@@ -22,8 +22,6 @@
* 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 _SMBIOS_H_
#define _SMBIOS_H_
diff --git a/usr/src/boot/lib/libstand/splitfs.c b/usr/src/boot/libsa/splitfs.c
index af28704bc4..af28704bc4 100644
--- a/usr/src/boot/lib/libstand/splitfs.c
+++ b/usr/src/boot/libsa/splitfs.c
diff --git a/usr/src/boot/lib/libstand/stand.h b/usr/src/boot/libsa/stand.h
index 14270065e9..98ff151e0a 100644
--- a/usr/src/boot/lib/libstand/stand.h
+++ b/usr/src/boot/libsa/stand.h
@@ -458,4 +458,9 @@ void Free(void *, const char *, int);
#define reallocf(x, y) Reallocf(x, y, NULL, 0)
#endif
+/*
+ * va <-> pa routines. MD code must supply.
+ */
+caddr_t ptov(uintptr_t);
+
#endif /* STAND_H */
diff --git a/usr/src/boot/lib/libstand/stat.c b/usr/src/boot/libsa/stat.c
index 249c2086a6..249c2086a6 100644
--- a/usr/src/boot/lib/libstand/stat.c
+++ b/usr/src/boot/libsa/stat.c
diff --git a/usr/src/boot/lib/libstand/strcasecmp.c b/usr/src/boot/libsa/strcasecmp.c
index 951b46fb89..951b46fb89 100644
--- a/usr/src/boot/lib/libstand/strcasecmp.c
+++ b/usr/src/boot/libsa/strcasecmp.c
diff --git a/usr/src/boot/lib/libstand/strdup.c b/usr/src/boot/libsa/strdup.c
index ecdc63a09c..ecdc63a09c 100644
--- a/usr/src/boot/lib/libstand/strdup.c
+++ b/usr/src/boot/libsa/strdup.c
diff --git a/usr/src/boot/lib/libstand/strerror.c b/usr/src/boot/libsa/strerror.c
index e08ca0a7f1..e08ca0a7f1 100644
--- a/usr/src/boot/lib/libstand/strerror.c
+++ b/usr/src/boot/libsa/strerror.c
diff --git a/usr/src/boot/lib/libc/string/bcmp.c b/usr/src/boot/libsa/string/bcmp.c
index f1178a660b..f1178a660b 100644
--- a/usr/src/boot/lib/libc/string/bcmp.c
+++ b/usr/src/boot/libsa/string/bcmp.c
diff --git a/usr/src/boot/lib/libc/string/bcopy.c b/usr/src/boot/libsa/string/bcopy.c
index c424de560f..c424de560f 100644
--- a/usr/src/boot/lib/libc/string/bcopy.c
+++ b/usr/src/boot/libsa/string/bcopy.c
diff --git a/usr/src/boot/lib/libc/string/bzero.c b/usr/src/boot/libsa/string/bzero.c
index 201bd64f80..201bd64f80 100644
--- a/usr/src/boot/lib/libc/string/bzero.c
+++ b/usr/src/boot/libsa/string/bzero.c
diff --git a/usr/src/boot/lib/libc/string/ffs.c b/usr/src/boot/libsa/string/ffs.c
index 42a94ef738..42a94ef738 100644
--- a/usr/src/boot/lib/libc/string/ffs.c
+++ b/usr/src/boot/libsa/string/ffs.c
diff --git a/usr/src/boot/lib/libc/string/fls.c b/usr/src/boot/libsa/string/fls.c
index 7145b909f0..7145b909f0 100644
--- a/usr/src/boot/lib/libc/string/fls.c
+++ b/usr/src/boot/libsa/string/fls.c
diff --git a/usr/src/boot/lib/libc/string/memccpy.c b/usr/src/boot/libsa/string/memccpy.c
index 6102a5bded..6102a5bded 100644
--- a/usr/src/boot/lib/libc/string/memccpy.c
+++ b/usr/src/boot/libsa/string/memccpy.c
diff --git a/usr/src/boot/lib/libc/string/memchr.c b/usr/src/boot/libsa/string/memchr.c
index 8020333dec..8020333dec 100644
--- a/usr/src/boot/lib/libc/string/memchr.c
+++ b/usr/src/boot/libsa/string/memchr.c
diff --git a/usr/src/boot/lib/libc/string/memcmp.c b/usr/src/boot/libsa/string/memcmp.c
index d2d0f27d35..d2d0f27d35 100644
--- a/usr/src/boot/lib/libc/string/memcmp.c
+++ b/usr/src/boot/libsa/string/memcmp.c
diff --git a/usr/src/boot/lib/libc/string/memcpy.c b/usr/src/boot/libsa/string/memcpy.c
index ed03856e54..ed03856e54 100644
--- a/usr/src/boot/lib/libc/string/memcpy.c
+++ b/usr/src/boot/libsa/string/memcpy.c
diff --git a/usr/src/boot/lib/libc/string/memmove.c b/usr/src/boot/libsa/string/memmove.c
index 05cf75a2ce..05cf75a2ce 100644
--- a/usr/src/boot/lib/libc/string/memmove.c
+++ b/usr/src/boot/libsa/string/memmove.c
diff --git a/usr/src/boot/lib/libc/string/memset.c b/usr/src/boot/libsa/string/memset.c
index ad0d513933..ad0d513933 100644
--- a/usr/src/boot/lib/libc/string/memset.c
+++ b/usr/src/boot/libsa/string/memset.c
diff --git a/usr/src/boot/lib/libc/string/stpcpy.c b/usr/src/boot/libsa/string/stpcpy.c
index 8cf24f3d8c..8cf24f3d8c 100644
--- a/usr/src/boot/lib/libc/string/stpcpy.c
+++ b/usr/src/boot/libsa/string/stpcpy.c
diff --git a/usr/src/boot/lib/libc/string/stpncpy.c b/usr/src/boot/libsa/string/stpncpy.c
index ac5ca203af..ac5ca203af 100644
--- a/usr/src/boot/lib/libc/string/stpncpy.c
+++ b/usr/src/boot/libsa/string/stpncpy.c
diff --git a/usr/src/boot/lib/libc/string/strcat.c b/usr/src/boot/libsa/string/strcat.c
index 07a3c08c1a..07a3c08c1a 100644
--- a/usr/src/boot/lib/libc/string/strcat.c
+++ b/usr/src/boot/libsa/string/strcat.c
diff --git a/usr/src/boot/lib/libc/string/strchr.c b/usr/src/boot/libsa/string/strchr.c
index ab83b3995a..ab83b3995a 100644
--- a/usr/src/boot/lib/libc/string/strchr.c
+++ b/usr/src/boot/libsa/string/strchr.c
diff --git a/usr/src/boot/lib/libc/string/strcmp.c b/usr/src/boot/libsa/string/strcmp.c
index 9daf624acc..9daf624acc 100644
--- a/usr/src/boot/lib/libc/string/strcmp.c
+++ b/usr/src/boot/libsa/string/strcmp.c
diff --git a/usr/src/boot/lib/libc/string/strcpy.c b/usr/src/boot/libsa/string/strcpy.c
index 8a48d0d0d7..8a48d0d0d7 100644
--- a/usr/src/boot/lib/libc/string/strcpy.c
+++ b/usr/src/boot/libsa/string/strcpy.c
diff --git a/usr/src/boot/lib/libc/string/strcspn.c b/usr/src/boot/libsa/string/strcspn.c
index 3879a3b085..3879a3b085 100644
--- a/usr/src/boot/lib/libc/string/strcspn.c
+++ b/usr/src/boot/libsa/string/strcspn.c
diff --git a/usr/src/boot/lib/libc/string/strlcat.c b/usr/src/boot/libsa/string/strlcat.c
index f5ed6c6cf7..f5ed6c6cf7 100644
--- a/usr/src/boot/lib/libc/string/strlcat.c
+++ b/usr/src/boot/libsa/string/strlcat.c
diff --git a/usr/src/boot/lib/libc/string/strlcpy.c b/usr/src/boot/libsa/string/strlcpy.c
index 019d2316a0..019d2316a0 100644
--- a/usr/src/boot/lib/libc/string/strlcpy.c
+++ b/usr/src/boot/libsa/string/strlcpy.c
diff --git a/usr/src/boot/lib/libc/string/strlen.c b/usr/src/boot/libsa/string/strlen.c
index 2bc1f2b1fe..2bc1f2b1fe 100644
--- a/usr/src/boot/lib/libc/string/strlen.c
+++ b/usr/src/boot/libsa/string/strlen.c
diff --git a/usr/src/boot/lib/libc/string/strncat.c b/usr/src/boot/libsa/string/strncat.c
index 6a0e553daa..6a0e553daa 100644
--- a/usr/src/boot/lib/libc/string/strncat.c
+++ b/usr/src/boot/libsa/string/strncat.c
diff --git a/usr/src/boot/lib/libc/string/strncmp.c b/usr/src/boot/libsa/string/strncmp.c
index 4967a9483e..4967a9483e 100644
--- a/usr/src/boot/lib/libc/string/strncmp.c
+++ b/usr/src/boot/libsa/string/strncmp.c
diff --git a/usr/src/boot/lib/libc/string/strncpy.c b/usr/src/boot/libsa/string/strncpy.c
index 3907403508..3907403508 100644
--- a/usr/src/boot/lib/libc/string/strncpy.c
+++ b/usr/src/boot/libsa/string/strncpy.c
diff --git a/usr/src/boot/lib/libc/string/strpbrk.c b/usr/src/boot/libsa/string/strpbrk.c
index 565ef82f11..565ef82f11 100644
--- a/usr/src/boot/lib/libc/string/strpbrk.c
+++ b/usr/src/boot/libsa/string/strpbrk.c
diff --git a/usr/src/boot/lib/libc/string/strrchr.c b/usr/src/boot/libsa/string/strrchr.c
index f84ffb78c4..f84ffb78c4 100644
--- a/usr/src/boot/lib/libc/string/strrchr.c
+++ b/usr/src/boot/libsa/string/strrchr.c
diff --git a/usr/src/boot/lib/libc/string/strsep.c b/usr/src/boot/libsa/string/strsep.c
index 73c61af811..73c61af811 100644
--- a/usr/src/boot/lib/libc/string/strsep.c
+++ b/usr/src/boot/libsa/string/strsep.c
diff --git a/usr/src/boot/lib/libc/string/strspn.c b/usr/src/boot/libsa/string/strspn.c
index 5dbac0a678..5dbac0a678 100644
--- a/usr/src/boot/lib/libc/string/strspn.c
+++ b/usr/src/boot/libsa/string/strspn.c
diff --git a/usr/src/boot/lib/libc/string/strstr.c b/usr/src/boot/libsa/string/strstr.c
index 18e60d5798..18e60d5798 100644
--- a/usr/src/boot/lib/libc/string/strstr.c
+++ b/usr/src/boot/libsa/string/strstr.c
diff --git a/usr/src/boot/lib/libc/string/strtok.c b/usr/src/boot/libsa/string/strtok.c
index 063a554339..063a554339 100644
--- a/usr/src/boot/lib/libc/string/strtok.c
+++ b/usr/src/boot/libsa/string/strtok.c
diff --git a/usr/src/boot/lib/libc/string/swab.c b/usr/src/boot/libsa/string/swab.c
index 84633094be..84633094be 100644
--- a/usr/src/boot/lib/libc/string/swab.c
+++ b/usr/src/boot/libsa/string/swab.c
diff --git a/usr/src/boot/lib/libstand/tftp.c b/usr/src/boot/libsa/tftp.c
index f324bf20e7..f324bf20e7 100644
--- a/usr/src/boot/lib/libstand/tftp.c
+++ b/usr/src/boot/libsa/tftp.c
diff --git a/usr/src/boot/lib/libstand/tftp.h b/usr/src/boot/libsa/tftp.h
index cbbbbd7821..cbbbbd7821 100644
--- a/usr/src/boot/lib/libstand/tftp.h
+++ b/usr/src/boot/libsa/tftp.h
diff --git a/usr/src/boot/lib/libstand/twiddle.c b/usr/src/boot/libsa/twiddle.c
index 31828542f7..31828542f7 100644
--- a/usr/src/boot/lib/libstand/twiddle.c
+++ b/usr/src/boot/libsa/twiddle.c
diff --git a/usr/src/boot/lib/libstand/udp.c b/usr/src/boot/libsa/udp.c
index 0e0ec5c788..0e0ec5c788 100644
--- a/usr/src/boot/lib/libstand/udp.c
+++ b/usr/src/boot/libsa/udp.c
diff --git a/usr/src/boot/lib/libstand/ufs.c b/usr/src/boot/libsa/ufs.c
index 4144c59a1e..4144c59a1e 100644
--- a/usr/src/boot/lib/libstand/ufs.c
+++ b/usr/src/boot/libsa/ufs.c
diff --git a/usr/src/boot/lib/libc/uuid/uuid_create_nil.c b/usr/src/boot/libsa/uuid/uuid_create_nil.c
index 6e85ae7fb7..6e85ae7fb7 100644
--- a/usr/src/boot/lib/libc/uuid/uuid_create_nil.c
+++ b/usr/src/boot/libsa/uuid/uuid_create_nil.c
diff --git a/usr/src/boot/lib/libc/uuid/uuid_equal.c b/usr/src/boot/libsa/uuid/uuid_equal.c
index e4c48e5253..e4c48e5253 100644
--- a/usr/src/boot/lib/libc/uuid/uuid_equal.c
+++ b/usr/src/boot/libsa/uuid/uuid_equal.c
diff --git a/usr/src/boot/lib/libc/uuid/uuid_is_nil.c b/usr/src/boot/libsa/uuid/uuid_is_nil.c
index ee1865349d..ee1865349d 100644
--- a/usr/src/boot/lib/libc/uuid/uuid_is_nil.c
+++ b/usr/src/boot/libsa/uuid/uuid_is_nil.c
diff --git a/usr/src/boot/lib/libstand/uuid_from_string.c b/usr/src/boot/libsa/uuid_from_string.c
index 7a59b4189e..7a59b4189e 100644
--- a/usr/src/boot/lib/libstand/uuid_from_string.c
+++ b/usr/src/boot/libsa/uuid_from_string.c
diff --git a/usr/src/boot/lib/libstand/uuid_to_string.c b/usr/src/boot/libsa/uuid_to_string.c
index d878af495a..d878af495a 100644
--- a/usr/src/boot/lib/libstand/uuid_to_string.c
+++ b/usr/src/boot/libsa/uuid_to_string.c
diff --git a/usr/src/boot/lib/libstand/write.c b/usr/src/boot/libsa/write.c
index 3edab25428..3edab25428 100644
--- a/usr/src/boot/lib/libstand/write.c
+++ b/usr/src/boot/libsa/write.c
diff --git a/usr/src/boot/lib/libstand/x86/hypervisor.c b/usr/src/boot/libsa/x86/hypervisor.c
index ea28863262..ea28863262 100644
--- a/usr/src/boot/lib/libstand/x86/hypervisor.c
+++ b/usr/src/boot/libsa/x86/hypervisor.c
diff --git a/usr/src/boot/lib/libstand/zalloc.c b/usr/src/boot/libsa/zalloc.c
index 8ecdc2fdf1..8ecdc2fdf1 100644
--- a/usr/src/boot/lib/libstand/zalloc.c
+++ b/usr/src/boot/libsa/zalloc.c
diff --git a/usr/src/boot/lib/libstand/zalloc_defs.h b/usr/src/boot/libsa/zalloc_defs.h
index f0de227529..f0de227529 100644
--- a/usr/src/boot/lib/libstand/zalloc_defs.h
+++ b/usr/src/boot/libsa/zalloc_defs.h
diff --git a/usr/src/boot/lib/libstand/zalloc_malloc.c b/usr/src/boot/libsa/zalloc_malloc.c
index 3105341c7b..3105341c7b 100644
--- a/usr/src/boot/lib/libstand/zalloc_malloc.c
+++ b/usr/src/boot/libsa/zalloc_malloc.c
diff --git a/usr/src/boot/lib/libstand/zalloc_mem.h b/usr/src/boot/libsa/zalloc_mem.h
index fd11f2bd9a..fd11f2bd9a 100644
--- a/usr/src/boot/lib/libstand/zalloc_mem.h
+++ b/usr/src/boot/libsa/zalloc_mem.h
diff --git a/usr/src/boot/lib/libstand/zalloc_protos.h b/usr/src/boot/libsa/zalloc_protos.h
index 71f29c5fd3..71f29c5fd3 100644
--- a/usr/src/boot/lib/libstand/zalloc_protos.h
+++ b/usr/src/boot/libsa/zalloc_protos.h
diff --git a/usr/src/boot/lib/libstand/zfs/Makefile.inc b/usr/src/boot/libsa/zfs/Makefile.inc
index a33a42d703..83d5a9e998 100644
--- a/usr/src/boot/lib/libstand/zfs/Makefile.inc
+++ b/usr/src/boot/libsa/zfs/Makefile.inc
@@ -22,11 +22,11 @@ OBJECTS += nvlist.o
OBJECTS += list.o
objs/zfs.o pics/zfs.o := CPPFLAGS += -I../../common
-objs/zfs.o pics/zfs.o := CPPFLAGS += -I../../../cddl/boot/zfs -I$(LZ4)
+objs/zfs.o pics/zfs.o := CPPFLAGS += -I../../sys/cddl/boot/zfs -I$(LZ4)
objs/zfs.o pics/zfs.o := CPPFLAGS += -I$(SRC)/uts/common/fs/zfs
objs/zfs.o pics/zfs.o := CPPFLAGS += -I$(CRYPTOSRC)
objs/nvlist.o pics/nvlist.o := CPPFLAGS += -I../../common
-objs/nvlist.o pics/nvlist.o := CPPFLAGS += -I../../../cddl/boot/zfs
+objs/nvlist.o pics/nvlist.o := CPPFLAGS += -I../../sys/cddl/boot/zfs
pics/%.o objs/%.o: $(ZFSSRC)/%.c
$(COMPILE.c) -o $@ $<
diff --git a/usr/src/boot/lib/libstand/zfs/devicename_stubs.c b/usr/src/boot/libsa/zfs/devicename_stubs.c
index dc0c0a556e..dc0c0a556e 100644
--- a/usr/src/boot/lib/libstand/zfs/devicename_stubs.c
+++ b/usr/src/boot/libsa/zfs/devicename_stubs.c
diff --git a/usr/src/boot/lib/libstand/zfs/gzip.c b/usr/src/boot/libsa/zfs/gzip.c
index 36afd981a6..36afd981a6 100644
--- a/usr/src/boot/lib/libstand/zfs/gzip.c
+++ b/usr/src/boot/libsa/zfs/gzip.c
diff --git a/usr/src/boot/lib/libstand/zfs/libzfs.h b/usr/src/boot/libsa/zfs/libzfs.h
index ddf7f91975..ddf7f91975 100644
--- a/usr/src/boot/lib/libstand/zfs/libzfs.h
+++ b/usr/src/boot/libsa/zfs/libzfs.h
diff --git a/usr/src/boot/lib/libstand/zfs/nvlist.c b/usr/src/boot/libsa/zfs/nvlist.c
index 96b0e63736..96b0e63736 100644
--- a/usr/src/boot/lib/libstand/zfs/nvlist.c
+++ b/usr/src/boot/libsa/zfs/nvlist.c
diff --git a/usr/src/boot/lib/libstand/zfs/zfs.c b/usr/src/boot/libsa/zfs/zfs.c
index 5cd79253e9..5cd79253e9 100644
--- a/usr/src/boot/lib/libstand/zfs/zfs.c
+++ b/usr/src/boot/libsa/zfs/zfs.c
diff --git a/usr/src/boot/lib/libstand/zfs/zfsimpl.c b/usr/src/boot/libsa/zfs/zfsimpl.c
index e83a8a3983..e83a8a3983 100644
--- a/usr/src/boot/lib/libstand/zfs/zfsimpl.c
+++ b/usr/src/boot/libsa/zfs/zfsimpl.c
diff --git a/usr/src/boot/sys/boot/Makefile b/usr/src/boot/sys/boot/Makefile
deleted file mode 100644
index b24280da9d..0000000000
--- a/usr/src/boot/sys/boot/Makefile
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# This file and its contents are supplied under the terms of the
-# Common Development and Distribution License ("CDDL"), version 1.0.
-# You may only use this file in accordance with the terms of version
-# 1.0 of the CDDL.
-#
-# A full copy of the text of the CDDL should have accompanied this
-# source. A copy of the CDDL is also available via the Internet at
-# http://www.illumos.org/license/CDDL.
-#
-
-#
-# Copyright 2015 Toomas Soome <tsoome@me.com>
-#
-
-.KEEP_STATE:
-
-include $(SRC)/Makefile.master
-
-INSTDIRS = i386 efi
-SUBDIRS = libstand libficl $(INSTDIRS)
-
-all := TARGET = all
-clean := TARGET = clean
-clobber := TARGET = clobber
-install := TARGET = install
-
-all clean clobber: $(SUBDIRS)
-
-#
-# The directories in INSTDIRS depend implicitly on SUBDIRS being built already.
-# We use .WAIT instead of explicit dependencies because we only want to make
-# the "install" target in INSTDIRS, not in SUBDIRS.
-#
-# If adding SUBDIRS which are not dependencies of INSTDIRS, "install: all"
-# rules should be added to the Makefiles in those directories.
-#
-install: all .WAIT $(INSTDIRS)
-
-.PARALLEL: libstand libficl
-
-$(SUBDIRS): FRC
- @cd $@; pwd; $(MAKE) $(TARGET)
-
-FRC:
diff --git a/usr/src/boot/sys/boot/forth/Makefile.inc b/usr/src/boot/sys/boot/forth/Makefile.inc
deleted file mode 100644
index e3fd239af7..0000000000
--- a/usr/src/boot/sys/boot/forth/Makefile.inc
+++ /dev/null
@@ -1,28 +0,0 @@
-# $FreeBSD$
-
-FORTH = beastie.4th
-FORTH += beadm.4th
-FORTH += brand.4th
-FORTH += brand-illumos.4th
-FORTH += check-password.4th
-FORTH += color.4th
-FORTH += delay.4th
-FORTH += efi.4th
-FORTH += frames.4th
-FORTH += loader.4th
-DEFFILES = loader.conf
-FORTH += logo-beastie.4th
-FORTH += logo-beastiebw.4th
-FORTH += logo-fbsdbw.4th
-FORTH += logo-illumos.4th
-FORTH += logo-orb.4th
-FORTH += logo-orbbw.4th
-FORTH += menu.4th
-FORTH += menu-commands.4th
-FORTH += menusets.4th
-FORTH += screen.4th
-FORTH += shortcuts.4th
-FORTH += support.4th
-FORTH += version.4th
-FILES += illumos-logo.png
-FILES += illumos-brand.png
diff --git a/usr/src/boot/sys/boot/forth/loader.rc b/usr/src/boot/sys/boot/forth/loader.rc
deleted file mode 100644
index 1bdc5dca30..0000000000
--- a/usr/src/boot/sys/boot/forth/loader.rc
+++ /dev/null
@@ -1,20 +0,0 @@
-\ Loader.rc
-\
-\ Includes additional commands
-include /boot/forth/loader.4th
-try-include /boot/loader.rc.local
-
-\ Reads and processes loader.conf variables
-\ NOTE: Change to `initialize' if you enable the below boot menu
-\ also note that initialize will leave flag in stack from any_conf_read?
-\ start
-initialize drop
-
-\ Tests for password -- executes autoboot first if a password was defined
-check-password
-
-\ Uncomment to enable boot menu
-include /boot/forth/beastie.4th
-beastie-start
-
-\ Unless set otherwise, autoboot is automatic at this point
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile
index 8159ad677b..4f496112e8 100644
--- a/usr/src/cmd/Makefile
+++ b/usr/src/cmd/Makefile
@@ -446,6 +446,7 @@ COMMON_SUBDIRS= \
utmpd \
uuidgen \
valtools \
+ varpd \
vgrind \
vi \
volcheck \
diff --git a/usr/src/cmd/bhyve/README.sync b/usr/src/cmd/bhyve/README.sync
index 45a1f759bc..b59e0f399a 100644
--- a/usr/src/cmd/bhyve/README.sync
+++ b/usr/src/cmd/bhyve/README.sync
@@ -4,12 +4,11 @@ public Git repository at https://git.freebsd.org/src.git
The bhyve kernel module and its associated userland consumers have been updated
to the latest upstream FreeBSD sources as of:
- commit 5ac4ac85ca20ce1f00c84502a65a3291bf416c18
- Author: John Baldwin <jhb@FreeBSD.org>
- Date: Wed Sep 15 09:03:17 2021 -0700
+ commit 4558c11f1b4dfd7fd505d70b79467eb7f1193f07
+ Author: Mark Johnston <markj@FreeBSD.org>
+ Date: Wed Jan 5 10:08:13 2022 -0500
- Remove an always-true check.
- This fixes a -Wtype-limits error from GCC 9.
+ bhyve: Correct unmapping of the MSI-X table BAR
Divergence Notes:
diff --git a/usr/src/cmd/bhyve/acpi.c b/usr/src/cmd/bhyve/acpi.c
index 76ddf5f5f6..1eb2246b94 100644
--- a/usr/src/cmd/bhyve/acpi.c
+++ b/usr/src/cmd/bhyve/acpi.c
@@ -77,7 +77,7 @@ __FBSDID("$FreeBSD$");
#include "vmgenc.h"
/*
- * Define the base address of the ACPI tables, the sizes of some tables,
+ * Define the base address of the ACPI tables, the sizes of some tables,
* and the offsets to the individual tables,
*/
#define BHYVE_ACPI_BASE 0xf2400
@@ -455,7 +455,7 @@ basl_fwrite_fadt(FILE *fp)
EFPRINTF(fp, "[0008]\t\tAddress : 00000000%08X\n",
PM1A_EVT_ADDR);
EFPRINTF(fp, "\n");
-
+
EFPRINTF(fp,
"[0012]\t\tPM1B Event Block : [Generic Address Structure]\n");
EFPRINTF(fp, "[0001]\t\tSpace ID : 01 [SystemIO]\n");
@@ -650,7 +650,7 @@ basl_fwrite_facs(FILE *fp)
EFFLUSH(fp);
return (0);
-
+
err_exit:
return (errno);
}
@@ -850,7 +850,7 @@ basl_load(struct vmctx *ctx, int fd, uint64_t off)
if (fstat(fd, &sb) < 0)
return (errno);
-
+
gaddr = paddr_guest2host(ctx, basl_acpi_base + off, sb.st_size);
if (gaddr == NULL)
return (EFAULT);
@@ -884,7 +884,7 @@ basl_compile(struct vmctx *ctx, int (*fwrite_section)(FILE *), uint64_t offset)
fmt = basl_verbose_iasl ?
"%s -p %s %s" :
"/bin/sh -c \"%s -p %s %s\" 1> /dev/null";
-
+
snprintf(iaslbuf, sizeof(iaslbuf),
fmt,
BHYVE_ASL_COMPILER,
@@ -915,7 +915,7 @@ basl_make_templates(void)
err = 0;
/*
- *
+ *
*/
if ((tmpdir = getenv("BHYVE_TMPDIR")) == NULL || *tmpdir == '\0' ||
(tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0') {
diff --git a/usr/src/cmd/bhyve/audio.h b/usr/src/cmd/bhyve/audio.h
index 2b559a43e5..88f4dc8709 100644
--- a/usr/src/cmd/bhyve/audio.h
+++ b/usr/src/cmd/bhyve/audio.h
@@ -28,7 +28,7 @@
* $FreeBSD$
*/
-#ifndef _AUDIO_EMUL_H_
+#ifndef _AUDIO_EMUL_H_
#define _AUDIO_EMUL_H_
#include <sys/types.h>
diff --git a/usr/src/cmd/bhyve/bhyverun.c b/usr/src/cmd/bhyve/bhyverun.c
index 37ec3de164..bf2b784a01 100644
--- a/usr/src/cmd/bhyve/bhyverun.c
+++ b/usr/src/cmd/bhyve/bhyverun.c
@@ -240,11 +240,11 @@ usage(int code)
#endif
" %*s [-c [[cpus=]numcpus][,sockets=n][,cores=n][,threads=n]]\n"
#ifdef __FreeBSD__
- " %*s [-G port] [-k file] [-l lpc] [-m mem] [-o var=value]\n"
+ " %*s [-G port] [-k config_file] [-l lpc] [-m mem] [-o var=value]\n"
" %*s [-p vcpu:hostcpu] [-r file] [-s pci] [-U uuid] vmname\n"
#else
- " %*s [-k <file>] [-l <lpc>] [-m mem] [-o <var>=<value>]\n"
+ " %*s [-k <config_file>] [-l <lpc>] [-m mem] [-o <var>=<value>]\n"
" %*s [-s <pci>] [-U uuid] vmname\n"
#endif
" -A: create ACPI tables\n"
@@ -1247,7 +1247,7 @@ do_open(const char *vmname)
bool reinit, romboot;
#ifndef WITHOUT_CAPSICUM
cap_rights_t rights;
- const cap_ioctl_t *cmds;
+ const cap_ioctl_t *cmds;
size_t ncmds;
#endif
@@ -1297,7 +1297,7 @@ do_open(const char *vmname)
#ifndef WITHOUT_CAPSICUM
cap_rights_init(&rights, CAP_IOCTL, CAP_MMAP_RW);
- if (caph_rights_limit(vm_get_device_fd(ctx), &rights) == -1)
+ if (caph_rights_limit(vm_get_device_fd(ctx), &rights) == -1)
errx(EX_OSERR, "Unable to apply rights for sandbox");
vm_get_ioctls(&ncmds);
cmds = vm_get_ioctls(NULL);
@@ -1307,7 +1307,7 @@ do_open(const char *vmname)
errx(EX_OSERR, "Unable to apply rights for sandbox");
free((cap_ioctl_t *)cmds);
#endif
-
+
if (reinit) {
#ifndef __FreeBSD__
error = vm_reinit(ctx, 0);
@@ -1532,7 +1532,7 @@ main(int argc, char *argv[])
set_config_bool("x86.mptable", false);
break;
case 'h':
- usage(0);
+ usage(0);
default:
usage(1);
}
diff --git a/usr/src/cmd/bhyve/block_if.c b/usr/src/cmd/bhyve/block_if.c
index 1bb085a8e4..29d55dfdda 100644
--- a/usr/src/cmd/bhyve/block_if.c
+++ b/usr/src/cmd/bhyve/block_if.c
@@ -143,7 +143,7 @@ struct blockif_ctxt {
struct mevent *bc_resize_event;
/* Request elements and free/pending/busy queues */
- TAILQ_HEAD(, blockif_elem) bc_freeq;
+ TAILQ_HEAD(, blockif_elem) bc_freeq;
TAILQ_HEAD(, blockif_elem) bc_pendq;
TAILQ_HEAD(, blockif_elem) bc_busyq;
struct blockif_elem bc_reqs[BLOCKIF_MAXREQ];
@@ -614,7 +614,7 @@ blockif_open(nvlist_t *nvl, const char *ident)
#ifndef WITHOUT_CAPSICUM
cap_rights_init(&rights, CAP_FSYNC, CAP_IOCTL, CAP_READ, CAP_SEEK,
- CAP_WRITE, CAP_FSTAT, CAP_EVENT);
+ CAP_WRITE, CAP_FSTAT, CAP_EVENT, CAP_FPATHCONF);
if (ro)
cap_rights_clear(&rights, CAP_FSYNC, CAP_WRITE);
diff --git a/usr/src/cmd/bhyve/bootrom.c b/usr/src/cmd/bhyve/bootrom.c
index 38a50490eb..cbb05c8c50 100644
--- a/usr/src/cmd/bhyve/bootrom.c
+++ b/usr/src/cmd/bhyve/bootrom.c
@@ -39,14 +39,17 @@ __FBSDID("$FreeBSD$");
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
#include <vmmapi.h>
+
#include "bhyverun.h"
#include "bootrom.h"
#include "debug.h"
+#include "mem.h"
#define BOOTROM_SIZE (16 * 1024 * 1024) /* 16 MB */
@@ -64,6 +67,56 @@ static vm_paddr_t gpa_base; /* GPA of low end of region. */
static vm_paddr_t gpa_allocbot; /* Low GPA of free region. */
static vm_paddr_t gpa_alloctop; /* High GPA, minus 1, of free region. */
+#define CFI_BCS_WRITE_BYTE 0x10
+#define CFI_BCS_CLEAR_STATUS 0x50
+#define CFI_BCS_READ_STATUS 0x70
+#define CFI_BCS_READ_ARRAY 0xff
+
+static struct bootrom_var_state {
+ uint8_t *mmap;
+ uint64_t gpa;
+ off_t size;
+ uint8_t cmd;
+} var = { NULL, 0, 0, CFI_BCS_READ_ARRAY };
+
+/*
+ * Emulate just those CFI basic commands that will convince EDK II
+ * that the Firmware Volume area is writable and persistent.
+ */
+static int
+bootrom_var_mem_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr,
+ int size, uint64_t *val, void *arg1, long arg2)
+{
+ off_t offset;
+
+ offset = addr - var.gpa;
+ if (offset + size > var.size || offset < 0 || offset + size <= offset)
+ return (EINVAL);
+
+ if (dir == MEM_F_WRITE) {
+ switch (var.cmd) {
+ case CFI_BCS_WRITE_BYTE:
+ memcpy(var.mmap + offset, val, size);
+ var.cmd = CFI_BCS_READ_ARRAY;
+ break;
+ default:
+ var.cmd = *(uint8_t *)val;
+ }
+ } else {
+ switch (var.cmd) {
+ case CFI_BCS_CLEAR_STATUS:
+ case CFI_BCS_READ_STATUS:
+ memset(val, 0, size);
+ var.cmd = CFI_BCS_READ_ARRAY;
+ break;
+ default:
+ memcpy(val, var.mmap + offset, size);
+ break;
+ }
+ }
+ return (0);
+}
+
void
init_bootrom(struct vmctx *ctx)
{
@@ -142,10 +195,16 @@ bootrom_loadrom(struct vmctx *ctx, const char *romfile)
{
struct stat sbuf;
ssize_t rlen;
- char *ptr;
- int fd, i, rv;
+ off_t rom_size, var_size, total_size;
+ char *ptr, *varfile;
+ int fd, varfd, i, rv;
rv = -1;
+ varfd = -1;
+
+ varfile = strdup(romfile);
+ romfile = strsep(&varfile, ",");
+
fd = open(romfile, O_RDONLY);
if (fd < 0) {
EPRINTLN("Error opening bootrom \"%s\": %s",
@@ -153,19 +212,56 @@ bootrom_loadrom(struct vmctx *ctx, const char *romfile)
goto done;
}
- if (fstat(fd, &sbuf) < 0) {
+ if (varfile != NULL) {
+ varfd = open(varfile, O_RDWR);
+ if (varfd < 0) {
+ fprintf(stderr, "Error opening bootrom variable file "
+ "\"%s\": %s\n", varfile, strerror(errno));
+ goto done;
+ }
+ }
+
+ if (fstat(fd, &sbuf) < 0) {
EPRINTLN("Could not fstat bootrom file \"%s\": %s",
- romfile, strerror(errno));
+ romfile, strerror(errno));
goto done;
- }
+ }
+
+ rom_size = sbuf.st_size;
+ if (varfd < 0) {
+ var_size = 0;
+ } else {
+ if (fstat(varfd, &sbuf) < 0) {
+ fprintf(stderr, "Could not fstat bootrom variable file \"%s\": %s\n",
+ varfile, strerror(errno));
+ goto done;
+ }
+ var_size = sbuf.st_size;
+ }
+
+ if (var_size > BOOTROM_SIZE ||
+ (var_size != 0 && var_size < PAGE_SIZE)) {
+ fprintf(stderr, "Invalid bootrom variable size %ld\n",
+ var_size);
+ goto done;
+ }
+
+ total_size = rom_size + var_size;
+
+ if (total_size > BOOTROM_SIZE) {
+ fprintf(stderr, "Invalid bootrom and variable aggregate size "
+ "%ld\n", total_size);
+ goto done;
+ }
/* Map the bootrom into the guest address space */
- if (bootrom_alloc(ctx, sbuf.st_size, PROT_READ | PROT_EXEC,
- BOOTROM_ALLOC_TOP, &ptr, NULL) != 0)
+ if (bootrom_alloc(ctx, rom_size, PROT_READ | PROT_EXEC,
+ BOOTROM_ALLOC_TOP, &ptr, NULL) != 0) {
goto done;
+ }
/* Read 'romfile' into the guest address space */
- for (i = 0; i < sbuf.st_size / PAGE_SIZE; i++) {
+ for (i = 0; i < rom_size / PAGE_SIZE; i++) {
rlen = read(fd, ptr + i * PAGE_SIZE, PAGE_SIZE);
if (rlen != PAGE_SIZE) {
EPRINTLN("Incomplete read of page %d of bootrom "
@@ -173,6 +269,31 @@ bootrom_loadrom(struct vmctx *ctx, const char *romfile)
goto done;
}
}
+
+ if (varfd >= 0) {
+#ifdef __FreeBSD__
+ var.mmap = mmap(NULL, var_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, varfd, 0);
+#else
+ var.mmap = (uint8_t *)mmap(NULL, var_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED, varfd, 0);
+#endif
+ if (var.mmap == MAP_FAILED)
+ goto done;
+ var.size = var_size;
+ var.gpa = (gpa_alloctop - var_size) + 1;
+ gpa_alloctop = var.gpa - 1;
+ rv = register_mem(&(struct mem_range){
+ .name = "bootrom variable",
+ .flags = MEM_F_RW,
+ .handler = bootrom_var_mem_handler,
+ .base = var.gpa,
+ .size = var.size,
+ });
+ if (rv != 0)
+ goto done;
+ }
+
rv = 0;
done:
if (fd >= 0)
diff --git a/usr/src/cmd/bhyve/config.c b/usr/src/cmd/bhyve/config.c
index db28cc5516..9383e49093 100644
--- a/usr/src/cmd/bhyve/config.c
+++ b/usr/src/cmd/bhyve/config.c
@@ -228,7 +228,7 @@ _expand_config_value(const char *value, int depth)
fputc('%', valfp);
vp++;
break;
- }
+ }
if (vp[1] != '(' || vp[2] == '\0')
cp = NULL;
else
diff --git a/usr/src/cmd/bhyve/config.h b/usr/src/cmd/bhyve/config.h
index 9f82afb267..574da966df 100644
--- a/usr/src/cmd/bhyve/config.h
+++ b/usr/src/cmd/bhyve/config.h
@@ -45,7 +45,7 @@
* Configuration variables are stored in a tree. The full path of a
* variable is specified as a dot-separated name similar to sysctl(8)
* OIDs.
- */
+ */
/*
* Fetches the value of a configuration variable. If the "raw" value
diff --git a/usr/src/cmd/bhyve/fwctl.c b/usr/src/cmd/bhyve/fwctl.c
index 0640bc28ba..f0f9aa3aff 100644
--- a/usr/src/cmd/bhyve/fwctl.c
+++ b/usr/src/cmd/bhyve/fwctl.c
@@ -98,7 +98,7 @@ fwctl_send_rest(uint32_t *data, size_t len)
int i;
cdata = (uint8_t *) data;
- u.w = 0;
+ u.w = 0;
for (i = 0, u.w = 0; i < len; i++)
u.c[i] = *cdata++;
@@ -472,16 +472,18 @@ fwctl_inb(void)
static void
fwctl_outw(uint16_t val)
{
- switch (be_state) {
- case IDENT_WAIT:
- if (val == 0) {
- be_state = IDENT_SEND;
- ident_idx = 0;
- }
- break;
- default:
- /* ignore */
- break;
+ if (be_state == DORMANT) {
+ return;
+ }
+
+ if (val == 0) {
+ /*
+ * The guest wants to read the signature. It's possible that the
+ * guest is unaware of the fwctl state at this moment. For that
+ * reason, reset the state machine unconditionally.
+ */
+ be_state = IDENT_SEND;
+ ident_idx = 0;
}
}
@@ -538,12 +540,32 @@ fwctl_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
return (0);
}
-INOUT_PORT(fwctl_wreg, FWCTL_OUT, IOPORT_F_INOUT, fwctl_handler);
-INOUT_PORT(fwctl_rreg, FWCTL_IN, IOPORT_F_IN, fwctl_handler);
void
fwctl_init(void)
{
+ struct inout_port iop;
+ int error;
+
+ bzero(&iop, sizeof(iop));
+ iop.name = "fwctl_wreg";
+ iop.port = FWCTL_OUT;
+ iop.size = 1;
+ iop.flags = IOPORT_F_INOUT;
+ iop.handler = fwctl_handler;
+
+ error = register_inout(&iop);
+ assert(error == 0);
+
+ bzero(&iop, sizeof(iop));
+ iop.name = "fwctl_rreg";
+ iop.port = FWCTL_IN;
+ iop.size = 1;
+ iop.flags = IOPORT_F_IN;
+ iop.handler = fwctl_handler;
+
+ error = register_inout(&iop);
+ assert(error == 0);
ops[OP_GET_LEN] = &fgetlen_info;
ops[OP_GET] = &fgetval_info;
diff --git a/usr/src/cmd/bhyve/hda_reg.h b/usr/src/cmd/bhyve/hda_reg.h
index b3034bf9f4..c309056c6f 100644
--- a/usr/src/cmd/bhyve/hda_reg.h
+++ b/usr/src/cmd/bhyve/hda_reg.h
@@ -668,7 +668,7 @@
/* Channel Count Control */
#define HDA_CMD_VERB_GET_CONV_CHAN_COUNT 0xf2d
-#define HDA_CMD_VERB_SET_CONV_CHAN_COUNT 0x72d
+#define HDA_CMD_VERB_SET_CONV_CHAN_COUNT 0x72d
#define HDA_CMD_GET_CONV_CHAN_COUNT(cad, nid) \
(HDA_CMD_12BIT((cad), (nid), \
@@ -677,20 +677,20 @@
(HDA_CMD_12BIT((cad), (nid), \
HDA_CMD_VERB_SET_CONV_CHAN_COUNT, (payload)))
-#define HDA_CMD_VERB_GET_HDMI_DIP_SIZE 0xf2e
+#define HDA_CMD_VERB_GET_HDMI_DIP_SIZE 0xf2e
#define HDA_CMD_GET_HDMI_DIP_SIZE(cad, nid, arg) \
(HDA_CMD_12BIT((cad), (nid), \
HDA_CMD_VERB_GET_HDMI_DIP_SIZE, (arg)))
-#define HDA_CMD_VERB_GET_HDMI_ELDD 0xf2f
+#define HDA_CMD_VERB_GET_HDMI_ELDD 0xf2f
#define HDA_CMD_GET_HDMI_ELDD(cad, nid, off) \
(HDA_CMD_12BIT((cad), (nid), \
HDA_CMD_VERB_GET_HDMI_ELDD, (off)))
-#define HDA_CMD_VERB_GET_HDMI_DIP_INDEX 0xf30
-#define HDA_CMD_VERB_SET_HDMI_DIP_INDEX 0x730
+#define HDA_CMD_VERB_GET_HDMI_DIP_INDEX 0xf30
+#define HDA_CMD_VERB_SET_HDMI_DIP_INDEX 0x730
#define HDA_CMD_GET_HDMI_DIP_INDEX(cad, nid) \
(HDA_CMD_12BIT((cad), (nid), \
@@ -699,8 +699,8 @@
(HDA_CMD_12BIT((cad), (nid), \
HDA_CMD_VERB_SET_HDMI_DIP_INDEX, (payload)))
-#define HDA_CMD_VERB_GET_HDMI_DIP_DATA 0xf31
-#define HDA_CMD_VERB_SET_HDMI_DIP_DATA 0x731
+#define HDA_CMD_VERB_GET_HDMI_DIP_DATA 0xf31
+#define HDA_CMD_VERB_SET_HDMI_DIP_DATA 0x731
#define HDA_CMD_GET_HDMI_DIP_DATA(cad, nid) \
(HDA_CMD_12BIT((cad), (nid), \
@@ -709,8 +709,8 @@
(HDA_CMD_12BIT((cad), (nid), \
HDA_CMD_VERB_SET_HDMI_DIP_DATA, (payload)))
-#define HDA_CMD_VERB_GET_HDMI_DIP_XMIT 0xf32
-#define HDA_CMD_VERB_SET_HDMI_DIP_XMIT 0x732
+#define HDA_CMD_VERB_GET_HDMI_DIP_XMIT 0xf32
+#define HDA_CMD_VERB_SET_HDMI_DIP_XMIT 0x732
#define HDA_CMD_GET_HDMI_DIP_XMIT(cad, nid) \
(HDA_CMD_12BIT((cad), (nid), \
@@ -719,11 +719,11 @@
(HDA_CMD_12BIT((cad), (nid), \
HDA_CMD_VERB_SET_HDMI_DIP_XMIT, (payload)))
-#define HDA_CMD_VERB_GET_HDMI_CP_CTRL 0xf33
-#define HDA_CMD_VERB_SET_HDMI_CP_CTRL 0x733
+#define HDA_CMD_VERB_GET_HDMI_CP_CTRL 0xf33
+#define HDA_CMD_VERB_SET_HDMI_CP_CTRL 0x733
-#define HDA_CMD_VERB_GET_HDMI_CHAN_SLOT 0xf34
-#define HDA_CMD_VERB_SET_HDMI_CHAN_SLOT 0x734
+#define HDA_CMD_VERB_GET_HDMI_CHAN_SLOT 0xf34
+#define HDA_CMD_VERB_SET_HDMI_CHAN_SLOT 0x734
#define HDA_CMD_GET_HDMI_CHAN_SLOT(cad, nid) \
(HDA_CMD_12BIT((cad), (nid), \
diff --git a/usr/src/cmd/bhyve/mevent.c b/usr/src/cmd/bhyve/mevent.c
index a859be6059..576ba3390e 100644
--- a/usr/src/cmd/bhyve/mevent.c
+++ b/usr/src/cmd/bhyve/mevent.c
@@ -30,11 +30,11 @@
/*
* Copyright 2018 Joyent, Inc.
- * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
*/
/*
- * Micro event library for FreeBSD, designed for a single i/o thread
+ * Micro event library for FreeBSD, designed for a single i/o thread
* using kqueue, and having events be persistent by default.
*/
@@ -82,11 +82,15 @@ __FBSDID("$FreeBSD$");
#define EV_ADD EV_ENABLE
#define EV_DISABLE 0x02
#define EV_DELETE 0x04
+
+static int mevent_file_poll_interval_ms = 5000;
#endif
static pthread_t mevent_tid;
static pthread_once_t mevent_once = PTHREAD_ONCE_INIT;
+#ifdef __FreeBSD__
static int mevent_timid = 43;
+#endif
static int mevent_pipefd[2];
static int mfd;
static pthread_mutex_t mevent_lmutex = PTHREAD_MUTEX_INITIALIZER;
@@ -112,6 +116,12 @@ struct mevent {
boolean_t me_auto_requeue;
struct file_obj me_fobj;
char *me_fname;
+ struct {
+ int mp_fd;
+ off_t mp_size;
+ void (*mp_func)(int, enum ev_type, void *);
+ void *mp_param;
+ } me_poll;
#endif
LIST_ENTRY(mevent) me_list;
};
@@ -149,7 +159,7 @@ static void
mevent_notify(void)
{
char c = '\0';
-
+
/*
* If calling from outside the i/o thread, write a byte on the
* pipe to force the i/o thread to exit the blocking kevent call.
@@ -177,7 +187,7 @@ mevent_init(void)
cap_rights_init(&rights, CAP_KQUEUE);
if (caph_rights_limit(mfd, &rights) == -1)
errx(EX_OSERR, "Unable to apply rights for sandbox");
- #endif
+#endif
LIST_INIT(&change_head);
LIST_INIT(&global_head);
@@ -213,7 +223,14 @@ mevent_kq_filter(struct mevent *mevp)
static int
mevent_kq_flags(struct mevent *mevp)
{
- return (mevp->me_state);
+ int retval;
+
+ retval = mevp->me_state;
+
+ if (mevp->me_type == EVF_VNODE)
+ retval |= EV_CLEAR;
+
+ return (retval);
}
static int
@@ -228,6 +245,11 @@ mevent_kq_fflags(struct mevent *mevp)
if ((mevp->me_fflags & EVFF_ATTRIB) != 0)
retval |= NOTE_ATTRIB;
break;
+ case EVF_READ:
+ case EVF_WRITE:
+ case EVF_TIMER:
+ case EVF_SIGNAL:
+ break;
}
return (retval);
@@ -370,149 +392,233 @@ mevent_fdpath(int fd)
}
static void
-mevent_update_one(struct mevent *mevp)
+mevent_poll_file_attrib(int fd, enum ev_type type, void *param)
{
- int portfd = mevp->me_notify.portnfy_port;
+ struct mevent *mevp = param;
+ struct stat st;
- switch (mevp->me_type) {
- case EVF_READ:
- case EVF_WRITE:
- mevp->me_auto_requeue = B_FALSE;
+ if (fstat(mevp->me_poll.mp_fd, &st) != 0) {
+ (void) fprintf(stderr, "%s: fstat(%d) \"%s\" failed: %s\n",
+ __func__, fd, mevp->me_fname, strerror(errno));
+ return;
+ }
- switch (mevp->me_state) {
- case EV_ENABLE:
- {
- int events;
+ if (mevp->me_poll.mp_size != st.st_size ||
+ mevp->me_fobj.fo_ctime.tv_sec != st.st_ctim.tv_sec ||
+ mevp->me_fobj.fo_ctime.tv_nsec != st.st_ctim.tv_nsec) {
+ mevp->me_poll.mp_size = st.st_size;
+ mevp->me_fobj.fo_atime = st.st_atim;
+ mevp->me_fobj.fo_mtime = st.st_mtim;
+ mevp->me_fobj.fo_ctime = st.st_ctim;
- events = (mevp->me_type == EVF_READ) ? POLLIN : POLLOUT;
+ (*mevp->me_poll.mp_func)(mevp->me_poll.mp_fd, EVF_VNODE,
+ mevp->me_poll.mp_param);
+ }
+}
- if (port_associate(portfd, PORT_SOURCE_FD, mevp->me_fd,
- events, mevp) != 0) {
- (void) fprintf(stderr,
- "port_associate fd %d %p failed: %s\n",
- mevp->me_fd, mevp, strerror(errno));
- }
- return;
+static void
+mevent_update_one_readwrite(struct mevent *mevp)
+{
+ int portfd = mevp->me_notify.portnfy_port;
+
+ mevp->me_auto_requeue = B_FALSE;
+
+ switch (mevp->me_state) {
+ case EV_ENABLE:
+ {
+ const int events = (mevp->me_type == EVF_READ) ?
+ POLLIN : POLLOUT;
+
+ if (port_associate(portfd, PORT_SOURCE_FD, mevp->me_fd,
+ events, mevp) != 0) {
+ (void) fprintf(stderr,
+ "port_associate fd %d %p failed: %s\n",
+ mevp->me_fd, mevp, strerror(errno));
}
- case EV_DISABLE:
- case EV_DELETE:
- /*
- * A disable that comes in while an event is being
- * handled will result in an ENOENT.
- */
- if (port_dissociate(portfd, PORT_SOURCE_FD,
- mevp->me_fd) != 0 && errno != ENOENT) {
- (void) fprintf(stderr, "port_dissociate "
- "portfd %d fd %d mevp %p failed: %s\n",
- portfd, mevp->me_fd, mevp, strerror(errno));
- }
- return;
- default:
- goto abort;
+ return;
+ }
+ case EV_DISABLE:
+ case EV_DELETE:
+ /*
+ * A disable that comes in while an event is being
+ * handled will result in an ENOENT.
+ */
+ if (port_dissociate(portfd, PORT_SOURCE_FD,
+ mevp->me_fd) != 0 && errno != ENOENT) {
+ (void) fprintf(stderr, "port_dissociate "
+ "portfd %d fd %d mevp %p failed: %s\n",
+ portfd, mevp->me_fd, mevp, strerror(errno));
}
+ return;
+ default:
+ (void) fprintf(stderr, "%s: unhandled state %d\n", __func__,
+ mevp->me_state);
+ abort();
+ }
+}
- case EVF_TIMER:
- mevp->me_auto_requeue = B_TRUE;
+static void
+mevent_update_one_timer(struct mevent *mevp)
+{
+ mevp->me_auto_requeue = B_TRUE;
- switch (mevp->me_state) {
- case EV_ENABLE:
- {
- struct itimerspec it = { 0 };
+ switch (mevp->me_state) {
+ case EV_ENABLE:
+ {
+ struct itimerspec it = { 0 };
- mevp->me_sigev.sigev_notify = SIGEV_PORT;
- mevp->me_sigev.sigev_value.sival_ptr = &mevp->me_notify;
+ mevp->me_sigev.sigev_notify = SIGEV_PORT;
+ mevp->me_sigev.sigev_value.sival_ptr = &mevp->me_notify;
- if (timer_create(CLOCK_REALTIME, &mevp->me_sigev,
- &mevp->me_timid) != 0) {
- (void) fprintf(stderr,
- "timer_create failed: %s", strerror(errno));
- return;
- }
+ if (timer_create(CLOCK_REALTIME, &mevp->me_sigev,
+ &mevp->me_timid) != 0) {
+ (void) fprintf(stderr, "timer_create failed: %s",
+ strerror(errno));
+ return;
+ }
- /* The first timeout */
- it.it_value.tv_sec = mevp->me_msecs / MILLISEC;
- it.it_value.tv_nsec =
- MSEC2NSEC(mevp->me_msecs % MILLISEC);
- /* Repeat at the same interval */
- it.it_interval = it.it_value;
+ /* The first timeout */
+ it.it_value.tv_sec = mevp->me_msecs / MILLISEC;
+ it.it_value.tv_nsec =
+ MSEC2NSEC(mevp->me_msecs % MILLISEC);
+ /* Repeat at the same interval */
+ it.it_interval = it.it_value;
- if (timer_settime(mevp->me_timid, 0, &it, NULL) != 0) {
- (void) fprintf(stderr, "timer_settime failed: "
- "%s", strerror(errno));
- }
- return;
+ if (timer_settime(mevp->me_timid, 0, &it, NULL) != 0) {
+ (void) fprintf(stderr, "timer_settime failed: %s",
+ strerror(errno));
}
- case EV_DISABLE:
- case EV_DELETE:
- if (timer_delete(mevp->me_timid) != 0) {
- (void) fprintf(stderr, "timer_delete failed: "
- "%s", strerror(errno));
- }
- return;
- default:
- goto abort;
+ return;
+ }
+ case EV_DISABLE:
+ case EV_DELETE:
+ if (timer_delete(mevp->me_timid) != 0) {
+ (void) fprintf(stderr, "timer_delete failed: %s",
+ strerror(errno));
}
+ mevp->me_timid = -1;
+ return;
+ default:
+ (void) fprintf(stderr, "%s: unhandled state %d\n", __func__,
+ mevp->me_state);
+ abort();
+ }
+}
- case EVF_VNODE:
- mevp->me_auto_requeue = B_FALSE;
+static void
+mevent_update_one_vnode(struct mevent *mevp)
+{
+ int portfd = mevp->me_notify.portnfy_port;
- switch (mevp->me_state) {
- case EV_ENABLE:
- {
- int events = 0;
+ mevp->me_auto_requeue = B_FALSE;
- if ((mevp->me_fflags & EVFF_ATTRIB) != 0)
- events |= FILE_ATTRIB;
+ switch (mevp->me_state) {
+ case EV_ENABLE:
+ {
+ int events = 0;
- assert(events != 0);
+ if ((mevp->me_fflags & EVFF_ATTRIB) != 0)
+ events |= FILE_ATTRIB;
- if (mevp->me_fname == NULL) {
- mevp->me_fname = mevent_fdpath(mevp->me_fd);
- if (mevp->me_fname == NULL)
- return;
- }
+ assert(events != 0);
- bzero(&mevp->me_fobj, sizeof (mevp->me_fobj));
- mevp->me_fobj.fo_name = mevp->me_fname;
+ if (mevp->me_fname == NULL) {
+ mevp->me_fname = mevent_fdpath(mevp->me_fd);
+ if (mevp->me_fname == NULL)
+ return;
+ }
- if (port_associate(portfd, PORT_SOURCE_FILE,
- (uintptr_t)&mevp->me_fobj, events, mevp) != 0) {
+ bzero(&mevp->me_fobj, sizeof (mevp->me_fobj));
+ mevp->me_fobj.fo_name = mevp->me_fname;
+
+ if (port_associate(portfd, PORT_SOURCE_FILE,
+ (uintptr_t)&mevp->me_fobj, events, mevp) != 0) {
+ /*
+ * If this file does not support event ports
+ * (e.g. ZVOLs do not yet have support)
+ * then convert this to a timer event and poll for
+ * file attribute changes.
+ */
+ struct stat st;
+
+ if (errno != ENOTSUP) {
(void) fprintf(stderr,
- "port_associate fd %d (%s) %p failed: %s\n",
+ "port_associate fd %d (%s) %p failed: %s"
+ ", polling instead\n",
mevp->me_fd, mevp->me_fname, mevp,
strerror(errno));
}
- return;
- }
- case EV_DISABLE:
- case EV_DELETE:
- /*
- * A disable that comes in while an event is being
- * handled will result in an ENOENT.
- */
- if (port_dissociate(portfd, PORT_SOURCE_FILE,
- (uintptr_t)&mevp->me_fobj) != 0 &&
- errno != ENOENT) {
- (void) fprintf(stderr, "port_dissociate "
- "portfd %d fd %d mevp %p failed: %s\n",
- portfd, mevp->me_fd, mevp, strerror(errno));
+
+ if (fstat(mevp->me_fd, &st) != 0) {
+ (void) fprintf(stderr,
+ "fstat(%d) \"%s\" failed: %s\n",
+ mevp->me_fd, mevp->me_fname,
+ strerror(errno));
+ return;
}
- free(mevp->me_fname);
- mevp->me_fname = NULL;
- return;
- default:
- goto abort;
- }
+ mevp->me_fobj.fo_atime = st.st_atim;
+ mevp->me_fobj.fo_mtime = st.st_mtim;
+ mevp->me_fobj.fo_ctime = st.st_ctim;
+
+ mevp->me_poll.mp_fd = mevp->me_fd;
+ mevp->me_poll.mp_size = st.st_size;
+
+ mevp->me_poll.mp_func = mevp->me_func;
+ mevp->me_poll.mp_param = mevp->me_param;
+ mevp->me_func = mevent_poll_file_attrib;
+ mevp->me_param = mevp;
+
+ mevp->me_type = EVF_TIMER;
+ mevp->me_timid = -1;
+ mevp->me_msecs = mevent_file_poll_interval_ms;
+ mevent_update_one_timer(mevp);
+ }
+ return;
+ }
+ case EV_DISABLE:
+ case EV_DELETE:
+ /*
+ * A disable that comes in while an event is being
+ * handled will result in an ENOENT.
+ */
+ if (port_dissociate(portfd, PORT_SOURCE_FILE,
+ (uintptr_t)&mevp->me_fobj) != 0 &&
+ errno != ENOENT) {
+ (void) fprintf(stderr, "port_dissociate "
+ "portfd %d fd %d mevp %p failed: %s\n",
+ portfd, mevp->me_fd, mevp, strerror(errno));
+ }
+ free(mevp->me_fname);
+ mevp->me_fname = NULL;
+ return;
default:
- /* EVF_SIGNAL not yet implemented. */
- goto abort;
+ (void) fprintf(stderr, "%s: unhandled state %d\n", __func__,
+ mevp->me_state);
+ abort();
}
+}
-abort:
- (void) fprintf(stderr, "%s: unhandled type %d state %d\n", __func__,
- mevp->me_type, mevp->me_state);
- abort();
+static void
+mevent_update_one(struct mevent *mevp)
+{
+ switch (mevp->me_type) {
+ case EVF_READ:
+ case EVF_WRITE:
+ mevent_update_one_readwrite(mevp);
+ break;
+ case EVF_TIMER:
+ mevent_update_one_timer(mevp);
+ break;
+ case EVF_VNODE:
+ mevent_update_one_vnode(mevp);
+ break;
+ case EVF_SIGNAL: /* EVF_SIGNAL not yet implemented. */
+ default:
+ (void) fprintf(stderr, "%s: unhandled event type %d\n",
+ __func__, mevp->me_type);
+ abort();
+ }
}
static void
@@ -625,13 +731,16 @@ mevent_add_state(int tfd, enum ev_type type,
if (type == EVF_TIMER) {
mevp->me_msecs = tfd;
+#ifdef __FreeBSD__
mevp->me_timid = mevent_timid++;
+#else
+ mevp->me_timid = -1;
+#endif
} else
mevp->me_fd = tfd;
mevp->me_type = type;
mevp->me_func = func;
mevp->me_param = param;
-
mevp->me_state = state;
mevp->me_fflags = fflags;
@@ -859,7 +968,7 @@ mevent_dispatch(void)
if (ret == -1 && errno != EINTR) {
perror("Error return from kevent monitor");
}
-
+
/*
* Handle reported events
*/
@@ -882,5 +991,5 @@ mevent_dispatch(void)
/* Handle reported event */
mevent_handle_pe(&pev);
#endif /* __FreeBSD__ */
- }
+ }
}
diff --git a/usr/src/cmd/bhyve/mevent.h b/usr/src/cmd/bhyve/mevent.h
index a26293867a..8c3db9db54 100644
--- a/usr/src/cmd/bhyve/mevent.h
+++ b/usr/src/cmd/bhyve/mevent.h
@@ -44,7 +44,7 @@ enum ev_type {
struct mevent;
-struct mevent *mevent_add(int fd, enum ev_type type,
+struct mevent *mevent_add(int fd, enum ev_type type,
void (*func)(int, enum ev_type, void *),
void *param);
struct mevent *mevent_add_flags(int fd, enum ev_type type, int fflags,
diff --git a/usr/src/cmd/bhyve/mevent_test.c b/usr/src/cmd/bhyve/mevent_test.c
index dad8b7773e..37072c5515 100644
--- a/usr/src/cmd/bhyve/mevent_test.c
+++ b/usr/src/cmd/bhyve/mevent_test.c
@@ -132,7 +132,7 @@ timer_callback(int fd, enum ev_type type, void *param)
#ifdef MEVENT_ECHO
struct esync {
pthread_mutex_t e_mt;
- pthread_cond_t e_cond;
+ pthread_cond_t e_cond;
};
static void
diff --git a/usr/src/cmd/bhyve/mptbl.c b/usr/src/cmd/bhyve/mptbl.c
index fc82faad89..923e0f42f5 100644
--- a/usr/src/cmd/bhyve/mptbl.c
+++ b/usr/src/cmd/bhyve/mptbl.c
@@ -180,7 +180,7 @@ mpt_build_bus_entries(bus_entry_ptr mpeb)
memset(mpeb, 0, sizeof(*mpeb));
mpeb->type = MPCT_ENTRY_BUS;
- mpeb->bus_id = 1;
+ mpeb->bus_id = 1;
memcpy(mpeb->bus_type, MPE_BUSNAME_ISA, MPE_BUSNAME_LEN);
}
@@ -243,7 +243,7 @@ mpt_build_ioint_entries(int_entry_ptr mpie, int id)
/*
* The following config is taken from kernel mptable.c
- * mptable_parse_default_config_ints(...), for now
+ * mptable_parse_default_config_ints(...), for now
* just use the default config, tweek later if needed.
*/
@@ -287,7 +287,7 @@ mpt_build_ioint_entries(int_entry_ptr mpie, int id)
/* Next, generate entries for any PCI INTx interrupts. */
for (bus = 0; bus <= PCI_BUSMAX; bus++)
- pci_walk_lintr(bus, mpt_generate_pci_int, &mpie);
+ pci_walk_lintr(bus, mpt_generate_pci_int, &mpie);
}
void
diff --git a/usr/src/cmd/bhyve/net_backends.c b/usr/src/cmd/bhyve/net_backends.c
index 426f330319..329405964e 100644
--- a/usr/src/cmd/bhyve/net_backends.c
+++ b/usr/src/cmd/bhyve/net_backends.c
@@ -538,7 +538,7 @@ ng_init(struct net_backend *be, const char *devname,
/*
* The default ng_socket(4) buffer's size is too low.
* Calculate the minimum value between NG_SBUF_MAX_SIZE
- * and kern.ipc.maxsockbuf.
+ * and kern.ipc.maxsockbuf.
*/
msbsz = sizeof(maxsbsz);
if (sysctlbyname("kern.ipc.maxsockbuf", &maxsbsz, &msbsz,
diff --git a/usr/src/cmd/bhyve/pci_ahci.c b/usr/src/cmd/bhyve/pci_ahci.c
index 2416edd166..6f99795ca4 100644
--- a/usr/src/cmd/bhyve/pci_ahci.c
+++ b/usr/src/cmd/bhyve/pci_ahci.c
@@ -1932,7 +1932,7 @@ ata_ioreq_cb(struct blockif_req *br, int err)
if (!err && aior->more) {
if (dsm)
ahci_handle_dsm_trim(p, slot, cfis, aior->done);
- else
+ else
ahci_handle_rw(p, slot, cfis, aior->done);
goto out;
}
@@ -2465,7 +2465,7 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
sc->ports = p;
ret = 1;
goto open_fail;
- }
+ }
sc->port[p].bctx = bctxt;
sc->port[p].pr_sc = sc;
sc->port[p].port = p;
diff --git a/usr/src/cmd/bhyve/pci_e82545.c b/usr/src/cmd/bhyve/pci_e82545.c
index 9f456f06f2..25cf0a48e7 100644
--- a/usr/src/cmd/bhyve/pci_e82545.c
+++ b/usr/src/cmd/bhyve/pci_e82545.c
@@ -263,7 +263,7 @@ struct e82545_softc {
uint32_t esc_FCTTV; /* x0170 flow ctl tx timer */
uint32_t esc_LEDCTL; /* x0E00 LED control */
uint32_t esc_PBA; /* x1000 pkt buffer allocation */
-
+
/* Interrupt control */
int esc_irq_asserted;
uint32_t esc_ICR; /* x00C0 cause read/clear */
@@ -293,12 +293,12 @@ struct e82545_softc {
uint32_t esc_TIDV; /* x3820 intr delay */
uint32_t esc_TXDCTL; /* x3828 desc control */
uint32_t esc_TADV; /* x382C intr absolute delay */
-
+
/* L2 frame acceptance */
struct eth_uni esc_uni[16]; /* 16 x unicast MAC addresses */
uint32_t esc_fmcast[128]; /* Multicast filter bit-match */
uint32_t esc_fvlan[128]; /* VLAN 4096-bit filter */
-
+
/* Receive */
struct e1000_rx_desc *esc_rxdesc;
pthread_cond_t esc_rx_cond;
@@ -319,7 +319,7 @@ struct e82545_softc {
uint32_t esc_RADV; /* x282C intr absolute delay */
uint32_t esc_RSRPD; /* x2C00 recv small packet detect */
uint32_t esc_RXCSUM; /* x5000 receive cksum ctl */
-
+
/* IO Port register access */
uint32_t io_addr;
@@ -577,7 +577,7 @@ e82545_icr_assert(struct e82545_softc *sc, uint32_t bits)
uint32_t new;
DPRINTF("icr assert: 0x%x", bits);
-
+
/*
* An interrupt is only generated if bits are set that
* aren't already in the ICR, these bits are unmasked,
@@ -653,7 +653,7 @@ e82545_intr_write(struct e82545_softc *sc, uint32_t offset, uint32_t value)
{
DPRINTF("intr_write: off %x, val %x", offset, value);
-
+
switch (offset) {
case E1000_ICR:
e82545_icr_deassert(sc, value);
@@ -687,7 +687,7 @@ e82545_intr_read(struct e82545_softc *sc, uint32_t offset)
retval = 0;
DPRINTF("intr_read: off %x", offset);
-
+
switch (offset) {
case E1000_ICR:
retval = sc->esc_ICR;
@@ -733,10 +733,10 @@ e82545_rx_update_rdba(struct e82545_softc *sc)
/* XXX verify desc base/len within phys mem range */
sc->esc_rdba = (uint64_t)sc->esc_RDBAH << 32 |
sc->esc_RDBAL;
-
+
/* Cache host mapping of guest descriptor array */
sc->esc_rxdesc = paddr_guest2host(sc->esc_ctx,
- sc->esc_rdba, sc->esc_RDLEN);
+ sc->esc_rdba, sc->esc_RDLEN);
}
static void
@@ -791,7 +791,7 @@ static void
e82545_tx_ctl(struct e82545_softc *sc, uint32_t val)
{
int on;
-
+
on = ((val & E1000_TCTL_EN) == E1000_TCTL_EN);
/* ignore TCTL_EN settings that don't change state */
@@ -1031,7 +1031,7 @@ e82545_txdesc_type(uint32_t lower)
int type;
type = 0;
-
+
if (lower & E1000_TXD_CMD_DEXT)
type = lower & E1000_TXD_MASK;
@@ -1087,7 +1087,7 @@ e82545_transmit(struct e82545_softc *sc, uint16_t head, uint16_t tail,
struct ck_info ckinfo[2];
struct iovec *iov;
union e1000_tx_udesc *dsc;
- int desc, dtype, len, ntype, iovcnt, tlen, tcp, tso;
+ int desc, dtype, len, ntype, iovcnt, tcp, tso;
int mss, paylen, seg, tiovcnt, left, now, nleft, nnow, pv, pvoff;
unsigned hdrlen, vlen;
uint32_t tcpsum, tcpseq;
@@ -1095,7 +1095,6 @@ e82545_transmit(struct e82545_softc *sc, uint16_t head, uint16_t tail,
ckinfo[0].ck_valid = ckinfo[1].ck_valid = 0;
iovcnt = 0;
- tlen = 0;
ntype = 0;
tso = 0;
ohead = head;
@@ -1153,7 +1152,6 @@ e82545_transmit(struct e82545_softc *sc, uint16_t head, uint16_t tail,
if ((dsc->td.lower.data & E1000_TXD_CMD_EOP) != 0 &&
(dsc->td.lower.data & E1000_TXD_CMD_IFCS) == 0)
len -= 2;
- tlen += len;
if (iovcnt < I82545_MAX_TXSEGS) {
iov[iovcnt].iov_base = paddr_guest2host(
sc->esc_ctx, dsc->td.buffer_addr, len);
@@ -1608,14 +1606,14 @@ e82545_read_ra(struct e82545_softc *sc, int reg)
eu->eu_eth.octet[0];
}
- return (retval);
+ return (retval);
}
static void
e82545_write_register(struct e82545_softc *sc, uint32_t offset, uint32_t value)
{
int ridx;
-
+
if (offset & 0x3) {
DPRINTF("Unaligned register write offset:0x%x value:0x%x", offset, value);
return;
@@ -1761,7 +1759,7 @@ e82545_write_register(struct e82545_softc *sc, uint32_t offset, uint32_t value)
break;
case E1000_VFTA ... (E1000_VFTA + (127*4)):
sc->esc_fvlan[(offset - E1000_VFTA) >> 2] = value;
- break;
+ break;
case E1000_EECD:
{
//DPRINTF("EECD write 0x%x -> 0x%x", sc->eeprom_control, value);
@@ -1816,7 +1814,7 @@ e82545_write_register(struct e82545_softc *sc, uint32_t offset, uint32_t value)
return;
}
case E1000_MANC:
- case E1000_STATUS:
+ case E1000_STATUS:
return;
default:
DPRINTF("Unknown write register: 0x%x value:%x", offset, value);
@@ -1909,7 +1907,7 @@ e82545_read_register(struct e82545_softc *sc, uint32_t offset)
case E1000_RSRPD:
retval = sc->esc_RSRPD;
break;
- case E1000_RXCSUM:
+ case E1000_RXCSUM:
retval = sc->esc_RXCSUM;
break;
case E1000_TXCW:
@@ -1958,7 +1956,7 @@ e82545_read_register(struct e82545_softc *sc, uint32_t offset)
break;
case E1000_VFTA ... (E1000_VFTA + (127*4)):
retval = sc->esc_fvlan[(offset - E1000_VFTA) >> 2];
- break;
+ break;
case E1000_EECD:
//DPRINTF("EECD read %x", sc->eeprom_control);
retval = sc->eeprom_control;
@@ -2154,7 +2152,7 @@ e82545_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
{
struct e82545_softc *sc;
uint64_t retval;
-
+
//DPRINTF("Read bar:%d offset:0x%lx size:%d", baridx, offset, size);
sc = pi->pi_arg;
retval = 0;
@@ -2226,7 +2224,7 @@ e82545_reset(struct e82545_softc *sc, int drvr)
}
sc->esc_LEDCTL = 0x07061302;
sc->esc_PBA = 0x00100030;
-
+
/* start nvm in opcode mode. */
sc->nvm_opaddr = 0;
sc->nvm_mode = E82545_NVM_MODE_OPADDR;
@@ -2240,7 +2238,7 @@ e82545_reset(struct e82545_softc *sc, int drvr)
sc->esc_ICS = 0;
sc->esc_IMS = 0;
sc->esc_IMC = 0;
-
+
/* L2 filters */
if (!drvr) {
memset(sc->esc_fvlan, 0, sizeof(sc->esc_fvlan));
@@ -2256,7 +2254,7 @@ e82545_reset(struct e82545_softc *sc, int drvr)
for (i = 0; i < 16; i++)
sc->esc_uni[i].eu_valid = 0;
}
-
+
/* receive */
if (!drvr) {
sc->esc_RDBAL = 0;
@@ -2324,7 +2322,7 @@ e82545_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
pci_set_cfgdata8(pi, PCIR_HDRTYPE, PCIM_HDRTYPE_NORMAL);
pci_set_cfgdata8(pi, PCIR_INTPIN, 0x1);
-
+
/* TODO: this card also supports msi, but the freebsd driver for it
* does not, so I have not implemented it. */
pci_lintr_request(pi);
diff --git a/usr/src/cmd/bhyve/pci_emul.c b/usr/src/cmd/bhyve/pci_emul.c
index ce218b8185..3cbf01158a 100644
--- a/usr/src/cmd/bhyve/pci_emul.c
+++ b/usr/src/cmd/bhyve/pci_emul.c
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <sys/linker_set.h>
#include <ctype.h>
+#include <err.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
@@ -56,6 +57,7 @@ __FBSDID("$FreeBSD$");
#include <strings.h>
#include <assert.h>
#include <stdbool.h>
+#include <sysexits.h>
#include <machine/vmm.h>
#include <vmmapi.h>
@@ -80,6 +82,8 @@ __FBSDID("$FreeBSD$");
#define MAXSLOTS (PCI_SLOTMAX + 1)
#define MAXFUNCS (PCI_FUNCMAX + 1)
+#define GB (1024 * 1024 * 1024UL)
+
struct funcinfo {
nvlist_t *fi_config;
struct pci_devemu *fi_pde;
@@ -111,6 +115,17 @@ SET_DECLARE(pci_devemu_set, struct pci_devemu);
static uint64_t pci_emul_iobase;
static uint64_t pci_emul_membase32;
static uint64_t pci_emul_membase64;
+static uint64_t pci_emul_memlim64;
+
+struct pci_bar_allocation {
+ TAILQ_ENTRY(pci_bar_allocation) chain;
+ struct pci_devinst *pdi;
+ int idx;
+ enum pcibar_type type;
+ uint64_t size;
+};
+TAILQ_HEAD(pci_bar_list, pci_bar_allocation) pci_bars = TAILQ_HEAD_INITIALIZER(
+ pci_bars);
#define PCI_EMUL_IOBASE 0x2000
#define PCI_EMUL_IOLIMIT 0x10000
@@ -119,10 +134,13 @@ static uint64_t pci_emul_membase64;
#define PCI_EMUL_ECFG_SIZE (MAXBUSES * 1024 * 1024) /* 1MB per bus */
SYSRES_MEM(PCI_EMUL_ECFG_BASE, PCI_EMUL_ECFG_SIZE);
+/*
+ * OVMF always uses 0xC0000000 as base address for 32 bit PCI MMIO. Don't
+ * change this address without changing it in OVMF.
+ */
+#define PCI_EMUL_MEMBASE32 0xC0000000
#define PCI_EMUL_MEMLIMIT32 PCI_EMUL_ECFG_BASE
-
-#define PCI_EMUL_MEMBASE64 0xD000000000UL
-#define PCI_EMUL_MEMLIMIT64 0xFD00000000UL
+#define PCI_EMUL_MEMSIZE64 (32*GB)
static struct pci_devemu *pci_emul_finddev(const char *name);
static void pci_lintr_route(struct pci_devinst *pi);
@@ -643,12 +661,6 @@ int
pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type,
uint64_t size)
{
- uint64_t *baseptr = NULL;
- uint64_t limit = 0, lobits = 0;
- uint64_t addr, mask, bar;
- uint16_t cmd, enbit;
- int error;
-
assert(idx >= 0 && idx <= PCI_BARMAX);
if ((size & (size - 1)) != 0)
@@ -663,17 +675,88 @@ pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type,
size = 16;
}
+ /*
+ * To reduce fragmentation of the MMIO space, we allocate the BARs by
+ * size. Therefore, don't allocate the BAR yet. We create a list of all
+ * BAR allocation which is sorted by BAR size. When all PCI devices are
+ * initialized, we will assign an address to the BARs.
+ */
+
+ /* create a new list entry */
+ struct pci_bar_allocation *const new_bar = malloc(sizeof(*new_bar));
+ memset(new_bar, 0, sizeof(*new_bar));
+ new_bar->pdi = pdi;
+ new_bar->idx = idx;
+ new_bar->type = type;
+ new_bar->size = size;
+
+ /*
+ * Search for a BAR which size is lower than the size of our newly
+ * allocated BAR.
+ */
+ struct pci_bar_allocation *bar = NULL;
+ TAILQ_FOREACH(bar, &pci_bars, chain) {
+ if (bar->size < size) {
+ break;
+ }
+ }
+
+ if (bar == NULL) {
+ /*
+ * Either the list is empty or new BAR is the smallest BAR of
+ * the list. Append it to the end of our list.
+ */
+ TAILQ_INSERT_TAIL(&pci_bars, new_bar, chain);
+ } else {
+ /*
+ * The found BAR is smaller than our new BAR. For that reason,
+ * insert our new BAR before the found BAR.
+ */
+ TAILQ_INSERT_BEFORE(bar, new_bar, chain);
+ }
+
+ /*
+ * pci_passthru devices synchronize their physical and virtual command
+ * register on init. For that reason, the virtual cmd reg should be
+ * updated as early as possible.
+ */
+ uint16_t enbit = 0;
+ switch (type) {
+ case PCIBAR_IO:
+ enbit = PCIM_CMD_PORTEN;
+ break;
+ case PCIBAR_MEM64:
+ case PCIBAR_MEM32:
+ enbit = PCIM_CMD_MEMEN;
+ break;
+ default:
+ enbit = 0;
+ break;
+ }
+
+ const uint16_t cmd = pci_get_cfgdata16(pdi, PCIR_COMMAND);
+ pci_set_cfgdata16(pdi, PCIR_COMMAND, cmd | enbit);
+
+ return (0);
+}
+
+static int
+pci_emul_assign_bar(struct pci_devinst *const pdi, const int idx,
+ const enum pcibar_type type, const uint64_t size)
+{
+ int error;
+ uint64_t *baseptr, limit, addr, mask, lobits, bar;
+
switch (type) {
case PCIBAR_NONE:
baseptr = NULL;
- addr = mask = lobits = enbit = 0;
+ addr = mask = lobits = 0;
break;
case PCIBAR_IO:
baseptr = &pci_emul_iobase;
limit = PCI_EMUL_IOLIMIT;
mask = PCIM_BAR_IO_BASE;
lobits = PCIM_BAR_IO_SPACE;
- enbit = PCIM_CMD_PORTEN;
break;
case PCIBAR_MEM64:
/*
@@ -685,7 +768,7 @@ pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type,
*/
if (size > 128 * 1024 * 1024) {
baseptr = &pci_emul_membase64;
- limit = PCI_EMUL_MEMLIMIT64;
+ limit = pci_emul_memlim64;
mask = PCIM_BAR_MEM_BASE;
lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 |
PCIM_BAR_MEM_PREFETCH;
@@ -695,14 +778,12 @@ pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type,
mask = PCIM_BAR_MEM_BASE;
lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64;
}
- enbit = PCIM_CMD_MEMEN;
break;
case PCIBAR_MEM32:
baseptr = &pci_emul_membase32;
limit = PCI_EMUL_MEMLIMIT32;
mask = PCIM_BAR_MEM_BASE;
lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32;
- enbit = PCIM_CMD_MEMEN;
break;
default:
printf("pci_emul_alloc_base: invalid bar type %d\n", type);
@@ -722,6 +803,15 @@ pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type,
pdi->pi_bar[idx].type = type;
pdi->pi_bar[idx].addr = addr;
pdi->pi_bar[idx].size = size;
+ /*
+ * passthru devices are using same lobits as physical device they set
+ * this property
+ */
+ if (pdi->pi_bar[idx].lobits != 0) {
+ lobits = pdi->pi_bar[idx].lobits;
+ } else {
+ pdi->pi_bar[idx].lobits = lobits;
+ }
/* Initialize the BAR register in config space */
bar = (addr & mask) | lobits;
@@ -733,9 +823,6 @@ pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type,
pci_set_cfgdata32(pdi, PCIR_BAR(idx + 1), bar >> 32);
}
- cmd = pci_get_cfgdata16(pdi, PCIR_COMMAND);
- if ((cmd & enbit) != enbit)
- pci_set_cfgdata16(pdi, PCIR_COMMAND, cmd | enbit);
register_bar(pdi, idx);
return (0);
@@ -1147,7 +1234,8 @@ pci_ecfg_base(void)
}
#define BUSIO_ROUNDUP 32
-#define BUSMEM_ROUNDUP (1024 * 1024)
+#define BUSMEM32_ROUNDUP (1024 * 1024)
+#define BUSMEM64_ROUNDUP (512 * 1024 * 1024)
int
init_pci(struct vmctx *ctx)
@@ -1164,9 +1252,15 @@ init_pci(struct vmctx *ctx)
int bus, slot, func;
int error;
+ if (vm_get_lowmem_limit(ctx) > PCI_EMUL_MEMBASE32)
+ errx(EX_OSERR, "Invalid lowmem limit");
+
pci_emul_iobase = PCI_EMUL_IOBASE;
- pci_emul_membase32 = vm_get_lowmem_limit(ctx);
- pci_emul_membase64 = PCI_EMUL_MEMBASE64;
+ pci_emul_membase32 = PCI_EMUL_MEMBASE32;
+
+ pci_emul_membase64 = 4*GB + vm_get_highmem_size(ctx);
+ pci_emul_membase64 = roundup2(pci_emul_membase64, PCI_EMUL_MEMSIZE64);
+ pci_emul_memlim64 = pci_emul_membase64 + PCI_EMUL_MEMSIZE64;
for (bus = 0; bus < MAXBUSES; bus++) {
snprintf(node_name, sizeof(node_name), "pci.%d", bus);
@@ -1184,6 +1278,7 @@ init_pci(struct vmctx *ctx)
bi->membase32 = pci_emul_membase32;
bi->membase64 = pci_emul_membase64;
+ /* first run: init devices */
for (slot = 0; slot < MAXSLOTS; slot++) {
si = &bi->slotinfo[slot];
for (func = 0; func < MAXFUNCS; func++) {
@@ -1223,6 +1318,16 @@ init_pci(struct vmctx *ctx)
}
}
+ /* second run: assign BARs and free list */
+ struct pci_bar_allocation *bar;
+ struct pci_bar_allocation *bar_tmp;
+ TAILQ_FOREACH_SAFE(bar, &pci_bars, chain, bar_tmp) {
+ pci_emul_assign_bar(bar->pdi, bar->idx, bar->type,
+ bar->size);
+ free(bar);
+ }
+ TAILQ_INIT(&pci_bars);
+
/*
* Add some slop to the I/O and memory resources decoded by
* this bus to give a guest some flexibility if it wants to
@@ -1232,14 +1337,14 @@ init_pci(struct vmctx *ctx)
pci_emul_iobase = roundup2(pci_emul_iobase, BUSIO_ROUNDUP);
bi->iolimit = pci_emul_iobase;
- pci_emul_membase32 += BUSMEM_ROUNDUP;
+ pci_emul_membase32 += BUSMEM32_ROUNDUP;
pci_emul_membase32 = roundup2(pci_emul_membase32,
- BUSMEM_ROUNDUP);
+ BUSMEM32_ROUNDUP);
bi->memlimit32 = pci_emul_membase32;
- pci_emul_membase64 += BUSMEM_ROUNDUP;
+ pci_emul_membase64 += BUSMEM64_ROUNDUP;
pci_emul_membase64 = roundup2(pci_emul_membase64,
- BUSMEM_ROUNDUP);
+ BUSMEM64_ROUNDUP);
bi->memlimit64 = pci_emul_membase64;
}
@@ -1267,8 +1372,8 @@ init_pci(struct vmctx *ctx)
/*
* The guest physical memory map looks like the following:
* [0, lowmem) guest system memory
- * [lowmem, lowmem_limit) memory hole (may be absent)
- * [lowmem_limit, 0xE0000000) PCI hole (32-bit BAR allocation)
+ * [lowmem, 0xC0000000) memory hole (may be absent)
+ * [0xC0000000, 0xE0000000) PCI hole (32-bit BAR allocation)
* [0xE0000000, 0xF0000000) PCI extended config window
* [0xF0000000, 4GB) LAPIC, IOAPIC, HPET, firmware
* [4GB, 4GB + highmem)
@@ -1954,7 +2059,7 @@ pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, int func,
case PCIBAR_IO:
addr = *eax & mask;
addr &= 0xffff;
- bar = addr | PCIM_BAR_IO_SPACE;
+ bar = addr | pi->pi_bar[idx].lobits;
/*
* Register the new BAR value for interception
*/
@@ -1965,7 +2070,7 @@ pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, int func,
break;
case PCIBAR_MEM32:
addr = bar = *eax & mask;
- bar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32;
+ bar |= pi->pi_bar[idx].lobits;
if (addr != pi->pi_bar[idx].addr) {
update_bar_address(pi, addr, idx,
PCIBAR_MEM32);
@@ -1973,8 +2078,7 @@ pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, int func,
break;
case PCIBAR_MEM64:
addr = bar = *eax & mask;
- bar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 |
- PCIM_BAR_MEM_PREFETCH;
+ bar |= pi->pi_bar[idx].lobits;
if (addr != (uint32_t)pi->pi_bar[idx].addr) {
update_bar_address(pi, addr, idx,
PCIBAR_MEM64);
@@ -2026,7 +2130,7 @@ pci_emul_cfgaddr(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
} else {
x = *eax;
cfgenable = (x & CONF1_ENABLE) == CONF1_ENABLE;
- cfgoff = x & PCI_REGMAX;
+ cfgoff = (x & PCI_REGMAX) & ~0x03;
cfgfunc = (x >> 8) & PCI_FUNCMAX;
cfgslot = (x >> 11) & PCI_SLOTMAX;
cfgbus = (x >> 16) & PCI_BUSMAX;
diff --git a/usr/src/cmd/bhyve/pci_emul.h b/usr/src/cmd/bhyve/pci_emul.h
index cc3a8c048c..d01d2a7596 100644
--- a/usr/src/cmd/bhyve/pci_emul.h
+++ b/usr/src/cmd/bhyve/pci_emul.h
@@ -99,6 +99,7 @@ struct pcibar {
enum pcibar_type type; /* io or memory */
uint64_t size;
uint64_t addr;
+ uint8_t lobits;
};
#define PI_NAMESZ 40
@@ -109,7 +110,7 @@ struct msix_table_entry {
uint32_t vector_control;
} __packed;
-/*
+/*
* In case the structure is modified to hold extra information, use a define
* for the size that should be emulated.
*/
@@ -155,10 +156,12 @@ struct pci_devinst {
int table_count;
uint32_t pba_offset;
int pba_size;
- int function_mask;
+ int function_mask;
struct msix_table_entry *table; /* allocated at runtime */
void *pba_page;
int pba_page_offset;
+ uint8_t *mapped_addr;
+ size_t mapped_size;
} pi_msix;
void *pi_arg; /* devemu-private data */
@@ -257,21 +260,21 @@ void pci_write_dsdt(void);
uint64_t pci_ecfg_base(void);
int pci_bus_configured(int bus);
-static __inline void
+static __inline void
pci_set_cfgdata8(struct pci_devinst *pi, int offset, uint8_t val)
{
assert(offset <= PCI_REGMAX);
*(uint8_t *)(pi->pi_cfgdata + offset) = val;
}
-static __inline void
+static __inline void
pci_set_cfgdata16(struct pci_devinst *pi, int offset, uint16_t val)
{
assert(offset <= (PCI_REGMAX - 1) && (offset & 1) == 0);
*(uint16_t *)(pi->pi_cfgdata + offset) = val;
}
-static __inline void
+static __inline void
pci_set_cfgdata32(struct pci_devinst *pi, int offset, uint32_t val)
{
assert(offset <= (PCI_REGMAX - 3) && (offset & 3) == 0);
diff --git a/usr/src/cmd/bhyve/pci_fbuf.c b/usr/src/cmd/bhyve/pci_fbuf.c
index 76041f8667..fad064ebf8 100644
--- a/usr/src/cmd/bhyve/pci_fbuf.c
+++ b/usr/src/cmd/bhyve/pci_fbuf.c
@@ -231,11 +231,11 @@ pci_fbuf_baraddr(struct vmctx *ctx, struct pci_devinst *pi, int baridx,
return;
sc = pi->pi_arg;
- if (!enabled && sc->fbaddr != 0) {
+ if (!enabled) {
if (vm_munmap_memseg(ctx, sc->fbaddr, FB_SIZE) != 0)
EPRINTLN("pci_fbuf: munmap_memseg failed");
sc->fbaddr = 0;
- } else if (sc->fb_base != NULL && sc->fbaddr == 0) {
+ } else {
prot = PROT_READ | PROT_WRITE;
if (vm_mmap_memseg(ctx, address, VM_FRAMEBUFFER, 0, FB_SIZE, prot) != 0)
EPRINTLN("pci_fbuf: mmap_memseg failed");
@@ -383,9 +383,9 @@ pci_fbuf_render(struct bhyvegc *gc, void *arg)
static int
pci_fbuf_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
{
- int error, prot;
+ int error;
struct pci_fbuf_softc *sc;
-
+
if (fbuf_sc != NULL) {
EPRINTLN("Only one frame buffer device is allowed.");
return (-1);
@@ -401,6 +401,13 @@ pci_fbuf_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_DISPLAY);
pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_DISPLAY_VGA);
+ sc->fb_base = vm_create_devmem(
+ ctx, VM_FRAMEBUFFER, "framebuffer", FB_SIZE);
+ if (sc->fb_base == MAP_FAILED) {
+ error = -1;
+ goto done;
+ }
+
error = pci_emul_alloc_bar(pi, 0, PCIBAR_MEM32, DMEMSZ);
assert(error == 0);
@@ -410,7 +417,6 @@ pci_fbuf_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
error = pci_emul_add_msicap(pi, PCI_FBUF_MSI_MSGS);
assert(error == 0);
- sc->fbaddr = pi->pi_bar[1].addr;
sc->memregs.fbsize = FB_SIZE;
sc->memregs.width = COLS_DEFAULT;
sc->memregs.height = ROWS_DEFAULT;
@@ -431,27 +437,9 @@ pci_fbuf_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
goto done;
}
- sc->fb_base = vm_create_devmem(ctx, VM_FRAMEBUFFER, "framebuffer", FB_SIZE);
- if (sc->fb_base == MAP_FAILED) {
- error = -1;
- goto done;
- }
DPRINTF(DEBUG_INFO, ("fbuf frame buffer base: %p [sz %lu]",
sc->fb_base, FB_SIZE));
- /*
- * Map the framebuffer into the guest address space.
- * XXX This may fail if the BAR is different than a prior
- * run. In this case flag the error. This will be fixed
- * when a change_memseg api is available.
- */
- prot = PROT_READ | PROT_WRITE;
- if (vm_mmap_memseg(ctx, sc->fbaddr, VM_FRAMEBUFFER, 0, FB_SIZE, prot) != 0) {
- EPRINTLN("pci_fbuf: mapseg failed - try deleting VM and restarting");
- error = -1;
- goto done;
- }
-
console_init(sc->memregs.width, sc->memregs.height, sc->fb_base);
console_fb_register(pci_fbuf_render, sc);
diff --git a/usr/src/cmd/bhyve/pci_hda.h b/usr/src/cmd/bhyve/pci_hda.h
index 65a85f6d60..a34366dedc 100644
--- a/usr/src/cmd/bhyve/pci_hda.h
+++ b/usr/src/cmd/bhyve/pci_hda.h
@@ -28,7 +28,7 @@
* $FreeBSD$
*/
-#ifndef _HDA_EMUL_H_
+#ifndef _HDA_EMUL_H_
#define _HDA_EMUL_H_
#include <stdio.h>
diff --git a/usr/src/cmd/bhyve/pci_lpc.c b/usr/src/cmd/bhyve/pci_lpc.c
index 2387f382c5..189623b5fc 100644
--- a/usr/src/cmd/bhyve/pci_lpc.c
+++ b/usr/src/cmd/bhyve/pci_lpc.c
@@ -164,7 +164,7 @@ lpc_uart_intr_assert(void *arg)
static void
lpc_uart_intr_deassert(void *arg)
{
- /*
+ /*
* The COM devices on the LPC bus generate edge triggered interrupts,
* so nothing more to do here.
*/
diff --git a/usr/src/cmd/bhyve/pci_nvme.c b/usr/src/cmd/bhyve/pci_nvme.c
index 49fbf54b70..73e8ab0371 100644
--- a/usr/src/cmd/bhyve/pci_nvme.c
+++ b/usr/src/cmd/bhyve/pci_nvme.c
@@ -5,7 +5,7 @@
* Copyright (c) 2018 Leon Dang
* Copyright (c) 2020 Chuck Tuffli
*
- * Function crc16 Copyright (c) 2017, Fedor Uporov
+ * Function crc16 Copyright (c) 2017, Fedor Uporov
* Obtained from function ext2_crc16() in sys/fs/ext2fs/ext2_csum.c
*
* Redistribution and use in source and binary forms, with or without
@@ -68,6 +68,7 @@ __FBSDID("$FreeBSD$");
#include <assert.h>
#include <pthread.h>
+#include <pthread_np.h>
#include <semaphore.h>
#include <stdbool.h>
#include <stddef.h>
@@ -253,11 +254,39 @@ struct nvme_feature_obj {
#define NVME_FID_MAX (NVME_FEAT_ENDURANCE_GROUP_EVENT_CONFIGURATION + 1)
+typedef enum {
+ PCI_NVME_AE_TYPE_ERROR = 0,
+ PCI_NVME_AE_TYPE_SMART,
+ PCI_NVME_AE_TYPE_NOTICE,
+ PCI_NVME_AE_TYPE_IO_CMD = 6,
+ PCI_NVME_AE_TYPE_VENDOR = 7,
+ PCI_NVME_AE_TYPE_MAX /* Must be last */
+} pci_nvme_async_type;
+
+/* Asynchronous Event Requests */
struct pci_nvme_aer {
STAILQ_ENTRY(pci_nvme_aer) link;
uint16_t cid; /* Command ID of the submitted AER */
};
+typedef enum {
+ PCI_NVME_AE_INFO_NS_ATTR_CHANGED = 0,
+ PCI_NVME_AE_INFO_FW_ACTIVATION,
+ PCI_NVME_AE_INFO_TELEMETRY_CHANGE,
+ PCI_NVME_AE_INFO_ANA_CHANGE,
+ PCI_NVME_AE_INFO_PREDICT_LATENCY_CHANGE,
+ PCI_NVME_AE_INFO_LBA_STATUS_ALERT,
+ PCI_NVME_AE_INFO_ENDURANCE_GROUP_CHANGE,
+ PCI_NVME_AE_INFO_MAX,
+} pci_nvme_async_info;
+
+/* Asynchronous Event Notifications */
+struct pci_nvme_aen {
+ pci_nvme_async_type atype;
+ uint32_t event_data;
+ bool posted;
+};
+
struct pci_nvme_softc {
struct pci_devinst *nsc_pi;
@@ -270,6 +299,7 @@ struct pci_nvme_softc {
struct nvme_error_information_entry err_log;
struct nvme_health_information_page health_log;
struct nvme_firmware_page fw_log;
+ struct nvme_ns_list ns_log;
struct pci_nvme_blockstore nvstore;
@@ -305,10 +335,21 @@ struct pci_nvme_softc {
uint32_t write_dunits_remainder;
STAILQ_HEAD(, pci_nvme_aer) aer_list;
+ pthread_mutex_t aer_mtx;
uint32_t aer_count;
+ struct pci_nvme_aen aen[PCI_NVME_AE_TYPE_MAX];
+ pthread_t aen_tid;
+ pthread_mutex_t aen_mtx;
+ pthread_cond_t aen_cond;
};
+static void pci_nvme_cq_update(struct pci_nvme_softc *sc,
+ struct nvme_completion_queue *cq,
+ uint32_t cdw0,
+ uint16_t cid,
+ uint16_t sqid,
+ uint16_t status);
static struct pci_nvme_ioreq *pci_nvme_get_ioreq(struct pci_nvme_softc *);
static void pci_nvme_release_ioreq(struct pci_nvme_softc *, struct pci_nvme_ioreq *);
static void pci_nvme_io_done(struct blockif_req *, int);
@@ -363,6 +404,8 @@ static void nvme_feature_iv_config(struct pci_nvme_softc *,
struct nvme_command *,
struct nvme_completion *);
+static void *aen_thr(void *arg);
+
static __inline void
cpywithpad(char *dst, size_t dst_size, const char *src, char pad)
{
@@ -471,6 +514,18 @@ pci_nvme_init_ctrldata(struct pci_nvme_softc *sc)
cd->ver = 0x00010300;
cd->oacs = 1 << NVME_CTRLR_DATA_OACS_FORMAT_SHIFT;
+#ifndef __FreeBSD__
+ /*
+ * Reported upstream against https://reviews.freebsd.org/D32953
+ * which introduced support for the namespace attribute changed AEN
+ * and the corresponding changed namespace log page, without setting
+ * the bit in oaes. A future sync will likely include this
+ * definition in usr/src/contrib/bhyve/dev/nvme/nvme.h once it's
+ * fixed there.
+ */
+#define NVME_CTRLR_DATA_OAES_NSCHANGE_SHIFT (8)
+ cd->oaes = 1 << NVME_CTRLR_DATA_OAES_NSCHANGE_SHIFT;
+#endif
cd->acl = 2;
cd->aerl = 4;
@@ -559,15 +614,23 @@ crc16(uint16_t crc, const void *buffer, unsigned int len)
}
static void
-pci_nvme_init_nsdata(struct pci_nvme_softc *sc,
- struct nvme_namespace_data *nd, uint32_t nsid,
- struct pci_nvme_blockstore *nvstore)
+pci_nvme_init_nsdata_size(struct pci_nvme_blockstore *nvstore,
+ struct nvme_namespace_data *nd)
{
/* Get capacity and block size information from backing store */
nd->nsze = nvstore->size / nvstore->sectsz;
nd->ncap = nd->nsze;
nd->nuse = nd->nsze;
+}
+
+static void
+pci_nvme_init_nsdata(struct pci_nvme_softc *sc,
+ struct nvme_namespace_data *nd, uint32_t nsid,
+ struct pci_nvme_blockstore *nvstore)
+{
+
+ pci_nvme_init_nsdata_size(nvstore, nd);
if (nvstore->type == NVME_STOR_BLOCKIF)
nvstore->deallocate = blockif_candelete(nvstore->ctx);
@@ -603,6 +666,7 @@ pci_nvme_init_logpages(struct pci_nvme_softc *sc)
memset(&sc->err_log, 0, sizeof(sc->err_log));
memset(&sc->health_log, 0, sizeof(sc->health_log));
memset(&sc->fw_log, 0, sizeof(sc->fw_log));
+ memset(&sc->ns_log, 0, sizeof(sc->ns_log));
/* Set read/write remainder to round up according to spec */
sc->read_dunits_remainder = 999;
@@ -626,6 +690,8 @@ pci_nvme_init_features(struct pci_nvme_softc *sc)
sc->feat[NVME_FEAT_NUMBER_OF_QUEUES].set = nvme_feature_num_queues;
sc->feat[NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION].set =
nvme_feature_iv_config;
+ /* Enable all AENs by default */
+ sc->feat[NVME_FEAT_ASYNC_EVENT_CONFIGURATION].cdw11 = 0x31f;
sc->feat[NVME_FEAT_PREDICTABLE_LATENCY_MODE_CONFIG].get =
nvme_feature_invalid_cb;
sc->feat[NVME_FEAT_PREDICTABLE_LATENCY_MODE_WINDOW].get =
@@ -633,7 +699,7 @@ pci_nvme_init_features(struct pci_nvme_softc *sc)
}
static void
-pci_nvme_aer_init(struct pci_nvme_softc *sc)
+pci_nvme_aer_reset(struct pci_nvme_softc *sc)
{
STAILQ_INIT(&sc->aer_list);
@@ -641,29 +707,35 @@ pci_nvme_aer_init(struct pci_nvme_softc *sc)
}
static void
+pci_nvme_aer_init(struct pci_nvme_softc *sc)
+{
+
+ pthread_mutex_init(&sc->aer_mtx, NULL);
+ pci_nvme_aer_reset(sc);
+}
+
+static void
pci_nvme_aer_destroy(struct pci_nvme_softc *sc)
{
struct pci_nvme_aer *aer = NULL;
+ pthread_mutex_lock(&sc->aer_mtx);
while (!STAILQ_EMPTY(&sc->aer_list)) {
aer = STAILQ_FIRST(&sc->aer_list);
STAILQ_REMOVE_HEAD(&sc->aer_list, link);
free(aer);
}
+ pthread_mutex_unlock(&sc->aer_mtx);
- pci_nvme_aer_init(sc);
+ pci_nvme_aer_reset(sc);
}
-#ifdef __FreeBSD__
static bool
pci_nvme_aer_available(struct pci_nvme_softc *sc)
{
- return (!STAILQ_EMPTY(&sc->aer_list));
+ return (sc->aer_count != 0);
}
-#else
-/* This is kept behind an ifdef while it's unused to appease the compiler. */
-#endif
static bool
pci_nvme_aer_limit_reached(struct pci_nvme_softc *sc)
@@ -694,11 +766,13 @@ pci_nvme_aer_add(struct pci_nvme_softc *sc, uint16_t cid)
if (aer == NULL)
return (-1);
- sc->aer_count++;
-
/* Save the Command ID for use in the completion message */
aer->cid = cid;
+
+ pthread_mutex_lock(&sc->aer_mtx);
+ sc->aer_count++;
STAILQ_INSERT_TAIL(&sc->aer_list, aer, link);
+ pthread_mutex_unlock(&sc->aer_mtx);
return (0);
}
@@ -709,24 +783,219 @@ pci_nvme_aer_add(struct pci_nvme_softc *sc, uint16_t cid)
* Returns a pointer to an AER previously submitted by the host or NULL if
* no AER's exist. Caller is responsible for freeing the returned struct.
*/
-#ifdef __FreeBSD__
static struct pci_nvme_aer *
pci_nvme_aer_get(struct pci_nvme_softc *sc)
{
struct pci_nvme_aer *aer = NULL;
+ pthread_mutex_lock(&sc->aer_mtx);
aer = STAILQ_FIRST(&sc->aer_list);
if (aer != NULL) {
STAILQ_REMOVE_HEAD(&sc->aer_list, link);
sc->aer_count--;
}
-
+ pthread_mutex_unlock(&sc->aer_mtx);
+
return (aer);
}
-#else
-/* This is kept behind an ifdef while it's unused to appease the compiler. */
+
+static void
+pci_nvme_aen_reset(struct pci_nvme_softc *sc)
+{
+ uint32_t atype;
+
+ memset(sc->aen, 0, PCI_NVME_AE_TYPE_MAX * sizeof(struct pci_nvme_aen));
+
+ for (atype = 0; atype < PCI_NVME_AE_TYPE_MAX; atype++) {
+ sc->aen[atype].atype = atype;
+ }
+}
+
+static void
+pci_nvme_aen_init(struct pci_nvme_softc *sc)
+{
+ char nstr[80];
+
+ pci_nvme_aen_reset(sc);
+
+ pthread_mutex_init(&sc->aen_mtx, NULL);
+ pthread_create(&sc->aen_tid, NULL, aen_thr, sc);
+ snprintf(nstr, sizeof(nstr), "nvme-aen-%d:%d", sc->nsc_pi->pi_slot,
+ sc->nsc_pi->pi_func);
+ pthread_set_name_np(sc->aen_tid, nstr);
+}
+
+static void
+pci_nvme_aen_destroy(struct pci_nvme_softc *sc)
+{
+
+ pci_nvme_aen_reset(sc);
+}
+
+/* Notify the AEN thread of pending work */
+static void
+pci_nvme_aen_notify(struct pci_nvme_softc *sc)
+{
+
+ pthread_cond_signal(&sc->aen_cond);
+}
+
+/*
+ * Post an Asynchronous Event Notification
+ */
+static int32_t
+pci_nvme_aen_post(struct pci_nvme_softc *sc, pci_nvme_async_type atype,
+ uint32_t event_data)
+{
+ struct pci_nvme_aen *aen;
+
+ if (atype >= PCI_NVME_AE_TYPE_MAX) {
+ return(EINVAL);
+ }
+
+ pthread_mutex_lock(&sc->aen_mtx);
+ aen = &sc->aen[atype];
+
+ /* Has the controller already posted an event of this type? */
+ if (aen->posted) {
+ pthread_mutex_unlock(&sc->aen_mtx);
+ return(EALREADY);
+ }
+
+ aen->event_data = event_data;
+ aen->posted = true;
+ pthread_mutex_unlock(&sc->aen_mtx);
+
+ pci_nvme_aen_notify(sc);
+
+ return(0);
+}
+
+static void
+pci_nvme_aen_process(struct pci_nvme_softc *sc)
+{
+ struct pci_nvme_aer *aer;
+ struct pci_nvme_aen *aen;
+ pci_nvme_async_type atype;
+ uint32_t mask;
+ uint16_t status;
+ uint8_t lid;
+
+#ifndef __FreeBSD__
+ lid = 0;
#endif
+ assert(pthread_mutex_isowned_np(&sc->aen_mtx));
+ for (atype = 0; atype < PCI_NVME_AE_TYPE_MAX; atype++) {
+ aen = &sc->aen[atype];
+ /* Previous iterations may have depleted the available AER's */
+ if (!pci_nvme_aer_available(sc)) {
+ DPRINTF("%s: no AER", __func__);
+ break;
+ }
+
+ if (!aen->posted) {
+ DPRINTF("%s: no AEN posted for atype=%#x", __func__, atype);
+ continue;
+ }
+
+ status = NVME_SC_SUCCESS;
+
+ /* Is the event masked? */
+ mask =
+ sc->feat[NVME_FEAT_ASYNC_EVENT_CONFIGURATION].cdw11;
+
+ DPRINTF("%s: atype=%#x mask=%#x event_data=%#x", __func__, atype, mask, aen->event_data);
+ switch (atype) {
+ case PCI_NVME_AE_TYPE_ERROR:
+ lid = NVME_LOG_ERROR;
+ break;
+ case PCI_NVME_AE_TYPE_SMART:
+ mask &= 0xff;
+ if ((mask & aen->event_data) == 0)
+ continue;
+ lid = NVME_LOG_HEALTH_INFORMATION;
+ break;
+ case PCI_NVME_AE_TYPE_NOTICE:
+ if (aen->event_data >= PCI_NVME_AE_INFO_MAX) {
+ EPRINTLN("%s unknown AEN notice type %u",
+ __func__, aen->event_data);
+ status = NVME_SC_INTERNAL_DEVICE_ERROR;
+ break;
+ }
+ mask >>= 8;
+ if (((1 << aen->event_data) & mask) == 0)
+ continue;
+ switch (aen->event_data) {
+ case PCI_NVME_AE_INFO_NS_ATTR_CHANGED:
+ lid = NVME_LOG_CHANGED_NAMESPACE;
+ break;
+ case PCI_NVME_AE_INFO_FW_ACTIVATION:
+ lid = NVME_LOG_FIRMWARE_SLOT;
+ break;
+ case PCI_NVME_AE_INFO_TELEMETRY_CHANGE:
+ lid = NVME_LOG_TELEMETRY_CONTROLLER_INITIATED;
+ break;
+ case PCI_NVME_AE_INFO_ANA_CHANGE:
+ lid = NVME_LOG_ASYMMETRIC_NAMESPAVE_ACCESS; //TODO spelling
+ break;
+ case PCI_NVME_AE_INFO_PREDICT_LATENCY_CHANGE:
+ lid = NVME_LOG_PREDICTABLE_LATENCY_EVENT_AGGREGATE;
+ break;
+ case PCI_NVME_AE_INFO_LBA_STATUS_ALERT:
+ lid = NVME_LOG_LBA_STATUS_INFORMATION;
+ break;
+ case PCI_NVME_AE_INFO_ENDURANCE_GROUP_CHANGE:
+ lid = NVME_LOG_ENDURANCE_GROUP_EVENT_AGGREGATE;
+ break;
+ default:
+ lid = 0;
+ }
+ break;
+ default:
+ /* bad type?!? */
+ EPRINTLN("%s unknown AEN type %u", __func__, atype);
+ status = NVME_SC_INTERNAL_DEVICE_ERROR;
+ break;
+ }
+
+ aer = pci_nvme_aer_get(sc);
+ assert(aer != NULL);
+
+ DPRINTF("%s: CID=%#x CDW0=%#x", __func__, aer->cid, (lid << 16) | (aen->event_data << 8) | atype);
+ pci_nvme_cq_update(sc, &sc->compl_queues[0],
+ (lid << 16) | (aen->event_data << 8) | atype, /* cdw0 */
+ aer->cid,
+ 0, /* SQID */
+ status);
+
+ aen->event_data = 0;
+ aen->posted = false;
+
+ pci_generate_msix(sc->nsc_pi, 0);
+ }
+}
+
+static void *
+aen_thr(void *arg)
+{
+ struct pci_nvme_softc *sc;
+
+ sc = arg;
+
+ pthread_mutex_lock(&sc->aen_mtx);
+ for (;;) {
+ pci_nvme_aen_process(sc);
+ pthread_cond_wait(&sc->aen_cond, &sc->aen_mtx);
+ }
+#ifdef __FreeBSD__
+ pthread_mutex_unlock(&sc->aen_mtx);
+
+ pthread_exit(NULL);
+#endif
+ return (NULL);
+}
+
static void
pci_nvme_reset_locked(struct pci_nvme_softc *sc)
{
@@ -767,6 +1036,7 @@ pci_nvme_reset_locked(struct pci_nvme_softc *sc)
sc->num_q_is_set = false;
pci_nvme_aer_destroy(sc);
+ pci_nvme_aen_destroy(sc);
}
static void
@@ -792,7 +1062,7 @@ pci_nvme_init_controller(struct vmctx *ctx, struct pci_nvme_softc *sc)
DPRINTF("%s mapping Admin-SQ guest 0x%lx, host: %p",
__func__, sc->regs.asq, sc->submit_queues[0].qbase);
- acqs = ((sc->regs.aqa >> NVME_AQA_REG_ACQS_SHIFT) &
+ acqs = ((sc->regs.aqa >> NVME_AQA_REG_ACQS_SHIFT) &
NVME_AQA_REG_ACQS_MASK) + 1;
sc->compl_queues[0].size = acqs;
sc->compl_queues[0].qbase = vm_map_gpa(ctx, sc->regs.acq,
@@ -973,7 +1243,7 @@ nvme_opc_create_io_sq(struct pci_nvme_softc* sc, struct nvme_command* command,
DPRINTF("%s completed creating IOSQ qid %u",
__func__, qid);
} else {
- /*
+ /*
* Guest sent non-cont submission queue request.
* This setting is unsupported by this emulation.
*/
@@ -1128,6 +1398,13 @@ nvme_opc_get_log_page(struct pci_nvme_softc* sc, struct nvme_command* command,
MIN(logsize, sizeof(sc->fw_log)),
NVME_COPY_TO_PRP);
break;
+ case NVME_LOG_CHANGED_NAMESPACE:
+ nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1,
+ command->prp2, (uint8_t *)&sc->ns_log,
+ MIN(logsize, sizeof(sc->ns_log)),
+ NVME_COPY_TO_PRP);
+ memset(&sc->ns_log, 0, sizeof(sc->ns_log));
+ break;
default:
DPRINTF("%s get log page %x command not supported",
__func__, logpage);
@@ -1425,8 +1702,13 @@ nvme_opc_set_features(struct pci_nvme_softc *sc, struct nvme_command *command,
if (feat->set)
feat->set(sc, feat, command, compl);
- if (compl->status == NVME_SC_SUCCESS)
+ DPRINTF("%s: status=%#x cdw11=%#x", __func__, compl->status, command->cdw11);
+ if (compl->status == NVME_SC_SUCCESS) {
feat->cdw11 = command->cdw11;
+ if ((fid == NVME_FEAT_ASYNC_EVENT_CONFIGURATION) &&
+ (command->cdw11 != 0))
+ pci_nvme_aen_notify(sc);
+ }
return (0);
}
@@ -1544,7 +1826,8 @@ static int
nvme_opc_async_event_req(struct pci_nvme_softc* sc,
struct nvme_command* command, struct nvme_completion* compl)
{
- DPRINTF("%s async event request 0x%x", __func__, command->cdw11);
+ DPRINTF("%s async event request count=%u aerl=%u cid=%#x", __func__,
+ sc->aer_count, sc->ctrldata.aerl, command->cid);
/* Don't exceed the Async Event Request Limit (AERL). */
if (pci_nvme_aer_limit_reached(sc)) {
@@ -1565,6 +1848,7 @@ nvme_opc_async_event_req(struct pci_nvme_softc* sc,
* there is an event reflective of the request to get event.
*/
compl->status = NVME_NO_STATUS;
+ pci_nvme_aen_notify(sc);
return (0);
}
@@ -1587,7 +1871,7 @@ pci_nvme_handle_admin_cmd(struct pci_nvme_softc* sc, uint64_t value)
sqhead = sq->head;
DPRINTF("sqhead %u, tail %u", sqhead, sq->tail);
-
+
while (sqhead != atomic_load_acq_short(&sq->tail)) {
cmd = &(sq->qbase)[sqhead];
compl.cdw0 = 0;
@@ -2056,6 +2340,7 @@ nvme_opc_write_read(struct pci_nvme_softc *sc,
lba = ((uint64_t)cmd->cdw11 << 32) | cmd->cdw10;
nblocks = (cmd->cdw12 & 0xFFFF) + 1;
+
if (pci_nvme_out_of_range(nvstore, lba, nblocks)) {
WPRINTF("%s command would exceed LBA range", __func__);
pci_nvme_status_genc(status, NVME_SC_LBA_OUT_OF_RANGE);
@@ -2755,6 +3040,28 @@ pci_nvme_parse_config(struct pci_nvme_softc *sc, nvlist_t *nvl)
return (0);
}
+static void
+pci_nvme_resized(struct blockif_ctxt *bctxt, void *arg, size_t new_size)
+{
+ struct pci_nvme_softc *sc;
+ struct pci_nvme_blockstore *nvstore;
+ struct nvme_namespace_data *nd;
+
+ sc = arg;
+ nvstore = &sc->nvstore;
+ nd = &sc->nsdata;
+
+ nvstore->size = new_size;
+ pci_nvme_init_nsdata_size(nvstore, nd);
+
+ /* Add changed NSID to list */
+ sc->ns_log.ns[0] = 1;
+ sc->ns_log.ns[1] = 0;
+
+ pci_nvme_aen_post(sc, PCI_NVME_AE_TYPE_NOTICE,
+ PCI_NVME_AE_INFO_NS_ATTR_CHANGED);
+}
+
static int
pci_nvme_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
{
@@ -2820,6 +3127,7 @@ pci_nvme_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
pthread_mutex_init(&sc->mtx, NULL);
sem_init(&sc->iosemlock, 0, sc->ioslots);
+ blockif_register_resize_callback(sc->nvstore.ctx, pci_nvme_resized, sc);
pci_nvme_init_queues(sc, sc->max_queues, sc->max_queues);
/*
@@ -2832,6 +3140,7 @@ pci_nvme_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
pci_nvme_init_features(sc);
pci_nvme_aer_init(sc);
+ pci_nvme_aen_init(sc);
pci_nvme_reset(sc);
diff --git a/usr/src/cmd/bhyve/pci_passthru.c b/usr/src/cmd/bhyve/pci_passthru.c
index 55e2f66e99..aea278c0c8 100644
--- a/usr/src/cmd/bhyve/pci_passthru.c
+++ b/usr/src/cmd/bhyve/pci_passthru.c
@@ -344,15 +344,14 @@ cfginitmsi(struct passthru_softc *sc)
#endif
/* Make sure one of the capabilities is present */
- if (sc->psc_msi.capoff == 0 && sc->psc_msix.capoff == 0) {
+ if (sc->psc_msi.capoff == 0 && sc->psc_msix.capoff == 0)
return (-1);
- } else {
+ else
return (0);
- }
}
static uint64_t
-passthru_msix_table_read(struct passthru_softc *sc, uint64_t offset, int size)
+msix_table_read(struct passthru_softc *sc, uint64_t offset, int size)
{
struct pci_devinst *pi;
struct msix_table_entry *entry;
@@ -362,30 +361,30 @@ passthru_msix_table_read(struct passthru_softc *sc, uint64_t offset, int size)
uint64_t *src64;
uint64_t data;
size_t entry_offset;
- int index;
+ uint32_t table_offset;
+ int index, table_count;
pi = sc->psc_pi;
- if (offset >= pi->pi_msix.pba_offset &&
- offset < pi->pi_msix.pba_offset + pi->pi_msix.pba_size) {
- switch(size) {
+
+ table_offset = pi->pi_msix.table_offset;
+ table_count = pi->pi_msix.table_count;
+ if (offset < table_offset ||
+ offset >= table_offset + table_count * MSIX_TABLE_ENTRY_SIZE) {
+ switch (size) {
case 1:
- src8 = (uint8_t *)(pi->pi_msix.pba_page + offset -
- pi->pi_msix.pba_page_offset);
+ src8 = (uint8_t *)(pi->pi_msix.mapped_addr + offset);
data = *src8;
break;
case 2:
- src16 = (uint16_t *)(pi->pi_msix.pba_page + offset -
- pi->pi_msix.pba_page_offset);
+ src16 = (uint16_t *)(pi->pi_msix.mapped_addr + offset);
data = *src16;
break;
case 4:
- src32 = (uint32_t *)(pi->pi_msix.pba_page + offset -
- pi->pi_msix.pba_page_offset);
+ src32 = (uint32_t *)(pi->pi_msix.mapped_addr + offset);
data = *src32;
break;
case 8:
- src64 = (uint64_t *)(pi->pi_msix.pba_page + offset -
- pi->pi_msix.pba_page_offset);
+ src64 = (uint64_t *)(pi->pi_msix.mapped_addr + offset);
data = *src64;
break;
default:
@@ -394,32 +393,28 @@ passthru_msix_table_read(struct passthru_softc *sc, uint64_t offset, int size)
return (data);
}
- if (offset < pi->pi_msix.table_offset)
- return (-1);
-
- offset -= pi->pi_msix.table_offset;
+ offset -= table_offset;
index = offset / MSIX_TABLE_ENTRY_SIZE;
- if (index >= pi->pi_msix.table_count)
- return (-1);
+ assert(index < table_count);
entry = &pi->pi_msix.table[index];
entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;
- switch(size) {
+ switch (size) {
case 1:
- src8 = (uint8_t *)((void *)entry + entry_offset);
+ src8 = (uint8_t *)((uint8_t *)entry + entry_offset);
data = *src8;
break;
case 2:
- src16 = (uint16_t *)((void *)entry + entry_offset);
+ src16 = (uint16_t *)((uint8_t *)entry + entry_offset);
data = *src16;
break;
case 4:
- src32 = (uint32_t *)((void *)entry + entry_offset);
+ src32 = (uint32_t *)((uint8_t *)entry + entry_offset);
data = *src32;
break;
case 8:
- src64 = (uint64_t *)((void *)entry + entry_offset);
+ src64 = (uint64_t *)((uint8_t *)entry + entry_offset);
data = *src64;
break;
default:
@@ -430,8 +425,8 @@ passthru_msix_table_read(struct passthru_softc *sc, uint64_t offset, int size)
}
static void
-passthru_msix_table_write(struct vmctx *ctx, int vcpu,
- struct passthru_softc *sc, uint64_t offset, int size, uint64_t data)
+msix_table_write(struct vmctx *ctx, int vcpu, struct passthru_softc *sc,
+ uint64_t offset, int size, uint64_t data)
{
struct pci_devinst *pi;
struct msix_table_entry *entry;
@@ -440,46 +435,39 @@ passthru_msix_table_write(struct vmctx *ctx, int vcpu,
uint32_t *dest32;
uint64_t *dest64;
size_t entry_offset;
- uint32_t vector_control;
- int index;
+ uint32_t table_offset, vector_control;
+ int index, table_count;
pi = sc->psc_pi;
- if (offset >= pi->pi_msix.pba_offset &&
- offset < pi->pi_msix.pba_offset + pi->pi_msix.pba_size) {
- switch(size) {
+
+ table_offset = pi->pi_msix.table_offset;
+ table_count = pi->pi_msix.table_count;
+ if (offset < table_offset ||
+ offset >= table_offset + table_count * MSIX_TABLE_ENTRY_SIZE) {
+ switch (size) {
case 1:
- dest8 = (uint8_t *)(pi->pi_msix.pba_page + offset -
- pi->pi_msix.pba_page_offset);
+ dest8 = (uint8_t *)(pi->pi_msix.mapped_addr + offset);
*dest8 = data;
break;
case 2:
- dest16 = (uint16_t *)(pi->pi_msix.pba_page + offset -
- pi->pi_msix.pba_page_offset);
+ dest16 = (uint16_t *)(pi->pi_msix.mapped_addr + offset);
*dest16 = data;
break;
case 4:
- dest32 = (uint32_t *)(pi->pi_msix.pba_page + offset -
- pi->pi_msix.pba_page_offset);
+ dest32 = (uint32_t *)(pi->pi_msix.mapped_addr + offset);
*dest32 = data;
break;
case 8:
- dest64 = (uint64_t *)(pi->pi_msix.pba_page + offset -
- pi->pi_msix.pba_page_offset);
+ dest64 = (uint64_t *)(pi->pi_msix.mapped_addr + offset);
*dest64 = data;
break;
- default:
- break;
}
return;
}
- if (offset < pi->pi_msix.table_offset)
- return;
-
- offset -= pi->pi_msix.table_offset;
+ offset -= table_offset;
index = offset / MSIX_TABLE_ENTRY_SIZE;
- if (index >= pi->pi_msix.table_count)
- return;
+ assert(index < table_count);
entry = &pi->pi_msix.table[index];
entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;
@@ -504,65 +492,64 @@ passthru_msix_table_write(struct vmctx *ctx, int vcpu,
}
static int
-init_msix_table(struct vmctx *ctx, struct passthru_softc *sc, uint64_t base)
+init_msix_table(struct vmctx *ctx, struct passthru_softc *sc)
{
- int idx;
- size_t remaining __unused;
- uint32_t table_size, table_offset;
- uint32_t pba_size, pba_offset;
- vm_paddr_t start __unused;
struct pci_devinst *pi = sc->psc_pi;
+ uint32_t table_size, table_offset;
+ int i;
- assert(pci_msix_table_bar(pi) >= 0 && pci_msix_pba_bar(pi) >= 0);
+ i = pci_msix_table_bar(pi);
+ assert(i >= 0);
+
+ /*
+ * Map the region of the BAR containing the MSI-X table. This is
+ * necessary for two reasons:
+ * 1. The PBA may reside in the first or last page containing the MSI-X
+ * table.
+ * 2. While PCI devices are not supposed to use the page(s) containing
+ * the MSI-X table for other purposes, some do in practice.
+ */
/*
- * If the MSI-X table BAR maps memory intended for
- * other uses, it is at least assured that the table
- * either resides in its own page within the region,
- * or it resides in a page shared with only the PBA.
+ * Mapping pptfd provides access to the BAR containing the MSI-X
+ * table. See ppt_devmap() in usr/src/uts/i86pc/io/vmm/io/ppt.c
+ *
+ * This maps the whole BAR and then mprotect(PROT_NONE) is used below
+ * to prevent access to pages that don't contain the MSI-X table.
+ * When porting this, it was tempting to just map the MSI-X table pages
+ * but that would mean updating everywhere that assumes that
+ * pi->pi_msix.mapped_addr points to the start of the BAR. For now,
+ * keep closer to upstream.
*/
+ pi->pi_msix.mapped_size = sc->psc_bar[i].size;
+ pi->pi_msix.mapped_addr = (uint8_t *)mmap(NULL, pi->pi_msix.mapped_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED, sc->pptfd, 0);
+ if (pi->pi_msix.mapped_addr == MAP_FAILED) {
+ warn("Failed to map MSI-X table BAR on %d", sc->pptfd);
+ return (-1);
+ }
+
table_offset = rounddown2(pi->pi_msix.table_offset, 4096);
table_size = pi->pi_msix.table_offset - table_offset;
table_size += pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE;
table_size = roundup2(table_size, 4096);
- idx = pi->pi_msix.table_bar;
- start = pi->pi_bar[idx].addr;
- remaining = pi->pi_bar[idx].size;
-
- if (pi->pi_msix.pba_bar == pi->pi_msix.table_bar) {
- pba_offset = pi->pi_msix.pba_offset;
- pba_size = pi->pi_msix.pba_size;
- if (pba_offset >= table_offset + table_size ||
- table_offset >= pba_offset + pba_size) {
- /*
- * If the PBA does not share a page with the MSI-x
- * tables, no PBA emulation is required.
- */
- pi->pi_msix.pba_page = NULL;
- pi->pi_msix.pba_page_offset = 0;
- } else {
- /*
- * The PBA overlaps with either the first or last
- * page of the MSI-X table region. Map the
- * appropriate page.
- */
- if (pba_offset <= table_offset)
- pi->pi_msix.pba_page_offset = table_offset;
- else
- pi->pi_msix.pba_page_offset = table_offset +
- table_size - 4096;
- pi->pi_msix.pba_page = mmap(NULL, 4096, PROT_READ |
- PROT_WRITE, MAP_SHARED, sc->pptfd,
- pi->pi_msix.pba_page_offset);
- if (pi->pi_msix.pba_page == MAP_FAILED) {
- warn("Failed to map PBA page for MSI-X on %d",
- sc->pptfd);
- return (-1);
- }
- }
- }
+ /*
+ * Unmap any pages not containing the table, we do not need to emulate
+ * accesses to them. Avoid releasing address space to help ensure that
+ * a buggy out-of-bounds access causes a crash.
+ */
+ if (table_offset != 0)
+ if (mprotect((caddr_t)pi->pi_msix.mapped_addr, table_offset,
+ PROT_NONE) != 0)
+ warn("Failed to unmap MSI-X table BAR region");
+ if (table_offset + table_size != pi->pi_msix.mapped_size)
+ if (mprotect((caddr_t)
+ pi->pi_msix.mapped_addr + table_offset + table_size,
+ pi->pi_msix.mapped_size - (table_offset + table_size),
+ PROT_NONE) != 0)
+ warn("Failed to unmap MSI-X table BAR region");
return (0);
}
@@ -598,18 +585,22 @@ cfginitbar(struct vmctx *ctx, struct passthru_softc *sc)
sc->psc_bar[i].type = bartype;
sc->psc_bar[i].size = size;
sc->psc_bar[i].addr = base;
+ sc->psc_bar[i].lobits = 0;
/* Allocate the BAR in the guest I/O or MMIO space */
error = pci_emul_alloc_bar(pi, i, bartype, size);
if (error)
return (-1);
- /* The MSI-X table needs special handling */
- if (i == pci_msix_table_bar(pi)) {
- error = init_msix_table(ctx, sc, base);
- if (error)
- return (-1);
+ /* Use same lobits as physical bar */
+ uint8_t lobits = read_config(sc, PCIR_BAR(i), 0x01);
+ if (bartype == PCIBAR_MEM32 || bartype == PCIBAR_MEM64) {
+ lobits &= ~PCIM_BAR_MEM_BASE;
+ } else {
+ lobits &= ~PCIM_BAR_IO_BASE;
}
+ sc->psc_bar[i].lobits = lobits;
+ pi->pi_bar[i].lobits = lobits;
/*
* 64-bit BAR takes up two slots so skip the next one.
@@ -627,6 +618,7 @@ static int
cfginit(struct vmctx *ctx, struct passthru_softc *sc)
{
struct pci_devinst *pi = sc->psc_pi;
+ int error;
if (cfginitmsi(sc) != 0) {
warnx("failed to initialize MSI for PCI %d", sc->pptfd);
@@ -638,9 +630,24 @@ cfginit(struct vmctx *ctx, struct passthru_softc *sc)
return (-1);
}
- pci_set_cfgdata16(pi, PCIR_COMMAND, read_config(sc, PCIR_COMMAND, 2));
+ write_config(sc, PCIR_COMMAND, 2, pci_get_cfgdata16(pi, PCIR_COMMAND));
- return (0);
+ /*
+ * We need to do this after PCIR_COMMAND got possibly updated, e.g.,
+ * a BAR was enabled.
+ */
+ if (pci_msix_table_bar(pi) >= 0) {
+ error = init_msix_table(ctx, sc);
+ if (error != 0) {
+ warnx("failed to initialize MSI-X table for PCI %d",
+ sc->pptfd);
+ goto done;
+ }
+ }
+
+ error = 0; /* success */
+done:
+ return (error);
}
static int
@@ -694,10 +701,7 @@ passthru_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
goto done;
/* initialize config space */
- if ((error = cfginit(ctx, sc)) != 0)
- goto done;
-
- error = 0; /* success */
+ error = cfginit(ctx, sc);
done:
if (error) {
free(sc);
@@ -744,7 +748,7 @@ msixcap_access(struct passthru_softc *sc, int coff)
static int
passthru_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
- int coff, int bytes, uint32_t *rv)
+ int coff, int bytes, uint32_t *rv)
{
struct passthru_softc *sc;
@@ -753,7 +757,8 @@ passthru_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
/*
* PCI BARs and MSI capability is emulated.
*/
- if (bar_access(coff) || msicap_access(sc, coff))
+ if (bar_access(coff) || msicap_access(sc, coff) ||
+ msixcap_access(sc, coff))
return (-1);
/*
@@ -795,7 +800,7 @@ passthru_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
static int
passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
- int coff, int bytes, uint32_t val)
+ int coff, int bytes, uint32_t val)
{
int error, msix_table_entries, i;
struct passthru_softc *sc;
@@ -872,12 +877,12 @@ passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
static void
passthru_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
- uint64_t offset, int size, uint64_t value)
+ uint64_t offset, int size, uint64_t value)
{
struct passthru_softc *sc = pi->pi_arg;
if (baridx == pci_msix_table_bar(pi)) {
- passthru_msix_table_write(ctx, vcpu, sc, offset, size, value);
+ msix_table_write(ctx, vcpu, sc, offset, size, value);
} else {
struct ppt_bar_io pbi;
@@ -893,13 +898,13 @@ passthru_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
static uint64_t
passthru_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
- uint64_t offset, int size)
+ uint64_t offset, int size)
{
struct passthru_softc *sc = pi->pi_arg;
uint64_t val;
if (baridx == pci_msix_table_bar(pi)) {
- val = passthru_msix_table_read(sc, offset, size);
+ val = msix_table_read(sc, offset, size);
} else {
struct ppt_bar_io pbi;
@@ -920,7 +925,7 @@ passthru_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
static void
passthru_msix_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx,
- int enabled, uint64_t address)
+ int enabled, uint64_t address)
{
struct passthru_softc *sc;
size_t remaining;
@@ -960,7 +965,7 @@ passthru_msix_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx,
static void
passthru_mmio_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx,
- int enabled, uint64_t address)
+ int enabled, uint64_t address)
{
struct passthru_softc *sc;
diff --git a/usr/src/cmd/bhyve/pci_virtio_9p.c b/usr/src/cmd/bhyve/pci_virtio_9p.c
index 8c975ac1dc..9808fee46d 100644
--- a/usr/src/cmd/bhyve/pci_virtio_9p.c
+++ b/usr/src/cmd/bhyve/pci_virtio_9p.c
@@ -159,7 +159,7 @@ pci_vt9p_get_buffer(struct l9p_request *req, struct iovec *iov, size_t *niov,
{
struct pci_vt9p_request *preq = req->lr_aux;
size_t n = preq->vsr_niov - preq->vsr_respidx;
-
+
memcpy(iov, preq->vsr_iov + preq->vsr_respidx,
n * sizeof(struct iovec));
*niov = n;
@@ -350,7 +350,7 @@ pci_vt9p_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
sc->vsc_config->tag_len = (uint16_t)strlen(sharename);
memcpy(sc->vsc_config->tag, sharename, sc->vsc_config->tag_len);
-
+
if (l9p_backend_fs_init(&sc->vsc_fs_backend, rootfd, ro) != 0) {
errno = ENXIO;
return (1);
diff --git a/usr/src/cmd/bhyve/pci_virtio_block.c b/usr/src/cmd/bhyve/pci_virtio_block.c
index b2fc84118f..30998161f0 100644
--- a/usr/src/cmd/bhyve/pci_virtio_block.c
+++ b/usr/src/cmd/bhyve/pci_virtio_block.c
@@ -434,7 +434,7 @@ pci_vtblk_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
{
char bident[sizeof("XX:X:X")];
struct blockif_ctxt *bctxt;
- const char *path;
+ const char *path, *serial;
MD5_CTX mdctx;
u_char digest[16];
struct pci_vtblk_softc *sc;
@@ -485,26 +485,23 @@ pci_vtblk_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
/* sc->vbsc_vq.vq_notify = we have no per-queue notify */
/*
- * Create an identifier for the backing file. Use parts of the
- * md5 sum of the filename
+ * If an explicit identifier is not given, create an
+ * identifier using parts of the md5 sum of the filename.
*/
- path = get_config_value_node(nvl, "path");
- MD5Init(&mdctx);
- MD5Update(&mdctx, path, strlen(path));
- MD5Final(digest, &mdctx);
- snprintf(sc->vbsc_ident, VTBLK_BLK_ID_BYTES,
- "BHYVE-%02X%02X-%02X%02X-%02X%02X",
- digest[0], digest[1], digest[2], digest[3], digest[4], digest[5]);
-
-#ifndef __FreeBSD__
- const char *serial;
-
+ bzero(sc->vbsc_ident, VTBLK_BLK_ID_BYTES);
if ((serial = get_config_value_node(nvl, "serial")) != NULL ||
(serial = get_config_value_node(nvl, "ser")) != NULL) {
- bzero(sc->vbsc_ident, VTBLK_BLK_ID_BYTES);
strlcpy(sc->vbsc_ident, serial, VTBLK_BLK_ID_BYTES);
+ } else {
+ path = get_config_value_node(nvl, "path");
+ MD5Init(&mdctx);
+ MD5Update(&mdctx, path, strlen(path));
+ MD5Final(digest, &mdctx);
+ snprintf(sc->vbsc_ident, VTBLK_BLK_ID_BYTES,
+ "BHYVE-%02X%02X-%02X%02X-%02X%02X",
+ digest[0], digest[1], digest[2], digest[3], digest[4],
+ digest[5]);
}
-#endif
/* setup virtio block config space */
sc->vbsc_cfg.vbc_capacity = size / VTBLK_BSIZE; /* 512-byte units */
@@ -593,6 +590,6 @@ struct pci_devemu pci_de_vblk = {
.pe_init = pci_vtblk_init,
.pe_legacy_config = blockif_legacy_config,
.pe_barwrite = vi_pci_write,
- .pe_barread = vi_pci_read
+ .pe_barread = vi_pci_read,
};
PCI_EMUL_SET(pci_de_vblk);
diff --git a/usr/src/cmd/bhyve/pci_virtio_console.c b/usr/src/cmd/bhyve/pci_virtio_console.c
index ba0ca48dbf..998d5e1d4c 100644
--- a/usr/src/cmd/bhyve/pci_virtio_console.c
+++ b/usr/src/cmd/bhyve/pci_virtio_console.c
@@ -618,7 +618,7 @@ pci_vtcon_control_send(struct pci_vtcon_softc *sc,
vq_relchain(vq, req.idx, sizeof(struct pci_vtcon_control) + len);
vq_endchains(vq, 1);
}
-
+
static void
pci_vtcon_notify_tx(void *vsc, struct vqueue_info *vq)
@@ -723,7 +723,7 @@ pci_vtcon_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
sc->vsc_config = calloc(1, sizeof(struct pci_vtcon_config));
sc->vsc_config->max_nr_ports = VTCON_MAXPORTS;
sc->vsc_config->cols = 80;
- sc->vsc_config->rows = 25;
+ sc->vsc_config->rows = 25;
vi_softc_linkup(&sc->vsc_vs, &vtcon_vi_consts, sc, pi, sc->vsc_queues);
sc->vsc_vs.vs_mtx = &sc->vsc_mtx;
diff --git a/usr/src/cmd/bhyve/pci_virtio_net.c b/usr/src/cmd/bhyve/pci_virtio_net.c
index 28c11b87c5..b7094484aa 100644
--- a/usr/src/cmd/bhyve/pci_virtio_net.c
+++ b/usr/src/cmd/bhyve/pci_virtio_net.c
@@ -116,7 +116,7 @@ struct pci_vtnet_softc {
int resetting; /* protected by tx_mtx */
uint64_t vsc_features; /* negotiated features */
-
+
pthread_mutex_t rx_mtx;
int rx_merge; /* merged rx bufs in use */
@@ -654,9 +654,9 @@ pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
sc->vsc_consts.vc_hv_caps |= VIRTIO_NET_F_MRG_RXBUF |
netbe_get_cap(sc->vsc_be);
- /*
+ /*
* Since we do not actually support multiqueue,
- * set the maximum virtqueue pairs to 1.
+ * set the maximum virtqueue pairs to 1.
*/
sc->vsc_config.max_virtqueue_pairs = 1;
@@ -669,7 +669,7 @@ pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
/* Link is always up. */
sc->vsc_config.status = 1;
-
+
vi_softc_linkup(&sc->vsc_vs, &sc->vsc_consts, sc, pi, sc->vsc_queues);
sc->vsc_vs.vs_mtx = &sc->vsc_mtx;
@@ -686,12 +686,12 @@ pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
sc->rx_merge = 0;
sc->vhdrlen = sizeof(struct virtio_net_rxhdr) - 2;
- pthread_mutex_init(&sc->rx_mtx, NULL);
+ pthread_mutex_init(&sc->rx_mtx, NULL);
- /*
+ /*
* Initialize tx semaphore & spawn TX processing thread.
* As of now, only one thread for TX desc processing is
- * spawned.
+ * spawned.
*/
sc->tx_in_progress = 0;
pthread_mutex_init(&sc->tx_mtx, NULL);
diff --git a/usr/src/cmd/bhyve/pci_virtio_scsi.c b/usr/src/cmd/bhyve/pci_virtio_scsi.c
index f4a701c0e2..b080749f79 100644
--- a/usr/src/cmd/bhyve/pci_virtio_scsi.c
+++ b/usr/src/cmd/bhyve/pci_virtio_scsi.c
@@ -628,7 +628,7 @@ pci_vtscsi_requestq_notify(void *vsc, struct vqueue_info *vq)
}
static int
-pci_vtscsi_init_queue(struct pci_vtscsi_softc *sc,
+pci_vtscsi_init_queue(struct pci_vtscsi_softc *sc,
struct pci_vtscsi_queue *queue, int num)
{
struct pci_vtscsi_worker *worker;
diff --git a/usr/src/cmd/bhyve/pci_xhci.c b/usr/src/cmd/bhyve/pci_xhci.c
index bbccc7f0bf..97ce582772 100644
--- a/usr/src/cmd/bhyve/pci_xhci.c
+++ b/usr/src/cmd/bhyve/pci_xhci.c
@@ -485,7 +485,7 @@ pci_xhci_portregs_write(struct pci_xhci_softc *sc, uint64_t offset,
p->portsc &= XHCI_PS_PED | XHCI_PS_PLS_MASK |
XHCI_PS_SPEED_MASK | XHCI_PS_PIC_MASK;
-
+
if (XHCI_DEVINST_PTR(sc, port))
p->portsc |= XHCI_PS_CCS;
@@ -541,7 +541,7 @@ pci_xhci_portregs_write(struct pci_xhci_softc *sc, uint64_t offset,
break;
}
break;
- case 4:
+ case 4:
/* Port power management status and control register */
p->portpmsc = value;
break;
@@ -595,7 +595,7 @@ pci_xhci_trb_next(struct pci_xhci_softc *sc, struct xhci_trb *curtrb,
if (XHCI_TRB_3_TYPE_GET(curtrb->dwTrb3) == XHCI_TRB_TYPE_LINK) {
if (guestaddr)
*guestaddr = curtrb->qwTrb0 & ~0xFUL;
-
+
next = XHCI_GADDR(sc, curtrb->qwTrb0 & ~0xFUL);
} else {
if (guestaddr)
@@ -1260,7 +1260,7 @@ pci_xhci_cmd_set_tr(struct pci_xhci_softc *sc, uint32_t slot,
cmderr = pci_xhci_find_stream(sc, ep_ctx, streamid, &sctx);
if (sctx != NULL) {
assert(devep->ep_sctx != NULL);
-
+
devep->ep_sctx[streamid].qwSctx0 = trb->qwTrb0;
devep->ep_sctx_trbs[streamid].ringaddr =
trb->qwTrb0 & ~0xF;
@@ -1379,7 +1379,7 @@ pci_xhci_complete_commands(struct pci_xhci_softc *sc)
while (1) {
sc->opregs.cr_p = trb;
-
+
type = XHCI_TRB_3_TYPE_GET(trb->dwTrb3);
if ((trb->dwTrb3 & XHCI_TRB_3_CYCLE_BIT) !=
@@ -1474,7 +1474,7 @@ pci_xhci_complete_commands(struct pci_xhci_softc *sc)
}
if (type != XHCI_TRB_TYPE_LINK) {
- /*
+ /*
* insert command completion event and assert intr
*/
evtrb.qwTrb0 = crcr;
@@ -1602,7 +1602,7 @@ pci_xhci_xfer_complete(struct pci_xhci_softc *sc, struct usb_data_xfer *xfer,
if (XHCI_TRB_3_TYPE_GET(trbflags) == XHCI_TRB_TYPE_EVENT_DATA) {
DPRINTF(("pci_xhci EVENT_DATA edtla %u", edtla));
evtrb.qwTrb0 = trb->qwTrb0;
- evtrb.dwTrb2 = (edtla & 0xFFFFF) |
+ evtrb.dwTrb2 = (edtla & 0xFFFFF) |
XHCI_TRB_2_ERROR_SET(err);
evtrb.dwTrb3 |= XHCI_TRB_3_ED_BIT;
edtla = 0;
@@ -2569,7 +2569,7 @@ pci_xhci_init_port(struct pci_xhci_softc *sc, int portn)
if (dev) {
port->portsc = XHCI_PS_CCS | /* connected */
XHCI_PS_PP; /* port power */
-
+
if (dev->dev_ue->ue_usbver == 2) {
port->portsc |= XHCI_PS_PLS_SET(UPS_PORT_LS_POLL) |
XHCI_PS_SPEED_SET(dev->dev_ue->ue_usbspeed);
@@ -2578,7 +2578,7 @@ pci_xhci_init_port(struct pci_xhci_softc *sc, int portn)
XHCI_PS_PED | /* enabled */
XHCI_PS_SPEED_SET(dev->dev_ue->ue_usbspeed);
}
-
+
DPRINTF(("Init port %d 0x%x", portn, port->portsc));
} else {
port->portsc = XHCI_PS_PLS_SET(UPS_PORT_LS_RX_DET) | XHCI_PS_PP;
diff --git a/usr/src/cmd/bhyve/rtc.c b/usr/src/cmd/bhyve/rtc.c
index 0f63156adb..9125b4f86a 100644
--- a/usr/src/cmd/bhyve/rtc.c
+++ b/usr/src/cmd/bhyve/rtc.c
@@ -75,7 +75,7 @@ rtc_time(struct vmctx *ctx)
void
rtc_init(struct vmctx *ctx)
-{
+{
size_t himem;
size_t lomem;
int err;
diff --git a/usr/src/cmd/bhyve/smbiostbl.c b/usr/src/cmd/bhyve/smbiostbl.c
index 6fd8cbac81..8c3cd6332d 100644
--- a/usr/src/cmd/bhyve/smbiostbl.c
+++ b/usr/src/cmd/bhyve/smbiostbl.c
@@ -53,9 +53,9 @@ __FBSDID("$FreeBSD$");
#define SMBIOS_BASE 0xF1000
-#define FIRMWARE_VERSION "13.0"
+#define FIRMWARE_VERSION "14.0"
/* The SMBIOS specification defines the date format to be mm/dd/yyyy */
-#define FIRMWARE_RELEASE_DATE "11/10/2020"
+#define FIRMWARE_RELEASE_DATE "10/10/2021"
/* BHYVE_ACPI_BASE - SMBIOS_BASE) */
#define SMBIOS_MAX_LENGTH (0xF2400 - 0xF1000)
diff --git a/usr/src/cmd/bhyve/test/tests/mevent/Makefile b/usr/src/cmd/bhyve/test/tests/mevent/Makefile
index 363deb02cc..9d93e17f5a 100644
--- a/usr/src/cmd/bhyve/test/tests/mevent/Makefile
+++ b/usr/src/cmd/bhyve/test/tests/mevent/Makefile
@@ -12,6 +12,7 @@
#
# Copyright 2018 Joyent, Inc.
# Copyright 2022 Oxide Computer Company
+# Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
#
TESTSUBDIR = mevent
@@ -19,7 +20,9 @@ PROG = \
lists_delete \
read_disable \
read_pause \
- read_requeue
+ read_requeue \
+ vnode_file \
+ vnode_zvol
SUPOBJS = mevent.o testlib.o
@@ -34,8 +37,12 @@ install: $(TESTDIR) $(CMDS)
$(CMDS): $(PROG)
+vnode_zvol := LDLIBS += -lzfs -lnvpair
+
include ../../Makefile.targ
%: %.o $(SUPOBJS)
$(LINK.c) -o $@ $< $(SUPOBJS) $(LDLIBS)
$(POST_PROCESS)
+
+mevent.o: ../../../mevent.c
diff --git a/usr/src/cmd/bhyve/test/tests/mevent/mevent.c b/usr/src/cmd/bhyve/test/tests/mevent/mevent.c
index 971cf4aa77..51c94a4c09 100644
--- a/usr/src/cmd/bhyve/test/tests/mevent/mevent.c
+++ b/usr/src/cmd/bhyve/test/tests/mevent/mevent.c
@@ -55,3 +55,9 @@ test_mevent_count_lists(int *ret_global, int *ret_change, int *ret_del_pending)
*ret_change = change;
*ret_del_pending = del_pending;
}
+
+void
+set_mevent_file_poll_interval_ms(int ms)
+{
+ mevent_file_poll_interval_ms = ms;
+}
diff --git a/usr/src/cmd/bhyve/test/tests/mevent/testlib.h b/usr/src/cmd/bhyve/test/tests/mevent/testlib.h
index 7e5ca2e9c9..1639f29f87 100644
--- a/usr/src/cmd/bhyve/test/tests/mevent/testlib.h
+++ b/usr/src/cmd/bhyve/test/tests/mevent/testlib.h
@@ -71,6 +71,7 @@
#define ASSERT_INT_EQ(msg, got, exp) ASSERT_CMP(msg, got, ==, exp, "%d")
#define ASSERT_INT_NEQ(msg, got, exp) ASSERT_CMP(msg, got, !=, exp, "%d")
#define ASSERT_INT64_EQ(msg, got, exp) ASSERT_CMP(msg, got, ==, exp, "%ld")
+#define ASSERT_INT64_NEQ(msg, got, exp) ASSERT_CMP(msg, got, !=, exp, "%ld")
#define ASSERT_PTR_EQ(msg, got, exp) ASSERT_CMP(msg, got, ==, exp, "%p")
#define ASSERT_PTR_NEQ(msg, got, exp) ASSERT_CMP(msg, got, !=, exp, "%p")
@@ -89,5 +90,6 @@ extern boolean_t testlib_verbose;
extern void start_test(const char *, uint32_t);
extern void start_event_thread(void);
extern void test_mevent_count_lists(int *, int *, int *);
+extern void set_mevent_file_poll_interval_ms(int);
#endif /* _TESTLIB_H_ */
diff --git a/usr/src/cmd/bhyve/test/tests/mevent/vnode_file.c b/usr/src/cmd/bhyve/test/tests/mevent/vnode_file.c
new file mode 100644
index 0000000000..850ac1be27
--- /dev/null
+++ b/usr/src/cmd/bhyve/test/tests/mevent/vnode_file.c
@@ -0,0 +1,141 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018 Joyent, Inc.
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "testlib.h"
+#include "mevent.h"
+
+static char *cookie = "Chocolate chip with fudge stripes";
+
+static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
+
+static void
+callback(int fd, enum ev_type ev, void *arg)
+{
+ static off_t size = 0;
+ struct stat st;
+
+ ASSERT_INT_EQ(("bad event"), ev, EVF_VNODE);
+ ASSERT_PTR_EQ(("bad cookie"), arg, cookie);
+
+ if (fstat(fd, &st) != 0)
+ FAIL_ERRNO("fstat failed");
+
+ ASSERT_INT64_NEQ(("File size has not changed"), size, st.st_size);
+ size = st.st_size;
+
+ pthread_mutex_lock(&mtx);
+ pthread_cond_signal(&cv);
+ VERBOSE(("wakeup"));
+ pthread_mutex_unlock(&mtx);
+}
+
+static void
+test_fd(int fd, char *tag)
+{
+ struct mevent *evp;
+ int err;
+
+ evp = mevent_add_flags(fd, EVF_VNODE, EVFF_ATTRIB, callback, cookie);
+ ASSERT_PTR_NEQ(("%s: mevent_add", tag), evp, NULL);
+
+ for (uint_t i = 0; cookie[i] != '\0'; i++) {
+ ssize_t written;
+
+ pthread_mutex_lock(&mtx);
+
+ if (i > 0) {
+ /*
+ * Check that no events are emitted for writes which do
+ * not alter the size.
+ */
+ if (lseek(fd, -1, SEEK_CUR) == -1)
+ FAIL_ERRNO("lseek");
+ if (write(fd, "X", 1) == -1)
+ FAIL_ERRNO("write");
+ }
+
+ written = write(fd, cookie + i, 1);
+ if (written < 0)
+ FAIL_ERRNO("bad write");
+ ASSERT_INT64_EQ(("write byte %d of cookie", i), written, 1);
+
+ /* Wait for the size change to be processed */
+ pthread_cond_wait(&cv, &mtx);
+ pthread_mutex_unlock(&mtx);
+ /*
+ * This is a bit unsatisfactory but we need to allow time
+ * for mevent to re-associate the port or the next write could
+ * be missed.
+ */
+ usleep(500);
+ }
+
+ err = mevent_disable(evp);
+ ASSERT_INT_EQ(("%s: mevent_disable: %s", tag, strerror(err)), err, 0);
+
+ (void) printf("PASS %s - %s\n", testlib_prog, tag);
+}
+
+int
+main(int argc, const char **argv)
+{
+ start_test(argv[0], 5);
+ start_event_thread();
+ int fd;
+
+ /* Test with a temporary file in /tmp */
+ char *template = strdup("/tmp/mevent.vnode.XXXXXX");
+ ASSERT_PTR_NEQ(("strdup"), template, NULL);
+ fd = mkstemp(template);
+ if (fd == -1)
+ FAIL_ERRNO("Couldn't create temporary file with mkstemp");
+
+ VERBOSE(("Opened temporary file at '%s'", template));
+
+ test_fd(fd, "temporary file");
+
+ /* Test with a file which is unlinked from the filesystem */
+ FILE *fp = tmpfile();
+ ASSERT_PTR_NEQ(("tmpfile"), fp, NULL);
+
+ fd = fileno(fp);
+ if (fd == -1)
+ FAIL_ERRNO("Couldn't get file descriptor for temporary file");
+
+ test_fd(fd, "anon file");
+
+ /*
+ * Defer to here to avoid generating a new event before the disable has
+ * been processed and the port deassociated.
+ */
+ unlink(template);
+ free(template);
+
+ PASS();
+}
diff --git a/usr/src/cmd/bhyve/test/tests/mevent/vnode_zvol.c b/usr/src/cmd/bhyve/test/tests/mevent/vnode_zvol.c
new file mode 100644
index 0000000000..8e99d7ba0d
--- /dev/null
+++ b/usr/src/cmd/bhyve/test/tests/mevent/vnode_zvol.c
@@ -0,0 +1,259 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018 Joyent, Inc.
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <libzfs.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <zone.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "testlib.h"
+#include "mevent.h"
+
+#define MB (1024 * 1024)
+
+static char *cookie = "Chocolate chip with fudge stripes";
+
+static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
+
+static void
+callback(int fd, enum ev_type ev, void *arg)
+{
+ static off_t size = 0;
+ struct stat st;
+
+ ASSERT_INT_EQ(("bad event"), ev, EVF_VNODE);
+ ASSERT_PTR_EQ(("bad cookie"), arg, cookie);
+
+ if (fstat(fd, &st) != 0)
+ FAIL_ERRNO("fstat failed");
+
+ ASSERT_INT64_NEQ(("Size has not changed"), size, st.st_size);
+ size = st.st_size;
+
+ pthread_mutex_lock(&mtx);
+ pthread_cond_signal(&cv);
+ VERBOSE(("wakeup"));
+ pthread_mutex_unlock(&mtx);
+}
+
+static void
+destroy_zpool(libzfs_handle_t *zfshdl, zpool_handle_t *poolhdl,
+ zfs_handle_t *volhdl)
+{
+ if (volhdl != NULL) {
+ if (zfs_destroy(volhdl, B_FALSE) != 0) {
+ FAIL(("Failed to destroy ZVOL - %s",
+ libzfs_error_description(zfshdl)));
+ }
+ }
+
+ if (poolhdl != NULL) {
+ if (zpool_destroy(poolhdl, testlib_prog) != 0) {
+ FAIL(("Failed to destroy ZPOOL - %s",
+ libzfs_error_description(zfshdl)));
+ }
+ }
+}
+
+static void
+create_zpool(libzfs_handle_t *zfshdl, const char *pool, const char *file)
+{
+ nvlist_t *nvroot, *props;
+ nvlist_t *vdevs[1];
+
+ nvroot = fnvlist_alloc();
+ props = fnvlist_alloc();
+ vdevs[0] = fnvlist_alloc();
+
+ fnvlist_add_string(vdevs[0], ZPOOL_CONFIG_PATH, file);
+ fnvlist_add_string(vdevs[0], ZPOOL_CONFIG_TYPE, VDEV_TYPE_FILE);
+ fnvlist_add_uint64(vdevs[0], ZPOOL_CONFIG_IS_LOG, 0);
+
+ fnvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE, VDEV_TYPE_ROOT);
+ fnvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, vdevs, 1);
+
+ fnvlist_add_string(props,
+ zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), ZFS_MOUNTPOINT_NONE);
+
+ if (zpool_create(zfshdl, pool, nvroot, NULL, props) != 0) {
+ FAIL(("Failed to create ZPOOL %s using %s - %s",
+ pool, file, libzfs_error_description(zfshdl)));
+ }
+
+ VERBOSE(("Created ZFS pool %s", pool));
+}
+
+static bool
+create_zvol(libzfs_handle_t *zfshdl, const char *vol)
+{
+ nvlist_t *volprops;
+ int err;
+
+ volprops = fnvlist_alloc();
+ fnvlist_add_uint64(volprops,
+ zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1 * MB);
+
+ err = zfs_create(zfshdl, vol, ZFS_TYPE_VOLUME, volprops);
+ if (err != 0) {
+ (void) printf("Failed to create ZVOL %s - %s",
+ vol, libzfs_error_description(zfshdl));
+ return (false);
+ }
+
+ VERBOSE(("Created ZVOL %s", vol));
+ return (true);
+}
+
+int
+main(int argc, const char **argv)
+{
+ libzfs_handle_t *zfshdl;
+ char *template, *pool, *vol, *backend;
+ struct mevent *evp;
+ zpool_handle_t *poolhdl = NULL;
+ zfs_handle_t *volhdl = NULL;
+ int err, fd;
+
+ start_test(argv[0], 10);
+ set_mevent_file_poll_interval_ms(1000);
+
+ if (getzoneid() != GLOBAL_ZONEID)
+ FAIL(("Can only be run in the global zone"));
+
+ if ((zfshdl = libzfs_init()) == NULL)
+ FAIL_ERRNO("Could not open ZFS library");
+
+ template = strdup("/tmp/mevent.vnode.zvol.XXXXXX");
+ ASSERT_PTR_NEQ(("strdup"), template, NULL);
+ fd = mkstemp(template);
+ if (fd == -1)
+ FAIL_ERRNO("Couldn't create temporary file with mkstemp");
+ VERBOSE(("Opened temporary file at '%s'", template));
+
+ err = asprintf(&pool, "mevent_test_%d", getpid());
+ ASSERT_INT_NEQ(("asprintf pool"), err, -1);
+
+ err = asprintf(&vol, "%s/test_zvol_%d", pool, getpid());
+ ASSERT_INT_NEQ(("asprintf vol"), err, -1);
+
+ err = asprintf(&backend, "/dev/zvol/rdsk/%s", vol);
+ ASSERT_INT_NEQ(("asprintf backend"), err, -1);
+
+ err = ftruncate(fd, 64 * MB);
+ if (err != 0)
+ FAIL_ERRNO("ftruncate");
+ (void) close(fd);
+ fd = -1;
+
+ /*
+ * Create the pool as late as possible to reduce the risk of leaving
+ * a test pool hanging around.
+ */
+ create_zpool(zfshdl, pool, template);
+
+ if ((poolhdl = zpool_open(zfshdl, pool)) == NULL) {
+ (void) printf("Could not open ZPOOL - %s\n",
+ libzfs_error_description(zfshdl));
+ err = EXIT_FAIL;
+ goto out;
+ }
+
+ if (!create_zvol(zfshdl, vol)) {
+ err = EXIT_FAIL;
+ goto out;
+ }
+
+ if ((volhdl = zfs_open(zfshdl, vol, ZFS_TYPE_VOLUME)) == NULL) {
+ (void) printf("Could not open ZFS volume - %s\n",
+ libzfs_error_description(zfshdl));
+ err = EXIT_FAIL;
+ goto out;
+ }
+
+ if ((fd = open(backend, O_RDWR)) == -1) {
+ (void) printf("Failed to open '%s': %s\n",
+ backend, strerror(errno));
+ err = EXIT_FAIL;
+ goto out;
+ }
+ VERBOSE(("Opened backend %s", backend));
+
+ start_event_thread();
+
+ evp = mevent_add_flags(fd, EVF_VNODE, EVFF_ATTRIB, callback, cookie);
+ if (evp == NULL) {
+ (void) printf("mevent_add returned NULL\n");
+ err = EXIT_FAIL;
+ goto out;
+ }
+
+ for (uint_t i = 2; i < 4; i++) {
+ ssize_t written;
+ char buf[64];
+
+ /*
+ * Check that a write to the volume does not trigger an event.
+ */
+ if (lseek(fd, 0, SEEK_SET) == -1)
+ FAIL_ERRNO("lseek");
+ written = write(fd, cookie, strlen(cookie));
+ if (written < 0)
+ FAIL_ERRNO("bad write");
+ ASSERT_INT64_EQ(("write cookie", i), written, strlen(cookie));
+
+ (void) snprintf(buf, sizeof (buf), "%llu", i * MB);
+ VERBOSE(("Setting volsize to %s", buf));
+
+ if (zfs_prop_set(volhdl,
+ zfs_prop_to_name(ZFS_PROP_VOLSIZE), buf) != 0) {
+ (void) printf("Failed to increase ZFS volume size\n");
+ pthread_mutex_unlock(&mtx);
+ err = EXIT_FAIL;
+ goto out;
+ }
+
+ /* Wait for the size change to be processed */
+ pthread_mutex_lock(&mtx);
+ pthread_cond_wait(&cv, &mtx);
+ pthread_mutex_unlock(&mtx);
+ }
+
+ (void) mevent_disable(evp);
+
+ err = EXIT_PASS;
+
+out:
+
+ (void) close(fd);
+ destroy_zpool(zfshdl, poolhdl, volhdl);
+ (void) libzfs_fini(zfshdl);
+ (void) unlink(template);
+
+ if (err == EXIT_PASS)
+ PASS();
+
+ exit(err);
+}
diff --git a/usr/src/cmd/bhyve/uart_emul.c b/usr/src/cmd/bhyve/uart_emul.c
index a04229b288..7ada0e76ee 100644
--- a/usr/src/cmd/bhyve/uart_emul.c
+++ b/usr/src/cmd/bhyve/uart_emul.c
@@ -221,7 +221,7 @@ rxfifo_reset(struct uart_softc *sc, int size)
struct fifo *fifo;
ssize_t nread;
int error;
-
+
fifo = &sc->rxfifo;
bzero(fifo, sizeof(struct fifo));
fifo->size = size;
diff --git a/usr/src/cmd/bhyve/usb_mouse.c b/usr/src/cmd/bhyve/usb_mouse.c
index 340fdc0cb0..21e8873c5f 100644
--- a/usr/src/cmd/bhyve/usb_mouse.c
+++ b/usr/src/cmd/bhyve/usb_mouse.c
@@ -533,8 +533,8 @@ umouse_request(void *scarg, struct usb_data_xfer *xfer)
eshort = data->blen > 0;
break;
- case UREQ(UR_GET_STATUS, UT_READ_INTERFACE):
- case UREQ(UR_GET_STATUS, UT_READ_ENDPOINT):
+ case UREQ(UR_GET_STATUS, UT_READ_INTERFACE):
+ case UREQ(UR_GET_STATUS, UT_READ_ENDPOINT):
DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_INTERFACE)"));
if (data != NULL && len > 1) {
USETW(udata, 0);
@@ -757,7 +757,7 @@ umouse_data_handler(void *scarg, struct usb_data_xfer *xfer, int dir,
sc->polling = 0;
pthread_mutex_unlock(&sc->mtx);
- } else {
+ } else {
USB_DATA_SET_ERRCODE(data, USB_STALL);
err = USB_ERR_STALLED;
}
diff --git a/usr/src/cmd/bhyvectl/Makefile b/usr/src/cmd/bhyvectl/Makefile
index 01d331c823..486f39da31 100644
--- a/usr/src/cmd/bhyvectl/Makefile
+++ b/usr/src/cmd/bhyvectl/Makefile
@@ -35,6 +35,9 @@ CPPFLAGS = -I$(COMPAT)/bhyve -I$(CONTRIB)/bhyve \
-I$(SRC)/uts/i86pc
LDLIBS += -lvmmapi
+# Force c99 for everything
+CSTD= $(CSTD_GNU99)
+
CERRWARN += -_gcc=-Wno-uninitialized
# main() is too hairy for smatch
diff --git a/usr/src/cmd/bhyvectl/bhyvectl.c b/usr/src/cmd/bhyvectl/bhyvectl.c
index 4fc6ddc251..cbe779a4ea 100644
--- a/usr/src/cmd/bhyvectl/bhyvectl.c
+++ b/usr/src/cmd/bhyvectl/bhyvectl.c
@@ -39,7 +39,7 @@
*
* Copyright 2015 Pluribus Networks Inc.
* Copyright 2019 Joyent, Inc.
- * Copyright 2021 Oxide Computer Company
+ * Copyright 2022 Oxide Computer Company
*/
#include <sys/cdefs.h>
@@ -51,6 +51,9 @@ __FBSDID("$FreeBSD$");
#include <sys/errno.h>
#include <sys/mman.h>
#include <sys/cpuset.h>
+#ifndef __FreeBSD__
+#include <sys/fp.h>
+#endif /* __FreeBSD__ */
#include <stdio.h>
#include <stdlib.h>
@@ -312,6 +315,7 @@ static int get_cpu_topology;
#ifndef __FreeBSD__
static int pmtmr_port;
static int wrlock_cycle;
+static int get_fpu;
#endif
/*
@@ -1534,6 +1538,7 @@ setup_options(bool cpu_intel)
#ifndef __FreeBSD__
{ "pmtmr-port", REQ_ARG, 0, PMTMR_PORT },
{ "wrlock-cycle", NO_ARG, &wrlock_cycle, 1 },
+ { "get-fpu", NO_ARG, &get_fpu, 1 },
#endif
};
@@ -1752,6 +1757,93 @@ show_memseg(struct vmctx *ctx)
}
}
+#ifndef __FreeBSD__
+static int
+show_fpu(struct vmctx *ctx, int vcpu)
+{
+ int res, fd;
+
+ struct vm_fpu_desc_entry entries[64];
+ struct vm_fpu_desc desc = {
+ .vfd_entry_data = entries,
+ .vfd_num_entries = 64,
+ };
+ fd = vm_get_device_fd(ctx);
+ res = ioctl(fd, VM_DESC_FPU_AREA, &desc);
+ if (res != 0) {
+ return (errno);
+ }
+ for (uint_t i = 0; i < desc.vfd_num_entries; i++) {
+ const struct vm_fpu_desc_entry *entry = &entries[i];
+
+ /* confirm that AVX fields are where we expect */
+ if (entry->vfde_feature == XFEATURE_AVX) {
+ if (entry->vfde_size != 0x100 ||
+ entry->vfde_off != 0x240) {
+ (void) fprintf(stderr,
+ "show_fpu: unexpected AVX size/placement "
+ "- size:%x off:%x\n",
+ entry->vfde_size, entry->vfde_off);
+ return (EINVAL);
+ }
+ }
+ }
+ void *buf = malloc(desc.vfd_req_size);
+ if (buf == NULL) {
+ return (ENOMEM);
+ }
+ struct vm_fpu_state req = {
+ .vcpuid = vcpu,
+ .buf = buf,
+ .len = desc.vfd_req_size,
+ };
+ res = ioctl(fd, VM_GET_FPU, &req);
+ if (res != 0) {
+ res = errno;
+ free(buf);
+ return (res);
+ }
+
+ const struct xsave_state *state = buf;
+ const struct fxsave_state *fx = &state->xs_fxsave;
+ (void) printf("fpu_fcw[%d]\t\t0x%04x\n", vcpu, fx->fx_fcw);
+ (void) printf("fpu_fsw[%d]\t\t0x%04x\n", vcpu, fx->fx_fsw);
+ (void) printf("fpu_ftw[%d]\t\t0x%04x\n", vcpu, fx->fx_fctw);
+ (void) printf("fpu_fop[%d]\t\t0x%04x\n", vcpu, fx->fx_fop);
+ (void) printf("fpu_rip[%d]\t\t0x%016lx\n", vcpu, fx->fx_rip);
+ (void) printf("fpu_rdp[%d]\t\t0x%016lx\n", vcpu, fx->fx_rdp);
+ (void) printf("fpu_mxcsr[%d]\t\t0x%08x\n", vcpu, fx->fx_mxcsr);
+ (void) printf("fpu_mxcsr_mask[%d]\t0x%08x\n", vcpu,
+ fx->fx_mxcsr_mask);
+ /* ST/MMX regs */
+ for (uint_t i = 0; i < 8; i++) {
+ (void) printf("fpu_st%u[%d]\t\t0x%08x%08x%08x%08x\n", vcpu, i,
+ fx->fx_st[i].__fpr_pad[0], fx->fx_st[i].__fpr_pad[1],
+ fx->fx_st[i].__fpr_pad[2], fx->fx_st[i].__fpr_pad[3]);
+ }
+ /* SSE regs */
+ for (uint_t i = 0; i < 16; i++) {
+ (void) printf("fpu_xmm%u[%d]\t\t0x%08x%08x%08x%08x\n",
+ i, vcpu,
+ fx->fx_xmm[i]._l[0], fx->fx_xmm[i]._l[1],
+ fx->fx_xmm[i]._l[2], fx->fx_xmm[i]._l[3]);
+ }
+
+ if (state->xs_header.xsh_xstate_bv & XFEATURE_AVX) {
+ /* AVX regs */
+ for (uint_t i = 0; i < 16; i++) {
+ (void) printf("fpu_ymm%u[%d]\t\t0x%08x%08x%08x%08x\n",
+ i, vcpu,
+ state->xs_ymm[i]._l[0], state->xs_ymm[i]._l[1],
+ state->xs_ymm[i]._l[2], state->xs_ymm[i]._l[3]);
+ }
+ }
+
+ free(buf);
+ return (0);
+}
+#endif /*__FreeBSD__ */
+
int
main(int argc, char *argv[])
{
@@ -2150,6 +2242,12 @@ main(int argc, char *argv[])
if (!error)
error = get_all_segments(ctx, vcpu);
+#ifndef __FreeBSD__
+ if (!error && (get_fpu || get_all)) {
+ error = show_fpu(ctx, vcpu);
+ }
+#endif /* __FreeBSD__ */
+
if (!error) {
if (cpu_intel)
error = get_misc_vmcs(ctx, vcpu);
diff --git a/usr/src/cmd/cmd-inet/etc/services b/usr/src/cmd/cmd-inet/etc/services
index 37514ac0a7..4562baff66 100644
--- a/usr/src/cmd/cmd-inet/etc/services
+++ b/usr/src/cmd/cmd-inet/etc/services
@@ -1,6 +1,7 @@
#
# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright 2015 Joyent, Inc.
#
# CDDL HEADER START
#
@@ -33,7 +34,7 @@ systat 11/tcp users
daytime 13/tcp
daytime 13/udp
netstat 15/tcp
-qotd 17/tcp # Quote of the Day
+qotd 17/tcp # Quote of the Day
chargen 19/tcp ttytst source
chargen 19/udp ttytst source
ftp-data 20/tcp
@@ -80,7 +81,7 @@ imap3 220/tcp
imap3 220/udp
clearcase 371/tcp
clearcase 371/udp
-ldap 389/tcp # Lightweight Directory Access Protocol
+ldap 389/tcp # Lightweight Directory Access Protocol
ldap 389/udp # Lightweight Directory Access Protocol
https 443/tcp
https 443/udp
@@ -227,6 +228,7 @@ eklogin 2105/tcp # Kerberos encrypted rlogin
lockd 4045/udp # NFS lock daemon/manager
lockd 4045/tcp
ipsec-nat-t 4500/udp # IPsec NAT-Traversal
+vxlan 4789/udp # Virtual eXtensible Local Area Network (VXLAN)
mdns 5353/udp # Multicast DNS
mdns 5353/tcp
vnc-server 5900/tcp # VNC Server
diff --git a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/ndp.xml b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/ndp.xml
index e90b3ba149..4459def5c8 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/ndp.xml
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/ndp.xml
@@ -76,7 +76,7 @@
value='solaris.smf.manage.routing' />
</property_group>
- <!-- Properties in this group are used by routeadm (1M) -->
+ <!-- Properties in this group are used by routeadm(8) -->
<property_group name='routeadm' type='application'>
<stability value='Unstable' />
<!--
@@ -94,7 +94,7 @@
</property_group>
- <!-- Properties in this group are modifiable via routeadm (1M) -->
+ <!-- Properties in this group are modifiable via routeadm(8) -->
<property_group name='routing' type='application'>
<stability value='Evolving' />
diff --git a/usr/src/cmd/cmd-inet/usr.lib/in.ripngd/ripng.xml b/usr/src/cmd/cmd-inet/usr.lib/in.ripngd/ripng.xml
index 17b697fe95..fbfc77bee1 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ripngd/ripng.xml
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ripngd/ripng.xml
@@ -95,7 +95,7 @@ privileges='basic,proc_owner,proc_fork,proc_exec,proc_info,proc_session,file_cho
value='solaris.smf.manage.routing' />
</property_group>
- <!-- Properties in this group are used by routeadm (1M) -->
+ <!-- Properties in this group are used by routeadm(8) -->
<property_group name='routeadm' type='application'>
<stability value='Unstable' />
<!-- Identifies service as a routing service -->
@@ -106,7 +106,7 @@ privileges='basic,proc_owner,proc_fork,proc_exec,proc_info,proc_session,file_cho
value='solaris.smf.value.routing' />
</property_group>
- <!-- Properties in this group are modifiable via routeadm (1M) -->
+ <!-- Properties in this group are modifiable via routeadm(8) -->
<property_group name='routing' type='application'>
<stability value='Evolving' />
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/in.rdisc/rdisc.xml b/usr/src/cmd/cmd-inet/usr.sbin/in.rdisc/rdisc.xml
index 3cdd0cd35c..2ef0b8701b 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.rdisc/rdisc.xml
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.rdisc/rdisc.xml
@@ -78,7 +78,7 @@ privileges='basic,proc_owner,proc_fork,proc_exec,proc_info,proc_session,file_cho
value='solaris.smf.manage.routing' />
</property_group>
- <!-- Properties in this group are used by routeadm (1M) -->
+ <!-- Properties in this group are used by routeadm(8) -->
<property_group name='routeadm' type='application'>
<stability value='Unstable' />
<propval name='protocol' type='astring' value='ipv4' />
@@ -89,7 +89,7 @@ privileges='basic,proc_owner,proc_fork,proc_exec,proc_info,proc_session,file_cho
</property_group>
- <!-- Properties in this group are modifiable via routeadm (1M) -->
+ <!-- Properties in this group are modifiable via routeadm(8) -->
<property_group name='routing' type='application'>
<stability value='Evolving' />
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/in.rlogind.c b/usr/src/cmd/cmd-inet/usr.sbin/in.rlogind.c
index 5d3bc60abf..1c495aff84 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.rlogind.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.rlogind.c
@@ -3,8 +3,8 @@
* Use is subject to license terms.
*/
-/* Copyright(c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
+/* Copyright(c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
/*
* Copyright (c) 1983 The Regents of the University of California.
@@ -1057,13 +1057,13 @@ doit(int f,
if ((p = open("/dev/ptmx", O_RDWR)) == -1)
fatalperror(f, "cannot open /dev/ptmx");
if (grantpt(p) == -1)
- fatal(f, "could not grant slave pty");
+ fatal(f, "could not grant subsidiary pty");
if (unlockpt(p) == -1)
- fatal(f, "could not unlock slave pty");
+ fatal(f, "could not unlock subsidiary pty");
if ((line = ptsname(p)) == NULL)
- fatal(f, "could not enable slave pty");
+ fatal(f, "could not enable subsidiary pty");
if ((t = open(line, O_RDWR)) == -1)
- fatal(f, "could not open slave pty");
+ fatal(f, "could not open subsidiary pty");
if (ioctl(t, I_PUSH, "ptem") == -1)
fatalperror(f, "ioctl I_PUSH ptem");
if (ioctl(t, I_PUSH, "ldterm") == -1)
@@ -1128,9 +1128,9 @@ doit(int f,
/*
* System V ptys allow the TIOC{SG}WINSZ ioctl to be
- * issued on the master side of the pty. Luckily, that's
+ * issued on the manager side of the pty. Luckily, that's
* the only tty ioctl we need to do do, so we can close the
- * slave side in the parent process after the fork.
+ * subsidiary side in the parent process after the fork.
*/
(void) ioctl(p, TIOCSWINSZ, &win);
@@ -1161,12 +1161,12 @@ doit(int f,
if (setsid() == -1)
fatalperror(f, "setsid");
if ((tt = open(line, O_RDWR)) == -1)
- fatalperror(f, "could not re-open slave pty");
+ fatalperror(f, "could not re-open subsidiary pty");
if (close(p) == -1)
- fatalperror(f, "error closing pty master");
+ fatalperror(f, "error closing pty manager");
if (close(t) == -1)
- fatalperror(f, "error closing pty slave"
+ fatalperror(f, "error closing pty subsidiary"
" opened before session established");
/*
* If this fails we may or may not be able to output an
@@ -1209,8 +1209,8 @@ doit(int f,
/*
* Must ignore SIGTTOU, otherwise we'll stop
- * when we try and set slave pty's window shape
- * (our controlling tty is the master pty).
+ * when we try and set subsidiary pty's window shape
+ * (our controlling tty is the manager pty).
* Likewise, we don't want any of the tty-generated
* signals from chars passing through.
*/
@@ -1332,7 +1332,7 @@ static void
protocol(int f, int p, int encr_flag)
{
struct stat buf;
- struct protocol_arg rloginp;
+ struct protocol_arg rloginp;
struct strioctl rloginmod;
int ptmfd; /* fd of logindmux coneected to ptmx */
int netfd; /* fd of logindmux connected to netf */
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/route.xml b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/route.xml
index 3e10fbacd2..e9d73eb57f 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/route.xml
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/route.xml
@@ -80,7 +80,7 @@ privileges='basic,proc_owner,proc_fork,proc_exec,proc_info,proc_session,file_cho
value='solaris.smf.manage.routing' />
</property_group>
- <!-- Properties in this group are used by routeadm (1M) -->
+ <!-- Properties in this group are used by routeadm(8) -->
<property_group name='routeadm' type='application'>
<stability value='Unstable' />
<propval name='protocol' type='astring' value='ipv4' />
@@ -90,7 +90,7 @@ privileges='basic,proc_owner,proc_fork,proc_exec,proc_info,proc_session,file_cho
value='solaris.smf.value.routing' />
</property_group>
- <!-- Properties in this group are modifiable via routeadm (1M) -->
+ <!-- Properties in this group are modifiable via routeadm(8) -->
<property_group name='routing' type='application'>
<stability value='Evolving' />
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/in.telnetd.c b/usr/src/cmd/cmd-inet/usr.sbin/in.telnetd.c
index aa5a27c0b7..08ad200c45 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.telnetd.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.telnetd.c
@@ -242,7 +242,7 @@ static int cryptmod_fd = -1;
#define TS_DONT 8 /* dont " */
static int ncc;
-static int master; /* master side of pty */
+static int manager; /* manager side of pty */
static int pty; /* side of pty that gets ioctls */
static int net;
static int inter;
@@ -2754,20 +2754,20 @@ doit(int f, struct sockaddr_storage *who)
char username[MAXUSERNAMELEN];
int len;
uchar_t passthru;
- char *slavename;
+ char *subsidname;
if ((p = open("/dev/ptmx", O_RDWR | O_NOCTTY)) == -1) {
fatalperror(f, "open /dev/ptmx", errno);
}
if (grantpt(p) == -1)
- fatal(f, "could not grant slave pty");
+ fatal(f, "could not grant subsidiary pty");
if (unlockpt(p) == -1)
- fatal(f, "could not unlock slave pty");
- if ((slavename = ptsname(p)) == NULL)
- fatal(f, "could not enable slave pty");
+ fatal(f, "could not unlock subsidiary pty");
+ if ((subsidname = ptsname(p)) == NULL)
+ fatal(f, "could not enable subsidiary pty");
(void) dup2(f, 0);
- if ((t = open(slavename, O_RDWR | O_NOCTTY)) == -1)
- fatal(f, "could not open slave pty");
+ if ((t = open(subsidname, O_RDWR | O_NOCTTY)) == -1)
+ fatal(f, "could not open subsidiary pty");
if (ioctl(t, I_PUSH, "ptem") == -1)
fatalperror(f, "ioctl I_PUSH ptem", errno);
if (ioctl(t, I_PUSH, "ldterm") == -1)
@@ -2775,7 +2775,7 @@ doit(int f, struct sockaddr_storage *who)
if (ioctl(t, I_PUSH, "ttcompat") == -1)
fatalperror(f, "ioctl I_PUSH ttcompat", errno);
- line = slavename;
+ line = subsidname;
pty = t;
@@ -3039,7 +3039,7 @@ doit(int f, struct sockaddr_storage *who)
fatal(netfd, "ioctl LOGDMX_IOC_QEXCHANGE of ptmfd failed\n");
net = netfd;
- master = ptmfd;
+ manager = ptmfd;
cryptmod_fd = netfd;
/*
@@ -3100,11 +3100,11 @@ doit(int f, struct sockaddr_storage *who)
if ((pid = fork()) < 0)
fatalperror(netfd, "fork", errno);
if (pid)
- telnet(net, master);
+ telnet(net, manager);
/*
* The child process needs to be the session leader
* and have the pty as its controlling tty. Thus we need
- * to re-open the slave side of the pty no without
+ * to re-open the subsidiary side of the pty no without
* the O_NOCTTY flag that we have been careful to
* use up to this point.
*/
@@ -3130,10 +3130,10 @@ doit(int f, struct sockaddr_storage *who)
if (terminaltype)
(void) local_setenv("TERM", terminaltype+5, 1);
/*
- * -h : pass on name of host.
+ * -h : pass on name of host.
* WARNING: -h is accepted by login if and only if
* getuid() == 0.
- * -p : don't clobber the environment (so terminal type stays set).
+ * -p : don't clobber the environment (so terminal type stays set).
*/
{
/* System V login expects a utmp entry to already be there */
@@ -3192,7 +3192,7 @@ doit(int f, struct sockaddr_storage *who)
((AuthenticatingUser != NULL) && strlen(AuthenticatingUser))) {
(void) execl(LOGIN_PROGRAM, "login",
"-p",
- "-d", slavename,
+ "-d", subsidname,
"-h", host,
"-u", krb5_name,
"-s", pam_svc_name,
@@ -3208,7 +3208,7 @@ doit(int f, struct sockaddr_storage *who)
*/
(void) execl(LOGIN_PROGRAM, "login",
"-p",
- "-d", slavename,
+ "-d", subsidname,
"-h", host,
"-s", pam_svc_name, "--",
(AuthenticatingUser != NULL ? AuthenticatingUser :
@@ -3216,7 +3216,7 @@ doit(int f, struct sockaddr_storage *who)
} else /* default, no auth. info available, login does it all */ {
(void) execl(LOGIN_PROGRAM, "login",
- "-p", "-h", host, "-d", slavename, "--",
+ "-p", "-h", host, "-d", subsidname, "--",
getenv("USER"), 0);
}
@@ -3254,7 +3254,7 @@ fatalperror(int f, char *msg, int errnum)
* inkernel telnet streams module (telmod).
*/
static void
-telnet(int net, int master)
+telnet(int net, int manager)
{
int on = 1;
char mode;
@@ -3265,7 +3265,7 @@ telnet(int net, int master)
if (ioctl(net, FIONBIO, &on) == -1)
syslog(LOG_INFO, "ioctl FIONBIO net: %m\n");
- if (ioctl(master, FIONBIO, &on) == -1)
+ if (ioctl(manager, FIONBIO, &on) == -1)
syslog(LOG_INFO, "ioctl FIONBIO pty p: %m\n");
(void) signal(SIGTSTP, SIG_IGN);
(void) signal(SIGCHLD, (void (*)())cleanup);
@@ -3302,7 +3302,7 @@ telnet(int net, int master)
* stuff in the corresponding output buffer
*/
if (pfrontp - pbackp) {
- FD_SET(master, &obits);
+ FD_SET(manager, &obits);
} else {
FD_SET(net, &ibits);
}
@@ -3390,7 +3390,7 @@ telnet(int net, int master)
fatal(net, "ioctl TEL_IOC_GETBLK failed\n");
}
- if ((c = select(max(net, master) + 1, &ibits, &obits, &xbits,
+ if ((c = select(max(net, manager) + 1, &ibits, &obits, &xbits,
(struct timeval *)0)) < 1) {
if (c == -1) {
if (errno == EINTR) {
@@ -3427,7 +3427,7 @@ telnet(int net, int master)
netflush();
if (ncc > 0)
telrcv();
- if (FD_ISSET(master, &obits) && (pfrontp - pbackp) > 0)
+ if (FD_ISSET(manager, &obits) && (pfrontp - pbackp) > 0)
ptyflush();
}
cleanup(0);
@@ -4279,7 +4279,7 @@ ptyflush(void)
int n;
if ((n = pfrontp - pbackp) > 0)
- n = write(master, pbackp, n);
+ n = write(manager, pbackp, n);
if (n < 0)
return;
pbackp += n;
@@ -4447,9 +4447,9 @@ cleanup(int signum)
/*
* If the TEL_IOC_ENABLE ioctl hasn't completed, then we need to
* handle closing differently. We close "net" first and then
- * "master" in that order. We do close(net) first because
+ * "manager" in that order. We do close(net) first because
* we have no other way to disconnect forwarding between the network
- * and master. So by issuing the close()'s we ensure that no further
+ * and manager. So by issuing the close()'s we ensure that no further
* data rises from TCP. A more complex fix would be adding proper
* support for throwing a "stop" switch for forwarding data between
* logindmux peers. It's possible to block in the close of the tty
@@ -4460,7 +4460,7 @@ cleanup(int signum)
if (!telmod_init_done) {
(void) close(net);
- (void) close(master);
+ (void) close(manager);
}
rmut();
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/routeadm/forwarding.xml b/usr/src/cmd/cmd-inet/usr.sbin/routeadm/forwarding.xml
index 88e9b5b855..2bdcaa6299 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/routeadm/forwarding.xml
+++ b/usr/src/cmd/cmd-inet/usr.sbin/routeadm/forwarding.xml
@@ -108,7 +108,7 @@
value='solaris.smf.manage.routing' />
</property_group>
- <!-- Properties in this group are modifiable via routeadm (1M) -->
+ <!-- Properties in this group are modifiable via routeadm(8) -->
<property_group name='routeadm' type='application'>
<propval name='default-ipv4-forwarding' type='boolean'
value='false' />
@@ -212,7 +212,7 @@
value='solaris.smf.manage.routing' />
</property_group>
- <!-- Properties in this group are modifiable via routeadm (1M) -->
+ <!-- Properties in this group are modifiable via routeadm(8) -->
<property_group name='routeadm' type='application'>
<propval name='default-ipv6-forwarding' type='boolean'
value='false' />
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/routeadm/legacy-routing.xml b/usr/src/cmd/cmd-inet/usr.sbin/routeadm/legacy-routing.xml
index 33b0bde139..30902c43b5 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/routeadm/legacy-routing.xml
+++ b/usr/src/cmd/cmd-inet/usr.sbin/routeadm/legacy-routing.xml
@@ -94,7 +94,7 @@
<instance name='ipv4' enabled='false'>
- <!-- Properties in this group are used by routeadm (1M) -->
+ <!-- Properties in this group are used by routeadm(8) -->
<property_group name='routeadm' type='application'>
<stability value='Evolving' />
<propval name='protocol' type='astring' value='ipv4' />
@@ -116,7 +116,7 @@
<instance name='ipv6' enabled='false'>
- <!-- Properties in this group are used by routeadm (1M) -->
+ <!-- Properties in this group are used by routeadm(8) -->
<property_group name='routeadm' type='application'>
<stability value='Evolving' />
<propval name='protocol' type='astring' value='ipv6' />
diff --git a/usr/src/cmd/dcs/sparc/sun4u/rdr_messages.c b/usr/src/cmd/dcs/sparc/sun4u/rdr_messages.c
index 187319c234..0ef0dde39d 100644
--- a/usr/src/cmd/dcs/sparc/sun4u/rdr_messages.c
+++ b/usr/src/cmd/dcs/sparc/sun4u/rdr_messages.c
@@ -1291,7 +1291,7 @@ rdr_setopt(int fd, int name, int level)
* Bind the specified file descriptor to a specified
* address. If the address is already bound, no error is
* returned. This is the expected behavior if a server
- * has been started by inetd (1M).
+ * has been started by inetd(8).
*/
static int
rdr_bind(int fd, struct sockaddr *addr)
@@ -1322,7 +1322,7 @@ rdr_bind(int fd, struct sockaddr *addr)
* Ignore the error if EINVAL is returned. In
* this case, we assume that this means that
* the address was already bound. This is not
- * an error for servers started by inetd (1M).
+ * an error for servers started by inetd(8).
*/
if ((rc == -1) && (errno != EINVAL)) {
return (RDR_NET_ERR);
diff --git a/usr/src/cmd/devfsadm/misc_link.c b/usr/src/cmd/devfsadm/misc_link.c
index 5f241df296..7397fcdb40 100644
--- a/usr/src/cmd/devfsadm/misc_link.c
+++ b/usr/src/cmd/devfsadm/misc_link.c
@@ -204,6 +204,9 @@ static devfsadm_create_t misc_cbt[] = {
{ "pseudo", "ddi_pseudo", "tpm",
TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name
},
+ { "pseudo", "ddi_pseudo", "overlay",
+ TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name
+ }
};
DEVFSADM_CREATE_INIT_V0(misc_cbt);
@@ -224,8 +227,8 @@ static devfsadm_remove_t misc_remove_cbt[] = {
{ "pseudo", "^daplt$",
RM_PRE | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all
},
- { "pseudo", "^zcons/" ZONENAME_REGEXP "/(" ZCONS_MASTER_NAME "|"
- ZCONS_SLAVE_NAME ")$",
+ { "pseudo", "^zcons/" ZONENAME_REGEXP "/(" ZCONS_MANAGER_NAME "|"
+ ZCONS_SUBSIDIARY_NAME ")$",
RM_PRE | RM_HOT | RM_ALWAYS, ILEVEL_0, devfsadm_rm_all
},
{ "pseudo", "^" CPUID_SELF_NAME "$", RM_ALWAYS | RM_PRE | RM_HOT,
@@ -474,7 +477,7 @@ fc_port(di_minor_t minor, di_node_t node)
/*
* Handles:
* minor node type "ddi_printer".
- * rules of the form: type=ddi_printer;name=bpp \M0
+ * rules of the form: type=ddi_printer;name=bpp \M0
*/
static int
printer_create(di_minor_t minor, di_node_t node)
@@ -676,7 +679,7 @@ zcons_create(di_minor_t minor, di_node_t node)
}
/*
- * /dev/cpu/self/cpuid -> /devices/pseudo/cpuid@0:self
+ * /dev/cpu/self/cpuid -> /devices/pseudo/cpuid@0:self
*/
static int
cpuid(di_minor_t minor, di_node_t node)
diff --git a/usr/src/cmd/dladm/Makefile b/usr/src/cmd/dladm/Makefile
index 6171822797..bba8a8cede 100644
--- a/usr/src/cmd/dladm/Makefile
+++ b/usr/src/cmd/dladm/Makefile
@@ -20,6 +20,7 @@
#
# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+# Copyright 2015 Joyent, Inc.
#
# Copyright (c) 2018, Joyent, Inc.
@@ -38,7 +39,7 @@ XGETFLAGS += -a -x $(PROG).xcl
LDLIBS += -L$(ROOT)/lib -lsocket
LDLIBS += -ldladm -ldlpi -lkstat -lsecdb -lbsm -lofmt -linetutil -ldevinfo
-LDLIBS += $(ZLAZYLOAD) -lrstp $(ZNOLAZYLOAD)
+LDLIBS += $(ZLAZYLOAD) -lrstp $(ZNOLAZYLOAD) -lnsl -lumem -lcustr
CERRWARN += -_gcc=-Wno-switch
CERRWARN += -_gcc=-Wno-unused-label
diff --git a/usr/src/cmd/dladm/dladm.c b/usr/src/cmd/dladm/dladm.c
index 21ff6ce195..020d0d7266 100644
--- a/usr/src/cmd/dladm/dladm.c
+++ b/usr/src/cmd/dladm/dladm.c
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2016 Nexenta Systems, Inc.
+ * Copyright (c) 2015 Joyent, Inc. All rights reserved.
* Copyright 2020 Peter Tribble.
* Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
*/
@@ -63,6 +64,7 @@
#include <libdliptun.h>
#include <libdlsim.h>
#include <libdlbridge.h>
+#include <libdloverlay.h>
#include <libinetutil.h>
#include <libvrrpadm.h>
#include <bsm/adt.h>
@@ -78,6 +80,7 @@
#include <stddef.h>
#include <stp_in.h>
#include <ofmt.h>
+#include <libcustr.h>
#define MAXPORT 256
#define MAXVNIC 256
@@ -196,6 +199,7 @@ static ofmt_cb_t print_lacp_cb, print_phys_one_mac_cb;
static ofmt_cb_t print_xaggr_cb, print_aggr_stats_cb;
static ofmt_cb_t print_phys_one_hwgrp_cb, print_wlan_attr_cb;
static ofmt_cb_t print_wifi_status_cb, print_link_attr_cb;
+static ofmt_cb_t print_overlay_cb, print_overlay_fma_cb, print_overlay_targ_cb;
typedef void cmdfunc_t(int, char **, const char *);
@@ -223,6 +227,8 @@ static cmdfunc_t do_create_bridge, do_modify_bridge, do_delete_bridge;
static cmdfunc_t do_add_bridge, do_remove_bridge, do_show_bridge;
static cmdfunc_t do_create_iptun, do_modify_iptun, do_delete_iptun;
static cmdfunc_t do_show_iptun, do_up_iptun, do_down_iptun;
+static cmdfunc_t do_create_overlay, do_delete_overlay, do_modify_overlay;
+static cmdfunc_t do_show_overlay;
static void do_up_vnic_common(int, char **, const char *, boolean_t);
@@ -258,8 +264,11 @@ static void die(const char *, ...);
static void die_optdup(int);
static void die_opterr(int, int, const char *);
static void die_dlerr(dladm_status_t, const char *, ...);
+static void die_dlerrlist(dladm_status_t, dladm_errlist_t *,
+ const char *, ...);
static void warn(const char *, ...);
static void warn_dlerr(dladm_status_t, const char *, ...);
+static void warn_dlerrlist(dladm_errlist_t *);
typedef struct cmd {
char *c_name;
@@ -406,6 +415,17 @@ static cmd_t cmds[] = {
" <bridge>\n"
" show-bridge -t [-p] [-o <field>,...] [-s [-i <interval>]]"
" <bridge>\n" },
+ { "create-overlay", do_create_overlay,
+ " create-overlay [-t] -e <encap> -s <search> -v <vnetid>\n"
+ "\t\t [ -p <prop>=<value>[,...]] <overlay>" },
+ { "delete-overlay", do_delete_overlay,
+ " delete-overlay <overlay>" },
+ { "modify-overlay", do_modify_overlay,
+ " modify-overlay -d mac | -f | -s mac=ip:port "
+ "<overlay>" },
+ { "show-overlay", do_show_overlay,
+ " show-overlay [-f | -t] [[-p] -o <field>,...] "
+ "[<overlay>]\n" },
{ "show-usage", do_show_usage,
" show-usage [-a] [-d | -F <format>] "
"[-s <DD/MM/YYYY,HH:MM:SS>]\n"
@@ -1430,6 +1450,82 @@ static ofmt_field_t bridge_trill_fields[] = {
offsetof(bridge_trill_fields_buf_t, bridget_nexthop), print_default_cb },
{ NULL, 0, 0, NULL}};
+static const struct option overlay_create_lopts[] = {
+ { "encap", required_argument, NULL, 'e' },
+ { "prop", required_argument, NULL, 'p' },
+ { "search", required_argument, NULL, 's' },
+ { "temporary", no_argument, NULL, 't' },
+ { "vnetid", required_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0 }
+};
+
+static const struct option overlay_modify_lopts[] = {
+ { "delete-entry", required_argument, NULL, 'd' },
+ { "flush-table", no_argument, NULL, 'f' },
+ { "set-entry", required_argument, NULL, 's' },
+ { NULL, 0, NULL, 0 }
+};
+
+static const struct option overlay_show_lopts[] = {
+ { "fma", no_argument, NULL, 'f' },
+ { "target", no_argument, NULL, 't' },
+ { "parsable", no_argument, NULL, 'p' },
+ { "parseable", no_argument, NULL, 'p' },
+ { "output", required_argument, NULL, 'o' },
+ { NULL, 0, NULL, 0 }
+};
+
+/*
+ * Structures for dladm show-overlay
+ */
+typedef enum {
+ OVERLAY_LINK,
+ OVERLAY_PROPERTY,
+ OVERLAY_PERM,
+ OVERLAY_REQ,
+ OVERLAY_VALUE,
+ OVERLAY_DEFAULT,
+ OVERLAY_POSSIBLE
+} overlay_field_index_t;
+
+static const ofmt_field_t overlay_fields[] = {
+/* name, field width, index */
+{ "LINK", 19, OVERLAY_LINK, print_overlay_cb },
+{ "PROPERTY", 19, OVERLAY_PROPERTY, print_overlay_cb },
+{ "PERM", 5, OVERLAY_PERM, print_overlay_cb },
+{ "REQ", 4, OVERLAY_REQ, print_overlay_cb },
+{ "VALUE", 11, OVERLAY_VALUE, print_overlay_cb },
+{ "DEFAULT", 10, OVERLAY_DEFAULT, print_overlay_cb },
+{ "POSSIBLE", 10, OVERLAY_POSSIBLE, print_overlay_cb },
+{ NULL, 0, 0, NULL }
+};
+
+typedef enum {
+ OVERLAY_FMA_LINK,
+ OVERLAY_FMA_STATUS,
+ OVERLAY_FMA_DETAILS
+} overlay_fma_field_index_t;
+
+static const ofmt_field_t overlay_fma_fields[] = {
+{ "LINK", 20, OVERLAY_FMA_LINK, print_overlay_fma_cb },
+{ "STATUS", 8, OVERLAY_FMA_STATUS, print_overlay_fma_cb },
+{ "DETAILS", 52, OVERLAY_FMA_DETAILS, print_overlay_fma_cb },
+{ NULL, 0, 0, NULL }
+};
+
+typedef enum {
+ OVERLAY_TARG_LINK,
+ OVERLAY_TARG_TARGET,
+ OVERLAY_TARG_DEST
+} overlay_targ_field_index_t;
+
+static const ofmt_field_t overlay_targ_fields[] = {
+{ "LINK", 20, OVERLAY_TARG_LINK, print_overlay_targ_cb },
+{ "TARGET", 18, OVERLAY_TARG_TARGET, print_overlay_targ_cb },
+{ "DESTINATION", 42, OVERLAY_TARG_DEST, print_overlay_targ_cb },
+{ NULL, 0, 0, NULL }
+};
+
static char *progname;
static sig_atomic_t signalled;
@@ -1439,6 +1535,12 @@ static sig_atomic_t signalled;
*/
static dladm_handle_t handle = NULL;
+/*
+ * Global error list that all routines can use. It's initialized by the main
+ * code.
+ */
+static dladm_errlist_t errlist;
+
#define DLADM_ETHERSTUB_NAME "etherstub"
#define DLADM_IS_ETHERSTUB(id) (id == DATALINK_INVALID_LINKID)
@@ -1506,6 +1608,8 @@ main(int argc, char *argv[])
"could not open /dev/dld");
}
+ dladm_errlist_init(&errlist);
+
cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage);
dladm_close(handle);
@@ -4801,7 +4905,7 @@ do_create_vnic(int argc, char *argv[], const char *use)
status = dladm_vnic_create(handle, name, dev_linkid, mac_addr_type,
mac_addr, maclen, &mac_slot, mac_prefix_len, vid, vrid, af,
- &linkid, proplist, flags);
+ &linkid, proplist, &errlist, flags);
switch (status) {
case DLADM_STATUS_OK:
break;
@@ -4812,7 +4916,8 @@ do_create_vnic(int argc, char *argv[], const char *use)
break;
default:
- die_dlerr(status, "vnic creation over %s failed", devname);
+ die_dlerrlist(status, &errlist, "vnic creation over %s failed",
+ devname);
}
dladm_free_props(proplist);
@@ -5311,7 +5416,7 @@ do_create_etherstub(int argc, char *argv[], const char *use)
status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID,
VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0,
- VRRP_VRID_NONE, AF_UNSPEC, NULL, NULL, flags);
+ VRRP_VRID_NONE, AF_UNSPEC, NULL, NULL, &errlist, flags);
if (status != DLADM_STATUS_OK)
die_dlerr(status, "etherstub creation failed");
}
@@ -8953,6 +9058,21 @@ warn_dlerr(dladm_status_t err, const char *format, ...)
(void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
}
+static void
+warn_dlerrlist(dladm_errlist_t *errlist)
+{
+ if (errlist != NULL && errlist->el_count > 0) {
+ int i;
+ for (i = 0; i < errlist->el_count; i++) {
+ (void) fprintf(stderr, gettext("%s: warning: "),
+ progname);
+
+ (void) fprintf(stderr, "%s\n",
+ gettext(errlist->el_errs[i]));
+ }
+ }
+}
+
/*
* Also closes the dladm handle if it is not NULL.
*/
@@ -8978,6 +9098,34 @@ die_dlerr(dladm_status_t err, const char *format, ...)
exit(EXIT_FAILURE);
}
+/*
+ * Like die_dlerr, but uses the errlist for additional information.
+ */
+/* PRINTFLIKE3 */
+static void
+die_dlerrlist(dladm_status_t err, dladm_errlist_t *errlist,
+ const char *format, ...)
+{
+ va_list alist;
+ char errmsg[DLADM_STRSIZE];
+
+ warn_dlerrlist(errlist);
+ format = gettext(format);
+ (void) fprintf(stderr, "%s: ", progname);
+
+ va_start(alist, format);
+ (void) vfprintf(stderr, format, alist);
+ va_end(alist);
+ (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
+
+ /* close dladm handle if it was opened */
+ if (handle != NULL)
+ dladm_close(handle);
+
+ exit(EXIT_FAILURE);
+
+}
+
/* PRINTFLIKE1 */
static void
die(const char *format, ...)
@@ -9685,3 +9833,680 @@ do_up_part(int argc, char *argv[], const char *use)
(void) dladm_part_up(handle, partid, 0);
}
+
+static void
+do_create_overlay(int argc, char *argv[], const char *use)
+{
+ int opt;
+ char *encap = NULL, *endp, *search = NULL;
+ char name[MAXLINKNAMELEN];
+ dladm_status_t status;
+ uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
+ uint64_t vid = 0;
+ boolean_t havevid = B_FALSE;
+ char propstr[DLADM_STRSIZE];
+ dladm_arg_list_t *proplist = NULL;
+
+ bzero(propstr, sizeof (propstr));
+ while ((opt = getopt_long(argc, argv, ":te:v:p:s:",
+ overlay_create_lopts, NULL)) != -1) {
+ switch (opt) {
+ case 'e':
+ encap = optarg;
+ break;
+ case 's':
+ search = optarg;
+ break;
+ case 't':
+ flags &= ~DLADM_OPT_PERSIST;
+ break;
+ case 'p':
+ (void) strlcat(propstr, optarg, DLADM_STRSIZE);
+ if (strlcat(propstr, ",", DLADM_STRSIZE) >=
+ DLADM_STRSIZE)
+ die("property list too long '%s'", propstr);
+ break;
+ case 'v':
+ vid = strtoul(optarg, &endp, 10);
+ if (*endp != '\0' || (vid == 0 && errno == EINVAL))
+ die("couldn't parse virtual networkd id: %s",
+ optarg);
+ if (vid == ULONG_MAX && errno == ERANGE)
+ die("virtual networkd id too large: %s",
+ optarg);
+ havevid = B_TRUE;
+ break;
+ default:
+ die_opterr(optopt, opt, use);
+ }
+ }
+
+ /*
+ * Overlays do not currently support persistence.
+ * This will be addressed by https://www.illumos.org/issues/14434
+ */
+ if ((flags & DLADM_OPT_PERSIST) != 0)
+ die("overlays do not (yet) support persistence, use -t");
+
+ if (havevid == B_FALSE)
+ die("missing required virtual network id");
+
+ if (encap == NULL)
+ die("missing required encapsulation plugin");
+
+ if (search == NULL)
+ die("missing required search plugin");
+
+ if (optind != (argc - 1))
+ die("missing device name");
+
+ if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
+ die("link name too long '%s'", argv[optind]);
+
+ if (!dladm_valid_linkname(name))
+ die("invalid link name '%s'", argv[optind]);
+
+ if (strlen(encap) + 1 > MAXLINKNAMELEN)
+ die("encapsulation plugin name too long '%s'", encap);
+
+ if (strlen(search) + 1 > MAXLINKNAMELEN)
+ die("search plugin name too long '%s'", encap);
+
+ if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
+ != DLADM_STATUS_OK)
+ die("invalid overlay property");
+
+ status = dladm_overlay_create(handle, name, encap, search, vid,
+ proplist, &errlist, flags);
+ dladm_free_props(proplist);
+ if (status != DLADM_STATUS_OK) {
+ die_dlerrlist(status, &errlist, "overlay creation failed");
+ }
+}
+
+/* ARGSUSED */
+static void
+do_delete_overlay(int argc, char *argv[], const char *use)
+{
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
+ dladm_status_t status;
+
+ if (argc != 2) {
+ usage();
+ }
+
+ status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL, NULL);
+ if (status != DLADM_STATUS_OK)
+ die_dlerr(status, "failed to delete %s", argv[1]);
+
+ status = dladm_overlay_delete(handle, linkid);
+ if (status != DLADM_STATUS_OK)
+ die_dlerr(status, "failed to delete %s", argv[1]);
+}
+
+typedef struct showoverlay_state {
+ ofmt_handle_t sho_ofmt;
+ const char *sho_linkname;
+ dladm_overlay_propinfo_handle_t sho_info;
+ uint8_t sho_value[DLADM_OVERLAY_PROP_SIZEMAX];
+ uint32_t sho_size;
+} showoverlay_state_t;
+
+typedef struct showoverlay_fma_state {
+ ofmt_handle_t shof_ofmt;
+ const char *shof_linkname;
+ dladm_overlay_status_t *shof_status;
+} showoverlay_fma_state_t;
+
+typedef struct showoverlay_targ_state {
+ ofmt_handle_t shot_ofmt;
+ const char *shot_linkname;
+ const struct ether_addr *shot_key;
+ const dladm_overlay_point_t *shot_point;
+} showoverlay_targ_state_t;
+
+static void
+print_overlay_value(char *outbuf, uint_t bufsize, uint_t type, const void *pbuf,
+ const size_t psize)
+{
+ const struct in6_addr *ipv6;
+ struct in_addr ip;
+
+ switch (type) {
+ case OVERLAY_PROP_T_INT:
+ if (psize != 1 && psize != 2 && psize != 4 && psize != 8) {
+ (void) snprintf(outbuf, bufsize, "?");
+ break;
+ }
+ if (psize == 1)
+ (void) snprintf(outbuf, bufsize, "%d", *(int8_t *)pbuf);
+ if (psize == 2)
+ (void) snprintf(outbuf, bufsize, "%d",
+ *(int16_t *)pbuf);
+ if (psize == 4)
+ (void) snprintf(outbuf, bufsize, "%d",
+ *(int32_t *)pbuf);
+ if (psize == 8)
+ (void) snprintf(outbuf, bufsize, "%d",
+ *(int64_t *)pbuf);
+ break;
+ case OVERLAY_PROP_T_UINT:
+ if (psize != 1 && psize != 2 && psize != 4 && psize != 8) {
+ (void) snprintf(outbuf, bufsize, "?");
+ break;
+ }
+ if (psize == 1)
+ (void) snprintf(outbuf, bufsize, "%d",
+ *(uint8_t *)pbuf);
+ if (psize == 2)
+ (void) snprintf(outbuf, bufsize, "%d",
+ *(uint16_t *)pbuf);
+ if (psize == 4)
+ (void) snprintf(outbuf, bufsize, "%d",
+ *(uint32_t *)pbuf);
+ if (psize == 8)
+ (void) snprintf(outbuf, bufsize, "%d",
+ *(uint64_t *)pbuf);
+ break;
+ case OVERLAY_PROP_T_IP:
+ if (psize != sizeof (struct in6_addr)) {
+ warn("malformed overlay IP property: %d bytes\n",
+ psize);
+ (void) snprintf(outbuf, bufsize, "--");
+ break;
+ }
+
+ ipv6 = pbuf;
+ if (IN6_IS_ADDR_V4MAPPED(ipv6)) {
+ IN6_V4MAPPED_TO_INADDR(ipv6, &ip);
+ if (inet_ntop(AF_INET, &ip, outbuf, bufsize) == NULL) {
+ warn("malformed overlay IP property\n");
+ (void) snprintf(outbuf, bufsize, "--");
+ break;
+ }
+ } else {
+ if (inet_ntop(AF_INET6, ipv6, outbuf, bufsize) ==
+ NULL) {
+ warn("malformed overlay IP property\n");
+ (void) snprintf(outbuf, bufsize, "--");
+ break;
+ }
+ }
+
+ break;
+ case OVERLAY_PROP_T_STRING:
+ (void) snprintf(outbuf, bufsize, "%s", pbuf);
+ break;
+ default:
+ abort();
+ }
+
+ return;
+
+}
+
+static boolean_t
+print_overlay_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
+{
+ dladm_status_t status;
+ showoverlay_state_t *sp = ofarg->ofmt_cbarg;
+ dladm_overlay_propinfo_handle_t infop = sp->sho_info;
+ const char *pname;
+ uint_t type, prot;
+ const void *def;
+ uint32_t defsize;
+ const mac_propval_range_t *rangep;
+
+ if ((status = dladm_overlay_prop_info(infop, &pname, &type, &prot, &def,
+ &defsize, &rangep)) != DLADM_STATUS_OK) {
+ warn_dlerr(status, "failed to get get property info");
+ return (B_TRUE);
+ }
+
+ switch (ofarg->ofmt_id) {
+ case OVERLAY_LINK:
+ (void) snprintf(buf, bufsize, "%s", sp->sho_linkname);
+ break;
+ case OVERLAY_PROPERTY:
+ (void) snprintf(buf, bufsize, "%s", pname);
+ break;
+ case OVERLAY_PERM:
+ if ((prot & OVERLAY_PROP_PERM_RW) == OVERLAY_PROP_PERM_RW) {
+ (void) snprintf(buf, bufsize, "%s", "rw");
+ } else if ((prot & OVERLAY_PROP_PERM_RW) ==
+ OVERLAY_PROP_PERM_READ) {
+ (void) snprintf(buf, bufsize, "%s", "r-");
+ } else {
+ (void) snprintf(buf, bufsize, "%s", "--");
+ }
+ break;
+ case OVERLAY_REQ:
+ (void) snprintf(buf, bufsize, "%s",
+ prot & OVERLAY_PROP_PERM_REQ ? "y" : "-");
+ break;
+ case OVERLAY_VALUE:
+ if (sp->sho_size == 0) {
+ (void) snprintf(buf, bufsize, "%s", "--");
+ } else {
+ print_overlay_value(buf, bufsize, type, sp->sho_value,
+ sp->sho_size);
+ }
+ break;
+ case OVERLAY_DEFAULT:
+ if (defsize == 0) {
+ (void) snprintf(buf, bufsize, "%s", "--");
+ } else {
+ print_overlay_value(buf, bufsize, type, def, defsize);
+ }
+ break;
+ case OVERLAY_POSSIBLE: {
+ int i;
+ char **vals, *ptr, *lim;
+ if (rangep->mpr_count == 0) {
+ (void) snprintf(buf, bufsize, "%s", "--");
+ break;
+ }
+
+ vals = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
+ rangep->mpr_count);
+ if (vals == NULL)
+ die("insufficient memory");
+ for (i = 0; i < rangep->mpr_count; i++) {
+ vals[i] = (char *)vals + sizeof (char *) *
+ rangep->mpr_count + i * DLADM_MAX_PROP_VALCNT;
+ }
+
+ if (dladm_range2strs(rangep, vals) != 0) {
+ free(vals);
+ (void) snprintf(buf, bufsize, "%s", "?");
+ break;
+ }
+
+ ptr = buf;
+ lim = buf + bufsize;
+ for (i = 0; i < rangep->mpr_count; i++) {
+ ptr += snprintf(ptr, lim - ptr, "%s,", vals[i]);
+ if (ptr >= lim)
+ break;
+ }
+ if (rangep->mpr_count > 0)
+ buf[strlen(buf) - 1] = '\0';
+ free(vals);
+ break;
+ }
+ default:
+ abort();
+ }
+ return (B_TRUE);
+}
+
+static int
+dladm_overlay_show_one(dladm_handle_t handle, datalink_id_t linkid,
+ dladm_overlay_propinfo_handle_t phdl, void *arg)
+{
+ showoverlay_state_t *sp = arg;
+ sp->sho_info = phdl;
+
+ sp->sho_size = sizeof (sp->sho_value);
+ if (dladm_overlay_get_prop(handle, linkid, phdl, &sp->sho_value,
+ &sp->sho_size) != DLADM_STATUS_OK)
+ return (DLADM_WALK_CONTINUE);
+
+ ofmt_print(sp->sho_ofmt, sp);
+ return (DLADM_WALK_CONTINUE);
+}
+
+static int
+show_one_overlay(dladm_handle_t hdl, datalink_id_t linkid, void *arg)
+{
+ char buf[MAXLINKNAMELEN];
+ showoverlay_state_t state;
+ datalink_class_t class;
+
+ if (dladm_datalink_id2info(hdl, linkid, NULL, &class, NULL, buf,
+ MAXLINKNAMELEN) != DLADM_STATUS_OK ||
+ class != DATALINK_CLASS_OVERLAY)
+ return (DLADM_WALK_CONTINUE);
+
+ state.sho_linkname = buf;
+ state.sho_ofmt = arg;
+
+ dladm_errlist_reset(&errlist);
+ (void) dladm_overlay_walk_prop(handle, linkid, dladm_overlay_show_one,
+ &state, &errlist);
+ warn_dlerrlist(&errlist);
+
+ return (DLADM_WALK_CONTINUE);
+}
+
+static boolean_t
+print_overlay_targ_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
+{
+ char keybuf[ETHERADDRSTRL];
+ const showoverlay_targ_state_t *shot = ofarg->ofmt_cbarg;
+ const dladm_overlay_point_t *point = shot->shot_point;
+ char macbuf[ETHERADDRSTRL];
+ char ipbuf[INET6_ADDRSTRLEN];
+ custr_t *cus;
+
+ switch (ofarg->ofmt_id) {
+ case OVERLAY_TARG_LINK:
+ (void) snprintf(buf, bufsize, shot->shot_linkname);
+ break;
+ case OVERLAY_TARG_TARGET:
+ if ((point->dop_flags & DLADM_OVERLAY_F_DEFAULT) != 0) {
+ (void) snprintf(buf, bufsize, "*:*:*:*:*:*");
+ } else {
+ if (ether_ntoa_r(shot->shot_key, keybuf) == NULL) {
+ warn("encountered malformed mac address key\n");
+ return (B_FALSE);
+ }
+ (void) snprintf(buf, bufsize, "%s", keybuf);
+ }
+ break;
+ case OVERLAY_TARG_DEST:
+ if (custr_alloc_buf(&cus, buf, bufsize) != 0) {
+ die("ran out of memory for printing the overlay "
+ "target destination");
+ }
+
+ if (point->dop_dest & OVERLAY_PLUGIN_D_ETHERNET) {
+ if (ether_ntoa_r(&point->dop_mac, macbuf) == NULL) {
+ warn("encountered malformed mac address target "
+ "for key %s\n", keybuf);
+ return (B_FALSE);
+ }
+ (void) custr_append(cus, macbuf);
+ }
+
+ if (point->dop_dest & OVERLAY_PLUGIN_D_IP) {
+ if (IN6_IS_ADDR_V4MAPPED(&point->dop_ip)) {
+ struct in_addr v4;
+ IN6_V4MAPPED_TO_INADDR(&point->dop_ip, &v4);
+ if (inet_ntop(AF_INET, &v4, ipbuf,
+ sizeof (ipbuf)) == NULL)
+ abort();
+ } else if (inet_ntop(AF_INET6, &point->dop_ip, ipbuf,
+ sizeof (ipbuf)) == NULL) {
+ /*
+ * The only failures we should get are
+ * EAFNOSUPPORT and ENOSPC because of buffer
+ * exhaustion. In either of these cases, that
+ * means something has gone horribly wrong.
+ */
+ abort();
+ }
+ if (point->dop_dest & OVERLAY_PLUGIN_D_ETHERNET)
+ (void) custr_appendc(cus, ',');
+ (void) custr_append(cus, ipbuf);
+ }
+
+ if (point->dop_dest & OVERLAY_PLUGIN_D_PORT) {
+ if (point->dop_dest & OVERLAY_PLUGIN_D_IP)
+ (void) custr_appendc(cus, ':');
+ else if (point->dop_dest & OVERLAY_PLUGIN_D_ETHERNET)
+ (void) custr_appendc(cus, ',');
+ (void) custr_append_printf(cus, "%u", point->dop_port);
+ }
+
+ custr_free(cus);
+
+ break;
+ }
+ return (B_TRUE);
+}
+
+/* ARGSUSED */
+static int
+show_one_overlay_table_entry(dladm_handle_t handle, datalink_id_t linkid,
+ const struct ether_addr *key, const dladm_overlay_point_t *point, void *arg)
+{
+ showoverlay_targ_state_t *shot = arg;
+
+ shot->shot_key = key;
+ shot->shot_point = point;
+ ofmt_print(shot->shot_ofmt, shot);
+
+ return (DLADM_WALK_CONTINUE);
+}
+
+/* ARGSUSED */
+static int
+show_one_overlay_table(dladm_handle_t handle, datalink_id_t linkid, void *arg)
+{
+ char linkbuf[MAXLINKNAMELEN];
+ showoverlay_targ_state_t shot;
+ datalink_class_t class;
+
+ if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, linkbuf,
+ MAXLINKNAMELEN) != DLADM_STATUS_OK ||
+ class != DATALINK_CLASS_OVERLAY)
+ return (DLADM_WALK_CONTINUE);
+
+ shot.shot_ofmt = arg;
+ shot.shot_linkname = linkbuf;
+
+ (void) dladm_overlay_walk_cache(handle, linkid,
+ show_one_overlay_table_entry, &shot);
+
+ return (DLADM_WALK_CONTINUE);
+}
+
+static boolean_t
+print_overlay_fma_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
+{
+ showoverlay_fma_state_t *shof = ofarg->ofmt_cbarg;
+ dladm_overlay_status_t *st = shof->shof_status;
+
+ switch (ofarg->ofmt_id) {
+ case OVERLAY_FMA_LINK:
+ (void) snprintf(buf, bufsize, "%s", shof->shof_linkname);
+ break;
+ case OVERLAY_FMA_STATUS:
+ (void) snprintf(buf, bufsize, st->dos_degraded == B_TRUE ?
+ "DEGRADED": "ONLINE");
+ break;
+ case OVERLAY_FMA_DETAILS:
+ (void) snprintf(buf, bufsize, "%s", st->dos_degraded == B_TRUE ?
+ st->dos_fmamsg : "-");
+ break;
+ default:
+ abort();
+ }
+ return (B_TRUE);
+}
+
+/* ARGSUSED */
+static void
+show_one_overlay_fma_cb(dladm_handle_t handle, datalink_id_t linkid,
+ dladm_overlay_status_t *stat, void *arg)
+{
+ showoverlay_fma_state_t *shof = arg;
+ shof->shof_status = stat;
+ ofmt_print(shof->shof_ofmt, shof);
+}
+
+
+static int
+show_one_overlay_fma(dladm_handle_t handle, datalink_id_t linkid, void *arg)
+{
+ dladm_status_t status;
+ char linkbuf[MAXLINKNAMELEN];
+ datalink_class_t class;
+ showoverlay_fma_state_t shof;
+
+ if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, linkbuf,
+ MAXLINKNAMELEN) != DLADM_STATUS_OK ||
+ class != DATALINK_CLASS_OVERLAY) {
+ die("datalink %s is not an overlay device\n", linkbuf);
+ }
+
+ shof.shof_ofmt = arg;
+ shof.shof_linkname = linkbuf;
+
+ status = dladm_overlay_status(handle, linkid,
+ show_one_overlay_fma_cb, &shof);
+ if (status != DLADM_STATUS_OK)
+ die_dlerr(status, "failed to obtain device status for %s",
+ linkbuf);
+
+ return (DLADM_WALK_CONTINUE);
+}
+
+static void
+do_show_overlay(int argc, char *argv[], const char *use)
+{
+ int i, opt;
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
+ dladm_status_t status;
+ int (*funcp)(dladm_handle_t, datalink_id_t, void *);
+ char *fields_str = NULL;
+ const ofmt_field_t *fieldsp;
+ ofmt_status_t oferr;
+ boolean_t parse;
+ ofmt_handle_t ofmt;
+ uint_t ofmtflags;
+ int err;
+
+
+ funcp = show_one_overlay;
+ fieldsp = overlay_fields;
+ parse = B_FALSE;
+ ofmtflags = OFMT_WRAP;
+ while ((opt = getopt_long(argc, argv, ":o:pft", overlay_show_lopts,
+ NULL)) != -1) {
+ switch (opt) {
+ case 'f':
+ funcp = show_one_overlay_fma;
+ fieldsp = overlay_fma_fields;
+ break;
+ case 'o':
+ fields_str = optarg;
+ break;
+ case 'p':
+ parse = B_TRUE;
+ ofmtflags = OFMT_PARSABLE;
+ break;
+ case 't':
+ funcp = show_one_overlay_table;
+ fieldsp = overlay_targ_fields;
+ break;
+ default:
+ die_opterr(optopt, opt, use);
+ }
+ }
+
+ if (fields_str != NULL && strcasecmp(fields_str, "all") == 0)
+ fields_str = NULL;
+
+ oferr = ofmt_open(fields_str, fieldsp, ofmtflags, 0, &ofmt);
+ ofmt_check(oferr, parse, ofmt, die, warn);
+
+ err = 0;
+ if (argc > optind) {
+ for (i = optind; i < argc; i++) {
+ status = dladm_name2info(handle, argv[i], &linkid,
+ NULL, NULL, NULL);
+ if (status != DLADM_STATUS_OK) {
+ warn_dlerr(status, "failed to find %s",
+ argv[i]);
+ err = 1;
+ continue;
+ }
+ (void) funcp(handle, linkid, ofmt);
+ }
+ } else {
+ (void) dladm_walk_datalink_id(funcp, handle, ofmt,
+ DATALINK_CLASS_OVERLAY, DATALINK_ANY_MEDIATYPE,
+ DLADM_OPT_ACTIVE);
+ }
+ ofmt_close(ofmt);
+
+ exit(err);
+}
+
+static void
+do_modify_overlay(int argc, char *argv[], const char *use)
+{
+ int opt, ocnt = 0;
+ boolean_t flush, set, delete;
+ struct ether_addr e;
+ char *dest = NULL;
+ datalink_id_t linkid = DATALINK_ALL_LINKID;
+ dladm_status_t status;
+
+ flush = set = delete = B_FALSE;
+ while ((opt = getopt_long(argc, argv, ":fd:s:", overlay_modify_lopts,
+ NULL)) != -1) {
+ switch (opt) {
+ case 'd':
+ if (delete == B_TRUE)
+ die_optdup('d');
+ delete = B_TRUE;
+ ocnt++;
+ if (ether_aton_r(optarg, &e) == NULL)
+ die("invalid mac address: %s\n", optarg);
+ break;
+ case 'f':
+ if (flush == B_TRUE)
+ die_optdup('f');
+ flush = B_TRUE;
+ ocnt++;
+ break;
+ case 's':
+ if (set == B_TRUE)
+ die_optdup('s');
+ set = B_TRUE;
+ ocnt++;
+ dest = strchr(optarg, '=');
+ *dest = '\0';
+ dest++;
+ if (dest == NULL)
+ die("malformed value, expected mac=dest, "
+ "got: %s\n", optarg);
+ if (ether_aton_r(optarg, &e) == NULL)
+ die("invalid mac address: %s\n", optarg);
+ break;
+ default:
+ die_opterr(optopt, opt, use);
+ }
+ }
+
+ if (ocnt == 0)
+ die("need to specify one of -d, -f, or -s");
+ if (ocnt > 1)
+ die("only one of -d, -f, or -s may be used");
+
+ if (argv[optind] == NULL)
+ die("missing required overlay device\n");
+ if (argc > optind + 1)
+ die("only one overlay device may be specified\n");
+
+ status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
+ NULL);
+ if (status != DLADM_STATUS_OK) {
+ die_dlerr(status, "failed to find overlay %s", argv[optind]);
+ }
+
+ if (flush == B_TRUE) {
+ status = dladm_overlay_cache_flush(handle, linkid);
+ if (status != DLADM_STATUS_OK)
+ die_dlerr(status, "failed to flush target cache for "
+ "overlay %s", argv[optind]);
+ }
+
+ if (delete == B_TRUE) {
+ status = dladm_overlay_cache_delete(handle, linkid, &e);
+ if (status != DLADM_STATUS_OK)
+ die_dlerr(status, "failed to flush target %s from "
+ "overlay target cache %s", optarg, argv[optind]);
+ }
+
+ if (set == B_TRUE) {
+ status = dladm_overlay_cache_set(handle, linkid, &e, dest);
+ if (status != DLADM_STATUS_OK)
+ die_dlerr(status, "failed to set target %s for overlay "
+ "target cache %s", optarg, argv[optind]);
+ }
+
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithChill.d b/usr/src/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithChill.d
index ebb3b01601..7d7d07671a 100644
--- a/usr/src/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithChill.d
+++ b/usr/src/cmd/dtrace/test/tst/common/speculation/err.D_ACT_SPEC.SpeculateWithChill.d
@@ -25,14 +25,12 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* ASSERTION:
* Destructive actions may never be speculative.
*
* SECTION: Speculative Tracing/Using a Speculation
- * SECTION: dtrace (1M) Utility/ -w option
+ * SECTION: dtrace(8) Utility/ -w option
*
*/
#pragma D option quiet
diff --git a/usr/src/cmd/enhance/enhance.c b/usr/src/cmd/enhance/enhance.c
index 25650e378e..3fb004fbd0 100644
--- a/usr/src/cmd/enhance/enhance.c
+++ b/usr/src/cmd/enhance/enhance.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -69,24 +67,24 @@ int unlockpt(int fd);
#define PTY_CNTRL "pty"
/*
- * Pseudo-terminal slave device file names start with the following
+ * Pseudo-terminal subsidiary device file names start with the following
* prefix.
*/
-#define PTY_SLAVE "tty"
+#define PTY_SUBSID "tty"
/*
- * Specify the maximum suffix length for the control and slave device
+ * Specify the maximum suffix length for the control and subsidiary device
* names.
*/
#define PTY_MAX_SUFFIX 10
/*
- * Set the maximum length of the master and slave terminal device filenames,
- * including space for a terminating '\0'.
+ * Set the maximum length of the manager and subsidiary terminal device
+ * filenames, including space for a terminating '\0'.
*/
#define PTY_MAX_NAME (sizeof(PTY_DEV_DIR)-1 + \
- (sizeof(PTY_SLAVE) > sizeof(PTY_CNTRL) ? \
- sizeof(PTY_SLAVE) : sizeof(PTY_CNTRL))-1 \
+ (sizeof(PTY_SUBSID) > sizeof(PTY_CNTRL) ? \
+ sizeof(PTY_SUBSID) : sizeof(PTY_CNTRL))-1 \
+ PTY_MAX_SUFFIX + 1)
/*
* Set the maximum length of an input line.
@@ -110,15 +108,15 @@ int unlockpt(int fd);
*/
#define PTY_READ_TIMEOUT 100000 /* micro-seconds */
-static int pty_open_master(const char *prog, int *cntrl, char *slave_name);
-static int pty_open_slave(const char *prog, char *slave_name);
-static int pty_child(const char *prog, int slave, char *argv[]);
+static int pty_open_manager(const char *prog, int *cntrl, char *subsid_name);
+static int pty_open_subsid(const char *prog, char *subsid_name);
+static int pty_child(const char *prog, int subsid, char *argv[]);
static int pty_parent(const char *prog, int cntrl);
static int pty_stop_parent(int waserr, int cntrl, GetLine *gl, char *rbuff);
static GL_FD_EVENT_FN(pty_read_from_program);
static int pty_write_to_fd(int fd, const char *string, int n);
static void pty_child_exited(int sig);
-static int pty_master_readable(int fd, long usec);
+static int pty_manager_readable(int fd, long usec);
/*.......................................................................
* Run a program with enhanced terminal editing facilities.
@@ -129,11 +127,11 @@ static int pty_master_readable(int fd, long usec);
int main(int argc, char *argv[])
{
int cntrl = -1; /* The fd of the pseudo-terminal controller device */
- int slave = -1; /* The fd of the pseudo-terminal slave device */
+ int subsid = -1; /* The fd of the pseudo-terminal subsidiary device */
pid_t pid; /* The return value of fork() */
int status; /* The return statuses of the parent and child functions */
- char slave_name[PTY_MAX_NAME]; /* The filename of the slave end of the */
- /* pseudo-terminal. */
+ char subsid_name[PTY_MAX_NAME]; /* The filename of the subsidiary end of */
+ /* the pseudo-terminal. */
char *prog; /* The name of the program (ie. argv[0]) */
/*
* Check the arguments.
@@ -165,11 +163,11 @@ int main(int argc, char *argv[])
};
};
/*
- * Open the master side of a pseudo-terminal pair, and return
+ * Open the manager side of a pseudo-terminal pair, and return
* the corresponding file descriptor and the filename of the
- * slave end of the pseudo-terminal.
+ * subsidiary end of the pseudo-terminal.
*/
- if(pty_open_master(prog, &cntrl, slave_name))
+ if(pty_open_manager(prog, &cntrl, subsid_name))
return 1;
/*
* Set up a signal handler to watch for the child process exiting.
@@ -201,11 +199,11 @@ int main(int argc, char *argv[])
status = pty_parent(prog, cntrl);
close(cntrl);
} else {
- close(cntrl); /* The child doesn't use the slave device */
+ close(cntrl); /* The child doesn't use the subsidiary device */
signal(SIGCHLD, pty_child_exited);
- if((slave = pty_open_slave(prog, slave_name)) >= 0) {
- status = pty_child(prog, slave, argv + 1);
- close(slave);
+ if((subsid = pty_open_subsid(prog, subsid_name)) >= 0) {
+ status = pty_child(prog, subsid, argv + 1);
+ close(subsid);
} else {
status = 1;
};
@@ -214,24 +212,24 @@ int main(int argc, char *argv[])
}
/*.......................................................................
- * Open the master side of a pseudo-terminal pair, and return
+ * Open the manager side of a pseudo-terminal pair, and return
* the corresponding file descriptor and the filename of the
- * slave end of the pseudo-terminal.
+ * subsidiary end of the pseudo-terminal.
*
* Input/Output:
* prog const char * The name of this program.
* cntrl int * The file descriptor of the pseudo-terminal
* controller device will be assigned tp *cntrl.
- * slave_name char * The file-name of the pseudo-terminal slave device
- * will be recorded in slave_name[], which must have
+ * subsid_name char * The file-name of the pseudo-terminal subsidiary device
+ * will be recorded in subsid_name[], which must have
* at least PTY_MAX_NAME elements.
* Output:
* return int 0 - OK.
* 1 - Error.
*/
-static int pty_open_master(const char *prog, int *cntrl, char *slave_name)
+static int pty_open_manager(const char *prog, int *cntrl, char *subsid_name)
{
- char master_name[PTY_MAX_NAME]; /* The filename of the master device */
+ char manager_name[PTY_MAX_NAME]; /* The filename of the manager device */
DIR *dir; /* The directory iterator */
struct dirent *file; /* A file in "/dev" */
/*
@@ -240,26 +238,26 @@ static int pty_open_master(const char *prog, int *cntrl, char *slave_name)
*cntrl = -1;
/*
* On systems with the Sys-V pseudo-terminal interface, we don't
- * have to search for a free master terminal. We just open /dev/ptmx,
- * and if there is a free master terminal device, we are given a file
+ * have to search for a free manager terminal. We just open /dev/ptmx,
+ * and if there is a free manager terminal device, we are given a file
* descriptor connected to it.
*/
#if HAVE_SYSV_PTY
*cntrl = open("/dev/ptmx", O_RDWR);
if(*cntrl >= 0) {
/*
- * Get the filename of the slave side of the pseudo-terminal.
+ * Get the filename of the subsidiary side of the pseudo-terminal.
*/
char *name = ptsname(*cntrl);
if(name) {
if(strlen(name)+1 > PTY_MAX_NAME) {
- fprintf(stderr, "%s: Slave pty filename too long.\n", prog);
+ fprintf(stderr, "%s: Subsidiary pty filename too long.\n", prog);
return 1;
};
- strlcpy(slave_name, name, PTY_MAX_NAME);
+ strlcpy(subsid_name, name, PTY_MAX_NAME);
/*
- * If unable to get the slave name, discard the controller file descriptor,
- * ready to try a search instead.
+ * If unable to get the subsidiary name, discard the controller file
+ * descriptor, ready to try a search instead.
*/
} else {
close(*cntrl);
@@ -269,7 +267,7 @@ static int pty_open_master(const char *prog, int *cntrl, char *slave_name)
#endif
/*
* On systems without /dev/ptmx, or if opening /dev/ptmx failed,
- * we open one master terminal after another, until one that isn't
+ * we open one manager terminal after another, until one that isn't
* in use by another program is found.
*
* Open the devices directory.
@@ -287,7 +285,7 @@ static int pty_open_master(const char *prog, int *cntrl, char *slave_name)
while(*cntrl < 0 && (file = readdir(dir))) {
if(strncmp(file->d_name, PTY_CNTRL, sizeof(PTY_CNTRL)-1) == 0) {
/*
- * Get the common extension of the control and slave filenames.
+ * Get the common extension of the control and subsidiary filenames.
*/
const char *ext = file->d_name + sizeof(PTY_CNTRL)-1;
if(strlen(ext) > PTY_MAX_SUFFIX)
@@ -295,18 +293,18 @@ static int pty_open_master(const char *prog, int *cntrl, char *slave_name)
/*
* Attempt to open the control file.
*/
- strlcpy(master_name, PTY_DEV_DIR, sizeof(master_name));
- strlcat(master_name, PTY_CNTRL, sizeof(master_name));
- strlcat(master_name, ext, sizeof(master_name));
- *cntrl = open(master_name, O_RDWR);
+ strlcpy(manager_name, PTY_DEV_DIR, sizeof(manager_name));
+ strlcat(manager_name, PTY_CNTRL, sizeof(manager_name));
+ strlcat(manager_name, ext, sizeof(manager_name));
+ *cntrl = open(manager_name, O_RDWR);
if(*cntrl < 0)
continue;
/*
- * Attempt to open the matching slave file.
+ * Attempt to open the matching subsidiary file.
*/
- strlcpy(slave_name, PTY_DEV_DIR, PTY_MAX_NAME);
- strlcat(slave_name, PTY_SLAVE, PTY_MAX_NAME);
- strlcat(slave_name, ext, PTY_MAX_NAME);
+ strlcpy(subsid_name, PTY_DEV_DIR, PTY_MAX_NAME);
+ strlcat(subsid_name, PTY_SUBSID, PTY_MAX_NAME);
+ strlcat(subsid_name, ext, PTY_MAX_NAME);
};
};
closedir(dir);
@@ -321,8 +319,8 @@ static int pty_open_master(const char *prog, int *cntrl, char *slave_name)
return 1;
};
/*
- * System V systems require the program that opens the master to
- * grant access to the slave side of the pseudo-terminal.
+ * System V systems require the program that opens the manager to
+ * grant access to the subsidiary side of the pseudo-terminal.
*/
#ifdef HAVE_SYSV_PTY
if(grantpt(*cntrl) < 0 ||
@@ -339,18 +337,18 @@ static int pty_open_master(const char *prog, int *cntrl, char *slave_name)
}
/*.......................................................................
- * Open the slave end of a pseudo-terminal.
+ * Open the subsidiary end of a pseudo-terminal.
*
* Input:
* prog const char * The name of this program.
- * slave_name char * The filename of the slave device.
+ * subsid_name char * The filename of the subsidiary device.
* Output:
* return int The file descriptor of the successfully opened
- * slave device, or < 0 on error.
+ * subsidiary device, or < 0 on error.
*/
-static int pty_open_slave(const char *prog, char *slave_name)
+static int pty_open_subsid(const char *prog, char *subsid_name)
{
- int fd; /* The file descriptor of the slave device */
+ int fd; /* The file descriptor of the subsidiary device */
/*
* Place the process in its own process group. In system-V based
* OS's, this ensures that when the pseudo-terminal is opened, it
@@ -364,16 +362,16 @@ static int pty_open_slave(const char *prog, char *slave_name)
/*
* Attempt to open the specified device.
*/
- fd = open(slave_name, O_RDWR);
+ fd = open(subsid_name, O_RDWR);
if(fd < 0) {
- fprintf(stderr, "%s: Unable to open pseudo-terminal slave device (%s).\n",
+ fprintf(stderr, "%s: Unable to open pty subsidiary device (%s).\n",
prog, strerror(errno));
return -1;
};
/*
* On system-V streams based systems, we need to push the stream modules
* that implement pseudo-terminal and termio interfaces. At least on
- * Solaris, which pushes these automatically when a slave is opened,
+ * Solaris, which pushes these automatically when a subsidiary is opened,
* this is redundant, so ignore errors when pushing the modules.
*/
#if HAVE_SYSV_PTY
@@ -498,11 +496,11 @@ static int pty_stop_parent(int waserr, int cntrl, GetLine *gl, char *rbuff)
/*.......................................................................
* Run the user's program, with its stdin and stdout connected to the
- * slave end of the psuedo-terminal.
+ * subsidiary end of the psuedo-terminal.
*
* Input:
* prog const char * The name of this program.
- * slave int The file descriptor of the slave end of the
+ * subsid int The file descriptor of the subsidiary end of the
* pseudo terminal.
* argv char *[] The argument vector to pass to the user's program,
* where argv[0] is the name of the user's program,
@@ -514,33 +512,33 @@ static int pty_stop_parent(int waserr, int cntrl, GetLine *gl, char *rbuff)
* with the user's program. In this case 1 is
* returned.
*/
-static int pty_child(const char *prog, int slave, char *argv[])
+static int pty_child(const char *prog, int subsid, char *argv[])
{
struct termios attr; /* The terminal attributes */
/*
* We need to stop the pseudo-terminal from echoing everything that we send it.
*/
- if(tcgetattr(slave, &attr)) {
+ if(tcgetattr(subsid, &attr)) {
fprintf(stderr, "%s: Can't get pseudo-terminal attributes (%s).\n", prog,
strerror(errno));
return 1;
};
attr.c_lflag &= ~(ECHO);
- while(tcsetattr(slave, TCSADRAIN, &attr)) {
+ while(tcsetattr(subsid, TCSADRAIN, &attr)) {
if(errno != EINTR) {
fprintf(stderr, "%s: tcsetattr error: %s\n", prog, strerror(errno));
return 1;
};
};
/*
- * Arrange for stdin, stdout and stderr to be connected to the slave device,
- * ignoring errors that imply that either stdin or stdout is closed.
+ * Arrange for stdin, stdout and stderr to be connected to the subsidiary
+ * device, ignoring errors that imply that either stdin or stdout is closed.
*/
- while(dup2(slave, STDIN_FILENO) < 0 && errno==EINTR)
+ while(dup2(subsid, STDIN_FILENO) < 0 && errno==EINTR)
;
- while(dup2(slave, STDOUT_FILENO) < 0 && errno==EINTR)
+ while(dup2(subsid, STDOUT_FILENO) < 0 && errno==EINTR)
;
- while(dup2(slave, STDERR_FILENO) < 0 && errno==EINTR)
+ while(dup2(subsid, STDERR_FILENO) < 0 && errno==EINTR)
;
/*
* Run the user's program.
@@ -648,7 +646,7 @@ static GL_FD_EVENT_FN(pty_read_from_program)
*/
memmove(rbuff, nextp, len - (nextp - rbuff) + 1);
};
- } while(pty_master_readable(fd, PTY_READ_TIMEOUT));
+ } while(pty_manager_readable(fd, PTY_READ_TIMEOUT));
/*
* Make the incomplete line in the output buffer the current prompt.
*/
@@ -686,7 +684,7 @@ static int pty_write_to_fd(int fd, const char *string, int n)
/*.......................................................................
* This is the signal handler that is called when the child process
* that is running the user's program exits for any reason. It closes
- * the slave end of the terminal, so that gl_get_line() in the parent
+ * the subsidiary end of the terminal, so that gl_get_line() in the parent
* process sees an end of file.
*/
static void pty_child_exited(int sig)
@@ -707,7 +705,7 @@ static void pty_child_exited(int sig)
* available).
* 1 - Data is waiting to be read.
*/
-static int pty_master_readable(int fd, long usec)
+static int pty_manager_readable(int fd, long usec)
{
#if HAVE_SELECT
fd_set rfds; /* The set of file descriptors to check */
diff --git a/usr/src/cmd/fmthard/Makefile b/usr/src/cmd/fmthard/Makefile
index 4f1205de7a..ac1cb3b292 100644
--- a/usr/src/cmd/fmthard/Makefile
+++ b/usr/src/cmd/fmthard/Makefile
@@ -24,14 +24,13 @@
# cmd/fmthard/Makefile
#
-PROG= fmthard
+PROG= fmthard
include ../Makefile.cmd
RELUSRSBIN= ../usr/sbin
ROOTSYMLINK= $(ROOTETC)/$(PROG)
LDLIBS += -ladm -lefi
-lint := LINTFLAGS = -u -erroff=E_BAD_FORMAT_ARG_TYPE2
.KEEP_STATE:
@@ -44,7 +43,4 @@ $(ROOTSYMLINK):
clean:
-lint: lint_PROG
-
include ../Makefile.targ
-
diff --git a/usr/src/cmd/fmthard/fmthard.c b/usr/src/cmd/fmthard/fmthard.c
index 46754e1b76..8a44358f97 100644
--- a/usr/src/cmd/fmthard/fmthard.c
+++ b/usr/src/cmd/fmthard/fmthard.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
/*
@@ -121,7 +121,7 @@ static diskaddr_t lastlba = 0; /* last LBA on 64-bit VTOC */
static char *uboot = "boot";
#elif defined(i386)
-/* use installgrub(8) to install boot blocks */
+/* use installboot(8) to install boot blocks */
static char *uboot = "";
#else
#error No platform defined.
@@ -168,7 +168,7 @@ main(int argc, char **argv)
case 'b':
(void) fprintf(stderr,
"fmthard: -p and -b no longer supported."
- " Use installgrub(8) to install boot blocks\n");
+ " Use installboot(8) to install boot blocks\n");
break;
#endif /* defined(i386) */
diff --git a/usr/src/cmd/make/bin/ar.cc b/usr/src/cmd/make/bin/ar.cc
index 9a884714b1..50c8c2c309 100644
--- a/usr/src/cmd/make/bin/ar.cc
+++ b/usr/src/cmd/make/bin/ar.cc
@@ -154,11 +154,11 @@ typedef struct {
/*
* File table of contents
*/
-extern timestruc_t& read_archive(register Name target);
-static Boolean open_archive(char *filename, register Ar *arp);
-static void close_archive(register Ar *arp);
-static Boolean read_archive_dir(register Ar *arp, Name library, char **long_names_table);
-static void translate_entry(register Ar *arp, Name target, register Property member, char **long_names_table);
+extern timestruc_t& read_archive(Name target);
+static Boolean open_archive(char *filename, Ar *arp);
+static void close_archive(Ar *arp);
+static Boolean read_archive_dir(Ar *arp, Name library, char **long_names_table);
+static void translate_entry(Ar *arp, Name target, Property member, char **long_names_table);
static long sgetl(char *);
/*
@@ -177,16 +177,16 @@ static long sgetl(char *);
*/
int read_member_header (Ar_port *header, FILE *fd, char* filename);
-int process_long_names_member (register Ar *arp, char **long_names_table, char *filename);
+int process_long_names_member (Ar *arp, char **long_names_table, char *filename);
timestruc_t&
-read_archive(register Name target)
+read_archive(Name target)
{
- register Property member;
+ Property member;
wchar_t *slash;
String_rec true_member_name;
wchar_t buffer[STRING_BUFFER_LENGTH];
- register Name true_member = NULL;
+ Name true_member = NULL;
Ar ar;
char *long_names_table = NULL; /* Table of long
member names */
@@ -267,7 +267,7 @@ read_archive(register Name target)
* Global variables used:
*/
static Boolean
-open_archive(char *filename, register Ar *arp)
+open_archive(char *filename, Ar *arp)
{
int fd;
char mag_5[AR_5_MAGIC_LENGTH];
@@ -350,7 +350,7 @@ open_archive(char *filename, register Ar *arp)
* Global variables used:
*/
static void
-close_archive(register Ar *arp)
+close_archive(Ar *arp)
{
if (arp->fd != NULL) {
(void) fclose(arp->fd);
@@ -374,14 +374,14 @@ close_archive(register Ar *arp)
* Global variables used:
*/
static Boolean
-read_archive_dir(register Ar *arp, Name library, char **long_names_table)
+read_archive_dir(Ar *arp, Name library, char **long_names_table)
{
wchar_t *name_string;
wchar_t *member_string;
- register long len;
- register wchar_t *p;
- register char *q;
- register Name name;
+ long len;
+ wchar_t *p;
+ char *q;
+ Name name;
Property member;
long ptr;
long date;
@@ -562,7 +562,7 @@ read_error:
* Global variables used:
*/
int
-process_long_names_member(register Ar *arp, char **long_names_table, char *filename)
+process_long_names_member(Ar *arp, char **long_names_table, char *filename)
{
Ar_port *ar_member_header;
int table_size;
@@ -614,10 +614,10 @@ process_long_names_member(register Ar *arp, char **long_names_table, char *filen
* Global variables used:
*/
static void
-translate_entry(register Ar *arp, Name target, register Property member, char **long_names_table)
+translate_entry(Ar *arp, Name target, Property member, char **long_names_table)
{
- register int len;
- register int i;
+ int len;
+ int i;
wchar_t *member_string;
ar_port_word *offs;
int strtablen;
@@ -625,8 +625,8 @@ translate_entry(register Ar *arp, Name target, register Property member, char **
char *csym; /* string table */
ar_port_word *offend; /* end of offsets table */
int date;
- register wchar_t *ap;
- register char *hp;
+ wchar_t *ap;
+ char *hp;
int maxs;
int offset;
char buffer[4];
@@ -794,10 +794,10 @@ read_error:
* Global variables used:
*/
static long
-sgetl(register char *buffer)
+sgetl(char *buffer)
{
- register long w = 0;
- register int i = BITSPERBYTE * AR_PORT_WORD;
+ long w = 0;
+ int i = BITSPERBYTE * AR_PORT_WORD;
while ((i -= BITSPERBYTE) >= 0) {
w |= (long) ((unsigned char) *buffer++) << i;
diff --git a/usr/src/cmd/make/bin/doname.cc b/usr/src/cmd/make/bin/doname.cc
index 70289cc0b5..5de1a99096 100644
--- a/usr/src/cmd/make/bin/doname.cc
+++ b/usr/src/cmd/make/bin/doname.cc
@@ -78,30 +78,30 @@ static int second_pass = 0;
/*
* File table of contents
*/
-extern Doname doname_check(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic);
-extern Doname doname(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic);
+extern Doname doname_check(Name target, Boolean do_get, Boolean implicit, Boolean automatic);
+extern Doname doname(Name target, Boolean do_get, Boolean implicit, Boolean automatic);
static Boolean check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean doing_subtree, Chain *out_of_date_tail, Property old_locals, Boolean implicit, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals);
void dynamic_dependencies(Name target);
-static Doname run_command(register Property line, Boolean print_machine);
+static Doname run_command(Property line, Boolean print_machine);
extern Doname execute_serial(Property line);
-extern Name vpath_translation(register Name cmd);
+extern Name vpath_translation(Name cmd);
extern void check_state(Name temp_file_name);
-static void read_dependency_file(register Name filename);
+static void read_dependency_file(Name filename);
static void check_read_state_file(void);
-static void do_assign(register Name line, register Name target);
-static void build_command_strings(Name target, register Property line);
-static Doname touch_command(register Property line, register Name target, Doname result);
+static void do_assign(Name line, Name target);
+static void build_command_strings(Name target, Property line);
+static Doname touch_command(Property line, Name target, Doname result);
extern void update_target(Property line, Doname result);
-static Doname sccs_get(register Name target, register Property *command);
-extern void read_directory_of_file(register Name file);
-static void add_pattern_conditionals(register Name target);
-extern void set_locals(register Name target, register Property old_locals);
-extern void reset_locals(register Name target, register Property old_locals, register Property conditional, register int index);
+static Doname sccs_get(Name target, Property *command);
+extern void read_directory_of_file(Name file);
+static void add_pattern_conditionals(Name target);
+extern void set_locals(Name target, Property old_locals);
+extern void reset_locals(Name target, Property old_locals, Property conditional, int index);
extern Boolean check_auto_dependencies(Name target, int auto_count, Name *automatics);
static void delete_query_chain(Chain ch);
// From read2.cc
-extern Name normalize_name(register wchar_t *name_string, register int length);
+extern Name normalize_name(wchar_t *name_string, int length);
@@ -127,7 +127,7 @@ extern Name normalize_name(register wchar_t *name_string, register int length);
* report_dependencies No error msg if -P is on
*/
Doname
-doname_check(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic)
+doname_check(Name target, Boolean do_get, Boolean implicit, Boolean automatic)
{
int first_time = 1;
Doname rv = build_failed;
@@ -288,19 +288,19 @@ find_dyntarget(Name target)
* report_dependencies make -P is on
*/
Doname
-doname(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic)
+doname(Name target, Boolean do_get, Boolean implicit, Boolean automatic)
{
Doname result = build_dont_know;
Chain out_of_date_list = NULL;
Chain target_group;
Property old_locals = NULL;
- register Property line;
+ Property line;
Property command = NULL;
- register Dependency dependency;
+ Dependency dependency;
Name less = NULL;
Name true_target = target;
Name *automatics = NULL;
- register int auto_count;
+ int auto_count;
Boolean rechecking_target = false;
Boolean saved_commands_done;
Boolean restart = false;
@@ -936,7 +936,7 @@ static Boolean
check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean doing_subtree, Chain *out_of_date_tail, Property old_locals, Boolean implicit, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals)
{
Boolean dependencies_running;
- register Dependency dependency;
+ Dependency dependency;
Doname dep_result;
Boolean dependency_changed = false;
@@ -1240,9 +1240,9 @@ check_dependencies(Doname *result, Property line, Boolean do_get, Name target, N
Name target_body;
Name tt = true_target;
Property member;
- register wchar_t *target_end;
- register Dependency suffix;
- register int suffix_length;
+ wchar_t *target_end;
+ Dependency suffix;
+ int suffix_length;
Wstring targ_string;
Wstring suf_string;
@@ -1318,16 +1318,16 @@ void
dynamic_dependencies(Name target)
{
wchar_t pattern[MAXPATHLEN];
- register wchar_t *p;
+ wchar_t *p;
Property line;
- register Dependency dependency;
- register Dependency *remove;
+ Dependency dependency;
+ Dependency *remove;
String_rec string;
wchar_t buffer[MAXPATHLEN];
- register Boolean set_at = false;
- register wchar_t *start;
+ Boolean set_at = false;
+ wchar_t *start;
Dependency new_depe;
- register Boolean reuse_cell;
+ Boolean reuse_cell;
Dependency first_member;
Name directory;
Name lib;
@@ -1574,11 +1574,11 @@ dynamic_dependencies(Name target)
* touch Indicates that make -t is on
*/
static Doname
-run_command(register Property line, Boolean)
+run_command(Property line, Boolean)
{
- register Doname result = build_ok;
- register Boolean remember_only = false;
- register Name target = line->body.line.target;
+ Doname result = build_ok;
+ Boolean remember_only = false;
+ Name target = line->body.line.target;
wchar_t *string;
char tmp_file_path[MAXPATHLEN];
@@ -1902,7 +1902,7 @@ execute_serial(Property line)
* Global variables used:
*/
Name
-vpath_translation(register Name cmd)
+vpath_translation(Name cmd)
{
wchar_t buffer[STRING_BUFFER_LENGTH];
String_rec new_cmd;
@@ -1991,9 +1991,9 @@ check_state(Name temp_file_name)
* trace_reader Debug flag
*/
static void
-read_dependency_file(register Name filename)
+read_dependency_file(Name filename)
{
- register Makefile_type save_makefile_type;
+ Makefile_type save_makefile_type;
if (filename == NULL) {
return;
@@ -2036,8 +2036,8 @@ static void
check_read_state_file(void)
{
timestruc_t previous = make_state->stat.time;
- register Makefile_type save_makefile_type;
- register Property makefile;
+ Makefile_type save_makefile_type;
+ Property makefile;
make_state->stat.time = file_no_time;
if ((exists(make_state) == file_doesnt_exist) ||
@@ -2080,13 +2080,13 @@ check_read_state_file(void)
* assign_done Set to indicate doname needs to reprocess
*/
static void
-do_assign(register Name line, register Name target)
+do_assign(Name line, Name target)
{
Wstring wcb(line);
- register wchar_t *string = wcb.get_string();
- register wchar_t *equal;
- register Name name;
- register Boolean append = false;
+ wchar_t *string = wcb.get_string();
+ wchar_t *equal;
+ Name name;
+ Boolean append = false;
/*
* If any runtime assignments are done, doname() must reprocess all
@@ -2163,17 +2163,17 @@ do_assign(register Name line, register Name target)
* silent Used to init field for line
*/
static void
-build_command_strings(Name target, register Property line)
+build_command_strings(Name target, Property line)
{
String_rec command_line;
- register Cmd_line command_template = line->body.line.command_template;
- register Cmd_line *insert = &line->body.line.command_used;
- register Cmd_line used = *insert;
+ Cmd_line command_template = line->body.line.command_template;
+ Cmd_line *insert = &line->body.line.command_used;
+ Cmd_line used = *insert;
wchar_t buffer[STRING_BUFFER_LENGTH];
wchar_t *start;
Name new_command_line;
- register Boolean new_command_longer = false;
- register Boolean ignore_all_command_dependency = true;
+ Boolean new_command_longer = false;
+ Boolean ignore_all_command_dependency = true;
Property member;
static Name less_name;
static Name percent_name;
@@ -2508,10 +2508,10 @@ build_command_strings(Name target, register Property line)
* silent Do not echo commands
*/
static Doname
-touch_command(register Property line, register Name target, Doname result)
+touch_command(Property line, Name target, Doname result)
{
Name name;
- register Chain target_group;
+ Chain target_group;
String_rec touch_string;
wchar_t buffer[MAXPATHLEN];
Name touch_cmd;
@@ -2677,15 +2677,15 @@ update_target(Property line, Doname result)
* sccs_get_rule The rule to used for sccs getting
*/
static Doname
-sccs_get(register Name target, register Property *command)
+sccs_get(Name target, Property *command)
{
- register int result;
+ int result;
char link[MAXPATHLEN];
String_rec string;
wchar_t name[MAXPATHLEN];
- register wchar_t *p;
+ wchar_t *p;
timestruc_t sccs_time;
- register Property line;
+ Property line;
int sym_link_depth = 0;
/* For sccs, we need to chase symlinks. */
@@ -2820,7 +2820,7 @@ sccs_get(register Name target, register Property *command)
* dot The Name ".", used as the default dir
*/
void
-read_directory_of_file(register Name file)
+read_directory_of_file(Name file)
{
Wstring file_string(file);
@@ -2828,10 +2828,10 @@ read_directory_of_file(register Name file)
wchar_t usr_include_buf[MAXPATHLEN];
wchar_t usr_include_sys_buf[MAXPATHLEN];
- register Name directory = dot;
- register wchar_t *p = (wchar_t *) wcsrchr(wcb,
+ Name directory = dot;
+ wchar_t *p = (wchar_t *) wcsrchr(wcb,
(int) slash_char);
- register int length = p - wcb;
+ int length = p - wcb;
static Name usr_include;
static Name usr_include_sys;
@@ -2884,9 +2884,9 @@ read_directory_of_file(register Name file)
* conditionals The list of pattern conditionals
*/
static void
-add_pattern_conditionals(register Name target)
+add_pattern_conditionals(Name target)
{
- register Property conditional;
+ Property conditional;
Property new_prop;
Property *previous;
Name_rec dummy;
@@ -2951,11 +2951,11 @@ add_pattern_conditionals(register Name target)
* recursion_level Used for tracing
*/
void
-set_locals(register Name target, register Property old_locals)
+set_locals(Name target, Property old_locals)
{
- register Property conditional;
- register int i;
- register Boolean saved_conditional_macro_used;
+ Property conditional;
+ int i;
+ Boolean saved_conditional_macro_used;
Chain cond_name;
Chain cond_chain;
@@ -3013,9 +3013,9 @@ set_locals(register Name target, register Property old_locals)
* recursion_level Used for tracing
*/
void
-reset_locals(register Name target, register Property old_locals, register Property conditional, register int index)
+reset_locals(Name target, Property old_locals, Property conditional, int index)
{
- register Property this_conditional;
+ Property this_conditional;
Chain cond_chain;
if (target->dont_activate_cond_values) {
@@ -3136,7 +3136,7 @@ delete_query_chain(Chain ch)
}
Doname
-target_can_be_built(register Name target) {
+target_can_be_built(Name target) {
Doname result = build_dont_know;
Name true_target = target;
Property line;
diff --git a/usr/src/cmd/make/bin/dosys.cc b/usr/src/cmd/make/bin/dosys.cc
index dcab4df019..2996835740 100644
--- a/usr/src/cmd/make/bin/dosys.cc
+++ b/usr/src/cmd/make/bin/dosys.cc
@@ -79,13 +79,13 @@ static void redirect_stderr(void);
* working_on_targets We started processing real targets
*/
Doname
-dosys(register Name command, register Boolean ignore_error, register Boolean call_make, Boolean silent_error, Boolean always_exec, Name target)
+dosys(Name command, Boolean ignore_error, Boolean call_make, Boolean silent_error, Boolean always_exec, Name target)
{
timestruc_t before;
- register int length = command->hash.length;
+ int length = command->hash.length;
Wstring wcb(command);
- register wchar_t *p = wcb.get_string();
- register wchar_t *q;
+ wchar_t *p = wcb.get_string();
+ wchar_t *q;
Doname result;
/* Strip spaces from head of command string */
diff --git a/usr/src/cmd/make/bin/files.cc b/usr/src/cmd/make/bin/files.cc
index dc2d86f32b..6d53241f12 100644
--- a/usr/src/cmd/make/bin/files.cc
+++ b/usr/src/cmd/make/bin/files.cc
@@ -61,12 +61,12 @@
/*
* File table of contents
*/
-extern timestruc_t& exists(register Name target);
-extern void set_target_stat(register Name target, struct stat buf);
-static timestruc_t& vpath_exists(register Name target);
+extern timestruc_t& exists(Name target);
+extern void set_target_stat(Name target, struct stat buf);
+static timestruc_t& vpath_exists(Name target);
static Name enter_file_name(wchar_t *name_string, wchar_t *library);
-static Boolean star_match(register char *string, register char *pattern);
-static Boolean amatch(register wchar_t *string, register wchar_t *pattern);
+static Boolean star_match(char *string, char *pattern);
+static Boolean amatch(wchar_t *string, wchar_t *pattern);
/*
* exists(target)
@@ -85,10 +85,10 @@ static Boolean amatch(register wchar_t *string, register wchar_t *pattern);
* vpath_defined Was the variable VPATH defined in environment?
*/
timestruc_t&
-exists(register Name target)
+exists(Name target)
{
struct stat buf;
- register int result;
+ int result;
/* We cache stat information. */
if (target->stat.time != file_no_time) {
@@ -174,7 +174,7 @@ exists(register Name target)
* represented by target.
*/
void
-set_target_stat(register Name target, struct stat buf)
+set_target_stat(Name target, struct stat buf)
{
target->stat.stat_errno = 0;
target->stat.is_file = true;
@@ -209,7 +209,7 @@ set_target_stat(register Name target, struct stat buf)
* vpath_name The Name "VPATH", used to get macro value
*/
static timestruc_t&
-vpath_exists(register Name target)
+vpath_exists(Name target)
{
wchar_t *vpath;
wchar_t file_name[MAXPATHLEN];
@@ -296,7 +296,7 @@ read_dir(Name dir, wchar_t *pattern, Property line, wchar_t *library)
DIR *dir_fd;
int m_local_dependency=0;
#define d_fileno d_ino
- register struct dirent *dp;
+ struct dirent *dp;
wchar_t *vpath = NULL;
wchar_t *p;
int result = 0;
@@ -613,9 +613,9 @@ enter_file_name(wchar_t *name_string, wchar_t *library)
* Global variables used:
*/
static Boolean
-star_match(register wchar_t *string, register wchar_t *pattern)
+star_match(wchar_t *string, wchar_t *pattern)
{
- register int pattern_ch;
+ int pattern_ch;
switch (*pattern) {
case 0:
@@ -657,12 +657,12 @@ star_match(register wchar_t *string, register wchar_t *pattern)
* Global variables used:
*/
static Boolean
-amatch(register wchar_t *string, register wchar_t *pattern)
+amatch(wchar_t *string, wchar_t *pattern)
{
- register long lower_bound;
- register long string_ch;
- register long pattern_ch;
- register int k;
+ long lower_bound;
+ long string_ch;
+ long pattern_ch;
+ int k;
top:
for (; 1; pattern++, string++) {
diff --git a/usr/src/cmd/make/bin/implicit.cc b/usr/src/cmd/make/bin/implicit.cc
index bd8eaab8d7..b0b08b6242 100644
--- a/usr/src/cmd/make/bin/implicit.cc
+++ b/usr/src/cmd/make/bin/implicit.cc
@@ -56,10 +56,10 @@ static wchar_t WIDE_NULL[1] = {(wchar_t) nul_char};
* File table of contents
*/
extern Doname find_suffix_rule(Name target, Name target_body, Name target_suffix, Property *command, Boolean rechecking);
-extern Doname find_ar_suffix_rule(register Name target, Name true_target, Property *command, Boolean rechecking);
-extern Doname find_double_suffix_rule(register Name target, Property *command, Boolean rechecking);
-extern void build_suffix_list(register Name target_suffix);
-extern Doname find_percent_rule(register Name target, Property *command, Boolean rechecking);
+extern Doname find_ar_suffix_rule(Name target, Name true_target, Property *command, Boolean rechecking);
+extern Doname find_double_suffix_rule(Name target, Property *command, Boolean rechecking);
+extern void build_suffix_list(Name target_suffix);
+extern Doname find_percent_rule(Name target, Property *command, Boolean rechecking);
static void create_target_group_and_dependencies_list(Name target, Percent pat_rule, String percent);
static Boolean match_found_with_pattern(Name target, Percent pat_rule, String percent, wchar_t *percent_buf);
static void construct_string_from_pattern(Percent pat_rule, String percent, String result);
@@ -113,11 +113,11 @@ find_suffix_rule(Name target, Name target_body, Name target_suffix, Property *co
static wchar_t static_string_buf_3M [ 3 * MAXPATHLEN ];
Name true_target = target;
wchar_t *sourcename = (wchar_t*)static_string_buf_3M;
- register wchar_t *put_suffix;
- register Property source_suffix;
- register Name source;
+ wchar_t *put_suffix;
+ Property source_suffix;
+ Name source;
Doname result;
- register Property line;
+ Property line;
extern Boolean tilde_rule;
Boolean name_found = true;
Boolean posix_tilde_attempt = true;
@@ -495,11 +495,11 @@ posix_attempts:
* suffixes List of suffixes used for scan (from .SUFFIXES)
*/
Doname
-find_ar_suffix_rule(register Name target, Name true_target, Property *command, Boolean rechecking)
+find_ar_suffix_rule(Name target, Name true_target, Property *command, Boolean rechecking)
{
wchar_t *target_end;
- register Dependency suffix;
- register int suffix_length;
+ Dependency suffix;
+ int suffix_length;
Property line;
Name body;
static Name dot_a;
@@ -590,13 +590,13 @@ find_ar_suffix_rule(register Name target, Name true_target, Property *command, B
* suffixes List of suffixes used for scan (from .SUFFIXES)
*/
Doname
-find_double_suffix_rule(register Name target, Property *command, Boolean rechecking)
+find_double_suffix_rule(Name target, Property *command, Boolean rechecking)
{
Name true_target = target;
Name target_body;
- register wchar_t *target_end;
- register Dependency suffix;
- register int suffix_length;
+ wchar_t *target_end;
+ Dependency suffix;
+ int suffix_length;
Boolean scanned_once = false;
Boolean name_found = true;
@@ -697,12 +697,12 @@ find_double_suffix_rule(register Name target, Property *command, Boolean recheck
* working_on_targets Indicates that this is a real target
*/
void
-build_suffix_list(register Name target_suffix)
+build_suffix_list(Name target_suffix)
{
- register Dependency source_suffix;
+ Dependency source_suffix;
wchar_t rule_name[MAXPATHLEN];
- register Property line;
- register Property suffix;
+ Property line;
+ Property suffix;
Name rule;
/* If this is before default.mk has been read we just return to try */
@@ -795,12 +795,12 @@ build_suffix_list(register Name target_suffix)
* empty_name
*/
Doname
-find_percent_rule(register Name target, Property *command, Boolean rechecking)
+find_percent_rule(Name target, Property *command, Boolean rechecking)
{
- register Percent pat_rule, pat_depe;
- register Name depe_to_check;
- register Dependency depe;
- register Property line;
+ Percent pat_rule, pat_depe;
+ Name depe_to_check;
+ Dependency depe;
+ Property line;
String_rec string;
wchar_t string_buf[STRING_BUFFER_LENGTH];
String_rec percent;
diff --git a/usr/src/cmd/make/bin/macro.cc b/usr/src/cmd/make/bin/macro.cc
index 7f4d5bfb46..f81d855556 100644
--- a/usr/src/cmd/make/bin/macro.cc
+++ b/usr/src/cmd/make/bin/macro.cc
@@ -53,14 +53,14 @@
*/
void
-setvar_append(register Name name, register Name value)
+setvar_append(Name name, Name value)
{
- register Property macro_apx = get_prop(name->prop, macro_append_prop);
- register Property macro = get_prop(name->prop, macro_prop);
+ Property macro_apx = get_prop(name->prop, macro_append_prop);
+ Property macro = get_prop(name->prop, macro_prop);
int length;
String_rec destination;
wchar_t buffer[STRING_BUFFER_LENGTH];
- register Chain chain;
+ Chain chain;
Name val = NULL;
if(macro_apx == NULL) {
@@ -113,8 +113,8 @@ setvar_envvar(void)
{
wchar_t buffer[STRING_BUFFER_LENGTH];
int length;
- register char *mbs, *tmp_mbs_buffer = NULL;
- register char *env, *tmp_mbs_buffer2 = NULL;
+ char *mbs, *tmp_mbs_buffer = NULL;
+ char *env, *tmp_mbs_buffer2 = NULL;
Envvar p;
String_rec value;
diff --git a/usr/src/cmd/make/bin/main.cc b/usr/src/cmd/make/bin/main.cc
index 8c35d06494..fbb54963c3 100644
--- a/usr/src/cmd/make/bin/main.cc
+++ b/usr/src/cmd/make/bin/main.cc
@@ -61,7 +61,7 @@
#include <vroot/report.h> /* report_dependency(), get_report_file() */
// From read2.cc
-extern Name normalize_name(register wchar_t *name_string, register int length);
+extern Name normalize_name(wchar_t *name_string, int length);
extern void job_adjust_fini();
@@ -129,7 +129,7 @@ extern "C" {
extern void dmake_message_callback(char *);
}
-extern Name normalize_name(register wchar_t *name_string, register int length);
+extern Name normalize_name(wchar_t *name_string, int length);
extern int main(int, char * []);
@@ -148,7 +148,7 @@ static void setup_for_projectdir(void);
static void setup_makeflags_argv(void);
static void report_dir_enter_leave(Boolean entering);
-extern void expand_value(Name, register String , Boolean);
+extern void expand_value(Name, String , Boolean);
static const char verstring[] = "illumos make";
@@ -184,7 +184,7 @@ main(int argc, char *argv[])
* cp is a -> to the value of the MAKEFLAGS env var,
* which has to be regular chars.
*/
- register char *cp;
+ char *cp;
char make_state_dir[MAXPATHLEN];
Boolean parallel_flag = false;
Boolean argv_zero_relative = false;
@@ -910,17 +910,17 @@ doalarm(int sig __attribute__((unused)))
* Global variables used:
*/
static void
-read_command_options(register int argc, register char **argv)
+read_command_options(int argc, char **argv)
{
- register int ch;
+ int ch;
int current_optind = 1;
int last_optind_with_double_hyphen = 0;
int last_optind;
int last_current_optind;
- register int i;
- register int j;
- register int k;
- register int makefile_next = 0; /*
+ int i;
+ int j;
+ int k;
+ int makefile_next = 0; /*
* flag to note options:
* -c, f, g, j, m, o
*/
@@ -1326,7 +1326,7 @@ setup_makeflags_argv()
* touch Set for make -t
*/
static int
-parse_command_option(register char ch)
+parse_command_option(char ch)
{
static int invert_next = 0;
int invert_this = invert_next;
@@ -1778,28 +1778,28 @@ read_files_and_state(int argc, char **argv)
{
wchar_t buffer[1000];
wchar_t buffer_posix[1000];
- register char ch;
- register char *cp;
+ char ch;
+ char *cp;
Property def_make_macro = NULL;
Name def_make_name;
Name default_makefile;
String_rec dest;
wchar_t destbuffer[STRING_BUFFER_LENGTH];
- register int i;
- register int j;
+ int i;
+ int j;
Name keep_state_name;
int length;
Name Makefile;
- register Property macro;
+ Property macro;
struct stat make_state_stat;
Name makefile_name;
- register int makefile_next = 0;
- register Boolean makefile_read = false;
+ int makefile_next = 0;
+ Boolean makefile_read = false;
String_rec makeflags_string;
String_rec makeflags_string_posix;
String_rec * makeflags_string_current;
Name makeflags_value_saved;
- register Name name;
+ Name name;
Name new_make_value;
Boolean save_do_not_exec_rule;
static wchar_t state_file_str;
@@ -1808,7 +1808,7 @@ read_files_and_state(int argc, char **argv)
Boolean temp;
char tmp_char;
wchar_t *tmp_wcs_buffer;
- register Name value;
+ Name value;
ASCII_Dyn_Array makeflags_and_macro;
Boolean is_xpg4;
@@ -2439,14 +2439,14 @@ read_files_and_state(int argc, char **argv)
static void
enter_argv_values(int argc, char *argv[], ASCII_Dyn_Array *makeflags_and_macro)
{
- register char *cp;
- register int i;
+ char *cp;
+ int i;
int length;
- register Name name;
+ Name name;
int opt_separator = argc;
char tmp_char;
wchar_t *tmp_wcs_buffer;
- register Name value;
+ Name value;
Boolean append = false;
Property macro;
struct stat statbuf;
@@ -2637,7 +2637,7 @@ enter_argv_values(int argc, char *argv[], ASCII_Dyn_Array *makeflags_and_macro)
* Append the DMake option and value to the MAKEFLAGS string.
*/
static void
-append_makeflags_string(Name name, register String makeflags_string)
+append_makeflags_string(Name name, String makeflags_string)
{
const char *option;
@@ -2687,13 +2687,13 @@ append_makeflags_string(Name name, register String makeflags_string)
static void
read_environment(Boolean read_only)
{
- register char **environment;
+ char **environment;
int length;
wchar_t *tmp_wcs_buffer;
Boolean alloced_tmp_wcs_buffer = false;
- register wchar_t *name;
- register wchar_t *value;
- register Name macro;
+ wchar_t *name;
+ wchar_t *value;
+ Name macro;
Property val;
Boolean read_only_saved;
@@ -2791,7 +2791,7 @@ read_environment(Boolean read_only)
* recursion_level Initialized
*/
static Boolean
-read_makefile(register Name makefile, Boolean complain, Boolean must_exist, Boolean report_file)
+read_makefile(Name makefile, Boolean complain, Boolean must_exist, Boolean report_file)
{
Boolean b;
@@ -2830,7 +2830,7 @@ make_targets(int argc, char **argv, Boolean parallel_flag)
int i;
char *cp;
Doname result;
- register Boolean target_to_make_found = false;
+ Boolean target_to_make_found = false;
(void) doname(init, true, true);
recursion_level = 1;
@@ -3068,9 +3068,9 @@ make_targets(int argc, char **argv, Boolean parallel_flag)
* report_dependency dwight
*/
static void
-report_recursion(register Name target)
+report_recursion(Name target)
{
- register FILE *report_file = get_report_file();
+ FILE *report_file = get_report_file();
if ((report_file == NULL) || (report_file == (FILE*)-1)) {
return;
@@ -3097,14 +3097,14 @@ report_recursion(register Name target)
extern void
append_or_replace_macro_in_dyn_array(ASCII_Dyn_Array *Ar, char *macro)
{
- register char *cp0; /* work pointer in macro */
- register char *cp1; /* work pointer in array */
- register char *cp2; /* work pointer in array */
- register char *cp3; /* work pointer in array */
- register char *name; /* macro name */
- register char *value; /* macro value */
- register int len_array;
- register int len_macro;
+ char *cp0; /* work pointer in macro */
+ char *cp1; /* work pointer in array */
+ char *cp2; /* work pointer in array */
+ char *cp3; /* work pointer in array */
+ char *name; /* macro name */
+ char *value; /* macro value */
+ int len_array;
+ int len_macro;
char * esc_value = NULL;
int esc_len;
diff --git a/usr/src/cmd/make/bin/misc.cc b/usr/src/cmd/make/bin/misc.cc
index ed4d89b78a..d6e2d0b87f 100644
--- a/usr/src/cmd/make/bin/misc.cc
+++ b/usr/src/cmd/make/bin/misc.cc
@@ -66,8 +66,8 @@ extern void job_adjust_fini();
/*
* File table of contents
*/
-static void print_rule(register Name target);
-static void print_target_n_deps(register Name target);
+static void print_rule(Name target);
+static void print_target_n_deps(Name target);
/*****************************************
*
@@ -318,9 +318,9 @@ void
dump_make_state(void)
{
Name_set::iterator p, e;
- register Property prop;
- register Dependency dep;
- register Cmd_line rule;
+ Property prop;
+ Dependency dep;
+ Cmd_line rule;
Percent percent, percent_depe;
/* Default target */
@@ -464,11 +464,11 @@ dump_make_state(void)
* Global variables used:
*/
static void
-print_rule(register Name target)
+print_rule(Name target)
{
- register Cmd_line rule;
- register Property line;
- register Dependency dependency;
+ Cmd_line rule;
+ Property line;
+ Dependency dependency;
if (target->dependency_printed ||
((line = get_prop(target->prop, line_prop)) == NULL) ||
@@ -514,11 +514,11 @@ dump_target_list(void)
}
static void
-print_target_n_deps(register Name target)
+print_target_n_deps(Name target)
{
- register Cmd_line rule;
- register Property line;
- register Dependency dependency;
+ Cmd_line rule;
+ Property line;
+ Dependency dependency;
if (target->dependency_printed) {
return;
diff --git a/usr/src/cmd/make/bin/nse_printdep.cc b/usr/src/cmd/make/bin/nse_printdep.cc
index dd2bc62825..cb7228d2da 100644
--- a/usr/src/cmd/make/bin/nse_printdep.cc
+++ b/usr/src/cmd/make/bin/nse_printdep.cc
@@ -32,15 +32,15 @@
/*
* File table of contents
*/
-void print_dependencies(register Name target, register Property line);
-static void print_deps(register Name target, register Property line);
+void print_dependencies(Name target, Property line);
+static void print_deps(Name target, Property line);
static void print_more_deps(Name target, Name name);
static void print_filename(Name name);
static Boolean should_print_dep(Property line);
static void print_forest(Name target);
static void print_deplist(Dependency head);
-void print_value(register Name value, Daemon daemon);
-static void print_rule(register Name target);
+void print_value(Name value, Daemon daemon);
+static void print_rule(Name target);
static void print_rec_info(Name target);
static Boolean is_out_of_date(Property line);
extern void depvar_print_results (void);
@@ -62,7 +62,7 @@ extern void depvar_print_results (void);
* makefiles_used List of all makefiles read
*/
void
-print_dependencies(register Name target, register Property line)
+print_dependencies(Name target, Property line)
{
Dependency dp;
static Boolean makefiles_printed = false;
@@ -120,7 +120,7 @@ static void
print_more_deps(Name target, Name name)
{
Property line;
- register Dependency dependencies;
+ Dependency dependencies;
line = get_prop(name->prop, line_prop);
if (line != NULL && line->body.line.dependencies != NULL) {
@@ -151,9 +151,9 @@ print_more_deps(Name target, Name name)
* recursive_name The Name ".RECURSIVE", printed
*/
static void
-print_deps(register Name target, register Property line)
+print_deps(Name target, Property line)
{
- register Dependency dep;
+ Dependency dep;
if ((target->dependency_printed) ||
(target == force)) {
@@ -302,7 +302,7 @@ print_forest(Name target)
* Used for the -p option
*/
void
-print_value(register Name value, Daemon daemon)
+print_value(Name value, Daemon daemon)
{
Chain cp;
@@ -323,10 +323,10 @@ print_value(register Name value, Daemon daemon)
}
static void
-print_rule(register Name target)
+print_rule(Name target)
{
- register Cmd_line rule;
- register Property line;
+ Cmd_line rule;
+ Property line;
if (((line= get_prop(target->prop, line_prop)) == NULL) ||
((line->body.line.command_template == NULL) &&
diff --git a/usr/src/cmd/make/bin/read.cc b/usr/src/cmd/make/bin/read.cc
index 9d697c6ced..93b1e5f726 100644
--- a/usr/src/cmd/make/bin/read.cc
+++ b/usr/src/cmd/make/bin/read.cc
@@ -59,10 +59,10 @@ static int line_started_with_space=0; // Used to diagnose spaces instead of tabs
/*
* File table of contents
*/
-static void parse_makefile(register Name true_makefile_name, register Source source);
-static Source push_macro_value(register Source bp, register wchar_t *buffer, int size, register Source source);
+static void parse_makefile(Name true_makefile_name, Source source);
+static Source push_macro_value(Source bp, wchar_t *buffer, int size, Source source);
extern void enter_target_groups_and_dependencies(Name_vector target, Name_vector depes, Cmd_line command, Separator separator, Boolean target_group_seen);
-extern Name normalize_name(register wchar_t *name_string, register int length);
+extern Name normalize_name(wchar_t *name_string, int length);
/*
* read_simple_file(makefile_name, chase_path, doname_it,
@@ -93,27 +93,27 @@ extern Name normalize_name(register wchar_t *name_string, register int length);
Boolean
-read_simple_file(register Name makefile_name, register Boolean chase_path, register Boolean doname_it, Boolean complain, Boolean must_exist, Boolean report_file, Boolean lock_makefile)
+read_simple_file(Name makefile_name, Boolean chase_path, Boolean doname_it, Boolean complain, Boolean must_exist, Boolean report_file, Boolean lock_makefile)
{
static short max_include_depth;
- register Property makefile = maybe_append_prop(makefile_name,
+ Property makefile = maybe_append_prop(makefile_name,
makefile_prop);
Boolean forget_after_parse = false;
static pathpt makefile_path;
- register int n;
+ int n;
char *path;
- register Source source = ALLOC(Source);
+ Source source = ALLOC(Source);
Property orig_makefile = makefile;
Dependency *dpp;
Dependency dp;
- register int length;
+ int length;
wchar_t *previous_file_being_read = file_being_read;
int previous_line_number = line_number;
wchar_t previous_current_makefile[MAXPATHLEN];
Makefile_type save_makefile_type;
Name normalized_makefile_name;
- register wchar_t *string_start;
- register wchar_t *string_end;
+ wchar_t *string_start;
+ wchar_t *string_end;
@@ -457,21 +457,21 @@ read_simple_file(register Name makefile_name, register Boolean chase_path, regis
* empty_name The Name ""
*/
static void
-parse_makefile(register Name true_makefile_name, register Source source)
+parse_makefile(Name true_makefile_name, Source source)
{
/*
char mb_buffer[MB_LEN_MAX];
*/
- register wchar_t *source_p;
- register wchar_t *source_end;
- register wchar_t *string_start;
+ wchar_t *source_p;
+ wchar_t *source_end;
+ wchar_t *string_start;
wchar_t *string_end;
- register Boolean macro_seen_in_string;
+ Boolean macro_seen_in_string;
Boolean append;
String_rec name_string;
wchar_t name_buffer[STRING_BUFFER_LENGTH];
- register int distance;
- register int paren_count;
+ int distance;
+ int paren_count;
int brace_count;
int char_number;
Cmd_line command;
@@ -486,9 +486,9 @@ parse_makefile(register Name true_makefile_name, register Source source)
Name_vector nvp;
Boolean target_group_seen;
- register Reader_state state;
- register Reader_state on_eoln_state;
- register Separator separator;
+ Reader_state state;
+ Reader_state on_eoln_state;
+ Separator separator;
wchar_t buffer[4 * STRING_BUFFER_LENGTH];
Source extrap;
@@ -2025,7 +2025,7 @@ default:
* Global variables used:
*/
static Source
-push_macro_value(register Source bp, register wchar_t *buffer, int size, register Source source)
+push_macro_value(Source bp, wchar_t *buffer, int size, Source source)
{
bp->string.buffer.start = bp->string.text.p = buffer;
bp->string.text.end = NULL;
diff --git a/usr/src/cmd/make/bin/read2.cc b/usr/src/cmd/make/bin/read2.cc
index a968e18b8b..c198ceef6e 100644
--- a/usr/src/cmd/make/bin/read2.cc
+++ b/usr/src/cmd/make/bin/read2.cc
@@ -57,11 +57,11 @@ static Boolean built_last_make_run_seen;
/*
* File table of contents
*/
-static Name_vector enter_member_name(register wchar_t *lib_start, register wchar_t *member_start, register wchar_t *string_end, Name_vector current_names, Name_vector *extra_names);
-extern Name normalize_name(register wchar_t *name_string, register int length);
-static void read_suffixes_list(register Name_vector depes);
+static Name_vector enter_member_name(wchar_t *lib_start, wchar_t *member_start, wchar_t *string_end, Name_vector current_names, Name_vector *extra_names);
+extern Name normalize_name(wchar_t *name_string, int length);
+static void read_suffixes_list(Name_vector depes);
static void make_relative(wchar_t *to, wchar_t *result);
-static void print_rule(register Cmd_line command);
+static void print_rule(Cmd_line command);
static void sh_transform(Name *name, Name *value);
@@ -94,10 +94,10 @@ static void sh_transform(Name *name, Name *value);
*/
Name_vector
-enter_name(String string, Boolean tail_present, register wchar_t *string_start, register wchar_t *string_end, Name_vector current_names, Name_vector *extra_names, Boolean *target_group_seen)
+enter_name(String string, Boolean tail_present, wchar_t *string_start, wchar_t *string_end, Name_vector current_names, Name_vector *extra_names, Boolean *target_group_seen)
{
Name name;
- register wchar_t *cp;
+ wchar_t *cp;
wchar_t ch;
/* If we were passed a separate tail of the name we append it to the */
@@ -192,9 +192,9 @@ if(current_names->used != 0 && current_names->names[current_names->used-1] == pl
* Global variables used:
*/
static Name_vector
-enter_member_name(register wchar_t *lib_start, register wchar_t *member_start, register wchar_t *string_end, Name_vector current_names, Name_vector *extra_names)
+enter_member_name(wchar_t *lib_start, wchar_t *member_start, wchar_t *string_end, Name_vector current_names, Name_vector *extra_names)
{
- register Boolean entry = false;
+ Boolean entry = false;
wchar_t buffer[STRING_BUFFER_LENGTH];
Name lib;
Name member;
@@ -202,9 +202,9 @@ enter_member_name(register wchar_t *lib_start, register wchar_t *member_start, r
Property prop;
wchar_t *memberp;
wchar_t *q;
- register int paren_count;
- register Boolean has_dollar;
- register wchar_t *cq;
+ int paren_count;
+ Boolean has_dollar;
+ wchar_t *cq;
Name long_member_name = NULL;
/* Internalize the name of the library */
@@ -334,15 +334,15 @@ enter_member_name(register wchar_t *lib_start, register wchar_t *member_start, r
* dotdot The Name "..", compared against
*/
Name
-normalize_name(register wchar_t *name_string, register int length)
+normalize_name(wchar_t *name_string, int length)
{
static Name dotdot;
- register wchar_t *string = ALLOC_WC(length + 1);
- register wchar_t *string2;
- register wchar_t *cdp;
+ wchar_t *string = ALLOC_WC(length + 1);
+ wchar_t *string2;
+ wchar_t *cdp;
wchar_t *current_component;
Name name;
- register int count;
+ int count;
if (dotdot == NULL) {
MBSTOWCS(wcs_buffer, "..");
@@ -464,7 +464,7 @@ removed_one:
* plus The Name "+", compared against
*/
Chain
-find_target_groups(register Name_vector target_list, register int i, Boolean reset)
+find_target_groups(Name_vector target_list, int i, Boolean reset)
{
static Chain target_group = NULL;
static Chain tail_target_group = NULL;
@@ -568,10 +568,10 @@ find_target_groups(register Name_vector target_list, register int i, Boolean res
* trace_reader Indicates that we should echo stuff we read
*/
void
-enter_dependencies(register Name target, Chain target_group, register Name_vector depes, register Cmd_line command, register Separator separator)
+enter_dependencies(Name target, Chain target_group, Name_vector depes, Cmd_line command, Separator separator)
{
- register int i;
- register Property line;
+ int i;
+ Property line;
Name name;
Name directory;
wchar_t *namep;
@@ -580,7 +580,7 @@ enter_dependencies(register Name target, Chain target_group, register Name_vecto
Dependency *dpp;
Property line2;
wchar_t relative[MAXPATHLEN];
- register int recursive_state;
+ int recursive_state;
Boolean register_as_auto;
Boolean not_auto_found;
char *slash;
@@ -870,10 +870,10 @@ enter_dependencies(register Name target, Chain target_group, register Name_vecto
* wait_name The Name ".WAIT", compared against
*/
void
-enter_dependency(Property line, register Name depe, Boolean automatic)
+enter_dependency(Property line, Name depe, Boolean automatic)
{
- register Dependency dp;
- register Dependency *insert;
+ Dependency dp;
+ Dependency *insert;
if (trace_reader) {
(void) printf("%s ", depe->string_mb);
@@ -927,13 +927,13 @@ enter_dependency(Property line, register Name depe, Boolean automatic)
* trace_reader Indicates that we should echo stuff we read
*/
Percent
-enter_percent(register Name target, Chain target_group, register Name_vector depes, Cmd_line command)
+enter_percent(Name target, Chain target_group, Name_vector depes, Cmd_line command)
{
- register Percent result = ALLOC(Percent);
- register Percent depe;
- register Percent *depe_tail = &result->dependencies;
- register Percent *insert;
- register wchar_t *cp, *cp1;
+ Percent result = ALLOC(Percent);
+ Percent depe;
+ Percent *depe_tail = &result->dependencies;
+ Percent *insert;
+ wchar_t *cp, *cp1;
Name_vector nvp;
int i;
int pattern;
@@ -1065,9 +1065,9 @@ enter_percent(register Name target, Chain target_group, register Name_vector dep
* trace_reader Indicates that we should echo stuff we read
*/
Dyntarget
-enter_dyntarget(register Name target)
+enter_dyntarget(Name target)
{
- register Dyntarget result = ALLOC(Dyntarget);
+ Dyntarget result = ALLOC(Dyntarget);
Dyntarget p;
Dyntarget *insert;
int i;
@@ -1130,9 +1130,9 @@ enter_dyntarget(register Name target)
* trace_reader Indicates that we should echo stuff we read
*/
void
-special_reader(Name target, register Name_vector depes, Cmd_line command)
+special_reader(Name target, Name_vector depes, Cmd_line command)
{
- register int n;
+ int n;
switch (target->special_reader) {
@@ -1471,14 +1471,14 @@ special_reader(Name target, register Name_vector depes, Cmd_line command)
* trace_reader Indicates that we should echo stuff we read
*/
static void
-read_suffixes_list(register Name_vector depes)
+read_suffixes_list(Name_vector depes)
{
- register int n;
- register Dependency dp;
- register Dependency *insert_dep;
- register Name np;
+ int n;
+ Dependency dp;
+ Dependency *insert_dep;
+ Name np;
Name np2;
- register Boolean first = true;
+ Boolean first = true;
if (depes->used == 0) {
/* .SUFFIXES with no dependency list clears the */
@@ -1652,7 +1652,7 @@ make_relative(wchar_t *to, wchar_t *result)
* Global variables used:
*/
static void
-print_rule(register Cmd_line command)
+print_rule(Cmd_line command)
{
for (; command != NULL; command = command->next) {
(void) printf("\t%s\n", command->command_line->string_mb);
@@ -1676,9 +1676,9 @@ print_rule(register Cmd_line command)
* trace_reader Indicates that we should echo stuff we read
*/
void
-enter_conditional(register Name target, Name name, Name value, register Boolean append)
+enter_conditional(Name target, Name name, Name value, Boolean append)
{
- register Property conditional;
+ Property conditional;
static int sequence;
Name orig_target = target;
@@ -1741,7 +1741,7 @@ enter_conditional(register Name target, Name name, Name value, register Boolean
* trace_reader Indicates that we should echo stuff we read
*/
void
-enter_equal(Name name, Name value, register Boolean append)
+enter_equal(Name name, Name value, Boolean append)
{
wchar_t *string;
Name temp;
diff --git a/usr/src/cmd/make/bin/rep.cc b/usr/src/cmd/make/bin/rep.cc
index 479967f938..87e9c0a782 100644
--- a/usr/src/cmd/make/bin/rep.cc
+++ b/usr/src/cmd/make/bin/rep.cc
@@ -323,7 +323,7 @@ gather_recursive_deps(void)
Name_set::iterator np, e;
String_rec rec;
wchar_t rec_buf[STRING_BUFFER_LENGTH];
- register Property lines;
+ Property lines;
Boolean has_recursive;
Dependency dp;
diff --git a/usr/src/cmd/make/bin/state.cc b/usr/src/cmd/make/bin/state.cc
index a7557a4946..91719d7ffa 100644
--- a/usr/src/cmd/make/bin/state.cc
+++ b/usr/src/cmd/make/bin/state.cc
@@ -93,7 +93,7 @@ static char * escape_target_name(Name np)
}
}
-static void print_auto_depes(register Dependency dependency, register FILE *fd, register Boolean built_this_run, register int *line_length, register char *target_name, jmp_buf long_jump);
+static void print_auto_depes(Dependency dependency, FILE *fd, Boolean built_this_run, int *line_length, char *target_name, jmp_buf long_jump);
/*
* write_state_file(report_recursive, exiting)
@@ -120,21 +120,21 @@ static void print_auto_depes(register Dependency dependency, register FILE *fd,
void
write_state_file(int, Boolean exiting)
{
- register FILE *fd;
+ FILE *fd;
int lock_err;
char buffer[MAXPATHLEN];
char make_state_tempfile[MAXPATHLEN];
jmp_buf long_jump;
- register int attempts = 0;
+ int attempts = 0;
Name_set::iterator np, e;
- register Property lines;
- register int m;
+ Property lines;
+ int m;
Dependency dependency;
- register Boolean name_printed;
+ Boolean name_printed;
Boolean built_this_run = false;
char *target_name;
int line_length;
- register Cmd_line cp;
+ Cmd_line cp;
if (!rewrite_statefile ||
@@ -410,7 +410,7 @@ write_state_file(int, Boolean exiting)
* force The Name " FORCE", compared against
*/
static void
-print_auto_depes(register Dependency dependency, register FILE *fd, register Boolean built_this_run, register int *line_length, register char *target_name, jmp_buf long_jump)
+print_auto_depes(Dependency dependency, FILE *fd, Boolean built_this_run, int *line_length, char *target_name, jmp_buf long_jump)
{
if (!dependency->automatic ||
dependency->stale ||
diff --git a/usr/src/cmd/make/include/mksh/dosys.h b/usr/src/cmd/make/include/mksh/dosys.h
index 18e33924d5..25b6ba8364 100644
--- a/usr/src/cmd/make/include/mksh/dosys.h
+++ b/usr/src/cmd/make/include/mksh/dosys.h
@@ -1,5 +1,3 @@
-#ifndef _MKSH_DOSYS_H
-#define _MKSH_DOSYS_H
/*
* CDDL HEADER START
*
@@ -25,13 +23,16 @@
* Use is subject to license terms.
*/
+#ifndef _MKSH_DOSYS_H
+#define _MKSH_DOSYS_H
+
#include <mksh/defs.h>
#include <vroot/vroot.h>
-extern Boolean await(register Boolean ignore_error, register Boolean silent_error, Name target, wchar_t *command, pid_t running_pid, void *xdrs, int job_msg_id);
-extern int doexec(register wchar_t *command, register Boolean ignore_error, char *stdout_file, char *stderr_file, pathpt vroot_path, int nice_prio);
-extern int doshell(wchar_t *command, register Boolean ignore_error, char *stdout_file, char *stderr_file, int nice_prio);
-extern void redirect_io(char *stdout_file, char *stderr_file);
-extern void sh_command2string(register String command, register String destination);
+extern Boolean await(Boolean, Boolean, Name, wchar_t *, pid_t, void *, int);
+extern int doexec(wchar_t *, Boolean, char *, char *, pathpt, int);
+extern int doshell(wchar_t *, Boolean, char *, char *, int);
+extern void redirect_io(char *, char *);
+extern void sh_command2string(String, String);
-#endif
+#endif /* _MKSH_DOSYS_H */
diff --git a/usr/src/cmd/make/include/mksh/macro.h b/usr/src/cmd/make/include/mksh/macro.h
index 2068d4884d..504289fbf8 100644
--- a/usr/src/cmd/make/include/mksh/macro.h
+++ b/usr/src/cmd/make/include/mksh/macro.h
@@ -1,5 +1,3 @@
-#ifndef _MKSH_MACRO_H
-#define _MKSH_MACRO_H
/*
* CDDL HEADER START
*
@@ -25,12 +23,15 @@
* Use is subject to license terms.
*/
+#ifndef _MKSH_MACRO_H
+#define _MKSH_MACRO_H
+
#include <mksh/defs.h>
-extern void expand_macro(register Source source, register String destination, wchar_t *current_string, Boolean cmd);
-extern void expand_value(Name value, register String destination, Boolean cmd);
-extern Name getvar(register Name name);
+extern void expand_macro(Source, String, wchar_t *, Boolean);
+extern void expand_value(Name, String, Boolean);
+extern Name getvar(Name);
-extern Property setvar_daemon(register Name name, register Name value, Boolean append, Daemon daemon, Boolean strip_trailing_spaces, short debug_level);
+extern Property setvar_daemon(Name, Name, Boolean, Daemon, Boolean, short);
-#endif
+#endif /* _MKSH_MACRO_H */
diff --git a/usr/src/cmd/make/include/mksh/misc.h b/usr/src/cmd/make/include/mksh/misc.h
index d5506fdedb..fd3d6410e5 100644
--- a/usr/src/cmd/make/include/mksh/misc.h
+++ b/usr/src/cmd/make/include/mksh/misc.h
@@ -1,5 +1,3 @@
-#ifndef _MKSH_MISC_H
-#define _MKSH_MISC_H
/*
* CDDL HEADER START
*
@@ -27,31 +25,35 @@
* Copyright 2019 RackTop Systems.
*/
+#ifndef _MKSH_MISC_H
+#define _MKSH_MISC_H
+
#include <mksh/defs.h>
-extern void append_char(wchar_t from, register String to);
-extern Property append_prop(register Name target, register Property_id type);
-extern void append_string(register wchar_t *from, register String to, register int length);
-extern void enable_interrupt(register void (*handler) (int));
-extern char *errmsg(int errnum);
-extern void fatal_mksh(const char *message, ...) __NORETURN;
-extern void fatal_reader_mksh(const char *pattern, ...) __NORETURN;
+extern void append_char(wchar_t, String);
+extern Property append_prop(Name, Property_id);
+extern void append_string(wchar_t *, String, int);
+extern void enable_interrupt(void (*) (int));
+extern char *errmsg(int);
+extern void fatal_mksh(const char *, ...) __NORETURN;
+extern void fatal_reader_mksh(const char *, ...) __NORETURN;
extern char *get_current_path_mksh(void);
-extern Property get_prop(register Property start, register Property_id type);
-extern char *getmem(size_t size);
-extern Name getname_fn(wchar_t *name, register int len, register Boolean dont_enter, register Boolean * foundp = NULL);
-extern void store_name(Name name);
-extern void free_name(Name name);
+extern Property get_prop(Property, Property_id);
+extern char *getmem(size_t);
+extern Name getname_fn(wchar_t *name, int len, Boolean dont_enter,
+ Boolean *foundp = NULL);
+extern void store_name(Name);
+extern void free_name(Name);
extern void handle_interrupt_mksh(int);
-extern Property maybe_append_prop(register Name target, register Property_id type);
-extern void retmem(wchar_t *p);
-extern void retmem_mb(caddr_t p);
+extern Property maybe_append_prop(Name, Property_id);
+extern void retmem(wchar_t *);
+extern void retmem_mb(caddr_t);
extern void setup_char_semantics(void);
-extern void setup_interrupt(register void (*handler) (int));
-extern void warning_mksh(char * message, ...);
+extern void setup_interrupt(void (*) (int));
+extern void warning_mksh(char *, ...);
-extern void append_string(register char *from, register String to, register int length);
-extern wchar_t *get_wstring(char * from);
+extern void append_string(char *, String, int);
+extern wchar_t *get_wstring(char *);
-#endif
+#endif /* _MKSH_MISC_H */
diff --git a/usr/src/cmd/make/include/mksh/read.h b/usr/src/cmd/make/include/mksh/read.h
index 7866d3d398..1151d529b0 100644
--- a/usr/src/cmd/make/include/mksh/read.h
+++ b/usr/src/cmd/make/include/mksh/read.h
@@ -1,5 +1,3 @@
-#ifndef _MKSH_READ_H
-#define _MKSH_READ_H
/*
* CDDL HEADER START
*
@@ -25,9 +23,11 @@
* Use is subject to license terms.
*/
+#ifndef _MKSH_READ_H
+#define _MKSH_READ_H
#include <mksh/defs.h>
-extern Source get_next_block_fn(register Source source);
+extern Source get_next_block_fn(Source source);
-#endif
+#endif /* _MKSH_READ_H */
diff --git a/usr/src/cmd/make/include/vroot/args.h b/usr/src/cmd/make/include/vroot/args.h
index 09bb4b47e5..d001b29ee6 100644
--- a/usr/src/cmd/make/include/vroot/args.h
+++ b/usr/src/cmd/make/include/vroot/args.h
@@ -25,7 +25,7 @@
#ifndef _ARGS_H_
-#define _ARGS_H_
+#define _ARGS_H_
#include <sys/syscall.h>
#include <errno.h>
@@ -39,25 +39,52 @@
typedef enum { rw_read, rw_write} rwt, *rwpt;
-extern void translate_with_thunk(register char *filename, int (*thunk) (char *), pathpt path_vector, pathpt vroot_vector, rwt rw);
+extern void translate_with_thunk(char *, int (*) (char *), pathpt, pathpt,
+ rwt);
union Args {
- struct { int mode;} access;
- struct { int mode;} chmod;
- struct { int user; int group;} chown;
- struct { int mode;} creat;
- struct { char **argv; char **environ;} execve;
- struct { struct stat *buffer;} lstat;
- struct { int mode;} mkdir;
- struct { char *name; int mode;} mount;
- struct { int flags; int mode;} open;
- struct { char *buffer; int buffer_size;} readlink;
- struct { struct stat *buffer;} stat;
- struct { int length;} truncate;
- struct { struct timeval *time;} utimes;
+ struct {
+ int mode;
+ } access;
+ struct {
+ int mode;
+ } chmod;
+ struct {
+ int user; int group;
+ } chown;
+ struct {
+ int mode;
+ } creat;
+ struct {
+ char **argv; char **environ;
+ } execve;
+ struct {
+ struct stat *buffer;
+ } lstat;
+ struct {
+ int mode;
+ } mkdir;
+ struct {
+ char *name; int mode;
+ } mount;
+ struct {
+ int flags; int mode;
+ } open;
+ struct {
+ char *buffer; int buffer_size;
+ } readlink;
+ struct {
+ struct stat *buffer;
+ } stat;
+ struct {
+ int length;
+ } truncate;
+ struct {
+ struct timeval *time;
+ } utimes;
};
extern union Args vroot_args;
extern int vroot_result;
-#endif
+#endif /* _ARGS_H_ */
diff --git a/usr/src/cmd/make/include/vroot/vroot.h b/usr/src/cmd/make/include/vroot/vroot.h
index cf84681ebf..eff7df173b 100644
--- a/usr/src/cmd/make/include/vroot/vroot.h
+++ b/usr/src/cmd/make/include/vroot/vroot.h
@@ -25,12 +25,12 @@
#ifndef _VROOT_H_
-#define _VROOT_H_
+#define _VROOT_H_
#include <stdio.h>
#include <nl_types.h>
-#define VROOT_DEFAULT ((pathpt)-1)
+#define VROOT_DEFAULT ((pathpt)-1)
typedef struct {
char *path;
@@ -38,24 +38,24 @@ typedef struct {
} pathcellt, *pathcellpt, patht;
typedef patht *pathpt;
-extern void add_dir_to_path(const char *path, register pathpt *pointer, register int position);
+extern void add_dir_to_path(const char *, pathpt *, int);
extern void flush_path_cache(void);
extern void flush_vroot_cache(void);
extern const char *get_path_name(void);
-extern char *get_vroot_path(register char **vroot, register char **path, register char **filename);
+extern char *get_vroot_path(char **, char **, char **);
extern const char *get_vroot_name(void);
-extern int open_vroot(char *path, int flags, int mode, pathpt vroot_path, pathpt vroot_vroot);
-extern pathpt parse_path_string(register char *string, register int remove_slash);
+extern int open_vroot(char *, int, int, pathpt, pathpt);
+extern pathpt parse_path_string(char *, int);
extern void scan_path_first(void);
extern void scan_vroot_first(void);
-extern void set_path_style(int style);
+extern void set_path_style(int);
-extern int access_vroot(char *path, int mode, pathpt vroot_path, pathpt vroot_vroot);
+extern int access_vroot(char *, int, pathpt, pathpt);
-extern int execve_vroot(char *path, char **argv, char **environ, pathpt vroot_path, pathpt vroot_vroot);
+extern int execve_vroot(char *, char **, char **, pathpt, pathpt);
-extern int lstat_vroot(char *path, struct stat *buffer, pathpt vroot_path, pathpt vroot_vroot);
-extern int stat_vroot(char *path, struct stat *buffer, pathpt vroot_path, pathpt vroot_vroot);
-extern int readlink_vroot(char *path, char *buffer, int buffer_size, pathpt vroot_path, pathpt vroot_vroot);
+extern int lstat_vroot(char *, struct stat *, pathpt, pathpt);
+extern int stat_vroot(char *, struct stat *, pathpt, pathpt);
+extern int readlink_vroot(char *, char *, int, pathpt, pathpt);
-#endif
+#endif /* _VROOT_H_ */
diff --git a/usr/src/cmd/make/lib/mksh/macro.cc b/usr/src/cmd/make/lib/mksh/macro.cc
index b8151054a9..24e3a453ba 100644
--- a/usr/src/cmd/make/lib/mksh/macro.cc
+++ b/usr/src/cmd/make/lib/mksh/macro.cc
@@ -45,7 +45,7 @@
* File table of contents
*/
static void add_macro_to_global_list(Name macro_to_add);
-static void expand_value_with_daemon(Name, register Property macro, register String destination, Boolean cmd);
+static void expand_value_with_daemon(Name, Property macro, String destination, Boolean cmd);
static void init_arch_macros(void);
static void init_mach_macros(void);
@@ -70,11 +70,11 @@ long env_alloc_bytes = 0;
* Global variables used:
*/
Name
-getvar(register Name name)
+getvar(Name name)
{
String_rec destination;
wchar_t buffer[STRING_BUFFER_LENGTH];
- register Name result;
+ Name result;
if ((name == host_arch) || (name == target_arch)) {
if (!init_arch_done) {
@@ -115,12 +115,12 @@ getvar(register Name name)
* Global variables used:
*/
void
-expand_value(Name value, register String destination, Boolean cmd)
+expand_value(Name value, String destination, Boolean cmd)
{
Source_rec sourceb;
- register Source source = &sourceb;
- register wchar_t *source_p = NULL;
- register wchar_t *source_end = NULL;
+ Source source = &sourceb;
+ wchar_t *source_p = NULL;
+ wchar_t *source_end = NULL;
wchar_t *block_start = NULL;
int quote_seen = 0;
@@ -235,9 +235,9 @@ expand_value(Name value, register String destination, Boolean cmd)
* and get the value. The value is then expanded.
* destination is a String that is filled in with the expanded macro.
* It may be passed in referencing a buffer to expand the macro into.
- * Note that most expansions are done on demand, e.g. right
+ * Note that most expansions are done on demand, e.g. right
* before the command is executed and not while the file is
- * being parsed.
+ * being parsed.
*
* Parameters:
* source The source block that references the string
@@ -256,19 +256,19 @@ expand_value(Name value, register String destination, Boolean cmd)
* query_mentioned Set if the word "?" is mentioned
*/
void
-expand_macro(register Source source, register String destination, wchar_t *current_string, Boolean cmd)
+expand_macro(Source source, String destination, wchar_t *current_string, Boolean cmd)
{
static Name make = (Name)NULL;
static wchar_t colon_sh[4];
static wchar_t colon_shell[7];
String_rec string;
wchar_t buffer[STRING_BUFFER_LENGTH];
- register wchar_t *source_p = source->string.text.p;
- register wchar_t *source_end = source->string.text.end;
- register int closer = 0;
+ wchar_t *source_p = source->string.text.p;
+ wchar_t *source_end = source->string.text.end;
+ int closer = 0;
wchar_t *block_start = (wchar_t *)NULL;
int quote_seen = 0;
- register int closer_level = 1;
+ int closer_level = 1;
Name name = (Name)NULL;
wchar_t *colon = (wchar_t *)NULL;
wchar_t *percent = (wchar_t *)NULL;
@@ -857,7 +857,7 @@ add_macro_to_global_list(Name macro_to_add)
value_to_add = "";
}
- /*
+ /*
* Check if this macro is already on list, if so, do nothing
*/
for (macro_on_list = cond_macro_list;
@@ -885,11 +885,11 @@ add_macro_to_global_list(Name macro_to_add)
*
* Set the magic macros TARGET_ARCH, HOST_ARCH,
*
- * Parameters:
+ * Parameters:
*
* Global variables used:
- * host_arch Property for magic macro HOST_ARCH
- * target_arch Property for magic macro TARGET_ARCH
+ * host_arch Property for magic macro HOST_ARCH
+ * target_arch Property for magic macro TARGET_ARCH
*
* Return value:
* The function does not return a value, but can
@@ -940,11 +940,11 @@ init_arch_macros(void)
*
* Set the magic macros TARGET_MACH, HOST_MACH,
*
- * Parameters:
+ * Parameters:
*
* Global variables used:
- * host_mach Property for magic macro HOST_MACH
- * target_mach Property for magic macro TARGET_MACH
+ * host_mach Property for magic macro HOST_MACH
+ * target_mach Property for magic macro TARGET_MACH
*
* Return value:
* The function does not return a value, but can
@@ -1005,9 +1005,9 @@ init_mach_macros(void)
* Global variables used:
*/
static void
-expand_value_with_daemon(Name, register Property macro, register String destination, Boolean cmd)
+expand_value_with_daemon(Name, Property macro, String destination, Boolean cmd)
{
- register Chain chain;
+ Chain chain;
switch (macro->body.macro.daemon) {
@@ -1074,14 +1074,14 @@ int sunpro_dependencies_buf_size = 0;
* envvar A list of environment vars with $ in value
*/
Property
-setvar_daemon(register Name name, register Name value, Boolean append, Daemon daemon, Boolean strip_trailing_spaces, short debug_level)
+setvar_daemon(Name name, Name value, Boolean append, Daemon daemon, Boolean strip_trailing_spaces, short debug_level)
{
- register Property macro = maybe_append_prop(name, macro_prop);
- register Property macro_apx = get_prop(name->prop, macro_append_prop);
+ Property macro = maybe_append_prop(name, macro_prop);
+ Property macro_apx = get_prop(name->prop, macro_append_prop);
int length = 0;
String_rec destination;
wchar_t buffer[STRING_BUFFER_LENGTH];
- register Chain chain;
+ Chain chain;
Name val;
wchar_t *val_string = (wchar_t*)NULL;
Wstring wcb;
@@ -1111,7 +1111,7 @@ setvar_daemon(register Name name, register Name value, Boolean append, Daemon da
value = GETNAME(destination.buffer.start, FIND_LENGTH);
}
}
-
+
if(macro_apx != NULL) {
val = macro_apx->body.macro_appendix.value;
} else {
@@ -1313,7 +1313,7 @@ found_it:;
new_value = ALLOC_WC(length);
new_value_allocated = true;
WCSTOMBS(mbs_buffer, old_vr);
- (void) swprintf(new_value, length * SIZEOFWCHAR_T,
+ (void) swprintf(new_value, length * SIZEOFWCHAR_T,
L"/usr/arch/%s/%s:%s",
ha->string_mb + 1,
ta->string_mb + 1,
diff --git a/usr/src/cmd/make/lib/mksh/misc.cc b/usr/src/cmd/make/lib/mksh/misc.cc
index fe14fd874d..b46a7a1fd4 100644
--- a/usr/src/cmd/make/lib/mksh/misc.cc
+++ b/usr/src/cmd/make/lib/mksh/misc.cc
@@ -84,7 +84,7 @@ long getwstring_count = 0;
/*
* File table of contents
*/
-static void expand_string(register String string, register int length);
+static void expand_string(String string, int length);
#define FATAL_ERROR_MSG_SIZE 200
@@ -154,11 +154,11 @@ retmem_mb(caddr_t p)
* hashtab The hashtable used for the nametable
*/
Name
-getname_fn(wchar_t *name, register int len, register Boolean dont_enter, register Boolean * foundp)
+getname_fn(wchar_t *name, int len, Boolean dont_enter, Boolean * foundp)
{
- register int length;
- register wchar_t *cap = name;
- register Name np;
+ int length;
+ wchar_t *cap = name;
+ Name np;
static Name_rec empty_Name;
char *tmp_mbs_buffer = NULL;
char *mbs_name = mbs_buffer;
@@ -266,7 +266,7 @@ free_name(Name name)
* sighvalue The original signal handler
*/
void
-enable_interrupt(register void (*handler) (int))
+enable_interrupt(void (*handler) (int))
{
if (sigivalue != SIG_IGN) {
(void) bsd_signal(SIGINT, (SIG_PF) handler);
@@ -546,11 +546,11 @@ get_current_path_mksh(void)
* Global variables used:
*/
Property
-append_prop(register Name target, register Property_id type)
+append_prop(Name target, Property_id type)
{
- register Property *insert = &target->prop;
- register Property prop = *insert;
- register int size;
+ Property *insert = &target->prop;
+ Property prop = *insert;
+ int size;
switch (type) {
case conditional_prop:
@@ -623,9 +623,9 @@ append_prop(register Name target, register Property_id type)
* Global variables used:
*/
Property
-maybe_append_prop(register Name target, register Property_id type)
+maybe_append_prop(Name target, Property_id type)
{
- register Property prop;
+ Property prop;
if ((prop = get_prop(target->prop, type)) != NULL) {
return prop;
@@ -649,7 +649,7 @@ maybe_append_prop(register Name target, register Property_id type)
* Global variables used:
*/
Property
-get_prop(register Property start, register Property_id type)
+get_prop(Property start, Property_id type)
{
for (; start != NULL; start = start->next) {
if (start->type == type) {
@@ -672,7 +672,7 @@ get_prop(register Property start, register Property_id type)
* Global variables used:
*/
void
-append_string(register wchar_t *from, register String to, register int length)
+append_string(wchar_t *from, String to, int length)
{
if (length == FIND_LENGTH) {
length = wcslen(from);
@@ -703,7 +703,7 @@ wchar_t * get_wstring(char *from) {
}
void
-append_string(register char *from, register String to, register int length)
+append_string(char *from, String to, int length)
{
if (length == FIND_LENGTH) {
length = strlen(from);
@@ -735,9 +735,9 @@ append_string(register char *from, register String to, register int length)
* Global variables used:
*/
static void
-expand_string(register String string, register int length)
+expand_string(String string, int length)
{
- register wchar_t *p;
+ wchar_t *p;
if (string->buffer.start == NULL) {
/* For strings that have no memory allocated */
@@ -784,7 +784,7 @@ expand_string(register String string, register int length)
* Global variables used:
*/
void
-append_char(wchar_t from, register String to)
+append_char(wchar_t from, String to)
{
if (to->buffer.start == NULL) {
expand_string(to, 32);
@@ -829,7 +829,7 @@ handle_interrupt_mksh(int)
* sighvalue The original signal handler
*/
void
-setup_interrupt(register void (*handler) (int))
+setup_interrupt(void (*handler) (int))
{
sigivalue = bsd_signal(SIGINT, SIG_IGN);
sigqvalue = bsd_signal(SIGQUIT, SIG_IGN);
diff --git a/usr/src/cmd/make/lib/mksh/read.cc b/usr/src/cmd/make/lib/mksh/read.cc
index 6a6a2612b4..08dec3d5b3 100644
--- a/usr/src/cmd/make/lib/mksh/read.cc
+++ b/usr/src/cmd/make/lib/mksh/read.cc
@@ -59,18 +59,18 @@
*/
Boolean make_state_locked;
Source
-get_next_block_fn(register Source source)
+get_next_block_fn(Source source)
{
- register off_t to_read;
- register int length;
- register size_t num_wc_chars;
+ off_t to_read;
+ int length;
+ size_t num_wc_chars;
char ch_save;
char *ptr;
if (source == NULL) {
return NULL;
}
- if ((source->fd < 0) ||
+ if ((source->fd < 0) ||
((source->bytes_left_in_file <= 0) &&
(source->inp_buf_ptr >= source->inp_buf_end))) {
/* We can't read from the makefile, so pop the source block */
@@ -104,7 +104,7 @@ get_next_block_fn(register Source source)
* Hopefully the kernel managed to prefetch the stuff.
*/
to_read = source->bytes_left_in_file;
- source->inp_buf_ptr = source->inp_buf = getmem(to_read + 1);
+ source->inp_buf_ptr = source->inp_buf = getmem(to_read + 1);
source->inp_buf_end = source->inp_buf + to_read;
length = read(source->fd, source->inp_buf, (unsigned int) to_read);
if (length != to_read) {
@@ -139,7 +139,7 @@ get_next_block_fn(register Source source)
break;
}
}
-
+
if ((int) num_wc_chars == (size_t)-1) {
source->error_converting = true;
return source;
diff --git a/usr/src/cmd/make/lib/vroot/report.cc b/usr/src/cmd/make/lib/vroot/report.cc
index 9def773476..d022971f4b 100644
--- a/usr/src/cmd/make/lib/vroot/report.cc
+++ b/usr/src/cmd/make/lib/vroot/report.cc
@@ -122,7 +122,7 @@ close_file(void)
/* If .nse_depinfo file doesn't exist */
if ((nse_depinfo_fp = fopen(nse_depinfo_file, "r+")) == NULL) {
if (is_path) {
- if ((nse_depinfo_fp =
+ if ((nse_depinfo_fp =
fopen(nse_depinfo_file, "w")) == NULL) {
fprintf(stderr, gettext("Cannot open `%s' for writing\n"),
nse_depinfo_file);
@@ -131,7 +131,7 @@ close_file(void)
unlink(lock_file);
return;
}
- while (fgets(line, MAXPATHLEN+2, command_output_fp)
+ while (fgets(line, MAXPATHLEN+2, command_output_fp)
!= NULL) {
fprintf(nse_depinfo_fp, "%s", line);
}
@@ -155,7 +155,7 @@ close_file(void)
len = strlen(sfile);
while (fgets(line, MAXPATHLEN+2, nse_depinfo_fp) != NULL) {
if (strncmp(line, sfile, len) == 0 && line[len] == ':') {
- while (fgets(buf, MAXPATHLEN+2, command_output_fp)
+ while (fgets(buf, MAXPATHLEN+2, command_output_fp)
!= NULL) {
if (is_path) {
fprintf(merge_fp, "%s", buf);
@@ -173,10 +173,10 @@ close_file(void)
!= NULL) {
fputs(line, merge_fp);
}
- clean_up(nse_depinfo_fp, merge_fp,
+ clean_up(nse_depinfo_fp, merge_fp,
nse_depinfo_file, merge_file, 0);
} else {
- clean_up(nse_depinfo_fp, merge_fp,
+ clean_up(nse_depinfo_fp, merge_fp,
nse_depinfo_file, merge_file, 1);
}
if (file_locked) {
@@ -186,7 +186,7 @@ close_file(void)
return;
} /* entry found */
fputs(line, merge_fp);
- }
+ }
/* Entry never found. Add it if there is a search path */
if (is_path) {
while (fgets(line, MAXPATHLEN+2, command_output_fp) != NULL) {
@@ -206,7 +206,7 @@ report_dep(char *iflag, char *filename)
{
if (command_output_fp == NULL) {
- sprintf(command_output_tmpfile,
+ sprintf(command_output_tmpfile,
"%s/%s.%d.XXXXXX", tmpdir, NSE_DEPINFO, getpid());
int fd = mkstemp(command_output_tmpfile);
if ((fd < 0) || (command_output_fp = fdopen(fd, "w")) == NULL) {
@@ -268,7 +268,7 @@ report_search_path(char *iflag)
}
sprintf(filename, "%s-CPP", ptr+1);
getcwd(curdir, sizeof(curdir));
- if (strcmp(curdir, sdir) != 0 && strlen(iflag) > 2 &&
+ if (strcmp(curdir, sdir) != 0 && strlen(iflag) > 2 &&
iflag[2] != '/') {
/* Makefile must have had an "cd xx; cc ..." */
/* Modify the -I path to be relative to the cd */
@@ -283,10 +283,10 @@ report_search_path(char *iflag)
void
report_dependency(const char *name)
{
- register char *filename;
+ char *filename;
char buffer[MAXPATHLEN+1];
- register char *p;
- register char *p2;
+ char *p;
+ char *p2;
char nse_depinfo_file[MAXPATHLEN];
if (report_file == NULL) {
diff --git a/usr/src/cmd/make/lib/vroot/vroot.cc b/usr/src/cmd/make/lib/vroot/vroot.cc
index 785a0bc638..cd61967e12 100644
--- a/usr/src/cmd/make/lib/vroot/vroot.cc
+++ b/usr/src/cmd/make/lib/vroot/vroot.cc
@@ -57,12 +57,12 @@ static vroot_datat vroot_data= {
"", NULL, NULL, NULL, 0, 1};
void
-add_dir_to_path(const char *path, register pathpt *pointer, register int position)
+add_dir_to_path(const char *path, pathpt *pointer, int position)
{
- register int size= 0;
- register int length;
- register char *name;
- register pathcellpt p;
+ int size= 0;
+ int length;
+ char *name;
+ pathcellpt p;
pathpt new_path;
if (*pointer != NULL) {
@@ -88,9 +88,9 @@ add_dir_to_path(const char *path, register pathpt *pointer, register int positio
}
pathpt
-parse_path_string(register char *string, register int remove_slash)
+parse_path_string(char *string, int remove_slash)
{
- register char *p;
+ char *p;
pathpt result= NULL;
if (string != NULL)
@@ -148,7 +148,7 @@ set_path_style(int style)
}
char *
-get_vroot_path(register char **vroot, register char **path, register char **filename)
+get_vroot_path(char **vroot, char **path, char **filename)
{
if (vroot != NULL) {
if ((*vroot= vroot_data.vroot_start) == NULL)
@@ -163,13 +163,13 @@ get_vroot_path(register char **vroot, register char **path, register char **file
}
void
-translate_with_thunk(register char *filename, int (*thunk) (char *), pathpt path_vector, pathpt vroot_vector, rwt rw)
+translate_with_thunk(char *filename, int (*thunk) (char *), pathpt path_vector, pathpt vroot_vector, rwt rw)
{
- register pathcellt *vp;
- pathcellt *pp;
- register pathcellt *pp1;
- register char *p;
- int flags[256];
+ pathcellt *vp;
+ pathcellt *pp;
+ pathcellt *pp1;
+ char *p;
+ int flags[256];
/* Setup path to use */
if (rw == rw_write)
diff --git a/usr/src/cmd/nvmeadm/nvmeadm.c b/usr/src/cmd/nvmeadm/nvmeadm.c
index 80f63b0767..8aa55184cb 100644
--- a/usr/src/cmd/nvmeadm/nvmeadm.c
+++ b/usr/src/cmd/nvmeadm/nvmeadm.c
@@ -10,10 +10,9 @@
*/
/*
- * Copyright 2016 Nexenta Systems, Inc.
* Copyright 2017 Joyent, Inc.
- * Copyright 2019 Western Digital Corporation.
* Copyright 2021 Oxide Computer Company
+ * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
*/
/*
@@ -28,8 +27,7 @@
* secure-erase ...
* detach ...
* attach ...
- * get-param ...
- * set-param ...
+ * list-firmware ...
* load-firmware ...
* commit-firmware ...
* activate-firmware ...
@@ -110,6 +108,7 @@ static void usage_get_features(const char *);
static void usage_format(const char *);
static void usage_secure_erase(const char *);
static void usage_attach_detach(const char *);
+static void usage_firmware_list(const char *);
static void usage_firmware_load(const char *);
static void usage_firmware_commit(const char *);
static void usage_firmware_activate(const char *);
@@ -169,6 +168,12 @@ static const nvmeadm_cmd_t nvmeadm_cmds[] = {
do_attach_detach, usage_attach_detach, B_FALSE
},
{
+ "list-firmware",
+ "list firmware on a controller",
+ NULL,
+ do_get_logpage_fwslot, usage_firmware_list, B_FALSE
+ },
+ {
"load-firmware",
"load firmware to a controller",
NULL,
@@ -722,6 +727,14 @@ usage_get_logpage(const char *c_name)
"are error, health, and firmware.\n", c_name);
}
+static void
+usage_firmware_list(const char *c_name)
+{
+ (void) fprintf(stderr, "%s <ctl>\n\n"
+ " Print the log page that contains the list of firmware "
+ "images installed on the specified NVMe controller.\n", c_name);
+}
+
static int
do_get_logpage_error(int fd, const nvme_process_arg_t *npa)
{
@@ -788,7 +801,7 @@ do_get_logpage_fwslot(int fd, const nvme_process_arg_t *npa)
return (-1);
(void) printf("%s: ", npa->npa_name);
- nvme_print_fwslot_log(fwlog);
+ nvme_print_fwslot_log(fwlog, npa->npa_idctl);
free(fwlog);
@@ -1314,6 +1327,7 @@ do_firmware_load(int fd, const nvme_process_arg_t *npa)
ssize_t len;
offset_t offset = 0;
size_t size;
+ uint16_t sc;
char buf[FIRMWARE_READ_BLKSIZE];
if (npa->npa_argc > 2)
@@ -1323,6 +1337,10 @@ do_firmware_load(int fd, const nvme_process_arg_t *npa)
errx(-1, "Requires firmware file name, and an "
"optional offset");
+ if (npa->npa_isns)
+ errx(-1, "Firmware loading not available on a per-namespace "
+ "basis");
+
if (npa->npa_argc == 2)
offset = get_fw_offsetb(npa->npa_argv[1]);
@@ -1342,9 +1360,9 @@ do_firmware_load(int fd, const nvme_process_arg_t *npa)
if (len == 0)
break;
- if (!nvme_firmware_load(fd, buf, len, offset))
+ if (!nvme_firmware_load(fd, buf, len, offset, &sc))
errx(-1, "Error loading \"%s\": %s", npa->npa_argv[0],
- strerror(errno));
+ nvme_fw_error(errno, sc));
offset += len;
size += len;
@@ -1390,7 +1408,7 @@ static int
do_firmware_commit(int fd, const nvme_process_arg_t *npa)
{
uint_t slot;
- uint16_t sct, sc;
+ uint16_t sc;
if (npa->npa_argc > 1)
errx(-1, "Too many arguments");
@@ -1398,11 +1416,18 @@ do_firmware_commit(int fd, const nvme_process_arg_t *npa)
if (npa->npa_argc == 0)
errx(-1, "Firmware slot number is required");
+ if (npa->npa_isns)
+ errx(-1, "Firmware committing not available on a per-namespace "
+ "basis");
+
slot = get_slot_number(npa->npa_argv[0]);
- if (!nvme_firmware_commit(fd, slot, NVME_FWC_SAVE, &sct, &sc))
+ if (slot == 1 && npa->npa_idctl->id_frmw.fw_readonly)
+ errx(-1, "Cannot commit firmware to slot 1: slot is read-only");
+
+ if (!nvme_firmware_commit(fd, slot, NVME_FWC_SAVE, &sc))
errx(-1, "Failed to commit firmware to slot %u: %s",
- slot, nvme_str_error(sct, sc));
+ slot, nvme_fw_error(errno, sc));
if (verbose)
(void) printf("Firmware committed to slot %u.\n", slot);
@@ -1423,7 +1448,7 @@ static int
do_firmware_activate(int fd, const nvme_process_arg_t *npa)
{
uint_t slot;
- uint16_t sct, sc;
+ uint16_t sc;
if (npa->npa_argc > 1)
errx(-1, "Too many arguments");
@@ -1431,15 +1456,19 @@ do_firmware_activate(int fd, const nvme_process_arg_t *npa)
if (npa->npa_argc == 0)
errx(-1, "Firmware slot number is required");
+ if (npa->npa_isns)
+ errx(-1, "Firmware activation not available on a per-namespace "
+ "basis");
+
slot = get_slot_number(npa->npa_argv[0]);
- if (!nvme_firmware_commit(fd, slot, NVME_FWC_ACTIVATE, &sct, &sc))
+ if (!nvme_firmware_commit(fd, slot, NVME_FWC_ACTIVATE, &sc))
errx(-1, "Failed to activate slot %u: %s", slot,
- nvme_str_error(sct, sc));
+ nvme_fw_error(errno, sc));
if (verbose)
printf("Slot %u activated: %s.\n", slot,
- nvme_str_error(sct, sc));
+ nvme_fw_error(errno, sc));
return (0);
}
diff --git a/usr/src/cmd/nvmeadm/nvmeadm.h b/usr/src/cmd/nvmeadm/nvmeadm.h
index ff6a21c87f..6b620f8fab 100644
--- a/usr/src/cmd/nvmeadm/nvmeadm.h
+++ b/usr/src/cmd/nvmeadm/nvmeadm.h
@@ -10,9 +10,8 @@
*/
/*
- * Copyright 2016 Nexenta Systems, Inc.
- * Copyright 2019 Western Digital Corporation
* Copyright 2021 Oxide Computer Company
+ * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
*/
#ifndef _NVMEADM_H
@@ -69,7 +68,7 @@ extern void nvme_print_error_log(int, nvme_error_log_entry_t *,
nvme_version_t *);
extern void nvme_print_health_log(nvme_health_log_t *, nvme_identify_ctrl_t *,
nvme_version_t *);
-extern void nvme_print_fwslot_log(nvme_fwslot_log_t *);
+extern void nvme_print_fwslot_log(nvme_fwslot_log_t *, nvme_identify_ctrl_t *);
extern void nvme_print_feat_arbitration(uint64_t, void *, size_t,
nvme_identify_ctrl_t *, nvme_version_t *);
@@ -97,7 +96,7 @@ extern void nvme_print_feat_auto_pst(uint64_t, void *, size_t,
nvme_identify_ctrl_t *, nvme_version_t *);
extern void nvme_print_feat_progress(uint64_t, void *, size_t,
nvme_identify_ctrl_t *, nvme_version_t *);
-extern const char *nvme_str_error(int, int);
+extern const char *nvme_fw_error(int, int);
/* device node functions */
extern int nvme_open(di_minor_t);
@@ -113,8 +112,8 @@ extern int nvme_intr_cnt(int);
extern boolean_t nvme_format_nvm(int, uint8_t, uint8_t);
extern boolean_t nvme_detach(int);
extern boolean_t nvme_attach(int);
-extern boolean_t nvme_firmware_load(int, void *, size_t, offset_t);
-extern boolean_t nvme_firmware_commit(int fd, int, int, uint16_t *, uint16_t *);
+extern boolean_t nvme_firmware_load(int, void *, size_t, offset_t, uint16_t *);
+extern boolean_t nvme_firmware_commit(int, int, int, uint16_t *);
/*
* ofmt related
diff --git a/usr/src/cmd/nvmeadm/nvmeadm_dev.c b/usr/src/cmd/nvmeadm/nvmeadm_dev.c
index fca609a320..1617de5da9 100644
--- a/usr/src/cmd/nvmeadm/nvmeadm_dev.c
+++ b/usr/src/cmd/nvmeadm/nvmeadm_dev.c
@@ -10,8 +10,7 @@
*/
/*
- * Copyright 2016 Nexenta Systems, Inc.
- * Copyright 2019 Western Digital Corporation
+ * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -35,9 +34,6 @@ nvme_ioctl(int fd, int ioc, size_t *bufsize, void **buf, uint64_t arg,
void *ptr = NULL;
int ret;
- if (res != NULL)
- *res = ~0ULL;
-
if (bufsize != NULL && *bufsize != 0) {
assert(buf != NULL);
@@ -62,6 +58,13 @@ nvme_ioctl(int fd, int ioc, size_t *bufsize, void **buf, uint64_t arg,
*res = nioc.n_arg;
if (ret != 0) {
+ /*
+ * We're not clearing *res here as there may be cases where
+ * we get an error _and_ we have interesting information in
+ * returned in *res that callers of this functions might be
+ * interested in.
+ */
+
if (debug)
warn("nvme_ioctl()");
if (ptr != NULL)
@@ -178,14 +181,28 @@ nvme_attach(int fd)
}
boolean_t
-nvme_firmware_load(int fd, void *buf, size_t len, offset_t offset)
+nvme_firmware_load(int fd, void *buf, size_t len, offset_t offset, uint16_t *sc)
{
- return (nvme_ioctl(fd, NVME_IOC_FIRMWARE_DOWNLOAD, &len, &buf, offset,
- NULL));
+ boolean_t rv;
+ uint64_t res;
+
+ rv = nvme_ioctl(fd, NVME_IOC_FIRMWARE_DOWNLOAD, &len, &buf, offset,
+ &res);
+
+ /*
+ * If the hardware returned a command-specific status code, we'll get
+ * it as a negative value from the driver.
+ */
+ if ((int64_t)res < 0)
+ *sc = (uint16_t)-(int64_t)res;
+ else
+ *sc = 0;
+
+ return (rv);
}
boolean_t
-nvme_firmware_commit(int fd, int slot, int action, uint16_t *sct, uint16_t *sc)
+nvme_firmware_commit(int fd, int slot, int action, uint16_t *sc)
{
boolean_t rv;
uint64_t res;
@@ -193,10 +210,14 @@ nvme_firmware_commit(int fd, int slot, int action, uint16_t *sct, uint16_t *sc)
rv = nvme_ioctl(fd, NVME_IOC_FIRMWARE_COMMIT, NULL, NULL,
((uint64_t)action << 32) | slot, &res);
- if (sct != NULL)
- *sct = (uint16_t)(res >> 16);
- if (sc != NULL)
- *sc = (uint16_t)res;
+ /*
+ * If the hardware returned a command-specific status code, we'll get
+ * it as a negative value from the driver.
+ */
+ if ((int64_t)res < 0)
+ *sc = (uint16_t)-(int64_t)res;
+ else
+ *sc = 0;
return (rv);
}
diff --git a/usr/src/cmd/nvmeadm/nvmeadm_print.c b/usr/src/cmd/nvmeadm/nvmeadm_print.c
index 9190131566..43c15925b2 100644
--- a/usr/src/cmd/nvmeadm/nvmeadm_print.c
+++ b/usr/src/cmd/nvmeadm/nvmeadm_print.c
@@ -10,9 +10,9 @@
*/
/*
- * Copyright 2016 Nexenta Systems, Inc.
- * Copyright 2019 Western Digital Corporation
* Copyright 2021 Oxide Computer Company
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
*/
/*
@@ -1909,17 +1909,25 @@ nvme_print_health_log(nvme_health_log_t *hlog, nvme_identify_ctrl_t *idctl,
* This function pretty-prints the firmware slot information.
*/
void
-nvme_print_fwslot_log(nvme_fwslot_log_t *fwlog)
+nvme_print_fwslot_log(nvme_fwslot_log_t *fwlog, nvme_identify_ctrl_t *idctl)
{
int i;
+ char str[NVME_FWVER_SZ + sizeof (" (read-only)")];
+
nvme_print(0, "Firmware Slot Information", -1, NULL);
nvme_print_uint64(2, "Active Firmware Slot", fwlog->fw_afi, NULL, NULL);
if (fwlog->fw_next != 0)
nvme_print_uint64(2, "Next Firmware Slot", fwlog->fw_next,
NULL, NULL);
- for (i = 0; i != ARRAYSIZE(fwlog->fw_frs); i++) {
+
+ (void) snprintf(str, sizeof (str), "%.*s%s",
+ nvme_strlen(fwlog->fw_frs[0], sizeof (fwlog->fw_frs[0])),
+ fwlog->fw_frs[0], idctl->id_frmw.fw_readonly ? " (read-only)" : "");
+ nvme_print_str(2, "Firmware Revision for Slot", 1, str, sizeof (str));
+
+ for (i = 1; i < idctl->id_frmw.fw_nslot; i++) {
nvme_print_str(2, "Firmware Revision for Slot", i + 1,
fwlog->fw_frs[i][0] == '\0' ? "<Unused>" :
fwlog->fw_frs[i], sizeof (fwlog->fw_frs[i]));
@@ -2166,6 +2174,34 @@ nvme_print_feat_async_event(uint64_t res, void *b, size_t s,
nvme_version_check(version, 1, 0),
aec.b.aec_volatile, "enabled", "disabled");
}
+
+ /* NVMe 1.2 */
+ nvme_print_bit(4, "Namespace attribute notices",
+ nvme_version_check(version, 1, 2),
+ aec.b.aec_nsan, "enabled", "disabled");
+ nvme_print_bit(4, "Firmware activation notices",
+ nvme_version_check(version, 1, 2),
+ aec.b.aec_fwact, "enabled", "disabled");
+
+ /* NVMe 1.3 */
+ nvme_print_bit(4, "Telemetry log notices",
+ nvme_version_check(version, 1, 3),
+ aec.b.aec_telln, "enabled", "disabled");
+
+ /* NVMe 1.4 */
+ nvme_print_bit(4, "ANA change notices",
+ nvme_version_check(version, 1, 4),
+ aec.b.aec_ansacn, "enabled", "disabled");
+ nvme_print_bit(4,
+ "Predictable latency event aggr. LCNs",
+ nvme_version_check(version, 1, 4),
+ aec.b.aec_plat, "enabled", "disabled");
+ nvme_print_bit(4, "LBA status information notices",
+ nvme_version_check(version, 1, 4),
+ aec.b.aec_lbasi, "enabled", "disabled");
+ nvme_print_bit(4, "Endurance group event aggregate LCNs",
+ nvme_version_check(version, 1, 4),
+ aec.b.aec_egeal, "enabled", "disabled");
}
void
@@ -2214,21 +2250,12 @@ nvme_print_feat_progress(uint64_t res, void *b, size_t s,
spm.b.spm_pbslc, NULL, NULL);
}
-static const char *
-nvme_str_generic_error(int sc)
+const char *
+nvme_fw_error(int err, int sc)
{
- switch (sc) {
- case NVME_CQE_SC_GEN_SUCCESS:
- return ("Success");
- default:
- return ("See message log (usually /var/adm/messages) "
- "for details");
- }
-}
+ if (sc == 0)
+ return (strerror(err));
-static const char *
-nvme_str_specific_error(int sc)
-{
switch (sc) {
case NVME_CQE_SC_SPC_INV_FW_SLOT:
return ("Invalid firmware slot");
@@ -2250,20 +2277,5 @@ nvme_str_specific_error(int sc)
return ("See message log (usually /var/adm/messages) "
"for details");
}
-}
-const char *
-nvme_str_error(int sct, int sc)
-{
- switch (sct) {
- case NVME_CQE_SCT_GENERIC:
- return (nvme_str_generic_error(sc));
-
- case NVME_CQE_SCT_SPECIFIC:
- return (nvme_str_specific_error(sc));
-
- default:
- return ("See message log (usually /var/adm/messages) "
- "for details");
- }
}
diff --git a/usr/src/cmd/pcieadm/pcieadm_cfgspace.c b/usr/src/cmd/pcieadm/pcieadm_cfgspace.c
index 1f4a5daf48..73841d4c23 100644
--- a/usr/src/cmd/pcieadm/pcieadm_cfgspace.c
+++ b/usr/src/cmd/pcieadm/pcieadm_cfgspace.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2021 Oxide Computer Company
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -499,6 +499,7 @@ pcieadm_cfgspace_print_regdef(pcieadm_cfgspace_walk_t *walkp,
if (strval == NULL) {
strval = "reserved";
}
+
pcieadm_field_printf(walkp, regdef->prd_short,
regdef->prd_human, regval, "%s (0x%" PRIx64 ")\n",
strval, regval << regdef->prd_lowbit);
@@ -1171,9 +1172,9 @@ static pcieadm_regdef_t pcieadm_regdef_msictrl[] = {
.prd_val = { .prdv_strval = { "unsupported", "supported" } } },
{ 8, 8, "pvm", "Per-Vector Masking Capable", PRDV_STRVAL,
.prd_val = { .prdv_strval = { "unsupported", "supported" } } },
- { 9, 9, "extmdcap", "Extended Message Data Capable",
+ { 9, 9, "extmdcap", "Extended Message Data Capable", PRDV_STRVAL,
.prd_val = { .prdv_strval = { "unsupported", "supported" } } },
- { 10, 10, "extmden", "extended Message Data Enable",
+ { 10, 10, "extmden", "extended Message Data Enable", PRDV_STRVAL,
.prd_val = { .prdv_strval = { "unsupported", "supported" } } },
{ -1, -1, NULL }
};
@@ -1438,17 +1439,19 @@ static pcieadm_regdef_t pcieadm_regdef_pcie_linkctl[] = {
{ 5, 5, "retrain", "Retrain Link", PRDV_HEX },
{ 6, 6, "ccc", "Common Clock Configuration", PRDV_STRVAL,
.prd_val = { .prdv_strval = { "asynchronous", "common" } } },
- { 7, 7, "extsync", "Extended Sync", PRDV_HEX,
+ { 7, 7, "extsync", "Extended Sync", PRDV_STRVAL,
.prd_val = { .prdv_strval = { "disabled", "enabled" } } },
- { 8, 8, "clkpm", "Clock Power Management", PRDV_HEX,
+ { 8, 8, "clkpm", "Clock Power Management", PRDV_STRVAL,
.prd_val = { .prdv_strval = { "disabled", "enabled" } } },
- { 9, 9, "hwawd", "Hardware Autonomous Width", PRDV_HEX,
+ { 9, 9, "hwawd", "Hardware Autonomous Width", PRDV_STRVAL,
.prd_val = { .prdv_strval = { "enabled", "disabled" } } },
- { 10, 10, "linkbwint", "Link Bandwidth Management Interrupt", PRDV_HEX,
- .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
- { 11, 11, "linkabwint", "Link Autonomous Bandwidth Interrupt", PRDV_HEX,
- .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
- { 14, 15, "drs", "DRS Signaling Control", PRDV_HEX,
+ { 10, 10, "linkbwint", "Link Bandwidth Management Interrupt",
+ PRDV_STRVAL, .prd_val = { .prdv_strval = { "disabled",
+ "enabled" } } },
+ { 11, 11, "linkabwint", "Link Autonomous Bandwidth Interrupt",
+ PRDV_STRVAL, .prd_val = { .prdv_strval = { "disabled",
+ "enabled" } } },
+ { 14, 15, "drs", "DRS Signaling Control", PRDV_STRVAL,
.prd_val = { .prdv_strval = { "not reported", "Interrupt enabled",
"DRS->FRS enabled" } } },
{ -1, -1, NULL }
@@ -1489,9 +1492,9 @@ static pcieadm_regdef_t pcieadm_regdef_pcie_slotcap[] = {
.prd_val = { .prdv_strval = { "unsupported", "supported" } } },
{ 7, 14, "slotplv", "Slot Power Limit Value", PRDV_HEX },
{ 15, 16, "slotpls", "Slot Power Limit Scale", PRDV_HEX },
- { 17, 17, "emi", "Electromechanical Interlock Present",
+ { 17, 17, "emi", "Electromechanical Interlock Present", PRDV_STRVAL,
.prd_val = { .prdv_strval = { "no", "yes" } } },
- { 18, 18, "ncc", "No Command Completed", PRDV_HEX,
+ { 18, 18, "ncc", "No Command Completed", PRDV_STRVAL,
.prd_val = { .prdv_strval = { "unsupported", "supported" } } },
{ 19, 31, "slotno", "Physical Slot Number", PRDV_HEX },
{ -1, -1, NULL }
@@ -4264,6 +4267,91 @@ pcieadm_cap_info_ht(pcieadm_cfgspace_walk_t *walkp,
}
}
+/*
+ * Root Complex Link Declaration
+ */
+static pcieadm_regdef_t pcieadm_regdef_rcld_desc[] = {
+ { 0, 3, "type", "Element Type", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "Configuration Space Element",
+ "System Egress Port or internal sink",
+ "Internal Root Complex Link" } } },
+ { 8, 15, "num", "Number of Entries", PRDV_HEX },
+ { 16, 23, "id", "Component ID", PRDV_HEX },
+ { 24, 31, "port", "Port Number", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_rcld_link[] = {
+ { 0, 0, "valid", "Link Valid", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 1, 1, "type", "Link Type", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "RCRB", "Configuration Space" } } },
+ { 2, 2, "rcrb", "Assosciate RCRB", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 16, 23, "tid", "Target Component ID", PRDV_HEX },
+ { 24, 31, "tport", "Target Port Number", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+/*
+ * Print a variable number of Root Complex Links.
+ */
+static void
+pcieadm_cfgspace_print_rcld(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ uint_t nlinks = walkp->pcw_data->pcb_u8[walkp->pcw_capoff + 5];
+
+ for (uint_t i = 0; i < nlinks; i++) {
+ char mshort[32], mhuman[128];
+ pcieadm_cfgspace_print_t p;
+ uint16_t off = print->pcp_off + i * 0x10;
+ uint8_t type = walkp->pcw_data->pcb_u8[walkp->pcw_capoff + off];
+
+ (void) snprintf(mshort, sizeof (mshort), "link%udesc", i);
+ (void) snprintf(mhuman, sizeof (mhuman), "Link %u Description");
+
+ p.pcp_off = off;
+ p.pcp_len = 4;
+ p.pcp_short = mshort;
+ p.pcp_human = mhuman;
+ p.pcp_print = pcieadm_cfgspace_print_regdef;
+ p.pcp_arg = pcieadm_regdef_rcld_link;
+
+ p.pcp_print(walkp, &p, p.pcp_arg);
+
+ /*
+ * The way that we print the link depends on the actual type of
+ * link which is in bit 2 of the link description.
+ */
+ p.pcp_off += 8;
+
+ if ((type & (1 << 1)) == 0) {
+ (void) snprintf(mshort, sizeof (mshort),
+ "link%uaddr", i);
+ (void) snprintf(mhuman, sizeof (mhuman),
+ "Link %u Address");
+ p.pcp_len = 8;
+ p.pcp_print = pcieadm_cfgspace_print_hex;
+ p.pcp_arg = NULL;
+
+ p.pcp_print(walkp, &p, p.pcp_arg);
+ } else {
+ warnx("encountered unsupported RCLD Link Address");
+ }
+ }
+}
+
+static pcieadm_cfgspace_print_t pcieadm_cap_rcld[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 4, "desc", "Self Description",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_rcld_desc },
+ { 0x10, 0x10, "link", "Link Entry", pcieadm_cfgspace_print_rcld },
+ { -1, -1, NULL }
+};
+
+
pcieadm_pci_cap_t pcieadm_pci_caps[] = {
{ PCI_CAP_ID_PM, "pcipm", "PCI Power Management",
pcieadm_cap_info_pcipm, { { 2, 8, pcieadm_cap_pcipm_v3 },
@@ -4316,7 +4404,8 @@ pcieadm_pci_cap_t pcieadm_pcie_caps[] = {
{ PCIE_EXT_CAP_ID_PWR_BUDGET, "powbudg", "Power Budgeting",
pcieadm_cap_info_vers, { { 1, 0x10, pcieadm_cap_powbudg } } },
{ PCIE_EXT_CAP_ID_RC_LINK_DECL, "rcld",
- "Root Complex Link Declaration" },
+ "Root Complex Link Declaration", pcieadm_cap_info_vers,
+ { { 1, 0x1c, pcieadm_cap_rcld } } },
{ PCIE_EXT_CAP_ID_RC_INT_LINKCTRL, "rcilc",
"Root Complex Internal Link Control" },
{ PCIE_EXT_CAP_ID_RC_EVNT_CEA, "rcecea",
diff --git a/usr/src/cmd/pcieadm/pcieadm_devs.c b/usr/src/cmd/pcieadm/pcieadm_devs.c
index dc157d8d2a..2459662c1a 100644
--- a/usr/src/cmd/pcieadm/pcieadm_devs.c
+++ b/usr/src/cmd/pcieadm/pcieadm_devs.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2021 Oxide Computer Company
+ * Copyright 2022 Oxide Computer Company
*/
#include <err.h>
@@ -28,6 +28,7 @@ typedef struct pcieadm_show_devs {
boolean_t psd_funcs;
int psd_nfilts;
char **psd_filts;
+ boolean_t *psd_used;
uint_t psd_nprint;
} pcieadm_show_devs_t;
@@ -291,20 +292,24 @@ pcieadm_show_devs_match(pcieadm_show_devs_t *psd,
const char *filt = psd->psd_filts[i];
if (strcmp(filt, psdo->psdo_path) == 0) {
+ psd->psd_used[i] = B_TRUE;
return (B_TRUE);
}
if (strcmp(filt, bdf) == 0) {
+ psd->psd_used[i] = B_TRUE;
return (B_TRUE);
}
if (psdo->psdo_driver != NULL &&
strcmp(filt, psdo->psdo_driver) == 0) {
+ psd->psd_used[i] = B_TRUE;
return (B_TRUE);
}
if (psdo->psdo_driver != NULL && psdo->psdo_instance != -1 &&
strcmp(filt, dinst) == 0) {
+ psd->psd_used[i] = B_TRUE;
return (B_TRUE);
}
@@ -313,6 +318,7 @@ pcieadm_show_devs_match(pcieadm_show_devs_t *psd,
}
if (strcmp(filt, psdo->psdo_path) == 0) {
+ psd->psd_used[i] = B_TRUE;
return (B_TRUE);
}
}
@@ -488,7 +494,7 @@ pcieadm_show_devs_help(const char *fmt, ...)
int
pcieadm_show_devs(pcieadm_t *pcip, int argc, char *argv[])
{
- int c;
+ int c, ret;
uint_t flags = 0;
const char *fields = NULL;
pcieadm_show_devs_t psd;
@@ -557,6 +563,11 @@ pcieadm_show_devs(pcieadm_t *pcip, int argc, char *argv[])
if (argc > 0) {
psd.psd_nfilts = argc;
psd.psd_filts = argv;
+ psd.psd_used = calloc(argc, sizeof (boolean_t));
+ if (psd.psd_used == NULL) {
+ err(EXIT_FAILURE, "failed to allocate filter tracking "
+ "memory");
+ }
}
oferr = ofmt_open(fields, pcieadm_show_dev_ofmt, flags, 0,
@@ -568,9 +579,18 @@ pcieadm_show_devs(pcieadm_t *pcip, int argc, char *argv[])
pcieadm_di_walk(pcip, &walk);
- if (psd.psd_nprint > 0) {
- return (EXIT_SUCCESS);
- } else {
- return (EXIT_FAILURE);
+ ret = EXIT_SUCCESS;
+ for (int i = 0; i < psd.psd_nfilts; i++) {
+ if (!psd.psd_used[i]) {
+ warnx("filter '%s' did not match any devices",
+ psd.psd_filts[i]);
+ ret = EXIT_FAILURE;
+ }
}
+
+ if (psd.psd_nprint == 0) {
+ ret = EXIT_FAILURE;
+ }
+
+ return (ret);
}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/LDAPAuthentication.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/LDAPAuthentication.rawhlp
index a2d86b8c9c..2951b9d9c5 100644
--- a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/LDAPAuthentication.rawhlp
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/LDAPAuthentication.rawhlp
@@ -45,7 +45,7 @@ different server name if appropriate.
2. Check the Distinguished Name (DN) for correctness. You may enter a
different distinguished name of another user if appropriate. This may be the DN
of any directory user who has permissions (directory update privileges) to
-update printer entries in the LDAP directory for the current ldapclient (1M)
+update printer entries in the LDAP directory for the current ldapclient(8)
naming service (NS) domain.
<p>
@@ -84,7 +84,7 @@ server specified then the first one will be used.
<p>
The Print Manager always displays printer entries from the current
-ldapclient (1M) server. If this is not the domain Master LDAP server then
+ldapclient(8) server. If this is not the domain Master LDAP server then
the list of printers displayed may <b>not</b> be the current list of printers,
this is because the ldapclient replica server may not have been updated by the
master server and so be out of sync with the master. Replica servers can have
@@ -105,7 +105,7 @@ Users can use the ldap command line utilities (ldapadd (1) & ldapmodify (1))
to update printer entries in the directory, but this is not recommended. If
these utilities are used then the user <b>must ensure</b> that the printer-name
attribute value is unique within the ou=printers container. If it is not unique
-the result of modifies done by the print manager (or lpset (1M)) may not be
+the result of modifies done by the print manager (or lpset(8)) may not be
predictable.
<p>
diff --git a/usr/src/cmd/ps/Makefile b/usr/src/cmd/ps/Makefile
index d1b61c7874..50f4f0f390 100644
--- a/usr/src/cmd/ps/Makefile
+++ b/usr/src/cmd/ps/Makefile
@@ -29,44 +29,31 @@ OBJS=ps.o ucbps.o
SRCS=$(OBJS:%.o=%.c)
include ../Makefile.cmd
+include ../Makefile.cmd.64
+include ../Makefile.ctf
+
+LDLIBS += -lproject
XGETFLAGS += -a -x ps.xcl
DCFILE= $(PROG).dc
ROOTUCBPROG = $(ROOT)/usr/ucb/$(PROG)
-ROOTUCBPROG32 = $(ROOT)/usr/ucb/$(MACH32)/$(PROG)
-ROOTUCBPROG64 = $(ROOT)/usr/ucb/$(MACH64)/$(PROG)
-
-$(64ONLY)SUBDIRS= $(MACH)
-$(BUILD64)SUBDIRS += $(MACH64)
-
-all := TARGET = all
-install := TARGET = install
-clean := TARGET = clean
-clobber := TARGET = clobber
-lint := TARGET = lint
.KEEP_STATE:
-all: $(SUBDIRS)
+all: $(PROG)
-clean clobber lint: $(SUBDIRS)
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
-install: $(SUBDIRS)
- -$(RM) $(ROOTPROG)
- -$(LN) $(ISAEXEC) $(ROOTPROG)
+install: $(PROG) $(ROOTPROG)
-$(RM) $(ROOTUCBPROG)
- -$(LN) $(ISAEXEC) $(ROOTUCBPROG)
- $(64ONLY)-$(RM) $(ROOTUCBPROG32)
- $(64ONLY)-$(LN) $(ROOTPROG32) $(ROOTUCBPROG32)
- $(BUILD64)-$(RM) $(ROOTUCBPROG64)
- $(BUILD64)-$(LN) $(ROOTPROG64) $(ROOTUCBPROG64)
-
-$(SUBDIRS): FRC
- @cd $@; pwd; $(MAKE) $(TARGET)
+ -$(LN) $(ROOTPROG) $(ROOTUCBPROG)
-FRC:
+clean:
+ $(RM) $(OBJS)
$(DCFILE): $(PROG).c
$(RM) $(DCFILE)
diff --git a/usr/src/cmd/ps/Makefile.com b/usr/src/cmd/ps/Makefile.com
deleted file mode 100644
index d9209ba95a..0000000000
--- a/usr/src/cmd/ps/Makefile.com
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-#
-# Copyright (c) 2018, Joyent, Inc.
-
-PROG= ps
-
-OBJS= ps.o ucbps.o
-
-SRCS= $(OBJS:%.o=../%.c)
-
-include ../../Makefile.cmd
-
-CFLAGS += $(CCVERBOSE)
-LDLIBS += -lproject
-
-# not linted
-SMATCH=off
-
-.KEEP_STATE:
-
-%.o: ../%.c
- $(COMPILE.c) $<
-
-$(PROG): $(OBJS)
- $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
- $(POST_PROCESS)
-
-clean:
- $(RM) $(OBJS)
-
-lint:
- $(LINT.c) $(SRCS) $(LDLIBS)
diff --git a/usr/src/cmd/ps/amd64/Makefile b/usr/src/cmd/ps/amd64/Makefile
deleted file mode 100644
index c33134f58c..0000000000
--- a/usr/src/cmd/ps/amd64/Makefile
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-#
-# ident "%Z%%M% %I% %E% SMI"
-#
-
-include ../Makefile.com
-include ../../Makefile.cmd.64
-
-all: $(PROG)
-
-install: all $(ROOTPROG64)
-
-include ../../Makefile.targ
diff --git a/usr/src/cmd/ps/i386/Makefile b/usr/src/cmd/ps/i386/Makefile
deleted file mode 100644
index 3f3aa6352a..0000000000
--- a/usr/src/cmd/ps/i386/Makefile
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-#ident "%Z%%M% %I% %E% SMI"
-#
-# Copyright (c) 1998-2000 by Sun Microsystems, Inc.
-# All rights reserved.
-#
-# cmd/ps/i386/Makefile
-#
-
-include ../Makefile.com
-
-lint := LINTFLAGS = -x
-
-all: $(PROG)
-
-install: all $(ROOTPROG32)
-
-include ../../Makefile.targ
diff --git a/usr/src/cmd/ps/sparcv9/Makefile b/usr/src/cmd/ps/sparcv9/Makefile
deleted file mode 100644
index aaa2f3ee7a..0000000000
--- a/usr/src/cmd/ps/sparcv9/Makefile
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-#
-# cmd/ps/sparcv9/Makefile
-#
-
-include ../Makefile.com
-include ../../Makefile.cmd.64
-
-CFLAGS64 += $(CCVERBOSE)
-
-lint := LINTFLAGS64 = -x -m64
-
-all: $(PROG)
-
-install: all $(ROOTPROG64)
-
-include ../../Makefile.targ
diff --git a/usr/src/cmd/ps/ucbps.c b/usr/src/cmd/ps/ucbps.c
index 3110e95313..6abeb1baea 100644
--- a/usr/src/cmd/ps/ucbps.c
+++ b/usr/src/cmd/ps/ucbps.c
@@ -167,7 +167,6 @@ ucbmain(int argc, char **argv)
struct dirent *dentp;
char psname[100];
char asname[100];
- int pdlen;
size_t len;
(void) setlocale(LC_ALL, "");
@@ -391,21 +390,24 @@ ucbmain(int argc, char **argv)
exit(1);
}
- (void) strcpy(psname, procdir);
- pdlen = strlen(psname);
- psname[pdlen++] = '/';
-
/* for each active process --- */
while ((dentp = readdir(dirp)) != NULL) {
int psfd; /* file descriptor for /proc/nnnnn/psinfo */
int asfd; /* file descriptor for /proc/nnnnn/as */
+ int n;
if (dentp->d_name[0] == '.') /* skip . and .. */
continue;
- (void) strcpy(psname + pdlen, dentp->d_name);
- (void) strcpy(asname, psname);
- (void) strcat(psname, "/psinfo");
- (void) strcat(asname, "/as");
+ n = snprintf(psname, sizeof (psname), "%s/%s/psinfo",
+ procdir, dentp->d_name);
+ if (n < 0 || n >= sizeof (psname))
+ exit(1);
+
+ n = snprintf(asname, sizeof (asname), "%s/%s/as",
+ procdir, dentp->d_name);
+ if (n < 0 || n >= sizeof (psname))
+ exit(1);
+
retry:
if ((psfd = open(psname, O_RDONLY)) == -1)
continue;
@@ -544,7 +546,7 @@ closeit:
}
static void
-usage() /* print usage message and quit */
+usage(void) /* print usage message and quit */
{
static char usage1[] = "ps [ -aceglnrSuUvwx ] [ -t term ] [ num ]";
diff --git a/usr/src/cmd/script/script.c b/usr/src/cmd/script/script.c
index 313a35df8a..0e73a9fd9b 100644
--- a/usr/src/cmd/script/script.c
+++ b/usr/src/cmd/script/script.c
@@ -3,8 +3,8 @@
* Use is subject to license terms.
*/
-/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
/*
@@ -33,8 +33,8 @@
#include <sys/file.h>
#include <errno.h>
-int grantpt();
-int unlockpt();
+int grantpt();
+int unlockpt();
char *ptsname();
void doinput() __NORETURN;
void dooutput();
@@ -42,13 +42,13 @@ void doshell();
void fixtty();
void fail();
void done() __NORETURN;
-void getmaster();
-void getslave();
+void getmanager();
+void getsubsid();
char *shell;
FILE *fscript;
-int master; /* file descriptor for master pseudo-tty */
-int slave; /* file descriptor for slave pseudo-tty */
+int manager; /* file descriptor for manager pseudo-tty */
+int subsid; /* file descriptor for subsidiary pseudo-tty */
int child;
int subchild;
char *fname = "typescript";
@@ -59,7 +59,7 @@ struct termios b;
struct winsize size;
int lb;
int l;
-char *mptname = "/dev/ptmx"; /* master pseudo-tty device */
+char *mptname = "/dev/ptmx"; /* manager pseudo-tty device */
int aflg;
@@ -103,7 +103,7 @@ main(int argc, char *argv[])
}
setbuf(fscript, NULL);
chown(fname, ruidt, gidt);
- getmaster();
+ getmanager();
printf(gettext("Script started, file is %s\n"), fname);
fixtty();
@@ -146,7 +146,7 @@ doinput()
break;
}
}
- (void) write(master, ibuf, cc);
+ (void) write(manager, ibuf, cc);
}
done();
}
@@ -157,7 +157,7 @@ sigwinch()
struct winsize ws;
if (ioctl(0, TIOCGWINSZ, &ws) == 0)
- (void) ioctl(master, TIOCSWINSZ, &ws);
+ (void) ioctl(manager, TIOCSWINSZ, &ws);
}
#include <sys/wait.h>
@@ -190,7 +190,7 @@ dooutput()
strftime(tbuf, BUFSIZ, "%c", localtime(&tvec));
fprintf(fscript, gettext("Script started on %s\n"), tbuf);
for (;;) {
- cc = read(master, obuf, sizeof (obuf));
+ cc = read(manager, obuf, sizeof (obuf));
if (cc <= 0)
break;
(void) write(1, obuf, cc);
@@ -204,13 +204,13 @@ doshell()
{
setpgrp(); /* relinquish control terminal */
- getslave();
- (void) close(master);
+ getsubsid();
+ (void) close(manager);
(void) fclose(fscript);
- (void) dup2(slave, 0);
- (void) dup2(slave, 1);
- (void) dup2(slave, 2);
- (void) close(slave);
+ (void) dup2(subsid, 0);
+ (void) dup2(subsid, 1);
+ (void) dup2(subsid, 2);
+ (void) close(subsid);
execl(shell, shell, "-i", (char *)0);
perror(shell);
fail();
@@ -249,7 +249,7 @@ done()
strftime(tbuf, BUFSIZ, "%c", localtime(&tvec));
fprintf(fscript, gettext("\nscript done on %s\n"), tbuf);
(void) fclose(fscript);
- (void) close(master);
+ (void) close(manager);
} else {
(void) ioctl(0, TCSETSW, (char *)&b);
printf(gettext("Script done, file is %s\n"), fname);
@@ -258,11 +258,11 @@ done()
}
void
-getmaster()
+getmanager()
{
struct stat stb;
- if ((master = open(mptname, O_RDWR)) >= 0) { /* a pseudo-tty is free */
+ if ((manager = open(mptname, O_RDWR)) >= 0) { /* a pseudo-tty is free */
(void) ioctl(0, TCGETS, (char *)&b);
(void) ioctl(0, TIOCGWINSZ, (char *)&size);
return;
@@ -274,21 +274,21 @@ getmaster()
}
void
-getslave()
+getsubsid()
{
- char *slavename; /* name of slave pseudo-tty */
-
- grantpt(master); /* change permissions of slave */
- unlockpt(master); /* unlock slave */
- slavename = ptsname(master); /* get name of slave */
- slave = open(slavename, O_RDWR); /* open slave */
- if (slave < 0) { /* error on opening slave */
- perror(slavename);
+ char *subsidname; /* name of subsidiary pseudo-tty */
+
+ grantpt(manager); /* change permissions of subsidiary */
+ unlockpt(manager); /* unlock subsidiary */
+ subsidname = ptsname(manager); /* get name of subsidiary */
+ subsid = open(subsidname, O_RDWR); /* open subsidiary */
+ if (subsid < 0) { /* error opening subsidiary */
+ perror(subsidname);
fail();
}
- ioctl(slave, I_PUSH, "ptem"); /* push pt hw emulation module */
- ioctl(slave, I_PUSH, "ldterm"); /* push line discipline */
+ ioctl(subsid, I_PUSH, "ptem"); /* push pt hw emulation module */
+ ioctl(subsid, I_PUSH, "ldterm"); /* push line discipline */
- (void) ioctl(slave, TCSETSF, (char *)&b);
- (void) ioctl(slave, TIOCSWINSZ, (char *)&size);
+ (void) ioctl(subsid, TCSETSF, (char *)&b);
+ (void) ioctl(subsid, TIOCSWINSZ, (char *)&size);
}
diff --git a/usr/src/cmd/sgs/ar/common/ar.msg b/usr/src/cmd/sgs/ar/common/ar.msg
index 6682ca42af..2c165d0afa 100644
--- a/usr/src/cmd/sgs/ar/common/ar.msg
+++ b/usr/src/cmd/sgs/ar/common/ar.msg
@@ -21,7 +21,7 @@
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
-# Copyright 2021 Oxide Computer Company
+# Copyright 2022 Oxide Computer Company
#
@ _START_
@@ -33,7 +33,7 @@
@ MSG_USAGE "usage: ar -d[-SvV] archive file ...\n \
ar -m[-abiSvV] [posname] archive file ...\n \
ar -p[-vV][-sS] archive [file ...]\n \
- ar -q[-cuvSV] [file ...]\n \
+ ar -q[-csuvSV] [file ...]\n \
ar -r[-cuvSV] [-abi] [posname] [file ...]\n \
ar -s[-vV] archive\n \
ar -t[-vV][-sS] archive [file ...]\n \
@@ -56,6 +56,8 @@
included in archive or not\n"
@ MSG_INTERNAL_02 "ar: internal header generation error\n"
+@ MSG_BAD_CREATE "ar: failed to create %s: %s, is the path correct?\n"
+
@ MSG_SYS_OPEN "ar: cannot open %s: %s\n"
@ MSG_SYS_CLOSE "ar: cannot close %s: %s\n"
@ MSG_SYS_WRITE "ar: %s: cannot write: %s\n"
diff --git a/usr/src/cmd/sgs/ar/common/file.c b/usr/src/cmd/sgs/ar/common/file.c
index 77e91c5898..c729617132 100644
--- a/usr/src/cmd/sgs/ar/common/file.c
+++ b/usr/src/cmd/sgs/ar/common/file.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -1187,7 +1188,8 @@ writefile(Cmd_info *cmd_info)
ar_outfile.fd = open(ar_outfile.path, O_RDWR|O_CREAT|O_LARGEFILE, 0666);
if (ar_outfile.fd == -1) {
int err = errno;
- (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
+ (void) fprintf(stderr, new_archive ?
+ MSG_INTL(MSG_BAD_CREATE) : MSG_INTL(MSG_SYS_OPEN),
ar_outfile.path, strerror(err));
exit(1);
}
diff --git a/usr/src/cmd/sgs/ar/common/main.c b/usr/src/cmd/sgs/ar/common/main.c
index 3f918e15db..3b95560816 100644
--- a/usr/src/cmd/sgs/ar/common/main.c
+++ b/usr/src/cmd/sgs/ar/common/main.c
@@ -27,7 +27,7 @@
/*
* Copyright (c) 2018, Joyent, Inc.
- * Copyright 2021 Oxide Computer Company
+ * Copyright 2022 Oxide Computer Company
*/
#include "inc.h"
@@ -141,7 +141,7 @@ main(int argc, char **argv, char *envp[])
boolean_t req_r = (cmd_info->opt_flgs & r_FLAG) &&
(cmd_info->opt_flgs & (a_FLAG | b_FLAG));
boolean_t req_s = (cmd_info->opt_flgs & s_FLAG) &&
- (cmd_info->opt_flgs & r_FLAG) == 0;
+ (cmd_info->opt_flgs & (r_FLAG | q_FLAG)) == 0;
if (req_arg || req_r || req_s) {
(void) fprintf(stderr, MSG_INTL(MSG_NOT_FOUND_AR),
diff --git a/usr/src/cmd/sgs/lex/Makefile.com b/usr/src/cmd/sgs/lex/Makefile.com
index c8100b1e3f..1b40639314 100644
--- a/usr/src/cmd/sgs/lex/Makefile.com
+++ b/usr/src/cmd/sgs/lex/Makefile.com
@@ -55,9 +55,8 @@ SRCDIR = ../common
CSTD= $(CSTD_GNU99)
+# unused labels in yaccpar
CERRWARN += -_gcc=-Wno-unused-label
-CERRWARN += $(CNOWARN_UNINIT)
-CERRWARN += -_gcc=-Wno-parentheses
# Override default source file derivation rule (in Makefile.lib)
# from objects
diff --git a/usr/src/cmd/sgs/lex/common/sub1.c b/usr/src/cmd/sgs/lex/common/sub1.c
index f1d3fa601b..e63a55e34b 100644
--- a/usr/src/cmd/sgs/lex/common/sub1.c
+++ b/usr/src/cmd/sgs/lex/common/sub1.c
@@ -131,15 +131,16 @@ warning(char *s, ...)
{
va_list ap;
- if (!eof)
- if (!yyline)
+ if (!eof) {
+ if (!yyline) {
(void) fprintf(errorf, "Command line: ");
- else {
+ } else {
(void) fprintf(errorf,
!no_input ? "" : "\"%s\":", sargv[optind]);
(void) fprintf(errorf,
"line %d: ", yyline);
}
+ }
(void) fprintf(errorf, "Warning: ");
va_start(ap, s);
(void) vfprintf(errorf, s, ap);
@@ -171,8 +172,8 @@ index(int a, CHR *s)
int
alpha(int c)
{
- return ('a' <= c && c <= 'z' ||
- 'A' <= c && c <= 'Z');
+ return (('a' <= c && c <= 'z') ||
+ ('A' <= c && c <= 'Z'));
}
int
@@ -209,7 +210,7 @@ scopy(CHR *s, CHR *t)
{
CHR *i;
i = t;
- while (*i++ = *s++)
+ while ((*i++ = *s++) != 0)
;
}
@@ -494,7 +495,7 @@ cpycom(CHR *p)
(void) putc(*t++, fout);
}
(void) putc('\n', fout);
- while (c = gch()) {
+ while ((c = gch()) != 0) {
while (c == '*') {
(void) putc((char)c, fout);
if ((c = gch()) == '/') {
@@ -570,7 +571,7 @@ cpyact(void)
goto swt;
(void) putwc(c, fout);
savline = yyline;
- while (c = gch()) {
+ while ((c = gch()) != 0) {
while (c == '*') {
(void) putwc(c, fout);
if ((c = gch()) == '/') {
@@ -591,7 +592,7 @@ cpyact(void)
case '"': /* character string */
mth = c;
(void) putwc(c, fout);
- while (c = gch()) {
+ while ((c = gch()) != 0) {
if (c == '\\') {
(void) putwc(c, fout);
c = gch();
diff --git a/usr/src/cmd/sgs/lex/common/sub2.c b/usr/src/cmd/sgs/lex/common/sub2.c
index 84ff4e4699..399503d7d9 100644
--- a/usr/src/cmd/sgs/lex/common/sub2.c
+++ b/usr/src/cmd/sgs/lex/common/sub2.c
@@ -462,9 +462,9 @@ nextstate(int s, int c)
for (i = 0; i < num; i++) {
curpos = *pos++;
j = name[curpos];
- if ((!ISOPERATOR(j)) && j == c ||
- j == RSTR && c == right[curpos] ||
- j == RCCL && member(c, (CHR *) left[curpos])) {
+ if ((!ISOPERATOR(j) && j == c) ||
+ (j == RSTR && c == right[curpos]) ||
+ (j == RCCL && member(c, (CHR *) left[curpos]))) {
f = foll[curpos];
number = *f;
newpos = f+1;
diff --git a/usr/src/cmd/sgs/lex/common/sub3.c b/usr/src/cmd/sgs/lex/common/sub3.c
index 107881958d..4b9cea94ab 100644
--- a/usr/src/cmd/sgs/lex/common/sub3.c
+++ b/usr/src/cmd/sgs/lex/common/sub3.c
@@ -134,12 +134,13 @@ remch(wchar_t c)
* Make sure no EUC chars are used in reg. exp.
*/
if (!handleeuc) {
- if (!isascii(c))
+ if (!isascii(c)) {
if (iswprint(c))
warning(
"Non-ASCII character '%wc' in pattern; use -w or -e lex option.", c);
else warning(
"Non-ASCII character of value %#x in pattern; use -w or -e lex option.", c);
+ }
/* In any case, we don't need to construct ncgidtbl[]. */
return;
}
@@ -301,7 +302,7 @@ repbycgid(void)
symbol[j] = FALSE;
s = (CHR *) left[i];
- while (cc = *s++) {
+ while ((cc = *s++) != 0) {
if (cc == RANGE) {
int low, high, i;
/*
@@ -388,7 +389,7 @@ repbycgid(void)
static void
setsymbol(int i)
{
- if (i > sizeof (symbol))
+ if (i > (int)sizeof (symbol))
error("setsymbol: (SYSERR) %d out of range", i);
symbol[i] = TRUE;
}
diff --git a/usr/src/cmd/sgs/libld/common/libld.msg b/usr/src/cmd/sgs/libld/common/libld.msg
index 86d8d2e9f3..4184f8c1e3 100644
--- a/usr/src/cmd/sgs/libld/common/libld.msg
+++ b/usr/src/cmd/sgs/libld/common/libld.msg
@@ -88,7 +88,7 @@
\t\t\tspecify library for which this file is a filter\n"
@ MSG_ARG_DETAIL_CG "\t[-G], [-shared]\n\
\t\t\tcreate a shared object\n"
-@ MSG_ARG_DETAIL_H "\t[-h name], [--soname name]\n\
+@ MSG_ARG_DETAIL_H "\t[-h name], [-soname name]\n\
\t\t\tuse 'name' as internal shared object identifier\n"
@ MSG_ARG_DETAIL_I "\t[-i]\t\tignore LD_LIBRARY_PATH setting\n"
@ MSG_ARG_DETAIL_CI "\t[-I name]\tuse 'name' as path of interpreter\n"
@@ -976,7 +976,7 @@
-z type=reloc)"
@ MSG_MARG_RPATH "runpath option (-R, -rpath)"
@ MSG_MARG_SO "shared object option (-G, -shared, -z type=shared)"
-@ MSG_MARG_SONAME "soname option (-h, --soname)"
+@ MSG_MARG_SONAME "soname option (-h, -soname)"
@ MSG_MARG_STRIP "strip option (-s, --strip-all)"
@ MSG_MARG_TYPE_KMOD "-z type=kmod"
diff --git a/usr/src/cmd/sgs/tools/SUNWonld-README b/usr/src/cmd/sgs/tools/SUNWonld-README
index 5429da0a1e..3e9f4432fc 100644
--- a/usr/src/cmd/sgs/tools/SUNWonld-README
+++ b/usr/src/cmd/sgs/tools/SUNWonld-README
@@ -1625,7 +1625,7 @@ Bugid Risk Synopsis
--------------------------------------------------------------------------------
--------------
-Illumos
+illumos
--------------
Bugid Risk Synopsis
================================================================================
@@ -1686,3 +1686,4 @@ Bugid Risk Synopsis
14308 discard SHF_EXCLUDE sections when linking kernel modules
14319 ld shouldn't warn about SHF_EXCLUDE unknown sections
14401 elfdump should understand LLVM section types
+4795 /usr/bin/ld manpage and help should indicate '-soname' not '--soname'
diff --git a/usr/src/cmd/smbsrv/testoplock/tol_main.c b/usr/src/cmd/smbsrv/testoplock/tol_main.c
index 126f3a17f5..5382802b82 100644
--- a/usr/src/cmd/smbsrv/testoplock/tol_main.c
+++ b/usr/src/cmd/smbsrv/testoplock/tol_main.c
@@ -12,6 +12,7 @@
/*
* Copyright 2018 Nexenta Systems, Inc. All rights reserved.
* Copyright 2019 Joyent, Inc.
+ * Copyright 2022 RackTop Systems, Inc.
*/
/*
@@ -190,10 +191,18 @@ do_close(int fid)
printf(" close fid %d already closed\n");
return;
}
+
+ smb_llist_enter(&node->n_ofile_list, RW_READER);
+ mutex_enter(&node->n_oplock.ol_mutex);
+
smb_oplock_break_CLOSE(ofile->f_node, ofile);
smb_llist_remove(&node->n_ofile_list, ofile);
node->n_open_count--;
+
+ mutex_exit(&node->n_oplock.ol_mutex);
+ smb_llist_exit(&node->n_ofile_list);
+
ofile->f_refcnt--;
bzero(ofile->TargetOplockKey, SMB_LEASE_KEY_SZ);
@@ -331,6 +340,7 @@ do_brk_setinfo(int fid, char *arg2)
static void
do_move(int fid, char *arg2)
{
+ smb_node_t *node = &test_node;
smb_ofile_t *ofile = &ofile_array[fid];
smb_ofile_t *of2;
int fid2;
@@ -346,7 +356,12 @@ do_move(int fid, char *arg2)
}
of2 = &ofile_array[fid2];
+ mutex_enter(&node->n_oplock.ol_mutex);
+
smb_oplock_move(&test_node, ofile, of2);
+
+ mutex_exit(&node->n_oplock.ol_mutex);
+
printf(" move %d %d\n", fid, fid2);
}
@@ -384,6 +399,8 @@ main(int argc, char *argv[])
if (isatty(0))
prompt = "> ";
+ mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
+
smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
offsetof(smb_ofile_t, f_node_lnd));
diff --git a/usr/src/cmd/svc/milestone/network-routing-setup.xml b/usr/src/cmd/svc/milestone/network-routing-setup.xml
index da16da8e4d..bc7560fa98 100644
--- a/usr/src/cmd/svc/milestone/network-routing-setup.xml
+++ b/usr/src/cmd/svc/milestone/network-routing-setup.xml
@@ -100,7 +100,7 @@
<instance name='default' enabled='true' >
- <!-- Properties in this group are used by routeadm (1M) -->
+ <!-- Properties in this group are used by routeadm(8) -->
<property_group name='routeadm' type='framework'>
<stability value='Evolving' />
<!-- set if routeadm -e/d ipv4-routing is explicitly invoked -->
diff --git a/usr/src/cmd/syseventd/modules/zfs_mod/zfs_mod.c b/usr/src/cmd/syseventd/modules/zfs_mod/zfs_mod.c
index 4697128c90..82c296a669 100644
--- a/usr/src/cmd/syseventd/modules/zfs_mod/zfs_mod.c
+++ b/usr/src/cmd/syseventd/modules/zfs_mod/zfs_mod.c
@@ -22,6 +22,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright 2016 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
*/
/*
@@ -32,15 +33,15 @@
*
* When a device is added to the system:
*
- * 1. Search for any vdevs whose devid matches that of the newly added
+ * 1. Search for any vdevs whose devid matches that of the newly added
* device.
*
- * 2. If no vdevs are found, then search for any vdevs whose devfs path
+ * 2. If no vdevs are found, then search for any vdevs whose devfs path
* matches that of the new device.
*
* 3. If no vdevs match by either method, then ignore the event.
*
- * 4. Attempt to online the device with a flag to indicate that it should
+ * 4. Attempt to online the device with a flag to indicate that it should
* be unspared when resilvering completes. If this succeeds, then the
* same device was inserted and we should continue normally.
*
@@ -319,11 +320,11 @@ zfs_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *data)
* string. However, we allow substring matches in the following
* cases:
*
- * <path>: This is a devpath, and the target is one
- * of its children.
+ * <path>: This is a devpath, and the target is one
+ * of its children.
*
- * <path/> This is a devid for a whole disk, and
- * the target is one of its children.
+ * <path/> This is a devid for a whole disk, and
+ * the target is one of its children.
*/
if (path[len] != '\0' && path[len] != ':' &&
path[len - 1] != '/')
@@ -555,7 +556,7 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
vdev_state_t newstate;
nvlist_t *tgt;
- syseventd_print(9, "zfsdle_vdev_online: searching for %s in pool %s\n",
+ syseventd_print(9, "%s: searching for %s in pool %s\n", __func__,
devname, zpool_get_name(zhp));
if ((tgt = zpool_find_vdev_by_physpath(zhp, devname,
@@ -568,6 +569,11 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
&wholedisk) == 0);
+ syseventd_print(9, "%s: "
+ "found %s in pool %s (wholedisk: %s)\n", __func__,
+ path, zpool_get_name(zhp),
+ wholedisk != 0 ? "true" : "false");
+
(void) strlcpy(fullpath, path, sizeof (fullpath));
if (wholedisk) {
fullpath[strlen(fullpath) - 2] = '\0';
@@ -581,12 +587,13 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
}
if (zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) {
- syseventd_print(9, "zfsdle_vdev_online: setting device"
- " device %s to ONLINE state in pool %s.\n",
- fullpath, zpool_get_name(zhp));
- if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL)
+ syseventd_print(9, "%s: "
+ "setting device %s to ONLINE state in pool %s.\n",
+ __func__, fullpath, zpool_get_name(zhp));
+ if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL) {
(void) zpool_vdev_online(zhp, fullpath, 0,
&newstate);
+ }
}
zpool_close(zhp);
return (1);
diff --git a/usr/src/cmd/truss/codes.c b/usr/src/cmd/truss/codes.c
index fd6e02bad6..21460008d4 100644
--- a/usr/src/cmd/truss/codes.c
+++ b/usr/src/cmd/truss/codes.c
@@ -1502,8 +1502,8 @@ const struct ioc {
{ (uint_t)IPTUN_GET_6TO4RELAY, "IPTUN_GET_6TO4RELAY", NULL},
/* zcons ioctls */
- { (uint_t)ZC_HOLDSLAVE, "ZC_HOLDSLAVE", NULL },
- { (uint_t)ZC_RELEASESLAVE, "ZC_RELEASESLAVE", NULL },
+ { (uint_t)ZC_HOLDSUBSID, "ZC_HOLDSUBSID", NULL },
+ { (uint_t)ZC_RELEASESUBSID, "ZC_RELEASESUBSID", NULL },
/* hid ioctls - ('h' << 8) - hid.h */
{ (uint_t)HIDIOCKMGDIRECT, "HIDIOCKMGDIRECT", NULL },
diff --git a/usr/src/cmd/ttymon/parms.h b/usr/src/cmd/ttymon/parms.h
index b293eb45a2..9299147f7c 100644
--- a/usr/src/cmd/ttymon/parms.h
+++ b/usr/src/cmd/ttymon/parms.h
@@ -19,13 +19,12 @@
*
* CDDL HEADER END
*/
-/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
-
-
-#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+#ifndef _PARMS_H
+#define _PARMS_H
/* If running SVR3, #define both ATTSVR3 and ATTSV */
#define ATTSVR3 /* System V Release 3 */
@@ -155,8 +154,8 @@
#define DEFAULT_BAUDRATE "9600" /* */
/*define permission modes for the device */
-#define M_DEVICEMODE (mode_t) 0600 /* MASTER device mode */
-#define S_DEVICEMODE (mode_t) 0600 /* SLAVE device mode */
+#define M_DEVICEMODE (mode_t) 0600 /* manager device mode */
+#define S_DEVICEMODE (mode_t) 0600 /* subsidiary device mode */
#define R_DEVICEMODE (mode_t) 0600 /* default mode to restore */
/* NO_MODEM_CTRL - define this if you have very old hardware
@@ -232,7 +231,7 @@
/* define USRSPOOLLOCKS if you like your lock files in /var/spool/locks
* be sure other programs such as 'cu' and 'ct' know about this
*
- * WARNING: if you do not define USRSPOOLLOCKS, then $LOCK in
+ * WARNING: if you do not define USRSPOOLLOCKS, then $LOCK in
* uudemon.cleanup must be changed.
*/
#define USRSPOOLLOCKS /* define to use /var/spool/locks for LCK files */
@@ -241,3 +240,5 @@
* this entails sleeping between reads at low baud rates.
*/
#define PKSPEEDUP /* */
+
+#endif /* !_PARMS_H */
diff --git a/usr/src/cmd/varpd/Makefile b/usr/src/cmd/varpd/Makefile
new file mode 100644
index 0000000000..4d9e29cd26
--- /dev/null
+++ b/usr/src/cmd/varpd/Makefile
@@ -0,0 +1,64 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2018 Joyent, Inc.
+#
+
+PROG= varpd
+OBJS = varpd.o
+SRCS = $(OBJS:%.o=../%.c)
+MANIFEST = varpd.xml
+ROOTLIBVARPD = $(ROOTLIB)/varpd
+ROOTLIBVARPDPROG= $(PROG:%=$(ROOTLIBVARPD)/%)
+
+
+include ../Makefile.cmd
+include ../Makefile.ctf
+
+ROOTMANIFESTDIR= $(ROOTSVCNETWORK)
+
+CLEANFILES += $(OBJS)
+CPPFLAGS += -D_REENTRANT
+CFLAGS += $(CCVERBOSE)
+LDLIBS += -lvarpd -lumem -lscf
+$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
+
+CSTD= $(CSTD_GNU99)
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+clean:
+ -$(RM) $(CLEANFILES)
+
+%.o: ../%.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+check: $(CHKMANIFEST)
+
+install: $(PROG) $(ROOTLIBVARPDPROG) $(ROOTMANIFEST)
+
+$(ROOTLIBVARPD):
+ $(INS.dir)
+
+$(ROOTLIBVARPD)/%: % $(ROOTLIBVARPD)
+ $(INS.file)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/varpd/varpd.c b/usr/src/cmd/varpd/varpd.c
new file mode 100644
index 0000000000..3eb969c371
--- /dev/null
+++ b/usr/src/cmd/varpd/varpd.c
@@ -0,0 +1,526 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2021 Joyent, Inc.
+ */
+
+/*
+ * virtual arp daemon -- varpd
+ *
+ * The virtual arp daemon is the user land counterpart to the overlay driver. To
+ * truly understand its purpose and how it fits into things, you should read the
+ * overlay big theory statement in uts/common/io/overlay/overlay.c.
+ *
+ * varpd's purpose it to provide a means for looking up the destination on the
+ * underlay network for a host on an overlay network and to also be a door
+ * server such that dladm(8) via libdladm can configure and get useful status
+ * information. The heavy lifting is all done by libvarpd and the various lookup
+ * plugins.
+ *
+ * When varpd first starts up, we take care of chdiring into /var/run/varpd,
+ * which is also where we create /var/run/varpd/varpd.door, our door server.
+ * After that we daemonize and only after we daemonize do we go ahead and load
+ * plugins. The reason that we don't load plugins before daemonizing is that
+ * they could very well be creating threads and thus lose them all. In general,
+ * we want to make things easier on our children and not require them to be
+ * fork safe.
+ *
+ * Once it's spun up, the main varpd thread sits in sigsuspend and really just
+ * hangs out waiting for something, libvarpd handles everything else.
+ */
+
+#include <libvarpd.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <libgen.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <paths.h>
+#include <limits.h>
+#include <sys/corectl.h>
+#include <signal.h>
+#include <strings.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <thread.h>
+#include <priv.h>
+#include <libscf.h>
+
+#define VARPD_EXIT_REQUESTED SMF_EXIT_OK
+#define VARPD_EXIT_FATAL SMF_EXIT_ERR_FATAL
+#define VARPD_EXIT_USAGE SMF_EXIT_ERR_CONFIG
+
+#define VARPD_RUNDIR "/var/run/varpd"
+#define VARPD_DEFAULT_DOOR "/var/run/varpd/varpd.door"
+
+#define VARPD_PG "varpd"
+#define VARPD_PROP_INC "include_path"
+
+static varpd_handle_t *varpd_handle;
+static const char *varpd_pname;
+static volatile boolean_t varpd_exit = B_FALSE;
+
+/*
+ * Debug builds are automatically wired up for umem debugging.
+ */
+#ifdef DEBUG
+const char *
+_umem_debug_init()
+{
+ return ("default,verbose");
+}
+
+const char *
+_umem_logging_init(void)
+{
+ return ("fail,contents");
+}
+#endif /* DEBUG */
+
+static void
+varpd_vwarn(FILE *out, const char *fmt, va_list ap)
+{
+ int error = errno;
+
+ (void) fprintf(out, "%s: ", varpd_pname);
+ (void) vfprintf(out, fmt, ap);
+
+ if (fmt[strlen(fmt) - 1] != '\n')
+ (void) fprintf(out, ": %s\n", strerror(error));
+}
+
+static void
+varpd_fatal(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ varpd_vwarn(stderr, fmt, ap);
+ va_end(ap);
+
+ exit(VARPD_EXIT_FATAL);
+}
+
+static void
+varpd_dfatal(int dfd, const char *fmt, ...)
+{
+ int status = VARPD_EXIT_FATAL;
+ va_list ap;
+
+ va_start(ap, fmt);
+ varpd_vwarn(stdout, fmt, ap);
+ va_end(ap);
+
+ /* Take a single shot at this */
+ (void) write(dfd, &status, sizeof (status));
+ exit(status);
+}
+
+/* ARGSUSED */
+static int
+varpd_plugin_walk_cb(varpd_handle_t *vph, const char *name, void *unused)
+{
+ (void) printf("loaded %s!\n", name);
+ return (0);
+}
+
+static int
+varpd_dir_setup(void)
+{
+ int fd;
+
+ if (mkdir(VARPD_RUNDIR, 0700) != 0) {
+ if (errno != EEXIST)
+ varpd_fatal("failed to create %s: %s", VARPD_RUNDIR,
+ strerror(errno));
+ }
+
+ fd = open(VARPD_RUNDIR, O_RDONLY);
+ if (fd < 0)
+ varpd_fatal("failed to open %s: %s", VARPD_RUNDIR,
+ strerror(errno));
+
+ if (fchown(fd, UID_NETADM, GID_NETADM) != 0)
+ varpd_fatal("failed to chown %s: %s\n", VARPD_RUNDIR,
+ strerror(errno));
+
+ return (fd);
+}
+
+/*
+ * Because varpd is generally run under SMF, we opt to keep its stdout and
+ * stderr to be whatever our parent set them up to be.
+ */
+static void
+varpd_fd_setup(void)
+{
+ int dupfd;
+
+ closefrom(STDERR_FILENO + 1);
+ dupfd = open(_PATH_DEVNULL, O_RDONLY);
+ if (dupfd < 0)
+ varpd_fatal("failed to open %s: %s", _PATH_DEVNULL,
+ strerror(errno));
+ if (dup2(dupfd, STDIN_FILENO) == -1)
+ varpd_fatal("failed to dup out stdin: %s", strerror(errno));
+}
+
+/*
+ * We borrow fmd's daemonization style. Basically, the parent waits for the
+ * child to successfully set up a door and recover all of the old configurations
+ * before we say that we're good to go.
+ */
+static int
+varpd_daemonize(int dirfd)
+{
+ char path[PATH_MAX];
+ struct rlimit rlim;
+ sigset_t set, oset;
+ int estatus, pfds[2];
+ pid_t child;
+ priv_set_t *pset;
+
+ /*
+ * Set a per-process core path to be inside of /var/run/varpd. Make sure
+ * that we aren't limited in our dump size.
+ */
+ (void) snprintf(path, sizeof (path),
+ "/var/run/varpd/core.%s.%%p", varpd_pname);
+ (void) core_set_process_path(path, strlen(path) + 1, getpid());
+
+ rlim.rlim_cur = RLIM_INFINITY;
+ rlim.rlim_max = RLIM_INFINITY;
+ (void) setrlimit(RLIMIT_CORE, &rlim);
+
+ /*
+ * Claim as many file descriptors as the system will let us.
+ */
+ if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
+ rlim.rlim_cur = rlim.rlim_max;
+ (void) setrlimit(RLIMIT_NOFILE, &rlim);
+ }
+
+ /*
+ * chdir /var/run/varpd
+ */
+ if (fchdir(dirfd) != 0)
+ varpd_fatal("failed to chdir to %s", VARPD_RUNDIR);
+
+
+ /*
+ * At this point block all signals going in so we don't have the parent
+ * mistakingly exit when the child is running, but never block SIGABRT.
+ */
+ if (sigfillset(&set) != 0)
+ abort();
+ if (sigdelset(&set, SIGABRT) != 0)
+ abort();
+ if (sigprocmask(SIG_BLOCK, &set, &oset) != 0)
+ abort();
+
+ /*
+ * Do the fork+setsid dance.
+ */
+ if (pipe(pfds) != 0)
+ varpd_fatal("failed to create pipe for daemonizing");
+
+ if ((child = fork()) == -1)
+ varpd_fatal("failed to fork for daemonizing");
+
+ if (child != 0) {
+ /* We'll be exiting shortly, so allow for silent failure */
+ (void) close(pfds[1]);
+ if (read(pfds[0], &estatus, sizeof (estatus)) ==
+ sizeof (estatus))
+ _exit(estatus);
+
+ if (waitpid(child, &estatus, 0) == child && WIFEXITED(estatus))
+ _exit(WEXITSTATUS(estatus));
+
+ _exit(VARPD_EXIT_FATAL);
+ }
+
+ /*
+ * Drop privileges here.
+ *
+ * We should make sure we keep around PRIV_NET_PRIVADDR and
+ * PRIV_SYS_DLCONFIG, but drop everything else; however, keep basic
+ * privs and have our child drop them.
+ *
+ * We should also run as netadm:netadm and drop all of our groups.
+ */
+ if (setgroups(0, NULL) != 0)
+ abort();
+ if (setgid(GID_NETADM) == -1 || seteuid(UID_NETADM) == -1)
+ abort();
+ if ((pset = priv_allocset()) == NULL)
+ abort();
+ priv_basicset(pset);
+ if (priv_delset(pset, PRIV_PROC_EXEC) == -1 ||
+ priv_delset(pset, PRIV_PROC_INFO) == -1 ||
+ priv_delset(pset, PRIV_PROC_FORK) == -1 ||
+ priv_delset(pset, PRIV_PROC_SESSION) == -1 ||
+ priv_delset(pset, PRIV_FILE_LINK_ANY) == -1 ||
+ priv_addset(pset, PRIV_SYS_DL_CONFIG) == -1 ||
+ priv_addset(pset, PRIV_NET_PRIVADDR) == -1) {
+ abort();
+ }
+ /*
+ * Remove privs from the permitted set. That will cause them to be
+ * removed from the effective set. We want to make sure that in the case
+ * of a vulnerability, something can't get back in here and wreak more
+ * havoc. But if we want non-basic privs in the effective set, we have
+ * to request them explicitly.
+ */
+ if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) == -1)
+ abort();
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pset) == -1)
+ abort();
+
+ priv_freeset(pset);
+
+ if (close(pfds[0]) != 0)
+ abort();
+ if (setsid() == -1)
+ abort();
+ if (sigprocmask(SIG_SETMASK, &oset, NULL) != 0)
+ abort();
+ (void) umask(0022);
+
+ return (pfds[1]);
+}
+
+static int
+varpd_setup_lookup_threads(void)
+{
+ int ret;
+ long i, ncpus = sysconf(_SC_NPROCESSORS_ONLN) * 2 + 1;
+
+ if (ncpus <= 0)
+ abort();
+ for (i = 0; i < ncpus; i++) {
+ thread_t thr;
+
+ ret = thr_create(NULL, 0, libvarpd_overlay_lookup_run,
+ varpd_handle, THR_DETACHED | THR_DAEMON, &thr);
+ if (ret != 0)
+ return (ret);
+ }
+
+ return (0);
+}
+
+static void
+varpd_cleanup(void)
+{
+ varpd_exit = B_TRUE;
+}
+
+/*
+ * Load default information from SMF and apply any of if necessary. We recognize
+ * the following properties:
+ *
+ * varpd/include_path Treat these as a series of -i options.
+ *
+ * If we're not under SMF, just move on.
+ */
+static void
+varpd_load_smf(int dfd)
+{
+ char *fmri, *inc;
+ scf_simple_prop_t *prop;
+
+ if ((fmri = getenv("SMF_FMRI")) == NULL)
+ return;
+
+ if ((prop = scf_simple_prop_get(NULL, fmri, VARPD_PG,
+ VARPD_PROP_INC)) == NULL)
+ return;
+
+ while ((inc = scf_simple_prop_next_astring(prop)) != NULL) {
+ int err = libvarpd_plugin_load(varpd_handle, inc);
+ if (err != 0) {
+ varpd_dfatal(dfd, "failed to load from %s: %s\n",
+ inc, strerror(err));
+ }
+ }
+
+ scf_simple_prop_free(prop);
+}
+
+/*
+ * There are a bunch of things we need to do to be a proper daemon here.
+ *
+ * o Ensure that /var/run/varpd exists or create it
+ * o make stdin /dev/null (stdout?)
+ * o Ensure any other fds that we somehow inherited are closed, eg.
+ * closefrom()
+ * o Properly daemonize
+ * o Mask all signals except sigabrt before creating our first door -- all
+ * other doors will inherit from that.
+ * o Have the main thread sigsuspend looking for most things that are
+ * actionable...
+ */
+int
+main(int argc, char *argv[])
+{
+ int err, c, dirfd, dfd, i;
+ const char *doorpath = VARPD_DEFAULT_DOOR;
+ sigset_t set;
+ struct sigaction act;
+ int nincpath = 0, nextincpath = 0;
+ char **incpath = NULL;
+
+ varpd_pname = basename(argv[0]);
+
+ /*
+ * We want to clean up our file descriptors before we do anything else
+ * as we can't assume that libvarpd won't open file descriptors, etc.
+ */
+ varpd_fd_setup();
+
+ if ((err = libvarpd_create(&varpd_handle)) != 0) {
+ varpd_fatal("failed to open a libvarpd handle");
+ return (1);
+ }
+
+ while ((c = getopt(argc, argv, ":i:d:")) != -1) {
+ switch (c) {
+ case 'i':
+ if (nextincpath == nincpath) {
+ if (nincpath == 0)
+ nincpath = 16;
+ else
+ nincpath *= 2;
+ incpath = realloc(incpath, sizeof (char *) *
+ nincpath);
+ if (incpath == NULL) {
+ (void) fprintf(stderr, "failed to "
+ "allocate memory for the %dth "
+ "-I option: %s\n", nextincpath + 1,
+ strerror(errno));
+ }
+
+ }
+ incpath[nextincpath] = optarg;
+ nextincpath++;
+ break;
+ case 'd':
+ doorpath = optarg;
+ break;
+ default:
+ (void) fprintf(stderr, "unknown option: %c\n", c);
+ return (1);
+ }
+ }
+
+ dirfd = varpd_dir_setup();
+
+ (void) libvarpd_plugin_walk(varpd_handle, varpd_plugin_walk_cb, NULL);
+
+ dfd = varpd_daemonize(dirfd);
+
+ /*
+ * Now that we're in the child, go ahead and load all of our plug-ins.
+ * We do this, in part, because these plug-ins may need threads of their
+ * own and fork won't preserve those and we'd rather the plug-ins don't
+ * have to learn about fork-handlers.
+ */
+ for (i = 0; i < nextincpath; i++) {
+ err = libvarpd_plugin_load(varpd_handle, incpath[i]);
+ if (err != 0) {
+ varpd_dfatal(dfd, "failed to load from %s: %s\n",
+ incpath[i], strerror(err));
+ }
+ }
+
+ varpd_load_smf(dfd);
+
+ if ((err = libvarpd_persist_enable(varpd_handle, VARPD_RUNDIR)) != 0)
+ varpd_dfatal(dfd, "failed to enable varpd persistence: %s\n",
+ strerror(err));
+
+ if ((err = libvarpd_persist_restore(varpd_handle)) != 0)
+ varpd_dfatal(dfd, "failed to enable varpd persistence: %s\n",
+ strerror(err));
+
+ /*
+ * The ur-door thread will inherit from this signal mask. So set it to
+ * what we want before doing anything else. In addition, so will our
+ * threads that handle varpd lookups.
+ */
+ if (sigfillset(&set) != 0)
+ varpd_dfatal(dfd, "failed to fill a signal set...");
+
+ if (sigdelset(&set, SIGABRT) != 0)
+ varpd_dfatal(dfd, "failed to unmask SIGABRT");
+
+ if (sigprocmask(SIG_BLOCK, &set, NULL) != 0)
+ varpd_dfatal(dfd, "failed to set our door signal mask");
+
+ if ((err = varpd_setup_lookup_threads()) != 0)
+ varpd_dfatal(dfd, "failed to create lookup threads: %s\n",
+ strerror(err));
+
+ if ((err = libvarpd_door_server_create(varpd_handle, doorpath)) != 0)
+ varpd_dfatal(dfd, "failed to create door server at %s: %s\n",
+ doorpath, strerror(err));
+
+ /*
+ * At this point, finish up signal initialization and finally go ahead,
+ * notify the parent that we're okay, and enter the sigsuspend loop.
+ */
+ bzero(&act, sizeof (struct sigaction));
+ act.sa_handler = varpd_cleanup;
+ if (sigfillset(&act.sa_mask) != 0)
+ varpd_dfatal(dfd, "failed to fill sigaction mask");
+ act.sa_flags = 0;
+ if (sigaction(SIGHUP, &act, NULL) != 0)
+ varpd_dfatal(dfd, "failed to register HUP handler");
+ if (sigdelset(&set, SIGHUP) != 0)
+ varpd_dfatal(dfd, "failed to remove HUP from mask");
+ if (sigaction(SIGQUIT, &act, NULL) != 0)
+ varpd_dfatal(dfd, "failed to register QUIT handler");
+ if (sigdelset(&set, SIGQUIT) != 0)
+ varpd_dfatal(dfd, "failed to remove QUIT from mask");
+ if (sigaction(SIGINT, &act, NULL) != 0)
+ varpd_dfatal(dfd, "failed to register INT handler");
+ if (sigdelset(&set, SIGINT) != 0)
+ varpd_dfatal(dfd, "failed to remove INT from mask");
+ if (sigaction(SIGTERM, &act, NULL) != 0)
+ varpd_dfatal(dfd, "failed to register TERM handler");
+ if (sigdelset(&set, SIGTERM) != 0)
+ varpd_dfatal(dfd, "failed to remove TERM from mask");
+
+ err = 0;
+ (void) write(dfd, &err, sizeof (err));
+ (void) close(dfd);
+
+ for (;;) {
+ if (sigsuspend(&set) == -1)
+ if (errno == EFAULT)
+ abort();
+ if (varpd_exit == B_TRUE)
+ break;
+ }
+
+ libvarpd_door_server_destroy(varpd_handle);
+ libvarpd_destroy(varpd_handle);
+
+ return (VARPD_EXIT_REQUESTED);
+}
diff --git a/usr/src/cmd/varpd/varpd.xml b/usr/src/cmd/varpd/varpd.xml
new file mode 100644
index 0000000000..df7015a3d6
--- /dev/null
+++ b/usr/src/cmd/varpd/varpd.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+This file and its contents are supplied under the terms of the
+Common Development and Distribution License ("CDDL"), version 1.0.
+You may only use this file in accordance with the terms of version
+1.0 of the CDDL.
+
+A full copy of the text of the CDDL should have accompanied this
+source. A copy of the CDDL is also available via the Internet at
+http://www.illumos.org/license/CDDL.
+
+Copyright 2018, Joyent, Inc.
+-->
+
+<service_bundle type="manifest" name="illumos:varpd" >
+
+ <service name="network/varpd" type="service" version="1" >
+
+ <create_default_instance enabled="true" />
+
+ <single_instance/>
+
+ <dependency name="varpd-network-physical"
+ grouping="require_all"
+ restart_on="none"
+ type="service">
+ <service_fmri value="svc:/network/physical:default" />
+ </dependency>
+
+ <dependency name="varpd-device-local"
+ grouping="require_all"
+ restart_on="none"
+ type="service">
+ <service_fmri value="svc:/system/device/local:default" />
+ </dependency>
+
+ <exec_method
+ type="method"
+ name="start"
+ exec="/usr/lib/varpd/varpd"
+ timeout_seconds="60" />
+
+ <exec_method
+ type="method"
+ name="stop"
+ exec=":kill"
+ timeout_seconds="10" />
+
+ <property_group name='varpd' type='application'>
+ <property name='include_path' type='astring'>
+ <astring_list>
+ <value_node value='/usr/lib/varpd'/>
+ </astring_list>
+ </property>
+ </property_group>
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang="C">virtual ARP daemon
+ </loctext>
+ </common_name>
+ </template>
+ </service>
+</service_bundle>
diff --git a/usr/src/cmd/vscan/vscand/vs_main.c b/usr/src/cmd/vscan/vscand/vs_main.c
index bcc4a055ae..5e13bf5870 100644
--- a/usr/src/cmd/vscan/vscand/vs_main.c
+++ b/usr/src/cmd/vscan/vscand/vs_main.c
@@ -139,7 +139,7 @@ vscand_sig_handler(int sig)
/*
* main
*
- * main must return SMF return code (see smf_method (5)) if vscand
+ * main must return SMF return code (see smf_method(7)) if vscand
* is invoked directly by smf (see manifest: vscan.xml)
* Exit codes: SMF_EXIT_ERR_CONFIG - error
* SMF_EXIT_ERR_FATAL - fatal error
diff --git a/usr/src/cmd/zoneadmd/zcons.c b/usr/src/cmd/zoneadmd/zcons.c
index 49a935c638..130b97d984 100644
--- a/usr/src/cmd/zoneadmd/zcons.c
+++ b/usr/src/cmd/zoneadmd/zcons.c
@@ -57,7 +57,7 @@
* | +-[Anchor]--+
* | | ptem |
* V +-----------+
- * +---master---+---slave---+
+ * +---manager--+-subsidiary+
* | |
* | zcons driver |
* | zonename="myzone" |
@@ -71,7 +71,7 @@
* to online new instances of zcons as needed. Care is taken to
* prune and manage these appropriately; see init_console_dev() and
* destroy_console_dev(). The end result is the creation of the
- * zcons(4D) instance and an open file descriptor to the master side.
+ * zcons(4D) instance and an open file descriptor to the manager side.
* zcons instances are associated with zones via their zonename device
* property. This the console instance to persist across reboots,
* and while the zone is halted.
@@ -79,7 +79,7 @@
* - Acting as a server for 'zlogin -C' instances. When zlogin -C is
* run, zlogin connects to zoneadmd via unix domain socket. zoneadmd
* functions as a two-way proxy for console I/O, relaying user input
- * to the master side of the console, and relaying output from the
+ * to the manager side of the console, and relaying output from the
* zone to the user.
*/
@@ -265,34 +265,35 @@ destroy_console_devs(zlog_t *zlogp)
char conspath[MAXPATHLEN];
di_node_t root;
struct cb_data cb;
- int masterfd;
- int slavefd;
+ int managerfd;
+ int subfd;
/*
- * Signal the master side to release its handle on the slave side by
- * issuing a ZC_RELEASESLAVE ioctl.
+ * Signal the manager side to release its handle on the subsidiary side
+ * by issuing a ZC_RELEASESUBSID ioctl.
*/
(void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
- zone_name, ZCONS_MASTER_NAME);
- if ((masterfd = open(conspath, O_RDWR | O_NOCTTY)) != -1) {
+ zone_name, ZCONS_MANAGER_NAME);
+ if ((managerfd = open(conspath, O_RDWR | O_NOCTTY)) != -1) {
(void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
- zone_name, ZCONS_SLAVE_NAME);
- if ((slavefd = open(conspath, O_RDWR | O_NOCTTY)) != -1) {
- if (ioctl(masterfd, ZC_RELEASESLAVE,
- (caddr_t)(intptr_t)slavefd) != 0)
+ zone_name, ZCONS_SUBSIDIARY_NAME);
+ if ((subfd = open(conspath, O_RDWR | O_NOCTTY)) != -1) {
+ if (ioctl(managerfd, ZC_RELEASESUBSID,
+ (caddr_t)(intptr_t)subfd) != 0)
zerror(zlogp, B_TRUE, "WARNING: error while "
- "releasing slave handle of zone console for"
- " %s", zone_name);
- (void) close(slavefd);
+ "releasing subsidiary handle of zone "
+ "console for %s", zone_name);
+ (void) close(subfd);
} else {
- zerror(zlogp, B_TRUE, "WARNING: could not open slave "
- "side of zone console for %s to release slave "
- "handle", zone_name);
+ zerror(zlogp, B_TRUE, "WARNING: could not open "
+ "subsidiary side of zone console for %s to "
+ "release subsidiary handle", zone_name);
}
- (void) close(masterfd);
+ (void) close(managerfd);
} else {
- zerror(zlogp, B_TRUE, "WARNING: could not open master side of "
- "zone console for %s to release slave handle", zone_name);
+ zerror(zlogp, B_TRUE, "WARNING: could not open manager side of "
+ "zone console for %s to release subsidiary handle",
+ zone_name);
}
bzero(&cb, sizeof (cb));
@@ -323,8 +324,8 @@ destroy_console_devs(zlog_t *zlogp)
* sanity checking, and are careful to reuse a console if one exists.
*
* Once the device is in the device tree, we kick devfsadm via di_init_devs()
- * to ensure that the appropriate symlinks (to the master and slave console
- * devices) are placed in /dev in the global zone.
+ * to ensure that the appropriate symlinks (to the manager and subsidiary
+ * console devices) are placed in /dev in the global zone.
*/
static int
init_console_dev(zlog_t *zlogp)
@@ -336,8 +337,8 @@ init_console_dev(zlog_t *zlogp)
di_devlink_handle_t dl = NULL;
int rv = -1;
int ndevs;
- int masterfd;
- int slavefd;
+ int managerfd;
+ int subfd;
int i;
/*
@@ -405,23 +406,26 @@ devlinks:
}
/*
- * Open the master side of the console and issue the ZC_HOLDSLAVE ioctl,
- * which will cause the master to retain a reference to the slave.
- * This prevents ttymon from blowing through the slave's STREAMS anchor.
+ * Open the manager side of the console and issue the ZC_HOLDSUBSID
+ * ioctl, which will cause the manager to retain a reference to the
+ * subsidiary. This prevents ttymon from blowing through the
+ * subsidiary's STREAMS anchor.
*/
(void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
- zone_name, ZCONS_MASTER_NAME);
- if ((masterfd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
- zerror(zlogp, B_TRUE, "ERROR: could not open master side of "
- "zone console for %s to acquire slave handle", zone_name);
+ zone_name, ZCONS_MANAGER_NAME);
+ if ((managerfd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
+ zerror(zlogp, B_TRUE, "ERROR: could not open manager side of "
+ "zone console for %s to acquire subsidiary handle",
+ zone_name);
goto error;
}
(void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
- zone_name, ZCONS_SLAVE_NAME);
- if ((slavefd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
- zerror(zlogp, B_TRUE, "ERROR: could not open slave side of zone"
- " console for %s to acquire slave handle", zone_name);
- (void) close(masterfd);
+ zone_name, ZCONS_SUBSIDIARY_NAME);
+ if ((subfd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
+ zerror(zlogp, B_TRUE, "ERROR: could not open subsidiary side "
+ "of zone console for %s to acquire subsidiary handle",
+ zone_name);
+ (void) close(managerfd);
goto error;
}
/*
@@ -430,7 +434,7 @@ devlinks:
* 1 sec. and retry a few times before we fail to boot the zone.
*/
for (i = 0; i < 5; i++) {
- if (ioctl(masterfd, ZC_HOLDSLAVE, (caddr_t)(intptr_t)slavefd)
+ if (ioctl(managerfd, ZC_HOLDSUBSID, (caddr_t)(intptr_t)subfd)
== 0) {
rv = 0;
break;
@@ -440,11 +444,11 @@ devlinks:
(void) sleep(1);
}
if (rv != 0)
- zerror(zlogp, B_TRUE, "ERROR: error while acquiring slave "
- "handle of zone console for %s", zone_name);
+ zerror(zlogp, B_TRUE, "ERROR: error while acquiring "
+ "subsidiary handle of zone console for %s", zone_name);
- (void) close(slavefd);
- (void) close(masterfd);
+ (void) close(subfd);
+ (void) close(managerfd);
error:
if (ddef_hdl)
@@ -700,7 +704,7 @@ test_client(int clifd)
/*
* This routine drives the console I/O loop. It polls for input from the
- * master side of the console (output to the console), and from the client
+ * manager side of the console (output to the console), and from the client
* (input from the console user). Additionally, it polls on the server fd,
* and disconnects any clients that might try to hook up with the zone while
* the console is in use.
@@ -904,17 +908,17 @@ init_console(zlog_t *zlogp)
void
serve_console(zlog_t *zlogp)
{
- int masterfd;
+ int managerfd;
zone_state_t zstate;
char conspath[MAXPATHLEN];
(void) snprintf(conspath, sizeof (conspath),
- "/dev/zcons/%s/%s", zone_name, ZCONS_MASTER_NAME);
+ "/dev/zcons/%s/%s", zone_name, ZCONS_MANAGER_NAME);
for (;;) {
- masterfd = open(conspath, O_RDWR|O_NONBLOCK|O_NOCTTY);
- if (masterfd == -1) {
- zerror(zlogp, B_TRUE, "failed to open console master");
+ managerfd = open(conspath, O_RDWR|O_NONBLOCK|O_NOCTTY);
+ if (managerfd == -1) {
+ zerror(zlogp, B_TRUE, "failed to open console manager");
(void) mutex_lock(&lock);
goto death;
}
@@ -926,14 +930,14 @@ serve_console(zlog_t *zlogp)
* messages, we wouldn't be able to use read(2), as it fails
* (EBADMSG) when a message with a control element is received.
*/
- if (ioctl(masterfd, I_SRDOPT, RNORM|RPROTDIS) == -1) {
+ if (ioctl(managerfd, I_SRDOPT, RNORM|RPROTDIS) == -1) {
zerror(zlogp, B_TRUE, "failed to set options on "
- "console master");
+ "console manager");
(void) mutex_lock(&lock);
goto death;
}
- do_console_io(zlogp, masterfd, serverfd);
+ do_console_io(zlogp, managerfd, serverfd);
/*
* We would prefer not to do this, but hostile zone processes
@@ -942,7 +946,7 @@ serve_console(zlog_t *zlogp)
* we dismantle the stream and reopen the console when we
* take another lap.
*/
- (void) close(masterfd);
+ (void) close(managerfd);
(void) mutex_lock(&lock);
/*
diff --git a/usr/src/common/core/core_shstrtab.c b/usr/src/common/core/core_shstrtab.c
index b1bcbce682..ea2d15db40 100644
--- a/usr/src/common/core/core_shstrtab.c
+++ b/usr/src/common/core/core_shstrtab.c
@@ -46,8 +46,7 @@ static void *
shstrtab_alloc(void)
{
#ifdef _KERNEL
- return (kmem_zalloc(sizeof (shstrtab_ent_t),
- KM_NOSLEEP | KM_NORMALPRI));
+ return (kmem_zalloc(sizeof (shstrtab_ent_t), KM_NOSLEEP_LAZY));
#else
return (calloc(1, sizeof (shstrtab_ent_t)));
#endif
diff --git a/usr/src/common/dis/i386/dis_tables.c b/usr/src/common/dis/i386/dis_tables.c
index 4d26a7ac2c..82d974ed67 100644
--- a/usr/src/common/dis/i386/dis_tables.c
+++ b/usr/src/common/dis/i386/dis_tables.c
@@ -4335,8 +4335,8 @@ not_avx512:
/*
* at this point we should have a correct (or invalid) opcode
*/
- if (cpu_mode == SIZE64 && dp->it_invalid64 ||
- cpu_mode != SIZE64 && dp->it_invalid32)
+ if ((cpu_mode == SIZE64 && dp->it_invalid64) ||
+ (cpu_mode != SIZE64 && dp->it_invalid32))
goto error;
if (dp->it_indirect != TERM)
goto error;
diff --git a/usr/src/common/fs/ufsops.c b/usr/src/common/fs/ufsops.c
index a467f41202..2b6d1c5a05 100644
--- a/usr/src/common/fs/ufsops.c
+++ b/usr/src/common/fs/ufsops.c
@@ -510,8 +510,11 @@ bufs_read(int fd, caddr_t buf, size_t count)
n = buf;
while (i > 0) {
if (filep->fi_flags & FI_COMPRESSED) {
- if ((j = cf_read(filep, buf, count)) < 0)
+ int rval;
+
+ if ((rval = cf_read(filep, buf, count)) < 0)
return (0); /* encountered an error */
+ j = (size_t)rval;
if (j < i)
i = j; /* short read, must have hit EOF */
} else {
diff --git a/usr/src/common/util/string.c b/usr/src/common/util/string.c
index 66d0cc0414..8e1247f381 100644
--- a/usr/src/common/util/string.c
+++ b/usr/src/common/util/string.c
@@ -223,33 +223,34 @@ next_fmt:
if (base == 0)
continue;
- if (h_count == 0 && l_count == 0)
+ if (h_count == 0 && l_count == 0) {
if (sign)
ul = (int64_t)va_arg(args, int);
else
ul = (int64_t)va_arg(args, unsigned int);
- else if (l_count > 1)
+ } else if (l_count > 1) {
if (sign)
ul = (int64_t)va_arg(args, int64_t);
else
ul = (int64_t)va_arg(args, uint64_t);
- else if (l_count > 0)
+ } else if (l_count > 0) {
if (sign)
ul = (int64_t)va_arg(args, long);
else
ul = (int64_t)va_arg(args, unsigned long);
- else if (h_count > 1)
+ } else if (h_count > 1) {
if (sign)
ul = (int64_t)((char)va_arg(args, int));
else
ul = (int64_t)((unsigned char)va_arg(args,
int));
- else if (h_count > 0)
+ } else if (h_count > 0) {
if (sign)
ul = (int64_t)((short)va_arg(args, int));
else
ul = (int64_t)((unsigned short)va_arg(args,
int));
+ }
if (sign && (int64_t)ul < 0)
ul = -ul;
diff --git a/usr/src/compat/bhyve/amd64/machine/fpu.h b/usr/src/compat/bhyve/amd64/machine/fpu.h
deleted file mode 100644
index 6bc651d996..0000000000
--- a/usr/src/compat/bhyve/amd64/machine/fpu.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * This file and its contents are supplied under the terms of the
- * Common Development and Distribution License ("CDDL"), version 1.0.
- * You may only use this file in accordance with the terms of version
- * 1.0 of the CDDL.
- *
- * A full copy of the text of the CDDL should have accompanied this
- * source. A copy of the CDDL is also available via the Internet at
- * http://www.illumos.org/license/CDDL.
- */
-
-/*
- * Copyright 2014 Pluribus Networks Inc.
- * Copyright (c) 2018, Joyent, Inc.
- */
-
-#ifndef _COMPAT_FREEBSD_AMD64_MACHINE_FPU_H_
-#define _COMPAT_FREEBSD_AMD64_MACHINE_FPU_H_
-
-void fpuexit(kthread_t *td);
-void fpurestore(void *);
-void fpusave(void *);
-
-struct savefpu *fpu_save_area_alloc(void);
-void fpu_save_area_free(struct savefpu *fsa);
-void fpu_save_area_reset(struct savefpu *fsa);
-
-#endif /* _COMPAT_FREEBSD_AMD64_MACHINE_FPU_H_ */
diff --git a/usr/src/compat/bhyve/amd64/machine/pcb.h b/usr/src/compat/bhyve/amd64/machine/pcb.h
deleted file mode 100644
index 75b5de640c..0000000000
--- a/usr/src/compat/bhyve/amd64/machine/pcb.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * This file and its contents are supplied under the terms of the
- * Common Development and Distribution License ("CDDL"), version 1.0.
- * You may only use this file in accordance with the terms of version
- * 1.0 of the CDDL.
- *
- * A full copy of the text of the CDDL should have accompanied this
- * source. A copy of the CDDL is also available via the Internet at
- * http://www.illumos.org/license/CDDL.
- */
-
-/*
- * Copyright 2014 Pluribus Networks Inc.
- */
-
-#ifndef _COMPAT_FREEBSD_AMD64_MACHINE_PCB_H_
-#define _COMPAT_FREEBSD_AMD64_MACHINE_PCB_H_
-
-#include <machine/fpu.h>
-
-#endif /* _COMPAT_FREEBSD_AMD64_MACHINE_PCB_H_ */
diff --git a/usr/src/data/consfonts/THIRDPARTYLICENSE b/usr/src/data/consfonts/THIRDPARTYLICENSE
index 3b809a6bfe..a5c2627a14 100644
--- a/usr/src/data/consfonts/THIRDPARTYLICENSE
+++ b/usr/src/data/consfonts/THIRDPARTYLICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2018 Dimitar Toshkov Zhekov,
+Copyright (C) 2020 Dimitar Toshkov Zhekov,
with Reserved Font Name "Terminus Font".
This Font Software is licensed under the SIL Open Font License, Version 1.1.
diff --git a/usr/src/data/consfonts/THIRDPARTYLICENSE.descrip b/usr/src/data/consfonts/THIRDPARTYLICENSE.descrip
index 46bf2f950a..aa76501fa9 100644
--- a/usr/src/data/consfonts/THIRDPARTYLICENSE.descrip
+++ b/usr/src/data/consfonts/THIRDPARTYLICENSE.descrip
@@ -1 +1 @@
-terminus-font-4.40
+terminus-font-4.49.1
diff --git a/usr/src/data/consfonts/ter-u12b.bdf b/usr/src/data/consfonts/ter-u12b.bdf
index 2ae8e45fdd..408b7cc403 100644
--- a/usr/src/data/consfonts/ter-u12b.bdf
+++ b/usr/src/data/consfonts/ter-u12b.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 10
FONT_DESCENT 2
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@@ -15491,6 +15491,44 @@ F8
00
00
ENDCHAR
+STARTCHAR uni21B2
+ENCODING 8626
+SWIDTH 500 0
+DWIDTH 6 0
+BBX 6 12 0 -2
+BITMAP
+00
+00
+08
+08
+08
+28
+68
+F8
+60
+20
+00
+00
+ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 500 0
+DWIDTH 6 0
+BBX 6 12 0 -2
+BITMAP
+00
+00
+80
+80
+80
+A0
+B0
+F8
+30
+20
+00
+00
+ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
@@ -15499,7 +15537,7 @@ BBX 6 12 0 -2
BITMAP
00
00
-08
+00
08
08
28
diff --git a/usr/src/data/consfonts/ter-u12n.bdf b/usr/src/data/consfonts/ter-u12n.bdf
index e2e74fe0f7..e6c19ce305 100644
--- a/usr/src/data/consfonts/ter-u12n.bdf
+++ b/usr/src/data/consfonts/ter-u12n.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 10
FONT_DESCENT 2
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@@ -15491,6 +15491,44 @@ F8
00
00
ENDCHAR
+STARTCHAR uni21B2
+ENCODING 8626
+SWIDTH 500 0
+DWIDTH 6 0
+BBX 6 12 0 -2
+BITMAP
+00
+00
+08
+08
+08
+28
+68
+F8
+60
+20
+00
+00
+ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 500 0
+DWIDTH 6 0
+BBX 6 12 0 -2
+BITMAP
+00
+00
+80
+80
+80
+A0
+B0
+F8
+30
+20
+00
+00
+ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
@@ -15499,7 +15537,7 @@ BBX 6 12 0 -2
BITMAP
00
00
-08
+00
08
08
28
diff --git a/usr/src/data/consfonts/ter-u14b.bdf b/usr/src/data/consfonts/ter-u14b.bdf
index 23ff14f156..12c71edafa 100644
--- a/usr/src/data/consfonts/ter-u14b.bdf
+++ b/usr/src/data/consfonts/ter-u14b.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 12
FONT_DESCENT 2
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 571 0
@@ -17119,8 +17119,8 @@ BITMAP
00
00
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 571 0
DWIDTH 8 0
BBX 8 14 0 -2
@@ -17140,6 +17140,48 @@ FE
00
00
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 571 0
+DWIDTH 8 0
+BBX 8 14 0 -2
+BITMAP
+00
+00
+C0
+C0
+C0
+C0
+C8
+CC
+FE
+FE
+0C
+08
+00
+00
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 571 0
+DWIDTH 8 0
+BBX 8 14 0 -2
+BITMAP
+00
+00
+00
+00
+06
+06
+26
+66
+FE
+FE
+60
+20
+00
+00
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 571 0
diff --git a/usr/src/data/consfonts/ter-u14n.bdf b/usr/src/data/consfonts/ter-u14n.bdf
index 0d00a116fc..870e180975 100644
--- a/usr/src/data/consfonts/ter-u14n.bdf
+++ b/usr/src/data/consfonts/ter-u14n.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 12
FONT_DESCENT 2
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 571 0
@@ -17119,8 +17119,8 @@ BITMAP
00
00
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 571 0
DWIDTH 8 0
BBX 8 14 0 -2
@@ -17140,6 +17140,48 @@ FE
00
00
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 571 0
+DWIDTH 8 0
+BBX 8 14 0 -2
+BITMAP
+00
+00
+80
+80
+80
+80
+80
+88
+84
+FE
+04
+08
+00
+00
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 571 0
+DWIDTH 8 0
+BBX 8 14 0 -2
+BITMAP
+00
+00
+00
+00
+02
+02
+02
+22
+42
+FE
+40
+20
+00
+00
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 571 0
diff --git a/usr/src/data/consfonts/ter-u14v.bdf b/usr/src/data/consfonts/ter-u14v.bdf
index 2cf33171e9..caaa15cef8 100644
--- a/usr/src/data/consfonts/ter-u14v.bdf
+++ b/usr/src/data/consfonts/ter-u14v.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 12
FONT_DESCENT 2
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 571 0
@@ -17119,8 +17119,8 @@ BITMAP
00
00
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 571 0
DWIDTH 8 0
BBX 8 14 0 -2
@@ -17140,6 +17140,48 @@ FE
00
00
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 571 0
+DWIDTH 8 0
+BBX 8 14 0 -2
+BITMAP
+00
+00
+C0
+C0
+C0
+C0
+C8
+CC
+FE
+FE
+0C
+08
+00
+00
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 571 0
+DWIDTH 8 0
+BBX 8 14 0 -2
+BITMAP
+00
+00
+00
+00
+06
+06
+26
+66
+FE
+FE
+60
+20
+00
+00
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 571 0
diff --git a/usr/src/data/consfonts/ter-u16b.bdf b/usr/src/data/consfonts/ter-u16b.bdf
index 8cd1f7cb54..d9a1d5f3bf 100644
--- a/usr/src/data/consfonts/ter-u16b.bdf
+++ b/usr/src/data/consfonts/ter-u16b.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 12
FONT_DESCENT 4
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@@ -18747,8 +18747,8 @@ BITMAP
00
00
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 500 0
DWIDTH 8 0
BBX 8 16 0 -4
@@ -18770,6 +18770,52 @@ FE
00
00
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 500 0
+DWIDTH 8 0
+BBX 8 16 0 -4
+BITMAP
+00
+00
+C0
+C0
+C0
+C0
+C8
+CC
+FE
+FE
+0C
+08
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 500 0
+DWIDTH 8 0
+BBX 8 16 0 -4
+BITMAP
+00
+00
+00
+00
+06
+06
+26
+66
+FE
+FE
+60
+20
+00
+00
+00
+00
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0
diff --git a/usr/src/data/consfonts/ter-u16n.bdf b/usr/src/data/consfonts/ter-u16n.bdf
index 137116c837..dff5debc36 100644
--- a/usr/src/data/consfonts/ter-u16n.bdf
+++ b/usr/src/data/consfonts/ter-u16n.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 12
FONT_DESCENT 4
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@@ -18747,8 +18747,8 @@ BITMAP
00
00
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 500 0
DWIDTH 8 0
BBX 8 16 0 -4
@@ -18770,6 +18770,52 @@ FE
00
00
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 500 0
+DWIDTH 8 0
+BBX 8 16 0 -4
+BITMAP
+00
+00
+80
+80
+80
+80
+80
+88
+84
+FE
+04
+08
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 500 0
+DWIDTH 8 0
+BBX 8 16 0 -4
+BITMAP
+00
+00
+00
+00
+02
+02
+02
+22
+42
+FE
+40
+20
+00
+00
+00
+00
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0
diff --git a/usr/src/data/consfonts/ter-u16v.bdf b/usr/src/data/consfonts/ter-u16v.bdf
index c83597bdd7..90e28c0346 100644
--- a/usr/src/data/consfonts/ter-u16v.bdf
+++ b/usr/src/data/consfonts/ter-u16v.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 12
FONT_DESCENT 4
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@@ -18747,8 +18747,8 @@ BITMAP
00
00
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 500 0
DWIDTH 8 0
BBX 8 16 0 -4
@@ -18770,6 +18770,52 @@ FE
00
00
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 500 0
+DWIDTH 8 0
+BBX 8 16 0 -4
+BITMAP
+00
+00
+C0
+C0
+C0
+C0
+C8
+CC
+FE
+FE
+0C
+08
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 500 0
+DWIDTH 8 0
+BBX 8 16 0 -4
+BITMAP
+00
+00
+00
+00
+06
+06
+26
+66
+FE
+FE
+60
+20
+00
+00
+00
+00
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0
diff --git a/usr/src/data/consfonts/ter-u18b.bdf b/usr/src/data/consfonts/ter-u18b.bdf
index e1723cc333..a34d0f7448 100644
--- a/usr/src/data/consfonts/ter-u18b.bdf
+++ b/usr/src/data/consfonts/ter-u18b.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 15
FONT_DESCENT 3
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 556 0
@@ -1656,6 +1656,7 @@ SWIDTH 556 0
DWIDTH 10 0
BBX 10 18 0 -3
BITMAP
+3000
1800
0C00
0000
@@ -1673,7 +1674,6 @@ BITMAP
0000
0000
0000
-0000
ENDCHAR
STARTCHAR a
ENCODING 97
@@ -20375,8 +20375,8 @@ BITMAP
0000
0000
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 556 0
DWIDTH 10 0
BBX 10 18 0 -3
@@ -20400,6 +20400,56 @@ FF80
0000
0000
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 556 0
+DWIDTH 10 0
+BBX 10 18 0 -3
+BITMAP
+0000
+0000
+0000
+C000
+C000
+C000
+C000
+C400
+C600
+C300
+FF80
+FF80
+0300
+0600
+0400
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 556 0
+DWIDTH 10 0
+BBX 10 18 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0180
+0180
+1180
+3180
+6180
+FF80
+FF80
+6000
+3000
+1000
+0000
+0000
+0000
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 556 0
diff --git a/usr/src/data/consfonts/ter-u18n.bdf b/usr/src/data/consfonts/ter-u18n.bdf
index 223c3b9afe..24bf95d975 100644
--- a/usr/src/data/consfonts/ter-u18n.bdf
+++ b/usr/src/data/consfonts/ter-u18n.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 15
FONT_DESCENT 3
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 556 0
@@ -1656,6 +1656,7 @@ SWIDTH 556 0
DWIDTH 10 0
BBX 10 18 0 -3
BITMAP
+2000
1000
0800
0000
@@ -1673,7 +1674,6 @@ BITMAP
0000
0000
0000
-0000
ENDCHAR
STARTCHAR a
ENCODING 97
@@ -20375,8 +20375,8 @@ BITMAP
0000
0000
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 556 0
DWIDTH 10 0
BBX 10 18 0 -3
@@ -20400,6 +20400,56 @@ FF80
0000
0000
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 556 0
+DWIDTH 10 0
+BBX 10 18 0 -3
+BITMAP
+0000
+0000
+0000
+8000
+8000
+8000
+8000
+8000
+8400
+8200
+8100
+FF80
+0100
+0200
+0400
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 556 0
+DWIDTH 10 0
+BBX 10 18 0 -3
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0080
+0080
+0080
+1080
+2080
+4080
+FF80
+4000
+2000
+1000
+0000
+0000
+0000
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 556 0
diff --git a/usr/src/data/consfonts/ter-u20b.bdf b/usr/src/data/consfonts/ter-u20b.bdf
index 846c0b61f0..cb7253cc29 100644
--- a/usr/src/data/consfonts/ter-u20b.bdf
+++ b/usr/src/data/consfonts/ter-u20b.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 16
FONT_DESCENT 4
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@@ -1786,6 +1786,7 @@ SWIDTH 500 0
DWIDTH 10 0
BBX 10 20 0 -4
BITMAP
+3000
1800
0C00
0000
@@ -1805,7 +1806,6 @@ BITMAP
0000
0000
0000
-0000
ENDCHAR
STARTCHAR a
ENCODING 97
@@ -22003,8 +22003,8 @@ BITMAP
0000
0000
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 500 0
DWIDTH 10 0
BBX 10 20 0 -4
@@ -22030,6 +22030,60 @@ FF80
0000
0000
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 500 0
+DWIDTH 10 0
+BBX 10 20 0 -4
+BITMAP
+0000
+0000
+0000
+C000
+C000
+C000
+C000
+C000
+C400
+C600
+C300
+FF80
+FF80
+0300
+0600
+0400
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 500 0
+DWIDTH 10 0
+BBX 10 20 0 -4
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0180
+0180
+0180
+1180
+3180
+6180
+FF80
+FF80
+6000
+3000
+1000
+0000
+0000
+0000
+0000
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0
diff --git a/usr/src/data/consfonts/ter-u20n.bdf b/usr/src/data/consfonts/ter-u20n.bdf
index 842581e1e0..f8a07618b4 100644
--- a/usr/src/data/consfonts/ter-u20n.bdf
+++ b/usr/src/data/consfonts/ter-u20n.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 16
FONT_DESCENT 4
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@@ -1786,6 +1786,7 @@ SWIDTH 500 0
DWIDTH 10 0
BBX 10 20 0 -4
BITMAP
+2000
1000
0800
0000
@@ -1805,7 +1806,6 @@ BITMAP
0000
0000
0000
-0000
ENDCHAR
STARTCHAR a
ENCODING 97
@@ -22003,8 +22003,8 @@ BITMAP
0000
0000
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 500 0
DWIDTH 10 0
BBX 10 20 0 -4
@@ -22030,6 +22030,60 @@ FF80
0000
0000
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 500 0
+DWIDTH 10 0
+BBX 10 20 0 -4
+BITMAP
+0000
+0000
+0000
+8000
+8000
+8000
+8000
+8000
+8000
+8400
+8200
+8100
+FF80
+0100
+0200
+0400
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 500 0
+DWIDTH 10 0
+BBX 10 20 0 -4
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0080
+0080
+0080
+1080
+2080
+4080
+FF80
+4000
+2000
+1000
+0000
+0000
+0000
+0000
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0
diff --git a/usr/src/data/consfonts/ter-u22b.bdf b/usr/src/data/consfonts/ter-u22b.bdf
index d8dde9cde4..6161315fa0 100644
--- a/usr/src/data/consfonts/ter-u22b.bdf
+++ b/usr/src/data/consfonts/ter-u22b.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 17
FONT_DESCENT 5
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@@ -23631,8 +23631,8 @@ BITMAP
0000
0000
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 500 0
DWIDTH 11 0
BBX 11 22 0 -5
@@ -23660,6 +23660,64 @@ FFC0
0000
0000
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 500 0
+DWIDTH 11 0
+BBX 11 22 0 -5
+BITMAP
+0000
+0000
+0000
+C000
+C000
+C000
+C000
+C000
+C000
+C200
+C300
+C180
+FFC0
+FFC0
+0180
+0300
+0200
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 500 0
+DWIDTH 11 0
+BBX 11 22 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+00C0
+00C0
+00C0
+10C0
+30C0
+60C0
+FFC0
+FFC0
+6000
+3000
+1000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0
diff --git a/usr/src/data/consfonts/ter-u22n.bdf b/usr/src/data/consfonts/ter-u22n.bdf
index 481910339d..743b6c0261 100644
--- a/usr/src/data/consfonts/ter-u22n.bdf
+++ b/usr/src/data/consfonts/ter-u22n.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 17
FONT_DESCENT 5
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@@ -23631,8 +23631,8 @@ BITMAP
0000
0000
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 500 0
DWIDTH 11 0
BBX 11 22 0 -5
@@ -23660,6 +23660,64 @@ FFC0
0000
0000
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 500 0
+DWIDTH 11 0
+BBX 11 22 0 -5
+BITMAP
+0000
+0000
+0000
+8000
+8000
+8000
+8000
+8000
+8000
+8000
+8200
+8100
+8080
+FFC0
+0080
+0100
+0200
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 500 0
+DWIDTH 11 0
+BBX 11 22 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0040
+0040
+0040
+0040
+1040
+2040
+4040
+FFC0
+4000
+2000
+1000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0
diff --git a/usr/src/data/consfonts/ter-u24b.bdf b/usr/src/data/consfonts/ter-u24b.bdf
index c21b8cf412..6700b6cb73 100644
--- a/usr/src/data/consfonts/ter-u24b.bdf
+++ b/usr/src/data/consfonts/ter-u24b.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 19
FONT_DESCENT 5
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@@ -2046,6 +2046,7 @@ SWIDTH 500 0
DWIDTH 12 0
BBX 12 24 0 -5
BITMAP
+0000
1800
0C00
0600
@@ -2069,7 +2070,6 @@ BITMAP
0000
0000
0000
-0000
ENDCHAR
STARTCHAR a
ENCODING 97
@@ -25259,8 +25259,8 @@ BITMAP
0000
0000
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 500 0
DWIDTH 12 0
BBX 12 24 0 -5
@@ -25290,6 +25290,68 @@ FFE0
0000
0000
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 500 0
+DWIDTH 12 0
+BBX 12 24 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+C000
+C000
+C000
+C000
+C000
+C200
+C300
+C180
+C0C0
+FFE0
+FFE0
+00C0
+0180
+0300
+0200
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 500 0
+DWIDTH 12 0
+BBX 12 24 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0060
+0060
+0060
+0860
+1860
+3060
+6060
+FFE0
+FFE0
+6000
+3000
+1800
+0800
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0
diff --git a/usr/src/data/consfonts/ter-u24n.bdf b/usr/src/data/consfonts/ter-u24n.bdf
index 888e788e63..9f3e4839ea 100644
--- a/usr/src/data/consfonts/ter-u24n.bdf
+++ b/usr/src/data/consfonts/ter-u24n.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 19
FONT_DESCENT 5
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@@ -2046,6 +2046,7 @@ SWIDTH 500 0
DWIDTH 12 0
BBX 12 24 0 -5
BITMAP
+0000
1000
0800
0400
@@ -2069,7 +2070,6 @@ BITMAP
0000
0000
0000
-0000
ENDCHAR
STARTCHAR a
ENCODING 97
@@ -25259,8 +25259,8 @@ BITMAP
0000
0000
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 500 0
DWIDTH 12 0
BBX 12 24 0 -5
@@ -25290,6 +25290,68 @@ FFE0
0000
0000
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 500 0
+DWIDTH 12 0
+BBX 12 24 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+8000
+8000
+8000
+8000
+8000
+8000
+8200
+8100
+8080
+8040
+FFE0
+0040
+0080
+0100
+0200
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 500 0
+DWIDTH 12 0
+BBX 12 24 0 -5
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0020
+0020
+0020
+0020
+0820
+1020
+2020
+4020
+FFE0
+4000
+2000
+1000
+0800
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0
diff --git a/usr/src/data/consfonts/ter-u28b.bdf b/usr/src/data/consfonts/ter-u28b.bdf
index 36c767a43c..6faa63200e 100644
--- a/usr/src/data/consfonts/ter-u28b.bdf
+++ b/usr/src/data/consfonts/ter-u28b.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 22
FONT_DESCENT 6
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@@ -2306,6 +2306,7 @@ SWIDTH 500 0
DWIDTH 14 0
BBX 14 28 0 -6
BITMAP
+3800
1C00
0E00
0700
@@ -2333,7 +2334,6 @@ BITMAP
0000
0000
0000
-0000
ENDCHAR
STARTCHAR a
ENCODING 97
@@ -28515,8 +28515,8 @@ BITMAP
0000
0000
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 500 0
DWIDTH 14 0
BBX 14 28 0 -6
@@ -28550,6 +28550,76 @@ FFF8
0000
0000
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 500 0
+DWIDTH 14 0
+BBX 14 28 0 -6
+BITMAP
+0000
+0000
+0000
+0000
+C000
+C000
+C000
+C000
+C000
+C000
+C100
+C180
+C1C0
+C0E0
+C070
+FFF8
+FFF8
+0070
+00E0
+01C0
+0180
+0100
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 500 0
+DWIDTH 14 0
+BBX 14 28 0 -6
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0018
+0018
+0018
+0418
+0C18
+1C18
+3818
+7018
+FFF8
+FFF8
+7000
+3800
+1C00
+0C00
+0400
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0
diff --git a/usr/src/data/consfonts/ter-u28n.bdf b/usr/src/data/consfonts/ter-u28n.bdf
index 32833fe425..92cc2025c6 100644
--- a/usr/src/data/consfonts/ter-u28n.bdf
+++ b/usr/src/data/consfonts/ter-u28n.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 22
FONT_DESCENT 6
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@@ -2306,6 +2306,7 @@ SWIDTH 500 0
DWIDTH 14 0
BBX 14 28 0 -6
BITMAP
+1800
0C00
0600
0300
@@ -2333,7 +2334,6 @@ BITMAP
0000
0000
0000
-0000
ENDCHAR
STARTCHAR a
ENCODING 97
@@ -13851,7 +13851,6 @@ BITMAP
0000
ENDCHAR
STARTCHAR uni0332
-STARTCHAR char818
ENCODING 818
SWIDTH 500 0
DWIDTH 14 0
@@ -28516,8 +28515,8 @@ BITMAP
0000
0000
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 500 0
DWIDTH 14 0
BBX 14 28 0 -6
@@ -28551,6 +28550,76 @@ FFF8
0000
0000
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 500 0
+DWIDTH 14 0
+BBX 14 28 0 -6
+BITMAP
+0000
+0000
+0000
+0000
+C000
+C000
+C000
+C000
+C000
+C000
+C100
+C180
+C0C0
+C060
+C030
+FFF8
+FFF8
+0030
+0060
+00C0
+0180
+0100
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 500 0
+DWIDTH 14 0
+BBX 14 28 0 -6
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0018
+0018
+0018
+0418
+0C18
+1818
+3018
+6018
+FFF8
+FFF8
+6000
+3000
+1800
+0C00
+0400
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0
diff --git a/usr/src/data/consfonts/ter-u32b.bdf b/usr/src/data/consfonts/ter-u32b.bdf
index 79f8a3c15f..20bf43f5d4 100644
--- a/usr/src/data/consfonts/ter-u32b.bdf
+++ b/usr/src/data/consfonts/ter-u32b.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 26
FONT_DESCENT 6
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@@ -2567,6 +2567,7 @@ DWIDTH 16 0
BBX 16 32 0 -6
BITMAP
0000
+0000
1C00
0E00
0700
@@ -2597,7 +2598,6 @@ BITMAP
0000
0000
0000
-0000
ENDCHAR
STARTCHAR a
ENCODING 97
@@ -31771,8 +31771,8 @@ BITMAP
0000
0000
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 500 0
DWIDTH 16 0
BBX 16 32 0 -6
@@ -31810,6 +31810,84 @@ BITMAP
0000
0000
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 500 0
+DWIDTH 16 0
+BBX 16 32 0 -6
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+7000
+7000
+7000
+7000
+7000
+7000
+7000
+70C0
+70E0
+7070
+7038
+701C
+7FFE
+7FFE
+7FFE
+001C
+0038
+0070
+00E0
+00C0
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 500 0
+DWIDTH 16 0
+BBX 16 32 0 -6
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+000E
+000E
+000E
+000E
+030E
+070E
+0E0E
+1C0E
+380E
+7FFE
+7FFE
+7FFE
+3800
+1C00
+0E00
+0700
+0300
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0
diff --git a/usr/src/data/consfonts/ter-u32n.bdf b/usr/src/data/consfonts/ter-u32n.bdf
index 16416791b6..e6211619f1 100644
--- a/usr/src/data/consfonts/ter-u32n.bdf
+++ b/usr/src/data/consfonts/ter-u32n.bdf
@@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
-COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
+COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@@ -24,7 +24,7 @@ FONT_ASCENT 26
FONT_DESCENT 6
DEFAULT_CHAR 65533
ENDPROPERTIES
-CHARS 1355
+CHARS 1357
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@@ -2567,6 +2567,7 @@ DWIDTH 16 0
BBX 16 32 0 -6
BITMAP
0000
+0000
0E00
0700
0380
@@ -2597,7 +2598,6 @@ BITMAP
0000
0000
0000
-0000
ENDCHAR
STARTCHAR a
ENCODING 97
@@ -31771,8 +31771,8 @@ BITMAP
0000
0000
ENDCHAR
-STARTCHAR carriagereturn
-ENCODING 8629
+STARTCHAR uni21B2
+ENCODING 8626
SWIDTH 500 0
DWIDTH 16 0
BBX 16 32 0 -6
@@ -31810,6 +31810,84 @@ BITMAP
0000
0000
ENDCHAR
+STARTCHAR uni21B3
+ENCODING 8627
+SWIDTH 500 0
+DWIDTH 16 0
+BBX 16 32 0 -6
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+6000
+6000
+6000
+6000
+6000
+6000
+6000
+6000
+6180
+61C0
+60E0
+6070
+6038
+7FFC
+7FFC
+0038
+0070
+00E0
+01C0
+0180
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
+STARTCHAR carriagereturn
+ENCODING 8629
+SWIDTH 500 0
+DWIDTH 16 0
+BBX 16 32 0 -6
+BITMAP
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+000C
+000C
+000C
+000C
+000C
+030C
+070C
+0E0C
+1C0C
+380C
+7FFC
+7FFC
+3800
+1C00
+0E00
+0700
+0300
+0000
+0000
+0000
+0000
+0000
+0000
+ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0
diff --git a/usr/src/data/ucode/Makefile.links b/usr/src/data/ucode/Makefile.links
index 39be3efa48..7c7233d9ca 100644
--- a/usr/src/data/ucode/Makefile.links
+++ b/usr/src/data/ucode/Makefile.links
@@ -153,7 +153,6 @@ INTEL_LINKS = \
000606A6-02 \
000606A6-04 \
000606A6-80 \
- 00080665-01 \
000806C2-40 \
000806C2-80 \
000806D1-40 \
@@ -601,9 +600,6 @@ $(ROOTINTELDIR)/000606A6-04: $(ROOTINTELDIR)/000606A6-01
$(ROOTINTELDIR)/000606A6-80: $(ROOTINTELDIR)/000606A6-01
$(RM) $@; $(LN) $^ $@
-$(ROOTINTELDIR)/00080665-01: $(ROOTINTELDIR)/00080664-01
- $(RM) $@; $(LN) $^ $@
-
$(ROOTINTELDIR)/000806C2-40: $(ROOTINTELDIR)/000806C2-02
$(RM) $@; $(LN) $^ $@
diff --git a/usr/src/data/ucode/README.ucode b/usr/src/data/ucode/README.ucode
index c2f0b03d81..b7785b5f99 100644
--- a/usr/src/data/ucode/README.ucode
+++ b/usr/src/data/ucode/README.ucode
@@ -38,4 +38,4 @@ of updating the manifest as necessary. Be careful about new files.
AMD: Updated in March 2012 as part of illumos#2546. Exact revision
unknown.
-Intel: Linux 20210608 release
+Intel: Linux 20220207 release
diff --git a/usr/src/data/ucode/intel/000306F2-01 b/usr/src/data/ucode/intel/000306F2-01
index 04a67cf050..41a9d903b9 100644
--- a/usr/src/data/ucode/intel/000306F2-01
+++ b/usr/src/data/ucode/intel/000306F2-01
Binary files differ
diff --git a/usr/src/data/ucode/intel/000306F4-80 b/usr/src/data/ucode/intel/000306F4-80
index fa7f56f52b..5f87dd2fab 100644
--- a/usr/src/data/ucode/intel/000306F4-80
+++ b/usr/src/data/ucode/intel/000306F4-80
Binary files differ
diff --git a/usr/src/data/ucode/intel/000406E3-40 b/usr/src/data/ucode/intel/000406E3-40
index d9426ae970..13b343ad2a 100644
--- a/usr/src/data/ucode/intel/000406E3-40
+++ b/usr/src/data/ucode/intel/000406E3-40
Binary files differ
diff --git a/usr/src/data/ucode/intel/000406F1-01 b/usr/src/data/ucode/intel/000406F1-01
index 1c6e7933a5..7ed66eabe2 100644
--- a/usr/src/data/ucode/intel/000406F1-01
+++ b/usr/src/data/ucode/intel/000406F1-01
Binary files differ
diff --git a/usr/src/data/ucode/intel/00050653-01 b/usr/src/data/ucode/intel/00050653-01
index c76fac3ab0..9ec944d6cd 100644
--- a/usr/src/data/ucode/intel/00050653-01
+++ b/usr/src/data/ucode/intel/00050653-01
Binary files differ
diff --git a/usr/src/data/ucode/intel/00050654-01 b/usr/src/data/ucode/intel/00050654-01
index cca28e70a8..894e5e172b 100644
--- a/usr/src/data/ucode/intel/00050654-01
+++ b/usr/src/data/ucode/intel/00050654-01
Binary files differ
diff --git a/usr/src/data/ucode/intel/00050656-01 b/usr/src/data/ucode/intel/00050656-01
index 96169ce3fe..64aabb0e21 100644
--- a/usr/src/data/ucode/intel/00050656-01
+++ b/usr/src/data/ucode/intel/00050656-01
Binary files differ
diff --git a/usr/src/data/ucode/intel/00050657-01 b/usr/src/data/ucode/intel/00050657-01
index f7779ee1dd..2749da188e 100644
--- a/usr/src/data/ucode/intel/00050657-01
+++ b/usr/src/data/ucode/intel/00050657-01
Binary files differ
diff --git a/usr/src/data/ucode/intel/0005065B-01 b/usr/src/data/ucode/intel/0005065B-01
index 96deb26c6e..8363e7cf7f 100644
--- a/usr/src/data/ucode/intel/0005065B-01
+++ b/usr/src/data/ucode/intel/0005065B-01
Binary files differ
diff --git a/usr/src/data/ucode/intel/00050663-10 b/usr/src/data/ucode/intel/00050663-10
index 2a9d8eaf7c..b4d965ff61 100644
--- a/usr/src/data/ucode/intel/00050663-10
+++ b/usr/src/data/ucode/intel/00050663-10
Binary files differ
diff --git a/usr/src/data/ucode/intel/00050664-10 b/usr/src/data/ucode/intel/00050664-10
index 9bb6fbea80..4d66e5532d 100644
--- a/usr/src/data/ucode/intel/00050664-10
+++ b/usr/src/data/ucode/intel/00050664-10
Binary files differ
diff --git a/usr/src/data/ucode/intel/00050665-10 b/usr/src/data/ucode/intel/00050665-10
index 12badd3891..65c6585674 100644
--- a/usr/src/data/ucode/intel/00050665-10
+++ b/usr/src/data/ucode/intel/00050665-10
Binary files differ
diff --git a/usr/src/data/ucode/intel/000506C9-01 b/usr/src/data/ucode/intel/000506C9-01
index 34e1525d17..3d1aa34e93 100644
--- a/usr/src/data/ucode/intel/000506C9-01
+++ b/usr/src/data/ucode/intel/000506C9-01
Binary files differ
diff --git a/usr/src/data/ucode/intel/000506CA-01 b/usr/src/data/ucode/intel/000506CA-01
index 44ca47239a..ca6f520ea5 100644
--- a/usr/src/data/ucode/intel/000506CA-01
+++ b/usr/src/data/ucode/intel/000506CA-01
Binary files differ
diff --git a/usr/src/data/ucode/intel/000506E3-02 b/usr/src/data/ucode/intel/000506E3-02
index b44e31abae..761fa6660e 100644
--- a/usr/src/data/ucode/intel/000506E3-02
+++ b/usr/src/data/ucode/intel/000506E3-02
Binary files differ
diff --git a/usr/src/data/ucode/intel/000506F1-01 b/usr/src/data/ucode/intel/000506F1-01
index f0f4c78068..943afa9f0d 100644
--- a/usr/src/data/ucode/intel/000506F1-01
+++ b/usr/src/data/ucode/intel/000506F1-01
Binary files differ
diff --git a/usr/src/data/ucode/intel/000606A6-01 b/usr/src/data/ucode/intel/000606A6-01
index e19f676689..7a126f970f 100644
--- a/usr/src/data/ucode/intel/000606A6-01
+++ b/usr/src/data/ucode/intel/000606A6-01
Binary files differ
diff --git a/usr/src/data/ucode/intel/000706A1-01 b/usr/src/data/ucode/intel/000706A1-01
index ee8a144fad..51866a1d01 100644
--- a/usr/src/data/ucode/intel/000706A1-01
+++ b/usr/src/data/ucode/intel/000706A1-01
Binary files differ
diff --git a/usr/src/data/ucode/intel/000706A8-01 b/usr/src/data/ucode/intel/000706A8-01
index 9099bd3108..ddd7034a4a 100644
--- a/usr/src/data/ucode/intel/000706A8-01
+++ b/usr/src/data/ucode/intel/000706A8-01
Binary files differ
diff --git a/usr/src/data/ucode/intel/000706E5-80 b/usr/src/data/ucode/intel/000706E5-80
index 0f8b5772f8..c005889fce 100644
--- a/usr/src/data/ucode/intel/000706E5-80
+++ b/usr/src/data/ucode/intel/000706E5-80
Binary files differ
diff --git a/usr/src/data/ucode/intel/00080664-01 b/usr/src/data/ucode/intel/00080664-01
deleted file mode 100644
index 2d3c357f8c..0000000000
--- a/usr/src/data/ucode/intel/00080664-01
+++ /dev/null
Binary files differ
diff --git a/usr/src/data/ucode/intel/000806A1-10 b/usr/src/data/ucode/intel/000806A1-10
index 45b544affe..2c0c71b9ce 100644
--- a/usr/src/data/ucode/intel/000806A1-10
+++ b/usr/src/data/ucode/intel/000806A1-10
Binary files differ
diff --git a/usr/src/data/ucode/intel/000806C1-80 b/usr/src/data/ucode/intel/000806C1-80
index e01ba0c1e9..906c56c3db 100644
--- a/usr/src/data/ucode/intel/000806C1-80
+++ b/usr/src/data/ucode/intel/000806C1-80
Binary files differ
diff --git a/usr/src/data/ucode/intel/000806C2-02 b/usr/src/data/ucode/intel/000806C2-02
index 12da9fe36f..21f3c4ded7 100644
--- a/usr/src/data/ucode/intel/000806C2-02
+++ b/usr/src/data/ucode/intel/000806C2-02
Binary files differ
diff --git a/usr/src/data/ucode/intel/000806D1-02 b/usr/src/data/ucode/intel/000806D1-02
index 5ac418b395..55cc03ab0f 100644
--- a/usr/src/data/ucode/intel/000806D1-02
+++ b/usr/src/data/ucode/intel/000806D1-02
Binary files differ
diff --git a/usr/src/data/ucode/intel/000806E9-10 b/usr/src/data/ucode/intel/000806E9-10
index 11fcf69c93..42f0b936d7 100644
--- a/usr/src/data/ucode/intel/000806E9-10
+++ b/usr/src/data/ucode/intel/000806E9-10
Binary files differ
diff --git a/usr/src/data/ucode/intel/000806E9-40 b/usr/src/data/ucode/intel/000806E9-40
index e08e7da081..8bce192d28 100644
--- a/usr/src/data/ucode/intel/000806E9-40
+++ b/usr/src/data/ucode/intel/000806E9-40
Binary files differ
diff --git a/usr/src/data/ucode/intel/000806EA-40 b/usr/src/data/ucode/intel/000806EA-40
index d9b7508844..ef6d4f138e 100644
--- a/usr/src/data/ucode/intel/000806EA-40
+++ b/usr/src/data/ucode/intel/000806EA-40
Binary files differ
diff --git a/usr/src/data/ucode/intel/000806EB-10 b/usr/src/data/ucode/intel/000806EB-10
index 6fb591d3bc..53d5ef011a 100644
--- a/usr/src/data/ucode/intel/000806EB-10
+++ b/usr/src/data/ucode/intel/000806EB-10
Binary files differ
diff --git a/usr/src/data/ucode/intel/000806EC-04 b/usr/src/data/ucode/intel/000806EC-04
index 00980231fe..2d65ba226b 100644
--- a/usr/src/data/ucode/intel/000806EC-04
+++ b/usr/src/data/ucode/intel/000806EC-04
Binary files differ
diff --git a/usr/src/data/ucode/intel/00090661-01 b/usr/src/data/ucode/intel/00090661-01
index 8140fcc082..06548466d3 100644
--- a/usr/src/data/ucode/intel/00090661-01
+++ b/usr/src/data/ucode/intel/00090661-01
Binary files differ
diff --git a/usr/src/data/ucode/intel/000906C0-01 b/usr/src/data/ucode/intel/000906C0-01
index 2cf44b1bef..7bc9cce441 100644
--- a/usr/src/data/ucode/intel/000906C0-01
+++ b/usr/src/data/ucode/intel/000906C0-01
Binary files differ
diff --git a/usr/src/data/ucode/intel/000906E9-02 b/usr/src/data/ucode/intel/000906E9-02
index 23327ecf8f..10af087b2e 100644
--- a/usr/src/data/ucode/intel/000906E9-02
+++ b/usr/src/data/ucode/intel/000906E9-02
Binary files differ
diff --git a/usr/src/data/ucode/intel/000906EA-02 b/usr/src/data/ucode/intel/000906EA-02
index 13855bb023..bab21517f7 100644
--- a/usr/src/data/ucode/intel/000906EA-02
+++ b/usr/src/data/ucode/intel/000906EA-02
Binary files differ
diff --git a/usr/src/data/ucode/intel/000906EB-02 b/usr/src/data/ucode/intel/000906EB-02
index c49cdc673c..0482e4b141 100644
--- a/usr/src/data/ucode/intel/000906EB-02
+++ b/usr/src/data/ucode/intel/000906EB-02
Binary files differ
diff --git a/usr/src/data/ucode/intel/000906EC-02 b/usr/src/data/ucode/intel/000906EC-02
index f9b5c5ae9f..ea21168781 100644
--- a/usr/src/data/ucode/intel/000906EC-02
+++ b/usr/src/data/ucode/intel/000906EC-02
Binary files differ
diff --git a/usr/src/data/ucode/intel/000906ED-02 b/usr/src/data/ucode/intel/000906ED-02
index 9b5a312dfc..ca07dec538 100644
--- a/usr/src/data/ucode/intel/000906ED-02
+++ b/usr/src/data/ucode/intel/000906ED-02
Binary files differ
diff --git a/usr/src/data/ucode/intel/000A0652-20 b/usr/src/data/ucode/intel/000A0652-20
index eed05a9868..cceb88c302 100644
--- a/usr/src/data/ucode/intel/000A0652-20
+++ b/usr/src/data/ucode/intel/000A0652-20
Binary files differ
diff --git a/usr/src/data/ucode/intel/000A0653-02 b/usr/src/data/ucode/intel/000A0653-02
index 9bf967dfcd..f2b8b4dff5 100644
--- a/usr/src/data/ucode/intel/000A0653-02
+++ b/usr/src/data/ucode/intel/000A0653-02
Binary files differ
diff --git a/usr/src/data/ucode/intel/000A0655-02 b/usr/src/data/ucode/intel/000A0655-02
index b8ede54fe6..ddc0e87246 100644
--- a/usr/src/data/ucode/intel/000A0655-02
+++ b/usr/src/data/ucode/intel/000A0655-02
Binary files differ
diff --git a/usr/src/data/ucode/intel/000A0660-80 b/usr/src/data/ucode/intel/000A0660-80
index 601bce5354..0f003e98b2 100644
--- a/usr/src/data/ucode/intel/000A0660-80
+++ b/usr/src/data/ucode/intel/000A0660-80
Binary files differ
diff --git a/usr/src/data/ucode/intel/000A0661-80 b/usr/src/data/ucode/intel/000A0661-80
index c38c1510f6..ab16cc4e0c 100644
--- a/usr/src/data/ucode/intel/000A0661-80
+++ b/usr/src/data/ucode/intel/000A0661-80
Binary files differ
diff --git a/usr/src/data/ucode/intel/000A0671-02 b/usr/src/data/ucode/intel/000A0671-02
index b8e29c36c7..9970cf58dd 100644
--- a/usr/src/data/ucode/intel/000A0671-02
+++ b/usr/src/data/ucode/intel/000A0671-02
Binary files differ
diff --git a/usr/src/data/ucode/intel/THIRDPARTYLICENSE b/usr/src/data/ucode/intel/THIRDPARTYLICENSE
index 8fbad3dd21..cb763c91a3 100644
--- a/usr/src/data/ucode/intel/THIRDPARTYLICENSE
+++ b/usr/src/data/ucode/intel/THIRDPARTYLICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2018-2020 Intel Corporation.
+Copyright (c) 2018-2021 Intel Corporation.
All rights reserved.
Redistribution.
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index aa163cc3bf..d1a33d262d 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -272,6 +272,7 @@ SUBDIRS += \
sun_fc \
sun_sas \
udapl \
+ varpd \
watchmalloc \
$($(MACH)_SUBDIRS)
@@ -491,6 +492,7 @@ HDRSUBDIRS= \
smbsrv \
smhba \
udapl \
+ varpd \
$($(MACH)_HDRSUBDIRS)
i386_HDRSUBDIRS= \
@@ -609,7 +611,7 @@ libdhcputil: libgen libinetutil libdlpi
libdiskmgt: libdevid libdevinfo libadm libefi libkstat libsysevent
$(INTEL_BLD)libdiskmgt: libfdisk
libdladm: libdevinfo libinetutil libscf librcm libexacct libkstat \
- libpool
+ libpool varpd
libdlpi: libinetutil libdladm
libds: libsysevent
libdtrace: libproc libgen libctf libmapmalloc
@@ -721,6 +723,8 @@ storage: libdevice libdevinfo libdevid
sun_fc: libdevinfo libsysevent
sun_sas: libdevinfo libsysevent libkstat libdevid
udapl: libdevinfo libdladm
+varpd: libavl libidspace libumem libnsl libnvpair libmd5 librename \
+ libcustr
#
# The reason this rule checks for the existence of the
diff --git a/usr/src/lib/gss_mechs/mech_dh/dh192/fakensl.c b/usr/src/lib/gss_mechs/mech_dh/dh192/fakensl.c
index bbf94cc174..22556b131c 100644
--- a/usr/src/lib/gss_mechs/mech_dh/dh192/fakensl.c
+++ b/usr/src/lib/gss_mechs/mech_dh/dh192/fakensl.c
@@ -26,8 +26,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <rpc/rpc.h>
#include <rpc/key_prot.h>
@@ -40,7 +38,7 @@ extern int key_decryptsession_pk(const char *, netobj *, des_block *);
/*ARGSUSED*/
int
-__getpublickey_cached_g(const char remotename[MAXNETNAMELEN], int keylen,
+__getpublickey_cached_g(const char remotename[], int keylen,
int algtype, char *pkey, size_t pkeylen, int *cached)
{
return (getpublickey(remotename, pkey));
@@ -49,7 +47,7 @@ __getpublickey_cached_g(const char remotename[MAXNETNAMELEN], int keylen,
#pragma weak getpublickey_g
/*ARGSUSED*/
int
-getpublickey_g(const char remotename[MAXNETNAMELEN], int keylen,
+getpublickey_g(const char remotename[], int keylen,
int algtype, char *pkey, size_t pkeylen)
{
return (getpublickey(remotename, pkey));
diff --git a/usr/src/lib/gss_mechs/mech_krb5/krb5/rcache/rc_file.c b/usr/src/lib/gss_mechs/mech_krb5/krb5/rcache/rc_file.c
index 945b6dd733..aae3a7be72 100644
--- a/usr/src/lib/gss_mechs/mech_krb5/krb5/rcache/rc_file.c
+++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/rcache/rc_file.c
@@ -49,7 +49,7 @@ rc_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep)
krb5_timeofday(context, &time);
/* Solaris: calling alive() on rep since it doesn't make sense to store an
- * expired replay.
+ * expired replay.
*/
if (alive(context, rep, t->lifespan, time) == CMP_EXPIRED){
return CMP_EXPIRED;
@@ -163,8 +163,8 @@ krb5_rc_file_close_no_free(krb5_context context, krb5_rcache id)
FREE_RC(q->rep.server);
FREE_RC(q);
}
- if (t->d.fd >= 0)
- (void) krb5_rc_io_close(context, &t->d);
+ if (t->d.fd >= 0)
+ (void) krb5_rc_io_close(context, &t->d);
FREE_RC(t);
id->data = NULL;
return 0;
@@ -283,7 +283,7 @@ krb5_rc_io_fetch(krb5_context context, struct file_data *t,
if (retval)
goto errout;
- retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) &len,
+ retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) &len,
sizeof(len));
if (retval)
goto errout;
@@ -365,7 +365,7 @@ krb5_rc_file_recover_locked(krb5_context context, krb5_rcache id)
retval = KRB5_RC_IO;
goto io_fail;
}
-
+
retval = krb5_rc_io_fetch (context, t, rep, (int) max_size);
if (retval == KRB5_RC_IO_EOF)
diff --git a/usr/src/lib/libdladm/Makefile b/usr/src/lib/libdladm/Makefile
index 5202579b6c..e4825d91da 100644
--- a/usr/src/lib/libdladm/Makefile
+++ b/usr/src/lib/libdladm/Makefile
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2015, Joyent, Inc.
#
#
@@ -29,7 +30,7 @@ HDRS = libdladm.h libdladm_impl.h libdllink.h libdlaggr.h \
libdlwlan.h libdlwlan_impl.h libdlvnic.h libdlvlan.h \
libdlmgmt.h libdlflow.h libdlflow_impl.h libdlstat.h \
libdlether.h libdlsim.h libdlbridge.h libdliptun.h \
- libdlib.h
+ libdlib.h libdloverlay.h
HDRDIR = common
@@ -71,7 +72,13 @@ TYPELIST = \
dlmgmt_getconfsnapshot_retval_t \
dlmgmt_door_zoneboot_t \
dlmgmt_remapid_retval_t \
- dlmgmt_createid_retval_t
+ dlmgmt_createid_retval_t \
+ overlay_ioc_create_t \
+ overlay_ioc_activate_t \
+ overlay_ioc_delete_t \
+ overlay_ioc_nprops_t \
+ overlay_ioc_propinfo_t \
+ overlay_ioc_prop_t
all := TARGET = all
clean := TARGET = clean
diff --git a/usr/src/lib/libdladm/Makefile.com b/usr/src/lib/libdladm/Makefile.com
index d170a97998..13a5e8384a 100644
--- a/usr/src/lib/libdladm/Makefile.com
+++ b/usr/src/lib/libdladm/Makefile.com
@@ -28,7 +28,8 @@ VERS = .1
OBJECTS = libdladm.o secobj.o linkprop.o libdllink.o libdlaggr.o \
libdlwlan.o libdlvnic.o libdlmgmt.o libdlvlan.o libdlib.o\
flowattr.o flowprop.o propfuncs.o libdlflow.o libdlstat.o \
- usage.o libdlether.o libdlsim.o libdlbridge.o libdliptun.o
+ usage.o libdlether.o libdlsim.o libdlbridge.o libdliptun.o \
+ libdloverlay.o
include ../../Makefile.lib
@@ -37,7 +38,7 @@ include ../../Makefile.rootfs
LIBS = $(DYNLIB)
LDLIBS += -ldevinfo -lc -linetutil -lsocket -lscf -lrcm -lnvpair \
- -lexacct -lkstat -lpool
+ -lexacct -lkstat -lpool -lvarpd
SRCDIR = ../common
@@ -51,9 +52,10 @@ CPPFLAGS += -I$(SRCDIR) -D_REENTRANT
# not linted
SMATCH=off
+CSTD= $(CSTD_GNU99)
+
.KEEP_STATE:
all: $(LIBS)
-
include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libdladm/common/libdladm.c b/usr/src/lib/libdladm/common/libdladm.c
index 5d51590058..ce85b67a92 100644
--- a/usr/src/lib/libdladm/common/libdladm.c
+++ b/usr/src/lib/libdladm/common/libdladm.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Joyent, Inc.
*/
/*
@@ -37,6 +38,9 @@
#include <strings.h>
#include <dirent.h>
#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdarg.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/param.h>
@@ -440,6 +444,9 @@ dladm_status2str(dladm_status_t status, char *buf)
case DLADM_STATUS_PERSIST_ON_TEMP:
s = "can't create persistent object on top of temporary object";
break;
+ case DLADM_STATUS_BAD_ENCAP:
+ s = "invalid encapsulation protocol";
+ break;
default:
s = "<unknown error>";
break;
@@ -672,6 +679,9 @@ dladm_class2str(datalink_class_t class, char *buf)
case DATALINK_CLASS_PART:
s = "part";
break;
+ case DATALINK_CLASS_OVERLAY:
+ s = "overlay";
+ break;
default:
s = "unknown";
break;
@@ -1157,15 +1167,15 @@ dladm_strs2range(char **prop_val, uint_t val_cnt, mac_propval_type_t type,
* Convert a mac_propval_range_t structure into an array of elements.
*/
dladm_status_t
-dladm_range2list(mac_propval_range_t *rangep, void *elem, uint_t *nelem)
+dladm_range2list(const mac_propval_range_t *rangep, void *elem, uint_t *nelem)
{
int i, j, k;
dladm_status_t status = DLADM_STATUS_OK;
switch (rangep->mpr_type) {
case MAC_PROPVAL_UINT32: {
- mac_propval_uint32_range_t *ur;
- uint32_t *elem32 = elem;
+ const mac_propval_uint32_range_t *ur;
+ uint32_t *elem32 = elem;
k = 0;
ur = &rangep->mpr_range_uint32[0];
@@ -1193,13 +1203,13 @@ dladm_range2list(mac_propval_range_t *rangep, void *elem, uint_t *nelem)
* of single elements or ranges.
*/
int
-dladm_range2strs(mac_propval_range_t *rangep, char **prop_val)
+dladm_range2strs(const mac_propval_range_t *rangep, char **prop_val)
{
int i;
switch (rangep->mpr_type) {
case MAC_PROPVAL_UINT32: {
- mac_propval_uint32_range_t *ur;
+ const mac_propval_uint32_range_t *ur;
/* Write ranges and individual elements */
ur = &rangep->mpr_range_uint32[0];
@@ -1216,6 +1226,20 @@ dladm_range2strs(mac_propval_range_t *rangep, char **prop_val)
}
return (0);
}
+ case MAC_PROPVAL_STR: {
+ const mac_propval_str_range_t *str;
+ size_t coff, len;
+
+ coff = 0;
+ str = &rangep->u.mpr_str;
+ for (i = 0; i < rangep->mpr_count; i++) {
+ len = strlen(&str->mpur_data[coff]);
+ (void) strlcpy(prop_val[i], &str->mpur_data[coff],
+ DLADM_PROP_VAL_MAX);
+ coff += len + 1;
+ }
+ return (0);
+ }
default:
break;
}
@@ -1293,3 +1317,54 @@ dladm_list2range(void *elem, uint_t nelem, mac_propval_type_t type,
return (status);
}
+
+void
+dladm_errlist_init(dladm_errlist_t *erl)
+{
+ bzero(erl, sizeof (dladm_errlist_t));
+}
+
+void
+dladm_errlist_reset(dladm_errlist_t *erl)
+{
+ uint_t i;
+
+ for (i = 0; i < erl->el_count; i++)
+ free(erl->el_errs[i]);
+ free(erl->el_errs);
+ dladm_errlist_init(erl);
+}
+
+dladm_status_t
+dladm_errlist_append(dladm_errlist_t *erl, const char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+ char *m = NULL;
+
+ if (erl->el_count == erl->el_alloc) {
+ int alloc;
+ void *addr;
+ if (erl->el_alloc == 0) {
+ assert(erl->el_errs == NULL);
+ alloc = 32;
+ } else {
+ alloc = erl->el_alloc + 32;
+ }
+ addr = realloc(erl->el_errs, sizeof (char *) * alloc);
+ if (addr == NULL)
+ return (DLADM_STATUS_NOMEM);
+
+ erl->el_errs = addr;
+ erl->el_alloc = alloc;
+ }
+
+ va_start(ap, fmt);
+ ret = vasprintf(&m, fmt, ap);
+ va_end(ap);
+ if (ret == -1)
+ return (dladm_errno2status(errno));
+ erl->el_errs[erl->el_count] = m;
+ erl->el_count++;
+ return (DLADM_STATUS_OK);
+}
diff --git a/usr/src/lib/libdladm/common/libdladm.h b/usr/src/lib/libdladm/common/libdladm.h
index 350c9c50f3..5a97bacaa0 100644
--- a/usr/src/lib/libdladm/common/libdladm.h
+++ b/usr/src/lib/libdladm/common/libdladm.h
@@ -23,6 +23,7 @@
*/
/*
+ * Copyright 2015, Joyent, Inc.
* Copyright 2020 OmniOS Community Edition (OmniOSce) Association
*/
@@ -179,7 +180,8 @@ typedef enum {
DLADM_STATUS_INVALID_PKEY_TBL_SIZE,
DLADM_STATUS_PORT_NOPROTO,
DLADM_STATUS_INVALID_MTU,
- DLADM_STATUS_PERSIST_ON_TEMP
+ DLADM_STATUS_PERSIST_ON_TEMP,
+ DLADM_STATUS_BAD_ENCAP
} dladm_status_t;
typedef enum {
@@ -233,6 +235,12 @@ typedef struct dladm_arg_list {
char *al_buf;
} dladm_arg_list_t;
+typedef struct dladm_errlist {
+ uint_t el_count;
+ uint_t el_alloc;
+ char **el_errs;
+} dladm_errlist_t;
+
typedef enum {
DLADM_LOGTYPE_LINK = 1,
DLADM_LOGTYPE_FLOW
@@ -294,12 +302,15 @@ extern dladm_status_t dladm_zone_halt(dladm_handle_t, zoneid_t);
extern dladm_status_t dladm_strs2range(char **, uint_t, mac_propval_type_t,
mac_propval_range_t **);
-extern dladm_status_t dladm_range2list(mac_propval_range_t *, void*,
+extern dladm_status_t dladm_range2list(const mac_propval_range_t *, void *,
uint_t *);
-extern int dladm_range2strs(mac_propval_range_t *, char **);
+extern int dladm_range2strs(const mac_propval_range_t *, char **);
extern dladm_status_t dladm_list2range(void *, uint_t, mac_propval_type_t,
mac_propval_range_t **);
+extern void dladm_errlist_init(dladm_errlist_t *);
+extern void dladm_errlist_reset(dladm_errlist_t *);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libdladm/common/libdladm_impl.h b/usr/src/lib/libdladm/common/libdladm_impl.h
index 20db1cb1d7..9cd91d56c1 100644
--- a/usr/src/lib/libdladm/common/libdladm_impl.h
+++ b/usr/src/lib/libdladm/common/libdladm_impl.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent, Inc.
*/
/*
@@ -173,6 +174,12 @@ typedef struct resource_prop_s {
*/
#define FBRIDGE "bridge" /* string */
+/*
+ * For error lists
+ */
+extern dladm_status_t dladm_errlist_append(dladm_errlist_t *,
+ const char *, ...);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libdladm/common/libdloverlay.c b/usr/src/lib/libdladm/common/libdloverlay.c
new file mode 100644
index 0000000000..a25be3d201
--- /dev/null
+++ b/usr/src/lib/libdladm/common/libdloverlay.c
@@ -0,0 +1,885 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2015 Joyent, Inc.
+ */
+
+#include <libdladm_impl.h>
+#include <libdllink.h>
+#include <libdloverlay.h>
+#include <sys/dld.h>
+#include <sys/overlay.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <limits.h>
+#include <libvarpd_client.h>
+
+#define VARPD_PROPERTY_NAME "varpd/id"
+
+static const char *dladm_overlay_doorpath = "/var/run/varpd/varpd.door";
+
+typedef struct dladm_overlay_propinfo {
+ boolean_t dop_isvarpd;
+ union {
+ overlay_ioc_propinfo_t *dop_overlay;
+ varpd_client_prop_handle_t *dop_varpd;
+ } dop_un;
+} dladm_overlay_propinfo_t;
+
+dladm_status_t
+dladm_overlay_prop_info(dladm_overlay_propinfo_handle_t phdl,
+ const char **namep, uint_t *typep, uint_t *protp, const void **defp,
+ uint32_t *sizep, const mac_propval_range_t **possp)
+{
+ dladm_overlay_propinfo_t *infop = (dladm_overlay_propinfo_t *)phdl;
+ overlay_ioc_propinfo_t *oinfop = infop->dop_un.dop_overlay;
+
+ if (infop->dop_isvarpd == B_FALSE) {
+ if (namep != NULL)
+ *namep = oinfop->oipi_name;
+ if (typep != NULL)
+ *typep = oinfop->oipi_type;
+ if (protp != NULL)
+ *protp = oinfop->oipi_prot;
+ if (defp != NULL)
+ *defp = oinfop->oipi_default;
+ if (sizep != NULL)
+ *sizep = oinfop->oipi_defsize;
+ if (possp != NULL) {
+ *possp = (const mac_propval_range_t *)oinfop->oipi_poss;
+ }
+
+ } else {
+ int ret;
+ ret = libvarpd_c_prop_info(infop->dop_un.dop_varpd, namep,
+ typep, protp, defp, sizep, possp);
+ if (ret != 0)
+ return (dladm_errno2status(ret));
+
+ }
+
+ return (DLADM_STATUS_OK);
+}
+
+static dladm_status_t
+dladm_overlay_parse_prop(overlay_prop_type_t type, void *buf, uint32_t *sizep,
+ const char *val)
+{
+ int ret;
+ int64_t ival;
+ uint64_t uval;
+ char *eptr;
+ struct in6_addr ipv6;
+ struct in_addr ip;
+
+ switch (type) {
+ case OVERLAY_PROP_T_INT:
+ errno = 0;
+ ival = strtol(val, &eptr, 10);
+ if ((ival == 0 && errno == EINVAL) ||
+ ((ival == LONG_MAX || ival == LONG_MIN) &&
+ errno == ERANGE))
+ return (DLADM_STATUS_BADARG);
+ bcopy(&ival, buf, sizeof (int64_t));
+ *sizep = sizeof (int64_t);
+ break;
+ case OVERLAY_PROP_T_UINT:
+ errno = 0;
+ uval = strtol(val, &eptr, 10);
+ if ((uval == 0 && errno == EINVAL) ||
+ (uval == ULONG_MAX && errno == ERANGE))
+ return (DLADM_STATUS_BADARG);
+ bcopy(&uval, buf, sizeof (uint64_t));
+ *sizep = sizeof (uint64_t);
+ break;
+ case OVERLAY_PROP_T_STRING:
+ ret = strlcpy((char *)buf, val, OVERLAY_PROP_SIZEMAX);
+ if (ret >= OVERLAY_PROP_SIZEMAX)
+ return (DLADM_STATUS_BADARG);
+ *sizep = ret + 1;
+ break;
+ case OVERLAY_PROP_T_IP:
+ /*
+ * Always try to parse the IP as an IPv6 address. If that fails,
+ * try to interpret it as an IPv4 address and transform it into
+ * an IPv6 mapped IPv4 address.
+ */
+ if (inet_pton(AF_INET6, val, &ipv6) != 1) {
+ if (inet_pton(AF_INET, val, &ip) != 1)
+ return (DLADM_STATUS_BADARG);
+
+ IN6_INADDR_TO_V4MAPPED(&ip, &ipv6);
+ }
+ bcopy(&ipv6, buf, sizeof (struct in6_addr));
+ *sizep = sizeof (struct in6_addr);
+ break;
+ default:
+ abort();
+ }
+
+ return (DLADM_STATUS_OK);
+}
+
+/* ARGSUSED */
+static dladm_status_t
+dladm_overlay_varpd_setprop(dladm_handle_t handle, varpd_client_handle_t *chdl,
+ uint64_t inst, const char *name, char *const *valp, uint_t cnt)
+{
+ int ret;
+ uint32_t size;
+ uint8_t buf[LIBVARPD_PROP_SIZEMAX];
+ varpd_client_prop_handle_t *phdl;
+ uint_t type;
+ dladm_status_t status;
+
+ if ((ret = libvarpd_c_prop_handle_alloc(chdl, inst, &phdl)) != 0)
+ return (dladm_errno2status(ret));
+
+ if ((ret = libvarpd_c_prop_info_fill_by_name(phdl, name)) != 0) {
+ libvarpd_c_prop_handle_free(phdl);
+ return (dladm_errno2status(ret));
+ }
+
+ if ((ret = libvarpd_c_prop_info(phdl, NULL, &type, NULL, NULL, NULL,
+ NULL)) != 0) {
+ libvarpd_c_prop_handle_free(phdl);
+ return (dladm_errno2status(ret));
+ }
+
+ if ((status = dladm_overlay_parse_prop(type, buf, &size, valp[0])) !=
+ DLADM_STATUS_OK) {
+ libvarpd_c_prop_handle_free(phdl);
+ return (status);
+ }
+
+ ret = libvarpd_c_prop_set(phdl, buf, size);
+ libvarpd_c_prop_handle_free(phdl);
+
+ return (dladm_errno2status(ret));
+}
+
+dladm_status_t
+dladm_overlay_setprop(dladm_handle_t handle, datalink_id_t linkid,
+ const char *name, char *const *valp, uint_t cnt)
+{
+ int ret;
+ dladm_status_t status;
+ overlay_ioc_propinfo_t info;
+ overlay_ioc_prop_t prop;
+
+ if (linkid == DATALINK_INVALID_LINKID ||
+ name == NULL || valp == NULL || cnt != 1)
+ return (DLADM_STATUS_BADARG);
+
+ bzero(&info, sizeof (overlay_ioc_propinfo_t));
+ info.oipi_linkid = linkid;
+ info.oipi_id = -1;
+ if (strlcpy(info.oipi_name, name, OVERLAY_PROP_NAMELEN) >=
+ OVERLAY_PROP_NAMELEN)
+ return (DLADM_STATUS_BADARG);
+
+ status = DLADM_STATUS_OK;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_PROPINFO, &info);
+ if (ret != 0)
+ status = dladm_errno2status(errno);
+
+ if (status != DLADM_STATUS_OK)
+ return (status);
+
+ prop.oip_linkid = linkid;
+ prop.oip_id = info.oipi_id;
+ prop.oip_name[0] = '\0';
+ if ((ret = dladm_overlay_parse_prop(info.oipi_type, prop.oip_value,
+ &prop.oip_size, valp[0])) != DLADM_STATUS_OK)
+ return (ret);
+
+ status = DLADM_STATUS_OK;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_SETPROP, &prop);
+ if (ret != 0)
+ status = dladm_errno2status(errno);
+
+ return (ret);
+}
+
+/*
+ * Tell the user about any unset required properties.
+ */
+static int
+dladm_overlay_activate_cb(dladm_handle_t handle, datalink_id_t linkid,
+ dladm_overlay_propinfo_handle_t phdl, void *arg)
+{
+ dladm_status_t status;
+ uint8_t buf[DLADM_OVERLAY_PROP_SIZEMAX];
+ uint_t prot;
+ size_t size = sizeof (buf);
+ const char *name;
+ dladm_errlist_t *errs = arg;
+
+ if ((status = dladm_overlay_prop_info(phdl, &name, NULL, &prot, NULL,
+ NULL, NULL)) != DLADM_STATUS_OK)
+ return (status);
+
+ if ((prot & OVERLAY_PROP_PERM_REQ) == 0)
+ return (DLADM_WALK_CONTINUE);
+
+ if (dladm_overlay_get_prop(handle, linkid, phdl, buf, &size) !=
+ DLADM_STATUS_OK)
+ return (DLADM_WALK_CONTINUE);
+
+ if (size == 0)
+ (void) dladm_errlist_append(errs, "unset required property: %s",
+ name);
+
+ return (DLADM_WALK_CONTINUE);
+}
+
+/*
+ * We need to clean up the world here. The problem is that we may or may not
+ * actually have everything created. While in the normal case, we'd always have
+ * an overlay device, assigned datalink id, and a varpd instance, we might not
+ * have any of those, except for the datalink instance. Therefore, as long as
+ * the id refers to a valid overlay, we should try to clean up as much of the
+ * state as possible and most importantly, we need to make sure we delete the
+ * datalink id. If we fail to do that, then that name will become lost to time.
+ */
+dladm_status_t
+dladm_overlay_delete(dladm_handle_t handle, datalink_id_t linkid)
+{
+ datalink_class_t class;
+ overlay_ioc_delete_t oid;
+ varpd_client_handle_t *chdl;
+ int ret;
+ uint32_t flags;
+ uint64_t varpdid;
+
+ if (dladm_datalink_id2info(handle, linkid, &flags, &class, NULL,
+ NULL, 0) != DLADM_STATUS_OK)
+ return (DLADM_STATUS_BADARG);
+
+ if (class != DATALINK_CLASS_OVERLAY)
+ return (DLADM_STATUS_BADARG);
+
+ oid.oid_linkid = linkid;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_DELETE, &oid);
+ if (ret != 0 && errno != ENOENT) {
+ return (dladm_errno2status(errno));
+ }
+
+ if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) {
+ return (dladm_errno2status(ret));
+ }
+
+ if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
+ if (ret == ENOENT) {
+ goto finish;
+ }
+ (void) libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ ret = libvarpd_c_instance_destroy(chdl, varpdid);
+finish:
+ (void) libvarpd_c_destroy(chdl);
+ (void) dladm_destroy_datalink_id(handle, linkid, flags);
+
+ return (dladm_errno2status(ret));
+}
+
+dladm_status_t
+dladm_overlay_get_prop(dladm_handle_t handle, datalink_id_t linkid,
+ dladm_overlay_propinfo_handle_t infohdl, void *buf, size_t *sizep)
+{
+ int ret;
+ overlay_ioc_prop_t oip;
+ dladm_overlay_propinfo_t *infop = (dladm_overlay_propinfo_t *)infohdl;
+
+ /*
+ * It'd be nice if we had a better or more specific error for this. If
+ * this kind of error becomes common place, let's get a better dladm
+ * error.
+ */
+ if (*sizep < DLADM_OVERLAY_PROP_SIZEMAX)
+ return (dladm_errno2status(ERANGE));
+
+ if (infop->dop_isvarpd == B_FALSE) {
+ bzero(&oip, sizeof (overlay_ioc_prop_t));
+ oip.oip_linkid = linkid;
+ oip.oip_id = infop->dop_un.dop_overlay->oipi_id;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_GETPROP, &oip);
+ if (ret != 0)
+ return (dladm_errno2status(errno));
+ bcopy(oip.oip_value, buf, DLADM_OVERLAY_PROP_SIZEMAX);
+ *sizep = oip.oip_size;
+ } else {
+ uint32_t size = *sizep;
+
+ ret = libvarpd_c_prop_get(infop->dop_un.dop_varpd, buf, &size);
+ if (ret != 0)
+ return (dladm_errno2status(errno));
+ *sizep = size;
+ }
+
+ return (DLADM_STATUS_OK);
+}
+
+static dladm_status_t
+dladm_overlay_walk_varpd_prop(dladm_handle_t handle, datalink_id_t linkid,
+ uint64_t varpdid, dladm_overlay_prop_f func, void *arg)
+{
+ int ret, i;
+ varpd_client_handle_t *chdl;
+ varpd_client_prop_handle_t *phdl;
+ uint_t nprops;
+ dladm_status_t status;
+
+ if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
+ return (dladm_errno2status(ret));
+
+ if ((ret = libvarpd_c_prop_handle_alloc(chdl, varpdid, &phdl)) != 0) {
+ (void) libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ if ((ret = libvarpd_c_prop_nprops(chdl, varpdid, &nprops)) != 0) {
+ libvarpd_c_prop_handle_free(phdl);
+ (void) libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ status = DLADM_STATUS_OK;
+ for (i = 0; i < nprops; i++) {
+ dladm_overlay_propinfo_t dop;
+
+ bzero(&dop, sizeof (dop));
+ dop.dop_isvarpd = B_TRUE;
+ dop.dop_un.dop_varpd = phdl;
+
+ if ((ret = libvarpd_c_prop_info_fill(phdl, i)) != 0) {
+ status = dladm_errno2status(ret);
+ break;
+ }
+
+ ret = func(handle, linkid,
+ (dladm_overlay_propinfo_handle_t)&dop, arg);
+ if (ret == DLADM_WALK_TERMINATE)
+ break;
+ }
+
+ libvarpd_c_prop_handle_free(phdl);
+ libvarpd_c_destroy(chdl);
+
+ return (status);
+}
+
+dladm_status_t
+dladm_overlay_walk_prop(dladm_handle_t handle, datalink_id_t linkid,
+ dladm_overlay_prop_f func, void *arg, dladm_errlist_t *errs)
+{
+ int i, ret;
+ datalink_class_t class;
+ overlay_ioc_nprops_t oin;
+ overlay_ioc_propinfo_t oipi;
+ dladm_overlay_propinfo_t dop;
+ uint64_t varpdid = UINT64_MAX;
+
+ if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
+ NULL, 0) != DLADM_STATUS_OK)
+ return (DLADM_STATUS_BADARG);
+
+ if (class != DATALINK_CLASS_OVERLAY)
+ return (DLADM_STATUS_BADARG);
+
+ bzero(&oin, sizeof (overlay_ioc_nprops_t));
+ oin.oipn_linkid = linkid;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_NPROPS, &oin);
+ if (ret != 0)
+ return (dladm_errno2status(errno));
+
+ for (i = 0; i < oin.oipn_nprops; i++) {
+ bzero(&dop, sizeof (dladm_overlay_propinfo_t));
+ bzero(&oipi, sizeof (overlay_ioc_propinfo_t));
+ oipi.oipi_linkid = linkid;
+ oipi.oipi_id = i;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_PROPINFO, &oipi);
+ if (ret != 0) {
+ (void) dladm_errlist_append(errs, "failed to get "
+ "propinfo for property %d: %s", i, strerror(errno));
+ return (dladm_errno2status(errno));
+ }
+
+ dop.dop_isvarpd = B_FALSE;
+ dop.dop_un.dop_overlay = &oipi;
+ ret = func(handle, linkid,
+ (dladm_overlay_propinfo_handle_t)&dop, arg);
+ if (ret == DLADM_WALK_TERMINATE)
+ break;
+
+ if (strcmp(oipi.oipi_name, VARPD_PROPERTY_NAME) == 0) {
+ uint8_t buf[DLADM_OVERLAY_PROP_SIZEMAX];
+ size_t bufsize = sizeof (buf);
+ uint64_t *vp;
+
+ if (dladm_overlay_get_prop(handle, linkid,
+ (dladm_overlay_propinfo_handle_t)&dop, buf,
+ &bufsize) != DLADM_STATUS_OK)
+ continue;
+
+ vp = (uint64_t *)buf;
+ varpdid = *vp;
+ }
+ }
+
+ /* Should this really be possible? */
+ if (varpdid == UINT64_MAX)
+ return (DLADM_STATUS_OK);
+
+ return (dladm_overlay_walk_varpd_prop(handle, linkid, varpdid, func,
+ arg));
+}
+
+dladm_status_t
+dladm_overlay_create(dladm_handle_t handle, const char *name,
+ const char *encap, const char *search, uint64_t vid,
+ dladm_arg_list_t *props, dladm_errlist_t *errs, uint32_t flags)
+{
+ int ret, i;
+ dladm_status_t status;
+ datalink_id_t linkid;
+ overlay_ioc_create_t oic;
+ overlay_ioc_activate_t oia;
+ size_t slen;
+ varpd_client_handle_t *vch;
+ uint64_t id;
+
+ status = dladm_create_datalink_id(handle, name, DATALINK_CLASS_OVERLAY,
+ DL_ETHER, flags, &linkid);
+ if (status != DLADM_STATUS_OK)
+ return (status);
+
+ bzero(&oic, sizeof (oic));
+ oic.oic_linkid = linkid;
+ oic.oic_vnetid = vid;
+ (void) strlcpy(oic.oic_encap, encap, MAXLINKNAMELEN);
+
+ status = DLADM_STATUS_OK;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_CREATE, &oic);
+ if (ret != 0) {
+ /*
+ * It'd be nice if we had private errors so we could better
+ * distinguish between different classes of errors.
+ */
+ status = dladm_errno2status(errno);
+ }
+
+ if (status != DLADM_STATUS_OK) {
+ (void) dladm_destroy_datalink_id(handle, linkid, flags);
+ return (status);
+ }
+
+ slen = strlen(search);
+ for (i = 0; props != NULL && i < props->al_count; i++) {
+ dladm_arg_info_t *aip = &props->al_info[i];
+
+ /*
+ * If it's a property for the search plugin, eg. it has the
+ * prefix '<search>/', then we don't set the property on the
+ * overlay device and instead set it on the varpd instance.
+ */
+ if (strncmp(aip->ai_name, search, slen) == 0 &&
+ aip->ai_name[slen] == '/')
+ continue;
+ status = dladm_overlay_setprop(handle, linkid, aip->ai_name,
+ aip->ai_val, aip->ai_count);
+ if (status != DLADM_STATUS_OK) {
+ (void) dladm_errlist_append(errs,
+ "failed to set property %s",
+ aip->ai_name);
+ (void) dladm_overlay_delete(handle, linkid);
+ return (status);
+ }
+ }
+
+ if ((ret = libvarpd_c_create(&vch, dladm_overlay_doorpath)) != 0) {
+ (void) dladm_errlist_append(errs,
+ "failed to create libvarpd handle: %s", strerror(ret));
+ (void) dladm_overlay_delete(handle, linkid);
+ return (dladm_errno2status(ret));
+ }
+
+ if ((ret = libvarpd_c_instance_create(vch, linkid, search,
+ &id)) != 0) {
+ (void) dladm_errlist_append(errs,
+ "failed to create varpd instance: %s", strerror(ret));
+ libvarpd_c_destroy(vch);
+ (void) dladm_overlay_delete(handle, linkid);
+ return (dladm_errno2status(ret));
+ }
+
+ for (i = 0; props != NULL && i < props->al_count; i++) {
+ dladm_arg_info_t *aip = &props->al_info[i];
+
+ /*
+ * Skip arguments we've processed already.
+ */
+ if (strncmp(aip->ai_name, search, slen) != 0)
+ continue;
+
+ if (aip->ai_name[slen] != '/')
+ continue;
+
+ ret = dladm_overlay_varpd_setprop(handle, vch, id, aip->ai_name,
+ aip->ai_val, aip->ai_count);
+ if (ret != 0) {
+ (void) dladm_errlist_append(errs,
+ "failed to set varpd prop: %s\n",
+ aip->ai_name);
+ (void) libvarpd_c_instance_destroy(vch, id);
+ libvarpd_c_destroy(vch);
+ (void) dladm_overlay_delete(handle, linkid);
+ return (dladm_errno2status(ret));
+ }
+ }
+
+ if ((ret = libvarpd_c_instance_activate(vch, id)) != 0) {
+ (void) dladm_errlist_append(errs,
+ "failed to activate varpd instance: %s", strerror(ret));
+ (void) dladm_overlay_walk_varpd_prop(handle, linkid, id,
+ dladm_overlay_activate_cb, errs);
+ (void) libvarpd_c_instance_destroy(vch, id);
+ libvarpd_c_destroy(vch);
+ (void) dladm_overlay_delete(handle, linkid);
+ return (dladm_errno2status(ret));
+
+ }
+
+ bzero(&oia, sizeof (oia));
+ oia.oia_linkid = linkid;
+ status = DLADM_STATUS_OK;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_ACTIVATE, &oia);
+ if (ret != 0) {
+ ret = errno;
+ (void) dladm_errlist_append(errs, "failed to activate "
+ "device: %s", strerror(ret));
+ (void) libvarpd_c_instance_destroy(vch, id);
+ (void) dladm_overlay_walk_prop(handle, linkid,
+ dladm_overlay_activate_cb, errs, errs);
+ status = dladm_errno2status(ret);
+ (void) libvarpd_c_instance_destroy(vch, id);
+ }
+
+ libvarpd_c_destroy(vch);
+ if (status != DLADM_STATUS_OK)
+ (void) dladm_overlay_delete(handle, linkid);
+
+ return (status);
+}
+
+
+
+typedef struct overlay_walk_cb {
+ dladm_handle_t owc_handle;
+ datalink_id_t owc_linkid;
+ void *owc_arg;
+ dladm_overlay_cache_f owc_func;
+ uint_t owc_mode;
+ uint_t owc_dest;
+} overlay_walk_cb_t;
+
+/* ARGSUSED */
+static int
+dladm_overlay_walk_cache_cb(varpd_client_handle_t *chdl, uint64_t varpdid,
+ const struct ether_addr *key, const varpd_client_cache_entry_t *entry,
+ void *arg)
+{
+ overlay_walk_cb_t *owc = arg;
+ dladm_overlay_point_t point;
+
+ bzero(&point, sizeof (dladm_overlay_point_t));
+ point.dop_dest = owc->owc_dest;
+ point.dop_mac = entry->vcp_mac;
+ point.dop_flags = entry->vcp_flags;
+ point.dop_ip = entry->vcp_ip;
+ point.dop_port = entry->vcp_port;
+
+ if (owc->owc_mode == OVERLAY_TARGET_POINT)
+ point.dop_flags |= DLADM_OVERLAY_F_DEFAULT;
+
+ if (owc->owc_func(owc->owc_handle, owc->owc_linkid, key, &point,
+ owc->owc_arg) == DLADM_WALK_TERMINATE)
+ return (1);
+ return (0);
+}
+
+dladm_status_t
+dladm_overlay_walk_cache(dladm_handle_t handle, datalink_id_t linkid,
+ dladm_overlay_cache_f func, void *arg)
+{
+ int ret;
+ uint_t mode, dest;
+ uint64_t varpdid;
+ varpd_client_handle_t *chdl;
+ overlay_walk_cb_t cbarg;
+
+ if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
+ return (dladm_errno2status(ret));
+
+ if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid,
+ &dest, &mode)) != 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ cbarg.owc_handle = handle;
+ cbarg.owc_linkid = linkid;
+ cbarg.owc_arg = arg;
+ cbarg.owc_func = func;
+ cbarg.owc_dest = dest;
+ cbarg.owc_mode = mode;
+ ret = libvarpd_c_instance_cache_walk(chdl, varpdid,
+ dladm_overlay_walk_cache_cb, &cbarg);
+ libvarpd_c_destroy(chdl);
+
+ return (dladm_errno2status(ret));
+}
+
+/* ARGSUSED */
+dladm_status_t
+dladm_overlay_cache_flush(dladm_handle_t handle, datalink_id_t linkid)
+{
+ int ret;
+ uint64_t varpdid;
+ varpd_client_handle_t *chdl;
+
+ if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
+ return (dladm_errno2status(ret));
+
+ if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ ret = libvarpd_c_instance_cache_flush(chdl, varpdid);
+ libvarpd_c_destroy(chdl);
+
+ return (dladm_errno2status(ret));
+}
+
+/* ARGSUSED */
+dladm_status_t
+dladm_overlay_cache_delete(dladm_handle_t handle, datalink_id_t linkid,
+ const struct ether_addr *key)
+{
+ int ret;
+ uint64_t varpdid;
+ varpd_client_handle_t *chdl;
+
+ if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
+ return (dladm_errno2status(ret));
+
+ if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ ret = libvarpd_c_instance_cache_delete(chdl, varpdid, key);
+ libvarpd_c_destroy(chdl);
+
+ return (dladm_errno2status(ret));
+}
+
+/* ARGSUSED */
+dladm_status_t
+dladm_overlay_cache_set(dladm_handle_t handle, datalink_id_t linkid,
+ const struct ether_addr *key, char *val)
+{
+ int ret;
+ uint_t dest;
+ uint64_t varpdid;
+ char *ip, *port = NULL;
+ varpd_client_handle_t *chdl;
+ varpd_client_cache_entry_t vcp;
+
+
+ if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
+ return (dladm_errno2status(ret));
+
+ if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid,
+ &dest, NULL)) != 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ /*
+ * Mode tells us what we should expect in val. It we have more than one
+ * thing listed, the canonical format of it right now is mac,ip:port.
+ */
+ bzero(&vcp, sizeof (varpd_client_cache_entry_t));
+
+ if (strcasecmp(val, "drop") == 0) {
+ vcp.vcp_flags = OVERLAY_TARGET_CACHE_DROP;
+ goto send;
+ }
+
+ if (dest & OVERLAY_PLUGIN_D_ETHERNET) {
+ if (ether_aton_r(val, &vcp.vcp_mac) == NULL) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(EINVAL));
+ }
+ }
+
+ if (dest & OVERLAY_PLUGIN_D_IP) {
+ if (dest & OVERLAY_PLUGIN_D_ETHERNET) {
+ if ((ip = strchr(val, ',')) == NULL) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+ ip++;
+ } else {
+ ip = val;
+ }
+
+ if (dest & OVERLAY_PLUGIN_D_PORT) {
+ if ((port = strchr(val, ':')) == NULL) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+ *port = '\0';
+ port++;
+ }
+
+ /* Try v6, then fall back to v4 */
+ ret = inet_pton(AF_INET6, ip, &vcp.vcp_ip);
+ if (ret == -1)
+ abort();
+ if (ret == 0) {
+ struct in_addr v4;
+
+ ret = inet_pton(AF_INET, ip, &v4);
+ if (ret == -1)
+ abort();
+ if (ret == 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+ IN6_INADDR_TO_V4MAPPED(&v4, &vcp.vcp_ip);
+ }
+ }
+
+ if (dest & OVERLAY_PLUGIN_D_PORT) {
+ char *eptr;
+ unsigned long l;
+ if (port == NULL && (dest & OVERLAY_PLUGIN_D_ETHERNET)) {
+ if ((port = strchr(val, ',')) == NULL) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(EINVAL));
+ }
+ } else if (port == NULL)
+ port = val;
+
+ errno = 0;
+ l = strtoul(port, &eptr, 10);
+ if (errno != 0 || *eptr != '\0') {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(EINVAL));
+ }
+ if (l == 0 || l > UINT16_MAX) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(EINVAL));
+ }
+ vcp.vcp_port = l;
+ }
+
+send:
+ ret = libvarpd_c_instance_cache_set(chdl, varpdid, key, &vcp);
+
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+}
+
+/* ARGSUSED */
+dladm_status_t
+dladm_overlay_cache_get(dladm_handle_t handle, datalink_id_t linkid,
+ const struct ether_addr *key, dladm_overlay_point_t *point)
+{
+ int ret;
+ uint_t dest, mode;
+ uint64_t varpdid;
+ varpd_client_handle_t *chdl;
+ varpd_client_cache_entry_t entry;
+
+ if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
+ return (dladm_errno2status(ret));
+
+ if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid,
+ &dest, &mode)) != 0) {
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+ }
+
+ ret = libvarpd_c_instance_cache_get(chdl, varpdid, key, &entry);
+ if (ret == 0) {
+ point->dop_dest = dest;
+ point->dop_mac = entry.vcp_mac;
+ point->dop_flags = entry.vcp_flags;
+ point->dop_ip = entry.vcp_ip;
+ point->dop_port = entry.vcp_port;
+ if (mode == OVERLAY_TARGET_POINT)
+ point->dop_flags |= DLADM_OVERLAY_F_DEFAULT;
+ }
+
+ libvarpd_c_destroy(chdl);
+ return (dladm_errno2status(ret));
+}
+
+dladm_status_t
+dladm_overlay_status(dladm_handle_t handle, datalink_id_t linkid,
+ dladm_overlay_status_f func, void *arg)
+{
+ int ret;
+ dladm_status_t status;
+ overlay_ioc_status_t ois;
+ dladm_overlay_status_t dos;
+
+ ois.ois_linkid = linkid;
+ status = DLADM_STATUS_OK;
+ ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_STATUS, &ois);
+ if (ret != 0)
+ status = dladm_errno2status(errno);
+ if (status != DLADM_STATUS_OK)
+ return (status);
+
+ dos.dos_degraded = ois.ois_status == OVERLAY_I_DEGRADED ? B_TRUE :
+ B_FALSE;
+ (void) strlcpy(dos.dos_fmamsg, ois.ois_message,
+ sizeof (dos.dos_fmamsg));
+ func(handle, linkid, &dos, arg);
+ return (DLADM_STATUS_OK);
+}
diff --git a/usr/src/lib/libdladm/common/libdloverlay.h b/usr/src/lib/libdladm/common/libdloverlay.h
new file mode 100644
index 0000000000..39b01ccae3
--- /dev/null
+++ b/usr/src/lib/libdladm/common/libdloverlay.h
@@ -0,0 +1,107 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2015 Joyent, Inc.
+ */
+
+#ifndef _LIBDLOVERLAY_H
+#define _LIBDLOVERLAY_H
+
+/*
+ * libdladm Overlay device routines
+ */
+
+#include <libdladm.h>
+#include <libdladm_impl.h>
+#include <sys/overlay.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DLADM_OVERLAY_F_DROP 0x0001
+#define DLADM_OVERLAY_F_DEFAULT 0xf000
+
+typedef struct dladm_overlay_point {
+ uint_t dop_dest;
+ struct ether_addr dop_mac;
+ uint16_t dop_flags;
+ struct in6_addr dop_ip;
+ uint16_t dop_port;
+} dladm_overlay_point_t;
+
+typedef struct dladm_overlay_status {
+ boolean_t dos_degraded;
+ char dos_fmamsg[256];
+} dladm_overlay_status_t;
+
+extern dladm_status_t dladm_overlay_create(dladm_handle_t, const char *,
+ const char *, const char *, uint64_t, dladm_arg_list_t *, dladm_errlist_t *,
+ uint32_t);
+extern dladm_status_t dladm_overlay_delete(dladm_handle_t, datalink_id_t);
+
+typedef void (*dladm_overlay_status_f)(dladm_handle_t, datalink_id_t,
+ dladm_overlay_status_t *, void *);
+extern dladm_status_t dladm_overlay_status(dladm_handle_t, datalink_id_t,
+ dladm_overlay_status_f, void *);
+
+extern dladm_status_t dladm_overlay_cache_flush(dladm_handle_t, datalink_id_t);
+extern dladm_status_t dladm_overlay_cache_delete(dladm_handle_t, datalink_id_t,
+ const struct ether_addr *);
+extern dladm_status_t dladm_overlay_cache_set(dladm_handle_t, datalink_id_t,
+ const struct ether_addr *, char *);
+extern dladm_status_t dladm_overlay_cache_get(dladm_handle_t, datalink_id_t,
+ const struct ether_addr *, dladm_overlay_point_t *);
+
+#define DLADM_OVERLAY_PROP_SIZEMAX 256
+#define DLADM_OVERLAY_PROP_NAMELEN 32
+
+typedef struct __dladm_overlay_propinfo *dladm_overlay_propinfo_handle_t;
+
+extern dladm_status_t dladm_overlay_prop_info(dladm_overlay_propinfo_handle_t,
+ const char **, uint_t *, uint_t *, const void **, uint32_t *,
+ const mac_propval_range_t **);
+extern dladm_status_t dladm_overlay_get_prop(dladm_handle_t, datalink_id_t,
+ dladm_overlay_propinfo_handle_t, void *buf, size_t *bufsize);
+
+typedef int (*dladm_overlay_prop_f)(dladm_handle_t, datalink_id_t,
+ dladm_overlay_propinfo_handle_t, void *);
+extern dladm_status_t dladm_overlay_walk_prop(dladm_handle_t, datalink_id_t,
+ dladm_overlay_prop_f, void *arg, dladm_errlist_t *);
+
+typedef int (*dladm_overlay_cache_f)(dladm_handle_t, datalink_id_t,
+ const struct ether_addr *, const dladm_overlay_point_t *, void *);
+extern dladm_status_t dladm_overlay_walk_cache(dladm_handle_t, datalink_id_t,
+ dladm_overlay_cache_f, void *);
+
+/*
+ * Some day we'll want to support being able to set properties after creation.
+ * If we do, the following strawman API might serve us well.
+ *
+ * extern dladm_status_t dladm_overlay_prop_lookup(dladm_handle_t,
+ * datalink_id_t, const char *, dladm_overlay_propinfo_handle_t *);
+ * extern void dladm_overlay_prop_handle_free(dladm_handle_t, datalink_id_t,
+ * dladm_overlay_propinfo_handle_t *);
+ * extern dladm_status_t dladm_overlay_set_prop(dladm_handle_t, datalink_id_t,
+ * dladm_propinfo_handle_t, void *buf, size_t *bufsize);
+ * extern dladm_status_t dladm_overlay_str_to_buf(dladm_handle_t, datalink_id_t,
+ * dladm_overlay_propinfo_handle_t *, const char *, void *, size_t *);
+ * extern dladm_status_t dladm_overlay_buf_to_str(dladm_handle_t, datalink_id_t,
+ * dladm_overlay_propinfo_handle_t *, const void *, const size_t, char *,
+ * size_t *);
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBDLOVERLAY_H */
diff --git a/usr/src/lib/libdladm/common/libdlvlan.c b/usr/src/lib/libdladm/common/libdlvlan.c
index 3ed060e38e..c54480cf0e 100644
--- a/usr/src/lib/libdladm/common/libdlvlan.c
+++ b/usr/src/lib/libdladm/common/libdlvlan.c
@@ -64,7 +64,7 @@ dladm_vlan_create(dladm_handle_t handle, const char *vlan, datalink_id_t linkid,
{
return (dladm_vnic_create(handle, vlan, linkid,
VNIC_MAC_ADDR_TYPE_PRIMARY, NULL, 0, NULL, 0, vid, VRRP_VRID_NONE,
- AF_UNSPEC, vlan_id_out, proplist, flags | DLADM_OPT_VLAN));
+ AF_UNSPEC, vlan_id_out, proplist, NULL, flags | DLADM_OPT_VLAN));
}
/*
diff --git a/usr/src/lib/libdladm/common/libdlvnic.c b/usr/src/lib/libdladm/common/libdlvnic.c
index bad25e69ed..73c001b744 100644
--- a/usr/src/lib/libdladm/common/libdlvnic.c
+++ b/usr/src/lib/libdladm/common/libdlvnic.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent Inc.
* Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
*/
@@ -400,7 +401,7 @@ dladm_vnic_create(dladm_handle_t handle, const char *vnic, datalink_id_t linkid,
vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, uint_t mac_len,
int *mac_slot, uint_t mac_prefix_len, uint16_t vid, vrid_t vrid,
int af, datalink_id_t *vnic_id_out, dladm_arg_list_t *proplist,
- uint32_t flags)
+ dladm_errlist_t *errs, uint32_t flags)
{
dladm_vnic_attr_t attr;
datalink_id_t vnic_id;
@@ -567,8 +568,14 @@ dladm_vnic_create(dladm_handle_t handle, const char *vnic, datalink_id_t linkid,
status = dladm_set_linkprop(handle, vnic_id,
aip->ai_name, aip->ai_val, aip->ai_count,
DLADM_OPT_PERSIST);
- if (status != DLADM_STATUS_OK)
+ if (status != DLADM_STATUS_OK) {
+ char errmsg[DLADM_STRSIZE];
+ (void) dladm_errlist_append(errs,
+ "failed to set property %s: %s",
+ aip->ai_name,
+ dladm_status2str(status, errmsg));
break;
+ }
}
}
diff --git a/usr/src/lib/libdladm/common/libdlvnic.h b/usr/src/lib/libdladm/common/libdlvnic.h
index 94b656aadf..839b2de9f2 100644
--- a/usr/src/lib/libdladm/common/libdlvnic.h
+++ b/usr/src/lib/libdladm/common/libdlvnic.h
@@ -55,7 +55,8 @@ typedef struct dladm_vnic_attr {
extern dladm_status_t dladm_vnic_create(dladm_handle_t, const char *,
datalink_id_t, vnic_mac_addr_type_t, uchar_t *,
uint_t, int *, uint_t, uint16_t, vrid_t, int,
- datalink_id_t *, dladm_arg_list_t *, uint32_t);
+ datalink_id_t *, dladm_arg_list_t *,
+ dladm_errlist_t *, uint32_t);
extern dladm_status_t dladm_vnic_delete(dladm_handle_t, datalink_id_t,
uint32_t);
diff --git a/usr/src/lib/libdladm/common/mapfile-vers b/usr/src/lib/libdladm/common/mapfile-vers
index 63a86529fc..eba6118ace 100644
--- a/usr/src/lib/libdladm/common/mapfile-vers
+++ b/usr/src/lib/libdladm/common/mapfile-vers
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2015 Joyent, Inc.
#
#
@@ -269,6 +270,23 @@ SYMBOL_VERSION SUNWprivate_1.1 {
dladm_strs2range;
dladm_range2list;
dladm_list2range;
+
+ dladm_errlist_init;
+ dladm_errlist_reset;
+ dladm_errlist_append;
+
+ dladm_overlay_create;
+ dladm_overlay_delete;
+ dladm_overlay_status;
+ dladm_overlay_prop_info;
+ dladm_overlay_get_prop;
+ dladm_overlay_walk_prop;
+
+ dladm_overlay_cache_set;
+ dladm_overlay_cache_get;
+ dladm_overlay_cache_delete;
+ dladm_overlay_cache_flush;
+ dladm_overlay_walk_cache;
local:
*;
};
diff --git a/usr/src/lib/libfakekernel/Makefile.com b/usr/src/lib/libfakekernel/Makefile.com
index 036dc5e205..18fece3bdc 100644
--- a/usr/src/lib/libfakekernel/Makefile.com
+++ b/usr/src/lib/libfakekernel/Makefile.com
@@ -61,7 +61,7 @@ CFLAGS += $(CCVERBOSE)
CPPFLAGS.first += -I../common
CPPFLAGS= $(CPPFLAGS.first)
-INCS += -I$(SRC)/uts/common
+INCS += -I$(SRC)/uts/common -I$(ROOT)/usr/include
CPPFLAGS += $(INCS) -D_REENTRANT -D_FAKE_KERNEL
CPPFLAGS += -D_FILE_OFFSET_BITS=64
diff --git a/usr/src/lib/libfakekernel/common/printf.c b/usr/src/lib/libfakekernel/common/printf.c
index 7bee92f0ca..ad492cfe28 100644
--- a/usr/src/lib/libfakekernel/common/printf.c
+++ b/usr/src/lib/libfakekernel/common/printf.c
@@ -22,7 +22,7 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright 2021 Tintri by DDN, Inc. All rights reserved.
- * Copyright 2017 RackTop Systems.
+ * Copyright 2022 RackTop Systems, Inc.
* Copyright (c) 2018, Joyent, Inc.
*/
@@ -32,10 +32,10 @@
#include <sys/systm.h>
#include <sys/cmn_err.h>
#include <sys/log.h>
+#include <upanic.h>
#include <fakekernel.h>
-void abort(void) __NORETURN;
void debug_enter(char *);
char *volatile panicstr;
@@ -133,12 +133,11 @@ vpanic(const char *fmt, va_list adx)
va_copy(tmpargs, adx);
fakekernel_cprintf(fmt, tmpargs, SL_FATAL, "fatal: ", "\n");
- /* Call libc`assfail() so that mdb ::status works */
(void) vsnprintf(panicbuf, sizeof (panicbuf), fmt, adx);
debug_enter(panicbuf);
- (void) assfail(panicbuf, "(panic)", 0);
- abort(); /* avoid "noreturn" warnings */
+ /* Call libc`upanic() so that mdb ::status works */
+ upanic(panicbuf, sizeof (panicbuf));
}
void
diff --git a/usr/src/lib/libsldap/common/ns_internal.h b/usr/src/lib/libsldap/common/ns_internal.h
index f6fb0f0bb0..86c197e528 100644
--- a/usr/src/lib/libsldap/common/ns_internal.h
+++ b/usr/src/lib/libsldap/common/ns_internal.h
@@ -59,7 +59,7 @@ extern "C" {
#define LDAPMAXHARDLOOKUPTIME 256
#define DONOTEDIT \
"Do not edit this file manually; your changes will be lost." \
- "Please use ldapclient (1M) instead."
+ "Please use ldapclient(8) instead."
#define MAXPORTNUMBER 65535
#define MAXPORTNUMBER_STR "65535"
#define CREDFILE 0
diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c
index 98a4617e08..844582b3c2 100644
--- a/usr/src/lib/libzfs/common/libzfs_pool.c
+++ b/usr/src/lib/libzfs/common/libzfs_pool.c
@@ -27,6 +27,7 @@
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
* Copyright (c) 2017 Datto Inc.
* Copyright (c) 2017, Intel Corporation.
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
*/
#include <ctype.h>
@@ -39,6 +40,7 @@
#include <strings.h>
#include <unistd.h>
#include <libgen.h>
+#include <sys/dkio.h>
#include <sys/efi_partition.h>
#include <sys/vtoc.h>
#include <sys/zfs_ioctl.h>
@@ -2797,6 +2799,7 @@ static int
zpool_relabel_disk(libzfs_handle_t *hdl, const char *name, const char *msg)
{
char path[MAXPATHLEN];
+ enum dkio_state st;
int fd, error;
int (*_efi_use_whole_disk)(int);
@@ -2818,12 +2821,25 @@ zpool_relabel_disk(libzfs_handle_t *hdl, const char *name, const char *msg)
* ignore that error and continue on.
*/
error = _efi_use_whole_disk(fd);
- (void) close(fd);
if (error && error != VT_ENOSPC) {
+ (void) close(fd);
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
"relabel '%s': unable to read disk capacity"), name);
return (zfs_error(hdl, EZFS_NOCAP, msg));
}
+
+ /*
+ * Writing a new EFI partition table to the disk will have marked
+ * the geometry as needing re-validation. Before returning, force
+ * it to be checked by querying the device state, otherwise the
+ * subsequent vdev_reopen() will very likely fail to read the device
+ * size, faulting the pool.
+ */
+ st = DKIO_NONE;
+ (void) ioctl(fd, DKIOCSTATE, (caddr_t)&st);
+
+ (void) close(fd);
+
return (0);
}
diff --git a/usr/src/lib/varpd/Makefile b/usr/src/lib/varpd/Makefile
new file mode 100644
index 0000000000..0962119d1c
--- /dev/null
+++ b/usr/src/lib/varpd/Makefile
@@ -0,0 +1,33 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2018 Joyent, Inc.
+#
+
+SUBDIRS = libvarpd direct files
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+check := TARGET = check
+install := TARGET = install
+install_h := TARGET = install_h
+
+.KEEP_STATE:
+
+all clean clobber install install_h check: $(SUBDIRS)
+direct files svp: libvarpd
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/varpd/Makefile.plugin b/usr/src/lib/varpd/Makefile.plugin
new file mode 100644
index 0000000000..48f188500c
--- /dev/null
+++ b/usr/src/lib/varpd/Makefile.plugin
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+ROOTLIBDIR = $(ROOT)/usr/lib/varpd
+ROOTLIBDIR64 = $(ROOT)/usr/lib/varpd/$(MACH64)
+
+MAPFILES += ../../libvarpd/common/mapfile-plugin
diff --git a/usr/src/lib/varpd/direct/Makefile b/usr/src/lib/varpd/direct/Makefile
new file mode 100644
index 0000000000..511ea1f94d
--- /dev/null
+++ b/usr/src/lib/varpd/direct/Makefile
@@ -0,0 +1,39 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../../Makefile.lib
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+
+.KEEP_STATE:
+
+all clean clobber install: $(SUBDIRS)
+
+install_h:
+
+check:
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/varpd/direct/Makefile.com b/usr/src/lib/varpd/direct/Makefile.com
new file mode 100644
index 0000000000..4e8564bae0
--- /dev/null
+++ b/usr/src/lib/varpd/direct/Makefile.com
@@ -0,0 +1,35 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+LIBRARY = libvarpd_direct.a
+VERS = .1
+OBJECTS = libvarpd_direct.o
+
+include ../../../Makefile.lib
+include ../../Makefile.plugin
+
+LIBS = $(DYNLIB)
+LDLIBS += -lc -lumem -lnvpair
+CPPFLAGS += -I../common
+
+CSTD= $(CSTD_GNU99)
+
+SRCDIR = ../common
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+include ../../../Makefile.targ
diff --git a/usr/src/lib/varpd/direct/amd64/Makefile b/usr/src/lib/varpd/direct/amd64/Makefile
new file mode 100644
index 0000000000..1881990d79
--- /dev/null
+++ b/usr/src/lib/varpd/direct/amd64/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/varpd/direct/common/libvarpd_direct.c b/usr/src/lib/varpd/direct/common/libvarpd_direct.c
new file mode 100644
index 0000000000..ed9f79fc7f
--- /dev/null
+++ b/usr/src/lib/varpd/direct/common/libvarpd_direct.c
@@ -0,0 +1,411 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * Point to point plug-in for varpd.
+ *
+ * This plugin implements a simple point to point plugin for a packet. It
+ * represents the traditional tunnel, just in overlay form. As such, the only
+ * properties it needs are those to determine where to send everything. At this
+ * time, we don't allow a multicast address; however, there's no reason that the
+ * direct plugin shouldn't in theory support multicast, though when implementing
+ * it the best path will become clear.
+ *
+ * In general this module has been designed to make it easy to support a
+ * destination of either IP or IP and port; however, we restrict it to the
+ * latter as we don't currently have an implementation that would allow us to
+ * test that.
+ */
+
+#include <libvarpd_provider.h>
+#include <umem.h>
+#include <errno.h>
+#include <thread.h>
+#include <synch.h>
+#include <strings.h>
+#include <assert.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <libnvpair.h>
+
+typedef struct varpd_direct {
+ overlay_plugin_dest_t vad_dest; /* RO */
+ mutex_t vad_lock; /* Protects the rest */
+ boolean_t vad_hip;
+ boolean_t vad_hport;
+ struct in6_addr vad_ip;
+ uint16_t vad_port;
+} varpd_direct_t;
+
+static const char *varpd_direct_props[] = {
+ "direct/dest_ip",
+ "direct/dest_port"
+};
+
+static boolean_t
+varpd_direct_valid_dest(overlay_plugin_dest_t dest)
+{
+ if (dest & ~(OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT))
+ return (B_FALSE);
+
+ if (!(dest & (OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT)))
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+/* ARGSUSED */
+static int
+varpd_direct_create(varpd_provider_handle_t *hdl, void **outp,
+ overlay_plugin_dest_t dest)
+{
+ int ret;
+ varpd_direct_t *vdp;
+
+ if (varpd_direct_valid_dest(dest) == B_FALSE)
+ return (ENOTSUP);
+
+ vdp = umem_alloc(sizeof (varpd_direct_t), UMEM_DEFAULT);
+ if (vdp == NULL)
+ return (ENOMEM);
+
+ if ((ret = mutex_init(&vdp->vad_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL)) != 0) {
+ umem_free(vdp, sizeof (varpd_direct_t));
+ return (ret);
+ }
+
+ vdp->vad_dest = dest;
+ vdp->vad_hip = B_FALSE;
+ vdp->vad_hport = B_FALSE;
+ *outp = vdp;
+ return (0);
+}
+
+static int
+varpd_direct_start(void *arg)
+{
+ varpd_direct_t *vdp = arg;
+
+ mutex_enter(&vdp->vad_lock);
+ if (vdp->vad_hip == B_FALSE ||((vdp->vad_dest & OVERLAY_PLUGIN_D_IP) &&
+ vdp->vad_hport == B_FALSE)) {
+ mutex_exit(&vdp->vad_lock);
+ return (EAGAIN);
+ }
+ mutex_exit(&vdp->vad_lock);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static void
+varpd_direct_stop(void *arg)
+{
+}
+
+static void
+varpd_direct_destroy(void *arg)
+{
+ varpd_direct_t *vdp = arg;
+
+ if (mutex_destroy(&vdp->vad_lock) != 0)
+ abort();
+ umem_free(vdp, sizeof (varpd_direct_t));
+}
+
+static int
+varpd_direct_default(void *arg, overlay_target_point_t *otp)
+{
+ varpd_direct_t *vdp = arg;
+
+ mutex_enter(&vdp->vad_lock);
+ bcopy(&vdp->vad_ip, &otp->otp_ip, sizeof (struct in6_addr));
+ otp->otp_port = vdp->vad_port;
+ mutex_exit(&vdp->vad_lock);
+
+ return (VARPD_LOOKUP_OK);
+}
+
+static int
+varpd_direct_nprops(void *arg, uint_t *nprops)
+{
+ const varpd_direct_t *vdp = arg;
+
+ *nprops = 0;
+ if (vdp->vad_dest & OVERLAY_PLUGIN_D_ETHERNET)
+ *nprops += 1;
+
+ if (vdp->vad_dest & OVERLAY_PLUGIN_D_IP)
+ *nprops += 1;
+
+ if (vdp->vad_dest & OVERLAY_PLUGIN_D_PORT)
+ *nprops += 1;
+
+ assert(*nprops == 1 || *nprops == 2);
+
+ return (0);
+}
+
+static int
+varpd_direct_propinfo(void *arg, uint_t propid, varpd_prop_handle_t *vph)
+{
+ varpd_direct_t *vdp = arg;
+
+ /*
+ * Because we only support IP + port combos right now, prop 0 should
+ * always be the IP. We don't support a port without an IP.
+ */
+ assert(vdp->vad_dest & OVERLAY_PLUGIN_D_IP);
+ if (propid == 0) {
+ libvarpd_prop_set_name(vph, varpd_direct_props[0]);
+ libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
+ libvarpd_prop_set_type(vph, OVERLAY_PROP_T_IP);
+ libvarpd_prop_set_nodefault(vph);
+ return (0);
+ }
+
+ if (propid == 1 && vdp->vad_dest & OVERLAY_PLUGIN_D_PORT) {
+ libvarpd_prop_set_name(vph, varpd_direct_props[1]);
+ libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
+ libvarpd_prop_set_type(vph, OVERLAY_PROP_T_UINT);
+ libvarpd_prop_set_nodefault(vph);
+ libvarpd_prop_set_range_uint32(vph, 1, UINT16_MAX);
+ return (0);
+ }
+
+ return (EINVAL);
+}
+
+static int
+varpd_direct_getprop(void *arg, const char *pname, void *buf, uint32_t *sizep)
+{
+ varpd_direct_t *vdp = arg;
+
+ /* direct/dest_ip */
+ if (strcmp(pname, varpd_direct_props[0]) == 0) {
+ if (*sizep < sizeof (struct in6_addr))
+ return (EOVERFLOW);
+ mutex_enter(&vdp->vad_lock);
+ if (vdp->vad_hip == B_FALSE) {
+ *sizep = 0;
+ } else {
+ bcopy(&vdp->vad_ip, buf, sizeof (struct in6_addr));
+ *sizep = sizeof (struct in6_addr);
+ }
+ mutex_exit(&vdp->vad_lock);
+ return (0);
+ }
+
+ /* direct/dest_port */
+ if (strcmp(pname, varpd_direct_props[1]) == 0) {
+ uint64_t val;
+
+ if (*sizep < sizeof (uint64_t))
+ return (EOVERFLOW);
+ mutex_enter(&vdp->vad_lock);
+ if (vdp->vad_hport == B_FALSE) {
+ *sizep = 0;
+ } else {
+ val = vdp->vad_port;
+ bcopy(&val, buf, sizeof (uint64_t));
+ *sizep = sizeof (uint64_t);
+ }
+ mutex_exit(&vdp->vad_lock);
+ return (0);
+ }
+
+ return (EINVAL);
+}
+
+static int
+varpd_direct_setprop(void *arg, const char *pname, const void *buf,
+ const uint32_t size)
+{
+ varpd_direct_t *vdp = arg;
+
+ /* direct/dest_ip */
+ if (strcmp(pname, varpd_direct_props[0]) == 0) {
+ const struct in6_addr *ipv6 = buf;
+
+ if (size < sizeof (struct in6_addr))
+ return (EOVERFLOW);
+
+ if (IN6_IS_ADDR_V4COMPAT(ipv6))
+ return (EINVAL);
+
+ if (IN6_IS_ADDR_6TO4(ipv6))
+ return (EINVAL);
+
+ mutex_enter(&vdp->vad_lock);
+ bcopy(buf, &vdp->vad_ip, sizeof (struct in6_addr));
+ vdp->vad_hip = B_TRUE;
+ mutex_exit(&vdp->vad_lock);
+ return (0);
+ }
+
+ /* direct/dest_port */
+ if (strcmp(pname, varpd_direct_props[1]) == 0) {
+ const uint64_t *valp = buf;
+ if (size < sizeof (uint64_t))
+ return (EOVERFLOW);
+
+ if (*valp == 0 || *valp > UINT16_MAX)
+ return (EINVAL);
+
+ mutex_enter(&vdp->vad_lock);
+ vdp->vad_port = (uint16_t)*valp;
+ vdp->vad_hport = B_TRUE;
+ mutex_exit(&vdp->vad_lock);
+ return (0);
+ }
+
+ return (EINVAL);
+}
+
+static int
+varpd_direct_save(void *arg, nvlist_t *nvp)
+{
+ int ret;
+ varpd_direct_t *vdp = arg;
+
+ mutex_enter(&vdp->vad_lock);
+ if (vdp->vad_hport == B_TRUE) {
+ if ((ret = nvlist_add_uint16(nvp, varpd_direct_props[1],
+ vdp->vad_port)) != 0) {
+ mutex_exit(&vdp->vad_lock);
+ return (ret);
+ }
+ }
+
+ if (vdp->vad_hip == B_TRUE) {
+ char buf[INET6_ADDRSTRLEN];
+
+ if (inet_ntop(AF_INET6, &vdp->vad_ip, buf, sizeof (buf)) ==
+ NULL)
+ abort();
+ if ((ret = nvlist_add_string(nvp, varpd_direct_props[0],
+ buf)) != 0) {
+ mutex_exit(&vdp->vad_lock);
+ return (ret);
+ }
+ }
+ mutex_exit(&vdp->vad_lock);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+varpd_direct_restore(nvlist_t *nvp, varpd_provider_handle_t *hdl,
+ overlay_plugin_dest_t dest, void **outp)
+{
+ int ret;
+ char *ipstr;
+ varpd_direct_t *vdp;
+
+ if (varpd_direct_valid_dest(dest) == B_FALSE)
+ return (ENOTSUP);
+
+ vdp = umem_alloc(sizeof (varpd_direct_t), UMEM_DEFAULT);
+ if (vdp == NULL)
+ return (ENOMEM);
+
+ if ((ret = mutex_init(&vdp->vad_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL)) != 0) {
+ umem_free(vdp, sizeof (varpd_direct_t));
+ return (ret);
+ }
+
+ if ((ret = nvlist_lookup_uint16(nvp, varpd_direct_props[1],
+ &vdp->vad_port)) != 0) {
+ if (ret != ENOENT) {
+ if (mutex_destroy(&vdp->vad_lock) != 0)
+ abort();
+ umem_free(vdp, sizeof (varpd_direct_t));
+ return (ret);
+ }
+ vdp->vad_hport = B_FALSE;
+ } else {
+ vdp->vad_hport = B_TRUE;
+ }
+
+ if ((ret = nvlist_lookup_string(nvp, varpd_direct_props[0],
+ &ipstr)) != 0) {
+ if (ret != ENOENT) {
+ if (mutex_destroy(&vdp->vad_lock) != 0)
+ abort();
+ umem_free(vdp, sizeof (varpd_direct_t));
+ return (ret);
+ }
+ vdp->vad_hip = B_FALSE;
+ } else {
+ ret = inet_pton(AF_INET6, ipstr, &vdp->vad_ip);
+ /*
+ * inet_pton is only defined to return -1 with errno set to
+ * EAFNOSUPPORT, which really, shouldn't happen.
+ */
+ if (ret == -1) {
+ assert(errno == EAFNOSUPPORT);
+ abort();
+ }
+ if (ret == 0) {
+ if (mutex_destroy(&vdp->vad_lock) != 0)
+ abort();
+ umem_free(vdp, sizeof (varpd_direct_t));
+ return (EINVAL);
+ }
+ }
+
+ *outp = vdp;
+ return (0);
+}
+
+static const varpd_plugin_ops_t varpd_direct_ops = {
+ 0,
+ varpd_direct_create,
+ varpd_direct_start,
+ varpd_direct_stop,
+ varpd_direct_destroy,
+ varpd_direct_default,
+ NULL,
+ varpd_direct_nprops,
+ varpd_direct_propinfo,
+ varpd_direct_getprop,
+ varpd_direct_setprop,
+ varpd_direct_save,
+ varpd_direct_restore
+};
+
+#pragma init(varpd_direct_init)
+static void
+varpd_direct_init(void)
+{
+ int err;
+ varpd_plugin_register_t *vpr;
+
+ vpr = libvarpd_plugin_alloc(VARPD_CURRENT_VERSION, &err);
+ if (vpr == NULL)
+ return;
+
+ vpr->vpr_mode = OVERLAY_TARGET_POINT;
+ vpr->vpr_name = "direct";
+ vpr->vpr_ops = &varpd_direct_ops;
+ (void) libvarpd_plugin_register(vpr);
+ libvarpd_plugin_free(vpr);
+}
diff --git a/usr/src/lib/varpd/direct/common/mapfile-vers b/usr/src/lib/varpd/direct/common/mapfile-vers
new file mode 100644
index 0000000000..6b7c5a5067
--- /dev/null
+++ b/usr/src/lib/varpd/direct/common/mapfile-vers
@@ -0,0 +1,35 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ local:
+ *;
+};
diff --git a/usr/src/lib/varpd/direct/i386/Makefile b/usr/src/lib/varpd/direct/i386/Makefile
new file mode 100644
index 0000000000..4398507523
--- /dev/null
+++ b/usr/src/lib/varpd/direct/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/varpd/files/Makefile b/usr/src/lib/varpd/files/Makefile
new file mode 100644
index 0000000000..511ea1f94d
--- /dev/null
+++ b/usr/src/lib/varpd/files/Makefile
@@ -0,0 +1,39 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../../Makefile.lib
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+
+.KEEP_STATE:
+
+all clean clobber install: $(SUBDIRS)
+
+install_h:
+
+check:
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/varpd/files/Makefile.com b/usr/src/lib/varpd/files/Makefile.com
new file mode 100644
index 0000000000..13ff2149ce
--- /dev/null
+++ b/usr/src/lib/varpd/files/Makefile.com
@@ -0,0 +1,36 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2018 Joyent, Inc.
+#
+
+LIBRARY = libvarpd_files.a
+VERS = .1
+OBJECTS = libvarpd_files.o \
+ libvarpd_files_json.o
+
+include ../../../Makefile.lib
+include ../../Makefile.plugin
+
+LIBS = $(DYNLIB)
+LDLIBS += -lc -lumem -lnvpair -lsocket -lcustr
+CPPFLAGS += -I../common
+
+CSTD= $(CSTD_GNU99)
+
+SRCDIR = ../common
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+include ../../../Makefile.targ
diff --git a/usr/src/lib/varpd/files/amd64/Makefile b/usr/src/lib/varpd/files/amd64/Makefile
new file mode 100644
index 0000000000..1881990d79
--- /dev/null
+++ b/usr/src/lib/varpd/files/amd64/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/varpd/files/common/libvarpd_files.c b/usr/src/lib/varpd/files/common/libvarpd_files.c
new file mode 100644
index 0000000000..84cb27f9e8
--- /dev/null
+++ b/usr/src/lib/varpd/files/common/libvarpd_files.c
@@ -0,0 +1,605 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015, Joyent, Inc.
+ */
+
+/*
+ * Files based plug-in for varpd
+ *
+ * This is a dynamic varpd plug-in that has a static backing store. It's really
+ * nothing more than a glorified version of /etc/ethers, though it facilitates
+ * a bit more. The files module allows for the full set of mappings to be fixed
+ * at creation time. In addition, it also provides support for proxying ARP,
+ * NDP, and DHCP.
+ *
+ * At this time, the plugin requires that the destination type involve both an
+ * IP address and a port; however, there's no reason that this cannot be made
+ * more flexible as we have additional encapsulation algorithms that support it.
+ * The plug-in only has a single property, which is the location of the JSON
+ * file. The JSON file itself looks something like:
+ *
+ * {
+ * "aa:bb:cc:dd:ee:ff": {
+ * "arp": "10.23.69.1",
+ * "ndp": "2600:3c00::f03c:91ff:fe96:a264",
+ * "ip": "192.168.1.1",
+ * "port": 8080
+ * },
+ * ...
+ * }
+ */
+
+#include <libvarpd_provider.h>
+#include <umem.h>
+#include <errno.h>
+#include <thread.h>
+#include <synch.h>
+#include <strings.h>
+#include <assert.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libnvpair.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/ethernet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <libvarpd_files_json.h>
+
+typedef struct varpd_files {
+ overlay_plugin_dest_t vaf_dest; /* RO */
+ varpd_provider_handle_t *vaf_hdl; /* RO */
+ char *vaf_path; /* WO */
+ nvlist_t *vaf_nvl; /* WO */
+ uint64_t vaf_nmisses; /* Atomic */
+ uint64_t vaf_narp; /* Atomic */
+} varpd_files_t;
+
+static const char *varpd_files_props[] = {
+ "files/config"
+};
+
+static boolean_t
+varpd_files_valid_dest(overlay_plugin_dest_t dest)
+{
+ if (dest & ~(OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT))
+ return (B_FALSE);
+
+ if (!(dest & (OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT)))
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+static int
+varpd_files_create(varpd_provider_handle_t *hdl, void **outp,
+ overlay_plugin_dest_t dest)
+{
+ varpd_files_t *vaf;
+
+ if (varpd_files_valid_dest(dest) == B_FALSE)
+ return (ENOTSUP);
+
+ vaf = umem_alloc(sizeof (varpd_files_t), UMEM_DEFAULT);
+ if (vaf == NULL)
+ return (ENOMEM);
+
+ bzero(vaf, sizeof (varpd_files_t));
+ vaf->vaf_dest = dest;
+ vaf->vaf_path = NULL;
+ vaf->vaf_nvl = NULL;
+ vaf->vaf_hdl = hdl;
+ *outp = vaf;
+ return (0);
+}
+
+static int
+varpd_files_normalize_nvlist(varpd_files_t *vaf, nvlist_t *nvl)
+{
+ int ret;
+ nvlist_t *out;
+ nvpair_t *pair;
+
+ if ((ret = nvlist_alloc(&out, NV_UNIQUE_NAME, 0)) != 0)
+ return (ret);
+
+ for (pair = nvlist_next_nvpair(nvl, NULL); pair != NULL;
+ pair = nvlist_next_nvpair(nvl, pair)) {
+ char *name, fname[ETHERADDRSTRL];
+ nvlist_t *data;
+ struct ether_addr ether, *e;
+ e = &ether;
+
+ if (nvpair_type(pair) != DATA_TYPE_NVLIST) {
+ nvlist_free(out);
+ return (EINVAL);
+ }
+
+ name = nvpair_name(pair);
+ if ((ret = nvpair_value_nvlist(pair, &data)) != 0) {
+ nvlist_free(out);
+ return (EINVAL);
+ }
+
+ if (ether_aton_r(name, e) == NULL) {
+ nvlist_free(out);
+ return (EINVAL);
+ }
+
+ if (ether_ntoa_r(e, fname) == NULL) {
+ nvlist_free(out);
+ return (ENOMEM);
+ }
+
+ if ((ret = nvlist_add_nvlist(out, fname, data)) != 0) {
+ nvlist_free(out);
+ return (EINVAL);
+ }
+ }
+
+ vaf->vaf_nvl = out;
+ return (0);
+}
+
+static int
+varpd_files_start(void *arg)
+{
+ int fd, ret;
+ void *maddr;
+ struct stat st;
+ nvlist_t *nvl;
+ varpd_files_t *vaf = arg;
+
+ if (vaf->vaf_path == NULL)
+ return (EAGAIN);
+
+ if ((fd = open(vaf->vaf_path, O_RDONLY)) < 0)
+ return (errno);
+
+ if (fstat(fd, &st) != 0) {
+ ret = errno;
+ if (close(fd) != 0)
+ abort();
+ return (ret);
+ }
+
+ maddr = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
+ fd, 0);
+ if (maddr == NULL) {
+ ret = errno;
+ if (close(fd) != 0)
+ abort();
+ return (ret);
+ }
+
+ ret = nvlist_parse_json(maddr, st.st_size, &nvl,
+ NVJSON_FORCE_INTEGER, NULL);
+ if (ret == 0) {
+ ret = varpd_files_normalize_nvlist(vaf, nvl);
+ nvlist_free(nvl);
+ }
+ if (munmap(maddr, st.st_size) != 0)
+ abort();
+ if (close(fd) != 0)
+ abort();
+
+ return (ret);
+}
+
+static void
+varpd_files_stop(void *arg)
+{
+ varpd_files_t *vaf = arg;
+
+ nvlist_free(vaf->vaf_nvl);
+ vaf->vaf_nvl = NULL;
+}
+
+static void
+varpd_files_destroy(void *arg)
+{
+ varpd_files_t *vaf = arg;
+
+ assert(vaf->vaf_nvl == NULL);
+ if (vaf->vaf_path != NULL) {
+ umem_free(vaf->vaf_path, strlen(vaf->vaf_path) + 1);
+ vaf->vaf_path = NULL;
+ }
+ umem_free(vaf, sizeof (varpd_files_t));
+}
+
+static void
+varpd_files_lookup(void *arg, varpd_query_handle_t *qh,
+ const overlay_targ_lookup_t *otl, overlay_target_point_t *otp)
+{
+ char macstr[ETHERADDRSTRL], *ipstr;
+ nvlist_t *nvl;
+ varpd_files_t *vaf = arg;
+ int32_t port;
+ static const uint8_t bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ /* We don't support a default */
+ if (otl == NULL) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (otl->otl_sap == ETHERTYPE_ARP) {
+ libvarpd_plugin_proxy_arp(vaf->vaf_hdl, qh, otl);
+ return;
+ }
+
+ if (otl->otl_sap == ETHERTYPE_IPV6 &&
+ otl->otl_dstaddr[0] == 0x33 &&
+ otl->otl_dstaddr[1] == 0x33) {
+ libvarpd_plugin_proxy_ndp(vaf->vaf_hdl, qh, otl);
+ return;
+ }
+
+ if (otl->otl_sap == ETHERTYPE_IP &&
+ bcmp(otl->otl_dstaddr, bcast, ETHERADDRL) == 0) {
+ char *mac;
+ struct ether_addr a, *addr;
+
+ addr = &a;
+ if (ether_ntoa_r((struct ether_addr *)otl->otl_srcaddr,
+ macstr) == NULL) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (nvlist_lookup_nvlist(vaf->vaf_nvl, macstr, &nvl) != 0) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (nvlist_lookup_string(nvl, "dhcp-proxy", &mac) != 0) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (ether_aton_r(mac, addr) == NULL) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ libvarpd_plugin_proxy_dhcp(vaf->vaf_hdl, qh, otl);
+ return;
+ }
+
+ if (ether_ntoa_r((struct ether_addr *)otl->otl_dstaddr,
+ macstr) == NULL) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (nvlist_lookup_nvlist(vaf->vaf_nvl, macstr, &nvl) != 0) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (nvlist_lookup_int32(nvl, "port", &port) != 0) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (port <= 0 || port > UINT16_MAX) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+ otp->otp_port = port;
+
+ if (nvlist_lookup_string(nvl, "ip", &ipstr) != 0) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ /*
+ * Try to parse it as a v6 address and then if it's not, try to
+ * transform it into a v4 address which we'll then wrap it into a v4
+ * mapped address.
+ */
+ if (inet_pton(AF_INET6, ipstr, &otp->otp_ip) != 1) {
+ uint32_t v4;
+ if (inet_pton(AF_INET, ipstr, &v4) != 1) {
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
+ return;
+ }
+ IN6_IPADDR_TO_V4MAPPED(v4, &otp->otp_ip);
+ }
+
+ libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_OK);
+}
+
+/* ARGSUSED */
+static int
+varpd_files_nprops(void *arg, uint_t *nprops)
+{
+ *nprops = 1;
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+varpd_files_propinfo(void *arg, uint_t propid, varpd_prop_handle_t *vph)
+{
+ if (propid != 0)
+ return (EINVAL);
+
+ libvarpd_prop_set_name(vph, varpd_files_props[0]);
+ libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
+ libvarpd_prop_set_type(vph, OVERLAY_PROP_T_STRING);
+ libvarpd_prop_set_nodefault(vph);
+ return (0);
+}
+
+static int
+varpd_files_getprop(void *arg, const char *pname, void *buf, uint32_t *sizep)
+{
+ varpd_files_t *vaf = arg;
+
+ if (strcmp(pname, varpd_files_props[0]) != 0)
+ return (EINVAL);
+
+ if (vaf->vaf_path != NULL) {
+ size_t len = strlen(vaf->vaf_path) + 1;
+ if (*sizep < len)
+ return (EOVERFLOW);
+ *sizep = len;
+ (void) strlcpy(buf, vaf->vaf_path, *sizep);
+
+ } else {
+ *sizep = 0;
+ }
+
+ return (0);
+}
+
+static int
+varpd_files_setprop(void *arg, const char *pname, const void *buf,
+ const uint32_t size)
+{
+ varpd_files_t *vaf = arg;
+
+ if (strcmp(pname, varpd_files_props[0]) != 0)
+ return (EINVAL);
+
+ if (vaf->vaf_path != NULL)
+ umem_free(vaf->vaf_path, strlen(vaf->vaf_path) + 1);
+
+ vaf->vaf_path = umem_alloc(size, UMEM_DEFAULT);
+ if (vaf->vaf_path == NULL)
+ return (ENOMEM);
+ (void) strlcpy(vaf->vaf_path, buf, size);
+ return (0);
+}
+
+static int
+varpd_files_save(void *arg, nvlist_t *nvp)
+{
+ int ret;
+ varpd_files_t *vaf = arg;
+
+ if (vaf->vaf_path == NULL)
+ return (0);
+
+ if ((ret = nvlist_add_string(nvp, varpd_files_props[0],
+ vaf->vaf_path)) != 0)
+ return (ret);
+
+ if ((ret = nvlist_add_uint64(nvp, "files/vaf_nmisses",
+ vaf->vaf_nmisses)) != 0)
+ return (ret);
+
+ if ((ret = nvlist_add_uint64(nvp, "files/vaf_narp",
+ vaf->vaf_narp)) != 0)
+ return (ret);
+ return (0);
+}
+
+static int
+varpd_files_restore(nvlist_t *nvp, varpd_provider_handle_t *hdl,
+ overlay_plugin_dest_t dest, void **outp)
+{
+ varpd_files_t *vaf;
+ char *str;
+ int ret;
+ uint64_t nmisses, narp;
+
+ if (varpd_files_valid_dest(dest) == B_FALSE)
+ return (EINVAL);
+
+ ret = nvlist_lookup_string(nvp, varpd_files_props[0], &str);
+ if (ret != 0 && ret != ENOENT)
+ return (ret);
+ else if (ret == ENOENT)
+ str = NULL;
+
+ if (nvlist_lookup_uint64(nvp, "files/vaf_nmisses", &nmisses) != 0)
+ return (EINVAL);
+ if (nvlist_lookup_uint64(nvp, "files/vaf_narp", &narp) != 0)
+ return (EINVAL);
+
+ vaf = umem_alloc(sizeof (varpd_files_t), UMEM_DEFAULT);
+ if (vaf == NULL)
+ return (ENOMEM);
+
+ bzero(vaf, sizeof (varpd_files_t));
+ vaf->vaf_dest = dest;
+ if (str != NULL) {
+ size_t len = strlen(str) + 1;
+ vaf->vaf_path = umem_alloc(len, UMEM_DEFAULT);
+ if (vaf->vaf_path == NULL) {
+ umem_free(vaf, sizeof (varpd_files_t));
+ return (ENOMEM);
+ }
+ (void) strlcpy(vaf->vaf_path, str, len);
+ }
+
+ vaf->vaf_hdl = hdl;
+ *outp = vaf;
+ return (0);
+}
+
+static void
+varpd_files_proxy_arp(void *arg, varpd_arp_handle_t *vah, int kind,
+ const struct sockaddr *sock, uint8_t *out)
+{
+ varpd_files_t *vaf = arg;
+ const struct sockaddr_in *ip;
+ const struct sockaddr_in6 *ip6;
+ nvpair_t *pair;
+
+ if (kind != VARPD_QTYPE_ETHERNET) {
+ libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (sock->sa_family != AF_INET && sock->sa_family != AF_INET6) {
+ libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ ip = (const struct sockaddr_in *)sock;
+ ip6 = (const struct sockaddr_in6 *)sock;
+ for (pair = nvlist_next_nvpair(vaf->vaf_nvl, NULL); pair != NULL;
+ pair = nvlist_next_nvpair(vaf->vaf_nvl, pair)) {
+ char *mac, *ipstr;
+ nvlist_t *data;
+ struct in_addr ia;
+ struct in6_addr ia6;
+ struct ether_addr ether, *e;
+ e = &ether;
+
+ if (nvpair_type(pair) != DATA_TYPE_NVLIST)
+ continue;
+
+ mac = nvpair_name(pair);
+ if (nvpair_value_nvlist(pair, &data) != 0)
+ continue;
+
+
+ if (sock->sa_family == AF_INET) {
+ if (nvlist_lookup_string(data, "arp", &ipstr) != 0)
+ continue;
+
+ if (inet_pton(AF_INET, ipstr, &ia) != 1)
+ continue;
+
+ if (bcmp(&ia, &ip->sin_addr,
+ sizeof (struct in_addr)) != 0)
+ continue;
+ } else {
+ if (nvlist_lookup_string(data, "ndp", &ipstr) != 0)
+ continue;
+
+ if (inet_pton(AF_INET6, ipstr, &ia6) != 1)
+ continue;
+
+ if (bcmp(&ia6, &ip6->sin6_addr,
+ sizeof (struct in6_addr)) != 0)
+ continue;
+ }
+
+ if (ether_aton_r(mac, e) == NULL) {
+ libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ bcopy(e, out, ETHERADDRL);
+ libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_OK);
+ return;
+ }
+
+ libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
+}
+
+static void
+varpd_files_proxy_dhcp(void *arg, varpd_dhcp_handle_t *vdh, int type,
+ const overlay_targ_lookup_t *otl, uint8_t *out)
+{
+ varpd_files_t *vaf = arg;
+ nvlist_t *nvl;
+ char macstr[ETHERADDRSTRL], *mac;
+ struct ether_addr a, *addr;
+
+ addr = &a;
+ if (type != VARPD_QTYPE_ETHERNET) {
+ libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (ether_ntoa_r((struct ether_addr *)otl->otl_srcaddr,
+ macstr) == NULL) {
+ libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (nvlist_lookup_nvlist(vaf->vaf_nvl, macstr, &nvl) != 0) {
+ libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (nvlist_lookup_string(nvl, "dhcp-proxy", &mac) != 0) {
+ libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ if (ether_aton_r(mac, addr) == NULL) {
+ libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_DROP);
+ return;
+ }
+
+ bcopy(addr, out, ETHERADDRL);
+ libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_OK);
+}
+
+static const varpd_plugin_ops_t varpd_files_ops = {
+ 0,
+ varpd_files_create,
+ varpd_files_start,
+ varpd_files_stop,
+ varpd_files_destroy,
+ NULL,
+ varpd_files_lookup,
+ varpd_files_nprops,
+ varpd_files_propinfo,
+ varpd_files_getprop,
+ varpd_files_setprop,
+ varpd_files_save,
+ varpd_files_restore,
+ varpd_files_proxy_arp,
+ varpd_files_proxy_dhcp
+};
+
+#pragma init(varpd_files_init)
+static void
+varpd_files_init(void)
+{
+ int err;
+ varpd_plugin_register_t *vpr;
+
+ vpr = libvarpd_plugin_alloc(VARPD_CURRENT_VERSION, &err);
+ if (vpr == NULL)
+ return;
+
+ vpr->vpr_mode = OVERLAY_TARGET_DYNAMIC;
+ vpr->vpr_name = "files";
+ vpr->vpr_ops = &varpd_files_ops;
+ (void) libvarpd_plugin_register(vpr);
+ libvarpd_plugin_free(vpr);
+}
diff --git a/usr/src/lib/varpd/files/common/libvarpd_files_json.c b/usr/src/lib/varpd/files/common/libvarpd_files_json.c
new file mode 100644
index 0000000000..53e63c6244
--- /dev/null
+++ b/usr/src/lib/varpd/files/common/libvarpd_files_json.c
@@ -0,0 +1,936 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <strings.h>
+#include <errno.h>
+#include <libnvpair.h>
+#include <sys/ccompile.h>
+
+#include "libvarpd_files_json.h"
+
+typedef enum json_type {
+ JSON_TYPE_NOTHING = 0,
+ JSON_TYPE_STRING = 1,
+ JSON_TYPE_INTEGER,
+ JSON_TYPE_DOUBLE,
+ JSON_TYPE_BOOLEAN,
+ JSON_TYPE_NULL,
+ JSON_TYPE_OBJECT,
+ JSON_TYPE_ARRAY
+} json_type_t;
+
+typedef enum parse_state {
+ PARSE_ERROR = -1,
+ PARSE_DONE = 0,
+ PARSE_REST,
+ PARSE_OBJECT,
+ PARSE_KEY_STRING,
+ PARSE_COLON,
+ PARSE_STRING,
+ PARSE_OBJECT_COMMA,
+ PARSE_ARRAY,
+ PARSE_BAREWORD,
+ PARSE_NUMBER,
+ PARSE_ARRAY_VALUE,
+ PARSE_ARRAY_COMMA
+} parse_state_t;
+
+#define JSON_MARKER ".__json_"
+#define JSON_MARKER_ARRAY JSON_MARKER "array"
+
+typedef struct parse_frame {
+ parse_state_t pf_ps;
+ nvlist_t *pf_nvl;
+
+ char *pf_key;
+ void *pf_value;
+ json_type_t pf_value_type;
+ int pf_array_index;
+
+ struct parse_frame *pf_next;
+} parse_frame_t;
+
+typedef struct state {
+ const char *s_in;
+ unsigned long s_pos;
+ unsigned long s_len;
+
+ parse_frame_t *s_top;
+
+ nvlist_parse_json_flags_t s_flags;
+
+ /*
+ * This string buffer is used for temporary storage by the
+ * "collect_*()" family of functions.
+ */
+ custr_t *s_collect;
+
+ int s_errno;
+ custr_t *s_errstr;
+} state_t;
+
+typedef void (*parse_handler_t)(state_t *);
+
+static void
+movestate(state_t *s, parse_state_t ps)
+{
+ if (s->s_flags & NVJSON_DEBUG) {
+ (void) fprintf(stderr, "nvjson: move state %d -> %d\n",
+ s->s_top->pf_ps, ps);
+ }
+ s->s_top->pf_ps = ps;
+}
+
+static void
+posterror(state_t *s, int erno, const char *error)
+{
+ /*
+ * If the caller wants error messages printed to stderr, do that
+ * first.
+ */
+ if (s->s_flags & NVJSON_ERRORS_TO_STDERR) {
+ (void) fprintf(stderr, "nvjson error (pos %ld, errno %d): %s\n",
+ s->s_pos, erno, error);
+ }
+
+ /*
+ * Try and store the error message for the caller. This may fail if
+ * the error was related to memory pressure, and that condition still
+ * exists.
+ */
+ s->s_errno = erno;
+ if (s->s_errstr != NULL) {
+ (void) custr_append(s->s_errstr, error);
+ }
+
+ movestate(s, PARSE_ERROR);
+}
+
+static int
+pushstate(state_t *s, parse_state_t ps, parse_state_t retps)
+{
+ parse_frame_t *n;
+
+ if (s->s_flags & NVJSON_DEBUG) {
+ (void) fprintf(stderr, "nvjson: push state %d -> %d (ret %d)\n",
+ s->s_top->pf_ps, ps, retps);
+ }
+
+ if ((n = calloc(1, sizeof (*n))) == NULL) {
+ posterror(s, errno, "pushstate calloc failure");
+ return (-1);
+ }
+
+ /*
+ * Store the state we'll return to when popping this
+ * frame:
+ */
+ s->s_top->pf_ps = retps;
+
+ /*
+ * Store the initial state for the new frame, and
+ * put it on top of the stack:
+ */
+ n->pf_ps = ps;
+ n->pf_value_type = JSON_TYPE_NOTHING;
+
+ n->pf_next = s->s_top;
+ s->s_top = n;
+
+ return (0);
+}
+
+static char
+popchar(state_t *s)
+{
+ if (s->s_pos > s->s_len) {
+ return (0);
+ }
+ return (s->s_in[s->s_pos++]);
+}
+
+static char
+peekchar(state_t *s)
+{
+ if (s->s_pos > s->s_len) {
+ return (0);
+ }
+ return (s->s_in[s->s_pos]);
+}
+
+static void
+discard_whitespace(state_t *s)
+{
+ while (isspace(peekchar(s))) {
+ (void) popchar(s);
+ }
+}
+
+static char *escape_pairs[] = {
+ "\"\"", "\\\\", "//", "b\b", "f\f", "n\n", "r\r", "t\t", NULL
+};
+
+static char
+collect_string_escape(state_t *s)
+{
+ int i;
+ char c = popchar(s);
+
+ if (c == '\0') {
+ posterror(s, EPROTO, "EOF mid-escape sequence");
+ return (-1);
+ }
+
+ /*
+ * Handle four-digit Unicode escapes up to and including \u007f.
+ * Strings that cannot be represented as 7-bit clean ASCII are not
+ * currently supported.
+ */
+ if (c == 'u') {
+ int res;
+ int ndigs = 0;
+ char digs[5];
+
+ /*
+ * Deal with 4-digit unicode escape.
+ */
+ while (ndigs < 4) {
+ if ((digs[ndigs++] = popchar(s)) == '\0') {
+ posterror(s, EPROTO, "EOF mid-escape "
+ "sequence");
+ return (-1);
+ }
+ }
+ digs[4] = '\0';
+ if ((res = atoi(digs)) > 127) {
+ posterror(s, EPROTO, "unicode escape above 0x7f");
+ return (-1);
+ }
+
+ if (custr_appendc(s->s_collect, res) != 0) {
+ posterror(s, errno, "custr_appendc failure");
+ return (-1);
+ }
+ return (0);
+ }
+
+ /*
+ * See if this is a C-style escape character we recognise.
+ */
+ for (i = 0; escape_pairs[i] != NULL; i++) {
+ char *ep = escape_pairs[i];
+ if (ep[0] == c) {
+ if (custr_appendc(s->s_collect, ep[1]) != 0) {
+ posterror(s, errno, "custr_appendc failure");
+ return (-1);
+ }
+ return (0);
+ }
+ }
+
+ posterror(s, EPROTO, "unrecognised escape sequence");
+ return (-1);
+}
+
+static int
+collect_string(state_t *s)
+{
+ custr_reset(s->s_collect);
+
+ for (;;) {
+ char c;
+
+ switch (c = popchar(s)) {
+ case '"':
+ /*
+ * Legal End of String.
+ */
+ return (0);
+
+ case '\0':
+ posterror(s, EPROTO, "EOF mid-string");
+ return (-1);
+
+ case '\\':
+ /*
+ * Escape Characters and Sequences.
+ */
+ if (collect_string_escape(s) != 0) {
+ return (-1);
+ }
+ break;
+
+ default:
+ if (custr_appendc(s->s_collect, c) != 0) {
+ posterror(s, errno, "custr_appendc failure");
+ return (-1);
+ }
+ break;
+ }
+ }
+}
+
+static int
+collect_bareword(state_t *s)
+{
+ custr_reset(s->s_collect);
+
+ for (;;) {
+ if (!islower(peekchar(s))) {
+ return (0);
+ }
+
+ if (custr_appendc(s->s_collect, popchar(s)) != 0) {
+ posterror(s, errno, "custr_appendc failure");
+ return (-1);
+ }
+ }
+}
+
+static void
+hdlr_bareword(state_t *s)
+{
+ const char *str;
+
+ if (collect_bareword(s) != 0) {
+ return;
+ }
+
+ str = custr_cstr(s->s_collect);
+ if (strcmp(str, "true") == 0) {
+ s->s_top->pf_value_type = JSON_TYPE_BOOLEAN;
+ s->s_top->pf_value = (void *)B_TRUE;
+ } else if (strcmp(str, "false") == 0) {
+ s->s_top->pf_value_type = JSON_TYPE_BOOLEAN;
+ s->s_top->pf_value = (void *)B_FALSE;
+ } else if (strcmp(str, "null") == 0) {
+ s->s_top->pf_value_type = JSON_TYPE_NULL;
+ } else {
+ posterror(s, EPROTO, "expected 'true', 'false' or 'null'");
+ return;
+ }
+
+ movestate(s, PARSE_DONE);
+}
+
+/* ARGSUSED */
+static int
+collect_number(state_t *s, boolean_t *isint, int32_t *result,
+ double *fresult __unused)
+{
+ boolean_t neg = B_FALSE;
+ int t;
+
+ custr_reset(s->s_collect);
+
+ if (peekchar(s) == '-') {
+ neg = B_TRUE;
+ (void) popchar(s);
+ }
+ /*
+ * Read the 'int' portion:
+ */
+ if (!isdigit(peekchar(s))) {
+ posterror(s, EPROTO, "malformed number: expected digit (0-9)");
+ return (-1);
+ }
+ for (;;) {
+ if (!isdigit(peekchar(s))) {
+ break;
+ }
+ if (custr_appendc(s->s_collect, popchar(s)) != 0) {
+ posterror(s, errno, "custr_append failure");
+ return (-1);
+ }
+ }
+ if (peekchar(s) == '.' || peekchar(s) == 'e' || peekchar(s) == 'E') {
+ posterror(s, ENOTSUP, "do not yet support FRACs or EXPs");
+ return (-1);
+ }
+
+ t = atoi(custr_cstr(s->s_collect));
+
+ *isint = B_TRUE;
+ *result = (neg == B_TRUE) ? (-t) : t;
+ return (0);
+}
+
+static void
+hdlr_number(state_t *s)
+{
+ boolean_t isint;
+ int32_t result;
+ double fresult;
+
+ if (collect_number(s, &isint, &result, &fresult) != 0) {
+ return;
+ }
+
+ if (isint == B_TRUE) {
+ s->s_top->pf_value = (void *)(uintptr_t)result;
+ s->s_top->pf_value_type = JSON_TYPE_INTEGER;
+ } else {
+ s->s_top->pf_value = malloc(sizeof (fresult));
+ bcopy(&fresult, s->s_top->pf_value, sizeof (fresult));
+ s->s_top->pf_value_type = JSON_TYPE_DOUBLE;
+ }
+
+ movestate(s, PARSE_DONE);
+}
+
+static void
+hdlr_rest(state_t *s)
+{
+ char c;
+ discard_whitespace(s);
+ c = popchar(s);
+ switch (c) {
+ case '{':
+ movestate(s, PARSE_OBJECT);
+ return;
+
+ case '[':
+ movestate(s, PARSE_ARRAY);
+ return;
+
+ default:
+ posterror(s, EPROTO, "EOF before object or array");
+ return;
+ }
+}
+
+static int
+add_empty_child(state_t *s)
+{
+ /*
+ * Here, we create an empty nvlist to represent this object
+ * or array:
+ */
+ nvlist_t *empty;
+ if (nvlist_alloc(&empty, NV_UNIQUE_NAME, 0) != 0) {
+ posterror(s, errno, "nvlist_alloc failure");
+ return (-1);
+ }
+ if (s->s_top->pf_next != NULL) {
+ /*
+ * If we're a child of the frame above, we store ourselves in
+ * that frame's nvlist:
+ */
+ nvlist_t *nvl = s->s_top->pf_next->pf_nvl;
+ char *key = s->s_top->pf_next->pf_key;
+
+ if (nvlist_add_nvlist(nvl, key, empty) != 0) {
+ posterror(s, errno, "nvlist_add_nvlist failure");
+ nvlist_free(empty);
+ return (-1);
+ }
+ nvlist_free(empty);
+ if (nvlist_lookup_nvlist(nvl, key, &empty) != 0) {
+ posterror(s, errno, "nvlist_lookup_nvlist failure");
+ return (-1);
+ }
+ }
+ s->s_top->pf_nvl = empty;
+ return (0);
+}
+
+static int
+decorate_array(state_t *s)
+{
+ int idx = s->s_top->pf_array_index;
+ /*
+ * When we are done creating an array, we store a 'length'
+ * property on it, as well as an internal-use marker value.
+ */
+ if (nvlist_add_boolean(s->s_top->pf_nvl, JSON_MARKER_ARRAY) != 0 ||
+ nvlist_add_uint32(s->s_top->pf_nvl, "length", idx) != 0) {
+ posterror(s, errno, "nvlist_add failure");
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void
+hdlr_array(state_t *s)
+{
+ s->s_top->pf_value_type = JSON_TYPE_ARRAY;
+
+ if (add_empty_child(s) != 0) {
+ return;
+ }
+
+ discard_whitespace(s);
+
+ switch (peekchar(s)) {
+ case ']':
+ (void) popchar(s);
+
+ if (decorate_array(s) != 0) {
+ return;
+ }
+
+ movestate(s, PARSE_DONE);
+ return;
+
+ default:
+ movestate(s, PARSE_ARRAY_VALUE);
+ return;
+ }
+}
+
+static void
+hdlr_array_comma(state_t *s)
+{
+ discard_whitespace(s);
+
+ switch (popchar(s)) {
+ case ']':
+ if (decorate_array(s) != 0) {
+ return;
+ }
+
+ movestate(s, PARSE_DONE);
+ return;
+ case ',':
+ movestate(s, PARSE_ARRAY_VALUE);
+ return;
+ default:
+ posterror(s, EPROTO, "expected ',' or ']'");
+ return;
+ }
+}
+
+static void
+hdlr_array_value(state_t *s)
+{
+ char c;
+
+ /*
+ * Generate keyname from the next array index:
+ */
+ if (s->s_top->pf_key != NULL) {
+ (void) fprintf(stderr, "pf_key not null! was %s\n",
+ s->s_top->pf_key);
+ abort();
+ }
+
+ if (asprintf(&s->s_top->pf_key, "%d", s->s_top->pf_array_index++) < 0) {
+ posterror(s, errno, "asprintf failure");
+ return;
+ }
+
+ discard_whitespace(s);
+
+ /*
+ * Select which type handler we need for the next value:
+ */
+ switch (c = peekchar(s)) {
+ case '"':
+ (void) popchar(s);
+ (void) pushstate(s, PARSE_STRING, PARSE_ARRAY_COMMA);
+ return;
+
+ case '{':
+ (void) popchar(s);
+ (void) pushstate(s, PARSE_OBJECT, PARSE_ARRAY_COMMA);
+ return;
+
+ case '[':
+ (void) popchar(s);
+ (void) pushstate(s, PARSE_ARRAY, PARSE_ARRAY_COMMA);
+ return;
+
+ default:
+ if (islower(c)) {
+ (void) pushstate(s, PARSE_BAREWORD,
+ PARSE_ARRAY_COMMA);
+ return;
+ } else if (c == '-' || isdigit(c)) {
+ (void) pushstate(s, PARSE_NUMBER, PARSE_ARRAY_COMMA);
+ return;
+ } else {
+ posterror(s, EPROTO, "unexpected character at start "
+ "of value");
+ return;
+ }
+ }
+}
+
+static void
+hdlr_object(state_t *s)
+{
+ s->s_top->pf_value_type = JSON_TYPE_OBJECT;
+
+ if (add_empty_child(s) != 0) {
+ return;
+ }
+
+ discard_whitespace(s);
+
+ switch (popchar(s)) {
+ case '}':
+ movestate(s, PARSE_DONE);
+ return;
+
+ case '"':
+ movestate(s, PARSE_KEY_STRING);
+ return;
+
+ default:
+ posterror(s, EPROTO, "expected key or '}'");
+ return;
+ }
+}
+
+static void
+hdlr_key_string(state_t *s)
+{
+ if (collect_string(s) != 0) {
+ return;
+ }
+
+ /*
+ * Record the key name of the next value.
+ */
+ if ((s->s_top->pf_key = strdup(custr_cstr(s->s_collect))) == NULL) {
+ posterror(s, errno, "strdup failure");
+ return;
+ }
+
+ movestate(s, PARSE_COLON);
+}
+
+static void
+hdlr_colon(state_t *s)
+{
+ char c;
+ discard_whitespace(s);
+
+ if ((c = popchar(s)) != ':') {
+ posterror(s, EPROTO, "expected ':'");
+ return;
+ }
+
+ discard_whitespace(s);
+
+ /*
+ * Select which type handler we need for the value after the colon:
+ */
+ switch (c = peekchar(s)) {
+ case '"':
+ (void) popchar(s);
+ (void) pushstate(s, PARSE_STRING, PARSE_OBJECT_COMMA);
+ return;
+
+ case '{':
+ (void) popchar(s);
+ (void) pushstate(s, PARSE_OBJECT, PARSE_OBJECT_COMMA);
+ return;
+
+ case '[':
+ (void) popchar(s);
+ (void) pushstate(s, PARSE_ARRAY, PARSE_OBJECT_COMMA);
+ return;
+
+ default:
+ if (islower(c)) {
+ (void) pushstate(s, PARSE_BAREWORD, PARSE_OBJECT_COMMA);
+ return;
+ } else if (c == '-' || isdigit(c)) {
+ (void) pushstate(s, PARSE_NUMBER, PARSE_OBJECT_COMMA);
+ return;
+ } else {
+ (void) posterror(s, EPROTO, "unexpected character at "
+ "start of value");
+ return;
+ }
+ }
+}
+
+static void
+hdlr_object_comma(state_t *s)
+{
+ discard_whitespace(s);
+
+ switch (popchar(s)) {
+ case '}':
+ movestate(s, PARSE_DONE);
+ return;
+
+ case ',':
+ discard_whitespace(s);
+ if (popchar(s) != '"') {
+ posterror(s, EPROTO, "expected '\"'");
+ return;
+ }
+ movestate(s, PARSE_KEY_STRING);
+ return;
+
+ default:
+ posterror(s, EPROTO, "expected ',' or '}'");
+ return;
+ }
+}
+
+static void
+hdlr_string(state_t *s)
+{
+ if (collect_string(s) != 0) {
+ return;
+ }
+
+ s->s_top->pf_value_type = JSON_TYPE_STRING;
+ if ((s->s_top->pf_value = strdup(custr_cstr(s->s_collect))) == NULL) {
+ posterror(s, errno, "strdup failure");
+ return;
+ }
+
+ movestate(s, PARSE_DONE);
+}
+
+static int
+store_value(state_t *s)
+{
+ nvlist_t *targ = s->s_top->pf_next->pf_nvl;
+ char *key = s->s_top->pf_next->pf_key;
+ json_type_t type = s->s_top->pf_value_type;
+ int ret = 0;
+
+ switch (type) {
+ case JSON_TYPE_STRING:
+ if (nvlist_add_string(targ, key, s->s_top->pf_value) != 0) {
+ posterror(s, errno, "nvlist_add_string failure");
+ ret = -1;
+ }
+ free(s->s_top->pf_value);
+ break;
+
+ case JSON_TYPE_BOOLEAN:
+ if (nvlist_add_boolean_value(targ, key,
+ (boolean_t)s->s_top->pf_value) != 0) {
+ posterror(s, errno, "nvlist_add_boolean_value "
+ "failure");
+ ret = -1;
+ }
+ break;
+
+ case JSON_TYPE_NULL:
+ if (nvlist_add_boolean(targ, key) != 0) {
+ posterror(s, errno, "nvlist_add_boolean failure");
+ ret = -1;
+ }
+ break;
+
+ case JSON_TYPE_INTEGER:
+ if (nvlist_add_int32(targ, key,
+ (int32_t)(uintptr_t)s->s_top->pf_value) != 0) {
+ posterror(s, errno, "nvlist_add_int32 failure");
+ ret = -1;
+ }
+ break;
+
+ case JSON_TYPE_ARRAY:
+ case JSON_TYPE_OBJECT:
+ /*
+ * Objects and arrays are already 'stored' in their target
+ * nvlist on creation. See: hdlr_object, hdlr_array.
+ */
+ break;
+
+ default:
+ (void) fprintf(stderr, "ERROR: could not store unknown "
+ "type %d\n", type);
+ abort();
+ }
+
+ s->s_top->pf_value = NULL;
+ free(s->s_top->pf_next->pf_key);
+ s->s_top->pf_next->pf_key = NULL;
+ return (ret);
+}
+
+static parse_frame_t *
+parse_frame_free(parse_frame_t *pf, boolean_t free_nvl)
+{
+ parse_frame_t *next = pf->pf_next;
+ if (pf->pf_key != NULL) {
+ free(pf->pf_key);
+ }
+ if (pf->pf_value != NULL) {
+ abort();
+ }
+ if (free_nvl && pf->pf_nvl != NULL) {
+ nvlist_free(pf->pf_nvl);
+ }
+ free(pf);
+ return (next);
+}
+
+static parse_handler_t hdlrs[] = {
+ NULL, /* PARSE_DONE */
+ hdlr_rest, /* PARSE_REST */
+ hdlr_object, /* PARSE_OBJECT */
+ hdlr_key_string, /* PARSE_KEY_STRING */
+ hdlr_colon, /* PARSE_COLON */
+ hdlr_string, /* PARSE_STRING */
+ hdlr_object_comma, /* PARSE_OBJECT_COMMA */
+ hdlr_array, /* PARSE_ARRAY */
+ hdlr_bareword, /* PARSE_BAREWORD */
+ hdlr_number, /* PARSE_NUMBER */
+ hdlr_array_value, /* PARSE_ARRAY_VALUE */
+ hdlr_array_comma /* PARSE_ARRAY_COMMA */
+};
+#define NUM_PARSE_HANDLERS (int)(sizeof (hdlrs) / sizeof (hdlrs[0]))
+
+int
+nvlist_parse_json(const char *buf, size_t buflen, nvlist_t **nvlp,
+ nvlist_parse_json_flags_t flag, nvlist_parse_json_error_t *errout)
+{
+ state_t s;
+
+ /*
+ * Check for valid flags:
+ */
+ if ((flag & NVJSON_FORCE_INTEGER) && (flag & NVJSON_FORCE_DOUBLE)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((flag & ~NVJSON_ALL) != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /*
+ * Initialise parsing state structure:
+ */
+ bzero(&s, sizeof (s));
+ s.s_in = buf;
+ s.s_pos = 0;
+ s.s_len = buflen;
+ s.s_flags = flag;
+
+ /*
+ * Allocate the collect buffer string.
+ */
+ if (custr_alloc(&s.s_collect) != 0) {
+ s.s_errno = errno;
+ if (errout != NULL) {
+ (void) snprintf(errout->nje_message,
+ sizeof (errout->nje_message),
+ "custr alloc failure: %s",
+ strerror(errno));
+ }
+ goto out;
+ }
+
+ /*
+ * If the caller has requested error information, allocate the error
+ * string now.
+ */
+ if (errout != NULL) {
+ if (custr_alloc_buf(&s.s_errstr, errout->nje_message,
+ sizeof (errout->nje_message)) != 0) {
+ s.s_errno = errno;
+ (void) snprintf(errout->nje_message,
+ sizeof (errout->nje_message),
+ "custr alloc failure: %s",
+ strerror(errno));
+ goto out;
+ }
+ custr_reset(s.s_errstr);
+ }
+
+ /*
+ * Allocate top-most stack frame:
+ */
+ if ((s.s_top = calloc(1, sizeof (*s.s_top))) == NULL) {
+ s.s_errno = errno;
+ goto out;
+ }
+
+ s.s_top->pf_ps = PARSE_REST;
+ for (;;) {
+ if (s.s_top->pf_ps < 0) {
+ /*
+ * The parser reported an error.
+ */
+ goto out;
+ }
+
+ if (s.s_top->pf_ps == PARSE_DONE) {
+ if (s.s_top->pf_next == NULL) {
+ /*
+ * Last frame, so we're really
+ * done.
+ */
+ *nvlp = s.s_top->pf_nvl;
+ goto out;
+ } else {
+ /*
+ * Otherwise, pop a frame and continue in
+ * previous state. Copy out the value we
+ * created in the old frame:
+ */
+ if (store_value(&s) != 0) {
+ goto out;
+ }
+
+ /*
+ * Free old frame:
+ */
+ s.s_top = parse_frame_free(s.s_top, B_FALSE);
+ }
+ }
+
+ /*
+ * Dispatch to parser handler routine for this state:
+ */
+ if (s.s_top->pf_ps >= NUM_PARSE_HANDLERS ||
+ hdlrs[s.s_top->pf_ps] == NULL) {
+ (void) fprintf(stderr, "no handler for state %d\n",
+ s.s_top->pf_ps);
+ abort();
+ }
+ hdlrs[s.s_top->pf_ps](&s);
+ }
+
+out:
+ if (errout != NULL) {
+ /*
+ * Copy out error number and parse position. The custr_t for
+ * the error message was backed by the buffer in the error
+ * object, so no copying is required.
+ */
+ errout->nje_errno = s.s_errno;
+ errout->nje_pos = s.s_pos;
+ }
+
+ /*
+ * Free resources:
+ */
+ while (s.s_top != NULL) {
+ s.s_top = parse_frame_free(s.s_top, s.s_errno == 0 ? B_FALSE :
+ B_TRUE);
+ }
+ custr_free(s.s_collect);
+ custr_free(s.s_errstr);
+
+ errno = s.s_errno;
+ return (s.s_errno == 0 ? 0 : -1);
+}
diff --git a/usr/src/lib/varpd/files/common/libvarpd_files_json.h b/usr/src/lib/varpd/files/common/libvarpd_files_json.h
new file mode 100644
index 0000000000..9fe765741b
--- /dev/null
+++ b/usr/src/lib/varpd/files/common/libvarpd_files_json.h
@@ -0,0 +1,52 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018 Joyent, Inc.
+ */
+
+#ifndef _LIBVARPD_FILES_JSON_H
+#define _LIBVARPD_FILES_JSON_H
+
+#include <libnvpair.h>
+#include <libcustr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum nvlist_parse_json_flags {
+ NVJSON_FORCE_INTEGER = 0x01,
+ NVJSON_FORCE_DOUBLE = 0x02,
+ NVJSON_ERRORS_TO_STDERR = 0x04,
+ NVJSON_DEBUG = 0x08
+} nvlist_parse_json_flags_t;
+
+typedef struct nvlist_parse_json_error {
+ int nje_errno;
+ long nje_pos;
+ char nje_message[512];
+} nvlist_parse_json_error_t;
+
+#define NVJSON_ALL \
+ (NVJSON_FORCE_INTEGER | \
+ NVJSON_FORCE_DOUBLE | \
+ NVJSON_ERRORS_TO_STDERR | \
+ NVJSON_DEBUG)
+
+extern int nvlist_parse_json(const char *, size_t, nvlist_t **,
+ nvlist_parse_json_flags_t, nvlist_parse_json_error_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBVARPD_FILES_JSON_H */
diff --git a/usr/src/lib/varpd/files/common/mapfile-vers b/usr/src/lib/varpd/files/common/mapfile-vers
new file mode 100644
index 0000000000..6b7c5a5067
--- /dev/null
+++ b/usr/src/lib/varpd/files/common/mapfile-vers
@@ -0,0 +1,35 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ local:
+ *;
+};
diff --git a/usr/src/lib/varpd/files/i386/Makefile b/usr/src/lib/varpd/files/i386/Makefile
new file mode 100644
index 0000000000..4398507523
--- /dev/null
+++ b/usr/src/lib/varpd/files/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/varpd/libvarpd/Makefile b/usr/src/lib/varpd/libvarpd/Makefile
new file mode 100644
index 0000000000..034ba30c1d
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/Makefile
@@ -0,0 +1,54 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../../Makefile.lib
+
+HDRS = libvarpd.h libvarpd_client.h libvarpd_provider.h
+HDRDIR = common
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+TYPECHECK_LIB = libvarpd.so.1
+TYPELIST = \
+ varpd_client_instance_arg_t \
+ varpd_client_nprops_arg_t \
+ varpd_client_propinfo_arg_t \
+ varpd_client_eresp_t \
+ varpd_persist_header_t \
+ overlay_targ_cache_entry_t \
+ overlay_targ_cache_t \
+ overlay_targ_cache_iter_t
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+
+.KEEP_STATE:
+
+all clean clobber: $(SUBDIRS)
+
+install: $(SUBDIRS) $(VARPD_MAPFILES) install_h
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS) $(TYPECHECK)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/varpd/libvarpd/Makefile.com b/usr/src/lib/varpd/libvarpd/Makefile.com
new file mode 100644
index 0000000000..73e8f17883
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/Makefile.com
@@ -0,0 +1,48 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+LIBRARY = libvarpd.a
+VERS = .1
+OBJECTS = libvarpd.o \
+ libvarpd_arp.o \
+ libvarpd_client.o \
+ libvarpd_door.o \
+ libvarpd_overlay.o \
+ libvarpd_panic.o \
+ libvarpd_persist.o \
+ libvarpd_prop.o \
+ libvarpd_plugin.o \
+ libvarpd_util.o
+
+include ../../../Makefile.lib
+
+# install this library in the root filesystem
+include ../../../Makefile.rootfs
+
+LIBS = $(DYNLIB)
+LDLIBS += -lc -lavl -lumem -lidspace -lnvpair -lmd5 -lrename
+CPPFLAGS += -I../common
+
+CERRWARN += -erroff=E_STRUCT_DERIVED_FROM_FLEX_MBR
+
+CSTD= $(CSTD_GNU99)
+
+SRCDIR = ../common
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+include ../../../Makefile.targ
diff --git a/usr/src/lib/varpd/libvarpd/amd64/Makefile b/usr/src/lib/varpd/libvarpd/amd64/Makefile
new file mode 100644
index 0000000000..1881990d79
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/amd64/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd.c b/usr/src/lib/varpd/libvarpd/common/libvarpd.c
new file mode 100644
index 0000000000..4e4c189a43
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd.c
@@ -0,0 +1,345 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * varpd library
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <umem.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/avl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <strings.h>
+
+#include <libvarpd_impl.h>
+
+static int
+libvarpd_instance_comparator(const void *lp, const void *rp)
+{
+ const varpd_instance_t *lpp, *rpp;
+ lpp = lp;
+ rpp = rp;
+
+ if (lpp->vri_id > rpp->vri_id)
+ return (1);
+ if (lpp->vri_id < rpp->vri_id)
+ return (-1);
+ return (0);
+}
+
+static int
+libvarpd_instance_lcomparator(const void *lp, const void *rp)
+{
+ const varpd_instance_t *lpp, *rpp;
+ lpp = lp;
+ rpp = rp;
+
+ if (lpp->vri_linkid > rpp->vri_linkid)
+ return (1);
+ if (lpp->vri_linkid < rpp->vri_linkid)
+ return (-1);
+ return (0);
+}
+
+int
+libvarpd_create(varpd_handle_t **vphp)
+{
+ int ret;
+ varpd_impl_t *vip;
+ char buf[32];
+
+ if (vphp == NULL)
+ return (EINVAL);
+
+ *vphp = NULL;
+ vip = umem_alloc(sizeof (varpd_impl_t), UMEM_DEFAULT);
+ if (vip == NULL)
+ return (errno);
+
+ bzero(vip, sizeof (varpd_impl_t));
+ (void) snprintf(buf, sizeof (buf), "varpd_%p", vip);
+ vip->vdi_idspace = id_space_create(buf, LIBVARPD_ID_MIN,
+ LIBVARPD_ID_MAX);
+ if (vip->vdi_idspace == NULL) {
+ int ret = errno;
+ umem_free(vip, sizeof (varpd_impl_t));
+ return (ret);
+ }
+
+ vip->vdi_qcache = umem_cache_create("query", sizeof (varpd_query_t), 0,
+ NULL, NULL, NULL, NULL, NULL, 0);
+ if (vip->vdi_qcache == NULL) {
+ int ret = errno;
+ id_space_destroy(vip->vdi_idspace);
+ umem_free(vip, sizeof (varpd_impl_t));
+ return (ret);
+ }
+
+ if ((ret = libvarpd_overlay_init(vip)) != 0) {
+ umem_cache_destroy(vip->vdi_qcache);
+ id_space_destroy(vip->vdi_idspace);
+ umem_free(vip, sizeof (varpd_impl_t));
+ return (ret);
+ }
+
+ libvarpd_persist_init(vip);
+
+ avl_create(&vip->vdi_plugins, libvarpd_plugin_comparator,
+ sizeof (varpd_plugin_t), offsetof(varpd_plugin_t, vpp_node));
+
+ avl_create(&vip->vdi_instances, libvarpd_instance_comparator,
+ sizeof (varpd_instance_t), offsetof(varpd_instance_t, vri_inode));
+ avl_create(&vip->vdi_linstances, libvarpd_instance_lcomparator,
+ sizeof (varpd_instance_t), offsetof(varpd_instance_t, vri_lnode));
+
+ if (mutex_init(&vip->vdi_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL) != 0)
+ libvarpd_panic("failed to create mutex: %d", errno);
+
+ vip->vdi_doorfd = -1;
+ *vphp = (varpd_handle_t *)vip;
+ return (0);
+}
+
+void
+libvarpd_destroy(varpd_handle_t *vhp)
+{
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+
+ libvarpd_overlay_lookup_quiesce(vhp);
+ if (mutex_destroy(&vip->vdi_lock) != 0)
+ libvarpd_panic("failed to destroy mutex: %d", errno);
+ libvarpd_persist_fini(vip);
+ libvarpd_overlay_fini(vip);
+ umem_cache_destroy(vip->vdi_qcache);
+ id_space_destroy(vip->vdi_idspace);
+ umem_free(vip, sizeof (varpd_impl_t));
+}
+
+int
+libvarpd_instance_create(varpd_handle_t *vhp, datalink_id_t linkid,
+ const char *pname, varpd_instance_handle_t **outp)
+{
+ int ret;
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+ varpd_plugin_t *plugin;
+ varpd_instance_t *inst, lookup;
+ overlay_plugin_dest_t dest;
+ uint64_t vid;
+
+ /*
+ * We should really have our own errnos.
+ */
+ plugin = libvarpd_plugin_lookup(vip, pname);
+ if (plugin == NULL)
+ return (ENOENT);
+
+ if ((ret = libvarpd_overlay_info(vip, linkid, &dest, NULL, &vid)) != 0)
+ return (ret);
+
+ inst = umem_alloc(sizeof (varpd_instance_t), UMEM_DEFAULT);
+ if (inst == NULL)
+ return (ENOMEM);
+
+ inst->vri_id = id_alloc(vip->vdi_idspace);
+ if (inst->vri_id == -1)
+ libvarpd_panic("failed to allocate id from vdi_idspace: %d",
+ errno);
+ inst->vri_linkid = linkid;
+ inst->vri_vnetid = vid;
+ inst->vri_mode = plugin->vpp_mode;
+ inst->vri_dest = dest;
+ inst->vri_plugin = plugin;
+ inst->vri_impl = vip;
+ inst->vri_flags = 0;
+ if ((ret = plugin->vpp_ops->vpo_create((varpd_provider_handle_t *)inst,
+ &inst->vri_private, dest)) != 0) {
+ id_free(vip->vdi_idspace, inst->vri_id);
+ umem_free(inst, sizeof (varpd_instance_t));
+ return (ret);
+ }
+
+ if (mutex_init(&inst->vri_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL) != 0)
+ libvarpd_panic("failed to create mutex: %d", errno);
+
+ mutex_enter(&vip->vdi_lock);
+ lookup.vri_id = inst->vri_id;
+ if (avl_find(&vip->vdi_instances, &lookup, NULL) != NULL)
+ libvarpd_panic("found duplicate instance with id %d",
+ lookup.vri_id);
+ avl_add(&vip->vdi_instances, inst);
+ lookup.vri_linkid = inst->vri_linkid;
+ if (avl_find(&vip->vdi_linstances, &lookup, NULL) != NULL)
+ libvarpd_panic("found duplicate linstance with id %d",
+ lookup.vri_linkid);
+ avl_add(&vip->vdi_linstances, inst);
+ mutex_exit(&vip->vdi_lock);
+ *outp = (varpd_instance_handle_t *)inst;
+ return (0);
+}
+
+uint64_t
+libvarpd_instance_id(varpd_instance_handle_t *ihp)
+{
+ varpd_instance_t *inst = (varpd_instance_t *)ihp;
+ return (inst->vri_id);
+}
+
+uint64_t
+libvarpd_plugin_vnetid(varpd_provider_handle_t *vhp)
+{
+ varpd_instance_t *inst = (varpd_instance_t *)vhp;
+ return (inst->vri_vnetid);
+}
+
+varpd_instance_handle_t *
+libvarpd_instance_lookup(varpd_handle_t *vhp, uint64_t id)
+{
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+ varpd_instance_t lookup, *retp;
+
+ lookup.vri_id = id;
+ mutex_enter(&vip->vdi_lock);
+ retp = avl_find(&vip->vdi_instances, &lookup, NULL);
+ mutex_exit(&vip->vdi_lock);
+ return ((varpd_instance_handle_t *)retp);
+}
+
+/*
+ * If this function becomes external to varpd, we need to change it to return a
+ * varpd_instance_handle_t.
+ */
+varpd_instance_t *
+libvarpd_instance_lookup_by_dlid(varpd_impl_t *vip, datalink_id_t linkid)
+{
+ varpd_instance_t lookup, *retp;
+
+ lookup.vri_linkid = linkid;
+ mutex_enter(&vip->vdi_lock);
+ retp = avl_find(&vip->vdi_linstances, &lookup, NULL);
+ mutex_exit(&vip->vdi_lock);
+ return (retp);
+}
+
+/*
+ * When an instance is being destroyed, that means we should deactivate it, as
+ * well as clean it up. That means here, the proper order is calling the plug-in
+ * stop and then the destroy function.
+ */
+void
+libvarpd_instance_destroy(varpd_instance_handle_t *ihp)
+{
+ varpd_instance_t *inst = (varpd_instance_t *)ihp;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ /*
+ * First things first, remove it from global visibility.
+ */
+ mutex_enter(&vip->vdi_lock);
+ avl_remove(&vip->vdi_instances, inst);
+ avl_remove(&vip->vdi_linstances, inst);
+ mutex_exit(&vip->vdi_lock);
+
+ mutex_enter(&inst->vri_lock);
+
+ /*
+ * We need to clean up this instance, that means remove it from
+ * persistence and stopping it. Then finally we'll have to clean it up
+ * entirely.
+ */
+ if (inst->vri_flags & VARPD_INSTANCE_F_ACTIVATED) {
+ inst->vri_flags &= ~VARPD_INSTANCE_F_ACTIVATED;
+ libvarpd_torch_instance(vip, inst);
+ inst->vri_plugin->vpp_ops->vpo_stop(inst->vri_private);
+ inst->vri_plugin->vpp_ops->vpo_destroy(inst->vri_private);
+ inst->vri_private = NULL;
+ }
+ mutex_exit(&inst->vri_lock);
+
+ /* Do the full clean up of the instance */
+ if (mutex_destroy(&inst->vri_lock) != 0)
+ libvarpd_panic("failed to destroy instance vri_lock");
+ id_free(vip->vdi_idspace, inst->vri_id);
+ umem_free(inst, sizeof (varpd_instance_t));
+}
+
+int
+libvarpd_instance_activate(varpd_instance_handle_t *ihp)
+{
+ int ret;
+ varpd_instance_t *inst = (varpd_instance_t *)ihp;
+
+ mutex_enter(&inst->vri_lock);
+
+ if (inst->vri_flags & VARPD_INSTANCE_F_ACTIVATED) {
+ ret = EEXIST;
+ goto out;
+ }
+
+ if ((ret = inst->vri_plugin->vpp_ops->vpo_start(inst->vri_private)) !=
+ 0)
+ goto out;
+
+ if ((ret = libvarpd_persist_instance(inst->vri_impl, inst)) != 0)
+ goto out;
+
+ /*
+ * If this fails, we don't need to call stop, as the caller should end
+ * up calling destroy on the instance, which takes care of calling stop
+ * and destroy.
+ */
+ if ((ret = libvarpd_overlay_associate(inst)) != 0)
+ goto out;
+
+ inst->vri_flags |= VARPD_INSTANCE_F_ACTIVATED;
+
+out:
+ mutex_exit(&inst->vri_lock);
+ return (ret);
+}
+
+static void
+libvarpd_prefork(void)
+{
+ libvarpd_plugin_prefork();
+}
+
+static void
+libvarpd_postfork(void)
+{
+ libvarpd_plugin_postfork();
+}
+
+#pragma init(libvarpd_init)
+static void
+libvarpd_init(void)
+{
+ libvarpd_plugin_init();
+ if (pthread_atfork(libvarpd_prefork, libvarpd_postfork,
+ libvarpd_postfork) != 0)
+ libvarpd_panic("failed to create varpd atfork: %d", errno);
+}
+
+#pragma fini(libvarpd_fini)
+static void
+libvarpd_fini(void)
+{
+ libvarpd_plugin_fini();
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd.h b/usr/src/lib/varpd/libvarpd/common/libvarpd.h
new file mode 100644
index 0000000000..106d4272d9
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd.h
@@ -0,0 +1,77 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _LIBVARPD_H
+#define _LIBVARPD_H
+
+/*
+ * varpd interfaces
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <sys/mac.h>
+#include <libvarpd_client.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct __varpd_handle varpd_handle_t;
+typedef struct __varpd_prop_handle varpd_prop_handle_t;
+typedef struct __varpd_instance_handle varpd_instance_handle_t;
+
+extern int libvarpd_create(varpd_handle_t **);
+extern void libvarpd_destroy(varpd_handle_t *);
+
+extern int libvarpd_persist_enable(varpd_handle_t *, const char *);
+extern int libvarpd_persist_restore(varpd_handle_t *);
+extern int libvarpd_persist_disable(varpd_handle_t *);
+
+extern int libvarpd_instance_create(varpd_handle_t *, datalink_id_t,
+ const char *, varpd_instance_handle_t **);
+extern uint64_t libvarpd_instance_id(varpd_instance_handle_t *);
+extern varpd_instance_handle_t *libvarpd_instance_lookup(varpd_handle_t *,
+ uint64_t);
+extern void libvarpd_instance_destroy(varpd_instance_handle_t *);
+extern int libvarpd_instance_activate(varpd_instance_handle_t *);
+
+extern int libvarpd_plugin_load(varpd_handle_t *, const char *);
+typedef int (*libvarpd_plugin_walk_f)(varpd_handle_t *, const char *, void *);
+extern int libvarpd_plugin_walk(varpd_handle_t *, libvarpd_plugin_walk_f,
+ void *);
+
+extern int libvarpd_prop_handle_alloc(varpd_handle_t *,
+ varpd_instance_handle_t *, varpd_prop_handle_t **);
+extern void libvarpd_prop_handle_free(varpd_prop_handle_t *);
+extern int libvarpd_prop_nprops(varpd_instance_handle_t *, uint_t *);
+extern int libvarpd_prop_info_fill(varpd_prop_handle_t *, uint_t);
+extern int libvarpd_prop_info(varpd_prop_handle_t *, const char **, uint_t *,
+ uint_t *, const void **, uint32_t *, const mac_propval_range_t **);
+extern int libvarpd_prop_get(varpd_prop_handle_t *, void *, uint32_t *);
+extern int libvarpd_prop_set(varpd_prop_handle_t *, const void *, uint32_t);
+
+extern int libvarpd_door_server_create(varpd_handle_t *, const char *);
+extern void libvarpd_door_server_destroy(varpd_handle_t *);
+
+extern void *libvarpd_overlay_lookup_run(void *);
+extern void libvarpd_overlay_lookup_quiesce(varpd_handle_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBVARPD_H */
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_arp.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_arp.c
new file mode 100644
index 0000000000..7180fcb2de
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_arp.c
@@ -0,0 +1,649 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Common routines for implementing proxy arp
+ */
+
+#include <sys/types.h>
+#include <net/if.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet/udp.h>
+#include <netinet/dhcp.h>
+#include <libvarpd_impl.h>
+#include <sys/vlan.h>
+#include <strings.h>
+#include <assert.h>
+
+#define IPV6_VERSION 6
+
+typedef struct varpd_arp_query {
+ int vaq_type;
+ char vaq_buf[ETHERMAX + VLAN_TAGSZ];
+ size_t vaq_bsize;
+ uint8_t vaq_lookup[ETHERADDRL];
+ struct sockaddr_storage vaq_sock;
+ varpd_instance_t *vaq_inst;
+ struct ether_arp *vaq_ea;
+ varpd_query_handle_t *vaq_query;
+ const overlay_targ_lookup_t *vaq_otl;
+ ip6_t *vaq_ip6;
+ nd_neighbor_solicit_t *vaq_ns;
+} varpd_arp_query_t;
+
+typedef struct varpd_dhcp_query {
+ char vdq_buf[ETHERMAX + VLAN_TAGSZ];
+ size_t vdq_bsize;
+ uint8_t vdq_lookup[ETHERADDRL];
+ const overlay_targ_lookup_t *vdq_otl;
+ varpd_instance_t *vdq_inst;
+ varpd_query_handle_t *vdq_query;
+ struct ether_header *vdq_ether;
+} varpd_dhcp_query_t;
+
+static const uint8_t libvarpd_arp_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff };
+
+void
+libvarpd_plugin_proxy_arp(varpd_provider_handle_t *hdl,
+ varpd_query_handle_t *vqh, const overlay_targ_lookup_t *otl)
+{
+ varpd_arp_query_t *vaq;
+ varpd_instance_t *inst = (varpd_instance_t *)hdl;
+ struct ether_arp *ea;
+ struct sockaddr_in *ip;
+
+ vaq = umem_alloc(sizeof (varpd_arp_query_t), UMEM_DEFAULT);
+ if (vaq == NULL) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ return;
+ }
+ vaq->vaq_bsize = sizeof (vaq->vaq_buf);
+
+ if (otl->otl_sap != ETHERTYPE_ARP) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ /*
+ * An ARP packet should not be very large because it's definited to only
+ * be allowed to have a single entry at a given time. But our data must
+ * be at least as large as an ether_arp and our header must be at least
+ * as large as a standard ethernet header.
+ */
+ if (otl->otl_hdrsize + otl->otl_pktsize > vaq->vaq_bsize ||
+ otl->otl_pktsize < sizeof (struct ether_arp) ||
+ otl->otl_hdrsize < sizeof (struct ether_header)) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ if (libvarpd_overlay_packet(inst->vri_impl, otl, vaq->vaq_buf,
+ &vaq->vaq_bsize) != 0) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ if (otl->otl_hdrsize + otl->otl_pktsize < vaq->vaq_bsize) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ ea = (void *)((uintptr_t)vaq->vaq_buf + (uintptr_t)otl->otl_hdrsize);
+
+ /*
+ * Make sure it matches something that we know about.
+ */
+ if (ntohs(ea->ea_hdr.ar_hrd) != ARPHRD_ETHER ||
+ ntohs(ea->ea_hdr.ar_pro) != ETHERTYPE_IP ||
+ ea->ea_hdr.ar_hln != ETHERADDRL ||
+ ea->ea_hdr.ar_pln != sizeof (ea->arp_spa) ||
+ ntohs(ea->ea_hdr.ar_op) != ARPOP_REQUEST) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ /*
+ * Now that we've verified that our data is sane, see if we're doing a
+ * gratuitous arp and if so, drop it. Otherwise, we may end up
+ * triggering duplicate address detection.
+ */
+ if (bcmp(ea->arp_spa, ea->arp_tpa, sizeof (ea->arp_spa)) == 0) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ bzero(&vaq->vaq_sock, sizeof (struct sockaddr_storage));
+ ip = (struct sockaddr_in *)&vaq->vaq_sock;
+ ip->sin_family = AF_INET;
+ bcopy(ea->arp_tpa, &ip->sin_addr, sizeof (ea->arp_tpa));
+
+ vaq->vaq_type = AF_INET;
+ vaq->vaq_inst = inst;
+ vaq->vaq_ea = ea;
+ vaq->vaq_query = vqh;
+ vaq->vaq_otl = otl;
+
+ if (inst->vri_plugin->vpp_ops->vpo_arp == NULL)
+ libvarpd_panic("%s plugin asked to do arp, but has no method",
+ inst->vri_plugin->vpp_name);
+
+ inst->vri_plugin->vpp_ops->vpo_arp(inst->vri_private,
+ (varpd_arp_handle_t *)vaq, VARPD_QTYPE_ETHERNET,
+ (struct sockaddr *)ip, vaq->vaq_lookup);
+}
+
+static void
+libvarpd_proxy_arp_fini(varpd_arp_query_t *vaq)
+{
+ struct ether_header *ether;
+ struct sockaddr_in *ip;
+
+ ip = (struct sockaddr_in *)&vaq->vaq_sock;
+ /*
+ * Modify our packet in place for a reply. We need to swap around the
+ * sender and target addresses.
+ */
+ vaq->vaq_ea->ea_hdr.ar_op = htons(ARPOP_REPLY);
+ bcopy(vaq->vaq_ea->arp_sha, vaq->vaq_ea->arp_tha, ETHERADDRL);
+ bcopy(vaq->vaq_lookup, vaq->vaq_ea->arp_sha, ETHERADDRL);
+ bcopy(vaq->vaq_ea->arp_spa, &ip->sin_addr,
+ sizeof (vaq->vaq_ea->arp_spa));
+ bcopy(vaq->vaq_ea->arp_tpa, vaq->vaq_ea->arp_spa,
+ sizeof (vaq->vaq_ea->arp_spa));
+ bcopy(&ip->sin_addr, vaq->vaq_ea->arp_tpa,
+ sizeof (vaq->vaq_ea->arp_spa));
+
+ /*
+ * Finally go ahead and fix up the mac header and reply to the sender
+ * explicitly.
+ */
+ ether = (struct ether_header *)vaq->vaq_buf;
+ bcopy(&ether->ether_shost, &ether->ether_dhost, ETHERADDRL);
+ bcopy(vaq->vaq_lookup, &ether->ether_shost, ETHERADDRL);
+
+ (void) libvarpd_overlay_inject(vaq->vaq_inst->vri_impl, vaq->vaq_otl,
+ vaq->vaq_buf, vaq->vaq_bsize);
+
+ libvarpd_plugin_query_reply(vaq->vaq_query, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+}
+
+static uint16_t
+libvarpd_icmpv6_checksum(const ip6_t *v6hdr, const uint16_t *buf, uint16_t mlen)
+{
+ int i;
+ uint16_t *v;
+ uint32_t sum = 0;
+
+ assert(mlen % 2 == 0);
+ v = (uint16_t *)&v6hdr->ip6_src;
+ for (i = 0; i < sizeof (struct in6_addr); i += 2, v++)
+ sum += *v;
+ v = (uint16_t *)&v6hdr->ip6_dst;
+ for (i = 0; i < sizeof (struct in6_addr); i += 2, v++)
+ sum += *v;
+ sum += htons(mlen);
+#ifdef _BIG_ENDIAN
+ sum += IPPROTO_ICMPV6;
+#else
+ sum += IPPROTO_ICMPV6 << 8;
+#endif /* _BIG_ENDIAN */
+
+ for (i = 0; i < mlen; i += 2, buf++)
+ sum += *buf;
+
+ while ((sum >> 16) != 0)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ return (sum & 0xffff);
+}
+
+/*
+ * Proxying NDP is much more involved than proxying ARP. For starters, NDP
+ * neighbor solicitations are implemented in terms of IPv6 ICMP as opposed to
+ * its own Ethertype. Therefore, we're going to have to grab a packet if it's a
+ * multicast packet and then determine if we actually want to do anything with
+ * it.
+ */
+void
+libvarpd_plugin_proxy_ndp(varpd_provider_handle_t *hdl,
+ varpd_query_handle_t *vqh, const overlay_targ_lookup_t *otl)
+{
+ size_t bsize, plen;
+ varpd_arp_query_t *vaq;
+ ip6_t *v6hdr;
+ nd_neighbor_solicit_t *ns;
+ nd_opt_hdr_t *opt;
+ struct sockaddr_in6 *s6;
+
+ varpd_instance_t *inst = (varpd_instance_t *)hdl;
+ uint8_t *eth = NULL;
+
+ vaq = umem_alloc(sizeof (varpd_arp_query_t), UMEM_DEFAULT);
+ if (vaq == NULL) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ return;
+ }
+ vaq->vaq_bsize = sizeof (vaq->vaq_buf);
+
+ if (otl->otl_dstaddr[0] != 0x33 ||
+ otl->otl_dstaddr[1] != 0x33) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ /*
+ * If we have more than a standard frame size for the ICMP neighbor
+ * solicitation, drop it. Similarly if there isn't enough data present
+ * for us, drop it.
+ */
+ if (otl->otl_hdrsize + otl->otl_pktsize > vaq->vaq_bsize) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ if (otl->otl_pktsize < sizeof (ip6_t) +
+ sizeof (nd_neighbor_solicit_t)) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ if (libvarpd_overlay_packet(inst->vri_impl, otl, vaq->vaq_buf,
+ &vaq->vaq_bsize) != 0) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ bsize = vaq->vaq_bsize;
+ bsize -= otl->otl_hdrsize;
+ assert(bsize > sizeof (ip6_t));
+
+ v6hdr = (ip6_t *)(vaq->vaq_buf + otl->otl_hdrsize);
+ if (((v6hdr->ip6_vfc & 0xf0) >> 4) != IPV6_VERSION) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ if (v6hdr->ip6_nxt != IPPROTO_ICMPV6) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ /*
+ * In addition to getting these requests on the multicast address for
+ * node solicitation, we may also end up getting them on a generic
+ * multicast address due to timeouts or other choices by various OSes.
+ * We should fairly liberal and accept both, even though the standard
+ * wants them to a solicitation address.
+ */
+ if (!IN6_IS_ADDR_MC_SOLICITEDNODE(&v6hdr->ip6_dst) &&
+ !IN6_IS_ADDR_MC_LINKLOCAL(&v6hdr->ip6_dst)) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ bsize -= sizeof (ip6_t);
+ plen = ntohs(v6hdr->ip6_plen);
+ if (bsize < plen) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ /*
+ * Now we know that this is an ICMPv6 request targeting the right
+ * IPv6 multicast prefix. Let's go through and verify that ICMPv6
+ * indicates that we have the real thing and ensure that per RFC 4861
+ * the target address is not a multicast address. Further, because this
+ * is a multicast on Ethernet, we must have a source link-layer address.
+ *
+ * We should probably enforce that we have a valid ICMP checksum at some
+ * point.
+ */
+ ns = (nd_neighbor_solicit_t *)(vaq->vaq_buf + otl->otl_hdrsize +
+ sizeof (ip6_t));
+ if (ns->nd_ns_type != ND_NEIGHBOR_SOLICIT && ns->nd_ns_code != 0) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ if (IN6_IS_ADDR_MULTICAST(&ns->nd_ns_target) ||
+ IN6_IS_ADDR_V4MAPPED(&ns->nd_ns_target) ||
+ IN6_IS_ADDR_LOOPBACK(&ns->nd_ns_target)) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ plen -= sizeof (nd_neighbor_solicit_t);
+ opt = (nd_opt_hdr_t *)(ns+1);
+ while (plen >= sizeof (struct nd_opt_hdr)) {
+ /* If we have an option with no lenght, that's clear bogus */
+ if (opt->nd_opt_len == 0) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ if (opt->nd_opt_type == ND_OPT_SOURCE_LINKADDR) {
+ eth = (uint8_t *)((uintptr_t)opt +
+ sizeof (nd_opt_hdr_t));
+ }
+ plen -= opt->nd_opt_len * 8;
+ opt = (nd_opt_hdr_t *)((uintptr_t)opt +
+ opt->nd_opt_len * 8);
+ }
+
+ if (eth == NULL) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ }
+
+ bzero(&vaq->vaq_sock, sizeof (struct sockaddr_storage));
+ s6 = (struct sockaddr_in6 *)&vaq->vaq_sock;
+ s6->sin6_family = AF_INET6;
+ bcopy(&ns->nd_ns_target, &s6->sin6_addr, sizeof (s6->sin6_addr));
+
+ if (inst->vri_plugin->vpp_ops->vpo_arp == NULL)
+ libvarpd_panic("%s plugin asked to do arp, but has no method",
+ inst->vri_plugin->vpp_name);
+
+ vaq->vaq_type = AF_INET6;
+ vaq->vaq_inst = inst;
+ vaq->vaq_ea = NULL;
+ vaq->vaq_query = vqh;
+ vaq->vaq_otl = otl;
+ vaq->vaq_ns = ns;
+ vaq->vaq_ip6 = v6hdr;
+ inst->vri_plugin->vpp_ops->vpo_arp(inst->vri_private,
+ (varpd_arp_handle_t *)vaq, VARPD_QTYPE_ETHERNET,
+ (struct sockaddr *)s6, vaq->vaq_lookup);
+}
+
+static void
+libvarpd_proxy_ndp_fini(varpd_arp_query_t *vaq)
+{
+ char resp[ETHERMAX + VLAN_TAGSZ];
+ struct ether_header *ether;
+ nd_neighbor_advert_t *na;
+ nd_opt_hdr_t *opt;
+ ip6_t *v6hdr;
+ size_t roff = 0;
+
+ /*
+ * Now we need to assemble an RA as a response. Unlike with arp, we opt
+ * to use a new packet just to make things a bit simpler saner here.
+ */
+ v6hdr = vaq->vaq_ip6;
+ bcopy(vaq->vaq_buf, resp, vaq->vaq_otl->otl_hdrsize);
+ ether = (struct ether_header *)resp;
+ bcopy(&ether->ether_shost, &ether->ether_dhost, ETHERADDRL);
+ bcopy(vaq->vaq_lookup, &ether->ether_shost, ETHERADDRL);
+ roff += vaq->vaq_otl->otl_hdrsize;
+ bcopy(v6hdr, resp + roff, sizeof (ip6_t));
+ v6hdr = (ip6_t *)(resp + roff);
+ bcopy(&v6hdr->ip6_src, &v6hdr->ip6_dst, sizeof (struct in6_addr));
+ bcopy(&vaq->vaq_ns->nd_ns_target, &v6hdr->ip6_src,
+ sizeof (struct in6_addr));
+ roff += sizeof (ip6_t);
+ na = (nd_neighbor_advert_t *)(resp + roff);
+ na->nd_na_type = ND_NEIGHBOR_ADVERT;
+ na->nd_na_code = 0;
+ /*
+ * RFC 4443 defines that we should set the checksum to zero before we
+ * calculate it.
+ */
+ na->nd_na_cksum = 0;
+ /*
+ * Nota bene, the header <netinet/icmp6.h> has already transformed this
+ * into the appropriate host order. Don't use htonl.
+ */
+ na->nd_na_flags_reserved = ND_NA_FLAG_SOLICITED | ND_NA_FLAG_OVERRIDE;
+ bcopy(&vaq->vaq_ns->nd_ns_target, &na->nd_na_target,
+ sizeof (struct in6_addr));
+ roff += sizeof (nd_neighbor_advert_t);
+
+ opt = (nd_opt_hdr_t *)(resp + roff);
+ opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
+ opt->nd_opt_len = 1;
+ roff += sizeof (nd_opt_hdr_t);
+ bcopy(vaq->vaq_lookup, resp + roff, ETHERADDRL);
+ roff += ETHERADDRL;
+
+ /*
+ * Now that we've filled in the packet, go back and compute the checksum
+ * and fill in the IPv6 payload size.
+ */
+ v6hdr->ip6_plen = htons(roff - sizeof (ip6_t) -
+ vaq->vaq_otl->otl_hdrsize);
+ na->nd_na_cksum = ~libvarpd_icmpv6_checksum(v6hdr, (uint16_t *)na,
+ ntohs(v6hdr->ip6_plen)) & 0xffff;
+
+ (void) libvarpd_overlay_inject(vaq->vaq_inst->vri_impl, vaq->vaq_otl,
+ resp, roff);
+
+ libvarpd_plugin_query_reply(vaq->vaq_query, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+}
+
+void
+libvarpd_plugin_arp_reply(varpd_arp_handle_t *vah, int action)
+{
+ varpd_arp_query_t *vaq = (varpd_arp_query_t *)vah;
+
+ if (vaq == NULL)
+ libvarpd_panic("unknown plugin passed invalid "
+ "varpd_arp_handle_t");
+
+ if (action == VARPD_LOOKUP_DROP) {
+ libvarpd_plugin_query_reply(vaq->vaq_query, VARPD_LOOKUP_DROP);
+ umem_free(vaq, sizeof (varpd_arp_query_t));
+ return;
+ } else if (action != VARPD_LOOKUP_OK)
+ libvarpd_panic("%s plugin returned invalid action %d",
+ vaq->vaq_inst->vri_plugin->vpp_name, action);
+
+ switch (vaq->vaq_type) {
+ case AF_INET:
+ libvarpd_proxy_arp_fini(vaq);
+ break;
+ case AF_INET6:
+ libvarpd_proxy_ndp_fini(vaq);
+ break;
+ default:
+ libvarpd_panic("encountered unknown vaq_type: %d",
+ vaq->vaq_type);
+ }
+}
+
+void
+libvarpd_plugin_proxy_dhcp(varpd_provider_handle_t *hdl,
+ varpd_query_handle_t *vqh, const overlay_targ_lookup_t *otl)
+{
+ varpd_dhcp_query_t *vdq;
+ struct ether_header *ether;
+ struct ip *ip;
+ struct udphdr *udp;
+ varpd_instance_t *inst = (varpd_instance_t *)hdl;
+
+ vdq = umem_alloc(sizeof (varpd_dhcp_query_t), UMEM_DEFAULT);
+ if (vdq == NULL) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ return;
+ }
+ vdq->vdq_bsize = sizeof (vdq->vdq_buf);
+
+ if (otl->otl_sap != ETHERTYPE_IP) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ }
+
+ if (bcmp(otl->otl_dstaddr, libvarpd_arp_bcast, ETHERADDRL) != 0) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ }
+
+ if (otl->otl_hdrsize + otl->otl_pktsize > vdq->vdq_bsize ||
+ otl->otl_pktsize < sizeof (struct ip) + sizeof (struct udphdr) +
+ sizeof (struct dhcp) ||
+ otl->otl_hdrsize < sizeof (struct ether_header)) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ }
+
+ if (libvarpd_overlay_packet(inst->vri_impl, otl, vdq->vdq_buf,
+ &vdq->vdq_bsize) != 0) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ }
+
+ if (vdq->vdq_bsize != otl->otl_hdrsize + otl->otl_pktsize) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ }
+
+ ether = (struct ether_header *)vdq->vdq_buf;
+ ip = (struct ip *)(vdq->vdq_buf + otl->otl_hdrsize);
+
+ if (ip->ip_v != IPVERSION && ip->ip_p != IPPROTO_UDP) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ }
+
+ if (otl->otl_hdrsize + ip->ip_hl * 4 + sizeof (struct udphdr) >
+ vdq->vdq_bsize) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ }
+
+ udp = (struct udphdr *)(vdq->vdq_buf + otl->otl_hdrsize +
+ ip->ip_hl * 4);
+
+ if (ntohs(udp->uh_sport) != IPPORT_BOOTPC ||
+ ntohs(udp->uh_dport) != IPPORT_BOOTPS) {
+ libvarpd_plugin_query_reply(vqh, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ }
+
+ vdq->vdq_ether = ether;
+ vdq->vdq_inst = inst;
+ vdq->vdq_query = vqh;
+ vdq->vdq_otl = otl;
+
+ if (inst->vri_plugin->vpp_ops->vpo_dhcp == NULL)
+ libvarpd_panic("%s plugin asked to do dhcp, but has no method",
+ inst->vri_plugin->vpp_name);
+
+ inst->vri_plugin->vpp_ops->vpo_dhcp(inst->vri_private,
+ (varpd_dhcp_handle_t *)vdq, VARPD_QTYPE_ETHERNET, otl,
+ vdq->vdq_lookup);
+}
+
+void
+libvarpd_plugin_dhcp_reply(varpd_dhcp_handle_t *vdh, int action)
+{
+ varpd_dhcp_query_t *vdq = (varpd_dhcp_query_t *)vdh;
+
+ if (vdq == NULL)
+ libvarpd_panic("unknown plugin passed invalid "
+ "varpd_dhcp_handle_t");
+
+ if (action == VARPD_LOOKUP_DROP) {
+ libvarpd_plugin_query_reply(vdq->vdq_query, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+ return;
+ } else if (action != VARPD_LOOKUP_OK)
+ libvarpd_panic("%s plugin returned invalid action %d",
+ vdq->vdq_inst->vri_plugin->vpp_name, action);
+
+ bcopy(vdq->vdq_lookup, &vdq->vdq_ether->ether_dhost, ETHERADDRL);
+ (void) libvarpd_overlay_resend(vdq->vdq_inst->vri_impl, vdq->vdq_otl,
+ vdq->vdq_buf, vdq->vdq_bsize);
+
+ libvarpd_plugin_query_reply(vdq->vdq_query, VARPD_LOOKUP_DROP);
+ umem_free(vdq, sizeof (varpd_dhcp_query_t));
+}
+
+/*
+ * Inject a gratuitous ARP packet to the specified mac address.
+ */
+void
+libvarpd_inject_arp(varpd_provider_handle_t *vph, const uint16_t vlan,
+ const uint8_t *srcmac, const struct in_addr *srcip, const uint8_t *dstmac)
+{
+ char buf[500];
+ size_t bsize = 0;
+ struct ether_arp *ea;
+ varpd_instance_t *inst = (varpd_instance_t *)vph;
+
+ if (vlan != 0) {
+ struct ether_vlan_header *eh;
+ eh = (struct ether_vlan_header *)(buf + bsize);
+ bsize += sizeof (struct ether_vlan_header);
+ bcopy(dstmac, &eh->ether_dhost, ETHERADDRL);
+ bcopy(srcmac, &eh->ether_shost, ETHERADDRL);
+ eh->ether_tpid = htons(ETHERTYPE_VLAN);
+ eh->ether_tci = htons(VLAN_TCI(0, ETHER_CFI, vlan));
+ eh->ether_type = htons(ETHERTYPE_ARP);
+ } else {
+ struct ether_header *eh;
+ eh = (struct ether_header *)(buf + bsize);
+ bsize += sizeof (struct ether_header);
+ bcopy(dstmac, &eh->ether_dhost, ETHERADDRL);
+ bcopy(srcmac, &eh->ether_shost, ETHERADDRL);
+ eh->ether_type = htons(ETHERTYPE_ARP);
+ }
+
+ ea = (struct ether_arp *)(buf + bsize);
+ bsize += sizeof (struct ether_arp);
+ ea->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
+ ea->ea_hdr.ar_pro = htons(ETHERTYPE_IP);
+ ea->ea_hdr.ar_hln = ETHERADDRL;
+ ea->ea_hdr.ar_pln = sizeof (struct in_addr);
+ ea->ea_hdr.ar_op = htons(ARPOP_REQUEST);
+ bcopy(srcmac, ea->arp_sha, ETHERADDRL);
+ bcopy(srcip, ea->arp_spa, sizeof (struct in_addr));
+ bcopy(libvarpd_arp_bcast, ea->arp_tha, ETHERADDRL);
+ bcopy(srcip, ea->arp_tpa, sizeof (struct in_addr));
+
+ (void) libvarpd_overlay_instance_inject(inst, buf, bsize);
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_client.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_client.c
new file mode 100644
index 0000000000..1254c14e19
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_client.c
@@ -0,0 +1,626 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+/*
+ * varpd client interfaces
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <umem.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <door.h>
+
+#include <libvarpd_impl.h>
+
+typedef struct varpd_client {
+ int vcl_doorfd;
+} varpd_client_t;
+
+typedef struct varpd_client_prop_info {
+ varpd_client_t *vcprop_client;
+ uint64_t vcprop_instance;
+ uint_t vcprop_propid;
+ uint_t vcprop_type;
+ uint_t vcprop_prot;
+ uint32_t vcprop_defsize;
+ uint32_t vcprop_psize;
+ char vcprop_name[LIBVARPD_PROP_NAMELEN];
+ uint8_t vcprop_default[LIBVARPD_PROP_SIZEMAX];
+ uint8_t vcprop_poss[LIBVARPD_PROP_SIZEMAX];
+} varpd_client_prop_info_t;
+
+static int
+libvarpd_c_door_call(varpd_client_t *client, varpd_client_arg_t *argp,
+ size_t altsize)
+{
+ int ret;
+ door_arg_t darg;
+
+ darg.data_ptr = (char *)argp;
+ darg.desc_ptr = NULL;
+ darg.desc_num = 0;
+ darg.rbuf = (char *)argp;
+ if (altsize != 0) {
+ darg.data_size = altsize;
+ darg.rsize = altsize;
+ } else {
+ darg.data_size = sizeof (varpd_client_arg_t);
+ darg.rsize = sizeof (varpd_client_arg_t);
+ }
+
+ do {
+ ret = door_call(client->vcl_doorfd, &darg);
+ } while (ret != 0 && errno == EINTR);
+ if (ret != 0) {
+ switch (errno) {
+ case E2BIG:
+ case EFAULT:
+ case EINVAL:
+ case ENOTSUP:
+ case EOVERFLOW:
+ case ENFILE:
+ libvarpd_panic("unhandleable errno from door_call: %d",
+ errno);
+ }
+ ret = errno;
+ }
+
+ return (ret);
+}
+
+int
+libvarpd_c_create(varpd_client_handle_t **chpp, const char *doorname)
+{
+ varpd_client_t *client;
+
+ client = umem_alloc(sizeof (varpd_client_t), UMEM_DEFAULT);
+ if (client == NULL)
+ return (ENOMEM);
+
+ client->vcl_doorfd = open(doorname, O_RDWR);
+ if (client->vcl_doorfd < 0) {
+ int ret = errno;
+ umem_free(client, sizeof (varpd_client_t));
+ return (ret);
+ }
+
+ *chpp = (varpd_client_handle_t *)client;
+ return (0);
+}
+
+void
+libvarpd_c_destroy(varpd_client_handle_t *chp)
+{
+ varpd_client_t *client = (varpd_client_t *)chp;
+ if (close(client->vcl_doorfd) != 0)
+ libvarpd_panic("failed to close door fd %d: %d",
+ client->vcl_doorfd, errno);
+
+ umem_free(chp, sizeof (varpd_client_t));
+}
+
+int
+libvarpd_c_instance_create(varpd_client_handle_t *chp, datalink_id_t linkid,
+ const char *search, uint64_t *cidp)
+{
+ int ret;
+ varpd_client_t *client = (varpd_client_t *)chp;
+ varpd_client_arg_t carg;
+ varpd_client_create_arg_t *cap = &carg.vca_un.vca_create;
+
+ if (strlen(search) >= LIBVARPD_PROP_NAMELEN)
+ return (EINVAL);
+ carg.vca_command = VARPD_CLIENT_CREATE;
+ carg.vca_errno = 0;
+ cap->vcca_linkid = linkid;
+ (void) strlcpy(cap->vcca_plugin, search, LIBVARPD_PROP_NAMELEN);
+
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ *cidp = cap->vcca_id;
+
+ return (0);
+}
+
+int
+libvarpd_c_instance_activate(varpd_client_handle_t *chp, uint64_t cid)
+{
+ int ret;
+ varpd_client_t *client = (varpd_client_t *)chp;
+ varpd_client_arg_t carg;
+ varpd_client_instance_arg_t *vciap = &carg.vca_un.vca_instance;
+
+ carg.vca_command = VARPD_CLIENT_ACTIVATE;
+ carg.vca_errno = 0;
+ vciap->vcia_id = cid;
+
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ return (0);
+}
+
+int
+libvarpd_c_instance_destroy(varpd_client_handle_t *chp, uint64_t cid)
+{
+ int ret;
+ varpd_client_t *client = (varpd_client_t *)chp;
+ varpd_client_arg_t carg;
+ varpd_client_instance_arg_t *vciap = &carg.vca_un.vca_instance;
+
+ carg.vca_command = VARPD_CLIENT_DESTROY;
+ carg.vca_errno = 0;
+ vciap->vcia_id = cid;
+
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ return (0);
+}
+
+int
+libvarpd_c_prop_nprops(varpd_client_handle_t *chp, uint64_t cid, uint_t *nprops)
+{
+ int ret;
+ varpd_client_t *client = (varpd_client_t *)chp;
+ varpd_client_arg_t carg;
+ varpd_client_nprops_arg_t *vcnap = &carg.vca_un.vca_nprops;
+
+ carg.vca_command = VARPD_CLIENT_NPROPS;
+ carg.vca_errno = 0;
+ vcnap->vcna_id = cid;
+ vcnap->vcna_nprops = 0;
+
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+ *nprops = vcnap->vcna_nprops;
+ return (0);
+}
+
+int
+libvarpd_c_prop_handle_alloc(varpd_client_handle_t *chp, uint64_t cid,
+ varpd_client_prop_handle_t **phdlp)
+{
+ varpd_client_prop_info_t *infop;
+
+ infop = umem_alloc(sizeof (varpd_client_prop_info_t), UMEM_DEFAULT);
+ if (infop == NULL)
+ return (ENOMEM);
+
+ bzero(infop, sizeof (varpd_client_prop_info_t));
+ infop->vcprop_client = (varpd_client_t *)chp;
+ infop->vcprop_instance = cid;
+ infop->vcprop_propid = UINT_MAX;
+ *phdlp = (varpd_client_prop_handle_t *)infop;
+ return (0);
+}
+
+void
+libvarpd_c_prop_handle_free(varpd_client_prop_handle_t *phdl)
+{
+ umem_free(phdl, sizeof (varpd_client_prop_info_t));
+ phdl = NULL;
+}
+
+static void
+libvarpd_c_prop_info_from_door(varpd_client_prop_info_t *infop,
+ const varpd_client_propinfo_arg_t *vcfap)
+{
+ infop->vcprop_propid = vcfap->vcfa_propid;
+ infop->vcprop_type = vcfap->vcfa_type;
+ infop->vcprop_prot = vcfap->vcfa_prot;
+ infop->vcprop_defsize = vcfap->vcfa_defsize;
+ infop->vcprop_psize = vcfap->vcfa_psize;
+ bcopy(vcfap->vcfa_name, infop->vcprop_name, LIBVARPD_PROP_NAMELEN);
+ bcopy(vcfap->vcfa_default, infop->vcprop_default,
+ LIBVARPD_PROP_SIZEMAX);
+ bcopy(vcfap->vcfa_poss, infop->vcprop_poss, LIBVARPD_PROP_SIZEMAX);
+}
+
+int
+libvarpd_c_prop_info_fill_by_name(varpd_client_prop_handle_t *phdl,
+ const char *name)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_propinfo_arg_t *vcfap = &carg.vca_un.vca_info;
+ varpd_client_prop_info_t *infop = (varpd_client_prop_info_t *)phdl;
+
+ if (strlen(name) >= LIBVARPD_PROP_NAMELEN)
+ return (EINVAL);
+ bzero(&carg, sizeof (varpd_client_arg_t));
+ carg.vca_command = VARPD_CLIENT_PROPINFO;
+ carg.vca_errno = 0;
+ vcfap->vcfa_id = infop->vcprop_instance;
+ vcfap->vcfa_propid = UINT_MAX;
+ (void) strlcpy(vcfap->vcfa_name, name, LIBVARPD_PROP_NAMELEN);
+
+ ret = libvarpd_c_door_call(infop->vcprop_client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ libvarpd_c_prop_info_from_door(infop, vcfap);
+ return (0);
+}
+
+int
+libvarpd_c_prop_info_fill(varpd_client_prop_handle_t *phdl, uint_t propid)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_propinfo_arg_t *vcfap = &carg.vca_un.vca_info;
+ varpd_client_prop_info_t *infop = (varpd_client_prop_info_t *)phdl;
+
+ bzero(&carg, sizeof (varpd_client_arg_t));
+ carg.vca_command = VARPD_CLIENT_PROPINFO;
+ carg.vca_errno = 0;
+ vcfap->vcfa_id = infop->vcprop_instance;
+ vcfap->vcfa_propid = propid;
+
+ ret = libvarpd_c_door_call(infop->vcprop_client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ libvarpd_c_prop_info_from_door(infop, vcfap);
+ return (0);
+}
+
+int
+libvarpd_c_prop_info(varpd_client_prop_handle_t *phdl, const char **namep,
+ uint_t *typep, uint_t *protp, const void **defp, uint32_t *defsizep,
+ const mac_propval_range_t **possp)
+{
+ varpd_client_prop_info_t *infop = (varpd_client_prop_info_t *)phdl;
+ if (infop->vcprop_propid == UINT_MAX)
+ return (EINVAL);
+
+ if (namep != NULL)
+ *namep = infop->vcprop_name;
+ if (typep != NULL)
+ *typep = infop->vcprop_type;
+ if (protp != NULL)
+ *protp = infop->vcprop_prot;
+ if (defp != NULL)
+ *defp = infop->vcprop_default;
+ if (defsizep != NULL)
+ *defsizep = infop->vcprop_defsize;
+ if (possp != NULL)
+ *possp = (const mac_propval_range_t *)infop->vcprop_poss;
+ return (0);
+}
+
+int
+libvarpd_c_prop_get(varpd_client_prop_handle_t *phdl, void *buf, uint32_t *len)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_prop_arg_t *vcpap = &carg.vca_un.vca_prop;
+ varpd_client_prop_info_t *infop = (varpd_client_prop_info_t *)phdl;
+
+ if (len == NULL || buf == NULL || infop->vcprop_propid == UINT_MAX)
+ return (EINVAL);
+ if (*len < LIBVARPD_PROP_SIZEMAX)
+ return (EOVERFLOW);
+
+ bzero(&carg, sizeof (varpd_client_arg_t));
+ carg.vca_command = VARPD_CLIENT_GETPROP;
+ carg.vca_errno = 0;
+ vcpap->vcpa_id = infop->vcprop_instance;
+ vcpap->vcpa_propid = infop->vcprop_propid;
+
+ ret = libvarpd_c_door_call(infop->vcprop_client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ /*
+ * If the buffer size is too large then something odd has certainly
+ * happened here, it means that varpd has gone rogue. In such a case we
+ * return a rather odd errror, though we don't believe that this should
+ * generally happen.
+ */
+ if (vcpap->vcpa_bufsize > LIBVARPD_PROP_SIZEMAX)
+ return (E2BIG);
+
+ bcopy(vcpap->vcpa_buf, buf, vcpap->vcpa_bufsize);
+ *len = vcpap->vcpa_bufsize;
+ return (0);
+}
+
+int
+libvarpd_c_prop_set(varpd_client_prop_handle_t *phdl, const void *buf,
+ uint32_t len)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_prop_arg_t *vcpap = &carg.vca_un.vca_prop;
+ varpd_client_prop_info_t *infop = (varpd_client_prop_info_t *)phdl;
+
+ if (len == 0 || buf == NULL || infop->vcprop_propid == UINT_MAX)
+ return (EINVAL);
+ if (len > LIBVARPD_PROP_SIZEMAX)
+ return (EOVERFLOW);
+
+ carg.vca_command = VARPD_CLIENT_SETPROP;
+ carg.vca_errno = 0;
+ vcpap->vcpa_id = infop->vcprop_instance;
+ vcpap->vcpa_propid = infop->vcprop_propid;
+ vcpap->vcpa_bufsize = len;
+ bcopy(buf, vcpap->vcpa_buf, len);
+
+ ret = libvarpd_c_door_call(infop->vcprop_client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ return (0);
+}
+
+int
+libvarpd_c_instance_lookup(varpd_client_handle_t *chp, datalink_id_t linkid,
+ uint64_t *instp)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_lookup_arg_t *vclap = &carg.vca_un.vca_lookup;
+ varpd_client_t *client = (varpd_client_t *)chp;
+
+ carg.vca_command = VARPD_CLIENT_LOOKUP;
+ carg.vca_errno = 0;
+ vclap->vcla_linkid = linkid;
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+ if (instp != NULL)
+ *instp = vclap->vcla_id;
+
+ return (0);
+}
+
+int
+libvarpd_c_instance_target_mode(varpd_client_handle_t *chp, uint64_t cid,
+ uint_t *dtype, uint_t *mtype)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_target_mode_arg_t *vctmap = &carg.vca_un.vca_mode;
+ varpd_client_t *client = (varpd_client_t *)chp;
+
+ carg.vca_command = VARPD_CLIENT_TARGET_MODE;
+ carg.vca_errno = 0;
+ vctmap->vtma_id = cid;
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+ if (ret == 0) {
+ if (mtype != NULL)
+ *mtype = vctmap->vtma_mode;
+ if (dtype != NULL)
+ *dtype = vctmap->vtma_dest;
+ }
+
+ return (ret);
+}
+
+int
+libvarpd_c_instance_cache_flush(varpd_client_handle_t *chp, uint64_t cid)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_target_cache_arg_t *vctcap = &carg.vca_un.vca_cache;
+ varpd_client_t *client = (varpd_client_t *)chp;
+
+ carg.vca_command = VARPD_CLIENT_CACHE_FLUSH;
+ carg.vca_errno = 0;
+
+ vctcap->vtca_id = cid;
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ return (0);
+}
+
+int
+libvarpd_c_instance_cache_delete(varpd_client_handle_t *chp, uint64_t cid,
+ const struct ether_addr *key)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_target_cache_arg_t *vctcap = &carg.vca_un.vca_cache;
+ varpd_client_t *client = (varpd_client_t *)chp;
+
+ if (key == NULL)
+ return (EINVAL);
+
+ carg.vca_command = VARPD_CLIENT_CACHE_DELETE;
+ carg.vca_errno = 0;
+ vctcap->vtca_id = cid;
+ bcopy(key, vctcap->vtca_key, ETHERADDRL);
+
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ return (0);
+}
+
+int
+libvarpd_c_instance_cache_get(varpd_client_handle_t *chp, uint64_t cid,
+ const struct ether_addr *key, varpd_client_cache_entry_t *entry)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_target_cache_arg_t *vctcap = &carg.vca_un.vca_cache;
+ varpd_client_t *client = (varpd_client_t *)chp;
+
+ if (key == NULL || entry == NULL)
+ return (EINVAL);
+
+ carg.vca_command = VARPD_CLIENT_CACHE_GET;
+ carg.vca_errno = 0;
+ vctcap->vtca_id = cid;
+ bcopy(key, vctcap->vtca_key, ETHERADDRL);
+ bzero(&vctcap->vtca_entry, sizeof (varpd_client_cache_entry_t));
+
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ bcopy(&vctcap->vtca_entry, entry, sizeof (varpd_client_cache_entry_t));
+ return (0);
+}
+
+int
+libvarpd_c_instance_cache_set(varpd_client_handle_t *chp, uint64_t cid,
+ const struct ether_addr *key, const varpd_client_cache_entry_t *entry)
+{
+ int ret;
+ varpd_client_arg_t carg;
+ varpd_client_target_cache_arg_t *vctcap = &carg.vca_un.vca_cache;
+ varpd_client_t *client = (varpd_client_t *)chp;
+
+ if (key == NULL || entry == NULL)
+ return (EINVAL);
+
+ carg.vca_command = VARPD_CLIENT_CACHE_SET;
+ carg.vca_errno = 0;
+ vctcap->vtca_id = cid;
+ bcopy(key, vctcap->vtca_key, ETHERADDRL);
+ bcopy(entry, &vctcap->vtca_entry, sizeof (varpd_client_cache_entry_t));
+
+ ret = libvarpd_c_door_call(client, &carg, 0);
+ if (ret != 0)
+ return (ret);
+
+ if (carg.vca_errno != 0)
+ return (carg.vca_errno);
+
+ return (0);
+}
+
+int
+libvarpd_c_instance_cache_walk(varpd_client_handle_t *chp, uint64_t cid,
+ varpd_client_cache_f func, void *arg)
+{
+ int ret = 0;
+ size_t bufsize = sizeof (varpd_client_arg_t) +
+ 100 * sizeof (varpd_client_cache_entry_t);
+ varpd_client_t *client = (varpd_client_t *)chp;
+ varpd_client_arg_t *cargp;
+ varpd_client_target_walk_arg_t *vctwap;
+
+ /*
+ * Because the number of entries involved in a walk may be large, we
+ * dynamically allocate a number of queries to make at a single time.
+ * This also means that the average door request doesn't inflate by the
+ * number of entries we want. For now, let's always grab 100 entries in
+ * a request.
+ */
+ cargp = umem_zalloc(bufsize, UMEM_DEFAULT);
+ if (cargp == NULL)
+ return (errno);
+ vctwap = &cargp->vca_un.vca_walk;
+ for (;;) {
+ int i;
+
+ cargp->vca_command = VARPD_CLIENT_CACHE_WALK;
+ cargp->vca_errno = 0;
+ vctwap->vtcw_id = cid;
+ vctwap->vtcw_count = 100;
+
+ ret = libvarpd_c_door_call(client, cargp, bufsize);
+ if (ret != 0)
+ break;
+
+ if (cargp->vca_errno != 0) {
+ ret = cargp->vca_errno;
+ break;
+ }
+
+ if (vctwap->vtcw_count == 0) {
+ ret = 0;
+ break;
+ }
+
+ for (i = 0; i < vctwap->vtcw_count; i++) {
+ varpd_client_cache_entry_t ent;
+
+ ent.vcp_flags = vctwap->vtcw_ents[i].otce_flags;
+ bcopy(vctwap->vtcw_ents[i].otce_dest.otp_mac,
+ &ent.vcp_mac, ETHERADDRL);
+ ent.vcp_ip = vctwap->vtcw_ents[i].otce_dest.otp_ip;
+ ent.vcp_port = vctwap->vtcw_ents[i].otce_dest.otp_port;
+ ret = func(chp, cid,
+ (struct ether_addr *)vctwap->vtcw_ents[i].otce_mac,
+ &ent, arg);
+ if (ret != 0) {
+ ret = 0;
+ goto done;
+ }
+ }
+ }
+
+done:
+ umem_free(cargp, bufsize);
+ return (ret);
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_client.h b/usr/src/lib/varpd/libvarpd/common/libvarpd_client.h
new file mode 100644
index 0000000000..459711b385
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_client.h
@@ -0,0 +1,92 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _LIBVARPD_CLIENT_H
+#define _LIBVARPD_CLIENT_H
+
+/*
+ * varpd interfaces
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <sys/mac.h>
+#include <sys/overlay_target.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct __varpd_client_handle varpd_client_handle_t;
+typedef struct __varpd_client_prop_handle varpd_client_prop_handle_t;
+
+typedef struct varpd_client_cache_entry {
+ struct ether_addr vcp_mac;
+ uint16_t vcp_flags;
+ struct in6_addr vcp_ip;
+ uint16_t vcp_port;
+} varpd_client_cache_entry_t;
+
+/*
+ * We just use the values from the kernel for now.
+ */
+#define LIBVARPD_PROP_SIZEMAX OVERLAY_PROP_SIZEMAX
+#define LIBVARPD_PROP_NAMELEN OVERLAY_PROP_NAMELEN
+
+extern int libvarpd_c_create(varpd_client_handle_t **, const char *);
+extern void libvarpd_c_destroy(varpd_client_handle_t *);
+extern int libvarpd_c_instance_create(varpd_client_handle_t *, datalink_id_t,
+ const char *, uint64_t *);
+extern int libvarpd_c_instance_activate(varpd_client_handle_t *, uint64_t);
+extern int libvarpd_c_instance_destroy(varpd_client_handle_t *, uint64_t);
+
+extern int libvarpd_c_prop_nprops(varpd_client_handle_t *, uint64_t, uint_t *);
+extern int libvarpd_c_prop_handle_alloc(varpd_client_handle_t *, uint64_t,
+ varpd_client_prop_handle_t **);
+extern void libvarpd_c_prop_handle_free(varpd_client_prop_handle_t *);
+extern int libvarpd_c_prop_info_fill(varpd_client_prop_handle_t *, uint_t);
+extern int libvarpd_c_prop_info_fill_by_name(varpd_client_prop_handle_t *,
+ const char *);
+extern int libvarpd_c_prop_info(varpd_client_prop_handle_t *, const char **,
+ uint_t *, uint_t *, const void **, uint32_t *,
+ const mac_propval_range_t **);
+extern int libvarpd_c_prop_get(varpd_client_prop_handle_t *, void *,
+ uint32_t *);
+extern int libvarpd_c_prop_set(varpd_client_prop_handle_t *, const void *,
+ uint32_t);
+
+extern int libvarpd_c_instance_lookup(varpd_client_handle_t *, datalink_id_t,
+ uint64_t *);
+extern int libvarpd_c_instance_target_mode(varpd_client_handle_t *, uint64_t,
+ uint_t *, uint_t *);
+extern int libvarpd_c_instance_cache_flush(varpd_client_handle_t *, uint64_t);
+extern int libvarpd_c_instance_cache_delete(varpd_client_handle_t *, uint64_t,
+ const struct ether_addr *);
+extern int libvarpd_c_instance_cache_get(varpd_client_handle_t *, uint64_t,
+ const struct ether_addr *, varpd_client_cache_entry_t *);
+extern int libvarpd_c_instance_cache_set(varpd_client_handle_t *, uint64_t,
+ const struct ether_addr *, const varpd_client_cache_entry_t *);
+
+typedef int (*varpd_client_cache_f)(varpd_client_handle_t *, uint64_t,
+ const struct ether_addr *, const varpd_client_cache_entry_t *, void *);
+extern int libvarpd_c_instance_cache_walk(varpd_client_handle_t *, uint64_t,
+ varpd_client_cache_f, void *);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBVARPD_CLIENT_H */
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_door.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_door.c
new file mode 100644
index 0000000000..f684e031a8
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_door.c
@@ -0,0 +1,469 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * varpd door server logic
+ */
+
+#include <door.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <priv.h>
+#include <libvarpd_impl.h>
+
+typedef int (libvarpd_door_f)(varpd_impl_t *, varpd_client_arg_t *, ucred_t *);
+
+static boolean_t
+libvarpd_door_privileged(ucred_t *credp)
+{
+ const priv_set_t *ps;
+
+ ps = ucred_getprivset(credp, PRIV_EFFECTIVE);
+ if (ps == NULL)
+ return (B_FALSE);
+
+ return (priv_ismember(ps, PRIV_SYS_NET_CONFIG));
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_create(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ int ret;
+ varpd_instance_handle_t *ihdl;
+ varpd_client_create_arg_t *vccap = &vcap->vca_un.vca_create;
+
+ vccap->vcca_plugin[LIBVARPD_PROP_NAMELEN-1] = '\0';
+ ret = libvarpd_instance_create((varpd_handle_t *)vip,
+ vccap->vcca_linkid, vccap->vcca_plugin, &ihdl);
+ if (ret == 0)
+ vccap->vcca_id = libvarpd_instance_id(ihdl);
+
+ return (ret);
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_activate(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_client_instance_arg_t *vciap = &vcap->vca_un.vca_instance;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vciap->vcia_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ return (libvarpd_instance_activate(ihp));
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_destroy(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_client_instance_arg_t *vciap = &vcap->vca_un.vca_instance;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vciap->vcia_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ libvarpd_instance_destroy(ihp);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_nprops(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_client_nprops_arg_t *vcnap = &vcap->vca_un.vca_nprops;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vcnap->vcna_id);
+ if (ihp == NULL)
+ return (ENOENT);
+
+ return (libvarpd_prop_nprops(ihp, &vcnap->vcna_nprops));
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_propinfo(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ int ret;
+ varpd_instance_handle_t *ihp;
+ varpd_prop_handle_t *phdl;
+ varpd_client_propinfo_arg_t *vcfap = &vcap->vca_un.vca_info;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vcfap->vcfa_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ ret = libvarpd_prop_handle_alloc((varpd_handle_t *)vip, ihp, &phdl);
+ if (ret != 0)
+ return (ret);
+
+ if (vcfap->vcfa_propid != UINT_MAX) {
+ ret = libvarpd_prop_info_fill(phdl, vcfap->vcfa_propid);
+ if (ret != 0) {
+ libvarpd_prop_handle_free(phdl);
+ return (ret);
+ }
+ } else {
+ uint_t i, nprop;
+ const char *name;
+
+ vcfap->vcfa_name[LIBVARPD_PROP_NAMELEN-1] = '\0';
+ ret = libvarpd_prop_nprops(ihp, &nprop);
+ if (ret != 0) {
+ libvarpd_prop_handle_free(phdl);
+ return (ret);
+ }
+ for (i = 0; i < nprop; i++) {
+ ret = libvarpd_prop_info_fill(phdl, i);
+ if (ret != 0) {
+ libvarpd_prop_handle_free(phdl);
+ return (ret);
+ }
+ ret = libvarpd_prop_info(phdl, &name, NULL, NULL, NULL,
+ NULL, NULL);
+ if (ret != 0) {
+ libvarpd_prop_handle_free(phdl);
+ return (ret);
+ }
+ if (strcmp(vcfap->vcfa_name, name) == 0)
+ break;
+ }
+
+ if (i == nprop) {
+ libvarpd_prop_handle_free(phdl);
+ return (ENOENT);
+ }
+ vcfap->vcfa_propid = i;
+ }
+ libvarpd_prop_door_convert(phdl, vcfap);
+ libvarpd_prop_handle_free(phdl);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_getprop(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ int ret;
+ uint32_t size;
+ varpd_instance_handle_t *ihp;
+ varpd_prop_handle_t *phdl;
+ varpd_client_prop_arg_t *vcpap = &vcap->vca_un.vca_prop;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vcpap->vcpa_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ ret = libvarpd_prop_handle_alloc((varpd_handle_t *)vip, ihp, &phdl);
+ if (ret != 0)
+ return (ret);
+
+ ret = libvarpd_prop_info_fill(phdl, vcpap->vcpa_propid);
+ if (ret != 0) {
+ libvarpd_prop_handle_free(phdl);
+ return (ret);
+ }
+
+ ret = libvarpd_prop_get(phdl, vcpap->vcpa_buf, &size);
+ if (ret == 0)
+ vcpap->vcpa_bufsize = size;
+ libvarpd_prop_handle_free(phdl);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_setprop(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ int ret;
+ varpd_instance_handle_t *ihp;
+ varpd_prop_handle_t *phdl;
+ varpd_client_prop_arg_t *vcpap = &vcap->vca_un.vca_prop;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vcpap->vcpa_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ ret = libvarpd_prop_handle_alloc((varpd_handle_t *)vip, ihp, &phdl);
+ if (ret != 0)
+ return (ret);
+
+ ret = libvarpd_prop_info_fill(phdl, vcpap->vcpa_propid);
+ if (ret != 0) {
+ libvarpd_prop_handle_free(phdl);
+ return (ret);
+ }
+
+ ret = libvarpd_prop_set(phdl, vcpap->vcpa_buf, vcpap->vcpa_bufsize);
+ libvarpd_prop_handle_free(phdl);
+ return (ret);
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_lookup(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_t *inst;
+ varpd_client_lookup_arg_t *vclap = &vcap->vca_un.vca_lookup;
+
+ inst = libvarpd_instance_lookup_by_dlid(vip, vclap->vcla_linkid);
+ if (inst == NULL)
+ return (ENOENT);
+
+ vclap->vcla_id = inst->vri_id;
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_target(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_instance_t *inst;
+ varpd_client_target_mode_arg_t *vtmap = &vcap->vca_un.vca_mode;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vtmap->vtma_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ inst = (varpd_instance_t *)ihp;
+ vtmap->vtma_dest = inst->vri_dest;
+ vtmap->vtma_mode = inst->vri_mode;
+ return (0);
+}
+
+static int
+libvarpd_door_f_flush(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_client_target_cache_arg_t *vtcap = &vcap->vca_un.vca_cache;
+
+ if (libvarpd_door_privileged(credp) == B_FALSE)
+ return (EPERM);
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vtcap->vtca_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ return (libvarpd_overlay_cache_flush((varpd_instance_t *)ihp));
+}
+
+static int
+libvarpd_door_f_delete(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_client_target_cache_arg_t *vtcap = &vcap->vca_un.vca_cache;
+
+ if (libvarpd_door_privileged(credp) == B_FALSE)
+ return (EPERM);
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vtcap->vtca_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ return (libvarpd_overlay_cache_delete((varpd_instance_t *)ihp,
+ vtcap->vtca_key));
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_get(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_client_target_cache_arg_t *vtcap = &vcap->vca_un.vca_cache;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vtcap->vtca_id);
+ if (ihp == NULL)
+ return (ENOENT);
+ return (libvarpd_overlay_cache_get((varpd_instance_t *)ihp,
+ vtcap->vtca_key, &vtcap->vtca_entry));
+}
+
+static int
+libvarpd_door_f_set(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_client_target_cache_arg_t *vtcap = &vcap->vca_un.vca_cache;
+
+ if (libvarpd_door_privileged(credp) == B_FALSE)
+ return (EPERM);
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vtcap->vtca_id);
+ if (ihp == NULL)
+ return (ENOENT);
+
+ return (libvarpd_overlay_cache_set((varpd_instance_t *)ihp,
+ vtcap->vtca_key, &vtcap->vtca_entry));
+}
+
+/* ARGSUSED */
+static int
+libvarpd_door_f_walk(varpd_impl_t *vip, varpd_client_arg_t *vcap,
+ ucred_t *credp)
+{
+ varpd_instance_handle_t *ihp;
+ varpd_client_target_walk_arg_t *vctwp = &vcap->vca_un.vca_walk;
+
+ ihp = libvarpd_instance_lookup((varpd_handle_t *)vip, vctwp->vtcw_id);
+ if (ihp == NULL)
+ return (ENOENT);
+
+ return (libvarpd_overlay_cache_walk_fill((varpd_instance_t *)ihp,
+ &vctwp->vtcw_marker, &vctwp->vtcw_count, vctwp->vtcw_ents));
+}
+
+static libvarpd_door_f *libvarpd_door_table[] = {
+ libvarpd_door_f_create,
+ libvarpd_door_f_activate,
+ libvarpd_door_f_destroy,
+ libvarpd_door_f_nprops,
+ libvarpd_door_f_propinfo,
+ libvarpd_door_f_getprop,
+ libvarpd_door_f_setprop,
+ libvarpd_door_f_lookup,
+ libvarpd_door_f_target,
+ libvarpd_door_f_flush,
+ libvarpd_door_f_delete,
+ libvarpd_door_f_get,
+ libvarpd_door_f_set,
+ libvarpd_door_f_walk
+};
+
+/* ARGSUSED */
+static void
+libvarpd_door_server(void *cookie, char *argp, size_t argsz, door_desc_t *dp,
+ uint_t ndesc)
+{
+ int ret;
+ varpd_client_eresp_t err;
+ ucred_t *credp = NULL;
+ varpd_impl_t *vip = cookie;
+ varpd_client_arg_t *vcap = (varpd_client_arg_t *)argp;
+
+ err.vce_command = VARPD_CLIENT_INVALID;
+ if (argsz < sizeof (varpd_client_arg_t)) {
+ err.vce_errno = EINVAL;
+ goto errout;
+ }
+
+ if ((ret = door_ucred(&credp)) != 0) {
+ err.vce_errno = ret;
+ goto errout;
+ }
+
+ if (vcap->vca_command == VARPD_CLIENT_INVALID ||
+ vcap->vca_command >= VARPD_CLIENT_MAX) {
+ err.vce_errno = EINVAL;
+ goto errout;
+ }
+
+ vcap->vca_errno = 0;
+ ret = libvarpd_door_table[vcap->vca_command - 1](vip, vcap, credp);
+ if (ret != 0)
+ vcap->vca_errno = ret;
+
+ ucred_free(credp);
+ (void) door_return(argp, argsz, NULL, 0);
+ return;
+
+errout:
+ ucred_free(credp);
+ (void) door_return((char *)&err, sizeof (err), NULL, 0);
+}
+
+int
+libvarpd_door_server_create(varpd_handle_t *vhp, const char *path)
+{
+ int fd, ret;
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+
+ mutex_enter(&vip->vdi_lock);
+ if (vip->vdi_doorfd >= 0) {
+ mutex_exit(&vip->vdi_lock);
+ return (EEXIST);
+ }
+
+ vip->vdi_doorfd = door_create(libvarpd_door_server, vip,
+ DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
+ if (vip->vdi_doorfd == -1) {
+ mutex_exit(&vip->vdi_lock);
+ return (errno);
+ }
+
+ if ((fd = open(path, O_CREAT | O_RDWR, 0666)) == -1) {
+ ret = errno;
+ if (door_revoke(vip->vdi_doorfd) != 0)
+ libvarpd_panic("failed to revoke door: %d",
+ errno);
+ mutex_exit(&vip->vdi_lock);
+ return (errno);
+ }
+
+ if (fchown(fd, UID_NETADM, GID_NETADM) != 0) {
+ ret = errno;
+ if (door_revoke(vip->vdi_doorfd) != 0)
+ libvarpd_panic("failed to revoke door: %d",
+ errno);
+ mutex_exit(&vip->vdi_lock);
+ return (ret);
+ }
+
+ if (close(fd) != 0)
+ libvarpd_panic("failed to close door fd %d: %d",
+ fd, errno);
+ (void) fdetach(path);
+ if (fattach(vip->vdi_doorfd, path) != 0) {
+ ret = errno;
+ if (door_revoke(vip->vdi_doorfd) != 0)
+ libvarpd_panic("failed to revoke door: %d",
+ errno);
+ mutex_exit(&vip->vdi_lock);
+ return (ret);
+ }
+
+ mutex_exit(&vip->vdi_lock);
+ return (0);
+}
+
+void
+libvarpd_door_server_destroy(varpd_handle_t *vhp)
+{
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+
+ mutex_enter(&vip->vdi_lock);
+ if (vip->vdi_doorfd != 0) {
+ if (door_revoke(vip->vdi_doorfd) != 0)
+ libvarpd_panic("failed to revoke door: %d",
+ errno);
+ vip->vdi_doorfd = -1;
+ }
+ mutex_exit(&vip->vdi_lock);
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_impl.h b/usr/src/lib/varpd/libvarpd/common/libvarpd_impl.h
new file mode 100644
index 0000000000..f8530a7112
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_impl.h
@@ -0,0 +1,248 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _LIBVARPD_IMPL_H
+#define _LIBVARPD_IMPL_H
+
+/*
+ * varpd internal interfaces
+ */
+
+#include <libvarpd.h>
+#include <libvarpd_provider.h>
+#include <sys/avl.h>
+#include <thread.h>
+#include <synch.h>
+#include <limits.h>
+#include <libidspace.h>
+#include <umem.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LIBVARPD_ID_MIN 1
+#define LIBVARPD_ID_MAX INT32_MAX
+
+typedef struct varpd_plugin {
+ avl_node_t vpp_node;
+ const char *vpp_name;
+ overlay_target_mode_t vpp_mode;
+ const varpd_plugin_ops_t *vpp_ops;
+ mutex_t vpp_lock;
+ uint_t vpp_active;
+} varpd_plugin_t;
+
+typedef struct varpd_impl {
+ mutex_t vdi_lock;
+ rwlock_t vdi_pfdlock;
+ avl_tree_t vdi_plugins; /* vdi_lock */
+ avl_tree_t vdi_instances; /* vdi_lock */
+ avl_tree_t vdi_linstances; /* vdi_lock */
+ id_space_t *vdi_idspace; /* RO */
+ umem_cache_t *vdi_qcache; /* RO */
+ int vdi_overlayfd; /* RO */
+ int vdi_doorfd; /* vdi_lock */
+ int vdi_persistfd; /* vdi_plock */
+ cond_t vdi_lthr_cv; /* vdi_lock */
+ boolean_t vdi_lthr_quiesce; /* vdi_lock */
+ uint_t vdi_lthr_count; /* vdi_lock */
+} varpd_impl_t;
+
+typedef enum varpd_instance_flags {
+ VARPD_INSTANCE_F_ACTIVATED = 0x01
+} varpd_instance_flags_t;
+
+typedef struct varpd_instance {
+ avl_node_t vri_inode;
+ avl_node_t vri_lnode;
+ uint64_t vri_id; /* RO */
+ uint64_t vri_vnetid; /* RO */
+ datalink_id_t vri_linkid; /* RO */
+ overlay_target_mode_t vri_mode; /* RO */
+ overlay_plugin_dest_t vri_dest; /* RO */
+ varpd_impl_t *vri_impl; /* RO */
+ varpd_plugin_t *vri_plugin; /* RO */
+ void *vri_private; /* RO */
+ mutex_t vri_lock;
+ varpd_instance_flags_t vri_flags; /* vri_lock */
+} varpd_instance_t;
+
+typedef struct varpd_query {
+ overlay_targ_lookup_t vq_lookup;
+ overlay_targ_resp_t vq_response;
+ varpd_instance_t *vq_instance;
+} varpd_query_t;
+
+typedef struct varpd_client_create_arg {
+ datalink_id_t vcca_linkid;
+ uint64_t vcca_id;
+ char vcca_plugin[LIBVARPD_PROP_NAMELEN];
+} varpd_client_create_arg_t;
+
+typedef struct varpd_client_instance_arg {
+ uint64_t vcia_id;
+} varpd_client_instance_arg_t;
+
+typedef struct varpd_client_nprops_arg {
+ uint64_t vcna_id;
+ uint_t vcna_nprops;
+ uint8_t vcna_pad[4];
+} varpd_client_nprops_arg_t;
+
+typedef struct varpd_client_propinfo_arg {
+ uint64_t vcfa_id;
+ uint_t vcfa_propid;
+ uint_t vcfa_type;
+ uint_t vcfa_prot;
+ uint32_t vcfa_defsize;
+ uint32_t vcfa_psize;
+ uint8_t vcfa_pad[4];
+ char vcfa_name[LIBVARPD_PROP_NAMELEN];
+ uint8_t vcfa_default[LIBVARPD_PROP_SIZEMAX];
+ uint8_t vcfa_poss[LIBVARPD_PROP_SIZEMAX];
+} varpd_client_propinfo_arg_t;
+
+typedef struct varpd_client_prop_arg {
+ uint64_t vcpa_id;
+ uint_t vcpa_propid;
+ uint8_t vcpa_buf[LIBVARPD_PROP_SIZEMAX];
+ size_t vcpa_bufsize;
+} varpd_client_prop_arg_t;
+
+typedef struct varpd_client_lookup_arg {
+ datalink_id_t vcla_linkid;
+ uint32_t vcla_pad;
+ uint64_t vcla_id;
+} varpd_client_lookup_arg_t;
+
+typedef struct varpd_client_target_mode_arg {
+ uint64_t vtma_id;
+ uint32_t vtma_dest;
+ uint32_t vtma_mode;
+} varpd_client_target_mode_arg_t;
+
+typedef struct varpd_client_target_cache_arg {
+ uint64_t vtca_id;
+ uint8_t vtca_key[ETHERADDRL];
+ uint8_t vtca_pad[2];
+ varpd_client_cache_entry_t vtca_entry;
+} varpd_client_target_cache_arg_t;
+
+typedef struct varpd_client_target_walk_arg {
+ uint64_t vtcw_id;
+ uint64_t vtcw_marker;
+ uint64_t vtcw_count;
+ overlay_targ_cache_entry_t vtcw_ents[];
+} varpd_client_target_walk_arg_t;
+
+typedef enum varpd_client_command {
+ VARPD_CLIENT_INVALID = 0x0,
+ VARPD_CLIENT_CREATE,
+ VARPD_CLIENT_ACTIVATE,
+ VARPD_CLIENT_DESTROY,
+ VARPD_CLIENT_NPROPS,
+ VARPD_CLIENT_PROPINFO,
+ VARPD_CLIENT_GETPROP,
+ VARPD_CLIENT_SETPROP,
+ VARPD_CLIENT_LOOKUP,
+ VARPD_CLIENT_TARGET_MODE,
+ VARPD_CLIENT_CACHE_FLUSH,
+ VARPD_CLIENT_CACHE_DELETE,
+ VARPD_CLIENT_CACHE_GET,
+ VARPD_CLIENT_CACHE_SET,
+ VARPD_CLIENT_CACHE_WALK,
+ VARPD_CLIENT_MAX
+} varpd_client_command_t;
+
+typedef struct varpd_client_arg {
+ uint_t vca_command;
+ uint_t vca_errno;
+ union {
+ varpd_client_create_arg_t vca_create;
+ varpd_client_instance_arg_t vca_instance;
+ varpd_client_nprops_arg_t vca_nprops;
+ varpd_client_propinfo_arg_t vca_info;
+ varpd_client_prop_arg_t vca_prop;
+ varpd_client_lookup_arg_t vca_lookup;
+ varpd_client_target_mode_arg_t vca_mode;
+ varpd_client_target_cache_arg_t vca_cache;
+ varpd_client_target_walk_arg_t vca_walk;
+ } vca_un;
+} varpd_client_arg_t;
+
+typedef struct varpd_client_eresp {
+ uint_t vce_command;
+ uint_t vce_errno;
+} varpd_client_eresp_t;
+
+extern void libvarpd_plugin_init(void);
+extern void libvarpd_plugin_prefork(void);
+extern void libvarpd_plugin_postfork(void);
+extern void libvarpd_plugin_fini(void);
+extern int libvarpd_plugin_comparator(const void *, const void *);
+extern varpd_plugin_t *libvarpd_plugin_lookup(varpd_impl_t *, const char *);
+
+extern varpd_instance_t *libvarpd_instance_lookup_by_dlid(varpd_impl_t *,
+ datalink_id_t);
+
+extern void libvarpd_prop_door_convert(const varpd_prop_handle_t *,
+ varpd_client_propinfo_arg_t *);
+
+extern const char *libvarpd_isaext(void);
+typedef int (*libvarpd_dirwalk_f)(varpd_impl_t *, const char *, void *);
+extern int libvarpd_dirwalk(varpd_impl_t *, const char *, const char *,
+ libvarpd_dirwalk_f, void *);
+
+extern int libvarpd_overlay_init(varpd_impl_t *);
+extern void libvarpd_overlay_fini(varpd_impl_t *);
+extern int libvarpd_overlay_info(varpd_impl_t *, datalink_id_t,
+ overlay_plugin_dest_t *, uint64_t *, uint64_t *);
+extern int libvarpd_overlay_associate(varpd_instance_t *);
+extern int libvarpd_overlay_disassociate(varpd_instance_t *);
+extern int libvarpd_overlay_degrade(varpd_instance_t *, const char *);
+extern int libvarpd_overlay_degrade_datalink(varpd_impl_t *, datalink_id_t,
+ const char *);
+extern int libvarpd_overlay_restore(varpd_instance_t *);
+extern int libvarpd_overlay_packet(varpd_impl_t *,
+ const overlay_targ_lookup_t *, void *, size_t *);
+extern int libvarpd_overlay_inject(varpd_impl_t *,
+ const overlay_targ_lookup_t *, void *, size_t);
+extern int libvarpd_overlay_instance_inject(varpd_instance_t *, void *, size_t);
+extern int libvarpd_overlay_resend(varpd_impl_t *,
+ const overlay_targ_lookup_t *, void *, size_t);
+typedef int (*libvarpd_overlay_iter_f)(varpd_impl_t *, datalink_id_t, void *);
+extern int libvarpd_overlay_iter(varpd_impl_t *, libvarpd_overlay_iter_f,
+ void *);
+extern int libvarpd_overlay_cache_flush(varpd_instance_t *);
+extern int libvarpd_overlay_cache_delete(varpd_instance_t *, const uint8_t *);
+extern int libvarpd_overlay_cache_delete(varpd_instance_t *, const uint8_t *);
+extern int libvarpd_overlay_cache_get(varpd_instance_t *, const uint8_t *,
+ varpd_client_cache_entry_t *);
+extern int libvarpd_overlay_cache_set(varpd_instance_t *, const uint8_t *,
+ const varpd_client_cache_entry_t *);
+extern int libvarpd_overlay_cache_walk_fill(varpd_instance_t *, uint64_t *,
+ uint64_t *, overlay_targ_cache_entry_t *);
+
+extern void libvarpd_persist_init(varpd_impl_t *);
+extern void libvarpd_persist_fini(varpd_impl_t *);
+extern int libvarpd_persist_instance(varpd_impl_t *, varpd_instance_t *);
+extern void libvarpd_torch_instance(varpd_impl_t *, varpd_instance_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBVARPD_IMPL_H */
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_overlay.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_overlay.c
new file mode 100644
index 0000000000..167c004a90
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_overlay.c
@@ -0,0 +1,588 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Interactions with /dev/overlay
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stropts.h>
+#include <strings.h>
+#include <umem.h>
+
+#include <libvarpd_impl.h>
+#include <sys/overlay_target.h>
+
+#define OVERLAY_PATH "/dev/overlay"
+
+int
+libvarpd_overlay_init(varpd_impl_t *vip)
+{
+ vip->vdi_overlayfd = open(OVERLAY_PATH, O_RDWR | O_EXCL);
+ if (vip->vdi_overlayfd == -1)
+ return (errno);
+ return (0);
+}
+
+void
+libvarpd_overlay_fini(varpd_impl_t *vip)
+{
+ assert(vip->vdi_overlayfd > 0);
+ if (close(vip->vdi_overlayfd) != 0)
+ libvarpd_panic("failed to close /dev/overlay fd %d: %d",
+ vip->vdi_overlayfd, errno);
+}
+
+int
+libvarpd_overlay_info(varpd_impl_t *vip, datalink_id_t linkid,
+ overlay_plugin_dest_t *destp, uint64_t *flags, uint64_t *vnetid)
+{
+ overlay_targ_info_t oti;
+
+ oti.oti_linkid = linkid;
+ if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_INFO, &oti) != 0)
+ return (errno);
+
+ if (destp != NULL)
+ *destp = oti.oti_needs;
+ if (flags != NULL)
+ *flags = oti.oti_flags;
+ if (vnetid != NULL)
+ *vnetid = oti.oti_vnetid;
+ return (0);
+}
+
+int
+libvarpd_overlay_associate(varpd_instance_t *inst)
+{
+ overlay_targ_associate_t ota;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ bzero(&ota, sizeof (overlay_targ_associate_t));
+ ota.ota_linkid = inst->vri_linkid;
+ ota.ota_mode = inst->vri_mode;
+ ota.ota_id = inst->vri_id;
+ ota.ota_provides = inst->vri_dest;
+
+ if (ota.ota_mode == OVERLAY_TARGET_POINT) {
+ int ret;
+ ret = inst->vri_plugin->vpp_ops->vpo_default(inst->vri_private,
+ &ota.ota_point);
+ if (ret != VARPD_LOOKUP_OK)
+ return (ret);
+ }
+
+ if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_ASSOCIATE, &ota) != 0)
+ return (errno);
+
+ return (0);
+}
+
+int
+libvarpd_overlay_disassociate(varpd_instance_t *inst)
+{
+ overlay_targ_id_t otid;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ otid.otid_linkid = inst->vri_linkid;
+ if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_DISASSOCIATE, &otid) != 0)
+ return (errno);
+ return (0);
+}
+
+int
+libvarpd_overlay_degrade_datalink(varpd_impl_t *vip, datalink_id_t linkid,
+ const char *msg)
+{
+ overlay_targ_degrade_t otd;
+
+ otd.otd_linkid = linkid;
+ (void) strlcpy(otd.otd_buf, msg, OVERLAY_STATUS_BUFLEN);
+ if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_DEGRADE, &otd) != 0)
+ return (errno);
+ return (0);
+
+}
+
+int
+libvarpd_overlay_degrade(varpd_instance_t *inst, const char *msg)
+{
+ return (libvarpd_overlay_degrade_datalink(inst->vri_impl,
+ inst->vri_linkid, msg));
+}
+
+int
+libvarpd_overlay_restore(varpd_instance_t *inst)
+{
+ overlay_targ_id_t otid;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ otid.otid_linkid = inst->vri_linkid;
+ if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_RESTORE, &otid) != 0)
+ return (errno);
+ return (0);
+}
+
+int
+libvarpd_overlay_packet(varpd_impl_t *vip, const overlay_targ_lookup_t *otl,
+ void *buf, size_t *buflen)
+{
+ int ret;
+ overlay_targ_pkt_t otp;
+
+ otp.otp_linkid = UINT64_MAX;
+ otp.otp_reqid = otl->otl_reqid;
+ otp.otp_size = *buflen;
+ otp.otp_buf = buf;
+
+ do {
+ ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_PKT, &otp);
+ } while (ret != 0 && errno == EINTR);
+ if (ret != 0 && errno == EFAULT)
+ libvarpd_panic("OVERLAY_TARG_PKT ioctl efault");
+ else if (ret != 0)
+ ret = errno;
+
+ if (ret == 0)
+ *buflen = otp.otp_size;
+
+ return (ret);
+}
+
+static int
+libvarpd_overlay_inject_common(varpd_impl_t *vip, varpd_instance_t *inst,
+ const overlay_targ_lookup_t *otl, void *buf, size_t buflen, int cmd)
+{
+ int ret;
+ overlay_targ_pkt_t otp;
+
+ if (otl == NULL) {
+ otp.otp_linkid = inst->vri_linkid;
+ otp.otp_reqid = 0;
+ } else {
+ otp.otp_linkid = UINT64_MAX;
+ otp.otp_reqid = otl->otl_reqid;
+ }
+ otp.otp_size = buflen;
+ otp.otp_buf = buf;
+
+ do {
+ ret = ioctl(vip->vdi_overlayfd, cmd, &otp);
+ } while (ret != 0 && errno == EINTR);
+ if (ret != 0 && errno == EFAULT)
+ libvarpd_panic("overlay_inject_common ioctl EFAULT");
+ else if (ret != 0)
+ ret = errno;
+
+ return (ret);
+}
+
+int
+libvarpd_overlay_inject(varpd_impl_t *vip, const overlay_targ_lookup_t *otl,
+ void *buf, size_t buflen)
+{
+ return (libvarpd_overlay_inject_common(vip, NULL, otl, buf, buflen,
+ OVERLAY_TARG_INJECT));
+}
+
+int
+libvarpd_overlay_instance_inject(varpd_instance_t *inst, void *buf,
+ size_t buflen)
+{
+ return (libvarpd_overlay_inject_common(inst->vri_impl, inst, NULL, buf,
+ buflen, OVERLAY_TARG_INJECT));
+}
+
+int
+libvarpd_overlay_resend(varpd_impl_t *vip, const overlay_targ_lookup_t *otl,
+ void *buf, size_t buflen)
+{
+ return (libvarpd_overlay_inject_common(vip, NULL, otl, buf, buflen,
+ OVERLAY_TARG_RESEND));
+}
+
+static void
+libvarpd_overlay_lookup_reply(varpd_impl_t *vip,
+ const overlay_targ_lookup_t *otl, overlay_targ_resp_t *otr, int cmd)
+{
+ int ret;
+
+ otr->otr_reqid = otl->otl_reqid;
+ do {
+ ret = ioctl(vip->vdi_overlayfd, cmd, otr);
+ } while (ret != 0 && errno == EINTR);
+
+ /*
+ * The only errors that should cause us to end up here are due to
+ * programmer errors. Arguably the EINVAL case indicates that something
+ * is a bit off; however, at this time we don't opt to kill varpd.
+ */
+ if (ret != 0 && errno != EINVAL)
+ libvarpd_panic("received bad errno from lookup_reply "
+ "(cmd %d): %d\n", cmd, errno);
+}
+
+static void
+libvarpd_overlay_lookup_handle(varpd_impl_t *vip)
+{
+ int ret;
+ varpd_query_t *vqp;
+ overlay_targ_lookup_t *otl;
+ overlay_targ_resp_t *otr;
+ varpd_instance_t *inst;
+
+ vqp = umem_cache_alloc(vip->vdi_qcache, UMEM_DEFAULT);
+ otl = &vqp->vq_lookup;
+ otr = &vqp->vq_response;
+ /*
+ * abort doesn't really help here that much, maybe we can instead try
+ * and for a reap or something?
+ */
+ if (vqp == NULL)
+ libvarpd_panic("failed to allocate memory for lookup "
+ "handle..., we should not panic()");
+ ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_LOOKUP, otl);
+ if (ret != 0 && errno != ETIME && errno != EINTR)
+ libvarpd_panic("received bad errno from OVERLAY_TARG_LOOKUP: "
+ "%d", errno);
+
+ if (ret != 0) {
+ umem_cache_free(vip->vdi_qcache, vqp);
+ return;
+ }
+
+ inst = (varpd_instance_t *)libvarpd_instance_lookup(
+ (varpd_handle_t *)vip, otl->otl_varpdid);
+ if (inst == NULL) {
+ libvarpd_overlay_lookup_reply(vip, otl, otr,
+ OVERLAY_TARG_DROP);
+ umem_cache_free(vip->vdi_qcache, vqp);
+ return;
+ }
+ vqp->vq_instance = inst;
+
+ inst->vri_plugin->vpp_ops->vpo_lookup(inst->vri_private,
+ (varpd_query_handle_t *)vqp, otl, &otr->otr_answer);
+}
+
+/* Use "void *" for vhp here to play nicely with thr_create(). */
+void *
+libvarpd_overlay_lookup_run(void *vhp)
+{
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+
+ mutex_enter(&vip->vdi_lock);
+ if (vip->vdi_lthr_quiesce == B_TRUE) {
+ mutex_exit(&vip->vdi_lock);
+ return (NULL);
+ }
+ vip->vdi_lthr_count++;
+
+ for (;;) {
+ mutex_exit(&vip->vdi_lock);
+ libvarpd_overlay_lookup_handle(vip);
+ mutex_enter(&vip->vdi_lock);
+ if (vip->vdi_lthr_quiesce == B_TRUE)
+ break;
+ }
+ assert(vip->vdi_lthr_count > 0);
+ vip->vdi_lthr_count--;
+ (void) cond_signal(&vip->vdi_lthr_cv);
+ mutex_exit(&vip->vdi_lock);
+ return (NULL);
+}
+
+void
+libvarpd_overlay_lookup_quiesce(varpd_handle_t *vhp)
+{
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+
+ mutex_enter(&vip->vdi_lock);
+ if (vip->vdi_lthr_count == 0) {
+ mutex_exit(&vip->vdi_lock);
+ return;
+ }
+ vip->vdi_lthr_quiesce = B_TRUE;
+ while (vip->vdi_lthr_count > 0)
+ (void) cond_wait(&vip->vdi_lthr_cv, &vip->vdi_lock);
+ vip->vdi_lthr_quiesce = B_FALSE;
+ mutex_exit(&vip->vdi_lock);
+}
+
+int
+libvarpd_overlay_iter(varpd_impl_t *vip, libvarpd_overlay_iter_f func,
+ void *arg)
+{
+ uint32_t curents = 0, i;
+ size_t size;
+ overlay_targ_list_t *otl;
+
+ for (;;) {
+ size = sizeof (overlay_targ_list_t) +
+ sizeof (uint32_t) * curents;
+ otl = umem_alloc(size, UMEM_DEFAULT);
+ if (otl == NULL)
+ return (ENOMEM);
+
+ otl->otl_nents = curents;
+ if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_LIST, otl) != 0) {
+ if (errno == EFAULT)
+ libvarpd_panic("OVERLAY_TARG_LIST ioctl "
+ "efault");
+ umem_free(otl, size);
+ if (errno == EINTR)
+ continue;
+ else
+ return (errno);
+ }
+
+ if (otl->otl_nents == curents)
+ break;
+
+ curents = otl->otl_nents;
+ umem_free(otl, size);
+ }
+
+ for (i = 0; i < otl->otl_nents; i++) {
+ if (func(vip, otl->otl_ents[i], arg) != 0)
+ break;
+ }
+ umem_free(otl, size);
+ return (0);
+}
+
+int
+libvarpd_overlay_cache_flush(varpd_instance_t *inst)
+{
+ int ret;
+ overlay_targ_cache_t cache;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ bzero(&cache, sizeof (overlay_targ_cache_t));
+ cache.otc_linkid = inst->vri_linkid;
+
+ ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_FLUSH, &cache);
+ if (ret != 0 && errno == EFAULT)
+ libvarpd_panic("OVERLAY_TARG_CACHE_FLUSH ioctl efault");
+ else if (ret != 0)
+ ret = errno;
+
+ return (ret);
+}
+
+int
+libvarpd_overlay_cache_delete(varpd_instance_t *inst, const uint8_t *key)
+{
+ int ret;
+ overlay_targ_cache_t cache;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ bzero(&cache, sizeof (overlay_targ_cache_t));
+ cache.otc_linkid = inst->vri_linkid;
+ bcopy(key, cache.otc_entry.otce_mac, ETHERADDRL);
+
+ ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_REMOVE, &cache);
+ if (ret != 0 && errno == EFAULT)
+ libvarpd_panic("OVERLAY_TARG_CACHE_REMOVE ioctl efault");
+ else if (ret != 0)
+ ret = errno;
+
+ return (ret);
+
+}
+
+int
+libvarpd_overlay_cache_get(varpd_instance_t *inst, const uint8_t *key,
+ varpd_client_cache_entry_t *entry)
+{
+ int ret;
+ overlay_targ_cache_t cache;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ bzero(&cache, sizeof (overlay_targ_cache_t));
+ cache.otc_linkid = inst->vri_linkid;
+ bcopy(key, cache.otc_entry.otce_mac, ETHERADDRL);
+
+ ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_GET, &cache);
+ if (ret != 0 && errno == EFAULT)
+ libvarpd_panic("OVERLAY_TARG_CACHE_GET ioctl efault");
+ else if (ret != 0)
+ return (errno);
+
+ bcopy(cache.otc_entry.otce_dest.otp_mac, &entry->vcp_mac, ETHERADDRL);
+ entry->vcp_flags = cache.otc_entry.otce_flags;
+ entry->vcp_ip = cache.otc_entry.otce_dest.otp_ip;
+ entry->vcp_port = cache.otc_entry.otce_dest.otp_port;
+
+ return (0);
+}
+
+int
+libvarpd_overlay_cache_set(varpd_instance_t *inst, const uint8_t *key,
+ const varpd_client_cache_entry_t *entry)
+{
+ int ret;
+ overlay_targ_cache_t cache;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ bzero(&cache, sizeof (overlay_targ_cache_t));
+ cache.otc_linkid = inst->vri_linkid;
+ bcopy(key, cache.otc_entry.otce_mac, ETHERADDRL);
+ bcopy(&entry->vcp_mac, cache.otc_entry.otce_dest.otp_mac, ETHERADDRL);
+ cache.otc_entry.otce_flags = entry->vcp_flags;
+ cache.otc_entry.otce_dest.otp_ip = entry->vcp_ip;
+ cache.otc_entry.otce_dest.otp_port = entry->vcp_port;
+
+ ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_SET, &cache);
+ if (ret != 0 && errno == EFAULT)
+ libvarpd_panic("OVERLAY_TARG_CACHE_SET ioctl efault");
+ else if (ret != 0)
+ return (errno);
+
+ return (0);
+}
+
+int
+libvarpd_overlay_cache_walk_fill(varpd_instance_t *inst, uint64_t *markerp,
+ uint64_t *countp, overlay_targ_cache_entry_t *ents)
+{
+ int ret;
+ size_t asize;
+ overlay_targ_cache_iter_t *iter;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ if (*countp > 200)
+ return (E2BIG);
+
+ asize = sizeof (overlay_targ_cache_iter_t) +
+ *countp * sizeof (overlay_targ_cache_entry_t);
+ iter = umem_alloc(asize, UMEM_DEFAULT);
+ if (iter == NULL)
+ return (ENOMEM);
+
+ iter->otci_linkid = inst->vri_linkid;
+ iter->otci_marker = *markerp;
+ iter->otci_count = *countp;
+ ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_ITER, iter);
+ if (ret != 0 && errno == EFAULT)
+ libvarpd_panic("OVERLAY_TARG_CACHE_ITER ioctl efault");
+ else if (ret != 0) {
+ ret = errno;
+ goto out;
+ }
+
+ *markerp = iter->otci_marker;
+ *countp = iter->otci_count;
+ bcopy(iter->otci_ents, ents,
+ *countp * sizeof (overlay_targ_cache_entry_t));
+out:
+ umem_free(iter, asize);
+ return (ret);
+}
+
+void
+libvarpd_plugin_query_reply(varpd_query_handle_t *vqh, int action)
+{
+ varpd_query_t *vqp = (varpd_query_t *)vqh;
+
+ if (vqp == NULL)
+ libvarpd_panic("unknown plugin passed invalid "
+ "varpd_query_handle_t");
+
+ if (action == VARPD_LOOKUP_DROP)
+ libvarpd_overlay_lookup_reply(vqp->vq_instance->vri_impl,
+ &vqp->vq_lookup, &vqp->vq_response, OVERLAY_TARG_DROP);
+ else if (action == VARPD_LOOKUP_OK)
+ libvarpd_overlay_lookup_reply(vqp->vq_instance->vri_impl,
+ &vqp->vq_lookup, &vqp->vq_response, OVERLAY_TARG_RESPOND);
+ else
+ libvarpd_panic("plugin %s passed in an invalid action: %d",
+ vqp->vq_instance->vri_plugin->vpp_name, action);
+
+ umem_cache_free(vqp->vq_instance->vri_impl->vdi_qcache, vqp);
+}
+
+void
+libvarpd_inject_varp(varpd_provider_handle_t *vph, const uint8_t *mac,
+ const overlay_target_point_t *otp)
+{
+ int ret;
+ overlay_targ_cache_t otc;
+ varpd_instance_t *inst = (varpd_instance_t *)vph;
+ varpd_impl_t *vip = inst->vri_impl;
+
+ if (otp == NULL) {
+ (void) libvarpd_overlay_cache_delete(inst, mac);
+ return;
+ }
+
+ otc.otc_linkid = inst->vri_linkid;
+ otc.otc_entry.otce_flags = 0;
+ bcopy(mac, otc.otc_entry.otce_mac, ETHERADDRL);
+ bcopy(otp, &otc.otc_entry.otce_dest, sizeof (overlay_target_point_t));
+
+ ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_SET, &otc);
+ if (ret != 0) {
+ switch (errno) {
+ case EBADF:
+ case EFAULT:
+ case ENOTSUP:
+ libvarpd_panic("received bad errno from "
+ "OVERLAY_TARG_CACHE_SET: %d", errno);
+ default:
+ break;
+ }
+ }
+}
+
+void
+libvarpd_fma_degrade(varpd_provider_handle_t *vph, const char *msg)
+{
+ int ret;
+ varpd_instance_t *inst = (varpd_instance_t *)vph;
+
+ ret = libvarpd_overlay_degrade(inst, msg);
+ switch (ret) {
+ case ENOENT:
+ case EFAULT:
+ libvarpd_panic("received bad errno from degrade ioctl: %d",
+ errno);
+ default:
+ break;
+ }
+}
+
+void
+libvarpd_fma_restore(varpd_provider_handle_t *vph)
+{
+ int ret;
+ varpd_instance_t *inst = (varpd_instance_t *)vph;
+
+ ret = libvarpd_overlay_restore(inst);
+ switch (ret) {
+ case ENOENT:
+ case EFAULT:
+ libvarpd_panic("received bad errno from restore ioctl: %d",
+ errno);
+ default:
+ break;
+ }
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_panic.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_panic.c
new file mode 100644
index 0000000000..ba6bc26bf6
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_panic.c
@@ -0,0 +1,53 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015, Joyent, Inc.
+ */
+
+/*
+ * No, 'tis not so deep as a well, nor so wide as a church door; but 'tis
+ * enough, 'twill serve. Ask for me tomorrow, and you shall find me a grave man.
+ *
+ * This file maintains various routines for handling when we die.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <thread.h>
+#include <stdlib.h>
+
+/*
+ * Normally these would be static, but if they're static, that throws off lint
+ * because it thinks we never use them, which is kind of the point, because we
+ * only read them in the core...
+ */
+int varpd_panic_errno;
+char varpd_panic_buf[1024];
+thread_t varpd_panic_thread;
+
+void
+libvarpd_panic(const char *fmt, ...)
+{
+ va_list ap;
+
+ /* Always save errno first! */
+ varpd_panic_errno = errno;
+ varpd_panic_thread = thr_self();
+
+ if (fmt != NULL) {
+ va_start(ap, fmt);
+ (void) vsnprintf(varpd_panic_buf, sizeof (varpd_panic_buf), fmt,
+ ap);
+ }
+ abort();
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_persist.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_persist.c
new file mode 100644
index 0000000000..27cc802a9c
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_persist.c
@@ -0,0 +1,586 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc. All rights reserved.
+ */
+
+/*
+ * varpd persistence backend
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <strings.h>
+#include <librename.h>
+#include <md5.h>
+#include <sys/sysmacros.h>
+#include <dirent.h>
+#include <sys/mman.h>
+#include <umem.h>
+#include <sys/debug.h>
+
+#include <libvarpd_impl.h>
+
+static uint8_t varpd_persist_magic[4] = {
+ 'v',
+ 'a',
+ 'r',
+ 'p',
+};
+
+#define VARPD_PERSIST_MAXWRITE 4096
+#define VARPD_PERSIST_VERSION_ONE 1
+#define VARPD_PERSIST_SUFFIX ".varpd"
+
+typedef struct varpd_persist_header {
+ uint8_t vph_magic[4];
+ uint32_t vph_version;
+ uint8_t vph_md5[16];
+} varpd_persist_header_t;
+
+void
+libvarpd_persist_init(varpd_impl_t *vip)
+{
+ vip->vdi_persistfd = -1;
+ if (rwlock_init(&vip->vdi_pfdlock, USYNC_THREAD, NULL) != 0)
+ libvarpd_panic("failed to create rw vdi_pfdlock");
+}
+
+void
+libvarpd_persist_fini(varpd_impl_t *vip)
+{
+ /*
+ * Clean up for someone that left something behind.
+ */
+ if (vip->vdi_persistfd != -1) {
+ if (close(vip->vdi_persistfd) != 0)
+ libvarpd_panic("failed to close persist fd %d: %d",
+ vip->vdi_persistfd, errno);
+ vip->vdi_persistfd = -1;
+ }
+ if (rwlock_destroy(&vip->vdi_pfdlock) != 0)
+ libvarpd_panic("failed to destroy rw vdi_pfdlock");
+}
+
+int
+libvarpd_persist_enable(varpd_handle_t *vhp, const char *rootdir)
+{
+ int fd;
+ struct stat st;
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+
+ fd = open(rootdir, O_RDONLY);
+ if (fd < 0)
+ return (errno);
+
+ if (fstat(fd, &st) != 0) {
+ int ret = errno;
+ if (close(fd) != 0)
+ libvarpd_panic("failed to close rootdir fd (%s) %d: %d",
+ rootdir, fd, errno);
+ return (ret);
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
+ if (close(fd) != 0)
+ libvarpd_panic("failed to close rootdir fd (%s) %d: %d",
+ rootdir, fd, errno);
+ return (EINVAL);
+ }
+
+
+ VERIFY0(rw_wrlock(&vip->vdi_pfdlock));
+ if (vip->vdi_persistfd != -1) {
+ VERIFY0(rw_unlock(&vip->vdi_pfdlock));
+ if (close(fd) != 0)
+ libvarpd_panic("failed to close rootdir fd (%s) %d: %d",
+ rootdir, fd, errno);
+ return (EEXIST);
+ }
+ vip->vdi_persistfd = fd;
+ VERIFY0(rw_unlock(&vip->vdi_pfdlock));
+
+ return (0);
+}
+
+static int
+libvarpd_persist_write(int fd, const void *buf, size_t buflen)
+{
+ ssize_t ret;
+ off_t off = 0;
+
+ while (buflen > 0) {
+ ret = write(fd, (void *)((uintptr_t)buf + off),
+ MIN(buflen, VARPD_PERSIST_MAXWRITE));
+ if (ret == -1 && errno == EINTR)
+ continue;
+ if (ret == -1)
+ return (errno);
+
+ off += ret;
+ buflen -= ret;
+ }
+
+ return (0);
+}
+
+static int
+libvarpd_persist_nvlist(int dirfd, uint64_t id, nvlist_t *nvl)
+{
+ int err, fd;
+ size_t size;
+ varpd_persist_header_t hdr;
+ librename_atomic_t *lrap;
+ char *buf = NULL, *name;
+
+ if ((err = nvlist_pack(nvl, &buf, &size, NV_ENCODE_XDR, 0)) != 0)
+ return (err);
+
+ if (asprintf(&name, "%llu%s", (unsigned long long)id, ".varpd") == -1) {
+ err = errno;
+ free(buf);
+ return (err);
+ }
+
+ if ((err = librename_atomic_fdinit(dirfd, name, NULL, 0600, 0,
+ &lrap)) != 0) {
+ free(name);
+ free(buf);
+ return (err);
+ }
+
+ fd = librename_atomic_fd(lrap);
+
+ bzero(&hdr, sizeof (varpd_persist_header_t));
+ bcopy(varpd_persist_magic, hdr.vph_magic, sizeof (varpd_persist_magic));
+ hdr.vph_version = VARPD_PERSIST_VERSION_ONE;
+ md5_calc(hdr.vph_md5, buf, size);
+
+ if ((err = libvarpd_persist_write(fd, &hdr,
+ sizeof (varpd_persist_header_t))) != 0) {
+ librename_atomic_fini(lrap);
+ free(name);
+ free(buf);
+ return (err);
+ }
+
+ if ((err = libvarpd_persist_write(fd, buf, size)) != 0) {
+ librename_atomic_fini(lrap);
+ free(name);
+ free(buf);
+ return (err);
+ }
+
+ do {
+ err = librename_atomic_commit(lrap);
+ } while (err == EINTR);
+
+ librename_atomic_fini(lrap);
+ free(name);
+ free(buf);
+ return (err);
+}
+
+int
+libvarpd_persist_instance(varpd_impl_t *vip, varpd_instance_t *inst)
+{
+ int err = 0;
+ nvlist_t *nvl = NULL, *cvl = NULL;
+
+ VERIFY0(rw_rdlock(&vip->vdi_pfdlock));
+ /* Check if persistence exists */
+ if (vip->vdi_persistfd == -1)
+ goto out;
+
+ if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
+ goto out;
+
+ if ((err = nvlist_alloc(&cvl, NV_UNIQUE_NAME, 0)) != 0)
+ goto out;
+
+ if ((err = nvlist_add_uint64(nvl, "vri_id", inst->vri_id)) != 0)
+ goto out;
+
+ if ((err = nvlist_add_uint32(nvl, "vri_linkid", inst->vri_linkid)) != 0)
+ goto out;
+
+ if ((err = nvlist_add_uint32(nvl, "vri_dest",
+ (uint32_t)inst->vri_dest)) != 0)
+ goto out;
+ if ((err = nvlist_add_uint32(nvl, "vri_mode",
+ (uint32_t)inst->vri_mode)) != 0)
+ goto out;
+
+ if ((err = nvlist_add_string(nvl, "vri_plugin",
+ inst->vri_plugin->vpp_name)) != 0)
+ goto out;
+
+ err = inst->vri_plugin->vpp_ops->vpo_save(inst->vri_private, cvl);
+ if (err != 0)
+ goto out;
+
+ if ((err = nvlist_add_nvlist(nvl, "vri_private", cvl)) != 0)
+ goto out;
+
+ err = libvarpd_persist_nvlist(vip->vdi_persistfd, inst->vri_id, nvl);
+out:
+ nvlist_free(nvl);
+ nvlist_free(cvl);
+ VERIFY0(rw_unlock(&vip->vdi_pfdlock));
+ return (err);
+}
+
+void
+libvarpd_torch_instance(varpd_impl_t *vip, varpd_instance_t *inst)
+{
+ char buf[32];
+ int ret;
+
+ VERIFY0(rw_rdlock(&vip->vdi_pfdlock));
+ if (vip->vdi_persistfd == -1) {
+ VERIFY0(rw_unlock(&vip->vdi_pfdlock));
+ return;
+ }
+
+ if (snprintf(buf, sizeof (buf), "%lld.varpd", inst->vri_id) >= 32)
+ libvarpd_panic("somehow exceeded static value for "
+ "libvarpd_torch_instance buffer");
+
+ do {
+ ret = unlinkat(vip->vdi_persistfd, buf, 0);
+ } while (ret == -1 && errno == EINTR);
+ if (ret != 0) {
+ switch (errno) {
+ case ENOENT:
+ break;
+ default:
+ libvarpd_panic("failed to unlinkat %d`%s: %s",
+ vip->vdi_persistfd, buf, strerror(errno));
+ }
+ }
+
+ VERIFY0(rw_unlock(&vip->vdi_pfdlock));
+}
+
+static int
+libvarpd_persist_restore_instance(varpd_impl_t *vip, nvlist_t *nvl)
+{
+ int err;
+ nvlist_t *pvl;
+ uint64_t id, flags, vid;
+ uint32_t linkid, dest, mode;
+ char *pluginstr;
+ varpd_plugin_t *plugin;
+ overlay_plugin_dest_t adest;
+ varpd_instance_t *inst, lookup;
+
+ if (nvlist_lookup_uint64(nvl, "vri_id", &id) != 0)
+ return (EINVAL);
+
+ if (nvlist_lookup_uint32(nvl, "vri_linkid", &linkid) != 0)
+ return (EINVAL);
+
+ if (nvlist_lookup_uint32(nvl, "vri_dest", &dest) != 0)
+ return (EINVAL);
+
+ if (nvlist_lookup_uint32(nvl, "vri_mode", &mode) != 0)
+ return (EINVAL);
+
+ if (nvlist_lookup_string(nvl, "vri_plugin", &pluginstr) != 0)
+ return (EINVAL);
+
+ if (nvlist_lookup_nvlist(nvl, "vri_private", &pvl) != 0)
+ return (EINVAL);
+
+ plugin = libvarpd_plugin_lookup(vip, pluginstr);
+ if (plugin == NULL)
+ return (EINVAL);
+
+ if (plugin->vpp_mode != mode)
+ return (EINVAL);
+
+ if (libvarpd_overlay_info(vip, linkid, &adest, &flags, &vid) != 0)
+ return (EINVAL);
+
+ if (dest != adest)
+ return (EINVAL);
+
+ inst = umem_alloc(sizeof (varpd_instance_t), UMEM_DEFAULT);
+ if (inst == NULL)
+ libvarpd_panic("failed to allocate instance for restore");
+
+ inst->vri_id = id_alloc_specific(vip->vdi_idspace, id);
+ if (inst->vri_id != id) {
+ umem_free(inst, sizeof (varpd_instance_t));
+ return (EINVAL);
+ }
+
+ inst->vri_linkid = linkid;
+ inst->vri_vnetid = vid;
+ inst->vri_mode = plugin->vpp_mode;
+ inst->vri_dest = dest;
+ inst->vri_plugin = plugin;
+ inst->vri_impl = vip;
+ inst->vri_flags = 0;
+ if (plugin->vpp_ops->vpo_restore(pvl, (varpd_provider_handle_t *)inst,
+ dest, &inst->vri_private) != 0) {
+ id_free(vip->vdi_idspace, id);
+ umem_free(inst, sizeof (varpd_instance_t));
+ return (EINVAL);
+ }
+
+ if (mutex_init(&inst->vri_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL) != 0)
+ libvarpd_panic("failed to create vri_lock mutex");
+
+ mutex_enter(&vip->vdi_lock);
+ lookup.vri_id = inst->vri_id;
+ if (avl_find(&vip->vdi_instances, &lookup, NULL) != NULL)
+ libvarpd_panic("found duplicate instance with id %d",
+ lookup.vri_id);
+ avl_add(&vip->vdi_instances, inst);
+ lookup.vri_linkid = inst->vri_linkid;
+ if (avl_find(&vip->vdi_linstances, &lookup, NULL) != NULL)
+ libvarpd_panic("found duplicate linstance with id %d",
+ lookup.vri_linkid);
+ avl_add(&vip->vdi_linstances, inst);
+ mutex_exit(&vip->vdi_lock);
+
+ if (plugin->vpp_ops->vpo_start(inst->vri_private) != 0) {
+ libvarpd_instance_destroy((varpd_instance_handle_t *)inst);
+ return (EINVAL);
+ }
+
+ if (flags & OVERLAY_TARG_INFO_F_ACTIVE)
+ (void) libvarpd_overlay_disassociate(inst);
+
+ if (libvarpd_overlay_associate(inst) != 0) {
+ libvarpd_instance_destroy((varpd_instance_handle_t *)inst);
+ return (EINVAL);
+ }
+
+ if (flags & OVERLAY_TARG_INFO_F_DEGRADED) {
+ if ((err = libvarpd_overlay_restore(inst)) != 0) {
+ libvarpd_panic("failed to restore instance %p: %d\n",
+ inst, err);
+ }
+ }
+
+ mutex_enter(&inst->vri_lock);
+ inst->vri_flags |= VARPD_INSTANCE_F_ACTIVATED;
+ mutex_exit(&inst->vri_lock);
+
+ return (0);
+}
+
+static int
+libvarpd_persist_restore_one(varpd_impl_t *vip, int fd)
+{
+ int err;
+ size_t fsize;
+ struct stat st;
+ void *buf, *datap;
+ varpd_persist_header_t *hdr;
+ uint8_t md5[16];
+ nvlist_t *nvl;
+
+ if (fstat(fd, &st) != 0)
+ return (errno);
+
+ if (st.st_size <= sizeof (varpd_persist_header_t))
+ return (EINVAL);
+ fsize = st.st_size - sizeof (varpd_persist_header_t);
+
+ buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (buf == MAP_FAILED)
+ return (errno);
+
+ hdr = buf;
+ if (bcmp(varpd_persist_magic, hdr->vph_magic,
+ sizeof (varpd_persist_magic)) != 0) {
+ if (munmap(buf, st.st_size) != 0)
+ libvarpd_panic("failed to munmap %p: %d", buf, errno);
+ return (EINVAL);
+ }
+
+ if (hdr->vph_version != VARPD_PERSIST_VERSION_ONE) {
+ if (munmap(buf, st.st_size) != 0)
+ libvarpd_panic("failed to munmap %p: %d", buf, errno);
+ return (EINVAL);
+ }
+
+ datap = (void *)((uintptr_t)buf + sizeof (varpd_persist_header_t));
+ md5_calc(md5, datap, fsize);
+ if (bcmp(md5, hdr->vph_md5, sizeof (uint8_t) * 16) != 0) {
+ if (munmap(buf, st.st_size) != 0)
+ libvarpd_panic("failed to munmap %p: %d", buf, errno);
+ return (EINVAL);
+ }
+
+ err = nvlist_unpack(datap, fsize, &nvl, 0);
+ if (munmap(buf, st.st_size) != 0)
+ libvarpd_panic("failed to munmap %p: %d", buf, errno);
+
+ if (err != 0)
+ return (EINVAL);
+
+ err = libvarpd_persist_restore_instance(vip, nvl);
+ nvlist_free(nvl);
+ return (err);
+}
+
+/* ARGSUSED */
+static int
+libvarpd_check_degrade_cb(varpd_impl_t *vip, datalink_id_t linkid, void *arg)
+{
+ varpd_instance_t *inst;
+
+ mutex_enter(&vip->vdi_lock);
+ for (inst = avl_first(&vip->vdi_instances); inst != NULL;
+ inst = AVL_NEXT(&vip->vdi_instances, inst)) {
+ if (inst->vri_linkid == linkid) {
+ mutex_exit(&vip->vdi_lock);
+ return (0);
+ }
+ }
+
+ mutex_exit(&vip->vdi_lock);
+
+ (void) libvarpd_overlay_degrade_datalink(vip, linkid,
+ "no varpd instance exists");
+ return (0);
+}
+
+static void
+libvarpd_check_degrade(varpd_impl_t *vip)
+{
+ (void) libvarpd_overlay_iter(vip, libvarpd_check_degrade_cb, NULL);
+}
+
+int
+libvarpd_persist_restore(varpd_handle_t *vhp)
+{
+ int dirfd;
+ int ret = 0;
+ DIR *dirp = NULL;
+ struct dirent *dp;
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+
+ VERIFY0(rw_rdlock(&vip->vdi_pfdlock));
+ if ((dirfd = dup(vip->vdi_persistfd)) < 0) {
+ ret = errno;
+ goto out;
+ }
+
+ if ((dirp = fdopendir(dirfd)) == NULL) {
+ ret = errno;
+ if (close(dirfd) != 0)
+ libvarpd_panic("failed to close dirfd %d: %d",
+ dirfd, errno);
+ goto out;
+ }
+
+ for (;;) {
+ int fd;
+ uint64_t id;
+ char *eptr;
+ struct stat st;
+
+ errno = 0;
+ dp = readdir(dirp);
+ if (dp == NULL) {
+ ret = errno;
+ break;
+ }
+
+ if (strcmp(dp->d_name, ".") == 0 ||
+ strcmp(dp->d_name, "..") == 0)
+ continue;
+
+ /*
+ * Leave files that we don't recognize alone. A valid file has
+ * the format `%llu.varpd`.
+ */
+ errno = 0;
+ id = strtoull(dp->d_name, &eptr, 10);
+ if ((id == 0 && errno == EINVAL) ||
+ (id == ULLONG_MAX && errno == ERANGE))
+ continue;
+
+ if (strcmp(eptr, VARPD_PERSIST_SUFFIX) != 0)
+ continue;
+
+ fd = openat(vip->vdi_persistfd, dp->d_name, O_RDONLY);
+ if (fd < 0) {
+ ret = errno;
+ break;
+ }
+
+ if (fstat(fd, &st) != 0) {
+ ret = errno;
+ break;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ if (close(fd) != 0)
+ libvarpd_panic("failed to close fd (%s) %d: "
+ "%d\n", dp->d_name, fd, errno);
+ continue;
+ }
+
+ ret = libvarpd_persist_restore_one(vip, fd);
+ if (close(fd) != 0)
+ libvarpd_panic("failed to close fd (%s) %d: "
+ "%d\n", dp->d_name, fd, errno);
+ /*
+ * This is an invalid file. We'll unlink it to save us this
+ * trouble in the future.
+ */
+ if (ret != 0) {
+ if (unlinkat(vip->vdi_persistfd, dp->d_name, 0) != 0) {
+ ret = errno;
+ break;
+ }
+ }
+ }
+
+ libvarpd_check_degrade(vip);
+
+out:
+ if (dirp != NULL)
+ (void) closedir(dirp);
+ VERIFY0(rw_unlock(&vip->vdi_pfdlock));
+ return (ret);
+}
+
+int
+libvarpd_persist_disable(varpd_handle_t *vhp)
+{
+ varpd_impl_t *vip = (varpd_impl_t *)vhp;
+
+ VERIFY0(rw_wrlock(&vip->vdi_pfdlock));
+ if (vip->vdi_persistfd == -1) {
+ mutex_exit(&vip->vdi_lock);
+ VERIFY0(rw_unlock(&vip->vdi_pfdlock));
+ return (ENOENT);
+ }
+ if (close(vip->vdi_persistfd) != 0)
+ libvarpd_panic("failed to close persist fd %d: %d",
+ vip->vdi_persistfd, errno);
+ vip->vdi_persistfd = -1;
+ VERIFY0(rw_unlock(&vip->vdi_pfdlock));
+ return (0);
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_plugin.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_plugin.c
new file mode 100644
index 0000000000..176306a3f7
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_plugin.c
@@ -0,0 +1,256 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * varpd plugin management
+ */
+
+#include <libvarpd_impl.h>
+#include <errno.h>
+#include <umem.h>
+#include <assert.h>
+#include <strings.h>
+#include <dlfcn.h>
+#include <link.h>
+#include <stdio.h>
+
+static varpd_impl_t *varpd_load_handle;
+static const char *varpd_load_path;
+static mutex_t varpd_load_lock;
+static cond_t varpd_load_cv;
+
+int
+libvarpd_plugin_comparator(const void *lp, const void *rp)
+{
+ int ret;
+ const varpd_plugin_t *lpp, *rpp;
+
+ lpp = lp;
+ rpp = rp;
+
+ ret = strcmp(lpp->vpp_name, rpp->vpp_name);
+ if (ret > 0)
+ return (1);
+ if (ret < 0)
+ return (-1);
+ return (0);
+}
+
+varpd_plugin_register_t *
+libvarpd_plugin_alloc(uint_t version, int *errp)
+{
+ int err;
+ varpd_plugin_register_t *vprp;
+
+ if (errp == NULL)
+ errp = &err;
+
+ if (version != VARPD_VERSION_ONE) {
+ (void) fprintf(stderr,
+ "unsupported registration version %u - %s\n",
+ version, varpd_load_path);
+ *errp = EINVAL;
+ return (NULL);
+ }
+
+ vprp = umem_alloc(sizeof (varpd_plugin_register_t), UMEM_DEFAULT);
+ if (vprp == NULL) {
+ (void) fprintf(stderr,
+ "failed to allocate registration handle - %s\n",
+ varpd_load_path);
+ *errp = ENOMEM;
+ return (NULL);
+ }
+
+ vprp->vpr_version = VARPD_VERSION_ONE;
+
+ return (vprp);
+}
+
+void
+libvarpd_plugin_free(varpd_plugin_register_t *vprp)
+{
+ umem_free(vprp, sizeof (varpd_plugin_register_t));
+}
+
+int
+libvarpd_plugin_register(varpd_plugin_register_t *vprp)
+{
+ varpd_plugin_t *vpp;
+ varpd_plugin_t lookup;
+
+ vpp = umem_alloc(sizeof (varpd_plugin_t), UMEM_DEFAULT);
+ if (vpp == NULL) {
+ (void) fprintf(stderr,
+ "failed to allocate memory for the varpd_plugin_t - %s\n",
+ varpd_load_path);
+ return (ENOMEM);
+ }
+
+ /* Watch out for an evil plugin */
+ if (vprp->vpr_version != VARPD_VERSION_ONE) {
+ (void) fprintf(stderr,
+ "unsupported registration version %u - %s\n",
+ vprp->vpr_version, varpd_load_path);
+ return (EINVAL);
+ }
+
+ mutex_enter(&varpd_load_lock);
+ if (varpd_load_handle == NULL)
+ libvarpd_panic("varpd_load_handle was unexpectedly null");
+
+ mutex_enter(&varpd_load_handle->vdi_lock);
+ lookup.vpp_name = vprp->vpr_name;
+ if (avl_find(&varpd_load_handle->vdi_plugins, &lookup, NULL) != NULL) {
+ (void) fprintf(stderr,
+ "module already exists with requested name '%s' - %s\n",
+ vprp->vpr_name, varpd_load_path);
+ mutex_exit(&varpd_load_handle->vdi_lock);
+ mutex_exit(&varpd_load_lock);
+ umem_free(vpp, sizeof (varpd_plugin_t));
+ return (EEXIST);
+ }
+ vpp->vpp_name = strdup(vprp->vpr_name);
+ if (vpp->vpp_name == NULL) {
+ (void) fprintf(stderr,
+ "failed to allocate memory to duplicate name - %s\n",
+ varpd_load_path);
+ mutex_exit(&varpd_load_handle->vdi_lock);
+ mutex_exit(&varpd_load_lock);
+ umem_free(vpp, sizeof (varpd_plugin_t));
+ return (ENOMEM);
+ }
+
+ vpp->vpp_mode = vprp->vpr_mode;
+ vpp->vpp_ops = vprp->vpr_ops;
+ if (mutex_init(&vpp->vpp_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL) != 0)
+ libvarpd_panic("failed to create plugin's vpp_lock");
+ vpp->vpp_active = 0;
+ avl_add(&varpd_load_handle->vdi_plugins, vpp);
+ mutex_exit(&varpd_load_handle->vdi_lock);
+ mutex_exit(&varpd_load_lock);
+
+ return (0);
+}
+
+varpd_plugin_t *
+libvarpd_plugin_lookup(varpd_impl_t *vip, const char *name)
+{
+ varpd_plugin_t lookup, *ret;
+
+ lookup.vpp_name = name;
+ mutex_enter(&vip->vdi_lock);
+ ret = avl_find(&vip->vdi_plugins, &lookup, NULL);
+ mutex_exit(&vip->vdi_lock);
+
+ return (ret);
+}
+
+/* ARGSUSED */
+static int
+libvarpd_plugin_load_cb(varpd_impl_t *vip, const char *path, void *unused)
+{
+ void *dlp;
+
+ varpd_load_path = path;
+ dlp = dlopen(path, RTLD_LOCAL | RTLD_NOW);
+ if (dlp == NULL)
+ (void) fprintf(stderr, "dlopen failed - %s\n", path);
+ path = NULL;
+
+ return (0);
+}
+
+int
+libvarpd_plugin_load(varpd_handle_t *vph, const char *path)
+{
+ int ret = 0;
+ varpd_impl_t *vip = (varpd_impl_t *)vph;
+
+ if (vip == NULL || path == NULL)
+ return (EINVAL);
+ mutex_enter(&varpd_load_lock);
+ while (varpd_load_handle != NULL)
+ (void) cond_wait(&varpd_load_cv, &varpd_load_lock);
+ varpd_load_handle = vip;
+ mutex_exit(&varpd_load_lock);
+
+ ret = libvarpd_dirwalk(vip, path, ".so", libvarpd_plugin_load_cb, NULL);
+
+ mutex_enter(&varpd_load_lock);
+ varpd_load_handle = NULL;
+ (void) cond_signal(&varpd_load_cv);
+ mutex_exit(&varpd_load_lock);
+
+ return (ret);
+}
+
+int
+libvarpd_plugin_walk(varpd_handle_t *vph, libvarpd_plugin_walk_f func,
+ void *arg)
+{
+ varpd_impl_t *vip = (varpd_impl_t *)vph;
+ varpd_plugin_t *vpp;
+
+ mutex_enter(&vip->vdi_lock);
+ for (vpp = avl_first(&vip->vdi_plugins); vpp != NULL;
+ vpp = AVL_NEXT(&vip->vdi_plugins, vpp)) {
+ if (func(vph, vpp->vpp_name, arg) != 0) {
+ mutex_exit(&vip->vdi_lock);
+ return (1);
+ }
+ }
+ mutex_exit(&vip->vdi_lock);
+ return (0);
+}
+
+void
+libvarpd_plugin_init(void)
+{
+ if (mutex_init(&varpd_load_lock, USYNC_THREAD | LOCK_RECURSIVE |
+ LOCK_ERRORCHECK, NULL) != 0)
+ libvarpd_panic("failed to create varpd_load_lock");
+
+ if (cond_init(&varpd_load_cv, USYNC_THREAD, NULL) != 0)
+ libvarpd_panic("failed to create varpd_load_cv");
+
+ varpd_load_handle = NULL;
+}
+
+void
+libvarpd_plugin_fini(void)
+{
+ assert(varpd_load_handle == NULL);
+ if (mutex_destroy(&varpd_load_lock) != 0)
+ libvarpd_panic("failed to destroy varpd_load_lock");
+ if (cond_destroy(&varpd_load_cv) != 0)
+ libvarpd_panic("failed to destroy varpd_load_cv");
+}
+
+void
+libvarpd_plugin_prefork(void)
+{
+ mutex_enter(&varpd_load_lock);
+ while (varpd_load_handle != NULL)
+ (void) cond_wait(&varpd_load_cv, &varpd_load_lock);
+}
+
+void
+libvarpd_plugin_postfork(void)
+{
+ (void) cond_signal(&varpd_load_cv);
+ mutex_exit(&varpd_load_lock);
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_prop.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_prop.c
new file mode 100644
index 0000000000..f3a1492408
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_prop.c
@@ -0,0 +1,300 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+/*
+ * varpd property management
+ */
+
+#include <libvarpd_impl.h>
+#include <errno.h>
+#include <strings.h>
+#include <sys/mac.h>
+#include <umem.h>
+
+typedef struct varpd_prop_info {
+ varpd_impl_t *vprop_vip;
+ varpd_instance_t *vprop_instance;
+ uint_t vprop_type;
+ uint_t vprop_prot;
+ uint32_t vprop_defsize;
+ uint32_t vprop_psize;
+ char vprop_name[LIBVARPD_PROP_NAMELEN];
+ uint8_t vprop_default[LIBVARPD_PROP_SIZEMAX];
+ uint8_t vprop_poss[LIBVARPD_PROP_SIZEMAX];
+} varpd_prop_info_t;
+
+/* Internal Properties */
+static int varpd_nintprops = 1;
+static const char *varpd_intprops[] = {
+ "search"
+};
+
+static int
+libvarpd_prop_get_search(varpd_prop_info_t *infop, void *buf, uint32_t *sizep)
+{
+ varpd_plugin_t *vpp = infop->vprop_instance->vri_plugin;
+ size_t nlen;
+
+ nlen = strlen(vpp->vpp_name) + 1;
+ if (nlen > *sizep)
+ return (EOVERFLOW);
+ *sizep = nlen;
+ (void) strlcpy(buf, vpp->vpp_name, *sizep);
+ return (0);
+}
+
+void
+libvarpd_prop_set_name(varpd_prop_handle_t *phdl, const char *name)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ (void) strlcpy(infop->vprop_name, name, OVERLAY_PROP_NAMELEN);
+}
+
+void
+libvarpd_prop_set_prot(varpd_prop_handle_t *phdl, overlay_prop_prot_t perm)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ infop->vprop_prot = perm;
+}
+
+void
+libvarpd_prop_set_type(varpd_prop_handle_t *phdl, overlay_prop_type_t type)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ infop->vprop_type = type;
+}
+
+int
+libvarpd_prop_set_default(varpd_prop_handle_t *phdl, void *buf, ssize_t len)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+
+ if (len > LIBVARPD_PROP_SIZEMAX)
+ return (E2BIG);
+
+ if (len < 0)
+ return (EOVERFLOW);
+
+ bcopy(buf, infop->vprop_default, len);
+ infop->vprop_defsize = len;
+ return (0);
+}
+
+void
+libvarpd_prop_set_nodefault(varpd_prop_handle_t *phdl)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+
+ infop->vprop_default[0] = '\0';
+ infop->vprop_defsize = 0;
+}
+
+void
+libvarpd_prop_set_range_uint32(varpd_prop_handle_t *phdl, uint32_t min,
+ uint32_t max)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ mac_propval_range_t *rangep = (mac_propval_range_t *)infop->vprop_poss;
+
+ if (rangep->mpr_count != 0 && rangep->mpr_type != MAC_PROPVAL_UINT32)
+ return;
+
+ if (infop->vprop_psize + sizeof (mac_propval_uint32_range_t) >
+ sizeof (infop->vprop_poss))
+ return;
+
+ infop->vprop_psize += sizeof (mac_propval_uint32_range_t);
+ rangep->mpr_count++;
+ rangep->mpr_type = MAC_PROPVAL_UINT32;
+ rangep->u.mpr_uint32[rangep->mpr_count-1].mpur_min = min;
+ rangep->u.mpr_uint32[rangep->mpr_count-1].mpur_max = max;
+}
+
+void
+libvarpd_prop_set_range_str(varpd_prop_handle_t *phdl, const char *str)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ size_t len = strlen(str) + 1; /* Account for a null terminator */
+ mac_propval_range_t *rangep = (mac_propval_range_t *)infop->vprop_poss;
+ mac_propval_str_range_t *pstr = &rangep->u.mpr_str;
+
+ if (rangep->mpr_count != 0 && rangep->mpr_type != MAC_PROPVAL_STR)
+ return;
+
+ if (infop->vprop_psize + len > sizeof (infop->vprop_poss))
+ return;
+
+ rangep->mpr_count++;
+ rangep->mpr_type = MAC_PROPVAL_STR;
+ (void) strlcpy((char *)&pstr->mpur_data[pstr->mpur_nextbyte], str,
+ sizeof (infop->vprop_poss) - infop->vprop_psize);
+ pstr->mpur_nextbyte += len;
+ infop->vprop_psize += len;
+}
+
+int
+libvarpd_prop_handle_alloc(varpd_handle_t *vph, varpd_instance_handle_t *inst,
+ varpd_prop_handle_t **phdlp)
+{
+ varpd_prop_info_t *infop;
+
+ infop = umem_alloc(sizeof (varpd_prop_info_t), UMEM_DEFAULT);
+ if (infop == NULL)
+ return (ENOMEM);
+
+ bzero(infop, sizeof (varpd_prop_info_t));
+ infop->vprop_vip = (varpd_impl_t *)vph;
+ infop->vprop_instance = (varpd_instance_t *)inst;
+
+ *phdlp = (varpd_prop_handle_t *)infop;
+ return (0);
+}
+
+void
+libvarpd_prop_handle_free(varpd_prop_handle_t *phdl)
+{
+ umem_free(phdl, sizeof (varpd_prop_info_t));
+}
+
+int
+libvarpd_prop_nprops(varpd_instance_handle_t *ihdl, uint_t *np)
+{
+ int ret;
+ varpd_instance_t *instp = (varpd_instance_t *)ihdl;
+
+ ret = instp->vri_plugin->vpp_ops->vpo_nprops(instp->vri_private, np);
+ if (ret != 0)
+ return (ret);
+ *np += varpd_nintprops;
+ return (0);
+}
+
+static int
+libvarpd_prop_info_fill_int_cb(varpd_handle_t *handle, const char *name,
+ void *arg)
+{
+ varpd_prop_handle_t *vph = arg;
+ libvarpd_prop_set_range_str(vph, name);
+ return (0);
+}
+
+static int
+libvarpd_prop_info_fill_int(varpd_prop_handle_t *vph, uint_t propid)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)vph;
+ if (propid >= varpd_nintprops)
+ abort();
+ libvarpd_prop_set_name(vph, varpd_intprops[0]);
+ libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_READ);
+ libvarpd_prop_set_type(vph, OVERLAY_PROP_T_STRING);
+ libvarpd_prop_set_nodefault(vph);
+ (void) libvarpd_plugin_walk(
+ (varpd_handle_t *)infop->vprop_instance->vri_impl,
+ libvarpd_prop_info_fill_int_cb, vph);
+ return (0);
+}
+
+int
+libvarpd_prop_info_fill(varpd_prop_handle_t *phdl, uint_t propid)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ varpd_instance_t *instp = infop->vprop_instance;
+ mac_propval_range_t *rangep = (mac_propval_range_t *)infop->vprop_poss;
+
+ infop->vprop_psize = sizeof (mac_propval_range_t);
+
+ bzero(rangep, sizeof (mac_propval_range_t));
+ if (propid < varpd_nintprops) {
+ return (libvarpd_prop_info_fill_int(phdl, propid));
+ } else {
+ varpd_plugin_t *vpp = instp->vri_plugin;
+ return (vpp->vpp_ops->vpo_propinfo(instp->vri_private,
+ propid - varpd_nintprops, phdl));
+ }
+}
+
+int
+libvarpd_prop_info(varpd_prop_handle_t *phdl, const char **namep,
+ uint_t *typep, uint_t *protp, const void **defp, uint32_t *sizep,
+ const mac_propval_range_t **possp)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ if (namep != NULL)
+ *namep = infop->vprop_name;
+ if (typep != NULL)
+ *typep = infop->vprop_type;
+ if (protp != NULL)
+ *protp = infop->vprop_prot;
+ if (defp != NULL)
+ *defp = infop->vprop_default;
+ if (sizep != NULL)
+ *sizep = infop->vprop_psize;
+ if (possp != NULL)
+ *possp = (mac_propval_range_t *)infop->vprop_poss;
+ return (0);
+}
+
+int
+libvarpd_prop_get(varpd_prop_handle_t *phdl, void *buf, uint32_t *sizep)
+{
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ varpd_instance_t *instp = infop->vprop_instance;
+
+ if (infop->vprop_name[0] == '\0')
+ return (EINVAL);
+
+ if (strcmp(varpd_intprops[0], infop->vprop_name) == 0) {
+ /* search property */
+ return (libvarpd_prop_get_search(infop, buf, sizep));
+ }
+
+ return (instp->vri_plugin->vpp_ops->vpo_getprop(instp->vri_private,
+ infop->vprop_name, buf, sizep));
+}
+
+int
+libvarpd_prop_set(varpd_prop_handle_t *phdl, const void *buf, uint32_t size)
+{
+ int i;
+ varpd_prop_info_t *infop = (varpd_prop_info_t *)phdl;
+ varpd_instance_t *instp = infop->vprop_instance;
+
+ if (infop->vprop_name[0] == '\0')
+ return (EINVAL);
+
+ for (i = 0; i < varpd_nintprops; i++) {
+ if (strcmp(infop->vprop_name, varpd_intprops[i]) == 0) {
+ return (EPERM);
+ }
+ }
+
+ return (instp->vri_plugin->vpp_ops->vpo_setprop(instp->vri_private,
+ infop->vprop_name, buf, size));
+}
+
+void
+libvarpd_prop_door_convert(const varpd_prop_handle_t *phdl,
+ varpd_client_propinfo_arg_t *vcfap)
+{
+ const varpd_prop_info_t *infop = (const varpd_prop_info_t *)phdl;
+
+ vcfap->vcfa_type = infop->vprop_type;
+ vcfap->vcfa_prot = infop->vprop_prot;
+ vcfap->vcfa_defsize = infop->vprop_defsize;
+ vcfap->vcfa_psize = infop->vprop_psize;
+ bcopy(infop->vprop_name, vcfap->vcfa_name, LIBVARPD_PROP_NAMELEN);
+ bcopy(infop->vprop_default, vcfap->vcfa_default, LIBVARPD_PROP_SIZEMAX);
+ bcopy(infop->vprop_poss, vcfap->vcfa_poss, LIBVARPD_PROP_SIZEMAX);
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_provider.h b/usr/src/lib/varpd/libvarpd/common/libvarpd_provider.h
new file mode 100644
index 0000000000..b6910b9ed5
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_provider.h
@@ -0,0 +1,417 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _LIBVARPD_PROVIDER_H
+#define _LIBVARPD_PROVIDER_H
+
+/*
+ * varpd provider interface for lookup modules
+ *
+ * This header file defines all the structures and functions that a given lookup
+ * module needs to implement and perform its purpose. At this time, all of these
+ * interfaces are considered private to illumos and therefore are subject to
+ * change. At some point we will move to more broadly stabilize these interfaces
+ * and commit to them. Until such time, expect breakage for out of gate
+ * consumers.
+ *
+ * A plugin is a dynamic shared object that is placed inside of varpd's default
+ * module.
+ *
+ * The shared object must define an initializer, such as with #pragma init. This
+ * function will be run with the module is dlopened by libvarpd. In that init
+ * function, the function must allocate a varpd_plugin_register by calling
+ * libvarpd_plugin_alloc() and specifying VARPD_CURRENT_VERSION. If that
+ * succeeds, then it should proceed to fill out the registration and then call,
+ * libvarpd_plugin_register() with it. Regardless of whether it succeeds or
+ * fails, it should call libvarpd_plugin_free(). In the case of failure, there
+ * is not much that the module should do, other than log some message to
+ * stderr.
+ *
+ * Once libvarpd_plugin_register() returns, the module should assume that any
+ * of the operations it defined in the operation vector may be called and
+ * therefore it is recommended that any other required initialization should be
+ * performed at that time.
+ *
+ * At this time, once a plugin is loaded, it will not be unloaded. Therefore,
+ * there is no corresponding requirement to unregister, though that may come in
+ * a future version.
+ *
+ * -----------------------------
+ * Plugin Types and Destinations
+ * -----------------------------
+ *
+ * There are two different kinds of plugins in this world, there are point to
+ * point plugins and there are dynamic plugins. The key difference is in how
+ * packets are routed through the system. In a point to point plugin, a single
+ * destination is used when the instance is started. In dynamic plugins,
+ * destinations are looked up as they are required and an instance of a plugin
+ * is required to provide that.
+ *
+ * These point to point plugins define a type of OVERLAY_TARGET_POINT and the
+ * dynamic plugins instead define a type of OVERLAY_TARGET_DYNAMIC.
+ *
+ * Encapsulation plugins have multiple types of destinations. They may require
+ * an Ethernet address (OVERLAY_PLUGIN_D_ETHERNET), IP address
+ * (OVERLAY_PLUGIN_D_IP), and a port (OVERLAY_PLUGIN_D_PORT). For example,
+ * consider vxlan, it requires an IP and a port; while a hypothetical nvgre,
+ * would only require an IP.
+ *
+ * A plugin is allowed to describe which of these fields that it supports and
+ * given which encapsulation plugin it is paired with, it can support a varying
+ * degree of properties. For example, consider the example of the direct plugin.
+ * It has a notion of a destination port and a destination IP. If it is paired
+ * with a plugin that only requires an IP, then it wouldn't need to show a
+ * property that's related to a destination port.
+ *
+ * ------------------
+ * Plugin Definitions
+ * ------------------
+ *
+ * A plugin is required to fill in both an operations vector and a series of
+ * additional metadata that it passed in to libvarpd_plugin_register(). The
+ * following lists all of the routines and their purposes. The full signatures
+ * are available in the body of the header file.
+ *
+ * varpd_plugin_create_f
+ *
+ * Create a new instance of a plugin. Each instance refers to a different
+ * overlay device and thus a different overlay identifier. Each instance
+ * has its own property space and is unique. This function gives the chance
+ * for the plugin to create and provide any private data that it will
+ * require.
+ *
+ * In addition, the plugin is given the type of destination that is
+ * required and it is its job to determine whether or not it supports it.
+ *
+ * varpd_plugin_destroy_f
+ *
+ * This is the opposite of varpd_plugin_create_f. It is called to allow the
+ * plugin to reclaim any resources with the private argument that it passed
+ * out as part of the destroy function.
+ *
+ * varpd_plugin_start_f
+ *
+ * This routine is called to indicate that an instance should be started.
+ * This is a plugin's chance to verify that it has all of its required
+ * properties set and to take care of any action that needs to be handled
+ * to begin the plugin. After this point it will be legal to have the
+ * varpd_plugin_default_f, varpd_plugin_lookup_f, varpd_plugin_arp_f and
+ * varpd_plugin_dhcp_f endpoints called.
+ *
+ * varpd_plugin_stop_f
+ *
+ * This routine is called to indicate that an instance is stopping, it is
+ * the opposite of varpd_plugin_start_f. This is a chance to clean up
+ * resources that are a side effect of having started the instance.
+ *
+ * varpd_plugin_default_f
+ *
+ * This routine is defined by plugins of type OVERLAY_TARGET_POINT. It is
+ * used to answer the question of where should all traffic for this
+ * instance be destined. Plugins of type OVERLAY_TARGET_DYNAMIC should
+ * leave this entry set to NULL.
+ *
+ * On success, the default routine should return VARPD_LOOKUP_OK. On
+ * failure, it should return the macro VARPD_LOOKUP_DROP.
+ *
+ * varpd_plugin_lookup_f
+ *
+ * This routine must be defined by plugins of type OVERLAY_TARGET_DYNAMIC.
+ * It is used to lookup the destination for a given request. Each request
+ * comes in with its own MAC address this allows a plugin to direct it to
+ * any remote location.
+ *
+ * This is designed as an asynchronous API. Once a lookup is completed it
+ * should call libvarpd_plugin_query_reply() and pass as the second
+ * argument either VARPD_LOOKUP_OK to indicate that it went alright or it
+ * should reply VARPD_LOOKUP_DROP to indicate that the packet should be
+ * dropped.
+ *
+ * In addition, there are several utility routines that can take care of
+ * various kinds of traffic automatically. For example, if an ARP, NDP, or
+ * DHCP packet comes in, there are utilities such as
+ * libvarpd_plugin_proxy_arp(), libvarpd_plugin_proxy_ndp() and
+ * libvarpd_plugin_proxy_dhcp(), which allows the system to do the heavy
+ * lifting of validating the packet once it finds that it matches certain
+ * properties.
+ *
+ * varpd_plugin_arp_f
+ *
+ * This is an optional entry for plugins of type OVERLAY_TARGET_DYNAMIC.
+ * This is called after a plugin calls libvarpd_plugin_proxy_arp() and is
+ * used to ask the plugin to perform an ARP or NDP query. The type of query
+ * is passed in in the third argument, the only valid value for which will
+ * be VARPD_QTYPE_ETHERNET, to indicate we're doing an Ethernet lookup.
+ *
+ * The layer three IP address that is being looked up will be included in
+ * the struct sockaddr. The sockaddr(3SOCKET)'s sa_family will be set to
+ * indicate the type, eg. AF_INET or AF_INET6 and that will indicate the
+ * kind of sockaddr that will be used. For more information see
+ * sockaddr(3SOCKET). The implementation ensures that enough space for the
+ * link layer address will exist.
+ *
+ * This is an asynchronous lookup. Once the answer has been written, a
+ * plugin should call libvarpd_plugin_arp_reply and if it was successful,
+ * VARPD_LOOKUP_OK should be passed in and if it failed, VARPD_LOOKUP_DROP
+ * should be passed in instead.
+ *
+ * varpd_plugin_dhcp_f
+ *
+ * This is an optional entry for plugins of type OVERLAY_TARGET_DYNAMIC.
+ * This is called after a plugin calls the libvarpd_plugin_proxy_dhcp() and
+ * is used to ask the plugin to determine where is the DHCP server that
+ * this packet should actually be sent to. What is happening here is that
+ * rather than broadcast the initial DHCP request, we instead unicast it to
+ * a specified DHCP server that this operation vector indicates.
+ *
+ * The plugin is given a type, the same as the ARP plugin which indicates
+ * the kind of link layer address, the only valid type is
+ * VARPD_QTYPE_ETHERNET, other types should be rejected. Then, like the arp
+ * entry point, the dhcp entry point should determine the link layer
+ * address of the DHCP server and write that out in the appropriate memory
+ * and call libvarpd_plugin_dhcp_reply() when done. Similar to the arp
+ * entry point, it should use VARPD_LOOKUP_OK to indicate that it was
+ * filled in and VARPD_LOOKUP_DROP to indicate that it was not.
+ *
+ * varpd_plugin_nprops_f
+ *
+ * This is used by a plugin to indicate the number of properties that
+ * should exist for this instance. Recall from the section that Plugin
+ * types and Destinations, that the number of entries here may vary. As
+ * such, the plugin should return the number that is appropriate for the
+ * instance.
+ *
+ * This number will be used to obtain information about a property via the
+ * propinfo functions. However, the getprop and setprop interfaces will
+ * always use names to indicate the property it is getting and setting.
+ * This difference is structured this way to deal with property discovery
+ * and to make the getprop and setprop interfaces slightly easier for other
+ * parts of the broader varpd/dladm infrastructure.
+ *
+ * varpd_plugin_propinfo_f
+ *
+ * This interface is used to get information about a property, the property
+ * that information is being requested for is being passed in via the
+ * second argument. Here, callers should set properties such as the name,
+ * the protection, whether or not the property is required, set any default
+ * value, if it exist, and if relevant, set the valid range of values.
+ *
+ * varpd_plugin_getprop_f
+ *
+ * This is used to get the value of a property, if it is set. The passed in
+ * length indicates the length of the buffer that is used for updating
+ * properties. If it is not of sufficient size, the function should return
+ * an error and not update the buffer. Otherwise, it should update the size
+ * pointer with the valid size.
+ *
+ * varpd_plugin_setprop_f
+ *
+ * This is used to set the value of a property. An endpoint should validate
+ * that the property is valid before updating it. In addition, it should
+ * update its state as appropriate.
+ *
+ * varpd_plugin_save_f
+ *
+ * This is used to serialize the state of a given instance of a plugin such
+ * that if varpd crashes, it can be recovered. The plugin should write all
+ * state into the nvlist that it is passed in, it may use any keys and
+ * values that it wants. The only consumer of that nvlist will be the
+ * plugin itself when the restore endpoint is called.
+ *
+ * varpd_plugin_restore_f
+ *
+ * This is called by the server to restore an instance that used to exist,
+ * but was lost due to a crash. This is a combination of calling create and
+ * setting properties. The plugin should restore any private state that it
+ * can find recorded from the nvlist. The only items in the nvlist will be
+ * those that were written out during a previous call to
+ * varpd_plugin_save_f.
+ *
+ *
+ * Once all of these interfaces are implemented, the plugin should define the
+ * following members in the varpd_plugin_register_t.
+ *
+ * vpr_version
+ *
+ * This indicates the version of the plugin. Plugins should set this to the
+ * macro VARPD_CURRENT_VERSION.
+ *
+ * vpr_mode
+ *
+ * This indicates the mode of the plugin. The plugin's mode should be one
+ * of OVERLAY_TARGET_POINT and OVERLAY_TARGET_DYNAMIC. For more discussion
+ * of these types and the differences, see the section on Plugin Types and
+ * Destinations.
+ *
+ * vpr_name
+ *
+ * This is the name of the plugin. This is how users will refer to it in
+ * the context of running dladm(8) commands. Note, this name must be
+ * unique across the different plugins, as it will cause others with the
+ * same name not to be registered.
+ *
+ * vpr_ops
+ *
+ * This is the operations vector as described above. Importantly, the
+ * member vpo_callbacks must be set to zero, this is being used for future
+ * expansion of the structure.
+ *
+ *
+ * --------------------------------------------------
+ * Downcalls, Upcalls, and Synchronization Guarantees
+ * --------------------------------------------------
+ *
+ * Every instance of a plugin is independent. Calls into a plugin may be made
+ * for different instances in parallel. Any necessary locking is left to the
+ * plugin module. Within an instance, various calls may come in parallel.
+ *
+ * The primary guarantees are that none of the varpd_plugin_save_f,
+ * varpd_plugin_lookup_f, varpd_default_f, varpd_plugin_arp_f, and
+ * varpd_plugin_dhcp_f will be called until after a call to varpd_plugin_start_f
+ * has been called. Similarly, they will not be called after a call to
+ * varpd_plugin_stop_f.
+ *
+ * The functions documented in this header may be called back into from any
+ * context, including from the operation vectors.
+ */
+
+#include <libvarpd.h>
+#include <libnvpair.h>
+#include <sys/socket.h>
+#include <sys/overlay_target.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define VARPD_VERSION_ONE 1
+#define VARPD_CURRENT_VERSION VARPD_VERSION_ONE
+
+typedef struct __varpd_provier_handle varpd_provider_handle_t;
+typedef struct __varpd_query_handle varpd_query_handle_t;
+typedef struct __varpd_arp_handle varpd_arp_handle_t;
+typedef struct __varpd_dhcp_handle varpd_dhcp_handle_t;
+
+typedef int (*varpd_plugin_create_f)(varpd_provider_handle_t *, void **,
+ overlay_plugin_dest_t);
+typedef int (*varpd_plugin_start_f)(void *);
+typedef void (*varpd_plugin_stop_f)(void *);
+typedef void (*varpd_plugin_destroy_f)(void *);
+
+#define VARPD_LOOKUP_OK (0)
+#define VARPD_LOOKUP_DROP (-1)
+typedef int (*varpd_plugin_default_f)(void *, overlay_target_point_t *);
+typedef void (*varpd_plugin_lookup_f)(void *, varpd_query_handle_t *,
+ const overlay_targ_lookup_t *, overlay_target_point_t *);
+
+#define VARPD_QTYPE_ETHERNET 0x0
+typedef void (*varpd_plugin_arp_f)(void *, varpd_arp_handle_t *, int,
+ const struct sockaddr *, uint8_t *);
+typedef void (*varpd_plugin_dhcp_f)(void *, varpd_dhcp_handle_t *, int,
+ const overlay_targ_lookup_t *, uint8_t *);
+
+typedef int (*varpd_plugin_nprops_f)(void *, uint_t *);
+typedef int (*varpd_plugin_propinfo_f)(void *, const uint_t,
+ varpd_prop_handle_t *);
+typedef int (*varpd_plugin_getprop_f)(void *, const char *, void *, uint32_t *);
+typedef int (*varpd_plugin_setprop_f)(void *, const char *, const void *,
+ const uint32_t);
+
+typedef int (*varpd_plugin_save_f)(void *, nvlist_t *);
+typedef int (*varpd_plugin_restore_f)(nvlist_t *, varpd_provider_handle_t *,
+ overlay_plugin_dest_t, void **);
+
+typedef struct varpd_plugin_ops {
+ uint_t vpo_callbacks;
+ varpd_plugin_create_f vpo_create;
+ varpd_plugin_start_f vpo_start;
+ varpd_plugin_stop_f vpo_stop;
+ varpd_plugin_destroy_f vpo_destroy;
+ varpd_plugin_default_f vpo_default;
+ varpd_plugin_lookup_f vpo_lookup;
+ varpd_plugin_nprops_f vpo_nprops;
+ varpd_plugin_propinfo_f vpo_propinfo;
+ varpd_plugin_getprop_f vpo_getprop;
+ varpd_plugin_setprop_f vpo_setprop;
+ varpd_plugin_save_f vpo_save;
+ varpd_plugin_restore_f vpo_restore;
+ varpd_plugin_arp_f vpo_arp;
+ varpd_plugin_dhcp_f vpo_dhcp;
+} varpd_plugin_ops_t;
+
+typedef struct varpd_plugin_register {
+ uint_t vpr_version;
+ uint_t vpr_mode;
+ const char *vpr_name;
+ const varpd_plugin_ops_t *vpr_ops;
+} varpd_plugin_register_t;
+
+extern varpd_plugin_register_t *libvarpd_plugin_alloc(uint_t, int *);
+extern void libvarpd_plugin_free(varpd_plugin_register_t *);
+extern int libvarpd_plugin_register(varpd_plugin_register_t *);
+
+/*
+ * Blowing up and logging
+ */
+extern void libvarpd_panic(const char *, ...) __NORETURN;
+
+/*
+ * Misc. Information APIs
+ */
+extern uint64_t libvarpd_plugin_vnetid(varpd_provider_handle_t *);
+
+/*
+ * Lookup Replying query and proxying
+ */
+extern void libvarpd_plugin_query_reply(varpd_query_handle_t *, int);
+
+extern void libvarpd_plugin_proxy_arp(varpd_provider_handle_t *,
+ varpd_query_handle_t *, const overlay_targ_lookup_t *);
+extern void libvarpd_plugin_proxy_ndp(varpd_provider_handle_t *,
+ varpd_query_handle_t *, const overlay_targ_lookup_t *);
+extern void libvarpd_plugin_arp_reply(varpd_arp_handle_t *, int);
+
+extern void libvarpd_plugin_proxy_dhcp(varpd_provider_handle_t *,
+ varpd_query_handle_t *, const overlay_targ_lookup_t *);
+extern void libvarpd_plugin_dhcp_reply(varpd_dhcp_handle_t *, int);
+
+
+/*
+ * Property information callbacks
+ */
+extern void libvarpd_prop_set_name(varpd_prop_handle_t *, const char *);
+extern void libvarpd_prop_set_prot(varpd_prop_handle_t *, overlay_prop_prot_t);
+extern void libvarpd_prop_set_type(varpd_prop_handle_t *, overlay_prop_type_t);
+extern int libvarpd_prop_set_default(varpd_prop_handle_t *, void *, ssize_t);
+extern void libvarpd_prop_set_nodefault(varpd_prop_handle_t *);
+extern void libvarpd_prop_set_range_uint32(varpd_prop_handle_t *, uint32_t,
+ uint32_t);
+extern void libvarpd_prop_set_range_str(varpd_prop_handle_t *, const char *);
+
+/*
+ * Various injecting and invalidation routines
+ */
+extern void libvarpd_inject_varp(varpd_provider_handle_t *, const uint8_t *,
+ const overlay_target_point_t *);
+extern void libvarpd_inject_arp(varpd_provider_handle_t *, const uint16_t,
+ const uint8_t *, const struct in_addr *, const uint8_t *);
+extern void libvarpd_fma_degrade(varpd_provider_handle_t *, const char *);
+extern void libvarpd_fma_restore(varpd_provider_handle_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBVARPD_PROVIDER_H */
diff --git a/usr/src/lib/varpd/libvarpd/common/libvarpd_util.c b/usr/src/lib/varpd/libvarpd/common/libvarpd_util.c
new file mode 100644
index 0000000000..92e50b5f1b
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/libvarpd_util.c
@@ -0,0 +1,91 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#include <libvarpd_impl.h>
+#include <assert.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+const char *
+libvarpd_isaext(void)
+{
+#if defined(__amd64)
+ return ("64");
+#elif defined(__i386)
+ return ("");
+#else
+#error "unknown ISA"
+#endif
+}
+
+int
+libvarpd_dirwalk(varpd_impl_t *vip, const char *path, const char *suffix,
+ libvarpd_dirwalk_f func, void *arg)
+{
+ int ret;
+ size_t slen;
+ char *dirpath, *filepath;
+ DIR *dirp;
+ struct dirent *dp;
+ assert(vip != NULL && path != NULL);
+
+ if (asprintf(&dirpath, "%s/%s", path, libvarpd_isaext()) == -1)
+ return (errno);
+
+ if ((dirp = opendir(dirpath)) == NULL) {
+ ret = errno;
+ return (ret);
+ }
+
+ slen = strlen(suffix);
+ for (;;) {
+ size_t len;
+
+ errno = 0;
+ dp = readdir(dirp);
+ if (dp == NULL) {
+ ret = errno;
+ break;
+ }
+
+ len = strlen(dp->d_name);
+ if (len <= slen)
+ continue;
+
+ if (strcmp(suffix, dp->d_name + (len - slen)) != 0)
+ continue;
+
+ if (asprintf(&filepath, "%s/%s", dirpath, dp->d_name) == -1) {
+ ret = errno;
+ break;
+ }
+
+ if (func(vip, filepath, arg) != 0) {
+ free(filepath);
+ ret = 0;
+ break;
+ }
+
+ free(filepath);
+ }
+
+ (void) closedir(dirp);
+ free(dirpath);
+ return (ret);
+}
diff --git a/usr/src/lib/varpd/libvarpd/common/mapfile-plugin b/usr/src/lib/varpd/libvarpd/common/mapfile-plugin
new file mode 100644
index 0000000000..8cef7f669f
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/mapfile-plugin
@@ -0,0 +1,57 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_SCOPE {
+ global:
+ libvarpd_fma_degrade { FLAGS = EXTERN };
+ libvarpd_inject_arp { FLAGS = EXTERN };
+ libvarpd_inject_ndp { FLAGS = EXTERN };
+ libvarpd_inject_varp { FLAGS = EXTERN };
+ libvarpd_fma_restore { FLAGS = EXTERN };
+ libvarpd_panic { FLAGS = EXTERN };
+ libvarpd_plugin_alloc { FLAGS = EXTERN };
+ libvarpd_plugin_arp_reply { FLAGS = EXTERN };
+ libvarpd_plugin_dhcp_reply { FLAGS = EXTERN };
+ libvarpd_plugin_free { FLAGS = EXTERN };
+ libvarpd_plugin_proxy_arp { FLAGS = EXTERN };
+ libvarpd_plugin_proxy_dhcp { FLAGS = EXTERN };
+ libvarpd_plugin_proxy_ndp { FLAGS = EXTERN };
+ libvarpd_plugin_query_reply { FLAGS = EXTERN };
+ libvarpd_plugin_register { FLAGS = EXTERN };
+ libvarpd_plugin_vnetid { FLAGS = EXTERN };
+ libvarpd_prop_set_name { FLAGS = EXTERN };
+ libvarpd_prop_set_prot { FLAGS = EXTERN };
+ libvarpd_prop_set_type { FLAGS = EXTERN };
+ libvarpd_prop_set_default { FLAGS = EXTERN };
+ libvarpd_prop_set_nodefault { FLAGS = EXTERN };
+ libvarpd_prop_set_range_uint32 { FLAGS = EXTERN };
+ libvarpd_prop_set_rangestr { FLAGS = EXTERN };
+};
diff --git a/usr/src/lib/varpd/libvarpd/common/mapfile-vers b/usr/src/lib/varpd/libvarpd/common/mapfile-vers
new file mode 100644
index 0000000000..7aa930cb54
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/common/mapfile-vers
@@ -0,0 +1,113 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate {
+ global:
+ libvarpd_c_create;
+ libvarpd_c_destroy;
+ libvarpd_c_instance_activate;
+ libvarpd_c_instance_create;
+ libvarpd_c_instance_destroy;
+ libvarpd_c_prop_nprops;
+ libvarpd_c_prop_handle_alloc;
+ libvarpd_c_prop_handle_free;
+ libvarpd_c_prop_info_fill;
+ libvarpd_c_prop_info_fill_by_name;
+ libvarpd_c_prop_info;
+ libvarpd_c_prop_get;
+ libvarpd_c_prop_set;
+
+ libvarpd_c_instance_lookup;
+ libvarpd_c_instance_target_mode;
+ libvarpd_c_instance_cache_flush;
+ libvarpd_c_instance_cache_delete;
+ libvarpd_c_instance_cache_get;
+ libvarpd_c_instance_cache_set;
+ libvarpd_c_instance_cache_walk;
+
+ libvarpd_create;
+ libvarpd_destroy;
+
+ libvarpd_door_server_create;
+ libvarpd_door_server_destroy;
+
+ libvarpd_fma_degrade;
+ libvarpd_fma_restore;
+
+ libvarpd_inject_varp;
+ libvarpd_inject_arp;
+
+ libvarpd_instance_activate;
+ libvarpd_instance_create;
+ libvarpd_instance_destroy;
+ libvarpd_instance_lookup;
+ libvarpd_instance_id;
+
+ libvarpd_panic;
+
+ libvarpd_persist_disable;
+ libvarpd_persist_enable;
+ libvarpd_persist_restore;
+
+ libvarpd_plugin_alloc;
+ libvarpd_plugin_load;
+ libvarpd_plugin_free;
+ libvarpd_plugin_arp_reply;
+ libvarpd_plugin_dhcp_reply;
+ libvarpd_plugin_query_reply;
+ libvarpd_plugin_proxy_arp;
+ libvarpd_plugin_proxy_dhcp;
+ libvarpd_plugin_proxy_ndp;
+ libvarpd_plugin_register;
+ libvarpd_plugin_walk;
+ libvarpd_plugin_vnetid;
+
+ libvarpd_prop_set_default;
+ libvarpd_prop_set_nodefault;
+ libvarpd_prop_set_name;
+ libvarpd_prop_set_prot;
+ libvarpd_prop_set_range_uint32;
+ libvarpd_prop_set_range_str;
+ libvarpd_prop_set_type;
+
+ libvarpd_prop_handle_alloc;
+ libvarpd_prop_handle_free;
+ libvarpd_prop_nprops;
+ libvarpd_prop_info_fill;
+ libvarpd_prop_info;
+ libvarpd_prop_get;
+ libvarpd_prop_set;
+
+ libvarpd_overlay_lookup_quiesce;
+ libvarpd_overlay_lookup_run;
+ local:
+ *;
+};
diff --git a/usr/src/lib/varpd/libvarpd/i386/Makefile b/usr/src/lib/varpd/libvarpd/i386/Makefile
new file mode 100644
index 0000000000..4398507523
--- /dev/null
+++ b/usr/src/lib/varpd/libvarpd/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/man/man1/ar.1 b/usr/src/man/man1/ar.1
index 35695f2385..5ccea66de9 100644
--- a/usr/src/man/man1/ar.1
+++ b/usr/src/man/man1/ar.1
@@ -43,8 +43,9 @@
.\" Copyright 1989 AT&T
.\" Portions Copyright (c) 1992, X/Open Company Limited All Rights Reserved
.\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright 2022 Oxide Computer Company
.\"
-.TH AR 1 "September 20, 2021"
+.TH AR 1 "January 23, 2022"
.SH NAME
ar \- maintain portable archive or library
.SH SYNOPSIS
@@ -64,7 +65,7 @@ ar \- maintain portable archive or library
.LP
.nf
-\fB/usr/bin/ar\fR \fB-q\fR [\fB-cVv\fR] \fIarchive\fR \fIfile\fR...
+\fB/usr/bin/ar\fR \fB-q\fR [\fB-csVv\fR] \fIarchive\fR \fIfile\fR...
.fi
.LP
diff --git a/usr/src/man/man1/ld.1 b/usr/src/man/man1/ld.1
index 1f8bd07d77..1bb133c6ce 100644
--- a/usr/src/man/man1/ld.1
+++ b/usr/src/man/man1/ld.1
@@ -5,7 +5,7 @@
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.
.\" See the License for the specific language governing permissions and limitations under the License. When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with
.\" the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH LD 1 "May 13, 2017"
+.TH LD 1 "Jan 28, 2022"
.SH NAME
ld \- link-editor for object files
.SH SYNOPSIS
@@ -452,7 +452,7 @@ See Chapter 4, \fIShared Objects,\fR in \fILinker and Libraries Guide\fR.
.ad
.br
.na
-\fB\fB--soname\fR \fIname\fR\fR
+\fB\fB-soname\fR \fIname\fR\fR
.ad
.sp .6
.RS 4n
diff --git a/usr/src/man/man2/chmod.2 b/usr/src/man/man2/chmod.2
index 6a764cad98..9bed574a08 100644
--- a/usr/src/man/man2/chmod.2
+++ b/usr/src/man/man2/chmod.2
@@ -45,11 +45,10 @@
.\" Copyright (c) 2005, Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright (c) 2014, Joyent, Inc.
.\"
-.TH CHMOD 2 "Dec 22, 2014"
+.TH CHMOD 2 "Jan 26, 2022"
.SH NAME
chmod, fchmod, fchmodat \- change access permission mode of file
.SH SYNOPSIS
-.LP
.nf
#include <sys/types.h>
#include <sys/stat.h>
@@ -68,7 +67,6 @@ chmod, fchmod, fchmodat \- change access permission mode of file
.fi
.SH DESCRIPTION
-.LP
The \fBchmod()\fR, \fBfchmod()\fR, and \fBfchmodat()\fR functions set the access
permission portion of the mode of the file whose name is given by \fIpath\fR or
referenced by the open file descriptor \fIfildes\fR to the bit pattern contained
@@ -196,12 +194,10 @@ will result in an error.
Upon successful completion, \fBchmod()\fR, \fBfchmod()\fR, \fBfchmodat()\fR mark
for update the \fBst_ctime\fR field of the file.
.SH RETURN VALUES
-.LP
Upon successful completion, \fB0\fR is returned. Otherwise, \fB\(mi1\fR is
returned, the file mode is unchanged, and \fBerrno\fR is set to indicate the
error.
.SH ERRORS
-.LP
The \fBchmod()\fR, \fBfchmod()\fR, and \fBfchmodat()\fR functions will fail if:
.sp
.ne 2
@@ -404,7 +400,8 @@ descriptor which does not refer to a file.
.B EOPNOTSUPP
.ad
.RS 16n
-The \fBAT_SYMLINK_NOFOLLOW\fR bit is set in the \fIflags\fR argument.
+The \fBAT_SYMLINK_NOFOLLOW\fR bit is set in the \fIflags\fR argument and
+\fIpath\fR refers to a symbolic link.
.RE
.sp
@@ -445,7 +442,6 @@ of this function on a pipe.
.RE
.SH EXAMPLES
-.LP
\fBExample 1 \fRSet Read Permissions for User, Group, and Others
.sp
.LP
@@ -517,7 +513,6 @@ status = stat("home/cnd/mod1", &buffer;);
.in -2
.SH USAGE
-.LP
If \fBchmod()\fR or \fBfchmod()\fR is used to change the file group owner
permissions on a file with non-trivial ACL entries, only the ACL mask is set to
the new permissions and the group owner permission bits in the file's mode
@@ -526,7 +521,6 @@ one whose meaning cannot be represented in the file's mode field alone. The new
ACL mask permissions might change the effective permissions for additional
users and groups that have ACL entries on the file.
.SH ATTRIBUTES
-.LP
See \fBattributes\fR(7) for descriptions of the following attributes:
.sp
diff --git a/usr/src/man/man2/close.2 b/usr/src/man/man2/close.2
index 86b3c45a43..1305270f45 100644
--- a/usr/src/man/man2/close.2
+++ b/usr/src/man/man2/close.2
@@ -43,173 +43,193 @@
.\" Copyright 1989 AT&T
.\" Portions Copyright (c) 1992, X/Open Company Limited. All Rights Reserved.
.\" Copyright (c) 2005, Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright 2022 Oxide Computer Company
.\"
-.TH CLOSE 2 "Oct 18, 2005"
-.SH NAME
-close \- close a file descriptor
-.SH SYNOPSIS
-.LP
-.nf
-#include <unistd.h>
-
-\fBint\fR \fBclose\fR(\fBint\fR \fIfildes\fR);
-.fi
-
-.SH DESCRIPTION
-.sp
-.LP
-The \fBclose()\fR function deallocates the file descriptor indicated by
-\fIfildes\fR. To deallocate means to make the file descriptor available for
-return by subsequent calls to \fBopen\fR(2) or other functions that allocate
-file descriptors. All outstanding record locks owned by the process on the file
-associated with the file descriptor will be removed (that is, unlocked).
-.sp
-.LP
-If \fBclose()\fR is interrupted by a signal that is to be caught, it will
-return \fB\(mi1\fR with \fBerrno\fR set to \fBEINTR\fR and the state of
-\fIfildes\fR is unspecified. If an I/O error occurred while reading from or
-writing to the file system during \fBclose()\fR, it returns -1, sets
-\fBerrno\fR to \fBEIO\fR, and the state of \fIfildes\fR is unspecified.
-.sp
-.LP
-When all file descriptors associated with a pipe or \fBFIFO\fR special file are
-closed, any data remaining in the pipe or \fBFIFO\fR will be discarded.
-.sp
-.LP
+.Dd February 5, 2022
+.Dt CLOSE 2
+.Os
+.Sh NAME
+.Nm close
+.Nd close a file descriptor
+.Sh SYNOPSIS
+.In unistd.h
+.Ft int
+.Fo close
+.Fa "int fildes"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn close
+function deallocates the file descriptor indicated by
+.Fa fildes .
+To deallocate means to make the file descriptor available for return by
+subsequent calls to
+.Xr open 2
+or other functions that allocate file descriptors.
+All outstanding record locks owned by the process on the file associated with
+the file descriptor will be removed
+.Pq "that is, unlocked" .
+.Pp
+If
+.Fn close
+is interrupted by a signal that is to be caught, it will return
+.Sy -1
+with
+.Va errno
+set to
+.Er EINTR
+and the state of
+.Fa fildes
+is unspecified.
+If an I/O error occurred while reading from or writing to the file system during
+.Fn close ,
+it returns
+.Sy -1 ,
+sets
+.Va errno
+to
+.Er EIO ,
+and the state of
+.Fa fildes
+is unspecified.
+.Pp
+When all file descriptors associated with a pipe or FIFO special file are
+closed, any data remaining in the pipe or FIFO will be discarded.
+.Pp
When all file descriptors associated with an open file description have been
closed the open file description will be freed.
-.sp
-.LP
-If the link count of the file is 0, when all file descriptors associated with
-the file are closed, the space occupied by the file will be freed and the file
-will no longer be accessible.
-.sp
-.LP
-If a streams-based (see \fBIntro\fR(2)) \fIfildes\fR is closed and the calling
-process was previously registered to receive a \fBSIGPOLL\fR signal (see
-\fBsignal\fR(3C)) for events associated with that stream (see \fBI_SETSIG\fR in
-\fBstreamio\fR(4I)), the calling process will be unregistered for events
-associated with the stream. The last \fBclose()\fR for a stream causes the
-stream associated with \fIfildes\fR to be dismantled. If \fBO_NONBLOCK\fR and
-\fBO_NDELAY\fR are not set and there have been no signals posted for the
-stream, and if there is data on the module's write queue, \fBclose()\fR waits
-up to 15 seconds (for each module and driver) for any output to drain before
-dismantling the stream. The time delay can be changed via an \fBI_SETCLTIME\fR
-\fBioctl\fR(2) request (see \fBstreamio\fR(4I)). If the \fBO_NONBLOCK\fR or
-\fBO_NDELAY\fR flag is set, or if there are any pending signals, \fBclose()\fR
+.Pp
+If the link count of the file is
+.Sy 0 ,
+when all file descriptors associated with the file are closed, the space
+occupied by the file will be freed and the file will no longer be accessible.
+.Pp
+If a streams-based
+.Po
+see
+.Xr Intro 2
+.Pc
+.Fa fildes
+is closed and the calling process was previously registered to receive a
+.Dv SIGPOLL
+signal
+.Po
+see
+.Xr signal 3C
+.Pc
+for events associated with that stream
+.Po
+see
+.Dv I_SETSIG
+in
+.Xr streamio 4I
+.Pc ,
+the calling process will be unregistered for events associated with the stream.
+The last
+.Fn close
+for a stream causes the stream associated with
+.Fa fildes
+to be dismantled.
+If
+.Dv O_NONBLOCK
+and
+.Dv O_NDELAY
+are not set and there have been no signals posted for the stream, and if there
+is data on the module's write queue,
+.Fn close
+waits up to 15 seconds
+.Pq for each module and driver
+for any output to drain
+before dismantling the stream.
+The time delay can be changed via an
+.Dv I_SETCLTIME
+.Xr ioctl 2
+request
+.Po
+see
+.Xr streamio 4I
+.Pc .
+If the
+.Dv O_NONBLOCK
+or
+.Dv O_NDELAY
+flag is set, or if there are any pending signals,
+.Fn close
does not wait for output to drain, and dismantles the stream immediately.
-.sp
-.LP
-If \fIfildes\fR is associated with one end of a pipe, the last \fBclose()\fR
-causes a hangup to occur on the other end of the pipe. In addition, if the
-other end of the pipe has been named by \fBfattach\fR(3C), then the last
-\fBclose()\fR forces the named end to be detached by \fBfdetach\fR(3C). If the
-named end has no open file descriptors associated with it and gets detached,
-the stream associated with that end is also dismantled.
-.sp
-.LP
-If \fIfildes\fR refers to the master side of a pseudo-terminal, a \fBSIGHUP\fR
-signal is sent to the session leader, if any, for which the slave side of the
-pseudo-terminal is the controlling terminal. It is unspecified whether closing
-the master side of the pseudo-terminal flushes all queued input and output.
-.sp
-.LP
-If \fIfildes\fR refers to the slave side of a streams-based pseudo-terminal, a
-zero-length message may be sent to the master.
-.sp
-.LP
+.Pp
+If
+.Fa fildes
+is associated with one end of a pipe, the last
+.Fn close
+causes a hangup to occur on the other end of the pipe.
+In addition, if the other end of the pipe has been named by
+.Xr fattach 3C ,
+then the last
+.Fn close
+forces the named end to be detached by
+.Xr fdetach 3C .
+If the named end has no open file descriptors associated with it and gets
+detached, the stream associated with that end is also dismantled.
+.Pp
+If
+.Fa fildes
+refers to the manager side of a pseudo-terminal, a
+.Dv SIGHUP
+signal is sent to the session leader, if any, for which the subsidiary side of
+the pseudo-terminal is the controlling terminal.
+It is unspecified whether closing the manager side of the pseudo-terminal
+flushes all queued input and output.
+.Pp
+If
+.Fa fildes
+refers to the subsidiary side of a streams-based pseudo-terminal, a zero-length
+message may be sent to the manager.
+.Pp
When there is an outstanding cancelable asynchronous I/O operation against
-\fIfildes\fR when \fBclose()\fR is called, that I/O operation is canceled. An
-I/O operation that is not canceled completes as if the \fBclose()\fR operation
-had not yet occurred. All operations that are not canceled will complete as if
-the \fBclose()\fR blocked until the operations completed.
-.sp
-.LP
+.Fa fildes
+when
+.Fn close
+is called, that I/O operation is canceled.
+An I/O operation that is not canceled completes as if the
+.Fn close
+operation had not yet occurred.
+All operations that are not canceled will complete as if the
+.Fn close
+blocked until the operations completed.
+.Pp
If a shared memory object or a memory mapped file remains referenced at the
-last close (that is, a process has it mapped), then the entire contents of the
-memory object will persist until the memory object becomes unreferenced. If
-this is the last close of a shared memory object or a memory mapped file and
+last close
+.Pq "that is, a process has it mapped" ,
+then the entire contents of the memory object will persist until the memory
+object becomes unreferenced.
+If this is the last close of a shared memory object or a memory mapped file and
the close results in the memory object becoming unreferenced, and the memory
object has been unlinked, then the memory object will be removed.
-.sp
-.LP
-If \fIfildes\fR refers to a socket, \fBclose()\fR causes the socket to be
-destroyed. If the socket is connection-mode, and the \fBSO_LINGER\fR option is
-set for the socket with non-zero linger time, and the socket has untransmitted
-data, then \fBclose()\fR will block for up to the current linger interval until
-all data is transmitted.
-.SH RETURN VALUES
-.sp
-.LP
-Upon successful completion, \fB0\fR is returned. Otherwise, \fB\(mi1\fR is
-returned and \fBerrno\fR is set to indicate the error.
-.SH ERRORS
-.sp
-.LP
-The \fBclose()\fR function will fail if:
-.sp
-.ne 2
-.na
-\fB\fBEBADF\fR\fR
-.ad
-.RS 11n
-The \fIfildes\fR argument is not a valid file descriptor.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEINTR\fR\fR
-.ad
-.RS 11n
-The \fBclose()\fR function was interrupted by a signal.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBENOLINK\fR\fR
-.ad
-.RS 11n
-The \fIfildes\fR argument is on a remote machine and the link to that machine
-is no longer active.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBENOSPC\fR\fR
-.ad
-.RS 11n
-There was no free space remaining on the device containing the file.
-.RE
-
-.sp
-.LP
-The \fBclose()\fR function may fail if:
-.sp
-.ne 2
-.na
-\fB\fBEIO\fR\fR
-.ad
-.RS 7n
-An I/O error occurred while reading from or writing to the file system.
-.RE
-
-.SH EXAMPLES
-.LP
-\fBExample 1 \fRReassign a file descriptor.
-.sp
-.LP
+.Pp
+If
+.Fa fildes
+refers to a socket,
+.Fn close
+causes the socket to be destroyed.
+If the socket is connection-mode, and the
+.Dv SO_LINGER
+option is set for the socket with non-zero linger time, and the socket has
+untransmitted data, then
+.Fn close
+will block for up to the current linger interval until all data is transmitted.
+.Sh RETURN VALUES
+.Rv -std close
+.Sh EXAMPLES
+.Sy Example 1
+Reassign a file descriptor.
+.Pp
The following example closes the file descriptor associated with standard
output for the current process, re-assigns standard output to a new file
-descriptor, and closes the original file descriptor to clean up. This example
-assumes that the file descriptor 0, which is the descriptor for standard input,
-is not closed.
-
-.sp
-.in +2
-.nf
+descriptor, and closes the original file descriptor to clean up.
+This example assumes that the file descriptor
+.Sy 0 ,
+which is the descriptor for standard input, is not closed.
+.Bd -literal -offset Ds
#include <unistd.h>
\&...
int pfd;
@@ -218,32 +238,22 @@ close(1);
dup(pfd);
close(pfd);
\&...
-.fi
-.in -2
-
-.sp
-.LP
+.Ed
+.Pp
Incidentally, this is exactly what could be achieved using:
-
-.sp
-.in +2
-.nf
+.Bd -literal -offset Ds
dup2(pfd, 1);
close(pfd);
-.fi
-.in -2
-
-.LP
-\fBExample 2 \fRClose a file descriptor.
-.sp
-.LP
-In the following example, \fBclose()\fR is used to close a file descriptor
-after an unsuccessful attempt is made to associate that file descriptor with a
-stream.
-
-.sp
-.in +2
-.nf
+.Ed
+.Pp
+.Sy Example 2
+Close a file descriptor.
+.Pp
+In the following example,
+.Fn close
+is used to close a file descriptor after an unsuccessful attempt is made to
+associate that file descriptor with a stream.
+.Bd -literal -offset Ds
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
@@ -259,44 +269,64 @@ if ((fpfd = fdopen (pfd, "w")) == NULL) {
exit(1);
}
\&...
-.fi
-.in -2
-
-.SH USAGE
-.sp
-.LP
-An application that used the \fBstdio\fR function \fBfopen\fR(3C) to open a
-file should use the corresponding \fBfclose\fR(3C) function rather than
-\fBclose()\fR.
-.SH ATTRIBUTES
-.sp
-.LP
-See \fBattributes\fR(7) for descriptions of the following attributes:
-.sp
-
-.sp
-.TS
-box;
-c | c
-l | l .
-ATTRIBUTE TYPE ATTRIBUTE VALUE
-_
-Interface Stability Standard
-_
-MT-Level Async-Signal-Safe
-.TE
-
-.SH SEE ALSO
-.sp
-.LP
-\fBIntro\fR(2), \fBcreat\fR(2), \fBdup\fR(2), \fBexec\fR(2), \fBfcntl\fR(2),
-\fBioctl\fR(2), \fBopen\fR(2) \fBpipe\fR(2),
-.BR fattach (3C),
-.BR fclose (3C),
-.BR fdetach (3C),
-.BR fopen (3C),
-.BR signal (3C),
-.BR signal.h (3HEAD),
-.BR streamio (4I),
-.BR attributes (7),
-.BR standards (7)
+.Ed
+.Sh ERRORS
+The
+.Fn close
+function will fail if:
+.Bl -tag -width Er
+.It Er EBADF
+The
+.Fa fildes
+argument is not a valid file descriptor.
+.It Er EINTR
+The
+.Fn close
+function was interrupted by a signal.
+.It Er ENOLINK
+The
+.Fa fildes
+argument is on a remote machine and the link to that machine is no longer
+active.
+.It Er ENOSPC
+There was no free space remaining on the device containing the file.
+.El
+.Pp
+The
+.Fn close
+function may fail if:
+.Bl -tag -width Er
+.It Er EIO
+An I/O error occurred while reading from or writing to the file system.
+.El
+.Sh USAGE
+An application that used the
+.Xr stdio 3C
+function
+.Xr fopen 3C
+to open a file should use the corresponding
+.Xr fclose 3C
+function rather than
+.Fn close .
+.Sh INTERFACE STABILITY
+.Sy Committed
+.Sh MT-LEVEL
+.Sy Async-Signal-Safe
+.Sh SEE ALSO
+.Xr creat 2 ,
+.Xr dup 2 ,
+.Xr exec 2 ,
+.Xr fcntl 2 ,
+.Xr Intro 2 ,
+.Xr ioctl 2 ,
+.Xr open 2 ,
+.Xr pipe 2 ,
+.Xr fattach 3C ,
+.Xr fclose 3C ,
+.Xr fdetach 3C ,
+.Xr fopen 3C ,
+.Xr signal 3C ,
+.Xr signal.h 3HEAD ,
+.Xr streamio 4I ,
+.Xr attributes 7 ,
+.Xr standards 7
diff --git a/usr/src/man/man2/open.2 b/usr/src/man/man2/open.2
index dd76bda477..3096f4cc9e 100644
--- a/usr/src/man/man2/open.2
+++ b/usr/src/man/man2/open.2
@@ -47,879 +47,586 @@
.\" All Rights Reserved.
.\" Copyright 2015 Nexenta Systems, Inc. All rights reserved.
.\" Copyright 2020 Joyent, Inc.
+.\" Copyright 2022 Oxide Computer Company
.\"
-.TH OPEN 2 "Mar 10, 2020"
-.SH NAME
-open, openat \- open a file
-.SH SYNOPSIS
-.nf
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-\fBint\fR \fBopen\fR(\fBconst char *\fR\fIpath\fR, \fBint\fR \fIoflag\fR, \fB/* mode_t\fR \fImode\fR */);
-.fi
-
-.LP
-.nf
-\fBint\fR \fBopenat\fR(\fBint\fR \fIfildes\fR, \fBconst char *\fR\fIpath\fR, \fBint\fR \fIoflag\fR,
- \fB/* mode_t\fR \fImode\fR */);
-.fi
-
-.SH DESCRIPTION
-The \fBopen()\fR function establishes the connection between a file and a file
-descriptor. It creates an open file description that refers to a file and a
-file descriptor that refers to that open file description. The file descriptor
-is used by other I/O functions to refer to that file. The \fIpath\fR argument
-points to a pathname naming the file.
-.sp
-.LP
-The \fBopenat()\fR function is identical to the \fBopen()\fR function except
-that the \fIpath\fR argument is interpreted relative to the starting point
-implied by the \fIfildes\fR argument. If the \fIfildes\fR argument has the
-special value \fBAT_FDCWD\fR, a relative path argument will be resolved
-relative to the current working directory. If the \fIpath\fR argument is
-absolute, the \fIfildes\fR argument is ignored.
-.sp
-.LP
-The \fBopen()\fR function returns a file descriptor for the named file that is
-the lowest file descriptor not currently open for that process. The open file
-description is new, and therefore the file descriptor does not share it with
-any other process in the system. The \fBFD_CLOEXEC\fR file descriptor flag
-associated with the new file descriptor is cleared.
-.sp
-.LP
+.Dd February 5, 2022
+.Dt OPEN 2
+.Os
+.Sh NAME
+.Nm open ,
+.Nm openat
+.Nd open a file
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/stat.h
+.In fcntl.h
+.Ft int
+.Fo open
+.Fa "const char *path"
+.Fa "int oflag"
+.Op , Fa "mode_t mode"
+.Fc
+.Ft int
+.Fo openat
+.Fa "int fildes"
+.Fa "const char *path"
+.Fa "int oflag"
+.Op , Fa "mode_t mode"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn open
+function establishes the connection between a file and a file descriptor.
+It creates an open file description that refers to a file and a file descriptor
+that refers to that open file description.
+The file descriptor is used by other I/O functions to refer to that file.
+The
+.Fa path
+argument points to a pathname naming the file.
+.Pp
+The
+.Fn openat
+function is identical to the
+.Fn open
+function except
+that the
+.Fa path
+argument is interpreted relative to the starting point
+implied by the
+.Fa fildes
+argument.
+If the
+.Fa fildes
+argument has the special value
+.Dv AT_FDCWD ,
+a relative path argument will be resolved relative to the current working
+directory.
+If the
+.Fa path
+argument is absolute, the
+.Fa fildes
+argument is ignored.
+.Pp
+The
+.Fn open
+function returns a file descriptor for the named file that is the lowest file
+descriptor not currently open for that process.
+The open file description is new, and therefore the file descriptor does not
+share it with any other process in the system.
+The
+.Dv FD_CLOEXEC
+file descriptor flag associated with the new file descriptor is cleared.
+.Pp
The file offset used to mark the current position within the file is set to the
beginning of the file.
-.sp
-.LP
+.Pp
The file status flags and file access modes of the open file description are
-set according to the value of \fIoflag\fR. The \fImode\fR argument is used only
-when \fBO_CREAT\fR is specified (see below.)
-.sp
-.LP
-Values for \fIoflag\fR are constructed by a bitwise-inclusive-OR of flags from
-the following list, defined in <\fBfcntl.h\fR>. Applications must specify
-exactly one of the first three values (file access modes) below in the value of
-\fIoflag\fR:
-.sp
-.ne 2
-.na
-\fB\fBO_RDONLY\fR\fR
-.ad
-.RS 12n
+set according to the value of
+.Fa oflag .
+The
+.Fa mode
+argument is used only
+when
+.Dv O_CREAT
+is specified
+.Pq "see below" .
+.Pp
+Values for
+.Fa oflag
+are constructed by a bitwise-inclusive-OR of flags from
+the following list, defined in
+.Xr fcntl.h 3HEAD .
+Applications must specify exactly one of the first three values (file access
+modes) below in the value of
+.Fa oflag :
+.Bl -tag -width Ds
+.It Dv O_RDONLY
Open for reading only.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBO_WRONLY\fR\fR
-.ad
-.RS 12n
+.It Dv O_WRONLY
Open for writing only.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBO_RDWR\fR\fR
-.ad
-.RS 12n
-Open for reading and writing. The result is undefined if this flag is applied
-to a FIFO.
-.RE
-
-.sp
-.LP
+.It Dv O_RDWR
+Open for reading and writing.
+The result is undefined if this flag is applied to a FIFO.
+.El
+.Pp
Any combination of the following may be used:
-.sp
-.ne 2
-.na
-\fB\fBO_APPEND\fR\fR
-.ad
-.sp .6
-.RS 4n
+.Bl -tag -width Ds
+.It Dv O_APPEND
If set, the file offset is set to the end of the file prior to each write.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBO_CREAT\fR\fR
-.ad
-.sp .6
-.RS 4n
-Create the file if it does not exist. This flag requires that the \fImode\fR
+.It Dv O_CREAT
+Create the file if it does not exist.
+This flag requires that the
+.Fa mode
argument be specified.
-.sp
-If the file exists, this flag has no effect except as noted under \fBO_EXCL\fR
-below. Otherwise, the file is created with the user \fBID\fR of the file set
-to the effective user \fBID\fR of the process. The group \fBID\fR of the file
-is set to the effective group \fBIDs\fR of the process, or if the \fBS_ISGID\fR
+.Pp
+If the file exists, this flag has no effect except as noted under
+.Dv O_EXCL
+below.
+Otherwise, the file is created with the user ID of the file set to the
+effective user ID of the process.
+The group ID of the file is set to the effective group IDs of the process, or
+if the
+.Dv S_ISGID
bit is set in the directory in which the file is being created, the file's
-group \fBID\fR is set to the group \fBID\fR of its parent directory. If the
-group \fBID\fR of the new file does not match the effective group \fBID\fR or
-one of the supplementary groups IDs, the \fBS_ISGID\fR bit is cleared. The
-access permission bits (see \fB<sys/stat.h>\fR) of the file mode are set to the
-value of \fImode\fR, modified as follows (see \fBcreat\fR(2)): a bitwise-AND is
-performed on the file-mode bits and the corresponding bits in the complement of
-the process's file mode creation mask. Thus, all bits set in the process's file
-mode creation mask (see \fBumask\fR(2)) are correspondingly cleared in the
-file's permission mask. The "save text image after execution bit" of the mode
-is cleared (see \fBchmod\fR(2)). When bits other than the file permission bits
-are set, the effect is unspecified. The \fImode\fR argument does not affect
-whether the file is open for reading, writing or for both.
-.RE
-
-.sp
-.ne 2
-.na
-.B O_DIRECT
-.ad
-.sp .6
-.RS 4n
+group ID is set to the group ID of its parent directory.
+If the group ID of the new file does not match the effective group
+ID or one of the supplementary groups IDs, the
+.Dv S_ISGID bit is cleared.
+.Pp
+The access permission bits
+.Po
+see
+.Xr stat.h 3HEAD
+.Pc
+of the file mode are set to the value of
+.Fa mode ,
+modified as follows
+.Po
+see
+.Xr creat 2
+.Pc :
+a bitwise-AND is performed on the file-mode bits and the corresponding bits in
+the complement of the process's file mode creation mask.
+Thus, all bits set in the process's file mode creation mask
+.Po
+see
+.Xr umask 2
+.Pc
+are correspondingly cleared in the file's permission mask.
+The
+.Dq save text image after execution bit
+of the mode is cleared
+.Po
+see
+.Xr chmod 2
+.Pc .
+When bits other than the file permission bits are set, the effect is
+unspecified.
+The
+.Fa mode
+argument does not affect whether the file is open for reading, writing or for
+both.
+.It Dv O_DIRECT
Indicates that the file data is not going to be reused in the near future.
When possible, data is read or written directly between the application's
-memory and the device when the data is accessed with \fBread\fR(2) and
-\fBwrite\fR(2) operations. See \fBdirectio\fR(3C) for more details.
-.RE
-
-.sp
-.ne 2
-.na
-.B O_DIRECTORY
-.ad
-.sp .6
-.RS 4n
+memory and the device when the data is accessed with
+.Xr read 2
+and
+.Xr write 2
+operations.
+See
+.Xr directio 3C
+for more details.
+.It Dv O_DIRECTORY
Indicates that attempts to open
-.I path
+.Fa path
should fail unless
-.I path
+.Fa path
is a directory.
If both
-.B O_CREAT
+.Dv O_CREAT
and
-.B O_DIRECTORY
+.Dv O_DIRECTORY
are specified then the call will fail if it would result in a file being
created.
If a directory already exists at
-.I path
+.Fa path
then it will behave as if the
-.B O_DIRECTORY
+.Dv O_DIRECTORY
flag had not been present.
If the
-.B O_EXCL
+.Dv O_EXCL
and
-.B O_CREAT
-flags are specified, then the call will always fail as they imply a file
-should always be created.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBO_DSYNC\fR\fR
-.ad
-.sp .6
-.RS 4n
+.Dv O_CREAT
+flags are specified, then the call will always fail as they imply a file should
+always be created.
+.It Dv O_DSYNC
Write I/O operations on the file descriptor complete as defined by synchronized
I/O data integrity completion.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBO_EXCL\fR\fR
-.ad
-.sp .6
-.RS 4n
-If \fBO_CREAT\fR and \fBO_EXCL\fR are set, \fBopen()\fR fails if the file
-exists. The check for the existence of the file and the creation of the file if
+.It Dv O_EXCL
+If
+.Dv O_CREAT
+and
+.Dv O_EXCL
+are set,
+.Fn open
+fails if the file exists.
+The check for the existence of the file and the creation of the file if
it does not exist is atomic with respect to other threads executing
-\fBopen()\fR naming the same filename in the same directory with \fBO_EXCL\fR
-and \fBO_CREAT\fR set. If \fBO_EXCL\fR and \fBO_CREAT\fR are set, and path
-names a symbolic link, \fBopen()\fR fails and sets \fBerrno\fR to \fBEEXIST\fR,
-regardless of the contents of the symbolic link. If \fBO_EXCL\fR is set and
-\fBO_CREAT\fR is not set, the result is undefined.
-.RE
-
-.sp
-.ne 2
-.na
-.B O_EXEC
-.na
-.ad
-.sp .6
-.RS 4n
+.Fn open
+naming the same filename in the same directory with
+.Dv O_EXCL
+and
+.Dv O_CREAT
+set.
+If
+.Dv O_EXCL
+and
+.Dv O_CREAT
+are set, and
+.Fa path
+names a symbolic link,
+.Fn open
+fails and sets
+.Va errno
+to
+.Er EEXIST ,
+regardless of the contents of the symbolic link.
+If
+.Dv O_EXCL
+is set and
+.Dv O_CREAT
+is not set, the result is undefined.
+.It Dv O_EXEC
If set, indicates that the file should be opened for execute permission.
-This option is only valid for regular files, an error will be returned
-if it is not.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBO_LARGEFILE\fR\fR
-.ad
-.sp .6
-.RS 4n
+This option is only valid for regular files; an error will be returned if the
+target is not a regular file.
+.It Dv O_LARGEFILE
If set, the offset maximum in the open file description is the largest value
-that can be represented correctly in an object of type \fBoff64_t\fR.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBO_NOCTTY\fR\fR
-.ad
-.sp .6
-.RS 4n
-If set and \fIpath\fR identifies a terminal device, \fBopen()\fR does not cause
-the terminal device to become the controlling terminal for the process.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBO_NOFOLLOW\fR\fR
-.ad
-.sp .6
-.RS 4n
-If the path names a symbolic link, \fBopen()\fR fails and sets \fBerrno\fR to
-\fBELOOP\fR.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBO_NOLINKS\fR\fR
-.ad
-.sp .6
-.RS 4n
-If the link count of the named file is greater than 1, \fBopen()\fR fails and
-sets \fBerrno\fR to \fBEMLINK\fR.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBO_CLOEXEC\fR\fR
-.ad
-.sp .6
-.RS 4n
+that can be represented correctly in an object of type
+.Vt off64_t .
+.It Dv O_NOCTTY
+If set and
+.Fa path
+identifies a terminal device,
+.Fn open
+does not cause the terminal device to become the controlling terminal for the
+process.
+.It Dv O_NOFOLLOW
+If the path names a symbolic link,
+.Fn open
+fails and sets
+.Va errno
+to
+.Er ELOOP .
+.It Dv O_NOLINKS
+If the link count of the named file is greater than
+.Sy 1 ,
+.Fn open
+fails and sets
+.Va errno
+to
+.Er EMLINK .
+.It Dv O_CLOEXEC
If set, the file descriptor returned will be closed prior to any future
-\fBexec()\fR calls.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBO_NONBLOCK\fR or \fBO_NDELAY\fR\fR
-.ad
-.sp .6
-.RS 4n
-These flags can affect subsequent reads and writes (see \fBread\fR(2) and
-\fBwrite\fR(2)). If both \fBO_NDELAY\fR and \fBO_NONBLOCK\fR are set,
-\fBO_NONBLOCK\fR takes precedence.
-.sp
-When opening a \fBFIFO\fR with \fBO_RDONLY\fR or \fBO_WRONLY\fR set:
-.RS +4
-.TP
-.ie t \(bu
-.el o
-If \fBO_NONBLOCK\fR or \fBO_NDELAY\fR is set, an \fBopen()\fR for reading only
-returns without delay. An \fBopen()\fR for writing only returns an error if no
-process currently has the file open for reading.
-.RE
-.RS +4
-.TP
-.ie t \(bu
-.el o
-If \fBO_NONBLOCK\fR and \fBO_NDELAY\fR are clear, an \fBopen()\fR for reading
-only blocks until a thread opens the file for writing. An \fBopen()\fR for
-writing only blocks the calling thread until a thread opens the file for
+.Xr exec 2
+calls.
+.It Dv O_NONBLOCK O_NDELAY
+These flags can affect subsequent reads and writes
+.Po
+see
+.Xr read 2
+and
+.Xr write 2
+.Pc .
+If both
+.Dv O_NDELAY
+and
+.Dv O_NONBLOCK
+are set,
+.Dv O_NONBLOCK
+takes precedence.
+.Pp
+When opening a FIFO with
+.Dv O_RDONLY
+or
+.Dv O_WRONLY
+set:
+.Bl -bullet
+.It
+If
+.Dv O_NONBLOCK
+or
+.Dv O_NDELAY
+is set, an
+.Fn open
+for reading only returns without delay.
+An
+.Fn open
+for writing only returns an error if no process currently has the file open for
reading.
-.RE
-After both ends of a \fBFIFO\fR have been opened, there is no guarantee that
-further calls to \fBopen()\fR \fBO_RDONLY\fR (\fBO_WRONLY\fR) will synchronize
-with later calls to \fBopen()\fR \fBO_WRONLY\fR (\fBO_RDONLY\fR) until both
-ends of the \fBFIFO\fR have been closed by all readers and writers. Any data
-written into a \fBFIFO\fR will be lost if both ends of the \fBFIFO\fR are
-closed before the data is read.
-.sp
+.It
+If
+.Dv O_NONBLOCK
+and
+.Dv O_NDELAY
+are clear, an
+.Fn open
+for reading only blocks until a thread opens the file for writing.
+An
+.Fn open
+for writing only blocks the calling thread until a thread opens the file for
+reading.
+.El
+.Pp
+After both ends of a FIFO have been opened once, there is no guarantee that
+further calls to
+.Fn open
+.Dv O_RDONLY
+.Pq Dv O_WRONLY
+will synchronize with later calls to
+.Fn open
+.Dv O_WRONLY
+.Pq Dv O_RDONLY
+until both ends of the FIFO have been closed by all readers and writers.
+Any data written into a FIFO will be lost if both ends of the FIFO are closed
+before the data is read.
+.Pp
When opening a block special or character special file that supports
non-blocking opens:
-.RS +4
-.TP
-.ie t \(bu
-.el o
-If \fBO_NONBLOCK\fR or \fBO_NDELAY\fR is set, the \fBopen()\fR function returns
-without blocking for the device to be ready or available. Subsequent behavior
-of the device is device-specific.
-.RE
-.RS +4
-.TP
-.ie t \(bu
-.el o
-If \fBO_NONBLOCK\fR and \fBO_NDELAY\fR are clear, the \fBopen()\fR function
-blocks the calling thread until the device is ready or available before
-returning.
-.RE
-Otherwise, the behavior of \fBO_NONBLOCK\fR and \fBO_NDELAY\fR is unspecified.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBO_RSYNC\fR\fR
-.ad
-.sp .6
-.RS 4n
+.Bl -bullet
+.It
+If
+.Dv O_NONBLOCK
+or
+.Dv O_NDELAY
+is set, the
+.Fn open
+function returns without blocking for the device to be ready or available.
+Subsequent behavior of the device is device-specific.
+.It
+If
+.Dv O_NONBLOCK
+and
+.Dv O_NDELAY
+are clear, the
+.Fn open
+function blocks the calling thread until the device is ready or available
+before returning.
+.El
+.Pp
+Otherwise, the behavior of
+.Dv O_NONBLOCK
+and
+.Dv O_NDELAY
+is unspecified.
+.It Dv O_RSYNC
Read I/O operations on the file descriptor complete at the same level of
-integrity as specified by the \fBO_DSYNC\fR and \fBO_SYNC\fR flags. If both
-\fBO_DSYNC\fR and \fBO_RSYNC\fR are set in \fIoflag\fR, all I/O operations on
-the file descriptor complete as defined by synchronized I/O data integrity
-completion. If both \fBO_SYNC\fR and \fBO_RSYNC\fR are set in \fIoflag\fR, all
-I/O operations on the file descriptor complete as defined by synchronized I/O
-file integrity completion.
-.RE
-
-.sp
-.ne 2
-.na
-.B O_SEARCH
-.ad
-.sp .6
-.RS 4n
+integrity as specified by the
+.Dv O_DSYNC
+and
+.Dv O_SYNC
+flags.
+If both
+.Dv O_DSYNC
+and
+.Dv O_RSYNC
+are set in
+.Fa oflag ,
+all I/O operations on the file descriptor complete as defined by synchronized
+I/O data integrity completion.
+If both
+.Dv O_SYNC
+and
+.Dv O_RSYNC
+are set in
+.Fa oflag ,
+all I/O operations on the file descriptor complete as defined by synchronized
+I/O file integrity completion.
+.It Dv O_SEARCH
If set, indicates that the directory should be opened for searching.
-This option is only valid for a directory, an error will be returned if
-it is not.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBO_SYNC\fR\fR
-.ad
-.sp .6
-.RS 4n
+This option is only valid for a directory; an error will be returned if the
+target is not a directory.
+.It Dv O_SYNC
Write I/O operations on the file descriptor complete as defined by synchronized
-I/O file integrity completion (see \fBfcntl.h\fR(3HEAD) definition of
-\fBO_SYNC\fR).
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBO_TRUNC\fR\fR
-.ad
-.sp .6
-.RS 4n
+I/O file integrity completion
+.Po
+see
+.Xr fcntl.h 3HEAD
+.Pc
+definition of
+.Dv O_SYNC .
+.It Dv O_TRUNC
If the file exists and is a regular file, and the file is successfully opened
-\fBO_RDWR\fR or \fBO_WRONLY\fR, its length is truncated to 0 and the mode and
-owner are unchanged. It has no effect on \fBFIFO\fR special files or terminal
-device files. Its effect on other file types is implementation-dependent. The
-result of using \fBO_TRUNC\fR with \fBO_RDONLY\fR is undefined.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBO_XATTR\fR\fR
-.ad
-.sp .6
-.RS 4n
-If set in \fBopenat()\fR, a relative path argument is interpreted as a
-reference to an extended attribute of the file associated with the supplied
-file descriptor. This flag therefore requires the presence of a legal
-\fIfildes\fR argument. If set in \fBopen()\fR, the implied file descriptor is
-that for the current working directory. Extended attributes must be referenced
-with a relative path; providing an absolute path results in a normal file
-reference.
-.RE
-
-.sp
-.LP
-If \fBO_CREAT\fR is set and the file did not previously exist, upon successful
-completion, \fBopen()\fR marks for update the \fBst_atime\fR, \fBst_ctime\fR,
-and \fBst_mtime\fR fields of the file and the \fBst_ctime\fR and \fBst_mtime\fR
+.Dv O_RDWR
+or
+.Dv O_WRONLY ,
+its length is truncated to
+.Sy 0
+and the mode and owner are unchanged.
+It has no effect on FIFO special files or terminal device files.
+Its effect on other file types is implementation-dependent.
+The result of using
+.Dv O_TRUNC
+with
+.Dv O_RDONLY
+is undefined.
+.It Dv O_XATTR
+If set in
+.Fn openat ,
+a relative path argument is interpreted as a reference to an extended attribute
+of the file associated with the supplied file descriptor.
+This flag therefore requires the presence of a legal
+.Fa fildes
+argument.
+If set in
+.Fn open ,
+the implied file descriptor is that for the current working directory.
+Extended attributes must be referenced with a relative path; providing an
+absolute path results in a normal file reference.
+.El
+.Pp
+If
+.Dv O_CREAT
+is set and the file did not previously exist, upon successful completion,
+.Fn open
+marks for update the
+.Fa st_atime ,
+.Fa st_ctime ,
+and
+.Fa st_mtime
+fields of the file and the
+.Fa st_ctime
+and
+.Fa st_mtime
fields of the parent directory.
-.sp
-.LP
-If \fBO_TRUNC\fR is set and the file did previously exist, upon successful
-completion, \fBopen()\fR marks for update the \fBst_ctime\fR and \fBst_mtime\fR
+.Pp
+If
+.Dv O_TRUNC
+is set and the file did previously exist, upon successful completion,
+.Fn open
+marks for update the
+.Fa st_ctime
+and
+.Fa st_mtime
fields of the file.
-.sp
-.LP
-If both the \fBO_SYNC\fR and \fBO_DSYNC\fR flags are set, the effect is as if
-only the \fBO_SYNC\fR flag was set.
-.sp
-.LP
-If \fIpath\fR refers to a \fBSTREAMS\fR file, \fIoflag\fR may be constructed
-from \fBO_NONBLOCK\fR or \fBO_NODELAY\fR OR-ed with either \fBO_RDONLY\fR,
-\fBO_WRONLY\fR, or \fBO_RDWR\fR. Other flag values are not applicable to
-\fBSTREAMS\fR devices and have no effect on them. The values \fBO_NONBLOCK\fR
-and \fBO_NODELAY\fR affect the operation of \fBSTREAMS\fR drivers and certain
-functions (see \fBread\fR(2), \fBgetmsg\fR(2), \fBputmsg\fR(2), and
-\fBwrite\fR(2)) applied to file descriptors associated with \fBSTREAMS\fR
-files. For \fBSTREAMS\fR drivers, the implementation of \fBO_NONBLOCK\fR and
-\fBO_NODELAY\fR is device-specific.
-.sp
-.LP
-When \fBopen()\fR is invoked to open a named stream, and the \fBconnld\fR
-module (see \fBconnld\fR(4M)) has been pushed on the pipe, \fBopen()\fR blocks
-until the server process has issued an \fBI_RECVFD\fR \fBioctl()\fR (see
-\fBstreamio\fR(4I)) to receive the file descriptor.
-.sp
-.LP
-If \fIpath\fR names the master side of a pseudo-terminal device, then it is
-unspecified whether \fBopen()\fR locks the slave side so that it cannot be
-opened. Portable applications must call \fBunlockpt\fR(3C) before opening the
-slave side.
-.sp
-.LP
+.Pp
+If both the
+.Dv O_SYNC
+and
+.Dv O_DSYNC
+flags are set, the effect is as if only the
+.Dv O_SYNC
+flag was set.
+.Pp
+If
+.Fa path
+refers to a STREAMS file,
+.Fa oflag
+may be constructed from
+.Dv O_NONBLOCK
+or
+.Dv O_NODELAY
+OR-ed with either
+.Dv O_RDONLY ,
+.Dv O_WRONLY ,
+or
+.Dv O_RDWR .
+Other flag values are not applicable to STREAMS devices and have no effect on
+them.
+The values
+.Dv O_NONBLOCK
+and
+.Dv O_NODELAY
+affect the operation of STREAMS drivers and certain functions
+.Po
+see
+.Xr read 2 ,
+.Xr getmsg 2 ,
+.Xr putmsg 2 ,
+and
+.Xr write 2
+.Pc
+applied to file descriptors associated with STREAMS files.
+For STREAMS drivers, the implementation of
+.Dv O_NONBLOCK
+and
+.Dv O_NODELAY
+is device-specific.
+.Pp
+When
+.Fn open
+is invoked to open a named stream, and the
+.Xr connld 4M
+module has been pushed on the pipe,
+.Fn open
+blocks until the server process has issued an
+.Dv I_RECVFD
+.Xr ioctl 2
+.Po
+see
+.Xr streamio 4I
+.Pc
+to receive the file descriptor.
+.Pp
+If
+.Fa path
+names the manager side of a pseudo-terminal device, then it is unspecified
+whether
+.Fn open
+locks the subsidiary side so that it cannot be opened.
+Portable applications must call
+.Xr unlockpt 3C
+before opening the subsidiary side.
+.Pp
If the file is a regular file and the local file system is mounted with the
-\fBnbmand\fR mount option, then a mandatory share reservation is automatically
-obtained on the file. The share reservation is obtained as if \fBfcntl\fR(2)
-were called with \fIcmd\fR \fBF_SHARE_NBMAND\fR and the \fBfshare_t\fR values
-set as follows:
-.sp
-.ne 2
-.na
-\fB\fBf_access\fR\fR
-.ad
-.RS 12n
+.Cm nbmand
+mount option, then a mandatory share reservation is automatically obtained on
+the file.
+The share reservation is obtained as if
+.Xr fcntl 2
+were called with
+.Fa cmd
+.Dv F_SHARE_NBMAND
+and the
+.Vt fshare_t
+values set as follows:
+.Bl -tag -width Ds -offset Ds
+.It Fa f_access
Set to the type of read/write access for which the file is opened.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBf_deny\fR\fR
-.ad
-.RS 12n
-\fBF_NODNY\fR
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBf_id\fR\fR
-.ad
-.RS 12n
-The file descriptor value returned from \fBopen()\fR.
-.RE
-
-.sp
-.LP
-If \fIpath\fR is a symbolic link and \fBO_CREAT\fR and \fBO_EXCL\fR are set,
-the link is not followed.
-.sp
-.LP
-Certain flag values can be set following \fBopen()\fR as described in
-\fBfcntl\fR(2).
-.sp
-.LP
+.It Fa f_deny
+.Dv F_NODNY
+.It Fa f_id
+The file descriptor value returned from
+.Fn open .
+.El
+.Pp
+If
+.Fa path
+is a symbolic link and
+.Dv O_CREAT
+and
+.Dv O_EXCL
+are set, the link is not followed.
+.Pp
+Certain flag values can be set following
+.Fn open
+as described in
+.Xr fcntl 2 .
+.Pp
The largest value that can be represented correctly in an object of type
-\fBoff_t\fR is established as the offset maximum in the open file description.
-.SH RETURN VALUES
-Upon successful completion, both \fBopen()\fR and \fBopenat()\fR functions open
-the file and return a non-negative integer representing the lowest numbered
-unused file descriptor. Otherwise, \fB\(mi1\fR is returned, \fBerrno\fR is set
-to indicate the error, and no files are created or modified.
-.SH ERRORS
-The \fBopen()\fR and \fBopenat()\fR functions will fail if:
-.sp
-.ne 2
-.na
-\fB\fBEACCES\fR\fR
-.ad
-.RS 16n
-Search permission is denied on a component of the path prefix.
-.sp
-The file exists and the permissions specified by \fIoflag\fR are denied.
-.sp
-The file does not exist and write permission is denied for the parent directory
-of the file to be created.
-.sp
-\fBO_TRUNC\fR is specified and write permission is denied.
-.sp
-The {\fBPRIV_FILE_DAC_SEARCH\fR} privilege allows processes to search
-directories regardless of permission bits. The {\fBPRIV_FILE_DAC_WRITE\fR}
-privilege allows processes to open files for writing regardless of permission
-bits. See \fBprivileges\fR(7) for special considerations when opening files
-owned by UID 0 for writing. The {\fBPRIV_FILE_DAC_READ\fR} privilege allows
-processes to open files for reading regardless of permission bits.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEAGAIN\fR\fR
-.ad
-.RS 16n
-A mandatory share reservation could not be obtained because the desired access
-conflicts with an existing \fBf_deny\fR share reservation.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEDQUOT\fR\fR
-.ad
-.RS 16n
-The file does not exist, \fBO_CREAT\fR is specified, and either the directory
-where the new file entry is being placed cannot be extended because the user's
-quota of disk blocks on that file system has been exhausted, or the user's
-quota of inodes on the file system where the file is being created has been
-exhausted.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEEXIST\fR\fR
-.ad
-.RS 16n
-The \fBO_CREAT\fR and \fBO_EXCL\fR flags are set and the named file exists.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEILSEQ\fR\fR
-.ad
-.RS 16n
-The \fIpath\fR argument includes non-UTF8 characters and the file system
-accepts only file names where all characters are part of the UTF-8 character
-codeset.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEINTR\fR\fR
-.ad
-.RS 16n
-A signal was caught during \fBopen()\fR.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEFAULT\fR\fR
-.ad
-.RS 16n
-The \fIpath\fR argument points to an illegal address.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEINVAL\fR\fR
-.ad
-.RS 16n
-The system does not support synchronized or direct I/O for this file, or the
-\fBO_XATTR\fR flag was supplied and the underlying file system does not support
-extended file attributes.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEIO\fR\fR
-.ad
-.RS 16n
-The \fIpath\fR argument names a \fBSTREAMS\fR file and a hangup or error
-occurred during the \fBopen()\fR.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEISDIR\fR\fR
-.ad
-.RS 16n
-The named file is a directory and \fIoflag\fR includes \fBO_WRONLY\fR or
-\fBO_RDWR\fR.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBELOOP\fR\fR
-.ad
-.RS 16n
-Too many symbolic links were encountered in resolving \fIpath\fR.
-.sp
-A loop exists in symbolic links encountered during resolution of the \fIpath\fR
-argument.
-.sp
-The \fBO_NOFOLLOW\fR flag is set and the final component of path is a symbolic
-link.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEMFILE\fR\fR
-.ad
-.RS 16n
-There are currently {\fBOPEN_MAX\fR} file descriptors open in the calling
-process.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEMLINK\fR\fR
-.ad
-.RS 16n
-The \fBO_NOLINKS\fR flag is set and the named file has a link count greater
-than 1.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEMULTIHOP\fR\fR
-.ad
-.RS 16n
-Components of \fIpath\fR require hopping to multiple remote machines and the
-file system does not allow it.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBENAMETOOLONG\fR\fR
-.ad
-.RS 16n
-The length of the \fIpath\fR argument exceeds {\fBPATH_MAX\fR} or a pathname
-component is longer than {\fBNAME_MAX\fR}.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBENFILE\fR\fR
-.ad
-.RS 16n
-The maximum allowable number of files is currently open in the system.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBENOENT\fR\fR
-.ad
-.RS 16n
-The \fBO_CREAT\fR flag is not set and the named file does not exist; or the
-\fBO_CREAT\fR flag is set and either the path prefix does not exist or the
-\fIpath\fR argument points to an empty string.
-.sp
+.Vt off_t
+is established as the offset maximum in the open file description.
+.Sh RETURN VALUES
The
-.B O_CREAT
+.Fn open
and
-.B O_DIRECTORY
-flags were both set and
-.I path
-did not point to a file.
-.RE
-
-.sp
-.ne 2
-.na
-.B ENOEXEC
-.ad
-.RS 16n
-The \fBO_EXEC\fR flag is set and \fIpath\fR does not point to a regular
-file.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBENOLINK\fR\fR
-.ad
-.RS 16n
-The \fIpath\fR argument points to a remote machine, and the link to that
-machine is no longer active.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBENOSR\fR\fR
-.ad
-.RS 16n
-The \fIpath\fR argument names a STREAMS-based file and the system is unable to
-allocate a STREAM.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBENOSPC\fR\fR
-.ad
-.RS 16n
-The directory or file system that would contain the new file cannot be
-expanded, the file does not exist, and \fBO_CREAT\fR is specified.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBENOSYS\fR\fR
-.ad
-.RS 16n
-The device specified by \fIpath\fR does not support the open operation.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBENOTDIR\fR\fR
-.ad
-.RS 16n
-A component of the path prefix is not a directory or a relative path was
-supplied to \fBopenat()\fR, the \fBO_XATTR\fR flag was not supplied, and the
-file descriptor does not refer to a directory. The \fBO_SEARCH\fR flag
-was passed and \fIpath\fR does not refer to a directory.
-.sp
-The
-.B O_DIRECTORY
-flag was set and the file was not a directory.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBENXIO\fR\fR
-.ad
-.RS 16n
-The \fBO_NONBLOCK\fR flag is set, the named file is a FIFO, the \fBO_WRONLY\fR
-flag is set, and no process has the file open for reading; or the named file is
-a character special or block special file and the device associated with this
-special file does not exist or has been retired by the fault management
-framework .
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEOPNOTSUPP\fR\fR
-.ad
-.RS 16n
-An attempt was made to open a path that corresponds to a \fBAF_UNIX\fR socket.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEOVERFLOW\fR\fR
-.ad
-.RS 16n
-The named file is a regular file and either \fBO_LARGEFILE\fR is not set and
-the size of the file cannot be represented correctly in an object of type
-\fBoff_t\fR or \fBO_LARGEFILE\fR is set and the size of the file cannot be
-represented correctly in an object of type \fBoff64_t\fR.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEROFS\fR\fR
-.ad
-.RS 16n
-The named file resides on a read-only file system and either \fBO_WRONLY\fR,
-\fBO_RDWR\fR, \fBO_CREAT\fR (if file does not exist), or \fBO_TRUNC\fR is set
-in the \fIoflag\fR argument.
-.RE
-
-.sp
-.LP
-The \fBopenat()\fR function will fail if:
-.sp
-.ne 2
-.na
-\fB\fBEBADF\fR\fR
-.ad
-.RS 9n
-The \fIfildes\fR argument is not a valid open file descriptor or is not
-\fBAT_FTCWD\fR.
-.RE
-
-.sp
-.LP
-The \fBopen()\fR function may fail if:
-.sp
-.ne 2
-.na
-\fB\fBEAGAIN\fR\fR
-.ad
-.RS 16n
-The \fIpath\fR argument names the slave side of a pseudo-terminal device that
-is locked.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEINVAL\fR\fR
-.ad
-.RS 16n
-The value of the \fIoflag\fR argument is not valid.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBENAMETOOLONG\fR\fR
-.ad
-.RS 16n
-Pathname resolution of a symbolic link produced an intermediate result whose
-length exceeds {\fBPATH_MAX\fR}.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBENOMEM\fR\fR
-.ad
-.RS 16n
-The \fIpath\fR argument names a \fBSTREAMS\fR file and the system is unable to
-allocate resources.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBETXTBSY\fR\fR
-.ad
-.RS 16n
-The file is a pure procedure (shared text) file that is being executed and
-\fIoflag\fR is \fBO_WRONLY\fR or \fBO_RDWR\fR.
-.RE
-
-.SH EXAMPLES
-\fBExample 1 \fROpen a file for writing by the owner.
-.sp
-.LP
-The following example opens the file \fB/tmp/file\fR, either by creating it if
-it does not already exist, or by truncating its length to 0 if it does exist.
+.Fn openat
+functions open the file and, if successful, return a non-negative integer
+representing the lowest numbered unused file descriptor; otherwise the
+value
+.Sy -1
+is returned and the global variable
+.Va errno
+is set to indicate the error and no files are created or modified.
+.Sh EXAMPLES
+.Sy Example 1
+Open a file for writing by the owner.
+.Pp
+The following example opens the file
+.Pa /tmp/file ,
+either by creating it if it does not already exist, or by truncating its length
+to
+.Sy 0
+if it does exist.
If the call creates a new file, the access permission bits in the file mode of
the file are set to permit reading and writing by the owner, and to permit
reading only by group members and others.
-
-.sp
-.LP
-If the call to \fBopen()\fR is successful, the file is opened for writing.
-
-.sp
-.in +2
-.nf
+.Pp
+If the call to
+.Fn open
+is successful, the file is opened for writing.
+.Bd -literal -offset Ds
#include <fcntl.h>
\&...
int fd;
@@ -928,117 +635,362 @@ char *filename = "/tmp/file";
\&...
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, mode);
\&...
-.fi
-.in -2
-
-.LP
-\fBExample 2 \fROpen a file using an existence check.
-.sp
-.LP
-The following example uses the \fBopen()\fR function to try to create the
-\fBLOCKFILE\fR file and open it for writing. Since the \fBopen()\fR function
-specifies the \fBO_EXCL\fR flag, the call fails if the file already exists. In
-that case, the application assumes that someone else is updating the password
-file and exits.
-
-.sp
-.in +2
-.nf
+.Ed
+.Pp
+.Sy Example 2
+Open a file using an existence check.
+.Pp
+The following example uses the
+.Fn open
+function to try to create the
+.Dv LOCKFILE
+file and open it for writing.
+Since the
+.Fn open
+function specifies the
+.Dv O_EXCL
+flag, the call fails if the file already exists.
+In that case, the application assumes that someone else is updating the
+password file and exits.
+.Bd -literal -offset Ds
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
+#include <err.h>
+\&...
#define LOCKFILE "/etc/ptmp"
\&...
int pfd; /* Integer for file descriptor returned by open() call. */
\&...
if ((pfd = open(LOCKFILE, O_WRONLY | O_CREAT | O_EXCL,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
-{
- fprintf(stderr, "Cannot open /etc/ptmp. Try again later.\en");
- exit(1);
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
+ err(1, "Cannot open %s. Try again later.", LOCKFILE);
}
\&...
-.fi
-.in -2
-
-.LP
-\fBExample 3 \fROpen a file for writing.
-.sp
-.LP
+.Ed
+.Pp
+.Sy Example 3
+Open a file for writing.
+.Pp
The following example opens a file for writing, creating the file if it does
-not already exist. If the file does exist, the system truncates the file to
-zero bytes.
-
-.sp
-.in +2
-.nf
+not already exist.
+If the file does exist, the system truncates the file to zero bytes.
+.Bd -literal -offset Ds
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
-#define LOCKFILE "/etc/ptmp"
+#include <err.h>
\&...
int pfd;
char filename[PATH_MAX+1];
\&...
if ((pfd = open(filename, O_WRONLY | O_CREAT | O_TRUNC,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
-{
- perror("Cannot open output file\en"); exit(1);
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
+ err(1, "Cannot open output file");
}
\&...
-.fi
-.in -2
-
-.SH USAGE
-The \fBopen()\fR function has a transitional interface for 64-bit file offsets.
-See \fBlf64\fR(7). Note that using \fBopen64()\fR is equivalent to using
-\fBopen()\fR with \fBO_LARGEFILE\fR set in \fIoflag\fR.
-.SH ATTRIBUTES
-See \fBattributes\fR(7) for descriptions of the following attributes:
-.sp
-
-.sp
-.TS
-box;
-c | c
-l | l .
-ATTRIBUTE TYPE ATTRIBUTE VALUE
-_
-Interface Stability Committed
-_
-MT-Level Async-Signal-Safe
-_
-Standard For \fBopen()\fR, see \fBstandards\fR(7).
-.TE
-
-.SH SEE ALSO
-.BR Intro (2),
-.BR chmod (2),
-.BR close (2),
-.BR creat (2),
-.BR dup (2),
-.BR exec (2),
-.BR fcntl (2),
-.BR getmsg (2),
-.BR getrlimit (2),
-.BR lseek (2),
-.BR putmsg (2),
-.BR read (2),
-.BR stat (2),
-.BR umask (2),
-.BR write (2),
-.BR attropen (3C),
-.BR directio (3C),
-.BR unlockpt (3C),
-.BR fcntl.h (3HEAD),
-.BR stat.h (3HEAD),
-.BR streamio (4I),
-.BR connld (4M),
-.BR attributes (7),
-.BR lf64 (7),
-.BR privileges (7),
-.BR standards (7)
-.SH NOTES
-Hierarchical Storage Management (HSM) file systems can sometimes cause long
-delays when opening a file, since HSM files must be recalled from secondary
-storage.
+.Ed
+.Sh ERRORS
+The
+.Fn open
+and
+.Fn openat
+functions will fail if:
+.Bl -tag -width Er
+.It Er EACCES
+Search permission is denied on a component of the path prefix.
+.Pp
+The file exists and the permissions specified by
+.Fa oflag
+are denied.
+.Pp
+The file does not exist and write permission is denied for the parent directory
+of the file to be created.
+.Pp
+.Dv O_TRUNC
+is specified and write permission is denied.
+.Pp
+The
+.Brq Dv PRIV_FILE_DAC_SEARCH
+privilege allows processes to search directories regardless of permission bits.
+The
+.Brq Dv PRIV_FILE_DAC_WRITE
+privilege allows processes to open files for writing regardless of permission
+bits.
+See
+.Xr privileges 7
+for special considerations when opening files owned by user ID
+.Sy 0
+for writing.
+The
+.Brq Dv PRIV_FILE_DAC_READ
+privilege allows
+processes to open files for reading regardless of permission bits.
+.It Er EAGAIN
+A mandatory share reservation could not be obtained because the desired access
+conflicts with an existing
+.Fa f_deny
+share reservation
+.Po
+see
+.Xr fcntl 2
+.Pc .
+.It Er EDQUOT
+The file does not exist,
+.Dv O_CREAT
+is specified, and either the directory where the new file entry is being placed
+cannot be extended because the user's quota of disk blocks on that file system
+has been exhausted, or the user's quota of inodes on the file system where the
+file is being created has been exhausted.
+.It Er EEXIST
+The
+.Dv O_CREAT
+and
+.Dv O_EXCL
+flags are set and the named file already exists.
+.It Er EILSEQ
+The
+.Fa path
+argument includes bytes that are not valid UTF-8 characters, and the file
+system accepts only file names where all characters are part of the UTF-8
+character codeset.
+.It Er EINTR
+A signal was caught during
+.Fn open .
+.It Er EFAULT
+The
+.Fa path
+argument points to an illegal address.
+.It Er EINVAL
+Either the system does not support synchronized or direct I/O for this file, or
+the
+.Dv O_XATTR
+flag was supplied and the underlying file system does not support extended file
+attributes.
+.It Er EIO
+The
+.Fa path
+argument names a STREAMS file and a hangup or error occurred during the
+.Fn open .
+.It Er EISDIR
+The named file is a directory and
+.Fa oflag
+includes
+.Dv O_WRONLY
+or
+.Dv O_RDWR .
+.It Er ELOOP
+Too many symbolic links were encountered in resolving
+.Fa path .
+.Pp
+A loop exists in symbolic links encountered during resolution of the
+.Fa path
+argument.
+.Pp
+The
+.Dv O_NOFOLLOW
+flag is set and the final component of path is a symbolic link.
+.It Er EMFILE
+There are currently
+.Brq Dv OPEN_MAX
+file descriptors open in the calling process.
+.It Er EMLINK
+The
+.Dv O_NOLINKS
+flag is set and the named file has a link count greater than
+.Sy 1 .
+.It Er EMULTIHOP
+Components of
+.Fa path
+require hopping to multiple remote machines and the file system does not allow
+it.
+.It Er ENAMETOOLONG
+The length of the
+.Fa path
+argument exceeds
+.Brq Dv PATH_MAX
+or a pathname component is longer than
+.Brq Dv NAME_MAX .
+.It Er ENFILE
+The maximum allowable number of files is currently open in the system.
+.It Er ENOENT
+The
+.Dv O_CREAT
+flag is not set and the named file does not exist; or the
+.Dv O_CREAT
+flag is set and either the path prefix does not exist or the
+.Fa path
+argument points to an empty string.
+.Pp
+The
+.Dv O_CREAT
+and
+.Dv O_DIRECTORY
+flags were both set and
+.Fa path
+did not point to a file.
+.It Er ENOEXEC
+The
+.Dv O_EXEC
+flag is set and
+.Fa path
+does not point to a regular file.
+.It Er ENOLINK
+The
+.Fa path
+argument points to a remote machine, and the link to that machine is no longer
+active.
+.It Er ENOSR
+Th
+.Fa path
+argument names a STREAMS-based file and the system is unable to allocate a
+STREAM.
+.It Er ENOSPC
+The directory or file system that would contain the new file cannot be
+expanded, the file does not exist, and
+.Dv O_CREAT
+is specified.
+.It Er ENOSYS
+The device specified by
+.Fa path
+does not support the open operation.
+.It Er ENOTDIR
+A component of the path prefix is not a directory or a relative path was
+supplied to
+.Fn openat ,
+the
+.Dv O_XATTR
+flag was not supplied, and the file descriptor does not refer to a directory.
+The
+.Dv O_SEARCH
+flag was passed and
+.Fa path
+does not refer to a directory.
+.Pp
+The
+.Dv O_DIRECTORY
+flag was set and the file was not a directory.
+.It Er ENXIO
+The
+.Dv O_NONBLOCK
+flag is set, the named file is a FIFO, the
+.Dv O_WRONLY
+flag is set, and no process has the file open for reading; or the named file is
+a character special or block special file and the device associated with this
+special file does not exist or has been retired by the fault management
+framework.
+.It Er EOPNOTSUPP
+An attempt was made to open a path that corresponds to an
+.Dv AF_UNIX
+socket.
+.It Er EOVERFLOW
+The named file is a regular file and either
+.Dv O_LARGEFILE
+is not set and the size of the file cannot be represented correctly in an
+object of type
+.Vt off_t
+or
+.Dv O_LARGEFILE
+is set and the size of the file cannot be represented correctly in an object of
+type
+.Vt off64_t .
+.It Er EROFS
+The named file resides on a read-only file system and either
+.Dv O_WRONLY ,
+.Dv O_RDWR ,
+.Dv O_CREAT
+(if file does not exist), or
+.Dv O_TRUNC
+is set in the
+.Fa oflag
+argument.
+.El
+.Pp
+The
+.Fn openat
+function will fail if:
+.Bl -tag -width Er
+.It Er EBADF
+The
+.Fa fildes
+argument is not a valid open file descriptor or is not
+.Dv AT_FTCWD .
+.El
+.Pp
+The
+.Fn open
+function may fail if:
+.Bl -tag -width Er
+.It Er EAGAIN
+The
+.Fa path
+argument names the subsidiary side of a pseudo-terminal device that is locked.
+.It Er EINVAL
+The value of the
+.Fa oflag
+argument is not valid.
+.It Er ENAMETOOLONG
+Pathname resolution of a symbolic link produced an intermediate result whose
+length exceeds
+.Brq Dv PATH_MAX .
+.It Er ENOMEM
+The
+.Fa path
+argument names a STREAMS file and the system is unable to allocate resources.
+.It Er ETXTBSY
+The file is a pure procedure (shared text) file that is being executed and
+.Fa oflag
+is
+.Dv O_WRONLY
+or
+.Dv O_RDWR .
+.El
+.Sh USAGE
+The
+.Fn open
+function has a transitional interface for 64-bit file offsets.
+See
+.Xr lf64 7 .
+Note that using
+.Fn open64
+is equivalent to using
+.Fn open with
+.Dv O_LARGEFILE
+set in
+.Fa oflag .
+.Sh INTERFACE STABILITY
+.Sy Committed
+.Sh MT LEVEL
+.Sy Async-Signal-Safe
+.Sh SEE ALSO
+.Xr chmod 2 ,
+.Xr close 2 ,
+.Xr creat 2 ,
+.Xr dup 2 ,
+.Xr exec 2 ,
+.Xr fcntl 2 ,
+.Xr getmsg 2 ,
+.Xr getrlimit 2 ,
+.Xr Intro 2 ,
+.Xr lseek 2 ,
+.Xr putmsg 2 ,
+.Xr read 2 ,
+.Xr stat 2 ,
+.Xr umask 2 ,
+.Xr write 2 ,
+.Xr attropen 3C ,
+.Xr directio 3C ,
+.Xr unlockpt 3C ,
+.Xr fcntl.h 3HEAD ,
+.Xr stat.h 3HEAD ,
+.Xr streamio 4I ,
+.Xr connld 4M ,
+.Xr attributes 7 ,
+.Xr lf64 7 ,
+.Xr privileges 7 ,
+.Xr standards 7
+.Sh NOTES
+Hierarchical Storage Management
+.Pq HSM
+file systems can sometimes cause long delays when opening a file, since HSM
+files must be recalled from secondary storage.
diff --git a/usr/src/man/man3c/grantpt.3c b/usr/src/man/man3c/grantpt.3c
index d32e2e71fc..671f156f0a 100644
--- a/usr/src/man/man3c/grantpt.3c
+++ b/usr/src/man/man3c/grantpt.3c
@@ -43,91 +43,76 @@
.\" Copyright 1989 AT&T
.\" Portions Copyright (c) 1994, X/Open Company Limited. All Rights Reserved.
.\" Copyright (c) 2006, Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright 2022 Oxide Computer Company
.\"
-.TH GRANTPT 3C "Aug 14, 2006"
-.SH NAME
-grantpt \- grant access to the slave pseudo-terminal device
-.SH SYNOPSIS
-.LP
-.nf
-#include <stdlib.h>
-
-\fBint\fR \fBgrantpt\fR(\fBint\fR \fIfildes\fR);
-.fi
-
-.SH DESCRIPTION
-.sp
-.LP
-The \fBgrantpt()\fR function changes the mode and ownership of the slave
-pseudo-terminal device associated with its master pseudo-terminal counterpart.
-\fIfildes\fR is the file descriptor returned from a successful open of the
-master pseudo-terminal device. The user ID of the slave is set to the real UID
-of the calling process and the group ID is set to a reserved group. The
-permission mode of the slave pseudo-terminal is set to readable and writable by
-the owner and writable by the group.
-.SH RETURN VALUES
-.sp
-.LP
-Upon successful completion, \fBgrantpt()\fR returns \fB0\fR. Otherwise, it
-returns \fB\(mi1\fR and sets \fBerrno\fR to indicate the error.
-.SH ERRORS
-.sp
-.LP
-The \fBgrantpt()\fR function may fail if:
-.sp
-.ne 2
-.na
-\fB\fBEBADF\fR\fR
-.ad
-.RS 10n
-The \fIfildes\fR argument is not a valid open file descriptor.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEINVAL\fR\fR
-.ad
-.RS 10n
-The \fIfildes\fR argument is not associated with a master pseudo-terminal
+.Dd February 5, 2022
+.Dt GRANTPT 3C
+.Os
+.Sh NAME
+.Nm grantpt
+.Nd grant access to the subsidiary device of a pseudo-terminal
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fo grantpt
+.Fa "int fildes"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn grantpt
+function changes the mode and ownership of the pseudo-terminal subsidiary
+device associated with its pseudo-terminal manager counterpart.
+.Pp
+The
+.Fa fildes
+argument is the file descriptor returned from a successful
+.Xr open 2
+of the pseudo-terminal manager device; e.g., by calling
+.Xr posix_openpt 3C
+or by performing an
+.Xr open 2
+of the
+.Xr ptm 4D
device.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEACCES\fR\fR
-.ad
-.RS 10n
-The corresponding slave pseudo-terminal device could not be accessed.
-.RE
-
-.SH ATTRIBUTES
-.sp
-.LP
-See \fBattributes\fR(7) for descriptions of the following attributes:
-.sp
-
-.sp
-.TS
-box;
-c | c
-l | l .
-ATTRIBUTE TYPE ATTRIBUTE VALUE
-_
-Interface Stability Standard
-_
-MT-Level Safe
-.TE
-
-.SH SEE ALSO
-.sp
-.LP
-.BR open (2),
-.BR ptsname (3C),
-.BR unlockpt (3C),
-.BR attributes (7),
-.BR standards (7)
-.sp
-.LP
-\fISTREAMS Programming Guide\fR
+.Pp
+The user ID owner of the subsidiary device is set to the real user ID of the
+calling process.
+The group ID owner is set to a reserved group.
+.Pp
+The permission mode of the subsidiary device is set to be readable and writable
+by the owner, and writable by the group.
+.Sh RETURN VALUES
+.Rv -std grantpt
+.Sh EXAMPLES
+See
+.Xr posix_openpt 3C
+for an example that includes a call to
+.Fn grantpt .
+.Sh ERRORS
+The
+.Fn grantpt
+function may fail if:
+.Bl -tag -width Er
+.It Er EBADF
+The
+.Fa fildes
+argument is not a valid open file descriptor.
+.It Er EINVAL
+The
+.Fa fildes
+argument is not associated with a pseudo-terminal manager device.
+.It Er EACCES
+The corresponding pseudo-terminal subsidiary device could not be accessed.
+.El
+.Sh INTERFACE STABILITY
+.Sy Committed
+.Sh MT LEVEL
+.Sy Safe
+.Sh SEE ALSO
+.Xr open 2 ,
+.Xr posix_openpt 3C ,
+.Xr ptsname 3C ,
+.Xr unlockpt 3C ,
+.Xr ptm 4D ,
+.Xr attributes 7 ,
+.Xr standards 7
diff --git a/usr/src/man/man3c/posix_openpt.3c b/usr/src/man/man3c/posix_openpt.3c
index 2f08312126..d539782b62 100644
--- a/usr/src/man/man3c/posix_openpt.3c
+++ b/usr/src/man/man3c/posix_openpt.3c
@@ -42,164 +42,142 @@
.\"
.\" Copyright (c) 2001, The IEEE and The Open Group. All Rights Reserved.
.\" Portions Copyright (c) 2003, Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright 2022 Oxide Computer Company
.\"
-.TH POSIX_OPENPT 3C "June 18, 2021"
-.SH NAME
-posix_openpt \- open a pseudo terminal device
-.SH SYNOPSIS
-.nf
-#include <stdlib.h>
-#include <fcntl.h>
-
-\fBint\fR \fBposix_openpt\fR(\fBint\fR \fIoflag\fR);
-.fi
-
-.SH DESCRIPTION
-The \fBposix_openpt()\fR function establishes a connection between a master
-device for a pseudo-terminal and a file descriptor. The file descriptor is used
-by other I/O functions that refer to that pseudo-terminal.
-.sp
-.LP
+.Dd February 5, 2022
+.Dt POSIX_OPENPT 3C
+.Os
+.Sh NAME
+.Nm posix_openpt
+.Nd open a pseudo-terminal manager device
+.Sh SYNOPSIS
+.In stdlib.h
+.In fcntl.h
+.Ft int
+.Fo posix_openpt
+.Fa "int oflag"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn posix_openpt
+function establishes a connection between a manager device for a
+pseudo-terminal and a file descriptor.
+The file descriptor is used by other I/O functions that refer to that
+pseudo-terminal.
+.Pp
The file status flags and file access modes of the open file description are
-set according to the value of \fIoflag\fR.
-.sp
-.LP
-Values for \fIoflag\fR are constructed by a bitwise-inclusive OR of flags from
-the following list, defined in <\fBfcntl.h\fR>.
-.sp
-.ne 2
-.na
-\fB\fBO_RDWR\fR\fR
-.ad
-.RS 12n
+set according to the value of
+.Fa oflag .
+.Pp
+Values for
+.Fa oflag
+are constructed by a bitwise-inclusive OR of flags from
+the following list, defined in
+.Xr fcntl.h 3HEAD :
+.Bl -tag -width Ds
+.It Dv O_RDWR
Open for reading and writing.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBO_NOCTTY\fR\fR
-.ad
-.RS 12n
-If set, \fBposix_openpt()\fR does not cause the terminal device to become the
-controlling terminal for the process.
-.RE
-
-.sp
-.LP
-The behavior of other values for the \fIoflag\fR argument is unspecified.
-.SH RETURN VALUES
-Upon successful completion, the \fBposix_openpt()\fR function opens a master
-pseudo-terminal device and returns a non-negative integer representing the
-lowest numbered unused file descriptor. Otherwise, -1 is returned and
-\fBerrno\fR is set to indicate the error.
-.SH ERRORS
-The \fBposix_openpt()\fR function will fail if:
-.sp
-.ne 2
-.na
-\fB\fBEMFILE\fR\fR
-.ad
-.RS 10n
-{\fBOPEN_MAX\fR} file descriptors are currently open in the calling process.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBENFILE\fR\fR
-.ad
-.RS 10n
-The maximum allowable number of files is currently open in the system.
-.RE
-
-.sp
-.LP
-The \fBposix_openpt()\fR function may fail if:
-.sp
-.ne 2
-.na
-\fB\fBEINVAL\fR\fR
-.ad
-.RS 10n
-The value of \fIoflag\fR is not valid.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEAGAIN\fR\fR
-.ad
-.RS 10n
-Out of pseudo-terminal resources.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBENOSR\fR\fR
-.ad
-.RS 10n
-Out of STREAMS resources.
-.RE
-
-.SH EXAMPLES
-\fBExample 1 \fROpen a pseudo-terminal.
-.sp
-.LP
-The following example opens a pseudo-terminal and returns the name of the slave
-device and a file descriptor.
-
-.sp
-.in +2
-.nf
+.It Dv O_NOCTTY
+If set,
+.Fn posix_openpt
+does not cause the terminal device to become the controlling terminal for the
+process.
+.El
+.Pp
+The behavior of other values for the
+.Fa oflag
+argument is unspecified.
+.Sh RETURN VALUES
+The
+.Fn posix_getopt
+function opens a manager pseudo-terminal device and, if successful, returns a
+non-negative integer representing the lowest numbered unused file descriptor ;
+otherwise, the value
+.Sy -1
+is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh EXAMPLES
+.Sy Example 1
+Open a pseudo-terminal.
+.Pp
+The following example opens a pseudo-terminal and returns the name of the
+subsidiary device and a file descriptor.
+.Bd -literal -offset Ds
#include <fcntl.h>
#include <stdio.h>
-
-int masterfd, slavefd;
-char *slavedevice;
-
-masterfd = posix_openpt(O_RDWR|O_NOCTTY);
-
-if (masterfd == -1
- || grantpt (masterfd) == -1
- || unlockpt (masterfd) == -1
- || (slavedevice = ptsname (masterfd)) == NULL)
- return -1;
-
-printf("slave device is: %s\en", slavedevice);
-
-slavefd = open(slave, O_RDWR|O_NOCTTY);
-if (slavefd < 0)
- return -1;
-.fi
-.in -2
-
-.SH USAGE
-This function provides a method for portably obtaining a file descriptor of a
-master terminal device for a pseudo-terminal. The \fBgrantpt\fR(3C) and
-\fBptsname\fR(3C) functions can be used to manipulate mode and ownership
-permissions and to obtain the name of the slave device, respectively.
-.SH ATTRIBUTES
-See \fBattributes\fR(7) for descriptions of the following attributes:
-.sp
-
-.sp
-.TS
-box;
-c | c
-l | l .
-ATTRIBUTE TYPE ATTRIBUTE VALUE
-_
-Interface Stability Standard
-_
-MT-Level MT-Safe
-.TE
-
-.SH SEE ALSO
-.BR open (2),
-.BR grantpt (3C),
-.BR ptsname (3C),
-.BR unlockpt (3C),
-.BR attributes (7),
-.BR standards (7)
+#include <err.h>
+
+int managerfd, subsidiaryfd;
+char *subsidiarydevice;
+
+if ((managerfd = posix_openpt(O_RDWR|O_NOCTTY)) < 0) {
+ err(1, "opening pseudo-terminal manager");
+}
+
+if (grantpt(managerfd) != 0 ||
+ unlockpt(managerfd) != 0 ||
+ (subsidiarydevice = ptsname(managerfd)) == NULL) {
+ (void) close(managerfd);
+ err(1, "locating pseudo-terminal subsidiary");
+}
+
+printf("subsidiary device is: %s\en", subsidiarydevice);
+
+if ((subsidiaryfd = open(subsidiary, O_RDWR|O_NOCTTY)) < 0) {
+ err(1, "opening pseudo-terminal subsidiary");
+}
+.Ed
+.Sh ERRORS
+The
+.Fn posix_openpt
+function will fail if:
+.Bl -tag -width Er
+.It Er EMFILE
+.Brq Dv OPEN_MAX
+file descriptors are currently open in the calling process.
+.It Er ENFILE
+The maximum allowable number of files is currently open in the system.
+.El
+.Pp
+The
+.Fn posix_openpt
+function may fail if:
+.Bl -tag -width Er
+.It Er EINVAL
+The value of
+.Fa oflag
+is not valid.
+.It Er EAGAIN
+The system has run out of pseudo-terminal resources.
+.It Er ENOSR
+The system has run out of STREAMS resources.
+.El
+.Sh USAGE
+This function provides a portable method for obtaining the file descriptor of a
+manager terminal device for a pseudo-terminal, as opposed to using
+.Xr open 2
+on the
+.Xr ptm 4D
+device which is system-specific.
+.Pp
+The
+.Xr grantpt 3C
+function can be used to manipulate the mode and ownership permissions
+of the subsidiary device.
+The
+.Xr ptsname 3C
+function can be used to obtain the name of the subsidiary device.
+.Sh INTERFACE STABILITY
+.Sy Committed
+.Sh MT LEVEL
+.Sy MT-Safe
+.Sh SEE ALSO
+.Xr open 2 ,
+.Xr grantpt 3C ,
+.Xr ptsname 3C ,
+.Xr unlockpt 3C ,
+.Xr ptm 4D ,
+.Xr pts 4D ,
+.Xr attributes 7 ,
+.Xr standards 7
diff --git a/usr/src/man/man3c/ptsname.3c b/usr/src/man/man3c/ptsname.3c
index 24cf276592..cb83f6f9b5 100644
--- a/usr/src/man/man3c/ptsname.3c
+++ b/usr/src/man/man3c/ptsname.3c
@@ -43,63 +43,72 @@
.\" Copyright 1989 AT&T
.\" Portions Copyright (c) 1992, X/Open Company Limited All Rights Reserved
.\" Copyright (c) 2002, Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright 2022 Oxide Computer Company
.\"
-.TH PTSNAME 3C "Aug 14, 2002"
-.SH NAME
-ptsname \- get name of the slave pseudo-terminal device
-.SH SYNOPSIS
-.LP
-.nf
-#include <stdlib.h>
-
-\fBchar *\fR\fBptsname\fR(\fBint\fR \fIfildes\fR);
-.fi
-
-.SH DESCRIPTION
-.sp
-.LP
-The \fBptsname()\fR function returns the name of the slave pseudo-terminal
-device associated with a master pseudo-terminal device. \fIfildes\fR is a file
-descriptor returned from a successful open of the master device.
-\fBptsname()\fR returns a pointer to a string containing the null-terminated
-path name of the slave device of the form \fB/dev/pts/N\fR, where \fBN\fR is a
-non-negative integer.
-.SH RETURN VALUES
-.sp
-.LP
-Upon successful completion, the function \fBptsname()\fR returns a pointer to a
-string which is the name of the pseudo-terminal slave device. This value points
-to a static data area that is overwritten by each call to \fBptsname()\fR. Upon
-failure, \fBptsname()\fR returns \fINULL\fR. This could occur if \fIfildes\fR
-is an invalid file descriptor or if the slave device name does not exist in
-the file system.
-.SH ATTRIBUTES
-.sp
-.LP
-See \fBattributes\fR(7) for descriptions of the following attributes:
-.sp
-
-.sp
-.TS
-box;
-c | c
-l | l .
-ATTRIBUTE TYPE ATTRIBUTE VALUE
-_
-Interface Stability Standard
-_
-MT-Level Safe
-.TE
-
-.SH SEE ALSO
-.sp
-.LP
-.BR open (2),
-.BR grantpt (3C),
-.BR ttyname (3C),
-.BR unlockpt (3C),
-.BR attributes (7),
-.BR standards (7)
-.sp
-.LP
-\fISTREAMS Programming Guide\fR
+.Dd February 5, 2022
+.Dt PTSNAME 3C
+.Os
+.Sh NAME
+.Nm ptsname
+.Nd get the name of the subsidiary device of a pseudo-terminal
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft char *
+.Fo ptsname
+.Fa "int fildes"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn ptsname
+function returns the name of the pseudo-terminal subsidiary device associated
+with a pseudo-terminal manager device.
+The
+.Fa fildes
+argument is a file descriptor returned from a successful open of the
+pseudo-terminal manager device; e.g., by calling
+.Xr posix_openpt 3C
+or by performing an
+.Xr open 2
+of the
+.Xr ptm 4D
+device.
+.Pp
+The
+.Fn ptsname
+function returns a pointer to a string containing the null-terminated
+path name of the subsidiary device.
+This string is of the form
+.Pa /dev/pts/N ,
+where
+.Sy N
+is a non-negative integer.
+.Sh RETURN VALUES
+If successful, the
+.Fn ptsname
+function returns a pointer to a string which is the name of the pseudo-terminal
+subsidiary device.
+This value points to a static data area that is overwritten by each call to
+.Fn ptsname .
+.Pp
+Upon failure,
+.Fn ptsname
+returns
+.Dv NULL .
+This could occur if
+.Fa fildes
+is an invalid file descriptor or if the subsidiary device name does not exist
+in the file system.
+.Sh INTERFACE STABILITY
+.Sy Committed
+.Sh MT LEVEL
+.Sy Safe
+.Sh SEE ALSO
+.Xr open 2 ,
+.Xr grantpt 3C ,
+.Xr posix_openpt 3C ,
+.Xr ttyname 3C ,
+.Xr unlockpt 3C ,
+.Xr ptm 4D ,
+.Xr pts 4D ,
+.Xr attributes 7 ,
+.Xr standards 7
diff --git a/usr/src/man/man3c/unlockpt.3c b/usr/src/man/man3c/unlockpt.3c
index 5c68e44ba6..2aa9360131 100644
--- a/usr/src/man/man3c/unlockpt.3c
+++ b/usr/src/man/man3c/unlockpt.3c
@@ -43,81 +43,69 @@
.\" Copyright 1989 AT&T
.\" Copyright (c) 1997, The Open Group. All Rights Reserved.
.\" Portions Copyright (c) 2002, Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright 2022 Oxide Computer Company
.\"
-.TH UNLOCKPT 3C "Aug 14, 2002"
-.SH NAME
-unlockpt \- unlock a pseudo-terminal master/slave pair
-.SH SYNOPSIS
-.LP
-.nf
-#include <stdlib.h>
-
-\fBint\fR \fBunlockpt\fR(\fBint\fR \fIfildes\fR);
-.fi
-
-.SH DESCRIPTION
-.sp
-.LP
-The \fBunlockpt()\fR function unlocks the slave pseudo-terminal device
-associated with the master to which \fIfildes\fR refers.
-.sp
-.LP
-Portable applications must call \fBunlockpt()\fR before opening the slave side
-of a pseudo-terminal device.
-.SH RETURN VALUES
-.sp
-.LP
-Upon successful completion, \fBunlockpt()\fR returns \fB0\fR. Otherwise, it
-returns \fB\(mi1\fR and sets \fBerrno\fR to indicate the error.
-.SH ERRORS
-.sp
-.LP
-The \fBunlockpt()\fR function may fail if:
-.sp
-.ne 2
-.na
-\fB\fBEBADF\fR\fR
-.ad
-.RS 10n
-The \fIfildes\fR argument is not a file descriptor open for writing.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBEINVAL\fR\fR
-.ad
-.RS 10n
-The \fIfildes\fR argument is not associated with a master pseudo-terminal
-device.
-.RE
-
-.SH ATTRIBUTES
-.sp
-.LP
-See \fBattributes\fR(7) for descriptions of the following attributes:
-.sp
-
-.sp
-.TS
-box;
-c | c
-l | l .
-ATTRIBUTE TYPE ATTRIBUTE VALUE
-_
-Interface Stability Standard
-_
-MT-Level Safe
-.TE
-
-.SH SEE ALSO
-.sp
-.LP
-.BR open (2),
-.BR grantpt (3C),
-.BR ptsname (3C),
-.BR attributes (7),
-.BR standards (7)
-.sp
-.LP
-\fISTREAMS Programming Guide\fR
+.Dd February 5, 2022
+.Dt UNLOCKPT 3C
+.Os
+.Sh NAME
+.Nm unlockpt
+.Nd unlock a pseudo-terminal device pair
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft int
+.Fo unlockpt
+.Fa "int fildes"
+.Fc
+.Sh DESCRIPTION
+When a pseudo-terminal manager device is opened, whether through
+.Xr posix_openpt 3C
+or
+.Xr open 2
+on a
+.Xr ptm 4D
+device, the subsidiary device begins operation in a locked state.
+The
+.Fn unlockpt
+function unlocks the pseudo-terminal subsidiary device associated with the
+manager device to which
+.Fa fildes
+refers.
+.Pp
+Portable applications must call
+.Fn unlockpt
+before opening the pseudo-terminal subsidiary device.
+.Sh RETURN VALUES
+.Rv -std unlockpt
+.Sh EXAMPLES
+See
+.Xr posix_openpt 3C
+for an example that includes a call to
+.Fn unlockpt .
+.Sh ERRORS
+The
+.Fn unlockpt
+function may fail if:
+.Bl -tag -width Er
+.It Er EBADF
+The
+.Fa fildes
+argument is not a file descriptor open for writing.
+.It Er EINVAL
+EINVAL
+The
+.Fa fildes
+argument is not associated with a pseudo-terminal manager device.
+.El
+.Sh INTERFACE STABILITY
+.Sy Committed
+.Sh MT LEVEL
+.Sy Safe
+.Sh SEE ALSO
+.Xr open 2 ,
+.Xr grantpt 3C ,
+.Xr posix_openpt 3C ,
+.Xr ptsname 3C ,
+.Xr ptm 4D ,
+.Xr attributes 7 ,
+.Xr standards 7
diff --git a/usr/src/man/man3cpc/cpc.3cpc b/usr/src/man/man3cpc/cpc.3cpc
index ab98621f7f..3fa9f624f8 100644
--- a/usr/src/man/man3cpc/cpc.3cpc
+++ b/usr/src/man/man3cpc/cpc.3cpc
@@ -145,7 +145,8 @@ Includes Ryzen, ThreadRipper, and EPYC branded processors.
AMD Family 17h Zen 2 processors, including models 30-7fh.
Includes Ryzen, ThreadRipper, and EPYC branded processors.
.It Xr amd_f17h_zen3_events 3CPC
-AMD Family 19h Zen 3 processors, including models 00-0fh and 20-2fh.
+AMD Family 19h Zen 3 processors, including models 00-0fh, 20-2fh, and
+50-5fh.
Includes Ryzen and EPYC branded processors.
.El
.Ss Using Attributes
diff --git a/usr/src/man/man3utempter/utempter_add_record.3utempter b/usr/src/man/man3utempter/utempter_add_record.3utempter
index 9a58da05ea..99d53f236d 100644
--- a/usr/src/man/man3utempter/utempter_add_record.3utempter
+++ b/usr/src/man/man3utempter/utempter_add_record.3utempter
@@ -23,7 +23,7 @@
.\" SUCH DAMAGE.
.\"
.\"
-.Dd May 5, 2020
+.Dd February 5, 2022
.Dt UTEMPTER_ADD_RECORD 3UTEMPTER
.Os
.Sh NAME
@@ -67,7 +67,7 @@ and
.Fn addToUtmp
functions add a login record to the
.Xr utmpx 5
-database for the TTY belonging to the pseudo-terminal master file descriptor
+database for the TTY belonging to the pseudo-terminal manager file descriptor
.Fa fd ,
using the username corresponding with the real user ID of the calling
process and the optional hostname
@@ -83,7 +83,7 @@ The
and
.Fn removeLineFromUtmp
functions mark the login session as being closed for the TTY belonging
-to the pseudo-terminal master file descriptor
+to the pseudo-terminal manager file descriptor
.Fa fd .
.Pp
The
diff --git a/usr/src/man/man4/Makefile b/usr/src/man/man4/Makefile
index 3c54b0910a..ae3db792b6 100644
--- a/usr/src/man/man4/Makefile
+++ b/usr/src/man/man4/Makefile
@@ -18,7 +18,6 @@ include $(SRC)/Makefile.master
MANSECT= 4
-
MANFILES= FSS.4 \
Intro.4 \
cpr.4 \
diff --git a/usr/src/man/man4d/Makefile b/usr/src/man/man4d/Makefile
index 0089ad0b4b..408beed188 100644
--- a/usr/src/man/man4d/Makefile
+++ b/usr/src/man/man4d/Makefile
@@ -105,7 +105,6 @@ _MANFILES= aac.4d \
poll.4d \
profile.4d \
ptm.4d \
- pts.4d \
pty.4d \
qlc.4d \
ramdisk.4d \
@@ -256,6 +255,7 @@ _MANLINKS= 1394.4d \
firewire.4d \
kmem.4d \
lo0.4d \
+ pts.4d \
ticots.4d \
ticotsord.4d \
urandom.4d \
@@ -279,6 +279,8 @@ firewire.4d := LINKSRC = ieee1394.4d
lo0.4d := LINKSRC = ipnet.4d
+pts.4d := LINKSRC = ptm.4d
+
allkmem.4d := LINKSRC = mem.4d
kmem.4d := LINKSRC = mem.4d
diff --git a/usr/src/man/man4d/amdzen.4d b/usr/src/man/man4d/amdzen.4d
index 68eb37faf2..7d17a6a9d4 100644
--- a/usr/src/man/man4d/amdzen.4d
+++ b/usr/src/man/man4d/amdzen.4d
@@ -9,7 +9,7 @@
.\" http://www.illumos.org/license/CDDL.
.\"
.\"
-.\" Copyright 2020 Oxide Computer Company
+.\" Copyright 2021 Oxide Computer Company
.\"
.Dd September 26, 2020
.Dt AMDZEN 4D
@@ -37,7 +37,7 @@ AMD Zen+ Colfax, Picasso, and Pinnacle Ridge
AMD Zen 2 Castle Peak, Matisse, Rome, and Renoir
.Pq Family 17h
.It
-AMD Zen 3 Milan and Vermeer
+AMD Zen 3 Cezanne, Milan, and Vermeer
.Pq Family 19h
.El
.Pp
diff --git a/usr/src/man/man4d/ptm.4d b/usr/src/man/man4d/ptm.4d
index 9d5965169a..ab30487267 100644
--- a/usr/src/man/man4d/ptm.4d
+++ b/usr/src/man/man4d/ptm.4d
@@ -4,92 +4,255 @@
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH PTM 4D "Feb 5, 1997"
-.SH NAME
-ptm \- STREAMS pseudo-tty master driver
-.SH DESCRIPTION
-.sp
-.LP
-The pseudo-tty subsystem simulates a terminal connection, where the master side
-represents the terminal and the slave represents the user process's special
-device end point. In order to use the pseudo-tty subsystem, a node for the
-master side driver \fB/dev/ptmx\fR and \fBN\fR number of nodes for the slave
-driver must be installed. See \fBpts\fR(4D). The master device is set up as a
-cloned device where its major device number is the major for the clone device
-and its minor device number is the major for the \fBptm\fR driver. There are no
-nodes in the file system for master devices. The master pseudo driver is opened
-using the \fBopen\fR(2) system call with \fB/dev/ptmx\fR as the device
-parameter. The clone open finds the next available minor device for the
-\fBptm\fR major device.
-.sp
-.LP
-A master device is available only if it and its corresponding slave device are
-not already open. When the master device is opened, the corresponding slave
-device is automatically locked out. Only one open is allowed on a master
-device. Multiple opens are allowed on the slave device. After both the master
-and slave have been opened, the user has two file descriptors which are the end
-points of a full duplex connection composed of two streams which are
-automatically connected at the master and slave drivers. The user may then push
-modules onto either side of the stream pair.
-.sp
-.LP
-The master and slave drivers pass all messages to their adjacent queues. Only
-the \fBM_FLUSH\fR needs some processing. Because the read queue of one side is
-connected to the write queue of the other, the \fBFLUSHR\fR flag is changed to
-the \fBFLUSHW\fR flag and vice versa. When the master device is closed an
-\fBM_HANGUP\fR message is sent to the slave device which will render the device
-unusable. The process on the slave side gets the errno \fBEIO\fR when
-attempting to write on that stream but it will be able to read any data
-remaining on the stream head read queue. When all the data has been read,
-\fBread()\fR returns 0 indicating that the stream can no longer be used. On the
-last close of the slave device, a 0-length message is sent to the master
-device. When the application on the master side issues a \fBread()\fR or
-\fBgetmsg()\fR and 0 is returned, the user of the master device decides whether
-to issue a \fBclose()\fR that dismantles the pseudo-terminal subsystem. If the
-master device is not closed, the pseudo-tty subsystem will be available to
-another user to open the slave device.
-.sp
-.LP
-If \fBO_NONBLOCK\fR or \fBO_NDELAY\fR is set, read on the master side returns
-\(mi1 with errno set to \fBEAGAIN\fR if no data is available, and write returns
-\(mi1 with errno set to \fBEAGAIN\fR if there is internal flow control.
-.SH IOCTLS
-.sp
-.LP
-The master driver supports the \fBISPTM\fR and \fBUNLKPT\fR ioctls that are
-used by the functions \fBgrantpt\fR(3C), \fBunlockpt\fR(3C) and
-\fBptsname\fR(3C). The ioctl \fBISPTM\fR determines whether the file descriptor
-is that of an open master device. On success, it returns the 0. The ioctl
-\fBUNLKPT\fR unlocks the master and slave devices. It returns 0 on success. On
-failure, the errno is set to \fBEINVAL\fR indicating that the master device is
-not open.
-.SH FILES
-.sp
-.ne 2
-.na
-\fB\fB/dev/ptmx\fR\fR
-.ad
-.RS 14n
-master clone device
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB/dev/pts/M\fR\fR
-.ad
-.RS 14n
-slave devices (M = 0 -> N-1)
-.RE
-
-.SH SEE ALSO
-.sp
-.LP
-.BR grantpt (3C),
-.BR ptsname (3C),
-.BR unlockpt (3C),
-.BR pts (4D),
-.BR pckt (4M)
-.sp
-.LP
-\fISTREAMS Programming Guide\fR
+.\" Copyright 2022 Oxide Computer Company
+.Dd February 5, 2022
+.Dt PTM 4D
+.Os
+.Sh NAME
+.Nm ptm ,
+.Nm pts
+.Nd STREAMS pseudo-terminal manager and subsidiary drivers
+.Sh SYNOPSIS
+.Pa /dev/ptmx
+.Pp
+.Pa /dev/pts/*
+.Sh DESCRIPTION
+The pseudo-terminal subsystem simulates a terminal connection, where the
+manager side represents the terminal and the subsidiary represents the user
+process's special device end point.
+The manager device is set up as a cloned device where its major device number
+is the major for the clone device and its minor device number is the major for
+the
+.Nm ptm
+driver; see
+.Dv CLONE_DEV
+in
+.Xr ddi_create_minor_node 9F .
+.Pp
+There are no nodes in the file system for manager devices.
+The manager pseudo driver is opened using the
+.Xr open 2
+system call with
+.Pa /dev/ptmx
+as the device parameter.
+The clone open finds the next available minor device for the
+.Nm ptm
+major device.
+.Pp
+A manager device is only available if it and its corresponding subsidiary
+device are not already open.
+Only one open is allowed on a manager device.
+Multiple opens are allowed on the subsidiary device.
+.Pp
+When the manager device is opened, the corresponding subsidiary device is
+automatically locked out.
+No user may open the subsidiary device until its permissions are adjusted and
+the device is unlocked by calling the functions
+.Xr grantpt 3C
+and
+.Xr unlockpt 3C .
+The user can then invoke the
+.Xr open 2
+system call with the device name returned by the
+.Xr ptsname 3C
+function.
+.Pp
+After both the manager and subsidiary have been opened, the user has two file
+descriptors which are the end points of a full duplex connection composed of
+two streams which are automatically connected at the manager and subsidiary
+drivers.
+The user may then push modules onto either side of the stream pair.
+Unless compiled in XPG4v2 mode
+.Po
+see
+.Sx "XPG4v2 MODE"
+.Pc ,
+the consumer needs to push the
+.Xr ptem 4M
+and
+.Xr ldterm 4M
+modules onto the subsidiary device to get terminal semantics.
+.Pp
+The manager and subsidiary drivers pass all messages to their adjacent queues.
+Only the
+.Dv M_FLUSH
+needs some processing.
+Because the read queue of one side is connected to the write queue of the
+other, the
+.Dv FLUSHR
+flag is changed to the
+.Dv FLUSHW
+flag and vice versa.
+.Pp
+When the manager device is closed, an
+.Dv M_HANGUP
+message is sent to the subsidiary device which will render the device unusable.
+The process on the subsidiary side gets an
+.Er EIO
+error when attempting to write on that stream, but it will be able to read
+any data remaining on the stream head read queue.
+When all the data has been read,
+.Xr read 2
+returns
+.Sy 0
+indicating that the stream can no longer be used.
+.Pp
+On the last close of the subsidiary device, a 0-length message is sent to the
+manager device.
+When the application on the manager side issues a
+.Xr read 2
+or
+.Xr getmsg 2
+and
+.Sy 0
+is returned, the user of the manager device decides whether to issue a
+.Xr close 2
+that dismantles the entire pseudo-terminal.
+If the manager device is not closed, the pseudo-terminal will be available to
+another user to open the subsidiary device.
+.Pp
+Since 0-length messages are used to indicate that the process on the
+subsidiary side has closed, and should be interpreted that way by the process
+on the manager side, applications on the subsidiary side should not write
+0-length messages.
+Unless the application is compiled in XPG4v2 mode
+.Po
+see
+.Sx "XPG4v2 MODE"
+.Pc ,
+then any 0-length messages written to the subsidiary device will be discarded
+by the
+.Xr ptem 4M
+module.
+.Pp
+If
+.Dv O_NONBLOCK
+or
+.Dv O_NDELAY
+is set on the manager side:
+.Bl -bullet
+.It
+Read on the manager side returns
+.Sy -1
+with
+.Va errno
+set to
+.Er EAGAIN
+if no data is available
+.It
+Write returns
+.Sy -1
+with
+.Va errno
+set to
+.Er EAGAIN
+if there is internal flow control
+.El
+.Pp
+Standard STREAMS system calls can access pseudo-terminal devices.
+The subsidiary devices support the
+.Dv O_NDELAY
+and
+.Dv O_NONBLOCK
+flags.
+.Sh XPG4v2 MODE
+.Em XPG4v2
+requires that subsidiary pseudo-terminal devices provide the process with an
+interface that is identical to the terminal interface, without needing to
+explicitly push any modules to achieve this.
+It also requires that 0-length messages written on the subsidiary device will
+be propagated to the manager device.
+.Pp
+Experience has shown that most software does not expect subsidiary
+pseudo-terminal devices to operate in this manner.
+This XPG4v2-compliant behaviour is only enabled in XPG4v2/SUS
+.Po
+see
+.Xr standards 7
+.Pc
+mode.
+.Sh IOCTLS
+The manager driver provides several ioctls to support the
+.Xr grantpt 3C ,
+.Xr unlockpt 3C ,
+and
+.Xr ptsname 3C
+functions:
+.Bl -tag -width Ds
+.It Dv ISPTM
+Determines whether the file descriptor is that of an open manager device.
+On success, it returns the value
+.Sy 0 .
+.It Dv UNLKPT
+Unlocks the manager and subsidiary devices.
+It returns
+.Sy 0
+on success.
+On failure,
+.Vt errno
+is set to
+.Vt EINVAL
+indicating that the manager device is not open.
+.El
+.Sh FILES
+.Bl -tag -width Pa
+.It Pa /dev/ptmx
+Pseudo-terminal manager clone device.
+.It Pa /dev/pts/N
+Pseudo-terminal subsidiary devices, where
+.Sy N
+is a non-negative integer.
+Located via calls to
+.Xr ptsname 3C .
+.El
+.Sh EXAMPLES
+.Sy Example 1
+Opening the manager and subsidiary device for a pseudo-terminal.
+.Bd -literal -offset Ds
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <fcntl.h>
+#include <err.h>
+\&...
+int fdm, fds;
+char *subsidiaryname;
+\&...
+/*
+ * NOTE: Portable applications should use posix_openpt(3C) here:
+ */
+if ((fdm = open("/dev/ptmx", O_RDWR | O_NOCTTY)) < 0) {
+ err(1, "open manager");
+}
+if (grantpt(fdm) != 0 || unlockpt(fdm) != 0 ||
+ (subsidiaryname = ptsname(fdm)) == NULL) {
+ close(fdm);
+ err(1, "locate subsidiary");
+}
+if ((fds = open(subsidiaryname, O_RDWR | O_NOCTTY)) < 0) {
+ close(fdm);
+ err(1, "open subsidiary");
+}
+if (ioctl(fds, I_PUSH, "ptem") != 0 ||
+ ioctl(fds, I_PUSH, "ldterm") != 0) {
+ close(fds);
+ close(fdm);
+ err(1, "push modules");
+}
+.Ed
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr getmsg 2 ,
+.Xr open 2 ,
+.Xr read 2 ,
+.Xr grantpt 3C ,
+.Xr posix_openpt 3C ,
+.Xr ptsname 3C ,
+.Xr unlockpt 3C ,
+.Xr ldterm 4M ,
+.Xr pckt 4M ,
+.Xr ptem 4M ,
+.Xr standards 7 ,
+.Xr ddi_create_minor_node 9F
diff --git a/usr/src/man/man4d/pts.4d b/usr/src/man/man4d/pts.4d
deleted file mode 100644
index 98f33f5cb7..0000000000
--- a/usr/src/man/man4d/pts.4d
+++ /dev/null
@@ -1,112 +0,0 @@
-'\" te
-.\" Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
-.\" Copyright 1992 Sun Microsystems
-.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
-.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
-.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH PTS 4D "Feb 29, 2020"
-.SH NAME
-pts \- STREAMS pseudo-tty slave driver
-.SH DESCRIPTION
-The pseudo-tty subsystem simulates a terminal connection, where the master side
-represents the terminal and the slave represents the user process's special
-device end point. In order to use the pseudo-tty subsystem, a node for the
-master side driver \fB/dev/ptmx\fR and N nodes for the slave driver (N is
-determined at installation time) must be installed. The names of the slave
-devices are \fB/dev/pts/M\fR where \fBM\fR has the values 0 through N-1. When
-the master device is opened, the corresponding slave device is automatically
-locked out. No user may open that slave device until its permissions are
-adjusted and the device unlocked by calling functions \fBgrantpt\fR(3C) and
-\fBunlockpt\fR(3C). The user can then invoke the open system call with the name
-that is returned by the \fBptsname\fR(3C) function. See the example below.
-.sp
-.LP
-Only one open is allowed on a master device. Multiple opens are allowed on the
-slave device. After both the master and slave have been opened, the user has
-two file descriptors which are end points of a full duplex connection composed
-of two streams automatically connected at the master and slave drivers. The
-user may then push modules onto either side of the stream pair. Unless compiled
-in XPG4v2 mode (see below), the consumer needs to push the \fBptem\fR(4M) and
-\fBldterm\fR(4M) modules onto the slave side of the pseudo-terminal subsystem
-to get terminal semantics.
-.sp
-.LP
-The master and slave drivers pass all messages to their adjacent queues. Only
-the \fBM_FLUSH\fR needs some processing. Because the read queue of one side is
-connected to the write queue of the other, the \fBFLUSHR\fR flag is changed to
-the \fBFLUSHW\fR flag and vice versa. When the master device is closed an
-\fBM_HANGUP\fR message is sent to the slave device which will render the device
-unusable. The process on the slave side gets the errno \fBEIO\fR when
-attempting to write on that stream but it will be able to read any data
-remaining on the stream head read queue. When all the data has been read, read
-returns 0 indicating that the stream can no longer be used. On the last close
-of the slave device, a 0-length message is sent to the master device. When the
-application on the master side issues a \fBread()\fR or \fBgetmsg()\fR and 0 is
-returned, the user of the master device decides whether to issue a
-\fBclose()\fR that dismantles the pseudo-terminal subsystem. If the master
-device is not closed, the pseudo-tty subsystem will be available to another
-user to open the slave device. Since 0-length messages are used to indicate
-that the process on the slave side has closed and should be interpreted that
-way by the process on the master side, applications on the slave side should
-not write 0-length messages. Unless the application is compiled in XPG4v2 mode
-(see below) then any 0-length messages written on the slave side will be
-discarded by the \fBptem\fR module.
-.sp
-.LP
-The standard STREAMS system calls can access the pseudo-tty devices. The slave
-devices support the \fBO_NDELAY\fR and \fBO_NONBLOCK\fR flags.
-.SH XPG4v2 MODE
-XPG4v2 requires that open of a slave pseudo terminal device provides the
-process with an interface that is identical to the terminal interface (without
-having to explicitly push any modules to achieve this). It also requires that
-0-length messages written on the slave side will be propagated to the master.
-.sp
-Experience has shown, however, that most software does not expect slave pty
-devices to operate in this manner and therefore this XPG4v2-compliant
-behaviour is only enabled in XPG4v2/SUS (see \fBstandards\fR(7)) mode.
-.SH EXAMPLES
-.in +2
-.nf
-int fdm fds;
-char *slavename;
-extern char *ptsname();
-
-fdm = open("/dev/ptmx", O_RDWR); /* open master */
-grantpt(fdm); /* change permission of slave */
-unlockpt(fdm); /* unlock slave */
-slavename = ptsname(fdm); /* get name of slave */
-fds = open(slavename, O_RDWR); /* open slave */
-ioctl(fds, I_PUSH, "ptem"); /* push ptem */
-ioctl(fds, I_PUSH, "ldterm"); /* push ldterm*/
-.fi
-.in -2
-
-.SH FILES
-.ne 2
-.na
-\fB\fB/dev/ptmx\fR\fR
-.ad
-.RS 14n
-master clone device
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB/dev/pts/M\fR\fR
-.ad
-.RS 14n
-slave devices (M = 0 -> N-1)
-.RE
-
-.SH SEE ALSO
-.BR grantpt (3C),
-.BR ptsname (3C),
-.BR unlockpt (3C),
-.BR ptm (4D),
-.BR ldterm (4M),
-.BR ptem (4M),
-.BR standards (7)
-.sp
-.LP
-\fISTREAMS Programming Guide\fR
diff --git a/usr/src/man/man4d/pty.4d b/usr/src/man/man4d/pty.4d
index 6551acdd7e..0e7cb9ad2f 100644
--- a/usr/src/man/man4d/pty.4d
+++ b/usr/src/man/man4d/pty.4d
@@ -3,244 +3,263 @@
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH PTY 4D "Aug 8, 1994"
-.SH NAME
-pty \- pseudo-terminal driver
-.SH DESCRIPTION
-.sp
-.LP
-The \fBpty\fR driver provides support for a pair of devices collectively known
-as a \fIpseudo-terminal\fR. The two devices comprising a pseudo-terminal are
-known as a \fIcontroller\fR and a \fIslave\fR. The slave device distinguishes
-between the \fBB0\fR baud rate and other baud rates specified in the
-\fBc_cflag\fR word of the \fBtermios\fR structure, and the \fBCLOCAL\fR flag in
-that word. It does not support any of the other \fBtermio\fR(4I) device control
-functions specified by flags in the \fBc_cflag\fR word of the \fBtermios\fR
-structure and by the \fB\fR\fBIGNBRK\fR\fB, \fR \fB\fR\fBIGNPAR\fR\fB, \fR
-\fB\fR\fBPARMRK\fR\fB, \fR or \fBINPCK\fR flags in the \fBc_iflag\fR word of
-the \fBtermios\fR structure, as these functions apply only to asynchronous
-serial ports. All other \fBtermio\fR(4I) functions must be performed by
-\fBSTREAMS\fR modules pushed atop the driver; when a slave device is opened,
-the \fBldterm\fR(4M) and \fBttcompat\fR(4M) \fBSTREAMS\fR modules are
-automatically pushed on top of the stream, providing the standard
-\fBtermio\fR(4I) interface.
-.sp
-.LP
+.\" Copyright 2022 Oxide Computer Company
+.Dd February 5, 2022
+.Dt PTY 4D
+.Os
+.Sh NAME
+.Nm pty
+.Nd legacy pseudo-terminal driver
+.Sh SYNOPSIS
+.Pa /dev/pty[p-r]*
+.Pp
+.Pa /dev/tty[p-r]*
+.Sh DESCRIPTION
+This driver provides support for legacy static pseudo-terminal devices.
+Modern software does not use this driver, preferring instead the STREAMS-based
+.Xr ptm 4D
+and
+.Xr pts 4D
+pseudo-terminal drivers, consumed through the portable
+.Xr posix_openpt 3C
+interface.
+.Pp
+The
+.Nm pty
+driver provides support for a pair of devices collectively known
+as a
+.Em pseudo-terminal .
+The two devices comprising a pseudo-terminal are known as a
+.Em manager
+and a
+.Em subsidiary .
+The subsidiary device distinguishes between the
+.Dv B0 baud rate and other baud rates specified in
+the
+.Fa c_cflag
+field of the
+.Vt termios
+structure, and the
+.Dv CLOCAL
+flag in that member.
+It does not support any of the other
+.Xr termio 4I
+device control functions specified by flags in the
+.Fa c_cflag
+field of the
+.Vt termios
+structure and by the
+.Dv IGNBRK ,
+.Dv IGNPAR ,
+.Dv PARMRK ,
+or
+.Dv INPCK
+flags in the
+.Fa c_iflag
+field of the
+.Vt termios
+structure, as these functions apply only to asynchronous serial ports.
+All other
+.Xr termio 4I
+functions must be performed by STREAMS modules pushed atop the driver; when a
+subsidiary device is opened, the
+.Xr ldterm 4M
+and
+.Xr ttcompat 4M
+STREAMS modules are automatically pushed on top of the stream, providing the
+standard
+.Xr termio 4I
+interface.
+.Pp
Instead of having a hardware interface and associated hardware that supports
the terminal functions, the functions are implemented by another process
-manipulating the controller device of the pseudo-terminal.
-.sp
-.LP
-The controller and the slave devices of the pseudo-terminal are tightly
-connected. Any data written on the controller device is given to the slave
-device as input, as though it had been received from a hardware interface. Any
-data written on the slave terminal can be read from the controller device
-(rather than being transmitted from a \fBUAR\fR).
-.sp
-.LP
-By default, 48 pseudo-terminal pairs are configured as follows:
-.sp
-.in +2
-.nf
-/dev/pty[p-r][0-9a-f] controller devices
-/dev/tty[p-r][0-9a-f] slave devices
-.fi
-.in -2
-
-.SH IOCTLS
-.sp
-.LP
-The standard set of \fBtermio ioctl\fRs are supported by the slave device.
-None of the bits in the \fBc_cflag\fR word have any effect on the
-pseudo-terminal, except that if the baud rate is set to \fBB0\fR, it will
-appear to the process on the controller device as if the last process on the
-slave device had closed the line; thus, setting the baud rate to \fBB0\fR has
-the effect of ``hanging up'' the pseudo-terminal, just as it has the effect of
-``hanging up'' a real terminal.
-.sp
-.LP
-There is no notion of ``parity'' on a pseudo-terminal, so none of the flags in
-the \fBc_iflag\fR word that control the processing of parity errors have any
-effect. Similarly, there is no notion of a ``break'', so none of the flags that
-control the processing of breaks, and none of the \fBioctl\fRs that generate
-breaks, have any effect.
-.sp
-.LP
+manipulating the manager device of the pseudo-terminal.
+.Pp
+The manager and the subsidiary devices of the pseudo-terminal are tightly
+connected.
+Any data written on the manager device is given to the subsidiary device as
+input, as though it had been received from a hardware interface.
+Any data written on the subsidiary terminal can be read from the manager device
+.Pq "rather than being transmitted from a UAR" .
+.Pp
+The driver is statically configured to provide 48 pseudo-terminal pairs.
+Software that requires dynamic pseudo-terminal devices, or a greater number
+of devices, must be converted to use
+.Xr ptm 4D .
+.Sh IOCTLS
+The standard set of
+.Xr termio 4I
+ioctls are supported by the subsidiary device.
+None of the bits in the
+.Fa c_cflag
+field have any effect on the pseudo-terminal, except that if the baud rate is
+set to
+.Dv B0 ,
+it will appear to the process on the manager device as if the last process on
+the subsidiary device had closed the line; thus, setting the baud rate to
+.Dv B0
+has the effect of
+.Dq hanging up
+the pseudo-terminal, just as it has the effect of
+.Dq hanging up
+a real terminal.
+.Pp
+There is no notion of
+.Dq parity
+on a pseudo-terminal, so none of the flags in the
+.Fa c_iflag
+field that control the processing of parity errors have any
+effect.
+Similarly, there is no notion of a
+.Fa break ,
+so none of the flags that control the processing of breaks, and none of the
+ioctls that generate breaks, have any effect.
+.Pp
Input flow control is automatically performed; a process that attempts to write
-to the controller device will be blocked if too much unconsumed data is
-buffered on the slave device. The input flow control provided by the
-\fBIXOFF\fR flag in the \fBc_iflag\fR word is not supported.
-.sp
-.LP
-The delays specified in the \fBc_oflag\fR word are not supported.
-.sp
-.LP
-As there are no modems involved in a pseudo-terminal, the \fBioctl\fRs that
-return or alter the state of modem control lines are silently ignored.
-.sp
-.LP
-A few special \fBioctl\fRs are provided on the controller devices of
-pseudo-terminals to provide the functionality needed by applications programs
-to emulate real hardware interfaces:
-.sp
-.ne 2
-.na
-\fB\fBTIOCSTOP\fR\fR
-.ad
-.RS 14n
-The argument is ignored. Output to the pseudo-terminal is suspended, as if a
-\fBSTOP\fR character had been typed.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBTIOCSTART\fR\fR
-.ad
-.RS 14n
-The argument is ignored. Output to the pseudo-terminal is restarted, as if a
-\fBSTART\fR character had been typed.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBTIOCPKT\fR\fR
-.ad
-.RS 14n
-The argument is a pointer to an \fBint\fR. If the value of the \fBint\fR is
-non-zero, \fIpacket\fR mode is enabled; if the value of the \fBint\fR is zero,
-packet mode is disabled. When a pseudo-terminal is in packet mode, each
-subsequent \fBread\fR(2) from the controller device will return data written on
-the slave device preceded by a zero byte (symbolically defined as
-\fB\fR\fBTIOCPKT_DATA\fR\fB), \fR or a single byte reflecting control status
-information. In the latter case, the byte is an inclusive-or of zero or more
-of the bits:
-.sp
-.ne 2
-.na
-\fB\fBTIOCPKT_FLUSHREAD\fR\fR
-.ad
-.RS 22n
-whenever the read queue for the terminal is flushed.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBTIOCPKT_FLUSHWRITE\fR\fR
-.ad
-.RS 22n
-whenever the write queue for the terminal is flushed.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBTIOCPKT_STOP\fR\fR
-.ad
-.RS 22n
-whenever output to the terminal is stopped using ^S.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBTIOCPKT_START\fR\fR
-.ad
-.RS 22n
-whenever output to the terminal is restarted.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBTIOCPKT_DOSTOP\fR\fR
-.ad
-.RS 22n
-whenever \fBXON/XOFF\fR flow control is enabled after being disabled; it is
-considered ``enabled'' when the \fBIXON\fR flag in the \fBc_iflag\fR word is
-set, the \fBVSTOP\fR member of the \fBc_cc\fR array is ^S and the \fBVSTART\fR
-member of the \fBc_cc\fR array is ^Q.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBTIOCPKT_NOSTOP\fR\fR
-.ad
-.RS 22n
-whenever \fBXON/XOFF\fR flow control is disabled after being enabled.
-.RE
-
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBTIOCREMOTE\fR\fR
-.ad
-.RS 14n
-The argument is a pointer to an \fBint\fR. If the value of the \fBint\fR is
-non-zero, \fIremote\fR mode is enabled; if the value of the \fBint\fR is zero,
-remote mode is disabled. This mode can be enabled or disabled independently of
-packet mode. When a pseudo-terminal is in remote mode, input to the slave
-device of the pseudo-terminal is flow controlled and not input edited
-(regardless of the mode the slave side of the pseudo-terminal). Each write to
-the controller device produces a record boundary for the process reading the
-slave device. In normal usage, a write of data is like the data typed as a
-line on the terminal; a write of 0 bytes is like typing an \fBEOF\fR character.
-Note: this means that a process writing to a pseudo-terminal controller in
-\fIremote\fR mode must keep track of line boundaries, and write only one line
-at a time to the controller. If, for example, it were to buffer up several
-\fBNEWLINE\fR characters and write them to the controller with one
-\fBwrite()\fR, it would appear to a process reading from the slave as if a
-single line containing several \fBNEWLINE\fR characters had been typed (as if,
-for example, a user had typed the \fBLNEXT\fR character before typing all but
-the last of those \fBNEWLINE\fR characters). Remote mode can be used when doing
-remote line editing in a window manager, or whenever flow controlled input is
-required.
-.RE
-
-.SH EXAMPLES
-.sp
-.in +2
-.nf
-#include <fcntl.h>
-#include <sys/termios.h>
-
-int fdm fds;
-fdm = open("/dev/ptyp0, O_RDWR); /* open master */
-fds = open("/dev/ttyp0, O_RDWR); /* open slave */
-.fi
-.in -2
-
-.SH FILES
-.sp
-.ne 2
-.na
-\fB\fB/dev/pty[p-z][0-9a-f]\fR\fR
-.ad
-.RS 25n
-pseudo-terminal controller devices
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB/dev/tty[p-z][0-9a-f]\fR\fR
-.ad
-.RS 25n
-pseudo-terminal slave devices
-.RE
-
-.SH SEE ALSO
-.sp
-.LP
-\fBrlogin\fR(1), \fBrlogind\fR(8), \fBldterm\fR(4M), \fBtermio\fR(4I),
-.BR ttcompat (4M),
-.SH NOTES
-.sp
-.LP
-It is apparently not possible to send an \fBEOT\fR by writing zero bytes in
-\fBTIOCREMOTE\fR mode.
+to the manager device will be blocked if too much unconsumed data is buffered
+on the subsidiary device.
+The input flow control provided by the
+.Dv IXOFF
+flag in the
+.Fa c_iflag
+field is not supported.
+.Pp
+The delays specified in the
+.Fa c_oflag
+field are not supported.
+.Pp
+As there are no modems involved in a pseudo-terminal, the ioctls that return or
+alter the state of modem control lines are silently ignored.
+.Pp
+A few special ioctls are provided on the manager devices of pseudo-terminals to
+provide the functionality needed by applications programs to emulate real
+hardware interfaces:
+.Bl -tag -width Ds
+.It Dv TIOCSTOP
+The argument is ignored.
+Output to the pseudo-terminal is suspended, as if a
+.Sy STOP
+character had been typed.
+.It Dv TIOCSTART
+The argument is ignored.
+Output to the pseudo-terminal is restarted, as if a
+.Sy START
+character had been typed.
+.It Dv TIOCPKT
+The argument is a pointer to an
+.Vt int .
+If the value of the
+.Vt int
+is non-zero,
+.Em packet
+mode is enabled; if the value of the
+.Vt int
+is zero, packet mode is disabled.
+When a pseudo-terminal is in packet mode, each subsequent
+.Xr read 2
+from the manager device will return data written on the subsidiary device
+preceded by a zero byte
+.Po
+symbolically defined as
+.Dv TIOCPKT_DATA
+.Pc ,
+or a single byte reflecting control status information.
+In the latter case, the byte is an inclusive-or of zero or more of the bits:
+.Bl -tag -width Ds
+.It Dv TIOCPKT_FLUSHREAD
+Whenever the read queue for the terminal is flushed.
+.It Dv TIOCPKT_FLUSHWRITE
+Whenever the write queue for the terminal is flushed.
+.It Dv TIOCPKT_STOP
+Whenever output to the terminal is stopped using
+.Sy ^S .
+.It Dv TIOCPKT_START
+Whenever output to the terminal is restarted.
+.It Dv TIOCPKT_DOSTOP
+Whenever
+.Em XON/XOFF
+flow control is enabled after being disabled; it is
+considered
+.Dq enabled
+when the
+.Dv IXON
+flag in the
+.Fa c_iflag
+field is set, the
+.Dv VSTOP
+member of the
+.Fa c_cc
+array is
+.Sy ^S
+and the
+.Dv VSTART
+member of the
+.Fa c_cc
+array is
+.Sy ^Q.
+.It Dv TIOCPKT_NOSTOP
+Whenever
+.Em XON/XOFF
+flow control is disabled after being enabled.
+.El
+.It Dv TIOCREMOTE
+The argument is a pointer to an
+.Vt int .
+If the value of the
+.Vt int
+is non-zero,
+.Em remote
+mode is enabled; if the value of the
+.Vt int
+is zero, remote mode is disabled.
+This mode can be enabled or disabled independently of packet mode.
+When a pseudo-terminal is in remote mode, input to the subsidiary device of the
+pseudo-terminal is flow controlled and not input edited (regardless of the mode
+the subsidiary side of the pseudo-terminal).
+.Pp
+Each write to the manager device produces a record boundary for the process
+reading the subsidiary device.
+In normal usage, a write of data is like the data typed as a line on the
+terminal; a write of 0 bytes is like typing an
+.Sy EOF
+character.
+Note: this means that a process writing to a pseudo-terminal manager in remote
+mode must keep track of line boundaries, and write only one line at a time to
+the manager.
+.Pp
+If, for example, it were to buffer up several newline characters and write them
+to the manager with one
+.Xr write 2 ,
+it would appear to a process reading from the subsidiary as if a single line
+containing several newline characters had been typed
+.Po
+as if, for example, a user had typed the literal next
+.Pq Sy LNEXT
+character before typing all but the last of those newline characters
+.Pc .
+Remote mode can be used when doing remote line editing in a window manager, or
+whenever flow controlled input is required.
+.El
+.Sh FILES
+.Bl -tag -width Pa
+.It Pa /dev/pty[p-r][0-9a-f]
+Pseudo-terminal manager devices.
+.It Pa /dev/tty[p-r][0-9a-f]
+Pseudo-terminal subsidiary devices.
+.El
+.Sh SEE ALSO
+.Xr rlogin 1 ,
+.Xr posix_openpty 3C ,
+.Xr ptm 4D ,
+.Xr termio 4I ,
+.Xr ldterm 4M ,
+.Xr ttcompat 4M ,
+.Xr rlogind 8
+.Sh NOTES
+This is a legacy device and should not be used by new software.
+.Pp
+It is apparently not possible to send an
+.Sy EOT
+by writing zero bytes in
+.Dv TIOCREMOTE
+mode.
diff --git a/usr/src/man/man4d/zcons.4d b/usr/src/man/man4d/zcons.4d
index 463a8afa96..2c55fb08f8 100644
--- a/usr/src/man/man4d/zcons.4d
+++ b/usr/src/man/man4d/zcons.4d
@@ -3,76 +3,62 @@
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH ZCONS 4D "Aug 24, 2003"
-.SH NAME
-zcons \- Zone console device driver
-.SH DESCRIPTION
-.sp
-.LP
-The \fBzcons\fR character driver exports the console for system zones. The
-driver is comprised of two "sides:" a master side with which applications in
-the global zone communicate, and a slave side, which receives I/O from the
-master side. The slave side is available in the global zones.
-.sp
-.LP
-Applications must not depend on the location of \fB/dev\fR or \fB/devices\fR
-entries exported by \fBzcons\fR. Inside a zone, the \fBzcons\fR slave side is
-fronted by \fB/dev/console\fR and other console-related symbolic links, which
-are used by applications that expect to write to the system console.
-.sp
-.LP
-The \fBzcons\fR driver is Sun Private, and may change in future releases.
-.SH FILES
-.sp
-.ne 2
-.na
-\fB\fB/dev/zcons/<\fIzonename\fR>/masterconsole\fR \fR
-.ad
-.sp .6
-.RS 4n
-Global zone master side console for zone <\fIzonename\fR>.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB/dev/zcons/<\fIzonename\fR>/slaveconsole\fR \fR
-.ad
-.sp .6
-.RS 4n
-Global zone slave side console for zone <\fIzonename\fR>.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB/dev/zconsole\fR \fR
-.ad
-.sp .6
-.RS 4n
-Non-global zone console (slave side).
-.RE
-
-.SH ATTRIBUTES
-.sp
-.LP
-See \fBattributes\fR(7) for descriptions of the following attributes:
-.sp
-
-.sp
-.TS
-box;
-c | c
-l | l .
-ATTRIBUTE TYPE ATTRIBUTE VALUE
-_
- Interface Stability Sun Private
-.TE
-
-.SH SEE ALSO
-.sp
-.LP
-.BR attributes (7),
-.BR zones (7),
-.BR zoneadm (8),
-.BR zonecfg (8)
+.\" Copyright 2022 Oxide Computer Company
+.Dd February 5, 2022
+.Dt ZCONS 4D
+.Os
+.Sh NAME
+.Nm zcons
+.Nd Zone console device driver
+.Sh DESCRIPTION
+The
+.Nm zcons
+character driver exports the console for system zones.
+The driver is fundamentally similar to a pseudo-terminal device, and is thus
+comprised of two sides:
+.Bl -bullet
+.It
+a manager device, which applications in the global zone can open for
+communication
+.It
+a subsidiary device, which processes in the non-global zone can write to, to
+communicate with global zone management applications
+.El
+.Pp
+Applications must not depend on the location of
+.Pa /dev
+or
+.Pa /devices
+entries exposed by
+.Nm zcons
+in the global zone.
+Inside a non-global zone, the
+.Nm zcons
+subsidiary device is fronted by
+.Pa /dev/console
+and other console-related symbolic links, which are used by applications that
+expect to write to the system console.
+.Pp
+The
+.Nm
+driver is not a
+.Sy Committed
+interface, and may change at any time.
+.Sh FILES
+.Bl -tag -width Pa
+.It Pa /dev/zcons/ZONENAME/globalconsole
+Global zone console manager device for zone
+.Sy ZONENAME .
+.It Pa /dev/zcons/ZONENAME/zoneconsole
+Global zone console subsidiary device for zone
+.Sy ZONENAME .
+.It Pa /dev/zconsole
+Non-global zone console (subsidiary device).
+.El
+.Sh INTERFACE STABILITY
+.Sy Uncommitted
+.Sh SEE ALSO
+.Xr attributes 7 ,
+.Xr zones 7 ,
+.Xr zoneadm 8 ,
+.Xr zonecfg 8
diff --git a/usr/src/man/man4m/pckt.4m b/usr/src/man/man4m/pckt.4m
index 25646321ee..2805b857af 100644
--- a/usr/src/man/man4m/pckt.4m
+++ b/usr/src/man/man4m/pckt.4m
@@ -3,21 +3,18 @@
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH PCKT 4M "Jul 3, 1990"
+.TH PCKT 4M "Feb 5, 2022"
.SH NAME
pckt \- STREAMS Packet Mode module
.SH SYNOPSIS
-.LP
.nf
int ioctl(\fI fd, \fRI_PUSH, "pckt");
.fi
.SH DESCRIPTION
-.sp
-.LP
\fBpckt\fR is a STREAMS module that may be used with a pseudo terminal to
packetize certain messages. The \fBpckt\fR module should be pushed (see
-\fBI_PUSH\fR on \fBstreamio\fR(4I)) onto the master side of a pseudo terminal.
+\fBI_PUSH\fR on \fBstreamio\fR(4I)) onto the manager side of a pseudo terminal.
.sp
.LP
Packetizing is performed by prefixing a message with an \fBM_PROTO\fR message.
@@ -31,21 +28,19 @@ On the read-side, only the \fBM_PROTO\fR, \fBM_PCPROTO\fR, \fBM_STOP\fR,
types are passed upstream unmodified.
.sp
.LP
-Since all unread state information is held in the master's stream head read
+Since all unread state information is held in the manager's stream head read
queue, flushing of this queue is disabled.
.sp
.LP
On the write-side, all messages are sent down unmodified.
.sp
.LP
-With this module in place, all reads from the master side of the pseudo
+With this module in place, all reads from the manager side of the pseudo
terminal should be performed with the \fBgetmsg\fR(2) or \fBgetpmsg\fR()
function. The control part of the message contains the message type. The data
part contains the actual data associated with that message type. The onus is on
the application to separate the data into its component parts.
.SH SEE ALSO
-.sp
-.LP
.BR getmsg (2),
.BR ioctl (2),
.BR streamio (4I),
diff --git a/usr/src/man/man4m/ptem.4m b/usr/src/man/man4m/ptem.4m
index 625cedecdc..da1b07971c 100644
--- a/usr/src/man/man4m/ptem.4m
+++ b/usr/src/man/man4m/ptem.4m
@@ -4,69 +4,127 @@
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH PTEM 4M "Jul 3, 1990"
-.SH NAME
-ptem \- STREAMS Pseudo Terminal Emulation module
-.SH SYNOPSIS
-.LP
-.nf
-\fBint ioctl(\fR\fIfd\fR, \fBI_PUSH\fR,\fB "ptem");\fR
-.fi
-
-.SH DESCRIPTION
-.sp
-.LP
-\fBptem\fR is a STREAMS module that, when used in conjunction with a line
-discipline and pseudo terminal driver, emulates a terminal.
-.sp
-.LP
-The \fBptem\fR module must be pushed (see \fBI_PUSH\fR, \fBstreamio\fR(4I))
-onto the slave side of a pseudo terminal STREAM, before the \fBldterm\fR(4M)
+.\" Copyright 2022 Oxide Computer Company
+.Dd February 5, 2022
+.Dt PTEM 4M
+.Os
+.Sh NAME
+.Nm ptem
+.Nd STREAMS Pseudo-Terminal Emulation module
+.Sh SYNOPSIS
+.In unistd.h
+.In stropts.h
+.Ft int
+.Fo ioctl
+.Fa "int fildes" ,
+.Dv I_PUSH ,
+.Qq ptem
+.Fc
+.Sh DESCRIPTION
+.Nm ptem
+is a STREAMS module that emulates a terminal device when used in conjunction
+with the line discipline,
+.Xr ldterm 4M ,
+and the pseudo terminal driver,
+.Xr ptm 4D .
+.Pp
+The
+.Nm ptem
+module must be pushed
+.Po
+see
+.Dv I_PUSH
+in
+.Xr streamio 4I
+.Pc
+onto the subsidiary device of a pseudo-terminal STREAM, before the
+.Xr ldterm 4M
module is pushed.
-.sp
-.LP
-On the write-side, the \fBTCSETA\fR, \fBTCSETAF\fR, \fBTCSETAW\fR,
-\fBTCGETA\fR, \fBTCSETS\fR, \fBTCSETSW\fR, \fBTCSETSF\fR, \fBTCGETS\fR,
-\fBTCSBRK\fR, \fBJWINSIZE\fR, \fBTIOCGWINSZ\fR, and \fBTIOCSWINSZ\fR
-\fBtermio\fR \fBioctl\fR(2) messages are processed and acknowledged. If remote
-mode is not in effect, \fBptem\fR handles the \fBTIOCSTI\fR ioctl by copying
-the argument bytes into an \fBM_DATA\fR message and passing it back up the
-read side. Regardless of the remote mode setting, \fBptem\fR acknowledges the
-ioctl and passes a copy of it downstream for possible further processing. A
-hang up (that is, \fBstty 0\fR) is converted to a zero length \fBM_DATA\fR
-message and passed downstream. Termio \fBcflags\fR and window row and column
-information are stored locally one per stream. \fBM_DELAY\fR messages are
-discarded. All other messages are passed downstream unmodified.
-.sp
-.LP
-On the read-side all messages are passed upstream unmodified with the following
-exceptions. All \fBM_READ\fR and \fBM_DELAY\fR messages are freed in both
-directions. A \fBTCSBRK\fR ioctl is converted to an \fBM_BREAK\fR message and
-passed upstream and an acknowledgement is returned downstream. A
-\fBTIOCSIGNAL\fR ioctl is converted into an \fBM_PCSIG\fR message, and passed
-upstream and an acknowledgement is returned downstream. Finally a
-\fBTIOCREMOTE\fR ioctl is converted into an \fBM_CTL\fR message, acknowledged,
-and passed upstream; the resulting mode is retained for use in subsequent
-\fBTIOCSTI\fR parsing.
-.SH FILES
-.sp
-.ne 2
-.na
-\fB<\fBsys/ptem.h\fR> \fR
-.ad
-.RS 17n
-
-.RE
-
-.SH SEE ALSO
-.sp
-.LP
-.BR stty (1),
-.BR ioctl (2),
-.BR streamio (4I),
-.BR termio (4I),
-.BR ldterm (4M),
-.BR pckt (4M)
-.sp
-.LP
-\fISTREAMS Programming Guide\fR
+.Ss Write-side Behaviour
+The
+.Dv TCSETA ,
+.Dv TCSETAF ,
+.Dv TCSETAW ,
+.Dv TCGETA ,
+.Dv TCSETS ,
+.Dv TCSETSW ,
+.Dv TCSETSF ,
+.Dv TCGETS ,
+.Dv TCSBRK ,
+.Dv JWINSIZE ,
+.Dv TIOCGWINSZ ,
+and
+.Dv TIOCSWINSZ
+.Xr termio 4I
+.Xr ioctl 2
+messages are processed and acknowledged.
+.Pp
+If
+.Em remote mode
+is not in effect,
+.Nm ptem
+handles the
+.Dv TIOCSTI
+ioctl by copying the argument bytes into an
+.Dv M_DATA
+message and passing it back up the read side.
+Regardless of the
+.Em remote mode
+setting,
+.Nm ptem
+acknowledges the ioctl and passes a copy of it downstream for possible further
+processing.
+.Pp
+A hang up
+.Po
+e.g.,
+.Ic stty 0
+.Pc
+is converted to a zero length
+.Dv M_DATA
+message and passed downstream.
+.Xr termio 4I
+.Sy cflags
+and window row and column information are stored locally, one per stream.
+.Dv M_DELAY
+messages are discarded.
+.Pp
+All other messages are passed downstream unmodified.
+.Ss Read-side Behaviour
+All messages are passed upstream unmodified with the following exceptions:
+.Bl -bullet
+.It
+All
+.Dv M_READ
+and
+.Dv M_DELAY
+messages are freed in both directions.
+.It
+A
+.Dv TCSBRK
+ioctl is converted to an
+.Dv M_BREAK
+message and passed upstream and an acknowledgement is returned downstream.
+.It
+A
+.Dv TIOCSIGNAL
+ioctl is converted into an
+.Dv M_PCSIG
+message, passed upstream, and an acknowledgement is returned downstream.
+.It
+A
+.Dv TIOCREMOTE
+ioctl is converted into an
+.Dv M_CTL
+message, acknowledged, and passed upstream; the resulting mode is retained for
+use in subsequent
+.Dv TIOCSTI
+parsing.
+.El
+.Sh SEE ALSO
+.Xr stty 1 ,
+.Xr ioctl 2 ,
+.Xr streamio 4I ,
+.Xr termio 4I ,
+.Xr ldterm 4M ,
+.Xr pckt 4M
diff --git a/usr/src/man/man4p/Makefile b/usr/src/man/man4p/Makefile
index 41a21f6999..1395a9834b 100644
--- a/usr/src/man/man4p/Makefile
+++ b/usr/src/man/man4p/Makefile
@@ -39,7 +39,8 @@ MANFILES= arp.4p \
sip.4p \
slp.4p \
tcp.4p \
- udp.4p
+ udp.4p \
+ vxlan.4p
MANLINKS= AH.4p \
ARP.4p \
@@ -51,6 +52,7 @@ MANLINKS= AH.4p \
SCTP.4p \
TCP.4p \
UDP.4p \
+ VXLAN.4p \
if.4p
ARP.4p := LINKSRC = arp.4p
@@ -75,6 +77,8 @@ TCP.4p := LINKSRC = tcp.4p
UDP.4p := LINKSRC = udp.4p
+VXLAN.4p := LINKSRC = vxlan.4p
+
.KEEP_STATE:
include $(SRC)/man/Makefile.man
diff --git a/usr/src/man/man4p/vxlan.4p b/usr/src/man/man4p/vxlan.4p
new file mode 100644
index 0000000000..dbace910b4
--- /dev/null
+++ b/usr/src/man/man4p/vxlan.4p
@@ -0,0 +1,130 @@
+.\"
+.\" This file and its contents are supplied under the terms of the
+.\" Common Development and Distribution License ("CDDL"), version 1.0.
+.\" You may only use this file in accordance with the terms of version
+.\" 1.0 of the CDDL.
+.\"
+.\" A full copy of the text of the CDDL should have accompanied this
+.\" source. A copy of the CDDL is also available via the Internet at
+.\" http://www.illumos.org/license/CDDL.
+.\"
+.\"
+.\" Copyright 2015 Joyent, Inc.
+.\"
+.Dd Apr 10, 2015
+.Dt VXLAN 4P
+.Os
+.Sh NAME
+.Nm VXLAN ,
+.Nm vxlan
+.Nd Virtual eXtensible Local Area Network
+.Sh SYNOPSIS
+.In sys/vxlan.h
+.Sh DESCRIPTION
+.Nm
+(RFC 7348) is a network encapsulation protocol that is used by
+.Xr overlay 7
+devices.
+A payload, commonly an Ethernet frame, is placed inside of a
+UDP packet and prepended with an 8-byte
+.Nm
+header.
+.Pp
+The
+.Nm
+header contains two 32-bit words.
+The first word is an 8-bit flags field followed by 24 reserved bits.
+The second word is a 24-bit virtual network identifier followed by 8
+reserved bits.
+The virtual network identifier identifies a unique
+.Nm
+and
+is similar in concept to an IEEE 802.1Q VLAN identifier.
+.Pp
+The system provides access to
+.Nm
+through dladm overlays.
+See
+.Xr dladm 8
+and
+.Xr overlay 7
+for more information.
+.Pp
+The
+.In sys/vxlan.h
+header provides information for working with the
+.Nm
+protocol.
+The contents of this header are
+.Sy uncommitted .
+The header defines a structure that may be used to encode and decode a VXLAN
+header.
+It defines a packed structure type
+.Sy vxlan_hdr_t
+which represents the
+.Nm
+frame header and has the following members:
+.Bd -literal
+ uint32_t vxlan_flags; /* flags in upper 8 bits */
+ uint32_t vxlan_id; /* VXLAN ID in upper 24 bits */
+.Ed
+.Sh EXAMPLES
+.Sy Example 1
+Decoding a
+.Nm
+header
+.Pp
+The following example shows how to validate a
+.Nm header.
+For more information on this process, see RFC 7348.
+.Bd -literal -offset indent
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+#include <sys/vxlan.h>
+
+\&...
+
+/*
+ * Validate the following bytes as a VXLAN header. If valid, return
+ * 0 and store the VXLAN identifier in *vidp. Otherwise, return an
+ * error.
+ */
+int
+validate_vxlan(void *buf, int len, uint32_t *vidp)
+{
+ vxlan_hdr_t *hdr;
+
+ if (len < sizeof (vxlan_hdr_t))
+ return (EINAVL);
+
+ hdr = buf;
+ if ((ntohl(hdr->vxlan_flags) & VXLAN_MAGIC) == 0)
+ return (EINAVL);
+
+ *vidp = ntohl(vxlan->vxlan_id) >> VXLAN_ID_SHIFT;
+
+ return (0);
+}
+.Ed
+.Sh STABILITY
+The contents of
+.In sys/vxlan.h
+are
+.Sy Uncommitted .
+.Sh SEE ALSO
+.Xr overlay 7 ,
+.Xr dladm 8
+.Rs
+.%A Mahalingam, M.
+.%A Dutt, D.
+.%A Duda, K.
+.%A Agarwal, P.
+.%A Kreeger L.
+.%A Sridhar, T.
+.%A Bursell, M.
+.%A C. Wright
+.%T RFC 7348, Virtual eXtensible Local Area Network (VXLAN): A Framework
+.%T for Overlaying Virtualized Layer 2 Networks over Layer 3 Networks
+.%D August 2014
+.Re
diff --git a/usr/src/man/man5/Makefile b/usr/src/man/man5/Makefile
index dd15e6b060..d7718eedec 100644
--- a/usr/src/man/man5/Makefile
+++ b/usr/src/man/man5/Makefile
@@ -133,6 +133,7 @@ _MANFILES= Intro.5 \
nsmbrc.5 \
nss.5 \
nsswitch.conf.5 \
+ overlay_files.5 \
packingrules.5 \
pam.conf.5 \
passwd.5 \
diff --git a/usr/src/man/man5/bhyve_config.5 b/usr/src/man/man5/bhyve_config.5
index d56053679d..7a50507a20 100644
--- a/usr/src/man/man5/bhyve_config.5
+++ b/usr/src/man/man5/bhyve_config.5
@@ -25,7 +25,7 @@
.\"
.\" Portions Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
.\"
-.Dd September 10, 2021
+.Dd September 25, 2021
.Dt BHYVE_CONFIG 5
.Os
.Sh NAME
@@ -126,6 +126,8 @@ Wire guest memory.
Generate ACPI tables.
.It Va destroy_on_poweroff Ta bool Ta false Ta
Destroy the VM on guest-initiated power-off.
+.It Va gdb.address Ta string Ta localhost Ta
+Hostname, IP address, or IPv6 address for the debug server.
.It Va gdb.port Ta integer Ta 0 Ta
TCP port number for the debug server.
If this is set to a non-zero value, a debug server
diff --git a/usr/src/man/man5/overlay_files.5 b/usr/src/man/man5/overlay_files.5
new file mode 100644
index 0000000000..a676e59f57
--- /dev/null
+++ b/usr/src/man/man5/overlay_files.5
@@ -0,0 +1,187 @@
+.\"
+.\" This file and its contents are supplied under the terms of the
+.\" Common Development and Distribution License ("CDDL"), version 1.0.
+.\" You may only use this file in accordance with the terms of version
+.\" 1.0 of the CDDL.
+.\"
+.\" A full copy of the text of the CDDL should have accompanied this
+.\" source. A copy of the CDDL is also available via the Internet at
+.\" http://www.illumos.org/license/CDDL.
+.\"
+.\"
+.\" Copyright 2015, Joyent, Inc.
+.\"
+.Dd Apr 13, 2015
+.Dt OVERLAY_FILES 5
+.Os
+.Sh NAME
+.Nm overlay_files
+.Nd Overlay files plugin file format
+.Sh DESCRIPTION
+The
+.Sy files
+plugin provides a means for a dynamic overlay where the destinations are
+determined based on a static description contained in a
+.Sy JSON
+file.
+This manual describes the format of the file used by the
+.Sy files/config
+property.
+To create and manage overlays with the
+.Sy files
+plugin, use
+.Xr dladm 8 .
+For more information on overlays, see
+.Xr overlay 7 .
+.Pp
+Using the
+.Sy files
+module, a static and simple overlay network can be created.
+This network does not support the use of
+.Em broadcast
+or
+.Em multicast
+traffic.
+Both ARP and NDP traffic are proxied by the plugin itself.
+In addition, the plugin allows for DHCP.
+Instead of providing a traditional DHCP proxy, when an initial DHCP broadcast
+goes out to a broadcast address, it will get rewritten to target a specific MAC
+address.
+The
+.Sy files
+plugin is useful as proof of concept and for simple static networks
+where addresses do not need to be reconfigured.
+If more advanced topologies or more streamlined updates are required, consider
+a different plugin.
+.Pp
+The file format is encoded as a series of
+.Sy JSON
+objects.
+Each object has a key, which is a MAC address on the
+.Sy overlay
+network.
+It has multiple values, some required, some optional, which describe various
+properties.
+The valid properties are:
+.Bl -hang -width Ds
+.It Sy ip
+.Bd -filled -compact
+The
+.Sy ip
+key indicates the IP address on the
+.Sy underlay
+network that houses the MAC address in question.
+Packets directed for the MAC address will be encapsulated and set to this
+address.
+This field is required.
+.Pp
+The value is a
+.Em JSON String .
+Both IPv4 and IPv6 addresses are supported and should be written out in their
+traditional forms.
+Follow the guidelines for writing addresses in
+.Xr inet_aton 3SOCKET .
+.Ed
+.It Sy port
+.Bd -filled -compact
+The
+.Sy port
+key indicates the port on the
+.Sy underlay
+network that houses the MAC address in question.
+This property is required if the encapsulation module requires a port for its
+destination.
+The value is a
+.Em JSON Number .
+.Ed
+.It Sy arp
+.Bd -filled -compact
+The
+.Sy arp
+key stores the IPv4 address that corresponds to this MAC address on the
+.Sy overlay
+network.
+This will be used to respond to ARP queries that would traditionally have been
+received by the OS kernel.
+If this address is not present, no IPv4 packets directed to this IP address will
+be received by the network interface that has this MAC address, regardless of
+what is configured on top of it.
+.Pp
+The value is a
+.Em JSON String
+and should be written out following the guidelines for IPv4 addresses in
+.Xr inet_aton 3SOCKET .
+.Ed
+.It Sy ndp
+.Bd -filled -compact
+The
+.Sy ndp
+key stores the IPv6 address that corresponds to this MAC address on the
+.Sy overlay
+network.
+This will be used to respond to NDP queries that would traditionally have been
+received by the OS kernel.
+If this address is not present, no IPv6 packets directed to this IP address will
+be received by the network interface that has this MAC address, regardless of
+what is configured on top of it.
+.Pp
+The value is a
+.Em JSON String
+and should be written out following the guidelines for IPv6 addresses in
+.Xr inet_aton 3SOCKET .
+.Ed
+.It Sy dhcp-proxy
+.Bd -filled -compact
+The
+.Sy dhcp-proxy
+key stores a MAC address that DHCP messages directed to a broadcast address get
+rewritten to be sent to.
+This can be viewed as a form of proxy DHCP, but is different in mechanism from a
+traditional proxy.
+The value is a
+.Em JSON String
+and should be written as a traditional MAC address string as described by
+.Xr ether_aton 3SOCKET .
+.Ed
+.El
+.Sh EXAMPLES
+.Sy Example 1
+Sample configuration file
+.Pp
+This configuration file provides information for three different MAC
+addresses.
+Each MAC address has an entry which describes what its IPv4
+and IPv6 address is, as well as the IP address and port of the host on
+the underlay network.
+Finally, one host has a DHCP proxy entry to demonstrate how one might
+configure DHCP.
+.Bd -literal -offset indent
+{
+ "de:ad:be:ef:00:00": {
+ "arp": "10.55.55.2",
+ "ip": "10.88.88.69",
+ "ndp": "fe80::3",
+ "port": 4789
+ },
+ "de:ad:be:ef:00:01": {
+ "arp": "10.55.55.3",
+ "dhcp-proxy": "de:ad:be:ef:00:00",
+ "ip": "10.88.88.70",
+ "ndp": "fe80::4",
+ "port": 4789
+ },
+ "de:ad:be:ef:00:02": {
+ "arp": "10.55.55.4",
+ "ip": "10.88.88.71",
+ "ndp": "fe80::5",
+ "port": 4789
+ }
+}
+.Ed
+.Sh STABILITY
+This file format is
+.Sy committed ;
+however, keys that are not listed here are reserved for future use.
+.Sh SEE ALSO
+.Xr overlay 7 ,
+.Xr dladm 8
diff --git a/usr/src/man/man7/Makefile b/usr/src/man/man7/Makefile
index 71eef3626f..2527fc1008 100644
--- a/usr/src/man/man7/Makefile
+++ b/usr/src/man/man7/Makefile
@@ -83,6 +83,7 @@ _MANFILES= Intro.7 \
ms.7 \
mutex.7 \
nfssec.7 \
+ overlay.7 \
pam_allow.7 \
pam_authtok_check.7 \
pam_authtok_get.7 \
diff --git a/usr/src/man/man7/overlay.7 b/usr/src/man/man7/overlay.7
new file mode 100644
index 0000000000..e9be5b95cf
--- /dev/null
+++ b/usr/src/man/man7/overlay.7
@@ -0,0 +1,521 @@
+.\"
+.\" This file and its contents are supplied under the terms of the
+.\" Common Development and Distribution License ("CDDL"), version 1.0.
+.\" You may only use this file in accordance with the terms of version
+.\" 1.0 of the CDDL.
+.\"
+.\" A full copy of the text of the CDDL should have accompanied this
+.\" source. A copy of the CDDL is also available via the Internet at
+.\" http://www.illumos.org/license/CDDL.
+.\"
+.\"
+.\" Copyright 2015 Joyent, Inc.
+.\"
+.Dd Apr 09, 2015
+.Dt OVERLAY 7
+.Os
+.Sh NAME
+.Nm overlay
+.Nd Overlay Devices
+.Sh DESCRIPTION
+Overlay devices are a GLDv3 device that allows users to create overlay
+networks that can be used to form the basis of network virtualization
+and software defined networking.
+Overlay networks allow a single physical network, often called an
+.Sy underlay
+network, to provide the means for creating multiple logical, isolated,
+and discrete layer two and layer three networks on top of it.
+.Pp
+Overlay devices are administered through
+.Xr dladm 8 .
+Overlay devices themselves cannot be plumbed up with
+.Sy IP ,
+.Sy vnd ,
+or any other protocol.
+Instead, like an
+.Sy etherstub ,
+they allow for VNICs to be created on top of them.
+Like an
+.Sy etherstub ,
+an overlay device acts as a local switch; however, when it encounters a
+non-local destination address, it instead looks up where it should send
+the packet, encapsulates it, and sends it out another interface in the
+system.
+.Pp
+A single overlay device encapsulates the logic to answer two different,
+but related, questions:
+.Pp
+.Bl -enum -offset indent -compact
+.It
+How should a packet be transformed and put on the wire?
+.It
+Where should a transformed packet be sent?
+.El
+.Pp
+Each of these questions is answered by a plugin.
+The first question is answered by what's called an
+.Em encapsulation plugin .
+The second question is answered by what's called a
+.Em search plugin .
+Packets are encapsulated and decapsulated using the encapsulation plugin
+by the kernel.
+The search plugins are all user land plugins that are consumed by the
+varpd service whose FMRI is
+.Em svc:/network/varpd:default .
+This separation allows for the kernel to be responsible for the data
+path, while having the search plugins in userland allows the system to
+provide a much more expressive interface.
+.Ss Overlay Types
+Overlay devices come in two different flavors, one where all packets are
+always sent to a single address, the other, where the destination of a
+packet varies based on the target MAC address of the packet.
+This information is maintained in a
+.Em target table ,
+which is independent and unique to each overlay device.
+We call the plugins that send traffic to a single location, for example
+a single unicast or multicast IP address, a
+.Sy point to point
+overlay and the overlay devices that can send traffic to different
+locations based on the MAC address of that packet a
+.Sy dynamic
+overlay.
+The plugin type is determined based on the type of the
+.Sy search plugin .
+These are all fully listed in the section
+.Sx Plugins and their Properties .
+.Ss Overlay Destination
+Both encapsulation and search plugins define the kinds of destinations
+that they know how to support.
+An encapsulation plugin always has a single destination type that's
+determined based on how the encapsulation is defined.
+A search plugin, on the other hand, can support multiple combinations of
+destinations.
+A search plugin must support the destination type of the encapsulation
+device.
+The destination may require any of the following three pieces of
+information, depending on the encapsulation plugin:
+.Bl -hang -width Ds
+.It Sy MAC Address
+.Bd -filled -compact
+An Ethernet MAC address is required to determine the destination.
+.Ed
+.It Sy IP Address
+.Bd -filled -compact
+An IP address is required.
+Both IPv4 and IPv6 addresses are supported.
+.Ed
+.It Sy Port
+.Bd -filled -compact
+An IP protocol level (TCP, UDP, SCTP, etc.) port is required.
+.Ed
+.El
+.Pp
+The list of destination types that are supported by both the search and
+encapsulation plugins is listed in the section
+.Sx Plugins and their Properties .
+.Ss varpd
+The varpd service, mentioned above, is responsible for providing the
+virtual ARP daemon.
+Its responsibility is conceptually similar to ARP.
+It runs all instances of search plugins in the system and is responsible
+for answering the kernel's ARP-like questions for where packets should
+be sent.
+.Pp
+The varpd service, svc:/network/varpd:default, must be enabled for
+overlay devices to function.
+If it is disabled while there are active devices, then most overlay
+devices will not function correctly and likely will end up dropping
+traffic.
+.Sh PLUGINS AND PROPERTIES
+Properties fall into three categories in the system:
+.Bl -enum -offset indent -compact
+.It
+Generic properties all overlay devices have
+.It
+Properties specific to the encapsulation plugin
+.It
+Properties specific to the search plugin
+.El
+.Pp
+Each property in the system has the following attributes, which mirror
+the traditional
+.Xr dladm 8
+link properties:
+.Bl -hang -width Ds
+.It Sy Name
+.Bd -filled -compact
+The name of a property is namespaced by its module and always structured
+and referred to as as module/property.
+This allows for both an encapsulation and search plugin to have a
+property with the same name.
+Properties that are valid for all overlay devices and not specific to a
+module do not generally use a module prefix.
+.Pp
+For example, the property
+.Sy vxlan/listen_ip
+is associated with the
+.Sy vxlan
+encapsulation module.
+.Ed
+.It Sy Type
+.Bd -filled -compact
+Each property in the system has a type.
+.Xr dladm 8
+takes care of converting between the internal representation and a
+value, but the type influences the acceptable input range.
+The types are:
+.Bl -hang -width Ds
+.It Sy INT
+A signed integer that is up to eight bytes long
+.Pq Sy int64_t .
+.It Sy UINT
+An unsigned integer that is up to eight bytes long
+.Pq Sy uint64_t .
+.It Sy IP
+Either an IPv4 or IPv6 address in traditional string form.
+For example, 192.168.128.23 or 2001:470:8af4::1:1.
+IPv4 addresses may also be encoded as IPv4-mapped IPv6 addresses.
+.It Sy STRING
+A string of ASCII or UTF-8 encoded characters terminated with a
+.Sy NUL
+byte.
+The maximum string length, including the terminator, is currently
+256 bytes.
+.El
+.Ed
+.It Sy Permissions
+.Bd -filled -compact
+Each property has permissions associated with it, which indicate whether
+the system considers them read-only properties or read-write properties.
+A read-only property can never be updated once the device is created.
+This generally includes things like the overlay's encapsulation module.
+.Ed
+.It Sy Required
+.Bd -filled -compact
+This property indicates whether the property is required for the given
+plugin.
+If it is not specified during a call to
+.Sy dladm create-overlay ,
+then the overlay cannot be successfully created.
+Properties which have a
+.Sy default
+will use that value if one is not specified rather than cause the
+overlay creation to fail.
+.Ed
+.It Sy Current Value
+.Bd -filled -compact
+The current value of a property, if the property has a value set.
+Required properties always have a value set.
+.Ed
+.It Sy Default Value
+.Bd -filled -compact
+The default value is an optional part of a given property.
+If a property does define a default value, then it will be used when an
+overlay is created and no other value is given.
+.Ed
+.It Sy Value ranges
+.Bd -filled -compact
+Value ranges are an optional part of a given property.
+They indicate a range or set of values that are valid and may be set for
+a property.
+A property may not declare such a range as it may be impractical or
+unknown.
+For example, most properties based on IP addresses will not
+declare a range.
+.Ed
+.El
+.Pp
+The following sections describe both the modules and the properties that
+exist for each module, noting their name, type, permissions, whether or
+not they are required, and if there is a default value.
+In addition, the effects of each property will be described.
+.Ss Encapsulation Plugins
+.Bl -hang -width Ds
+.It Sy vxlan
+The
+.Sy vxlan
+module is a UDP based encapsulation method.
+It takes a frame that would be put on the wire, wraps it up in a VXLAN
+header and places it in a UDP packet that gets sent out on the
+underlying network.
+For more details about the specific format of the VXLAN header, see
+.Xr vxlan 4P .
+.Pp
+The
+.Sy vxlan
+module requires both an
+.Sy IP address
+and
+.Sy port
+to address it.
+It has a 24-bit virtual network ID space, allowing for
+virtual network identifiers that range from
+.Sy 0
+-
+.Sy 16777215 .
+.Pp
+The
+.Sy vxlan
+module has the following properties:
+.Bl -hang -width Ds
+.It Sy vxlan/listen_ip
+.Bd -filled -compact
+Type:
+.Sy IP |
+Permissions:
+.Sy Read/Write |
+.Sy Required
+.Ed
+.Bd -filled
+The
+.Sy vxlan/listen_ip
+property determines the IP address that the system will accept VXLAN
+encapsulated packets on for this overlay.
+.Ed
+.It Sy vxlan/listen_port
+.Bd -filled -compact
+Type:
+.Sy UINT |
+Permissions:
+.Sy Read/Write |
+.Sy Required
+.Ed
+.Bd -filled -compact
+Default Value:
+.Sy 4789 |
+Range:
+.Sy 0 - 65535
+.Ed
+.Bd -filled
+The
+.Sy vxlan/listen_port
+property determines the UDP port that the system will listen on for
+VXLAN traffic for this overlay.
+The default value is
+.Sy 4789 ,
+the IANA assigned port for VXLAN.
+.Ed
+.El
+.Pp
+The
+.Sy vxlan/listen_ip
+and
+.Sy vxlan/listen_port
+properties determine how the system will accept VXLAN encapsulated
+packets for this interface.
+It does not determine the interface that packets will be sent out over.
+Multiple overlays that all use VXLAN can share the same IP and port
+combination, as the virtual network identifier can be used to tell the
+different overlays apart.
+.El
+.Ss Search Plugins
+Because search plugins may support multiple destinations, they may have
+more properties listed than necessarily show up for a given overlay.
+For example, the
+.Sy direct
+plugin supports destinations that are identified by both an IP address
+and a port, or just an IP address.
+In cases where the device is created over an overlay that only uses an
+IP address for its destination, then it will not have the
+.Sy direct/dest_port
+property.
+.Bl -hang -width Ds
+.It Sy direct
+The
+.Sy direct
+plugin is a point to point module that can be used to create an overlay
+that forwards all non-local traffic to a single destination.
+It supports destinations that are a combination of an
+.Sy IP Address
+and a
+.Sy port .
+.Pp
+The
+.Sy direct
+plugin has the following properties:
+.Bl -hang -width Ds
+.It Sy direct/dest_ip
+.Bd -filled -compact
+Type:
+.Sy IP |
+Permissions:
+.Sy Read/Write |
+.Sy Required
+.Ed
+.Bd -filled
+The
+.Sy direct/dest_ip
+property indicates the IP address that all traffic will be sent out.
+Traffic will be sent out the corresponding interface based on
+traditional IP routing rules and the configuration of the networking
+stack of the global zone.
+.Ed
+.It Sy direct/dest_port
+.Bd -filled -compact
+Type:
+.Sy UINT |
+Permissions:
+.Sy Read/Write |
+.Sy Required
+.Ed
+.Bd -filled -compact
+Default Value:
+.Sy - |
+Range:
+.Sy 0 - 65535
+.Ed
+.Bd -filled
+The
+.Sy direct/dest_port
+property indicates the TCP or UDP port that all traffic will be directed
+to.
+.Ed
+.El
+.It Sy files
+The
+.Sy files
+plugin implements a
+.Sy dynamic
+plugin that specifies where traffic should be sent based on a file.
+It is a glorified version of /etc/ethers.
+The
+.Sy dynamic
+plugin does not support broadcast or multicast traffic, but it has
+support for proxy ARP, NDP, and DHCPv4.
+For the full details of the file format, see
+.Xr overlay_files 4 .
+.Pp
+The
+.Sy files
+plugin has the following property:
+.Bl -hang -width Ds
+.It Sy files/config
+.Bd -filled -compact
+Type:
+.Sy String |
+Permissions:
+.Sy Read/Write |
+.Sy Required
+.Ed
+.Bd -filled
+The
+.Sy files/config
+property specifies an absolute path to a file to read.
+The file is a JSON file that is formatted according to
+.Xr overlay_files 5 .
+.Ed
+.El
+.El
+.Ss General Properties
+Each overlay has the following properties which are used to give
+additional information about the system.
+None of these properties may be specified as part of a
+.Sy dladm create-overlay ,
+instead they come from other arguments or from internal parts of the
+system.
+.Bl -hang -width Ds
+.It Sy encap
+.Bd -filled -compact
+.Sy String |
+Permissions:
+.Sy Read Only
+.Ed
+.Bd -filled
+The
+.Sy encap
+property contains the name of the encapsulation module that's in use.
+.Ed
+.It Sy mtu
+.Bd -filled -compact
+.Sy UINT |
+Permissions:
+.Sy Read/Write
+.Ed
+.Bd -filled -compact
+Default Value:
+.Sy 1400 |
+Range:
+.Sy 576 - 9000
+.Ed
+.Bd -filled
+The
+.Sy mtu
+property describes the maximum transmission unit of the overlay.
+The default value is
+.Sy 1400
+bytes, which ensures that in a traditional deployment with an MTU of
+1500 bytes, the overhead that is added from encapsulation is all
+accounted for.
+It is the administrator's responsibility to ensure that
+the device's MTU and the encapsulation overhead does not exceed that of
+the interfaces that the encapsulated traffic will be sent out of.
+.Pp
+To modify the
+.Sy mtu
+property, use
+.Sy dladm set-linkprop .
+.Ed
+.It Sy search
+.Bd -filled -compact
+.Sy String |
+Permissions:
+.Sy Read Only
+.Ed
+.Bd -filled
+The
+.Sy search
+property contains the name of the search plugin that's in use.
+.Ed
+.It Sy varpd/id
+.Bd -filled -compact
+.Sy String |
+Permissions:
+.Sy Read Only
+.Ed
+.Bd -filled
+The
+.Sy varpd/id
+property indicates the identifier which the
+.Sy varpd
+service uses for this overlay.
+.Ed
+.It Sy vnetid
+.Bd -filled -compact
+.Sy UINT |
+Permissions:
+.Sy Read/Write
+.Ed
+.Bd -filled
+The
+.Sy vnetid
+property has the virtual network identifier that belongs to this overlay.
+The valid range for the virtual network identifier depends on the
+encapsulation engine.
+.Ed
+.El
+.Sh FMA INTEGRATION
+Overlay devices are wired into FMA, the illumos fault management
+architecture, and generates error reports depending on the
+.Sy search
+plugin in use.
+Due to limitations in FMA today, when a single overlay
+enters a degraded state, meaning that it cannot properly perform look
+ups or another error occurred, then it degrades the overall
+.Sy overlay
+pseudo-device driver.
+.Pp
+For more fine-grained information about which overlay is actually in a
+.Em degraded
+state, one should run
+.Sy dladm show-overlay -f .
+In addition, for each overlay in a degraded state a more useful
+diagnostic message is provided which describes the reason that caused
+this overlay to enter into a degraded state.
+.Pp
+The overlay driver is self-healing.
+If the problem corrects itself on its own, it will clear the fault on
+the corresponding device.
+.Sh SEE ALSO
+.Xr overlay_files 5 ,
+.Xr vxlan 7P ,
+.Xr dladm 8
diff --git a/usr/src/man/man8/bhyve.8 b/usr/src/man/man8/bhyve.8
index 0f32b57cd8..e3be137fe5 100644
--- a/usr/src/man/man8/bhyve.8
+++ b/usr/src/man/man8/bhyve.8
@@ -24,7 +24,7 @@
.\"
.\" Portions Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
.\"
-.Dd September 10, 2021
+.Dd November 18, 2021
.Dt BHYVE 8
.Os
.Sh NAME
@@ -60,14 +60,14 @@
.Oo \&, Ns Ar key Ns = Ns Ar value Ns Oc \&...
.Oc
.Sm on
-.Op Fl k Ar file
+.Op Fl k Ar config_file
.Oo Fl l
.Sm off
.Ar lpcdev Op Cm \&, Ar conf
.Sm on
.Oc
-.Oo Fl m
.Sm off
+.Oo Fl m\~
.Ar memsize
.Oo
.Cm K | k | M | m | G | g | T | t
@@ -191,7 +191,7 @@ Yield the virtual CPU thread when a HLT instruction is detected.
If this option is not specified, virtual CPUs will use 100% of a host CPU.
.It Fl h
Print help message and exit.
-.It Fl k Ar file
+.It Fl k Ar config_file
Set configuration variables from a simple, key-value config file.
Each line of the config file is expected to consist of a config variable
name, an equals sign
@@ -202,6 +202,9 @@ value.
Blank lines and lines starting with
.Sq #
are ignored.
+See
+.Xr bhyve_config 5
+for more details.
.It Fl l Cm help
Print a list of supported LPC devices.
.It Fl l Ar lpcdev Ns Op \&, Ns Ar conf
@@ -474,10 +477,15 @@ Use the host TTY device for serial port I/O.
.Pp
.Sy Boot ROM device backends :
.Bl -tag -width 10n
-.It Pa romfile
+.It Pa romfile Ns Op Cm \&, Ns Ar varfile
Map
.Ar romfile
in the guest address space reserved for boot firmware.
+If
+.Ar varfile
+is provided, that file is also mapped in the boot firmware guest
+address space, and any modifications the guest makes will be saved
+to that file.
.El
.Pp
.Sy Pass-through device backends :
@@ -804,6 +812,20 @@ bhyve -c 2 -m 4G -w -H \e
-l bootrom,/usr/share/bhyve/firmware/BHYVE_UEFI.fd \e
uefivm
.Ed
+.Pp
+Run a UEFI virtual machine with a VARS file to save EFI variables.
+Note that
+.Nm
+will write guest modifications to the given VARS file.
+Be sure to create a per-guest copy of the template VARS file from
+.Pa /usr/share/bhyve/firmware .
+.Bd -literal -offset indent
+bhyve -c 2 -m 4g -w -H \e
+ -s 0,hostbridge \e
+ -s 31,lpc -p com1,stdio \e
+ -l bootrom,/usr/share/bhyve/firmware/BHYVE_UEFI.fd,BHYVE_UEFI_VARS.fd \e
+ uefivm
+.Ed
.Sh SEE ALSO
.Xr bhyve_config 5 ,
.Xr bhyvectl 8
diff --git a/usr/src/man/man8/dladm.8 b/usr/src/man/man8/dladm.8
index ea432b28fc..f7ac9ab8d6 100644
--- a/usr/src/man/man8/dladm.8
+++ b/usr/src/man/man8/dladm.8
@@ -178,6 +178,14 @@ dladm \- administer data links
.LP
.nf
+\fBdladm create-overlay\fR [\fB-t\fR] \fB-e\fR \fIencap\fR \fB-s\fR \fIsearch\fR \fB-v\fR \fIvnetid\fR [\fB-p\fR \fIprop\fR=\fIvalue\fR[,...]] \fIoverlay\fR
+\fBdladm delete-overlay\fR \fIoverlay\fR
+\fBdladm modify-overlay\fR \fB-d\fR \fImac\fR | \fB-f\fR | \fB-s\fR \fImac=ip:port\fR \fIoverlay\fR
+\fBdladm show-overlay\fR [ \fB-f\fR | \fB-t\fR ] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]] [\fIoverlay\fR]
+.fi
+
+.LP
+.nf
\fBdladm show-usage\fR [\fB-a\fR] \fB-f\fR \fIfilename\fR [\fB-p\fR \fIplotfile\fR \fB-F\fR \fIformat\fR] [\fB-s\fR \fItime\fR]
[\fB-e\fR \fItime\fR] [\fIlink\fR]
.fi
@@ -264,9 +272,9 @@ A WiFi datalink.
.ad
.sp .6
.RS 4n
-A virtual network interface created on a link or an \fBetherstub\fR. It is a
-pseudo device that can be treated as if it were an network interface card on a
-machine.
+A virtual network interface created on a link, an \fBetherstub\fR, or \fBan
+overlay\fR. It is a pseudo device that can be treated as if it were an network
+interface card on a machine.
.RE
.sp
@@ -334,6 +342,20 @@ use any alphanumeric characters, as well as underscore (\fB_\fR), period
characters.
.RE
+.sp
+.ne 2
+.na
+.B overlay
+.ad
+.sp .6
+.RS 4n
+An overlay instance, identified by an administratively-chosen name. An overlay
+can be used to create or join an existing software defined network.
+VNICs created on an overlay will appear to be connected by a local virtual
+switch and will also be connected to interfaces on matching overlays provided by
+other hosts. For more information on overlay devices, see \fBoverlay\fR(5).
+.RE
+
.SS "Options"
Each \fBdladm\fR subcommand has its own set of options. However, many of the
subcommands have the following as a common option:
@@ -4370,6 +4392,348 @@ The tunnel destination address.
.sp
.ne 2
.na
+\fBdladm create-overlay\fR \fB-e\fR \fIencap\fR \fB-s\fR \fIsearch\fR
+\fB-v\fR \fIvnetid\fR [\fB-p\fR \fIprop\fR=\fIvalue\fR[,...]] \fIoverlay\fR
+.ad
+.sp .6
+.RS 4n
+Create an overlay device named \fIoverlay\fR.
+.sp
+Overlay devices are similar to etherstubs. VNICs can be created on top
+of them. However, unlike an etherstub which is local to the system, an
+overlay device can be configured to communicate to remote hosts,
+providing a means for network virtualization. The way in which it does
+this is described by the encapsulation module and the search plugin. For
+more information on these, see \fBoverlay\fR(5).
+.sp
+An overlay device has a series of required and optional properties. These
+properties vary based upon the search and encapsulation modules and are fully
+specified in \fBoverlay\fR(5). Not every property needs to be specified - some
+have default values which will be used if nothing specific is specified. For
+example, the default port for VXLAN comes from its IANA standard. If a
+required property is missing, the command will fail and inform you of the
+missing properties.
+.sp
+.ne 2
+.na
+\fB\fB-t\fR, \fB--temporary\fR\fR
+.ad
+.sp .6
+.RS 4n
+Specifies that the overlay is temporary. Temporary overlays last until
+the next reboot.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-e\fR \fIencap\fR, \fB--encap\fR=\fIencap\fR
+.ad
+.sp .6
+.RS 4n
+Use \fIencap\fR as the encapsulation plugin for the overlay device
+\fIoverlay\fR. The encapsulation plugin determines how packets are transformed
+before being put on the wire.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-s\fR \fIsearch\fR, \fB--search\fR=\fIsearch\fR
+.ad
+.sp .6
+.RS 4n
+Use \fIsearch\fR as the search plugin for \fIoverlay\fR. The search plugin
+determines how non-local targets are found and where packets are directed to.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-p\fR \fIprop\fR=\fIvalue\fR,..., \fB--prop\fR
+\fIprop\fR=\fIvalue\fR,...\fR
+.ad
+.sp .6
+.RS 4n
+A comma-separated list of properties to set to the specified values.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-v\fR \fIvnetid\fR, \fB--vnetid\fR=\fIvnetid\fR
+.ad
+.sp .6
+.RS 4n
+Sets the virtual networking identifier to \fIvnetid\fR. A virtual network
+identifier determines is similar to a VLAN identifier, in that it identifies a
+unique virtual network. All overlay devices on the system share the same space
+for the virtual network identifier. However, the valid range of identifiers is
+determined by the encapsulation plugin specified by \fB-e\fR.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fBdladm delete-overlay\fR \fIoverlay\fR
+.ad
+.sp .6
+.RS 4n
+Delete the specified overlay. This will fail if there are VNICs on top of the
+device.
+.RE
+
+.sp
+.ne 2
+.na
+\fBdladm modify-overlay\fR \fB-d\fR \fImac\fR | \fB-f\fR | \fB-s\fR \fImac=ip:port\fR \fIoverlay\fR
+.ad
+.sp .6
+.RS 4n
+Modifies the target tables for the specified overlay.
+.sp
+The different options allow for different ways of modifying the target table.
+One of \fB-d\fR, \fB-f\fR, and \fB-s\fR is required. This is not applicable for
+all kinds of overlay devices. For more information, see \fBoverlay\fR(5).
+.sp
+.ne 2
+.na
+\fB-d\fR \fImac\fR, \fB--delete-entry\fR=\fImac\fR
+.ad
+.sp .6
+.RS 4n
+Deletes the entry for \fImac\fR from the target table for \fIoverlay\fR. Note,
+if a lookup is pending or outstanding, this does not cancel it or stop it from
+updating the value.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-f\fR, \fB--flush-table\fR
+.ad
+.sp .6
+.RS 4n
+Flushes all values in the target table for \fIoverlay\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-s\fR \fImac\fR=\fIvalue\fR, \fB--set-entry\fR=\fImac\fR=\fIvalue\fR
+.ad
+.sp .6
+.RS 4n
+Sets the value of \fIoverlay\fR's target table entry for \fImac\fR to the
+specified value. The specified value varies upon the encapsulation plugin. The
+value may be a combination of a MAC address, IP address, and port. Generally,
+this looks like [\fImac\fR,][\fIIP\fR:][\fIport\fR]. If a component is the last
+one, then there is no need for a separator. eg. if just the MAC address or IP
+is needed, it would look like \fImac\fR and \fIIP\fR respectively.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fBdladm show-overlay\fR [ \fB-f\fR | \fB-t\fR ] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]] [\fIoverlay\fR]
+.ad
+.sp .6
+.RS 4n
+Shows overlay configuration (the default), internal target tables (\fB-t\fR), or
+the FMA state (\fB-f\fR), either for all overlays or the specified overlay.
+.sp
+By default (with neither \fB-f\fR or \fB-t\fR specified), the following fields
+will be displayed:
+.sp
+.ne 2
+.na
+\fB\fBLINK\fR\fR
+.ad
+.sp .6
+.RS 4n
+The name of the overlay.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBPROPERTY\fR\fR
+.ad
+.sp .6
+.RS 4n
+The name of the property.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBPERM\fR\fR
+.ad
+.sp .6
+.RS 4n
+The read/write permissions of the property. The value shown is one of \fBr-\fR
+or \fBrw\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBVALUE\fR\fR
+.ad
+.sp .6
+.RS 4n
+The current property value. If the value is not set, it is shown as \fB--\fR.
+If it is unknown, the value is shown as \fB?\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBDEFAULT\fR\fR
+.ad
+.sp .6
+.RS 4n
+The default value of the property. If the property has no default value,
+\fB--\fR is shown.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBPOSSIBLE\fR\fR
+.ad
+.sp .6
+.RS 4n
+A comma-separated list of the values the property can have. If the values span
+a numeric range, \fImin\fR - \fImax\fR might be shown as shorthand. If the
+possible values are unknown or unbounded, \fB--\fR is shown.
+.RE
+
+.sp
+When the \fB-f\fR option is displayed, the following fields will be displayed:
+.sp
+.ne 2
+.na
+\fB\fBLINK\fR\fR
+.ad
+.sp .6
+.RS 4n
+The name of the overlay.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTATUS\fR\fR
+.ad
+.sp .6
+.RS 4n
+Either \fBONLINE\fR or \fBDEGRADED\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBDETAILS\fR\fR
+.ad
+.sp .6
+.RS 4n
+When the \fBoverlay\fR's status is \fBONLINE\fR, then this has the value
+\fB--\fR. Otherwise, when it is \fBDEGRADED\fR, this field provides a more
+detailed explanation as to why it's degraded.
+.RE
+
+.sp
+When the \fB-t\fR option is displayed, the following fields will be displayed:
+.sp
+.ne 2
+.na
+\fB\fBLINK\fR\fR
+.ad
+.sp .6
+.RS 4n
+The name of the overlay.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBTARGET\fR\fR
+.ad
+.sp .6
+.RS 4n
+The target MAC address of a table entry.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBDESTINATION\fR\fR
+.ad
+.sp .6
+.RS 4n
+The address that an encapsulated packet will be sent to when a packet has the
+address specified by \fBTARGET\fR.
+.RE
+
+The \fBshow-overlay\fR command supports the following options:
+
+.sp
+.ne 2
+.na
+\fB-f\fR, \fB--fma\fR
+.ad
+.sp .6
+.RS 4n
+Displays information about an overlay device's FMA state. For more
+information on the target table, see \fBoverlay\fR(5).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIfield\fR[,...], \fB--output\fR=\fIfield\fR\fR
+.ad
+.sp .6
+.RS 4n
+A case-insensitive, comma-separated list of output fields to display. The field
+name must be one of the fields listed above, or the special value \fBall\fR, to
+display all fields. The fields applicable to the \fB-o\fR option are limited to
+those listed under each output mode. For example, if using \fB-L\fR, only the
+fields listed under \fB-L\fR, above, can be used with \fB-o\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-p\fR, \fB--parsable\fR\fR
+.ad
+.sp .6
+.RS 4n
+Display using a stable machine-parsable format. The \fB-o\fR option is
+required with \fB-p\fR. See "Parsable Output Format", below.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-t\fR, \fB--target\fR
+.ad
+.sp .6
+.RS 4n
+Displays information about an overlay device's target table. For more
+information on the target table, see \fBoverlay\fR(5).
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
\fB\fBdladm show-usage\fR [\fB-a\fR] \fB-f\fR \fIfilename\fR [\fB-p\fR
\fIplotfile\fR \fB-F\fR \fIformat\fR] [\fB-s\fR \fItime\fR] [\fB-e\fR
\fItime\fR] [\fIlink\fR]\fR
@@ -5607,6 +5971,7 @@ Interface Stability Committed
.BR dlpi (4P),
.BR attributes (7),
.BR ieee802.3 (7),
+.BR overlay (7),
.BR acctadm (8),
.BR autopush (8),
.BR ifconfig (8),
diff --git a/usr/src/man/man8/flowadm.8 b/usr/src/man/man8/flowadm.8
index 4857740035..420835b7aa 100644
--- a/usr/src/man/man8/flowadm.8
+++ b/usr/src/man/man8/flowadm.8
@@ -4,7 +4,7 @@
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH FLOWADM 8 "February 26, 2020"
+.TH FLOWADM 8 "February 5, 2022"
.SH NAME
flowadm \- administer bandwidth resource control and priority for protocols,
services, containers, and virtual machines
@@ -501,12 +501,12 @@ A comma-separated list of properties to show.
.RE
.SS "Flow Attributes"
-The flow operand that identify a flow in a \fBflowadm\fR command is a
+The flow operand that identifies a flow in a \fBflowadm\fR command is a
comma-separated list of one or more keyword, value pairs from the list below.
.sp
.ne 2
.na
-\fB\fBlocal_ip\fR[\fB/\fR\fIprefix_len\fR]\fR
+\fB\fBlocal_ip\fR=\fIvalue\fR[\fB/\fR\fIprefix_len\fR]\fR
.ad
.sp .6
.RS 4n
@@ -524,7 +524,7 @@ address is \fB/32\fR and for IPv6 is \fB/128\fR.
.sp
.ne 2
.na
-\fB\fBremote_ip\fR[\fB/\fR\fIprefix_len\fR]\fR
+\fB\fBremote_ip\fR=\fIvalue\fR[\fB/\fR\fIprefix_len\fR]\fR
.ad
.sp .6
.RS 4n
@@ -546,7 +546,7 @@ with local_port to identify the service that needs special attention.
.sp
.ne 2
.na
-\fB\fBlocal_port\fR\fR
+\fB\fBlocal_port\fR=\fIport\fR\fR
.ad
.sp .6
.RS 4n
@@ -556,7 +556,7 @@ Identifies a service specified by the local port.
.sp
.ne 2
.na
-\fB\fBremote_port\fR\fR
+\fB\fBremote_port\fR=\fIport\fR\fR
.ad
.sp .6
.RS 4n
@@ -566,7 +566,7 @@ Identifies a service specified by the remote port.
.sp
.ne 2
.na
-\fB\fBdsfield\fR[\fB:\fR\fIdsfield_mask\fR]\fR
+\fB\fBdsfield\fR=\fIvalue\fR[\fB:\fR\fIdsfield_mask\fR]\fR
.ad
.sp .6
.RS 4n
@@ -586,8 +586,8 @@ The following six types of combinations of attributes are supported:
.sp
.in +2
.nf
-local_ip[/\fIprefixlen\fR]=\fIaddress\fR
-remote_ip[/\fIprefixlen\fR]=\fIaddress\fR
+local_ip=\fIaddress\fR[/\fIprefixlen\fR]
+remote_ip=\fIaddress\fR[/\fIprefixlen\fR]
transport={tcp|udp|sctp|icmp|icmpv6}
transport={tcp|udp|sctp},local_port=\fIport\fR
transport={tcp|udp|sctp},remote_port=\fIport\fR
diff --git a/usr/src/man/man8/fmthard.8 b/usr/src/man/man8/fmthard.8
index dcffff8c1d..5bf261a348 100644
--- a/usr/src/man/man8/fmthard.8
+++ b/usr/src/man/man8/fmthard.8
@@ -1,197 +1,227 @@
-'\" te
-.\" Copyright 1989 AT&T Copyright (c) 2002, Sun Microsystems, Inc. All Rights Reserved
-.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
-.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
-.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH FMTHARD 8 "Sep 25, 2008"
-.SH NAME
-fmthard \- populate label on hard disks
-.SH SYNOPSIS
-.SS "SPARC"
-.LP
-.nf
-\fBfmthard\fR \fB-d\fR \fIdata\fR | \fB-n\fR \fIvolume_name\fR | \fB-s\fR \fIdatafile\fR [\fB-i\fR] /dev/rdsk/c?
- [t?] d?s2
-.fi
-
-.SS "x86"
-.LP
-.nf
-\fBfmthard\fR \fB-d\fR \fIdata\fR | \fB-n\fR \fIvolume_name\fR | \fB-s\fR \fIdatafile\fR [\fB-i\fR] /dev/rdsk/c?
- [t?] d?s2
-.fi
-
-.SH DESCRIPTION
-.sp
-.LP
-The \fBfmthard\fR command updates the \fBVTOC\fR (Volume Table of Contents) on
-hard disks and, on x86 systems, adds boot information to the Solaris
-\fBfdisk\fR partition. One or more of the options \fB-s\fR \fIdatafile\fR,
-\fB-d\fR \fIdata\fR, or \fB-n\fR \fIvolume_name\fR must be used to request
-modifications to the disk label. To print disk label contents, see
-\fBprtvtoc\fR(8). The
-\fB/dev/rdsk/c\fR\fI?\fR[\fBt\fR\fI?\fR]\fBd\fR\fI?\fR\fBs2\fR file must be the
-character special file of the device where the new label is to be installed. On
-x86 systems, \fBfdisk\fR(8) must be run on the drive before \fBfmthard\fR.
-.sp
-.LP
-If you are using an x86 system, note that the term ``partition'' in this page
-refers to \fIslices\fR within the x86 \fBfdisk\fR partition on x86 machines. Do
-not confuse the partitions created by \fBfmthard\fR with the partitions created
-by \fBfdisk\fR.
-.SH OPTIONS
-.sp
-.LP
+.\"
+.\" CDDL HEADER START
+.\"
+.\" The contents of this file are subject to the terms of the
+.\" Common Development and Distribution License (the "License").
+.\" You may not use this file except in compliance with the License.
+.\"
+.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+.\" or http://www.opensolaris.org/os/licensing.
+.\" See the License for the specific language governing permissions
+.\" and limitations under the License.
+.\"
+.\" When distributing Covered Code, include this CDDL HEADER in each
+.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+.\" If applicable, add the following below this CDDL HEADER, with the
+.\" fields enclosed by brackets "[]" replaced with your own identifying
+.\" information: Portions Copyright [yyyy] [name of copyright owner]
+.\"
+.\" CDDL HEADER END
+.\"
+.\" Copyright 1989 AT&T
+.\" Copyright (c) 2002, Sun Microsystems, Inc. All Rights Reserved
+.\" Copyright 2022 Toomas Soome <tsoome@me.com>
+.\"
+.Dd January 31, 2022
+.Dt FMTHARD 8
+.Os
+.Sh NAME
+.Nm fmthard
+.Nd populate label on hard disks
+.Sh SYNOPSIS
+.Nm
+.Fl d Ar data | Fl n Ar volume_name | Fl s Ar datafile Op Fl i
+.Sm off
+.Ar /dev/rdsk/c? Oo t? Oc d?s2
+.Sm on
+.Sh DESCRIPTION
+The
+.Nm
+command updates the
+.Sy VTOC
+.Pq Volume Table of Contents
+on hard disks.
+One or more of the options
+.Fl s Ar datafile ,
+.Fl d Ar data ,
+or
+.Fl n Ar volume_name
+must be used to request modifications to the disk label.
+To print disk label contents, see
+.Xr prtvtoc 8 .
+The
+.Sm off
+.Ar /dev/rdsk/c? Oo t? Oc d?s2
+.Sm on
+file must be the character special file of the device where the new label
+is to be installed.
+On x86 systems,
+.Xr fdisk 8
+must be run on the drive before
+.Nm .
+.Pp
+If you are using an x86 system, note that the term
+.Sq partition
+in this page refers to
+.Em slices
+within the x86
+.Sy fdisk
+partition on x86 machines.
+Do not confuse the partitions created by
+.Nm
+with the partitions created by
+.Xr fdisk 8 .
+.Sh OPTIONS
The following options are supported:
-.sp
-.ne 2
-.na
-\fB\fB-d\fR \fIdata\fR\fR
-.ad
-.sp .6
-.RS 4n
-The \fIdata\fR argument of this option is a string representing the information
-for a particular partition in the current VTOC. The string must be of the
-format \fIpart:tag:flag:start:size\fR where \fIpart\fR is the partition number,
-\fItag\fR is the \fBID\fR TAG of the partition, \fIflag\fR is the set of
-permission flags, \fIstart\fR is the starting sector number of the partition,
-and \fIsize\fR is the number of sectors in the partition. See the description
-of the \fIdatafile\fR below for more information on these fields.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-i\fR\fR
-.ad
-.sp .6
-.RS 4n
-This option allows the command to create the desired \fBVTOC\fR table, but
-prints the information to standard output instead of modifying the \fBVTOC\fR
+.Bl -tag -width Ds
+.It Fl d Ar data
+The
+.Ar data
+argument of this option is a string representing the information
+for a particular partition in the current
+.Sy VTOC .
+The string must be of the format
+.Em part:tag:flag:start:size
+where
+.Em part
+is the partition number,
+.Em tag
+is the
+.Sy ID
+TAG of the partition,
+.Em flag
+is the set of permission flags,
+.Em start
+is the starting sector number of the partition, and
+.Em size
+is the number of sectors in the partition.
+See the description of the
+.Ar datafile
+below for more information on these fields.
+.It Fl i
+This option allows the command to create the desired
+.Sy VTOC
+table, but prints the information to standard output instead of modifying the
+.Sy VTOC
on the disk.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-n\fR \fIvolume_name\fR\fR
-.ad
-.sp .6
-.RS 4n
-This option is used to give the disk a \fIvolume_name\fR up to 8 characters
-long.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-s\fR \fIdatafile\fR\fR
-.ad
-.sp .6
-.RS 4n
-This option is used to populate the \fBVTOC\fR according to a \fIdatafile\fR
-created by the user. If the \fIdatafile\fR is \fB\(mi\fR (a hyphen),
-\fBfmthard\fR reads from standard input. The \fIdatafile\fR format is described
-below. This option causes all of the disk partition timestamp fields to be set
+.It Fl n Ar volume_name
+This option is used to give the disk a
+.Ar volume_name
+up to 8 characters long.
+.It Fl s Ar datafile
+This option is used to populate the
+.Sy VTOC
+according to a
+.Ar datafile
+created by the user.
+If the
+.Ar datafile
+is
+.Sy \(mi Pq a hyphen ,
+.Nm
+reads from standard input.
+The
+.Ar datafile
+format is described below.
+This option causes all of the disk partition timestamp fields to be set
to zero.
.sp
-Every \fBVTOC\fR generated by \fBfmthard\fR will also have partition 2, by
-convention, that corresponds to the whole disk. If the input in \fIdatafile\fR
+Every
+.Sy VTOC
+generated by
+.Nm
+will also have partition 2, by convention, that corresponds to the whole disk.
+If the input in
+.Ar datafile
does not specify an entry for partition 2, a default partition 2 entry will be
-created automatically in \fBVTOC\fR with the tag \fBV_BACKUP\fR and size equal
-to the full size of the disk.
-.sp
-The \fIdatafile\fR contains one specification line for each partition, starting
-with partition 0. Each line is delimited by a new-line character (\fB\en\fR).
-If the first character of a line is an asterisk (*), the line is treated as a
-comment. Each line is composed of entries that are position-dependent,
+created automatically in
+.Sy VTOC
+with the tag
+.Sy V_BACKUP
+and size equal to the full size of the disk.
+.sp
+The
+.Ar datafile
+contains one specification line for each partition, starting with partition 0.
+Each line is delimited by a new-line character
+.Pq Sy \en .
+If the first character of a line is an asterisk
+.Pq \&* ,
+the line is treated as a comment.
+Each line is composed of entries that are position-dependent,
separated by white space and having the following format:
.sp
-\fIpartition tag flag starting_sector size_in_sectors\fR
+.Em partition tag flag starting_sector size_in_sectors
.sp
where the entries have the following values:
-.sp
-.ne 2
-.na
-\fB\fIpartition\fR\fR
-.ad
-.sp .6
-.RS 4n
-The partition number. Currently, for Solaris SPARC, a disk can have up to 8
-partitions, \fB0\fR\(mi\fB7\fR. Even though the \fIpartition\fR field has 4
-bits, only 3 bits are currently used. For x86, all 4 bits are used to allow
-slices \fB0\fR\(mi\fB15\fR. Each Solaris \fBfdisk\fR partition can have up to
-16 slices.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fItag\fR\fR
-.ad
-.sp .6
-.RS 4n
-The partition tag: a decimal number. The following are reserved codes: \fB0\fR
-(\fBV_UNASSIGNED\fR), \fB1\fR (\fBV_BOOT\fR), \fB2\fR (\fBV_ROOT\fR), \fB3\fR
-(\fBV_SWAP\fR), \fB4\fR (\fBV_USR\fR), \fB5\fR (\fBV_BACKUP\fR), \fB6\fR
-(\fBV_STAND\fR), \fB7\fR (\fBV_VAR\fR), and \fB8\fR (\fBV_HOME\fR).
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fIflag\fR\fR
-.ad
-.sp .6
-.RS 4n
+.Bl -tag -width Ds
+.It Em partition
+The partition number.
+Currently, for Solaris SPARC, a disk can have up to 8 partitions,
+.Sy 0\(mi7 .
+Even though the
+.Em partition
+field has 4 bits, only 3 bits are currently used.
+For x86, all 4 bits are used to allow slices
+.Sy 0\(mi15 .
+Each Solaris
+.Sy fdisk
+partition can have up to 16 slices.
+.It Em tag
+The partition tag: a decimal number.
+The following are reserved codes:
+.Sy 0 Pq Sy V_UNASSIGNED ,
+.Sy 1 Pq Sy V_BOOT ,
+.Sy 2 Pq Sy V_ROOT ,
+.Sy 3 Pq Sy V_SWAP ,
+.Sy 4 Pq Sy V_USR ,
+.Sy 5 Pq Sy V_BACKUP ,
+.Sy 6 Pq Sy V_STAND ,
+.Sy 7 Pq Sy V_VAR ,
+and
+.Sy 8 Pq Sy V_HOME .
+.It Em flag
The flag allows a partition to be flagged as unmountable or read only, the
-masks being: \fBV_UNMNT 0x01\fR, and \fBV_RONLY 0x10\fR. For mountable
-partitions use \fB0x00\fR.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fIstarting_sector\fR\fR
-.ad
-.sp .6
-.RS 4n
+masks being:
+.Sy V_UNMNT 0x01 ,
+and
+.Sy V_RONLY 0x10 .
+For mountable partitions use
+.Sy 0x00 .
+.It Em starting_sector
The sector number (decimal) on which the partition starts.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fIsize_in_sectors\fR\fR
-.ad
-.sp .6
-.RS 4n
+.It Em size_in_sectors
The number (decimal) of sectors occupied by the partition.
-.RE
-
-You can save the output of a \fBprtvtoc\fR command to a file, edit the file,
-and use it as the \fIdatafile\fR argument to the \fB-s\fR option.
-.RE
-
-.SH SEE ALSO
-.sp
-.LP
-.BR uname (1),
-.BR format (8),
-.BR prtvtoc (8),
-.BR attributes (7)
-.SS "x86 Only"
-.sp
-.LP
-.BR fdisk (8),
-.BR installgrub (8)
-.SH NOTES
-.sp
-.LP
-Special care should be exercised when overwriting an existing \fBVTOC\fR, as
-incorrect entries could result in current data being inaccessible. As a
-precaution, save the old \fBVTOC\fR.
-.sp
-.LP
-For disks under two terabytes, \fBfmthard\fR cannot write a \fBVTOC\fR on an
-unlabeled disk. Use \fBformat\fR(8) for this purpose.
+.El
+.sp
+You can save the output of a
+.Xr prtvtoc 8
+command to a file, edit the file, and use it as the
+.Ar datafile
+argument to the
+.Fl s
+option.
+.El
+.Sh SEE ALSO
+.Xr uname 1 ,
+.Xr attributes 7 ,
+.Xr format 8 ,
+.Xr installboot 8 ,
+.Xr prtvtoc 8
+.Ss "x86 Only"
+.Xr fdisk 8
+.Sh NOTES
+Special care should be exercised when overwriting an existing
+.Sy VTOC ,
+as incorrect entries could result in current data being inaccessible.
+As a precaution, save the old
+.Sy VTOC .
+.sp
+For disks under two terabytes,
+.Nm
+cannot write a
+.Sy VTOC
+on an unlabeled disk.
+Use
+.Xr format 1M
+for this purpose.
diff --git a/usr/src/man/man8/in.rlogind.8 b/usr/src/man/man8/in.rlogind.8
index 43da8e5bec..0c9fb64f98 100644
--- a/usr/src/man/man8/in.rlogind.8
+++ b/usr/src/man/man8/in.rlogind.8
@@ -4,7 +4,7 @@
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH IN.RLOGIND 8 "June 20, 2021"
+.TH IN.RLOGIND 8 "February 5, 2022"
.SH NAME
in.rlogind, rlogind \- remote login server
.SH SYNOPSIS
@@ -82,9 +82,9 @@ client is present in \fB/etc/hosts.equiv\fR. See \fBhosts\fR(5) and
.sp
.LP
Once the source port and address have been checked, \fBin.rlogind\fR allocates
-a pseudo-terminal and manipulates file descriptors so that the slave half of
-the pseudo-terminal becomes the \fBstdin\fR, \fBstdout\fR, and \fBstderr\fR for
-a login process. The login process is an instance of the \fBlogin\fR(1)
+a pseudo-terminal and manipulates file descriptors so that the subsidiary half
+of the pseudo-terminal becomes the \fBstdin\fR, \fBstdout\fR, and \fBstderr\fR
+for a login process. The login process is an instance of the \fBlogin\fR(1)
program, invoked with the \fB-r\fR.
.sp
.LP
@@ -93,7 +93,7 @@ process. See \fBSECURITY\fR below. If automatic authentication fails, it
reprompts the user to login.
.sp
.LP
-The parent of the login process manipulates the master side of the
+The parent of the login process manipulates the manager side of the
pseudo-terminal, operating as an intermediary between the login process and the
client instance of the \fBrlogin\fR program. In normal operation, a packet
protocol is invoked to provide Ctrl-S and Ctrl-Q type facilities and propagate
diff --git a/usr/src/man/man8/in.telnetd.8 b/usr/src/man/man8/in.telnetd.8
index e47c1e6df2..2ca2d2b7d3 100644
--- a/usr/src/man/man8/in.telnetd.8
+++ b/usr/src/man/man8/in.telnetd.8
@@ -4,7 +4,7 @@
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH IN.TELNETD 8 "June 20, 2021"
+.TH IN.TELNETD 8 "February 5, 2022"
.SH NAME
in.telnetd, telnetd \- DARPA TELNET protocol server
.SH SYNOPSIS
@@ -22,10 +22,11 @@ the internet server (see \fBinetd\fR(8)), for requests to connect to the
.sp
.LP
\fBin.telnetd\fR operates by allocating a pseudo-terminal device for a client,
-then creating a login process which has the slave side of the pseudo-terminal
-as its standard input, output, and error. \fBin.telnetd\fR manipulates the
-master side of the pseudo-terminal, implementing the \fBTELNET\fR protocol and
-passing characters between the remote client and the login process.
+then creating a login process which has the subsidiary side of the
+pseudo-terminal as its standard input, output, and error. \fBin.telnetd\fR
+manipulates the manager side of the pseudo-terminal, implementing the
+\fBTELNET\fR protocol and passing characters between the remote client and the
+login process.
.sp
.LP
When a \fBTELNET\fR session starts up, \fBin.telnetd\fR sends \fBTELNET\fR
diff --git a/usr/src/man/man8/nvmeadm.8 b/usr/src/man/man8/nvmeadm.8
index 7d3cb6e332..b025ae7413 100644
--- a/usr/src/man/man8/nvmeadm.8
+++ b/usr/src/man/man8/nvmeadm.8
@@ -9,11 +9,10 @@
.\" http://www.illumos.org/license/CDDL.
.\"
.\"
-.\" Copyright 2016 Nexenta Systems, Inc. All rights reserved.
-.\" Copyright 2019 Western Digital Corporation.
.\" Copyright 2021 Oxide Computer Company
+.\" Copyright 2022 Tintri by DDN, Inc. All rights reserved.
.\"
-.Dd March 24, 2021
+.Dd February 15, 2022
.Dt NVMEADM 8
.Os
.Sh NAME
@@ -65,6 +64,10 @@
.Ar ctl[/ns]
.Nm
.Op Fl dv
+.Cm list-firmware
+.Ar ctl
+.Nm
+.Op Fl dv
.Cm load-firmware
.Ar ctl
.Ar firmware-file
@@ -174,11 +177,10 @@ using the
command, and subsequently activated with the
.Cm activate-firmware
command.
-Slots and their contents can be printed using
-.Cm nvmeadm get-logpage
-to request the
-.Ar firmware
-logpage.
+Slots and their contents can be printed using the
+.Nm
+.Cm list-firmware
+command.
.El
.Sh COMMANDS
.Bl -tag -width ""
@@ -403,6 +405,19 @@ previous
command.
.It Xo
.Nm
+.Cm list-firmware
+.Ar ctl
+.Xc
+List currently active firmware slot, the next active firmware slot, and the
+current contents of all firmware slots of an NVMe controller.
+This is a synonym for the
+.Nm
+.Cm get-logpage
+.Ar ctl
+.Cm firmware
+command.
+.It Xo
+.Nm
.Cm load-firmware
.Ar ctl
.Ar firmware-file
@@ -528,17 +543,15 @@ nvme4: Get Features
.Ed
.It Sy Example 5: Load and activate firmware
.Bd -literal
-# nvmeadm get-logpage nvme3 firmware
+# nvmeadm list-firmware nvme3
nvme3: Firmware Slot Information
Active Firmware Slot: 4
Next Firmware Slot: 4
- Firmware Revision for Slot 1: KNGND110
+ Firmware Revision for Slot 1: KNGND110 (read-only)
Firmware Revision for Slot 2: KNGND110
Firmware Revision for Slot 3: KNGND110
Firmware Revision for Slot 4: KNGND112
Firmware Revision for Slot 5: KNGND110
- Firmware Revision for Slot 6: <Unused>
- Firmware Revision for Slot 7: <Unused>
# nvmeadm -v load-firmware nvme3 KNGND113.bin
1740544 bytes downloaded.
@@ -549,17 +562,15 @@ Firmware committed to slot 5.
# nvmeadm -v activate-firmware nvme3 5
Slot 5 activated: NVM subsystem reset required - power cycle your system.
-# nvmeadm get-logpage nvme3 firmware
+# nvmeadm list-firmware nvme3
nvme3: Firmware Slot Information
Active Firmware Slot: 4
Next Firmware Slot: 5
- Firmware Revision for Slot 1: KNGND110
+ Firmware Revision for Slot 1: KNGND110 (read-only)
Firmware Revision for Slot 2: KNGND110
Firmware Revision for Slot 3: KNGND110
Firmware Revision for Slot 4: KNGND112
Firmware Revision for Slot 5: KNGND113
- Firmware Revision for Slot 6: <Unused>
- Firmware Revision for Slot 7: <Unused>
.Ed
.El
.Sh INTERFACE STABILITY
diff --git a/usr/src/man/man8/pppd.8 b/usr/src/man/man8/pppd.8
index c20ff2ed16..304a98dfe7 100644
--- a/usr/src/man/man8/pppd.8
+++ b/usr/src/man/man8/pppd.8
@@ -3,7 +3,7 @@
.\" Redistribution and use in source and binary forms are permitted provided that the above copyright notice and this paragraph are duplicated in all such forms and that any documentation, advertising materials, and other materials related to such distribution and use acknowledge that the software was developed by Carnegie Mellon University. The name of the University may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\" Portions Copyright (c) 2008, Sun Microsystems, Inc. All Right Reserved.
-.TH PPPD 8 "November 22, 2021"
+.TH PPPD 8 "February 5, 2022"
.SH NAME
pppd \- point to point protocol daemon
.SH SYNOPSIS
@@ -1301,11 +1301,11 @@ proxy ARP entries with \fBpppd\fR, place this option in the
.sp .6
.RS 4n
Normally, \fBpppd\fR requires a terminal device. With this option, \fBpppd\fR
-allocates itself a pseudo-tty master/slave pair and uses the slave as its
+allocates itself a pseudo-terminal pair and uses the subsidiary as its
terminal device. \fBpppd\fR creates a child process to act as a character shunt
-to transfer characters between the pseudo-tty master and its standard input and
-output. Thus, \fBpppd\fR transmits characters on its standard output and
-receives characters on its standard input even if they are not terminal
+to transfer characters between the pseudo-terminal manager and its standard
+input and output. Thus, \fBpppd\fR transmits characters on its standard output
+and receives characters on its standard input even if they are not terminal
devices. This option increases the latency and CPU overhead of transferring
data over the ppp interface as all of the characters sent and received must
flow through the character shunt process. An explicit device name may not be
@@ -1506,12 +1506,12 @@ Ethernet interface.
.sp .6
.RS 4n
Specifies that the command \fIscript\fR, and not a specific terminal device is
-used for serial communication. \fBpppd\fR allocates itself a pseudo-tty
-master/slave pair and uses the slave as its terminal device. \fIscript\fR runs
-in a child process with the pseudo-tty master as its standard input and output.
-An explicit device name may not be given if this option is used. (Note: if the
-\fBrecord\fR option is used in conjunction with the \fBpty\fR option, the child
-process will have pipes on its standard input and output.)
+used for serial communication. \fBpppd\fR allocates itself a pseudo-terminal
+pair and uses the subsidiary as its terminal device. \fIscript\fR runs
+in a child process with the pseudo-terminal manager as its standard input and
+output. An explicit device name may not be given if this option is used.
+(Note: if the \fBrecord\fR option is used in conjunction with the \fBpty\fR
+option, the child process will have pipes on its standard input and output.)
.RE
.sp
@@ -1537,14 +1537,14 @@ dial-back implementations.
.RS 4n
Directs \fBpppd\fR to record all characters sent and received to a file named
\fIfilename\fR. \fIfilename\fR is opened in append mode, using the user's
-user-ID and permissions. Because this option uses a pseudo-tty and a process to
-transfer characters between the pseudo-tty and the real serial device, it
-increases the latency and CPU overhead of transferring data over the PPP
-interface. Characters are stored in a tagged format with timestamps that can be
-displayed in readable form using the \fBpppdump\fR(8) program. This option is
-generally used when debugging the kernel portion of \fBpppd\fR (especially CCP
-compression algorithms) and not for debugging link configuration problems. See
-the \fBdebug\fR option.
+user-ID and permissions. Because this option uses a pseudo-terminal and a
+process to transfer characters between the pseudo-terminal and the real serial
+device, it increases the latency and CPU overhead of transferring data over the
+PPP interface. Characters are stored in a tagged format with timestamps that
+can be displayed in readable form using the \fBpppdump\fR(8) program. This
+option is generally used when debugging the kernel portion of \fBpppd\fR
+(especially CCP compression algorithms) and not for debugging link
+configuration problems. See the \fBdebug\fR option.
.RE
.sp
diff --git a/usr/src/man/man9f/kmem_alloc.9f b/usr/src/man/man9f/kmem_alloc.9f
index f25c670cf5..6a9b6c9eb3 100644
--- a/usr/src/man/man9f/kmem_alloc.9f
+++ b/usr/src/man/man9f/kmem_alloc.9f
@@ -1,5 +1,6 @@
'\" te
.\" Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+.\" Copyright 2022 Joyent, Inc.
.\" Copyright 1989 AT&T
.\" Copyright (c) 2006, Sun Microsystems, Inc., All Rights Reserved
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
@@ -46,8 +47,14 @@ Number of bytes to allocate.
.ad
.RS 8n
Determines whether caller can sleep for memory. Possible flags are
-\fBKM_SLEEP\fR to allow sleeping until memory is available, or \fBKM_NOSLEEP\fR
-to return \fINULL\fR immediately if memory is not available.
+\fBKM_SLEEP\fR to allow sleeping until memory is available, \fBKM_NOSLEEP\fR
+to return \fINULL\fR if memory is not available even after some reclamation
+attempts, and \fBKM_NOSLEEP_LAZY\fR to return \fINULL\fR without reclamation
+attempts. \fBKM_NOSLEEP_LAZY\fR is actually two flags combined:
+(\fBKM_NOSLEEP\fR | \fBKM_NORMALPRI\fR), the latter flag indicating not to
+attempt reclamation before giving up and returning NULL. If any mention of
+\fBKM_NOSLEEP\fR appears in this man page by itself, it applies equally to
+\fBKM_NOSLEEP_LAZY\fR as well.
.RE
.sp
@@ -65,9 +72,12 @@ returns a pointer to the allocated memory. The allocated memory is at least
double-word aligned, so it can hold any C data structure. No greater alignment
can be assumed. \fIflag\fR determines whether the caller can sleep for memory.
\fBKM_SLEEP\fR allocations may sleep but are guaranteed to succeed.
-\fBKM_NOSLEEP\fR allocations are guaranteed not to sleep but may fail (return
-\fINULL\fR) if no memory is currently available. The initial contents of memory
-allocated using \fBkmem_alloc()\fR are random garbage.
+\fBKM_NOSLEEP\fR and \fBKM_NOSLEEP_LAZY\fR allocations are guaranteed not to
+sleep but may fail (return \fINULL\fR) if no memory is currently
+available. \fBKM_NOSLEEP\fR will first attempt to aggressively reclaim memory
+from otherwise unused blocks, while \fBKM_NOSLEEP_LAZY\fR will not attempt any
+reclamation. The initial contents of memory allocated using
+\fBkmem_alloc()\fR are random garbage.
.sp
.LP
The \fBkmem_zalloc()\fR function is like \fBkmem_alloc()\fR but returns
@@ -79,13 +89,14 @@ buffer address and size must exactly match the original allocation. Memory
cannot be returned piecemeal.
.SH RETURN VALUES
If successful, \fBkmem_alloc()\fR and \fBkmem_zalloc()\fR return a pointer to
-the allocated memory. If \fBKM_NOSLEEP\fR is set and memory cannot be allocated
-without sleeping, \fBkmem_alloc()\fR and \fBkmem_zalloc()\fR return \fINULL\fR.
+the allocated memory. If \fBKM_NOSLEEP\fR is set and memory cannot be
+allocated without sleeping, \fBkmem_alloc()\fR and \fBkmem_zalloc()\fR return
+\fINULL\fR.
.SH CONTEXT
The \fBkmem_alloc()\fR and \fBkmem_zalloc()\fR functions can be called from
-interrupt context only if the \fBKM_NOSLEEP\fR flag is set. They can be called
-from user context with any valid \fIflag\fR. The \fBkmem_free()\fR function can
-be called from from user, interrupt, or kernel context.
+interrupt context only if the \fBKM_NOSLEEP\fR flag is set. They can be
+called from user context with any valid \fIflag\fR. The \fBkmem_free()\fR
+function can be called from from user, interrupt, or kernel context.
.SH SEE ALSO
.BR copyout (9F),
.BR freerbuf (9F),
diff --git a/usr/src/man/man9f/kmem_cache_create.9f b/usr/src/man/man9f/kmem_cache_create.9f
index 48ed14716f..c3218b9b36 100644
--- a/usr/src/man/man9f/kmem_cache_create.9f
+++ b/usr/src/man/man9f/kmem_cache_create.9f
@@ -1,5 +1,6 @@
'\" te
.\" Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+.\" Copyright 2022 Joyent, Inc.
.\" Copyright (c) 2002, Sun Microsystems, Inc. All Rights Reserved.
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
@@ -169,7 +170,21 @@ Allow sleeping (blocking) until memory is available.
\fB\fBKM_NOSLEEP\fR\fR
.ad
.RS 15n
-Return NULL immediately if memory is not available.
+Return NULL immediately if memory is not available, but after an aggressive
+reclaiming attempt. Any mention of \fBKM_NOSLEEP\fR without mentioning
+\fBKM_NOSLEEP_LAZY\fR (see below) applies to both values.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBKM_NOSLEEP_LAZY\fR\fR
+.ad
+.RS 15n
+Return NULL immediately if memory is not available, without the aggressive
+reclaiming attempt. This is actually two flags combined:
+(\fBKM_NOSLEEP\fR | \fBKM_NORMALPRI\fR), the latter flag indicating not to
+attempt reclamation before giving up and returning NULL.
.RE
.sp
@@ -350,8 +365,8 @@ object cache.
.LP
\fBkmem_cache_alloc()\fR gets an object from the cache. The object will be in
its constructed state. \fIkmflag\fR has either \fBKM_SLEEP\fR or
-\fBKM_NOSLEEP\fR set, indicating whether it is acceptable to wait for memory if
-none is currently available.
+\fBKM_NOSLEEP\fR set, indicating whether it is acceptable to wait for memory
+if none is currently available.
.sp
.LP
A small pool of reserved memory is available to allow the system to progress
@@ -573,8 +588,8 @@ memory.
.sp
.LP
\fBkmem_cache_alloc()\fR can be called from interrupt context only if the
-\fBKM_NOSLEEP\fR flag is set. It can be called from user or kernel context with
-any valid flag.
+\fBKM_NOSLEEP\fR flag is set. It can be called from user or kernel context
+with any valid flag.
.sp
.LP
\fBkmem_cache_free()\fR can be called from user, kernel, or interrupt context.
@@ -709,9 +724,11 @@ kmem_cache_set_move(object_cache, object_move);
.in -2
.SH RETURN VALUES
-If successful, the constructor function must return \fB0\fR. If KM_NOSLEEP is
-set and memory cannot be allocated without sleeping, the constructor must
-return -\fB1\fR.
+If successful, the constructor function must return \fB0\fR. If
+\fBKM_NOSLEEP\fR or \fBKM_NOSLEEP_LAZY\fR is set and memory cannot be
+allocated without sleeping, the constructor must return -\fB1\fR. If the
+constructor takes extraordinary steps during a \fBKM_NOSLEEP\fR construction,
+it may not take those for a \fBKM_NOSLEEP_LAZY\fR construction.
.sp
.LP
\fBkmem_cache_create()\fR returns a pointer to the allocated cache.
diff --git a/usr/src/man/man9f/scsi_hba_tgtmap_create.9f b/usr/src/man/man9f/scsi_hba_tgtmap_create.9f
index 788f7e8435..a8a16afab0 100644
--- a/usr/src/man/man9f/scsi_hba_tgtmap_create.9f
+++ b/usr/src/man/man9f/scsi_hba_tgtmap_create.9f
@@ -10,8 +10,9 @@
.\"
.\"
.\" Copyright 2019, Joyent, Inc.
+.\" Copyright 2022 Oxide Computer Company
.\"
-.Dd June 03, 2019
+.Dd January 29, 2022
.Dt SCSI_HBA_TGTMAP_CREATE 9F
.Os
.Sh NAME
@@ -173,8 +174,9 @@ argument.
.Pp
The
.Fa dip
-argument should correspond to the HBA driver's device node or one of its
-iports.
+argument should correspond to one of the HBA driver's iports.
+The overall driver instance cannot be used here.
+Target maps are only supported on iports.
.Pp
The
.Fa mode
@@ -198,7 +200,7 @@ argument to
and use the
.Fn scsi_hba_tgtmap_tgt_add
and
-.Fn scsi_hba_tgtmap_tgt_destroy
+.Fn scsi_hba_tgtmap_tgt_remove
functions.
See the section
.Sx Per-Address Reporting
diff --git a/usr/src/man/man9s/scsi_address.9s b/usr/src/man/man9s/scsi_address.9s
index 65fc9a017f..da00339a35 100644
--- a/usr/src/man/man9s/scsi_address.9s
+++ b/usr/src/man/man9s/scsi_address.9s
@@ -1,9 +1,10 @@
.\" Copyright (c) 2000, Sun Microsystems, Inc., All Rights Reserved
.\" Copyright (c) 2017, Joyent, Inc.
+.\" Copyright 2022 Oxide Computer Company
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.Dd Apr 23, 2017
+.Dd January 29, 2022
.Dt SCSI_ADDRESS 9S
.Os
.Sh NAME
@@ -16,47 +17,56 @@ illumos architecture specific (illumos DDI)
.Sh DESCRIPTION
A
.Vt scsi_address
-structure defines the addressing components for a
-.Sy SCSI
-target device.
+structure defines the addressing components for a SCSI target device.
The address of the target device is separated into two components:
target number and logical unit number.
The two addressing components are used to uniquely identify any type of
-.Sy SCSI
-device; however, most devices can be addressed with the target component of the
-address.
+SCSI device; however, most devices can be addressed with the target
+component of the address.
.Pp
In the case where only the target component is used to address the device, the
logical unit should be set to
-.Sy 0 . If the
-.Sy SCSI
-target device supports logical units, then the HBA must interpret the
-logical units field of the data structure.
+.Sy 0 .
+If the SCSI target device supports logical units, then the HBA must
+interpret the logical units field of the data structure.
.Pp
The
-.Sy pkt_address
+.Fa pkt_address
member of a
.Xr scsi_pkt 9S
is initialized by
.Xr scsi_init_pkt 9F .
.Ss Complex Addressing
-Drivers may set the flag
+HBA drivers may set the flag
.Dv SCSI_HBA_ADDR_COMPLEX
in the
.Fa hba_flags
argument to
.Xr scsi_hba_attach_setup 9F .
-When the flag is set, this structure must be treated as opaque.
-Instead of storing a traditional target and LUN, the address is treated
-as the string form of a unit address.
-In addition, rather than storing a pointer to the
+When the flag is set, the way this structure is used changes.
+While the
+.Fa a_hba_tran
+member is still accessible for accessing the
.Xr scsi_hba_tran 9S
-structure, the address structure can store any arbitrary pointer through
-the
+structure, the nature of addressing changes.
+.Pp
+When using complex addressing, a particular device is addressed through a unit
+address which takes the shape of a string.
+When using complex addressing, the target and lun fields are inaccessible and
+instead a device driver can obtain the
+.Xr scsi_device 9S
+structure that this address corresponds to.
+In the complex addressing world, this is generally a direct mapping.
+To obtain this structure, a driver would call the
+.Xr scsi_address_device 9F
+function.
+.Pp
+With the
+.Xr scsi_device 9S
+structure, the device driver can then get to the device-specific private data
+through the
.Xr scsi_device_hba_private_get 9F
-and
-.Xr scsi_device_hba_private_set 9F
-functions.
+function.
.Sh STRUCTURE MEMBERS
.Bd -literal
scsi_hba_tran_t *a_hba_tran; /* Transport vectors for the SCSI bus */
@@ -65,44 +75,27 @@ uchar_t a_lun; /* SCSI logical unit */
.Ed
.Pp
.Fa a_hba_tran
-is a pointer to the controlling
-.Sy HBA 's
-transport vector
-structure.
-The
-.Sy SCSA
-interface uses this field to pass any transport
-requests from the
-.Sy SCSI
-target device drivers to the
-.Sy HBA
-driver.
+is a pointer to the controlling HBA's transport vector structure.
+The SCSA interface uses this field to pass any transport requests from the SCSI
+target device drivers to the HBA driver.
+This member is accessible regardless of whether the device driver uses complex
+addressing or not.
.Pp
.Fa a_target
-is the target component of the
-.Sy SCSI
-address
+is the target component of the SCSI address.
+This member is not accessible when the device driver uses complex addressing.
.Pp
.Fa a_lun
-is the logical unit component of the
-.Sy SCSI
-address.
-The logical unit is used to further distinguish a
-.Sy SCSI
-target device that
+is the logical unit component of the SCSI address.
+The logical unit is used to further distinguish a SCSI target device that
supports multiple logical units from one that does not.
-.Pp
-If the flag,
-.Dv SCSI_HBA_ADDR_COMPLEX
-was set, then the driver
-.Em must not
-dereference any of these fields, the structure contents will have
-changed and should be considered opaque.
+This member is not accessible when the device driver uses complex addressing.
.Sh SEE ALSO
+.Xr scsi_address_device 9F ,
.Xr scsi_device_hba_private_get 9F ,
-.Xr scsi_device_hba_private_set 9F ,
.Xr scsi_hba_attach_setup 9F ,
.Xr scsi_init_pkt 9F ,
+.Xr scsi_device 9S ,
.Xr scsi_hba_tran 9S ,
.Xr scsi_pkt 9S
.Pp
diff --git a/usr/src/pkg/manifests/SUNWcs.man4d.inc b/usr/src/pkg/manifests/SUNWcs.man4d.inc
index 9e4743776f..bec335fafc 100644
--- a/usr/src/pkg/manifests/SUNWcs.man4d.inc
+++ b/usr/src/pkg/manifests/SUNWcs.man4d.inc
@@ -14,4 +14,4 @@
file path=usr/share/man/man4d/kstat.4d
file path=usr/share/man/man4d/ksyms.4d
file path=usr/share/man/man4d/ptm.4d
-file path=usr/share/man/man4d/pts.4d
+link path=usr/share/man/man4d/pts.4d target=ptm.4d
diff --git a/usr/src/pkg/manifests/SUNWcs.p5m b/usr/src/pkg/manifests/SUNWcs.p5m
index 2d10a04d96..76e7943d1e 100644
--- a/usr/src/pkg/manifests/SUNWcs.p5m
+++ b/usr/src/pkg/manifests/SUNWcs.p5m
@@ -552,7 +552,6 @@ $(i386_ONLY)file path=usr/bin/$(ARCH32)/newtask group=sys mode=4555
$(i386_ONLY)file path=usr/bin/$(ARCH32)/nohup mode=0555
$(i386_ONLY)file path=usr/bin/$(ARCH32)/prctl mode=0555
$(i386_ONLY)file path=usr/bin/$(ARCH32)/prstat mode=0555
-$(i386_ONLY)file path=usr/bin/$(ARCH32)/ps mode=0555
file path=usr/bin/$(ARCH32)/savecore mode=0555
$(i386_ONLY)file path=usr/bin/$(ARCH32)/setuname mode=0555
dir path=usr/bin/$(ARCH64)
@@ -568,7 +567,6 @@ file path=usr/bin/$(ARCH64)/newtask group=sys mode=4555
file path=usr/bin/$(ARCH64)/nohup mode=0555
file path=usr/bin/$(ARCH64)/prctl mode=0555
file path=usr/bin/$(ARCH64)/prstat mode=0555
-file path=usr/bin/$(ARCH64)/ps mode=0555
file path=usr/bin/$(ARCH64)/savecore mode=0555
file path=usr/bin/$(ARCH64)/setuname mode=0555
$(i386_ONLY)file path=usr/bin/addbadsec mode=0555
@@ -719,7 +717,7 @@ file path=usr/bin/priocntl mode=0555
file path=usr/bin/profiles mode=0555
file path=usr/bin/projects mode=0555
hardlink path=usr/bin/prstat target=../../usr/lib/isaexec
-hardlink path=usr/bin/ps target=../../usr/lib/isaexec
+file path=usr/bin/ps mode=0555
file path=usr/bin/putdev mode=0555
file path=usr/bin/putdgrp mode=0555
link path=usr/bin/pwconv target=../sbin/pwconv
diff --git a/usr/src/pkg/manifests/compatibility-ucb.p5m b/usr/src/pkg/manifests/compatibility-ucb.p5m
index 154f725d2f..3b28328535 100644
--- a/usr/src/pkg/manifests/compatibility-ucb.p5m
+++ b/usr/src/pkg/manifests/compatibility-ucb.p5m
@@ -86,9 +86,7 @@ file path=usr/share/man/man1b/whereis.1b
file path=usr/share/man/man1b/whoami.1b
dir path=usr/ucb
$(i386_ONLY)dir path=usr/ucb/$(ARCH32)
-$(i386_ONLY)hardlink path=usr/ucb/$(ARCH32)/ps target=../../bin/$(ARCH32)/ps
dir path=usr/ucb/$(ARCH64)
-hardlink path=usr/ucb/$(ARCH64)/ps target=../../bin/$(ARCH64)/ps
link path=usr/ucb/Mail target=../bin/mailx
link path=usr/ucb/arch target=../bin/arch
file path=usr/ucb/basename mode=0755
@@ -126,7 +124,7 @@ link path=usr/ucb/netstat target=../bin/netstat
link path=usr/ucb/page target=../bin/more
link path=usr/ucb/pagesize target=../bin/pagesize
file path=usr/ucb/printenv mode=0755
-hardlink path=usr/ucb/ps target=../../usr/lib/isaexec
+hardlink path=usr/ucb/ps target=../bin/ps
link path=usr/ucb/quota target=../lib/fs/ufs/quota
link path=usr/ucb/rcp target=../bin/rcp
link path=usr/ucb/rdate target=../bin/rdate
diff --git a/usr/src/pkg/manifests/driver-cpu-amd-zen.p5m b/usr/src/pkg/manifests/driver-cpu-amd-zen.p5m
index a2ff3c2113..a8500fac4f 100644
--- a/usr/src/pkg/manifests/driver-cpu-amd-zen.p5m
+++ b/usr/src/pkg/manifests/driver-cpu-amd-zen.p5m
@@ -10,7 +10,7 @@
#
#
-# Copyright 2020 Oxide Computer Company
+# Copyright 2021 Oxide Computer Company
#
<include global_zone_only_component>
@@ -39,8 +39,9 @@ driver name=amdzen
# 1490-1497: f17h m30-3f df
# 15d0: f17h m10-m2f nb
# 15e8-15ef: f17h m10-m2f df
-# 1630: f17h m60-6f nb
+# 1630: f17h m60-6f, f19h m50-5f nb
# 1650-1657: f19h m00-0f df
+# 166a-1671: f19h m50-5f df
#
driver name=amdzen_stub \
alias=pci1022,1440,p \
@@ -94,5 +95,13 @@ driver name=amdzen_stub \
alias=pci1022,1654,p \
alias=pci1022,1655,p \
alias=pci1022,1656,p \
- alias=pci1022,1657,p
+ alias=pci1022,1657,p \
+ alias=pci1022,166a,p \
+ alias=pci1022,166b,p \
+ alias=pci1022,166c,p \
+ alias=pci1022,166d,p \
+ alias=pci1022,166e,p \
+ alias=pci1022,166f,p \
+ alias=pci1022,1670,p \
+ alias=pci1022,1671,p
license lic_CDDL license=lic_CDDL
diff --git a/usr/src/pkg/manifests/driver-storage-smrt.p5m b/usr/src/pkg/manifests/driver-storage-smrt.p5m
new file mode 100644
index 0000000000..8ef3e50718
--- /dev/null
+++ b/usr/src/pkg/manifests/driver-storage-smrt.p5m
@@ -0,0 +1,74 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2019 Joyent, Inc.
+#
+
+<include global_zone_only_component>
+set name=pkg.fmri value=pkg:/driver/storage/smrt@$(PKGVERS)
+set name=pkg.summary value="HP SmartArray SAS HBA Driver"
+set name=pkg.description value="HP SmartArray SAS HBA Driver"
+set name=info.classification value=org.opensolaris.category.2008:Drivers/Storage
+set name=variant.arch value=i386
+dir path=kernel group=sys
+dir path=kernel/drv group=sys
+dir path=kernel/drv/$(ARCH64) group=sys
+file path=kernel/drv/$(ARCH64)/smrt group=sys
+file path=kernel/drv/smrt.conf group=sys
+driver name=smrt class=scsi-self-identifying
+#
+# The smrt driver overlaps with cpqary3 and supports several of the same
+# devices. To ensure that folks can still boot existing systems we have
+# left all the devices supported by smrt commented out as they all
+# overlay with cpqary3. In this form, users may swap over and the driver
+# also provides a useful reference for SCSAv3. When adding these
+# aliases, please make sure to remember to add the appropriate '\' to
+# the driver line above and below as needed.
+#
+# alias=pci103c,1920
+# alias=pci103c,1921
+# alias=pci103c,1922
+# alias=pci103c,1923
+# alias=pci103c,1924
+# alias=pci103c,1926
+# alias=pci103c,1928
+# alias=pci103c,21bd
+# alias=pci103c,21be
+# alias=pci103c,21bf
+# alias=pci103c,21c0
+# alias=pci103c,21c1
+# alias=pci103c,21c2
+# alias=pci103c,21c3
+# alias=pci103c,21c5
+# alias=pci103c,21c6
+# alias=pci103c,21c7
+# alias=pci103c,21c8
+# alias=pci103c,21ca
+# alias=pci103c,21cb
+# alias=pci103c,21cc
+# alias=pci103c,21cd
+# alias=pci103c,21ce
+# alias=pci103c,3241
+# alias=pci103c,3243
+# alias=pci103c,3245
+# alias=pci103c,3247
+# alias=pci103c,3249
+# alias=pci103c,324a
+# alias=pci103c,324b
+# alias=pci103c,3350
+# alias=pci103c,3351
+# alias=pci103c,3352
+# alias=pci103c,3353
+# alias=pci103c,3354
+# alias=pci103c,3355
+# alias=pci103c,3356
+license lic_CDDL license=lic_CDDL
diff --git a/usr/src/pkg/manifests/system-bhyve-tests.p5m b/usr/src/pkg/manifests/system-bhyve-tests.p5m
index 74881cf19c..823ed69a60 100644
--- a/usr/src/pkg/manifests/system-bhyve-tests.p5m
+++ b/usr/src/pkg/manifests/system-bhyve-tests.p5m
@@ -14,7 +14,7 @@
#
#
-# Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
+# Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
# Copyright 2022 Oxide Computer Company
#
@@ -35,7 +35,10 @@ file path=opt/bhyve-tests/tests/mevent/lists_delete mode=0555
file path=opt/bhyve-tests/tests/mevent/read_disable mode=0555
file path=opt/bhyve-tests/tests/mevent/read_pause mode=0555
file path=opt/bhyve-tests/tests/mevent/read_requeue mode=0555
+file path=opt/bhyve-tests/tests/mevent/vnode_file mode=0555
+file path=opt/bhyve-tests/tests/mevent/vnode_zvol mode=0555
dir path=opt/bhyve-tests/tests/vmm
+file path=opt/bhyve-tests/tests/vmm/fpu_getset mode=0555
file path=opt/bhyve-tests/tests/vmm/mem_partial mode=0555
file path=opt/bhyve-tests/tests/vmm/mem_seg_map mode=0555
license lic_CDDL license=lic_CDDL
diff --git a/usr/src/pkg/manifests/system-boot-loader.p5m b/usr/src/pkg/manifests/system-boot-loader.p5m
index 8339b377b7..72bb3f6329 100644
--- a/usr/src/pkg/manifests/system-boot-loader.p5m
+++ b/usr/src/pkg/manifests/system-boot-loader.p5m
@@ -98,8 +98,8 @@ $(i386_ONLY)file path=usr/share/man/man7/pxeboot.7
$(i386_ONLY)file path=usr/share/man/man7/version.4th.7
license lic_CDDL license=lic_CDDL
$(i386_ONLY)license usr/src/boot/COPYRIGHT license=usr/src/boot/COPYRIGHT
-$(i386_ONLY)license usr/src/boot/sys/boot/common/linenoise/LICENSE \
- license=usr/src/boot/sys/boot/common/linenoise/LICENSE
+$(i386_ONLY)license usr/src/boot/common/linenoise/LICENSE \
+ license=usr/src/boot/common/linenoise/LICENSE
$(i386_ONLY)license usr/src/common/crypto/skein/THIRDPARTYLICENSE \
license=usr/src/common/crypto/skein/THIRDPARTYLICENSE
$(i386_ONLY)license usr/src/common/pnglite/THIRDPARTYLICENSE \
diff --git a/usr/src/pkg/manifests/system-kernel-platform.p5m b/usr/src/pkg/manifests/system-kernel-platform.p5m
index 250be1589c..f6380db53d 100644
--- a/usr/src/pkg/manifests/system-kernel-platform.p5m
+++ b/usr/src/pkg/manifests/system-kernel-platform.p5m
@@ -559,6 +559,8 @@ $(i386_ONLY)file path=platform/i86pc/kernel/misc/$(ARCH64)/acpidev group=sys \
mode=0755
$(i386_ONLY)file path=platform/i86pc/kernel/misc/$(ARCH64)/gfx_private \
group=sys mode=0755
+$(i386_ONLY)file path=platform/i86pc/kernel/misc/$(ARCH64)/pci_prd group=sys \
+ mode=0755
$(i386_ONLY)dir path=platform/i86pc/ucode group=sys
$(i386_ONLY)dir path=platform/i86xpv group=sys
$(i386_ONLY)dir path=platform/i86xpv/kernel group=sys
diff --git a/usr/src/pkg/manifests/system-microcode-intel.p5m b/usr/src/pkg/manifests/system-microcode-intel.p5m
index 9590f18276..2c7be17346 100644
--- a/usr/src/pkg/manifests/system-microcode-intel.p5m
+++ b/usr/src/pkg/manifests/system-microcode-intel.p5m
@@ -24,8 +24,8 @@
# Copyright 2012 Nexenta Systems, Inc. All rights reserved.
# Copyright 2014 Gary Mills
# Copyright 2019 Peter Tribble.
-# Copyright 2020 Joyent, Inc.
# Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
+# Copyright 2022 Joyent, Inc.
#
#
@@ -35,7 +35,7 @@
#
<include global_zone_only_component>
set name=pkg.fmri \
- value=pkg:/system/microcode/intel@20210608,$(PKGVERS_BUILTON)-$(PKGVERS_BRANCH)
+ value=pkg:/system/microcode/intel@20220207,$(PKGVERS_BUILTON)-$(PKGVERS_BRANCH)
set name=pkg.summary value="Microcode for Intel CPUs"
set name=pkg.description value="Microcode for Intel CPUs"
set name=info.classification value=org.opensolaris.category.2008:System/Core
@@ -550,9 +550,6 @@ file path=platform/i86pc/ucode/GenuineIntel/000706A8-01 group=sys mode=0444 \
reboot-needed=true
file path=platform/i86pc/ucode/GenuineIntel/000706E5-80 group=sys mode=0444 \
reboot-needed=true
-file path=platform/i86pc/ucode/GenuineIntel/00080664-01 group=sys mode=0444 \
- reboot-needed=true
-hardlink path=platform/i86pc/ucode/GenuineIntel/00080665-01 target=00080664-01
file path=platform/i86pc/ucode/GenuineIntel/000806A1-10 group=sys mode=0444 \
reboot-needed=true
file path=platform/i86pc/ucode/GenuineIntel/000806C1-80 group=sys mode=0444 \
diff --git a/usr/src/pkg/manifests/system-network-overlay.p5m b/usr/src/pkg/manifests/system-network-overlay.p5m
new file mode 100644
index 0000000000..ce24882834
--- /dev/null
+++ b/usr/src/pkg/manifests/system-network-overlay.p5m
@@ -0,0 +1,62 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+#
+
+<include global_zone_only_component>
+set name=pkg.fmri value=pkg:/system/network/overlay@$(PKGVERS)
+set name=pkg.summary value="illumos overlay driver"
+set name=pkg.description value="Device driver implementing network overlays"
+set name=info.classification \
+ value=org.opensolaris.category.2008:Drivers/Networking
+set name=variant.arch value=$(ARCH)
+dir path=kernel group=sys
+dir path=kernel/drv group=sys
+dir path=kernel/drv/$(ARCH64) group=sys
+file path=kernel/drv/$(ARCH64)/overlay group=sys
+file path=kernel/drv/overlay.conf group=sys
+dir path=kernel/overlay
+dir path=kernel/overlay/$(ARCH64)
+file path=kernel/overlay/$(ARCH64)/vxlan group=sys mode=0755
+dir path=lib
+file path=lib/$(ARCH64)/libvarpd.so.1 mode=0755 \
+ variant.opensolaris.zone=__NODEFAULT
+file path=lib/libvarpd.so.1 mode=0755 variant.opensolaris.zone=__NODEFAULT
+dir path=lib/svc
+dir path=lib/svc/manifest group=sys
+dir path=lib/svc/manifest/network group=sys
+file path=lib/svc/manifest/network/varpd.xml mode=0444
+dir path=usr/lib
+dir path=usr/lib/$(ARCH64)
+dir path=usr/lib/varpd
+dir path=usr/lib/varpd/$(ARCH64)
+link path=usr/lib/varpd/$(ARCH64)/libvarpd_direct.so target=libvarpd_direct.so.1
+file path=usr/lib/varpd/$(ARCH64)/libvarpd_direct.so.1
+link path=usr/lib/varpd/$(ARCH64)/libvarpd_files.so target=libvarpd_files.so.1
+file path=usr/lib/varpd/$(ARCH64)/libvarpd_files.so.1
+link path=usr/lib/varpd/64 target=$(ARCH64)
+link path=usr/lib/varpd/libvarpd_direct.so target=libvarpd_direct.so.1
+file path=usr/lib/varpd/libvarpd_direct.so.1
+link path=usr/lib/varpd/libvarpd_files.so target=libvarpd_files.so.1
+file path=usr/lib/varpd/libvarpd_files.so.1
+file path=usr/lib/varpd/varpd mode=0555
+dir path=usr/share/man
+dir path=usr/share/man/man4p
+link path=usr/share/man/man4p/VXLAN.4p target=vxlan.4p
+file path=usr/share/man/man4p/vxlan.4p mode=0444
+dir path=usr/share/man/man5
+file path=usr/share/man/man5/overlay_files.5
+dir path=usr/share/man/man7
+file path=usr/share/man/man7/overlay.7
+driver name=overlay
+license lic_CDDL license=lic_CDDL
diff --git a/usr/src/pkg/manifests/system-test-ostest.p5m b/usr/src/pkg/manifests/system-test-ostest.p5m
index 8f8f38407c..1f89619630 100644
--- a/usr/src/pkg/manifests/system-test-ostest.p5m
+++ b/usr/src/pkg/manifests/system-test-ostest.p5m
@@ -132,6 +132,8 @@ file path=opt/os-tests/tests/stackalign/stackalign.64 mode=0555
dir path=opt/os-tests/tests/stress
file path=opt/os-tests/tests/stress/dladm-kstat mode=0555
dir path=opt/os-tests/tests/syscall
+file path=opt/os-tests/tests/syscall/fchmodat.32 mode=0555
+file path=opt/os-tests/tests/syscall/fchmodat.64 mode=0555
file path=opt/os-tests/tests/syscall/open.32 mode=0555
file path=opt/os-tests/tests/syscall/open.64 mode=0555
dir path=opt/os-tests/tests/timer
diff --git a/usr/src/test/bhyve-tests/runfiles/default.run b/usr/src/test/bhyve-tests/runfiles/default.run
index 51afd4581a..3055f3e2d8 100644
--- a/usr/src/test/bhyve-tests/runfiles/default.run
+++ b/usr/src/test/bhyve-tests/runfiles/default.run
@@ -20,8 +20,13 @@ post =
outputdir = /var/tmp/test_results
[/opt/bhyve-tests/tests/vmm]
-tests = ['mem_partial', 'mem_seg_map']
+tests = ['mem_partial', 'mem_seg_map', 'fpu_getset']
# Tests of userspace mevent system, built from cmd/bhyve
[/opt/bhyve-tests/tests/mevent]
-tests = ['lists_delete', 'read_disable', 'read_pause', 'read_requeue']
+tests = ['lists_delete', 'read_disable', 'read_pause', 'read_requeue',
+ 'vnode_file']
+
+[/opt/bhyve-tests/tests/mevent/vnode_zvol]
+user = root
+
diff --git a/usr/src/test/bhyve-tests/tests/vmm/Makefile b/usr/src/test/bhyve-tests/tests/vmm/Makefile
index c91ed9a7e4..30d06a0f6b 100644
--- a/usr/src/test/bhyve-tests/tests/vmm/Makefile
+++ b/usr/src/test/bhyve-tests/tests/vmm/Makefile
@@ -16,7 +16,8 @@ include $(SRC)/cmd/Makefile.cmd.64
include $(SRC)/test/Makefile.com
PROG = mem_partial \
- mem_seg_map
+ mem_seg_map \
+ fpu_getset
COMMON_OBJS = common.o
CLEAN_OBJS = $(PROG:%=%.o)
diff --git a/usr/src/test/bhyve-tests/tests/vmm/common.c b/usr/src/test/bhyve-tests/tests/vmm/common.c
index b7f0a30ed0..622a14c61f 100644
--- a/usr/src/test/bhyve-tests/tests/vmm/common.c
+++ b/usr/src/test/bhyve-tests/tests/vmm/common.c
@@ -23,12 +23,13 @@
#include <vmmapi.h>
struct vmctx *
-create_test_vm(void)
+create_test_vm(const char *test_suite_name)
{
char name[VM_MAX_NAMELEN];
int res;
- (void) snprintf(name, sizeof (name), "bhyve-test-memmap-%d", getpid());
+ (void) snprintf(name, sizeof (name), "bhyve-test-%s-%d",
+ test_suite_name, getpid());
res = vm_create(name, 0);
if (res != 0) {
diff --git a/usr/src/test/bhyve-tests/tests/vmm/common.h b/usr/src/test/bhyve-tests/tests/vmm/common.h
index 7b64574cf2..f210408b71 100644
--- a/usr/src/test/bhyve-tests/tests/vmm/common.h
+++ b/usr/src/test/bhyve-tests/tests/vmm/common.h
@@ -16,7 +16,7 @@
#ifndef _COMMON_H_
#define _COMMON_H_
-struct vmctx *create_test_vm(void);
+struct vmctx *create_test_vm(const char *);
int alloc_memseg(struct vmctx *, int, size_t, const char *);
#define PROT_ALL (PROT_READ | PROT_WRITE | PROT_EXEC)
diff --git a/usr/src/test/bhyve-tests/tests/vmm/fpu_getset.c b/usr/src/test/bhyve-tests/tests/vmm/fpu_getset.c
new file mode 100644
index 0000000000..814e15dec3
--- /dev/null
+++ b/usr/src/test/bhyve-tests/tests/vmm/fpu_getset.c
@@ -0,0 +1,333 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2022 Oxide Computer Company
+ */
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stropts.h>
+#include <strings.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <libgen.h>
+#include <sys/debug.h>
+#include <sys/fp.h>
+
+#include <sys/vmm.h>
+#include <sys/vmm_dev.h>
+#include <sys/x86_archext.h>
+#include <vmmapi.h>
+
+#include "common.h"
+
+/* Minimal xsave state area (sans any AVX storage) */
+struct xsave_min {
+ struct fxsave_state legacy;
+ struct xsave_header header;
+};
+
+CTASSERT(sizeof (struct xsave_min) == MIN_XSAVE_SIZE);
+
+struct avx_state {
+ /* 16 x 128-bit: high portions of the ymm registers */
+ uint64_t ymm[32];
+};
+
+static bool
+get_fpu(int fd, struct vm_fpu_state *req)
+{
+ int res = ioctl(fd, VM_GET_FPU, req);
+ if (res != 0) {
+ perror("could not read FPU for vCPU");
+ return (false);
+ }
+ return (true);
+}
+
+static bool
+set_fpu(int fd, struct vm_fpu_state *req)
+{
+ int res = ioctl(fd, VM_SET_FPU, req);
+ if (res != 0) {
+ perror("could not write FPU for vCPU");
+ return (false);
+ }
+ return (true);
+}
+
+static bool
+check_sse(int fd, const struct vm_fpu_desc *desc, void *fpu_area,
+ size_t fpu_size)
+{
+ /* Make sure the x87/MMX/SSE state is described as present */
+ bool found_fp = false, found_sse = false;
+ for (uint_t i = 0; i < desc->vfd_num_entries; i++) {
+ const struct vm_fpu_desc_entry *ent = &desc->vfd_entry_data[i];
+
+ switch (ent->vfde_feature) {
+ case XFEATURE_LEGACY_FP:
+ found_fp = true;
+ if (ent->vfde_off != 0 ||
+ ent->vfde_size != sizeof (struct fxsave_state)) {
+ (void) fprintf(stderr,
+ "unexpected entity for %x: "
+ "size=%x off=%x\n", ent->vfde_feature,
+ ent->vfde_size, ent->vfde_off);
+ return (false);
+ }
+ break;
+ case XFEATURE_SSE:
+ found_sse = true;
+ if (ent->vfde_off != 0 ||
+ ent->vfde_size != sizeof (struct fxsave_state)) {
+ (void) fprintf(stderr,
+ "unexpected entity for %x: "
+ "size=%x off=%x\n", ent->vfde_feature,
+ ent->vfde_size, ent->vfde_off);
+ return (false);
+ }
+ break;
+ }
+ }
+
+ if (!found_fp || !found_sse) {
+ (void) fprintf(stderr, "did not find x87 and SSE area "
+ "descriptors as expected in initial FPU\n");
+ return (false);
+ }
+
+ struct vm_fpu_state req = {
+ .vcpuid = 0,
+ .buf = fpu_area,
+ .len = fpu_size,
+ };
+
+ if (!get_fpu(fd, &req)) {
+ return (false);
+ }
+
+ struct xsave_min *xs = fpu_area;
+ /*
+ * Executing this test on a freshly-created instance, we expect the FPU
+ * to only have the legacy and SSE features present in its active state.
+ */
+ if (xs->header.xsh_xstate_bv != (XFEATURE_LEGACY_FP | XFEATURE_SSE)) {
+ (void) fprintf(stderr, "bad xstate_bv %lx, expected %lx",
+ xs->header.xsh_xstate_bv,
+ (XFEATURE_LEGACY_FP | XFEATURE_SSE));
+ return (false);
+ }
+
+ /* load some SSE values to check for a get/set cycle */
+ uint64_t *xmm = (void *)&xs->legacy.fx_xmm[0];
+ xmm[0] = UINT64_MAX;
+ xmm[2] = 1;
+
+ if (!set_fpu(fd, &req)) {
+ return (false);
+ }
+
+ /* check that those values made it in/out of the guest FPU */
+ bzero(fpu_area, fpu_size);
+ if (!get_fpu(fd, &req)) {
+ return (false);
+ }
+ if (xmm[0] != UINT64_MAX || xmm[2] != 1) {
+ (void) fprintf(stderr, "SSE test registers not saved\n");
+ return (false);
+ }
+
+ /* Make sure that a bogus MXCSR value is rejected */
+ xs->legacy.fx_mxcsr = UINT32_MAX;
+ int res = ioctl(fd, VM_SET_FPU, &req);
+ if (res == 0) {
+ (void) fprintf(stderr,
+ "write of invalid MXCSR erroneously allowed\n");
+ return (false);
+ }
+
+ return (true);
+}
+
+static bool
+check_avx(int fd, const struct vm_fpu_desc *desc, void *fpu_area,
+ size_t fpu_size)
+{
+ bool found_avx = false;
+ size_t avx_size, avx_off;
+ for (uint_t i = 0; i < desc->vfd_num_entries; i++) {
+ const struct vm_fpu_desc_entry *ent = &desc->vfd_entry_data[i];
+
+ if (ent->vfde_feature == XFEATURE_AVX) {
+ found_avx = true;
+ avx_size = ent->vfde_size;
+ avx_off = ent->vfde_off;
+ break;
+ }
+ }
+
+ if (!found_avx) {
+ (void) printf("AVX capability not found on host CPU, "
+ "skipping related tests\n");
+ return (true);
+ }
+
+ if (avx_size != sizeof (struct avx_state)) {
+ (void) fprintf(stderr, "unexpected AVX state size: %x, "
+ "expected %x\n", avx_size, sizeof (struct avx_state));
+ return (false);
+ }
+ if ((avx_off + avx_size) > fpu_size) {
+ (void) fprintf(stderr, "AVX data falls outside fpu size: "
+ "%x > %x\n", avx_off + avx_size, fpu_size);
+ return (false);
+ }
+
+ struct xsave_min *xs = fpu_area;
+ struct avx_state *avx = fpu_area + avx_off;
+
+ /* do a simple data round-trip */
+ struct vm_fpu_state req = {
+ .vcpuid = 0,
+ .buf = fpu_area,
+ .len = fpu_size,
+ };
+ if (!get_fpu(fd, &req)) {
+ return (false);
+ }
+
+ /* With AVX unused so far, we expect it to be absent from the BV */
+ if (xs->header.xsh_xstate_bv != (XFEATURE_LEGACY_FP | XFEATURE_SSE)) {
+ (void) fprintf(stderr, "bad xstate_bv %lx, expected %lx\n",
+ xs->header.xsh_xstate_bv,
+ (XFEATURE_LEGACY_FP | XFEATURE_SSE));
+ return (false);
+ }
+
+ avx->ymm[0] = UINT64_MAX;
+ avx->ymm[2] = 2;
+
+ /* first write without asserting AVX in BV */
+ if (!set_fpu(fd, &req)) {
+ return (false);
+ }
+
+ /* And check that the AVX state stays empty */
+ bzero(fpu_area, fpu_size);
+ if (!get_fpu(fd, &req)) {
+ return (false);
+ }
+ if (xs->header.xsh_xstate_bv != (XFEATURE_LEGACY_FP | XFEATURE_SSE)) {
+ (void) fprintf(stderr, "xstate_bv changed unexpectedly %lx\n",
+ xs->header.xsh_xstate_bv);
+ return (false);
+ }
+ if (avx->ymm[0] != 0 || avx->ymm[2] != 0) {
+ (void) fprintf(stderr, "YMM state changed unexpectedly "
+ "%lx %lx\n", avx->ymm[0], avx->ymm[2]);
+ return (false);
+ }
+
+ /* Now write YMM and set the appropriate AVX BV state */
+ avx->ymm[0] = UINT64_MAX;
+ avx->ymm[2] = 2;
+ xs->header.xsh_xstate_bv |= XFEATURE_AVX;
+ if (!set_fpu(fd, &req)) {
+ return (false);
+ }
+
+ /* ... and now check that it stuck */
+ bzero(fpu_area, fpu_size);
+ if (!get_fpu(fd, &req)) {
+ return (false);
+ }
+ if ((xs->header.xsh_xstate_bv & XFEATURE_AVX) == 0) {
+ (void) fprintf(stderr, "AVX missing from xstate_bv %lx\n",
+ xs->header.xsh_xstate_bv);
+ return (false);
+ }
+ if (avx->ymm[0] != UINT64_MAX || avx->ymm[2] != 2) {
+ (void) fprintf(stderr, "YMM state not preserved "
+ "%lx != %lx | %lx != %lx\n",
+ avx->ymm[0], UINT64_MAX, avx->ymm[2], 2);
+ return (false);
+ }
+
+
+ return (true);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct vmctx *ctx;
+ int res, fd;
+ const char *suite_name = basename(argv[0]);
+
+ ctx = create_test_vm(suite_name);
+ if (ctx == NULL) {
+ perror("could not open test VM");
+ return (EXIT_FAILURE);
+ }
+ fd = vm_get_device_fd(ctx);
+
+ struct vm_fpu_desc_entry entries[64];
+ struct vm_fpu_desc desc = {
+ .vfd_entry_data = entries,
+ .vfd_num_entries = 64,
+ };
+
+ res = ioctl(fd, VM_DESC_FPU_AREA, &desc);
+ if (res != 0) {
+ perror("could not query fpu area description");
+ goto bail;
+ }
+
+ /* Make sure the XSAVE area described for this machine is reasonable */
+ if (desc.vfd_num_entries == 0) {
+ (void) fprintf(stderr, "no FPU description entries found\n");
+ goto bail;
+ }
+ if (desc.vfd_req_size < MIN_XSAVE_SIZE) {
+ (void) fprintf(stderr, "required XSAVE size %lu < "
+ "expected %lu\n", desc.vfd_req_size, MIN_XSAVE_SIZE);
+ goto bail;
+ }
+
+ const size_t fpu_size = desc.vfd_req_size;
+ void *fpu_area = malloc(fpu_size);
+ if (fpu_area == NULL) {
+ perror("could not allocate fpu area");
+ goto bail;
+ }
+ bzero(fpu_area, fpu_size);
+
+ if (!check_sse(fd, &desc, fpu_area, fpu_size)) {
+ goto bail;
+ }
+ if (!check_avx(fd, &desc, fpu_area, fpu_size)) {
+ goto bail;
+ }
+
+ /* mission accomplished */
+ vm_destroy(ctx);
+ (void) printf("%s\tPASS\n", suite_name);
+ return (EXIT_SUCCESS);
+
+bail:
+ vm_destroy(ctx);
+ (void) printf("%s\tFAIL\n", suite_name);
+ return (EXIT_FAILURE);
+}
diff --git a/usr/src/test/bhyve-tests/tests/vmm/mem_partial.c b/usr/src/test/bhyve-tests/tests/vmm/mem_partial.c
index b410c673ab..964fdf95c5 100644
--- a/usr/src/test/bhyve-tests/tests/vmm/mem_partial.c
+++ b/usr/src/test/bhyve-tests/tests/vmm/mem_partial.c
@@ -57,8 +57,9 @@ main(int argc, char *argv[])
struct vmctx *ctx;
int res, fd;
void *guest_mem;
+ const char *suite_name = basename(argv[0]);
- ctx = create_test_vm();
+ ctx = create_test_vm(suite_name);
if (ctx == NULL) {
perror("could open test VM");
return (1);
@@ -192,7 +193,7 @@ main(int argc, char *argv[])
}
/* mission accomplished */
- (void) printf("%s\tPASS\n", basename(argv[0]));
+ (void) printf("%s\tPASS\n", suite_name);
vm_destroy(ctx);
return (0);
diff --git a/usr/src/test/bhyve-tests/tests/vmm/mem_seg_map.c b/usr/src/test/bhyve-tests/tests/vmm/mem_seg_map.c
index e80f18547e..92d90bbf28 100644
--- a/usr/src/test/bhyve-tests/tests/vmm/mem_seg_map.c
+++ b/usr/src/test/bhyve-tests/tests/vmm/mem_seg_map.c
@@ -40,8 +40,9 @@ main(int argc, char *argv[])
struct vmctx *ctx;
int res, fd;
void *seg_obj, *guest_mem;
+ const char *suite_name = basename(argv[0]);
- ctx = create_test_vm();
+ ctx = create_test_vm(suite_name);
if (ctx == NULL) {
perror("could open test VM");
return (1);
@@ -129,7 +130,7 @@ main(int argc, char *argv[])
/* mission accomplished */
vm_destroy(ctx);
- (void) printf("%s\tPASS\n", basename(argv[0]));
+ (void) printf("%s\tPASS\n", suite_name);
return (0);
bail:
diff --git a/usr/src/test/libc-tests/runfiles/default.run b/usr/src/test/libc-tests/runfiles/default.run
index d08475b596..891f558865 100644
--- a/usr/src/test/libc-tests/runfiles/default.run
+++ b/usr/src/test/libc-tests/runfiles/default.run
@@ -167,3 +167,4 @@ tests = [
'wchar_h',
'wctype_h'
]
+timeout = 180
diff --git a/usr/src/test/os-tests/runfiles/default.run b/usr/src/test/os-tests/runfiles/default.run
index 0861ede6a4..dcf65fceed 100644
--- a/usr/src/test/os-tests/runfiles/default.run
+++ b/usr/src/test/os-tests/runfiles/default.run
@@ -76,7 +76,7 @@ tests = ['conn', 'dgram', 'drop_priv', 'nosignal', 'rights.32', 'rights.64',
'sockpair', 'recvmsg.32', 'recvmsg.64']
[/opt/os-tests/tests/syscall]
-tests = ['open.32', 'open.64']
+tests = ['fchmodat.32', 'fchmodat.64', 'open.32', 'open.64']
[/opt/os-tests/tests/pf_key]
user = root
diff --git a/usr/src/test/os-tests/tests/syscall/Makefile b/usr/src/test/os-tests/tests/syscall/Makefile
index b4ba83a18b..b2842d4681 100644
--- a/usr/src/test/os-tests/tests/syscall/Makefile
+++ b/usr/src/test/os-tests/tests/syscall/Makefile
@@ -16,7 +16,7 @@
include $(SRC)/cmd/Makefile.cmd
include $(SRC)/test/Makefile.com
-PROGS = open
+PROGS = fchmodat open
CSTD = $(CSTD_GNU99)
diff --git a/usr/src/test/os-tests/tests/syscall/fchmodat.c b/usr/src/test/os-tests/tests/syscall/fchmodat.c
new file mode 100644
index 0000000000..7a0f5caca7
--- /dev/null
+++ b/usr/src/test/os-tests/tests/syscall/fchmodat.c
@@ -0,0 +1,92 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2022 Marcel Telka <marcel@telka.sk>
+ */
+
+/*
+ * Test for fchmodat(AT_SYMLINK_NOFOLLOW)
+ */
+
+#include <sys/param.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main(void)
+{
+ int ret = 0;
+
+ char template[MAXPATHLEN];
+ char *path;
+ char file[MAXPATHLEN];
+ char link[MAXPATHLEN];
+
+ /* prepare template for temporary directory */
+ if (strlcpy(template, "/tmp/XXXXXX", sizeof (template))
+ >= sizeof (template)) {
+ (void) printf("FAIL: Template copy failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* create temporary directory */
+ if ((path = mkdtemp(template)) == NULL) {
+ (void) printf("FAIL: Temporary directory creation failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* format file and link paths */
+ (void) snprintf(file, sizeof (file), "%s/file", path);
+ (void) snprintf(link, sizeof (link), "%s/link", path);
+
+ /* create the file */
+ int fd = open(file, O_WRONLY | O_CREAT, 0644);
+ if (fd < 0) {
+ (void) printf("FAIL: File %s creation failed\n", file);
+ (void) rmdir(path);
+ exit(EXIT_FAILURE);
+ }
+ (void) close(fd);
+
+ /* create symlink */
+ if (symlink("file", link) != 0) {
+ (void) printf("FAIL: Symlink %s creation failed\n", link);
+ (void) unlink(file);
+ (void) rmdir(path);
+ exit(EXIT_FAILURE);
+ }
+
+ /* test fchmodat(AT_SYMLINK_NOFOLLOW) for symlink */
+ if (fchmodat(AT_FDCWD, link, 0666, AT_SYMLINK_NOFOLLOW) == 0) {
+ (void) printf("FAIL: fchmodat(AT_SYMLINK_NOFOLLOW) "
+ "unexpectedly succeeded for symlink\n");
+ ret = EXIT_FAILURE;
+ }
+ /* test fchmodat(AT_SYMLINK_NOFOLLOW) for regular file */
+ if (fchmodat(AT_FDCWD, file, 0666, AT_SYMLINK_NOFOLLOW) != 0) {
+ (void) printf("FAIL: fchmodat(AT_SYMLINK_NOFOLLOW) failed for "
+ "regular file\n");
+ ret = EXIT_FAILURE;
+ }
+
+ /* cleanup */
+ (void) unlink(link);
+ (void) unlink(file);
+ (void) rmdir(path);
+
+ return (ret);
+}
diff --git a/usr/src/test/util-tests/tests/ar/artest.ksh b/usr/src/test/util-tests/tests/ar/artest.ksh
index ad494ef85a..5854a95c3a 100644
--- a/usr/src/test/util-tests/tests/ar/artest.ksh
+++ b/usr/src/test/util-tests/tests/ar/artest.ksh
@@ -11,7 +11,7 @@
#
#
-# Copyright 2021 Oxide Computer Company
+# Copyright 2022 Oxide Computer Company
#
#
@@ -437,6 +437,46 @@ function test_t
fi
}
+function test_q
+{
+ typeset alt="$ar_tmpdir/q.a"
+
+ if ! $ar_prog q $alt $ar_data1 $ar_data0; then
+ warn "ar -q: did not create an archive"
+ fi
+
+ if ! compare_files $ar_f10 $alt; then
+ warn "ar -q: did not create expected file"
+ else
+ print "TEST PASSED: ar -q creates archives"
+ fi
+
+ rm -f $alt
+
+ if ! $ar_prog cq $alt $ar_data1 $ar_data0; then
+ warn "ar -rs: did not create an archive"
+ fi
+
+ if ! compare_files $ar_f10 $alt; then
+ warn "ar -cq: did not create expected file"
+ else
+ print "TEST PASSED: ar -cq creates archives"
+ fi
+
+ rm -f $alt
+
+ if ! $ar_prog cqs $alt $ar_data1 $ar_data0; then
+ warn "ar -cqs: did not create an archive"
+ fi
+
+ if ! compare_files $ar_f10 $alt; then
+ warn "ar -cqs: did not create expected file"
+ else
+ print "TEST PASSED: ar -cqs creates archives"
+ fi
+
+}
+
function test_err
{
if $ar_prog $@ 2>/dev/null 1>/dev/null; then
@@ -483,6 +523,7 @@ test_x
test_xs
test_m
test_t
+test_q
#
# Note, there are many cases here which probably should be failures and
diff --git a/usr/src/test/util-tests/tests/ctf/precheck.ksh b/usr/src/test/util-tests/tests/ctf/precheck.ksh
index bf6f6be8d8..06339eb769 100644
--- a/usr/src/test/util-tests/tests/ctf/precheck.ksh
+++ b/usr/src/test/util-tests/tests/ctf/precheck.ksh
@@ -29,7 +29,7 @@ check_env()
}
}
-check_env as
+check_env gas
check_env ctfconvert
check_env ctfmerge
check_env elfdump
diff --git a/usr/src/test/util-tests/tests/dladm/Makefile b/usr/src/test/util-tests/tests/dladm/Makefile
index e37ae56072..53fc2ce092 100644
--- a/usr/src/test/util-tests/tests/dladm/Makefile
+++ b/usr/src/test/util-tests/tests/dladm/Makefile
@@ -25,8 +25,6 @@ all:
install: $(ROOTPROG)
-lint:
-
clobber: clean
clean:
diff --git a/usr/src/test/util-tests/tests/pcieadm/pcieadm-priv.ksh b/usr/src/test/util-tests/tests/pcieadm/pcieadm-priv.ksh
index 0e9c8bc796..749e4b5e4b 100644
--- a/usr/src/test/util-tests/tests/pcieadm/pcieadm-priv.ksh
+++ b/usr/src/test/util-tests/tests/pcieadm/pcieadm-priv.ksh
@@ -12,7 +12,7 @@
#
#
-# Copyright 2021 Oxide Computer Company
+# Copyright 2022 Oxide Computer Company
#
#
@@ -48,6 +48,12 @@ pcieadm_validate_filter()
printf "TEST PASSED: show-devs $filter\n"
fi
+ if $pcieadm_prog show-devs $filter 9000/9000/9000; then
+ warn "show-devs $filter 9000/9000/9000, should have failed"
+ else
+ printf "TEST PASSED: show-devs $filter 9000/9000/9000\n"
+ fi
+
if ! $pcieadm_prog show-cfgspace -d $filter >/dev/null; then
warn "failed to show-cfgspace with filter $filter"
else
@@ -96,9 +102,22 @@ else
fi
#
-# Verify based on device.
+# Do the same based on the device name
+#
+pcieadm_dev=$($pcieadm_prog show-devs -p -o driver | \
+ awk '{ if ($1 != "--") { print $1; exit 0 } }')
+if [[ -z "$pcieadm_dev" ]]; then
+ warn "failed to obtain driver based filter"
+else
+ pcieadm_validate_filter "$pcieadm_dev"
+fi
+
+#
+# Verify based on the /devices path. Note, we use the device name to
+# seed this as if there is no device driver attached, the path may
+# overlap with another device on a PCI-only (non-express) based system.
#
-pcieadm_path=$($pcieadm_prog show-devs -p -o path | \
+pcieadm_path=$($pcieadm_prog show-devs -p -o path $pcieadm_dev | \
awk '{ print $1; exit 0 }')
if [[ -z "$pcieadm_path" ]]; then
warn "failed to obtain path based filter"
@@ -107,14 +126,12 @@ else
fi
#
-# Do the same based on the device name
+# Verify a bad filter doesn't work and results in an error.
#
-pcieadm_dev=$($pcieadm_prog show-devs -p -o driver | \
- awk '{ if ($1 != "--") { print $1; exit 0 } }')
-if [[ -z "$pcieadm_dev" ]]; then
- warn "failed to obtain driver based filter"
+if $pcieadm_prog show-devs /enoent >/dev/null; then
+ warn "pcieadm succeeded with bad filter '/enoent'"
else
- pcieadm_validate_filter "$pcieadm_dev"
+ printf "TEST PASSED: show-devs /enoent\n"
fi
if ! $pcieadm_prog save-cfgspace -a "$pcieadm_tmp" > /dev/null; then
diff --git a/usr/src/tools/scripts/onu.1onbld b/usr/src/tools/scripts/onu.1onbld
index 987db80e65..d6fa09ac28 100644
--- a/usr/src/tools/scripts/onu.1onbld
+++ b/usr/src/tools/scripts/onu.1onbld
@@ -162,6 +162,6 @@ If the -U option is not provided, and this variable is set, it will be
used as the publisher name for the packaging repository. If -U is not
provided and this variable is not set, on-nightly will be used.
.SH SEE ALSO
-.BR beadm "(1M), "
-.BR pkg "(1), "
-.BR pkg "(5) "
+.BR beadm (8),
+.BR pkg (1),
+.BR pkg (7)
diff --git a/usr/src/uts/Makefile.targ b/usr/src/uts/Makefile.targ
index 1f686f2ca0..bb03cca4e2 100644
--- a/usr/src/uts/Makefile.targ
+++ b/usr/src/uts/Makefile.targ
@@ -177,6 +177,9 @@ $(ROOT_FONT_DIR)/%: $(OBJS_DIR)/% $(ROOT_MOD_DIR) $(ROOT_FONT_DIR) FRC
$(ROOT_MAC_DIR)/%: $(OBJS_DIR)/% $(ROOT_MOD_DIR) $(ROOT_MAC_DIR) FRC
$(INS.file)
+$(ROOT_OVERLAY_DIR)/%: $(OBJS_DIR)/% $(ROOT_MOD_DIR) $(ROOT_OVERLAY_DIR) FRC
+ $(INS.file)
+
$(USR_DRV_DIR)/%: $(OBJS_DIR)/% $(USR_DRV_DIR) FRC
$(INS.file)
diff --git a/usr/src/uts/Makefile.uts b/usr/src/uts/Makefile.uts
index a508c37287..841e84e40a 100644
--- a/usr/src/uts/Makefile.uts
+++ b/usr/src/uts/Makefile.uts
@@ -400,6 +400,7 @@ ROOT_DACF_DIR_32 = $(ROOT_MOD_DIR)/dacf
ROOT_CRYPTO_DIR_32 = $(ROOT_MOD_DIR)/crypto
ROOT_MAC_DIR_32 = $(ROOT_MOD_DIR)/mac
ROOT_CC_DIR_32 = $(ROOT_MOD_DIR)/cc
+ROOT_OVERLAY_DIR_32 = $(ROOT_MOD_DIR)/overlay
ROOT_KICONV_DIR_32 = $(ROOT_MOD_DIR)/kiconv
ROOT_KERN_DIR_64 = $(ROOT_MOD_DIR)/$(SUBDIR64)
@@ -428,6 +429,7 @@ ROOT_DACF_DIR_64 = $(ROOT_MOD_DIR)/dacf/$(SUBDIR64)
ROOT_CRYPTO_DIR_64 = $(ROOT_MOD_DIR)/crypto/$(SUBDIR64)
ROOT_MAC_DIR_64 = $(ROOT_MOD_DIR)/mac/$(SUBDIR64)
ROOT_CC_DIR_64 = $(ROOT_MOD_DIR)/cc/$(SUBDIR64)
+ROOT_OVERLAY_DIR_64 = $(ROOT_MOD_DIR)/overlay/$(SUBDIR64)
ROOT_KICONV_DIR_64 = $(ROOT_MOD_DIR)/kiconv/$(SUBDIR64)
ROOT_KERN_DIR = $(ROOT_KERN_DIR_$(CLASS))
@@ -456,6 +458,7 @@ ROOT_DACF_DIR = $(ROOT_DACF_DIR_$(CLASS))
ROOT_CRYPTO_DIR = $(ROOT_CRYPTO_DIR_$(CLASS))
ROOT_MAC_DIR = $(ROOT_MAC_DIR_$(CLASS))
ROOT_CC_DIR = $(ROOT_CC_DIR_$(CLASS))
+ROOT_OVERLAY_DIR = $(ROOT_OVERLAY_DIR_$(CLASS))
ROOT_KICONV_DIR = $(ROOT_KICONV_DIR_$(CLASS))
ROOT_FIRMWARE_DIR = $(ROOT_MOD_DIR)/firmware
@@ -475,6 +478,7 @@ ROOT_MOD_DIRS_32 += $(ROOT_CPU_DIR_32) $(ROOT_FONT_DIR_32)
ROOT_MOD_DIRS_32 += $(ROOT_TOD_DIR_32) $(ROOT_DACF_DIR_32)
ROOT_MOD_DIRS_32 += $(ROOT_CRYPTO_DIR_32) $(ROOT_MAC_DIR_32)
ROOT_MOD_DIRS_32 += $(ROOT_CC_DIR_32)
+ROOT_MOD_DIRS_32 += $(ROOT_OVERLAY_DIR_32)
ROOT_MOD_DIRS_32 += $(ROOT_KICONV_DIR_32)
ROOT_MOD_DIRS_32 += $(ROOT_FIRMWARE_DIR)
@@ -568,7 +572,7 @@ PARALLEL_KMODS = $(DRV_KMODS) $(EXEC_KMODS) $(FS_KMODS) $(SCHED_KMODS) \
$(MMU_KMODS) $(DACF_KMODS) $(EXPORT_KMODS) $(IPP_KMODS) \
$(CRYPTO_KMODS) $(PCBE_KMODS) \
$(DRV_KMODS_$(CLASS)) $(MISC_KMODS_$(CLASS)) $(MAC_KMODS) \
- $(BRAND_KMODS) $(KICONV_KMODS) $(CC_KMODS) \
+ $(BRAND_KMODS) $(KICONV_KMODS) $(CC_KMODS) $(OVERLAY_KMODS) \
$(SOCKET_KMODS)
KMODS = $(GENUNIX_KMODS) $(PARALLEL_KMODS)
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 0662cb5308..7050c1b8e7 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -705,6 +705,11 @@ NET80211_OBJS += net80211.o net80211_proto.o net80211_input.o \
VNIC_OBJS += vnic_ctl.o vnic_dev.o
+OVERLAY_OBJS += overlay.o overlay_fm.o overlay_mux.o overlay_plugin.o \
+ overlay_prop.o overlay_target.o
+
+OVERLAY_VXLAN_OBJS += overlay_vxlan.o
+
SIMNET_OBJS += simnet.o
IB_OBJS += ibnex.o ibnex_ioctl.o ibnex_hca.o
@@ -2157,6 +2162,20 @@ CPQARY3_OBJS = cpqary3.o cpqary3_noe.o cpqary3_talk2ctlr.o \
cpqary3_bd.o
#
+# HP Smart Array driver module (smrt)
+#
+SMRT_OBJS = smrt.o \
+ smrt_device.o \
+ smrt_interrupts.o \
+ smrt_commands.o \
+ smrt_logvol.o \
+ smrt_hba.o \
+ smrt_ciss_simple.o \
+ smrt_ciss.o \
+ smrt_physical.o \
+ smrt_sata.o
+
+#
# ISCSI_INITIATOR module
#
ISCSI_INITIATOR_OBJS = chap.o iscsi_io.o iscsi_thread.o \
diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules
index edfcf89150..870758e866 100644
--- a/usr/src/uts/common/Makefile.rules
+++ b/usr/src/uts/common/Makefile.rules
@@ -1004,6 +1004,14 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/nxge/npi/%.c
$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/nxge/%.s
$(COMPILE.s) -o $@ $<
+$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/overlay/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
+$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/overlay/plugins/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/pci-ide/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -1108,6 +1116,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/scsi/adapters/scsi_vhci/fops/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/scsi/adapters/smrt/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/fibre-channel/ulp/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
diff --git a/usr/src/uts/common/disp/cpupart.c b/usr/src/uts/common/disp/cpupart.c
index 123776a123..37d98f8afc 100644
--- a/usr/src/uts/common/disp/cpupart.c
+++ b/usr/src/uts/common/disp/cpupart.c
@@ -885,7 +885,7 @@ cpupart_unbind_threads(cpupart_t *pp, boolean_t unbind_all)
kthread_t *t;
proc_t *p;
int err = 0;
- psetid_t psid = pp->cp_id;
+ psetid_t psid;
ASSERT(pool_lock_held());
ASSERT(MUTEX_HELD(&cpu_lock));
@@ -893,6 +893,7 @@ cpupart_unbind_threads(cpupart_t *pp, boolean_t unbind_all)
if (pp == NULL || pp == &cp_default) {
return (EINVAL);
}
+ psid = pp->cp_id;
/*
* Pre-allocate enough buffers for FSS for all active projects and
@@ -974,7 +975,7 @@ cpupart_destroy(psetid_t psid)
newpp = &cp_default;
while ((cp = pp->cp_cpulist) != NULL) {
- if (err = cpupart_move_cpu(cp, newpp, 0)) {
+ if ((err = cpupart_move_cpu(cp, newpp, 0)) != 0) {
mutex_exit(&cpu_lock);
return (err);
}
diff --git a/usr/src/uts/common/dtrace/dtrace.c b/usr/src/uts/common/dtrace/dtrace.c
index f3a78f5f69..054cb43c9b 100644
--- a/usr/src/uts/common/dtrace/dtrace.c
+++ b/usr/src/uts/common/dtrace/dtrace.c
@@ -11603,8 +11603,8 @@ dtrace_buffer_alloc(dtrace_buffer_t *bufs, size_t size, int flags,
ASSERT(buf->dtb_xamot == NULL);
- if ((buf->dtb_tomax = kmem_zalloc(size,
- KM_NOSLEEP | KM_NORMALPRI)) == NULL)
+ if ((buf->dtb_tomax = kmem_zalloc(size, KM_NOSLEEP_LAZY)) ==
+ NULL)
goto err;
buf->dtb_size = size;
@@ -11615,8 +11615,8 @@ dtrace_buffer_alloc(dtrace_buffer_t *bufs, size_t size, int flags,
if (flags & DTRACEBUF_NOSWITCH)
continue;
- if ((buf->dtb_xamot = kmem_zalloc(size,
- KM_NOSLEEP | KM_NORMALPRI)) == NULL)
+ if ((buf->dtb_xamot = kmem_zalloc(size, KM_NOSLEEP_LAZY)) ==
+ NULL)
goto err;
} while ((cp = cp->cpu_next) != cpu_list);
@@ -13564,7 +13564,7 @@ dtrace_dstate_init(dtrace_dstate_t *dstate, size_t size)
if (size < (min = dstate->dtds_chunksize + sizeof (dtrace_dynhash_t)))
size = min;
- if ((base = kmem_zalloc(size, KM_NOSLEEP | KM_NORMALPRI)) == NULL)
+ if ((base = kmem_zalloc(size, KM_NOSLEEP_LAZY)) == NULL)
return (ENOMEM);
dstate->dtds_size = size;
@@ -14091,7 +14091,7 @@ dtrace_state_go(dtrace_state_t *state, processorid_t *cpu)
}
spec = kmem_zalloc(nspec * sizeof (dtrace_speculation_t),
- KM_NOSLEEP | KM_NORMALPRI);
+ KM_NOSLEEP_LAZY);
if (spec == NULL) {
rval = ENOMEM;
@@ -14102,8 +14102,7 @@ dtrace_state_go(dtrace_state_t *state, processorid_t *cpu)
state->dts_nspeculations = (int)nspec;
for (i = 0; i < nspec; i++) {
- if ((buf = kmem_zalloc(bufsize,
- KM_NOSLEEP | KM_NORMALPRI)) == NULL) {
+ if ((buf = kmem_zalloc(bufsize, KM_NOSLEEP_LAZY)) == NULL) {
rval = ENOMEM;
goto err;
}
diff --git a/usr/src/uts/common/fs/bootfs/bootfs_vfsops.c b/usr/src/uts/common/fs/bootfs/bootfs_vfsops.c
index e642e86169..5b3171e0d1 100644
--- a/usr/src/uts/common/fs/bootfs/bootfs_vfsops.c
+++ b/usr/src/uts/common/fs/bootfs/bootfs_vfsops.c
@@ -93,7 +93,7 @@ bootfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
* there's nothing to be done about that.
*/
vfs_setresource(vfsp, bootfs_name, 0);
- bfs = kmem_zalloc(sizeof (bootfs_t), KM_NOSLEEP | KM_NORMALPRI);
+ bfs = kmem_zalloc(sizeof (bootfs_t), KM_NOSLEEP_LAZY);
if (bfs == NULL)
return (ENOMEM);
diff --git a/usr/src/uts/common/fs/dev/sdev_ptsops.c b/usr/src/uts/common/fs/dev/sdev_ptsops.c
index 4d8f47397b..1b3f1561de 100644
--- a/usr/src/uts/common/fs/dev/sdev_ptsops.c
+++ b/usr/src/uts/common/fs/dev/sdev_ptsops.c
@@ -97,7 +97,6 @@ devpts_strtol(const char *nm, minor_t *mp)
* away, we use the validator to do deferred cleanup i.e. when such
* nodes are encountered during subsequent lookup() and readdir().
*/
-/*ARGSUSED*/
int
devpts_validate(struct sdev_node *dv)
{
@@ -124,8 +123,8 @@ devpts_validate(struct sdev_node *dv)
/*
* Check if pts driver is attached
*/
- if (ptms_slave_attached() == (major_t)-1) {
- sdcmn_err7(("devpts_validate: slave not attached\n"));
+ if (ptms_subsidiary_attached() == (major_t)-1) {
+ sdcmn_err7(("devpts_validate: subsidiary not attached\n"));
return (SDEV_VTOR_INVALID);
}
@@ -159,7 +158,6 @@ devpts_validate(struct sdev_node *dv)
* This callback is invoked from devname_lookup_func() to create
* a pts entry when the node is not found in the cache.
*/
-/*ARGSUSED*/
static int
devpts_create_rvp(struct sdev_node *ddv, char *nm,
void **arg, cred_t *cred, void *whatever, char *whichever)
@@ -177,12 +175,11 @@ devpts_create_rvp(struct sdev_node *ddv, char *nm,
}
/*
- * Check if pts driver is attached and if it is
- * get the major number.
+ * Check if pts driver is attached and if it is get the major number.
*/
- maj = ptms_slave_attached();
+ maj = ptms_subsidiary_attached();
if (maj == (major_t)-1) {
- sdcmn_err7(("devpts_create_rvp: slave not attached\n"));
+ sdcmn_err7(("devpts_create_rvp: subsidiary not attached\n"));
return (-1);
}
@@ -286,7 +283,6 @@ devpts_prunedir(struct sdev_node *ddv)
* access the realvp of the specfs node directly instead of using
* VOP_REALVP().
*/
-/*ARGSUSED3*/
static int
devpts_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
@@ -326,7 +322,6 @@ devpts_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
* - creating an existing dir read-only succeeds, otherwise EISDIR
* - exclusive creates fail - EEXIST
*/
-/*ARGSUSED2*/
static int
devpts_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
int mode, struct vnode **vpp, struct cred *cred, int flag,
@@ -359,11 +354,10 @@ devpts_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
}
/*
- * Display all instantiated pts (slave) device nodes.
- * A /dev/pts entry will be created only after the first lookup of the slave
- * device succeeds.
+ * Display all instantiated pts (subsidiary) device nodes.
+ * A /dev/pts entry will be created only after the first lookup of the
+ * subsidiary device succeeds.
*/
-/*ARGSUSED4*/
static int
devpts_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred,
int *eofp, caller_context_t *ct, int flags)
@@ -387,7 +381,6 @@ devpts_set_id(struct sdev_node *dv, struct vattr *vap, int protocol)
}
-/*ARGSUSED4*/
static int
devpts_setattr(struct vnode *vp, struct vattr *vap, int flags,
struct cred *cred, caller_context_t *ctp)
diff --git a/usr/src/uts/common/fs/nfs/nfs_auth.c b/usr/src/uts/common/fs/nfs/nfs_auth.c
index 3ee8bb07f6..16979e1422 100644
--- a/usr/src/uts/common/fs/nfs/nfs_auth.c
+++ b/usr/src/uts/common/fs/nfs/nfs_auth.c
@@ -922,7 +922,7 @@ nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor,
rw_exit(&exi->exi_cache_lock);
- nc = kmem_alloc(sizeof (*nc), KM_NOSLEEP | KM_NORMALPRI);
+ nc = kmem_alloc(sizeof (*nc), KM_NOSLEEP_LAZY);
if (nc == NULL)
goto retrieve;
@@ -930,8 +930,7 @@ nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor,
* Initialize the new auth_cache_clnt
*/
nc->authc_addr = addr;
- nc->authc_addr.buf = kmem_alloc(addr.maxlen,
- KM_NOSLEEP | KM_NORMALPRI);
+ nc->authc_addr.buf = kmem_alloc(addr.maxlen, KM_NOSLEEP_LAZY);
if (addr.maxlen != 0 && nc->authc_addr.buf == NULL) {
kmem_free(nc, sizeof (*nc));
goto retrieve;
@@ -972,8 +971,7 @@ nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor,
rw_exit(&c->authc_lock);
- np = kmem_cache_alloc(exi_cache_handle,
- KM_NOSLEEP | KM_NORMALPRI);
+ np = kmem_cache_alloc(exi_cache_handle, KM_NOSLEEP_LAZY);
if (np == NULL) {
rw_exit(&exi->exi_cache_lock);
goto retrieve;
@@ -1071,7 +1069,7 @@ nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor,
* auth_cache entry
*/
tmpgids = kmem_alloc(tmpngids * sizeof (gid_t),
- KM_NOSLEEP | KM_NORMALPRI);
+ KM_NOSLEEP_LAZY);
if (tmpgids != NULL)
bcopy(*gids, tmpgids,
tmpngids * sizeof (gid_t));
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_fsctl_copychunk.c b/usr/src/uts/common/fs/smbsrv/smb2_fsctl_copychunk.c
index 4a657bbf19..930bd353c4 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_fsctl_copychunk.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_fsctl_copychunk.c
@@ -204,7 +204,7 @@ smb2_fsctl_copychunk(smb_request_t *sr, smb_fsctl_t *fsctl)
* The client should then fall back to normal copy.
*/
args->bufsize = smb2_copychunk_max_seg;
- args->buffer = kmem_alloc(args->bufsize, KM_NOSLEEP | KM_NORMALPRI);
+ args->buffer = kmem_alloc(args->bufsize, KM_NOSLEEP_LAZY);
if (args->buffer == NULL) {
status = NT_STATUS_INSUFF_SERVER_RESOURCES;
goto out;
diff --git a/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c b/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c
index 0452cddb39..fe748bbd62 100644
--- a/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c
+++ b/usr/src/uts/common/fs/smbsrv/smb2_fsctl_odx.c
@@ -667,7 +667,7 @@ smb2_fsctl_odx_write_native1(smb_request_t *sr,
* allow the allocation to fail and return an error.
* The client should then fall back to normal copy.
*/
- buffer = kmem_alloc(bufsize, KM_NOSLEEP | KM_NORMALPRI);
+ buffer = kmem_alloc(bufsize, KM_NOSLEEP_LAZY);
if (buffer == NULL) {
status = NT_STATUS_INSUFF_SERVER_RESOURCES;
goto out;
diff --git a/usr/src/uts/common/fs/zfs/zcp.c b/usr/src/uts/common/fs/zfs/zcp.c
index ba915ff4f1..e2db01c5b6 100644
--- a/usr/src/uts/common/fs/zfs/zcp.c
+++ b/usr/src/uts/common/fs/zfs/zcp.c
@@ -718,8 +718,7 @@ static void *
zcp_lua_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
{
zcp_alloc_arg_t *allocargs = ud;
- int flags = (allocargs->aa_must_succeed) ?
- KM_SLEEP : (KM_NOSLEEP | KM_NORMALPRI);
+ int flags = (allocargs->aa_must_succeed) ? KM_SLEEP : KM_NOSLEEP_LAZY;
if (nsize == 0) {
if (ptr != NULL) {
diff --git a/usr/src/uts/common/fs/zfs/zfs_dir.c b/usr/src/uts/common/fs/zfs/zfs_dir.c
index 3841c11d11..5d377a109e 100644
--- a/usr/src/uts/common/fs/zfs/zfs_dir.c
+++ b/usr/src/uts/common/fs/zfs/zfs_dir.c
@@ -717,6 +717,7 @@ zfs_rmnode(znode_t *zp)
dmu_tx_hold_free(tx, acl_obj, 0, DMU_OBJECT_END);
zfs_sa_upgrade_txholds(tx, zp);
+ dmu_tx_mark_netfree(tx);
error = dmu_tx_assign(tx, TXG_WAIT);
if (error) {
/*
diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c
index 157b23ded8..1ee01c9146 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vnops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c
@@ -738,6 +738,57 @@ out:
return (error);
}
+static void
+zfs_write_clear_setid_bits_if_necessary(zfsvfs_t *zfsvfs, znode_t *zp,
+ cred_t *cr, boolean_t *did_check, dmu_tx_t *tx)
+{
+ ASSERT(did_check != NULL);
+ ASSERT(tx != NULL);
+
+ if (*did_check)
+ return;
+
+ zilog_t *zilog = zfsvfs->z_log;
+
+ /*
+ * Clear Set-UID/Set-GID bits on successful write if not
+ * privileged and at least one of the execute bits is set.
+ *
+ * It would be nice to do this after all writes have
+ * been done, but that would still expose the ISUID/ISGID
+ * to another app after the partial write is committed.
+ *
+ * Note: we don't call zfs_fuid_map_id() here because
+ * user 0 is not an ephemeral uid.
+ */
+ mutex_enter(&zp->z_acl_lock);
+ if ((zp->z_mode & (S_IXUSR | (S_IXUSR >> 3) | (S_IXUSR >> 6))) != 0 &&
+ (zp->z_mode & (S_ISUID | S_ISGID)) != 0 &&
+ secpolicy_vnode_setid_retain(cr,
+ ((zp->z_mode & S_ISUID) != 0 && zp->z_uid == 0)) != 0) {
+ uint64_t newmode;
+ vattr_t va;
+
+ zp->z_mode &= ~(S_ISUID | S_ISGID);
+ newmode = zp->z_mode;
+ (void) sa_update(zp->z_sa_hdl, SA_ZPL_MODE(zfsvfs),
+ (void *)&newmode, sizeof (uint64_t), tx);
+
+ /*
+ * Make sure SUID/SGID bits will be removed when we replay the
+ * log.
+ */
+ bzero(&va, sizeof (va));
+ va.va_mask = AT_MODE;
+ va.va_nodeid = zp->z_id;
+ va.va_mode = newmode;
+ zfs_log_setattr(zilog, tx, TX_SETATTR, zp, &va, AT_MODE, NULL);
+ }
+ mutex_exit(&zp->z_acl_lock);
+
+ *did_check = B_TRUE;
+}
+
/*
* Write the bytes to a file.
*
@@ -784,6 +835,7 @@ zfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct)
int count = 0;
sa_bulk_attr_t bulk[4];
uint64_t mtime[2], ctime[2];
+ boolean_t did_clear_setid_bits = B_FALSE;
/*
* Fasttrack empty write
@@ -973,6 +1025,11 @@ zfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct)
}
/*
+ * NB: We must call zfs_write_clear_setid_bits_if_necessary
+ * before committing the transaction!
+ */
+
+ /*
* If rangelock_enter() over-locked we grow the blocksize
* and then reduce the lock range. This will only happen
* on the first iteration since rangelock_reduce() will
@@ -1049,30 +1106,8 @@ zfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct)
break;
}
- /*
- * Clear Set-UID/Set-GID bits on successful write if not
- * privileged and at least one of the excute bits is set.
- *
- * It would be nice to to this after all writes have
- * been done, but that would still expose the ISUID/ISGID
- * to another app after the partial write is committed.
- *
- * Note: we don't call zfs_fuid_map_id() here because
- * user 0 is not an ephemeral uid.
- */
- mutex_enter(&zp->z_acl_lock);
- if ((zp->z_mode & (S_IXUSR | (S_IXUSR >> 3) |
- (S_IXUSR >> 6))) != 0 &&
- (zp->z_mode & (S_ISUID | S_ISGID)) != 0 &&
- secpolicy_vnode_setid_retain(cr,
- (zp->z_mode & S_ISUID) != 0 && zp->z_uid == 0) != 0) {
- uint64_t newmode;
- zp->z_mode &= ~(S_ISUID | S_ISGID);
- newmode = zp->z_mode;
- (void) sa_update(zp->z_sa_hdl, SA_ZPL_MODE(zfsvfs),
- (void *)&newmode, sizeof (uint64_t), tx);
- }
- mutex_exit(&zp->z_acl_lock);
+ zfs_write_clear_setid_bits_if_necessary(zfsvfs, zp, cr,
+ &did_clear_setid_bits, tx);
zfs_tstamp_update_setup(zp, CONTENT_MODIFIED, mtime, ctime,
B_TRUE);
@@ -1100,6 +1135,11 @@ zfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct)
prev_error = error;
error = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
+ /*
+ * NB: During replay, the TX_SETATTR record logged by
+ * zfs_write_clear_setid_bits_if_necessary must precede
+ * any of the TX_WRITE records logged here.
+ */
zfs_log_write(zilog, tx, TX_WRITE, zp, woff, tx_bytes, ioflag);
dmu_tx_commit(tx);
diff --git a/usr/src/uts/common/fs/zfs/zfs_znode.c b/usr/src/uts/common/fs/zfs/zfs_znode.c
index 257d5b2a35..84ba5947fa 100644
--- a/usr/src/uts/common/fs/zfs/zfs_znode.c
+++ b/usr/src/uts/common/fs/zfs/zfs_znode.c
@@ -1246,6 +1246,8 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp)
if (zp == NULL) {
err = SET_ERROR(ENOENT);
} else {
+ if (zp->z_links == 0)
+ zp->z_unlinked = B_TRUE;
*zpp = zp;
}
ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num);
diff --git a/usr/src/uts/common/fs/zfs/zio_crypt.c b/usr/src/uts/common/fs/zfs/zio_crypt.c
index 78c26e3e90..9541a0a734 100644
--- a/usr/src/uts/common/fs/zfs/zio_crypt.c
+++ b/usr/src/uts/common/fs/zfs/zio_crypt.c
@@ -1061,14 +1061,17 @@ zio_crypt_do_dnode_hmac_updates(crypto_context_t ctx, uint64_t version,
dnode_phys_t *adnp;
boolean_t le_bswap = (should_bswap == ZFS_HOST_BYTEORDER);
crypto_data_t cd;
- uint8_t tmp_dncore[offsetof(dnode_phys_t, dn_blkptr)];
+ uint8_t tmp_dncore[sizeof (dnode_phys_t)];
+ adnp = (dnode_phys_t *)tmp_dncore;
cd.cd_format = CRYPTO_DATA_RAW;
cd.cd_offset = 0;
+ cd.cd_length = offsetof(dnode_phys_t, dn_blkptr);
+ cd.cd_raw.iov_base = (char *)adnp;
+ cd.cd_raw.iov_len = cd.cd_length;
/* authenticate the core dnode (masking out non-portable bits) */
- bcopy(dnp, tmp_dncore, sizeof (tmp_dncore));
- adnp = (dnode_phys_t *)tmp_dncore;
+ bcopy(dnp, tmp_dncore, cd.cd_length);
if (le_bswap) {
adnp->dn_datablkszsec = BSWAP_16(adnp->dn_datablkszsec);
adnp->dn_bonuslen = BSWAP_16(adnp->dn_bonuslen);
@@ -1078,10 +1081,6 @@ zio_crypt_do_dnode_hmac_updates(crypto_context_t ctx, uint64_t version,
adnp->dn_flags &= DNODE_CRYPT_PORTABLE_FLAGS_MASK;
adnp->dn_used = 0;
- cd.cd_length = sizeof (tmp_dncore);
- cd.cd_raw.iov_base = (char *)adnp;
- cd.cd_raw.iov_len = cd.cd_length;
-
ret = crypto_mac_update(ctx, &cd, NULL);
if (ret != CRYPTO_SUCCESS) {
ret = SET_ERROR(EIO);
diff --git a/usr/src/uts/common/inet/ip/ip_attr.c b/usr/src/uts/common/inet/ip/ip_attr.c
index 6dfbc53d77..0aa969d971 100644
--- a/usr/src/uts/common/inet/ip/ip_attr.c
+++ b/usr/src/uts/common/inet/ip/ip_attr.c
@@ -862,7 +862,7 @@ conn_get_ixa_exclusive(conn_t *connp)
ip_xmit_attr_t *oldixa;
ip_xmit_attr_t *ixa;
- ixa = kmem_alloc(sizeof (*ixa), KM_NOSLEEP | KM_NORMALPRI);
+ ixa = kmem_alloc(sizeof (*ixa), KM_NOSLEEP_LAZY);
if (ixa == NULL)
return (NULL);
diff --git a/usr/src/uts/common/inet/udp/udp.c b/usr/src/uts/common/inet/udp/udp.c
index 58e6d95e99..5d42a69fa2 100644
--- a/usr/src/uts/common/inet/udp/udp.c
+++ b/usr/src/uts/common/inet/udp/udp.c
@@ -22,7 +22,7 @@
* Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
* Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
- * Copyright 2015, Joyent, Inc.
+ * Copyright 2018, Joyent, Inc.
* Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
*/
/* Copyright (c) 1990 Mentat Inc. */
@@ -388,7 +388,19 @@ udp_srcport_hash(mblk_t *mp, int type, uint16_t min, uint16_t max,
if (!IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t)))
return (def);
- if (MBLKL(mp) < VXLAN_HDR_LEN) {
+ /*
+ * The following logic is VXLAN specific to get at the header, if we
+ * have formats, eg. GENEVE, then we should ignore this.
+ *
+ * The kernel overlay device often puts a first mblk_t for the data
+ * which is just the encap. If so, then we're going to use that and try
+ * to avoid a pull up.
+ */
+ if (MBLKL(mp) == VXLAN_HDR_LEN) {
+ if (mp->b_cont == NULL)
+ return (def);
+ mp = mp->b_cont;
+ } else if (MBLKL(mp) < VXLAN_HDR_LEN) {
return (def);
} else {
szused = VXLAN_HDR_LEN;
diff --git a/usr/src/uts/common/io/audio/impl/audio_ddi.c b/usr/src/uts/common/io/audio/impl/audio_ddi.c
index 7acf57da82..41ac11d528 100644
--- a/usr/src/uts/common/io/audio/impl/audio_ddi.c
+++ b/usr/src/uts/common/io/audio/impl/audio_ddi.c
@@ -507,7 +507,7 @@ audio_init_ops(struct dev_ops *devops, const char *name)
(void) strlcpy(helper->name, name, sizeof (helper->name));
- helper->minfo.mi_idnum = 0; /* only for strlog(1M) */
+ helper->minfo.mi_idnum = 0; /* only for strlog(8) */
helper->minfo.mi_idname = helper->name;
helper->minfo.mi_minpsz = 0;
helper->minfo.mi_maxpsz = 8192;
diff --git a/usr/src/uts/common/io/avintr.c b/usr/src/uts/common/io/avintr.c
index 05afc12055..f13eda8a34 100644
--- a/usr/src/uts/common/io/avintr.c
+++ b/usr/src/uts/common/io/avintr.c
@@ -741,7 +741,7 @@ av_dispatch_softvect(uint_t pil)
caddr_t arg2;
ASSERT_STACK_ALIGNED();
- ASSERT(pil >= 0 && pil <= PIL_MAX);
+ ASSERT3U(pil, <=, PIL_MAX);
for (av = softvect[pil].avh_link; av; av = av->av_link) {
/*
diff --git a/usr/src/uts/common/io/blkdev/blkdev.c b/usr/src/uts/common/io/blkdev/blkdev.c
index c0bdb3dab2..611666b0a1 100644
--- a/usr/src/uts/common/io/blkdev/blkdev.c
+++ b/usr/src/uts/common/io/blkdev/blkdev.c
@@ -26,6 +26,7 @@
* Copyright 2017 The MathWorks, Inc. All rights reserved.
* Copyright 2019 Western Digital Corporation.
* Copyright 2020 Joyent, Inc.
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
*/
#include <sys/types.h>
@@ -55,6 +56,11 @@
#include <sys/note.h>
#include <sys/blkdev.h>
#include <sys/scsi/impl/inquiry.h>
+#include <sys/taskq.h>
+#include <sys/taskq_impl.h>
+#include <sys/disp.h>
+#include <sys/sysevent/eventdefs.h>
+#include <sys/sysevent/dev.h>
/*
* blkdev is a driver which provides a lot of the common functionality
@@ -122,8 +128,8 @@
*
* Locks
* -----
- * There are 4 instance global locks d_ocmutex, d_ksmutex, d_errmutex and
- * d_statemutex. As well a q_iomutex per waitq/runq pair.
+ * There are 5 instance global locks d_ocmutex, d_ksmutex, d_errmutex,
+ * d_statemutex and d_dle_mutex. As well a q_iomutex per waitq/runq pair.
*
* Lock Hierarchy
* --------------
@@ -139,11 +145,16 @@ typedef struct bd bd_t;
typedef struct bd_xfer_impl bd_xfer_impl_t;
typedef struct bd_queue bd_queue_t;
+typedef enum {
+ BD_DLE_PENDING = 1 << 0,
+ BD_DLE_RUNNING = 1 << 1
+} bd_dle_state_t;
+
struct bd {
void *d_private;
dev_info_t *d_dip;
- kmutex_t d_ocmutex;
- kmutex_t d_ksmutex;
+ kmutex_t d_ocmutex; /* open/close */
+ kmutex_t d_ksmutex; /* kstat */
kmutex_t d_errmutex;
kmutex_t d_statemutex;
kcondvar_t d_statecv;
@@ -183,6 +194,10 @@ struct bd {
ddi_dma_attr_t d_dma;
bd_ops_t d_ops;
bd_handle_t d_handle;
+
+ kmutex_t d_dle_mutex;
+ taskq_ent_t d_dle_ent;
+ bd_dle_state_t d_dle_state;
};
struct bd_handle {
@@ -328,20 +343,34 @@ static struct modlinkage modlinkage = {
static void *bd_state;
static krwlock_t bd_lock;
+static taskq_t *bd_taskq;
int
_init(void)
{
- int rv;
+ char taskq_name[TASKQ_NAMELEN];
+ const char *name;
+ int rv;
rv = ddi_soft_state_init(&bd_state, sizeof (struct bd), 2);
- if (rv != DDI_SUCCESS) {
+ if (rv != DDI_SUCCESS)
return (rv);
+
+ name = mod_modname(&modlinkage);
+ (void) snprintf(taskq_name, sizeof (taskq_name), "%s_taskq", name);
+ bd_taskq = taskq_create(taskq_name, 1, minclsyspri, 0, 0, 0);
+ if (bd_taskq == NULL) {
+ cmn_err(CE_WARN, "%s: unable to create %s", name, taskq_name);
+ ddi_soft_state_fini(&bd_state);
+ return (DDI_FAILURE);
}
+
rw_init(&bd_lock, NULL, RW_DRIVER, NULL);
+
rv = mod_install(&modlinkage);
if (rv != DDI_SUCCESS) {
rw_destroy(&bd_lock);
+ taskq_destroy(bd_taskq);
ddi_soft_state_fini(&bd_state);
}
return (rv);
@@ -355,6 +384,7 @@ _fini(void)
rv = mod_remove(&modlinkage);
if (rv == DDI_SUCCESS) {
rw_destroy(&bd_lock);
+ taskq_destroy(bd_taskq);
ddi_soft_state_fini(&bd_state);
}
return (rv);
@@ -696,6 +726,8 @@ bd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
mutex_init(&bd->d_ocmutex, NULL, MUTEX_DRIVER, NULL);
mutex_init(&bd->d_statemutex, NULL, MUTEX_DRIVER, NULL);
cv_init(&bd->d_statecv, NULL, CV_DRIVER, NULL);
+ mutex_init(&bd->d_dle_mutex, NULL, MUTEX_DRIVER, NULL);
+ bd->d_dle_state = 0;
bd->d_cache = kmem_cache_create(kcache, sizeof (bd_xfer_impl_t), 8,
bd_xfer_ctor, bd_xfer_dtor, NULL, bd, NULL, 0);
@@ -853,6 +885,7 @@ fail_drive_info:
mutex_destroy(&bd->d_statemutex);
mutex_destroy(&bd->d_ocmutex);
mutex_destroy(&bd->d_ksmutex);
+ mutex_destroy(&bd->d_dle_mutex);
ddi_soft_state_free(bd_state, inst);
return (DDI_FAILURE);
}
@@ -891,6 +924,7 @@ bd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
mutex_destroy(&bd->d_ocmutex);
mutex_destroy(&bd->d_statemutex);
cv_destroy(&bd->d_statecv);
+ mutex_destroy(&bd->d_dle_mutex);
bd_queues_free(bd);
ddi_soft_state_free(bd_state, ddi_get_instance(dip));
return (DDI_SUCCESS);
@@ -1890,6 +1924,69 @@ bd_runq_exit(bd_xfer_impl_t *xi, int err)
}
static void
+bd_dle_sysevent_task(void *arg)
+{
+ nvlist_t *attr = NULL;
+ char *path = NULL;
+ bd_t *bd = arg;
+ dev_info_t *dip = bd->d_dip;
+ size_t n;
+
+ mutex_enter(&bd->d_dle_mutex);
+ bd->d_dle_state &= ~BD_DLE_PENDING;
+ bd->d_dle_state |= BD_DLE_RUNNING;
+ mutex_exit(&bd->d_dle_mutex);
+
+ dev_err(dip, CE_NOTE, "!dynamic LUN expansion");
+
+ if (nvlist_alloc(&attr, NV_UNIQUE_NAME_TYPE, KM_SLEEP) != 0) {
+ mutex_enter(&bd->d_dle_mutex);
+ bd->d_dle_state &= ~(BD_DLE_RUNNING|BD_DLE_PENDING);
+ mutex_exit(&bd->d_dle_mutex);
+ return;
+ }
+
+ path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+
+ n = snprintf(path, MAXPATHLEN, "/devices");
+ (void) ddi_pathname(dip, path + n);
+ n = strlen(path);
+ n += snprintf(path + n, MAXPATHLEN - n, ":x");
+
+ for (;;) {
+ /*
+ * On receipt of this event, the ZFS sysevent module will scan
+ * active zpools for child vdevs matching this physical path.
+ * In order to catch both whole disk pools and those with an
+ * EFI boot partition, generate separate sysevents for minor
+ * node 'a' and 'b'. (By comparison, io/scsi/targets/sd.c sends
+ * events for just 'a')
+ */
+ for (char c = 'a'; c < 'c'; c++) {
+ path[n - 1] = c;
+
+ if (nvlist_add_string(attr, DEV_PHYS_PATH, path) != 0)
+ break;
+
+ (void) ddi_log_sysevent(dip, DDI_VENDOR_SUNW,
+ EC_DEV_STATUS, ESC_DEV_DLE, attr, NULL, DDI_SLEEP);
+ }
+
+ mutex_enter(&bd->d_dle_mutex);
+ if ((bd->d_dle_state & BD_DLE_PENDING) == 0) {
+ bd->d_dle_state &= ~BD_DLE_RUNNING;
+ mutex_exit(&bd->d_dle_mutex);
+ break;
+ }
+ bd->d_dle_state &= ~BD_DLE_PENDING;
+ mutex_exit(&bd->d_dle_mutex);
+ }
+
+ nvlist_free(attr);
+ kmem_free(path, MAXPATHLEN);
+}
+
+static void
bd_update_state(bd_t *bd)
{
enum dkio_state state = DKIO_INSERTED;
@@ -1908,8 +2005,7 @@ bd_update_state(bd_t *bd)
if ((media.m_blksize < 512) ||
(!ISP2(media.m_blksize)) ||
(P2PHASE(bd->d_maxxfer, media.m_blksize))) {
- cmn_err(CE_WARN, "%s%d: Invalid media block size (%d)",
- ddi_driver_name(bd->d_dip), ddi_get_instance(bd->d_dip),
+ dev_err(bd->d_dip, CE_WARN, "Invalid media block size (%d)",
media.m_blksize);
/*
* We can't use the media, treat it as not present.
@@ -1954,6 +2050,21 @@ done:
if (docmlb) {
if (state == DKIO_INSERTED) {
(void) cmlb_validate(bd->d_cmlbh, 0, 0);
+
+ mutex_enter(&bd->d_dle_mutex);
+ /*
+ * If there is already an event pending, there's
+ * nothing to do; we coalesce multiple events.
+ */
+ if ((bd->d_dle_state & BD_DLE_PENDING) == 0) {
+ if ((bd->d_dle_state & BD_DLE_RUNNING) == 0) {
+ taskq_dispatch_ent(bd_taskq,
+ bd_dle_sysevent_task, bd, 0,
+ &bd->d_dle_ent);
+ }
+ bd->d_dle_state |= BD_DLE_PENDING;
+ }
+ mutex_exit(&bd->d_dle_mutex);
} else {
cmlb_invalidate(bd->d_cmlbh, 0);
}
diff --git a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c
index 4ab032e354..d39f1954b1 100644
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c
@@ -2389,7 +2389,7 @@ sbd_write_same_data(struct scsi_task *task, sbd_cmd_t *scmd)
* Don't sleep for the allocation, and don't make the system
* reclaim memory. Trade higher I/Os if in a low-memory situation.
*/
- big_buf = kmem_alloc(big_buf_size, KM_NOSLEEP | KM_NORMALPRI);
+ big_buf = kmem_alloc(big_buf_size, KM_NOSLEEP_LAZY);
if (big_buf == NULL) {
/*
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3.c b/usr/src/uts/common/io/cpqary3/cpqary3.c
index 622f0dcf68..f67d77b3d2 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3.c
+++ b/usr/src/uts/common/io/cpqary3/cpqary3.c
@@ -41,7 +41,7 @@ extern cpqary3_driver_info_t gdriver_info;
* Global Variables Definitions
*/
-static char cpqary3_brief[] = "HP Smart Array Driver";
+static char cpqary3_brief[] = "HP Smart Array (Legacy)";
void *cpqary3_state;
/* HPQaculi Changes */
diff --git a/usr/src/uts/common/io/dld/dld_drv.c b/usr/src/uts/common/io/dld/dld_drv.c
index eca17349c3..dbcd9caea8 100644
--- a/usr/src/uts/common/io/dld/dld_drv.c
+++ b/usr/src/uts/common/io/dld/dld_drv.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent Inc.
* Copyright (c) 2017, Joyent, Inc.
*/
@@ -631,7 +632,7 @@ drv_ioc_prop_common(dld_ioc_macprop_t *prop, intptr_t arg, boolean_t set,
cred_t *cred, int mode)
{
int err = EINVAL;
- dls_dl_handle_t dlh = NULL;
+ dls_dl_handle_t dlh = NULL;
dls_link_t *dlp = NULL;
mac_perim_handle_t mph = NULL;
dld_ioc_macprop_t *kprop;
@@ -1327,7 +1328,7 @@ drv_ioc_gettran(void *karg, intptr_t arg, int mode, cred_t *cred,
{
int ret = 0;
mac_perim_handle_t mph = NULL;
- dls_dl_handle_t dlh = NULL;
+ dls_dl_handle_t dlh = NULL;
dls_link_t *dlp = NULL;
dld_ioc_gettran_t *dgt = karg;
@@ -1371,7 +1372,7 @@ drv_ioc_readtran(void *karg, intptr_t arg, int mode, cred_t *cred,
{
int ret = 0;
mac_perim_handle_t mph = NULL;
- dls_dl_handle_t dlh = NULL;
+ dls_dl_handle_t dlh = NULL;
dls_link_t *dlp = NULL;
dld_ioc_tranio_t *dti = karg;
uint8_t buf[256];
@@ -1424,7 +1425,7 @@ drv_ioc_getled(void *karg, intptr_t arg, int mode, cred_t *cred,
{
int ret = 0;
mac_perim_handle_t mph = NULL;
- dls_dl_handle_t dlh = NULL;
+ dls_dl_handle_t dlh = NULL;
dls_link_t *dlp = NULL;
dld_ioc_led_t *dil = karg;
@@ -1470,7 +1471,7 @@ drv_ioc_setled(void *karg, intptr_t arg, int mode, cred_t *cred,
{
int ret = 0;
mac_perim_handle_t mph = NULL;
- dls_dl_handle_t dlh = NULL;
+ dls_dl_handle_t dlh = NULL;
dls_link_t *dlp = NULL;
dld_ioc_led_t *dil = karg;
@@ -1585,7 +1586,8 @@ static dld_ioc_modentry_t dld_ioc_modtable[] = {
{SIMNET_IOC, "simnet", 0, NULL, 0},
{BRIDGE_IOC, "bridge", 0, NULL, 0},
{IPTUN_IOC, "iptun", 0, NULL, 0},
- {IBPART_IOC, "ibp", -1, NULL, 0}
+ {IBPART_IOC, "ibp", -1, NULL, 0},
+ {OVERLAY_IOC, "overlay", 0, NULL, 0}
};
#define DLDIOC_CNT \
(sizeof (dld_ioc_modtable) / sizeof (dld_ioc_modentry_t))
diff --git a/usr/src/uts/common/io/iwn/if_iwnreg.h b/usr/src/uts/common/io/iwn/if_iwnreg.h
index 78bfc3088f..e6d6d6d4b8 100644
--- a/usr/src/uts/common/io/iwn/if_iwnreg.h
+++ b/usr/src/uts/common/io/iwn/if_iwnreg.h
@@ -100,10 +100,10 @@
#define IWN_MEM_WADDR 0x410
#define IWN_MEM_WDATA 0x418
#define IWN_MEM_RDATA 0x41c
-#define IWN_PRPH_WADDR 0x444
-#define IWN_PRPH_RADDR 0x448
-#define IWN_PRPH_WDATA 0x44c
-#define IWN_PRPH_RDATA 0x450
+#define IWN_PRPH_WADDR 0x444
+#define IWN_PRPH_RADDR 0x448
+#define IWN_PRPH_WDATA 0x44c
+#define IWN_PRPH_RDATA 0x450
#define IWN_HBUS_TARG_WRPTR 0x460
/*
@@ -1694,8 +1694,8 @@ static const struct iwn_chan_band {
{ 11, { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 } }
};
-#define IWN1000_OTP_NBLOCKS 3
-#define IWN6000_OTP_NBLOCKS 4
+#define IWN1000_OTP_NBLOCKS 3
+#define IWN6000_OTP_NBLOCKS 4
#define IWN6050_OTP_NBLOCKS 7
/* HW rate indices. */
@@ -1971,7 +1971,7 @@ static const char * const iwn_fw_errmsg[] = {
"NMI_INTERRUPT_DATA_ACTION_PT",
"NMI_TRM_HW_ER",
"NMI_INTERRUPT_TRM",
- "NMI_INTERRUPT_BREAKPOINT"
+ "NMI_INTERRUPT_BREAKPOINT",
"DEBUG_0",
"DEBUG_1",
"DEBUG_2",
diff --git a/usr/src/uts/common/io/mac/mac_client.c b/usr/src/uts/common/io/mac/mac_client.c
index 605cb51bf7..167ed2b90f 100644
--- a/usr/src/uts/common/io/mac/mac_client.c
+++ b/usr/src/uts/common/io/mac/mac_client.c
@@ -4524,7 +4524,13 @@ mac_addr_len(mac_handle_t mh)
boolean_t
mac_is_vnic(mac_handle_t mh)
{
- return (((mac_impl_t *)mh)->mi_state_flags & MIS_IS_VNIC);
+ return ((((mac_impl_t *)mh)->mi_state_flags & MIS_IS_VNIC) != 0);
+}
+
+boolean_t
+mac_is_overlay(mac_handle_t mh)
+{
+ return ((((mac_impl_t *)mh)->mi_state_flags & MIS_IS_OVERLAY) != 0);
}
mac_handle_t
diff --git a/usr/src/uts/common/io/mac/mac_datapath_setup.c b/usr/src/uts/common/io/mac/mac_datapath_setup.c
index bfb41afe5e..0da404853c 100644
--- a/usr/src/uts/common/io/mac/mac_datapath_setup.c
+++ b/usr/src/uts/common/io/mac/mac_datapath_setup.c
@@ -605,6 +605,7 @@ mac_srs_cpu_setup(cpu_setup_t what, int id, void *arg)
*
* TODO: Cleanup and tighten some of the assumptions.
*/
+boolean_t mac_check_overlay = B_TRUE;
boolean_t mac_use_bw_heuristic = B_TRUE;
static int
mac_compute_soft_ring_count(flow_entry_t *flent, int rx_srs_cnt, int maxcpus)
@@ -612,6 +613,7 @@ mac_compute_soft_ring_count(flow_entry_t *flent, int rx_srs_cnt, int maxcpus)
uint64_t cpu_speed, bw = 0;
int srings = 0;
boolean_t bw_enabled = B_FALSE;
+ mac_client_impl_t *mcip = flent->fe_mcip;
ASSERT(!(flent->fe_type & FLOW_USER));
if (flent->fe_resource_props.mrp_mask & MRP_MAXBW &&
@@ -639,7 +641,16 @@ mac_compute_soft_ring_count(flow_entry_t *flent, int rx_srs_cnt, int maxcpus)
*/
if (mac_soft_ring_enable)
srings = srings * 2;
+ } else if (mac_check_overlay == B_TRUE &&
+ (mcip->mci_state_flags & MCIS_IS_VNIC) != 0) {
+ /* Is this a VNIC on an overlay? */
+ mac_handle_t mh = (mac_handle_t)mcip->mci_mip;
+ if (mac_is_overlay(mh) == B_TRUE) {
+ srings = mac_rx_soft_ring_10gig_count;
+ }
}
+
+
} else {
/*
* Soft ring computation using CPU speed and specified
diff --git a/usr/src/uts/common/io/mac/mac_protect.c b/usr/src/uts/common/io/mac/mac_protect.c
index da83dc643e..17959ac48d 100644
--- a/usr/src/uts/common/io/mac/mac_protect.c
+++ b/usr/src/uts/common/io/mac/mac_protect.c
@@ -1469,8 +1469,8 @@ insert_slaac_prefix(mac_client_impl_t *mcip, nd_opt_prefix_info_t *po)
return;
}
- if ((addr = kmem_zalloc(sizeof (slaac_addr_t),
- KM_NOSLEEP | KM_NORMALPRI)) == NULL)
+ if ((addr = kmem_zalloc(sizeof (slaac_addr_t), KM_NOSLEEP_LAZY)) ==
+ NULL)
return;
bcopy(&po->nd_opt_pi_prefix, &addr->sla_prefix,
diff --git a/usr/src/uts/common/io/mac/mac_provider.c b/usr/src/uts/common/io/mac/mac_provider.c
index bfaf232d25..bcca602589 100644
--- a/usr/src/uts/common/io/mac/mac_provider.c
+++ b/usr/src/uts/common/io/mac/mac_provider.c
@@ -393,6 +393,9 @@ mac_register(mac_register_t *mregp, mac_handle_t *mhp)
if (i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_AGGR, NULL))
mip->mi_state_flags |= MIS_IS_AGGR;
+ if (i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_OVERLAY, NULL))
+ mip->mi_state_flags |= MIS_IS_OVERLAY;
+
mac_addr_factory_init(mip);
mac_transceiver_init(mip);
diff --git a/usr/src/uts/common/io/mwl/mwl.c b/usr/src/uts/common/io/mwl/mwl.c
index 47bffb6cd8..114b32eeab 100644
--- a/usr/src/uts/common/io/mwl/mwl.c
+++ b/usr/src/uts/common/io/mwl/mwl.c
@@ -268,12 +268,14 @@ static int mwl_hal_sethwdma(struct mwl_softc *,
const struct mwl_hal_txrxdma *);
static int mwl_hal_getchannelinfo(struct mwl_softc *, int, int,
const MWL_HAL_CHANNELINFO **);
-static int mwl_hal_setmac_locked(struct mwl_softc *, const uint8_t *);
+static int mwl_hal_setmac_locked(struct mwl_softc *,
+ const uint8_t [IEEE80211_ADDR_LEN]);
static int mwl_hal_keyreset(struct mwl_softc *, const MWL_HAL_KEYVAL *,
const uint8_t mac[IEEE80211_ADDR_LEN]);
static int mwl_hal_keyset(struct mwl_softc *, const MWL_HAL_KEYVAL *,
const uint8_t mac[IEEE80211_ADDR_LEN]);
-static int mwl_hal_newstation(struct mwl_softc *, const uint8_t *,
+static int mwl_hal_newstation(struct mwl_softc *,
+ const uint8_t [IEEE80211_ADDR_LEN],
uint16_t, uint16_t, const MWL_HAL_PEERINFO *, int, int);
static int mwl_hal_setantenna(struct mwl_softc *, MWL_HAL_ANTENNA, int);
static int mwl_hal_setradio(struct mwl_softc *, int, MWL_HAL_PREAMBLE);
@@ -288,8 +290,8 @@ static int mwl_hal_settxrate_auto(struct mwl_softc *,
static int mwl_hal_setrateadaptmode(struct mwl_softc *, uint16_t);
static int mwl_hal_setoptimizationlevel(struct mwl_softc *, int);
static int mwl_hal_setregioncode(struct mwl_softc *, int);
-static int mwl_hal_setassocid(struct mwl_softc *, const uint8_t *,
- uint16_t);
+static int mwl_hal_setassocid(struct mwl_softc *,
+ const uint8_t [IEEE80211_ADDR_LEN], uint16_t);
static int mwl_setrates(struct ieee80211com *);
static int mwl_hal_setrtsthreshold(struct mwl_softc *, int);
static int mwl_hal_setcsmode(struct mwl_softc *, MWL_HAL_CSMODE);
@@ -307,7 +309,8 @@ static int mwl_key_delete(struct ieee80211com *,
const struct ieee80211_key *);
static int mwl_key_set(struct ieee80211com *, const struct ieee80211_key *,
const uint8_t mac[IEEE80211_ADDR_LEN]);
-static void mwl_setanywepkey(struct ieee80211com *, const uint8_t *);
+static void mwl_setanywepkey(struct ieee80211com *,
+ const uint8_t [IEEE80211_ADDR_LEN]);
static void mwl_setglobalkeys(struct ieee80211com *c);
static int addgroupflags(MWL_HAL_KEYVAL *, const struct ieee80211_key *);
static void mwl_hal_txstart(struct mwl_softc *, int);
@@ -346,8 +349,8 @@ mwl_debug(uint32_t dbg_flags, const int8_t *fmt, ...)
*/
static int
mwl_alloc_dma_mem(dev_info_t *devinfo, ddi_dma_attr_t *dma_attr,
- size_t memsize, ddi_device_acc_attr_t *attr_p, uint_t alloc_flags,
- uint_t bind_flags, struct dma_area *dma_p)
+ size_t memsize, ddi_device_acc_attr_t *attr_p, uint_t alloc_flags,
+ uint_t bind_flags, struct dma_area *dma_p)
{
int err;
@@ -1466,7 +1469,7 @@ addchan(struct mwl_channel *c, int freq, int flags, int ieee, int txpow)
static const struct mwl_channel *
findchannel(const struct mwl_channel chans[], int nchans,
- int freq, int flags)
+ int freq, int flags)
{
const struct mwl_channel *c;
int i;
@@ -1481,7 +1484,7 @@ findchannel(const struct mwl_channel chans[], int nchans,
static void
addht40channels(struct mwl_channel chans[], int maxchans, int *nchans,
- const MWL_HAL_CHANNELINFO *ci, int flags)
+ const MWL_HAL_CHANNELINFO *ci, int flags)
{
struct mwl_channel *c;
const struct mwl_channel *extc;
@@ -1518,7 +1521,7 @@ addht40channels(struct mwl_channel chans[], int maxchans, int *nchans,
static void
addchannels(struct mwl_channel chans[], int maxchans, int *nchans,
- const MWL_HAL_CHANNELINFO *ci, int flags)
+ const MWL_HAL_CHANNELINFO *ci, int flags)
{
struct mwl_channel *c;
int i;
@@ -1567,7 +1570,7 @@ addchannels(struct mwl_channel chans[], int maxchans, int *nchans,
static int
mwl_hal_getchannelinfo(struct mwl_softc *sc, int band, int chw,
- const MWL_HAL_CHANNELINFO **ci)
+ const MWL_HAL_CHANNELINFO **ci)
{
switch (band) {
case MWL_FREQ_BAND_2DOT4GHZ:
@@ -1585,7 +1588,7 @@ mwl_hal_getchannelinfo(struct mwl_softc *sc, int band, int chw,
static void
getchannels(struct mwl_softc *sc, int maxchans, int *nchans,
- struct mwl_channel chans[])
+ struct mwl_channel chans[])
{
const MWL_HAL_CHANNELINFO *ci;
@@ -1679,7 +1682,7 @@ mwl_gethwspecs(struct mwl_softc *sc)
static int
mwl_hal_setmac_locked(struct mwl_softc *sc,
- const uint8_t addr[IEEE80211_ADDR_LEN])
+ const uint8_t addr[IEEE80211_ADDR_LEN])
{
HostCmd_DS_SET_MAC *pCmd;
@@ -1709,8 +1712,8 @@ cvtPeerInfo(PeerInfo_t *to, const MWL_HAL_PEERINFO *from)
/* XXX station id must be in [0..63] */
static int
mwl_hal_newstation(struct mwl_softc *sc,
- const uint8_t addr[IEEE80211_ADDR_LEN], uint16_t aid, uint16_t sid,
- const MWL_HAL_PEERINFO *peer, int isQosSta, int wmeInfo)
+ const uint8_t addr[IEEE80211_ADDR_LEN], uint16_t aid, uint16_t sid,
+ const MWL_HAL_PEERINFO *peer, int isQosSta, int wmeInfo)
{
HostCmd_FW_SET_NEW_STN *pCmd;
int retval;
@@ -1895,7 +1898,7 @@ mwl_hal_settxpower(struct mwl_softc *sc,
static int
mwl_hal_settxrate(struct mwl_softc *sc, MWL_HAL_TXRATE_HANDLING handling,
- const MWL_HAL_TXRATE *rate)
+ const MWL_HAL_TXRATE *rate)
{
HostCmd_FW_USE_FIXED_RATE *pCmd;
FIXED_RATE_ENTRY *fp;
@@ -2024,7 +2027,7 @@ mwl_hal_setregioncode(struct mwl_softc *sc, int regionCode)
static int
mwl_hal_setassocid(struct mwl_softc *sc,
- const uint8_t bssId[IEEE80211_ADDR_LEN], uint16_t assocId)
+ const uint8_t bssId[IEEE80211_ADDR_LEN], uint16_t assocId)
{
HostCmd_FW_SET_AID *pCmd = (HostCmd_FW_SET_AID *) &sc->sc_cmd_mem[0];
int retval;
@@ -2154,7 +2157,7 @@ mwl_hal_stop(struct mwl_softc *sc)
static int
mwl_hal_keyset(struct mwl_softc *sc, const MWL_HAL_KEYVAL *kv,
- const uint8_t mac[IEEE80211_ADDR_LEN])
+ const uint8_t mac[IEEE80211_ADDR_LEN])
{
HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY *pCmd;
int retval;
@@ -2261,7 +2264,7 @@ mwl_node_free(struct ieee80211_node *ni)
*/
static int
mwl_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k,
- ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
+ ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
{
if (k->wk_keyix != IEEE80211_KEYIX_NONE ||
(k->wk_flags & IEEE80211_KEY_GROUP)) {
@@ -2328,7 +2331,7 @@ mwl_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
/* ARGSUSED */
static int
mwl_key_set(struct ieee80211com *ic, const struct ieee80211_key *k,
- const uint8_t mac[IEEE80211_ADDR_LEN])
+ const uint8_t mac[IEEE80211_ADDR_LEN])
{
#define GRPXMIT (IEEE80211_KEY_XMIT | IEEE80211_KEY_GROUP)
/* NB: static wep keys are marked GROUP+tx/rx; GTK will be tx or rx */
diff --git a/usr/src/uts/common/io/nvme/nvme.c b/usr/src/uts/common/io/nvme/nvme.c
index 6cdd8275e4..c368ecb365 100644
--- a/usr/src/uts/common/io/nvme/nvme.c
+++ b/usr/src/uts/common/io/nvme/nvme.c
@@ -10,13 +10,12 @@
*/
/*
- * Copyright 2018 Nexenta Systems, Inc.
- * Copyright 2016 Tegile Systems, Inc. All rights reserved.
* Copyright (c) 2016 The MathWorks, Inc. All rights reserved.
* Copyright 2020 Joyent, Inc.
- * Copyright 2019 Western Digital Corporation.
* Copyright 2020 Racktop Systems.
* Copyright 2022 Oxide Computer Company.
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
*/
/*
@@ -216,7 +215,7 @@
*
* While the callback registration relies on the NDI event framework, the
* removal event itself is kicked off in the PCIe hotplug framework, when the
- * PCIe bridge driver ("pcieb") gets a hotplug interrupt indicatating that a
+ * PCIe bridge driver ("pcieb") gets a hotplug interrupt indicating that a
* device was removed from the slot.
*
* The NVMe driver instance itself will remain until the final close of the
@@ -343,7 +342,7 @@ int nvme_commit_save_cmd_timeout = 15;
/*
* tunable for the size of arbitrary vendor specific admin commands,
- * default is 16MiB
+ * default is 16MiB.
*/
uint32_t nvme_vendor_specific_admin_cmd_size = 1 << 24;
@@ -444,6 +443,8 @@ static int nvme_open(dev_t *, int, int, cred_t *);
static int nvme_close(dev_t, int, int, cred_t *);
static int nvme_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+static void nvme_changed_ns(nvme_t *, int);
+
static ddi_ufm_ops_t nvme_ufm_ops = {
NULL,
nvme_ufm_fill_image,
@@ -456,7 +457,35 @@ static ddi_ufm_ops_t nvme_ufm_ops = {
#define NVME_MINOR_INST(minor) ((minor) >> NVME_MINOR_INST_SHIFT)
#define NVME_MINOR_NSID(minor) ((minor) & ((1 << NVME_MINOR_INST_SHIFT) - 1))
#define NVME_MINOR_MAX (NVME_MINOR(1, 0) - 2)
-#define NVME_IS_VENDOR_UNIQUE_CMD(x) (((x) >= 0xC0) && ((x) <= 0xFF))
+#define NVME_IS_VENDOR_SPECIFIC_CMD(x) (((x) >= 0xC0) && ((x) <= 0xFF))
+#define NVME_VENDOR_SPECIFIC_LOGPAGE_MIN 0xC0
+#define NVME_VENDOR_SPECIFIC_LOGPAGE_MAX 0xFF
+#define NVME_IS_VENDOR_SPECIFIC_LOGPAGE(x) \
+ (((x) >= NVME_VENDOR_SPECIFIC_LOGPAGE_MIN) && \
+ ((x) <= NVME_VENDOR_SPECIFIC_LOGPAGE_MAX))
+
+/*
+ * NVMe versions 1.3 and later actually support log pages up to UINT32_MAX
+ * DWords in size. However, revision 1.3 also modified the layout of the Get Log
+ * Page command significantly relative to version 1.2, including changing
+ * reserved bits, adding new bitfields, and requiring the use of command DWord
+ * 11 to fully specify the size of the log page (the lower and upper 16 bits of
+ * the number of DWords in the page are split between DWord 10 and DWord 11,
+ * respectively).
+ *
+ * All of these impose significantly different layout requirements on the
+ * `nvme_getlogpage_t` type. This could be solved with two different types, or a
+ * complicated/nested union with the two versions as the overlying members. Both
+ * of these are reasonable, if a bit convoluted. However, these is no current
+ * need for such large pages, or a way to test them, as most log pages actually
+ * fit within the current size limit. So for simplicity, we retain the size cap
+ * from version 1.2.
+ *
+ * Note that the number of DWords is zero-based, so we add 1. It is subtracted
+ * to form a zero-based value in `nvme_get_logpage`.
+ */
+#define NVME_VENDOR_SPECIFIC_LOGPAGE_MAX_SIZE \
+ (((1 << 12) + 1) * sizeof (uint32_t))
static void *nvme_state;
static kmem_cache_t *nvme_cmd_cache;
@@ -1762,6 +1791,7 @@ nvme_async_event_task(void *arg)
nvme_t *nvme = cmd->nc_nvme;
nvme_error_log_entry_t *error_log = NULL;
nvme_health_log_t *health_log = NULL;
+ nvme_nschange_list_t *nslist = NULL;
size_t logsize = 0;
nvme_async_event_t event;
@@ -1804,7 +1834,6 @@ nvme_async_event_task(void *arg)
return;
}
-
event.r = cmd->nc_cqe.cqe_dw0;
/* Clear CQE and re-submit the async request. */
@@ -1898,6 +1927,91 @@ nvme_async_event_task(void *arg)
}
break;
+ case NVME_ASYNC_TYPE_NOTICE:
+ switch (event.b.ae_info) {
+ case NVME_ASYNC_NOTICE_NS_CHANGE:
+ dev_err(nvme->n_dip, CE_NOTE,
+ "namespace attribute change event, "
+ "logpage = %x", event.b.ae_logpage);
+ atomic_inc_32(&nvme->n_notice_event);
+
+ if (event.b.ae_logpage != NVME_LOGPAGE_NSCHANGE)
+ break;
+
+ if (nvme_get_logpage(nvme, B_FALSE, (void **)&nslist,
+ &logsize, event.b.ae_logpage, -1) != 0) {
+ break;
+ }
+
+ if (nslist->nscl_ns[0] == UINT32_MAX) {
+ dev_err(nvme->n_dip, CE_CONT,
+ "more than %u namespaces have changed.\n",
+ NVME_NSCHANGE_LIST_SIZE);
+ break;
+ }
+
+ for (uint_t i = 0; i < NVME_NSCHANGE_LIST_SIZE; i++) {
+ uint32_t nsid = nslist->nscl_ns[i];
+
+ if (nsid == 0) /* end of list */
+ break;
+ nvme_changed_ns(nvme, nsid);
+ }
+
+ break;
+
+ case NVME_ASYNC_NOTICE_FW_ACTIVATE:
+ dev_err(nvme->n_dip, CE_NOTE,
+ "firmware activation starting, "
+ "logpage = %x", event.b.ae_logpage);
+ atomic_inc_32(&nvme->n_notice_event);
+ break;
+
+ case NVME_ASYNC_NOTICE_TELEMETRY:
+ dev_err(nvme->n_dip, CE_NOTE,
+ "telemetry log changed, "
+ "logpage = %x", event.b.ae_logpage);
+ atomic_inc_32(&nvme->n_notice_event);
+ break;
+
+ case NVME_ASYNC_NOTICE_NS_ASYMM:
+ dev_err(nvme->n_dip, CE_NOTE,
+ "asymmetric namespace access change, "
+ "logpage = %x", event.b.ae_logpage);
+ atomic_inc_32(&nvme->n_notice_event);
+ break;
+
+ case NVME_ASYNC_NOTICE_LATENCYLOG:
+ dev_err(nvme->n_dip, CE_NOTE,
+ "predictable latency event aggregate log change, "
+ "logpage = %x", event.b.ae_logpage);
+ atomic_inc_32(&nvme->n_notice_event);
+ break;
+
+ case NVME_ASYNC_NOTICE_LBASTATUS:
+ dev_err(nvme->n_dip, CE_NOTE,
+ "LBA status information alert, "
+ "logpage = %x", event.b.ae_logpage);
+ atomic_inc_32(&nvme->n_notice_event);
+ break;
+
+ case NVME_ASYNC_NOTICE_ENDURANCELOG:
+ dev_err(nvme->n_dip, CE_NOTE,
+ "endurance group event aggregate log page change, "
+ "logpage = %x", event.b.ae_logpage);
+ atomic_inc_32(&nvme->n_notice_event);
+ break;
+
+ default:
+ dev_err(nvme->n_dip, CE_WARN,
+ "!unknown notice async event received, "
+ "info = %x, logpage = %x", event.b.ae_info,
+ event.b.ae_logpage);
+ atomic_inc_32(&nvme->n_unknown_event);
+ break;
+ }
+ break;
+
case NVME_ASYNC_TYPE_VENDOR:
dev_err(nvme->n_dip, CE_WARN, "!vendor specific async event "
"received, info = %x, logpage = %x", event.b.ae_info,
@@ -1913,11 +2027,14 @@ nvme_async_event_task(void *arg)
break;
}
- if (error_log)
+ if (error_log != NULL)
kmem_free(error_log, logsize);
- if (health_log)
+ if (health_log != NULL)
kmem_free(health_log, logsize);
+
+ if (nslist != NULL)
+ kmem_free(nslist, logsize);
}
static void
@@ -1988,6 +2105,12 @@ nvme_format_nvm(nvme_t *nvme, boolean_t user, uint32_t nsid, uint8_t lbaf,
return (ret);
}
+/*
+ * The `bufsize` parameter is usually an output parameter, set by this routine
+ * when filling in the supported types of logpages from the device. However, for
+ * vendor-specific pages, it is an input parameter, and must be set
+ * appropriately by callers.
+ */
static int
nvme_get_logpage(nvme_t *nvme, boolean_t user, void **buf, size_t *bufsize,
uint8_t logpage, ...)
@@ -2011,11 +2134,7 @@ nvme_get_logpage(nvme_t *nvme, boolean_t user, void **buf, size_t *bufsize,
switch (logpage) {
case NVME_LOGPAGE_ERROR:
cmd->nc_sqe.sqe_nsid = (uint32_t)-1;
- /*
- * The GET LOG PAGE command can use at most 2 pages to return
- * data, PRP lists are not supported.
- */
- *bufsize = MIN(2 * nvme->n_pagesize,
+ *bufsize = MIN(NVME_VENDOR_SPECIFIC_LOGPAGE_MAX_SIZE,
nvme->n_error_log_len * sizeof (nvme_error_log_entry_t));
break;
@@ -2029,12 +2148,26 @@ nvme_get_logpage(nvme_t *nvme, boolean_t user, void **buf, size_t *bufsize,
*bufsize = sizeof (nvme_fwslot_log_t);
break;
+ case NVME_LOGPAGE_NSCHANGE:
+ cmd->nc_sqe.sqe_nsid = (uint32_t)-1;
+ *bufsize = sizeof (nvme_nschange_list_t);
+ break;
+
default:
- dev_err(nvme->n_dip, CE_WARN, "!unknown log page requested: %d",
- logpage);
- atomic_inc_32(&nvme->n_unknown_logpage);
- ret = EINVAL;
- goto fail;
+ /*
+ * This intentionally only checks against the minimum valid
+ * log page ID. `logpage` is a uint8_t, and `0xFF` is a valid
+ * page ID, so this one-sided check avoids a compiler error
+ * about a check that's always true.
+ */
+ if (logpage < NVME_VENDOR_SPECIFIC_LOGPAGE_MIN) {
+ dev_err(nvme->n_dip, CE_WARN,
+ "!unknown log page requested: %d", logpage);
+ atomic_inc_32(&nvme->n_unknown_logpage);
+ ret = EINVAL;
+ goto fail;
+ }
+ cmd->nc_sqe.sqe_nsid = va_arg(ap, uint32_t);
}
va_end(ap);
@@ -2051,22 +2184,8 @@ nvme_get_logpage(nvme_t *nvme, boolean_t user, void **buf, size_t *bufsize,
goto fail;
}
- if (cmd->nc_dma->nd_ncookie > 2) {
- dev_err(nvme->n_dip, CE_WARN,
- "!too many DMA cookies for GET LOG PAGE");
- atomic_inc_32(&nvme->n_too_many_cookies);
- ret = ENOMEM;
+ if ((ret = nvme_fill_prp(cmd, cmd->nc_dma->nd_dmah)) != 0)
goto fail;
- }
-
- cmd->nc_sqe.sqe_dptr.d_prp[0] = cmd->nc_dma->nd_cookie.dmac_laddress;
- if (cmd->nc_dma->nd_ncookie > 1) {
- ddi_dma_nextcookie(cmd->nc_dma->nd_dmah,
- &cmd->nc_dma->nd_cookie);
- cmd->nc_sqe.sqe_dptr.d_prp[1] =
- cmd->nc_dma->nd_cookie.dmac_laddress;
- }
-
nvme_admin_cmd(cmd, nvme_admin_cmd_timeout);
if ((ret = nvme_check_cmd_status(cmd)) != 0) {
@@ -2367,7 +2486,7 @@ nvme_set_nqueues(nvme_t *nvme)
nvme->n_completion_queues = nvme->n_intr_cnt;
/*
- * There is no point in having more compeletion queues than
+ * There is no point in having more completion queues than
* interrupt vectors.
*/
nvme->n_completion_queues = MIN(nvme->n_completion_queues,
@@ -2570,6 +2689,41 @@ nvme_prepare_devid(nvme_t *nvme, uint32_t nsid)
nvme->n_idctl->id_vid, model, serial, nsid);
}
+static void
+nvme_changed_ns(nvme_t *nvme, int nsid)
+{
+ nvme_namespace_t *ns = &nvme->n_ns[nsid - 1];
+ nvme_identify_nsid_t *idns, *oidns;
+
+ dev_err(nvme->n_dip, CE_NOTE, "!namespace %u (%s) has changed.",
+ nsid, ns->ns_name);
+
+ if (ns->ns_ignore)
+ return;
+
+ /*
+ * The namespace has changed in some way. At present, we only update
+ * the device capacity and trigger blkdev to check the device state.
+ */
+
+ if (nvme_identify(nvme, B_FALSE, nsid, (void **)&idns) != 0) {
+ dev_err(nvme->n_dip, CE_WARN,
+ "!failed to identify namespace %d", nsid);
+ return;
+ }
+
+ oidns = ns->ns_idns;
+ ns->ns_idns = idns;
+ kmem_free(oidns, sizeof (nvme_identify_nsid_t));
+
+ ns->ns_block_count = idns->id_nsize;
+ ns->ns_block_size =
+ 1 << idns->id_lbaf[idns->id_flbas.lba_format].lbaf_lbads;
+ ns->ns_best_block_size = ns->ns_block_size;
+
+ bd_state_change(ns->ns_bd_hdl);
+}
+
static int
nvme_init_ns(nvme_t *nvme, int nsid)
{
@@ -2842,7 +2996,7 @@ nvme_init(nvme_t *nvme)
sema_init(&nvme->n_abort_sema, 1, NULL, SEMA_DRIVER, NULL);
/*
- * Setup initial interrupt for admin queue.
+ * Set up initial interrupt for admin queue.
*/
if ((nvme_setup_interrupts(nvme, DDI_INTR_TYPE_MSIX, 1)
!= DDI_SUCCESS) &&
@@ -3474,7 +3628,7 @@ nvme_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
nvme->n_sgl_dma_attr = nvme_sgl_dma_attr;
/*
- * Setup FMA support.
+ * Set up FMA support.
*/
nvme->n_fm_cap = ddi_getprop(DDI_DEV_T_ANY, dip,
DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "fm-capable",
@@ -4285,7 +4439,7 @@ nvme_ioc_cmd(nvme_t *nvme, nvme_sqe_t *sqe, boolean_t is_admin, void *data_addr,
}
/*
- * This function is used to faciliate requests from
+ * This function is used to facilitate requests from
* userspace, so don't panic if the command fails. This
* is especially true for admin passthru commands, where
* the actual command data structure is entirely defined
@@ -4426,7 +4580,19 @@ nvme_ioctl_get_logpage(nvme_t *nvme, int nsid, nvme_ioctl_t *nioc,
return (EINVAL);
break;
default:
- return (EINVAL);
+ if (!NVME_IS_VENDOR_SPECIFIC_LOGPAGE(nioc->n_arg))
+ return (EINVAL);
+ if (nioc->n_len > NVME_VENDOR_SPECIFIC_LOGPAGE_MAX_SIZE) {
+ dev_err(nvme->n_dip, CE_NOTE, "!Vendor-specific log "
+ "page size exceeds device maximum supported size: "
+ "%lu", NVME_VENDOR_SPECIFIC_LOGPAGE_MAX_SIZE);
+ return (EINVAL);
+ }
+ if (nioc->n_len == 0)
+ return (EINVAL);
+ bufsize = nioc->n_len;
+ if (nsid == 0)
+ nsid = (uint32_t)-1;
}
if (nvme_get_logpage(nvme, B_TRUE, &log, &bufsize, nioc->n_arg, nsid)
@@ -4734,6 +4900,7 @@ nvme_ioctl_firmware_download(nvme_t *nvme, int nsid, nvme_ioctl_t *nioc,
size_t len, copylen;
offset_t offset;
uintptr_t buf;
+ nvme_cqe_t cqe = { 0 };
nvme_sqe_t sqe = {
.sqe_opc = NVME_OPC_FW_IMAGE_LOAD
};
@@ -4759,6 +4926,9 @@ nvme_ioctl_firmware_download(nvme_t *nvme, int nsid, nvme_ioctl_t *nioc,
len = nioc->n_len;
offset = nioc->n_arg;
buf = (uintptr_t)nioc->n_buf;
+
+ nioc->n_arg = 0;
+
while (len > 0 && rv == 0) {
/*
* nvme_ioc_cmd() does not use SGLs or PRP lists.
@@ -4771,7 +4941,22 @@ nvme_ioctl_firmware_download(nvme_t *nvme, int nsid, nvme_ioctl_t *nioc,
sqe.sqe_cdw11 = (uint32_t)(offset >> NVME_DWORD_SHIFT);
rv = nvme_ioc_cmd(nvme, &sqe, B_TRUE, (void *)buf, copylen,
- FWRITE, NULL, nvme_admin_cmd_timeout);
+ FWRITE, &cqe, nvme_admin_cmd_timeout);
+
+ /*
+ * Regardless of whether the command succeeded or not, whether
+ * there's an errno in rv to be returned, we'll return any
+ * command-specific status code in n_arg.
+ *
+ * As n_arg isn't cleared in all other possible code paths
+ * returning an error, we return the status code as a negative
+ * value so it can be distinguished easily from whatever value
+ * was passed in n_arg originally. This of course only works as
+ * long as arguments passed in n_arg are less than INT64_MAX,
+ * which they currently are.
+ */
+ if (cqe.cqe_sf.sf_sct == NVME_CQE_SCT_SPECIFIC)
+ nioc->n_arg = (uint64_t)-cqe.cqe_sf.sf_sc;
buf += copylen;
offset += copylen;
@@ -4815,6 +5000,8 @@ nvme_ioctl_firmware_commit(nvme_t *nvme, int nsid, nvme_ioctl_t *nioc,
case NVME_FWC_SAVE:
case NVME_FWC_SAVE_ACTIVATE:
timeout = nvme_commit_save_cmd_timeout;
+ if (slot == 1 && nvme->n_idctl->id_frmw.fw_readonly)
+ return (EROFS);
break;
case NVME_FWC_ACTIVATE:
case NVME_FWC_ACTIVATE_IMMED:
@@ -4828,9 +5015,23 @@ nvme_ioctl_firmware_commit(nvme_t *nvme, int nsid, nvme_ioctl_t *nioc,
fc_dw10.b.fc_action = action;
sqe.sqe_cdw10 = fc_dw10.r;
+ nioc->n_arg = 0;
rv = nvme_ioc_cmd(nvme, &sqe, B_TRUE, NULL, 0, 0, &cqe, timeout);
- nioc->n_arg = ((uint64_t)cqe.cqe_sf.sf_sct << 16) | cqe.cqe_sf.sf_sc;
+ /*
+ * Regardless of whether the command succeeded or not, whether
+ * there's an errno in rv to be returned, we'll return any
+ * command-specific status code in n_arg.
+ *
+ * As n_arg isn't cleared in all other possible code paths
+ * returning an error, we return the status code as a negative
+ * value so it can be distinguished easily from whatever value
+ * was passed in n_arg originally. This of course only works as
+ * long as arguments passed in n_arg are less than INT64_MAX,
+ * which they currently are.
+ */
+ if (cqe.cqe_sf.sf_sct == NVME_CQE_SCT_SPECIFIC)
+ nioc->n_arg = (uint64_t)-cqe.cqe_sf.sf_sc;
/*
* Let the DDI UFM subsystem know that the firmware information for
@@ -4977,7 +5178,7 @@ nvme_ioctl_passthru(nvme_t *nvme, int nsid, nvme_ioctl_t *nioc, int mode,
if (nvme_passthru_copy_cmd_in((const void*)nioc->n_buf, &cmd, mode))
return (EFAULT);
- if (!NVME_IS_VENDOR_UNIQUE_CMD(cmd.npc_opcode)) {
+ if (!NVME_IS_VENDOR_SPECIFIC_CMD(cmd.npc_opcode)) {
cmd.npc_err = NVME_PASSTHRU_ERR_INVALID_OPCODE;
rv = EINVAL;
goto out;
diff --git a/usr/src/uts/common/io/nvme/nvme_reg.h b/usr/src/uts/common/io/nvme/nvme_reg.h
index 110b1ea6b4..9c981cf33a 100644
--- a/usr/src/uts/common/io/nvme/nvme_reg.h
+++ b/usr/src/uts/common/io/nvme/nvme_reg.h
@@ -13,6 +13,7 @@
* Copyright 2016 Nexenta Systems, Inc. All rights reserved.
* Copyright 2020 Joyent, Inc.
* Copyright 2019 Western Digital Corporation
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
*/
/*
@@ -327,7 +328,8 @@ typedef struct {
*/
#define NVME_ASYNC_TYPE_ERROR 0x0 /* Error Status */
#define NVME_ASYNC_TYPE_HEALTH 0x1 /* SMART/Health Status */
-#define NVME_ASYNC_TYPE_VENDOR 0x7 /* vendor specific */
+#define NVME_ASYNC_TYPE_NOTICE 0x2 /* Notice (1.2) */
+#define NVME_ASYNC_TYPE_VENDOR 0x7 /* Vendor specific */
#define NVME_ASYNC_ERROR_INV_SQ 0x0 /* Invalid Submission Queue */
#define NVME_ASYNC_ERROR_INV_DBL 0x1 /* Invalid Doorbell Write */
@@ -340,6 +342,17 @@ typedef struct {
#define NVME_ASYNC_HEALTH_TEMPERATURE 0x1 /* Temp. Above Threshold */
#define NVME_ASYNC_HEALTH_SPARE 0x2 /* Spare Below Threshold */
+/* NVMe 1.2 */
+#define NVME_ASYNC_NOTICE_NS_CHANGE 0x0 /* Namespace attribute change */
+#define NVME_ASYNC_NOTICE_FW_ACTIVATE 0x1 /* Firmware activation start */
+/* NVMe 1.3 */
+#define NVME_ASYNC_NOTICE_TELEMETRY 0x2 /* Telemetry log changed */
+/* NVMe 1.4 */
+#define NVME_ASYNC_NOTICE_NS_ASYMM 0x3 /* Asymm. NS access change */
+#define NVME_ASYNC_NOTICE_LATENCYLOG 0x4 /* Pred. Latency log change */
+#define NVME_ASYNC_NOTICE_LBASTATUS 0x5 /* LBA status alert */
+#define NVME_ASYNC_NOTICE_ENDURANCELOG 0x6 /* Endurance log change */
+
typedef union {
struct {
uint8_t ae_type:3; /* Asynchronous Event Type */
diff --git a/usr/src/uts/common/io/nvme/nvme_var.h b/usr/src/uts/common/io/nvme/nvme_var.h
index 4742807d5d..75039d4bc7 100644
--- a/usr/src/uts/common/io/nvme/nvme_var.h
+++ b/usr/src/uts/common/io/nvme/nvme_var.h
@@ -15,6 +15,7 @@
* Copyright 2019 Joyent, Inc.
* Copyright 2019 Western Digital Corporation.
* Copyright 2021 Oxide Computer Company.
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
*/
#ifndef _NVME_VAR_H
@@ -252,6 +253,7 @@ struct nvme {
uint32_t n_temperature_event;
uint32_t n_spare_event;
uint32_t n_vendor_event;
+ uint32_t n_notice_event;
uint32_t n_unknown_event;
/* hot removal NDI event handling */
diff --git a/usr/src/uts/common/io/overlay/overlay.c b/usr/src/uts/common/io/overlay/overlay.c
new file mode 100644
index 0000000000..6e5c808690
--- /dev/null
+++ b/usr/src/uts/common/io/overlay/overlay.c
@@ -0,0 +1,2184 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * Overlay Devices
+ *
+ * Overlay devices provide a means for creating overlay networks, a means of
+ * multiplexing multiple logical, isolated, and discrete layer two and layer
+ * three networks on top of one physical network.
+ *
+ * In general, these overlay devices encapsulate the logic to answer two
+ * different questions:
+ *
+ * 1) How should I transform a packet to put it on the wire?
+ * 2) Where should I send a transformed packet?
+ *
+ * Each overlay device is presented to the user as a GLDv3 device. While the
+ * link itself cannot have an IP interface created on top of it, it allows for
+ * additional GLDv3 devices, such as a VNIC, to be created on top of it which
+ * can be plumbed up with IP interfaces.
+ *
+ *
+ * --------------------
+ * General Architecture
+ * --------------------
+ *
+ * The logical overlay device that a user sees in dladm(8) is a combination of
+ * two different components that work together. The first component is this
+ * kernel module, which is responsible for answering question one -- how should
+ * I transform a packet to put it on the wire.
+ *
+ * The second component is what we call the virtual ARP daemon, or varpd. It is
+ * a userland component that is responsible for answering the second question --
+ * Where should I send a transformed packet. Instances of the kernel overlay
+ * GLDv3 device ask varpd the question of where should a packet go.
+ *
+ * The split was done for a few reasons. Importantly, we wanted to keep the act
+ * of generating encapsulated packets in the kernel so as to ensure that the
+ * general data path was fast and also kept simple. On the flip side, while the
+ * question of where should something go may be simple, it may often be
+ * complicated and need to interface with several different external or
+ * distributed systems. In those cases, it's simpler to allow for the full
+ * flexibility of userland to be brought to bear to solve that problem and in
+ * general, the path isn't very common.
+ *
+ * The following is what makes up the logical overlay device that a user would
+ * create with dladm(8).
+ *
+ * Kernel Userland
+ * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+ * . +--------+ +--------+ +--------+ . . .
+ * . | VNIC 0 | | VNIC 1 | | VNIC 2 | . . .
+ * . +--------+ +--------+ +--------+ . . .
+ * . | | | . . .
+ * . | | | . . .
+ * . +------------+-----------+ . . .
+ * . | . . /dev/overlay .
+ * . +--------------+ . . . +------------+ .
+ * . | | . . . | | .
+ * . | Overlay |======*=================| Virtual | .
+ * . | GLDv3 Device |========================| ARP Daemon | .
+ * . | | . . | | .
+ * . +--------------+ . . +------------+ .
+ * . | . . | .
+ * . | . . | .
+ * . +----------------+ . . +--------+ .
+ * . | Overlay | . . | varpd | .
+ * . | Encapsulation | . . | Lookup | .
+ * . | Plugin | . . | Plugin | .
+ * . +----------------+ . . +--------+ .
+ * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+ *
+ *
+ * This image shows the two different components and where they live.
+ * Importantly, it also shows that both the kernel overlay device and the
+ * userland varpd both support plugins. The plugins actually implement the
+ * things that users care about and the APIs have been designed to try to
+ * minimize the amount of things that a module writer needs to worry about it.
+ *
+ * IDENTIFIERS
+ *
+ * Every overlay device is defined by a unique identifier which is the overlay
+ * identifier. Its purpose is similar to that of a VLAN identifier, it's a
+ * unique number that is used to differentiate between different entries on the
+ * wire.
+ *
+ * ENCAPSULATION
+ *
+ * An overlay encapsulation plugin is a kernel miscellaneous module whose
+ * purpose is to contain knowledge about how to transform packets to put them
+ * onto the wire and to take them off. An example of an encapsulation plugin is
+ * vxlan. It's also how support for things like nvgre or geneve would be brought
+ * into the system.
+ *
+ * Each encapsulation plugins defines a series of operation vectors and
+ * properties. For the full details on everything they should provide, please
+ * read uts/common/sys/overlay_plugin.h. The encapsulation plugin is responsible
+ * for telling the system what information is required to send a packet. For
+ * example, vxlan is defined to send everything over a UDP packet and therefore
+ * requires a port and an IP address, while nvgre on the other hand is its own
+ * IP type and therefore just requires an IP address. In addition, it also
+ * provides information about the kind of socket that should be created. This is
+ * used by the kernel multiplexor, more of that in the Kernel Components
+ * section.
+ *
+ * LOOKUPS
+ *
+ * The kernel communicates requests for lookups over the character device
+ * /dev/overlay. varpd is responsible for listening for requests on that device
+ * and answering them. The character device is specific to the target path and
+ * varpd.
+ *
+ * Much as the kernel overlay module handles the bulk of the scaffolding but
+ * leaves the important work to the encapsulation plugin, varpd provides a
+ * similar role and leaves the full brunt of lookups to a userland dynamic
+ * shared object which implements the logic of lookups.
+ *
+ * Each lookup plugin defines a series of operation vectors and properties. For
+ * the full details on everything that they should provide, please read
+ * lib/varpd/libvarpd/libvarpd_provider.h. Essentially, they are given a MAC
+ * address and asked to give an address on the physical network that it should
+ * be sent to. In addition, they handle questions related to how to handle
+ * things like broadcast and multicast traffic, etc.
+ *
+ * ----------
+ * Properties
+ * ----------
+ *
+ * A device from a dladm perspective has a unique set of properties that are
+ * combined from three different sources:
+ *
+ * 1) Generic properties that every overlay device has
+ * 2) Properties that are specific to the encapsulation plugin
+ * 3) Properties that are specific to the lookup plugin
+ *
+ * All of these are exposed in a single set of properties in dladm. Note that
+ * these are not necessarily traditional link properties. However, if something
+ * is both a traditional GLDv3 link property, say the MTU of a device, and a
+ * specific property here, than the driver ensures that all existing GLDv3
+ * specific means of manipulating it are used and wraps up its private property
+ * interfaces to ensure that works.
+ *
+ * Properties in the second and third category are prefixed with the name of
+ * their module. For example, the vxlan encapsulation module has a property
+ * called the 'listen_ip'. This property would show up in dladm as
+ * 'vxlan/listen_ip'. This allows different plugins to both use similar names
+ * for similar properties and to also have independent name spaces so that
+ * overlapping names do not conflict with anything else.
+ *
+ * While the kernel combines both sets one and two into a single coherent view,
+ * it does not do anything with respect to the properties that are owned by the
+ * lookup plugin -- those are owned wholly by varpd. Instead, libdladm is in
+ * charge of bridging these two worlds into one magical experience for the user.
+ * It carries the burden of knowing about both overlay specific and varpd
+ * specific properties. Importantly, we want to maintain this distinction. We
+ * don't want to treat the kernel as an arbitrary key/value store for varpd and
+ * we want the kernel to own its own data and not have to ask userland for
+ * information that it owns.
+ *
+ * Every property in the system has the following attributes:
+ *
+ * o A name
+ * o A type
+ * o A size
+ * o Permissions
+ * o Default value
+ * o Valid value ranges
+ * o A value
+ *
+ * Everything except for the value is obtained by callers through the propinfo
+ * callbacks and a property has a maximum size of OVERLAY_PROP_SIZEMAX,
+ * currently 256 bytes.
+ *
+ * The following are the supported types of properties:
+ *
+ * OVERLAY_PROP_T_INT
+ *
+ * A signed integer, its length is 8 bytes, corresponding to a
+ * int64_t.
+ *
+ * OVERLAY_PROP_T_UINT
+ *
+ * An unsigned integer, its length is 8 bytes, corresponding to a
+ * uint64_t.
+ *
+ * OVERLAY_PROP_T_IP
+ *
+ * A struct in6_addr, it has a fixed size.
+ *
+ * OVERLAY_PROP_T_STRING
+ *
+ * A null-terminated character string encoded in either ASCII or
+ * UTF-8. Note that the size of the string includes the null
+ * terminator.
+ *
+ * The next thing that we apply to a property is its permission. The permissions
+ * are put together by the bitwise or of the following flags and values.
+ *
+ * OVERLAY_PROP_PERM_REQ
+ *
+ * This indicates a required property. A property that is required
+ * must be set by a consumer before the device can be created. If a
+ * required property has a default property, this constraint is
+ * loosened because the default property defines the value.
+ *
+ * OVERLAY_PORP_PERM_READ
+ *
+ * This indicates that a property can be read. All properties will
+ * have this value set.
+ *
+ * OVERLAY_PROP_PERM_WRITE
+ *
+ * This indicates that a property can be written to and thus
+ * updated by userland. Properties that are only intended to
+ * display information, will not have OVERLAY_PROP_PERM_WRITE set.
+ *
+ * In addition, a few additional values are defined as a convenience to
+ * consumers. The first, OVERLAY_PROP_PERM_RW, is a combination of
+ * OVERLAY_PROP_PERM_READ and OVERLAY_PERM_PROP_WRITE. The second,
+ * OVERLAY_PROP_PERM_RRW, is a combination of OVERLAY_PROP_PERM_REQ,
+ * OVERLAY_PROP_PERM_READ, and OVERLAY_PROP_PERM_WRITE. The protection mode of a
+ * property should generally be a constant across its lifetime.
+ *
+ * A property may optionally have a default value. If it does have a default
+ * value, and that property is not set to be a different value, then the default
+ * value is inherited automatically. It also means that if the default value is
+ * acceptable, there is no need to set the value for a required property. For
+ * example, the vxlan module has the vxlan/listen_port property which is
+ * required, but has a default value of 4789 (the IANA assigned port). Because
+ * of that default value, there is no need for it to be set.
+ *
+ * Finally, a property may declare a list of valid values. These valid values
+ * are used for display purposes, they are not enforced by the broader system,
+ * but merely allow a means for the information to be communicated to the user
+ * through dladm(8). Like a default value, this is optional.
+ *
+ * The general scaffolding does not do very much with respect to the getting and
+ * setting of properties. That is really owned by the individual plugins
+ * themselves.
+ *
+ * -----------------------------
+ * Destinations and Plugin Types
+ * -----------------------------
+ *
+ * Both encapsulation and lookup plugins define the kinds of destinations that
+ * they know how to support. There are three different pieces of information
+ * that can be used to address to a destination currently, all of which is
+ * summarized in the type overlay_point_t. Any combination of these is
+ * supported.
+ *
+ * OVERLAY_PLUGIN_D_ETHERNET
+ *
+ * An Ethernet MAC address is required.
+ *
+ * OVERLAY_PLUGIN_D_IP
+ *
+ * An IP address is required. All IP addresses used by the overlay
+ * system are transmitted as IPv6 addresses. IPv4 addresses can be
+ * represented by using IPv4-mapped IPv6 addresses.
+ *
+ * OVERLAY_PLUGIN_D_PORT
+ *
+ * A TCP/UDP port is required.
+ *
+ * A kernel encapsulation plugin declares which of these that it requires, it's
+ * a static set. On the other hand, a userland lookup plugin can be built to
+ * support all of these or any combination thereof. It gets passed the required
+ * destination type, based on the kernel encapsulation method, and then it makes
+ * the determination as to whether or not it supports it. For example, the
+ * direct plugin can support either an IP or both an IP and a port, it simply
+ * doesn't display the direct/dest_port property in the cases where a port is
+ * not required to support this.
+ *
+ * The user lookup plugins have two different modes of operation which
+ * determines how they interact with the broader system and how look ups are
+ * performed. These types are:
+ *
+ * OVERLAY_TARGET_POINT
+ *
+ * A point to point plugin has a single static definition for where
+ * to send all traffic. Every packet in the system always gets sent
+ * to the exact same destination which is programmed into the
+ * kernel when the general device is activated.
+ *
+ * OVERLAY_TARGET_DYNAMIC
+ *
+ * A dynamic plugin does not have a single static definition.
+ * Instead, for each destination, the kernel makes an asynchronous
+ * request to varpd to determine where the packet should be routed,
+ * and if a specific destination is found, then that destination is
+ * cached in the overlay device's target cache.
+ *
+ * This distinction, while important for the general overlay device's operation,
+ * is not important to the encapsulation plugins. They don't need to know about
+ * any of these pieces. It's just a concern for varpd, the userland plugin, and
+ * the general overlay scaffolding.
+ *
+ * When an overlay device is set to OVERLAY_TARGET_POINT, then it does not
+ * maintain a target cache, and instead just keeps track of the destination and
+ * always sends encapsulated packets to that address. When the target type is of
+ * OVERLAY_TARGET_DYNAMIC, then the kernel maintains a cache of all such
+ * destinations. These destinations are kept around in an instance of a
+ * reference hash that is specific to the given overlay device. Entries in the
+ * cache can be invalidated and replaced by varpd and its lookup plugins.
+ *
+ * ----------------------------------
+ * Kernel Components and Architecture
+ * ----------------------------------
+ *
+ * There are multiple pieces inside the kernel that work together, there is the
+ * general overlay_dev_t structure, which is the logical GLDv3 device, but it
+ * itself has references to things like an instance of an encapsulation plugin,
+ * a pointer to a mux and a target cache. It can roughly be summarized in the
+ * following image:
+ *
+ * +------------------+
+ * | global |
+ * | overlay list |
+ * | overlay_dev_list |
+ * +------------------+
+ * |
+ * | +-----------------------+ +---------------+
+ * +->| GLDv3 Device |----------->| GLDv3 Device | -> ...
+ * | overlay_dev_t | | overlay_dev_t |
+ * | | +---------------+
+ * | |
+ * | mac_handle_t -----+---> GLDv3 handle to MAC
+ * | datalink_id_t -----+---> Datalink ID used by DLS
+ * | overlay_dev_flag_t ---+---> Device state
+ * | uint_t -----+---> Current device MTU
+ * | uint_t -----+---> In-progress RX operations
+ * | uint_t -----+---> In-progress TX operations
+ * | char[] -----+---> FMA degraded message
+ * | void * -----+---> plugin private data
+ * | overlay_target_t * ---+---------------------+
+ * | overlay_plugin_t * ---+---------+ |
+ * +-----------------------+ | |
+ * ^ | |
+ * +--------------------+ | | |
+ * | Kernel Socket | | | |
+ * | Multiplexor | | | |
+ * | overlay_mux_t | | | |
+ * | | | | |
+ * | avl_tree_t -+--+ | |
+ * | uint_t -+--> socket family | |
+ * | uint_t -+--> socket type | |
+ * | uint_t -+--> socket protocol | |
+ * | ksocket_t -+--> I/O socket | |
+ * | struct sockaddr * -+--> ksocket address | |
+ * | overlay_plugin_t --+--------+ | |
+ * +--------------------+ | | |
+ * | | |
+ * +-------------------------+ | | |
+ * | Encap Plugin |<--+-----------+ |
+ * | overlay_plugin_t | |
+ * | | |
+ * | char * ---+--> plugin name |
+ * | overlay_plugin_ops_t * -+--> plugin downcalls |
+ * | char ** (props) ---+--> property list |
+ * | uint_t ---+--> id length |
+ * | overlay_plugin_flags_t -+--> plugin flags |
+ * | overlay_plugin_dest_t --+--> destination type v
+ * +-------------------------+ +-------------------------+
+ * | Target Cache |
+ * | overlay_target_t |
+ * | |
+ * cache mode <--+- overlay_target_mode_t |
+ * dest type <--+- overlay_plugin_dest_t |
+ * cache flags <--+- overlay_target_flag_t |
+ * varpd id <--+- uint64_t |
+ * outstanding varpd reqs. <--+- uint_t |
+ * OVERLAY_TARGET_POINT state <--+- overlay_target_point_t |
+ * OVERLAY_TARGET_DYNAMIC state <-+---+- overlay_target_dyn_t |
+ * | +-------------------------+
+ * +-----------------------+
+ * |
+ * v
+ * +-------------------------------+ +------------------------+
+ * | Target Entry |-->| Target Entry |--> ...
+ * | overlay_target_entry_t | | overlay_target_entry_t |
+ * | | +------------------------+
+ * | |
+ * | overlay_target_entry_flags_t -+--> Entry flags
+ * | uint8_t[ETHERADDRL] ---+--> Target MAC address
+ * | overlay_target_point_t ---+--> Target underlay address
+ * | mblk_t * ---+--> outstanding mblk head
+ * | mblk_t * ---+--> outstanding mblk tail
+ * | size_t ---+--> outstanding mblk size
+ * +-------------------------------+
+ *
+ * The primary entries that we care about are the overlay_dev_t, which
+ * correspond to each overlay device that is created with dladm(8). Globally,
+ * these devices are maintained in a simple list_t which is protected with a
+ * lock. Hence, these include important information such as the mac_handle_t
+ * and a datalink_id_t which is used to interact with the broader MAC and DLS
+ * ecosystem. We also maintain additional information such as the current state,
+ * outstanding operations, the mtu, and importantly, the plugin's private data.
+ * This is the instance of an encapsulation plugin that gets created as part of
+ * creating an overlay device. Another aspect of this is that the overlay_dev_t
+ * also includes information with respect to FMA. For more information, see the
+ * FMA section.
+ *
+ * Each overlay_dev_t has a pointer to a plugin, a mux, and a target. The plugin
+ * is the encapsulation plugin. This allows the device to make downcalls into it
+ * based on doing things like getting and setting properties. Otherwise, the
+ * plugin itself is a fairly straightforward entity. They are maintained in an
+ * (not pictured above) list. The plugins themselves mostly maintain things like
+ * the static list of properties, what kind of destination they require, and the
+ * operations vector. A given module may contain more if necessary.
+ *
+ * The next piece of the puzzle is the mux, or a multiplexor. The mux itself
+ * maintains a ksocket and it is through the mux that we send and receive
+ * message blocks. The mux represents a socket type and address, as well as a
+ * plugin. Multiple overlay_dev_t devices may then share the same mux. For
+ * example, consider the case where you have different instances of vxlan all on
+ * the same underlay network. These would all logically share the same IP
+ * address and port that packets are sent and received on; however, what differs
+ * is the decapuslation ID.
+ *
+ * Each mux maintains a ksocket_t which is similar to a socket(3SOCKET). Unlike
+ * a socket, we enable a direct callback on the ksocket. This means that
+ * whenever a message block chain is received, rather than sitting there and
+ * getting a callback in a context and kicking that back out to a taskq. Instead
+ * data comes into the callback function overlay_mux_recv().
+ *
+ * The mux is given encapsulated packets (via overlay_m_tx, the GLDv3 tx
+ * function) to transmit. It receives encapsulated packets, decapsulates them to
+ * determine the overlay identifier, looks up the given device that matches that
+ * identifier, and then causes the broader MAC world to receive the packet with
+ * a call to mac_rx().
+ *
+ * Today, we don't do too much that's special with the ksocket; however, as
+ * hardware is gaining understanding for these encapsulation protocols, we'll
+ * probably want to think of better ways to get those capabilities passed down
+ * and potentially better ways to program receive filters so they get directly
+ * to us. Though, that's all fantasy future land.
+ *
+ * The next part of the puzzle is the target cache. The purpose of the target
+ * cache is to cache where we should send a packet on the underlay network,
+ * given its mac address. The target cache operates in two modes depending on
+ * whether the lookup module was declared to OVERLAY_TARGET_POINT or
+ * OVERLAY_TARGET_DYANMIC.
+ *
+ * In the case where the target cache has been programmed to be
+ * OVERLAY_TARGET_POINT, then we only maintain a single overlay_target_point_t
+ * which has the destination that we send everything, no matter the destination
+ * mac address.
+ *
+ * On the other hand, when we have an instance of OVERLAY_TARGET_DYNAMIC, things
+ * are much more interesting and as a result, more complicated. We primarily
+ * store lists of overlay_target_entry_t's which are stored in both an avl tree
+ * and a refhash_t. The primary look up path uses the refhash_t and the avl tree
+ * is only used for a few of the target ioctls used to dump data such that we
+ * can get a consistent iteration order for things like dladm show-overlay -t.
+ * The key that we use for the reference hashtable is based on the mac address
+ * in the cache and currently we just do a simple CRC32 to transform it into a
+ * hash.
+ *
+ * Each entry maintains a set of flags to indicate the current status of the
+ * request. The flags may indicate one of three states: that current cache entry
+ * is valid, that the current cache entry has been directed to drop all output,
+ * and that the current cache entry is invalid and may be being looked up. In
+ * the case where it's valid, we just take the destination address and run with
+ * it.
+ *
+ * If it's invalid and a lookup has not been made, then we start the process
+ * that prepares a query that will make its way up to varpd. The cache entry
+ * entry maintains a message block chain of outstanding message blocks and a
+ * size. These lists are populated only when we don't know the answer as to
+ * where should these be sent. The size entry is used to cap the amount of
+ * outstanding data that we don't know the answer to. If we exceed a cap on the
+ * amount of outstanding data (currently 1 Mb), then we'll drop any additional
+ * packets. Once we get an answer indicating a valid destination, we transmit
+ * any outstanding data to that place. For the full story on how we look that up
+ * will be discussed in the section on the Target Cache Lifecycle.
+ *
+ * ------------------------
+ * FMA and Degraded Devices
+ * ------------------------
+ *
+ * Every kernel overlay device keeps track of its FMA state. Today in FMA we
+ * cannot represent partitions between resources nor can we represent that a
+ * given minor node of a pseudo device has failed -- if we degrade the overlay
+ * device, then the entire dev_info_t is degraded. However, we still want to be
+ * able to indicate to administrators that things may go wrong.
+ *
+ * To this end, we've added a notion of a degraded state to every overlay
+ * device. This state is primarily dictated by userland and it can happen for
+ * various reasons. Generally, because a userland lookup plugin has been
+ * partitioned, or something has gone wrong such that there is no longer any
+ * userland lookup module for a device, then we'll mark it degraded.
+ *
+ * As long as any of our minor instances is degraded, then we'll fire off the
+ * FMA event to note that. Once the last degraded instance is no longer
+ * degraded, then we'll end up telling FMA that we're all clean.
+ *
+ * To help administrators get a better sense of which of the various minor
+ * devices is wrong, we store the odd_fmamsg[] character array. This character
+ * array can be fetched with doing a dladm show-overlay -f.
+ *
+ * Note, that it's important that we do not update the link status of the
+ * devices. We want to remain up as much as possible. By changing the link in a
+ * degraded state, this may end up making things worse. We may still actually
+ * have information in the target cache and if we mark the link down, that'll
+ * result in not being able to use it. The reason being that this'll mark all
+ * the downstream VNICs down which will go to IP and from there we end up
+ * dealing with sadness.
+ *
+ * -----------------------
+ * Target Cache Life Cycle
+ * -----------------------
+ *
+ * This section only applies when we have a lookup plugin of
+ * OVERLAY_TARGET_DYNAMIC. None of this applies to those of type
+ * OVERLAY_TARGET_POINT.
+ *
+ * While we got into the target cache in the general architecture section, it's
+ * worth going into more details as to how this actually works and showing some
+ * examples and state machines. Recall that a target cache entry basically has
+ * the following state transition diagram:
+ *
+ * Initial state
+ * . . . . . . first access . . . varpd lookup enqueued
+ * . . .
+ * . . .
+ * +-------+ . +----------+ .
+ * | No |------*---->| Invalid |-------*----+
+ * | Entry | | Entry | |
+ * +-------+ +----------+ |
+ * varpd ^ ^ varpd |
+ * invalidate | | drop |
+ * . . . * * . . v
+ * +-------+ | | +---------+
+ * | Entry |--->-----+ +----<----| Entry |
+ * | Valid |<----------*---------<----| Pending |->-+ varpd
+ * +-------+ . +---------+ * . . drop, but
+ * . varpd ^ | other queued
+ * . success | | entries
+ * +-----+
+ *
+ * When the table is first created, it is empty. As we attempt to lookup entries
+ * and we find there is no entry at all, we'll create a new table entry for it.
+ * At that point the entry is technically in an invalid state, that means that
+ * we have no valid data from varpd. In that case, we'll go ahead and queue the
+ * packet into the entry's pending chain, and queue a varpd lookup, setting the
+ * OVERLAY_ENTRY_F_PENDING flag in the progress.
+ *
+ * If additional mblk_t's come in for this entry, we end up appending them to
+ * the tail of the chain, if and only if, we don't exceed the threshold for the
+ * amount of space they can take up. An entry remains pending until we get a
+ * varpd reply. If varpd replies with a valid results, we move to the valid
+ * entry state, and remove the OVERLAY_ENTRY_F_PENDING flag and set it with one
+ * of OVERLAY_ENTRY_F_VALID or OVERLAY_ENTRY_F_DROP as appropriate.
+ *
+ * Once an entry is valid, it stays valid until user land tells us to invalidate
+ * it with an ioctl or replace it, OVERLAY_TARG_CACHE_REMOE and
+ * OVERLAY_TARG_CACHE_SET respectively.
+ *
+ * If the lookup fails with a call to drop the packet, then the next state is
+ * determined by the state of the queue. If the set of outstanding entries is
+ * empty, then we just transition back to the invalid state. If instead, the
+ * set of outstanding entries is not empty, then we'll queue another entry and
+ * stay in the same state, repeating this until the number of requests is
+ * drained.
+ *
+ * The following images describes the flow of a given lookup and where the
+ * overlay_target_entry_t is at any given time.
+ *
+ * +-------------------+
+ * | Invalid Entry | An entry starts off as an invalid entry
+ * | de:ad:be:ef:00:00 | and only exists in the target cache.
+ * +-------------------+
+ *
+ * ~~~~
+ *
+ * +---------------------+
+ * | Global list_t | A mblk_t comes in for an entry. We
+ * | overlay_target_list | append it to the overlay_target_list.
+ * +---------------------+
+ * |
+ * v
+ * +-------------------+ +-------------------+
+ * | Pending Entry |----->| Pending Entry |--->...
+ * | 42:5e:1a:10:d6:2d | | de:ad:be:ef:00:00 |
+ * +-------------------+ +-------------------+
+ *
+ * ~~~~
+ *
+ * +--------------------------+
+ * | /dev/overlay minor state | User land said that it would look up an
+ * | overlay_target_hdl_t | entry for us. We remove it from the
+ * +--------------------------+ global list and add it to the handle's
+ * | outstanding list.
+ * |
+ * v
+ * +-------------------+ +-------------------+
+ * | Pending Entry |----->| Pending Entry |
+ * | 90:b8:d0:79:02:dd | | de:ad:be:ef:00:00 |
+ * +-------------------+ +-------------------+
+ *
+ * ~~~~
+ *
+ * +-------------------+
+ * | Valid Entry | varpd returned an answer with
+ * | de:ad:be:ef:00:00 | OVERLAY_IOC_RESPOND and the target cache
+ * | 10.169.23.42:4789 | entry is now populated with a
+ * +-------------------+ destination and marked as valid
+ *
+ *
+ * The lookup mechanism is performed via a series of operations on the character
+ * pseudo-device /dev/overlay. The only thing that uses this device is the
+ * userland daemon varpd. /dev/overlay is a cloneable device, each open of it
+ * granting a new minor number which maintains its own state. We maintain this
+ * state so that way if an outstanding lookup was queued to something that
+ * crashed or closed its handle without responding, we can know about this and
+ * thus handle it appropriately.
+ *
+ * When a lookup is first created it's added to our global list of outstanding
+ * lookups. To service requests, userland is required to perform an ioctl to ask
+ * for a request. We will block it in the kernel a set amount of time waiting
+ * for a request. When we give a request to a given minor instance of the
+ * device, we remove it from the global list and append the request to the
+ * device's list of outstanding entries, for the reasons we discussed above.
+ * When a lookup comes in, we give user land a smaller amount of information
+ * specific to that packet, the overlay_targ_lookup_t. It includes a request id
+ * to identify this, and then the overlay id, the varpd id, the header and
+ * packet size, the source and destination mac address, the SAP, and any
+ * potential VLAN header.
+ *
+ * At that point, it stays in that outstanding list until one of two ioctls are
+ * returned: OVERLAY_TARG_RESPOND or OVERLAY_TARG_DROP. During this time,
+ * userland may also perform other operations. For example, it may use
+ * OVERLAY_TARG_PKT to get a copy of this packet so it can perform more in-depth
+ * analysis of what to do beyond what we gave it initially. This is useful for
+ * providing proxy arp and the like. Finally, there are two other ioctls that
+ * varpd can then do. The first is OVERLAY_TARG_INJECT which injects the
+ * non-jumbo frame packet up into that mac device and OVERLAY_TARG_RESEND which
+ * causes us to encapsulate and send out the packet they've given us.
+ *
+ *
+ * Finally, through the target cache, several ioctls are provided to allow for
+ * interrogation and management of the cache. They allow for individual entries
+ * to be retrieved, set, or have the entire table flushed. For the full set of
+ * ioctls here and what they do, take a look at uts/common/sys/overlay_target.h.
+ *
+ * ------------------
+ * Sample Packet Flow
+ * ------------------
+ *
+ * There's a lot of pieces here, hopefully an example of how this all fits
+ * together will help clarify and elucidate what's going on. We're going to
+ * first track an outgoing packet, eg. one that is sent from an IP interface on
+ * a VNIC on top of an overlay device, and then we'll look at what it means to
+ * respond to that.
+ *
+ *
+ * +----------------+ +--------------+ +------------------+
+ * | IP/DLS send |------->| MAC sends it |----------->| mblk_t reaches |
+ * | packet to MAC | | to the GLDv3 | | overlay GLDv3 tx |
+ * +----------------+ | VNIC device | | overlay_m_tx() |
+ * +--------------+ +------------------+
+ * |
+ * . lookup . cache |
+ * . drop . miss v
+ * +---------+ . +--------+ . +------------------+
+ * | freemsg |<-----*-------| varpd |<---*------| Lookup each mblk |
+ * | mblk_t | | lookup | | in the target |
+ * +---------+ | queued | | cache |
+ * ^ +--------+ +------------------+
+ * on send | | | cache
+ * error . . * *. . lookup * . . hit
+ * | | success v
+ * | | +------------------+
+ * +-----------------+ +--------------->| call plugin |
+ * | Send out | | ovpo_encap() to |
+ * | overlay_mux_t's |<----------------------------------| get encap mblk_t |
+ * | ksocket | +------------------+
+ * +-----------------+
+ *
+ * The receive end point looks a little different and looks more like:
+ *
+ * +------------------+ +----------------+ +-----------+
+ * | mblk_t comes off |---->| enter netstack |--->| delivered |---+
+ * | the physical | | IP stack | | to | * . . direct
+ * | device | +----------------+ | ksocket | | callback
+ * +------------------+ +-----------+ |
+ * . overlay id |
+ * . not found v
+ * +-----------+ . +-----------------+ +--------------------+
+ * | freemsg |<--*------| call plugin |<------| overlay_mux_recv() |
+ * | mblk_t | | ovpo_decap() to | +--------------------+
+ * +-----------+ | decap mblk_t |
+ * +-----------------+
+ * |
+ * * . . overlay id
+ * v found
+ * +--------+ +----------------+
+ * | adjust |----->| call mac_rx |
+ * | mblk_t | | on original |
+ * +--------+ | decaped packet |
+ * +----------------+
+ *
+ * ------------------
+ * Netstack Awareness
+ * ------------------
+ *
+ * In the above image we note that this enters a netstack. Today the only
+ * netstack that can be is the global zone as the overlay driver itself is not
+ * exactly netstack aware. What this really means is that varpd cannot run in a
+ * non-global zone and an overlay device cannot belong to a non-global zone.
+ * Non-global zones can still have a VNIC assigned to them that's been created
+ * over the overlay device the same way they would if it had been created over
+ * an etherstub or a physical device.
+ *
+ * The majority of the work to make it netstack aware is straightforward and the
+ * biggest thing is to create a netstack module that allows us to hook into
+ * netstack (and thus zone) creation and destruction. From there, we need to
+ * amend the target cache lookup routines that we discussed earlier to not have
+ * a global outstanding list and a global list of handles, but rather, one per
+ * netstack.
+ *
+ * For the mux, we'll need to open the ksocket in the context of the zone, we
+ * can likely do this with a properly composed credential, but we'll need to do
+ * some more work on that path. Finally, we'll want to make sure the dld ioctls
+ * are aware of the zoneid of the caller and we use that appropriately and store
+ * it in the overlay_dev_t.
+ *
+ * -----------
+ * GLDv3 Notes
+ * -----------
+ *
+ * The overlay driver implements a GLDv3 device. Parts of GLDv3 are more
+ * relevant and other parts are much less relevant for us. For example, the
+ * GLDv3 is used to toggle the device being put into and out of promiscuous
+ * mode, to program MAC addresses for unicast and multicast hardware filters.
+ * Today, an overlay device doesn't have a notion of promiscuous mode nor does
+ * it have a notion of unicast and multicast addresses programmed into the
+ * device. Instead, for the purposes of the hardware filter, we don't do
+ * anything and just always accept new addresses being added and removed.
+ *
+ * If the GLDv3 start function has not been called, then we will not use this
+ * device for I/O purposes. Any calls to transmit or receive should be dropped,
+ * though the GLDv3 guarantees us that transmit will not be called without
+ * calling start. Similarly, once stop is called, then no packets can be dealt
+ * with.
+ *
+ * Today we don't support the stat interfaces, though there's no good reason
+ * that we shouldn't assemble some of the stats based on what we have in the
+ * future.
+ *
+ * When it comes to link properties, many of the traditional link properties do
+ * not apply and many others MAC handles for us. For example, we don't need to
+ * implement anything for overlay_m_getprop() to deal with returning the MTU, as
+ * MAC never calls into us for that. As such, there isn't much of anything to
+ * support in terms of properties.
+ *
+ * Today, we don't support any notion of hardware capabilities. However, if
+ * future NIC hardware or other changes to the system cause it to make sense for
+ * us to emulate logical groups, then we should do that. However, we still do
+ * implement a capab function so that we can identify ourselves as an overlay
+ * device to the broader MAC framework. This is done mostly so that a device
+ * created on top of us can have fanout rings as we don't try to lie about a
+ * speed for our device.
+ *
+ * The other question is what should be done for a device's MTU and margin. We
+ * set our minimum supported MTU to be the minimum value that an IP network may
+ * be set to 576 -- which mimics what an etherstub does. On the flip side, we
+ * have our upper bound set to 8900. This value comes from the fact that a lot
+ * of jumbo networks use their maximum as 9000. As such, we want to reserve 100
+ * bytes, which isn't exactly the most accurate number, but it'll be good enough
+ * for now. Because of that, our default MTU off of these devices is 1400, as
+ * the default MTU for everything is usually 1500 or whatever the underlying
+ * device is at; however, this is a bit simpler than asking the netstack what
+ * are all the IP interfaces at. It also calls into question how PMTU and PMTU
+ * discovery should work here. The challenge, especially for
+ * OVERLAY_TARG_DYNAMIC is that the MTU to any of the places will vary and it's
+ * not clear that if you have a single bad entry that the overall MTU should be
+ * lowered. Instead, we should figure out a better way of determining these
+ * kinds of PMTU errors and appropriately alerting the administrator via FMA.
+ *
+ * Regarding margin, we allow a margin of up to VLAN_TAGSZ depending on whether
+ * or not the underlying encapsulation device supports VLAN tags. If it does,
+ * then we'll set the margin to allow for it, otherwise, we will not.
+ */
+
+#include <sys/conf.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/modctl.h>
+#include <sys/policy.h>
+#include <sys/stream.h>
+#include <sys/strsubr.h>
+#include <sys/strsun.h>
+#include <sys/types.h>
+#include <sys/kmem.h>
+#include <sys/param.h>
+#include <sys/sysmacros.h>
+#include <sys/ddifm.h>
+
+#include <sys/dls.h>
+#include <sys/dld_ioc.h>
+#include <sys/mac_provider.h>
+#include <sys/mac_client_priv.h>
+#include <sys/mac_ether.h>
+#include <sys/vlan.h>
+
+#include <sys/overlay_impl.h>
+
+dev_info_t *overlay_dip;
+static kmutex_t overlay_dev_lock;
+static list_t overlay_dev_list;
+static uint8_t overlay_macaddr[ETHERADDRL] =
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+typedef enum overlay_dev_prop {
+ OVERLAY_DEV_P_MTU = 0,
+ OVERLAY_DEV_P_VNETID,
+ OVERLAY_DEV_P_ENCAP,
+ OVERLAY_DEV_P_VARPDID
+} overlay_dev_prop_t;
+
+#define OVERLAY_DEV_NPROPS 4
+static const char *overlay_dev_props[] = {
+ "mtu",
+ "vnetid",
+ "encap",
+ "varpd/id"
+};
+
+#define OVERLAY_MTU_MIN 576
+#define OVERLAY_MTU_DEF 1400
+#define OVERLAY_MTU_MAX 8900
+
+overlay_dev_t *
+overlay_hold_by_dlid(datalink_id_t id)
+{
+ overlay_dev_t *o;
+
+ mutex_enter(&overlay_dev_lock);
+ for (o = list_head(&overlay_dev_list); o != NULL;
+ o = list_next(&overlay_dev_list, o)) {
+ if (id == o->odd_linkid) {
+ mutex_enter(&o->odd_lock);
+ o->odd_ref++;
+ mutex_exit(&o->odd_lock);
+ mutex_exit(&overlay_dev_lock);
+ return (o);
+ }
+ }
+
+ mutex_exit(&overlay_dev_lock);
+ return (NULL);
+}
+
+void
+overlay_hold_rele(overlay_dev_t *odd)
+{
+ mutex_enter(&odd->odd_lock);
+ ASSERT(odd->odd_ref > 0);
+ odd->odd_ref--;
+ mutex_exit(&odd->odd_lock);
+}
+
+void
+overlay_io_start(overlay_dev_t *odd, overlay_dev_flag_t flag)
+{
+ ASSERT(flag == OVERLAY_F_IN_RX || flag == OVERLAY_F_IN_TX);
+ ASSERT(MUTEX_HELD(&odd->odd_lock));
+
+ if (flag & OVERLAY_F_IN_RX)
+ odd->odd_rxcount++;
+ if (flag & OVERLAY_F_IN_TX)
+ odd->odd_txcount++;
+ odd->odd_flags |= flag;
+}
+
+void
+overlay_io_done(overlay_dev_t *odd, overlay_dev_flag_t flag)
+{
+ boolean_t signal = B_FALSE;
+
+ ASSERT(flag == OVERLAY_F_IN_RX || flag == OVERLAY_F_IN_TX);
+ ASSERT(MUTEX_HELD(&odd->odd_lock));
+
+ if (flag & OVERLAY_F_IN_RX) {
+ ASSERT(odd->odd_rxcount > 0);
+ odd->odd_rxcount--;
+ if (odd->odd_rxcount == 0) {
+ signal = B_TRUE;
+ odd->odd_flags &= ~OVERLAY_F_IN_RX;
+ }
+ }
+ if (flag & OVERLAY_F_IN_TX) {
+ ASSERT(odd->odd_txcount > 0);
+ odd->odd_txcount--;
+ if (odd->odd_txcount == 0) {
+ signal = B_TRUE;
+ odd->odd_flags &= ~OVERLAY_F_IN_TX;
+ }
+ }
+
+ if (signal == B_TRUE)
+ cv_broadcast(&odd->odd_iowait);
+}
+
+static void
+overlay_io_wait(overlay_dev_t *odd, overlay_dev_flag_t flag)
+{
+ ASSERT((flag & ~OVERLAY_F_IOMASK) == 0);
+ ASSERT(MUTEX_HELD(&odd->odd_lock));
+
+ while (odd->odd_flags & flag) {
+ cv_wait(&odd->odd_iowait, &odd->odd_lock);
+ }
+}
+
+void
+overlay_dev_iter(overlay_dev_iter_f func, void *arg)
+{
+ overlay_dev_t *odd;
+
+ mutex_enter(&overlay_dev_lock);
+ for (odd = list_head(&overlay_dev_list); odd != NULL;
+ odd = list_next(&overlay_dev_list, odd)) {
+ if (func(odd, arg) != 0) {
+ mutex_exit(&overlay_dev_lock);
+ return;
+ }
+ }
+ mutex_exit(&overlay_dev_lock);
+}
+
+/* ARGSUSED */
+static int
+overlay_m_stat(void *arg, uint_t stat, uint64_t *val)
+{
+ return (ENOTSUP);
+}
+
+static int
+overlay_m_start(void *arg)
+{
+ overlay_dev_t *odd = arg;
+ overlay_mux_t *mux;
+ int ret, domain, family, prot;
+ struct sockaddr_storage storage;
+ socklen_t slen;
+
+ mutex_enter(&odd->odd_lock);
+ if ((odd->odd_flags & OVERLAY_F_ACTIVATED) == 0) {
+ mutex_exit(&odd->odd_lock);
+ return (EAGAIN);
+ }
+ mutex_exit(&odd->odd_lock);
+
+ ret = odd->odd_plugin->ovp_ops->ovpo_socket(odd->odd_pvoid, &domain,
+ &family, &prot, (struct sockaddr *)&storage, &slen);
+ if (ret != 0)
+ return (ret);
+
+ mux = overlay_mux_open(odd->odd_plugin, domain, family, prot,
+ (struct sockaddr *)&storage, slen, &ret);
+ if (mux == NULL)
+ return (ret);
+
+ overlay_mux_add_dev(mux, odd);
+ odd->odd_mux = mux;
+ mutex_enter(&odd->odd_lock);
+ ASSERT(!(odd->odd_flags & OVERLAY_F_IN_MUX));
+ odd->odd_flags |= OVERLAY_F_IN_MUX;
+ mutex_exit(&odd->odd_lock);
+
+ return (0);
+}
+
+static void
+overlay_m_stop(void *arg)
+{
+ overlay_dev_t *odd = arg;
+
+ /*
+ * The MAC Perimeter is held here, so we don't have to worry about
+ * synchronizing this with respect to metadata operations.
+ */
+ mutex_enter(&odd->odd_lock);
+ VERIFY(odd->odd_flags & OVERLAY_F_IN_MUX);
+ VERIFY(!(odd->odd_flags & OVERLAY_F_MDDROP));
+ odd->odd_flags |= OVERLAY_F_MDDROP;
+ overlay_io_wait(odd, OVERLAY_F_IOMASK);
+ mutex_exit(&odd->odd_lock);
+
+ overlay_mux_remove_dev(odd->odd_mux, odd);
+ overlay_mux_close(odd->odd_mux);
+ odd->odd_mux = NULL;
+
+ mutex_enter(&odd->odd_lock);
+ odd->odd_flags &= ~OVERLAY_F_IN_MUX;
+ odd->odd_flags &= ~OVERLAY_F_MDDROP;
+ VERIFY((odd->odd_flags & OVERLAY_F_STOPMASK) == 0);
+ mutex_exit(&odd->odd_lock);
+}
+
+/*
+ * For more info on this, see the big theory statement.
+ */
+/* ARGSUSED */
+static int
+overlay_m_promisc(void *arg, boolean_t on)
+{
+ return (0);
+}
+
+/*
+ * For more info on this, see the big theory statement.
+ */
+/* ARGSUSED */
+static int
+overlay_m_multicast(void *arg, boolean_t add, const uint8_t *addrp)
+{
+ return (0);
+}
+
+/*
+ * For more info on this, see the big theory statement.
+ */
+/* ARGSUSED */
+static int
+overlay_m_unicast(void *arg, const uint8_t *macaddr)
+{
+ return (0);
+}
+
+mblk_t *
+overlay_m_tx(void *arg, mblk_t *mp_chain)
+{
+ overlay_dev_t *odd = arg;
+ mblk_t *mp, *ep;
+ int ret;
+ ovep_encap_info_t einfo;
+ struct msghdr hdr;
+
+ mutex_enter(&odd->odd_lock);
+ if ((odd->odd_flags & OVERLAY_F_MDDROP) ||
+ !(odd->odd_flags & OVERLAY_F_IN_MUX)) {
+ mutex_exit(&odd->odd_lock);
+ freemsgchain(mp_chain);
+ return (NULL);
+ }
+ overlay_io_start(odd, OVERLAY_F_IN_TX);
+ mutex_exit(&odd->odd_lock);
+
+ bzero(&hdr, sizeof (struct msghdr));
+
+ bzero(&einfo, sizeof (ovep_encap_info_t));
+ einfo.ovdi_id = odd->odd_vid;
+ mp = mp_chain;
+ while (mp != NULL) {
+ socklen_t slen;
+ struct sockaddr_storage storage;
+
+ mp_chain = mp->b_next;
+ mp->b_next = NULL;
+ ep = NULL;
+
+ ret = overlay_target_lookup(odd, mp,
+ (struct sockaddr *)&storage, &slen);
+ if (ret != OVERLAY_TARGET_OK) {
+ if (ret == OVERLAY_TARGET_DROP)
+ freemsg(mp);
+ mp = mp_chain;
+ continue;
+ }
+
+ hdr.msg_name = &storage;
+ hdr.msg_namelen = slen;
+
+ ret = odd->odd_plugin->ovp_ops->ovpo_encap(odd->odd_mh, mp,
+ &einfo, &ep);
+ if (ret != 0 || ep == NULL) {
+ freemsg(mp);
+ goto out;
+ }
+
+ ASSERT(ep->b_cont == mp || ep == mp);
+ ret = overlay_mux_tx(odd->odd_mux, &hdr, ep);
+ if (ret != 0)
+ goto out;
+
+ mp = mp_chain;
+ }
+
+out:
+ mutex_enter(&odd->odd_lock);
+ overlay_io_done(odd, OVERLAY_F_IN_TX);
+ mutex_exit(&odd->odd_lock);
+ return (mp_chain);
+}
+
+/* ARGSUSED */
+static void
+overlay_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
+{
+ miocnak(q, mp, 0, ENOTSUP);
+}
+
+/* ARGSUSED */
+static boolean_t
+overlay_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
+{
+ /*
+ * Tell MAC we're an overlay.
+ */
+ if (cap == MAC_CAPAB_OVERLAY)
+ return (B_TRUE);
+ return (B_FALSE);
+}
+
+/* ARGSUSED */
+static int
+overlay_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
+ uint_t pr_valsize, const void *pr_val)
+{
+ uint32_t mtu, old;
+ int err;
+ overlay_dev_t *odd = arg;
+
+ if (pr_num != MAC_PROP_MTU)
+ return (ENOTSUP);
+
+ bcopy(pr_val, &mtu, sizeof (mtu));
+ if (mtu < OVERLAY_MTU_MIN || mtu > OVERLAY_MTU_MAX)
+ return (EINVAL);
+
+ mutex_enter(&odd->odd_lock);
+ old = odd->odd_mtu;
+ odd->odd_mtu = mtu;
+ err = mac_maxsdu_update(odd->odd_mh, mtu);
+ if (err != 0)
+ odd->odd_mtu = old;
+ mutex_exit(&odd->odd_lock);
+
+ return (err);
+}
+
+/* ARGSUSED */
+static int
+overlay_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
+ uint_t pr_valsize, void *pr_val)
+{
+ return (ENOTSUP);
+}
+
+/* ARGSUSED */
+static void
+overlay_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
+ mac_prop_info_handle_t prh)
+{
+ if (pr_num != MAC_PROP_MTU)
+ return;
+
+ mac_prop_info_set_default_uint32(prh, OVERLAY_MTU_DEF);
+ mac_prop_info_set_range_uint32(prh, OVERLAY_MTU_MIN, OVERLAY_MTU_MAX);
+}
+
+static mac_callbacks_t overlay_m_callbacks = {
+ .mc_callbacks = (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP |
+ MC_PROPINFO),
+ .mc_getstat = overlay_m_stat,
+ .mc_start = overlay_m_start,
+ .mc_stop = overlay_m_stop,
+ .mc_setpromisc = overlay_m_promisc,
+ .mc_multicst = overlay_m_multicast,
+ .mc_unicst = overlay_m_unicast,
+ .mc_tx = overlay_m_tx,
+ .mc_ioctl = overlay_m_ioctl,
+ .mc_getcapab = overlay_m_getcapab,
+ .mc_getprop = overlay_m_getprop,
+ .mc_setprop = overlay_m_setprop,
+ .mc_propinfo = overlay_m_propinfo
+};
+
+static boolean_t
+overlay_valid_name(const char *name, size_t buflen)
+{
+ size_t actlen;
+ int err, i;
+
+ for (i = 0; i < buflen; i++) {
+ if (name[i] == '\0')
+ break;
+ }
+
+ if (i == 0 || i == buflen)
+ return (B_FALSE);
+ actlen = i;
+ if (strchr(name, '/') != NULL)
+ return (B_FALSE);
+ if (u8_validate((char *)name, actlen, NULL,
+ U8_VALIDATE_ENTIRE, &err) < 0)
+ return (B_FALSE);
+ return (B_TRUE);
+}
+
+/* ARGSUSED */
+static int
+overlay_i_create(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
+{
+ int err;
+ uint64_t maxid;
+ overlay_dev_t *odd, *o;
+ mac_register_t *mac;
+ overlay_ioc_create_t *oicp = karg;
+
+ if (overlay_valid_name(oicp->oic_encap, MAXLINKNAMELEN) == B_FALSE)
+ return (EINVAL);
+
+ odd = kmem_zalloc(sizeof (overlay_dev_t), KM_SLEEP);
+ odd->odd_linkid = oicp->oic_linkid;
+ odd->odd_plugin = overlay_plugin_lookup(oicp->oic_encap);
+ if (odd->odd_plugin == NULL) {
+ kmem_free(odd, sizeof (overlay_dev_t));
+ return (ENOENT);
+ }
+ err = odd->odd_plugin->ovp_ops->ovpo_init((overlay_handle_t)odd,
+ &odd->odd_pvoid);
+ if (err != 0) {
+ odd->odd_plugin->ovp_ops->ovpo_fini(odd->odd_pvoid);
+ overlay_plugin_rele(odd->odd_plugin);
+ kmem_free(odd, sizeof (overlay_dev_t));
+ return (EINVAL);
+ }
+
+ /*
+ * Make sure that our virtual network id is valid for the given plugin
+ * that we're working with.
+ */
+ ASSERT(odd->odd_plugin->ovp_id_size <= 8);
+ maxid = UINT64_MAX;
+ if (odd->odd_plugin->ovp_id_size != 8)
+ maxid = (1ULL << (odd->odd_plugin->ovp_id_size * 8)) - 1ULL;
+ if (oicp->oic_vnetid > maxid) {
+ odd->odd_plugin->ovp_ops->ovpo_fini(odd->odd_pvoid);
+ overlay_plugin_rele(odd->odd_plugin);
+ kmem_free(odd, sizeof (overlay_dev_t));
+ return (EINVAL);
+ }
+ odd->odd_vid = oicp->oic_vnetid;
+
+ mac = mac_alloc(MAC_VERSION);
+ if (mac == NULL) {
+ mutex_exit(&overlay_dev_lock);
+ odd->odd_plugin->ovp_ops->ovpo_fini(odd->odd_pvoid);
+ overlay_plugin_rele(odd->odd_plugin);
+ kmem_free(odd, sizeof (overlay_dev_t));
+ return (EINVAL);
+ }
+
+ mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
+ mac->m_driver = odd;
+ mac->m_dip = overlay_dip;
+ mac->m_dst_addr = NULL;
+ mac->m_callbacks = &overlay_m_callbacks;
+ mac->m_pdata = NULL;
+ mac->m_pdata_size = 0;
+
+ mac->m_priv_props = NULL;
+
+ /* Let mac handle this itself. */
+ mac->m_instance = (uint_t)-1;
+
+ /*
+ * There is no real source address that should be used here, but saying
+ * that we're not ethernet is going to cause its own problems. At the
+ * end of the say, this is fine.
+ */
+ mac->m_src_addr = overlay_macaddr;
+
+ /*
+ * Start with the default MTU as the max SDU. If the MTU is changed, the
+ * SDU will be changed to reflect that.
+ */
+ mac->m_min_sdu = 1;
+ mac->m_max_sdu = OVERLAY_MTU_DEF;
+ mac->m_multicast_sdu = 0;
+
+ /*
+ * The underlying device doesn't matter, instead this comes from the
+ * encapsulation protocol and whether or not they allow VLAN tags.
+ */
+ if (odd->odd_plugin->ovp_flags & OVEP_F_VLAN_TAG) {
+ mac->m_margin = VLAN_TAGSZ;
+ } else {
+ mac->m_margin = 0;
+ }
+
+ /*
+ * Today, we have no MAC virtualization, it may make sense in the future
+ * to go ahead and emulate some subset of this, but it doesn't today.
+ */
+ mac->m_v12n = MAC_VIRT_NONE;
+
+ mutex_enter(&overlay_dev_lock);
+ for (o = list_head(&overlay_dev_list); o != NULL;
+ o = list_next(&overlay_dev_list, o)) {
+ if (o->odd_linkid == oicp->oic_linkid) {
+ mutex_exit(&overlay_dev_lock);
+ odd->odd_plugin->ovp_ops->ovpo_fini(odd->odd_pvoid);
+ overlay_plugin_rele(odd->odd_plugin);
+ kmem_free(odd, sizeof (overlay_dev_t));
+ return (EEXIST);
+ }
+
+ if (o->odd_vid == oicp->oic_vnetid &&
+ o->odd_plugin == odd->odd_plugin) {
+ mutex_exit(&overlay_dev_lock);
+ odd->odd_plugin->ovp_ops->ovpo_fini(odd->odd_pvoid);
+ overlay_plugin_rele(odd->odd_plugin);
+ kmem_free(odd, sizeof (overlay_dev_t));
+ return (EEXIST);
+ }
+ }
+
+ err = mac_register(mac, &odd->odd_mh);
+ mac_free(mac);
+ if (err != 0) {
+ mutex_exit(&overlay_dev_lock);
+ odd->odd_plugin->ovp_ops->ovpo_fini(odd->odd_pvoid);
+ overlay_plugin_rele(odd->odd_plugin);
+ kmem_free(odd, sizeof (overlay_dev_t));
+ return (err);
+ }
+
+ err = dls_devnet_create(odd->odd_mh, odd->odd_linkid,
+ crgetzoneid(cred));
+ if (err != 0) {
+ mutex_exit(&overlay_dev_lock);
+ (void) mac_unregister(odd->odd_mh);
+ odd->odd_plugin->ovp_ops->ovpo_fini(odd->odd_pvoid);
+ overlay_plugin_rele(odd->odd_plugin);
+ kmem_free(odd, sizeof (overlay_dev_t));
+ return (err);
+ }
+
+ mutex_init(&odd->odd_lock, NULL, MUTEX_DRIVER, NULL);
+ cv_init(&odd->odd_iowait, NULL, CV_DRIVER, NULL);
+ odd->odd_ref = 0;
+ odd->odd_flags = 0;
+ list_insert_tail(&overlay_dev_list, odd);
+ mutex_exit(&overlay_dev_lock);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+overlay_i_activate(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
+{
+ int i, ret;
+ overlay_dev_t *odd;
+ mac_perim_handle_t mph;
+ overlay_ioc_activate_t *oiap = karg;
+ overlay_ioc_propinfo_t *infop;
+ overlay_ioc_prop_t *oip;
+ overlay_prop_handle_t phdl;
+
+ odd = overlay_hold_by_dlid(oiap->oia_linkid);
+ if (odd == NULL)
+ return (ENOENT);
+
+ infop = kmem_alloc(sizeof (overlay_ioc_propinfo_t), KM_SLEEP);
+ oip = kmem_alloc(sizeof (overlay_ioc_prop_t), KM_SLEEP);
+ phdl = (overlay_prop_handle_t)infop;
+
+ mac_perim_enter_by_mh(odd->odd_mh, &mph);
+ mutex_enter(&odd->odd_lock);
+ if (odd->odd_flags & OVERLAY_F_ACTIVATED) {
+ mutex_exit(&odd->odd_lock);
+ mac_perim_exit(mph);
+ overlay_hold_rele(odd);
+ kmem_free(infop, sizeof (overlay_ioc_propinfo_t));
+ kmem_free(oip, sizeof (overlay_ioc_prop_t));
+ return (EEXIST);
+ }
+ mutex_exit(&odd->odd_lock);
+
+ for (i = 0; i < odd->odd_plugin->ovp_nprops; i++) {
+ const char *pname = odd->odd_plugin->ovp_props[i];
+ bzero(infop, sizeof (overlay_ioc_propinfo_t));
+ overlay_prop_init(phdl);
+ ret = odd->odd_plugin->ovp_ops->ovpo_propinfo(pname, phdl);
+ if (ret != 0) {
+ mac_perim_exit(mph);
+ overlay_hold_rele(odd);
+ kmem_free(infop, sizeof (overlay_ioc_propinfo_t));
+ kmem_free(oip, sizeof (overlay_ioc_prop_t));
+ return (ret);
+ }
+
+ if ((infop->oipi_prot & OVERLAY_PROP_PERM_REQ) == 0)
+ continue;
+ bzero(oip, sizeof (overlay_ioc_prop_t));
+ oip->oip_size = sizeof (oip->oip_value);
+ ret = odd->odd_plugin->ovp_ops->ovpo_getprop(odd->odd_pvoid,
+ pname, oip->oip_value, &oip->oip_size);
+ if (ret != 0) {
+ mac_perim_exit(mph);
+ overlay_hold_rele(odd);
+ kmem_free(infop, sizeof (overlay_ioc_propinfo_t));
+ kmem_free(oip, sizeof (overlay_ioc_prop_t));
+ return (ret);
+ }
+ if (oip->oip_size == 0) {
+ mac_perim_exit(mph);
+ overlay_hold_rele(odd);
+ kmem_free(infop, sizeof (overlay_ioc_propinfo_t));
+ kmem_free(oip, sizeof (overlay_ioc_prop_t));
+ return (EINVAL);
+ }
+ }
+
+ mutex_enter(&odd->odd_lock);
+ if ((odd->odd_flags & OVERLAY_F_VARPD) == 0) {
+ mutex_exit(&odd->odd_lock);
+ mac_perim_exit(mph);
+ overlay_hold_rele(odd);
+ kmem_free(infop, sizeof (overlay_ioc_propinfo_t));
+ kmem_free(oip, sizeof (overlay_ioc_prop_t));
+ return (ENXIO);
+ }
+
+ ASSERT((odd->odd_flags & OVERLAY_F_ACTIVATED) == 0);
+ odd->odd_flags |= OVERLAY_F_ACTIVATED;
+
+ /*
+ * Now that we've activated ourselves, we should indicate to the world
+ * that we're up. Note that we may not be able to perform lookups at
+ * this time, but our notion of being 'up' isn't dependent on that
+ * ability.
+ */
+ mac_link_update(odd->odd_mh, LINK_STATE_UP);
+ mutex_exit(&odd->odd_lock);
+
+ mac_perim_exit(mph);
+ overlay_hold_rele(odd);
+ kmem_free(infop, sizeof (overlay_ioc_propinfo_t));
+ kmem_free(oip, sizeof (overlay_ioc_prop_t));
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+overlay_i_delete(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
+{
+ overlay_ioc_delete_t *oidp = karg;
+ overlay_dev_t *odd;
+ datalink_id_t tid;
+ int ret;
+
+ odd = overlay_hold_by_dlid(oidp->oid_linkid);
+ if (odd == NULL) {
+ return (ENOENT);
+ }
+
+ mutex_enter(&odd->odd_lock);
+ /* If we're not the only hold, we're busy */
+ if (odd->odd_ref != 1) {
+ mutex_exit(&odd->odd_lock);
+ overlay_hold_rele(odd);
+ return (EBUSY);
+ }
+
+ if (odd->odd_flags & OVERLAY_F_IN_MUX) {
+ mutex_exit(&odd->odd_lock);
+ overlay_hold_rele(odd);
+ return (EBUSY);
+ }
+
+ /*
+ * To remove this, we need to first remove it from dls and then remove
+ * it from mac. The act of removing it from mac will check if there are
+ * devices on top of this, eg. vnics. If there are, then that will fail
+ * and we'll have to go through and recreate the dls entry. Only after
+ * mac_unregister has succeeded, then we'll go through and actually free
+ * everything and drop the dev lock.
+ */
+ ret = dls_devnet_destroy(odd->odd_mh, &tid, B_TRUE);
+ if (ret != 0) {
+ overlay_hold_rele(odd);
+ return (ret);
+ }
+
+ ASSERT(oidp->oid_linkid == tid);
+ ret = mac_disable(odd->odd_mh);
+ if (ret != 0) {
+ (void) dls_devnet_create(odd->odd_mh, odd->odd_linkid,
+ crgetzoneid(cred));
+ overlay_hold_rele(odd);
+ return (ret);
+ }
+
+ overlay_target_quiesce(odd->odd_target);
+
+ mutex_enter(&overlay_dev_lock);
+ list_remove(&overlay_dev_list, odd);
+ mutex_exit(&overlay_dev_lock);
+
+ cv_destroy(&odd->odd_iowait);
+ mutex_destroy(&odd->odd_lock);
+ overlay_target_free(odd);
+ odd->odd_plugin->ovp_ops->ovpo_fini(odd->odd_pvoid);
+ overlay_plugin_rele(odd->odd_plugin);
+ kmem_free(odd, sizeof (overlay_dev_t));
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+overlay_i_nprops(void *karg, intptr_t arg, int mode, cred_t *cred,
+ int *rvalp)
+{
+ overlay_dev_t *odd;
+ overlay_ioc_nprops_t *on = karg;
+
+ odd = overlay_hold_by_dlid(on->oipn_linkid);
+ if (odd == NULL)
+ return (ENOENT);
+ on->oipn_nprops = odd->odd_plugin->ovp_nprops + OVERLAY_DEV_NPROPS;
+ overlay_hold_rele(odd);
+
+ return (0);
+}
+
+static int
+overlay_propinfo_plugin_cb(overlay_plugin_t *opp, void *arg)
+{
+ overlay_prop_handle_t phdl = arg;
+ overlay_prop_set_range_str(phdl, opp->ovp_name);
+ return (0);
+}
+
+static int
+overlay_i_name_to_propid(overlay_dev_t *odd, const char *name, uint_t *id)
+{
+ int i;
+
+ for (i = 0; i < OVERLAY_DEV_NPROPS; i++) {
+ if (strcmp(overlay_dev_props[i], name) == 0) {
+ *id = i;
+ return (0);
+ }
+ }
+
+ for (i = 0; i < odd->odd_plugin->ovp_nprops; i++) {
+ if (strcmp(odd->odd_plugin->ovp_props[i], name) == 0) {
+ *id = i + OVERLAY_DEV_NPROPS;
+ return (0);
+ }
+ }
+
+ return (ENOENT);
+}
+
+static void
+overlay_i_propinfo_mtu(overlay_dev_t *odd, overlay_prop_handle_t phdl)
+{
+ uint32_t def;
+ mac_propval_range_t range;
+ uint_t perm;
+
+ ASSERT(MAC_PERIM_HELD(odd->odd_mh));
+
+ bzero(&range, sizeof (mac_propval_range_t));
+ range.mpr_count = 1;
+ if (mac_prop_info(odd->odd_mh, MAC_PROP_MTU, "mtu", &def,
+ sizeof (def), &range, &perm) != 0)
+ return;
+
+ if (perm == MAC_PROP_PERM_READ)
+ overlay_prop_set_prot(phdl, OVERLAY_PROP_PERM_READ);
+ else if (perm == MAC_PROP_PERM_WRITE)
+ overlay_prop_set_prot(phdl, OVERLAY_PROP_PERM_WRITE);
+ else if (perm == MAC_PROP_PERM_RW)
+ overlay_prop_set_prot(phdl, OVERLAY_PROP_PERM_RW);
+
+ overlay_prop_set_type(phdl, OVERLAY_PROP_T_UINT);
+ overlay_prop_set_default(phdl, &def, sizeof (def));
+ overlay_prop_set_range_uint32(phdl, range.mpr_range_uint32[0].mpur_min,
+ range.mpr_range_uint32[0].mpur_max);
+}
+
+/* ARGSUSED */
+static int
+overlay_i_propinfo(void *karg, intptr_t arg, int mode, cred_t *cred,
+ int *rvalp)
+{
+ overlay_dev_t *odd;
+ int ret;
+ mac_perim_handle_t mph;
+ uint_t propid = UINT_MAX;
+ overlay_ioc_propinfo_t *oip = karg;
+ overlay_prop_handle_t phdl = (overlay_prop_handle_t)oip;
+
+ odd = overlay_hold_by_dlid(oip->oipi_linkid);
+ if (odd == NULL)
+ return (ENOENT);
+
+ overlay_prop_init(phdl);
+ mac_perim_enter_by_mh(odd->odd_mh, &mph);
+
+ /*
+ * If the id is -1, then the property that we're looking for is named in
+ * oipi_name and we should fill in its id. Otherwise, we've been given
+ * an id and we need to turn that into a name for our plugin's sake. The
+ * id is our own fabrication for property discovery.
+ */
+ if (oip->oipi_id == -1) {
+ /*
+ * Determine if it's a known generic property or it belongs to a
+ * module by checking against the list of known names.
+ */
+ oip->oipi_name[OVERLAY_PROP_NAMELEN-1] = '\0';
+ if ((ret = overlay_i_name_to_propid(odd, oip->oipi_name,
+ &propid)) != 0) {
+ overlay_hold_rele(odd);
+ mac_perim_exit(mph);
+ return (ret);
+ }
+ oip->oipi_id = propid;
+ if (propid >= OVERLAY_DEV_NPROPS) {
+ ret = odd->odd_plugin->ovp_ops->ovpo_propinfo(
+ oip->oipi_name, phdl);
+ overlay_hold_rele(odd);
+ mac_perim_exit(mph);
+ return (ret);
+
+ }
+ } else if (oip->oipi_id >= OVERLAY_DEV_NPROPS) {
+ uint_t id = oip->oipi_id - OVERLAY_DEV_NPROPS;
+
+ if (id >= odd->odd_plugin->ovp_nprops) {
+ overlay_hold_rele(odd);
+ mac_perim_exit(mph);
+ return (EINVAL);
+ }
+ ret = odd->odd_plugin->ovp_ops->ovpo_propinfo(
+ odd->odd_plugin->ovp_props[id], phdl);
+ overlay_hold_rele(odd);
+ mac_perim_exit(mph);
+ return (ret);
+ } else if (oip->oipi_id < -1) {
+ overlay_hold_rele(odd);
+ mac_perim_exit(mph);
+ return (EINVAL);
+ } else {
+ ASSERT(oip->oipi_id < OVERLAY_DEV_NPROPS);
+ ASSERT(oip->oipi_id >= 0);
+ propid = oip->oipi_id;
+ (void) strlcpy(oip->oipi_name, overlay_dev_props[propid],
+ sizeof (oip->oipi_name));
+ }
+
+ switch (propid) {
+ case OVERLAY_DEV_P_MTU:
+ overlay_i_propinfo_mtu(odd, phdl);
+ break;
+ case OVERLAY_DEV_P_VNETID:
+ overlay_prop_set_prot(phdl, OVERLAY_PROP_PERM_RW);
+ overlay_prop_set_type(phdl, OVERLAY_PROP_T_UINT);
+ overlay_prop_set_nodefault(phdl);
+ break;
+ case OVERLAY_DEV_P_ENCAP:
+ overlay_prop_set_prot(phdl, OVERLAY_PROP_PERM_READ);
+ overlay_prop_set_type(phdl, OVERLAY_PROP_T_STRING);
+ overlay_prop_set_nodefault(phdl);
+ overlay_plugin_walk(overlay_propinfo_plugin_cb, phdl);
+ break;
+ case OVERLAY_DEV_P_VARPDID:
+ overlay_prop_set_prot(phdl, OVERLAY_PROP_PERM_READ);
+ overlay_prop_set_type(phdl, OVERLAY_PROP_T_UINT);
+ overlay_prop_set_nodefault(phdl);
+ break;
+ default:
+ overlay_hold_rele(odd);
+ mac_perim_exit(mph);
+ return (ENOENT);
+ }
+
+ overlay_hold_rele(odd);
+ mac_perim_exit(mph);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+overlay_i_getprop(void *karg, intptr_t arg, int mode, cred_t *cred,
+ int *rvalp)
+{
+ int ret;
+ overlay_dev_t *odd;
+ mac_perim_handle_t mph;
+ overlay_ioc_prop_t *oip = karg;
+ uint_t propid, mtu;
+
+ odd = overlay_hold_by_dlid(oip->oip_linkid);
+ if (odd == NULL)
+ return (ENOENT);
+
+ mac_perim_enter_by_mh(odd->odd_mh, &mph);
+ oip->oip_size = OVERLAY_PROP_SIZEMAX;
+ oip->oip_name[OVERLAY_PROP_NAMELEN-1] = '\0';
+ if (oip->oip_id == -1) {
+ int i;
+
+ for (i = 0; i < OVERLAY_DEV_NPROPS; i++) {
+ if (strcmp(overlay_dev_props[i], oip->oip_name) == 0)
+ break;
+ if (i == OVERLAY_DEV_NPROPS) {
+ ret = odd->odd_plugin->ovp_ops->ovpo_getprop(
+ odd->odd_pvoid, oip->oip_name,
+ oip->oip_value, &oip->oip_size);
+ overlay_hold_rele(odd);
+ mac_perim_exit(mph);
+ return (ret);
+ }
+ }
+
+ propid = i;
+ } else if (oip->oip_id >= OVERLAY_DEV_NPROPS) {
+ uint_t id = oip->oip_id - OVERLAY_DEV_NPROPS;
+
+ if (id > odd->odd_plugin->ovp_nprops) {
+ overlay_hold_rele(odd);
+ mac_perim_exit(mph);
+ return (EINVAL);
+ }
+ ret = odd->odd_plugin->ovp_ops->ovpo_getprop(odd->odd_pvoid,
+ odd->odd_plugin->ovp_props[id], oip->oip_value,
+ &oip->oip_size);
+ overlay_hold_rele(odd);
+ mac_perim_exit(mph);
+ return (ret);
+ } else if (oip->oip_id < -1) {
+ overlay_hold_rele(odd);
+ mac_perim_exit(mph);
+ return (EINVAL);
+ } else {
+ ASSERT(oip->oip_id < OVERLAY_DEV_NPROPS);
+ ASSERT(oip->oip_id >= 0);
+ propid = oip->oip_id;
+ }
+
+ ret = 0;
+ switch (propid) {
+ case OVERLAY_DEV_P_MTU:
+ /*
+ * The MTU is always set and retrieved through MAC, to allow for
+ * MAC to do whatever it wants, as really that property belongs
+ * to MAC. This is important for things where vnics have hold on
+ * the MTU.
+ */
+ mac_sdu_get(odd->odd_mh, NULL, &mtu);
+ bcopy(&mtu, oip->oip_value, sizeof (uint_t));
+ oip->oip_size = sizeof (uint_t);
+ break;
+ case OVERLAY_DEV_P_VNETID:
+ /*
+ * While it's read-only while inside of a mux, we're not in a
+ * context that can guarantee that. Therefore we always grab the
+ * overlay_dev_t's odd_lock.
+ */
+ mutex_enter(&odd->odd_lock);
+ bcopy(&odd->odd_vid, oip->oip_value, sizeof (uint64_t));
+ mutex_exit(&odd->odd_lock);
+ oip->oip_size = sizeof (uint64_t);
+ break;
+ case OVERLAY_DEV_P_ENCAP:
+ oip->oip_size = strlcpy((char *)oip->oip_value,
+ odd->odd_plugin->ovp_name, oip->oip_size);
+ break;
+ case OVERLAY_DEV_P_VARPDID:
+ mutex_enter(&odd->odd_lock);
+ if (odd->odd_flags & OVERLAY_F_VARPD) {
+ const uint64_t val = odd->odd_target->ott_id;
+ bcopy(&val, oip->oip_value, sizeof (uint64_t));
+ oip->oip_size = sizeof (uint64_t);
+ } else {
+ oip->oip_size = 0;
+ }
+ mutex_exit(&odd->odd_lock);
+ break;
+ default:
+ ret = ENOENT;
+ }
+
+ overlay_hold_rele(odd);
+ mac_perim_exit(mph);
+ return (ret);
+}
+
+static void
+overlay_setprop_vnetid(overlay_dev_t *odd, uint64_t vnetid)
+{
+ mutex_enter(&odd->odd_lock);
+
+ /* Simple case, not active */
+ if (!(odd->odd_flags & OVERLAY_F_IN_MUX)) {
+ odd->odd_vid = vnetid;
+ mutex_exit(&odd->odd_lock);
+ return;
+ }
+
+ /*
+ * In the hard case, we need to set the drop flag, quiesce I/O and then
+ * we can go ahead and do everything.
+ */
+ odd->odd_flags |= OVERLAY_F_MDDROP;
+ overlay_io_wait(odd, OVERLAY_F_IOMASK);
+ mutex_exit(&odd->odd_lock);
+
+ overlay_mux_remove_dev(odd->odd_mux, odd);
+ mutex_enter(&odd->odd_lock);
+ odd->odd_vid = vnetid;
+ mutex_exit(&odd->odd_lock);
+ overlay_mux_add_dev(odd->odd_mux, odd);
+
+ mutex_enter(&odd->odd_lock);
+ ASSERT(odd->odd_flags & OVERLAY_F_IN_MUX);
+ odd->odd_flags &= ~OVERLAY_F_IN_MUX;
+ mutex_exit(&odd->odd_lock);
+}
+
+/* ARGSUSED */
+static int
+overlay_i_setprop(void *karg, intptr_t arg, int mode, cred_t *cred,
+ int *rvalp)
+{
+ int ret;
+ overlay_dev_t *odd;
+ overlay_ioc_prop_t *oip = karg;
+ uint_t propid = UINT_MAX;
+ mac_perim_handle_t mph;
+ uint64_t maxid, *vidp;
+
+ if (oip->oip_size > OVERLAY_PROP_SIZEMAX)
+ return (EINVAL);
+
+ odd = overlay_hold_by_dlid(oip->oip_linkid);
+ if (odd == NULL)
+ return (ENOENT);
+
+ oip->oip_name[OVERLAY_PROP_NAMELEN-1] = '\0';
+ mac_perim_enter_by_mh(odd->odd_mh, &mph);
+ mutex_enter(&odd->odd_lock);
+ if (odd->odd_flags & OVERLAY_F_ACTIVATED) {
+ mac_perim_exit(mph);
+ mutex_exit(&odd->odd_lock);
+ return (ENOTSUP);
+ }
+ mutex_exit(&odd->odd_lock);
+ if (oip->oip_id == -1) {
+ int i;
+
+ for (i = 0; i < OVERLAY_DEV_NPROPS; i++) {
+ if (strcmp(overlay_dev_props[i], oip->oip_name) == 0)
+ break;
+ if (i == OVERLAY_DEV_NPROPS) {
+ ret = odd->odd_plugin->ovp_ops->ovpo_setprop(
+ odd->odd_pvoid, oip->oip_name,
+ oip->oip_value, oip->oip_size);
+ overlay_hold_rele(odd);
+ mac_perim_exit(mph);
+ return (ret);
+ }
+ }
+
+ propid = i;
+ } else if (oip->oip_id >= OVERLAY_DEV_NPROPS) {
+ uint_t id = oip->oip_id - OVERLAY_DEV_NPROPS;
+
+ if (id > odd->odd_plugin->ovp_nprops) {
+ mac_perim_exit(mph);
+ overlay_hold_rele(odd);
+ return (EINVAL);
+ }
+ ret = odd->odd_plugin->ovp_ops->ovpo_setprop(odd->odd_pvoid,
+ odd->odd_plugin->ovp_props[id], oip->oip_value,
+ oip->oip_size);
+ mac_perim_exit(mph);
+ overlay_hold_rele(odd);
+ return (ret);
+ } else if (oip->oip_id < -1) {
+ mac_perim_exit(mph);
+ overlay_hold_rele(odd);
+ return (EINVAL);
+ } else {
+ ASSERT(oip->oip_id < OVERLAY_DEV_NPROPS);
+ ASSERT(oip->oip_id >= 0);
+ propid = oip->oip_id;
+ }
+
+ ret = 0;
+ switch (propid) {
+ case OVERLAY_DEV_P_MTU:
+ ret = mac_set_prop(odd->odd_mh, MAC_PROP_MTU, "mtu",
+ oip->oip_value, oip->oip_size);
+ break;
+ case OVERLAY_DEV_P_VNETID:
+ if (oip->oip_size != sizeof (uint64_t)) {
+ ret = EINVAL;
+ break;
+ }
+ vidp = (uint64_t *)oip->oip_value;
+ ASSERT(odd->odd_plugin->ovp_id_size <= 8);
+ maxid = UINT64_MAX;
+ if (odd->odd_plugin->ovp_id_size != 8)
+ maxid = (1ULL << (odd->odd_plugin->ovp_id_size * 8)) -
+ 1ULL;
+ if (*vidp >= maxid) {
+ ret = EINVAL;
+ break;
+ }
+ overlay_setprop_vnetid(odd, *vidp);
+ break;
+ case OVERLAY_DEV_P_ENCAP:
+ case OVERLAY_DEV_P_VARPDID:
+ ret = EPERM;
+ break;
+ default:
+ ret = ENOENT;
+ }
+
+ mac_perim_exit(mph);
+ overlay_hold_rele(odd);
+ return (ret);
+}
+
+/* ARGSUSED */
+static int
+overlay_i_status(void *karg, intptr_t arg, int mode, cred_t *cred,
+ int *rvalp)
+{
+ overlay_dev_t *odd;
+ overlay_ioc_status_t *os = karg;
+
+ odd = overlay_hold_by_dlid(os->ois_linkid);
+ if (odd == NULL)
+ return (ENOENT);
+
+ mutex_enter(&odd->odd_lock);
+ if ((odd->odd_flags & OVERLAY_F_DEGRADED) != 0) {
+ os->ois_status = OVERLAY_I_DEGRADED;
+ if (odd->odd_fmamsg != NULL) {
+ (void) strlcpy(os->ois_message, odd->odd_fmamsg,
+ OVERLAY_STATUS_BUFLEN);
+ } else {
+ os->ois_message[0] = '\0';
+ }
+
+ } else {
+ os->ois_status = OVERLAY_I_OK;
+ os->ois_message[0] = '\0';
+ }
+ mutex_exit(&odd->odd_lock);
+ overlay_hold_rele(odd);
+
+ return (0);
+}
+
+static dld_ioc_info_t overlay_ioc_list[] = {
+ { OVERLAY_IOC_CREATE, DLDCOPYIN, sizeof (overlay_ioc_create_t),
+ overlay_i_create, secpolicy_dl_config },
+ { OVERLAY_IOC_ACTIVATE, DLDCOPYIN, sizeof (overlay_ioc_activate_t),
+ overlay_i_activate, secpolicy_dl_config },
+ { OVERLAY_IOC_DELETE, DLDCOPYIN, sizeof (overlay_ioc_delete_t),
+ overlay_i_delete, secpolicy_dl_config },
+ { OVERLAY_IOC_PROPINFO, DLDCOPYIN | DLDCOPYOUT,
+ sizeof (overlay_ioc_propinfo_t), overlay_i_propinfo,
+ secpolicy_dl_config },
+ { OVERLAY_IOC_GETPROP, DLDCOPYIN | DLDCOPYOUT,
+ sizeof (overlay_ioc_prop_t), overlay_i_getprop,
+ secpolicy_dl_config },
+ { OVERLAY_IOC_SETPROP, DLDCOPYIN,
+ sizeof (overlay_ioc_prop_t), overlay_i_setprop,
+ secpolicy_dl_config },
+ { OVERLAY_IOC_NPROPS, DLDCOPYIN | DLDCOPYOUT,
+ sizeof (overlay_ioc_nprops_t), overlay_i_nprops,
+ secpolicy_dl_config },
+ { OVERLAY_IOC_STATUS, DLDCOPYIN | DLDCOPYOUT,
+ sizeof (overlay_ioc_status_t), overlay_i_status,
+ NULL }
+};
+
+static int
+overlay_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ int fmcap = DDI_FM_EREPORT_CAPABLE;
+ if (cmd != DDI_ATTACH)
+ return (DDI_FAILURE);
+
+ if (overlay_dip != NULL || ddi_get_instance(dip) != 0)
+ return (DDI_FAILURE);
+
+ ddi_fm_init(dip, &fmcap, NULL);
+
+ if (ddi_create_minor_node(dip, OVERLAY_CTL, S_IFCHR,
+ ddi_get_instance(dip), DDI_PSEUDO, 0) == DDI_FAILURE)
+ return (DDI_FAILURE);
+
+ if (dld_ioc_register(OVERLAY_IOC, overlay_ioc_list,
+ DLDIOCCNT(overlay_ioc_list)) != 0) {
+ ddi_remove_minor_node(dip, OVERLAY_CTL);
+ return (DDI_FAILURE);
+ }
+
+ overlay_dip = dip;
+ return (DDI_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+overlay_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp)
+{
+ int error;
+
+ switch (cmd) {
+ case DDI_INFO_DEVT2DEVINFO:
+ *resp = (void *)overlay_dip;
+ error = DDI_SUCCESS;
+ break;
+ case DDI_INFO_DEVT2INSTANCE:
+ *resp = (void *)0;
+ error = DDI_SUCCESS;
+ break;
+ default:
+ error = DDI_FAILURE;
+ break;
+ }
+
+ return (error);
+}
+
+static int
+overlay_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ if (cmd != DDI_DETACH)
+ return (DDI_FAILURE);
+
+ mutex_enter(&overlay_dev_lock);
+ if (!list_is_empty(&overlay_dev_list) || overlay_target_busy()) {
+ mutex_exit(&overlay_dev_lock);
+ return (EBUSY);
+ }
+ mutex_exit(&overlay_dev_lock);
+
+
+ dld_ioc_unregister(OVERLAY_IOC);
+ ddi_remove_minor_node(dip, OVERLAY_CTL);
+ ddi_fm_fini(dip);
+ overlay_dip = NULL;
+ return (DDI_SUCCESS);
+}
+
+static struct cb_ops overlay_cbops = {
+ overlay_target_open, /* cb_open */
+ overlay_target_close, /* cb_close */
+ nodev, /* cb_strategy */
+ nodev, /* cb_print */
+ nodev, /* cb_dump */
+ nodev, /* cb_read */
+ nodev, /* cb_write */
+ overlay_target_ioctl, /* cb_ioctl */
+ nodev, /* cb_devmap */
+ nodev, /* cb_mmap */
+ nodev, /* cb_segmap */
+ nochpoll, /* cb_chpoll */
+ ddi_prop_op, /* cb_prop_op */
+ NULL, /* cb_stream */
+ D_MP, /* cb_flag */
+ CB_REV, /* cb_rev */
+ nodev, /* cb_aread */
+ nodev, /* cb_awrite */
+};
+
+static struct dev_ops overlay_dev_ops = {
+ DEVO_REV, /* devo_rev */
+ 0, /* devo_refcnt */
+ overlay_getinfo, /* devo_getinfo */
+ nulldev, /* devo_identify */
+ nulldev, /* devo_probe */
+ overlay_attach, /* devo_attach */
+ overlay_detach, /* devo_detach */
+ nulldev, /* devo_reset */
+ &overlay_cbops, /* devo_cb_ops */
+ NULL, /* devo_bus_ops */
+ NULL, /* devo_power */
+ ddi_quiesce_not_supported /* devo_quiesce */
+};
+
+static struct modldrv overlay_modldrv = {
+ &mod_driverops,
+ "Overlay Network Driver",
+ &overlay_dev_ops
+};
+
+static struct modlinkage overlay_linkage = {
+ MODREV_1,
+ &overlay_modldrv
+};
+
+static int
+overlay_init(void)
+{
+ mutex_init(&overlay_dev_lock, NULL, MUTEX_DRIVER, NULL);
+ list_create(&overlay_dev_list, sizeof (overlay_dev_t),
+ offsetof(overlay_dev_t, odd_link));
+ overlay_mux_init();
+ overlay_plugin_init();
+ overlay_target_init();
+
+ return (DDI_SUCCESS);
+}
+
+static void
+overlay_fini(void)
+{
+ overlay_target_fini();
+ overlay_plugin_fini();
+ overlay_mux_fini();
+ mutex_destroy(&overlay_dev_lock);
+ list_destroy(&overlay_dev_list);
+}
+
+int
+_init(void)
+{
+ int err;
+
+ if ((err = overlay_init()) != DDI_SUCCESS)
+ return (err);
+
+ mac_init_ops(NULL, "overlay");
+ err = mod_install(&overlay_linkage);
+ if (err != DDI_SUCCESS) {
+ overlay_fini();
+ return (err);
+ }
+
+ return (0);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&overlay_linkage, modinfop));
+}
+
+int
+_fini(void)
+{
+ int err;
+
+ err = mod_remove(&overlay_linkage);
+ if (err != 0)
+ return (err);
+
+ overlay_fini();
+ return (0);
+}
diff --git a/usr/src/uts/common/io/overlay/overlay.conf b/usr/src/uts/common/io/overlay/overlay.conf
new file mode 100644
index 0000000000..4b62fafd94
--- /dev/null
+++ b/usr/src/uts/common/io/overlay/overlay.conf
@@ -0,0 +1,16 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015, Joyent, Inc.
+#
+
+name="overlay" parent="pseudo" instance=0;
diff --git a/usr/src/uts/common/io/overlay/overlay.mapfile b/usr/src/uts/common/io/overlay/overlay.mapfile
new file mode 100644
index 0000000000..800d72dc2b
--- /dev/null
+++ b/usr/src/uts/common/io/overlay/overlay.mapfile
@@ -0,0 +1,46 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION ILLUMOSprivate {
+ global:
+ # DDI Interfaces
+ _fini;
+ _init;
+ _info;
+
+ # Encapsualation Plugin interfaces
+ overlay_plugin_alloc;
+ overlay_plugin_free;
+ overlay_plugin_register;
+ overlay_plugin_unregister;
+ local:
+ *;
+};
diff --git a/usr/src/uts/common/io/overlay/overlay_fm.c b/usr/src/uts/common/io/overlay/overlay_fm.c
new file mode 100644
index 0000000000..0701d08e8b
--- /dev/null
+++ b/usr/src/uts/common/io/overlay/overlay_fm.c
@@ -0,0 +1,82 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * Overlay device FMA operations.
+ *
+ * For more information, see the big theory statement in
+ * uts/common/io/overlay/overlay.c
+ */
+
+#include <sys/ddifm.h>
+#include <sys/overlay_impl.h>
+
+kmutex_t overlay_fm_lock;
+uint_t overlay_fm_count;
+
+void
+overlay_fm_init(void)
+{
+ overlay_fm_count = 0;
+ mutex_init(&overlay_fm_lock, NULL, MUTEX_DRIVER, NULL);
+}
+
+void
+overlay_fm_fini(void)
+{
+ VERIFY(overlay_fm_count == 0);
+ mutex_destroy(&overlay_fm_lock);
+}
+
+void
+overlay_fm_degrade(overlay_dev_t *odd, const char *msg)
+{
+ mutex_enter(&overlay_fm_lock);
+ mutex_enter(&odd->odd_lock);
+
+ if (msg != NULL)
+ (void) strlcpy(odd->odd_fmamsg, msg, OVERLAY_STATUS_BUFLEN);
+
+ if (odd->odd_flags & OVERLAY_F_DEGRADED)
+ goto out;
+
+ odd->odd_flags |= OVERLAY_F_DEGRADED;
+ overlay_fm_count++;
+ if (overlay_fm_count == 1) {
+ ddi_fm_service_impact(overlay_dip, DDI_SERVICE_DEGRADED);
+ }
+out:
+ mutex_exit(&odd->odd_lock);
+ mutex_exit(&overlay_fm_lock);
+}
+
+void
+overlay_fm_restore(overlay_dev_t *odd)
+{
+ mutex_enter(&overlay_fm_lock);
+ mutex_enter(&odd->odd_lock);
+ if (!(odd->odd_flags & OVERLAY_F_DEGRADED))
+ goto out;
+
+ odd->odd_fmamsg[0] = '\0';
+ odd->odd_flags &= ~OVERLAY_F_DEGRADED;
+ overlay_fm_count--;
+ if (overlay_fm_count == 0) {
+ ddi_fm_service_impact(overlay_dip, DDI_SERVICE_RESTORED);
+ }
+out:
+ mutex_exit(&odd->odd_lock);
+ mutex_exit(&overlay_fm_lock);
+}
diff --git a/usr/src/uts/common/io/overlay/overlay_mux.c b/usr/src/uts/common/io/overlay/overlay_mux.c
new file mode 100644
index 0000000000..cd612763e1
--- /dev/null
+++ b/usr/src/uts/common/io/overlay/overlay_mux.c
@@ -0,0 +1,363 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+/*
+ * Overlay device ksocket multiplexer.
+ *
+ * For more information, see the big theory statement in
+ * uts/common/io/overlay/overlay.c
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ksynch.h>
+#include <sys/ksocket.h>
+#include <sys/avl.h>
+#include <sys/list.h>
+#include <sys/pattr.h>
+#include <sys/sysmacros.h>
+#include <sys/strsubr.h>
+#include <sys/strsun.h>
+#include <sys/tihdr.h>
+
+#include <sys/overlay_impl.h>
+
+#include <sys/sdt.h>
+
+#define OVERLAY_FREEMSG(mp, reason) \
+ DTRACE_PROBE2(overlay__freemsg, mblk_t *, mp, char *, reason)
+
+static list_t overlay_mux_list;
+static kmutex_t overlay_mux_lock;
+
+void
+overlay_mux_init(void)
+{
+ list_create(&overlay_mux_list, sizeof (overlay_mux_t),
+ offsetof(overlay_mux_t, omux_lnode));
+ mutex_init(&overlay_mux_lock, NULL, MUTEX_DRIVER, NULL);
+}
+
+void
+overlay_mux_fini(void)
+{
+ mutex_destroy(&overlay_mux_lock);
+ list_destroy(&overlay_mux_list);
+}
+
+static int
+overlay_mux_comparator(const void *a, const void *b)
+{
+ const overlay_dev_t *odl, *odr;
+ odl = a;
+ odr = b;
+ if (odl->odd_vid > odr->odd_vid)
+ return (1);
+ else if (odl->odd_vid < odr->odd_vid)
+ return (-1);
+ else
+ return (0);
+}
+
+/*
+ * This is the central receive data path. We need to decode the packet, if we
+ * can, and then deliver it to the appropriate overlay.
+ */
+/* ARGSUSED */
+static boolean_t
+overlay_mux_recv(ksocket_t ks, mblk_t *mpchain, size_t msgsize, int oob,
+ void *arg)
+{
+ mblk_t *mp, *nmp, *fmp;
+ overlay_mux_t *mux = arg;
+
+ /*
+ * We may have a received a chain of messages. Each message in the
+ * chain will likely have a T_unitdata_ind attached to it as an M_PROTO.
+ * If we aren't getting that, we should probably drop that for the
+ * moment.
+ */
+ for (mp = mpchain; mp != NULL; mp = nmp) {
+ struct T_unitdata_ind *tudi;
+ ovep_encap_info_t infop;
+ overlay_dev_t od, *odd;
+ int ret;
+
+ nmp = mp->b_next;
+ mp->b_next = NULL;
+
+ if (DB_TYPE(mp) != M_PROTO) {
+ OVERLAY_FREEMSG(mp, "first one isn't M_PROTO");
+ freemsg(mp);
+ continue;
+ }
+
+ if (mp->b_cont == NULL) {
+ OVERLAY_FREEMSG(mp, "missing a b_cont");
+ freemsg(mp);
+ continue;
+ }
+
+ tudi = (struct T_unitdata_ind *)mp->b_rptr;
+ if (tudi->PRIM_type != T_UNITDATA_IND) {
+ OVERLAY_FREEMSG(mp, "Not a T_unitdata_ind *");
+ freemsg(mp);
+ continue;
+ }
+
+ /*
+ * In the future, we'll care about the source information
+ * for purposes of telling varpd for oob invalidation. But for
+ * now, just drop that block.
+ */
+ fmp = mp;
+ mp = fmp->b_cont;
+ freeb(fmp);
+
+ /*
+ * Until we have VXLAN-or-other-decap HW acceleration support
+ * (e.g. we support NICs that reach into VXLAN-encapsulated
+ * packets and check the inside-VXLAN IP packets' checksums,
+ * or do LSO with VXLAN), we should clear any HW-accelerated-
+ * performed bits.
+ */
+ DB_CKSUMFLAGS(mp) = 0;
+
+ /*
+ * Decap and deliver.
+ */
+ bzero(&infop, sizeof (ovep_encap_info_t));
+ ret = mux->omux_plugin->ovp_ops->ovpo_decap(NULL, mp, &infop);
+ if (ret != 0) {
+ OVERLAY_FREEMSG(mp, "decap failed");
+ freemsg(mp);
+ continue;
+ }
+ if (MBLKL(mp) > infop.ovdi_hdr_size) {
+ mp->b_rptr += infop.ovdi_hdr_size;
+ } else {
+ while (infop.ovdi_hdr_size != 0) {
+ size_t rem, blkl;
+
+ if (mp == NULL)
+ break;
+
+ blkl = MBLKL(mp);
+ rem = MIN(infop.ovdi_hdr_size, blkl);
+ infop.ovdi_hdr_size -= rem;
+ mp->b_rptr += rem;
+ if (rem == blkl) {
+ fmp = mp;
+ mp = fmp->b_cont;
+ fmp->b_cont = NULL;
+ OVERLAY_FREEMSG(mp,
+ "freed a fmp block");
+ freemsg(fmp);
+ }
+ }
+ if (mp == NULL) {
+ OVERLAY_FREEMSG(mp, "freed it all...");
+ continue;
+ }
+ }
+
+
+ od.odd_vid = infop.ovdi_id;
+ mutex_enter(&mux->omux_lock);
+ odd = avl_find(&mux->omux_devices, &od, NULL);
+ if (odd == NULL) {
+ mutex_exit(&mux->omux_lock);
+ OVERLAY_FREEMSG(mp, "no matching vid");
+ freemsg(mp);
+ continue;
+ }
+ mutex_enter(&odd->odd_lock);
+ if ((odd->odd_flags & OVERLAY_F_MDDROP) ||
+ !(odd->odd_flags & OVERLAY_F_IN_MUX)) {
+ mutex_exit(&odd->odd_lock);
+ mutex_exit(&mux->omux_lock);
+ OVERLAY_FREEMSG(mp, "dev dropped");
+ freemsg(mp);
+ continue;
+ }
+ overlay_io_start(odd, OVERLAY_F_IN_RX);
+ mutex_exit(&odd->odd_lock);
+ mutex_exit(&mux->omux_lock);
+
+ mac_rx(odd->odd_mh, NULL, mp);
+
+ mutex_enter(&odd->odd_lock);
+ overlay_io_done(odd, OVERLAY_F_IN_RX);
+ mutex_exit(&odd->odd_lock);
+ }
+
+ return (B_TRUE);
+}
+
+/*
+ * Register a given device with a socket backend. If no such device socket
+ * exists, create a new one.
+ */
+overlay_mux_t *
+overlay_mux_open(overlay_plugin_t *opp, int domain, int family, int protocol,
+ struct sockaddr *addr, socklen_t len, int *errp)
+{
+ int err;
+ overlay_mux_t *mux;
+ ksocket_t ksock;
+
+ if (errp == NULL)
+ errp = &err;
+
+ mutex_enter(&overlay_mux_lock);
+ for (mux = list_head(&overlay_mux_list); mux != NULL;
+ mux = list_next(&overlay_mux_list, mux)) {
+ if (domain == mux->omux_domain &&
+ family == mux->omux_family &&
+ protocol == mux->omux_protocol &&
+ len == mux->omux_alen &&
+ bcmp(addr, mux->omux_addr, len) == 0) {
+
+ if (opp != mux->omux_plugin) {
+ *errp = EEXIST;
+ return (NULL);
+ }
+
+ mutex_enter(&mux->omux_lock);
+ mux->omux_count++;
+ mutex_exit(&mux->omux_lock);
+ mutex_exit(&overlay_mux_lock);
+ *errp = 0;
+ return (mux);
+ }
+ }
+
+ /*
+ * Today we aren't zone-aware and only exist in the global zone. When we
+ * allow for things to exist in the non-global zone, we'll want to use a
+ * credential that's actually specific to the zone.
+ */
+ *errp = ksocket_socket(&ksock, domain, family, protocol, KSOCKET_SLEEP,
+ kcred);
+ if (*errp != 0) {
+ mutex_exit(&overlay_mux_lock);
+ return (NULL);
+ }
+
+ *errp = ksocket_bind(ksock, addr, len, kcred);
+ if (*errp != 0) {
+ mutex_exit(&overlay_mux_lock);
+ ksocket_close(ksock, kcred);
+ return (NULL);
+ }
+
+ /*
+ * Ask our lower layer to optionally toggle anything they need on this
+ * socket. Because a socket is owned by a single type of plugin, we can
+ * then ask it to perform any additional socket set up it'd like to do.
+ */
+ if (opp->ovp_ops->ovpo_sockopt != NULL &&
+ (*errp = opp->ovp_ops->ovpo_sockopt(ksock)) != 0) {
+ mutex_exit(&overlay_mux_lock);
+ ksocket_close(ksock, kcred);
+ return (NULL);
+ }
+
+ mux = kmem_alloc(sizeof (overlay_mux_t), KM_SLEEP);
+ list_link_init(&mux->omux_lnode);
+ mux->omux_ksock = ksock;
+ mux->omux_plugin = opp;
+ mux->omux_domain = domain;
+ mux->omux_family = family;
+ mux->omux_protocol = protocol;
+ mux->omux_addr = kmem_alloc(len, KM_SLEEP);
+ bcopy(addr, mux->omux_addr, len);
+ mux->omux_alen = len;
+ mux->omux_count = 1;
+ avl_create(&mux->omux_devices, overlay_mux_comparator,
+ sizeof (overlay_dev_t), offsetof(overlay_dev_t, odd_muxnode));
+ mutex_init(&mux->omux_lock, NULL, MUTEX_DRIVER, NULL);
+
+
+ /* Once this is called, we need to expect to rx data */
+ *errp = ksocket_krecv_set(ksock, overlay_mux_recv, mux);
+ if (*errp != 0) {
+ ksocket_close(ksock, kcred);
+ mutex_destroy(&mux->omux_lock);
+ avl_destroy(&mux->omux_devices);
+ kmem_free(mux->omux_addr, len);
+ kmem_free(mux, sizeof (overlay_mux_t));
+ return (NULL);
+ }
+
+ list_insert_tail(&overlay_mux_list, mux);
+ mutex_exit(&overlay_mux_lock);
+
+ *errp = 0;
+ return (mux);
+}
+
+void
+overlay_mux_close(overlay_mux_t *mux)
+{
+ mutex_enter(&overlay_mux_lock);
+ mutex_enter(&mux->omux_lock);
+ mux->omux_count--;
+ if (mux->omux_count != 0) {
+ mutex_exit(&mux->omux_lock);
+ mutex_exit(&overlay_mux_lock);
+ return;
+ }
+ list_remove(&overlay_mux_list, mux);
+ mutex_exit(&mux->omux_lock);
+ mutex_exit(&overlay_mux_lock);
+
+ ksocket_close(mux->omux_ksock, kcred);
+ avl_destroy(&mux->omux_devices);
+ kmem_free(mux->omux_addr, mux->omux_alen);
+ kmem_free(mux, sizeof (overlay_mux_t));
+}
+
+void
+overlay_mux_add_dev(overlay_mux_t *mux, overlay_dev_t *odd)
+{
+ mutex_enter(&mux->omux_lock);
+ avl_add(&mux->omux_devices, odd);
+ mutex_exit(&mux->omux_lock);
+}
+
+void
+overlay_mux_remove_dev(overlay_mux_t *mux, overlay_dev_t *odd)
+{
+ mutex_enter(&mux->omux_lock);
+ avl_remove(&mux->omux_devices, odd);
+ mutex_exit(&mux->omux_lock);
+}
+
+int
+overlay_mux_tx(overlay_mux_t *mux, struct msghdr *hdr, mblk_t *mp)
+{
+ int ret;
+
+ /*
+ * It'd be nice to be able to use MSG_MBLK_QUICKRELE, unfortunately,
+ * that isn't actually supported by UDP at this time.
+ */
+ ret = ksocket_sendmblk(mux->omux_ksock, hdr, 0, &mp, kcred);
+ if (ret != 0)
+ freemsg(mp);
+
+ return (ret);
+}
diff --git a/usr/src/uts/common/io/overlay/overlay_plugin.c b/usr/src/uts/common/io/overlay/overlay_plugin.c
new file mode 100644
index 0000000000..348ddb92a2
--- /dev/null
+++ b/usr/src/uts/common/io/overlay/overlay_plugin.c
@@ -0,0 +1,281 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Overlay device encapsulation plugin management
+ *
+ * For more information, see the big theory statement in
+ * uts/common/io/overlay/overlay.c
+ */
+
+#include <sys/types.h>
+#include <sys/kmem.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/errno.h>
+#include <sys/sysmacros.h>
+#include <sys/modctl.h>
+
+#include <sys/overlay_impl.h>
+
+static kmem_cache_t *overlay_plugin_cache;
+static kmutex_t overlay_plugin_lock;
+static list_t overlay_plugin_list;
+
+#define OVERLAY_MODDIR "overlay"
+
+/* ARGSUSED */
+static int
+overlay_plugin_cache_constructor(void *buf, void *arg, int kmflags)
+{
+ overlay_plugin_t *opp = buf;
+
+ mutex_init(&opp->ovp_mutex, NULL, MUTEX_DRIVER, NULL);
+ list_link_init(&opp->ovp_link);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static void
+overlay_plugin_cache_destructor(void *buf, void *arg)
+{
+ overlay_plugin_t *opp = buf;
+ ASSERT(list_link_active(&opp->ovp_link) == 0);
+ mutex_destroy(&opp->ovp_mutex);
+}
+
+void
+overlay_plugin_init(void)
+{
+ mutex_init(&overlay_plugin_lock, NULL, MUTEX_DRIVER, 0);
+
+ /*
+ * In the future we may want to have a reaper to unload unused modules
+ * to help the kernel be able to reclaim memory.
+ */
+ overlay_plugin_cache = kmem_cache_create("overlay_plugin_cache",
+ sizeof (overlay_plugin_t), 0, overlay_plugin_cache_constructor,
+ overlay_plugin_cache_destructor, NULL, NULL, NULL, 0);
+ list_create(&overlay_plugin_list, sizeof (overlay_plugin_t),
+ offsetof(overlay_plugin_t, ovp_link));
+}
+
+void
+overlay_plugin_fini(void)
+{
+ mutex_enter(&overlay_plugin_lock);
+ VERIFY(list_is_empty(&overlay_plugin_list));
+ mutex_exit(&overlay_plugin_lock);
+
+ list_destroy(&overlay_plugin_list);
+ kmem_cache_destroy(overlay_plugin_cache);
+ mutex_destroy(&overlay_plugin_lock);
+}
+
+overlay_plugin_register_t *
+overlay_plugin_alloc(uint_t version)
+{
+ overlay_plugin_register_t *ovrp;
+ /* Version 1 is the only one that exists */
+ if (version != OVEP_VERSION_ONE)
+ return (NULL);
+
+ ovrp = kmem_zalloc(sizeof (overlay_plugin_register_t), KM_SLEEP);
+ ovrp->ovep_version = version;
+ return (ovrp);
+}
+
+void
+overlay_plugin_free(overlay_plugin_register_t *ovrp)
+{
+ kmem_free(ovrp, sizeof (overlay_plugin_register_t));
+}
+
+int
+overlay_plugin_register(overlay_plugin_register_t *ovrp)
+{
+ overlay_plugin_t *opp, *ipp;
+
+ /* Sanity check parameters of the registration */
+ if (ovrp->ovep_version != OVEP_VERSION_ONE)
+ return (EINVAL);
+
+ if (ovrp->ovep_name == NULL || ovrp->ovep_ops == NULL)
+ return (EINVAL);
+
+ if ((ovrp->ovep_flags & ~(OVEP_F_VLAN_TAG)) != 0)
+ return (EINVAL);
+
+ if (ovrp->ovep_id_size < 1)
+ return (EINVAL);
+
+ /* Don't support anything that has an id size larger than 8 bytes */
+ if (ovrp->ovep_id_size > 8)
+ return (ENOTSUP);
+
+ if (ovrp->ovep_dest == OVERLAY_PLUGIN_D_INVALID)
+ return (EINVAL);
+
+ if ((ovrp->ovep_dest & ~OVERLAY_PLUGIN_D_MASK) != 0)
+ return (EINVAL);
+
+ if (ovrp->ovep_ops->ovpo_callbacks != 0)
+ return (EINVAL);
+ if (ovrp->ovep_ops->ovpo_init == NULL)
+ return (EINVAL);
+ if (ovrp->ovep_ops->ovpo_fini == NULL)
+ return (EINVAL);
+ if (ovrp->ovep_ops->ovpo_encap == NULL)
+ return (EINVAL);
+ if (ovrp->ovep_ops->ovpo_decap == NULL)
+ return (EINVAL);
+ if (ovrp->ovep_ops->ovpo_socket == NULL)
+ return (EINVAL);
+ if (ovrp->ovep_ops->ovpo_getprop == NULL)
+ return (EINVAL);
+ if (ovrp->ovep_ops->ovpo_setprop == NULL)
+ return (EINVAL);
+ if (ovrp->ovep_ops->ovpo_propinfo == NULL)
+ return (EINVAL);
+
+
+ opp = kmem_cache_alloc(overlay_plugin_cache, KM_SLEEP);
+ opp->ovp_active = 0;
+ opp->ovp_name = ovrp->ovep_name;
+ opp->ovp_ops = ovrp->ovep_ops;
+ opp->ovp_props = ovrp->ovep_props;
+ opp->ovp_id_size = ovrp->ovep_id_size;
+ opp->ovp_flags = ovrp->ovep_flags;
+ opp->ovp_dest = ovrp->ovep_dest;
+
+ opp->ovp_nprops = 0;
+ if (ovrp->ovep_props != NULL) {
+ while (ovrp->ovep_props[opp->ovp_nprops] != NULL) {
+ if (strlen(ovrp->ovep_props[opp->ovp_nprops]) >=
+ OVERLAY_PROP_NAMELEN) {
+ mutex_exit(&overlay_plugin_lock);
+ kmem_cache_free(overlay_plugin_cache, opp);
+ return (EINVAL);
+ }
+ opp->ovp_nprops++;
+ }
+ }
+
+ mutex_enter(&overlay_plugin_lock);
+ for (ipp = list_head(&overlay_plugin_list); ipp != NULL;
+ ipp = list_next(&overlay_plugin_list, ipp)) {
+ if (strcmp(ipp->ovp_name, opp->ovp_name) == 0) {
+ mutex_exit(&overlay_plugin_lock);
+ kmem_cache_free(overlay_plugin_cache, opp);
+ return (EEXIST);
+ }
+ }
+ list_insert_tail(&overlay_plugin_list, opp);
+ mutex_exit(&overlay_plugin_lock);
+
+ return (0);
+}
+
+int
+overlay_plugin_unregister(const char *name)
+{
+ overlay_plugin_t *opp;
+
+ mutex_enter(&overlay_plugin_lock);
+ for (opp = list_head(&overlay_plugin_list); opp != NULL;
+ opp = list_next(&overlay_plugin_list, opp)) {
+ if (strcmp(opp->ovp_name, name) == 0)
+ break;
+ }
+
+ if (opp == NULL) {
+ mutex_exit(&overlay_plugin_lock);
+ return (ENOENT);
+ }
+
+ mutex_enter(&opp->ovp_mutex);
+ if (opp->ovp_active > 0) {
+ mutex_exit(&opp->ovp_mutex);
+ mutex_exit(&overlay_plugin_lock);
+ return (EBUSY);
+ }
+ mutex_exit(&opp->ovp_mutex);
+
+ list_remove(&overlay_plugin_list, opp);
+ mutex_exit(&overlay_plugin_lock);
+
+ kmem_cache_free(overlay_plugin_cache, opp);
+ return (0);
+}
+
+overlay_plugin_t *
+overlay_plugin_lookup(const char *name)
+{
+ overlay_plugin_t *opp;
+ boolean_t trymodload = B_FALSE;
+
+ for (;;) {
+ mutex_enter(&overlay_plugin_lock);
+ for (opp = list_head(&overlay_plugin_list); opp != NULL;
+ opp = list_next(&overlay_plugin_list, opp)) {
+ if (strcmp(name, opp->ovp_name) == 0) {
+ mutex_enter(&opp->ovp_mutex);
+ opp->ovp_active++;
+ mutex_exit(&opp->ovp_mutex);
+ mutex_exit(&overlay_plugin_lock);
+ return (opp);
+ }
+ }
+ mutex_exit(&overlay_plugin_lock);
+
+ if (trymodload == B_TRUE)
+ return (NULL);
+
+ /*
+ * If we didn't find it, it may still exist, but just not have
+ * been a loaded module. In that case, we'll do one attempt to
+ * load it.
+ */
+ if (modload(OVERLAY_MODDIR, (char *)name) == -1)
+ return (NULL);
+ trymodload = B_TRUE;
+ }
+
+}
+
+void
+overlay_plugin_rele(overlay_plugin_t *opp)
+{
+ mutex_enter(&opp->ovp_mutex);
+ ASSERT(opp->ovp_active > 0);
+ opp->ovp_active--;
+ mutex_exit(&opp->ovp_mutex);
+}
+
+void
+overlay_plugin_walk(overlay_plugin_walk_f func, void *arg)
+{
+ overlay_plugin_t *opp;
+ mutex_enter(&overlay_plugin_lock);
+ for (opp = list_head(&overlay_plugin_list); opp != NULL;
+ opp = list_next(&overlay_plugin_list, opp)) {
+ if (func(opp, arg) != 0) {
+ mutex_exit(&overlay_plugin_lock);
+ return;
+ }
+ }
+ mutex_exit(&overlay_plugin_lock);
+}
diff --git a/usr/src/uts/common/io/overlay/overlay_prop.c b/usr/src/uts/common/io/overlay/overlay_prop.c
new file mode 100644
index 0000000000..ba1ea2a629
--- /dev/null
+++ b/usr/src/uts/common/io/overlay/overlay_prop.c
@@ -0,0 +1,122 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015, Joyent, Inc.
+ */
+
+/*
+ * Routines for manipulating property information structures.
+ *
+ * For more information, see the big theory statement in
+ * uts/common/io/overlay/overlay.c
+ */
+
+#include <sys/overlay_impl.h>
+
+void
+overlay_prop_init(overlay_prop_handle_t phdl)
+{
+ overlay_ioc_propinfo_t *infop = (overlay_ioc_propinfo_t *)phdl;
+ mac_propval_range_t *rangep = (mac_propval_range_t *)infop->oipi_poss;
+
+ infop->oipi_posssize = sizeof (mac_propval_range_t);
+ bzero(rangep, sizeof (mac_propval_range_t));
+}
+
+void
+overlay_prop_set_name(overlay_prop_handle_t phdl, const char *name)
+{
+ overlay_ioc_propinfo_t *infop = (overlay_ioc_propinfo_t *)phdl;
+ (void) strlcpy(infop->oipi_name, name, OVERLAY_PROP_NAMELEN);
+}
+
+void
+overlay_prop_set_prot(overlay_prop_handle_t phdl, overlay_prop_prot_t prot)
+{
+ overlay_ioc_propinfo_t *infop = (overlay_ioc_propinfo_t *)phdl;
+ infop->oipi_prot = prot;
+}
+
+void
+overlay_prop_set_type(overlay_prop_handle_t phdl, overlay_prop_type_t type)
+{
+ overlay_ioc_propinfo_t *infop = (overlay_ioc_propinfo_t *)phdl;
+ infop->oipi_type = type;
+}
+
+int
+overlay_prop_set_default(overlay_prop_handle_t phdl, void *def, ssize_t len)
+{
+ overlay_ioc_propinfo_t *infop = (overlay_ioc_propinfo_t *)phdl;
+
+ if (len > OVERLAY_PROP_SIZEMAX)
+ return (E2BIG);
+
+ if (len < 0)
+ return (EOVERFLOW);
+
+ bcopy(def, infop->oipi_default, len);
+ infop->oipi_defsize = (uint32_t)len;
+
+ return (0);
+}
+
+void
+overlay_prop_set_nodefault(overlay_prop_handle_t phdl)
+{
+ overlay_ioc_propinfo_t *infop = (overlay_ioc_propinfo_t *)phdl;
+ infop->oipi_default[0] = '\0';
+ infop->oipi_defsize = 0;
+}
+
+void
+overlay_prop_set_range_uint32(overlay_prop_handle_t phdl, uint32_t min,
+ uint32_t max)
+{
+ overlay_ioc_propinfo_t *infop = (overlay_ioc_propinfo_t *)phdl;
+ mac_propval_range_t *rangep = (mac_propval_range_t *)infop->oipi_poss;
+
+ if (rangep->mpr_count != 0 && rangep->mpr_type != MAC_PROPVAL_UINT32)
+ return;
+
+ if (infop->oipi_posssize + sizeof (mac_propval_uint32_range_t) >
+ sizeof (infop->oipi_poss))
+ return;
+
+ infop->oipi_posssize += sizeof (mac_propval_uint32_range_t);
+ rangep->mpr_count++;
+ rangep->mpr_type = MAC_PROPVAL_UINT32;
+ rangep->u.mpr_uint32[rangep->mpr_count-1].mpur_min = min;
+ rangep->u.mpr_uint32[rangep->mpr_count-1].mpur_max = max;
+}
+
+void
+overlay_prop_set_range_str(overlay_prop_handle_t phdl, const char *str)
+{
+ size_t len = strlen(str) + 1; /* Account for a null terminator */
+ overlay_ioc_propinfo_t *infop = (overlay_ioc_propinfo_t *)phdl;
+ mac_propval_range_t *rangep = (mac_propval_range_t *)infop->oipi_poss;
+ mac_propval_str_range_t *pstr = &rangep->u.mpr_str;
+
+ if (rangep->mpr_count != 0 && rangep->mpr_type != MAC_PROPVAL_STR)
+ return;
+
+ if (infop->oipi_posssize + len > sizeof (infop->oipi_poss))
+ return;
+
+ rangep->mpr_count++;
+ rangep->mpr_type = MAC_PROPVAL_STR;
+ strlcpy((char *)&pstr->mpur_data[pstr->mpur_nextbyte], str,
+ sizeof (infop->oipi_poss) - infop->oipi_posssize);
+ pstr->mpur_nextbyte += len;
+ infop->oipi_posssize += len;
+}
diff --git a/usr/src/uts/common/io/overlay/overlay_target.c b/usr/src/uts/common/io/overlay/overlay_target.c
new file mode 100644
index 0000000000..3f2167620a
--- /dev/null
+++ b/usr/src/uts/common/io/overlay/overlay_target.c
@@ -0,0 +1,1650 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * Overlay device target cache management
+ *
+ * For more information, see the big theory statement in
+ * uts/common/io/overlay/overlay.c
+ */
+
+#include <sys/types.h>
+#include <sys/ethernet.h>
+#include <sys/kmem.h>
+#include <sys/policy.h>
+#include <sys/sysmacros.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/strsubr.h>
+#include <sys/mac_provider.h>
+#include <sys/mac_client.h>
+#include <sys/mac_client_priv.h>
+#include <sys/vlan.h>
+#include <sys/crc32.h>
+#include <sys/cred.h>
+#include <sys/file.h>
+#include <sys/errno.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+
+#include <sys/overlay_impl.h>
+#include <sys/sdt.h>
+
+/*
+ * This is total straw man, but at least it's a prime number. Here we're
+ * going to have to go through and do a lot of evaluation and understanding as
+ * to how these target caches should grow and shrink, as well as, memory
+ * pressure and evictions. This just gives us a starting point that'll be 'good
+ * enough', until it's not.
+ */
+#define OVERLAY_HSIZE 823
+
+/*
+ * We use this data structure to keep track of what requests have been actively
+ * allocated to a given instance so we know what to put back on the pending
+ * list.
+ */
+typedef struct overlay_target_hdl {
+ minor_t oth_minor; /* RO */
+ zoneid_t oth_zoneid; /* RO */
+ int oth_oflags; /* RO */
+ list_node_t oth_link; /* overlay_target_lock */
+ kmutex_t oth_lock;
+ list_t oth_outstanding; /* oth_lock */
+} overlay_target_hdl_t;
+
+typedef int (*overlay_target_copyin_f)(const void *, void **, size_t *, int);
+typedef int (*overlay_target_ioctl_f)(overlay_target_hdl_t *, void *);
+typedef int (*overlay_target_copyout_f)(void *, void *, size_t, int);
+
+typedef struct overlay_target_ioctl {
+ int oti_cmd; /* ioctl id */
+ boolean_t oti_write; /* ioctl requires FWRITE */
+ boolean_t oti_ncopyout; /* copyout data? */
+ overlay_target_copyin_f oti_copyin; /* copyin func */
+ overlay_target_ioctl_f oti_func; /* function to call */
+ overlay_target_copyout_f oti_copyout; /* copyin func */
+ size_t oti_size; /* size of user level structure */
+} overlay_target_ioctl_t;
+
+static kmem_cache_t *overlay_target_cache;
+static kmem_cache_t *overlay_entry_cache;
+static id_space_t *overlay_thdl_idspace;
+static void *overlay_thdl_state;
+
+/*
+ * When we support overlay devices in the NGZ, then all of these need to become
+ * zone aware, by plugging into the netstack engine and becoming per-netstack
+ * data.
+ */
+static list_t overlay_thdl_list;
+static kmutex_t overlay_target_lock;
+static kcondvar_t overlay_target_condvar;
+static list_t overlay_target_list;
+static boolean_t overlay_target_excl;
+
+/*
+ * Outstanding data per hash table entry.
+ */
+static int overlay_ent_size = 128 * 1024;
+
+/* ARGSUSED */
+static int
+overlay_target_cache_constructor(void *buf, void *arg, int kmflgs)
+{
+ overlay_target_t *ott = buf;
+
+ mutex_init(&ott->ott_lock, NULL, MUTEX_DRIVER, NULL);
+ cv_init(&ott->ott_cond, NULL, CV_DRIVER, NULL);
+ return (0);
+}
+
+/* ARGSUSED */
+static void
+overlay_target_cache_destructor(void *buf, void *arg)
+{
+ overlay_target_t *ott = buf;
+
+ cv_destroy(&ott->ott_cond);
+ mutex_destroy(&ott->ott_lock);
+}
+
+/* ARGSUSED */
+static int
+overlay_entry_cache_constructor(void *buf, void *arg, int kmflgs)
+{
+ overlay_target_entry_t *ote = buf;
+
+ bzero(ote, sizeof (overlay_target_entry_t));
+ mutex_init(&ote->ote_lock, NULL, MUTEX_DRIVER, NULL);
+ return (0);
+}
+
+/* ARGSUSED */
+static void
+overlay_entry_cache_destructor(void *buf, void *arg)
+{
+ overlay_target_entry_t *ote = buf;
+
+ mutex_destroy(&ote->ote_lock);
+}
+
+static uint64_t
+overlay_mac_hash(const void *v)
+{
+ uint32_t crc;
+ CRC32(crc, v, ETHERADDRL, -1U, crc32_table);
+ return (crc);
+}
+
+static int
+overlay_mac_cmp(const void *a, const void *b)
+{
+ return (bcmp(a, b, ETHERADDRL));
+}
+
+/* ARGSUSED */
+static void
+overlay_target_entry_dtor(void *arg)
+{
+ overlay_target_entry_t *ote = arg;
+
+ ote->ote_flags = 0;
+ bzero(ote->ote_addr, ETHERADDRL);
+ ote->ote_ott = NULL;
+ ote->ote_odd = NULL;
+ freemsgchain(ote->ote_chead);
+ ote->ote_chead = ote->ote_ctail = NULL;
+ ote->ote_mbsize = 0;
+ ote->ote_vtime = 0;
+ kmem_cache_free(overlay_entry_cache, ote);
+}
+
+static int
+overlay_mac_avl(const void *a, const void *b)
+{
+ int i;
+ const overlay_target_entry_t *l, *r;
+ l = a;
+ r = b;
+
+ for (i = 0; i < ETHERADDRL; i++) {
+ if (l->ote_addr[i] > r->ote_addr[i])
+ return (1);
+ else if (l->ote_addr[i] < r->ote_addr[i])
+ return (-1);
+ }
+
+ return (0);
+}
+
+void
+overlay_target_init(void)
+{
+ int ret;
+ ret = ddi_soft_state_init(&overlay_thdl_state,
+ sizeof (overlay_target_hdl_t), 1);
+ VERIFY(ret == 0);
+ overlay_target_cache = kmem_cache_create("overlay_target",
+ sizeof (overlay_target_t), 0, overlay_target_cache_constructor,
+ overlay_target_cache_destructor, NULL, NULL, NULL, 0);
+ overlay_entry_cache = kmem_cache_create("overlay_entry",
+ sizeof (overlay_target_entry_t), 0, overlay_entry_cache_constructor,
+ overlay_entry_cache_destructor, NULL, NULL, NULL, 0);
+ mutex_init(&overlay_target_lock, NULL, MUTEX_DRIVER, NULL);
+ cv_init(&overlay_target_condvar, NULL, CV_DRIVER, NULL);
+ list_create(&overlay_target_list, sizeof (overlay_target_entry_t),
+ offsetof(overlay_target_entry_t, ote_qlink));
+ list_create(&overlay_thdl_list, sizeof (overlay_target_hdl_t),
+ offsetof(overlay_target_hdl_t, oth_link));
+ overlay_thdl_idspace = id_space_create("overlay_target_minors",
+ 1, INT32_MAX);
+}
+
+void
+overlay_target_fini(void)
+{
+ id_space_destroy(overlay_thdl_idspace);
+ list_destroy(&overlay_thdl_list);
+ list_destroy(&overlay_target_list);
+ cv_destroy(&overlay_target_condvar);
+ mutex_destroy(&overlay_target_lock);
+ kmem_cache_destroy(overlay_entry_cache);
+ kmem_cache_destroy(overlay_target_cache);
+ ddi_soft_state_fini(&overlay_thdl_state);
+}
+
+void
+overlay_target_free(overlay_dev_t *odd)
+{
+ if (odd->odd_target == NULL)
+ return;
+
+ if (odd->odd_target->ott_mode == OVERLAY_TARGET_DYNAMIC) {
+ refhash_t *rp = odd->odd_target->ott_u.ott_dyn.ott_dhash;
+ avl_tree_t *ap = &odd->odd_target->ott_u.ott_dyn.ott_tree;
+ overlay_target_entry_t *ote;
+
+ /*
+ * Our AVL tree and hashtable contain the same elements,
+ * therefore we should just remove it from the tree, but then
+ * delete the entries when we remove them from the hash table
+ * (which happens through the refhash dtor).
+ */
+ while ((ote = avl_first(ap)) != NULL)
+ avl_remove(ap, ote);
+
+ avl_destroy(ap);
+ for (ote = refhash_first(rp); ote != NULL;
+ ote = refhash_next(rp, ote)) {
+ refhash_remove(rp, ote);
+ }
+ refhash_destroy(rp);
+ }
+
+ ASSERT(odd->odd_target->ott_ocount == 0);
+ kmem_cache_free(overlay_target_cache, odd->odd_target);
+}
+
+int
+overlay_target_busy()
+{
+ int ret;
+
+ mutex_enter(&overlay_target_lock);
+ ret = !list_is_empty(&overlay_thdl_list);
+ mutex_exit(&overlay_target_lock);
+
+ return (ret);
+}
+
+static void
+overlay_target_queue(overlay_target_entry_t *entry)
+{
+ mutex_enter(&overlay_target_lock);
+ mutex_enter(&entry->ote_ott->ott_lock);
+ if (entry->ote_ott->ott_flags & OVERLAY_T_TEARDOWN) {
+ mutex_exit(&entry->ote_ott->ott_lock);
+ mutex_exit(&overlay_target_lock);
+ return;
+ }
+ entry->ote_ott->ott_ocount++;
+ mutex_exit(&entry->ote_ott->ott_lock);
+ list_insert_tail(&overlay_target_list, entry);
+ cv_signal(&overlay_target_condvar);
+ mutex_exit(&overlay_target_lock);
+}
+
+void
+overlay_target_quiesce(overlay_target_t *ott)
+{
+ if (ott == NULL)
+ return;
+ mutex_enter(&ott->ott_lock);
+ ott->ott_flags |= OVERLAY_T_TEARDOWN;
+ while (ott->ott_ocount != 0)
+ cv_wait(&ott->ott_cond, &ott->ott_lock);
+ mutex_exit(&ott->ott_lock);
+}
+
+/*
+ * This functions assumes that the destination mode is OVERLAY_PLUGIN_D_IP |
+ * OVERLAY_PLUGIN_D_PORT. As we don't have an implementation of anything else at
+ * this time, say for NVGRE, we drop all packets that mcuh this.
+ */
+int
+overlay_target_lookup(overlay_dev_t *odd, mblk_t *mp, struct sockaddr *sock,
+ socklen_t *slenp)
+{
+ int ret;
+ struct sockaddr_in6 *v6;
+ overlay_target_t *ott;
+ mac_header_info_t mhi;
+ overlay_target_entry_t *entry;
+
+ ASSERT(odd->odd_target != NULL);
+
+ /*
+ * At this point, the overlay device is in a mux which means that it's
+ * been activated. At this point, parts of the target, such as the mode
+ * and the destination are now read-only and we don't have to worry
+ * about synchronization for them.
+ */
+ ott = odd->odd_target;
+ if (ott->ott_dest != (OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT))
+ return (OVERLAY_TARGET_DROP);
+
+ v6 = (struct sockaddr_in6 *)sock;
+ bzero(v6, sizeof (struct sockaddr_in6));
+ v6->sin6_family = AF_INET6;
+
+ if (ott->ott_mode == OVERLAY_TARGET_POINT) {
+ mutex_enter(&ott->ott_lock);
+ bcopy(&ott->ott_u.ott_point.otp_ip, &v6->sin6_addr,
+ sizeof (struct in6_addr));
+ v6->sin6_port = htons(ott->ott_u.ott_point.otp_port);
+ mutex_exit(&ott->ott_lock);
+ *slenp = sizeof (struct sockaddr_in6);
+
+ return (OVERLAY_TARGET_OK);
+ }
+
+ ASSERT(ott->ott_mode == OVERLAY_TARGET_DYNAMIC);
+
+ /*
+ * Note we only want the MAC address here, therefore we won't bother
+ * using mac_vlan_header_info(). If any caller needs the vlan info at
+ * this point, this should change to a call to mac_vlan_header_info().
+ */
+ if (mac_header_info(odd->odd_mh, mp, &mhi) != 0)
+ return (OVERLAY_TARGET_DROP);
+ mutex_enter(&ott->ott_lock);
+ entry = refhash_lookup(ott->ott_u.ott_dyn.ott_dhash,
+ mhi.mhi_daddr);
+ if (entry == NULL) {
+ entry = kmem_cache_alloc(overlay_entry_cache, KM_NOSLEEP_LAZY);
+ if (entry == NULL) {
+ mutex_exit(&ott->ott_lock);
+ return (OVERLAY_TARGET_DROP);
+ }
+ bcopy(mhi.mhi_daddr, entry->ote_addr, ETHERADDRL);
+ entry->ote_chead = entry->ote_ctail = mp;
+ entry->ote_mbsize = msgsize(mp);
+ entry->ote_flags |= OVERLAY_ENTRY_F_PENDING;
+ entry->ote_ott = ott;
+ entry->ote_odd = odd;
+ refhash_insert(ott->ott_u.ott_dyn.ott_dhash, entry);
+ avl_add(&ott->ott_u.ott_dyn.ott_tree, entry);
+ mutex_exit(&ott->ott_lock);
+ overlay_target_queue(entry);
+ return (OVERLAY_TARGET_ASYNC);
+ }
+ refhash_hold(ott->ott_u.ott_dyn.ott_dhash, entry);
+ mutex_exit(&ott->ott_lock);
+
+ mutex_enter(&entry->ote_lock);
+ if (entry->ote_flags & OVERLAY_ENTRY_F_DROP) {
+ ret = OVERLAY_TARGET_DROP;
+ } else if (entry->ote_flags & OVERLAY_ENTRY_F_VALID) {
+ bcopy(&entry->ote_dest.otp_ip, &v6->sin6_addr,
+ sizeof (struct in6_addr));
+ v6->sin6_port = htons(entry->ote_dest.otp_port);
+ *slenp = sizeof (struct sockaddr_in6);
+ ret = OVERLAY_TARGET_OK;
+ } else {
+ size_t mlen = msgsize(mp);
+
+ if (mlen + entry->ote_mbsize > overlay_ent_size) {
+ ret = OVERLAY_TARGET_DROP;
+ } else {
+ if (entry->ote_ctail != NULL) {
+ ASSERT(entry->ote_ctail->b_next ==
+ NULL);
+ entry->ote_ctail->b_next = mp;
+ entry->ote_ctail = mp;
+ } else {
+ entry->ote_chead = mp;
+ entry->ote_ctail = mp;
+ }
+ entry->ote_mbsize += mlen;
+ if ((entry->ote_flags &
+ OVERLAY_ENTRY_F_PENDING) == 0) {
+ entry->ote_flags |=
+ OVERLAY_ENTRY_F_PENDING;
+ overlay_target_queue(entry);
+ }
+ ret = OVERLAY_TARGET_ASYNC;
+ }
+ }
+ mutex_exit(&entry->ote_lock);
+
+ mutex_enter(&ott->ott_lock);
+ refhash_rele(ott->ott_u.ott_dyn.ott_dhash, entry);
+ mutex_exit(&ott->ott_lock);
+
+ return (ret);
+}
+
+/* ARGSUSED */
+static int
+overlay_target_info(overlay_target_hdl_t *thdl, void *arg)
+{
+ overlay_dev_t *odd;
+ overlay_targ_info_t *oti = arg;
+
+ odd = overlay_hold_by_dlid(oti->oti_linkid);
+ if (odd == NULL)
+ return (ENOENT);
+
+ mutex_enter(&odd->odd_lock);
+ oti->oti_flags = 0;
+ oti->oti_needs = odd->odd_plugin->ovp_dest;
+ if (odd->odd_flags & OVERLAY_F_DEGRADED)
+ oti->oti_flags |= OVERLAY_TARG_INFO_F_DEGRADED;
+ if (odd->odd_flags & OVERLAY_F_ACTIVATED)
+ oti->oti_flags |= OVERLAY_TARG_INFO_F_ACTIVE;
+ oti->oti_vnetid = odd->odd_vid;
+ mutex_exit(&odd->odd_lock);
+ overlay_hold_rele(odd);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+overlay_target_associate(overlay_target_hdl_t *thdl, void *arg)
+{
+ overlay_dev_t *odd;
+ overlay_target_t *ott;
+ overlay_targ_associate_t *ota = arg;
+
+ odd = overlay_hold_by_dlid(ota->ota_linkid);
+ if (odd == NULL)
+ return (ENOENT);
+
+ if (ota->ota_id == 0) {
+ overlay_hold_rele(odd);
+ return (EINVAL);
+ }
+
+ if (ota->ota_mode != OVERLAY_TARGET_POINT &&
+ ota->ota_mode != OVERLAY_TARGET_DYNAMIC) {
+ overlay_hold_rele(odd);
+ return (EINVAL);
+ }
+
+ if (ota->ota_provides != odd->odd_plugin->ovp_dest) {
+ overlay_hold_rele(odd);
+ return (EINVAL);
+ }
+
+ if (ota->ota_mode == OVERLAY_TARGET_POINT) {
+ if (ota->ota_provides & OVERLAY_PLUGIN_D_IP) {
+ if (IN6_IS_ADDR_UNSPECIFIED(&ota->ota_point.otp_ip) ||
+ IN6_IS_ADDR_V4COMPAT(&ota->ota_point.otp_ip) ||
+ IN6_IS_ADDR_V4MAPPED_ANY(&ota->ota_point.otp_ip)) {
+ overlay_hold_rele(odd);
+ return (EINVAL);
+ }
+ }
+
+ if (ota->ota_provides & OVERLAY_PLUGIN_D_PORT) {
+ if (ota->ota_point.otp_port == 0) {
+ overlay_hold_rele(odd);
+ return (EINVAL);
+ }
+ }
+ }
+
+ ott = kmem_cache_alloc(overlay_target_cache, KM_SLEEP);
+ ott->ott_flags = 0;
+ ott->ott_ocount = 0;
+ ott->ott_mode = ota->ota_mode;
+ ott->ott_dest = ota->ota_provides;
+ ott->ott_id = ota->ota_id;
+
+ if (ott->ott_mode == OVERLAY_TARGET_POINT) {
+ bcopy(&ota->ota_point, &ott->ott_u.ott_point,
+ sizeof (overlay_target_point_t));
+ } else {
+ ott->ott_u.ott_dyn.ott_dhash = refhash_create(OVERLAY_HSIZE,
+ overlay_mac_hash, overlay_mac_cmp,
+ overlay_target_entry_dtor, sizeof (overlay_target_entry_t),
+ offsetof(overlay_target_entry_t, ote_reflink),
+ offsetof(overlay_target_entry_t, ote_addr), KM_SLEEP);
+ avl_create(&ott->ott_u.ott_dyn.ott_tree, overlay_mac_avl,
+ sizeof (overlay_target_entry_t),
+ offsetof(overlay_target_entry_t, ote_avllink));
+ }
+ mutex_enter(&odd->odd_lock);
+ if (odd->odd_flags & OVERLAY_F_VARPD) {
+ mutex_exit(&odd->odd_lock);
+ kmem_cache_free(overlay_target_cache, ott);
+ overlay_hold_rele(odd);
+ return (EEXIST);
+ }
+
+ odd->odd_flags |= OVERLAY_F_VARPD;
+ odd->odd_target = ott;
+ mutex_exit(&odd->odd_lock);
+
+ overlay_hold_rele(odd);
+
+
+ return (0);
+}
+
+
+/* ARGSUSED */
+static int
+overlay_target_degrade(overlay_target_hdl_t *thdl, void *arg)
+{
+ overlay_dev_t *odd;
+ overlay_targ_degrade_t *otd = arg;
+
+ odd = overlay_hold_by_dlid(otd->otd_linkid);
+ if (odd == NULL)
+ return (ENOENT);
+
+ overlay_fm_degrade(odd, otd->otd_buf);
+ overlay_hold_rele(odd);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+overlay_target_restore(overlay_target_hdl_t *thdl, void *arg)
+{
+ overlay_dev_t *odd;
+ overlay_targ_id_t *otid = arg;
+
+ odd = overlay_hold_by_dlid(otid->otid_linkid);
+ if (odd == NULL)
+ return (ENOENT);
+
+ overlay_fm_restore(odd);
+ overlay_hold_rele(odd);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+overlay_target_disassociate(overlay_target_hdl_t *thdl, void *arg)
+{
+ overlay_dev_t *odd;
+ overlay_targ_id_t *otid = arg;
+
+ odd = overlay_hold_by_dlid(otid->otid_linkid);
+ if (odd == NULL)
+ return (ENOENT);
+
+ mutex_enter(&odd->odd_lock);
+ odd->odd_flags &= ~OVERLAY_F_VARPD;
+ mutex_exit(&odd->odd_lock);
+
+ overlay_hold_rele(odd);
+ return (0);
+
+}
+
+static int
+overlay_target_lookup_request(overlay_target_hdl_t *thdl, void *arg)
+{
+ overlay_targ_lookup_t *otl = arg;
+ overlay_target_entry_t *entry;
+ clock_t ret, timeout;
+ mac_header_info_t mhi;
+
+ timeout = ddi_get_lbolt() + drv_usectohz(MICROSEC);
+again:
+ mutex_enter(&overlay_target_lock);
+ while (list_is_empty(&overlay_target_list)) {
+ ret = cv_timedwait(&overlay_target_condvar,
+ &overlay_target_lock, timeout);
+ if (ret == -1) {
+ mutex_exit(&overlay_target_lock);
+ return (ETIME);
+ }
+ }
+ entry = list_remove_head(&overlay_target_list);
+ mutex_exit(&overlay_target_lock);
+ mutex_enter(&entry->ote_lock);
+ if (entry->ote_flags & OVERLAY_ENTRY_F_VALID) {
+ ASSERT(entry->ote_chead == NULL);
+ mutex_exit(&entry->ote_lock);
+ goto again;
+ }
+ ASSERT(entry->ote_chead != NULL);
+
+ /*
+ * If we have a bogon that doesn't have a valid mac header, drop it and
+ * try again.
+ */
+ if (mac_vlan_header_info(entry->ote_odd->odd_mh, entry->ote_chead,
+ &mhi) != 0) {
+ boolean_t queue = B_FALSE;
+ mblk_t *mp = entry->ote_chead;
+ entry->ote_chead = mp->b_next;
+ mp->b_next = NULL;
+ if (entry->ote_ctail == mp)
+ entry->ote_ctail = entry->ote_chead;
+ entry->ote_mbsize -= msgsize(mp);
+ if (entry->ote_chead != NULL)
+ queue = B_TRUE;
+ mutex_exit(&entry->ote_lock);
+ if (queue == B_TRUE)
+ overlay_target_queue(entry);
+ freemsg(mp);
+ goto again;
+ }
+
+ otl->otl_dlid = entry->ote_odd->odd_linkid;
+ otl->otl_reqid = (uintptr_t)entry;
+ otl->otl_varpdid = entry->ote_ott->ott_id;
+ otl->otl_vnetid = entry->ote_odd->odd_vid;
+
+ otl->otl_hdrsize = mhi.mhi_hdrsize;
+ otl->otl_pktsize = msgsize(entry->ote_chead) - otl->otl_hdrsize;
+ bcopy(mhi.mhi_daddr, otl->otl_dstaddr, ETHERADDRL);
+ bcopy(mhi.mhi_saddr, otl->otl_srcaddr, ETHERADDRL);
+ otl->otl_dsttype = mhi.mhi_dsttype;
+ otl->otl_sap = mhi.mhi_bindsap;
+ otl->otl_vlan = VLAN_ID(mhi.mhi_tci);
+ mutex_exit(&entry->ote_lock);
+
+ mutex_enter(&thdl->oth_lock);
+ list_insert_tail(&thdl->oth_outstanding, entry);
+ mutex_exit(&thdl->oth_lock);
+
+ return (0);
+}
+
+static int
+overlay_target_lookup_respond(overlay_target_hdl_t *thdl, void *arg)
+{
+ const overlay_targ_resp_t *otr = arg;
+ overlay_target_entry_t *entry;
+ mblk_t *mp;
+
+ mutex_enter(&thdl->oth_lock);
+ for (entry = list_head(&thdl->oth_outstanding); entry != NULL;
+ entry = list_next(&thdl->oth_outstanding, entry)) {
+ if ((uintptr_t)entry == otr->otr_reqid)
+ break;
+ }
+
+ if (entry == NULL) {
+ mutex_exit(&thdl->oth_lock);
+ return (EINVAL);
+ }
+ list_remove(&thdl->oth_outstanding, entry);
+ mutex_exit(&thdl->oth_lock);
+
+ mutex_enter(&entry->ote_lock);
+ bcopy(&otr->otr_answer, &entry->ote_dest,
+ sizeof (overlay_target_point_t));
+ entry->ote_flags &= ~OVERLAY_ENTRY_F_PENDING;
+ entry->ote_flags |= OVERLAY_ENTRY_F_VALID;
+ mp = entry->ote_chead;
+ entry->ote_chead = NULL;
+ entry->ote_ctail = NULL;
+ entry->ote_mbsize = 0;
+ entry->ote_vtime = gethrtime();
+ mutex_exit(&entry->ote_lock);
+
+ /*
+ * For now do an in-situ drain.
+ */
+ mp = overlay_m_tx(entry->ote_odd, mp);
+ freemsgchain(mp);
+
+ mutex_enter(&entry->ote_ott->ott_lock);
+ entry->ote_ott->ott_ocount--;
+ cv_signal(&entry->ote_ott->ott_cond);
+ mutex_exit(&entry->ote_ott->ott_lock);
+
+ return (0);
+}
+
+static int
+overlay_target_lookup_drop(overlay_target_hdl_t *thdl, void *arg)
+{
+ const overlay_targ_resp_t *otr = arg;
+ overlay_target_entry_t *entry;
+ mblk_t *mp;
+ boolean_t queue = B_FALSE;
+
+ mutex_enter(&thdl->oth_lock);
+ for (entry = list_head(&thdl->oth_outstanding); entry != NULL;
+ entry = list_next(&thdl->oth_outstanding, entry)) {
+ if ((uintptr_t)entry == otr->otr_reqid)
+ break;
+ }
+
+ if (entry == NULL) {
+ mutex_exit(&thdl->oth_lock);
+ return (EINVAL);
+ }
+ list_remove(&thdl->oth_outstanding, entry);
+ mutex_exit(&thdl->oth_lock);
+
+ mutex_enter(&entry->ote_lock);
+
+ /* Safeguard against a confused varpd */
+ if (entry->ote_flags & OVERLAY_ENTRY_F_VALID) {
+ entry->ote_flags &= ~OVERLAY_ENTRY_F_PENDING;
+ DTRACE_PROBE1(overlay__target__valid__drop,
+ overlay_target_entry_t *, entry);
+ mutex_exit(&entry->ote_lock);
+ goto done;
+ }
+
+ mp = entry->ote_chead;
+ if (mp != NULL) {
+ entry->ote_chead = mp->b_next;
+ mp->b_next = NULL;
+ if (entry->ote_ctail == mp)
+ entry->ote_ctail = entry->ote_chead;
+ entry->ote_mbsize -= msgsize(mp);
+ }
+ if (entry->ote_chead != NULL) {
+ queue = B_TRUE;
+ entry->ote_flags |= OVERLAY_ENTRY_F_PENDING;
+ } else {
+ entry->ote_flags &= ~OVERLAY_ENTRY_F_PENDING;
+ }
+ mutex_exit(&entry->ote_lock);
+
+ if (queue == B_TRUE)
+ overlay_target_queue(entry);
+ freemsg(mp);
+
+done:
+ mutex_enter(&entry->ote_ott->ott_lock);
+ entry->ote_ott->ott_ocount--;
+ cv_signal(&entry->ote_ott->ott_cond);
+ mutex_exit(&entry->ote_ott->ott_lock);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+overlay_target_pkt_copyin(const void *ubuf, void **outp, size_t *bsize,
+ int flags)
+{
+ overlay_targ_pkt_t *pkt;
+ overlay_targ_pkt32_t *pkt32;
+
+ pkt = kmem_alloc(sizeof (overlay_targ_pkt_t), KM_SLEEP);
+ *outp = pkt;
+ *bsize = sizeof (overlay_targ_pkt_t);
+ if (ddi_model_convert_from(flags & FMODELS) == DDI_MODEL_ILP32) {
+ uintptr_t addr;
+
+ if (ddi_copyin(ubuf, pkt, sizeof (overlay_targ_pkt32_t),
+ flags & FKIOCTL) != 0) {
+ kmem_free(pkt, *bsize);
+ return (EFAULT);
+ }
+ pkt32 = (overlay_targ_pkt32_t *)pkt;
+ addr = pkt32->otp_buf;
+ pkt->otp_buf = (void *)addr;
+ } else {
+ if (ddi_copyin(ubuf, pkt, *bsize, flags & FKIOCTL) != 0) {
+ kmem_free(pkt, *bsize);
+ return (EFAULT);
+ }
+ }
+ return (0);
+}
+
+static int
+overlay_target_pkt_copyout(void *ubuf, void *buf, size_t bufsize,
+ int flags)
+{
+ if (ddi_model_convert_from(flags & FMODELS) == DDI_MODEL_ILP32) {
+ overlay_targ_pkt_t *pkt = buf;
+ overlay_targ_pkt32_t *pkt32 = buf;
+ uintptr_t addr = (uintptr_t)pkt->otp_buf;
+ pkt32->otp_buf = (caddr32_t)addr;
+ if (ddi_copyout(buf, ubuf, sizeof (overlay_targ_pkt32_t),
+ flags & FKIOCTL) != 0)
+ return (EFAULT);
+ } else {
+ if (ddi_copyout(buf, ubuf, bufsize, flags & FKIOCTL) != 0)
+ return (EFAULT);
+ }
+ return (0);
+}
+
+static int
+overlay_target_packet(overlay_target_hdl_t *thdl, void *arg)
+{
+ overlay_targ_pkt_t *pkt = arg;
+ overlay_target_entry_t *entry;
+ mblk_t *mp;
+ size_t mlen;
+ size_t boff;
+
+ mutex_enter(&thdl->oth_lock);
+ for (entry = list_head(&thdl->oth_outstanding); entry != NULL;
+ entry = list_next(&thdl->oth_outstanding, entry)) {
+ if ((uintptr_t)entry == pkt->otp_reqid)
+ break;
+ }
+
+ if (entry == NULL) {
+ mutex_exit(&thdl->oth_lock);
+ return (EINVAL);
+ }
+ mutex_enter(&entry->ote_lock);
+ mutex_exit(&thdl->oth_lock);
+ mp = entry->ote_chead;
+ /* Protect against a rogue varpd */
+ if (mp == NULL) {
+ mutex_exit(&entry->ote_lock);
+ return (EINVAL);
+ }
+ mlen = MIN(msgsize(mp), pkt->otp_size);
+ pkt->otp_size = mlen;
+ boff = 0;
+ while (mlen > 0) {
+ size_t wlen = MIN(MBLKL(mp), mlen);
+ if (ddi_copyout(mp->b_rptr,
+ (void *)((uintptr_t)pkt->otp_buf + boff),
+ wlen, 0) != 0) {
+ mutex_exit(&entry->ote_lock);
+ return (EFAULT);
+ }
+ mlen -= wlen;
+ boff += wlen;
+ mp = mp->b_cont;
+ }
+ mutex_exit(&entry->ote_lock);
+ return (0);
+}
+
+static int
+overlay_target_inject(overlay_target_hdl_t *thdl, void *arg)
+{
+ overlay_targ_pkt_t *pkt = arg;
+ overlay_target_entry_t *entry;
+ overlay_dev_t *odd;
+ mblk_t *mp;
+
+ if (pkt->otp_size > ETHERMAX + VLAN_TAGSZ)
+ return (EINVAL);
+
+ mp = allocb(pkt->otp_size, 0);
+ if (mp == NULL)
+ return (ENOMEM);
+
+ if (ddi_copyin(pkt->otp_buf, mp->b_rptr, pkt->otp_size, 0) != 0) {
+ freeb(mp);
+ return (EFAULT);
+ }
+ mp->b_wptr += pkt->otp_size;
+
+ if (pkt->otp_linkid != UINT64_MAX) {
+ odd = overlay_hold_by_dlid(pkt->otp_linkid);
+ if (odd == NULL) {
+ freeb(mp);
+ return (ENOENT);
+ }
+ } else {
+ mutex_enter(&thdl->oth_lock);
+ for (entry = list_head(&thdl->oth_outstanding); entry != NULL;
+ entry = list_next(&thdl->oth_outstanding, entry)) {
+ if ((uintptr_t)entry == pkt->otp_reqid)
+ break;
+ }
+
+ if (entry == NULL) {
+ mutex_exit(&thdl->oth_lock);
+ freeb(mp);
+ return (ENOENT);
+ }
+ odd = entry->ote_odd;
+ mutex_exit(&thdl->oth_lock);
+ }
+
+ mutex_enter(&odd->odd_lock);
+ overlay_io_start(odd, OVERLAY_F_IN_RX);
+ mutex_exit(&odd->odd_lock);
+
+ mac_rx(odd->odd_mh, NULL, mp);
+
+ mutex_enter(&odd->odd_lock);
+ overlay_io_done(odd, OVERLAY_F_IN_RX);
+ mutex_exit(&odd->odd_lock);
+
+ return (0);
+}
+
+static int
+overlay_target_resend(overlay_target_hdl_t *thdl, void *arg)
+{
+ overlay_targ_pkt_t *pkt = arg;
+ overlay_target_entry_t *entry;
+ overlay_dev_t *odd;
+ mblk_t *mp;
+
+ if (pkt->otp_size > ETHERMAX + VLAN_TAGSZ)
+ return (EINVAL);
+
+ mp = allocb(pkt->otp_size, 0);
+ if (mp == NULL)
+ return (ENOMEM);
+
+ if (ddi_copyin(pkt->otp_buf, mp->b_rptr, pkt->otp_size, 0) != 0) {
+ freeb(mp);
+ return (EFAULT);
+ }
+ mp->b_wptr += pkt->otp_size;
+
+ if (pkt->otp_linkid != UINT64_MAX) {
+ odd = overlay_hold_by_dlid(pkt->otp_linkid);
+ if (odd == NULL) {
+ freeb(mp);
+ return (ENOENT);
+ }
+ } else {
+ mutex_enter(&thdl->oth_lock);
+ for (entry = list_head(&thdl->oth_outstanding); entry != NULL;
+ entry = list_next(&thdl->oth_outstanding, entry)) {
+ if ((uintptr_t)entry == pkt->otp_reqid)
+ break;
+ }
+
+ if (entry == NULL) {
+ mutex_exit(&thdl->oth_lock);
+ freeb(mp);
+ return (ENOENT);
+ }
+ odd = entry->ote_odd;
+ mutex_exit(&thdl->oth_lock);
+ }
+
+ mp = overlay_m_tx(odd, mp);
+ freemsgchain(mp);
+
+ return (0);
+}
+
+typedef struct overlay_targ_list_int {
+ boolean_t otli_count;
+ uint32_t otli_cur;
+ uint32_t otli_nents;
+ uint32_t otli_ents[];
+} overlay_targ_list_int_t;
+
+static int
+overlay_target_list_copyin(const void *ubuf, void **outp, size_t *bsize,
+ int flags)
+{
+ overlay_targ_list_t n;
+ overlay_targ_list_int_t *otl;
+
+ if (ddi_copyin(ubuf, &n, sizeof (overlay_targ_list_t),
+ flags & FKIOCTL) != 0)
+ return (EFAULT);
+
+ /*
+ */
+ if (n.otl_nents >= INT32_MAX / sizeof (uint32_t))
+ return (EINVAL);
+ *bsize = sizeof (overlay_targ_list_int_t) +
+ sizeof (uint32_t) * n.otl_nents;
+ otl = kmem_zalloc(*bsize, KM_SLEEP);
+ otl->otli_cur = 0;
+ otl->otli_nents = n.otl_nents;
+ if (otl->otli_nents != 0) {
+ otl->otli_count = B_FALSE;
+ if (ddi_copyin((void *)((uintptr_t)ubuf +
+ offsetof(overlay_targ_list_t, otl_ents)),
+ otl->otli_ents, n.otl_nents * sizeof (uint32_t),
+ flags & FKIOCTL) != 0) {
+ kmem_free(otl, *bsize);
+ return (EFAULT);
+ }
+ } else {
+ otl->otli_count = B_TRUE;
+ }
+
+ *outp = otl;
+ return (0);
+}
+
+static int
+overlay_target_ioctl_list_cb(overlay_dev_t *odd, void *arg)
+{
+ overlay_targ_list_int_t *otl = arg;
+
+ if (otl->otli_cur < otl->otli_nents)
+ otl->otli_ents[otl->otli_cur] = odd->odd_linkid;
+ otl->otli_cur++;
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+overlay_target_ioctl_list(overlay_target_hdl_t *thdl, void *arg)
+{
+ overlay_dev_iter(overlay_target_ioctl_list_cb, arg);
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+overlay_target_list_copyout(void *ubuf, void *buf, size_t bufsize, int flags)
+{
+ overlay_targ_list_int_t *otl = buf;
+
+ if (ddi_copyout(&otl->otli_cur, ubuf, sizeof (uint32_t),
+ flags & FKIOCTL) != 0)
+ return (EFAULT);
+
+ if (otl->otli_count == B_FALSE) {
+ if (ddi_copyout(otl->otli_ents,
+ (void *)((uintptr_t)ubuf +
+ offsetof(overlay_targ_list_t, otl_ents)),
+ sizeof (uint32_t) * otl->otli_nents,
+ flags & FKIOCTL) != 0)
+ return (EFAULT);
+ }
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+overlay_target_cache_get(overlay_target_hdl_t *thdl, void *arg)
+{
+ int ret = 0;
+ overlay_dev_t *odd;
+ overlay_target_t *ott;
+ overlay_targ_cache_t *otc = arg;
+
+ odd = overlay_hold_by_dlid(otc->otc_linkid);
+ if (odd == NULL)
+ return (ENOENT);
+
+ mutex_enter(&odd->odd_lock);
+ if (!(odd->odd_flags & OVERLAY_F_VARPD)) {
+ mutex_exit(&odd->odd_lock);
+ overlay_hold_rele(odd);
+ return (ENXIO);
+ }
+ ott = odd->odd_target;
+ if (ott->ott_mode != OVERLAY_TARGET_POINT &&
+ ott->ott_mode != OVERLAY_TARGET_DYNAMIC) {
+ mutex_exit(&odd->odd_lock);
+ overlay_hold_rele(odd);
+ return (ENOTSUP);
+ }
+ mutex_enter(&ott->ott_lock);
+ mutex_exit(&odd->odd_lock);
+
+ if (ott->ott_mode == OVERLAY_TARGET_POINT) {
+ otc->otc_entry.otce_flags = 0;
+ bcopy(&ott->ott_u.ott_point, &otc->otc_entry.otce_dest,
+ sizeof (overlay_target_point_t));
+ } else {
+ overlay_target_entry_t *ote;
+ ote = refhash_lookup(ott->ott_u.ott_dyn.ott_dhash,
+ otc->otc_entry.otce_mac);
+ if (ote != NULL) {
+ mutex_enter(&ote->ote_lock);
+ if ((ote->ote_flags &
+ OVERLAY_ENTRY_F_VALID_MASK) != 0) {
+ if (ote->ote_flags & OVERLAY_ENTRY_F_DROP) {
+ otc->otc_entry.otce_flags =
+ OVERLAY_TARGET_CACHE_DROP;
+ } else {
+ otc->otc_entry.otce_flags = 0;
+ bcopy(&ote->ote_dest,
+ &otc->otc_entry.otce_dest,
+ sizeof (overlay_target_point_t));
+ }
+ ret = 0;
+ } else {
+ ret = ENOENT;
+ }
+ mutex_exit(&ote->ote_lock);
+ } else {
+ ret = ENOENT;
+ }
+ }
+
+ mutex_exit(&ott->ott_lock);
+ overlay_hold_rele(odd);
+
+ return (ret);
+}
+
+/* ARGSUSED */
+static int
+overlay_target_cache_set(overlay_target_hdl_t *thdl, void *arg)
+{
+ overlay_dev_t *odd;
+ overlay_target_t *ott;
+ overlay_target_entry_t *ote;
+ overlay_targ_cache_t *otc = arg;
+ mblk_t *mp = NULL;
+
+ if (otc->otc_entry.otce_flags & ~OVERLAY_TARGET_CACHE_DROP)
+ return (EINVAL);
+
+ odd = overlay_hold_by_dlid(otc->otc_linkid);
+ if (odd == NULL)
+ return (ENOENT);
+
+ mutex_enter(&odd->odd_lock);
+ if (!(odd->odd_flags & OVERLAY_F_VARPD)) {
+ mutex_exit(&odd->odd_lock);
+ overlay_hold_rele(odd);
+ return (ENXIO);
+ }
+ ott = odd->odd_target;
+ if (ott->ott_mode != OVERLAY_TARGET_DYNAMIC) {
+ mutex_exit(&odd->odd_lock);
+ overlay_hold_rele(odd);
+ return (ENOTSUP);
+ }
+ mutex_enter(&ott->ott_lock);
+ mutex_exit(&odd->odd_lock);
+
+ ote = refhash_lookup(ott->ott_u.ott_dyn.ott_dhash,
+ otc->otc_entry.otce_mac);
+ if (ote == NULL) {
+ ote = kmem_cache_alloc(overlay_entry_cache, KM_SLEEP);
+ bcopy(otc->otc_entry.otce_mac, ote->ote_addr, ETHERADDRL);
+ ote->ote_chead = ote->ote_ctail = NULL;
+ ote->ote_mbsize = 0;
+ ote->ote_ott = ott;
+ ote->ote_odd = odd;
+ mutex_enter(&ote->ote_lock);
+ refhash_insert(ott->ott_u.ott_dyn.ott_dhash, ote);
+ avl_add(&ott->ott_u.ott_dyn.ott_tree, ote);
+ } else {
+ mutex_enter(&ote->ote_lock);
+ }
+
+ if (otc->otc_entry.otce_flags & OVERLAY_TARGET_CACHE_DROP) {
+ ote->ote_flags |= OVERLAY_ENTRY_F_DROP;
+ } else {
+ ote->ote_flags |= OVERLAY_ENTRY_F_VALID;
+ bcopy(&otc->otc_entry.otce_dest, &ote->ote_dest,
+ sizeof (overlay_target_point_t));
+ mp = ote->ote_chead;
+ ote->ote_chead = NULL;
+ ote->ote_ctail = NULL;
+ ote->ote_mbsize = 0;
+ ote->ote_vtime = gethrtime();
+ }
+
+ mutex_exit(&ote->ote_lock);
+ mutex_exit(&ott->ott_lock);
+
+ if (mp != NULL) {
+ mp = overlay_m_tx(ote->ote_odd, mp);
+ freemsgchain(mp);
+ }
+
+ overlay_hold_rele(odd);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+overlay_target_cache_remove(overlay_target_hdl_t *thdl, void *arg)
+{
+ int ret = 0;
+ overlay_dev_t *odd;
+ overlay_target_t *ott;
+ overlay_target_entry_t *ote;
+ overlay_targ_cache_t *otc = arg;
+
+ odd = overlay_hold_by_dlid(otc->otc_linkid);
+ if (odd == NULL)
+ return (ENOENT);
+
+ mutex_enter(&odd->odd_lock);
+ if (!(odd->odd_flags & OVERLAY_F_VARPD)) {
+ mutex_exit(&odd->odd_lock);
+ overlay_hold_rele(odd);
+ return (ENXIO);
+ }
+ ott = odd->odd_target;
+ if (ott->ott_mode != OVERLAY_TARGET_DYNAMIC) {
+ mutex_exit(&odd->odd_lock);
+ overlay_hold_rele(odd);
+ return (ENOTSUP);
+ }
+ mutex_enter(&ott->ott_lock);
+ mutex_exit(&odd->odd_lock);
+
+ ote = refhash_lookup(ott->ott_u.ott_dyn.ott_dhash,
+ otc->otc_entry.otce_mac);
+ if (ote != NULL) {
+ mutex_enter(&ote->ote_lock);
+ ote->ote_flags &= ~OVERLAY_ENTRY_F_VALID_MASK;
+ mutex_exit(&ote->ote_lock);
+ ret = 0;
+ } else {
+ ret = ENOENT;
+ }
+
+ mutex_exit(&ott->ott_lock);
+ overlay_hold_rele(odd);
+
+ return (ret);
+}
+
+/* ARGSUSED */
+static int
+overlay_target_cache_flush(overlay_target_hdl_t *thdl, void *arg)
+{
+ avl_tree_t *avl;
+ overlay_dev_t *odd;
+ overlay_target_t *ott;
+ overlay_target_entry_t *ote;
+ overlay_targ_cache_t *otc = arg;
+
+ odd = overlay_hold_by_dlid(otc->otc_linkid);
+ if (odd == NULL)
+ return (ENOENT);
+
+ mutex_enter(&odd->odd_lock);
+ if (!(odd->odd_flags & OVERLAY_F_VARPD)) {
+ mutex_exit(&odd->odd_lock);
+ overlay_hold_rele(odd);
+ return (ENXIO);
+ }
+ ott = odd->odd_target;
+ if (ott->ott_mode != OVERLAY_TARGET_DYNAMIC) {
+ mutex_exit(&odd->odd_lock);
+ overlay_hold_rele(odd);
+ return (ENOTSUP);
+ }
+ mutex_enter(&ott->ott_lock);
+ mutex_exit(&odd->odd_lock);
+ avl = &ott->ott_u.ott_dyn.ott_tree;
+
+ for (ote = avl_first(avl); ote != NULL; ote = AVL_NEXT(avl, ote)) {
+ mutex_enter(&ote->ote_lock);
+ ote->ote_flags &= ~OVERLAY_ENTRY_F_VALID_MASK;
+ mutex_exit(&ote->ote_lock);
+ }
+ ote = refhash_lookup(ott->ott_u.ott_dyn.ott_dhash,
+ otc->otc_entry.otce_mac);
+
+ mutex_exit(&ott->ott_lock);
+ overlay_hold_rele(odd);
+
+ return (0);
+}
+
+static int
+overlay_target_cache_iter_copyin(const void *ubuf, void **outp, size_t *bsize,
+ int flags)
+{
+ overlay_targ_cache_iter_t base, *iter;
+
+ if (ddi_copyin(ubuf, &base, sizeof (overlay_targ_cache_iter_t),
+ flags & FKIOCTL) != 0)
+ return (EFAULT);
+
+ if (base.otci_count > OVERLAY_TARGET_ITER_MAX)
+ return (E2BIG);
+
+ if (base.otci_count == 0)
+ return (EINVAL);
+
+ *bsize = sizeof (overlay_targ_cache_iter_t) +
+ base.otci_count * sizeof (overlay_targ_cache_entry_t);
+ iter = kmem_alloc(*bsize, KM_SLEEP);
+ bcopy(&base, iter, sizeof (overlay_targ_cache_iter_t));
+ *outp = iter;
+
+ return (0);
+}
+
+typedef struct overlay_targ_cache_marker {
+ uint8_t otcm_mac[ETHERADDRL];
+ uint16_t otcm_done;
+} overlay_targ_cache_marker_t;
+
+/* ARGSUSED */
+static int
+overlay_target_cache_iter(overlay_target_hdl_t *thdl, void *arg)
+{
+ overlay_dev_t *odd;
+ overlay_target_t *ott;
+ overlay_target_entry_t lookup, *ent;
+ overlay_targ_cache_marker_t *mark;
+ avl_index_t where;
+ avl_tree_t *avl;
+ uint16_t written = 0;
+
+ overlay_targ_cache_iter_t *iter = arg;
+ mark = (void *)&iter->otci_marker;
+
+ if (mark->otcm_done != 0) {
+ iter->otci_count = 0;
+ return (0);
+ }
+
+ odd = overlay_hold_by_dlid(iter->otci_linkid);
+ if (odd == NULL)
+ return (ENOENT);
+
+ mutex_enter(&odd->odd_lock);
+ if (!(odd->odd_flags & OVERLAY_F_VARPD)) {
+ mutex_exit(&odd->odd_lock);
+ overlay_hold_rele(odd);
+ return (ENXIO);
+ }
+ ott = odd->odd_target;
+ if (ott->ott_mode != OVERLAY_TARGET_DYNAMIC &&
+ ott->ott_mode != OVERLAY_TARGET_POINT) {
+ mutex_exit(&odd->odd_lock);
+ overlay_hold_rele(odd);
+ return (ENOTSUP);
+ }
+
+ /*
+ * Holding this lock across the entire iteration probably isn't very
+ * good. We should perhaps add an r/w lock for the avl tree. But we'll
+ * wait until we now it's necessary before we do more.
+ */
+ mutex_enter(&ott->ott_lock);
+ mutex_exit(&odd->odd_lock);
+
+ if (ott->ott_mode == OVERLAY_TARGET_POINT) {
+ overlay_targ_cache_entry_t *out = &iter->otci_ents[0];
+ bzero(out->otce_mac, ETHERADDRL);
+ out->otce_flags = 0;
+ bcopy(&ott->ott_u.ott_point, &out->otce_dest,
+ sizeof (overlay_target_point_t));
+ written++;
+ mark->otcm_done = 1;
+ }
+
+ avl = &ott->ott_u.ott_dyn.ott_tree;
+ bcopy(mark->otcm_mac, lookup.ote_addr, ETHERADDRL);
+ ent = avl_find(avl, &lookup, &where);
+
+ /*
+ * NULL ent means that the entry does not exist, so we want to start
+ * with the closest node in the tree. This means that we implicitly rely
+ * on the tree's order and the first node will be the mac 00:00:00:00:00
+ * and the last will be ff:ff:ff:ff:ff:ff.
+ */
+ if (ent == NULL) {
+ ent = avl_nearest(avl, where, AVL_AFTER);
+ if (ent == NULL) {
+ mark->otcm_done = 1;
+ goto done;
+ }
+ }
+
+ for (; ent != NULL && written < iter->otci_count;
+ ent = AVL_NEXT(avl, ent)) {
+ overlay_targ_cache_entry_t *out = &iter->otci_ents[written];
+ mutex_enter(&ent->ote_lock);
+ if ((ent->ote_flags & OVERLAY_ENTRY_F_VALID_MASK) == 0) {
+ mutex_exit(&ent->ote_lock);
+ continue;
+ }
+ bcopy(ent->ote_addr, out->otce_mac, ETHERADDRL);
+ out->otce_flags = 0;
+ if (ent->ote_flags & OVERLAY_ENTRY_F_DROP)
+ out->otce_flags |= OVERLAY_TARGET_CACHE_DROP;
+ if (ent->ote_flags & OVERLAY_ENTRY_F_VALID)
+ bcopy(&ent->ote_dest, &out->otce_dest,
+ sizeof (overlay_target_point_t));
+ written++;
+ mutex_exit(&ent->ote_lock);
+ }
+
+ if (ent != NULL) {
+ bcopy(ent->ote_addr, mark->otcm_mac, ETHERADDRL);
+ } else {
+ mark->otcm_done = 1;
+ }
+
+done:
+ iter->otci_count = written;
+ mutex_exit(&ott->ott_lock);
+ overlay_hold_rele(odd);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+overlay_target_cache_iter_copyout(void *ubuf, void *buf, size_t bufsize,
+ int flags)
+{
+ size_t outsize;
+ const overlay_targ_cache_iter_t *iter = buf;
+
+ outsize = sizeof (overlay_targ_cache_iter_t) +
+ iter->otci_count * sizeof (overlay_targ_cache_entry_t);
+
+ if (ddi_copyout(buf, ubuf, outsize, flags & FKIOCTL) != 0)
+ return (EFAULT);
+
+ return (0);
+}
+
+static overlay_target_ioctl_t overlay_target_ioctab[] = {
+ { OVERLAY_TARG_INFO, B_TRUE, B_TRUE,
+ NULL, overlay_target_info,
+ NULL, sizeof (overlay_targ_info_t) },
+ { OVERLAY_TARG_ASSOCIATE, B_TRUE, B_FALSE,
+ NULL, overlay_target_associate,
+ NULL, sizeof (overlay_targ_associate_t) },
+ { OVERLAY_TARG_DISASSOCIATE, B_TRUE, B_FALSE,
+ NULL, overlay_target_disassociate,
+ NULL, sizeof (overlay_targ_id_t) },
+ { OVERLAY_TARG_DEGRADE, B_TRUE, B_FALSE,
+ NULL, overlay_target_degrade,
+ NULL, sizeof (overlay_targ_degrade_t) },
+ { OVERLAY_TARG_RESTORE, B_TRUE, B_FALSE,
+ NULL, overlay_target_restore,
+ NULL, sizeof (overlay_targ_id_t) },
+ { OVERLAY_TARG_LOOKUP, B_FALSE, B_TRUE,
+ NULL, overlay_target_lookup_request,
+ NULL, sizeof (overlay_targ_lookup_t) },
+ { OVERLAY_TARG_RESPOND, B_TRUE, B_FALSE,
+ NULL, overlay_target_lookup_respond,
+ NULL, sizeof (overlay_targ_resp_t) },
+ { OVERLAY_TARG_DROP, B_TRUE, B_FALSE,
+ NULL, overlay_target_lookup_drop,
+ NULL, sizeof (overlay_targ_resp_t) },
+ { OVERLAY_TARG_PKT, B_TRUE, B_TRUE,
+ overlay_target_pkt_copyin,
+ overlay_target_packet,
+ overlay_target_pkt_copyout,
+ sizeof (overlay_targ_pkt_t) },
+ { OVERLAY_TARG_INJECT, B_TRUE, B_FALSE,
+ overlay_target_pkt_copyin,
+ overlay_target_inject,
+ NULL, sizeof (overlay_targ_pkt_t) },
+ { OVERLAY_TARG_RESEND, B_TRUE, B_FALSE,
+ overlay_target_pkt_copyin,
+ overlay_target_resend,
+ NULL, sizeof (overlay_targ_pkt_t) },
+ { OVERLAY_TARG_LIST, B_FALSE, B_TRUE,
+ overlay_target_list_copyin,
+ overlay_target_ioctl_list,
+ overlay_target_list_copyout,
+ sizeof (overlay_targ_list_t) },
+ { OVERLAY_TARG_CACHE_GET, B_FALSE, B_TRUE,
+ NULL, overlay_target_cache_get,
+ NULL, sizeof (overlay_targ_cache_t) },
+ { OVERLAY_TARG_CACHE_SET, B_TRUE, B_TRUE,
+ NULL, overlay_target_cache_set,
+ NULL, sizeof (overlay_targ_cache_t) },
+ { OVERLAY_TARG_CACHE_REMOVE, B_TRUE, B_TRUE,
+ NULL, overlay_target_cache_remove,
+ NULL, sizeof (overlay_targ_cache_t) },
+ { OVERLAY_TARG_CACHE_FLUSH, B_TRUE, B_TRUE,
+ NULL, overlay_target_cache_flush,
+ NULL, sizeof (overlay_targ_cache_t) },
+ { OVERLAY_TARG_CACHE_ITER, B_FALSE, B_TRUE,
+ overlay_target_cache_iter_copyin,
+ overlay_target_cache_iter,
+ overlay_target_cache_iter_copyout,
+ sizeof (overlay_targ_cache_iter_t) },
+ { 0 }
+};
+
+int
+overlay_target_open(dev_t *devp, int flags, int otype, cred_t *credp)
+{
+ minor_t mid;
+ overlay_target_hdl_t *thdl;
+
+ if (secpolicy_dl_config(credp) != 0)
+ return (EPERM);
+
+ if (getminor(*devp) != 0)
+ return (ENXIO);
+
+ if (otype & OTYP_BLK)
+ return (EINVAL);
+
+ if (flags & ~(FREAD | FWRITE | FEXCL))
+ return (EINVAL);
+
+ if ((flags & FWRITE) &&
+ !(flags & FEXCL))
+ return (EINVAL);
+
+ if (!(flags & FREAD) && !(flags & FWRITE))
+ return (EINVAL);
+
+ if (crgetzoneid(credp) != GLOBAL_ZONEID)
+ return (EPERM);
+
+ mid = id_alloc(overlay_thdl_idspace);
+ if (ddi_soft_state_zalloc(overlay_thdl_state, mid) != 0) {
+ id_free(overlay_thdl_idspace, mid);
+ return (ENXIO);
+ }
+
+ thdl = ddi_get_soft_state(overlay_thdl_state, mid);
+ VERIFY(thdl != NULL);
+ thdl->oth_minor = mid;
+ thdl->oth_zoneid = crgetzoneid(credp);
+ thdl->oth_oflags = flags;
+ mutex_init(&thdl->oth_lock, NULL, MUTEX_DRIVER, NULL);
+ list_create(&thdl->oth_outstanding, sizeof (overlay_target_entry_t),
+ offsetof(overlay_target_entry_t, ote_qlink));
+ *devp = makedevice(getmajor(*devp), mid);
+
+ mutex_enter(&overlay_target_lock);
+ if ((flags & FEXCL) && overlay_target_excl == B_TRUE) {
+ mutex_exit(&overlay_target_lock);
+ list_destroy(&thdl->oth_outstanding);
+ mutex_destroy(&thdl->oth_lock);
+ ddi_soft_state_free(overlay_thdl_state, mid);
+ id_free(overlay_thdl_idspace, mid);
+ return (EEXIST);
+ } else if ((flags & FEXCL) != 0) {
+ VERIFY(overlay_target_excl == B_FALSE);
+ overlay_target_excl = B_TRUE;
+ }
+ list_insert_tail(&overlay_thdl_list, thdl);
+ mutex_exit(&overlay_target_lock);
+
+ return (0);
+}
+
+/* ARGSUSED */
+int
+overlay_target_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
+ int *rvalp)
+{
+ overlay_target_ioctl_t *ioc;
+ overlay_target_hdl_t *thdl;
+
+ if (secpolicy_dl_config(credp) != 0)
+ return (EPERM);
+
+ if ((thdl = ddi_get_soft_state(overlay_thdl_state,
+ getminor(dev))) == NULL)
+ return (ENXIO);
+
+ for (ioc = &overlay_target_ioctab[0]; ioc->oti_cmd != 0; ioc++) {
+ int ret;
+ caddr_t buf;
+ size_t bufsize;
+
+ if (ioc->oti_cmd != cmd)
+ continue;
+
+ if (ioc->oti_write == B_TRUE && !(mode & FWRITE))
+ return (EBADF);
+
+ if (ioc->oti_copyin == NULL) {
+ bufsize = ioc->oti_size;
+ buf = kmem_alloc(bufsize, KM_SLEEP);
+ if (ddi_copyin((void *)(uintptr_t)arg, buf, bufsize,
+ mode & FKIOCTL) != 0) {
+ kmem_free(buf, bufsize);
+ return (EFAULT);
+ }
+ } else {
+ if ((ret = ioc->oti_copyin((void *)(uintptr_t)arg,
+ (void **)&buf, &bufsize, mode)) != 0)
+ return (ret);
+ }
+
+ ret = ioc->oti_func(thdl, buf);
+ if (ret == 0 && ioc->oti_size != 0 &&
+ ioc->oti_ncopyout == B_TRUE) {
+ if (ioc->oti_copyout == NULL) {
+ if (ddi_copyout(buf, (void *)(uintptr_t)arg,
+ bufsize, mode & FKIOCTL) != 0)
+ ret = EFAULT;
+ } else {
+ ret = ioc->oti_copyout((void *)(uintptr_t)arg,
+ buf, bufsize, mode);
+ }
+ }
+
+ kmem_free(buf, bufsize);
+ return (ret);
+ }
+
+ return (ENOTTY);
+}
+
+/* ARGSUSED */
+int
+overlay_target_close(dev_t dev, int flags, int otype, cred_t *credp)
+{
+ overlay_target_hdl_t *thdl;
+ overlay_target_entry_t *entry;
+ minor_t mid = getminor(dev);
+
+ if ((thdl = ddi_get_soft_state(overlay_thdl_state, mid)) == NULL)
+ return (ENXIO);
+
+ mutex_enter(&overlay_target_lock);
+ list_remove(&overlay_thdl_list, thdl);
+ mutex_enter(&thdl->oth_lock);
+ while ((entry = list_remove_head(&thdl->oth_outstanding)) != NULL)
+ list_insert_tail(&overlay_target_list, entry);
+ cv_signal(&overlay_target_condvar);
+ mutex_exit(&thdl->oth_lock);
+ if ((thdl->oth_oflags & FEXCL) != 0) {
+ VERIFY(overlay_target_excl == B_TRUE);
+ overlay_target_excl = B_FALSE;
+ }
+ mutex_exit(&overlay_target_lock);
+
+ list_destroy(&thdl->oth_outstanding);
+ mutex_destroy(&thdl->oth_lock);
+ mid = thdl->oth_minor;
+ ddi_soft_state_free(overlay_thdl_state, mid);
+ id_free(overlay_thdl_idspace, mid);
+
+ return (0);
+}
diff --git a/usr/src/uts/common/io/overlay/plugins/overlay_vxlan.c b/usr/src/uts/common/io/overlay/plugins/overlay_vxlan.c
new file mode 100644
index 0000000000..92144b3985
--- /dev/null
+++ b/usr/src/uts/common/io/overlay/plugins/overlay_vxlan.c
@@ -0,0 +1,394 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018 Joyent, Inc.
+ */
+
+/*
+ * VXLAN encapsulation module
+ *
+ *
+ * The VXLAN header looks as follows in network byte order:
+ *
+ * |0 3| 4 |5 31|
+ * +----------+---+------------------------+
+ * | Reserved | I | Reserved |
+ * +---------------------------------------+
+ * | Virtual Network ID | Reserved |
+ * +----------------------------+----------+
+ * |0 23|24 31|
+ *
+ * All reserved values must be 0. The I bit must be 1. We call the top
+ * word the VXLAN magic field for the time being. The second word is
+ * definitely not the most friendly way to operate. Specifically, the ID
+ * is a 24-bit big endian value, but we have to make sure not to use the
+ * reserved byte.
+ *
+ * For us, VXLAN encapsulation is a fairly straightforward implementation. It
+ * only has two properties, a listen_ip and a listen_port. These determine on
+ * what address we should be listening on. While we do not have a default
+ * address to listen upon, we do have a default port, which is the IANA assigned
+ * port for VXLAN -- 4789.
+ */
+
+#include <sys/overlay_plugin.h>
+#include <sys/modctl.h>
+#include <sys/errno.h>
+#include <sys/byteorder.h>
+#include <sys/vxlan.h>
+#include <inet/ip.h>
+#include <netinet/in.h>
+#include <sys/strsun.h>
+#include <netinet/udp.h>
+
+static const char *vxlan_ident = "vxlan";
+static uint16_t vxlan_defport = IPPORT_VXLAN;
+
+/*
+ * Should we enable UDP source port hashing for fanout.
+ */
+boolean_t vxlan_fanout = B_TRUE;
+
+/*
+ * This represents the size in bytes that we want to allocate when allocating a
+ * vxlan header block. This is intended such that lower levels can try and use
+ * the message block that we allocate for the IP and UPD header. The hope is
+ * that even if this is tunneled, that this is enough space.
+ *
+ * The vxlan_noalloc_min value represents the minimum amount of space we need to
+ * consider not allocating a message block and just passing it down the stack in
+ * this form. This number assumes that we have a VLAN tag, so 18 byte Ethernet
+ * header, 20 byte IP header, 8 byte UDP header, and 8 byte VXLAN header.
+ */
+uint_t vxlan_alloc_size = 128;
+uint_t vxlan_noalloc_min = 54;
+
+static const char *vxlan_props[] = {
+ "vxlan/listen_ip",
+ "vxlan/listen_port",
+ NULL
+};
+
+typedef struct vxlan {
+ kmutex_t vxl_lock;
+ overlay_handle_t vxl_oh;
+ uint16_t vxl_lport;
+ boolean_t vxl_hladdr;
+ struct in6_addr vxl_laddr;
+} vxlan_t;
+
+static int
+vxlan_o_init(overlay_handle_t oh, void **outp)
+{
+ vxlan_t *vxl;
+
+ vxl = kmem_alloc(sizeof (vxlan_t), KM_SLEEP);
+ *outp = vxl;
+ mutex_init(&vxl->vxl_lock, NULL, MUTEX_DRIVER, NULL);
+ vxl->vxl_oh = oh;
+ vxl->vxl_lport = vxlan_defport;
+ vxl->vxl_hladdr = B_FALSE;
+
+ return (0);
+}
+
+static void
+vxlan_o_fini(void *arg)
+{
+ vxlan_t *vxl = arg;
+
+ mutex_destroy(&vxl->vxl_lock);
+ kmem_free(arg, sizeof (vxlan_t));
+}
+
+static int
+vxlan_o_socket(void *arg, int *dp, int *fp, int *pp, struct sockaddr *addr,
+ socklen_t *slenp)
+{
+ vxlan_t *vxl = arg;
+ struct sockaddr_in6 *in;
+
+ in = (struct sockaddr_in6 *)addr;
+ *dp = AF_INET6;
+ *fp = SOCK_DGRAM;
+ *pp = 0;
+ bzero(in, sizeof (struct sockaddr_in6));
+ in->sin6_family = AF_INET6;
+
+ /*
+ * We should consider a more expressive private errno set that
+ * provider's can use.
+ */
+ mutex_enter(&vxl->vxl_lock);
+ if (vxl->vxl_hladdr == B_FALSE) {
+ mutex_exit(&vxl->vxl_lock);
+ return (EINVAL);
+ }
+ in->sin6_port = htons(vxl->vxl_lport);
+ in->sin6_addr = vxl->vxl_laddr;
+ mutex_exit(&vxl->vxl_lock);
+ *slenp = sizeof (struct sockaddr_in6);
+
+ return (0);
+}
+
+static int
+vxlan_o_sockopt(ksocket_t ksock)
+{
+ int val, err;
+ if (vxlan_fanout == B_FALSE)
+ return (0);
+
+ val = UDP_HASH_VXLAN;
+ err = ksocket_setsockopt(ksock, IPPROTO_UDP, UDP_SRCPORT_HASH, &val,
+ sizeof (val), kcred);
+ return (err);
+}
+
+/* ARGSUSED */
+static int
+vxlan_o_encap(void *arg, mblk_t *mp, ovep_encap_info_t *einfop,
+ mblk_t **outp)
+{
+ mblk_t *ob;
+ vxlan_hdr_t *vxh;
+
+ ASSERT(einfop->ovdi_id < (1 << 24));
+
+ if (DB_REF(mp) != 1 || mp->b_rptr - vxlan_noalloc_min < DB_BASE(mp)) {
+ /*
+ * This allocation could get hot. We may want to have a good
+ * way to cache and handle this allocation the same way that IP
+ * does with keeping around a message block per entry, or
+ * basically treating this as an immutable message block in the
+ * system. Basically freemsg() will be a nop, but we'll do the
+ * right thing with respect to the rest of the chain.
+ */
+ ob = allocb(vxlan_alloc_size, 0);
+ if (ob == NULL)
+ return (ENOMEM);
+
+ ob->b_wptr = DB_LIM(ob);
+ ob->b_rptr = ob->b_wptr;
+ ob->b_cont = mp;
+ } else {
+ ob = mp;
+ }
+ ob->b_rptr -= VXLAN_HDR_LEN;
+
+ vxh = (vxlan_hdr_t *)ob->b_rptr;
+ vxh->vxlan_flags = ntohl(VXLAN_F_VDI);
+ vxh->vxlan_id = htonl((uint32_t)einfop->ovdi_id << VXLAN_ID_SHIFT);
+ *outp = ob;
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+vxlan_o_decap(void *arg, mblk_t *mp, ovep_encap_info_t *dinfop)
+{
+ vxlan_hdr_t *vxh;
+
+ if (MBLKL(mp) < sizeof (vxlan_hdr_t))
+ return (EINVAL);
+ vxh = (vxlan_hdr_t *)mp->b_rptr;
+ if ((ntohl(vxh->vxlan_flags) & VXLAN_F_VDI) == 0)
+ return (EINVAL);
+
+ dinfop->ovdi_id = ntohl(vxh->vxlan_id) >> VXLAN_ID_SHIFT;
+ dinfop->ovdi_hdr_size = VXLAN_HDR_LEN;
+
+ return (0);
+}
+
+static int
+vxlan_o_getprop(void *arg, const char *pr_name, void *buf, uint32_t *bufsize)
+{
+ vxlan_t *vxl = arg;
+
+ /* vxlan/listen_ip */
+ if (strcmp(pr_name, vxlan_props[0]) == 0) {
+ if (*bufsize < sizeof (struct in6_addr))
+ return (EOVERFLOW);
+
+ mutex_enter(&vxl->vxl_lock);
+ if (vxl->vxl_hladdr == B_FALSE) {
+ *bufsize = 0;
+ } else {
+ bcopy(&vxl->vxl_laddr, buf, sizeof (struct in6_addr));
+ *bufsize = sizeof (struct in6_addr);
+ }
+ mutex_exit(&vxl->vxl_lock);
+ return (0);
+ }
+
+ /* vxlan/listen_port */
+ if (strcmp(pr_name, vxlan_props[1]) == 0) {
+ uint64_t val;
+ if (*bufsize < sizeof (uint64_t))
+ return (EOVERFLOW);
+
+ mutex_enter(&vxl->vxl_lock);
+ val = vxl->vxl_lport;
+ bcopy(&val, buf, sizeof (uint64_t));
+ *bufsize = sizeof (uint64_t);
+ mutex_exit(&vxl->vxl_lock);
+ return (0);
+ }
+
+ return (EINVAL);
+}
+
+static int
+vxlan_o_setprop(void *arg, const char *pr_name, const void *buf,
+ uint32_t bufsize)
+{
+ vxlan_t *vxl = arg;
+
+ /* vxlan/listen_ip */
+ if (strcmp(pr_name, vxlan_props[0]) == 0) {
+ const struct in6_addr *ipv6 = buf;
+ if (bufsize != sizeof (struct in6_addr))
+ return (EINVAL);
+
+ if (IN6_IS_ADDR_V4COMPAT(ipv6))
+ return (EINVAL);
+
+ if (IN6_IS_ADDR_MULTICAST(ipv6))
+ return (EINVAL);
+
+ if (IN6_IS_ADDR_6TO4(ipv6))
+ return (EINVAL);
+
+ if (IN6_IS_ADDR_V4MAPPED(ipv6)) {
+ ipaddr_t v4;
+ IN6_V4MAPPED_TO_IPADDR(ipv6, v4);
+ if (IN_MULTICAST(v4))
+ return (EINVAL);
+ }
+
+ mutex_enter(&vxl->vxl_lock);
+ vxl->vxl_hladdr = B_TRUE;
+ bcopy(ipv6, &vxl->vxl_laddr, sizeof (struct in6_addr));
+ mutex_exit(&vxl->vxl_lock);
+
+ return (0);
+ }
+
+ /* vxlan/listen_port */
+ if (strcmp(pr_name, vxlan_props[1]) == 0) {
+ const uint64_t *valp = buf;
+ if (bufsize != 8)
+ return (EINVAL);
+
+ if (*valp == 0 || *valp > UINT16_MAX)
+ return (EINVAL);
+
+ mutex_enter(&vxl->vxl_lock);
+ vxl->vxl_lport = *valp;
+ mutex_exit(&vxl->vxl_lock);
+ return (0);
+ }
+ return (EINVAL);
+}
+
+static int
+vxlan_o_propinfo(const char *pr_name, overlay_prop_handle_t phdl)
+{
+ /* vxlan/listen_ip */
+ if (strcmp(pr_name, vxlan_props[0]) == 0) {
+ overlay_prop_set_name(phdl, vxlan_props[0]);
+ overlay_prop_set_prot(phdl, OVERLAY_PROP_PERM_RRW);
+ overlay_prop_set_type(phdl, OVERLAY_PROP_T_IP);
+ overlay_prop_set_nodefault(phdl);
+ return (0);
+ }
+
+ if (strcmp(pr_name, vxlan_props[1]) == 0) {
+ overlay_prop_set_name(phdl, vxlan_props[1]);
+ overlay_prop_set_prot(phdl, OVERLAY_PROP_PERM_RRW);
+ overlay_prop_set_type(phdl, OVERLAY_PROP_T_UINT);
+ (void) overlay_prop_set_default(phdl, &vxlan_defport,
+ sizeof (vxlan_defport));
+ overlay_prop_set_range_uint32(phdl, 1, UINT16_MAX);
+ return (0);
+ }
+
+ return (EINVAL);
+}
+
+static struct overlay_plugin_ops vxlan_o_ops = {
+ 0,
+ vxlan_o_init,
+ vxlan_o_fini,
+ vxlan_o_encap,
+ vxlan_o_decap,
+ vxlan_o_socket,
+ vxlan_o_sockopt,
+ vxlan_o_getprop,
+ vxlan_o_setprop,
+ vxlan_o_propinfo
+};
+
+static struct modlmisc vxlan_modlmisc = {
+ &mod_miscops,
+ "VXLAN encap plugin"
+};
+
+static struct modlinkage vxlan_modlinkage = {
+ MODREV_1,
+ &vxlan_modlmisc
+};
+
+int
+_init(void)
+{
+ int err;
+ overlay_plugin_register_t *ovrp;
+
+ ovrp = overlay_plugin_alloc(OVEP_VERSION);
+ if (ovrp == NULL)
+ return (ENOTSUP);
+ ovrp->ovep_name = vxlan_ident;
+ ovrp->ovep_ops = &vxlan_o_ops;
+ ovrp->ovep_id_size = VXLAN_ID_LEN;
+ ovrp->ovep_flags = OVEP_F_VLAN_TAG;
+ ovrp->ovep_dest = OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT;
+ ovrp->ovep_props = vxlan_props;
+
+ if ((err = overlay_plugin_register(ovrp)) == 0) {
+ if ((err = mod_install(&vxlan_modlinkage)) != 0) {
+ (void) overlay_plugin_unregister(vxlan_ident);
+ }
+ }
+
+ overlay_plugin_free(ovrp);
+ return (err);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&vxlan_modlinkage, modinfop));
+}
+
+int
+_fini(void)
+{
+ int err;
+
+ if ((err = overlay_plugin_unregister(vxlan_ident)) != 0)
+ return (err);
+
+ return (mod_remove(&vxlan_modlinkage));
+}
diff --git a/usr/src/uts/common/io/ptem.c b/usr/src/uts/common/io/ptem.c
index afe14a2ad9..137f2916b5 100644
--- a/usr/src/uts/common/io/ptem.c
+++ b/usr/src/uts/common/io/ptem.c
@@ -401,7 +401,7 @@ ptemrput(queue_t *q, mblk_t *mp)
case M_IOCACK:
case M_IOCNAK:
/*
- * We only pass write-side ioctls through to the master that
+ * We only pass write-side ioctls through to the manager that
* we've already ACKed or NAKed to the stream head. Thus, we
* discard ones arriving from below, since they're redundant
* from the point of view of modules above us.
@@ -626,7 +626,7 @@ ptemwmsg(queue_t *q, mblk_t *mp)
* of the M_IOCTL message is made and passed
* downstream. Eventually the PCKT module, if
* it has been pushed, should pick up this message.
- * If the PCKT module has not been pushed the master
+ * If the PCKT module has not been pushed the manager
* side stream head will free it.
*/
iocp = (struct iocblk *)mp->b_rptr;
@@ -843,8 +843,9 @@ out:
default:
/*
- * End of the line. The slave driver doesn't see any
- * ioctls that we don't explicitly pass along to it.
+ * End of the line. The subsidiary driver doesn't see
+ * any ioctls that we don't explicitly pass along to
+ * it.
*/
miocnak(q, mp, 0, EINVAL);
break;
@@ -983,14 +984,14 @@ ptioc(queue_t *q, mblk_t *mp, int qside)
(void) putnextctl1(q, M_SIG, SIGWINCH);
/*
* Message may have come in as an M_IOCDATA; pass it
- * to the master side as an M_IOCTL.
+ * to the manager side as an M_IOCTL.
*/
mp->b_datap->db_type = M_IOCTL;
if (qside == WRSIDE) {
/*
* Need a copy of this message to pass on to
* the PCKT module, only if the M_IOCTL
- * orginated from the slave side.
+ * orginated from the subsidiary side.
*/
if ((pckt_msgp = copymsg(mp)) == NULL) {
miocnak(q, mp, 0, EAGAIN);
@@ -1010,7 +1011,7 @@ ptioc(queue_t *q, mblk_t *mp, int qside)
case TIOCSIGNAL: {
/*
- * This ioctl can emanate from the master side in remote
+ * This ioctl can emanate from the manager side in remote
* mode only.
*/
int sig;
@@ -1034,8 +1035,8 @@ ptioc(queue_t *q, mblk_t *mp, int qside)
}
/*
- * Send an M_PCSIG message up the slave's read side and
- * respond back to the master with an ACK or NAK as
+ * Send an M_PCSIG message up the subsidiary's read side and
+ * respond back to the manager with an ACK or NAK as
* appropriate.
*/
if (putnextctl1(q, M_PCSIG, sig) == 0) {
diff --git a/usr/src/uts/common/io/ptm.c b/usr/src/uts/common/io/ptm.c
index 472cbf6936..8127d54594 100644
--- a/usr/src/uts/common/io/ptm.c
+++ b/usr/src/uts/common/io/ptm.c
@@ -26,97 +26,107 @@
/*
* Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2021 Oxide Computer Company
*/
/*
- * Pseudo Terminal Master Driver.
+ * PSEUDO-TERMINAL MANAGER DRIVER (PTM)
*
- * The pseudo-tty subsystem simulates a terminal connection, where the master
- * side represents the terminal and the slave represents the user process's
- * special device end point. The master device is set up as a cloned device
- * where its major device number is the major for the clone device and its minor
- * device number is the major for the ptm driver. There are no nodes in the file
- * system for master devices. The master pseudo driver is opened using the
- * open(2) system call with /dev/ptmx as the device parameter. The clone open
- * finds the next available minor device for the ptm major device.
+ * The pseudo-terminal subsystem simulates a terminal connection, where the
+ * manager side represents the terminal and the subsidiary represents the user
+ * process's special device end point. The manager device is set up as a
+ * cloned device where its major device number is the major for the clone
+ * device and its minor device number is the major for the ptm driver. There
+ * are no nodes in the file system for manager devices. The manager pseudo
+ * driver is opened using the open(2) system call with /dev/ptmx as the device
+ * parameter. The clone open finds the next available minor device for the ptm
+ * major device.
*
- * A master device is available only if it and its corresponding slave device
- * are not already open. When the master device is opened, the corresponding
- * slave device is automatically locked out. Only one open is allowed on a
- * master device. Multiple opens are allowed on the slave device. After both
- * the master and slave have been opened, the user has two file descriptors
- * which are the end points of a full duplex connection composed of two streams
- * which are automatically connected at the master and slave drivers. The user
- * may then push modules onto either side of the stream pair.
+ * A manager device is available only if it and its corresponding subsidiary
+ * device are not already open. When the manager device is opened, the
+ * corresponding subsidiary device is automatically locked out. Only one open
+ * is allowed on a manager device. Multiple opens are allowed on the
+ * subsidiary device. After both the manager and subsidiary have been opened,
+ * the user has two file descriptors which are the end points of a full duplex
+ * connection composed of two streams which are automatically connected at the
+ * manager and subsidiary drivers. The user may then push modules onto either
+ * side of the stream pair.
*
- * The master and slave drivers pass all messages to their adjacent queues.
- * Only the M_FLUSH needs some processing. Because the read queue of one side
- * is connected to the write queue of the other, the FLUSHR flag is changed to
- * the FLUSHW flag and vice versa. When the master device is closed an M_HANGUP
- * message is sent to the slave device which will render the device
- * unusable. The process on the slave side gets the EIO when attempting to write
- * on that stream but it will be able to read any data remaining on the stream
- * head read queue. When all the data has been read, read() returns 0
- * indicating that the stream can no longer be used. On the last close of the
- * slave device, a 0-length message is sent to the master device. When the
- * application on the master side issues a read() or getmsg() and 0 is returned,
- * the user of the master device decides whether to issue a close() that
- * dismantles the pseudo-terminal subsystem. If the master device is not closed,
- * the pseudo-tty subsystem will be available to another user to open the slave
- * device.
+ * The manager and subsidiary drivers pass all messages to their adjacent
+ * queues. Only the M_FLUSH needs some processing. Because the read queue of
+ * one side is connected to the write queue of the other, the FLUSHR flag is
+ * changed to the FLUSHW flag and vice versa. When the manager device is
+ * closed an M_HANGUP message is sent to the subsidiary device which will
+ * render the device unusable. The process on the subsidiary side gets an EIO
+ * error when attempting to write on that stream but it will be able to read
+ * any data remaining on the stream head read queue. When all the data has
+ * been read, read() returns 0 indicating that the stream can no longer be
+ * used. On the last close of the subsidiary device, a 0-length message is
+ * sent to the manager device. When the application on the manager side issues
+ * a read() or getmsg() and 0 is returned, the user of the manager device
+ * decides whether to issue a close() that dismantles the pseudo-terminal
+ * subsystem. If the manager device is not closed, the pseudo-terminal
+ * subsystem will be available to another user to open the subsidiary device.
*
- * If O_NONBLOCK or O_NDELAY is set, read on the master side returns -1 with
+ * If O_NONBLOCK or O_NDELAY is set, read on the manager side returns -1 with
* errno set to EAGAIN if no data is available, and write returns -1 with errno
* set to EAGAIN if there is internal flow control.
*
- * IOCTLS:
*
- * ISPTM: determines whether the file descriptor is that of an open master
- * device. Return code of zero indicates that the file descriptor
- * represents master device.
+ * IOCTLS
*
- * UNLKPT: unlocks the master and slave devices. It returns 0 on success. On
- * failure, the errno is set to EINVAL indicating that the master
- * device is not open.
+ * ISPTM
+ * Determines whether the file descriptor is that of an open
+ * manager device. Return code of zero indicates that the file
+ * descriptor represents a manager device.
*
- * ZONEPT: sets the zone membership of the associated pts device.
+ * UNLKPT
+ * Unlocks the manager and subsidiary devices. It returns 0 on
+ * success. On failure, the errno is set to EINVAL indicating that
+ * the manager device is not open.
*
- * GRPPT: sets the group owner of the associated pts device.
+ * ZONEPT
+ * Sets the zone membership of the associated subsidiary device.
*
- * Synchronization:
+ * GRPPT
+ * Sets the group owner of the associated subsidiary device.
*
- * All global data synchronization between ptm/pts is done via global
- * ptms_lock mutex which is initialized at system boot time from
- * ptms_initspace (called from space.c).
*
- * Individual fields of pt_ttys structure (except ptm_rdq, pts_rdq and
- * pt_nullmsg) are protected by pt_ttys.pt_lock mutex.
+ * SYNCHRONIZATION
*
- * PT_ENTER_READ/PT_ENTER_WRITE are reference counter based read-write locks
- * which allow reader locks to be reacquired by the same thread (usual
- * reader/writer locks can't be used for that purpose since it is illegal for
- * a thread to acquire a lock it already holds, even as a reader). The sole
- * purpose of these macros is to guarantee that the peer queue will not
- * disappear (due to closing peer) while it is used. It is safe to use
- * PT_ENTER_READ/PT_EXIT_READ brackets across calls like putq/putnext (since
- * they are not real locks but reference counts).
+ * All global data synchronization between ptm/pts is done via global ptms_lock
+ * mutex which is initialized at system boot time from ptms_initspace (called
+ * from space.c).
*
- * PT_ENTER_WRITE/PT_EXIT_WRITE brackets are used ONLY in master/slave
- * open/close paths to modify ptm_rdq and pts_rdq fields. These fields should
- * be set to appropriate queues *after* qprocson() is called during open (to
- * prevent peer from accessing the queue with incomplete plumbing) and set to
- * NULL before qprocsoff() is called during close.
+ * Individual fields of pt_ttys structure (except ptm_rdq, pts_rdq and
+ * pt_nullmsg) are protected by pt_ttys.pt_lock mutex.
*
- * The pt_nullmsg field is only used in open/close routines and it is also
- * protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex
- * holds.
+ * PT_ENTER_READ/PT_ENTER_WRITE are reference counter based read-write locks
+ * which allow reader locks to be reacquired by the same thread (usual
+ * reader/writer locks can't be used for that purpose since it is illegal for a
+ * thread to acquire a lock it already holds, even as a reader). The sole
+ * purpose of these macros is to guarantee that the peer queue will not
+ * disappear (due to closing peer) while it is used. It is safe to use
+ * PT_ENTER_READ/PT_EXIT_READ brackets across calls like putq/putnext (since
+ * they are not real locks but reference counts).
*
- * Lock Ordering:
+ * PT_ENTER_WRITE/PT_EXIT_WRITE brackets are used ONLY in manager/subsidiary
+ * open/close paths to modify ptm_rdq and pts_rdq fields. These fields should
+ * be set to appropriate queues *after* qprocson() is called during open (to
+ * prevent peer from accessing the queue with incomplete plumbing) and set to
+ * NULL before qprocsoff() is called during close.
*
- * If both ptms_lock and per-pty lock should be held, ptms_lock should always
- * be entered first, followed by per-pty lock.
+ * The pt_nullmsg field is only used in open/close routines and it is also
+ * protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex
+ * holds.
*
- * See ptms.h, pts.c and ptms_conf.c for more information.
+ *
+ * LOCK ORDERING
+ *
+ * If both ptms_lock and per-pty lock should be held, ptms_lock should always
+ * be entered first, followed by per-pty lock.
+ *
+ * See ptms.h, pts.c, and ptms_conf.c for more information.
*/
#include <sys/types.h>
@@ -152,10 +162,6 @@ static int ptmwput(queue_t *, mblk_t *);
static int ptmrsrv(queue_t *);
static int ptmwsrv(queue_t *);
-/*
- * Master Stream Pseudo Terminal Module: stream data structure definitions
- */
-
static struct module_info ptm_info = {
0xdead,
"ptm",
@@ -209,9 +215,9 @@ DDI_DEFINE_STREAM_OPS(ptm_ops, nulldev, nulldev, ptm_attach, ptm_detach,
*/
static struct modldrv modldrv = {
- &mod_driverops, /* Type of module. This one is a pseudo driver */
- "Master streams driver 'ptm'",
- &ptm_ops, /* driver ops */
+ &mod_driverops,
+ "Pseudo-Terminal Manager Driver",
+ &ptm_ops,
};
static struct modlinkage modlinkage = {
@@ -273,7 +279,6 @@ ptm_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
return (DDI_SUCCESS);
}
-/*ARGSUSED*/
static int
ptm_devinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
void **result)
@@ -300,12 +305,11 @@ ptm_devinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
}
-/* ARGSUSED */
/*
- * Open a minor of the master device. Store the write queue pointer and set the
- * pt_state field to (PTMOPEN | PTLOCK).
+ * Open a minor of the manager device. Store the write queue pointer and set
+ * the pt_state field to (PTMOPEN | PTLOCK).
* This code will work properly with both clone opens and direct opens of the
- * master device.
+ * manager device.
*/
static int
ptmopen(
@@ -329,19 +333,18 @@ ptmopen(
if (!(sflag & CLONEOPEN) && dminor != 0) {
/*
- * This is a direct open to specific master device through an
+ * This is a direct open to specific manager device through an
* artificially created entry with specific minor in
- * /dev/directory. Such behavior is not supported.
+ * /dev/directory. Such behavior is not supported.
*/
return (ENXIO);
}
/*
- * The master open requires that the slave be attached
- * before it returns so that attempts to open the slave will
- * succeeed
+ * The manager open requires that the subsidiary be attached before it
+ * returns so that attempts to open the subsidiary will succeeed
*/
- if (ptms_attach_slave() != 0) {
+ if (ptms_attach_subsidiary() != 0) {
return (ENXIO);
}
@@ -366,7 +369,7 @@ ptmopen(
qprocson(rqp);
- /* Allow slave to send messages to master */
+ /* Allow subsidiary to send messages to manager */
PT_ENTER_WRITE(ptmp);
ptmp->ptm_rdq = rqp;
PT_EXIT_WRITE(ptmp);
@@ -397,13 +400,12 @@ ptmopen(
/*
- * Find the address to private data identifying the slave's write queue.
- * Send a hang-up message up the slave's read queue to designate the
- * master/slave pair is tearing down. Uattach the master and slave by
- * nulling out the write queue fields in the private data structure.
- * Finally, unlock the master/slave pair and mark the master as closed.
+ * Find the address to private data identifying the subsidiary's write queue.
+ * Send a hang-up message up the subsidiary's read queue to designate the
+ * manager/subsidiary pair is tearing down. Uattach the manager and subsidiary
+ * by nulling out the write queue fields in the private data structure.
+ * Finally, unlock the manager/subsidiary pair and mark the manager as closed.
*/
-/*ARGSUSED1*/
static int
ptmclose(queue_t *rqp, int flag, cred_t *credp)
{
@@ -417,7 +419,7 @@ ptmclose(queue_t *rqp, int flag, cred_t *credp)
if (ptmp->pts_rdq) {
pts_rdq = ptmp->pts_rdq;
if (pts_rdq->q_next) {
- DBG(("send hangup message to slave\n"));
+ DBG(("send hangup message to subsidiary\n"));
(void) putnextctl(pts_rdq, M_HANGUP);
}
}
@@ -431,8 +433,8 @@ ptmclose(queue_t *rqp, int flag, cred_t *credp)
freemsg(ptmp->pt_nullmsg);
ptmp->pt_nullmsg = NULL;
/*
- * qenable slave side write queue so that it can flush
- * its messages as master's read queue is going away
+ * qenable subsidiary side write queue so that it can flush
+ * its messages as manager's read queue is going away
*/
if (ptmp->pts_rdq)
qenable(WR(ptmp->pts_rdq));
@@ -466,9 +468,9 @@ ptmwput(queue_t *qp, mblk_t *mp)
switch (mp->b_datap->db_type) {
/*
- * if write queue request, flush master's write
- * queue and send FLUSHR up slave side. If read
- * queue request, convert to FLUSHW and putnext().
+ * If this is a write queue request, flush manager's write queue and
+ * send FLUSHR up subsidiary side. If it is a read queue request,
+ * convert to FLUSHW and putnext().
*/
case M_FLUSH:
{
@@ -477,14 +479,15 @@ ptmwput(queue_t *qp, mblk_t *mp)
DBG(("ptm got flush request\n"));
if (*mp->b_rptr & FLUSHW) {
DBG(("got FLUSHW, flush ptm write Q\n"));
- if (*mp->b_rptr & FLUSHBAND)
+ if (*mp->b_rptr & FLUSHBAND) {
/*
* if it is a FLUSHBAND, do flushband.
*/
flushband(qp, *(mp->b_rptr + 1),
FLUSHDATA);
- else
+ } else {
flushq(qp, FLUSHDATA);
+ }
flush_flg = (*mp->b_rptr & ~FLUSHW) | FLUSHR;
}
if (*mp->b_rptr & FLUSHR) {
@@ -496,8 +499,9 @@ ptmwput(queue_t *qp, mblk_t *mp)
DBG(("putnext to pts\n"));
*mp->b_rptr = flush_flg;
putnext(ptmp->pts_rdq, mp);
- } else
+ } else {
freemsg(mp);
+ }
break;
}
@@ -507,7 +511,7 @@ ptmwput(queue_t *qp, mblk_t *mp)
default:
if ((ptmp->pt_state & PTLOCK) ||
(ptmp->pts_rdq == NULL)) {
- DBG(("got M_IOCTL but no slave\n"));
+ DBG(("got M_IOCTL but no subsidiary\n"));
miocnak(qp, mp, 0, EINVAL);
PT_EXIT_READ(ptmp);
return (0);
@@ -587,16 +591,16 @@ ptmwput(queue_t *qp, mblk_t *mp)
break;
case M_READ:
- /* Caused by ldterm - can not pass to slave */
+ /* Caused by ldterm - can not pass to subsidiary */
freemsg(mp);
break;
/*
- * send other messages to slave
+ * Send other messages to the subsidiary:
*/
default:
- if ((ptmp->pt_state & PTLOCK) || (ptmp->pts_rdq == NULL)) {
- DBG(("got msg. but no slave\n"));
+ if ((ptmp->pt_state & PTLOCK) || (ptmp->pts_rdq == NULL)) {
+ DBG(("got msg. but no subsidiary\n"));
mp = mexchange(NULL, mp, 2, M_ERROR, -1);
if (mp != NULL) {
mp->b_rptr[0] = NOERROR;
@@ -606,7 +610,7 @@ ptmwput(queue_t *qp, mblk_t *mp)
PT_EXIT_READ(ptmp);
return (0);
}
- DBG(("put msg on master's write queue\n"));
+ DBG(("put msg on manager's write queue\n"));
(void) putq(qp, mp);
break;
}
@@ -617,9 +621,8 @@ ptmwput(queue_t *qp, mblk_t *mp)
/*
- * enable the write side of the slave. This triggers the
- * slave to send any messages queued on its write side to
- * the read side of this master.
+ * Enable the write side of the subsidiary. This triggers the subsidiary to
+ * send any messages queued on its write side to the read side of this manager.
*/
static int
ptmrsrv(queue_t *qp)
@@ -641,10 +644,10 @@ ptmrsrv(queue_t *qp)
/*
- * If there are messages on this queue that can be sent to
- * slave, send them via putnext(). Else, if queued messages
- * cannot be sent, leave them on this queue. If priority
- * messages on this queue, send them to slave no matter what.
+ * If there are messages on this queue that can be sent to subsidiary, send
+ * them via putnext(). Otherwise, if queued messages cannot be sent, leave
+ * them on this queue. If priority messages on this queue, send them to the
+ * subsidiary no matter what.
*/
static int
ptmwsrv(queue_t *qp)
@@ -665,7 +668,7 @@ ptmwsrv(queue_t *qp)
PT_ENTER_READ(ptmp);
if ((ptmp->pt_state & PTLOCK) || (ptmp->pts_rdq == NULL)) {
- DBG(("in master write srv proc but no slave\n"));
+ DBG(("in manager write srv proc but no subsidiary\n"));
/*
* Free messages on the write queue and send
* NAK for any M_IOCTL type messages to wakeup
@@ -690,13 +693,12 @@ ptmwsrv(queue_t *qp)
return (0);
}
/*
- * while there are messages on this write queue...
+ * While there are messages on this write queue...
*/
do {
/*
- * if don't have control message and cannot put
- * msg. on slave's read queue, put it back on
- * this queue.
+ * If this is not a control message, and we cannot put messages
+ * on the subsidiary's read queue, put it back on this queue.
*/
if (mp->b_datap->db_type <= QPCTL &&
!bcanputnext(ptmp->pts_rdq, mp->b_band)) {
@@ -705,9 +707,9 @@ ptmwsrv(queue_t *qp)
break;
}
/*
- * else send the message up slave's stream
+ * Otherwise send the message up subsidiary's stream
*/
- DBG(("send message to slave\n"));
+ DBG(("send message to subsidiary\n"));
putnext(ptmp->pts_rdq, mp);
} while ((mp = getq(qp)) != NULL);
DBG(("leaving ptmwsrv\n"));
diff --git a/usr/src/uts/common/io/ptms_conf.c b/usr/src/uts/common/io/ptms_conf.c
index f593f5313f..b032b093ed 100644
--- a/usr/src/uts/common/io/ptms_conf.c
+++ b/usr/src/uts/common/io/ptms_conf.c
@@ -21,79 +21,86 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2021 Oxide Computer Company
*/
/*
- * This file contains global data and code shared between master and slave parts
- * of the pseudo-terminal driver.
+ * PSEUDO-TERMINAL COMMON DATA AND ROUTINES (PTM, PTS)
*
- * Pseudo terminals (or pt's for short) are allocated dynamically.
- * pt's are put in the global ptms_slots array indexed by minor numbers.
+ * This file contains global data and code shared between manager and
+ * subsidiary parts of the pseudo-terminal driver.
*
- * The slots array is initially small (of the size NPTY_MIN). When more pt's are
+ * Pseudo-terminals (or ptys for short) are allocated dynamically.
+ * ptys are put in the global ptms_slots array indexed by minor numbers.
+ *
+ * The slots array is initially small (of the size NPTY_MIN). When more ptys are
* needed than the slot array size, the larger slot array is allocated and all
- * opened pt's move to the new one.
+ * opened ptys move to the new one.
+ *
+ *
+ * RESOURCE ALLOCATION
+ *
+ * - pt_ttys structures are allocated via pt_ttys_alloc, which uses
+ * kmem_cache_alloc().
+ * - Minor number space is allocated via vmem_alloc() interface.
+ * - ptms_slots arrays are allocated via kmem_alloc().
*
- * Resource allocation:
+ * Minors start from 1 instead of 0, because vmem_alloc() returns 0 in case of
+ * failure. Also, in anticipation of removing the clone device interface to
+ * pseudo-terminal subsystem, minor 0 should not be used. (Potential future
+ * development).
*
- * pt_ttys structures are allocated via pt_ttys_alloc, which uses
- * kmem_cache_alloc().
- * Minor number space is allocated via vmem_alloc() interface.
- * ptms_slots arrays are allocated via kmem_alloc().
+ * After the table slot size reaches pt_maxdelta, we stop 2^N extension
+ * algorithm and start extending the slot table size by pt_maxdelta.
*
- * Minors are started from 1 instead of 0 because vmem_alloc returns 0 in case
- * of failure. Also, in anticipation of removing clone device interface to
- * pseudo-terminal subsystem, minor 0 should not be used. (Potential future
- * development).
+ * Device entries /dev/pts directory are created dynamically by the /dev
+ * filesystem. We no longer call ddi_create_minor_node() on behalf of the
+ * subsidiary driver. The /dev filesystem creates /dev/pts nodes based on the
+ * pt_ttys array.
*
- * After the table slot size reaches pt_maxdelta, we stop 2^N extension
- * algorithm and start extending the slot table size by pt_maxdelta.
*
- * Device entries /dev/pts directory are created dynamically by the
- * /dev filesystem. We no longer call ddi_create_minor_node() on
- * behalf of the slave driver. The /dev filesystem creates /dev/pts
- * nodes based on the pt_ttys array.
+ * SYNCHRONIZATION
*
- * Synchronization:
+ * All global data synchronization between ptm/pts is done via global ptms_lock
+ * mutex which is implicitly initialized by declaring it global.
*
- * All global data synchronization between ptm/pts is done via global
- * ptms_lock mutex which is implicitly initialized by declaring it global.
+ * Individual fields of pt_ttys structure (except ptm_rdq, pts_rdq and
+ * pt_nullmsg) are protected by pt_ttys.pt_lock mutex.
*
- * Individual fields of pt_ttys structure (except ptm_rdq, pts_rdq and
- * pt_nullmsg) are protected by pt_ttys.pt_lock mutex.
+ * PT_ENTER_READ/PT_ENTER_WRITE are reference counter based read-write locks
+ * which allow reader locks to be reacquired by the same thread (usual
+ * reader/writer locks can't be used for that purpose since it is illegal for a
+ * thread to acquire a lock it already holds, even as a reader). The sole
+ * purpose of these macros is to guarantee that the peer queue will not
+ * disappear (due to closing peer) while it is used. It is safe to use
+ * PT_ENTER_READ/PT_EXIT_READ brackets across calls like putq/putnext (since
+ * they are not real locks but reference counts).
*
- * PT_ENTER_READ/PT_ENTER_WRITE are reference counter based read-write locks
- * which allow reader locks to be reacquired by the same thread (usual
- * reader/writer locks can't be used for that purpose since it is illegal for
- * a thread to acquire a lock it already holds, even as a reader). The sole
- * purpose of these macros is to guarantee that the peer queue will not
- * disappear (due to closing peer) while it is used. It is safe to use
- * PT_ENTER_READ/PT_EXIT_READ brackets across calls like putq/putnext (since
- * they are not real locks but reference counts).
+ * PT_ENTER_WRITE/PT_EXIT_WRITE brackets are used ONLY in manager/subsidiary
+ * open/close paths to modify ptm_rdq and pts_rdq fields. These fields should
+ * be set to appropriate queues *after* qprocson() is called during open (to
+ * prevent peer from accessing the queue with incomplete plumbing) and set to
+ * NULL before qprocsoff() is called during close. Put and service procedures
+ * use PT_ENTER_READ/PT_EXIT_READ to prevent peer closes.
*
- * PT_ENTER_WRITE/PT_EXIT_WRITE brackets are used ONLY in master/slave
- * open/close paths to modify ptm_rdq and pts_rdq fields. These fields should
- * be set to appropriate queues *after* qprocson() is called during open (to
- * prevent peer from accessing the queue with incomplete plumbing) and set to
- * NULL before qprocsoff() is called during close. Put and service procedures
- * use PT_ENTER_READ/PT_EXIT_READ to prevent peer closes.
+ * The pt_nullmsg field is only used in open/close routines and is also
+ * protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex
+ * holds.
*
- * The pt_nullmsg field is only used in open/close routines and is also
- * protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex
- * holds.
*
- * Lock Ordering:
+ * LOCK ORDERING
*
- * If both ptms_lock and per-pty lock should be held, ptms_lock should always
- * be entered first, followed by per-pty lock.
+ * If both ptms_lock and per-pty lock should be held, ptms_lock should always
+ * be entered first, followed by per-pty lock.
*
- * Global functions:
+ *
+ * GLOBAL FUNCTIONS
*
* void ptms_init(void);
*
* Called by pts/ptm _init entry points. It performes one-time
- * initialization needed for both pts and ptm. This initialization is done
- * here and not in ptms_initspace because all these data structures are not
+ * initialization needed for both pts and ptm. This initialization is done
+ * here and not in ptms_initspace because all these data structures are not
* needed if pseudo-terminals are not used in the system.
*
* struct pt_ttys *pt_ttys_alloc(void);
@@ -117,6 +124,7 @@
* Also returns owner of pty.
*
* int ptms_minor_exists(minor_t minor)
+ *
* Check if minor refers to an allocated pty (in any zone)
* Returns
* 0 if not an allocated pty
@@ -129,32 +137,33 @@
* void ptms_close(struct pt_ttys *pt, uint_t flags_to_clear);
*
* Clear flags_to_clear in pt and if no one owns it (PTMOPEN/PTSOPEN not
- * set) free pt entry and corresponding slot.
+ * set) free pt entry and corresponding slot.
*
- * Tuneables and configuration:
+ *
+ * TUNEABLES AND CONFIGURATION
*
* pt_cnt: minimum number of pseudo-terminals in the system. The system
* should provide at least this number of ptys (provided sufficient
- * memory is available). It is different from the older semantics
+ * memory is available). It is different from the older semantics
* of pt_cnt meaning maximum number of ptys.
* Set to 0 by default.
*
* pt_max_pty: Maximum number of pseudo-terminals in the system. The system
* should not allocate more ptys than pt_max_pty (although, it may
- * impose stricter maximum). Zero value means no user-defined
- * maximum. This is intended to be used as "denial-of-service"
+ * impose stricter maximum). Zero value means no user-defined
+ * maximum. This is intended to be used as "denial-of-service"
* protection.
* Set to 0 by default.
*
- * Both pt_cnt and pt_max_pty may be modified during system lifetime
- * with their semantics preserved.
+ * Both pt_cnt and pt_max_pty may be modified during system
+ * lifetime with their semantics preserved.
*
* pt_init_cnt: Initial size of ptms_slots array. Set to NPTY_INITIAL.
*
* pt_ptyofmem: Approximate percentage of system memory that may be
* occupied by pty data structures. Initially set to NPTY_PERCENT.
* This variable is used once during initialization to estimate
- * maximum number of ptys in the system. The actual maximum is
+ * maximum number of ptys in the system. The actual maximum is
* determined as minimum of pt_max_pty and calculated value.
*
* pt_maxdelta: Maximum extension chunk of the slot table.
@@ -193,7 +202,7 @@
* Tuneable variables.
*/
uint_t pt_cnt = 0; /* Minimum number of ptys */
-size_t pt_max_pty = 0; /* Maximum number of ptys */
+size_t pt_max_pty = 0; /* Maximum number of ptys */
uint_t pt_init_cnt = NPTY_INITIAL; /* Initial number of ptms slots */
uint_t pt_pctofmem = NPTY_PERCENT; /* Percent of memory to use for ptys */
uint_t pt_maxdelta = PTY_MAXDELTA; /* Max increment for slot table size */
@@ -210,7 +219,7 @@ static size_t ptms_nslots = 0; /* Size of slot array */
static size_t ptms_ptymax = 0; /* Maximum number of ptys */
static size_t ptms_inuse = 0; /* # of ptys currently allocated */
-dev_info_t *pts_dip = NULL; /* set if slave is attached */
+dev_info_t *pts_dip = NULL; /* Set if subsidiary is attached */
static struct kmem_cache *ptms_cache = NULL; /* pty cache */
@@ -222,9 +231,9 @@ static void ptms_destructor(void *, void *);
static minor_t ptms_grow(void);
/*
- * Total size occupied by one pty. Each pty master/slave pair consumes one
- * pointer for ptms_slots array, one pt_ttys structure and one empty message
- * preallocated for pts close.
+ * Total size occupied by one pty. Each pty manager/subsidiary pair consumes
+ * one pointer for ptms_slots array, one pt_ttys structure, and one empty
+ * message preallocated for pts close.
*/
#define PTY_SIZE (sizeof (struct pt_ttys) + \
@@ -239,7 +248,7 @@ int ptms_debug = 0;
/*
* Clear all bits of x except the highest bit
*/
-#define truncate(x) ((x) <= 2 ? (x) : (1 << (highbit(x) - 1)))
+#define truncate(x) ((x) <= 2 ? (x) : (1 << (highbit(x) - 1)))
/*
* Roundup the number to the nearest power of 2
@@ -295,7 +304,7 @@ ptms_init(void)
* This routine attaches the pts dip.
*/
int
-ptms_attach_slave(void)
+ptms_attach_subsidiary(void)
{
if (pts_dip == NULL && i_ddi_attach_pseudo_node("pts") == NULL)
return (-1);
@@ -309,7 +318,7 @@ ptms_attach_slave(void)
* and if it is, returns its major number.
*/
major_t
-ptms_slave_attached(void)
+ptms_subsidiary_attached(void)
{
major_t maj = DDI_MAJOR_T_NONE;
@@ -422,10 +431,7 @@ ptms_set_owner(minor_t dminor, uid_t ruid, gid_t rgid)
{
struct pt_ttys *pt;
- ASSERT(ruid >= 0);
- ASSERT(rgid >= 0);
-
- if (ruid < 0 || rgid < 0)
+ if (ruid > MAXUID || rgid > MAXUID)
return;
/*
@@ -478,8 +484,8 @@ ptms_minor_valid(minor_t dminor, uid_t *ruid, gid_t *rgid)
mutex_enter(&ptms_lock);
pt = ptms_minor2ptty(dminor);
if (pt != NULL) {
- ASSERT(pt->pt_ruid >= 0);
- ASSERT(pt->pt_rgid >= 0);
+ ASSERT(pt->pt_ruid <= MAXUID);
+ ASSERT(pt->pt_rgid <= MAXUID);
if (pt->pt_zoneid == getzoneid()) {
ret = 1;
*ruid = pt->pt_ruid;
diff --git a/usr/src/uts/common/io/pts.c b/usr/src/uts/common/io/pts.c
index ff2d91f566..046a2bc76b 100644
--- a/usr/src/uts/common/io/pts.c
+++ b/usr/src/uts/common/io/pts.c
@@ -27,80 +27,84 @@
/*
* Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2021 Oxide Computer Company
*/
/*
- * Pseudo Terminal Slave Driver.
+ * PSEUDO-TERMINAL SUBSIDIARY DRIVER (PTS)
*
- * The pseudo-tty subsystem simulates a terminal connection, where the master
- * side represents the terminal and the slave represents the user process's
- * special device end point. The master device is set up as a cloned device
- * where its major device number is the major for the clone device and its minor
- * device number is the major for the ptm driver. There are no nodes in the file
- * system for master devices. The master pseudo driver is opened using the
- * open(2) system call with /dev/ptmx as the device parameter. The clone open
- * finds the next available minor device for the ptm major device.
+ * The pseudo-terminal subsystem simulates a terminal connection, where the
+ * manager side represents the terminal and the subsidiary represents the user
+ * process's special device end point. The manager device is set up as a
+ * cloned device where its major device number is the major for the clone
+ * device and its minor device number is the major for the ptm driver. There
+ * are no nodes in the file system for manager devices. The manager pseudo
+ * driver is opened using the open(2) system call with /dev/ptmx as the device
+ * parameter. The clone open finds the next available minor device for the ptm
+ * major device.
*
- * A master device is available only if it and its corresponding slave device
- * are not already open. When the master device is opened, the corresponding
- * slave device is automatically locked out. Only one open is allowed on a
- * master device. Multiple opens are allowed on the slave device. After both
- * the master and slave have been opened, the user has two file descriptors
- * which are the end points of a full duplex connection composed of two streams
- * which are automatically connected at the master and slave drivers. The user
- * may then push modules onto either side of the stream pair.
+ * A manager device is available only if it and its corresponding subsidiary
+ * device are not already open. When the manager device is opened, the
+ * corresponding subsidiary device is automatically locked out. Only one open
+ * is allowed on a manager device. Multiple opens are allowed on the
+ * subsidiary device. After both the manager and subsidiary have been opened,
+ * the user has two file descriptors which are the end points of a full duplex
+ * connection composed of two streams which are automatically connected at the
+ * manager and subsidiary drivers. The user may then push modules onto either
+ * side of the stream pair.
*
- * The master and slave drivers pass all messages to their adjacent queues.
- * Only the M_FLUSH needs some processing. Because the read queue of one side
- * is connected to the write queue of the other, the FLUSHR flag is changed to
- * the FLUSHW flag and vice versa. When the master device is closed an M_HANGUP
- * message is sent to the slave device which will render the device
- * unusable. The process on the slave side gets the EIO when attempting to write
- * on that stream but it will be able to read any data remaining on the stream
- * head read queue. When all the data has been read, read() returns 0
- * indicating that the stream can no longer be used. On the last close of the
- * slave device, a 0-length message is sent to the master device. When the
- * application on the master side issues a read() or getmsg() and 0 is returned,
- * the user of the master device decides whether to issue a close() that
- * dismantles the pseudo-terminal subsystem. If the master device is not closed,
- * the pseudo-tty subsystem will be available to another user to open the slave
- * device.
+ * The manager and subsidiary drivers pass all messages to their adjacent
+ * queues. Only the M_FLUSH needs some processing. Because the read queue of
+ * one side is connected to the write queue of the other, the FLUSHR flag is
+ * changed to the FLUSHW flag and vice versa. When the manager device is
+ * closed an M_HANGUP message is sent to the subsidiary device which will
+ * render the device unusable. The process on the subsidiary side gets the EIO
+ * when attempting to write on that stream but it will be able to read any data
+ * remaining on the stream head read queue. When all the data has been read,
+ * read() returns 0 indicating that the stream can no longer be used. On the
+ * last close of the subsidiary device, a 0-length message is sent to the
+ * manager device. When the application on the manager side issues a read() or
+ * getmsg() and 0 is returned, the user of the manager device decides whether
+ * to issue a close() that dismantles the pseudo-terminal subsystem. If the
+ * manager device is not closed, the pseudo-tty subsystem will be available to
+ * another user to open the subsidiary device.
*
- * Synchronization:
*
- * All global data synchronization between ptm/pts is done via global
- * ptms_lock mutex which is initialized at system boot time from
- * ptms_initspace (called from space.c).
+ * SYNCHRONIZATION
*
- * Individual fields of pt_ttys structure (except ptm_rdq, pts_rdq and
- * pt_nullmsg) are protected by pt_ttys.pt_lock mutex.
+ * All global data synchronization between ptm/pts is done via global ptms_lock
+ * mutex which is initialized at system boot time from ptms_initspace (called
+ * from space.c).
*
- * PT_ENTER_READ/PT_ENTER_WRITE are reference counter based read-write locks
- * which allow reader locks to be reacquired by the same thread (usual
- * reader/writer locks can't be used for that purpose since it is illegal for
- * a thread to acquire a lock it already holds, even as a reader). The sole
- * purpose of these macros is to guarantee that the peer queue will not
- * disappear (due to closing peer) while it is used. It is safe to use
- * PT_ENTER_READ/PT_EXIT_READ brackets across calls like putq/putnext (since
- * they are not real locks but reference counts).
+ * Individual fields of pt_ttys structure (except ptm_rdq, pts_rdq and
+ * pt_nullmsg) are protected by pt_ttys.pt_lock mutex.
*
- * PT_ENTER_WRITE/PT_EXIT_WRITE brackets are used ONLY in master/slave
- * open/close paths to modify ptm_rdq and pts_rdq fields. These fields should
- * be set to appropriate queues *after* qprocson() is called during open (to
- * prevent peer from accessing the queue with incomplete plumbing) and set to
- * NULL before qprocsoff() is called during close.
+ * PT_ENTER_READ/PT_ENTER_WRITE are reference counter based read-write locks
+ * which allow reader locks to be reacquired by the same thread (usual
+ * reader/writer locks can't be used for that purpose since it is illegal for a
+ * thread to acquire a lock it already holds, even as a reader). The sole
+ * purpose of these macros is to guarantee that the peer queue will not
+ * disappear (due to closing peer) while it is used. It is safe to use
+ * PT_ENTER_READ/PT_EXIT_READ brackets across calls like putq/putnext (since
+ * they are not real locks but reference counts).
*
- * The pt_nullmsg field is only used in open/close routines and it is also
- * protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex
- * holds.
+ * PT_ENTER_WRITE/PT_EXIT_WRITE brackets are used ONLY in manager/subsidiary
+ * open/close paths to modify ptm_rdq and pts_rdq fields. These fields should
+ * be set to appropriate queues *after* qprocson() is called during open (to
+ * prevent peer from accessing the queue with incomplete plumbing) and set to
+ * NULL before qprocsoff() is called during close.
*
- * Lock Ordering:
+ * The pt_nullmsg field is only used in open/close routines and it is also
+ * protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex
+ * holds.
*
- * If both ptms_lock and per-pty lock should be held, ptms_lock should always
- * be entered first, followed by per-pty lock.
*
- * See ptms.h, ptm.c and ptms_conf.c fore more information.
+ * LOCK ORDERING
+ *
+ * If both ptms_lock and per-pty lock should be held, ptms_lock should always
+ * be entered first, followed by per-pty lock.
*
+ * See ptms.h, ptm.c and ptms_conf.c fore more information.
*/
#include <sys/types.h>
@@ -135,9 +139,6 @@ static int ptswput(queue_t *, mblk_t *);
static int ptsrsrv(queue_t *);
static int ptswsrv(queue_t *);
-/*
- * Slave Stream Pseudo Terminal Module: stream data structure definitions
- */
static struct module_info pts_info = {
0xface,
"pts",
@@ -192,9 +193,9 @@ DDI_DEFINE_STREAM_OPS(pts_ops, nulldev, nulldev, \
*/
static struct modldrv modldrv = {
- &mod_driverops, /* Type of module. This one is a pseudo driver */
- "Slave Stream Pseudo Terminal driver 'pts'",
- &pts_ops, /* driver ops */
+ &mod_driverops,
+ "Pseudo-Terminal Subsidiary Driver",
+ &pts_ops,
};
static struct modlinkage modlinkage = {
@@ -239,7 +240,6 @@ pts_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
return (DDI_SUCCESS);
}
-/*ARGSUSED*/
static int
pts_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
{
@@ -252,7 +252,6 @@ pts_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
return (DDI_FAILURE);
}
-/*ARGSUSED*/
static int
pts_devinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
void **result)
@@ -280,9 +279,9 @@ pts_devinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
/* ARGSUSED */
/*
- * Open the slave device. Reject a clone open and do not allow the
- * driver to be pushed. If the slave/master pair is locked or if
- * the master is not open, return EACCESS.
+ * Open the subsidiary device. Reject a clone open and do not allow the
+ * driver to be pushed. If the subsidiary/manager pair is locked or if
+ * the manager is not open, return EACCESS.
* Upon success, store the write queue pointer in private data and
* set the PTSOPEN bit in the pt_state field.
*/
@@ -369,10 +368,10 @@ ptsopen(
}
/*
- * Slave should send zero-length message to a master when it is
- * closing. If memory is low at that time, master will not detect slave
- * closes, this pty will not be deallocated. So, preallocate this
- * zero-length message block early.
+ * Subsidiary should send zero-length message to a manager when it is
+ * closing. If memory is low at that time, manager will not detect
+ * subsidiary closes, this pty will not be deallocated. So,
+ * preallocate this zero-length message block early.
*/
if ((mp = allocb(0, BPRI_MED)) == NULL) {
mutex_exit(&ptsp->pt_lock);
@@ -395,9 +394,10 @@ ptsopen(
/*
* After qprocson pts driver is fully plumbed into the stream and can
- * send/receive messages. Setting pts_rdq will allow master side to send
- * messages to the slave. This setting can't occur before qprocson() is
- * finished because slave is not ready to process them.
+ * send/receive messages. Setting pts_rdq will allow manager side to
+ * send messages to the subsidiary. This setting can't occur before
+ * qprocson() is finished because subsidiary is not ready to process
+ * them.
*/
PT_ENTER_WRITE(ptsp);
ptsp->pts_rdq = rqp;
@@ -422,12 +422,11 @@ ptsopen(
}
/*
- * Find the address to private data identifying the slave's write
- * queue. Send a 0-length msg up the slave's read queue to designate
- * the master is closing. Uattach the master from the slave by nulling
- * out master's write queue field in private data.
+ * Find the address to private data identifying the subsidiary's write queue.
+ * Send a 0-length msg up the subsidiary's read queue to designate the manager
+ * is closing. Uattach the manager from the subsidiary by nulling out
+ * manager's write queue field in private data.
*/
-/*ARGSUSED1*/
static int
ptsclose(queue_t *rqp, int flag, cred_t *credp)
{
@@ -450,10 +449,10 @@ ptsclose(queue_t *rqp, int flag, cred_t *credp)
ptsp = (struct pt_ttys *)rqp->q_ptr;
/*
- * Slave is going to close and doesn't want any new messages coming
- * from the master side, so set pts_rdq to NULL. This should be done
- * before call to qprocsoff() since slave can't process additional
- * messages from the master after qprocsoff is called.
+ * Subsidiary is going to close and doesn't want any new messages
+ * coming from the manager side, so set pts_rdq to NULL. This should
+ * be done before call to qprocsoff() since subsidiary can't process
+ * additional messages from the manager after qprocsoff is called.
*/
PT_ENTER_WRITE(ptsp);
mp = ptsp->pt_nullmsg;
@@ -479,8 +478,8 @@ ptsclose(queue_t *rqp, int flag, cred_t *credp)
}
}
/*
- * qenable master side write queue so that it can flush
- * its messages as slaves's read queue is going away
+ * qenable manager side write queue so that it can flush its messages
+ * as subsidiarys's read queue is going away:
*/
if (ptsp->ptm_rdq) {
if (mp)
@@ -503,9 +502,9 @@ ptsclose(queue_t *rqp, int flag, cred_t *credp)
/*
- * The wput procedure will only handle flush messages.
- * All other messages are queued and the write side
- * service procedure sends them off to the master side.
+ * The wput procedure will only handle flush messages. All other messages are
+ * queued and the write side service procedure sends them off to the manager
+ * side.
*/
static int
ptswput(queue_t *qp, mblk_t *mp)
@@ -520,9 +519,9 @@ ptswput(queue_t *qp, mblk_t *mp)
ptsp = (struct pt_ttys *)qp->q_ptr;
PT_ENTER_READ(ptsp);
if (ptsp->ptm_rdq == NULL) {
- DBG(("in write put proc but no master\n"));
+ DBG(("in write put proc but no manager\n"));
/*
- * NAK ioctl as slave side read queue is gone.
+ * NAK ioctl as subsidiary side read queue is gone.
* Or else free the message.
*/
if (mp->b_datap->db_type == M_IOCTL) {
@@ -540,7 +539,7 @@ ptswput(queue_t *qp, mblk_t *mp)
switch (type) {
/*
- * if write queue request, flush slave's write
+ * if write queue request, flush subsidiary's write
* queue and send FLUSHR to ptm. If read queue
* request, send FLUSHR to ptm.
*/
@@ -585,9 +584,9 @@ ptswput(queue_t *qp, mblk_t *mp)
}
}
/*
- * Since the packet module will toss any
- * M_FLUSHES sent to the master's stream head
- * read queue, we simply turn it around here.
+ * Since the packet module will toss any M_FLUSHES sent to the
+ * manager's stream head read queue, we simply turn it around
+ * here.
*/
if (*mp->b_rptr & FLUSHR) {
ASSERT(RD(qp)->q_first == NULL);
@@ -599,7 +598,7 @@ ptswput(queue_t *qp, mblk_t *mp)
break;
case M_READ:
- /* Caused by ldterm - can not pass to master */
+ /* Caused by ldterm - can not pass to manager */
freemsg(mp);
break;
@@ -645,9 +644,9 @@ ptswput(queue_t *qp, mblk_t *mp)
/* FALLTHROUGH */
default:
/*
- * send other messages to the master
+ * send other messages to the manager
*/
- DBG(("put msg on slave's write queue\n"));
+ DBG(("put msg on subsidiary's write queue\n"));
(void) putq(qp, mp);
break;
}
@@ -659,9 +658,8 @@ ptswput(queue_t *qp, mblk_t *mp)
/*
- * enable the write side of the master. This triggers the
- * master to send any messages queued on its write side to
- * the read side of this slave.
+ * Enable the write side of the manager. This triggers the manager to send any
+ * messages queued on its write side to the read side of this subsidiary.
*/
static int
ptsrsrv(queue_t *qp)
@@ -674,7 +672,7 @@ ptsrsrv(queue_t *qp)
ptsp = (struct pt_ttys *)qp->q_ptr;
PT_ENTER_READ(ptsp);
if (ptsp->ptm_rdq == NULL) {
- DBG(("in read srv proc but no master\n"));
+ DBG(("in read srv proc but no manager\n"));
PT_EXIT_READ(ptsp);
return (0);
}
@@ -685,10 +683,10 @@ ptsrsrv(queue_t *qp)
}
/*
- * If there are messages on this queue that can be sent to
- * master, send them via putnext(). Else, if queued messages
- * cannot be sent, leave them on this queue. If priority
- * messages on this queue, send them to master no matter what.
+ * If there are messages on this queue that can be sent to manager, send them
+ * via putnext(). Otherwise, if queued messages cannot be sent, leave them on
+ * this queue. If priority messages on this queue, send them to manager no
+ * matter what.
*/
static int
ptswsrv(queue_t *qp)
@@ -703,12 +701,11 @@ ptswsrv(queue_t *qp)
ptsp = (struct pt_ttys *)qp->q_ptr;
PT_ENTER_READ(ptsp);
if (ptsp->ptm_rdq == NULL) {
- DBG(("in write srv proc but no master\n"));
+ DBG(("in write srv proc but no manager\n"));
/*
- * Free messages on the write queue and send
- * NAK for any M_IOCTL type messages to wakeup
- * the user process waiting for ACK/NAK from
- * the ioctl invocation
+ * Free messages on the write queue and send NAK for any
+ * M_IOCTL type messages to wakeup the user process waiting for
+ * ACK/NAK from the ioctl invocation
*/
while ((mp = getq(qp)) != NULL) {
if (mp->b_datap->db_type == M_IOCTL) {
@@ -726,13 +723,12 @@ ptswsrv(queue_t *qp)
}
/*
- * while there are messages on this write queue...
+ * While there are messages on this write queue...
*/
while ((mp = getq(qp)) != NULL) {
/*
- * if don't have control message and cannot put
- * msg. on master's read queue, put it back on
- * this queue.
+ * If this is not a control message and we cannot put messages
+ * on the manager's read queue, put it back on this queue.
*/
if (mp->b_datap->db_type <= QPCTL &&
!bcanputnext(ptm_rdq, mp->b_band)) {
@@ -741,9 +737,9 @@ ptswsrv(queue_t *qp)
break;
}
/*
- * else send the message up master's stream
+ * Otherwise, send the message up manager's stream:
*/
- DBG(("send message to master\n"));
+ DBG(("send message to manager\n"));
putnext(ptm_rdq, mp);
}
DBG(("leaving ptswsrv\n"));
diff --git a/usr/src/uts/common/io/sata/adapters/ahci/ahci.c b/usr/src/uts/common/io/sata/adapters/ahci/ahci.c
index 691c03bff4..e3b6d2fa8d 100644
--- a/usr/src/uts/common/io/sata/adapters/ahci/ahci.c
+++ b/usr/src/uts/common/io/sata/adapters/ahci/ahci.c
@@ -10766,7 +10766,7 @@ ahci_em_ioctl_set(ahci_ctl_t *ahci_ctlp, intptr_t arg)
return (ENOTSUP);
}
- task = kmem_alloc(sizeof (*task), KM_NOSLEEP | KM_NORMALPRI);
+ task = kmem_alloc(sizeof (*task), KM_NOSLEEP_LAZY);
if (task == NULL) {
return (ENOMEM);
}
diff --git a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_attach.c b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_attach.c
index 02243c4171..189edbefd5 100644
--- a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_attach.c
+++ b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_attach.c
@@ -3100,12 +3100,10 @@ pmcs_create_one_phy_stats(pmcs_iport_t *iport, pmcs_phy_t *phyp)
static void
pmcs_create_all_phy_stats(pmcs_iport_t *iport)
{
- pmcs_hw_t *pwp;
pmcs_phy_t *phyp;
ASSERT(iport != NULL);
- pwp = iport->pwp;
- ASSERT(pwp != NULL);
+ ASSERT(iport->pwp != NULL);
mutex_enter(&iport->lock);
diff --git a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_sata.c b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_sata.c
index 03e632e161..688ae0c07e 100644
--- a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_sata.c
+++ b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_sata.c
@@ -23,7 +23,7 @@
* Use is subject to license terms.
*/
/*
- * SATA midlayer interface for PMC drier.
+ * SATA midlayer interface for PMC driver.
*/
#include <sys/scsi/adapters/pmcs/pmcs.h>
@@ -52,7 +52,8 @@ SATAcopy(pmcs_cmd_t *sp, void *kbuf, uint32_t amt)
*
* Called with PHY lock and xp statlock held.
*/
-#define SRESPSZ 128
+#define SRESPSZ 132
+CTASSERT(SRESPSZ == sizeof (struct scsi_inquiry));
static int
pmcs_sata_special_work(pmcs_hw_t *pwp, pmcs_xscsi_t *xp)
diff --git a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c
index fb5bb00420..a3b22a9adc 100644
--- a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c
+++ b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c
@@ -58,7 +58,9 @@ static void pmcs_flush_observations(pmcs_hw_t *);
static boolean_t pmcs_report_observations(pmcs_hw_t *);
static boolean_t pmcs_report_iport_observations(pmcs_hw_t *, pmcs_iport_t *,
pmcs_phy_t *);
+#ifdef DEBUG
static pmcs_phy_t *pmcs_find_phy_needing_work(pmcs_hw_t *, pmcs_phy_t *);
+#endif
static int pmcs_kill_devices(pmcs_hw_t *, pmcs_phy_t *);
static void pmcs_lock_phy_impl(pmcs_phy_t *, int);
static void pmcs_unlock_phy_impl(pmcs_phy_t *, int);
@@ -958,7 +960,7 @@ pmcs_stop_phys(pmcs_hw_t *pwp)
/*
* Run SAS_DIAG_EXECUTE with cmd and cmd_desc passed.
- * ERR_CNT_RESET: return status of cmd
+ * ERR_CNT_RESET: return status of cmd
* DIAG_REPORT_GET: return value of the counter
*/
int
@@ -2631,6 +2633,7 @@ restart:
mutex_exit(&pwp->config_lock);
}
+#ifdef DEBUG
/*
* Return any PHY that needs to have scheduled work done. The PHY is returned
* locked.
@@ -2665,6 +2668,7 @@ pmcs_find_phy_needing_work(pmcs_hw_t *pwp, pmcs_phy_t *pptr)
return (NULL);
}
+#endif
/*
* We may (or may not) report observations to SCSA. This is prefaced by
@@ -6726,7 +6730,7 @@ pmcs_wr_oqpi(pmcs_hw_t *pwp, uint32_t qnum, uint32_t val)
void
pmcs_check_iomb_status(pmcs_hw_t *pwp, uint32_t *iomb)
{
- uint16_t opcode;
+ uint16_t opcode;
int offset;
if (iomb == NULL) {
diff --git a/usr/src/uts/common/io/scsi/adapters/smrt/smrt.c b/usr/src/uts/common/io/scsi/adapters/smrt/smrt.c
new file mode 100644
index 0000000000..a7ef2b69d7
--- /dev/null
+++ b/usr/src/uts/common/io/scsi/adapters/smrt/smrt.c
@@ -0,0 +1,565 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+#include <sys/scsi/adapters/smrt/smrt.h>
+
+static int smrt_attach(dev_info_t *, ddi_attach_cmd_t);
+static int smrt_detach(dev_info_t *, ddi_detach_cmd_t);
+static int smrt_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+static void smrt_cleanup(smrt_t *);
+static int smrt_command_comparator(const void *, const void *);
+
+/*
+ * Controller soft state. Each entry is an object of type "smrt_t".
+ */
+void *smrt_state;
+
+/*
+ * DMA attributes template. Each controller will make a copy of this template
+ * with appropriate customisations; e.g., the Scatter/Gather List Length.
+ */
+static ddi_dma_attr_t smrt_dma_attr_template = {
+ .dma_attr_version = DMA_ATTR_V0,
+ .dma_attr_addr_lo = 0x0000000000000000,
+ .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFF,
+ .dma_attr_count_max = 0x00FFFFFF,
+ .dma_attr_align = 0x20,
+ .dma_attr_burstsizes = 0x20,
+ .dma_attr_minxfer = DMA_UNIT_8,
+ .dma_attr_maxxfer = 0xFFFFFFFF,
+ /*
+ * There is some suggestion that at least some, possibly older, Smart
+ * Array controllers cannot tolerate a DMA segment that straddles a 4GB
+ * boundary.
+ */
+ .dma_attr_seg = 0xFFFFFFFF,
+ .dma_attr_sgllen = 1,
+ .dma_attr_granular = 512,
+ .dma_attr_flags = 0
+};
+
+/*
+ * Device memory access attributes for device control registers.
+ */
+ddi_device_acc_attr_t smrt_dev_attributes = {
+ .devacc_attr_version = DDI_DEVICE_ATTR_V0,
+ .devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC,
+ .devacc_attr_dataorder = DDI_STRICTORDER_ACC,
+ .devacc_attr_access = 0
+};
+
+/*
+ * Character/Block Operations Structure
+ */
+static struct cb_ops smrt_cb_ops = {
+ .cb_rev = CB_REV,
+ .cb_flag = D_NEW | D_MP,
+
+ .cb_open = scsi_hba_open,
+ .cb_close = scsi_hba_close,
+
+ .cb_ioctl = smrt_ioctl,
+
+ .cb_strategy = nodev,
+ .cb_print = nodev,
+ .cb_dump = nodev,
+ .cb_read = nodev,
+ .cb_write = nodev,
+ .cb_devmap = nodev,
+ .cb_mmap = nodev,
+ .cb_segmap = nodev,
+ .cb_chpoll = nochpoll,
+ .cb_prop_op = ddi_prop_op,
+ .cb_str = NULL,
+ .cb_aread = nodev,
+ .cb_awrite = nodev
+};
+
+/*
+ * Device Operations Structure
+ */
+static struct dev_ops smrt_dev_ops = {
+ .devo_rev = DEVO_REV,
+ .devo_refcnt = 0,
+
+ .devo_attach = smrt_attach,
+ .devo_detach = smrt_detach,
+
+ .devo_cb_ops = &smrt_cb_ops,
+
+ .devo_getinfo = nodev,
+ .devo_identify = nulldev,
+ .devo_probe = nulldev,
+ .devo_reset = nodev,
+ .devo_bus_ops = NULL,
+ .devo_power = nodev,
+ .devo_quiesce = nodev
+};
+
+/*
+ * Linkage structures
+ */
+static struct modldrv smrt_modldrv = {
+ .drv_modops = &mod_driverops,
+ .drv_linkinfo = "HP Smart Array",
+ .drv_dev_ops = &smrt_dev_ops
+};
+
+static struct modlinkage smrt_modlinkage = {
+ .ml_rev = MODREV_1,
+ .ml_linkage = { &smrt_modldrv, NULL }
+};
+
+
+int
+_init()
+{
+ int r;
+
+ VERIFY0(ddi_soft_state_init(&smrt_state, sizeof (smrt_t), 0));
+
+ if ((r = scsi_hba_init(&smrt_modlinkage)) != 0) {
+ goto fail;
+ }
+
+ if ((r = mod_install(&smrt_modlinkage)) != 0) {
+ scsi_hba_fini(&smrt_modlinkage);
+ goto fail;
+ }
+
+ return (r);
+
+fail:
+ ddi_soft_state_fini(&smrt_state);
+ return (r);
+}
+
+int
+_fini()
+{
+ int r;
+
+ if ((r = mod_remove(&smrt_modlinkage)) == 0) {
+ scsi_hba_fini(&smrt_modlinkage);
+ ddi_soft_state_fini(&smrt_state);
+ }
+
+ return (r);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&smrt_modlinkage, modinfop));
+}
+
+static int
+smrt_iport_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ const char *addr;
+ dev_info_t *pdip;
+ int instance;
+ smrt_t *smrt;
+
+ if (cmd != DDI_ATTACH)
+ return (DDI_FAILURE);
+
+ /*
+ * Note, we cannot get to our parent via the tran's tran_hba_private
+ * member. This pointer is reset to NULL when the scsi_hba_tran_t
+ * structure is duplicated.
+ */
+ addr = scsi_hba_iport_unit_address(dip);
+ VERIFY(addr != NULL);
+ pdip = ddi_get_parent(dip);
+ instance = ddi_get_instance(pdip);
+ smrt = ddi_get_soft_state(smrt_state, instance);
+ VERIFY(smrt != NULL);
+
+ if (strcmp(addr, SMRT_IPORT_VIRT) == 0) {
+ if (smrt_logvol_hba_setup(smrt, dip) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+ smrt->smrt_virt_iport = dip;
+ } else if (strcmp(addr, SMRT_IPORT_PHYS) == 0) {
+ if (smrt_phys_hba_setup(smrt, dip) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+ smrt->smrt_phys_iport = dip;
+ } else {
+ return (DDI_FAILURE);
+ }
+
+ return (DDI_SUCCESS);
+}
+
+static int
+smrt_iport_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ const char *addr;
+ scsi_hba_tran_t *tran;
+ smrt_t *smrt;
+
+ if (cmd != DDI_DETACH)
+ return (DDI_FAILURE);
+
+ tran = ddi_get_driver_private(dip);
+ VERIFY(tran != NULL);
+ smrt = tran->tran_hba_private;
+ VERIFY(smrt != NULL);
+
+ addr = scsi_hba_iport_unit_address(dip);
+ VERIFY(addr != NULL);
+
+ if (strcmp(addr, SMRT_IPORT_VIRT) == 0) {
+ smrt_logvol_hba_teardown(smrt, dip);
+ smrt->smrt_virt_iport = NULL;
+ } else if (strcmp(addr, SMRT_IPORT_PHYS) == 0) {
+ smrt_phys_hba_teardown(smrt, dip);
+ smrt->smrt_phys_iport = NULL;
+ } else {
+ return (DDI_FAILURE);
+ }
+
+ return (DDI_SUCCESS);
+}
+
+static int
+smrt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ uint32_t instance;
+ smrt_t *smrt;
+ boolean_t check_for_interrupts = B_FALSE;
+ int r;
+ char taskq_name[64];
+
+ if (scsi_hba_iport_unit_address(dip) != NULL)
+ return (smrt_iport_attach(dip, cmd));
+
+ if (cmd != DDI_ATTACH) {
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Allocate the per-controller soft state object and get
+ * a pointer to it.
+ */
+ instance = ddi_get_instance(dip);
+ if (ddi_soft_state_zalloc(smrt_state, instance) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "could not allocate soft state");
+ return (DDI_FAILURE);
+ }
+ if ((smrt = ddi_get_soft_state(smrt_state, instance)) == NULL) {
+ dev_err(dip, CE_WARN, "could not get soft state");
+ ddi_soft_state_free(smrt_state, instance);
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Initialise per-controller state object.
+ */
+ smrt->smrt_dip = dip;
+ smrt->smrt_instance = instance;
+ smrt->smrt_next_tag = SMRT_MIN_TAG_NUMBER;
+ list_create(&smrt->smrt_commands, sizeof (smrt_command_t),
+ offsetof(smrt_command_t, smcm_link));
+ list_create(&smrt->smrt_finishq, sizeof (smrt_command_t),
+ offsetof(smrt_command_t, smcm_link_finish));
+ list_create(&smrt->smrt_abortq, sizeof (smrt_command_t),
+ offsetof(smrt_command_t, smcm_link_abort));
+ list_create(&smrt->smrt_volumes, sizeof (smrt_volume_t),
+ offsetof(smrt_volume_t, smlv_link));
+ list_create(&smrt->smrt_physicals, sizeof (smrt_physical_t),
+ offsetof(smrt_physical_t, smpt_link));
+ list_create(&smrt->smrt_targets, sizeof (smrt_target_t),
+ offsetof(smrt_target_t, smtg_link_ctlr));
+ avl_create(&smrt->smrt_inflight, smrt_command_comparator,
+ sizeof (smrt_command_t), offsetof(smrt_command_t,
+ smcm_node));
+ cv_init(&smrt->smrt_cv_finishq, NULL, CV_DRIVER, NULL);
+
+ smrt->smrt_init_level |= SMRT_INITLEVEL_BASIC;
+
+ /*
+ * Perform basic device setup, including identifying the board, mapping
+ * the I2O registers and the Configuration Table.
+ */
+ if (smrt_device_setup(smrt) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "device setup failed");
+ goto fail;
+ }
+
+ /*
+ * Select a Transport Method (e.g. Simple or Performant) and update
+ * the Configuration Table. This function also waits for the
+ * controller to become ready.
+ */
+ if (smrt_ctlr_init(smrt) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "controller initialisation failed");
+ goto fail;
+ }
+
+ /*
+ * Each controller may have a different Scatter/Gather Element count.
+ * Configure a per-controller set of DMA attributes with the
+ * appropriate S/G size.
+ */
+ VERIFY(smrt->smrt_sg_cnt > 0);
+ smrt->smrt_dma_attr = smrt_dma_attr_template;
+ smrt->smrt_dma_attr.dma_attr_sgllen = smrt->smrt_sg_cnt;
+
+ /*
+ * Now that we have selected a Transport Method, we can configure
+ * the appropriate interrupt handlers.
+ */
+ if (smrt_interrupts_setup(smrt) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "interrupt handler setup failed");
+ goto fail;
+ }
+
+ /*
+ * Now that we have the correct interrupt priority, we can initialise
+ * the mutex. This must be done before the interrupt handler is
+ * enabled.
+ */
+ mutex_init(&smrt->smrt_mutex, NULL, MUTEX_DRIVER,
+ DDI_INTR_PRI(smrt->smrt_interrupt_pri));
+ smrt->smrt_init_level |= SMRT_INITLEVEL_MUTEX;
+
+ /*
+ * From this point forward, the controller is able to accept commands
+ * and (at least by polling) return command submissions. Setting this
+ * flag allows the rest of the driver to interact with the device.
+ */
+ smrt->smrt_status |= SMRT_CTLR_STATUS_RUNNING;
+
+ if (smrt_interrupts_enable(smrt) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "interrupt handler could not be enabled");
+ goto fail;
+ }
+
+ if (smrt_ctrl_hba_setup(smrt) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "SCSI framework setup failed");
+ goto fail;
+ }
+
+ /*
+ * Set the appropriate Interrupt Mask Register bits to start
+ * command completion interrupts from the controller.
+ */
+ smrt_intr_set(smrt, B_TRUE);
+ check_for_interrupts = B_TRUE;
+
+ /*
+ * Register the maintenance routine for periodic execution:
+ */
+ smrt->smrt_periodic = ddi_periodic_add(smrt_periodic, smrt,
+ SMRT_PERIODIC_RATE * NANOSEC, DDI_IPL_0);
+ smrt->smrt_init_level |= SMRT_INITLEVEL_PERIODIC;
+
+ (void) snprintf(taskq_name, sizeof (taskq_name), "smrt_discover_%u",
+ instance);
+ smrt->smrt_discover_taskq = ddi_taskq_create(smrt->smrt_dip, taskq_name,
+ 1, TASKQ_DEFAULTPRI, 0);
+ if (smrt->smrt_discover_taskq == NULL) {
+ dev_err(dip, CE_WARN, "failed to create discovery task queue");
+ goto fail;
+ }
+ smrt->smrt_init_level |= SMRT_INITLEVEL_TASKQ;
+
+ if ((r = smrt_event_init(smrt)) != 0) {
+ dev_err(dip, CE_WARN, "could not initialize event subsystem "
+ "(%d)", r);
+ goto fail;
+ }
+ smrt->smrt_init_level |= SMRT_INITLEVEL_ASYNC_EVENT;
+
+ if (scsi_hba_iport_register(dip, SMRT_IPORT_VIRT) != DDI_SUCCESS)
+ goto fail;
+
+ if (scsi_hba_iport_register(dip, SMRT_IPORT_PHYS) != DDI_SUCCESS)
+ goto fail;
+
+ /*
+ * Announce the attachment of this controller.
+ */
+ ddi_report_dev(dip);
+
+ return (DDI_SUCCESS);
+
+fail:
+ if (check_for_interrupts) {
+ if (smrt->smrt_stats.smrts_claimed_interrupts == 0) {
+ dev_err(dip, CE_WARN, "controller did not interrupt "
+ "during attach");
+ }
+ }
+ smrt_cleanup(smrt);
+ return (DDI_FAILURE);
+}
+
+static int
+smrt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ scsi_hba_tran_t *tran = (scsi_hba_tran_t *)ddi_get_driver_private(dip);
+ smrt_t *smrt = (smrt_t *)tran->tran_hba_private;
+
+ if (scsi_hba_iport_unit_address(dip) != NULL)
+ return (smrt_iport_detach(dip, cmd));
+
+ if (cmd != DDI_DETACH) {
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * First, check to make sure that all SCSI framework targets have
+ * detached.
+ */
+ mutex_enter(&smrt->smrt_mutex);
+ if (!list_is_empty(&smrt->smrt_targets)) {
+ mutex_exit(&smrt->smrt_mutex);
+ dev_err(smrt->smrt_dip, CE_WARN, "cannot detach; targets still "
+ "using HBA");
+ return (DDI_FAILURE);
+ }
+
+ if (smrt->smrt_virt_iport != NULL || smrt->smrt_phys_iport != NULL) {
+ mutex_exit(&smrt->smrt_mutex);
+ dev_err(smrt->smrt_dip, CE_WARN, "cannot detach: iports still "
+ "attached");
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Prevent new targets from attaching now:
+ */
+ smrt->smrt_status |= SMRT_CTLR_STATUS_DETACHING;
+ mutex_exit(&smrt->smrt_mutex);
+
+ /*
+ * Clean up all remaining resources.
+ */
+ smrt_cleanup(smrt);
+
+ return (DDI_SUCCESS);
+}
+
+static int
+smrt_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
+ int *rval)
+{
+ int inst = MINOR2INST(getminor(dev));
+ int status;
+
+ if (secpolicy_sys_config(credp, B_FALSE) != 0) {
+ return (EPERM);
+ }
+
+ /*
+ * Ensure that we have a soft state object for this instance.
+ */
+ if (ddi_get_soft_state(smrt_state, inst) == NULL) {
+ return (ENXIO);
+ }
+
+ switch (cmd) {
+ default:
+ status = scsi_hba_ioctl(dev, cmd, arg, mode, credp, rval);
+ break;
+ }
+
+ return (status);
+}
+
+static void
+smrt_cleanup(smrt_t *smrt)
+{
+ if (smrt->smrt_init_level & SMRT_INITLEVEL_ASYNC_EVENT) {
+ smrt_event_fini(smrt);
+ smrt->smrt_init_level &= ~SMRT_INITLEVEL_ASYNC_EVENT;
+ }
+
+ smrt_interrupts_teardown(smrt);
+
+ if (smrt->smrt_init_level & SMRT_INITLEVEL_TASKQ) {
+ ddi_taskq_destroy(smrt->smrt_discover_taskq);
+ smrt->smrt_discover_taskq = NULL;
+ smrt->smrt_init_level &= ~SMRT_INITLEVEL_TASKQ;
+ }
+
+ if (smrt->smrt_init_level & SMRT_INITLEVEL_PERIODIC) {
+ ddi_periodic_delete(smrt->smrt_periodic);
+ smrt->smrt_init_level &= ~SMRT_INITLEVEL_PERIODIC;
+ }
+
+ smrt_ctrl_hba_teardown(smrt);
+
+ smrt_ctlr_teardown(smrt);
+
+ smrt_device_teardown(smrt);
+
+ if (smrt->smrt_init_level & SMRT_INITLEVEL_BASIC) {
+ smrt_logvol_teardown(smrt);
+ smrt_phys_teardown(smrt);
+
+ cv_destroy(&smrt->smrt_cv_finishq);
+
+ VERIFY(list_is_empty(&smrt->smrt_commands));
+ list_destroy(&smrt->smrt_commands);
+ list_destroy(&smrt->smrt_finishq);
+ list_destroy(&smrt->smrt_abortq);
+
+ VERIFY(list_is_empty(&smrt->smrt_volumes));
+ list_destroy(&smrt->smrt_volumes);
+
+ VERIFY(list_is_empty(&smrt->smrt_physicals));
+ list_destroy(&smrt->smrt_physicals);
+
+ VERIFY(list_is_empty(&smrt->smrt_targets));
+ list_destroy(&smrt->smrt_targets);
+
+ VERIFY(avl_is_empty(&smrt->smrt_inflight));
+ avl_destroy(&smrt->smrt_inflight);
+
+ smrt->smrt_init_level &= ~SMRT_INITLEVEL_BASIC;
+ }
+
+ if (smrt->smrt_init_level & SMRT_INITLEVEL_MUTEX) {
+ mutex_destroy(&smrt->smrt_mutex);
+
+ smrt->smrt_init_level &= ~SMRT_INITLEVEL_MUTEX;
+ }
+
+ VERIFY0(smrt->smrt_init_level);
+
+ ddi_soft_state_free(smrt_state, ddi_get_instance(smrt->smrt_dip));
+}
+
+/*
+ * Comparator for the "smrt_inflight" AVL tree in a "smrt_t". This AVL tree
+ * allows a tag ID to be mapped back to the relevant "smrt_command_t".
+ */
+static int
+smrt_command_comparator(const void *lp, const void *rp)
+{
+ const smrt_command_t *l = lp;
+ const smrt_command_t *r = rp;
+
+ if (l->smcm_tag > r->smcm_tag) {
+ return (1);
+ } else if (l->smcm_tag < r->smcm_tag) {
+ return (-1);
+ } else {
+ return (0);
+ }
+}
diff --git a/usr/src/uts/common/io/scsi/adapters/smrt/smrt.conf b/usr/src/uts/common/io/scsi/adapters/smrt/smrt.conf
new file mode 100644
index 0000000000..758ecd0779
--- /dev/null
+++ b/usr/src/uts/common/io/scsi/adapters/smrt/smrt.conf
@@ -0,0 +1,16 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2016 Joyent, Inc.
+#
+
+scsi-no-quiesce=1;
diff --git a/usr/src/uts/common/io/scsi/adapters/smrt/smrt_ciss.c b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_ciss.c
new file mode 100644
index 0000000000..8da9ac9038
--- /dev/null
+++ b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_ciss.c
@@ -0,0 +1,2023 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+#include <sys/scsi/adapters/smrt/smrt.h>
+
+/*
+ * Discovery, Resets, Periodics, and Events
+ * ----------------------------------------
+ *
+ * Discovery is the act of figuring out what logical and physical volumes exist
+ * under the controller. Discovery happens in response to the following events:
+ *
+ * o iports for virtual and physical devices being attached
+ * o Controller event notifications indicating potential topology changes
+ * o After a reset of the controller, before we can perform I/O again
+ *
+ * Because we have to perform discovery after a reset, which can happen during
+ * panic(), that also means that discovery may be run in panic context. We
+ * also need to emphasize the need for discovery to happen after a controller
+ * reset. Once a reset is initiated, we cannot be certain about the addresses
+ * of any of the existing targets until the reset has completed. The driver
+ * performs I/Os to addresses that the controller provides. The controller
+ * specification says that these addresses may change after a controller reset.
+ *
+ * Unfortunately, all of this combined means that making sure we can correctly
+ * run discovery is somewhat complicated. In non-panic contexts, discovery is
+ * always run from a taskq. We'll kick off the discovery in the taskq if
+ * nothing is pending at that time. The state is managed by bits in the
+ * smrt_status member of the smrt_t. There are four bits at this time:
+ *
+ * SMRT_CTLR_DISCOVERY_REQUESTED This flag indicates that something has
+ * requested that a discovery be performed.
+ * If no flags are set when this is set,
+ * then we will kick off discovery. All
+ * discovery requests are initiated via the
+ * smrt_discover_request() function.
+ *
+ * SMRT_CTLR_DISCOVERY_RUNNING This flag is set at the start of us
+ * running a discovery. It is removed when
+ * discovery finishes.
+ *
+ * SMRT_CTLR_DISCOVERY_PERIODIC This flag is set in a number of
+ * circumstances, which will be described
+ * in a subsequent section. This indicates
+ * that the periodic must kick off the
+ * discovery process.
+ *
+ * SMRT_CTLR_DISCOVERY_REQUIRED This flag indicates that at some point a
+ * controller reset occurred and we need to
+ * have a successful discovery to finish
+ * the act of resetting and allowing I/O to
+ * continue.
+ *
+ * In general, a request to discover kicks off the taskq to discover entries, if
+ * it hasn't already been requested or started. This also allows us to coalesce
+ * multiple requests, if needed. Note that if a request comes in when a
+ * discovery is ongoing, we do not kick off discovery again. Instead, we set
+ * the SMRT_CTLR_DISCOVERY_REQUESTED flag which will rerun discovery after the
+ * initial pass has completed.
+ *
+ * When a discovery starts, the first thing it does is clear the
+ * SMRT_CTLR_DISCOVERY_REQUESTED flag. This is important, because any
+ * additional requests for discovery that come in after this has started likely
+ * indicate that we've missed something. As such, when the discovery process
+ * finishes, if it sees the REQUESTED flag, then it will need to set the
+ * PERIODIC flag. The PERIODIC flag is used to indicate that we should run
+ * discovery again, but not kick if off immediately. Instead, it should be
+ * driven by the normal periodic behavior.
+ *
+ * If for some reason the act of discovery fails, or we fail to dispatch
+ * discovery due to a transient error, then we will flag PERIODIC so that the
+ * periodic tick will try and run things again.
+ *
+ * Now, we need to talk about SMRT_CTLR_DISCOVERY_REQUIRED. This flag is set
+ * after a reset occurs. The reset thread will be blocked on this.
+ * Importantly, none of the code in the discovery path can ask for a controller
+ * reset at this time. If at the end of a discovery, this flag is set, then we
+ * will signal the reset thread that it should check on its status by
+ * broadcasting on the smrt_cv_finishq. At that point, the reset thread will
+ * continue.
+ *
+ * Panic Context
+ * -------------
+ *
+ * All of this talk of threads and taskqs is well and good, but as an HBA
+ * driver, we have a serious responsibility to try and deal with panic sanely.
+ * In panic context, we will directly call the discovery functions and not poll
+ * for them to occur.
+ *
+ * However, because our discovery relies on the target maps, which aren't safe
+ * for panic context at this time, we have to take a different approach. We
+ * leverage the fact that we have a generation number stored with every
+ * discovery. If we try to do an I/O to a device where the generation doesn't
+ * match, then we know that it disappeared and should not be used. We also
+ * sanity check the model, serial numbers, and WWNs to make sure that these are
+ * the same devices. If they are, then we'll end up updating the address
+ * structures.
+ *
+ * Now, it is possible that when we were panicking, we had a thread that was in
+ * the process of running a discovery or even resetting the system. Once we're
+ * in panic, those threads aren't running, so if they didn't end up producing a
+ * new view of the world that the SCSI framework is using, then it shouldn't
+ * really matter, as we won't have updated the list of devices. Importantly,
+ * once we're in that context, we're not going to be attaching or detaching
+ * targets. If we get a request for one of these targets which has disappeared,
+ * we're going to have to end up giving up.
+ *
+ * Request Attributes
+ * ------------------
+ *
+ * The CISS specification allows for three different kinds of attributes that
+ * describe how requests are queued to the controller. These are:
+ *
+ * HEAD OF QUEUE The request should go to the head of the
+ * controller queue. This is used for resets and
+ * aborts to ensure that they're not blocked behind
+ * additional I/O.
+ *
+ * SIMPLE This queues the request for normal processing.
+ * Commands queued this way are not special with
+ * respect to one another. We use this for all I/O
+ * and discovery commands.
+ *
+ * ORDERED This attribute is used to indicate that commands
+ * should be submitted and processed in some order.
+ * This is used primarily for the event
+ * notification bits so we can ensure that at the
+ * return of a cancellation of the event
+ * notification, that any outstanding request has
+ * been honored.
+ */
+
+static int smrt_ctlr_versions(smrt_t *, uint16_t, smrt_versions_t *);
+static void smrt_discover(void *);
+
+/*
+ * The maximum number of seconds to wait for the controller to come online.
+ */
+unsigned smrt_ciss_init_time = 90;
+
+/*
+ * A tunable that determines the number of events per tick that we'll process
+ * via asynchronous event notification. If this rate is very high, then we will
+ * not submit the event and it will be picked up at the next tick of the
+ * periodic.
+ */
+uint_t smrt_event_intervention_threshold = 1000;
+
+/*
+ * Converts a LUN Address to a BMIC Identifier. The BMIC Identifier is used
+ * when performing various physical commands and generally should stay the same
+ * for a given device across inserts and removals; however, not across
+ * controller resets. These are calculated based on what the CISS specification
+ * calls the 'Level 2' target and bus, which don't have a real meaning in the
+ * SAS world otherwise.
+ */
+uint16_t
+smrt_lun_addr_to_bmic(PhysDevAddr_t *paddr)
+{
+ uint16_t id;
+
+ id = (paddr->Target[1].PeripDev.Bus - 1) << 8;
+ id += paddr->Target[1].PeripDev.Dev;
+
+ return (id);
+}
+
+void
+smrt_write_lun_addr_phys(LUNAddr_t *lun, boolean_t masked, unsigned bus,
+ unsigned target)
+{
+ lun->PhysDev.Mode = masked ? MASK_PERIPHERIAL_DEV_ADDR :
+ PERIPHERIAL_DEV_ADDR;
+
+ lun->PhysDev.TargetId = target;
+ lun->PhysDev.Bus = bus;
+
+ bzero(&lun->PhysDev.Target, sizeof (lun->PhysDev.Target));
+}
+
+/*
+ * According to the CISS Specification, the controller is always addressed in
+ * Mask Perhiperhal mode with a bus and target ID of zero. This is used by
+ * commands that need to write to the controller itself, which is generally
+ * discovery and other commands.
+ */
+void
+smrt_write_controller_lun_addr(LUNAddr_t *lun)
+{
+ smrt_write_lun_addr_phys(lun, B_TRUE, 0, 0);
+}
+
+void
+smrt_write_message_common(smrt_command_t *smcm, uint8_t type, int timeout_secs)
+{
+ switch (type) {
+ case CISS_MSG_ABORT:
+ case CISS_MSG_RESET:
+ case CISS_MSG_NOP:
+ break;
+
+ default:
+ panic("unknown message type");
+ }
+
+ smcm->smcm_va_cmd->Request.Type.Type = CISS_TYPE_MSG;
+ smcm->smcm_va_cmd->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
+ smcm->smcm_va_cmd->Request.Type.Direction = CISS_XFER_NONE;
+ smcm->smcm_va_cmd->Request.Timeout = LE_16(timeout_secs);
+ smcm->smcm_va_cmd->Request.CDBLen = CISS_CDBLEN;
+ smcm->smcm_va_cmd->Request.CDB[0] = type;
+}
+
+void
+smrt_write_message_abort_one(smrt_command_t *smcm, uint32_t tag)
+{
+ smrt_tag_t cisstag;
+
+ /*
+ * When aborting a particular command, the request is addressed
+ * to the controller.
+ */
+ smrt_write_lun_addr_phys(&smcm->smcm_va_cmd->Header.LUN,
+ B_TRUE, 0, 0);
+
+ smrt_write_message_common(smcm, CISS_MSG_ABORT, 0);
+
+ /*
+ * Abort a single command.
+ */
+ smcm->smcm_va_cmd->Request.CDB[1] = CISS_ABORT_TASK;
+
+ /*
+ * The CISS Specification says that the tag value for a task-level
+ * abort should be in the CDB in bytes 4-11.
+ */
+ bzero(&cisstag, sizeof (cisstag));
+ cisstag.tag_value = tag;
+ bcopy(&cisstag, &smcm->smcm_va_cmd->Request.CDB[4],
+ sizeof (cisstag));
+}
+
+void
+smrt_write_message_abort_all(smrt_command_t *smcm, LUNAddr_t *addr)
+{
+ /*
+ * When aborting all tasks for a particular Logical Volume,
+ * the command is addressed not to the controller but to
+ * the Volume itself.
+ */
+ smcm->smcm_va_cmd->Header.LUN = *addr;
+
+ smrt_write_message_common(smcm, CISS_MSG_ABORT, 0);
+
+ /*
+ * Abort all commands for a particular Logical Volume.
+ */
+ smcm->smcm_va_cmd->Request.CDB[1] = CISS_ABORT_TASKSET;
+}
+
+void
+smrt_write_message_event_notify(smrt_command_t *smcm)
+{
+ smrt_event_notify_req_t senr;
+
+ smrt_write_controller_lun_addr(&smcm->smcm_va_cmd->Header.LUN);
+
+ smcm->smcm_va_cmd->Request.Type.Type = CISS_TYPE_CMD;
+ smcm->smcm_va_cmd->Request.Type.Attribute = CISS_ATTR_ORDERED;
+ smcm->smcm_va_cmd->Request.Type.Direction = CISS_XFER_READ;
+ smcm->smcm_va_cmd->Request.Timeout = 0;
+ smcm->smcm_va_cmd->Request.CDBLen = sizeof (senr);
+
+ bzero(&senr, sizeof (senr));
+ senr.senr_opcode = CISS_SCMD_READ;
+ senr.senr_subcode = CISS_BMIC_NOTIFY_ON_EVENT;
+ senr.senr_flags = BE_32(0);
+ senr.senr_size = BE_32(SMRT_EVENT_NOTIFY_BUFLEN);
+
+ bcopy(&senr, &smcm->smcm_va_cmd->Request.CDB[0],
+ MIN(CISS_CDBLEN, sizeof (senr)));
+}
+
+void
+smrt_write_message_cancel_event_notify(smrt_command_t *smcm)
+{
+ smrt_event_notify_req_t senr;
+
+ smrt_write_controller_lun_addr(&smcm->smcm_va_cmd->Header.LUN);
+
+ smcm->smcm_va_cmd->Request.Type.Type = CISS_TYPE_CMD;
+ smcm->smcm_va_cmd->Request.Type.Attribute = CISS_ATTR_ORDERED;
+ smcm->smcm_va_cmd->Request.Type.Direction = CISS_XFER_WRITE;
+ smcm->smcm_va_cmd->Request.Timeout = LE_16(SMRT_ASYNC_CANCEL_TIMEOUT);
+ smcm->smcm_va_cmd->Request.CDBLen = sizeof (senr);
+
+ bzero(&senr, sizeof (senr));
+ senr.senr_opcode = CISS_SCMD_WRITE;
+ senr.senr_subcode = CISS_BMIC_NOTIFY_ON_EVENT_CANCEL;
+ senr.senr_size = BE_32(SMRT_EVENT_NOTIFY_BUFLEN);
+
+ bcopy(&senr, &smcm->smcm_va_cmd->Request.CDB[0],
+ MIN(CISS_CDBLEN, sizeof (senr)));
+}
+
+void
+smrt_write_message_reset_ctlr(smrt_command_t *smcm)
+{
+ smrt_write_lun_addr_phys(&smcm->smcm_va_cmd->Header.LUN,
+ B_TRUE, 0, 0);
+
+ smrt_write_message_common(smcm, CISS_MSG_RESET, 0);
+
+ smcm->smcm_va_cmd->Request.CDB[1] = CISS_RESET_CTLR;
+}
+
+void
+smrt_write_message_nop(smrt_command_t *smcm, int timeout_secs)
+{
+ /*
+ * No-op messages are always sent to the controller.
+ */
+ smrt_write_lun_addr_phys(&smcm->smcm_va_cmd->Header.LUN,
+ B_TRUE, 0, 0);
+
+ smrt_write_message_common(smcm, CISS_MSG_NOP, timeout_secs);
+}
+
+/*
+ * This routine is executed regularly by ddi_periodic_add(9F). It checks the
+ * health of the controller and looks for submitted commands that have timed
+ * out.
+ */
+void
+smrt_periodic(void *arg)
+{
+ smrt_t *smrt = arg;
+
+ mutex_enter(&smrt->smrt_mutex);
+
+ /*
+ * Before we even check if the controller is running to process
+ * everything else, we must first check if we had a request to kick off
+ * discovery. We do this before the check if the controller is running,
+ * as this may be required to finish a discovery.
+ */
+ if ((smrt->smrt_status & SMRT_CTLR_DISCOVERY_PERIODIC) != 0 &&
+ (smrt->smrt_status & SMRT_CTLR_DISCOVERY_RUNNING) == 0 &&
+ (smrt->smrt_status & SMRT_CTLR_STATUS_RESETTING) == 0) {
+ if (ddi_taskq_dispatch(smrt->smrt_discover_taskq,
+ smrt_discover, smrt, DDI_NOSLEEP) != DDI_SUCCESS) {
+ smrt->smrt_stats.smrts_discovery_tq_errors++;
+ } else {
+ smrt->smrt_status &= ~SMRT_CTLR_DISCOVERY_PERIODIC;
+ }
+ }
+
+ if (!(smrt->smrt_status & SMRT_CTLR_STATUS_RUNNING)) {
+ /*
+ * The device is currently not active, e.g. due to an
+ * in-progress controller reset.
+ */
+ mutex_exit(&smrt->smrt_mutex);
+ return;
+ }
+
+ /*
+ * Check on the health of the controller firmware. Note that if the
+ * controller has locked up, this routine will panic the system.
+ */
+ smrt_lockup_check(smrt);
+
+ /*
+ * Reset the event notification threshold counter.
+ */
+ smrt->smrt_event_count = 0;
+
+ /*
+ * Check inflight commands to see if they have timed out.
+ */
+ for (smrt_command_t *smcm = avl_first(&smrt->smrt_inflight);
+ smcm != NULL; smcm = AVL_NEXT(&smrt->smrt_inflight, smcm)) {
+ if (smcm->smcm_status & SMRT_CMD_STATUS_POLLED) {
+ /*
+ * Polled commands are timed out by the polling
+ * routine.
+ */
+ continue;
+ }
+
+ if (smcm->smcm_status & SMRT_CMD_STATUS_ABORT_SENT) {
+ /*
+ * This command has been aborted; either it will
+ * complete or the controller will be reset.
+ */
+ continue;
+ }
+
+ if (list_link_active(&smcm->smcm_link_abort)) {
+ /*
+ * Already on the abort queue.
+ */
+ continue;
+ }
+
+ if (smcm->smcm_expiry == 0) {
+ /*
+ * This command has no expiry time.
+ */
+ continue;
+ }
+
+ if (gethrtime() > smcm->smcm_expiry) {
+ list_insert_tail(&smrt->smrt_abortq, smcm);
+ smcm->smcm_status |= SMRT_CMD_STATUS_TIMEOUT;
+ }
+ }
+
+ /*
+ * Process the abort queue.
+ */
+ (void) smrt_process_abortq(smrt);
+
+ /*
+ * Check if we have an outstanding event intervention request. Note,
+ * the command in question should always be in a state such that it is
+ * usable by the system here. The command is always prepared again by
+ * the normal event notification path, even if a reset has occurred.
+ * The reset will be processed before we'd ever consider running an
+ * event again. Note, if we fail to submit this, then we leave this for
+ * the next occurrence of the periodic.
+ */
+ if (smrt->smrt_status & SMRT_CTLR_ASYNC_INTERVENTION) {
+ smrt->smrt_stats.smrts_events_intervened++;
+
+ if (smrt_submit(smrt, smrt->smrt_event_cmd) == 0) {
+ smrt->smrt_status &= ~SMRT_CTLR_ASYNC_INTERVENTION;
+ }
+ }
+
+ mutex_exit(&smrt->smrt_mutex);
+}
+
+int
+smrt_retrieve(smrt_t *smrt)
+{
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+
+ switch (smrt->smrt_ctlr_mode) {
+ case SMRT_CTLR_MODE_SIMPLE:
+ smrt_retrieve_simple(smrt);
+ return (DDI_SUCCESS);
+
+ case SMRT_CTLR_MODE_UNKNOWN:
+ break;
+ }
+
+ panic("unknown controller mode");
+ /* LINTED: E_FUNC_NO_RET_VAL */
+}
+
+/*
+ * Grab a new tag number for this command. We aim to avoid reusing tag numbers
+ * as much as possible, so as to avoid spurious double completion from the
+ * controller.
+ */
+static void
+smrt_set_new_tag(smrt_t *smrt, smrt_command_t *smcm)
+{
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+
+ /*
+ * Loop until we find a tag that is not in use. The tag space is
+ * very large (~30 bits) and the maximum number of inflight commands
+ * is comparatively small (~1024 in current controllers).
+ */
+ for (;;) {
+ uint32_t new_tag = smrt->smrt_next_tag;
+
+ if (++smrt->smrt_next_tag > SMRT_MAX_TAG_NUMBER) {
+ smrt->smrt_next_tag = SMRT_MIN_TAG_NUMBER;
+ }
+
+ if (smrt_lookup_inflight(smrt, new_tag) != NULL) {
+ /*
+ * This tag is already used on an inflight command.
+ * Choose another.
+ */
+ continue;
+ }
+
+ /*
+ * Set the tag for the command and also write it into the
+ * appropriate part of the request block.
+ */
+ smcm->smcm_tag = new_tag;
+ smcm->smcm_va_cmd->Header.Tag.tag_value = new_tag;
+ return;
+ }
+}
+
+/*
+ * Submit a command to the controller.
+ */
+int
+smrt_submit(smrt_t *smrt, smrt_command_t *smcm)
+{
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+ VERIFY(smcm->smcm_type != SMRT_CMDTYPE_PREINIT);
+
+ /*
+ * Anything that asks us to ignore the running state of the controller
+ * must be wired up to poll for completion.
+ */
+ if (smcm->smcm_status & SMRT_CMD_IGNORE_RUNNING) {
+ VERIFY(smcm->smcm_status & SMRT_CMD_STATUS_POLLED);
+ }
+
+ /*
+ * If the controller is currently being reset, do not allow command
+ * submission. However, if this is one of the commands needed to finish
+ * reset, as indicated on the command structure, allow it.
+ */
+ if (!(smrt->smrt_status & SMRT_CTLR_STATUS_RUNNING) &&
+ !(smcm->smcm_status & SMRT_CMD_IGNORE_RUNNING)) {
+ return (EIO);
+ }
+
+ /*
+ * Do not allow submission of more concurrent commands than the
+ * controller supports.
+ */
+ if (avl_numnodes(&smrt->smrt_inflight) >= smrt->smrt_maxcmds) {
+ return (EAGAIN);
+ }
+
+ /*
+ * Synchronise the Command Block DMA resources to ensure that the
+ * device has a consistent view before we pass it the command.
+ */
+ if (ddi_dma_sync(smcm->smcm_contig.smdma_dma_handle, 0, 0,
+ DDI_DMA_SYNC_FORDEV) != DDI_SUCCESS) {
+ dev_err(smrt->smrt_dip, CE_PANIC, "DMA sync failure");
+ return (EIO);
+ }
+
+ /*
+ * Ensure that this command is not re-used without issuing a new
+ * tag number and performing any appropriate cleanup.
+ */
+ VERIFY(!(smcm->smcm_status & SMRT_CMD_STATUS_USED));
+ smcm->smcm_status |= SMRT_CMD_STATUS_USED;
+
+ /*
+ * Assign a tag that is not currently in use
+ */
+ smrt_set_new_tag(smrt, smcm);
+
+ /*
+ * Insert this command into the inflight AVL.
+ */
+ avl_index_t where;
+ if (avl_find(&smrt->smrt_inflight, smcm, &where) != NULL) {
+ dev_err(smrt->smrt_dip, CE_PANIC, "duplicate submit tag %x",
+ smcm->smcm_tag);
+ }
+ avl_insert(&smrt->smrt_inflight, smcm, where);
+ if (smrt->smrt_stats.smrts_max_inflight <
+ avl_numnodes(&smrt->smrt_inflight)) {
+ smrt->smrt_stats.smrts_max_inflight =
+ avl_numnodes(&smrt->smrt_inflight);
+ }
+
+ VERIFY(!(smcm->smcm_status & SMRT_CMD_STATUS_INFLIGHT));
+ smcm->smcm_status |= SMRT_CMD_STATUS_INFLIGHT;
+
+ smcm->smcm_time_submit = gethrtime();
+
+ switch (smrt->smrt_ctlr_mode) {
+ case SMRT_CTLR_MODE_SIMPLE:
+ smrt_submit_simple(smrt, smcm);
+ return (0);
+
+ case SMRT_CTLR_MODE_UNKNOWN:
+ break;
+ }
+ panic("unknown controller mode");
+ /* LINTED: E_FUNC_NO_RET_VAL */
+}
+
+static void
+smrt_process_finishq_sync(smrt_command_t *smcm)
+{
+ smrt_t *smrt = smcm->smcm_ctlr;
+
+ if (ddi_dma_sync(smcm->smcm_contig.smdma_dma_handle, 0, 0,
+ DDI_DMA_SYNC_FORCPU) != DDI_SUCCESS) {
+ dev_err(smrt->smrt_dip, CE_PANIC, "finishq DMA sync failure");
+ }
+}
+
+static void
+smrt_process_finishq_one(smrt_command_t *smcm)
+{
+ smrt_t *smrt = smcm->smcm_ctlr;
+
+ VERIFY(!(smcm->smcm_status & SMRT_CMD_STATUS_COMPLETE));
+ smcm->smcm_status |= SMRT_CMD_STATUS_COMPLETE;
+
+ switch (smcm->smcm_type) {
+ case SMRT_CMDTYPE_INTERNAL:
+ cv_broadcast(&smcm->smcm_ctlr->smrt_cv_finishq);
+ return;
+
+ case SMRT_CMDTYPE_SCSA:
+ smrt_hba_complete(smcm);
+ return;
+
+ case SMRT_CMDTYPE_EVENT:
+ smrt_event_complete(smcm);
+ return;
+
+ case SMRT_CMDTYPE_ABORTQ:
+ /*
+ * Abort messages sent as part of abort queue processing
+ * do not require any completion activity.
+ */
+ mutex_exit(&smrt->smrt_mutex);
+ smrt_command_free(smcm);
+ mutex_enter(&smrt->smrt_mutex);
+ return;
+
+ case SMRT_CMDTYPE_PREINIT:
+ dev_err(smrt->smrt_dip, CE_PANIC, "preinit command "
+ "completed after initialisation");
+ return;
+ }
+
+ panic("unknown command type");
+}
+
+/*
+ * Process commands in the completion queue.
+ */
+void
+smrt_process_finishq(smrt_t *smrt)
+{
+ smrt_command_t *smcm;
+
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+
+ while ((smcm = list_remove_head(&smrt->smrt_finishq)) != NULL) {
+ /*
+ * Synchronise the Command Block before we read from it or
+ * free it, to ensure that any writes from the controller are
+ * visible.
+ */
+ smrt_process_finishq_sync(smcm);
+
+ /*
+ * Check if this command was in line to be aborted.
+ */
+ if (list_link_active(&smcm->smcm_link_abort)) {
+ /*
+ * This command was in line, but the controller
+ * subsequently completed the command before we
+ * were able to do so.
+ */
+ list_remove(&smrt->smrt_abortq, smcm);
+ smcm->smcm_status &= ~SMRT_CMD_STATUS_TIMEOUT;
+ }
+
+ /*
+ * Check if this command has been abandoned by the original
+ * submitter. If it has, free it now to avoid a leak.
+ */
+ if (smcm->smcm_status & SMRT_CMD_STATUS_ABANDONED) {
+ mutex_exit(&smrt->smrt_mutex);
+ smrt_command_free(smcm);
+ mutex_enter(&smrt->smrt_mutex);
+ continue;
+ }
+
+ if (smcm->smcm_status & SMRT_CMD_STATUS_POLLED) {
+ /*
+ * This command will be picked up and processed
+ * by "smrt_poll_for()" once the CV is triggered
+ * at the end of processing.
+ */
+ smcm->smcm_status |= SMRT_CMD_STATUS_POLL_COMPLETE;
+ continue;
+ }
+
+ smrt_process_finishq_one(smcm);
+ }
+
+ cv_broadcast(&smrt->smrt_cv_finishq);
+}
+
+/*
+ * Process commands in the abort queue.
+ */
+void
+smrt_process_abortq(smrt_t *smrt)
+{
+ smrt_command_t *smcm;
+ smrt_command_t *abort_smcm = NULL;
+
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+
+ if (list_is_empty(&smrt->smrt_abortq)) {
+ goto out;
+ }
+
+another:
+ mutex_exit(&smrt->smrt_mutex);
+ if ((abort_smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_ABORTQ,
+ KM_NOSLEEP)) == NULL) {
+ /*
+ * No resources available to send abort messages. We will
+ * try again the next time around.
+ */
+ mutex_enter(&smrt->smrt_mutex);
+ goto out;
+ }
+ mutex_enter(&smrt->smrt_mutex);
+
+ while ((smcm = list_remove_head(&smrt->smrt_abortq)) != NULL) {
+ if (!(smcm->smcm_status & SMRT_CMD_STATUS_INFLIGHT)) {
+ /*
+ * This message is not currently inflight, so
+ * no abort is needed.
+ */
+ continue;
+ }
+
+ if (smcm->smcm_status & SMRT_CMD_STATUS_ABORT_SENT) {
+ /*
+ * An abort message has already been sent for
+ * this command.
+ */
+ continue;
+ }
+
+ /*
+ * Send an abort message for the command.
+ */
+ smrt_write_message_abort_one(abort_smcm, smcm->smcm_tag);
+ if (smrt_submit(smrt, abort_smcm) != 0) {
+ /*
+ * The command could not be submitted to the
+ * controller. Put it back in the abort queue
+ * and give up for now.
+ */
+ list_insert_head(&smrt->smrt_abortq, smcm);
+ goto out;
+ }
+ smcm->smcm_status |= SMRT_CMD_STATUS_ABORT_SENT;
+
+ /*
+ * Record some debugging information about the abort we
+ * sent:
+ */
+ smcm->smcm_abort_time = gethrtime();
+ smcm->smcm_abort_tag = abort_smcm->smcm_tag;
+
+ /*
+ * The abort message was sent. Release it and
+ * allocate another command.
+ */
+ abort_smcm = NULL;
+ goto another;
+ }
+
+out:
+ cv_broadcast(&smrt->smrt_cv_finishq);
+ if (abort_smcm != NULL) {
+ mutex_exit(&smrt->smrt_mutex);
+ smrt_command_free(abort_smcm);
+ mutex_enter(&smrt->smrt_mutex);
+ }
+}
+
+int
+smrt_poll_for(smrt_t *smrt, smrt_command_t *smcm)
+{
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+ VERIFY(smcm->smcm_status & SMRT_CMD_STATUS_POLLED);
+
+ while (!(smcm->smcm_status & SMRT_CMD_STATUS_POLL_COMPLETE)) {
+ if (smcm->smcm_expiry != 0) {
+ /*
+ * This command has an expiry time. Check to see
+ * if it has already passed:
+ */
+ if (smcm->smcm_expiry < gethrtime()) {
+ return (ETIMEDOUT);
+ }
+ }
+
+ if (ddi_in_panic()) {
+ /*
+ * When the system is panicking, there are no
+ * interrupts or other threads. Drive the polling loop
+ * on our own, but with a small delay to avoid
+ * aggrevating the controller while we're trying to
+ * dump.
+ */
+ (void) smrt_retrieve(smrt);
+ smrt_process_finishq(smrt);
+ drv_usecwait(100);
+ continue;
+ }
+
+ /*
+ * Wait for command completion to return through the regular
+ * interrupt handling path.
+ */
+ if (smcm->smcm_expiry == 0) {
+ cv_wait(&smrt->smrt_cv_finishq, &smrt->smrt_mutex);
+ } else {
+ /*
+ * Wait only until the expiry time for this command.
+ */
+ (void) cv_timedwait_sig_hrtime(&smrt->smrt_cv_finishq,
+ &smrt->smrt_mutex, smcm->smcm_expiry);
+ }
+ }
+
+ /*
+ * Fire the completion callback for this command. The callback
+ * is responsible for freeing the command, so it may not be
+ * referenced again once this call returns.
+ */
+ smrt_process_finishq_one(smcm);
+
+ return (0);
+}
+
+void
+smrt_intr_set(smrt_t *smrt, boolean_t enabled)
+{
+ /*
+ * Read the Interrupt Mask Register.
+ */
+ uint32_t imr = smrt_get32(smrt, CISS_I2O_INTERRUPT_MASK);
+
+ switch (smrt->smrt_ctlr_mode) {
+ case SMRT_CTLR_MODE_SIMPLE:
+ if (enabled) {
+ imr &= ~CISS_IMR_BIT_SIMPLE_INTR_DISABLE;
+ } else {
+ imr |= CISS_IMR_BIT_SIMPLE_INTR_DISABLE;
+ }
+ smrt_put32(smrt, CISS_I2O_INTERRUPT_MASK, imr);
+ return;
+
+ case SMRT_CTLR_MODE_UNKNOWN:
+ break;
+ }
+ panic("unknown controller mode");
+}
+
+/*
+ * Signal to the controller that we have updated the Configuration Table by
+ * writing to the Inbound Doorbell Register. The controller will, after some
+ * number of seconds, acknowledge this by clearing the bit.
+ *
+ * If successful, return DDI_SUCCESS. If the controller takes too long to
+ * acknowledge, return DDI_FAILURE.
+ */
+int
+smrt_cfgtbl_flush(smrt_t *smrt)
+{
+ /*
+ * Read the current value of the Inbound Doorbell Register.
+ */
+ uint32_t idr = smrt_get32(smrt, CISS_I2O_INBOUND_DOORBELL);
+
+ /*
+ * Signal the Configuration Table change to the controller.
+ */
+ idr |= CISS_IDR_BIT_CFGTBL_CHANGE;
+ smrt_put32(smrt, CISS_I2O_INBOUND_DOORBELL, idr);
+
+ /*
+ * Wait for the controller to acknowledge the change.
+ */
+ for (unsigned i = 0; i < smrt_ciss_init_time; i++) {
+ idr = smrt_get32(smrt, CISS_I2O_INBOUND_DOORBELL);
+
+ if ((idr & CISS_IDR_BIT_CFGTBL_CHANGE) == 0) {
+ return (DDI_SUCCESS);
+ }
+
+ /*
+ * Wait for one second before trying again.
+ */
+ delay(drv_usectohz(1000000));
+ }
+
+ dev_err(smrt->smrt_dip, CE_WARN, "time out expired before controller "
+ "configuration completed");
+ return (DDI_FAILURE);
+}
+
+int
+smrt_cfgtbl_transport_has_support(smrt_t *smrt, int xport)
+{
+ VERIFY(xport == CISS_CFGTBL_XPORT_SIMPLE);
+
+ /*
+ * Read the current value of the "Supported Transport Methods" field in
+ * the Configuration Table.
+ */
+ uint32_t xport_active = ddi_get32(smrt->smrt_ct_handle,
+ &smrt->smrt_ct->TransportSupport);
+
+ /*
+ * Check that the desired transport method is supported by the
+ * controller:
+ */
+ if ((xport_active & xport) == 0) {
+ dev_err(smrt->smrt_dip, CE_WARN, "controller does not support "
+ "method \"%s\"", xport == CISS_CFGTBL_XPORT_SIMPLE ?
+ "simple" : "performant");
+ return (DDI_FAILURE);
+ }
+
+ return (DDI_SUCCESS);
+}
+
+void
+smrt_cfgtbl_transport_set(smrt_t *smrt, int xport)
+{
+ VERIFY(xport == CISS_CFGTBL_XPORT_SIMPLE);
+
+ ddi_put32(smrt->smrt_ct_handle, &smrt->smrt_ct->TransportRequest,
+ xport);
+}
+
+int
+smrt_cfgtbl_transport_confirm(smrt_t *smrt, int xport)
+{
+ VERIFY(xport == CISS_CFGTBL_XPORT_SIMPLE);
+
+ /*
+ * Read the current value of the TransportActive field in the
+ * Configuration Table.
+ */
+ uint32_t xport_active = ddi_get32(smrt->smrt_ct_handle,
+ &smrt->smrt_ct->TransportActive);
+
+ /*
+ * Check that the desired transport method is now active:
+ */
+ if ((xport_active & xport) == 0) {
+ dev_err(smrt->smrt_dip, CE_WARN, "failed to enable transport "
+ "method \"%s\"", xport == CISS_CFGTBL_XPORT_SIMPLE ?
+ "simple" : "performant");
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Ensure that the controller is now ready to accept commands.
+ */
+ if ((xport_active & CISS_CFGTBL_READY_FOR_COMMANDS) == 0) {
+ dev_err(smrt->smrt_dip, CE_WARN, "controller not ready to "
+ "accept commands");
+ return (DDI_FAILURE);
+ }
+
+ return (DDI_SUCCESS);
+}
+
+uint32_t
+smrt_ctlr_get_maxsgelements(smrt_t *smrt)
+{
+ return (ddi_get32(smrt->smrt_ct_handle, &smrt->smrt_ct->MaxSGElements));
+}
+
+uint32_t
+smrt_ctlr_get_cmdsoutmax(smrt_t *smrt)
+{
+ return (ddi_get32(smrt->smrt_ct_handle, &smrt->smrt_ct->CmdsOutMax));
+}
+
+static uint32_t
+smrt_ctlr_get_hostdrvsup(smrt_t *smrt)
+{
+ return (ddi_get32(smrt->smrt_ct_handle,
+ &smrt->smrt_ct->HostDrvrSupport));
+}
+
+int
+smrt_ctlr_init(smrt_t *smrt)
+{
+ uint8_t signature[4] = { 'C', 'I', 'S', 'S' };
+ int e;
+
+ if ((e = smrt_ctlr_wait_for_state(smrt,
+ SMRT_WAIT_STATE_READY)) != DDI_SUCCESS) {
+ return (e);
+ }
+
+ /*
+ * The configuration table contains an ASCII signature ("CISS") which
+ * should be checked as we initialise the controller.
+ * See: "9.1 Configuration Table" in CISS Specification.
+ */
+ for (unsigned i = 0; i < 4; i++) {
+ if (ddi_get8(smrt->smrt_ct_handle,
+ &smrt->smrt_ct->Signature[i]) != signature[i]) {
+ dev_err(smrt->smrt_dip, CE_WARN, "invalid signature "
+ "detected");
+ return (DDI_FAILURE);
+ }
+ }
+
+ /*
+ * Initialise an appropriate Transport Method. For now, this driver
+ * only supports the "Simple" method.
+ */
+ if ((e = smrt_ctlr_init_simple(smrt)) != DDI_SUCCESS) {
+ return (e);
+ }
+
+ /*
+ * Save some common feature support bitfields.
+ */
+ smrt->smrt_host_support = smrt_ctlr_get_hostdrvsup(smrt);
+ smrt->smrt_bus_support = ddi_get32(smrt->smrt_ct_handle,
+ &smrt->smrt_ct->BusTypes);
+
+ /*
+ * Read initial controller heartbeat value and mark the current
+ * reading time.
+ */
+ smrt->smrt_last_heartbeat = ddi_get32(smrt->smrt_ct_handle,
+ &smrt->smrt_ct->HeartBeat);
+ smrt->smrt_last_heartbeat_time = gethrtime();
+
+ /*
+ * Determine the firmware version of the controller so that we can
+ * select which type of interrupts to use.
+ */
+ if ((e = smrt_ctlr_versions(smrt, SMRT_DISCOVER_TIMEOUT,
+ &smrt->smrt_versions)) != 0) {
+ dev_err(smrt->smrt_dip, CE_WARN, "could not identify "
+ "controller (%d)", e);
+ return (DDI_FAILURE);
+ }
+
+ dev_err(smrt->smrt_dip, CE_NOTE, "!firmware rev %s",
+ smrt->smrt_versions.smrtv_firmware_rev);
+
+ return (DDI_SUCCESS);
+}
+
+void
+smrt_ctlr_teardown(smrt_t *smrt)
+{
+ smrt->smrt_status &= ~SMRT_CTLR_STATUS_RUNNING;
+
+ switch (smrt->smrt_ctlr_mode) {
+ case SMRT_CTLR_MODE_SIMPLE:
+ smrt_ctlr_teardown_simple(smrt);
+ return;
+
+ case SMRT_CTLR_MODE_UNKNOWN:
+ return;
+ }
+
+ panic("unknown controller mode");
+}
+
+int
+smrt_ctlr_wait_for_state(smrt_t *smrt, smrt_wait_state_t state)
+{
+ unsigned wait_usec = 100 * 1000;
+ unsigned wait_count = SMRT_WAIT_DELAY_SECONDS * 1000000 / wait_usec;
+
+ VERIFY(state == SMRT_WAIT_STATE_READY ||
+ state == SMRT_WAIT_STATE_UNREADY);
+
+ /*
+ * Read from the Scratchpad Register until the expected ready signature
+ * is detected. This behaviour is not described in the CISS
+ * specification.
+ *
+ * If the device is not in the desired state immediately, sleep for a
+ * second and try again. If the device has not become ready in 300
+ * seconds, give up.
+ */
+ for (unsigned i = 0; i < wait_count; i++) {
+ uint32_t spr = smrt_get32(smrt, CISS_I2O_SCRATCHPAD);
+
+ switch (state) {
+ case SMRT_WAIT_STATE_READY:
+ if (spr == CISS_SCRATCHPAD_INITIALISED) {
+ return (DDI_SUCCESS);
+ }
+ break;
+
+ case SMRT_WAIT_STATE_UNREADY:
+ if (spr != CISS_SCRATCHPAD_INITIALISED) {
+ return (DDI_SUCCESS);
+ }
+ break;
+ }
+
+ if (ddi_in_panic()) {
+ /*
+ * There is no sleep for the panicking, so we
+ * must spin wait:
+ */
+ drv_usecwait(wait_usec);
+ } else {
+ /*
+ * Wait for a quarter second and try again.
+ */
+ delay(drv_usectohz(wait_usec));
+ }
+ }
+
+ dev_err(smrt->smrt_dip, CE_WARN, "time out waiting for controller "
+ "to enter state \"%s\"", state == SMRT_WAIT_STATE_READY ?
+ "ready": "unready");
+ return (DDI_FAILURE);
+}
+
+void
+smrt_lockup_check(smrt_t *smrt)
+{
+ /*
+ * Read the current controller heartbeat value.
+ */
+ uint32_t heartbeat = ddi_get32(smrt->smrt_ct_handle,
+ &smrt->smrt_ct->HeartBeat);
+
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+
+ /*
+ * Check to see if the value is the same as last time we looked:
+ */
+ if (heartbeat != smrt->smrt_last_heartbeat) {
+ /*
+ * The heartbeat value has changed, which suggests that the
+ * firmware in the controller has not yet come to a complete
+ * stop. Record the new value, as well as the current time.
+ */
+ smrt->smrt_last_heartbeat = heartbeat;
+ smrt->smrt_last_heartbeat_time = gethrtime();
+ return;
+ }
+
+ /*
+ * The controller _might_ have been able to signal to us that is
+ * has locked up. This is a truly unfathomable state of affairs:
+ * If the firmware can tell it has flown off the rails, why not
+ * simply reset the controller?
+ */
+ uint32_t odr = smrt_get32(smrt, CISS_I2O_OUTBOUND_DOORBELL_STATUS);
+ uint32_t spr = smrt_get32(smrt, CISS_I2O_SCRATCHPAD);
+ if ((odr & CISS_ODR_BIT_LOCKUP) != 0) {
+ dev_err(smrt->smrt_dip, CE_PANIC, "HP SmartArray firmware has "
+ "reported a critical fault (odr %08x spr %08x)",
+ odr, spr);
+ }
+
+ if (gethrtime() > smrt->smrt_last_heartbeat_time + 60 * NANOSEC) {
+ dev_err(smrt->smrt_dip, CE_PANIC, "HP SmartArray firmware has "
+ "stopped responding (odr %08x spr %08x)",
+ odr, spr);
+ }
+}
+
+/*
+ * Probe the controller with the IDENTIFY CONTROLLER request. This is a BMIC
+ * command, so it must be submitted to the controller and we must poll for its
+ * completion. This functionality is only presently used during controller
+ * initialisation, so it uses the special pre-initialisation path for command
+ * allocation and submission.
+ */
+static int
+smrt_ctlr_identify(smrt_t *smrt, uint16_t timeout,
+ smrt_identify_controller_t *resp)
+{
+ smrt_command_t *smcm;
+ smrt_identify_controller_req_t smicr;
+ int r;
+ size_t sz;
+
+ /*
+ * Allocate a command with a data buffer; the controller will fill it
+ * with identification information. There is some suggestion in the
+ * firmware-level specification that the buffer length should be a
+ * multiple of 512 bytes for some controllers, so we round up.
+ */
+ sz = P2ROUNDUP_TYPED(sizeof (*resp), 512, size_t);
+ if ((smcm = smrt_command_alloc_preinit(smrt, sz, KM_SLEEP)) == NULL) {
+ return (ENOMEM);
+ }
+
+ smrt_write_controller_lun_addr(&smcm->smcm_va_cmd->Header.LUN);
+
+ smcm->smcm_va_cmd->Request.CDBLen = sizeof (smicr);
+ smcm->smcm_va_cmd->Request.Timeout = timeout;
+ smcm->smcm_va_cmd->Request.Type.Type = CISS_TYPE_CMD;
+ smcm->smcm_va_cmd->Request.Type.Attribute = CISS_ATTR_SIMPLE;
+ smcm->smcm_va_cmd->Request.Type.Direction = CISS_XFER_READ;
+
+ /*
+ * Construct the IDENTIFY CONTROLLER request CDB. Note that any
+ * reserved fields in the request must be filled with zeroes.
+ */
+ bzero(&smicr, sizeof (smicr));
+ smicr.smicr_opcode = CISS_SCMD_BMIC_READ;
+ smicr.smicr_lun = 0;
+ smicr.smicr_command = CISS_BMIC_IDENTIFY_CONTROLLER;
+ bcopy(&smicr, &smcm->smcm_va_cmd->Request.CDB[0],
+ MIN(CISS_CDBLEN, sizeof (smicr)));
+
+ /*
+ * Send the command to the device and poll for its completion.
+ */
+ smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
+ smcm->smcm_expiry = gethrtime() + timeout * NANOSEC;
+ if ((r = smrt_preinit_command_simple(smrt, smcm)) != 0) {
+ VERIFY3S(r, ==, ETIMEDOUT);
+ VERIFY0(smcm->smcm_status & SMRT_CMD_STATUS_POLL_COMPLETE);
+
+ /*
+ * This command timed out, but the driver is not presently
+ * initialised to the point where we can try to abort it.
+ * The command was created with the PREINIT type, so it
+ * does not appear in the global command tracking list.
+ * In order to avoid problems with DMA from the controller,
+ * we have to leak the command allocation.
+ */
+ smcm = NULL;
+ goto out;
+ }
+
+ if (smcm->smcm_status & SMRT_CMD_STATUS_RESET_SENT) {
+ /*
+ * The controller was reset while we were trying to identify
+ * it. Report failure.
+ */
+ r = EIO;
+ goto out;
+ }
+
+ if (smcm->smcm_status & SMRT_CMD_STATUS_ERROR) {
+ ErrorInfo_t *ei = smcm->smcm_va_err;
+
+ if (ei->CommandStatus != CISS_CMD_DATA_UNDERRUN) {
+ dev_err(smrt->smrt_dip, CE_WARN, "identify "
+ "controller error: status 0x%x",
+ ei->CommandStatus);
+ r = EIO;
+ goto out;
+ }
+ }
+
+ if (resp != NULL) {
+ /*
+ * Copy the identify response out for the caller.
+ */
+ bcopy(smcm->smcm_internal->smcmi_va, resp, sizeof (*resp));
+ }
+
+ r = 0;
+
+out:
+ if (smcm != NULL) {
+ smrt_command_free(smcm);
+ }
+ return (r);
+}
+
+/*
+ * The firmware versions in an IDENTIFY CONTROLLER response generally take
+ * the form of a four byte ASCII string containing a dotted decimal version
+ * number; e.g., "8.00".
+ *
+ * This function sanitises the firmware version, replacing unexpected
+ * values with a question mark.
+ */
+static void
+smrt_copy_firmware_version(uint8_t *src, char *dst)
+{
+ for (unsigned i = 0; i < 4; i++) {
+ /*
+ * Make sure that this is a 7-bit clean ASCII value.
+ */
+ char c = src[i] <= 0x7f ? (char)(src[i] & 0x7f) : '?';
+
+ if (isalnum(c) || c == '.' || c == ' ') {
+ dst[i] = c;
+ } else {
+ dst[i] = '?';
+ }
+ }
+ dst[4] = '\0';
+}
+
+/*
+ * Using an IDENTIFY CONTROLLER request, determine firmware and controller
+ * version details. See the comments for "smrt_ctlr_identify()" for more
+ * details about calling context.
+ */
+static int
+smrt_ctlr_versions(smrt_t *smrt, uint16_t timeout, smrt_versions_t *smrtv)
+{
+ smrt_identify_controller_t smic;
+ int r;
+
+ if ((r = smrt_ctlr_identify(smrt, timeout, &smic)) != 0) {
+ return (r);
+ }
+
+ smrtv->smrtv_hardware_version = smic.smic_hardware_version;
+ smrt_copy_firmware_version(smic.smic_firmware_rev,
+ smrtv->smrtv_firmware_rev);
+ smrt_copy_firmware_version(smic.smic_recovery_rev,
+ smrtv->smrtv_recovery_rev);
+ smrt_copy_firmware_version(smic.smic_bootblock_rev,
+ smrtv->smrtv_bootblock_rev);
+
+ return (0);
+}
+
+int
+smrt_ctlr_reset(smrt_t *smrt)
+{
+ smrt_command_t *smcm, *smcm_nop;
+ int r;
+
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+
+ if (ddi_in_panic()) {
+ goto skip_check;
+ }
+
+ if (smrt->smrt_status & SMRT_CTLR_STATUS_RESETTING) {
+ /*
+ * Don't pile on. One reset is enough. Wait until
+ * it's complete, and then return success.
+ */
+ while (smrt->smrt_status & SMRT_CTLR_STATUS_RESETTING) {
+ cv_wait(&smrt->smrt_cv_finishq, &smrt->smrt_mutex);
+ }
+ return (0);
+ }
+ smrt->smrt_status |= SMRT_CTLR_STATUS_RESETTING;
+ smrt->smrt_last_reset_start = gethrtime();
+ smrt->smrt_stats.smrts_ctlr_resets++;
+
+skip_check:
+ /*
+ * Allocate two commands: one for the soft reset message, which we
+ * cannot free until the controller has reset; and one for the ping we
+ * will use to determine when it is once again functional.
+ */
+ mutex_exit(&smrt->smrt_mutex);
+ if ((smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_INTERNAL,
+ KM_NOSLEEP)) == NULL) {
+ mutex_enter(&smrt->smrt_mutex);
+ return (ENOMEM);
+ }
+ if ((smcm_nop = smrt_command_alloc(smrt, SMRT_CMDTYPE_INTERNAL,
+ KM_NOSLEEP)) == NULL) {
+ smrt_command_free(smcm);
+ mutex_enter(&smrt->smrt_mutex);
+ return (ENOMEM);
+ }
+ mutex_enter(&smrt->smrt_mutex);
+
+ /*
+ * Send a soft reset command to the controller. If this command
+ * succeeds, there will likely be no completion notification. Instead,
+ * the device should become unavailable for some period of time and
+ * then become available again. Once available again, we know the soft
+ * reset has completed and should abort all in-flight commands.
+ */
+ smrt_write_message_reset_ctlr(smcm);
+
+ /*
+ * Disable interrupts now.
+ */
+ smrt_intr_set(smrt, B_FALSE);
+
+ dev_err(smrt->smrt_dip, CE_WARN, "attempting controller soft reset");
+ smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
+ if ((r = smrt_submit(smrt, smcm)) != 0) {
+ dev_err(smrt->smrt_dip, CE_PANIC, "soft reset failed: "
+ "submit failed (%d)", r);
+ }
+
+ /*
+ * Mark every currently inflight command as being reset, including the
+ * soft reset command we just sent. Once we confirm the reset works,
+ * we can safely report that these commands have failed.
+ */
+ for (smrt_command_t *t = avl_first(&smrt->smrt_inflight);
+ t != NULL; t = AVL_NEXT(&smrt->smrt_inflight, t)) {
+ t->smcm_status |= SMRT_CMD_STATUS_RESET_SENT;
+ }
+
+ /*
+ * Now that we have submitted our soft reset command, prevent
+ * the rest of the driver from interacting with the controller.
+ */
+ smrt->smrt_status &= ~SMRT_CTLR_STATUS_RUNNING;
+
+ /*
+ * We do not expect a completion from the controller for our soft
+ * reset command, but we also cannot remove it from the inflight
+ * list until we know the controller has actually reset. To do
+ * otherwise would potentially allow the controller to scribble
+ * on the memory we were using.
+ */
+ smcm->smcm_status |= SMRT_CMD_STATUS_ABANDONED;
+
+ if (smrt_ctlr_wait_for_state(smrt, SMRT_WAIT_STATE_UNREADY) !=
+ DDI_SUCCESS) {
+ dev_err(smrt->smrt_dip, CE_PANIC, "soft reset failed: "
+ "controller did not become unready");
+ }
+ dev_err(smrt->smrt_dip, CE_NOTE, "soft reset: controller unready");
+
+ if (smrt_ctlr_wait_for_state(smrt, SMRT_WAIT_STATE_READY) !=
+ DDI_SUCCESS) {
+ dev_err(smrt->smrt_dip, CE_PANIC, "soft reset failed: "
+ "controller did not come become ready");
+ }
+ dev_err(smrt->smrt_dip, CE_NOTE, "soft reset: controller ready");
+
+ /*
+ * In at least the Smart Array P420i, the controller can take 30-45
+ * seconds after the scratchpad register shows it as being available
+ * before it is ready to receive commands. In order to avoid hitting
+ * it too early with our post-reset ping, we will sleep for 10 seconds
+ * here.
+ */
+ if (ddi_in_panic()) {
+ drv_usecwait(10 * MICROSEC);
+ } else {
+ delay(drv_usectohz(10 * MICROSEC));
+ }
+
+ smrt_ctlr_teardown(smrt);
+ if (smrt_ctlr_init(smrt) != DDI_SUCCESS) {
+ dev_err(smrt->smrt_dip, CE_PANIC, "soft reset failed: "
+ "controller transport could not be configured");
+ }
+ dev_err(smrt->smrt_dip, CE_NOTE, "soft reset: controller configured");
+
+ smrt_write_message_nop(smcm_nop, 0);
+ smcm_nop->smcm_status |= SMRT_CMD_STATUS_POLLED |
+ SMRT_CMD_IGNORE_RUNNING;
+ if ((r = smrt_submit(smrt, smcm_nop)) != 0) {
+ dev_err(smrt->smrt_dip, CE_PANIC, "soft reset failed: "
+ "ping could not be submitted (%d)", r);
+ }
+
+ /*
+ * Interrupts are still masked at this stage. Poll manually in
+ * a way that will not trigger regular finish queue processing:
+ */
+ VERIFY(smcm_nop->smcm_status & SMRT_CMD_STATUS_INFLIGHT);
+ for (unsigned i = 0; i < 600; i++) {
+ smrt_retrieve_simple(smrt);
+
+ if (!(smcm_nop->smcm_status & SMRT_CMD_STATUS_INFLIGHT)) {
+ /*
+ * Remove the ping command from the finish queue and
+ * process it manually. This processing must mirror
+ * what would have been done in smrt_process_finishq().
+ */
+ VERIFY(list_link_active(&smcm_nop->smcm_link_finish));
+ list_remove(&smrt->smrt_finishq, smcm_nop);
+ smrt_process_finishq_sync(smcm_nop);
+ smcm_nop->smcm_status |= SMRT_CMD_STATUS_POLL_COMPLETE;
+ smrt_process_finishq_one(smcm_nop);
+ break;
+ }
+
+ if (ddi_in_panic()) {
+ drv_usecwait(100 * 1000);
+ } else {
+ delay(drv_usectohz(100 * 1000));
+ }
+ }
+
+ if (!(smcm_nop->smcm_status & SMRT_CMD_STATUS_COMPLETE)) {
+ dev_err(smrt->smrt_dip, CE_PANIC, "soft reset failed: "
+ "ping did not complete");
+ } else if (smcm_nop->smcm_status & SMRT_CMD_STATUS_ERROR) {
+ dev_err(smrt->smrt_dip, CE_WARN, "soft reset: ping completed "
+ "in error (status %u)",
+ (unsigned)smcm_nop->smcm_va_err->CommandStatus);
+ } else {
+ dev_err(smrt->smrt_dip, CE_NOTE, "soft reset: ping completed");
+ }
+
+ /*
+ * Now that the controller is working again, we can abort any
+ * commands that were inflight during the reset.
+ */
+ smrt_command_t *nt;
+ for (smrt_command_t *t = avl_first(&smrt->smrt_inflight);
+ t != NULL; t = nt) {
+ nt = AVL_NEXT(&smrt->smrt_inflight, t);
+
+ if (t->smcm_status & SMRT_CMD_STATUS_RESET_SENT) {
+ avl_remove(&smrt->smrt_inflight, t);
+ t->smcm_status &= ~SMRT_CMD_STATUS_INFLIGHT;
+
+ list_insert_tail(&smrt->smrt_finishq, t);
+ }
+ }
+
+ /*
+ * Quiesce our discovery thread. Note, because
+ * SMRT_CTLR_STATUS_RESTARTING is set, nothing can cause it to be
+ * enabled again.
+ */
+ if (!ddi_in_panic()) {
+ mutex_exit(&smrt->smrt_mutex);
+ ddi_taskq_wait(smrt->smrt_discover_taskq);
+ mutex_enter(&smrt->smrt_mutex);
+ }
+
+ /*
+ * Re-enable interrupts. Now, we must kick off a discovery to make sure
+ * that the system is in a sane state and that we can perform I/O.
+ */
+ smrt_intr_set(smrt, B_TRUE);
+ smrt->smrt_status &= ~SMRT_CTLR_STATUS_RESETTING;
+ smrt->smrt_status |= SMRT_CTLR_DISCOVERY_REQUIRED;
+
+ /*
+ * Attempt a discovery to make sure that the drivers sees a realistic
+ * view of the world. If we're not in panic context, spin for the
+ * asynchronous process to complete, otherwise we're in panic context
+ * and this is going to happen regardless if we want it to or not.
+ * Before we kick off the request to run discovery, we reset the
+ * discovery request flags as we know that nothing else can consider
+ * running discovery and we don't want to delay until the next smrt
+ * periodic tick if we can avoid it. In panic context, if this failed,
+ * then we won't make it back.
+ */
+ VERIFY0(smrt->smrt_status & SMRT_CTLR_DISCOVERY_RUNNING);
+ smrt->smrt_status &= ~(SMRT_CTLR_DISCOVERY_MASK);
+ smrt_discover(smrt);
+ if (!ddi_in_panic()) {
+ while (smrt->smrt_status & SMRT_CTLR_DISCOVERY_REQUIRED) {
+ cv_wait(&smrt->smrt_cv_finishq, &smrt->smrt_mutex);
+ }
+ }
+
+ smrt->smrt_status |= SMRT_CTLR_STATUS_RUNNING;
+ smrt->smrt_last_reset_finish = gethrtime();
+
+ /*
+ * Wake anybody that was waiting for the reset to complete.
+ */
+ cv_broadcast(&smrt->smrt_cv_finishq);
+
+ /*
+ * Process the completion queue one last time before we let go
+ * of the mutex.
+ */
+ smrt_process_finishq(smrt);
+
+ mutex_exit(&smrt->smrt_mutex);
+ smrt_command_free(smcm_nop);
+ mutex_enter(&smrt->smrt_mutex);
+ return (0);
+}
+
+int
+smrt_event_init(smrt_t *smrt)
+{
+ int ret;
+ smrt_command_t *event, *cancel;
+
+ event = smrt_command_alloc(smrt, SMRT_CMDTYPE_EVENT, KM_NOSLEEP);
+ if (event == NULL)
+ return (ENOMEM);
+ if (smrt_command_attach_internal(smrt, event, SMRT_EVENT_NOTIFY_BUFLEN,
+ KM_NOSLEEP) != 0) {
+ smrt_command_free(event);
+ return (ENOMEM);
+ }
+ smrt_write_message_event_notify(event);
+
+ cancel = smrt_command_alloc(smrt, SMRT_CMDTYPE_INTERNAL, KM_NOSLEEP);
+ if (cancel == NULL) {
+ smrt_command_free(event);
+ return (ENOMEM);
+ }
+ if (smrt_command_attach_internal(smrt, cancel, SMRT_EVENT_NOTIFY_BUFLEN,
+ KM_NOSLEEP) != 0) {
+ smrt_command_free(event);
+ smrt_command_free(cancel);
+ return (ENOMEM);
+ }
+ smrt_write_message_cancel_event_notify(cancel);
+
+ cv_init(&smrt->smrt_event_queue, NULL, CV_DRIVER, NULL);
+
+ mutex_enter(&smrt->smrt_mutex);
+ if ((ret = smrt_submit(smrt, event)) != 0) {
+ mutex_exit(&smrt->smrt_mutex);
+ smrt_command_free(event);
+ smrt_command_free(cancel);
+ return (ret);
+ }
+
+ smrt->smrt_event_cmd = event;
+ smrt->smrt_event_cancel_cmd = cancel;
+ mutex_exit(&smrt->smrt_mutex);
+
+ return (0);
+}
+
+void
+smrt_event_complete(smrt_command_t *smcm)
+{
+ smrt_event_notify_t *sen;
+ boolean_t log, rescan;
+
+ boolean_t intervene = B_FALSE;
+ smrt_t *smrt = smcm->smcm_ctlr;
+
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+ VERIFY3P(smcm, ==, smrt->smrt_event_cmd);
+ VERIFY0(smrt->smrt_status & SMRT_CTLR_ASYNC_INTERVENTION);
+
+ smrt->smrt_stats.smrts_events_received++;
+
+ if (smrt->smrt_status & SMRT_CTLR_STATUS_DETACHING) {
+ cv_signal(&smrt->smrt_event_queue);
+ return;
+ }
+
+ if (smrt->smrt_status & SMRT_CTLR_STATUS_RESETTING) {
+ intervene = B_TRUE;
+ goto clean;
+ }
+
+ /*
+ * The event notification command failed for some reason. Attempt to
+ * drive on and try again at the next intervention period. Because this
+ * may represent a programmer error (though it's hard to know), we wait
+ * until the next intervention period and don't panic.
+ */
+ if (smcm->smcm_status & SMRT_CMD_STATUS_ERROR) {
+ ErrorInfo_t *ei = smcm->smcm_va_err;
+ intervene = B_TRUE;
+
+ smrt->smrt_stats.smrts_events_errors++;
+ dev_err(smrt->smrt_dip, CE_WARN, "!event notification request "
+ "error: status 0x%x", ei->CommandStatus);
+ goto clean;
+ }
+
+ sen = smcm->smcm_internal->smcmi_va;
+ log = rescan = B_FALSE;
+ switch (sen->sen_class) {
+ case SMRT_EVENT_CLASS_PROTOCOL:
+ /*
+ * Most of the event protocol class events aren't really
+ * actionable. However, subclass 1 indicates errors. Today,
+ * the only error is an event overflow. If there's an event
+ * overflow, then we must assume that we need to rescan.
+ */
+ if (sen->sen_subclass == SMRT_EVENT_PROTOCOL_SUBCLASS_ERROR) {
+ rescan = B_TRUE;
+ }
+ break;
+ case SMRT_EVENT_CLASS_HOTPLUG:
+ /*
+ * We want to log all hotplug events. However we only need to
+ * scan these if the subclass indicates the event is for a disk.
+ */
+ log = B_TRUE;
+ if (sen->sen_subclass == SMRT_EVENT_HOTPLUG_SUBCLASS_DRIVE) {
+ rescan = B_TRUE;
+ }
+ break;
+ case SMRT_EVENT_CLASS_HWERROR:
+ case SMRT_EVENT_CLASS_ENVIRONMENT:
+ log = B_TRUE;
+ break;
+ case SMRT_EVENT_CLASS_PHYS:
+ log = B_TRUE;
+ /*
+ * This subclass indicates some change for physical drives. As
+ * such, this should trigger a rescan.
+ */
+ if (sen->sen_subclass == SMRT_EVENT_PHYS_SUBCLASS_STATE) {
+ rescan = B_TRUE;
+ }
+ break;
+ case SMRT_EVENT_CLASS_LOGVOL:
+ rescan = B_TRUE;
+ log = B_TRUE;
+ break;
+ default:
+ /*
+ * While there are other classes of events, it's hard to say how
+ * actionable they are for the moment. If we revamp this such
+ * that it becomes an ireport based system, then we should just
+ * always log these. We opt not to at the moment to try and be
+ * kind to the system log.
+ */
+ break;
+ }
+
+ /*
+ * Ideally, this would be an ireport that we could pass onto
+ * administrators; however, since we don't have any way to generate
+ * that, we provide a subset of the event information.
+ */
+ if (log) {
+ const char *rmsg;
+ if (rescan == B_TRUE) {
+ rmsg = "rescanning";
+ } else {
+ rmsg = "not rescanning";
+ }
+ if (sen->sen_message[0] != '\0') {
+ sen->sen_message[sizeof (sen->sen_message) - 1] = '\0';
+ dev_err(smrt->smrt_dip, CE_NOTE, "!controller event "
+ "class/sub-class/detail %x, %x, %x: %s; %s devices",
+ sen->sen_class, sen->sen_subclass, sen->sen_detail,
+ sen->sen_message, rmsg);
+ } else {
+ dev_err(smrt->smrt_dip, CE_NOTE, "!controller event "
+ "class/sub-class/detail %x, %x, %x; %s devices",
+ sen->sen_class, sen->sen_subclass, sen->sen_detail,
+ rmsg);
+ }
+ }
+
+ if (rescan)
+ smrt_discover_request(smrt);
+
+clean:
+ mutex_exit(&smrt->smrt_mutex);
+ smrt_command_reuse(smcm);
+ bzero(smcm->smcm_internal->smcmi_va, SMRT_EVENT_NOTIFY_BUFLEN);
+ mutex_enter(&smrt->smrt_mutex);
+
+ /*
+ * Make sure we're not _now_ detaching or resetting.
+ */
+ if (smrt->smrt_status & SMRT_CTLR_STATUS_DETACHING) {
+ cv_signal(&smrt->smrt_event_queue);
+ return;
+ }
+
+ if ((smrt->smrt_status & SMRT_CTLR_STATUS_RESETTING) != 0 ||
+ intervene == B_TRUE) {
+ smrt->smrt_status |= SMRT_CTLR_ASYNC_INTERVENTION;
+ return;
+ }
+
+ /*
+ * Check out command count per tick. If it's too high, leave it for
+ * intervention to solve. Likely there is some serious driver or
+ * firmware error going on.
+ */
+ smrt->smrt_event_count++;
+ if (smrt->smrt_event_count > smrt_event_intervention_threshold) {
+ smrt->smrt_status |= SMRT_CTLR_ASYNC_INTERVENTION;
+ return;
+ }
+
+ if (smrt_submit(smrt, smcm) != 0) {
+ smrt->smrt_status |= SMRT_CTLR_ASYNC_INTERVENTION;
+ }
+}
+
+void
+smrt_event_fini(smrt_t *smrt)
+{
+ int ret;
+ smrt_command_t *event, *cancel;
+ mutex_enter(&smrt->smrt_mutex);
+
+ /*
+ * If intervention has been requested, there is nothing for us to do. We
+ * clear the flag so nothing else accidentally sees this and takes
+ * action. We also don't need to bother sending a cancellation request,
+ * as there is no outstanding event.
+ */
+ if (smrt->smrt_status & SMRT_CTLR_ASYNC_INTERVENTION) {
+ smrt->smrt_status &= ~SMRT_CTLR_ASYNC_INTERVENTION;
+ goto free;
+ }
+
+ /*
+ * Submit a cancel request for the event notification queue. Because we
+ * submit both the cancel event and the regular notification event as an
+ * ordered command, we know that by the time this completes, that the
+ * existing one will have completed.
+ */
+ smrt->smrt_event_cancel_cmd->smcm_status |= SMRT_CMD_STATUS_POLLED;
+ if ((ret = smrt_submit(smrt, smrt->smrt_event_cancel_cmd)) != 0) {
+ /*
+ * This is unfortunate. We've failed to submit the command. At
+ * this point all we can do is reset the device. If the reset
+ * succeeds, we're done and we can clear all the memory. If it
+ * fails, then all we can do is just leak the command and scream
+ * to the system, sorry.
+ */
+ if (smrt_ctlr_reset(smrt) != 0) {
+ dev_err(smrt->smrt_dip, CE_WARN, "failed to reset "
+ "device after failure to submit cancellation "
+ "(%d), abandoning smrt_command_t at address %p",
+ ret, smrt->smrt_event_cmd);
+ smrt->smrt_event_cmd = NULL;
+ goto free;
+ }
+ }
+
+ smrt->smrt_event_cancel_cmd->smcm_expiry = gethrtime() +
+ SMRT_ASYNC_CANCEL_TIMEOUT * NANOSEC;
+ if ((ret = smrt_poll_for(smrt, smrt->smrt_event_cancel_cmd)) != 0) {
+ VERIFY3S(ret, ==, ETIMEDOUT);
+ VERIFY0(smrt->smrt_event_cancel_cmd->smcm_status &
+ SMRT_CMD_STATUS_POLL_COMPLETE);
+
+ /*
+ * The command timed out. All we can do is hope a reset will
+ * work.
+ */
+ if (smrt_ctlr_reset(smrt) != 0) {
+ dev_err(smrt->smrt_dip, CE_WARN, "failed to reset "
+ "device after failure to poll for async "
+ "cancellation command abandoning smrt_command_t "
+ "event command at address %p and cancellation "
+ "command at %p", smrt->smrt_event_cmd,
+ smrt->smrt_event_cancel_cmd);
+ smrt->smrt_event_cmd = NULL;
+ smrt->smrt_event_cancel_cmd = NULL;
+ goto free;
+ }
+
+ }
+
+ /*
+ * Well, in the end, it's results that count.
+ */
+ if (smrt->smrt_event_cancel_cmd->smcm_status &
+ SMRT_CMD_STATUS_RESET_SENT) {
+ goto free;
+ }
+
+ if (smrt->smrt_event_cancel_cmd->smcm_status & SMRT_CMD_STATUS_ERROR) {
+ ErrorInfo_t *ei = smrt->smrt_event_cancel_cmd->smcm_va_err;
+
+ /*
+ * This can return a CISS_CMD_TARGET_STATUS entry when the
+ * controller doesn't think a command is outstanding. It is
+ * possible we raced, so don't think too much about that case.
+ * Anything else leaves us between a rock and a hard place, the
+ * only way out is a reset.
+ */
+ if (ei->CommandStatus != CISS_CMD_TARGET_STATUS &&
+ smrt_ctlr_reset(smrt) != 0) {
+ dev_err(smrt->smrt_dip, CE_WARN, "failed to reset "
+ "device after receiving an error on the async "
+ "cancellation command (%d); abandoning "
+ "smrt_command_t event command at address %p and "
+ "cancellation command at %p", ei->CommandStatus,
+ smrt->smrt_event_cmd, smrt->smrt_event_cancel_cmd);
+ smrt->smrt_event_cmd = NULL;
+ smrt->smrt_event_cancel_cmd = NULL;
+ goto free;
+ }
+ }
+
+free:
+ event = smrt->smrt_event_cmd;
+ smrt->smrt_event_cmd = NULL;
+ cancel = smrt->smrt_event_cancel_cmd;
+ smrt->smrt_event_cancel_cmd = NULL;
+ mutex_exit(&smrt->smrt_mutex);
+ if (event != NULL)
+ smrt_command_free(event);
+ if (cancel != NULL)
+ smrt_command_free(cancel);
+ cv_destroy(&smrt->smrt_event_queue);
+}
+
+/*
+ * We've been asked to do a discovery in panic context. This would have
+ * occurred because there was a device reset. Because we can't rely on the
+ * target maps, all we can do at the moment is go over all the active targets
+ * and note which ones no longer exist. If this target was required to dump,
+ * then the dump code will encounter a fatal error. If not, then we should
+ * count ourselves surprisingly lucky.
+ */
+static void
+smrt_discover_panic_check(smrt_t *smrt)
+{
+ smrt_target_t *smtg;
+
+ ASSERT(MUTEX_HELD(&smrt->smrt_mutex));
+ for (smtg = list_head(&smrt->smrt_targets); smtg != NULL;
+ smtg = list_next(&smrt->smrt_targets, smtg)) {
+ uint64_t gen;
+
+ if (smtg->smtg_physical) {
+ smrt_physical_t *smpt = smtg->smtg_lun.smtg_phys;
+ /*
+ * Don't worry about drives that aren't visible.
+ */
+ if (!smpt->smpt_visible)
+ continue;
+ gen = smpt->smpt_gen;
+ } else {
+ smrt_volume_t *smlv = smtg->smtg_lun.smtg_vol;
+ gen = smlv->smlv_gen;
+ }
+
+ if (gen != smrt->smrt_discover_gen) {
+ dev_err(smrt->smrt_dip, CE_WARN, "target %s "
+ "disappeared during post-panic discovery",
+ scsi_device_unit_address(smtg->smtg_scsi_dev));
+ smtg->smtg_gone = B_TRUE;
+ }
+ }
+}
+
+static void
+smrt_discover(void *arg)
+{
+ int log = 0, phys = 0;
+ smrt_t *smrt = arg;
+ uint64_t gen;
+ boolean_t runphys, runvirt;
+
+ mutex_enter(&smrt->smrt_mutex);
+ smrt->smrt_status |= SMRT_CTLR_DISCOVERY_RUNNING;
+ smrt->smrt_status &= ~SMRT_CTLR_DISCOVERY_REQUESTED;
+
+ smrt->smrt_discover_gen++;
+ gen = smrt->smrt_discover_gen;
+ runphys = smrt->smrt_phys_tgtmap != NULL;
+ runvirt = smrt->smrt_virt_tgtmap != NULL;
+ mutex_exit(&smrt->smrt_mutex);
+ if (runphys)
+ phys = smrt_phys_discover(smrt, SMRT_DISCOVER_TIMEOUT, gen);
+ if (runvirt)
+ log = smrt_logvol_discover(smrt, SMRT_DISCOVER_TIMEOUT, gen);
+ mutex_enter(&smrt->smrt_mutex);
+
+ if (phys != 0 || log != 0) {
+ if (!ddi_in_panic()) {
+ smrt->smrt_status |= SMRT_CTLR_DISCOVERY_PERIODIC;
+ } else {
+ panic("smrt_t %p failed to perform discovery after "
+ "a reset in panic context, unable to continue. "
+ "logvol: %d, phys: %d", smrt, log, phys);
+ }
+ } else {
+ if (!ddi_in_panic() &&
+ smrt->smrt_status & SMRT_CTLR_DISCOVERY_REQUIRED) {
+ smrt->smrt_status &= ~SMRT_CTLR_DISCOVERY_REQUIRED;
+ cv_broadcast(&smrt->smrt_cv_finishq);
+ }
+
+ if (ddi_in_panic()) {
+ smrt_discover_panic_check(smrt);
+ }
+ }
+ smrt->smrt_status &= ~SMRT_CTLR_DISCOVERY_RUNNING;
+ if (smrt->smrt_status & SMRT_CTLR_DISCOVERY_REQUESTED)
+ smrt->smrt_status |= SMRT_CTLR_DISCOVERY_PERIODIC;
+ mutex_exit(&smrt->smrt_mutex);
+}
+
+/*
+ * Request discovery, which is always run via a taskq.
+ */
+void
+smrt_discover_request(smrt_t *smrt)
+{
+ boolean_t run;
+ ASSERT(MUTEX_HELD(&smrt->smrt_mutex));
+
+ if (ddi_in_panic()) {
+ smrt_discover(smrt);
+ return;
+ }
+
+ run = (smrt->smrt_status & SMRT_CTLR_DISCOVERY_MASK) == 0;
+ smrt->smrt_status |= SMRT_CTLR_DISCOVERY_REQUESTED;
+ if (run && ddi_taskq_dispatch(smrt->smrt_discover_taskq,
+ smrt_discover, smrt, DDI_NOSLEEP) != DDI_SUCCESS) {
+ smrt->smrt_status |= SMRT_CTLR_DISCOVERY_PERIODIC;
+ smrt->smrt_stats.smrts_discovery_tq_errors++;
+ }
+}
diff --git a/usr/src/uts/common/io/scsi/adapters/smrt/smrt_ciss_simple.c b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_ciss_simple.c
new file mode 100644
index 0000000000..1b3d7b2602
--- /dev/null
+++ b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_ciss_simple.c
@@ -0,0 +1,282 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#include <sys/scsi/adapters/smrt/smrt.h>
+
+uint_t
+smrt_isr_hw_simple(caddr_t arg1, caddr_t arg2)
+{
+ _NOTE(ARGUNUSED(arg2))
+
+ /* LINTED: E_BAD_PTR_CAST_ALIGN */
+ smrt_t *smrt = (smrt_t *)arg1;
+ uint32_t isr = smrt_get32(smrt, CISS_I2O_INTERRUPT_STATUS);
+ hrtime_t now = gethrtime();
+
+ mutex_enter(&smrt->smrt_mutex);
+ if (!(smrt->smrt_status & SMRT_CTLR_STATUS_RUNNING)) {
+ smrt->smrt_stats.smrts_unclaimed_interrupts++;
+ smrt->smrt_last_interrupt_unclaimed = now;
+
+ /*
+ * We should not be receiving interrupts from the controller
+ * while the driver is not running.
+ */
+ mutex_exit(&smrt->smrt_mutex);
+ return (DDI_INTR_UNCLAIMED);
+ }
+
+ /*
+ * Check to see if this interrupt came from the device:
+ */
+ if ((isr & CISS_ISR_BIT_SIMPLE_INTR) == 0) {
+ smrt->smrt_stats.smrts_unclaimed_interrupts++;
+ smrt->smrt_last_interrupt_unclaimed = now;
+
+ /*
+ * Check to see if the firmware has come to rest. If it has,
+ * this routine will panic the system.
+ */
+ smrt_lockup_check(smrt);
+
+ mutex_exit(&smrt->smrt_mutex);
+ return (DDI_INTR_UNCLAIMED);
+ }
+
+ smrt->smrt_stats.smrts_claimed_interrupts++;
+ smrt->smrt_last_interrupt_claimed = now;
+
+ /*
+ * The interrupt was from our controller, so collect any pending
+ * command completions.
+ */
+ smrt_retrieve_simple(smrt);
+
+ /*
+ * Process any commands in the completion queue.
+ */
+ smrt_process_finishq(smrt);
+
+ mutex_exit(&smrt->smrt_mutex);
+ return (DDI_INTR_CLAIMED);
+}
+
+/*
+ * Read tags and process completion of the associated command until the supply
+ * of tags is exhausted.
+ */
+void
+smrt_retrieve_simple(smrt_t *smrt)
+{
+ uint32_t opq;
+ uint32_t none = 0xffffffff;
+
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+
+ while ((opq = smrt_get32(smrt, CISS_I2O_OUTBOUND_POST_Q)) != none) {
+ uint32_t tag = CISS_OPQ_READ_TAG(opq);
+ smrt_command_t *smcm;
+
+ if ((smcm = smrt_lookup_inflight(smrt, tag)) == NULL) {
+ dev_err(smrt->smrt_dip, CE_WARN, "spurious tag %x",
+ tag);
+ continue;
+ }
+
+ avl_remove(&smrt->smrt_inflight, smcm);
+ smcm->smcm_status &= ~SMRT_CMD_STATUS_INFLIGHT;
+ if (CISS_OPQ_READ_ERROR(opq) != 0) {
+ smcm->smcm_status |= SMRT_CMD_STATUS_ERROR;
+ }
+ smcm->smcm_time_complete = gethrtime();
+
+ /*
+ * Push this command onto the completion queue.
+ */
+ list_insert_tail(&smrt->smrt_finishq, smcm);
+ }
+}
+
+/*
+ * Submit a command to the controller by posting it to the Inbound Post Queue
+ * Register.
+ */
+void
+smrt_submit_simple(smrt_t *smrt, smrt_command_t *smcm)
+{
+ smrt_put32(smrt, CISS_I2O_INBOUND_POST_Q, smcm->smcm_pa_cmd);
+}
+
+/*
+ * Submit a command to the controller by posting it to the Inbound Post Queue
+ * Register. Immediately begin polling on the completion of that command.
+ *
+ * NOTE: This function is for controller initialisation only. It discards
+ * completions of commands other than the expected command as spurious, and
+ * will not interact correctly with the rest of the driver once it is running.
+ */
+int
+smrt_preinit_command_simple(smrt_t *smrt, smrt_command_t *smcm)
+{
+ /*
+ * The controller must be initialised to use the Simple Transport
+ * Method, but not be marked RUNNING. The command to process must be a
+ * PREINIT command with the expected tag number, marked for polling.
+ */
+ VERIFY(smrt->smrt_ctlr_mode == SMRT_CTLR_MODE_SIMPLE);
+ VERIFY(!(smrt->smrt_status & SMRT_CTLR_STATUS_RUNNING));
+ VERIFY(smcm->smcm_type == SMRT_CMDTYPE_PREINIT);
+ VERIFY(smcm->smcm_status & SMRT_CMD_STATUS_POLLED);
+ VERIFY3U(smcm->smcm_tag, ==, SMRT_PRE_TAG_NUMBER);
+
+ /*
+ * Submit this command to the controller.
+ */
+ smcm->smcm_status |= SMRT_CMD_STATUS_INFLIGHT;
+ smrt_put32(smrt, CISS_I2O_INBOUND_POST_Q, smcm->smcm_pa_cmd);
+
+ /*
+ * Poll the controller for completions until we see the command we just
+ * sent, or the timeout expires.
+ */
+ for (;;) {
+ uint32_t none = 0xffffffff;
+ uint32_t opq = smrt_get32(smrt, CISS_I2O_OUTBOUND_POST_Q);
+ uint32_t tag;
+
+ if (smcm->smcm_expiry != 0) {
+ /*
+ * This command has an expiry time. Check to see
+ * if it has already passed:
+ */
+ if (smcm->smcm_expiry < gethrtime()) {
+ return (ETIMEDOUT);
+ }
+ }
+
+ if (opq == none) {
+ delay(drv_usectohz(10 * 1000));
+ continue;
+ }
+
+ if ((tag = CISS_OPQ_READ_TAG(opq)) != SMRT_PRE_TAG_NUMBER) {
+ dev_err(smrt->smrt_dip, CE_WARN, "unexpected tag 0x%x"
+ " completed during driver init", tag);
+ delay(drv_usectohz(10 * 1000));
+ continue;
+ }
+
+ smcm->smcm_status &= ~SMRT_CMD_STATUS_INFLIGHT;
+ if (CISS_OPQ_READ_ERROR(opq) != 0) {
+ smcm->smcm_status |= SMRT_CMD_STATUS_ERROR;
+ }
+ smcm->smcm_time_complete = gethrtime();
+ smcm->smcm_status |= SMRT_CMD_STATUS_POLL_COMPLETE;
+
+ return (0);
+ }
+}
+
+int
+smrt_ctlr_init_simple(smrt_t *smrt)
+{
+ VERIFY(smrt->smrt_ctlr_mode == SMRT_CTLR_MODE_UNKNOWN);
+
+ if (smrt_cfgtbl_transport_has_support(smrt,
+ CISS_CFGTBL_XPORT_SIMPLE) != DDI_SUCCESS) {
+ return (DDI_FAILURE);
+ }
+ smrt->smrt_ctlr_mode = SMRT_CTLR_MODE_SIMPLE;
+
+ /*
+ * Disable device interrupts while we are setting up.
+ */
+ smrt_intr_set(smrt, B_FALSE);
+
+ if ((smrt->smrt_maxcmds = smrt_ctlr_get_cmdsoutmax(smrt)) == 0) {
+ dev_err(smrt->smrt_dip, CE_WARN, "maximum outstanding "
+ "commands set to zero");
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Determine the number of Scatter/Gather List entries this controller
+ * supports. The maximum number we allow is CISS_MAXSGENTRIES: the
+ * number of elements in the static struct we use for command
+ * submission.
+ */
+ if ((smrt->smrt_sg_cnt = smrt_ctlr_get_maxsgelements(smrt)) == 0) {
+ /*
+ * The CISS specification states that if this value is
+ * zero, we should assume a value of 31 for compatibility
+ * with older firmware.
+ */
+ smrt->smrt_sg_cnt = CISS_SGCNT_FALLBACK;
+
+ } else if (smrt->smrt_sg_cnt > CISS_MAXSGENTRIES) {
+ /*
+ * If the controller supports more than we have allocated,
+ * just cap the count at the allocation size.
+ */
+ smrt->smrt_sg_cnt = CISS_MAXSGENTRIES;
+ }
+
+ /*
+ * Zero the upper 32 bits of the address in the Controller.
+ */
+ ddi_put32(smrt->smrt_ct_handle, &smrt->smrt_ct->Upper32Addr, 0);
+
+ /*
+ * Set the Transport Method and flush the changes to the
+ * Configuration Table.
+ */
+ smrt_cfgtbl_transport_set(smrt, CISS_CFGTBL_XPORT_SIMPLE);
+ if (smrt_cfgtbl_flush(smrt) != DDI_SUCCESS) {
+ return (DDI_FAILURE);
+ }
+
+ if (smrt_cfgtbl_transport_confirm(smrt,
+ CISS_CFGTBL_XPORT_SIMPLE) != DDI_SUCCESS) {
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Check the outstanding command cap a second time now that we have
+ * flushed out the new Transport Method. This is entirely defensive;
+ * we do not expect this value to change.
+ */
+ uint32_t check_again = smrt_ctlr_get_cmdsoutmax(smrt);
+ if (check_again != smrt->smrt_maxcmds) {
+ dev_err(smrt->smrt_dip, CE_WARN, "maximum outstanding commands "
+ "changed during initialisation (was %u, now %u)",
+ smrt->smrt_maxcmds, check_again);
+ return (DDI_FAILURE);
+ }
+
+ return (DDI_SUCCESS);
+}
+
+void
+smrt_ctlr_teardown_simple(smrt_t *smrt)
+{
+ VERIFY(smrt->smrt_ctlr_mode == SMRT_CTLR_MODE_SIMPLE);
+
+ /*
+ * Due to the nominal simplicity of the simple mode, we have no
+ * particular teardown to perform as we do not allocate anything
+ * on the way up.
+ */
+ smrt->smrt_ctlr_mode = SMRT_CTLR_MODE_UNKNOWN;
+}
diff --git a/usr/src/uts/common/io/scsi/adapters/smrt/smrt_commands.c b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_commands.c
new file mode 100644
index 0000000000..edcbfa65e2
--- /dev/null
+++ b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_commands.c
@@ -0,0 +1,362 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+#include <sys/scsi/adapters/smrt/smrt.h>
+
+
+static ddi_dma_attr_t smrt_command_dma_attr = {
+ .dma_attr_version = DMA_ATTR_V0,
+ .dma_attr_addr_lo = 0x00000000,
+ .dma_attr_addr_hi = 0xFFFFFFFF,
+ .dma_attr_count_max = 0x00FFFFFF,
+ .dma_attr_align = 0x20,
+ .dma_attr_burstsizes = 0x20,
+ .dma_attr_minxfer = DMA_UNIT_8,
+ .dma_attr_maxxfer = 0xFFFFFFFF,
+ .dma_attr_seg = 0x0000FFFF,
+ .dma_attr_sgllen = 1,
+ .dma_attr_granular = 512,
+ .dma_attr_flags = 0
+};
+
+/*
+ * These device access attributes are for command block allocation, where we do
+ * not use any of the structured byte swapping facilities.
+ */
+static ddi_device_acc_attr_t smrt_command_dev_attr = {
+ .devacc_attr_version = DDI_DEVICE_ATTR_V0,
+ .devacc_attr_endian_flags = DDI_NEVERSWAP_ACC,
+ .devacc_attr_dataorder = DDI_STRICTORDER_ACC,
+ .devacc_attr_access = 0
+};
+
+
+static void smrt_contig_free(smrt_dma_t *);
+
+
+static int
+smrt_check_command_type(smrt_command_type_t type)
+{
+ /*
+ * Note that we leave out the default case in order to utilise
+ * compiler warnings about missed enum values.
+ */
+ switch (type) {
+ case SMRT_CMDTYPE_ABORTQ:
+ case SMRT_CMDTYPE_SCSA:
+ case SMRT_CMDTYPE_INTERNAL:
+ case SMRT_CMDTYPE_PREINIT:
+ case SMRT_CMDTYPE_EVENT:
+ return (type);
+ }
+
+ panic("unexpected command type");
+ /* LINTED: E_FUNC_NO_RET_VAL */
+}
+
+static int
+smrt_contig_alloc(smrt_t *smrt, smrt_dma_t *smdma, size_t sz, int kmflags,
+ void **vap, uint32_t *pap)
+{
+ caddr_t va;
+ int rv;
+ dev_info_t *dip = smrt->smrt_dip;
+ int (*dma_wait)(caddr_t) = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP :
+ DDI_DMA_DONTWAIT;
+
+ VERIFY(kmflags == KM_SLEEP || kmflags == KM_NOSLEEP);
+
+ /*
+ * Ensure we don't try to allocate a second time using the same
+ * tracking object.
+ */
+ VERIFY0(smdma->smdma_level);
+
+ if ((rv = ddi_dma_alloc_handle(dip, &smrt_command_dma_attr,
+ dma_wait, NULL, &smdma->smdma_dma_handle)) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "DMA handle allocation failed (%x)",
+ rv);
+ goto fail;
+ }
+ smdma->smdma_level |= SMRT_DMALEVEL_HANDLE_ALLOC;
+
+ if ((rv = ddi_dma_mem_alloc(smdma->smdma_dma_handle, sz,
+ &smrt_command_dev_attr, DDI_DMA_CONSISTENT, dma_wait, NULL,
+ &va, &smdma->smdma_real_size, &smdma->smdma_acc_handle)) !=
+ DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "DMA memory allocation failed (%x)", rv);
+ goto fail;
+ }
+ smdma->smdma_level |= SMRT_DMALEVEL_MEMORY_ALLOC;
+
+ if ((rv = ddi_dma_addr_bind_handle(smdma->smdma_dma_handle,
+ NULL, va, smdma->smdma_real_size,
+ DDI_DMA_CONSISTENT | DDI_DMA_RDWR, dma_wait, NULL,
+ smdma->smdma_dma_cookies, &smdma->smdma_dma_ncookies)) !=
+ DDI_DMA_MAPPED) {
+ dev_err(dip, CE_WARN, "DMA handle bind failed (%x)", rv);
+ goto fail;
+ }
+ smdma->smdma_level |= SMRT_DMALEVEL_HANDLE_BOUND;
+
+ VERIFY3U(smdma->smdma_dma_ncookies, ==, 1);
+ *pap = smdma->smdma_dma_cookies[0].dmac_address;
+ *vap = (void *)va;
+ return (DDI_SUCCESS);
+
+fail:
+ *vap = NULL;
+ *pap = 0;
+ smrt_contig_free(smdma);
+ return (DDI_FAILURE);
+}
+
+static void
+smrt_contig_free(smrt_dma_t *smdma)
+{
+ if (smdma->smdma_level & SMRT_DMALEVEL_HANDLE_BOUND) {
+ VERIFY3U(ddi_dma_unbind_handle(smdma->smdma_dma_handle), ==,
+ DDI_SUCCESS);
+
+ smdma->smdma_level &= ~SMRT_DMALEVEL_HANDLE_BOUND;
+ }
+
+ if (smdma->smdma_level & SMRT_DMALEVEL_MEMORY_ALLOC) {
+ ddi_dma_mem_free(&smdma->smdma_acc_handle);
+
+ smdma->smdma_level &= ~SMRT_DMALEVEL_MEMORY_ALLOC;
+ }
+
+ if (smdma->smdma_level & SMRT_DMALEVEL_HANDLE_ALLOC) {
+ ddi_dma_free_handle(&smdma->smdma_dma_handle);
+
+ smdma->smdma_level &= ~SMRT_DMALEVEL_HANDLE_ALLOC;
+ }
+
+ VERIFY(smdma->smdma_level == 0);
+ bzero(smdma, sizeof (*smdma));
+}
+
+static smrt_command_t *
+smrt_command_alloc_impl(smrt_t *smrt, smrt_command_type_t type, int kmflags)
+{
+ smrt_command_t *smcm;
+
+ VERIFY(kmflags == KM_SLEEP || kmflags == KM_NOSLEEP);
+
+ if ((smcm = kmem_zalloc(sizeof (*smcm), kmflags)) == NULL) {
+ return (NULL);
+ }
+
+ smcm->smcm_ctlr = smrt;
+ smcm->smcm_type = smrt_check_command_type(type);
+
+ /*
+ * Allocate a single contiguous chunk of memory for the command block
+ * (smcm_va_cmd) and the error information block (smcm_va_err). The
+ * physical address of each block should be 32-byte aligned.
+ */
+ size_t contig_size = 0;
+ contig_size += P2ROUNDUP_TYPED(sizeof (CommandList_t), 32, size_t);
+
+ size_t errorinfo_offset = contig_size;
+ contig_size += P2ROUNDUP_TYPED(sizeof (ErrorInfo_t), 32, size_t);
+
+ if (smrt_contig_alloc(smrt, &smcm->smcm_contig, contig_size,
+ kmflags, (void **)&smcm->smcm_va_cmd, &smcm->smcm_pa_cmd) !=
+ DDI_SUCCESS) {
+ kmem_free(smcm, sizeof (*smcm));
+ return (NULL);
+ }
+
+ smcm->smcm_va_err = (void *)((caddr_t)smcm->smcm_va_cmd +
+ errorinfo_offset);
+ smcm->smcm_pa_err = smcm->smcm_pa_cmd + errorinfo_offset;
+
+ /*
+ * Ensure we asked for, and received, the correct physical alignment:
+ */
+ VERIFY0(smcm->smcm_pa_cmd & 0x1f);
+ VERIFY0(smcm->smcm_pa_err & 0x1f);
+
+ /*
+ * Populate Fields.
+ */
+ bzero(smcm->smcm_va_cmd, contig_size);
+ smcm->smcm_va_cmd->ErrDesc.Addr = smcm->smcm_pa_err;
+ smcm->smcm_va_cmd->ErrDesc.Len = sizeof (ErrorInfo_t);
+
+ return (smcm);
+}
+
+smrt_command_t *
+smrt_command_alloc_preinit(smrt_t *smrt, size_t datasize, int kmflags)
+{
+ smrt_command_t *smcm;
+
+ if ((smcm = smrt_command_alloc_impl(smrt, SMRT_CMDTYPE_PREINIT,
+ kmflags)) == NULL) {
+ return (NULL);
+ }
+
+ /*
+ * Note that most driver infrastructure has not been initialised at
+ * this time. All commands are submitted to the controller serially,
+ * using a pre-specified tag, and are not attached to the command
+ * tracking list.
+ */
+ smcm->smcm_tag = SMRT_PRE_TAG_NUMBER;
+ smcm->smcm_va_cmd->Header.Tag.tag_value = SMRT_PRE_TAG_NUMBER;
+
+ if (smrt_command_attach_internal(smrt, smcm, datasize, kmflags) != 0) {
+ smrt_command_free(smcm);
+ return (NULL);
+ }
+
+ return (smcm);
+}
+
+smrt_command_t *
+smrt_command_alloc(smrt_t *smrt, smrt_command_type_t type, int kmflags)
+{
+ smrt_command_t *smcm;
+
+ VERIFY(type != SMRT_CMDTYPE_PREINIT);
+
+ if ((smcm = smrt_command_alloc_impl(smrt, type, kmflags)) == NULL) {
+ return (NULL);
+ }
+
+ /*
+ * Insert into the per-controller command list.
+ */
+ mutex_enter(&smrt->smrt_mutex);
+ list_insert_tail(&smrt->smrt_commands, smcm);
+ mutex_exit(&smrt->smrt_mutex);
+
+ return (smcm);
+}
+
+int
+smrt_command_attach_internal(smrt_t *smrt, smrt_command_t *smcm, size_t len,
+ int kmflags)
+{
+ smrt_command_internal_t *smcmi;
+
+ VERIFY(kmflags == KM_SLEEP || kmflags == KM_NOSLEEP);
+ VERIFY3U(len, <=, UINT32_MAX);
+
+ if ((smcmi = kmem_zalloc(sizeof (*smcmi), kmflags)) == NULL) {
+ return (ENOMEM);
+ }
+
+ if (smrt_contig_alloc(smrt, &smcmi->smcmi_contig, len, kmflags,
+ &smcmi->smcmi_va, &smcmi->smcmi_pa) != DDI_SUCCESS) {
+ kmem_free(smcmi, sizeof (*smcmi));
+ return (ENOMEM);
+ }
+
+ bzero(smcmi->smcmi_va, smcmi->smcmi_len);
+
+ smcm->smcm_internal = smcmi;
+
+ smcm->smcm_va_cmd->SG[0].Addr = smcmi->smcmi_pa;
+ smcm->smcm_va_cmd->SG[0].Len = (uint32_t)len;
+ smcm->smcm_va_cmd->Header.SGList = 1;
+ smcm->smcm_va_cmd->Header.SGTotal = 1;
+
+ return (0);
+}
+
+void
+smrt_command_reuse(smrt_command_t *smcm)
+{
+ smrt_t *smrt = smcm->smcm_ctlr;
+
+ mutex_enter(&smrt->smrt_mutex);
+
+ /*
+ * Make sure the command is not currently inflight, then
+ * reset the command status.
+ */
+ VERIFY(!(smcm->smcm_status & SMRT_CMD_STATUS_INFLIGHT));
+ smcm->smcm_status = SMRT_CMD_STATUS_REUSED;
+
+ /*
+ * Ensure we are not trying to reuse a command that is in the finish or
+ * abort queue.
+ */
+ VERIFY(!list_link_active(&smcm->smcm_link_abort));
+ VERIFY(!list_link_active(&smcm->smcm_link_finish));
+
+ /*
+ * Clear the previous tag value.
+ */
+ smcm->smcm_tag = 0;
+ smcm->smcm_va_cmd->Header.Tag.tag_value = 0;
+
+ mutex_exit(&smrt->smrt_mutex);
+}
+
+void
+smrt_command_free(smrt_command_t *smcm)
+{
+ smrt_t *smrt = smcm->smcm_ctlr;
+
+ /*
+ * Ensure the object we are about to free is not currently in the
+ * inflight AVL.
+ */
+ VERIFY(!(smcm->smcm_status & SMRT_CMD_STATUS_INFLIGHT));
+
+ if (smcm->smcm_internal != NULL) {
+ smrt_command_internal_t *smcmi = smcm->smcm_internal;
+
+ smrt_contig_free(&smcmi->smcmi_contig);
+ kmem_free(smcmi, sizeof (*smcmi));
+ }
+
+ smrt_contig_free(&smcm->smcm_contig);
+
+ if (smcm->smcm_type != SMRT_CMDTYPE_PREINIT) {
+ mutex_enter(&smrt->smrt_mutex);
+
+ /*
+ * Ensure we are not trying to free a command that is in the
+ * finish or abort queue.
+ */
+ VERIFY(!list_link_active(&smcm->smcm_link_abort));
+ VERIFY(!list_link_active(&smcm->smcm_link_finish));
+
+ list_remove(&smrt->smrt_commands, smcm);
+
+ mutex_exit(&smrt->smrt_mutex);
+ }
+
+ kmem_free(smcm, sizeof (*smcm));
+}
+
+smrt_command_t *
+smrt_lookup_inflight(smrt_t *smrt, uint32_t tag)
+{
+ smrt_command_t srch;
+
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+
+ bzero(&srch, sizeof (srch));
+ srch.smcm_tag = tag;
+
+ return (avl_find(&smrt->smrt_inflight, &srch, NULL));
+}
diff --git a/usr/src/uts/common/io/scsi/adapters/smrt/smrt_device.c b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_device.c
new file mode 100644
index 0000000000..433b2ea2ee
--- /dev/null
+++ b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_device.c
@@ -0,0 +1,238 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+#include <sys/scsi/adapters/smrt/smrt.h>
+
+/*
+ * We must locate what the CISS specification describes as the "I2O
+ * registers". The Intelligent I/O (I2O) Architecture Specification describes
+ * this somewhat more coherently as "the memory region specified by the first
+ * base address configuration register indicating memory space (offset 10h,
+ * 14h, and so forth)".
+ */
+static int
+smrt_locate_bar(pci_regspec_t *regs, unsigned nregs,
+ unsigned *i2o_bar)
+{
+ /*
+ * Locate the first memory-mapped BAR:
+ */
+ for (unsigned i = 0; i < nregs; i++) {
+ unsigned type = regs[i].pci_phys_hi & PCI_ADDR_MASK;
+
+ if (type == PCI_ADDR_MEM32 || type == PCI_ADDR_MEM64) {
+ *i2o_bar = i;
+ return (DDI_SUCCESS);
+ }
+ }
+
+ return (DDI_FAILURE);
+}
+
+static int
+smrt_locate_cfgtbl(smrt_t *smrt, pci_regspec_t *regs, unsigned nregs,
+ unsigned *ct_bar, uint32_t *baseaddr)
+{
+ uint32_t cfg_offset, mem_offset;
+ unsigned want_type;
+ uint32_t want_bar;
+
+ cfg_offset = smrt_get32(smrt, CISS_I2O_CFGTBL_CFG_OFFSET);
+ mem_offset = smrt_get32(smrt, CISS_I2O_CFGTBL_MEM_OFFSET);
+
+ VERIFY3U(cfg_offset, !=, 0xffffffff);
+ VERIFY3U(mem_offset, !=, 0xffffffff);
+
+ /*
+ * Locate the Configuration Table. Three different values read
+ * from two I2O registers allow us to determine the location:
+ * - the correct PCI BAR offset is in the low 16 bits of
+ * CISS_I2O_CFGTBL_CFG_OFFSET
+ * - bit 16 is 0 for a 32-bit space, and 1 for 64-bit
+ * - the memory offset from the base of this BAR is
+ * in CISS_I2O_CFGTBL_MEM_OFFSET
+ */
+ want_bar = (cfg_offset & 0xffff);
+ want_type = (cfg_offset & (1UL << 16)) ? PCI_ADDR_MEM64 :
+ PCI_ADDR_MEM32;
+
+ DTRACE_PROBE4(locate_cfgtbl, uint32_t, want_bar, unsigned,
+ want_type, uint32_t, cfg_offset, uint32_t, mem_offset);
+
+ for (unsigned i = 0; i < nregs; i++) {
+ unsigned type = regs[i].pci_phys_hi & PCI_ADDR_MASK;
+ unsigned bar = PCI_REG_REG_G(regs[i].pci_phys_hi);
+
+ if (type != PCI_ADDR_MEM32 && type != PCI_ADDR_MEM64) {
+ continue;
+ }
+
+ if (bar == want_bar) {
+ *ct_bar = i;
+ *baseaddr = mem_offset;
+ return (DDI_SUCCESS);
+ }
+ }
+
+ return (DDI_FAILURE);
+}
+
+/*
+ * Determine the PCI vendor and device ID which is a proxy for which generation
+ * of controller we're working with.
+ */
+static int
+smrt_identify_device(smrt_t *smrt)
+{
+ ddi_acc_handle_t pci_hdl;
+
+ if (pci_config_setup(smrt->smrt_dip, &pci_hdl) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+
+ smrt->smrt_pci_vendor = pci_config_get16(pci_hdl, PCI_CONF_VENID);
+ smrt->smrt_pci_device = pci_config_get16(pci_hdl, PCI_CONF_DEVID);
+
+ pci_config_teardown(&pci_hdl);
+
+ return (DDI_SUCCESS);
+}
+
+static int
+smrt_map_device(smrt_t *smrt)
+{
+ pci_regspec_t *regs;
+ uint_t regslen, nregs;
+ dev_info_t *dip = smrt->smrt_dip;
+ int r = DDI_FAILURE;
+
+ /*
+ * Get the list of PCI registers from the DDI property "regs":
+ */
+ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+ "reg", (int **)&regs, &regslen) != DDI_PROP_SUCCESS) {
+ dev_err(dip, CE_WARN, "could not load \"reg\" DDI prop");
+ return (DDI_FAILURE);
+ }
+ nregs = regslen * sizeof (int) / sizeof (pci_regspec_t);
+
+ if (smrt_locate_bar(regs, nregs, &smrt->smrt_i2o_bar) !=
+ DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "did not find any memory BARs");
+ goto out;
+ }
+
+ /*
+ * Map enough of the I2O memory space to enable us to talk to the
+ * device.
+ */
+ if (ddi_regs_map_setup(dip, smrt->smrt_i2o_bar, &smrt->smrt_i2o_space,
+ CISS_I2O_MAP_BASE, CISS_I2O_MAP_LIMIT - CISS_I2O_MAP_BASE,
+ &smrt_dev_attributes, &smrt->smrt_i2o_handle) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "failed to map I2O registers");
+ goto out;
+ }
+ smrt->smrt_init_level |= SMRT_INITLEVEL_I2O_MAPPED;
+
+ if (smrt_locate_cfgtbl(smrt, regs, nregs, &smrt->smrt_ct_bar,
+ &smrt->smrt_ct_baseaddr) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "could not find config table");
+ goto out;
+ }
+
+ /*
+ * Map the Configuration Table.
+ */
+ if (ddi_regs_map_setup(dip, smrt->smrt_ct_bar,
+ (caddr_t *)&smrt->smrt_ct, smrt->smrt_ct_baseaddr,
+ sizeof (CfgTable_t), &smrt_dev_attributes,
+ &smrt->smrt_ct_handle) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "could not map config table");
+ goto out;
+ }
+ smrt->smrt_init_level |= SMRT_INITLEVEL_CFGTBL_MAPPED;
+
+ r = DDI_SUCCESS;
+
+out:
+ ddi_prop_free(regs);
+ return (r);
+}
+
+int
+smrt_device_setup(smrt_t *smrt)
+{
+ /*
+ * Ensure that the controller is installed in such a fashion that it
+ * may become a DMA master.
+ */
+ if (ddi_slaveonly(smrt->smrt_dip) == DDI_SUCCESS) {
+ dev_err(smrt->smrt_dip, CE_WARN, "device cannot become DMA "
+ "master");
+ return (DDI_FAILURE);
+ }
+
+ if (smrt_identify_device(smrt) != DDI_SUCCESS)
+ goto fail;
+
+ if (smrt_map_device(smrt) != DDI_SUCCESS) {
+ goto fail;
+ }
+
+ return (DDI_SUCCESS);
+
+fail:
+ smrt_device_teardown(smrt);
+ return (DDI_FAILURE);
+}
+
+void
+smrt_device_teardown(smrt_t *smrt)
+{
+ if (smrt->smrt_init_level & SMRT_INITLEVEL_CFGTBL_MAPPED) {
+ ddi_regs_map_free(&smrt->smrt_ct_handle);
+ smrt->smrt_init_level &= ~SMRT_INITLEVEL_CFGTBL_MAPPED;
+ }
+
+ if (smrt->smrt_init_level & SMRT_INITLEVEL_I2O_MAPPED) {
+ ddi_regs_map_free(&smrt->smrt_i2o_handle);
+ smrt->smrt_init_level &= ~SMRT_INITLEVEL_I2O_MAPPED;
+ }
+}
+
+uint32_t
+smrt_get32(smrt_t *smrt, offset_t off)
+{
+ VERIFY3S(off, >=, CISS_I2O_MAP_BASE);
+ VERIFY3S(off, <, CISS_I2O_MAP_BASE + CISS_I2O_MAP_LIMIT);
+
+ /* LINTED: E_BAD_PTR_CAST_ALIGN */
+ uint32_t *addr = (uint32_t *)(smrt->smrt_i2o_space +
+ (off - CISS_I2O_MAP_BASE));
+
+ return (ddi_get32(smrt->smrt_i2o_handle, addr));
+}
+
+void
+smrt_put32(smrt_t *smrt, offset_t off, uint32_t val)
+{
+ VERIFY3S(off, >=, CISS_I2O_MAP_BASE);
+ VERIFY3S(off, <, CISS_I2O_MAP_BASE + CISS_I2O_MAP_LIMIT);
+
+ /* LINTED: E_BAD_PTR_CAST_ALIGN */
+ uint32_t *addr = (uint32_t *)(smrt->smrt_i2o_space +
+ (off - CISS_I2O_MAP_BASE));
+
+ ddi_put32(smrt->smrt_i2o_handle, addr, val);
+}
diff --git a/usr/src/uts/common/io/scsi/adapters/smrt/smrt_hba.c b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_hba.c
new file mode 100644
index 0000000000..0eec7c2482
--- /dev/null
+++ b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_hba.c
@@ -0,0 +1,1457 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+#include <sys/scsi/adapters/smrt/smrt.h>
+
+/*
+ * The controller is not allowed to attach.
+ */
+static int
+smrt_ctrl_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
+ scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
+{
+ return (DDI_FAILURE);
+}
+
+/*
+ * The controller is not allowed to send packets.
+ */
+static int
+smrt_ctrl_tran_start(struct scsi_address *sa, struct scsi_pkt *pkt)
+{
+ return (TRAN_BADPKT);
+}
+
+static boolean_t
+smrt_logvol_parse(const char *ua, uint_t *targp)
+{
+ long targ, lun;
+ const char *comma;
+ char *eptr;
+
+ comma = strchr(ua, ',');
+ if (comma == NULL) {
+ return (B_FALSE);
+ }
+
+ /*
+ * We expect the target number for a logical unit number to be zero for
+ * a logical volume.
+ */
+ if (ddi_strtol(comma + 1, &eptr, 16, &lun) != 0 || *eptr != '\0' ||
+ lun != 0) {
+ return (B_FALSE);
+ }
+
+ if (ddi_strtol(ua, &eptr, 16, &targ) != 0 || eptr != comma ||
+ targ < 0 || targ >= SMRT_MAX_LOGDRV) {
+ return (B_FALSE);
+ }
+
+ *targp = (uint_t)targ;
+
+ return (B_TRUE);
+}
+
+static int
+smrt_logvol_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
+ scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
+{
+ _NOTE(ARGUNUSED(hba_dip))
+
+ smrt_volume_t *smlv;
+ smrt_target_t *smtg;
+ const char *ua;
+ uint_t targ;
+
+ smrt_t *smrt = (smrt_t *)hba_tran->tran_hba_private;
+ dev_info_t *dip = smrt->smrt_dip;
+
+ /*
+ * The unit address comes in the form of 'target,lun'. We expect the
+ * lun to be zero. The target is what we set when we added it to the
+ * target map earlier.
+ */
+ ua = scsi_device_unit_address(sd);
+ if (ua == NULL) {
+ return (DDI_FAILURE);
+ }
+
+ if (!smrt_logvol_parse(ua, &targ)) {
+ return (DDI_FAILURE);
+ }
+
+ if ((smtg = kmem_zalloc(sizeof (*smtg), KM_NOSLEEP)) == NULL) {
+ dev_err(dip, CE_WARN, "could not allocate target object "
+ "due to memory exhaustion");
+ return (DDI_FAILURE);
+ }
+
+ mutex_enter(&smrt->smrt_mutex);
+
+ if (smrt->smrt_status & SMRT_CTLR_STATUS_DETACHING) {
+ /*
+ * We are detaching. Do not accept any more requests to
+ * attach targets from the framework.
+ */
+ mutex_exit(&smrt->smrt_mutex);
+ kmem_free(smtg, sizeof (*smtg));
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Look for a logical volume for the SCSI unit address of this target.
+ */
+ if ((smlv = smrt_logvol_lookup_by_id(smrt, targ)) == NULL) {
+ mutex_exit(&smrt->smrt_mutex);
+ kmem_free(smtg, sizeof (*smtg));
+ return (DDI_FAILURE);
+ }
+
+ smtg->smtg_lun.smtg_vol = smlv;
+ smtg->smtg_addr = &smlv->smlv_addr;
+ smtg->smtg_physical = B_FALSE;
+ list_insert_tail(&smlv->smlv_targets, smtg);
+
+ /*
+ * Link this target object to the controller:
+ */
+ smtg->smtg_ctlr = smrt;
+ list_insert_tail(&smrt->smrt_targets, smtg);
+
+ smtg->smtg_scsi_dev = sd;
+ VERIFY(sd->sd_dev == tgt_dip);
+
+ scsi_device_hba_private_set(sd, smtg);
+
+ mutex_exit(&smrt->smrt_mutex);
+ return (DDI_SUCCESS);
+}
+
+static void
+smrt_logvol_tran_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
+ scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
+{
+ _NOTE(ARGUNUSED(hba_dip, tgt_dip))
+
+ smrt_t *smrt = (smrt_t *)hba_tran->tran_hba_private;
+ smrt_target_t *smtg = scsi_device_hba_private_get(sd);
+ smrt_volume_t *smlv = smtg->smtg_lun.smtg_vol;
+
+ VERIFY(smtg->smtg_scsi_dev == sd);
+ VERIFY(smtg->smtg_physical == B_FALSE);
+
+ mutex_enter(&smrt->smrt_mutex);
+ list_remove(&smlv->smlv_targets, smtg);
+ list_remove(&smrt->smrt_targets, smtg);
+
+ scsi_device_hba_private_set(sd, NULL);
+
+ mutex_exit(&smrt->smrt_mutex);
+
+ kmem_free(smtg, sizeof (*smtg));
+}
+
+static int
+smrt_phys_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
+ scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
+{
+ _NOTE(ARGUNUSED(hba_dip))
+
+ smrt_target_t *smtg;
+ smrt_physical_t *smpt;
+ const char *ua, *comma;
+ char *eptr;
+ long lun;
+
+ smrt_t *smrt = (smrt_t *)hba_tran->tran_hba_private;
+ dev_info_t *dip = smrt->smrt_dip;
+
+ /*
+ * The unit address comes in the form of 'target,lun'. We expect the
+ * lun to be zero. The target is what we set when we added it to the
+ * target map earlier.
+ */
+ ua = scsi_device_unit_address(sd);
+ if (ua == NULL)
+ return (DDI_FAILURE);
+
+ comma = strchr(ua, ',');
+ if (comma == NULL) {
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Confirm the LUN is zero. We may want to instead check the scsi
+ * 'lun'/'lun64' property or do so in addition to this logic.
+ */
+ if (ddi_strtol(comma + 1, &eptr, 16, &lun) != 0 || *eptr != '\0' ||
+ lun != 0) {
+ return (DDI_FAILURE);
+ }
+
+ if ((smtg = kmem_zalloc(sizeof (*smtg), KM_NOSLEEP)) == NULL) {
+ dev_err(dip, CE_WARN, "could not allocate target object "
+ "due to memory exhaustion");
+ return (DDI_FAILURE);
+ }
+
+ mutex_enter(&smrt->smrt_mutex);
+
+ if (smrt->smrt_status & SMRT_CTLR_STATUS_DETACHING) {
+ /*
+ * We are detaching. Do not accept any more requests to
+ * attach targets from the framework.
+ */
+ mutex_exit(&smrt->smrt_mutex);
+ kmem_free(smtg, sizeof (*smtg));
+ return (DDI_FAILURE);
+ }
+
+
+ /*
+ * Look for a physical target based on the unit address of the target
+ * (which will encode its WWN and LUN).
+ */
+ smpt = smrt_phys_lookup_by_ua(smrt, ua);
+ if (smpt == NULL) {
+ mutex_exit(&smrt->smrt_mutex);
+ kmem_free(smtg, sizeof (*smtg));
+ return (DDI_FAILURE);
+ }
+
+ smtg->smtg_scsi_dev = sd;
+ smtg->smtg_physical = B_TRUE;
+ smtg->smtg_lun.smtg_phys = smpt;
+ list_insert_tail(&smpt->smpt_targets, smtg);
+ smtg->smtg_addr = &smpt->smpt_addr;
+
+ /*
+ * Link this target object to the controller:
+ */
+ smtg->smtg_ctlr = smrt;
+ list_insert_tail(&smrt->smrt_targets, smtg);
+
+ VERIFY(sd->sd_dev == tgt_dip);
+ smtg->smtg_scsi_dev = sd;
+
+ scsi_device_hba_private_set(sd, smtg);
+ mutex_exit(&smrt->smrt_mutex);
+
+ return (DDI_SUCCESS);
+}
+
+static void
+smrt_phys_tran_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
+ scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
+{
+ _NOTE(ARGUNUSED(hba_dip, tgt_dip))
+
+ smrt_t *smrt = (smrt_t *)hba_tran->tran_hba_private;
+ smrt_target_t *smtg = scsi_device_hba_private_get(sd);
+ smrt_physical_t *smpt = smtg->smtg_lun.smtg_phys;
+
+ VERIFY(smtg->smtg_scsi_dev == sd);
+ VERIFY(smtg->smtg_physical == B_TRUE);
+
+ mutex_enter(&smrt->smrt_mutex);
+ list_remove(&smpt->smpt_targets, smtg);
+ list_remove(&smrt->smrt_targets, smtg);
+
+ scsi_device_hba_private_set(sd, NULL);
+ mutex_exit(&smrt->smrt_mutex);
+ kmem_free(smtg, sizeof (*smtg));
+}
+
+/*
+ * This function is called when the SCSI framework has allocated a packet and
+ * our private per-packet object.
+ *
+ * We choose not to have the framework pre-allocate memory for the CDB.
+ * Instead, we will make available the CDB area in the controller command block
+ * itself.
+ *
+ * Status block memory is allocated by the framework because we passed
+ * SCSI_HBA_TRAN_SCB to scsi_hba_attach_setup(9F).
+ */
+static int
+smrt_tran_setup_pkt(struct scsi_pkt *pkt, int (*callback)(caddr_t),
+ caddr_t arg)
+{
+ _NOTE(ARGUNUSED(arg))
+
+ struct scsi_device *sd;
+ smrt_target_t *smtg;
+ smrt_t *smrt;
+ smrt_command_t *smcm;
+ smrt_command_scsa_t *smcms;
+ int kmflags = callback == SLEEP_FUNC ? KM_SLEEP : KM_NOSLEEP;
+
+ sd = scsi_address_device(&pkt->pkt_address);
+ VERIFY(sd != NULL);
+ smtg = scsi_device_hba_private_get(sd);
+ VERIFY(smtg != NULL);
+ smrt = smtg->smtg_ctlr;
+ VERIFY(smrt != NULL);
+ smcms = (smrt_command_scsa_t *)pkt->pkt_ha_private;
+
+ /*
+ * Check that we have enough space in the command object for the
+ * request from the target driver:
+ */
+ if (pkt->pkt_cdblen > CISS_CDBLEN) {
+ /*
+ * The CDB member of the Request Block of a controller
+ * command is fixed at 16 bytes.
+ */
+ dev_err(smrt->smrt_dip, CE_WARN, "oversize CDB: had %u, "
+ "needed %u", CISS_CDBLEN, pkt->pkt_cdblen);
+ return (-1);
+ }
+
+ /*
+ * Allocate our command block:
+ */
+ if ((smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_SCSA,
+ kmflags)) == NULL) {
+ return (-1);
+ }
+ smcm->smcm_scsa = smcms;
+ smcms->smcms_command = smcm;
+ smcms->smcms_pkt = pkt;
+
+ pkt->pkt_cdbp = &smcm->smcm_va_cmd->Request.CDB[0];
+ smcm->smcm_va_cmd->Request.CDBLen = pkt->pkt_cdblen;
+
+ smcm->smcm_target = smtg;
+
+ return (0);
+}
+
+static void
+smrt_tran_teardown_pkt(struct scsi_pkt *pkt)
+{
+ smrt_command_scsa_t *smcms = (smrt_command_scsa_t *)
+ pkt->pkt_ha_private;
+ smrt_command_t *smcm = smcms->smcms_command;
+
+ smrt_command_free(smcm);
+
+ pkt->pkt_cdbp = NULL;
+}
+
+static void
+smrt_set_arq_data(struct scsi_pkt *pkt, uchar_t key)
+{
+ struct scsi_arq_status *sts;
+
+ VERIFY3U(pkt->pkt_scblen, >=, sizeof (struct scsi_arq_status));
+
+ /* LINTED: E_BAD_PTR_CAST_ALIGN */
+ sts = (struct scsi_arq_status *)(pkt->pkt_scbp);
+ bzero(sts, sizeof (*sts));
+
+ /*
+ * Mock up a CHECK CONDITION SCSI status for the original command:
+ */
+ sts->sts_status.sts_chk = 1;
+
+ /*
+ * Pretend that we successfully performed REQUEST SENSE:
+ */
+ sts->sts_rqpkt_reason = CMD_CMPLT;
+ sts->sts_rqpkt_resid = 0;
+ sts->sts_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
+ STATE_SENT_CMD | STATE_XFERRED_DATA;
+ sts->sts_rqpkt_statistics = 0;
+
+ /*
+ * Return the key value we were provided in the fake sense data:
+ */
+ sts->sts_sensedata.es_valid = 1;
+ sts->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
+ sts->sts_sensedata.es_key = key;
+
+ pkt->pkt_state |= STATE_ARQ_DONE;
+}
+
+/*
+ * When faking up a REPORT LUNS data structure, we simply report one LUN, LUN 0.
+ * We need 16 bytes for this, 4 for the size, 4 reserved bytes, and the 8 for
+ * the actual LUN.
+ */
+static void
+smrt_fake_report_lun(smrt_command_t *smcm, struct scsi_pkt *pkt)
+{
+ size_t sz;
+ char resp[16];
+ struct buf *bp;
+
+ pkt->pkt_reason = CMD_CMPLT;
+ pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD |
+ STATE_GOT_STATUS;
+
+ /*
+ * Check to make sure this is valid. If reserved bits are set or if the
+ * mode is one other than 0x00, 0x01, 0x02, then it's an illegal
+ * request.
+ */
+ if (pkt->pkt_cdbp[1] != 0 || pkt->pkt_cdbp[3] != 0 ||
+ pkt->pkt_cdbp[4] != 0 || pkt->pkt_cdbp[5] != 0 ||
+ pkt->pkt_cdbp[10] != 0 || pkt->pkt_cdbp[11] != 0 ||
+ pkt->pkt_cdbp[2] > 0x2) {
+ smrt_set_arq_data(pkt, KEY_ILLEGAL_REQUEST);
+ return;
+ }
+
+ /*
+ * Construct the actual REPORT LUNS reply. We need to indicate a single
+ * LUN of all zeros. This means that the length needs to be 8 bytes,
+ * the size of the lun. Otherwise, the rest of this structure can be
+ * zeros.
+ */
+ bzero(resp, sizeof (resp));
+ resp[3] = sizeof (scsi_lun_t);
+
+ bp = scsi_pkt2bp(pkt);
+ sz = MIN(sizeof (resp), bp->b_bcount);
+
+ bp_mapin(bp);
+ bcopy(resp, bp->b_un.b_addr, sz);
+ bp_mapout(bp);
+ pkt->pkt_state |= STATE_XFERRED_DATA;
+ pkt->pkt_resid = bp->b_bcount - sz;
+ if (pkt->pkt_scblen >= 1) {
+ pkt->pkt_scbp[0] = STATUS_GOOD;
+ }
+}
+
+static int
+smrt_tran_start(struct scsi_address *sa, struct scsi_pkt *pkt)
+{
+ _NOTE(ARGUNUSED(sa))
+
+ struct scsi_device *sd;
+ smrt_target_t *smtg;
+ smrt_t *smrt;
+ smrt_command_scsa_t *smcms;
+ smrt_command_t *smcm;
+ int r;
+
+ sd = scsi_address_device(&pkt->pkt_address);
+ VERIFY(sd != NULL);
+ smtg = scsi_device_hba_private_get(sd);
+ VERIFY(smtg != NULL);
+ smrt = smtg->smtg_ctlr;
+ VERIFY(smrt != NULL);
+ smcms = (smrt_command_scsa_t *)pkt->pkt_ha_private;
+ VERIFY(smcms != NULL);
+ smcm = smcms->smcms_command;
+ VERIFY(smcm != NULL);
+
+ if (smcm->smcm_status & SMRT_CMD_STATUS_TRAN_START) {
+ /*
+ * This is a retry of a command that has already been
+ * used once. Assign it a new tag number.
+ */
+ smrt_command_reuse(smcm);
+ }
+ smcm->smcm_status |= SMRT_CMD_STATUS_TRAN_START;
+
+ /*
+ * The sophisticated firmware in this controller cannot possibly bear
+ * the following SCSI commands. It appears to return a response with
+ * the status STATUS_ACA_ACTIVE (0x30), which is not something we
+ * expect. Instead, fake up a failure response.
+ */
+ switch (pkt->pkt_cdbp[0]) {
+ case SCMD_FORMAT:
+ case SCMD_LOG_SENSE_G1:
+ case SCMD_MODE_SELECT:
+ case SCMD_PERSISTENT_RESERVE_IN:
+ if (smtg->smtg_physical) {
+ break;
+ }
+
+ smrt->smrt_stats.smrts_ignored_scsi_cmds++;
+ smcm->smcm_status |= SMRT_CMD_STATUS_TRAN_IGNORED;
+
+ /*
+ * Mark the command as completed to the point where we
+ * received a SCSI status code:
+ */
+ pkt->pkt_reason = CMD_CMPLT;
+ pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
+ STATE_SENT_CMD | STATE_GOT_STATUS;
+
+ /*
+ * Mock up sense data for an illegal request:
+ */
+ smrt_set_arq_data(pkt, KEY_ILLEGAL_REQUEST);
+
+ scsi_hba_pkt_comp(pkt);
+ return (TRAN_ACCEPT);
+ case SCMD_REPORT_LUNS:
+ /*
+ * The SMRT controller does not accept a REPORT LUNS command for
+ * logical volumes. As such, we need to fake up a REPORT LUNS
+ * response that has a single LUN, LUN 0.
+ */
+ if (smtg->smtg_physical) {
+ break;
+ }
+
+ smrt_fake_report_lun(smcm, pkt);
+
+ scsi_hba_pkt_comp(pkt);
+ return (TRAN_ACCEPT);
+ default:
+ break;
+ }
+
+ if (pkt->pkt_flags & FLAG_NOINTR) {
+ /*
+ * We must sleep and wait for the completion of this command.
+ */
+ smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
+ }
+
+ /*
+ * Because we provide a tran_setup_pkt(9E) entrypoint, we must now
+ * set up the Scatter/Gather List in the Command to reflect any
+ * DMA resources passed to us by the framework.
+ */
+ if (pkt->pkt_numcookies > smrt->smrt_sg_cnt) {
+ /*
+ * More DMA cookies than we are prepared to handle.
+ */
+ dev_err(smrt->smrt_dip, CE_WARN, "too many DMA cookies (got %u;"
+ " expected %u)", pkt->pkt_numcookies, smrt->smrt_sg_cnt);
+ return (TRAN_BADPKT);
+ }
+ smcm->smcm_va_cmd->Header.SGList = pkt->pkt_numcookies;
+ smcm->smcm_va_cmd->Header.SGTotal = pkt->pkt_numcookies;
+ for (unsigned i = 0; i < pkt->pkt_numcookies; i++) {
+ smcm->smcm_va_cmd->SG[i].Addr =
+ LE_64(pkt->pkt_cookies[i].dmac_laddress);
+ smcm->smcm_va_cmd->SG[i].Len =
+ LE_32(pkt->pkt_cookies[i].dmac_size);
+ }
+
+ /*
+ * Copy logical volume address from the target object:
+ */
+ smcm->smcm_va_cmd->Header.LUN = *smcm->smcm_target->smtg_addr;
+
+ /*
+ * Initialise the command block.
+ */
+ smcm->smcm_va_cmd->Request.CDBLen = pkt->pkt_cdblen;
+ smcm->smcm_va_cmd->Request.Type.Type = CISS_TYPE_CMD;
+ smcm->smcm_va_cmd->Request.Type.Attribute = CISS_ATTR_SIMPLE;
+ smcm->smcm_va_cmd->Request.Timeout = LE_16(pkt->pkt_time);
+ if (pkt->pkt_numcookies > 0) {
+ /*
+ * There are DMA resources; set the transfer direction
+ * appropriately:
+ */
+ if (pkt->pkt_dma_flags & DDI_DMA_READ) {
+ smcm->smcm_va_cmd->Request.Type.Direction =
+ CISS_XFER_READ;
+ } else if (pkt->pkt_dma_flags & DDI_DMA_WRITE) {
+ smcm->smcm_va_cmd->Request.Type.Direction =
+ CISS_XFER_WRITE;
+ } else {
+ smcm->smcm_va_cmd->Request.Type.Direction =
+ CISS_XFER_NONE;
+ }
+ } else {
+ /*
+ * No DMA resources means no transfer.
+ */
+ smcm->smcm_va_cmd->Request.Type.Direction = CISS_XFER_NONE;
+ }
+
+ /*
+ * Initialise the SCSI packet as described in tran_start(9E). We will
+ * progressively update these fields as the command moves through the
+ * submission and completion states.
+ */
+ pkt->pkt_resid = 0;
+ pkt->pkt_reason = CMD_CMPLT;
+ pkt->pkt_statistics = 0;
+ pkt->pkt_state = 0;
+
+ /*
+ * If this SCSI packet has a timeout, configure an appropriate
+ * expiry time:
+ */
+ if (pkt->pkt_time != 0) {
+ smcm->smcm_expiry = gethrtime() + pkt->pkt_time * NANOSEC;
+ }
+
+ /*
+ * Submit the command to the controller.
+ */
+ mutex_enter(&smrt->smrt_mutex);
+
+ /*
+ * If we're dumping, there's a chance that the target we're talking to
+ * could have ended up disappearing during the process of discovery. If
+ * this target is part of the dump device, we check here and return that
+ * we hit a fatal error.
+ */
+ if (ddi_in_panic() && smtg->smtg_gone) {
+ mutex_exit(&smrt->smrt_mutex);
+
+ dev_err(smrt->smrt_dip, CE_WARN, "smrt_submit failed: target "
+ "%s is gone, it did not come back after post-panic reset "
+ "device discovery", scsi_device_unit_address(sd));
+
+ return (TRAN_FATAL_ERROR);
+ }
+
+ smrt->smrt_stats.smrts_tran_starts++;
+ if ((r = smrt_submit(smrt, smcm)) != 0) {
+ mutex_exit(&smrt->smrt_mutex);
+
+ dev_err(smrt->smrt_dip, CE_WARN, "smrt_submit failed %d", r);
+
+ /*
+ * Inform the SCSI framework that we could not submit
+ * the command.
+ */
+ return (r == EAGAIN ? TRAN_BUSY : TRAN_FATAL_ERROR);
+ }
+
+ /*
+ * Update the SCSI packet to reflect submission of the command.
+ */
+ pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD;
+
+ if (pkt->pkt_flags & FLAG_NOINTR) {
+ /*
+ * Poll the controller for completion of the command we
+ * submitted. Once this routine has returned, the completion
+ * callback will have been fired with either an active response
+ * (success or error) or a timeout. The command is freed by
+ * the completion callback, so it may not be referenced again
+ * after this call returns.
+ */
+ (void) smrt_poll_for(smrt, smcm);
+ }
+
+ mutex_exit(&smrt->smrt_mutex);
+ return (TRAN_ACCEPT);
+}
+
+static int
+smrt_tran_reset(struct scsi_address *sa, int level)
+{
+ _NOTE(ARGUNUSED(level))
+
+ struct scsi_device *sd;
+ smrt_target_t *smtg;
+ smrt_t *smrt;
+ smrt_command_t *smcm;
+ int r;
+
+ sd = scsi_address_device(sa);
+ VERIFY(sd != NULL);
+ smtg = scsi_device_hba_private_get(sd);
+ VERIFY(smtg != NULL);
+ smrt = smtg->smtg_ctlr;
+
+ /*
+ * The framework has requested some kind of SCSI reset. A
+ * controller-level soft reset can take a very long time -- often on
+ * the order of 30-60 seconds -- but might well be our only option if
+ * the controller is non-responsive.
+ *
+ * First, check if the controller is responding to pings.
+ */
+again:
+ if ((smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_INTERNAL,
+ KM_NOSLEEP)) == NULL) {
+ return (0);
+ }
+
+ smrt_write_message_nop(smcm, SMRT_PING_CHECK_TIMEOUT);
+
+ mutex_enter(&smrt->smrt_mutex);
+ smrt->smrt_stats.smrts_tran_resets++;
+ if (ddi_in_panic()) {
+ goto skip_check;
+ }
+
+ if (smrt->smrt_status & SMRT_CTLR_STATUS_RESETTING) {
+ /*
+ * The controller is already resetting. Wait for that
+ * to finish.
+ */
+ while (smrt->smrt_status & SMRT_CTLR_STATUS_RESETTING) {
+ cv_wait(&smrt->smrt_cv_finishq, &smrt->smrt_mutex);
+ }
+ }
+
+skip_check:
+ /*
+ * Submit our ping to the controller.
+ */
+ smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
+ smcm->smcm_expiry = gethrtime() + SMRT_PING_CHECK_TIMEOUT * NANOSEC;
+ if (smrt_submit(smrt, smcm) != 0) {
+ mutex_exit(&smrt->smrt_mutex);
+ smrt_command_free(smcm);
+ return (0);
+ }
+
+ if ((r = smrt_poll_for(smrt, smcm)) != 0) {
+ VERIFY3S(r, ==, ETIMEDOUT);
+ VERIFY0(smcm->smcm_status & SMRT_CMD_STATUS_POLL_COMPLETE);
+
+ /*
+ * The ping command timed out. Abandon it now.
+ */
+ dev_err(smrt->smrt_dip, CE_WARN, "controller ping timed out");
+ smcm->smcm_status |= SMRT_CMD_STATUS_ABANDONED;
+ smcm->smcm_status &= ~SMRT_CMD_STATUS_POLLED;
+
+ } else if ((smcm->smcm_status & SMRT_CMD_STATUS_RESET_SENT) ||
+ (smcm->smcm_status & SMRT_CMD_STATUS_ERROR)) {
+ /*
+ * The command completed in error, or a controller reset
+ * was sent while we were trying to ping.
+ */
+ dev_err(smrt->smrt_dip, CE_WARN, "controller ping error");
+ mutex_exit(&smrt->smrt_mutex);
+ smrt_command_free(smcm);
+ mutex_enter(&smrt->smrt_mutex);
+
+ } else {
+ VERIFY(smcm->smcm_status & SMRT_CMD_STATUS_COMPLETE);
+
+ /*
+ * The controller is responsive, and a full soft reset would be
+ * extremely disruptive to the system. Given our spotty
+ * support for some SCSI commands (which can upset the target
+ * drivers) and the historically lax behaviour of the "smrt"
+ * driver, we grit our teeth and pretend we were able to
+ * perform a reset.
+ */
+ mutex_exit(&smrt->smrt_mutex);
+ smrt_command_free(smcm);
+ return (1);
+ }
+
+ /*
+ * If a reset has been initiated in the last 90 seconds, try
+ * another ping.
+ */
+ if (gethrtime() < smrt->smrt_last_reset_start + 90 * NANOSEC) {
+ dev_err(smrt->smrt_dip, CE_WARN, "controller ping failed, but "
+ "was recently reset; retrying ping");
+ mutex_exit(&smrt->smrt_mutex);
+
+ /*
+ * Sleep for a second first.
+ */
+ if (ddi_in_panic()) {
+ drv_usecwait(1 * MICROSEC);
+ } else {
+ delay(drv_usectohz(1 * MICROSEC));
+ }
+ goto again;
+ }
+
+ dev_err(smrt->smrt_dip, CE_WARN, "controller ping failed; resetting "
+ "controller");
+ if (smrt_ctlr_reset(smrt) != 0) {
+ dev_err(smrt->smrt_dip, CE_WARN, "controller reset failure");
+ mutex_exit(&smrt->smrt_mutex);
+ return (0);
+ }
+
+ mutex_exit(&smrt->smrt_mutex);
+ return (1);
+}
+
+static int
+smrt_tran_abort(struct scsi_address *sa, struct scsi_pkt *pkt)
+{
+ struct scsi_device *sd;
+ smrt_target_t *smtg;
+ smrt_t *smrt;
+ smrt_command_t *smcm = NULL;
+ smrt_command_t *abort_smcm;
+
+ sd = scsi_address_device(sa);
+ VERIFY(sd != NULL);
+ smtg = scsi_device_hba_private_get(sd);
+ VERIFY(smtg != NULL);
+ smrt = smtg->smtg_ctlr;
+ VERIFY(smrt != NULL);
+
+
+ if ((abort_smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_INTERNAL,
+ KM_NOSLEEP)) == NULL) {
+ /*
+ * No resources available to send an abort message.
+ */
+ return (0);
+ }
+
+ mutex_enter(&smrt->smrt_mutex);
+ smrt->smrt_stats.smrts_tran_aborts++;
+ if (pkt != NULL) {
+ /*
+ * The framework wants us to abort a specific SCSI packet.
+ */
+ smrt_command_scsa_t *smcms = (smrt_command_scsa_t *)
+ pkt->pkt_ha_private;
+ smcm = smcms->smcms_command;
+
+ if (!(smcm->smcm_status & SMRT_CMD_STATUS_INFLIGHT)) {
+ /*
+ * This message is not currently in flight, so we
+ * cannot abort it.
+ */
+ goto fail;
+ }
+
+ if (smcm->smcm_status & SMRT_CMD_STATUS_ABORT_SENT) {
+ /*
+ * An abort message for this command has already been
+ * sent to the controller. Return failure.
+ */
+ goto fail;
+ }
+
+ smrt_write_message_abort_one(abort_smcm, smcm->smcm_tag);
+ } else {
+ /*
+ * The framework wants us to abort every in flight command
+ * for the target with this address.
+ */
+ smrt_write_message_abort_all(abort_smcm, smtg->smtg_addr);
+ }
+
+ /*
+ * Submit the abort message to the controller.
+ */
+ abort_smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
+ if (smrt_submit(smrt, abort_smcm) != 0) {
+ goto fail;
+ }
+
+ if (pkt != NULL) {
+ /*
+ * Record some debugging information about the abort we
+ * sent:
+ */
+ smcm->smcm_abort_time = gethrtime();
+ smcm->smcm_abort_tag = abort_smcm->smcm_tag;
+
+ /*
+ * Mark the command as aborted so that we do not send
+ * a second abort message:
+ */
+ smcm->smcm_status |= SMRT_CMD_STATUS_ABORT_SENT;
+ }
+
+ /*
+ * Poll for completion of the abort message. Note that this function
+ * only fails if we set a timeout on the command, which we have not
+ * done.
+ */
+ VERIFY0(smrt_poll_for(smrt, abort_smcm));
+
+ if ((abort_smcm->smcm_status & SMRT_CMD_STATUS_RESET_SENT) ||
+ (abort_smcm->smcm_status & SMRT_CMD_STATUS_ERROR)) {
+ /*
+ * Either the controller was reset or the abort command
+ * failed.
+ */
+ goto fail;
+ }
+
+ /*
+ * The command was successfully aborted.
+ */
+ mutex_exit(&smrt->smrt_mutex);
+ smrt_command_free(abort_smcm);
+ return (1);
+
+fail:
+ mutex_exit(&smrt->smrt_mutex);
+ smrt_command_free(abort_smcm);
+ return (0);
+}
+
+static void
+smrt_hba_complete_status(smrt_command_t *smcm)
+{
+ ErrorInfo_t *ei = smcm->smcm_va_err;
+ struct scsi_pkt *pkt = smcm->smcm_scsa->smcms_pkt;
+
+ bzero(pkt->pkt_scbp, pkt->pkt_scblen);
+
+ if (ei->ScsiStatus != STATUS_CHECK) {
+ /*
+ * If the SCSI status is not CHECK CONDITION, we don't want
+ * to try and read the sense data buffer.
+ */
+ goto simple_status;
+ }
+
+ if (pkt->pkt_scblen < sizeof (struct scsi_arq_status)) {
+ /*
+ * There is not enough room for a request sense structure.
+ * Fall back to reporting just the SCSI status code.
+ */
+ goto simple_status;
+ }
+
+ /* LINTED: E_BAD_PTR_CAST_ALIGN */
+ struct scsi_arq_status *sts = (struct scsi_arq_status *)pkt->pkt_scbp;
+
+ /*
+ * Copy in the SCSI status from the original command.
+ */
+ bcopy(&ei->ScsiStatus, &sts->sts_status, sizeof (sts->sts_status));
+
+ /*
+ * Mock up a successful REQUEST SENSE:
+ */
+ sts->sts_rqpkt_reason = CMD_CMPLT;
+ sts->sts_rqpkt_resid = 0;
+ sts->sts_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
+ STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS;
+ sts->sts_rqpkt_statistics = 0;
+
+ /*
+ * The sense data from the controller should be copied into place
+ * starting at the "sts_sensedata" member of the auto request
+ * sense object.
+ */
+ size_t sense_len = pkt->pkt_scblen - offsetof(struct scsi_arq_status,
+ sts_sensedata);
+ if (ei->SenseLen < sense_len) {
+ /*
+ * Only copy sense data bytes that are within the region
+ * the controller marked as valid.
+ */
+ sense_len = ei->SenseLen;
+ }
+ bcopy(ei->SenseInfo, &sts->sts_sensedata, sense_len);
+
+ pkt->pkt_state |= STATE_ARQ_DONE;
+ return;
+
+simple_status:
+ if (pkt->pkt_scblen < sizeof (struct scsi_status)) {
+ /*
+ * There is not even enough room for the SCSI status byte.
+ */
+ return;
+ }
+
+ bcopy(&ei->ScsiStatus, pkt->pkt_scbp, sizeof (struct scsi_status));
+}
+
+static void
+smrt_hba_complete_log_error(smrt_command_t *smcm, const char *name)
+{
+ smrt_t *smrt = smcm->smcm_ctlr;
+ ErrorInfo_t *ei = smcm->smcm_va_err;
+
+ dev_err(smrt->smrt_dip, CE_WARN, "!SCSI command failed: %s: "
+ "SCSI op %x, CISS status %x, SCSI status %x", name,
+ (unsigned)smcm->smcm_va_cmd->Request.CDB[0],
+ (unsigned)ei->CommandStatus, (unsigned)ei->ScsiStatus);
+}
+
+/*
+ * Completion routine for commands submitted to the controller via the SCSI
+ * framework.
+ */
+void
+smrt_hba_complete(smrt_command_t *smcm)
+{
+ smrt_t *smrt = smcm->smcm_ctlr;
+ ErrorInfo_t *ei = smcm->smcm_va_err;
+ struct scsi_pkt *pkt = smcm->smcm_scsa->smcms_pkt;
+
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+
+ pkt->pkt_resid = ei->ResidualCnt;
+
+ /*
+ * Check if the controller was reset while this packet was in flight.
+ */
+ if (smcm->smcm_status & SMRT_CMD_STATUS_RESET_SENT) {
+ if (pkt->pkt_reason != CMD_CMPLT) {
+ /*
+ * If another error status has already been written,
+ * do not overwrite it.
+ */
+ pkt->pkt_reason = CMD_RESET;
+ }
+ pkt->pkt_statistics |= STAT_BUS_RESET | STAT_DEV_RESET;
+ goto finish;
+ }
+
+ if (!(smcm->smcm_status & SMRT_CMD_STATUS_ERROR)) {
+ /*
+ * The command was completed without error by the controller.
+ *
+ * As per the specification, if an error was not signalled
+ * by the controller through the CISS transport method,
+ * the error information (including CommandStatus) has not
+ * been written and should not be checked.
+ */
+ pkt->pkt_state |= STATE_XFERRED_DATA | STATE_GOT_STATUS;
+ goto finish;
+ }
+
+ /*
+ * Check the completion status to determine what befell this request.
+ */
+ switch (ei->CommandStatus) {
+ case CISS_CMD_SUCCESS:
+ /*
+ * In a certain sense, the specification contradicts itself.
+ * On the one hand, it suggests that a successful command
+ * will not result in a controller write to the error
+ * information block; on the other hand, it makes room
+ * for a status code (0) which denotes a successful
+ * execution.
+ *
+ * To be on the safe side, we check for that condition here.
+ */
+ pkt->pkt_state |= STATE_XFERRED_DATA | STATE_GOT_STATUS;
+ break;
+
+ case CISS_CMD_DATA_UNDERRUN:
+ /*
+ * A data underrun occurred. Ideally this will result in
+ * an appropriate SCSI status and sense data.
+ */
+ pkt->pkt_state |= STATE_XFERRED_DATA | STATE_GOT_STATUS;
+ break;
+
+ case CISS_CMD_TARGET_STATUS:
+ /*
+ * The command completed, but an error occurred. We need
+ * to provide the sense data to the SCSI framework.
+ */
+ pkt->pkt_state |= STATE_XFERRED_DATA | STATE_GOT_STATUS;
+ break;
+
+ case CISS_CMD_DATA_OVERRUN:
+ /*
+ * Data overrun has occurred.
+ */
+ smrt_hba_complete_log_error(smcm, "data overrun");
+ pkt->pkt_reason = CMD_DATA_OVR;
+ pkt->pkt_state |= STATE_XFERRED_DATA | STATE_GOT_STATUS;
+ break;
+
+ case CISS_CMD_INVALID:
+ /*
+ * One or more fields in the command has invalid data.
+ */
+ smrt_hba_complete_log_error(smcm, "invalid command");
+ pkt->pkt_reason = CMD_BADMSG;
+ pkt->pkt_state |= STATE_GOT_STATUS;
+ break;
+
+ case CISS_CMD_PROTOCOL_ERR:
+ /*
+ * An error occurred in communication with the end device.
+ */
+ smrt_hba_complete_log_error(smcm, "protocol error");
+ pkt->pkt_reason = CMD_BADMSG;
+ pkt->pkt_state |= STATE_GOT_STATUS;
+ break;
+
+ case CISS_CMD_HARDWARE_ERR:
+ /*
+ * A hardware error occurred.
+ */
+ smrt_hba_complete_log_error(smcm, "hardware error");
+ pkt->pkt_reason = CMD_INCOMPLETE;
+ break;
+
+ case CISS_CMD_CONNECTION_LOST:
+ /*
+ * The connection with the end device cannot be
+ * re-established.
+ */
+ smrt_hba_complete_log_error(smcm, "connection lost");
+ pkt->pkt_reason = CMD_INCOMPLETE;
+ break;
+
+ case CISS_CMD_ABORTED:
+ case CISS_CMD_UNSOLICITED_ABORT:
+ if (smcm->smcm_status & SMRT_CMD_STATUS_TIMEOUT) {
+ /*
+ * This abort was arranged by the periodic routine
+ * in response to an elapsed timeout.
+ */
+ pkt->pkt_reason = CMD_TIMEOUT;
+ pkt->pkt_statistics |= STAT_TIMEOUT;
+ } else {
+ pkt->pkt_reason = CMD_ABORTED;
+ }
+ pkt->pkt_state |= STATE_XFERRED_DATA | STATE_GOT_STATUS;
+ pkt->pkt_statistics |= STAT_ABORTED;
+ break;
+
+ case CISS_CMD_TIMEOUT:
+ smrt_hba_complete_log_error(smcm, "timeout");
+ pkt->pkt_reason = CMD_TIMEOUT;
+ pkt->pkt_statistics |= STAT_TIMEOUT;
+ break;
+
+ default:
+ /*
+ * This is an error that we were not prepared to handle.
+ * Signal a generic transport-level error to the framework.
+ */
+ smrt_hba_complete_log_error(smcm, "unexpected error");
+ pkt->pkt_reason = CMD_TRAN_ERR;
+ }
+
+ /*
+ * Attempt to read a SCSI status code and any automatic
+ * request sense data that may exist:
+ */
+ smrt_hba_complete_status(smcm);
+
+finish:
+ mutex_exit(&smrt->smrt_mutex);
+ scsi_hba_pkt_comp(pkt);
+ mutex_enter(&smrt->smrt_mutex);
+}
+
+static int
+smrt_getcap(struct scsi_address *sa, char *cap, int whom)
+{
+ _NOTE(ARGUNUSED(whom))
+
+ struct scsi_device *sd;
+ smrt_target_t *smtg;
+ smrt_t *smrt;
+ int index;
+
+ sd = scsi_address_device(sa);
+ VERIFY(sd != NULL);
+ smtg = scsi_device_hba_private_get(sd);
+ VERIFY(smtg != NULL);
+ smrt = smtg->smtg_ctlr;
+ VERIFY(smrt != NULL);
+
+ if ((index = scsi_hba_lookup_capstr(cap)) == DDI_FAILURE) {
+ /*
+ * This capability string could not be translated to an
+ * ID number, so it must not exist.
+ */
+ return (-1);
+ }
+
+ switch (index) {
+ case SCSI_CAP_CDB_LEN:
+ /*
+ * The CDB field in the CISS request block is fixed at 16
+ * bytes.
+ */
+ return (CISS_CDBLEN);
+
+ case SCSI_CAP_DMA_MAX:
+ if (smrt->smrt_dma_attr.dma_attr_maxxfer > INT_MAX) {
+ return (INT_MAX);
+ }
+ return ((int)smrt->smrt_dma_attr.dma_attr_maxxfer);
+
+ case SCSI_CAP_SECTOR_SIZE:
+ if (smrt->smrt_dma_attr.dma_attr_granular > INT_MAX) {
+ return (-1);
+ }
+ return ((int)smrt->smrt_dma_attr.dma_attr_granular);
+
+ /*
+ * If this target corresponds to a physical device, then we always
+ * indicate that we're on a SAS interconnect. Otherwise, we default to
+ * saying that we're on a parallel bus. We can't use SAS for
+ * everything, unfortunately. When you declare yourself to be a SAS
+ * interconnect, it's expected that you have a full 16-byte WWN as the
+ * target. If not, devfsadm will not be able to enumerate the device
+ * and create /dev/[r]dsk entries.
+ */
+ case SCSI_CAP_INTERCONNECT_TYPE:
+ if (smtg->smtg_physical) {
+ return (INTERCONNECT_SAS);
+ } else {
+ return (INTERCONNECT_PARALLEL);
+ }
+
+ case SCSI_CAP_DISCONNECT:
+ case SCSI_CAP_SYNCHRONOUS:
+ case SCSI_CAP_WIDE_XFER:
+ case SCSI_CAP_ARQ:
+ case SCSI_CAP_UNTAGGED_QING:
+ case SCSI_CAP_TAGGED_QING:
+ /*
+ * These capabilities are supported by the driver and the
+ * controller. See scsi_ifgetcap(9F) for more information.
+ */
+ return (1);
+
+ case SCSI_CAP_INITIATOR_ID:
+ case SCSI_CAP_RESET_NOTIFICATION:
+ /*
+ * These capabilities are not supported.
+ */
+ return (0);
+
+ default:
+ /*
+ * The property in question is not known to this driver.
+ */
+ return (-1);
+ }
+}
+
+/* ARGSUSED */
+static int
+smrt_setcap(struct scsi_address *sa, char *cap, int value, int whom)
+{
+ int index;
+
+ if ((index = scsi_hba_lookup_capstr(cap)) == DDI_FAILURE) {
+ /*
+ * This capability string could not be translated to an
+ * ID number, so it must not exist.
+ */
+ return (-1);
+ }
+
+ if (whom == 0) {
+ /*
+ * When whom is 0, this is a request to set a capability for
+ * all targets. As per the recommendation in tran_setcap(9E),
+ * we do not support this mode of operation.
+ */
+ return (-1);
+ }
+
+ switch (index) {
+ case SCSI_CAP_CDB_LEN:
+ case SCSI_CAP_DMA_MAX:
+ case SCSI_CAP_SECTOR_SIZE:
+ case SCSI_CAP_INITIATOR_ID:
+ case SCSI_CAP_DISCONNECT:
+ case SCSI_CAP_SYNCHRONOUS:
+ case SCSI_CAP_WIDE_XFER:
+ case SCSI_CAP_ARQ:
+ case SCSI_CAP_UNTAGGED_QING:
+ case SCSI_CAP_TAGGED_QING:
+ case SCSI_CAP_RESET_NOTIFICATION:
+ case SCSI_CAP_INTERCONNECT_TYPE:
+ /*
+ * We do not support changing any capabilities at this time.
+ */
+ return (0);
+
+ default:
+ /*
+ * The capability in question is not known to this driver.
+ */
+ return (-1);
+ }
+}
+
+int
+smrt_ctrl_hba_setup(smrt_t *smrt)
+{
+ int flags;
+ dev_info_t *dip = smrt->smrt_dip;
+ scsi_hba_tran_t *tran;
+
+ if ((tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP)) == NULL) {
+ dev_err(dip, CE_WARN, "could not allocate SCSA resources");
+ return (DDI_FAILURE);
+ }
+
+ smrt->smrt_hba_tran = tran;
+ tran->tran_hba_private = smrt;
+
+ tran->tran_tgt_init = smrt_ctrl_tran_tgt_init;
+ tran->tran_tgt_probe = scsi_hba_probe;
+
+ tran->tran_start = smrt_ctrl_tran_start;
+
+ tran->tran_getcap = smrt_getcap;
+ tran->tran_setcap = smrt_setcap;
+
+ tran->tran_setup_pkt = smrt_tran_setup_pkt;
+ tran->tran_teardown_pkt = smrt_tran_teardown_pkt;
+ tran->tran_hba_len = sizeof (smrt_command_scsa_t);
+ tran->tran_interconnect_type = INTERCONNECT_SAS;
+
+ flags = SCSI_HBA_HBA | SCSI_HBA_TRAN_SCB | SCSI_HBA_ADDR_COMPLEX;
+ if (scsi_hba_attach_setup(dip, &smrt->smrt_dma_attr, tran, flags) !=
+ DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "could not attach to SCSA framework");
+ scsi_hba_tran_free(tran);
+ return (DDI_FAILURE);
+ }
+
+ smrt->smrt_init_level |= SMRT_INITLEVEL_SCSA;
+ return (DDI_SUCCESS);
+}
+
+void
+smrt_ctrl_hba_teardown(smrt_t *smrt)
+{
+ if (smrt->smrt_init_level & SMRT_INITLEVEL_SCSA) {
+ VERIFY(scsi_hba_detach(smrt->smrt_dip) != DDI_FAILURE);
+ scsi_hba_tran_free(smrt->smrt_hba_tran);
+ smrt->smrt_init_level &= ~SMRT_INITLEVEL_SCSA;
+ }
+}
+
+int
+smrt_logvol_hba_setup(smrt_t *smrt, dev_info_t *iport)
+{
+ scsi_hba_tran_t *tran;
+
+ tran = ddi_get_driver_private(iport);
+ if (tran == NULL)
+ return (DDI_FAILURE);
+
+ tran->tran_tgt_init = smrt_logvol_tran_tgt_init;
+ tran->tran_tgt_free = smrt_logvol_tran_tgt_free;
+
+ tran->tran_start = smrt_tran_start;
+ tran->tran_reset = smrt_tran_reset;
+ tran->tran_abort = smrt_tran_abort;
+
+ tran->tran_hba_private = smrt;
+
+ mutex_enter(&smrt->smrt_mutex);
+ if (scsi_hba_tgtmap_create(iport, SCSI_TM_FULLSET, MICROSEC,
+ 2 * MICROSEC, smrt, smrt_logvol_tgtmap_activate,
+ smrt_logvol_tgtmap_deactivate, &smrt->smrt_virt_tgtmap) !=
+ DDI_SUCCESS) {
+ return (DDI_FAILURE);
+ }
+
+ smrt_discover_request(smrt);
+ mutex_exit(&smrt->smrt_mutex);
+
+ return (DDI_SUCCESS);
+}
+
+void
+smrt_logvol_hba_teardown(smrt_t *smrt, dev_info_t *iport)
+{
+ ASSERT(smrt->smrt_virt_iport == iport);
+
+ mutex_enter(&smrt->smrt_mutex);
+
+ if (smrt->smrt_virt_tgtmap != NULL) {
+ scsi_hba_tgtmap_t *t;
+
+ /*
+ * Ensure that we can't be racing with discovery.
+ */
+ while (smrt->smrt_status & SMRT_CTLR_DISCOVERY_RUNNING) {
+ mutex_exit(&smrt->smrt_mutex);
+ ddi_taskq_wait(smrt->smrt_discover_taskq);
+ mutex_enter(&smrt->smrt_mutex);
+ }
+
+ t = smrt->smrt_virt_tgtmap;
+ smrt->smrt_virt_tgtmap = NULL;
+ mutex_exit(&smrt->smrt_mutex);
+ scsi_hba_tgtmap_destroy(t);
+ mutex_enter(&smrt->smrt_mutex);
+ }
+
+ mutex_exit(&smrt->smrt_mutex);
+}
+
+int
+smrt_phys_hba_setup(smrt_t *smrt, dev_info_t *iport)
+{
+ scsi_hba_tran_t *tran;
+
+ tran = ddi_get_driver_private(iport);
+ if (tran == NULL)
+ return (DDI_FAILURE);
+
+ tran->tran_tgt_init = smrt_phys_tran_tgt_init;
+ tran->tran_tgt_free = smrt_phys_tran_tgt_free;
+
+ tran->tran_start = smrt_tran_start;
+ tran->tran_reset = smrt_tran_reset;
+ tran->tran_abort = smrt_tran_abort;
+
+ tran->tran_hba_private = smrt;
+
+ mutex_enter(&smrt->smrt_mutex);
+ if (scsi_hba_tgtmap_create(iport, SCSI_TM_FULLSET, MICROSEC,
+ 2 * MICROSEC, smrt, smrt_phys_tgtmap_activate,
+ smrt_phys_tgtmap_deactivate, &smrt->smrt_phys_tgtmap) !=
+ DDI_SUCCESS) {
+ return (DDI_FAILURE);
+ }
+
+ smrt_discover_request(smrt);
+ mutex_exit(&smrt->smrt_mutex);
+
+ return (DDI_SUCCESS);
+}
+
+void
+smrt_phys_hba_teardown(smrt_t *smrt, dev_info_t *iport)
+{
+ ASSERT(smrt->smrt_phys_iport == iport);
+
+ mutex_enter(&smrt->smrt_mutex);
+
+ if (smrt->smrt_phys_tgtmap != NULL) {
+ scsi_hba_tgtmap_t *t;
+
+ /*
+ * Ensure that we can't be racing with discovery.
+ */
+ while (smrt->smrt_status & SMRT_CTLR_DISCOVERY_RUNNING) {
+ mutex_exit(&smrt->smrt_mutex);
+ ddi_taskq_wait(smrt->smrt_discover_taskq);
+ mutex_enter(&smrt->smrt_mutex);
+ }
+
+ t = smrt->smrt_phys_tgtmap;
+ smrt->smrt_phys_tgtmap = NULL;
+ mutex_exit(&smrt->smrt_mutex);
+ scsi_hba_tgtmap_destroy(t);
+ mutex_enter(&smrt->smrt_mutex);
+ }
+
+ mutex_exit(&smrt->smrt_mutex);
+}
diff --git a/usr/src/uts/common/io/scsi/adapters/smrt/smrt_interrupts.c b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_interrupts.c
new file mode 100644
index 0000000000..18d5b8e936
--- /dev/null
+++ b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_interrupts.c
@@ -0,0 +1,286 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+#include <sys/scsi/adapters/smrt/smrt.h>
+
+static char *
+smrt_interrupt_type_name(int type)
+{
+ switch (type) {
+ case DDI_INTR_TYPE_MSIX:
+ return ("MSI-X");
+ case DDI_INTR_TYPE_MSI:
+ return ("MSI");
+ case DDI_INTR_TYPE_FIXED:
+ return ("fixed");
+ default:
+ return ("?");
+ }
+}
+
+static boolean_t
+smrt_try_msix(smrt_t *smrt)
+{
+ char *fwver = smrt->smrt_versions.smrtv_firmware_rev;
+
+ /*
+ * Generation 9 controllers end up having a different firmware
+ * versioning scheme than others. If this is a generation 9 controller,
+ * which all share the same PCI device ID, then we default to MSI.
+ */
+ if (smrt->smrt_pci_vendor == SMRT_VENDOR_HP &&
+ smrt->smrt_pci_device == SMRT_DEVICE_GEN9) {
+ return (B_FALSE);
+ }
+
+ if (fwver[0] == '8' && fwver[1] == '.' && isdigit(fwver[2]) &&
+ isdigit(fwver[3])) {
+ /*
+ * Version 8.00 of the Smart Array firmware appears to have
+ * broken MSI support on at least one controller. We could
+ * blindly try MSI-X everywhere, except that on at least some
+ * 6.XX firmware versions, MSI-X interrupts do not appear
+ * to be triggered for Simple Transport Method command
+ * completions.
+ *
+ * For now, assume we should try for MSI-X with all 8.XX
+ * versions of the firmware.
+ */
+ dev_err(smrt->smrt_dip, CE_NOTE, "!trying MSI-X interrupts "
+ "to work around 8.XX firmware defect");
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+static int
+smrt_interrupts_disable(smrt_t *smrt)
+{
+ if (smrt->smrt_interrupt_cap & DDI_INTR_FLAG_BLOCK) {
+ return (ddi_intr_block_disable(smrt->smrt_interrupts,
+ smrt->smrt_ninterrupts));
+ } else {
+ VERIFY3S(smrt->smrt_ninterrupts, ==, 1);
+
+ return (ddi_intr_disable(smrt->smrt_interrupts[0]));
+ }
+}
+
+int
+smrt_interrupts_enable(smrt_t *smrt)
+{
+ int ret;
+
+ VERIFY(!(smrt->smrt_init_level & SMRT_INITLEVEL_INT_ENABLED));
+
+ if (smrt->smrt_interrupt_cap & DDI_INTR_FLAG_BLOCK) {
+ ret = ddi_intr_block_enable(smrt->smrt_interrupts,
+ smrt->smrt_ninterrupts);
+ } else {
+ VERIFY3S(smrt->smrt_ninterrupts, ==, 1);
+
+ ret = ddi_intr_enable(smrt->smrt_interrupts[0]);
+ }
+
+ if (ret == DDI_SUCCESS) {
+ smrt->smrt_init_level |= SMRT_INITLEVEL_INT_ENABLED;
+ }
+
+ return (ret);
+}
+
+static void
+smrt_interrupts_free(smrt_t *smrt)
+{
+ for (int i = 0; i < smrt->smrt_ninterrupts; i++) {
+ (void) ddi_intr_free(smrt->smrt_interrupts[i]);
+ }
+ smrt->smrt_ninterrupts = 0;
+ smrt->smrt_interrupt_type = 0;
+ smrt->smrt_interrupt_cap = 0;
+ smrt->smrt_interrupt_pri = 0;
+}
+
+static int
+smrt_interrupts_alloc(smrt_t *smrt, int type)
+{
+ dev_info_t *dip = smrt->smrt_dip;
+ int nintrs = 0;
+ int navail = 0;
+
+ if (ddi_intr_get_nintrs(dip, type, &nintrs) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "could not count %s interrupts",
+ smrt_interrupt_type_name(type));
+ return (DDI_FAILURE);
+ }
+ if (nintrs < 1) {
+ dev_err(dip, CE_WARN, "no %s interrupts supported",
+ smrt_interrupt_type_name(type));
+ return (DDI_FAILURE);
+ }
+
+ if (ddi_intr_get_navail(dip, type, &navail) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "could not count available %s "
+ "interrupts", smrt_interrupt_type_name(type));
+ return (DDI_FAILURE);
+ }
+ if (navail < 1) {
+ dev_err(dip, CE_WARN, "no %s interrupts available",
+ smrt_interrupt_type_name(type));
+ return (DDI_FAILURE);
+ }
+
+ if (ddi_intr_alloc(dip, smrt->smrt_interrupts, type, 0, 1,
+ &smrt->smrt_ninterrupts, DDI_INTR_ALLOC_STRICT) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "%s interrupt allocation failed",
+ smrt_interrupt_type_name(type));
+ smrt_interrupts_free(smrt);
+ return (DDI_FAILURE);
+ }
+
+ smrt->smrt_init_level |= SMRT_INITLEVEL_INT_ALLOC;
+ smrt->smrt_interrupt_type = type;
+ return (DDI_SUCCESS);
+}
+
+int
+smrt_interrupts_setup(smrt_t *smrt)
+{
+ int types;
+ unsigned ipri;
+ uint_t (*hw_isr)(caddr_t, caddr_t);
+ dev_info_t *dip = smrt->smrt_dip;
+
+ /*
+ * Select the correct hardware interrupt service routine for the
+ * Transport Method we have configured:
+ */
+ switch (smrt->smrt_ctlr_mode) {
+ case SMRT_CTLR_MODE_SIMPLE:
+ hw_isr = smrt_isr_hw_simple;
+ break;
+ default:
+ panic("unknown controller mode");
+ }
+
+ if (ddi_intr_get_supported_types(dip, &types) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "could not get support interrupts");
+ goto fail;
+ }
+
+ /*
+ * At least one firmware version has been released for the Smart Array
+ * line with entirely defective MSI support. The specification is
+ * somewhat unclear on the precise nature of MSI-X support with Smart
+ * Array controllers, particularly with respect to the Simple Transport
+ * Method, but for those broken firmware versions we need to try
+ * anyway.
+ */
+ if (smrt_try_msix(smrt) && (types & DDI_INTR_TYPE_MSIX)) {
+ if (smrt_interrupts_alloc(smrt, DDI_INTR_TYPE_MSIX) ==
+ DDI_SUCCESS) {
+ goto add_handler;
+ }
+ }
+
+ /*
+ * If MSI-X is not available, or not expected to work, fall back to
+ * MSI.
+ */
+ if (types & DDI_INTR_TYPE_MSI) {
+ if (smrt_interrupts_alloc(smrt, DDI_INTR_TYPE_MSI) ==
+ DDI_SUCCESS) {
+ goto add_handler;
+ }
+ }
+
+ /*
+ * If neither MSI-X nor MSI is available, fall back to fixed
+ * interrupts. Note that the use of fixed interrupts has been
+ * observed, with some combination of controllers and systems, to
+ * result in interrupts stopping completely at random times.
+ */
+ if (types & DDI_INTR_TYPE_FIXED) {
+ if (smrt_interrupts_alloc(smrt, DDI_INTR_TYPE_FIXED) ==
+ DDI_SUCCESS) {
+ goto add_handler;
+ }
+ }
+
+ /*
+ * We were unable to allocate any interrupts.
+ */
+ dev_err(dip, CE_WARN, "interrupt allocation failed");
+ goto fail;
+
+add_handler:
+ /*
+ * Ensure that we have not been given a high-level interrupt, as our
+ * interrupt handlers do not support them.
+ */
+ if (ddi_intr_get_pri(smrt->smrt_interrupts[0], &ipri) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "could not determine interrupt priority");
+ goto fail;
+ }
+ if (ipri >= ddi_intr_get_hilevel_pri()) {
+ dev_err(dip, CE_WARN, "high level interrupts not supported");
+ goto fail;
+ }
+ smrt->smrt_interrupt_pri = ipri;
+
+ if (ddi_intr_get_cap(smrt->smrt_interrupts[0],
+ &smrt->smrt_interrupt_cap) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "could not get %s interrupt cap",
+ smrt_interrupt_type_name(smrt->smrt_interrupt_type));
+ goto fail;
+ }
+
+ if (ddi_intr_add_handler(smrt->smrt_interrupts[0], hw_isr,
+ (caddr_t)smrt, NULL) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "adding %s interrupt failed",
+ smrt_interrupt_type_name(smrt->smrt_interrupt_type));
+ goto fail;
+ }
+ smrt->smrt_init_level |= SMRT_INITLEVEL_INT_ADDED;
+
+ return (DDI_SUCCESS);
+
+fail:
+ smrt_interrupts_teardown(smrt);
+ return (DDI_FAILURE);
+}
+
+void
+smrt_interrupts_teardown(smrt_t *smrt)
+{
+ if (smrt->smrt_init_level & SMRT_INITLEVEL_INT_ENABLED) {
+ (void) smrt_interrupts_disable(smrt);
+
+ smrt->smrt_init_level &= ~SMRT_INITLEVEL_INT_ENABLED;
+ }
+
+ if (smrt->smrt_init_level & SMRT_INITLEVEL_INT_ADDED) {
+ (void) ddi_intr_remove_handler(smrt->smrt_interrupts[0]);
+
+ smrt->smrt_init_level &= ~SMRT_INITLEVEL_INT_ADDED;
+ }
+
+ if (smrt->smrt_init_level & SMRT_INITLEVEL_INT_ALLOC) {
+ smrt_interrupts_free(smrt);
+
+ smrt->smrt_init_level &= ~SMRT_INITLEVEL_INT_ALLOC;
+ }
+}
diff --git a/usr/src/uts/common/io/scsi/adapters/smrt/smrt_logvol.c b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_logvol.c
new file mode 100644
index 0000000000..05963ac2e2
--- /dev/null
+++ b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_logvol.c
@@ -0,0 +1,367 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+#include <sys/scsi/adapters/smrt/smrt.h>
+
+static void
+smrt_logvol_free(smrt_volume_t *smlv)
+{
+ /*
+ * By this stage of teardown, all of the SCSI target drivers
+ * must have been detached from this logical volume.
+ */
+ VERIFY(list_is_empty(&smlv->smlv_targets));
+ list_destroy(&smlv->smlv_targets);
+
+ kmem_free(smlv, sizeof (*smlv));
+}
+
+smrt_volume_t *
+smrt_logvol_lookup_by_id(smrt_t *smrt, unsigned long id)
+{
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+
+ for (smrt_volume_t *smlv = list_head(&smrt->smrt_volumes);
+ smlv != NULL; smlv = list_next(&smrt->smrt_volumes, smlv)) {
+ if (smlv->smlv_addr.LogDev.VolId == id) {
+ return (smlv);
+ }
+ }
+
+ return (NULL);
+}
+
+static int
+smrt_read_logvols(smrt_t *smrt, smrt_report_logical_lun_t *smrll, uint64_t gen)
+{
+ smrt_report_logical_lun_ent_t *ents = smrll->smrll_data.ents;
+ uint32_t count = BE_32(smrll->smrll_datasize) /
+ sizeof (smrt_report_logical_lun_ent_t);
+
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+
+ if (count > SMRT_MAX_LOGDRV) {
+ count = SMRT_MAX_LOGDRV;
+ }
+
+ for (unsigned i = 0; i < count; i++) {
+ smrt_volume_t *smlv;
+ char id[SCSI_MAXNAMELEN];
+
+ DTRACE_PROBE2(read_logvol, unsigned, i,
+ smrt_report_logical_lun_ent_t *, &ents[i]);
+
+ if ((smlv = smrt_logvol_lookup_by_id(smrt,
+ ents[i].smrle_addr.VolId)) == NULL) {
+
+ /*
+ * This is a new Logical Volume, so add it the the list.
+ */
+ if ((smlv = kmem_zalloc(sizeof (*smlv), KM_NOSLEEP)) ==
+ NULL) {
+ return (ENOMEM);
+ }
+
+ list_create(&smlv->smlv_targets,
+ sizeof (smrt_target_t),
+ offsetof(smrt_target_t, smtg_link_lun));
+
+ smlv->smlv_ctlr = smrt;
+ list_insert_tail(&smrt->smrt_volumes, smlv);
+ }
+
+ /*
+ * Always make sure that the address and the generation are up
+ * to date, regardless of where this came from.
+ */
+ smlv->smlv_addr.LogDev = ents[i].smrle_addr;
+ smlv->smlv_gen = gen;
+ (void) snprintf(id, sizeof (id), "%x",
+ smlv->smlv_addr.LogDev.VolId);
+ if (!ddi_in_panic() &&
+ scsi_hba_tgtmap_set_add(smrt->smrt_virt_tgtmap,
+ SCSI_TGT_SCSI_DEVICE, id, NULL) != DDI_SUCCESS) {
+ return (EIO);
+ }
+ }
+
+ return (0);
+}
+
+static int
+smrt_read_logvols_ext(smrt_t *smrt, smrt_report_logical_lun_t *smrll,
+ uint64_t gen)
+{
+ smrt_report_logical_lun_extent_t *extents =
+ smrll->smrll_data.extents;
+ uint32_t count = BE_32(smrll->smrll_datasize) /
+ sizeof (smrt_report_logical_lun_extent_t);
+
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+
+ if (count > SMRT_MAX_LOGDRV) {
+ count = SMRT_MAX_LOGDRV;
+ }
+
+ for (unsigned i = 0; i < count; i++) {
+ smrt_volume_t *smlv;
+ char id[SCSI_MAXNAMELEN];
+
+ DTRACE_PROBE2(read_logvol_ext, unsigned, i,
+ smrt_report_logical_lun_extent_t *, &extents[i]);
+
+ if ((smlv = smrt_logvol_lookup_by_id(smrt,
+ extents[i].smrle_addr.VolId)) != NULL) {
+ if ((smlv->smlv_flags & SMRT_VOL_FLAG_WWN) &&
+ bcmp(extents[i].smrle_wwn, smlv->smlv_wwn,
+ 16) != 0) {
+ dev_err(smrt->smrt_dip, CE_PANIC, "logical "
+ "volume %u WWN changed unexpectedly", i);
+ }
+ } else {
+ /*
+ * This is a new Logical Volume, so add it the the list.
+ */
+ if ((smlv = kmem_zalloc(sizeof (*smlv), KM_NOSLEEP)) ==
+ NULL) {
+ return (ENOMEM);
+ }
+
+ bcopy(extents[i].smrle_wwn, smlv->smlv_wwn, 16);
+ smlv->smlv_flags |= SMRT_VOL_FLAG_WWN;
+
+ list_create(&smlv->smlv_targets,
+ sizeof (smrt_target_t),
+ offsetof(smrt_target_t, smtg_link_lun));
+
+ smlv->smlv_ctlr = smrt;
+ list_insert_tail(&smrt->smrt_volumes, smlv);
+ }
+
+ /*
+ * Always make sure that the address and the generation are up
+ * to date. The address may have changed on a reset.
+ */
+ smlv->smlv_addr.LogDev = extents[i].smrle_addr;
+ smlv->smlv_gen = gen;
+ (void) snprintf(id, sizeof (id), "%x",
+ smlv->smlv_addr.LogDev.VolId);
+ if (!ddi_in_panic() &&
+ scsi_hba_tgtmap_set_add(smrt->smrt_virt_tgtmap,
+ SCSI_TGT_SCSI_DEVICE, id, NULL) != DDI_SUCCESS) {
+ return (EIO);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Discover the currently visible set of Logical Volumes exposed by the
+ * controller.
+ */
+int
+smrt_logvol_discover(smrt_t *smrt, uint16_t timeout, uint64_t gen)
+{
+ smrt_command_t *smcm;
+ smrt_report_logical_lun_t *smrll;
+ smrt_report_logical_lun_req_t smrllr = { 0 };
+ int r;
+
+ /*
+ * Allocate the command to send to the device, including buffer space
+ * for the returned list of Logical Volumes.
+ */
+ if ((smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_INTERNAL,
+ KM_NOSLEEP)) == NULL || smrt_command_attach_internal(smrt, smcm,
+ sizeof (smrt_report_logical_lun_t), KM_NOSLEEP) != 0) {
+ r = ENOMEM;
+ mutex_enter(&smrt->smrt_mutex);
+ goto out;
+ }
+
+ smrll = smcm->smcm_internal->smcmi_va;
+
+ smrt_write_controller_lun_addr(&smcm->smcm_va_cmd->Header.LUN);
+
+ smcm->smcm_va_cmd->Request.CDBLen = sizeof (smrllr);
+ smcm->smcm_va_cmd->Request.Timeout = LE_16(timeout);
+ smcm->smcm_va_cmd->Request.Type.Type = CISS_TYPE_CMD;
+ smcm->smcm_va_cmd->Request.Type.Attribute = CISS_ATTR_SIMPLE;
+ smcm->smcm_va_cmd->Request.Type.Direction = CISS_XFER_READ;
+
+ /*
+ * The Report Logical LUNs command is essentially a vendor-specific
+ * SCSI command, which we assemble into the CDB region of the command
+ * block.
+ */
+ bzero(&smrllr, sizeof (smrllr));
+ smrllr.smrllr_opcode = CISS_SCMD_REPORT_LOGICAL_LUNS;
+ smrllr.smrllr_extflag = 1;
+ smrllr.smrllr_datasize = htonl(sizeof (smrt_report_logical_lun_t));
+ bcopy(&smrllr, &smcm->smcm_va_cmd->Request.CDB[0],
+ MIN(CISS_CDBLEN, sizeof (smrllr)));
+
+ mutex_enter(&smrt->smrt_mutex);
+
+ /*
+ * Send the command to the device.
+ */
+ smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
+ if ((r = smrt_submit(smrt, smcm)) != 0) {
+ goto out;
+ }
+
+ /*
+ * Poll for completion.
+ */
+ smcm->smcm_expiry = gethrtime() + timeout * NANOSEC;
+ if ((r = smrt_poll_for(smrt, smcm)) != 0) {
+ VERIFY3S(r, ==, ETIMEDOUT);
+ VERIFY0(smcm->smcm_status & SMRT_CMD_STATUS_POLL_COMPLETE);
+
+ /*
+ * The command timed out; abandon it now. Remove the POLLED
+ * flag so that the periodic routine will send an abort to
+ * clean it up next time around.
+ */
+ smcm->smcm_status |= SMRT_CMD_STATUS_ABANDONED;
+ smcm->smcm_status &= ~SMRT_CMD_STATUS_POLLED;
+ smcm = NULL;
+ goto out;
+ }
+
+ if (smcm->smcm_status & SMRT_CMD_STATUS_RESET_SENT) {
+ /*
+ * The controller was reset while we were trying to discover
+ * logical volumes. Report failure.
+ */
+ r = EIO;
+ goto out;
+ }
+
+ if (smcm->smcm_status & SMRT_CMD_STATUS_ERROR) {
+ ErrorInfo_t *ei = smcm->smcm_va_err;
+
+ if (ei->CommandStatus != CISS_CMD_DATA_UNDERRUN) {
+ dev_err(smrt->smrt_dip, CE_WARN, "logical volume "
+ "discovery error: status 0x%x", ei->CommandStatus);
+ r = EIO;
+ goto out;
+ }
+ }
+
+ if (!ddi_in_panic() &&
+ scsi_hba_tgtmap_set_begin(smrt->smrt_virt_tgtmap) != DDI_SUCCESS) {
+ dev_err(smrt->smrt_dip, CE_WARN, "failed to begin target map "
+ "observation on %s", SMRT_IPORT_VIRT);
+ r = EIO;
+ goto out;
+ }
+
+ if ((smrll->smrll_extflag & 0x1) != 0) {
+ r = smrt_read_logvols_ext(smrt, smrll, gen);
+ } else {
+ r = smrt_read_logvols(smrt, smrll, gen);
+ }
+
+ if (r == 0 && !ddi_in_panic()) {
+ if (scsi_hba_tgtmap_set_end(smrt->smrt_virt_tgtmap, 0) !=
+ DDI_SUCCESS) {
+ dev_err(smrt->smrt_dip, CE_WARN, "failed to end target "
+ "map observation on %s", SMRT_IPORT_VIRT);
+ r = EIO;
+ }
+ } else if (r != 0 && !ddi_in_panic()) {
+ if (scsi_hba_tgtmap_set_flush(smrt->smrt_virt_tgtmap) !=
+ DDI_SUCCESS) {
+ dev_err(smrt->smrt_dip, CE_WARN, "failed to end target "
+ "map observation on %s", SMRT_IPORT_VIRT);
+ r = EIO;
+ }
+ }
+
+ if (r == 0) {
+ /*
+ * Update the time of the last successful Logical Volume
+ * discovery:
+ */
+ smrt->smrt_last_log_discovery = gethrtime();
+ }
+
+out:
+ mutex_exit(&smrt->smrt_mutex);
+
+ if (smcm != NULL) {
+ smrt_command_free(smcm);
+ }
+ return (r);
+}
+
+void
+smrt_logvol_tgtmap_activate(void *arg, char *addr, scsi_tgtmap_tgt_type_t type,
+ void **privpp)
+{
+ smrt_t *smrt = arg;
+ unsigned long volume;
+ char *eptr;
+
+ VERIFY(type == SCSI_TGT_SCSI_DEVICE);
+ VERIFY0(ddi_strtoul(addr, &eptr, 16, &volume));
+ VERIFY3S(*eptr, ==, '\0');
+ VERIFY3S(volume, >=, 0);
+ VERIFY3S(volume, <, SMRT_MAX_LOGDRV);
+ mutex_enter(&smrt->smrt_mutex);
+ VERIFY(smrt_logvol_lookup_by_id(smrt, volume) != NULL);
+ mutex_exit(&smrt->smrt_mutex);
+ *privpp = NULL;
+}
+
+boolean_t
+smrt_logvol_tgtmap_deactivate(void *arg, char *addr,
+ scsi_tgtmap_tgt_type_t type, void *priv, scsi_tgtmap_deact_rsn_t reason)
+{
+ smrt_t *smrt = arg;
+ smrt_volume_t *smlv;
+ unsigned long volume;
+ char *eptr;
+
+ VERIFY(type == SCSI_TGT_SCSI_DEVICE);
+ VERIFY(priv == NULL);
+ VERIFY0(ddi_strtoul(addr, &eptr, 16, &volume));
+ VERIFY3S(*eptr, ==, '\0');
+ VERIFY3S(volume, >=, 0);
+ VERIFY3S(volume, <, SMRT_MAX_LOGDRV);
+
+ mutex_enter(&smrt->smrt_mutex);
+ smlv = smrt_logvol_lookup_by_id(smrt, volume);
+ VERIFY(smlv != NULL);
+
+ list_remove(&smrt->smrt_volumes, smlv);
+ smrt_logvol_free(smlv);
+ mutex_exit(&smrt->smrt_mutex);
+
+ return (B_FALSE);
+}
+
+void
+smrt_logvol_teardown(smrt_t *smrt)
+{
+ smrt_volume_t *smlv;
+
+ while ((smlv = list_remove_head(&smrt->smrt_volumes)) != NULL) {
+ smrt_logvol_free(smlv);
+ }
+}
diff --git a/usr/src/uts/common/io/scsi/adapters/smrt/smrt_physical.c b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_physical.c
new file mode 100644
index 0000000000..88ed57bc7d
--- /dev/null
+++ b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_physical.c
@@ -0,0 +1,612 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017 Joyent, Inc.
+ */
+
+#include <sys/scsi/adapters/smrt/smrt.h>
+
+static void
+smrt_physical_free(smrt_physical_t *smpt)
+{
+ VERIFY(list_is_empty(&smpt->smpt_targets));
+ VERIFY(smpt->smpt_info != NULL);
+
+ kmem_free(smpt->smpt_info, sizeof (*smpt->smpt_info));
+ list_destroy(&smpt->smpt_targets);
+ kmem_free(smpt, sizeof (*smpt));
+}
+
+/*
+ * Determine if a physical device enumerated should be shown to the world. There
+ * are three conditions to satisfy for this to be true.
+ *
+ * 1. The device (SAS, SATA, SES, etc.) must not have a masked CISS address. A
+ * masked CISS address indicates a device that we should not be performing I/O
+ * to.
+ * 2. The drive (SAS or SATA device) must not be marked as a member of a logical
+ * volume.
+ * 3. The drive (SAS or SATA device) must not be marked as a spare.
+ */
+static boolean_t
+smrt_physical_visible(PhysDevAddr_t *addr, smrt_identify_physical_drive_t *info)
+{
+ if (addr->Mode == SMRT_CISS_MODE_MASKED) {
+ return (B_FALSE);
+ }
+
+ if ((info->sipd_more_flags & (SMRT_MORE_FLAGS_LOGVOL |
+ SMRT_MORE_FLAGS_SPARE)) != 0) {
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
+
+/*
+ * Note, the caller is responsible for making sure that the unit-address form of
+ * the WWN is pased in. Any additional information to target a specific LUN
+ * will be ignored.
+ */
+smrt_physical_t *
+smrt_phys_lookup_by_ua(smrt_t *smrt, const char *ua)
+{
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+
+ /*
+ * Sanity check that the caller has provided us enough bytes for a
+ * properly formed unit-address form of a WWN.
+ */
+ if (strlen(ua) < SCSI_WWN_UA_STRLEN)
+ return (NULL);
+
+ for (smrt_physical_t *smpt = list_head(&smrt->smrt_physicals);
+ smpt != NULL; smpt = list_next(&smrt->smrt_physicals, smpt)) {
+ char wwnstr[SCSI_WWN_BUFLEN];
+
+ (void) scsi_wwn_to_wwnstr(smpt->smpt_wwn, 1, wwnstr);
+ if (strncmp(wwnstr, ua, SCSI_WWN_UA_STRLEN) != 0)
+ continue;
+
+ /*
+ * Verify that the UA string is either a comma or null there.
+ * We accept the comma in case it's being used as part of a
+ * normal UA with a LUN.
+ */
+ if (ua[SCSI_WWN_UA_STRLEN] != '\0' &&
+ ua[SCSI_WWN_UA_STRLEN] != ',') {
+ continue;
+ }
+
+ return (smpt);
+ }
+
+ return (NULL);
+}
+
+static smrt_physical_t *
+smrt_phys_lookup_by_wwn(smrt_t *smrt, uint64_t wwn)
+{
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+
+ for (smrt_physical_t *smpt = list_head(&smrt->smrt_physicals);
+ smpt != NULL; smpt = list_next(&smrt->smrt_physicals, smpt)) {
+ if (wwn == smpt->smpt_wwn)
+ return (smpt);
+ }
+
+ return (NULL);
+}
+
+static int
+smrt_phys_identify(smrt_t *smrt, smrt_identify_physical_drive_t *info,
+ uint16_t bmic, uint16_t timeout)
+{
+ smrt_command_t *smcm = NULL;
+ smrt_identify_physical_drive_t *sipd;
+ smrt_identify_physical_drive_req_t sipdr;
+ int ret;
+ size_t sz, copysz;
+
+ sz = sizeof (smrt_identify_physical_drive_t);
+ sz = P2ROUNDUP_TYPED(sz, 512, size_t);
+ if ((smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_INTERNAL,
+ KM_NOSLEEP)) == NULL || smrt_command_attach_internal(smrt, smcm,
+ sizeof (*sipd), KM_NOSLEEP) != 0) {
+ ret = ENOMEM;
+ goto out;
+ }
+
+ sipd = smcm->smcm_internal->smcmi_va;
+
+ smrt_write_controller_lun_addr(&smcm->smcm_va_cmd->Header.LUN);
+
+ smcm->smcm_va_cmd->Request.CDBLen = sizeof (sipdr);
+ smcm->smcm_va_cmd->Request.Timeout = LE_16(timeout);
+ smcm->smcm_va_cmd->Request.Type.Type = CISS_TYPE_CMD;
+ smcm->smcm_va_cmd->Request.Type.Attribute = CISS_ATTR_SIMPLE;
+ smcm->smcm_va_cmd->Request.Type.Direction = CISS_XFER_READ;
+
+ /*
+ * Construct the IDENTIFY PHYSICAL DEVICE request CDB. Note that any
+ * reserved fields in the request must be filled with zeroes.
+ */
+ bzero(&sipdr, sizeof (sipdr));
+ sipdr.sipdr_opcode = CISS_SCMD_BMIC_READ;
+ sipdr.sipdr_lun = 0;
+ sipdr.sipdr_bmic_index1 = bmic & 0x00ff;
+ sipdr.sipdr_command = CISS_BMIC_IDENTIFY_PHYSICAL_DEVICE;
+ sipdr.sipdr_bmic_index2 = (bmic & 0xff00) >> 8;
+ bcopy(&sipdr, &smcm->smcm_va_cmd->Request.CDB[0],
+ MIN(CISS_CDBLEN, sizeof (sipdr)));
+
+ mutex_enter(&smrt->smrt_mutex);
+
+ /*
+ * Send the command to the device.
+ */
+ smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
+ if ((ret = smrt_submit(smrt, smcm)) != 0) {
+ mutex_exit(&smrt->smrt_mutex);
+ goto out;
+ }
+
+ /*
+ * Poll for completion.
+ */
+ smcm->smcm_expiry = gethrtime() + timeout * NANOSEC;
+ if ((ret = smrt_poll_for(smrt, smcm)) != 0) {
+ VERIFY3S(ret, ==, ETIMEDOUT);
+ VERIFY0(smcm->smcm_status & SMRT_CMD_STATUS_POLL_COMPLETE);
+
+ /*
+ * The command timed out; abandon it now. Remove the POLLED
+ * flag so that the periodic routine will send an abort to
+ * clean it up next time around.
+ */
+ smcm->smcm_status |= SMRT_CMD_STATUS_ABANDONED;
+ smcm->smcm_status &= ~SMRT_CMD_STATUS_POLLED;
+ smcm = NULL;
+ mutex_exit(&smrt->smrt_mutex);
+ goto out;
+ }
+ mutex_exit(&smrt->smrt_mutex);
+
+ if (smcm->smcm_status & SMRT_CMD_STATUS_RESET_SENT) {
+ /*
+ * The controller was reset while we were trying to discover
+ * physical volumes. Report failure.
+ */
+ ret = EIO;
+ goto out;
+ }
+
+ if (smcm->smcm_status & SMRT_CMD_STATUS_ERROR) {
+ ErrorInfo_t *ei = smcm->smcm_va_err;
+
+ if (ei->CommandStatus != CISS_CMD_DATA_UNDERRUN) {
+ dev_err(smrt->smrt_dip, CE_WARN, "identify physical "
+ "device error: status 0x%x", ei->CommandStatus);
+ ret = EIO;
+ goto out;
+ }
+
+ copysz = MIN(sizeof (*sipd), sz - ei->ResidualCnt);
+ } else {
+ copysz = sizeof (*sipd);
+ }
+
+
+ sz = MIN(sizeof (*sipd), copysz);
+ bcopy(sipd, info, sizeof (*sipd));
+
+ ret = 0;
+out:
+ if (smcm != NULL) {
+ smrt_command_free(smcm);
+ }
+
+ return (ret);
+}
+
+static int
+smrt_read_phys_ext(smrt_t *smrt, smrt_report_physical_lun_t *smrpl,
+ uint16_t timeout, uint64_t gen)
+{
+ smrt_report_physical_lun_extent_t *extents = smrpl->smrpl_data.extents;
+ uint32_t count = BE_32(smrpl->smrpl_datasize) /
+ sizeof (smrt_report_physical_lun_extent_t);
+ uint32_t i;
+
+ VERIFY(MUTEX_HELD(&smrt->smrt_mutex));
+
+ if (count > SMRT_MAX_PHYSDEV) {
+ count = SMRT_MAX_PHYSDEV;
+ }
+
+ for (i = 0; i < count; i++) {
+ int ret;
+ smrt_physical_t *smpt;
+ smrt_identify_physical_drive_t *info;
+ smrt_report_physical_opdi_t *opdi;
+ uint16_t bmic;
+ uint64_t wwn, satawwn;
+ char name[SCSI_MAXNAMELEN];
+
+ opdi = &extents[i].srple_extdata.srple_opdi;
+
+ mutex_exit(&smrt->smrt_mutex);
+
+ /*
+ * Get the extended information about this device.
+ */
+ info = kmem_zalloc(sizeof (*info), KM_NOSLEEP);
+ if (info == NULL) {
+ mutex_enter(&smrt->smrt_mutex);
+ return (ENOMEM);
+ }
+
+ bmic = smrt_lun_addr_to_bmic(&extents[i].srple_addr);
+ ret = smrt_phys_identify(smrt, info, bmic, timeout);
+ if (ret != 0) {
+ mutex_enter(&smrt->smrt_mutex);
+ kmem_free(info, sizeof (*info));
+ return (ret);
+ }
+
+ wwn = *(uint64_t *)opdi->srpo_wwid;
+ wwn = BE_64(wwn);
+
+ /*
+ * SATA devices may not have a proper WWN returned from firmware
+ * based on the SATL specification. Try to fetch the proper id
+ * for SATA devices, if the drive has one. If the drive doesn't
+ * have one or the SATL refuses to give us one, we use whatever
+ * the controller told us.
+ */
+ if (opdi->srpo_dtype == SMRT_DTYPE_SATA &&
+ smrt_sata_determine_wwn(smrt, &extents[i].srple_addr,
+ &satawwn, timeout) == 0) {
+ wwn = satawwn;
+ }
+
+ mutex_enter(&smrt->smrt_mutex);
+ smpt = smrt_phys_lookup_by_wwn(smrt, wwn);
+ if (smpt != NULL) {
+ /*
+ * Sanity check that the model and serial number of this
+ * device is the same for this WWN. If it's not, the
+ * controller is probably lying about something.
+ */
+ if (bcmp(smpt->smpt_info->sipd_model, info->sipd_model,
+ sizeof (info->sipd_model)) != 0 ||
+ bcmp(smpt->smpt_info->sipd_serial,
+ info->sipd_serial, sizeof (info->sipd_serial)) !=
+ 0 || smpt->smpt_dtype != opdi->srpo_dtype) {
+ dev_err(smrt->smrt_dip, CE_PANIC, "physical "
+ "target with wwn 0x%" PRIx64 " changed "
+ "model, serial, or type unexpectedly: "
+ "smrt_physical_t %p, phys info: %p", wwn,
+ smpt, info);
+ }
+
+ /*
+ * When panicking, we don't allow a device's visibility
+ * to change to being invisible and be able to actually
+ * panic. We only worry about devices which are used
+ * for I/O. We purposefully ignore SES devices.
+ */
+ if (ddi_in_panic() &&
+ (opdi->srpo_dtype == SMRT_DTYPE_SATA ||
+ opdi->srpo_dtype == SMRT_DTYPE_SAS)) {
+ boolean_t visible;
+
+ visible = smrt_physical_visible(
+ &smpt->smpt_addr.PhysDev, smpt->smpt_info);
+
+ if (visible != smpt->smpt_visible) {
+ dev_err(smrt->smrt_dip, CE_PANIC,
+ "physical target with wwn 0x%"
+ PRIx64 " changed visibility status "
+ "unexpectedly", wwn);
+ }
+ }
+
+ kmem_free(smpt->smpt_info, sizeof (*smpt->smpt_info));
+ smpt->smpt_info = NULL;
+ } else {
+ smpt = kmem_zalloc(sizeof (smrt_physical_t),
+ KM_NOSLEEP);
+ if (smpt == NULL) {
+ kmem_free(info, sizeof (*info));
+ return (ENOMEM);
+ }
+
+ smpt->smpt_wwn = wwn;
+ smpt->smpt_dtype = opdi->srpo_dtype;
+ list_create(&smpt->smpt_targets, sizeof (smrt_target_t),
+ offsetof(smrt_target_t, smtg_link_lun));
+ smpt->smpt_ctlr = smrt;
+ list_insert_tail(&smrt->smrt_physicals, smpt);
+ }
+
+ VERIFY3P(smpt->smpt_info, ==, NULL);
+
+ /*
+ * Determine if this device is supported and if it's visible to
+ * the system. Some devices may not be visible to the system
+ * because they're used in logical volumes or spares.
+ * Unsupported devices are also not visible.
+ */
+ switch (smpt->smpt_dtype) {
+ case SMRT_DTYPE_SATA:
+ case SMRT_DTYPE_SAS:
+ smpt->smpt_supported = B_TRUE;
+ smpt->smpt_visible =
+ smrt_physical_visible(&extents[i].srple_addr, info);
+ break;
+ case SMRT_DTYPE_SES:
+ smpt->smpt_supported = B_TRUE;
+ smpt->smpt_visible =
+ smrt_physical_visible(&extents[i].srple_addr, info);
+ break;
+ default:
+ smpt->smpt_visible = B_FALSE;
+ smpt->smpt_supported = B_FALSE;
+ }
+
+ smpt->smpt_info = info;
+ smpt->smpt_addr.PhysDev = extents[i].srple_addr;
+ smpt->smpt_bmic = bmic;
+ smpt->smpt_gen = gen;
+ (void) scsi_wwn_to_wwnstr(smpt->smpt_wwn, 1, name);
+ if (!ddi_in_panic() && smpt->smpt_visible &&
+ scsi_hba_tgtmap_set_add(smrt->smrt_phys_tgtmap,
+ SCSI_TGT_SCSI_DEVICE, name, NULL) != DDI_SUCCESS) {
+ return (EIO);
+ }
+ }
+
+ return (0);
+}
+
+int
+smrt_phys_discover(smrt_t *smrt, uint16_t timeout, uint64_t gen)
+{
+ smrt_command_t *smcm;
+ smrt_report_physical_lun_t *smrpl;
+ smrt_report_physical_lun_req_t smrplr;
+ int r;
+
+ /*
+ * Allocate the command to send to the device, including buffer space
+ * for the returned list of Physical Volumes.
+ */
+ if ((smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_INTERNAL,
+ KM_NOSLEEP)) == NULL || smrt_command_attach_internal(smrt, smcm,
+ sizeof (*smrpl), KM_NOSLEEP) != 0) {
+ r = ENOMEM;
+ mutex_enter(&smrt->smrt_mutex);
+ goto out;
+ }
+
+ smrpl = smcm->smcm_internal->smcmi_va;
+
+ smrt_write_controller_lun_addr(&smcm->smcm_va_cmd->Header.LUN);
+
+ smcm->smcm_va_cmd->Request.CDBLen = sizeof (smrplr);
+ smcm->smcm_va_cmd->Request.Timeout = LE_16(timeout);
+ smcm->smcm_va_cmd->Request.Type.Type = CISS_TYPE_CMD;
+ smcm->smcm_va_cmd->Request.Type.Attribute = CISS_ATTR_SIMPLE;
+ smcm->smcm_va_cmd->Request.Type.Direction = CISS_XFER_READ;
+
+ /*
+ * The Report Physical LUNs command is essentially a vendor-specific
+ * SCSI command, which we assemble into the CDB region of the command
+ * block.
+ */
+ bzero(&smrplr, sizeof (smrplr));
+ smrplr.smrplr_opcode = CISS_SCMD_REPORT_PHYSICAL_LUNS;
+ smrplr.smrplr_extflag = SMRT_REPORT_PHYSICAL_LUN_EXT_OPDI;
+ smrplr.smrplr_datasize = BE_32(sizeof (smrt_report_physical_lun_t));
+ bcopy(&smrplr, &smcm->smcm_va_cmd->Request.CDB[0],
+ MIN(CISS_CDBLEN, sizeof (smrplr)));
+
+ mutex_enter(&smrt->smrt_mutex);
+
+ /*
+ * Send the command to the device.
+ */
+ smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
+ if ((r = smrt_submit(smrt, smcm)) != 0) {
+ goto out;
+ }
+
+ /*
+ * Poll for completion.
+ */
+ smcm->smcm_expiry = gethrtime() + timeout * NANOSEC;
+ if ((r = smrt_poll_for(smrt, smcm)) != 0) {
+ VERIFY3S(r, ==, ETIMEDOUT);
+ VERIFY0(smcm->smcm_status & SMRT_CMD_STATUS_POLL_COMPLETE);
+
+ /*
+ * The command timed out; abandon it now. Remove the POLLED
+ * flag so that the periodic routine will send an abort to
+ * clean it up next time around.
+ */
+ smcm->smcm_status |= SMRT_CMD_STATUS_ABANDONED;
+ smcm->smcm_status &= ~SMRT_CMD_STATUS_POLLED;
+ smcm = NULL;
+ goto out;
+ }
+
+ if (smcm->smcm_status & SMRT_CMD_STATUS_RESET_SENT) {
+ /*
+ *
+ * The controller was reset while we were trying to discover
+ * logical volumes. Report failure.
+ */
+ r = EIO;
+ goto out;
+ }
+
+ if (smcm->smcm_status & SMRT_CMD_STATUS_ERROR) {
+ ErrorInfo_t *ei = smcm->smcm_va_err;
+
+ if (ei->CommandStatus != CISS_CMD_DATA_UNDERRUN) {
+ dev_err(smrt->smrt_dip, CE_WARN, "physical target "
+ "discovery error: status 0x%x", ei->CommandStatus);
+ r = EIO;
+ goto out;
+ }
+ }
+
+ /*
+ * If the controller doesn't support extended physical reporting, it
+ * likely doesn't even support physical devices that we'd care about
+ * exposing. As such, we treat this as an OK case.
+ */
+ if ((smrpl->smrpl_extflag & SMRT_REPORT_PHYSICAL_LUN_EXT_MASK) !=
+ SMRT_REPORT_PHYSICAL_LUN_EXT_OPDI) {
+ r = 0;
+ goto out;
+ }
+
+ if (!ddi_in_panic() &&
+ scsi_hba_tgtmap_set_begin(smrt->smrt_phys_tgtmap) != DDI_SUCCESS) {
+ dev_err(smrt->smrt_dip, CE_WARN, "failed to begin target map "
+ "observation on %s", SMRT_IPORT_PHYS);
+ r = EIO;
+ goto out;
+ }
+
+ r = smrt_read_phys_ext(smrt, smrpl, timeout, gen);
+
+ if (r == 0 && !ddi_in_panic()) {
+ if (scsi_hba_tgtmap_set_end(smrt->smrt_phys_tgtmap, 0) !=
+ DDI_SUCCESS) {
+ dev_err(smrt->smrt_dip, CE_WARN, "failed to end target "
+ "map observation on %s", SMRT_IPORT_PHYS);
+ r = EIO;
+ }
+ } else if (r != 0 && !ddi_in_panic()) {
+ if (scsi_hba_tgtmap_set_flush(smrt->smrt_phys_tgtmap) !=
+ DDI_SUCCESS) {
+ dev_err(smrt->smrt_dip, CE_WARN, "failed to end target "
+ "map observation on %s", SMRT_IPORT_PHYS);
+ r = EIO;
+ }
+ }
+
+ if (r == 0) {
+ smrt_physical_t *smpt, *next;
+
+ /*
+ * Prune physical devices that do not match the current
+ * generation and are not marked as visible devices. Visible
+ * devices will be dealt with as part of the target map work.
+ */
+ for (smpt = list_head(&smrt->smrt_physicals), next = NULL;
+ smpt != NULL; smpt = next) {
+ next = list_next(&smrt->smrt_physicals, smpt);
+ if (smpt->smpt_visible || smpt->smpt_gen == gen)
+ continue;
+ list_remove(&smrt->smrt_physicals, smpt);
+ smrt_physical_free(smpt);
+ }
+
+ /*
+ * Update the time of the last successful Physical Volume
+ * discovery:
+ */
+ smrt->smrt_last_phys_discovery = gethrtime();
+
+ /*
+ * Now, for each unsupported device that we haven't warned about
+ * encountering, try and give the administrator some hope of
+ * knowing about this.
+ */
+ for (smpt = list_head(&smrt->smrt_physicals), next = NULL;
+ smpt != NULL; smpt = next) {
+ if (smpt->smpt_supported || smpt->smpt_unsup_warn)
+ continue;
+ smpt->smpt_unsup_warn = B_TRUE;
+ dev_err(smrt->smrt_dip, CE_WARN, "encountered "
+ "unsupported device with device type %d",
+ smpt->smpt_dtype);
+ }
+ }
+
+out:
+ mutex_exit(&smrt->smrt_mutex);
+
+ if (smcm != NULL) {
+ smrt_command_free(smcm);
+ }
+ return (r);
+}
+
+void
+smrt_phys_tgtmap_activate(void *arg, char *addr, scsi_tgtmap_tgt_type_t type,
+ void **privpp)
+{
+ smrt_t *smrt = arg;
+ smrt_physical_t *smpt;
+
+ VERIFY3S(type, ==, SCSI_TGT_SCSI_DEVICE);
+ mutex_enter(&smrt->smrt_mutex);
+ smpt = smrt_phys_lookup_by_ua(smrt, addr);
+ VERIFY(smpt != NULL);
+ VERIFY(smpt->smpt_supported);
+ VERIFY(smpt->smpt_visible);
+ *privpp = NULL;
+ mutex_exit(&smrt->smrt_mutex);
+}
+
+boolean_t
+smrt_phys_tgtmap_deactivate(void *arg, char *addr, scsi_tgtmap_tgt_type_t type,
+ void *priv, scsi_tgtmap_deact_rsn_t reason)
+{
+ smrt_t *smrt = arg;
+ smrt_physical_t *smpt;
+
+ VERIFY3S(type, ==, SCSI_TGT_SCSI_DEVICE);
+ VERIFY3P(priv, ==, NULL);
+
+ mutex_enter(&smrt->smrt_mutex);
+ smpt = smrt_phys_lookup_by_ua(smrt, addr);
+
+ /*
+ * If the device disappeared or became invisible, then it may have
+ * already been removed.
+ */
+ if (smpt == NULL || !smpt->smpt_visible) {
+ mutex_exit(&smrt->smrt_mutex);
+ return (B_FALSE);
+ }
+
+ list_remove(&smrt->smrt_physicals, smpt);
+ smrt_physical_free(smpt);
+ mutex_exit(&smrt->smrt_mutex);
+ return (B_FALSE);
+}
+
+void
+smrt_phys_teardown(smrt_t *smrt)
+{
+ smrt_physical_t *smpt;
+
+ while ((smpt = list_remove_head(&smrt->smrt_physicals)) != NULL) {
+ smrt_physical_free(smpt);
+ }
+}
diff --git a/usr/src/uts/common/io/scsi/adapters/smrt/smrt_sata.c b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_sata.c
new file mode 100644
index 0000000000..6224b97732
--- /dev/null
+++ b/usr/src/uts/common/io/scsi/adapters/smrt/smrt_sata.c
@@ -0,0 +1,160 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Joyent, Inc.
+ */
+
+/*
+ * Collection of routines specific to SATA devices and attempting to make them
+ * work.
+ */
+
+#include <sys/scsi/adapters/smrt/smrt.h>
+
+/*
+ * This is a buffer size that should easily cover all of the data that we need
+ * to properly determine the buffer allocation.
+ */
+#define SMRT_SATA_INQ83_LEN 256
+
+/*
+ * We need to try and determine if a SATA WWN exists on the device. SAT-2
+ * defines that the response to the inquiry page 0x83.
+ */
+int
+smrt_sata_determine_wwn(smrt_t *smrt, PhysDevAddr_t *addr, uint64_t *wwnp,
+ uint16_t timeout)
+{
+ smrt_command_t *smcm;
+ int r;
+ uint8_t *inq;
+ uint64_t wwn;
+ size_t resid;
+
+ VERIFY3P(wwnp, !=, NULL);
+
+ if ((smcm = smrt_command_alloc(smrt, SMRT_CMDTYPE_INTERNAL,
+ KM_NOSLEEP)) == NULL || smrt_command_attach_internal(smrt, smcm,
+ SMRT_SATA_INQ83_LEN, KM_NOSLEEP) != 0) {
+ if (smcm != NULL) {
+ smrt_command_free(smcm);
+ }
+ return (ENOMEM);
+ }
+
+ smcm->smcm_va_cmd->Header.LUN.PhysDev = *addr;
+ smcm->smcm_va_cmd->Request.CDBLen = CDB_GROUP0;
+ smcm->smcm_va_cmd->Request.Type.Type = CISS_TYPE_CMD;
+ smcm->smcm_va_cmd->Request.Type.Attribute = CISS_ATTR_SIMPLE;
+ smcm->smcm_va_cmd->Request.Type.Direction = CISS_XFER_READ;
+ smcm->smcm_va_cmd->Request.Timeout = LE_16(timeout);
+
+ smcm->smcm_va_cmd->Request.CDB[0] = SCMD_INQUIRY;
+ smcm->smcm_va_cmd->Request.CDB[1] = 1;
+ smcm->smcm_va_cmd->Request.CDB[2] = 0x83;
+ smcm->smcm_va_cmd->Request.CDB[3] = (SMRT_SATA_INQ83_LEN & 0xff00) >> 8;
+ smcm->smcm_va_cmd->Request.CDB[4] = SMRT_SATA_INQ83_LEN & 0x00ff;
+ smcm->smcm_va_cmd->Request.CDB[5] = 0;
+
+ mutex_enter(&smrt->smrt_mutex);
+
+ /*
+ * Send the command to the device.
+ */
+ smcm->smcm_status |= SMRT_CMD_STATUS_POLLED;
+ if ((r = smrt_submit(smrt, smcm)) != 0) {
+ mutex_exit(&smrt->smrt_mutex);
+ smrt_command_free(smcm);
+ return (r);
+ }
+
+ if ((r = smrt_poll_for(smrt, smcm)) != 0) {
+ VERIFY3S(r, ==, ETIMEDOUT);
+ VERIFY0(smcm->smcm_status & SMRT_CMD_STATUS_POLL_COMPLETE);
+
+ /*
+ * The command timed out; abandon it now. Remove the POLLED
+ * flag so that the periodic routine will send an abort to
+ * clean it up next time around.
+ */
+ smcm->smcm_status |= SMRT_CMD_STATUS_ABANDONED;
+ smcm->smcm_status &= ~SMRT_CMD_STATUS_POLLED;
+ mutex_exit(&smrt->smrt_mutex);
+ return (r);
+ }
+
+ if (smcm->smcm_status & SMRT_CMD_STATUS_RESET_SENT) {
+ /*
+ * The controller was reset while we were trying to discover
+ * logical volumes. Report failure.
+ */
+ mutex_exit(&smrt->smrt_mutex);
+ smrt_command_free(smcm);
+ return (EIO);
+ }
+
+ if (smcm->smcm_status & SMRT_CMD_STATUS_ERROR) {
+ ErrorInfo_t *ei = smcm->smcm_va_err;
+
+ if (ei->CommandStatus != CISS_CMD_DATA_UNDERRUN) {
+ dev_err(smrt->smrt_dip, CE_WARN, "physical target "
+ "SATA WWN error: status 0x%x", ei->CommandStatus);
+ mutex_exit(&smrt->smrt_mutex);
+ smrt_command_free(smcm);
+ return (EIO);
+ }
+ resid = ei->ResidualCnt;
+ } else {
+ resid = 0;
+ }
+
+ mutex_exit(&smrt->smrt_mutex);
+
+ /*
+ * We must have at least 12 bytes. The first four bytes are the header,
+ * the next four are for the LUN header, and the last 8 are for the
+ * actual WWN, which according to SAT-2 will always be first.
+ */
+ if (SMRT_SATA_INQ83_LEN - resid < 16) {
+ smrt_command_free(smcm);
+ return (EINVAL);
+ }
+ inq = smcm->smcm_internal->smcmi_va;
+
+ /*
+ * Sanity check we have the right page.
+ */
+ if (inq[1] != 0x83) {
+ smrt_command_free(smcm);
+ return (EINVAL);
+ }
+
+ /*
+ * Check to see if we have a proper Network Address Authority (NAA)
+ * based world wide number for this LUN. It is possible that firmware
+ * interposes on this and constructs a fake world wide number (WWN). If
+ * this is the case, we don't want to actually use it. We need to
+ * verify that the WWN declares the correct naming authority and is of
+ * the proper length.
+ */
+ if ((inq[5] & 0x30) != 0 || (inq[5] & 0x0f) != 3 || inq[7] != 8) {
+ smrt_command_free(smcm);
+ return (ENOTSUP);
+ }
+
+ bcopy(&inq[8], &wwn, sizeof (uint64_t));
+ *wwnp = BE_64(wwn);
+
+ smrt_command_free(smcm);
+
+ return (0);
+}
diff --git a/usr/src/uts/common/io/tty_pts.c b/usr/src/uts/common/io/tty_pts.c
index 2e69280908..65a4669259 100644
--- a/usr/src/uts/common/io/tty_pts.c
+++ b/usr/src/uts/common/io/tty_pts.c
@@ -12,7 +12,7 @@
/*
* PTY - Stream "pseudo-tty" device.
- * This is the "slave" side.
+ * This is the "subsidiary" side.
*/
@@ -30,7 +30,7 @@
#include <sys/user.h>
#include <sys/conf.h>
#include <sys/file.h>
-#include <sys/vnode.h> /* 1/0 on the vomit meter */
+#include <sys/vnode.h>
#include <sys/proc.h>
#include <sys/uio.h>
#include <sys/errno.h>
@@ -65,7 +65,7 @@ extern struct pollhead ptcph; /* poll head for ptcpoll() use */
*/
/*
- * Slave side. This is a streams device.
+ * Subsidiary side. This is a streams device.
*/
static int ptslopen(queue_t *, dev_t *, int flag, int, cred_t *);
static int ptslclose(queue_t *, int, cred_t *);
@@ -141,7 +141,7 @@ DDI_DEFINE_STREAM_OPS(ptsl_ops, nulldev, nulldev,
static struct modldrv modldrv = {
&mod_driverops, /* Type of module. This one is a pseudo driver */
- "tty pseudo driver slave 'ptsl'",
+ "tty pseudo driver subsidiary 'ptsl'",
&ptsl_ops, /* driver ops */
};
@@ -226,7 +226,7 @@ ptsl_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
/*
- * Open the slave side of a pty.
+ * Open the subsidiary side of a pty.
*/
/*ARGSUSED*/
static int
@@ -277,13 +277,13 @@ again:
pty->pt_sdev = dev;
q->q_ptr = WR(q)->q_ptr = pty;
- pty->pt_flags &= ~PF_SLAVEGONE;
+ pty->pt_flags &= ~PF_SUBSIDGONE;
pty->pt_ttycommon.t_readq = pty->pt_ttycommon.t_writeq = NULL;
/*
- * Slave is ready to accept messages but master still can't send
- * messages to the slave queue since it is not plumbed
- * yet. So do qprocson() and finish slave initialization.
+ * Subsidiary is ready to accept messages but manager still can't send
+ * messages to the subsidiary queue since it is not plumbed
+ * yet. So do qprocson() and finish subsidiary initialization.
*/
mutex_exit(&pty->ptc_lock);
@@ -291,8 +291,8 @@ again:
qprocson(q);
/*
- * Now it is safe to send messages to q, so wakeup master possibly
- * waiting for slave queue to finish open.
+ * Now it is safe to send messages to q, so wakeup manager possibly
+ * waiting for subsidiary queue to finish open.
*/
mutex_enter(&pty->ptc_lock);
/*
@@ -303,7 +303,7 @@ again:
VN_RELE(pty->pt_vnode);
pty->pt_ttycommon.t_readq = q;
pty->pt_ttycommon.t_writeq = WR(q);
- /* tell master device that slave is ready for writing */
+ /* tell manager device that subsidiary is ready for writing */
if (pty->pt_flags & PF_CARR_ON)
cv_broadcast(&pty->pt_cv_readq);
mutex_exit(&pty->ptc_lock);
@@ -326,10 +326,10 @@ ptslclose(queue_t *q, int flag, cred_t *cred)
return (ENODEV); /* already been closed once */
/*
- * Prevent the queues from being uses by master device.
- * This should be done before qprocsoff or writer may attempt
- * to use the slave queue after qprocsoff removed it from the stream and
- * before entering mutex_enter().
+ * Prevent the queues from being uses by manager device. This should
+ * be done before qprocsoff or writer may attempt to use the subsidiary
+ * queue after qprocsoff removed it from the stream and before entering
+ * mutex_enter().
*/
mutex_enter(&pty->ptc_lock);
pty->pt_ttycommon.t_readq = NULL;
@@ -359,11 +359,11 @@ ptslclose(queue_t *q, int flag, cred_t *cred)
}
/*
- * Clear out all the slave-side state.
+ * Clear out all the subsidiary-side state.
*/
pty->pt_flags &= ~(PF_WOPEN|PF_STOPPED|PF_NOSTOP);
if (pty->pt_flags & PF_CARR_ON) {
- pty->pt_flags |= PF_SLAVEGONE; /* let the controller know */
+ pty->pt_flags |= PF_SUBSIDGONE; /* let the controller know */
ptcpollwakeup(pty, 0); /* wake up readers/selectors */
ptcpollwakeup(pty, FWRITE); /* wake up writers/selectors */
cv_broadcast(&pty->pt_cv_flags);
@@ -942,10 +942,10 @@ pt_sendstop(struct pty *pty)
if ((pty->pt_ttycommon.t_cflag&CBAUD) == 0) {
if (pty->pt_flags & PF_CARR_ON) {
/*
- * Let the controller know, then wake up
+ * Let the manager know, then wake up
* readers/selectors and writers/selectors.
*/
- pty->pt_flags |= PF_SLAVEGONE;
+ pty->pt_flags |= PF_SUBSIDGONE;
ptcpollwakeup(pty, 0);
ptcpollwakeup(pty, FWRITE);
}
@@ -977,7 +977,7 @@ pt_sendstop(struct pty *pty)
* user control mode message has been queued up (this data is readable,
* so we also treat it as a regular data event; should we send SIGIO,
* though?), FREAD if regular data has been queued up, or FWRITE if
- * the slave's read queue has drained sufficiently to allow writing.
+ * the subsidiary's read queue has drained sufficiently to allow writing.
*/
static void
ptcpollwakeup(struct pty *pty, int flag)
@@ -997,7 +997,7 @@ ptcpollwakeup(struct pty *pty, int flag)
if (flag & FREAD) {
/*
* Wake up the parent process as there is regular
- * data to read from slave's write queue
+ * data to read from subsidiary's write queue
*/
pollwakeup(&ptcph, POLLIN | POLLRDNORM);
cv_broadcast(&pty->pt_cv_writeq);
@@ -1007,7 +1007,7 @@ ptcpollwakeup(struct pty *pty, int flag)
if (flag & FWRITE) {
/*
* Wake up the parent process to write
- * data into slave's read queue as the
+ * data into subsidiary's read queue as the
* read queue has drained enough
*/
pollwakeup(&ptcph, POLLOUT | POLLWRNORM);
diff --git a/usr/src/uts/common/io/tty_pty.c b/usr/src/uts/common/io/tty_pty.c
index c1e15de161..d6bbda6626 100644
--- a/usr/src/uts/common/io/tty_pty.c
+++ b/usr/src/uts/common/io/tty_pty.c
@@ -11,8 +11,8 @@
*/
/*
- * PTY - Stream "pseudo-tty" device. For each "controller" side
- * it connects to a "slave" side.
+ * PTY - Stream "pseudo-terminal" device. For each "manager" side it connects
+ * to a "subsidiary" side.
*/
@@ -29,7 +29,7 @@
#include <sys/user.h>
#include <sys/conf.h>
#include <sys/file.h>
-#include <sys/vnode.h> /* 1/0 on the vomit meter */
+#include <sys/vnode.h>
#include <sys/proc.h>
#include <sys/uio.h>
#include <sys/errno.h>
@@ -116,9 +116,9 @@ extern struct dev_ops ptc_ops;
*/
static struct modldrv modldrv = {
- &mod_driverops, /* Type of module. This one is a pseudo driver */
+ &mod_driverops,
"tty pseudo driver control 'ptc'",
- &ptc_ops, /* driver ops */
+ &ptc_ops,
};
static struct modlinkage modlinkage = {
@@ -236,12 +236,11 @@ ptc_uninit(void)
}
/*
- * Controller side. This is not, alas, a streams device; there are too
+ * Manager side. This is not, alas, a streams device; there are too
* many old features that we must support and that don't work well
* with streams.
*/
-/*ARGSUSED*/
int
ptcopen(dev_t *devp, int flag, int otyp, struct cred *cred)
{
@@ -256,7 +255,7 @@ ptcopen(dev_t *devp, int flag, int otyp, struct cred *cred)
mutex_enter(&pty->ptc_lock);
if (pty->pt_flags & PF_CARR_ON) {
mutex_exit(&pty->ptc_lock);
- return (EIO); /* controller is exclusive use */
+ return (EIO); /* manager is exclusive use */
/* XXX - should be EBUSY! */
}
if (pty->pt_flags & PF_WOPEN) {
@@ -266,7 +265,7 @@ ptcopen(dev_t *devp, int flag, int otyp, struct cred *cred)
if ((q = pty->pt_ttycommon.t_readq) != NULL) {
/*
- * Send an un-hangup to the slave, since "carrier" is
+ * Send an un-hangup to the subsidiary, since "carrier" is
* coming back up. Make sure we're doing canonicalization.
*/
(void) putctl(q, M_UNHANGUP);
@@ -280,7 +279,6 @@ ptcopen(dev_t *devp, int flag, int otyp, struct cred *cred)
return (0);
}
-/*ARGSUSED1*/
int
ptcclose(dev_t dev, int flag, int otyp, struct cred *cred)
{
@@ -293,15 +291,15 @@ ptcclose(dev_t dev, int flag, int otyp, struct cred *cred)
mutex_enter(&pty->ptc_lock);
if ((q = pty->pt_ttycommon.t_readq) != NULL) {
/*
- * Send a hangup to the slave, since "carrier" is dropping.
+ * Send a hangup to the subsidiary, since "carrier" is dropping.
*/
(void) putctl(q, M_HANGUP);
}
/*
- * Clear out all the controller-side state. This also
+ * Clear out all the manager-side state. This also
* clears PF_CARR_ON, which is correct because the
- * "carrier" is dropping since the controller process
+ * "carrier" is dropping since the manager process
* is going away.
*/
pty->pt_flags &= (PF_WOPEN|PF_STOPPED|PF_NOSTOP);
@@ -329,10 +327,6 @@ ptcread(dev_t dev, struct uio *uio, struct cred *cred)
int error;
off_t off;
-#ifdef lint
- cred = cred;
-#endif
-
off = uio->uio_offset;
mutex_enter(&pty->ptc_lock);
@@ -475,14 +469,14 @@ ptcread(dev_t dev, struct uio *uio, struct cred *cred)
/*
* There's no data available.
- * We want to block until the slave is open, and there's
- * something to read; but if we lost the slave or we're NBIO,
- * then return the appropriate error instead. POSIX-style
- * non-block has top billing and gives -1 with errno = EAGAIN,
- * BSD-style comes next and gives -1 with errno = EWOULDBLOCK,
- * SVID-style comes last and gives 0.
+ * We want to block until the subsidiary is open, and there's
+ * something to read; but if we lost the subsidiary or we're
+ * NBIO, then return the appropriate error instead.
+ * POSIX-style non-block has top billing and gives -1 with
+ * errno = EAGAIN, BSD-style comes next and gives -1 with
+ * errno = EWOULDBLOCK, SVID-style comes last and gives 0.
*/
- if (pty->pt_flags & PF_SLAVEGONE) {
+ if (pty->pt_flags & PF_SUBSIDGONE) {
error = EIO;
goto out;
}
@@ -532,11 +526,6 @@ ptcwrite(dev_t dev, struct uio *uio, struct cred *cred)
off_t off;
off = uio->uio_offset;
-#ifdef lint
- cred = cred;
-#endif
-
-
mutex_enter(&pty->ptc_lock);
again:
@@ -550,9 +539,9 @@ again:
if ((q = pty->pt_ttycommon.t_readq) == NULL) {
/*
- * Wait for slave to open.
+ * Wait for subsidiary to open.
*/
- if (pty->pt_flags & PF_SLAVEGONE) {
+ if (pty->pt_flags & PF_SUBSIDGONE) {
error = EIO;
goto out;
}
@@ -588,9 +577,9 @@ again:
do {
while (!canput(q)) {
/*
- * Wait for slave's read queue to unclog.
+ * Wait for subsidiary's read queue to unclog.
*/
- if (pty->pt_flags & PF_SLAVEGONE) {
+ if (pty->pt_flags & PF_SUBSIDGONE) {
error = EIO;
goto out;
}
@@ -763,7 +752,7 @@ ptcioctl(dev_t dev, int cmd, intptr_t data, int flag, struct cred *cred,
case TIOCSIGNAL:
/*
- * Blast a M_PCSIG message up the slave stream; the
+ * Blast a M_PCSIG message up the subsidiary stream; the
* signal number is the argument to the "ioctl".
*/
copy_in(data, d_arg);
@@ -794,7 +783,7 @@ ptcioctl(dev_t dev, int cmd, intptr_t data, int flag, struct cred *cred,
break;
/*
- * These, at least, can work on the controller-side process
+ * These, at least, can work on the manager-side process
* group.
*/
case FIOGETOWN:
@@ -813,9 +802,9 @@ ptcioctl(dev_t dev, int cmd, intptr_t data, int flag, struct cred *cred,
case FIONREAD: {
/*
- * Return the total number of bytes of data in all messages
- * in slave write queue, which is master read queue, unless a
- * special message would be read.
+ * Return the total number of bytes of data in all messages in
+ * subsidiary write queue, which is manager read queue, unless
+ * a special message would be read.
*/
mblk_t *mp;
size_t count = 0;
@@ -916,13 +905,13 @@ ptcioctl(dev_t dev, int cmd, intptr_t data, int flag, struct cred *cred,
/*
* XXX These should not be here. The only reason why an
- * "ioctl" on the controller side should get the
- * slave side's process group is so that the process on
- * the controller side can send a signal to the slave
+ * "ioctl" on the manager side should get the
+ * subsidiary side's process group is so that the process on
+ * the manager side can send a signal to the subsidiary
* side's process group; however, this is better done
* with TIOCSIGNAL, both because it doesn't require us
- * to know about the slave side's process group and because
- * the controller side process may not have permission to
+ * to know about the subsidiary side's process group and because
+ * the manager side process may not have permission to
* send that signal to the entire process group.
*
* However, since vanilla 4BSD doesn't provide TIOCSIGNAL,
@@ -933,9 +922,9 @@ ptcioctl(dev_t dev, int cmd, intptr_t data, int flag, struct cred *cred,
/*
* This is amazingly disgusting, but the stupid semantics of
* 4BSD pseudo-ttys makes us do it. If we do one of these guys
- * on the controller side, it really applies to the slave-side
+ * on the manager side, it really applies to the subsidiary-side
* stream. It should NEVER have been possible to do ANY sort
- * of tty operations on the controller side, but it's too late
+ * of tty operations on the manager side, but it's too late
* to fix that now. However, we won't waste our time implementing
* anything that the original pseudo-tty driver didn't handle.
*/
@@ -983,9 +972,6 @@ ptcpoll(dev_t dev, short events, int anyyet, short *reventsp,
queue_t *q;
int pos = 0;
-#ifdef lint
- anyyet = anyyet;
-#endif
if (polllock(php, &pty->ptc_lock) != 0) {
*reventsp = POLLNVAL;
return (0);
@@ -994,7 +980,7 @@ ptcpoll(dev_t dev, short events, int anyyet, short *reventsp,
ASSERT(MUTEX_HELD(&pty->ptc_lock));
*reventsp = 0;
- if (pty->pt_flags & PF_SLAVEGONE) {
+ if (pty->pt_flags & PF_SUBSIDGONE) {
if (events & (POLLIN|POLLRDNORM))
*reventsp |= (events & (POLLIN|POLLRDNORM));
if (events & (POLLOUT|POLLWRNORM))
diff --git a/usr/src/uts/common/io/ufmtest.c b/usr/src/uts/common/io/ufmtest.c
index 25c4af8fee..241d71d5c5 100644
--- a/usr/src/uts/common/io/ufmtest.c
+++ b/usr/src/uts/common/io/ufmtest.c
@@ -256,7 +256,7 @@ ufmtest_do_setfw(intptr_t data, int mode)
ufmt.ufmt_nvl = NULL;
}
- nvlbuf = kmem_zalloc(setfw.utsw_bufsz, KM_NOSLEEP | KM_NORMALPRI);
+ nvlbuf = kmem_zalloc(setfw.utsw_bufsz, KM_NOSLEEP_LAZY);
if (nvlbuf == NULL)
return (ENOMEM);
diff --git a/usr/src/uts/common/io/usb/clients/ccid/ccid.c b/usr/src/uts/common/io/usb/clients/ccid/ccid.c
index 9631a99283..60574f8aa1 100644
--- a/usr/src/uts/common/io/usb/clients/ccid/ccid.c
+++ b/usr/src/uts/common/io/usb/clients/ccid/ccid.c
@@ -1636,7 +1636,7 @@ ccid_command_alloc(ccid_t *ccid, ccid_slot_t *slot, boolean_t block,
kmflag = KM_SLEEP;
usbflag = USB_FLAGS_SLEEP;
} else {
- kmflag = KM_NOSLEEP | KM_NORMALPRI;
+ kmflag = KM_NOSLEEP_LAZY;
usbflag = 0;
}
diff --git a/usr/src/uts/common/io/usb/clients/hid/hid.c b/usr/src/uts/common/io/usb/clients/hid/hid.c
index 084fa7fedc..31a0aad206 100644
--- a/usr/src/uts/common/io/usb/clients/hid/hid.c
+++ b/usr/src/uts/common/io/usb/clients/hid/hid.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2016 Joyent, Inc.
+ * Copyright 2017 Joyent, Inc.
*/
@@ -139,6 +139,12 @@ static int hid_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
static int hid_attach(dev_info_t *, ddi_attach_cmd_t);
static int hid_detach(dev_info_t *, ddi_detach_cmd_t);
static int hid_power(dev_info_t *, int, int);
+/* These are to enable ugen support: */
+static int hid_chropen(dev_t *, int, int, cred_t *);
+static int hid_chrclose(dev_t, int, int, cred_t *);
+static int hid_read(dev_t, struct uio *, cred_t *);
+static int hid_write(dev_t, struct uio *, cred_t *);
+static int hid_poll(dev_t, short, int, short *, struct pollhead **);
/*
* Warlock is not aware of the automatic locking mechanisms for
@@ -198,18 +204,18 @@ struct streamtab hid_streamtab = {
};
struct cb_ops hid_cb_ops = {
- nulldev, /* open */
- nulldev, /* close */
+ hid_chropen, /* open */
+ hid_chrclose, /* close */
nulldev, /* strategy */
nulldev, /* print */
nulldev, /* dump */
- nulldev, /* read */
- nulldev, /* write */
+ hid_read, /* read */
+ hid_write, /* write */
nulldev, /* ioctl */
nulldev, /* devmap */
nulldev, /* mmap */
nulldev, /* segmap */
- nochpoll, /* poll */
+ hid_poll, /* poll */
ddi_prop_op, /* cb_prop_op */
&hid_streamtab, /* streamtab */
D_MP | D_MTPERQ
@@ -349,6 +355,7 @@ hid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
usb_alt_if_data_t *altif_data;
char minor_name[HID_MINOR_NAME_LEN];
usb_ep_data_t *ep_data;
+ usb_ugen_info_t usb_ugen_info;
switch (cmd) {
case DDI_ATTACH:
@@ -491,6 +498,28 @@ hid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
usb_free_dev_data(dip, dev_data);
hidp->hid_dev_data = NULL;
+ if (usb_owns_device(dip)) {
+ /* Get a ugen handle. */
+ bzero(&usb_ugen_info, sizeof (usb_ugen_info));
+
+ usb_ugen_info.usb_ugen_flags = 0;
+ usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask =
+ (dev_t)HID_MINOR_UGEN_BITS_MASK;
+ usb_ugen_info.usb_ugen_minor_node_instance_mask =
+ (dev_t)HID_MINOR_INSTANCE_MASK;
+ hidp->hid_ugen_hdl = usb_ugen_get_hdl(dip, &usb_ugen_info);
+
+ if (usb_ugen_attach(hidp->hid_ugen_hdl, cmd) !=
+ USB_SUCCESS) {
+ USB_DPRINTF_L2(PRINT_MASK_ATTA,
+ hidp->hid_log_handle,
+ "usb_ugen_attach failed");
+
+ usb_ugen_release_hdl(hidp->hid_ugen_hdl);
+ hidp->hid_ugen_hdl = NULL;
+ }
+ }
+
/*
* Don't get the report descriptor if parsing hid descriptor earlier
* failed since device probably won't return valid report descriptor
@@ -769,6 +798,149 @@ hid_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
return (rval);
}
+static int
+hid_chropen(dev_t *devp, int flag, int sflag, cred_t *credp)
+{
+ int rval;
+ minor_t minor = getminor(*devp);
+ int instance;
+ hid_state_t *hidp;
+
+ instance = HID_MINOR_TO_INSTANCE(minor);
+
+ hidp = ddi_get_soft_state(hid_statep, instance);
+ if (hidp == NULL) {
+ return (ENXIO);
+ }
+
+ if (!HID_IS_UGEN_OPEN(minor)) {
+ return (ENXIO);
+ }
+
+ hid_pm_busy_component(hidp);
+ (void) pm_raise_power(hidp->hid_dip, 0, USB_DEV_OS_FULL_PWR);
+
+ mutex_enter(&hidp->hid_mutex);
+
+ rval = usb_ugen_open(hidp->hid_ugen_hdl, devp, flag,
+ sflag, credp);
+
+ mutex_exit(&hidp->hid_mutex);
+
+ if (rval != 0) {
+ hid_pm_idle_component(hidp);
+ }
+
+ return (rval);
+}
+
+static int
+hid_chrclose(dev_t dev, int flag, int otyp, cred_t *credp)
+{
+ int rval;
+ minor_t minor = getminor(dev);
+ int instance;
+ hid_state_t *hidp;
+
+ instance = HID_MINOR_TO_INSTANCE(minor);
+
+ hidp = ddi_get_soft_state(hid_statep, instance);
+ if (hidp == NULL) {
+ return (ENXIO);
+ }
+
+ if (!HID_IS_UGEN_OPEN(minor)) {
+ return (ENXIO);
+ }
+
+ mutex_enter(&hidp->hid_mutex);
+
+ rval = usb_ugen_close(hidp->hid_ugen_hdl, dev, flag,
+ otyp, credp);
+
+ mutex_exit(&hidp->hid_mutex);
+
+ if (rval == 0) {
+ hid_pm_idle_component(hidp);
+ }
+
+ return (rval);
+}
+
+static int
+hid_read(dev_t dev, struct uio *uiop, cred_t *credp)
+{
+ int rval;
+ minor_t minor = getminor(dev);
+ int instance;
+ hid_state_t *hidp;
+
+ instance = HID_MINOR_TO_INSTANCE(minor);
+
+ hidp = ddi_get_soft_state(hid_statep, instance);
+ if (hidp == NULL) {
+ return (ENXIO);
+ }
+
+ if (!HID_IS_UGEN_OPEN(minor)) {
+ return (ENXIO);
+ }
+
+ rval = usb_ugen_read(hidp->hid_ugen_hdl, dev, uiop, credp);
+
+ return (rval);
+}
+
+static int
+hid_write(dev_t dev, struct uio *uiop, cred_t *credp)
+{
+ int rval;
+ minor_t minor = getminor(dev);
+ int instance;
+ hid_state_t *hidp;
+
+ instance = HID_MINOR_TO_INSTANCE(minor);
+
+ hidp = ddi_get_soft_state(hid_statep, instance);
+ if (hidp == NULL) {
+ return (ENXIO);
+ }
+
+ if (!HID_IS_UGEN_OPEN(minor)) {
+ return (ENXIO);
+ }
+
+ rval = usb_ugen_write(hidp->hid_ugen_hdl, dev, uiop, credp);
+
+ return (rval);
+}
+
+static int
+hid_poll(dev_t dev, short events, int anyyet, short *reventsp,
+ struct pollhead **phpp)
+{
+ int rval;
+ minor_t minor = getminor(dev);
+ int instance;
+ hid_state_t *hidp;
+
+ instance = HID_MINOR_TO_INSTANCE(minor);
+
+ hidp = ddi_get_soft_state(hid_statep, instance);
+ if (hidp == NULL) {
+ return (ENXIO);
+ }
+
+ if (!HID_IS_UGEN_OPEN(minor)) {
+ return (ENXIO);
+ }
+
+ rval = usb_ugen_poll(hidp->hid_ugen_hdl, dev, events, anyyet,
+ reventsp, phpp);
+
+ return (rval);
+}
+
/*
* hid_open :
* Open entry point: Opens the interrupt pipe. Sets up queues.
@@ -787,13 +959,21 @@ hid_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
hidp = ddi_get_soft_state(hid_statep, instance);
if (hidp == NULL) {
-
return (ENXIO);
}
USB_DPRINTF_L4(PRINT_MASK_OPEN, hidp->hid_log_handle,
"hid_open: Begin");
+ /*
+ * If this is a ugen device, return ENOSTR (no streams). This will
+ * cause spec_open to try hid_chropen from our regular ops_cb instead
+ * (and thus treat us as a plain character device).
+ */
+ if (HID_IS_UGEN_OPEN(minor)) {
+ return (ENOSTR);
+ }
+
if (sflag) {
/* clone open NOT supported here */
return (ENXIO);
@@ -803,6 +983,8 @@ hid_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
return (EIO);
}
+ mutex_enter(&hidp->hid_mutex);
+
/*
* This is a workaround:
* Currently, if we open an already disconnected device, and send
@@ -812,7 +994,6 @@ hid_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
* The consconfig_dacf module need this interface to detect if the
* device is already disconnnected.
*/
- mutex_enter(&hidp->hid_mutex);
if (HID_IS_INTERNAL_OPEN(minor) &&
(hidp->hid_dev_state == USB_DEV_DISCONNECTED)) {
mutex_exit(&hidp->hid_mutex);
@@ -1688,6 +1869,11 @@ hid_cpr_suspend(hid_state_t *hidp)
}
mutex_exit(&hidp->hid_mutex);
+ if ((retval == USB_SUCCESS) && hidp->hid_ugen_hdl != NULL) {
+ retval = usb_ugen_detach(hidp->hid_ugen_hdl,
+ DDI_SUSPEND);
+ }
+
return (retval);
}
@@ -1699,6 +1885,10 @@ hid_cpr_resume(hid_state_t *hidp)
"hid_cpr_resume: dip=0x%p", (void *)hidp->hid_dip);
hid_restore_device_state(hidp->hid_dip, hidp);
+
+ if (hidp->hid_ugen_hdl != NULL) {
+ (void) usb_ugen_attach(hidp->hid_ugen_hdl, DDI_RESUME);
+ }
}
@@ -2136,6 +2326,12 @@ hid_detach_cleanup(dev_info_t *dip, hid_state_t *hidp)
hidp->hid_pm = NULL;
}
+ if (hidp->hid_ugen_hdl != NULL) {
+ rval = usb_ugen_detach(hidp->hid_ugen_hdl, DDI_DETACH);
+ VERIFY0(rval);
+ usb_ugen_release_hdl(hidp->hid_ugen_hdl);
+ }
+
mutex_exit(&hidp->hid_mutex);
if (hidp->hid_report_descr != NULL) {
diff --git a/usr/src/uts/common/io/usb/clients/usbecm/usbecm.c b/usr/src/uts/common/io/usb/clients/usbecm/usbecm.c
index 8cb9218912..cdaf1f04ce 100644
--- a/usr/src/uts/common/io/usb/clients/usbecm/usbecm.c
+++ b/usr/src/uts/common/io/usb/clients/usbecm/usbecm.c
@@ -2828,7 +2828,7 @@ usbecm_usb_init(usbecm_state_t *ecmp)
} else {
USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
"usbecm_usb_init: A nonstandard device is attached to "
- "usbecm(7D) driver. This device doesn't conform to "
+ "usbecm(4D) driver. This device doesn't conform to "
"usb cdc spec.");
ecmp->ecm_compatibility = B_FALSE;
diff --git a/usr/src/uts/common/io/vioblk/vioblk.c b/usr/src/uts/common/io/vioblk/vioblk.c
index 0cccb84bce..f6649bdd12 100644
--- a/usr/src/uts/common/io/vioblk/vioblk.c
+++ b/usr/src/uts/common/io/vioblk/vioblk.c
@@ -25,6 +25,7 @@
* Copyright 2020 Joyent Inc.
* Copyright 2019 Western Digital Corporation.
* Copyright 2020 Oxide Computer Company
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
*/
/*
@@ -94,9 +95,10 @@
#include "vioblk.h"
static void vioblk_get_id(vioblk_t *);
-uint_t vioblk_int_handler(caddr_t, caddr_t);
+static uint_t vioblk_int_handler(caddr_t, caddr_t);
static uint_t vioblk_poll(vioblk_t *);
static int vioblk_quiesce(dev_info_t *);
+static int vioblk_read_capacity(vioblk_t *);
static int vioblk_attach(dev_info_t *, ddi_attach_cmd_t);
static int vioblk_detach(dev_info_t *, ddi_detach_cmd_t);
@@ -737,8 +739,8 @@ vioblk_poll(vioblk_t *vib)
return (count);
}
-uint_t
-vioblk_int_handler(caddr_t arg0, caddr_t arg1)
+static uint_t
+vioblk_int_handler(caddr_t arg0, caddr_t arg1 __unused)
{
vioblk_t *vib = (vioblk_t *)arg0;
uint_t count;
@@ -755,6 +757,33 @@ vioblk_int_handler(caddr_t arg0, caddr_t arg1)
return (DDI_INTR_CLAIMED);
}
+static uint_t
+vioblk_cfgchange(caddr_t arg0, caddr_t arg1 __unused)
+{
+ vioblk_t *vib = (vioblk_t *)arg0;
+
+ dev_err(vib->vib_dip, CE_NOTE, "!Configuration changed");
+
+ mutex_enter(&vib->vib_mutex);
+
+ /*
+ * The configuration space of the device has changed in some way.
+ * At present, we only re-read the device capacity and trigger
+ * blkdev to check the device state.
+ */
+
+ if (vioblk_read_capacity(vib) == DDI_FAILURE) {
+ mutex_exit(&vib->vib_mutex);
+ return (DDI_INTR_CLAIMED);
+ }
+
+ mutex_exit(&vib->vib_mutex);
+
+ bd_state_change(vib->vib_bd_h);
+
+ return (DDI_INTR_CLAIMED);
+}
+
static void
vioblk_free_reqs(vioblk_t *vib)
{
@@ -823,6 +852,50 @@ fail:
}
static int
+vioblk_read_capacity(vioblk_t *vib)
+{
+ virtio_t *vio = vib->vib_virtio;
+
+ /* The capacity is always available */
+ if ((vib->vib_nblks = virtio_dev_get64(vio,
+ VIRTIO_BLK_CONFIG_CAPACITY)) == UINT64_MAX) {
+ dev_err(vib->vib_dip, CE_WARN, "invalid capacity");
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Determine the optimal logical block size recommended by the device.
+ * This size is advisory; the protocol always deals in 512 byte blocks.
+ */
+ vib->vib_blk_size = DEV_BSIZE;
+ if (virtio_feature_present(vio, VIRTIO_BLK_F_BLK_SIZE)) {
+ uint32_t v = virtio_dev_get32(vio, VIRTIO_BLK_CONFIG_BLK_SIZE);
+
+ if (v != 0 && v != PCI_EINVAL32)
+ vib->vib_blk_size = v;
+ }
+
+ /*
+ * Device capacity is always in 512-byte units, convert to
+ * native blocks.
+ */
+ vib->vib_nblks = (vib->vib_nblks * DEV_BSIZE) / vib->vib_blk_size;
+
+ /*
+ * The device may also provide an advisory physical block size.
+ */
+ vib->vib_pblk_size = vib->vib_blk_size;
+ if (virtio_feature_present(vio, VIRTIO_BLK_F_TOPOLOGY)) {
+ uint8_t v = virtio_dev_get8(vio, VIRTIO_BLK_CONFIG_TOPO_PBEXP);
+
+ if (v != PCI_EINVAL8)
+ vib->vib_pblk_size <<= v;
+ }
+
+ return (DDI_SUCCESS);
+}
+
+static int
vioblk_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
int instance = ddi_get_instance(dip);
@@ -906,6 +979,8 @@ vioblk_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
goto fail;
}
+ virtio_register_cfgchange_handler(vio, vioblk_cfgchange, vib);
+
if (virtio_init_complete(vio, 0) != DDI_SUCCESS) {
dev_err(dip, CE_WARN, "failed to complete Virtio init");
goto fail;
@@ -944,42 +1019,9 @@ vioblk_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
kstat_install(vib->vib_kstat);
vib->vib_readonly = virtio_feature_present(vio, VIRTIO_BLK_F_RO);
- if ((vib->vib_nblks = virtio_dev_get64(vio,
- VIRTIO_BLK_CONFIG_CAPACITY)) == UINT64_MAX) {
- dev_err(dip, CE_WARN, "invalid capacity");
- goto fail;
- }
-
- /*
- * Determine the optimal logical block size recommended by the device.
- * This size is advisory; the protocol always deals in 512 byte blocks.
- */
- vib->vib_blk_size = DEV_BSIZE;
- if (virtio_feature_present(vio, VIRTIO_BLK_F_BLK_SIZE)) {
- uint32_t v = virtio_dev_get32(vio, VIRTIO_BLK_CONFIG_BLK_SIZE);
-
- if (v != 0 && v != PCI_EINVAL32) {
- vib->vib_blk_size = v;
- }
- }
-
- /*
- * Device capacity is always in 512-byte units, convert to
- * native blocks.
- */
- vib->vib_nblks = (vib->vib_nblks * DEV_BSIZE) / vib->vib_blk_size;
- /*
- * The device may also provide an advisory physical block size.
- */
- vib->vib_pblk_size = vib->vib_blk_size;
- if (virtio_feature_present(vio, VIRTIO_BLK_F_TOPOLOGY)) {
- uint8_t v = virtio_dev_get8(vio, VIRTIO_BLK_CONFIG_TOPO_PBEXP);
-
- if (v != PCI_EINVAL8) {
- vib->vib_pblk_size <<= v;
- }
- }
+ if (vioblk_read_capacity(vib) == DDI_FAILURE)
+ goto fail;
/*
* The maximum size for a cookie in a request.
diff --git a/usr/src/uts/common/io/virtio/virtio.h b/usr/src/uts/common/io/virtio/virtio.h
index 420f9ccfed..48e15b28f2 100644
--- a/usr/src/uts/common/io/virtio/virtio.h
+++ b/usr/src/uts/common/io/virtio/virtio.h
@@ -11,6 +11,7 @@
/*
* Copyright 2019 Joyent, Inc.
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
*/
#ifndef _VIRTIO_H
@@ -81,6 +82,18 @@
* is usually either negotiated with the device, or determined structurally
* based on the shape of the buffers required for device operation.
*
+ * FRAMEWORK INITIALISATION: CONFIGURATION SPACE CHANGE HANDLER
+ *
+ * During the initialisation phase, the client driver may register a handler
+ * function for receiving device configuration space change events. Once
+ * initialisation has been completed, this cannot be changed without destroying
+ * the framework object and beginning again from scratch.
+ *
+ * When a configuration space change interrupt is received, the provided
+ * handler will be called with two arguments: first, the provided user data
+ * argument; and second, a pointer to the "virtio_t" object for this instance.
+ * The handler is called in an interrupt context.
+ *
* FRAMEWORK INITIALISATION: FINISHING
*
* Once queue configuration has been completed, the client driver calls
@@ -281,6 +294,9 @@ int virtio_init_complete(virtio_t *, int);
int virtio_quiesce(virtio_t *);
void virtio_shutdown(virtio_t *);
+void virtio_register_cfgchange_handler(virtio_t *, ddi_intr_handler_t *,
+ void *);
+
void *virtio_intr_pri(virtio_t *);
void virtio_device_reset(virtio_t *);
diff --git a/usr/src/uts/common/io/virtio/virtio_impl.h b/usr/src/uts/common/io/virtio/virtio_impl.h
index af786583f4..ef5f43397a 100644
--- a/usr/src/uts/common/io/virtio/virtio_impl.h
+++ b/usr/src/uts/common/io/virtio/virtio_impl.h
@@ -11,6 +11,7 @@
/*
* Copyright 2019 Joyent, Inc.
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
*/
#ifndef _VIRTIO_IMPL_H
@@ -98,6 +99,11 @@ struct virtio {
int vio_interrupt_type;
int vio_interrupt_cap;
uint_t vio_interrupt_priority;
+
+ ddi_intr_handler_t *vio_cfgchange_handler;
+ void *vio_cfgchange_handlerarg;
+ boolean_t vio_cfgchange_handler_added;
+ uint_t vio_cfgchange_handler_index;
};
struct virtio_queue {
diff --git a/usr/src/uts/common/io/virtio/virtio_main.c b/usr/src/uts/common/io/virtio/virtio_main.c
index 04b22709e8..28dce6dc92 100644
--- a/usr/src/uts/common/io/virtio/virtio_main.c
+++ b/usr/src/uts/common/io/virtio/virtio_main.c
@@ -11,6 +11,7 @@
/*
* Copyright 2019 Joyent, Inc.
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
*/
/*
@@ -322,6 +323,26 @@ virtio_init(dev_info_t *dip, uint64_t driver_features, boolean_t allow_indirect)
}
/*
+ * Some virtio devices can change their device configuration state at any
+ * time. This function may be called by the driver during the initialisation
+ * phase - before calling virtio_init_complete() - in order to register a
+ * handler function which will be called when the device configuration space
+ * is updated.
+ */
+void
+virtio_register_cfgchange_handler(virtio_t *vio, ddi_intr_handler_t *func,
+ void *funcarg)
+{
+ VERIFY(!(vio->vio_initlevel & VIRTIO_INITLEVEL_INT_ADDED));
+ VERIFY(!vio->vio_cfgchange_handler_added);
+
+ mutex_enter(&vio->vio_mutex);
+ vio->vio_cfgchange_handler = func;
+ vio->vio_cfgchange_handlerarg = funcarg;
+ mutex_exit(&vio->vio_mutex);
+}
+
+/*
* This function must be called by the driver once it has completed early setup
* calls. The value of "allowed_interrupt_types" is a mask of interrupt types
* (DDI_INTR_TYPE_MSIX, etc) that we'll try to use when installing handlers, or
@@ -333,7 +354,8 @@ virtio_init_complete(virtio_t *vio, int allowed_interrupt_types)
VERIFY(!(vio->vio_initlevel & VIRTIO_INITLEVEL_PROVIDER));
vio->vio_initlevel |= VIRTIO_INITLEVEL_PROVIDER;
- if (!list_is_empty(&vio->vio_queues)) {
+ if (!list_is_empty(&vio->vio_queues) ||
+ vio->vio_cfgchange_handler != NULL) {
/*
* Set up interrupts for the queues that have been registered.
*/
@@ -1343,32 +1365,45 @@ virtio_shared_isr(caddr_t arg0, caddr_t arg1)
* this field resets it to zero.
*/
isr = virtio_get8(vio, VIRTIO_LEGACY_ISR_STATUS);
- if ((isr & VIRTIO_ISR_CHECK_QUEUES) == 0) {
- goto done;
- }
- for (virtio_queue_t *viq = list_head(&vio->vio_queues); viq != NULL;
- viq = list_next(&vio->vio_queues, viq)) {
- if (viq->viq_func != NULL) {
- mutex_exit(&vio->vio_mutex);
- if (viq->viq_func(viq->viq_funcarg, arg0) ==
- DDI_INTR_CLAIMED) {
- r = DDI_INTR_CLAIMED;
- }
- mutex_enter(&vio->vio_mutex);
+ if ((isr & VIRTIO_ISR_CHECK_QUEUES) != 0) {
+ r = DDI_INTR_CLAIMED;
- if (vio->vio_initlevel & VIRTIO_INITLEVEL_SHUTDOWN) {
- /*
- * The device was shut down while in a queue
- * handler routine.
- */
- goto done;
+ for (virtio_queue_t *viq = list_head(&vio->vio_queues);
+ viq != NULL; viq = list_next(&vio->vio_queues, viq)) {
+ if (viq->viq_func != NULL) {
+ mutex_exit(&vio->vio_mutex);
+ (void) viq->viq_func(viq->viq_funcarg, arg0);
+ mutex_enter(&vio->vio_mutex);
+
+ if (vio->vio_initlevel &
+ VIRTIO_INITLEVEL_SHUTDOWN) {
+ /*
+ * The device was shut down while in a
+ * queue handler routine.
+ */
+ break;
+ }
}
}
}
-done:
mutex_exit(&vio->vio_mutex);
+
+ /*
+ * vio_cfgchange_{handler,handlerarg} cannot change while interrupts
+ * are configured so it is safe to access them outside of the lock.
+ */
+
+ if ((isr & VIRTIO_ISR_CHECK_CONFIG) != 0) {
+ r = DDI_INTR_CLAIMED;
+ if (vio->vio_cfgchange_handler != NULL) {
+ (void) vio->vio_cfgchange_handler(
+ (caddr_t)vio->vio_cfgchange_handlerarg,
+ (caddr_t)vio);
+ }
+ }
+
return (r);
}
@@ -1392,6 +1427,13 @@ virtio_interrupts_setup(virtio_t *vio, int allow_types)
}
}
+ /*
+ * If there is a configuration change handler, one extra interrupt
+ * is needed for that.
+ */
+ if (vio->vio_cfgchange_handler != NULL)
+ count++;
+
if (ddi_intr_get_supported_types(dip, &types) != DDI_SUCCESS) {
dev_err(dip, CE_WARN, "could not get supported interrupts");
mutex_exit(&vio->vio_mutex);
@@ -1493,6 +1535,22 @@ add_handlers:
VERIFY3S(vio->vio_ninterrupts, ==, count);
uint_t n = 0;
+
+ /* Bind the configuration vector interrupt */
+ if (vio->vio_cfgchange_handler != NULL) {
+ if (ddi_intr_add_handler(vio->vio_interrupts[n],
+ vio->vio_cfgchange_handler,
+ (caddr_t)vio->vio_cfgchange_handlerarg,
+ (caddr_t)vio) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN,
+ "adding configuration change interrupt failed");
+ goto fail;
+ }
+ vio->vio_cfgchange_handler_added = B_TRUE;
+ vio->vio_cfgchange_handler_index = n;
+ n++;
+ }
+
for (virtio_queue_t *viq = list_head(&vio->vio_queues); viq != NULL;
viq = list_next(&vio->vio_queues, viq)) {
if (viq->viq_func == NULL) {
@@ -1546,6 +1604,21 @@ virtio_interrupts_teardown(virtio_t *vio)
}
}
} else {
+ /*
+ * Remove the configuration vector interrupt handler.
+ */
+ if (vio->vio_cfgchange_handler_added) {
+ int r;
+
+ if ((r = ddi_intr_remove_handler(
+ vio->vio_interrupts[0])) != DDI_SUCCESS) {
+ dev_err(vio->vio_dip, CE_WARN,
+ "removing configuration change interrupt "
+ "handler failed (%d)", r);
+ }
+ vio->vio_cfgchange_handler_added = B_FALSE;
+ }
+
for (virtio_queue_t *viq = list_head(&vio->vio_queues);
viq != NULL; viq = list_next(&vio->vio_queues, viq)) {
int r;
@@ -1606,6 +1679,11 @@ virtio_interrupts_unwind(virtio_t *vio)
virtio_put16(vio, VIRTIO_LEGACY_MSIX_QUEUE,
VIRTIO_LEGACY_MSI_NO_VECTOR);
}
+
+ if (vio->vio_cfgchange_handler_added) {
+ virtio_put16(vio, VIRTIO_LEGACY_MSIX_CONFIG,
+ VIRTIO_LEGACY_MSI_NO_VECTOR);
+ }
}
if (vio->vio_interrupt_cap & DDI_INTR_FLAG_BLOCK) {
@@ -1703,6 +1781,23 @@ virtio_interrupts_enable(virtio_t *vio)
return (DDI_FAILURE);
}
}
+
+ if (vio->vio_cfgchange_handler_added) {
+ virtio_put16(vio, VIRTIO_LEGACY_MSIX_CONFIG,
+ vio->vio_cfgchange_handler_index);
+
+ /* Verify the value was accepted. */
+ if (virtio_get16(vio, VIRTIO_LEGACY_MSIX_CONFIG) !=
+ vio->vio_cfgchange_handler_index) {
+ dev_err(vio->vio_dip, CE_WARN,
+ "failed to configure MSI-X vector for "
+ "configuration");
+
+ virtio_interrupts_unwind(vio);
+ mutex_exit(&vio->vio_mutex);
+ return (DDI_FAILURE);
+ }
+ }
}
vio->vio_initlevel |= VIRTIO_INITLEVEL_INT_ENABLED;
diff --git a/usr/src/uts/common/io/zcons.c b/usr/src/uts/common/io/zcons.c
index b264cd8e61..ad64099f2d 100644
--- a/usr/src/uts/common/io/zcons.c
+++ b/usr/src/uts/common/io/zcons.c
@@ -30,18 +30,18 @@
* This driver, derived from the pts/ptm drivers, is the pseudo console driver
* for system zones. Its implementation is straightforward. Each instance
* of the driver represents a global-zone/local-zone pair (this maps in a
- * straightforward way to the commonly used terminal notion of "master side"
- * and "slave side", and we use that terminology throughout).
+ * straightforward way to the commonly used terminal notion of "manager side"
+ * and "subsidiary side", and we use that terminology throughout).
*
* Instances of zcons are onlined as children of /pseudo/zconsnex@1/
* by zoneadmd in userland, using the devctl framework; thus the driver
* does not need to maintain any sort of "admin" node.
*
- * The driver shuttles I/O from master side to slave side and back. In a break
- * from the pts/ptm semantics, if one side is not open, I/O directed towards
- * it will simply be discarded. This is so that if zoneadmd is not holding
- * the master side console open (i.e. it has died somehow), processes in
- * the zone do not experience any errors and I/O to the console does not
+ * The driver shuttles I/O from manager side to subsidiary side and back. In a
+ * break from the pts/ptm semantics, if one side is not open, I/O directed
+ * towards it will simply be discarded. This is so that if zoneadmd is not
+ * holding the manager side console open (i.e. it has died somehow), processes
+ * in the zone do not experience any errors and I/O to the console does not
* hang.
*
* TODO: we may want to revisit the other direction; i.e. we may want
@@ -50,64 +50,67 @@
*
*
*
- * MASTER SIDE IOCTLS
+ * MANAGER SIDE IOCTLS
*
- * The ZC_HOLDSLAVE and ZC_RELEASESLAVE ioctls instruct the master side of the
- * console to hold and release a reference to the slave side's vnode. They are
- * meant to be issued by zoneadmd after the console device node is created and
- * before it is destroyed so that the slave's STREAMS anchor, ptem, is
- * preserved when ttymon starts popping STREAMS modules from within the
- * associated zone. This guarantees that the zone console will always have
+ * The ZC_HOLDSUBSID and ZC_RELEASESUBSID ioctls instruct the manager side of
+ * the console to hold and release a reference to the subsidiary side's vnode.
+ * They are meant to be issued by zoneadmd after the console device node is
+ * created and before it is destroyed so that the subsidiary's STREAMS anchor,
+ * ptem, is preserved when ttymon starts popping STREAMS modules from within
+ * the associated zone. This guarantees that the zone console will always have
* terminal semantics while the zone is running.
*
* Here is the issue: the ptem module is anchored in the zone console
- * (slave side) so that processes within the associated non-global zone will
- * fail to pop it off, thus ensuring that the slave will retain terminal
- * semantics. When a process attempts to pop the anchor off of a stream, the
- * STREAMS subsystem checks whether the calling process' zone is the same as
- * that of the process that pushed the anchor onto the stream and cancels the
- * pop if they differ. zoneadmd used to hold an open file descriptor for the
- * slave while the associated non-global zone ran, thus ensuring that the
- * slave's STREAMS anchor would never be popped from within the non-global zone
- * (because zoneadmd runs in the global zone). However, this file descriptor
- * was removed to make zone console management more robust. sad(4D) is now
- * used to automatically set up the slave's STREAMS modules when the zone
- * console is freshly opened within the associated non-global zone. However,
- * when a process within the non-global zone freshly opens the zone console, the
- * anchor is pushed from within the non-global zone, making it possible for
- * processes within the non-global zone (e.g., ttymon) to pop the anchor and
- * destroy the zone console's terminal semantics.
+ * (subsidiary side) so that processes within the associated non-global zone
+ * will fail to pop it off, thus ensuring that the subsidiary will retain
+ * terminal semantics. When a process attempts to pop the anchor off of a
+ * stream, the STREAMS subsystem checks whether the calling process' zone is
+ * the same as that of the process that pushed the anchor onto the stream and
+ * cancels the pop if they differ. zoneadmd used to hold an open file
+ * descriptor for the subsidiary while the associated non-global zone ran, thus
+ * ensuring that the subsidiary's STREAMS anchor would never be popped from
+ * within the non-global zone (because zoneadmd runs in the global zone).
+ * However, this file descriptor was removed to make zone console management
+ * more robust. sad(4D) is now used to automatically set up the subsidiary's
+ * STREAMS modules when the zone console is freshly opened within the
+ * associated non-global zone. However, when a process within the non-global
+ * zone freshly opens the zone console, the anchor is pushed from within the
+ * non-global zone, making it possible for processes within the non-global zone
+ * (e.g., ttymon) to pop the anchor and destroy the zone console's terminal
+ * semantics.
*
- * One solution is to make the zcons device hold the slave open while the
+ * One solution is to make the zcons device hold the subsidiary open while the
* associated non-global zone runs so that the STREAMS anchor will always be
- * associated with the global zone. Unfortunately, the slave cannot be opened
- * from within the zcons driver because the driver is not reentrant: it has
- * an outer STREAMS perimeter. Therefore, the next best option is for zcons to
- * provide an ioctl interface to zoneadmd to manage holding and releasing
- * the slave side of the console. It is sufficient to hold the slave side's
- * vnode and bump the associated snode's reference count to preserve the slave's
- * STREAMS configuration while the associated zone runs, so that's what the
- * ioctls do.
+ * associated with the global zone. Unfortunately, the subsidiary cannot be
+ * opened from within the zcons driver because the driver is not reentrant: it
+ * has an outer STREAMS perimeter. Therefore, the next best option is for
+ * zcons to provide an ioctl interface to zoneadmd to manage holding and
+ * releasing the subsidiary side of the console. It is sufficient to hold the
+ * subsidiary side's vnode and bump the associated snode's reference count to
+ * preserve the subsidiary's STREAMS configuration while the associated zone
+ * runs, so that's what the ioctls do.
*
*
- * ZC_HOLDSLAVE
+ * ZC_HOLDSUBSID
*
* This ioctl takes a file descriptor as an argument. It effectively gets a
- * reference to the slave side's minor node's vnode and bumps the associated
- * snode's reference count. The vnode reference is stored in the zcons device
- * node's soft state. This ioctl succeeds if the given file descriptor refers
- * to the slave side's minor node or if there is already a reference to the
- * slave side's minor node's vnode in the device's soft state.
+ * reference to the subsidiary side's minor node's vnode and bumps the
+ * associated snode's reference count. The vnode reference is stored in the
+ * zcons device node's soft state. This ioctl succeeds if the given file
+ * descriptor refers to the subsidiary side's minor node or if there is already
+ * a reference to the subsidiary side's minor node's vnode in the device's soft
+ * state.
*
*
- * ZC_RELEASESLAVE
+ * ZC_RELEASESUBSID
*
* This ioctl takes a file descriptor as an argument. It effectively releases
* the vnode reference stored in the zcons device node's soft state (which was
- * previously acquired via ZC_HOLDSLAVE) and decrements the reference count of
+ * previously acquired via ZC_HOLDSUBSID) and decrements the reference count of
* the snode associated with the vnode. This ioctl succeeds if the given file
- * descriptor refers to the slave side's minor node or if no reference to the
- * slave side's minor node's vnode is stored in the device's soft state.
+ * descriptor refers to the subsidiary side's minor node or if no reference to
+ * the subsidiary side's minor node's vnode is stored in the device's soft
+ * state.
*
*
* Note that the file descriptor arguments for both ioctls must be cast to
@@ -117,35 +120,36 @@
*
* Zone boot:
* 1. While booting the zone, zoneadmd creates an instance of zcons.
- * 2. zoneadmd opens the master and slave sides of the new zone console
- * and issues the ZC_HOLDSLAVE ioctl on the master side, passing its
- * file descriptor for the slave side as the ioctl argument.
- * 3. zcons holds the slave side's vnode, bumps the snode's reference
+ * 2. zoneadmd opens the manager and subsidiary sides of the new zone
+ * console and issues the ZC_HOLDSUBSID ioctl on the manager side,
+ * passing its file descriptor for the subsidiary side as the ioctl
+ * argument.
+ * 3. zcons holds the subsidiary side's vnode, bumps the snode's reference
* count, and stores a pointer to the vnode in the device's soft
* state.
- * 4. zoneadmd closes the master and slave sides and continues to boot
- * the zone.
+ * 4. zoneadmd closes the manager and subsidiary sides and continues to
+ * boot the zone.
*
* Zone halt:
- * 1. While halting the zone, zoneadmd opens the master and slave sides
- * of the zone's console and issues the ZC_RELEASESLAVE ioctl on the
- * master side, passing its file descriptor for the slave side as the
- * ioctl argument.
- * 2. zcons decrements the slave side's snode's reference count, releases
- * the slave's vnode, and eliminates its reference to the vnode in the
- * device's soft state.
- * 3. zoneadmd closes the master and slave sides.
+ * 1. While halting the zone, zoneadmd opens the manager and subsidiary
+ * sides of the zone's console and issues the ZC_RELEASESUBSID ioctl on
+ * the manager side, passing its file descriptor for the subsidiary
+ * side as the ioctl argument.
+ * 2. zcons decrements the subsidiary side's snode's reference count,
+ * releases the subsidiary's vnode, and eliminates its reference to the
+ * vnode in the device's soft state.
+ * 3. zoneadmd closes the manager and subsidiary sides.
* 4. zoneadmd destroys the zcons device and continues to halt the zone.
*
- * It is necessary for zoneadmd to hold the slave open while issuing
- * ZC_RELEASESLAVE because zcons might otherwise release the last reference to
- * the slave's vnode. If it does, then specfs will panic because it will expect
- * that the STREAMS configuration for the vnode was destroyed, which VN_RELE
- * doesn't do. Forcing zoneadmd to hold the slave open guarantees that zcons
- * won't release the vnode's last reference. zoneadmd will properly destroy the
- * vnode and the snode when it closes the file descriptor.
+ * It is necessary for zoneadmd to hold the subsidiary open while issuing
+ * ZC_RELEASESUBSID because zcons might otherwise release the last reference to
+ * the subsidiary's vnode. If it does, then specfs will panic because it will
+ * expect that the STREAMS configuration for the vnode was destroyed, which
+ * VN_RELE doesn't do. Forcing zoneadmd to hold the subsidiary open guarantees
+ * that zcons won't release the vnode's last reference. zoneadmd will properly
+ * destroy the vnode and the snode when it closes the file descriptor.
*
- * Technically, any process that can access the master side can issue these
+ * Technically, any process that can access the manager side can issue these
* ioctls, but they should be treated as private interfaces for zoneadmd.
*/
@@ -186,21 +190,22 @@ static int zc_wsrv(queue_t *);
/*
* The instance number is encoded in the dev_t in the minor number; the lowest
- * bit of the minor number is used to track the master vs. slave side of the
- * virtual console. The rest of the bits in the minor number are the instance.
+ * bit of the minor number is used to track the manager vs. subsidiary side of
+ * the virtual console. The rest of the bits in the minor number are the
+ * instance.
*/
-#define ZC_MASTER_MINOR 0
-#define ZC_SLAVE_MINOR 1
+#define ZC_MANAGER_MINOR 0
+#define ZC_SUBSID_MINOR 1
#define ZC_INSTANCE(x) (getminor((x)) >> 1)
#define ZC_NODE(x) (getminor((x)) & 0x01)
/*
- * This macro converts a zc_state_t pointer to the associated slave minor node's
- * dev_t.
+ * This macro converts a zc_state_t pointer to the associated subsidiary minor
+ * node's dev_t.
*/
-#define ZC_STATE_TO_SLAVEDEV(x) (makedevice(ddi_driver_major((x)->zc_devinfo), \
- (minor_t)(ddi_get_instance((x)->zc_devinfo) << 1 | ZC_SLAVE_MINOR)))
+#define ZC_STATE_TO_SUBDEV(x) (makedevice(ddi_driver_major((x)->zc_devinfo), \
+ (minor_t)(ddi_get_instance((x)->zc_devinfo) << 1 | ZC_SUBSID_MINOR)))
int zcons_debug = 0;
#define DBG(a) if (zcons_debug) cmn_err(CE_NOTE, a)
@@ -272,9 +277,9 @@ static struct modlinkage modlinkage = {
typedef struct zc_state {
dev_info_t *zc_devinfo;
- queue_t *zc_master_rdq;
- queue_t *zc_slave_rdq;
- vnode_t *zc_slave_vnode;
+ queue_t *zc_manager_rdq;
+ queue_t *zc_subsid_rdq;
+ vnode_t *zc_subsid_vnode;
int zc_state;
} zc_state_t;
@@ -284,7 +289,7 @@ typedef struct zc_state {
static void *zc_soft_state;
/*
- * List of STREAMS modules that should be pushed onto every slave instance.
+ * List of STREAMS modules that should be pushed onto every subsidiary instance.
*/
static char *zcons_mods[] = {
"ptem",
@@ -343,12 +348,12 @@ zc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
return (DDI_FAILURE);
/*
- * Create the master and slave minor nodes.
+ * Create the manager and subsidiary minor nodes.
*/
- if ((ddi_create_minor_node(dip, ZCONS_SLAVE_NAME, S_IFCHR,
- instance << 1 | ZC_SLAVE_MINOR, DDI_PSEUDO, 0) == DDI_FAILURE) ||
- (ddi_create_minor_node(dip, ZCONS_MASTER_NAME, S_IFCHR,
- instance << 1 | ZC_MASTER_MINOR, DDI_PSEUDO, 0) == DDI_FAILURE)) {
+ if ((ddi_create_minor_node(dip, ZCONS_SUBSIDIARY_NAME, S_IFCHR,
+ instance << 1 | ZC_SUBSID_MINOR, DDI_PSEUDO, 0) == DDI_FAILURE) ||
+ (ddi_create_minor_node(dip, ZCONS_MANAGER_NAME, S_IFCHR,
+ instance << 1 | ZC_MANAGER_MINOR, DDI_PSEUDO, 0) == DDI_FAILURE)) {
ddi_remove_minor_node(dip, NULL);
ddi_soft_state_free(zc_soft_state, instance);
return (DDI_FAILURE);
@@ -388,7 +393,6 @@ zc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
* zc_getinfo()
* getinfo(9e) entrypoint.
*/
-/*ARGSUSED*/
static int
zc_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
{
@@ -410,7 +414,7 @@ zc_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
/*
* Return the equivalent queue from the other side of the relationship.
- * e.g.: given the slave's write queue, return the master's write queue.
+ * e.g.: given the subsidiary's write queue, return the manager's write queue.
*/
static queue_t *
zc_switch(queue_t *qp)
@@ -418,16 +422,19 @@ zc_switch(queue_t *qp)
zc_state_t *zcs = qp->q_ptr;
ASSERT(zcs != NULL);
- if (qp == zcs->zc_master_rdq)
- return (zcs->zc_slave_rdq);
- else if (OTHERQ(qp) == zcs->zc_master_rdq && zcs->zc_slave_rdq != NULL)
- return (OTHERQ(zcs->zc_slave_rdq));
- else if (qp == zcs->zc_slave_rdq)
- return (zcs->zc_master_rdq);
- else if (OTHERQ(qp) == zcs->zc_slave_rdq && zcs->zc_master_rdq != NULL)
- return (OTHERQ(zcs->zc_master_rdq));
- else
+ if (qp == zcs->zc_manager_rdq) {
+ return (zcs->zc_subsid_rdq);
+ } else if (OTHERQ(qp) == zcs->zc_manager_rdq &&
+ zcs->zc_subsid_rdq != NULL) {
+ return (OTHERQ(zcs->zc_subsid_rdq));
+ } else if (qp == zcs->zc_subsid_rdq) {
+ return (zcs->zc_manager_rdq);
+ } else if (OTHERQ(qp) == zcs->zc_subsid_rdq &&
+ zcs->zc_manager_rdq != NULL) {
+ return (OTHERQ(zcs->zc_manager_rdq));
+ } else {
return (NULL);
+ }
}
/*
@@ -440,17 +447,16 @@ zc_side(queue_t *qp)
zc_state_t *zcs = qp->q_ptr;
ASSERT(zcs != NULL);
- if (qp == zcs->zc_master_rdq ||
- OTHERQ(qp) == zcs->zc_master_rdq) {
- return ("master");
+ if (qp == zcs->zc_manager_rdq ||
+ OTHERQ(qp) == zcs->zc_manager_rdq) {
+ return ("manager");
}
- ASSERT(qp == zcs->zc_slave_rdq || OTHERQ(qp) == zcs->zc_slave_rdq);
- return ("slave");
+ ASSERT(qp == zcs->zc_subsid_rdq || OTHERQ(qp) == zcs->zc_subsid_rdq);
+ return ("subsidiary");
}
-/*ARGSUSED*/
static int
-zc_master_open(zc_state_t *zcs,
+zc_manager_open(zc_state_t *zcs,
queue_t *rqp, /* pointer to the read side queue */
dev_t *devp, /* pointer to stream tail's dev */
int oflag, /* the user open(2) supplied flags */
@@ -461,14 +467,14 @@ zc_master_open(zc_state_t *zcs,
struct stroptions *sop;
/*
- * Enforce exclusivity on the master side; the only consumer should
+ * Enforce exclusivity on the manager side; the only consumer should
* be the zoneadmd for the zone.
*/
if ((zcs->zc_state & ZC_STATE_MOPEN) != 0)
return (EBUSY);
if ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) {
- DBG("zc_master_open(): mop allocation failed\n");
+ DBG("zc_manager_open(): mop allocation failed\n");
return (ENOMEM);
}
@@ -482,13 +488,13 @@ zc_master_open(zc_state_t *zcs,
qprocson(rqp);
/*
- * Following qprocson(), the master side is fully plumbed into the
- * STREAM and may send/receive messages. Setting zcs->zc_master_rdq
- * will allow the slave to send messages to us (the master).
- * This cannot occur before qprocson() because the master is not
+ * Following qprocson(), the manager side is fully plumbed into the
+ * STREAM and may send/receive messages. Setting zcs->zc_manager_rdq
+ * will allow the subsidiary to send messages to us (the manager).
+ * This cannot occur before qprocson() because the manager is not
* ready to process them until that point.
*/
- zcs->zc_master_rdq = rqp;
+ zcs->zc_manager_rdq = rqp;
/*
* set up hi/lo water marks on stream head read queue and add
@@ -508,9 +514,8 @@ zc_master_open(zc_state_t *zcs,
return (0);
}
-/*ARGSUSED*/
static int
-zc_slave_open(zc_state_t *zcs,
+zc_subsidiary_open(zc_state_t *zcs,
queue_t *rqp, /* pointer to the read side queue */
dev_t *devp, /* pointer to stream tail's dev */
int oflag, /* the user open(2) supplied flags */
@@ -525,7 +530,7 @@ zc_slave_open(zc_state_t *zcs,
uint_t anchorindex;
/*
- * The slave side can be opened as many times as needed.
+ * The subsidiary side can be opened as many times as needed.
*/
if ((zcs->zc_state & ZC_STATE_SOPEN) != 0) {
ASSERT((rqp != NULL) && (WR(rqp)->q_ptr == zcs));
@@ -538,18 +543,18 @@ zc_slave_open(zc_state_t *zcs,
* in place (see streamio(4I)) because we always want the console to
* have terminal semantics.
*/
- minor = ddi_get_instance(zcs->zc_devinfo) << 1 | ZC_SLAVE_MINOR;
+ minor = ddi_get_instance(zcs->zc_devinfo) << 1 | ZC_SUBSID_MINOR;
major = ddi_driver_major(zcs->zc_devinfo);
lastminor = 0;
anchorindex = 1;
if (kstr_autopush(SET_AUTOPUSH, &major, &minor, &lastminor,
&anchorindex, zcons_mods) != 0) {
- DBG("zc_slave_open(): kstr_autopush() failed\n");
+ DBG("zc_subsidiary_open(): kstr_autopush() failed\n");
return (EIO);
}
if ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) {
- DBG("zc_slave_open(): mop allocation failed\n");
+ DBG("zc_subsidiary_open(): mop allocation failed\n");
return (ENOMEM);
}
@@ -566,7 +571,7 @@ zc_slave_open(zc_state_t *zcs,
/*
* Must follow qprocson(), since we aren't ready to process until then.
*/
- zcs->zc_slave_rdq = rqp;
+ zcs->zc_subsid_rdq = rqp;
/*
* set up hi/lo water marks on stream head read queue and add
@@ -604,11 +609,11 @@ zc_open(queue_t *rqp, /* pointer to the read side queue */
return (ENXIO);
switch (ZC_NODE(*devp)) {
- case ZC_MASTER_MINOR:
- ret = zc_master_open(zcs, rqp, devp, oflag, sflag, credp);
+ case ZC_MANAGER_MINOR:
+ ret = zc_manager_open(zcs, rqp, devp, oflag, sflag, credp);
break;
- case ZC_SLAVE_MINOR:
- ret = zc_slave_open(zcs, rqp, devp, oflag, sflag, credp);
+ case ZC_SUBSID_MINOR:
+ ret = zc_subsidiary_open(zcs, rqp, devp, oflag, sflag, credp);
break;
default:
ret = ENXIO;
@@ -621,7 +626,6 @@ zc_open(queue_t *rqp, /* pointer to the read side queue */
/*
* close(9e) entrypoint.
*/
-/*ARGSUSED1*/
static int
zc_close(queue_t *rqp, int flag, cred_t *credp)
{
@@ -633,33 +637,33 @@ zc_close(queue_t *rqp, int flag, cred_t *credp)
zcs = (zc_state_t *)rqp->q_ptr;
- if (rqp == zcs->zc_master_rdq) {
- DBG("Closing master side");
+ if (rqp == zcs->zc_manager_rdq) {
+ DBG("Closing manager side");
- zcs->zc_master_rdq = NULL;
+ zcs->zc_manager_rdq = NULL;
zcs->zc_state &= ~ZC_STATE_MOPEN;
/*
- * qenable slave side write queue so that it can flush
- * its messages as master's read queue is going away
+ * qenable subsidiary side write queue so that it can flush
+ * its messages as manager's read queue is going away
*/
- if (zcs->zc_slave_rdq != NULL) {
- qenable(WR(zcs->zc_slave_rdq));
+ if (zcs->zc_subsid_rdq != NULL) {
+ qenable(WR(zcs->zc_subsid_rdq));
}
qprocsoff(rqp);
WR(rqp)->q_ptr = rqp->q_ptr = NULL;
- } else if (rqp == zcs->zc_slave_rdq) {
+ } else if (rqp == zcs->zc_subsid_rdq) {
- DBG("Closing slave side");
+ DBG("Closing subsidiary side");
zcs->zc_state &= ~ZC_STATE_SOPEN;
- zcs->zc_slave_rdq = NULL;
+ zcs->zc_subsid_rdq = NULL;
wqp = WR(rqp);
while ((bp = getq(wqp)) != NULL) {
- if (zcs->zc_master_rdq != NULL)
- putnext(zcs->zc_master_rdq, bp);
+ if (zcs->zc_manager_rdq != NULL)
+ putnext(zcs->zc_manager_rdq, bp);
else if (bp->b_datap->db_type == M_IOCTL)
miocnak(wqp, bp, 0, 0);
else
@@ -667,11 +671,11 @@ zc_close(queue_t *rqp, int flag, cred_t *credp)
}
/*
- * Qenable master side write queue so that it can flush its
- * messages as slaves's read queue is going away.
+ * Qenable manager side write queue so that it can flush its
+ * messages as subsidiarys's read queue is going away.
*/
- if (zcs->zc_master_rdq != NULL)
- qenable(WR(zcs->zc_master_rdq));
+ if (zcs->zc_manager_rdq != NULL)
+ qenable(WR(zcs->zc_manager_rdq));
qprocsoff(rqp);
WR(rqp)->q_ptr = rqp->q_ptr = NULL;
@@ -681,7 +685,8 @@ zc_close(queue_t *rqp, int flag, cred_t *credp)
* to set up sad configuration.
*/
major = ddi_driver_major(zcs->zc_devinfo);
- minor = ddi_get_instance(zcs->zc_devinfo) << 1 | ZC_SLAVE_MINOR;
+ minor = ddi_get_instance(zcs->zc_devinfo) << 1 |
+ ZC_SUBSID_MINOR;
(void) kstr_autopush(CLR_AUTOPUSH, &major, &minor, NULL, NULL,
NULL);
}
@@ -729,9 +734,9 @@ handle_mflush(queue_t *qp, mblk_t *mp)
}
/*
- * wput(9E) is symmetric for master and slave sides, so this handles both
+ * wput(9E) is symmetric for manager and subsidiary sides, so this handles both
* without splitting the codepath. (The only exception to this is the
- * processing of zcons ioctls, which is restricted to the master side.)
+ * processing of zcons ioctls, which is restricted to the manager side.)
*
* zc_wput() looks at the other side; if there is no process holding that
* side open, it frees the message. This prevents processes from hanging
@@ -746,34 +751,34 @@ zc_wput(queue_t *qp, mblk_t *mp)
unsigned char type = mp->b_datap->db_type;
zc_state_t *zcs;
struct iocblk *iocbp;
- file_t *slave_filep;
- struct snode *slave_snodep;
- int slave_fd;
+ file_t *subsidiary_filep;
+ struct snode *subsidiary_snodep;
+ int subsidiary_fd;
ASSERT(qp->q_ptr);
DBG1("entering zc_wput, %s side", zc_side(qp));
/*
- * Process zcons ioctl messages if qp is the master console's write
+ * Process zcons ioctl messages if qp is the manager console's write
* queue.
*/
zcs = (zc_state_t *)qp->q_ptr;
- if (zcs->zc_master_rdq != NULL && qp == WR(zcs->zc_master_rdq) &&
+ if (zcs->zc_manager_rdq != NULL && qp == WR(zcs->zc_manager_rdq) &&
type == M_IOCTL) {
iocbp = (struct iocblk *)(void *)mp->b_rptr;
switch (iocbp->ioc_cmd) {
- case ZC_HOLDSLAVE:
+ case ZC_HOLDSUBSID:
/*
- * Hold the slave's vnode and increment the refcount
- * of the snode. If the vnode is already held, then
- * indicate success.
+ * Hold the subsidiary's vnode and increment the
+ * refcount of the snode. If the vnode is already
+ * held, then indicate success.
*/
if (iocbp->ioc_count != TRANSPARENT) {
miocack(qp, mp, 0, EINVAL);
return (0);
}
- if (zcs->zc_slave_vnode != NULL) {
+ if (zcs->zc_subsid_vnode != NULL) {
miocack(qp, mp, 0, 0);
return (0);
}
@@ -789,49 +794,49 @@ zc_wput(queue_t *qp, mblk_t *mp)
/*
* The calling process must pass a file descriptor for
- * the slave device.
+ * the subsidiary device.
*/
- slave_fd =
+ subsidiary_fd =
(int)(intptr_t)*(caddr_t *)(void *)mp->b_cont->
b_rptr;
- slave_filep = getf(slave_fd);
- if (slave_filep == NULL) {
+ subsidiary_filep = getf(subsidiary_fd);
+ if (subsidiary_filep == NULL) {
miocack(qp, mp, 0, EINVAL);
return (0);
}
- if (ZC_STATE_TO_SLAVEDEV(zcs) !=
- slave_filep->f_vnode->v_rdev) {
- releasef(slave_fd);
+ if (ZC_STATE_TO_SUBDEV(zcs) !=
+ subsidiary_filep->f_vnode->v_rdev) {
+ releasef(subsidiary_fd);
miocack(qp, mp, 0, EINVAL);
return (0);
}
/*
- * Get a reference to the slave's vnode. Also bump the
- * reference count on the associated snode.
+ * Get a reference to the subsidiary's vnode. Also
+ * bump the reference count on the associated snode.
*/
- ASSERT(vn_matchops(slave_filep->f_vnode,
+ ASSERT(vn_matchops(subsidiary_filep->f_vnode,
spec_getvnodeops()));
- zcs->zc_slave_vnode = slave_filep->f_vnode;
- VN_HOLD(zcs->zc_slave_vnode);
- slave_snodep = VTOCS(zcs->zc_slave_vnode);
- mutex_enter(&slave_snodep->s_lock);
- ++slave_snodep->s_count;
- mutex_exit(&slave_snodep->s_lock);
- releasef(slave_fd);
+ zcs->zc_subsid_vnode = subsidiary_filep->f_vnode;
+ VN_HOLD(zcs->zc_subsid_vnode);
+ subsidiary_snodep = VTOCS(zcs->zc_subsid_vnode);
+ mutex_enter(&subsidiary_snodep->s_lock);
+ ++subsidiary_snodep->s_count;
+ mutex_exit(&subsidiary_snodep->s_lock);
+ releasef(subsidiary_fd);
miocack(qp, mp, 0, 0);
return (0);
- case ZC_RELEASESLAVE:
+ case ZC_RELEASESUBSID:
/*
- * Release the master's handle on the slave's vnode.
- * If there isn't a handle for the vnode, then indicate
- * success.
+ * Release the manager's handle on the subsidiary's
+ * vnode. If there isn't a handle for the vnode, then
+ * indicate success.
*/
if (iocbp->ioc_count != TRANSPARENT) {
miocack(qp, mp, 0, EINVAL);
return (0);
}
- if (zcs->zc_slave_vnode == NULL) {
+ if (zcs->zc_subsid_vnode == NULL) {
miocack(qp, mp, 0, 0);
return (0);
}
@@ -847,20 +852,20 @@ zc_wput(queue_t *qp, mblk_t *mp)
/*
* The process that passed the ioctl must have provided
- * a file descriptor for the slave device. Make sure
- * this is correct.
+ * a file descriptor for the subsidiary device. Make
+ * sure this is correct.
*/
- slave_fd =
+ subsidiary_fd =
(int)(intptr_t)*(caddr_t *)(void *)mp->b_cont->
b_rptr;
- slave_filep = getf(slave_fd);
- if (slave_filep == NULL) {
+ subsidiary_filep = getf(subsidiary_fd);
+ if (subsidiary_filep == NULL) {
miocack(qp, mp, 0, EINVAL);
return (0);
}
- if (zcs->zc_slave_vnode->v_rdev !=
- slave_filep->f_vnode->v_rdev) {
- releasef(slave_fd);
+ if (zcs->zc_subsid_vnode->v_rdev !=
+ subsidiary_filep->f_vnode->v_rdev) {
+ releasef(subsidiary_fd);
miocack(qp, mp, 0, EINVAL);
return (0);
}
@@ -869,15 +874,15 @@ zc_wput(queue_t *qp, mblk_t *mp)
* Decrement the snode's reference count and release the
* vnode.
*/
- ASSERT(vn_matchops(slave_filep->f_vnode,
+ ASSERT(vn_matchops(subsidiary_filep->f_vnode,
spec_getvnodeops()));
- slave_snodep = VTOCS(zcs->zc_slave_vnode);
- mutex_enter(&slave_snodep->s_lock);
- --slave_snodep->s_count;
- mutex_exit(&slave_snodep->s_lock);
- VN_RELE(zcs->zc_slave_vnode);
- zcs->zc_slave_vnode = NULL;
- releasef(slave_fd);
+ subsidiary_snodep = VTOCS(zcs->zc_subsid_vnode);
+ mutex_enter(&subsidiary_snodep->s_lock);
+ --subsidiary_snodep->s_count;
+ mutex_exit(&subsidiary_snodep->s_lock);
+ VN_RELE(zcs->zc_subsid_vnode);
+ zcs->zc_subsid_vnode = NULL;
+ releasef(subsidiary_fd);
miocack(qp, mp, 0, 0);
return (0);
default:
@@ -939,7 +944,7 @@ zc_wput(queue_t *qp, mblk_t *mp)
}
/*
- * rsrv(9E) is symmetric for master and slave, so zc_rsrv() handles both
+ * rsrv(9E) is symmetric for manager and subsidiary, so zc_rsrv() handles both
* without splitting up the codepath.
*
* Enable the write side of the partner. This triggers the partner to send
@@ -952,10 +957,10 @@ zc_rsrv(queue_t *qp)
zcs = (zc_state_t *)qp->q_ptr;
/*
- * Care must be taken here, as either of the master or slave side
+ * Care must be taken here, as either of the manager or subsidiary side
* qptr could be NULL.
*/
- ASSERT(qp == zcs->zc_master_rdq || qp == zcs->zc_slave_rdq);
+ ASSERT(qp == zcs->zc_manager_rdq || qp == zcs->zc_subsid_rdq);
if (zc_switch(qp) == NULL) {
DBG("zc_rsrv: other side isn't listening\n");
return (0);
@@ -965,8 +970,8 @@ zc_rsrv(queue_t *qp)
}
/*
- * This routine is symmetric for master and slave, so it handles both without
- * splitting up the codepath.
+ * This routine is symmetric for manager and subsidiary, so it handles both
+ * without splitting up the codepath.
*
* If there are messages on this queue that can be sent to the other, send
* them via putnext(). Else, if queued messages cannot be sent, leave them
@@ -977,7 +982,7 @@ zc_wsrv(queue_t *qp)
{
mblk_t *mp;
- DBG1("zc_wsrv master (%s) side", zc_side(qp));
+ DBG1("zc_wsrv manager (%s) side", zc_side(qp));
/*
* Partner has no read queue, so take the data, and throw it away.
diff --git a/usr/src/uts/common/krtld/kobj.c b/usr/src/uts/common/krtld/kobj.c
index e6a91bcb33..6c36cd5e95 100644
--- a/usr/src/uts/common/krtld/kobj.c
+++ b/usr/src/uts/common/krtld/kobj.c
@@ -1030,12 +1030,10 @@ kobj_notify_remove(kobj_notify_list_t *knp)
mutex_enter(&kobj_lock);
- /* LINTED */
- if (tknp = knp->kn_next)
+ if ((tknp = knp->kn_next) != NULL)
tknp->kn_prev = knp->kn_prev;
- /* LINTED */
- if (tknp = knp->kn_prev)
+ if ((tknp = knp->kn_prev) != NULL)
tknp->kn_next = knp->kn_next;
else
*knl = knp->kn_next;
@@ -2240,7 +2238,7 @@ free_module_data(struct module *mp)
break;
}
}
-err_free_done:
+
if (!(mp->flags & KOBJ_PRIM)) {
kobj_free(mp->shdrs,
mp->hdr.e_shentsize * mp->hdr.e_shnum);
diff --git a/usr/src/uts/common/netinet/in.h b/usr/src/uts/common/netinet/in.h
index 1f732c2f65..8b4358cb8d 100644
--- a/usr/src/uts/common/netinet/in.h
+++ b/usr/src/uts/common/netinet/in.h
@@ -3,6 +3,7 @@
* Use is subject to license terms.
*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2015, Joyent, Inc.
* Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
*/
/*
diff --git a/usr/src/uts/common/os/bio.c b/usr/src/uts/common/os/bio.c
index abaaef1b4a..daf3b638a6 100644
--- a/usr/src/uts/common/os/bio.c
+++ b/usr/src/uts/common/os/bio.c
@@ -1488,7 +1488,6 @@ bio_getfreeblk(long bsize)
*/
bio_mem_get(bsize); /* Account for our memory request */
-again:
bp = bio_bhdr_alloc(); /* Get a buf hdr */
sema_p(&bp->b_sem); /* Should never fail */
diff --git a/usr/src/uts/common/os/cpu.c b/usr/src/uts/common/os/cpu.c
index 7f7216688c..075bb6e70a 100644
--- a/usr/src/uts/common/os/cpu.c
+++ b/usr/src/uts/common/os/cpu.c
@@ -614,7 +614,7 @@ again:
* requests will continue to be satisfied in the same way,
* even if weak bindings have recommenced.
*/
- if (t->t_nomigrate < 0 || weakbindingbarrier && t->t_nomigrate == 0) {
+ if (t->t_nomigrate < 0 || (weakbindingbarrier && t->t_nomigrate == 0)) {
--t->t_nomigrate;
thread_unlock(curthread);
return; /* with kpreempt_disable still active */
diff --git a/usr/src/uts/common/os/ddi_ufm.c b/usr/src/uts/common/os/ddi_ufm.c
index a9da32cc4c..940ebf82bf 100644
--- a/usr/src/uts/common/os/ddi_ufm.c
+++ b/usr/src/uts/common/os/ddi_ufm.c
@@ -181,7 +181,7 @@ ufm_cache_fill(ddi_ufm_handle_t *ufmh)
*/
ufmh->ufmh_images =
kmem_zalloc((sizeof (ddi_ufm_image_t) * ufmh->ufmh_nimages),
- KM_NOSLEEP | KM_NORMALPRI);
+ KM_NOSLEEP_LAZY);
if (ufmh->ufmh_images == NULL)
return (ENOMEM);
@@ -201,7 +201,7 @@ ufm_cache_fill(ddi_ufm_handle_t *ufmh)
img->ufmi_slots =
kmem_zalloc((sizeof (ddi_ufm_slot_t) * img->ufmi_nslots),
- KM_NOSLEEP | KM_NORMALPRI);
+ KM_NOSLEEP_LAZY);
if (img->ufmi_slots == NULL) {
ret = ENOMEM;
goto cache_fail;
diff --git a/usr/src/uts/common/os/driver_lyr.c b/usr/src/uts/common/os/driver_lyr.c
index 0392b590f1..d64342738b 100644
--- a/usr/src/uts/common/os/driver_lyr.c
+++ b/usr/src/uts/common/os/driver_lyr.c
@@ -1131,7 +1131,7 @@ ldi_usage_walker_helper(struct ldi_ident *lip, vnode_t *vp,
else
major = lip->li_major;
- ASSERT((major >= 0) && (major < devcnt));
+ ASSERT3U(major, <, devcnt);
dnp = &devnamesp[major];
LOCK_DEV_OPS(&dnp->dn_lock);
diff --git a/usr/src/uts/common/os/exacct.c b/usr/src/uts/common/os/exacct.c
index c9214cec84..1051c037fa 100644
--- a/usr/src/uts/common/os/exacct.c
+++ b/usr/src/uts/common/os/exacct.c
@@ -1508,10 +1508,8 @@ exacct_attach_flow_item(flow_usage_t *fu, ea_object_t *record, int res)
}
break;
case AC_FLOW_UID:
- if (fu->fu_userid >= 0) {
- (void) ea_attach_item(record, &fu->fu_userid,
- sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_UID);
- }
+ (void) ea_attach_item(record, &fu->fu_userid,
+ sizeof (uint32_t), EXT_UINT32 | EXD_FLOW_UID);
break;
case AC_FLOW_ANAME:
(void) ea_attach_item(record, fu->fu_aname,
diff --git a/usr/src/uts/common/os/fio.c b/usr/src/uts/common/os/fio.c
index 7b6d973b9e..c25564d85f 100644
--- a/usr/src/uts/common/os/fio.c
+++ b/usr/src/uts/common/os/fio.c
@@ -1585,7 +1585,9 @@ fsetattrat(int fd, char *path, int flags, struct vattr *vap)
VN_HOLD(vp);
}
- if (vn_is_readonly(vp)) {
+ if (vp->v_type == VLNK && (vap->va_mask & AT_MODE) != 0) {
+ error = EOPNOTSUPP;
+ } else if (vn_is_readonly(vp)) {
error = EROFS;
} else {
error = VOP_SETATTR(vp, vap, 0, CRED(), NULL);
diff --git a/usr/src/uts/common/os/flock.c b/usr/src/uts/common/os/flock.c
index 77ec4fe9ce..2d7849e30d 100644
--- a/usr/src/uts/common/os/flock.c
+++ b/usr/src/uts/common/os/flock.c
@@ -1122,8 +1122,8 @@ flk_process_request(lock_descriptor_t *request)
}
if (!request_blocked_by_active) {
- lock_descriptor_t *lk[1];
- lock_descriptor_t *first_glock = NULL;
+ lock_descriptor_t *lk[1];
+ lock_descriptor_t *first_glock = NULL;
/*
* Shall we grant this?! NO!!
* What about those locks that were just granted and still
@@ -2093,12 +2093,12 @@ flk_graph_uncolor(graph_t *gp)
if (gp->mark == UINT_MAX) {
gp->mark = 1;
- for (lock = ACTIVE_HEAD(gp)->l_next; lock != ACTIVE_HEAD(gp);
- lock = lock->l_next)
+ for (lock = ACTIVE_HEAD(gp)->l_next; lock != ACTIVE_HEAD(gp);
+ lock = lock->l_next)
lock->l_color = 0;
- for (lock = SLEEPING_HEAD(gp)->l_next; lock != SLEEPING_HEAD(gp);
- lock = lock->l_next)
+ for (lock = SLEEPING_HEAD(gp)->l_next;
+ lock != SLEEPING_HEAD(gp); lock = lock->l_next)
lock->l_color = 0;
} else {
gp->mark++;
@@ -4469,34 +4469,34 @@ check_sleeping_locks(graph_t *gp)
edge_t *ep;
for (lock1 = SLEEPING_HEAD(gp)->l_next; lock1 != SLEEPING_HEAD(gp);
lock1 = lock1->l_next) {
- ASSERT(!IS_BARRIER(lock1));
- for (lock2 = lock1->l_next; lock2 != SLEEPING_HEAD(gp);
- lock2 = lock2->l_next) {
- if (lock1->l_vnode == lock2->l_vnode) {
- if (BLOCKS(lock2, lock1)) {
- ASSERT(!IS_GRANTED(lock1));
- ASSERT(!NOT_BLOCKED(lock1));
- path(lock1, lock2);
+ ASSERT(!IS_BARRIER(lock1));
+ for (lock2 = lock1->l_next; lock2 != SLEEPING_HEAD(gp);
+ lock2 = lock2->l_next) {
+ if (lock1->l_vnode == lock2->l_vnode) {
+ if (BLOCKS(lock2, lock1)) {
+ ASSERT(!IS_GRANTED(lock1));
+ ASSERT(!NOT_BLOCKED(lock1));
+ path(lock1, lock2);
+ }
}
}
- }
- for (lock2 = ACTIVE_HEAD(gp)->l_next; lock2 != ACTIVE_HEAD(gp);
- lock2 = lock2->l_next) {
- ASSERT(!IS_BARRIER(lock1));
- if (lock1->l_vnode == lock2->l_vnode) {
- if (BLOCKS(lock2, lock1)) {
- ASSERT(!IS_GRANTED(lock1));
- ASSERT(!NOT_BLOCKED(lock1));
- path(lock1, lock2);
+ for (lock2 = ACTIVE_HEAD(gp)->l_next; lock2 != ACTIVE_HEAD(gp);
+ lock2 = lock2->l_next) {
+ ASSERT(!IS_BARRIER(lock1));
+ if (lock1->l_vnode == lock2->l_vnode) {
+ if (BLOCKS(lock2, lock1)) {
+ ASSERT(!IS_GRANTED(lock1));
+ ASSERT(!NOT_BLOCKED(lock1));
+ path(lock1, lock2);
+ }
}
}
- }
- ep = FIRST_ADJ(lock1);
- while (ep != HEAD(lock1)) {
- ASSERT(BLOCKS(ep->to_vertex, lock1));
- ep = NEXT_ADJ(ep);
- }
+ ep = FIRST_ADJ(lock1);
+ while (ep != HEAD(lock1)) {
+ ASSERT(BLOCKS(ep->to_vertex, lock1));
+ ep = NEXT_ADJ(ep);
+ }
}
}
diff --git a/usr/src/uts/common/os/fm.c b/usr/src/uts/common/os/fm.c
index 6b0c27aaef..bd3e5dceac 100644
--- a/usr/src/uts/common/os/fm.c
+++ b/usr/src/uts/common/os/fm.c
@@ -336,6 +336,7 @@ fm_nvprintr(nvlist_t *nvl, int d, int c, int cols)
c = fm_printf(d + 1, c, cols, "[...]");
break;
case DATA_TYPE_UNKNOWN:
+ case DATA_TYPE_DONTCARE:
c = fm_printf(d + 1, c, cols, "<unknown>");
break;
}
diff --git a/usr/src/uts/common/os/klpd.c b/usr/src/uts/common/os/klpd.c
index 8592b47021..0879f791b5 100644
--- a/usr/src/uts/common/os/klpd.c
+++ b/usr/src/uts/common/os/klpd.c
@@ -1150,7 +1150,7 @@ check_user_privs(const cred_t *cr, const priv_set_t *set)
out:
if (da.rbuf != (char *)&res)
kmem_free(da.rbuf, da.rsize);
-out1:
+
kmem_free(pap, pasize);
klpd_rele(pfd);
return (err);
diff --git a/usr/src/uts/common/os/kmem.c b/usr/src/uts/common/os/kmem.c
index 14c587d804..394235f26c 100644
--- a/usr/src/uts/common/os/kmem.c
+++ b/usr/src/uts/common/os/kmem.c
@@ -5362,7 +5362,7 @@ kmem_cache_scan(kmem_cache_t *cp)
}
if (kmem_cache_is_fragmented(cp, &reap)) {
- size_t slabs_found;
+ int slabs_found;
/*
* Consolidate reclaimable slabs from the end of the partial
diff --git a/usr/src/uts/common/os/lgrp.c b/usr/src/uts/common/os/lgrp.c
index f3404a1cdf..31b0cf7e0d 100644
--- a/usr/src/uts/common/os/lgrp.c
+++ b/usr/src/uts/common/os/lgrp.c
@@ -1449,8 +1449,8 @@ lgrp_mem_fini(int mnode, lgrp_handle_t hand, boolean_t is_copy_rename)
* Remove memory node from lgroup.
*/
lgrp->lgrp_mnodes &= ~mnodes_mask;
+ ASSERT(lgrp->lgrp_nmnodes > 0);
lgrp->lgrp_nmnodes--;
- ASSERT(lgrp->lgrp_nmnodes >= 0);
}
ASSERT(lgrp_root->lgrp_nmnodes > 0);
@@ -2160,8 +2160,8 @@ lpl_topo_verify(cpupart_t *cpupart)
/* do the parent lgroups exist and do they match? */
if (lgrp->lgrp_parent) {
- ASSERT(lpl->lpl_parent);
- ASSERT(lgrp->lgrp_parent->lgrp_id ==
+ ASSERT(lpl->lpl_parent != NULL &&
+ lgrp->lgrp_parent->lgrp_id ==
lpl->lpl_parent->lpl_lgrpid);
if (!lpl->lpl_parent) {
@@ -4100,12 +4100,13 @@ lgrp_shm_policy_split(avl_tree_t *tree, lgrp_shm_policy_seg_t *seg,
lgrp_shm_policy_seg_t *newseg;
avl_index_t where;
- ASSERT(seg != NULL);
- ASSERT(off >= seg->shm_off && off <= seg->shm_off + seg->shm_size);
+ ASSERT(seg != NULL && (off >= seg->shm_off &&
+ off <= seg->shm_off + seg->shm_size));
- if (!seg || off < seg->shm_off || off > seg->shm_off +
- seg->shm_size)
+ if (!seg || off < seg->shm_off ||
+ off > seg->shm_off + seg->shm_size) {
return (NULL);
+ }
if (off == seg->shm_off || off == seg->shm_off + seg->shm_size)
return (seg);
diff --git a/usr/src/uts/common/os/log_sysevent.c b/usr/src/uts/common/os/log_sysevent.c
index 35e0048ee7..50dc5dfd82 100644
--- a/usr/src/uts/common/os/log_sysevent.c
+++ b/usr/src/uts/common/os/log_sysevent.c
@@ -1277,7 +1277,7 @@ get_registration(sysevent_channel_descriptor_t *chan, char *databuf,
class_lst_t *clist;
subclass_lst_t *sc_list;
- if (class_index < 0 || class_index > CLASS_HASH_SZ)
+ if (class_index > CLASS_HASH_SZ)
return (EINVAL);
if ((clist = chan->scd_class_list_tbl[class_index]) == NULL) {
@@ -1395,10 +1395,15 @@ log_sysevent_register(char *channel_name, char *udatabuf, se_pubsub_t *udata)
case SE_CLOSE_REGISTRATION:
close_channel(kchannel);
break;
- case SE_BIND_REGISTRATION:
- if ((kdata.ps_id = bind_common(chan, kdata.ps_type)) <= 0)
+ case SE_BIND_REGISTRATION: {
+ id_t id;
+
+ id = bind_common(chan, kdata.ps_type);
+ kdata.ps_id = (uint32_t)id;
+ if (id <= 0)
error = EBUSY;
break;
+ }
case SE_UNBIND_REGISTRATION:
(void) unbind_common(chan, kdata.ps_type, (id_t)kdata.ps_id);
break;
diff --git a/usr/src/uts/common/os/mmapobj.c b/usr/src/uts/common/os/mmapobj.c
index 78421c9bb6..779cd340f4 100644
--- a/usr/src/uts/common/os/mmapobj.c
+++ b/usr/src/uts/common/os/mmapobj.c
@@ -1008,8 +1008,8 @@ mmapobj_map_flat(vnode_t *vp, mmapobj_result_t *mrp, size_t padding,
* fcred - credentials for the file associated with vp at open time.
*/
static int
-mmapobj_map_ptload(struct vnode *vp, caddr_t addr, size_t len, size_t zfodlen,
- off_t offset, int prot, cred_t *fcred)
+mmapobj_map_ptload(struct vnode *vp, caddr_t addr, size_t len,
+ volatile size_t zfodlen, off_t offset, int prot, cred_t *fcred)
{
int error = 0;
caddr_t zfodbase, oldaddr;
@@ -1058,8 +1058,8 @@ mmapobj_map_ptload(struct vnode *vp, caddr_t addr, size_t len, size_t zfodlen,
* maxprot is passed as PROT_ALL so that mdb can
* write to this segment.
*/
- if (error = VOP_MAP(vp, (offset_t)offset, as, &addr,
- len, prot, PROT_ALL, mflag, fcred, NULL)) {
+ if ((error = VOP_MAP(vp, (offset_t)offset, as, &addr,
+ len, prot, PROT_ALL, mflag, fcred, NULL)) != 0) {
return (error);
}
diff --git a/usr/src/uts/common/os/modctl.c b/usr/src/uts/common/os/modctl.c
index d8782b320e..f141fb4bf0 100644
--- a/usr/src/uts/common/os/modctl.c
+++ b/usr/src/uts/common/os/modctl.c
@@ -2694,7 +2694,7 @@ modrload(const char *subdir, const char *filename, struct modctl **rmodp)
CPU_STATS_ADDQ(CPU, sys, modload, 1);
}
-done: if (subdir != NULL)
+ if (subdir != NULL)
kmem_free(fullname, size);
return (rmodp ? retval : id);
}
diff --git a/usr/src/uts/common/os/modsubr.c b/usr/src/uts/common/os/modsubr.c
index e980516b10..53c4195e48 100644
--- a/usr/src/uts/common/os/modsubr.c
+++ b/usr/src/uts/common/os/modsubr.c
@@ -74,8 +74,7 @@ static void hwc_unhash(struct hwc_spec *);
int
major_valid(major_t major)
{
- return (major != DDI_MAJOR_T_NONE &&
- (major >= 0 && major < devcnt));
+ return (major != DDI_MAJOR_T_NONE && major < devcnt);
}
int
diff --git a/usr/src/uts/common/os/panic.c b/usr/src/uts/common/os/panic.c
index 62be47e843..addb8b79cb 100644
--- a/usr/src/uts/common/os/panic.c
+++ b/usr/src/uts/common/os/panic.c
@@ -213,7 +213,7 @@ panicsys(const char *format, va_list alist, struct regs *rp, int on_panic_stack)
cpu_t *cp = CPU;
caddr_t intr_stack = NULL;
- uint_t intr_actv;
+ volatile uint_t intr_actv;
ushort_t schedflag = t->t_schedflag;
cpu_t *bound_cpu = t->t_bound_cpu;
diff --git a/usr/src/uts/common/os/pool.c b/usr/src/uts/common/os/pool.c
index f9fe8649c0..57bd2241fd 100644
--- a/usr/src/uts/common/os/pool.c
+++ b/usr/src/uts/common/os/pool.c
@@ -1441,9 +1441,13 @@ pool_do_bind(pool_t *pool, idtype_t idtype, id_t id, int flags)
switch (idtype) {
case P_PID:
case P_TASKID:
+ default:
+
/*
- * Can't bind processes or tasks
- * in local zones to pools.
+ * Can't bind processes or tasks in local zones
+ * to pools. Also catch all remaining types of
+ * idtype_t that should already have been
+ * filtered out.
*/
mutex_exit(&p->p_lock);
mutex_exit(&pidlock);
@@ -1715,6 +1719,8 @@ out: switch (idtype) {
zone->zone_pool_mod = gethrtime();
zone_rele(zone);
break;
+ default:
+ break;
}
kmem_free(procs, procs_size * sizeof (proc_t *));
diff --git a/usr/src/uts/common/os/priv.c b/usr/src/uts/common/os/priv.c
index ccde6e5af5..388ccd8918 100644
--- a/usr/src/uts/common/os/priv.c
+++ b/usr/src/uts/common/os/priv.c
@@ -182,8 +182,7 @@ priv_pr_spriv(proc_t *p, prpriv_t *prpriv, const cred_t *cr)
if (prpriv->pr_nsets != PRIV_NSET ||
prpriv->pr_setsize != PRIV_SETSIZE ||
(prpriv->pr_infosize & (sizeof (uint32_t) - 1)) != 0 ||
- prpriv->pr_infosize > priv_info->priv_infosize ||
- prpriv->pr_infosize < 0)
+ prpriv->pr_infosize > priv_info->priv_infosize)
return (EINVAL);
mutex_exit(&p->p_lock);
diff --git a/usr/src/uts/common/os/rctl.c b/usr/src/uts/common/os/rctl.c
index f365bb4594..81a1b5454a 100644
--- a/usr/src/uts/common/os/rctl.c
+++ b/usr/src/uts/common/os/rctl.c
@@ -1567,8 +1567,6 @@ rctl_local_op(rctl_hndl_t hndl, rctl_val_t *oval, rctl_val_t *nval,
int ret = 0;
rctl_dict_entry_t *rde = rctl_dict_lookup_hndl(hndl);
-local_op_retry:
-
ASSERT(MUTEX_HELD(&p->p_lock));
rset = rctl_entity_obtain_rset(rde, p);
diff --git a/usr/src/uts/common/os/sunddi.c b/usr/src/uts/common/os/sunddi.c
index 4df2b7e55f..06ade6cc58 100644
--- a/usr/src/uts/common/os/sunddi.c
+++ b/usr/src/uts/common/os/sunddi.c
@@ -2813,7 +2813,7 @@ ddi_prop_int64_op(prop_handle_t *ph, uint_t cmd, int64_t *data)
*/
ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
sizeof (int64_t);
- return (DDI_PROP_RESULT_OK);
+ return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_ENCODE:
/*
@@ -2861,7 +2861,7 @@ ddi_prop_int64_op(prop_handle_t *ph, uint_t cmd, int64_t *data)
*/
ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
sizeof (int64_t);
- return (DDI_PROP_RESULT_OK);
+ return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_GET_ESIZE:
/*
@@ -9827,7 +9827,7 @@ e_ddi_branch_unconfigure(
/* The dip still exists, so do a hold */
e_ddi_branch_hold(rdip);
}
-out:
+
kmem_free(devnm, MAXNAMELEN + 1);
ndi_devi_exit(pdip, circ);
return (ndi2errno(rv));
diff --git a/usr/src/uts/common/os/sunmdi.c b/usr/src/uts/common/os/sunmdi.c
index 0cdfd30392..6d1e10e0a4 100644
--- a/usr/src/uts/common/os/sunmdi.c
+++ b/usr/src/uts/common/os/sunmdi.c
@@ -3597,6 +3597,16 @@ i_mdi_pi_state_change(mdi_pathinfo_t *pip, mdi_pathinfo_state_t state, int flag)
MDI_PI_LOCK(pip);
MDI_PI_SET_OFFLINING(pip);
break;
+
+ case MDI_PATHINFO_STATE_INIT:
+ /*
+ * Callers are not allowed to ask us to change the state to the
+ * initial state.
+ */
+ rv = MDI_FAILURE;
+ MDI_PI_UNLOCK(pip);
+ goto state_change_exit;
+
}
MDI_PI_UNLOCK(pip);
MDI_CLIENT_UNSTABLE(ct);
@@ -5722,6 +5732,7 @@ mdi_post_attach(dev_info_t *dip, ddi_attach_cmd_t cmd, int error)
break;
case DDI_RESUME:
+ case DDI_PM_RESUME:
MDI_DEBUG(2, (MDI_NOTE, dip,
"pHCI post_resume: called %p", (void *)ph));
if (error == DDI_SUCCESS) {
@@ -5769,6 +5780,7 @@ mdi_post_attach(dev_info_t *dip, ddi_attach_cmd_t cmd, int error)
break;
case DDI_RESUME:
+ case DDI_PM_RESUME:
MDI_DEBUG(2, (MDI_NOTE, dip,
"client post_attach: called %p", (void *)ct));
if (error == DDI_SUCCESS) {
@@ -6011,12 +6023,15 @@ i_mdi_phci_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error)
break;
case DDI_SUSPEND:
+ case DDI_PM_SUSPEND:
MDI_DEBUG(2, (MDI_NOTE, dip,
"pHCI post_suspend: called %p",
(void *)ph));
if (error != DDI_SUCCESS)
MDI_PHCI_SET_RESUME(ph);
break;
+ case DDI_HOTPLUG_DETACH:
+ break;
}
MDI_PHCI_UNLOCK(ph);
}
@@ -6054,11 +6069,14 @@ i_mdi_client_post_detach(dev_info_t *dip, ddi_detach_cmd_t cmd, int error)
break;
case DDI_SUSPEND:
+ case DDI_PM_SUSPEND:
MDI_DEBUG(2, (MDI_NOTE, dip,
"called %p", (void *)ct));
if (error != DDI_SUCCESS)
MDI_CLIENT_SET_RESUME(ct);
break;
+ case DDI_HOTPLUG_DETACH:
+ break;
}
MDI_CLIENT_UNLOCK(ct);
}
@@ -6820,6 +6838,10 @@ mdi_bus_power(dev_info_t *parent, void *impl_arg, pm_bus_power_op_t op,
i_mdi_pm_rele_client(ct, ct->ct_path_count);
}
break;
+ default:
+ dev_err(parent, CE_WARN, "!unhandled bus power operation: 0x%x",
+ op);
+ break;
}
MDI_CLIENT_UNLOCK(ct);
diff --git a/usr/src/uts/common/os/sunpm.c b/usr/src/uts/common/os/sunpm.c
index bb7d643c22..7518c45cea 100644
--- a/usr/src/uts/common/os/sunpm.c
+++ b/usr/src/uts/common/os/sunpm.c
@@ -1616,7 +1616,7 @@ power_dev(dev_info_t *dip, int comp, int level, int old_level,
(PM_CP(dip, comp)->pmc_flags &
PM_PHC_WHILE_SET_POWER));
- resume_needed = suspended;
+ resume_needed = suspended;
}
} else {
if (POWERING_OFF(old_level, level)) {
@@ -1629,7 +1629,7 @@ power_dev(dev_info_t *dip, int comp, int level, int old_level,
(PM_CP(dip, comp)->pmc_flags &
PM_PHC_WHILE_SET_POWER));
- resume_needed = suspended;
+ resume_needed = suspended;
}
}
}
@@ -2076,13 +2076,12 @@ e_pm_hold_rele_power(dev_info_t *dip, int cnt)
return;
PM_LOCK_POWER(dip, &circ);
- ASSERT(cnt >= 0 && PM_KUC(dip) >= 0 || cnt < 0 && PM_KUC(dip) > 0);
+ ASSERT(cnt >= 0 || (cnt < 0 && PM_KUC(dip) > 0));
PMD(PMD_KIDSUP, ("%s: kidsupcnt for %s@%s(%s#%d) %d->%d\n", pmf,
PM_DEVICE(dip), PM_KUC(dip), (PM_KUC(dip) + cnt)))
PM_KUC(dip) += cnt;
- ASSERT(PM_KUC(dip) >= 0);
PM_UNLOCK_POWER(dip, circ);
if (cnt < 0 && PM_KUC(dip) == 0)
diff --git a/usr/src/uts/common/os/vm_pageout.c b/usr/src/uts/common/os/vm_pageout.c
index 9b740c16ef..c3fd3658d6 100644
--- a/usr/src/uts/common/os/vm_pageout.c
+++ b/usr/src/uts/common/os/vm_pageout.c
@@ -133,7 +133,7 @@
* v allocations (e.g., KM_SLEEP) are held here while we wait for
* | more memory. Non-sleeping allocations are generally allowed to
* | proceed, unless their priority is explicitly lowered with
- * | KM_NORMALPRI.
+ * | KM_NORMALPRI (Note: KM_NOSLEEP_LAZY == (KM_NOSLEEP | KM_NORMALPRI).).
* |
* +------- pageout_reserve (3/4 of throttlefree, 0.44% of physmem, min. 4MB)
* |
diff --git a/usr/src/uts/common/os/watchpoint.c b/usr/src/uts/common/os/watchpoint.c
index eee612ef93..24db9637d4 100644
--- a/usr/src/uts/common/os/watchpoint.c
+++ b/usr/src/uts/common/os/watchpoint.c
@@ -821,7 +821,6 @@ watch_xcopyin(const void *uaddr, void *kaddr, size_t count)
count -= part;
}
-error:
/* if we hit a watched address, do the watchpoint logic */
if (watchcode &&
(!sys_watchpoint(vaddr, watchcode, ta) ||
diff --git a/usr/src/uts/common/pcmcia/cs/cs_stubs.c b/usr/src/uts/common/pcmcia/cs/cs_stubs.c
index 9bf02d2a2e..593898577d 100644
--- a/usr/src/uts/common/pcmcia/cs/cs_stubs.c
+++ b/usr/src/uts/common/pcmcia/cs/cs_stubs.c
@@ -131,9 +131,9 @@ csx_register_cardservices(cs_register_cardservices_t *rcs)
{
#ifdef CS_STUBS_DEBUG
if (cs_stubs_debug > 2)
- cmn_err(CE_CONT, "csx_register_cardservices: "
- "magic: 0x%x function: 0x%x cardservices: 0x%p\n",
- rcs->magic, rcs->function, (void *)rcs->cardservices);
+ cmn_err(CE_CONT, "csx_register_cardservices: "
+ "magic: 0x%x function: 0x%x cardservices: 0x%p\n",
+ rcs->magic, rcs->function, (void *)rcs->cardservices);
#endif
if (rcs->magic != CS_STUBS_MAGIC)
@@ -144,8 +144,9 @@ csx_register_cardservices(cs_register_cardservices_t *rcs)
cardservices = rcs->cardservices;
do_cs_call = 1;
#ifdef CS_STUBS_DEBUG
- if (cs_stubs_debug > 2)
- cmn_err(CE_CONT, "csx_register_cardservices: CS_ENTRY_REGISTER\n");
+ if (cs_stubs_debug > 2)
+ cmn_err(CE_CONT, "csx_register_cardservices: "
+ "CS_ENTRY_REGISTER\n");
#endif
return (CS_SUCCESS);
@@ -154,17 +155,18 @@ csx_register_cardservices(cs_register_cardservices_t *rcs)
do_cs_call = 0;
cardservices = cs_no_carservices;
#ifdef CS_STUBS_DEBUG
- if (cs_stubs_debug > 2)
- cmn_err(CE_CONT,
- "csx_register_cardservices: CS_ENTRY_DEREGISTER\n");
+ if (cs_stubs_debug > 2)
+ cmn_err(CE_CONT, "csx_register_cardservices: "
+ "CS_ENTRY_DEREGISTER\n");
#endif
return (CS_UNSUPPORTED_FUNCTION);
case CS_ENTRY_INQUIRE:
rcs->cardservices = cardservices;
#ifdef CS_STUBS_DEBUG
- if (cs_stubs_debug > 2)
- cmn_err(CE_CONT, "csx_register_cardservices: CS_ENTRY_INQUIRE\n");
+ if (cs_stubs_debug > 2)
+ cmn_err(CE_CONT, "csx_register_cardservices: "
+ "CS_ENTRY_INQUIRE\n");
#endif
if (do_cs_call)
@@ -174,8 +176,9 @@ csx_register_cardservices(cs_register_cardservices_t *rcs)
default:
#ifdef CS_STUBS_DEBUG
- if (cs_stubs_debug > 2)
- cmn_err(CE_CONT, "csx_register_cardservices: (unknown function)\n");
+ if (cs_stubs_debug > 2)
+ cmn_err(CE_CONT, "csx_register_cardservices: "
+ "(unknown function)\n");
#endif
return (CS_UNSUPPORTED_FUNCTION);
}
diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile
index 71fe53313c..ed4fcbef5a 100644
--- a/usr/src/uts/common/sys/Makefile
+++ b/usr/src/uts/common/sys/Makefile
@@ -436,6 +436,9 @@ CHKHDRS= \
ontrap.h \
open.h \
openpromio.h \
+ overlay.h \
+ overlay_common.h \
+ overlay_target.h \
panic.h \
param.h \
pathconf.h \
@@ -1125,6 +1128,9 @@ NXGEHDRS= \
nxge_virtual.h \
nxge_espc.h
+PLATHDRS= \
+ pci_prd.h
+
include Makefile.syshdrs
dcam/%.check: dcam/%.h
@@ -1192,7 +1198,8 @@ CHECKHDRS= \
$(I1394HDRS:%.h=1394/%.check) \
$(RSMHDRS:%.h=rsm/%.check) \
$(TSOLHDRS:%.h=tsol/%.check) \
- $(NXGEHDRS:%.h=nxge/%.check)
+ $(NXGEHDRS:%.h=nxge/%.check) \
+ $(PLATHDRS:%.h=plat/%.check)
.KEEP_STATE:
@@ -1232,6 +1239,7 @@ CHECKHDRS= \
$(ROOTTAVORHDRS) \
$(ROOTHERMONHDRS) \
$(ROOTMLNXHDRS) \
+ $(ROOTPLATHDRS) \
$(ROOTSCSIHDRS) \
$(ROOTSCSIADHDRS) \
$(ROOTSCSICONFHDRS) \
@@ -1300,6 +1308,7 @@ install_h: \
$(ROOTTAVORHDRS) \
$(ROOTHERMONHDRS) \
$(ROOTMLNXHDRS) \
+ $(ROOTPLATHDRS) \
$(ROOTSCSIHDRS) \
$(ROOTSCSIADHDRS) \
$(ROOTSCSIISCSIHDRS) \
diff --git a/usr/src/uts/common/sys/dld_ioc.h b/usr/src/uts/common/sys/dld_ioc.h
index 2f519a8eda..093a4dc0c3 100644
--- a/usr/src/uts/common/sys/dld_ioc.h
+++ b/usr/src/uts/common/sys/dld_ioc.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Joyent, Inc.
*/
#ifndef _SYS_DLD_IOC_H
@@ -59,6 +60,7 @@ extern "C" {
#define IPTUN_IOC 0x454A
#define BRIDGE_IOC 0xB81D
#define IBPART_IOC 0x6171
+#define OVERLAY_IOC 0x2005
/* GLDv3 modules use these macros to generate unique ioctl commands */
#define DLDIOC(cmdid) DLD_IOC_CMD(DLD_IOC, (cmdid))
@@ -68,6 +70,7 @@ extern "C" {
#define IPTUNIOC(cmdid) DLD_IOC_CMD(IPTUN_IOC, (cmdid))
#define BRIDGEIOC(cmdid) DLD_IOC_CMD(BRIDGE_IOC, (cmdid))
#define IBPARTIOC(cmdid) DLD_IOC_CMD(IBPART_IOC, (cmdid))
+#define OVERLAYIOC(cmdid) DLD_IOC_CMD(OVERLAY_IOC, (cmdid))
#ifdef _KERNEL
diff --git a/usr/src/uts/common/sys/dls_mgmt.h b/usr/src/uts/common/sys/dls_mgmt.h
index e2893a2295..b60e53b267 100644
--- a/usr/src/uts/common/sys/dls_mgmt.h
+++ b/usr/src/uts/common/sys/dls_mgmt.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent, Inc.
*/
#ifndef _DLS_MGMT_H
@@ -46,13 +47,15 @@ typedef enum {
DATALINK_CLASS_SIMNET = 0x20,
DATALINK_CLASS_BRIDGE = 0x40,
DATALINK_CLASS_IPTUN = 0x80,
- DATALINK_CLASS_PART = 0x100
+ DATALINK_CLASS_PART = 0x100,
+ DATALINK_CLASS_OVERLAY = 0x200
} datalink_class_t;
#define DATALINK_CLASS_ALL (DATALINK_CLASS_PHYS | \
DATALINK_CLASS_VLAN | DATALINK_CLASS_AGGR | DATALINK_CLASS_VNIC | \
DATALINK_CLASS_ETHERSTUB | DATALINK_CLASS_SIMNET | \
- DATALINK_CLASS_BRIDGE | DATALINK_CLASS_IPTUN | DATALINK_CLASS_PART)
+ DATALINK_CLASS_BRIDGE | DATALINK_CLASS_IPTUN | DATALINK_CLASS_PART | \
+ DATALINK_CLASS_OVERLAY)
/*
* A combination of flags and media.
diff --git a/usr/src/uts/common/sys/kmem.h b/usr/src/uts/common/sys/kmem.h
index aac2eafa3c..bfc301a521 100644
--- a/usr/src/uts/common/sys/kmem.h
+++ b/usr/src/uts/common/sys/kmem.h
@@ -23,7 +23,7 @@
* Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
- * Copyright 2018, Joyent, Inc.
+ * Copyright 2022 Joyent, Inc.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -49,6 +49,7 @@ extern "C" {
#define KM_PANIC 0x0002 /* if memory cannot be allocated, panic */
#define KM_PUSHPAGE 0x0004 /* can block for memory; may use reserve */
#define KM_NORMALPRI 0x0008 /* with KM_NOSLEEP, lower priority allocation */
+#define KM_NOSLEEP_LAZY (KM_NOSLEEP | KM_NORMALPRI) /* Syntactic sugar. */
#define KM_VMFLAGS 0x00ff /* flags that must match VM_* flags */
#define KM_FLAGS 0xffff /* all settable kmem flags */
diff --git a/usr/src/uts/common/sys/mac_client_priv.h b/usr/src/uts/common/sys/mac_client_priv.h
index 965dca263c..01cb27644c 100644
--- a/usr/src/uts/common/sys/mac_client_priv.h
+++ b/usr/src/uts/common/sys/mac_client_priv.h
@@ -188,6 +188,7 @@ extern void mac_client_set_intr_cpu(void *, mac_client_handle_t, int32_t);
extern void *mac_get_devinfo(mac_handle_t);
extern boolean_t mac_is_vnic(mac_handle_t);
+extern boolean_t mac_is_overlay(mac_handle_t);
extern uint32_t mac_no_notification(mac_handle_t);
extern int mac_set_prop(mac_handle_t, mac_prop_id_t, char *, void *, uint_t);
diff --git a/usr/src/uts/common/sys/mac_impl.h b/usr/src/uts/common/sys/mac_impl.h
index da645ad382..21f2c10a8e 100644
--- a/usr/src/uts/common/sys/mac_impl.h
+++ b/usr/src/uts/common/sys/mac_impl.h
@@ -609,6 +609,7 @@ struct mac_impl_s {
#define MIS_LEGACY 0x0040
#define MIS_NO_ACTIVE 0x0080
#define MIS_POLL_DISABLE 0x0100
+#define MIS_IS_OVERLAY 0x0200
#define mi_getstat mi_callbacks->mc_getstat
#define mi_start mi_callbacks->mc_start
diff --git a/usr/src/uts/common/sys/mac_provider.h b/usr/src/uts/common/sys/mac_provider.h
index 2cb326814a..431de67ff5 100644
--- a/usr/src/uts/common/sys/mac_provider.h
+++ b/usr/src/uts/common/sys/mac_provider.h
@@ -109,7 +109,8 @@ typedef enum {
MAC_CAPAB_NO_ZCOPY = 0x00100000, /* boolean only, no data */
MAC_CAPAB_LEGACY = 0x00200000, /* data is mac_capab_legacy_t */
MAC_CAPAB_VRRP = 0x00400000, /* data is mac_capab_vrrp_t */
- MAC_CAPAB_TRANSCEIVER = 0x01000000, /* mac_capab_transciever_t */
+ MAC_CAPAB_OVERLAY = 0x00800000, /* boolean only, no data */
+ MAC_CAPAB_TRANSCEIVER = 0x01000000, /* mac_capab_transceiver_t */
MAC_CAPAB_LED = 0x02000000 /* data is mac_capab_led_t */
} mac_capab_t;
diff --git a/usr/src/uts/common/sys/nvme.h b/usr/src/uts/common/sys/nvme.h
index 787d5d4016..529f24dee0 100644
--- a/usr/src/uts/common/sys/nvme.h
+++ b/usr/src/uts/common/sys/nvme.h
@@ -14,6 +14,7 @@
* Copyright 2020 Joyent, Inc.
* Copyright 2019 Western Digital Corporation
* Copyright 2021 Oxide Computer Company
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
*/
#ifndef _SYS_NVME_H
@@ -557,6 +558,7 @@ typedef struct {
#define NVME_LOGPAGE_ERROR 0x1 /* Error Information */
#define NVME_LOGPAGE_HEALTH 0x2 /* SMART/Health Information */
#define NVME_LOGPAGE_FWSLOT 0x3 /* Firmware Slot Information */
+#define NVME_LOGPAGE_NSCHANGE 0x4 /* Changed namespace (1.2) */
typedef struct {
uint64_t el_count; /* Error Count */
@@ -634,6 +636,18 @@ typedef struct {
uint8_t fw_rsvd4[512 - 64];
} nvme_fwslot_log_t;
+/*
+ * The NVMe spec specifies that the changed namespace list contains up to
+ * 1024 entries.
+ */
+#define NVME_NSCHANGE_LIST_SIZE 1024
+
+typedef struct {
+ uint32_t nscl_ns[NVME_NSCHANGE_LIST_SIZE];
+} __packed nvme_nschange_list_t;
+
+/* CSTYLED */
+_Static_assert(sizeof (nvme_nschange_list_t) == 4096, "bad size for nvme_nschange_list_t");
/*
* NVMe Format NVM
@@ -798,13 +812,21 @@ typedef union {
/* Asynchronous Event Configuration Feature */
typedef union {
struct {
- uint8_t aec_avail:1; /* available space too low */
- uint8_t aec_temp:1; /* temperature too high */
- uint8_t aec_reliab:1; /* degraded reliability */
- uint8_t aec_readonly:1; /* media is read-only */
- uint8_t aec_volatile:1; /* volatile memory backup failed */
+ uint8_t aec_avail:1; /* Available space too low */
+ uint8_t aec_temp:1; /* Temperature too high */
+ uint8_t aec_reliab:1; /* Degraded reliability */
+ uint8_t aec_readonly:1; /* Media is read-only */
+ uint8_t aec_volatile:1; /* Volatile memory backup failed */
uint8_t aec_rsvd1:3;
- uint8_t aec_rsvd2[3];
+ uint8_t aec_nsan:1; /* Namespace attribute notices (1.2) */
+ uint8_t aec_fwact:1; /* Firmware activation notices (1.2) */
+ uint8_t aec_telln:1; /* Telemetry log notices (1.3) */
+ uint8_t aec_ansacn:1; /* Asymm. NS access change (1.4) */
+ uint8_t aec_plat:1; /* Predictable latency ev. agg. (1.4) */
+ uint8_t aec_lbasi:1; /* LBA status information (1.4) */
+ uint8_t aec_egeal:1; /* Endurance group ev. agg. (1.4) */
+ uint8_t aec_rsvd2:1;
+ uint8_t aec_rsvd3[2];
} b;
uint32_t r;
} nvme_async_event_conf_t;
diff --git a/usr/src/uts/common/sys/overlay.h b/usr/src/uts/common/sys/overlay.h
new file mode 100644
index 0000000000..12d0dbca51
--- /dev/null
+++ b/usr/src/uts/common/sys/overlay.h
@@ -0,0 +1,96 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015, Joyent, Inc.
+ */
+
+#ifndef _SYS_OVERLAY_H
+#define _SYS_OVERLAY_H
+
+/*
+ * Overlay device support
+ */
+
+#include <sys/param.h>
+#include <sys/dld_ioc.h>
+#include <sys/mac.h>
+#include <sys/overlay_common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OVERLAY_IOC_CREATE OVERLAYIOC(1)
+#define OVERLAY_IOC_DELETE OVERLAYIOC(2)
+#define OVERLAY_IOC_PROPINFO OVERLAYIOC(3)
+#define OVERLAY_IOC_GETPROP OVERLAYIOC(4)
+#define OVERLAY_IOC_SETPROP OVERLAYIOC(5)
+#define OVERLAY_IOC_NPROPS OVERLAYIOC(6)
+#define OVERLAY_IOC_ACTIVATE OVERLAYIOC(7)
+#define OVERLAY_IOC_STATUS OVERLAYIOC(8)
+
+typedef struct overlay_ioc_create {
+ datalink_id_t oic_linkid;
+ uint32_t oic_filler;
+ uint64_t oic_vnetid;
+ char oic_encap[MAXLINKNAMELEN];
+} overlay_ioc_create_t;
+
+typedef struct overlay_ioc_activate {
+ datalink_id_t oia_linkid;
+} overlay_ioc_activate_t;
+
+typedef struct overlay_ioc_delete {
+ datalink_id_t oid_linkid;
+} overlay_ioc_delete_t;
+
+typedef struct overlay_ioc_nprops {
+ datalink_id_t oipn_linkid;
+ int32_t oipn_nprops;
+} overlay_ioc_nprops_t;
+
+typedef struct overlay_ioc_propinfo {
+ datalink_id_t oipi_linkid;
+ int32_t oipi_id;
+ char oipi_name[OVERLAY_PROP_NAMELEN];
+ uint_t oipi_type;
+ uint_t oipi_prot;
+ uint8_t oipi_default[OVERLAY_PROP_SIZEMAX];
+ uint32_t oipi_defsize;
+ uint32_t oipi_posssize;
+ uint8_t oipi_poss[OVERLAY_PROP_SIZEMAX];
+} overlay_ioc_propinfo_t;
+
+typedef struct overlay_ioc_prop {
+ datalink_id_t oip_linkid;
+ int32_t oip_id;
+ char oip_name[OVERLAY_PROP_NAMELEN];
+ uint8_t oip_value[OVERLAY_PROP_SIZEMAX];
+ uint32_t oip_size;
+} overlay_ioc_prop_t;
+
+typedef enum overlay_status {
+ OVERLAY_I_OK = 0x00,
+ OVERLAY_I_DEGRADED = 0x01
+} overlay_status_t;
+
+typedef struct overlay_ioc_status {
+ datalink_id_t ois_linkid;
+ uint_t ois_status;
+ char ois_message[OVERLAY_STATUS_BUFLEN];
+} overlay_ioc_status_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_OVERLAY_H */
diff --git a/usr/src/uts/common/sys/overlay_common.h b/usr/src/uts/common/sys/overlay_common.h
new file mode 100644
index 0000000000..5c4b651f2c
--- /dev/null
+++ b/usr/src/uts/common/sys/overlay_common.h
@@ -0,0 +1,65 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _SYS_OVERLAY_COMMON_H
+#define _SYS_OVERLAY_COMMON_H
+
+/*
+ * Common overlay definitions
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum overlay_target_mode {
+ OVERLAY_TARGET_NONE = 0x0,
+ OVERLAY_TARGET_POINT,
+ OVERLAY_TARGET_DYNAMIC
+} overlay_target_mode_t;
+
+typedef enum overlay_plugin_dest {
+ OVERLAY_PLUGIN_D_INVALID = 0x0,
+ OVERLAY_PLUGIN_D_ETHERNET = 0x1,
+ OVERLAY_PLUGIN_D_IP = 0x2,
+ OVERLAY_PLUGIN_D_PORT = 0x4,
+ OVERLAY_PLUGIN_D_MASK = 0x7
+} overlay_plugin_dest_t;
+
+typedef enum overlay_prop_type {
+ OVERLAY_PROP_T_INT = 0x1, /* signed int */
+ OVERLAY_PROP_T_UINT, /* unsigned int */
+ OVERLAY_PROP_T_IP, /* sinaddr6 */
+ OVERLAY_PROP_T_STRING /* OVERLAY_PROPS_SIZEMAX */
+} overlay_prop_type_t;
+
+typedef enum overlay_prop_prot {
+ OVERLAY_PROP_PERM_REQ = 0x1,
+ OVERLAY_PROP_PERM_READ = 0x2,
+ OVERLAY_PROP_PERM_WRITE = 0x4,
+ OVERLAY_PROP_PERM_RW = 0x6,
+ OVERLAY_PROP_PERM_RRW = 0x7,
+ OVERLAY_PROP_PERM_MASK = 0x7
+} overlay_prop_prot_t;
+
+#define OVERLAY_PROP_NAMELEN 64
+#define OVERLAY_PROP_SIZEMAX 256
+#define OVERLAY_STATUS_BUFLEN 256
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_OVERLAY_COMMON_H */
diff --git a/usr/src/uts/common/sys/overlay_impl.h b/usr/src/uts/common/sys/overlay_impl.h
new file mode 100644
index 0000000000..0095c75eeb
--- /dev/null
+++ b/usr/src/uts/common/sys/overlay_impl.h
@@ -0,0 +1,205 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#ifndef _SYS_OVERLAY_IMPL_H
+#define _SYS_OVERLAY_IMPL_H
+
+/*
+ * Overlay device support
+ */
+
+#include <sys/overlay.h>
+#include <sys/overlay_common.h>
+#include <sys/overlay_plugin.h>
+#include <sys/overlay_target.h>
+#include <sys/ksynch.h>
+#include <sys/list.h>
+#include <sys/avl.h>
+#include <sys/ksocket.h>
+#include <sys/socket.h>
+#include <sys/refhash.h>
+#include <sys/ethernet.h>
+#include <sys/list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OVEP_VERSION_ONE 0x1
+
+typedef struct overlay_plugin {
+ kmutex_t ovp_mutex;
+ list_node_t ovp_link; /* overlay_plugin_lock */
+ uint_t ovp_active; /* ovp_mutex */
+ const char *ovp_name; /* RO */
+ const overlay_plugin_ops_t *ovp_ops; /* RO */
+ const char *const *ovp_props; /* RO */
+ uint_t ovp_nprops; /* RO */
+ uint_t ovp_id_size; /* RO */
+ overlay_plugin_flags_t ovp_flags; /* RO */
+ overlay_plugin_dest_t ovp_dest; /* RO */
+} overlay_plugin_t;
+
+typedef struct overlay_mux {
+ list_node_t omux_lnode;
+ ksocket_t omux_ksock; /* RO */
+ overlay_plugin_t *omux_plugin; /* RO: associated encap */
+ int omux_domain; /* RO: socket domain */
+ int omux_family; /* RO: socket family */
+ int omux_protocol; /* RO: socket protocol */
+ struct sockaddr *omux_addr; /* RO: socket address */
+ socklen_t omux_alen; /* RO: sockaddr len */
+ kmutex_t omux_lock; /* Protects everything below */
+ uint_t omux_count; /* Active instances */
+ avl_tree_t omux_devices; /* Tree of devices */
+} overlay_mux_t;
+
+typedef enum overlay_target_flag {
+ OVERLAY_T_TEARDOWN = 0x1
+} overlay_target_flag_t;
+
+typedef struct overlay_target {
+ kmutex_t ott_lock;
+ kcondvar_t ott_cond;
+ overlay_target_mode_t ott_mode; /* RO */
+ overlay_plugin_dest_t ott_dest; /* RO */
+ uint64_t ott_id; /* RO */
+ overlay_target_flag_t ott_flags; /* ott_lock */
+ uint_t ott_ocount; /* ott_lock */
+ union { /* ott_lock */
+ overlay_target_point_t ott_point;
+ struct overlay_target_dyn {
+ refhash_t *ott_dhash;
+ avl_tree_t ott_tree;
+ } ott_dyn;
+ } ott_u;
+} overlay_target_t;
+
+typedef enum overlay_dev_flag {
+ OVERLAY_F_ACTIVATED = 0x01, /* Activate ioctl completed */
+ OVERLAY_F_IN_MUX = 0x02, /* Currently in a mux */
+ OVERLAY_F_IN_TX = 0x04, /* Currently doing tx */
+ OVERLAY_F_IN_RX = 0x08, /* Currently doing rx */
+ OVERLAY_F_IOMASK = 0x0c, /* A mask for rx and tx */
+ OVERLAY_F_MDDROP = 0x10, /* Drop traffic for metadata update */
+ OVERLAY_F_STOPMASK = 0x1e, /* None set when stopping */
+ OVERLAY_F_VARPD = 0x20, /* varpd plugin exists */
+ OVERLAY_F_DEGRADED = 0x40, /* device is degraded */
+ OVERLAY_F_MASK = 0x7f /* mask of everything */
+} overlay_dev_flag_t;
+
+typedef struct overlay_dev {
+ kmutex_t odd_lock;
+ kcondvar_t odd_iowait;
+ list_node_t odd_link; /* overlay_dev_lock */
+ mac_handle_t odd_mh; /* RO */
+ overlay_plugin_t *odd_plugin; /* RO */
+ datalink_id_t odd_linkid; /* RO */
+ void *odd_pvoid; /* RO -- only used by plugin */
+ uint_t odd_ref; /* protected by odd_lock */
+ uint_t odd_mtu; /* protected by odd_lock */
+ overlay_dev_flag_t odd_flags; /* protected by odd_lock */
+ uint_t odd_rxcount; /* protected by odd_lock */
+ uint_t odd_txcount; /* protected by odd_lock */
+ overlay_mux_t *odd_mux; /* protected by odd_lock */
+ uint64_t odd_vid; /* RO if active else odd_lock */
+ avl_node_t odd_muxnode; /* managed by mux */
+ overlay_target_t *odd_target; /* See big theory statement */
+ char odd_fmamsg[OVERLAY_STATUS_BUFLEN]; /* odd_lock */
+} overlay_dev_t;
+
+typedef enum overlay_target_entry_flags {
+ OVERLAY_ENTRY_F_PENDING = 0x01, /* lookup in progress */
+ OVERLAY_ENTRY_F_VALID = 0x02, /* entry is currently valid */
+ OVERLAY_ENTRY_F_DROP = 0x04, /* always drop target */
+ OVERLAY_ENTRY_F_VALID_MASK = 0x06
+} overlay_target_entry_flags_t;
+
+typedef struct overlay_target_entry {
+ kmutex_t ote_lock;
+ refhash_link_t ote_reflink; /* hashtable link */
+ avl_node_t ote_avllink; /* iteration link */
+ list_node_t ote_qlink;
+ overlay_target_entry_flags_t ote_flags; /* RW: state flags */
+ uint8_t ote_addr[ETHERADDRL]; /* RO: mac addr */
+ overlay_target_t *ote_ott; /* RO */
+ overlay_dev_t *ote_odd; /* RO */
+ overlay_target_point_t ote_dest; /* RW: destination */
+ mblk_t *ote_chead; /* RW: blocked mb chain head */
+ mblk_t *ote_ctail; /* RW: blocked mb chain tail */
+ size_t ote_mbsize; /* RW: outstanding mblk size */
+ hrtime_t ote_vtime; /* RW: valid timestamp */
+} overlay_target_entry_t;
+
+
+#define OVERLAY_CTL "overlay"
+
+extern dev_info_t *overlay_dip;
+
+extern mblk_t *overlay_m_tx(void *, mblk_t *);
+
+typedef int (*overlay_dev_iter_f)(overlay_dev_t *, void *);
+extern void overlay_dev_iter(overlay_dev_iter_f, void *);
+
+extern void overlay_plugin_init(void);
+extern overlay_plugin_t *overlay_plugin_lookup(const char *);
+extern void overlay_plugin_rele(overlay_plugin_t *);
+extern void overlay_plugin_fini(void);
+typedef int (*overlay_plugin_walk_f)(overlay_plugin_t *, void *);
+extern void overlay_plugin_walk(overlay_plugin_walk_f, void *);
+
+extern void overlay_io_start(overlay_dev_t *, overlay_dev_flag_t);
+extern void overlay_io_done(overlay_dev_t *, overlay_dev_flag_t);
+
+extern void overlay_mux_init(void);
+extern void overlay_mux_fini(void);
+
+extern overlay_mux_t *overlay_mux_open(overlay_plugin_t *, int, int, int,
+ struct sockaddr *, socklen_t, int *);
+extern void overlay_mux_close(overlay_mux_t *);
+extern void overlay_mux_add_dev(overlay_mux_t *, overlay_dev_t *);
+extern void overlay_mux_remove_dev(overlay_mux_t *, overlay_dev_t *);
+extern int overlay_mux_tx(overlay_mux_t *, struct msghdr *, mblk_t *);
+
+extern void overlay_prop_init(overlay_prop_handle_t);
+
+extern void overlay_target_init(void);
+extern int overlay_target_busy(void);
+extern int overlay_target_open(dev_t *, int, int, cred_t *);
+extern int overlay_target_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+extern int overlay_target_close(dev_t, int, int, cred_t *);
+extern void overlay_target_free(overlay_dev_t *);
+
+#define OVERLAY_TARGET_OK 0
+#define OVERLAY_TARGET_DROP 1
+#define OVERLAY_TARGET_ASYNC 2
+extern int overlay_target_lookup(overlay_dev_t *, mblk_t *, struct sockaddr *,
+ socklen_t *);
+extern void overlay_target_quiesce(overlay_target_t *);
+extern void overlay_target_fini(void);
+
+extern void overlay_fm_init(void);
+extern void overlay_fm_fini(void);
+extern void overlay_fm_degrade(overlay_dev_t *, const char *);
+extern void overlay_fm_restore(overlay_dev_t *);
+
+extern overlay_dev_t *overlay_hold_by_dlid(datalink_id_t);
+extern void overlay_hold_rele(overlay_dev_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_OVERLAY_IMPL_H */
diff --git a/usr/src/uts/common/sys/overlay_plugin.h b/usr/src/uts/common/sys/overlay_plugin.h
new file mode 100644
index 0000000000..3392973562
--- /dev/null
+++ b/usr/src/uts/common/sys/overlay_plugin.h
@@ -0,0 +1,324 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2015 Joyent, Inc.
+ */
+
+#ifndef _SYS_OVERLAY_PLUGIN_H
+#define _SYS_OVERLAY_PLUGIN_H
+
+/*
+ * overlay plugin interface for encapsulation/decapsulation modules
+ *
+ * This header file defines how encapsulation and decapsulation plugins
+ * interact within the broader system. At this time, these interfaces are
+ * considered private to illumos and therefore are subject to change. As we gain
+ * more experience with a few of the different encapsulation formats, say nvgre
+ * or geneve, then we can move to make this a more-stable interface.
+ *
+ * A plugin is a general kernel module that uses the miscellaneous mod-linkage.
+ *
+ * In it's _init(9E) routine, it must register itself with the overlay
+ * subsystem. To do this, it allocates an overlay_plugin_register_t via
+ * overlay_plugin_alloc(), that it then * fills out with various required
+ * information and then attempts to register with the system via a call to
+ * overlay_plugin_register(). If that succeeds, it should then call
+ * mod_install(9F). If the mod_install(9F) fails, then it should call
+ * overlay_plugin_unregister(). Regardless of success or failure, it should call
+ * overlay_plugin_free() to ensure that any memory that may be associated with
+ * the registration is freed.
+ *
+ * When the module's _fini(9E) is called, overlay_plugin_unregister() should be
+ * called first. It may return an error, such as EBUSY. In such cases, it should
+ * be returned as the return status of _fini(9E). This is quite necessary, it
+ * ensures that if the module is in use it doesn't get unloaded out from under
+ * us the broader subsystem while it's still in use. A driver can use that to
+ * know that there are no current instances of its private data.
+ *
+ * ------------------
+ * Plugin Definitions
+ * ------------------
+ *
+ * A plugin is required to fill in both an operations vector and a series of
+ * information to the callback routine. Here are the routines and their
+ * purposes. The full signatures are available below.
+ *
+ * overlay_plugin_init_t
+ *
+ * This interface is used to create a new instance of a plugin. An instance
+ * of a plugin will be created for each overlay device that is created. For
+ * example, if a device is created with VXLAN ID 23 and ID 42, then there
+ * will be two different calls to this function.
+ *
+ * This function gives the plugin a chance to create a private data
+ * structure that will be returned on subsequent calls to the system.
+ *
+ * overlay_plugin_fini_t
+ *
+ * This is the opposite of overlay_plugin_init_t. It will be called when it
+ * is safe to remove any private data that is associated with this instance
+ * of the plugin.
+ *
+ * overlay_plugin_propinfo_t
+ *
+ * This is called with the name of a property that is registered when the
+ * plugin is created. This function will be called with the name of the
+ * property that information is being requested about. The plugin is
+ * responsible for filling out information such as setting the name, the
+ * type of property it is, the protection of the property (can a user
+ * update it?), whether the property is required, an optional default value
+ * for the property, and an optional set of values or ranges that are
+ * allowed.
+ *
+ * overlay_plugin_getprop_t
+ *
+ * Return the value of the named property from the current instance of the
+ * plugin.
+ *
+ * overlay_plugin_setprop_t
+ *
+ * Set the value of the named property to the specified value for the
+ * current instance of the plugin. Note, that it is the plugin's
+ * responsibility to ensure that the value of the property is valid and to
+ * update state as appropriate.
+ *
+ * overlay_plugin_socket_t
+ *
+ * Every overlay device has a corresponding socket that it uses to send and
+ * receive traffic. This routine is used to get the parameters that should
+ * be used to define such a socket. The actual socket may be multiplexed
+ * with other uses of it.
+ *
+ * overlay_plugin_sockopt_t
+ *
+ * Allow a plugin to set any necessary socket options that it needs on the
+ * kernel socket that is being used by a mux. This will only be called once
+ * for a given mux, if additional devices are added to a mux, it will not
+ * be called additional times.
+ *
+ * overlay_plugin_encap_t
+ *
+ * In this routine you're given a message block and information about the
+ * packet, such as the identifier and are asked to fill out a message block
+ * that represents the encapsulation header and optionally manipulate the
+ * input message if required.
+ *
+ * overlay_plugin_decap_t
+ *
+ * In this routine, you're given the encapsulated message block. The
+ * requirement is to decapsulate it and determine what is the correct
+ * overlay identifier for this network and to fill in the header size so
+ * the broader system knows how much of this data should be considered
+ * consumed.
+ *
+ * ovpo_callbacks
+ *
+ * This should be set to zero, it's reserved for future use.
+ *
+ * Once these properties are defined, the module should define the following
+ * members in the overlay_plugin_register_t.
+ *
+ * ovep_version
+ *
+ * Should be set to the value of the macro OVEP_VERSION.
+ *
+ * ovep_name
+ *
+ * Should be set to a character string that has the name of the module.
+ * Generally this should match the name of the kernel module; however, this
+ * is the name that users will use to refer to this module when creating
+ * devices.
+ *
+ * overlay_plugin_ops_t
+ *
+ * Should be set to the functions as described above.
+ *
+ * ovep_props
+ *
+ * This is an array of character strings that holds the names of the
+ * properties of the encapsulation plugin.
+ *
+ *
+ * ovep_id_size
+ *
+ * This is the size in bytes of the valid range for the identifier. The
+ * valid identifier range is considered a ovep_id_size byte unsigned
+ * integer, [ 0, 1 << (ovep_id_size * 8) ).
+ *
+ * ovep_flags
+ *
+ * A series of flags that indicate optional features that are supported.
+ * Valid flags include:
+ *
+ * OVEP_F_VLAN_TAG
+ *
+ * The encapsulation format allows for the encapsulated
+ * packet to maintain a VLAN tag.
+ *
+ * ovep_dest
+ *
+ * Describes the kind of destination that the overlay plugin supports for
+ * sending traffic. For example, vxlan uses UDP, therefore it requires both
+ * an IP address and a port; however, nvgre uses the gre header and
+ * therefore only requires an IP address. The following flags may be
+ * combined:
+ *
+ * OVERLAY_PLUGIN_D_ETHERNET
+ *
+ * Indicates that to send a packet to its destination, we
+ * require a link-layer ethernet address.
+ *
+ * OVERLAY_PLUGIN_D_IP
+ *
+ * Indicates that to send a packet to its destination, we
+ * require an IP address. Note, all IP addresses are
+ * transmitted as IPv6 addresses and for an IPv4
+ * destination, using an IPv4-mapped IPv6 address is the
+ * expected way to transmit that.
+ *
+ * OVERLAY_PLUGIN_D_PORT
+ *
+ * Indicates that to send a packet to its destination, a
+ * port is required, this usually indicates that the
+ * protocol uses something like TCP or UDP.
+ *
+ *
+ * -------------------------------------------------
+ * Downcalls, Upcalls, and Synchronization Guarantees
+ * -------------------------------------------------
+ *
+ * Every instance of a given module is independent. The kernel only guarantees
+ * that it will probably perform downcalls into different instances in parallel
+ * at some point. No locking is provided by the framework for synchronization
+ * across instances. If a module finds itself needing that, it will be up to it
+ * to provide it.
+ *
+ * In a given instance, the kernel may call into entry points in parallel. If
+ * the instance has private data, it should likely synchronize it. The one
+ * guarantee that we do make, is that calls to getprop and setprop will be done
+ * synchronized by a caller holding the MAC perimeter.
+ *
+ * While servicing a downcall from the general overlay device framework, a
+ * kernel module should not make any upcalls, excepting those functions that are
+ * defined in this header file, eg. the property related callbacks. Importantly,
+ * it cannot make any assumptions about what locks may or may not be held by the
+ * broader system. The only thing that it is safe for it to use are its own
+ * locks.
+ *
+ * ----------------
+ * Downcall Context
+ * ----------------
+ *
+ * For all of the downcalls, excepting the overlay_plugin_encap_t and
+ * overlay_plugin_decap_t, the calls will be made either in kernel or user
+ * context, the module should not assume either way.
+ *
+ * overlay_plugin_encap_t and overlay_plugin_decap_t may be called in user,
+ * kernel or interrupt context; however, it is guaranteed that the interrupt
+ * will be below LOCK_LEVEL, and therefore it is safe to grab locks.
+ */
+
+#include <sys/stream.h>
+#include <sys/mac_provider.h>
+#include <sys/ksocket.h>
+#include <sys/overlay_common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OVEP_VERSION 0x1
+
+typedef enum overlay_plugin_flags {
+ OVEP_F_VLAN_TAG = 0x01 /* Supports VLAN Tags */
+} overlay_plugin_flags_t;
+
+/*
+ * The ID space could easily be more than a 64-bit number, even
+ * though today it's either a 24-64 bit value. How should we future
+ * proof ourselves here?
+ */
+typedef struct ovep_encap_info {
+ uint64_t ovdi_id;
+ size_t ovdi_hdr_size;
+} ovep_encap_info_t;
+
+typedef struct __overlay_prop_handle *overlay_prop_handle_t;
+typedef struct __overlay_handle *overlay_handle_t;
+
+/*
+ * Plugins are guaranteed that calls to setprop are serialized. However, any
+ * number of other calls can be going on in parallel otherwise.
+ */
+typedef int (*overlay_plugin_encap_t)(void *, mblk_t *,
+ ovep_encap_info_t *, mblk_t **);
+typedef int (*overlay_plugin_decap_t)(void *, mblk_t *,
+ ovep_encap_info_t *);
+typedef int (*overlay_plugin_init_t)(overlay_handle_t, void **);
+typedef void (*overlay_plugin_fini_t)(void *);
+typedef int (*overlay_plugin_socket_t)(void *, int *, int *, int *,
+ struct sockaddr *, socklen_t *);
+typedef int (*overlay_plugin_sockopt_t)(ksocket_t);
+typedef int (*overlay_plugin_getprop_t)(void *, const char *, void *,
+ uint32_t *);
+typedef int (*overlay_plugin_setprop_t)(void *, const char *, const void *,
+ uint32_t);
+typedef int (*overlay_plugin_propinfo_t)(const char *, overlay_prop_handle_t);
+
+typedef struct overlay_plugin_ops {
+ uint_t ovpo_callbacks;
+ overlay_plugin_init_t ovpo_init;
+ overlay_plugin_fini_t ovpo_fini;
+ overlay_plugin_encap_t ovpo_encap;
+ overlay_plugin_decap_t ovpo_decap;
+ overlay_plugin_socket_t ovpo_socket;
+ overlay_plugin_sockopt_t ovpo_sockopt;
+ overlay_plugin_getprop_t ovpo_getprop;
+ overlay_plugin_setprop_t ovpo_setprop;
+ overlay_plugin_propinfo_t ovpo_propinfo;
+} overlay_plugin_ops_t;
+
+typedef struct overlay_plugin_register {
+ uint_t ovep_version;
+ const char *ovep_name;
+ const overlay_plugin_ops_t *ovep_ops;
+ const char **ovep_props;
+ uint_t ovep_id_size;
+ uint_t ovep_flags;
+ uint_t ovep_dest;
+} overlay_plugin_register_t;
+
+/*
+ * Functions that interact with registration
+ */
+extern overlay_plugin_register_t *overlay_plugin_alloc(uint_t);
+extern void overlay_plugin_free(overlay_plugin_register_t *);
+extern int overlay_plugin_register(overlay_plugin_register_t *);
+extern int overlay_plugin_unregister(const char *);
+
+/*
+ * Property information callbacks
+ */
+extern void overlay_prop_set_name(overlay_prop_handle_t, const char *);
+extern void overlay_prop_set_prot(overlay_prop_handle_t, overlay_prop_prot_t);
+extern void overlay_prop_set_type(overlay_prop_handle_t, overlay_prop_type_t);
+extern int overlay_prop_set_default(overlay_prop_handle_t, void *, ssize_t);
+extern void overlay_prop_set_nodefault(overlay_prop_handle_t);
+extern void overlay_prop_set_range_uint32(overlay_prop_handle_t, uint32_t,
+ uint32_t);
+extern void overlay_prop_set_range_str(overlay_prop_handle_t, const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_OVERLAY_PLUGIN_H */
diff --git a/usr/src/uts/common/sys/overlay_target.h b/usr/src/uts/common/sys/overlay_target.h
new file mode 100644
index 0000000000..775c7d27b8
--- /dev/null
+++ b/usr/src/uts/common/sys/overlay_target.h
@@ -0,0 +1,295 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2015 Joyent, Inc.
+ */
+
+#ifndef _OVERLAY_TARGET_H
+#define _OVERLAY_TARGET_H
+
+/*
+ * Overlay device varpd ioctl interface (/dev/overlay)
+ */
+
+#include <sys/types.h>
+#include <sys/ethernet.h>
+#include <netinet/in.h>
+#include <sys/overlay_common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct overlay_target_point {
+ uint8_t otp_mac[ETHERADDRL];
+ struct in6_addr otp_ip;
+ uint16_t otp_port;
+} overlay_target_point_t;
+
+#define OVERLAY_TARG_IOCTL (('o' << 24) | ('v' << 16) | ('t' << 8))
+
+#define OVERLAY_TARG_INFO (OVERLAY_TARG_IOCTL | 0x01)
+
+typedef enum overlay_targ_info_flags {
+ OVERLAY_TARG_INFO_F_ACTIVE = 0x01,
+ OVERLAY_TARG_INFO_F_DEGRADED = 0x02
+} overlay_targ_info_flags_t;
+
+/*
+ * Get target information about an overlay device
+ */
+typedef struct overlay_targ_info {
+ datalink_id_t oti_linkid;
+ uint32_t oti_needs;
+ uint64_t oti_flags;
+ uint64_t oti_vnetid;
+} overlay_targ_info_t;
+
+/*
+ * Declare an association between a given varpd instance and a datalink.
+ */
+#define OVERLAY_TARG_ASSOCIATE (OVERLAY_TARG_IOCTL | 0x02)
+
+typedef struct overlay_targ_associate {
+ datalink_id_t ota_linkid;
+ uint32_t ota_mode;
+ uint64_t ota_id;
+ uint32_t ota_provides;
+ overlay_target_point_t ota_point;
+} overlay_targ_associate_t;
+
+/*
+ * Remove an association from a device. If the device has already been started,
+ * this implies OVERLAY_TARG_DEGRADE.
+ */
+#define OVERLAY_TARG_DISASSOCIATE (OVERLAY_TARG_IOCTL | 0x3)
+
+/*
+ * Tells the kernel that while a varpd instance still exists, it basically isn't
+ * making any forward progress, so the device should consider itself degraded.
+ */
+#define OVERLAY_TARG_DEGRADE (OVERLAY_TARG_IOCTL | 0x4)
+
+typedef struct overlay_targ_degrade {
+ datalink_id_t otd_linkid;
+ uint32_t otd_pad;
+ char otd_buf[OVERLAY_STATUS_BUFLEN];
+} overlay_targ_degrade_t;
+
+/*
+ * Tells the kernel to remove the degraded status that it set on a device.
+ */
+#define OVERLAY_TARG_RESTORE (OVERLAY_TARG_IOCTL | 0x5)
+
+typedef struct overlay_targ_id {
+ datalink_id_t otid_linkid;
+} overlay_targ_id_t;
+
+/*
+ * The following ioctls are all used to support dynamic lookups from userland,
+ * generally serviced by varpd.
+ *
+ * The way this is designed to work is that user land will have threads sitting
+ * in OVERLAY_TARG_LOOKUP ioctls waiting to service requests. A thread will sit
+ * waiting for work for up to approximately one second of time before they will
+ * be sent back out to user land to give user land a chance to clean itself up
+ * or more generally, come back into the kernel for work. Once these threads
+ * return, they will have a request with which more action can be done. The
+ * following ioctls can all be used to answer the request.
+ *
+ * OVERLAY_TARG_RESPOND - overlay_targ_resp_t
+ *
+ * The overlay_targ_resp_t has the appropriate information from
+ * which a reply can be generated. The information is filled into
+ * an overlay_targ_point_t as appropriate based on the
+ * overlay_plugin_dest_t type.
+ *
+ *
+ * OVERLAY_TARG_DROP - overlay_targ_resp_t
+ *
+ * The overlay_targ_resp_t should identify a request for which to
+ * drop a packet.
+ *
+ *
+ * OVERLAY_TARG_INJECT - overlay_targ_pkt_t
+ *
+ * The overlay_targ_pkt_t injects a fully formed packet into the
+ * virtual network. It may either be identified by its data link id
+ * or by the request id. If both are specified, the
+ * datalink id will be used. Note, that an injection is not
+ * considered a reply and if this corresponds to a request, then
+ * that individual packet must still be dropped.
+ *
+ *
+ * OVERLAY_TARG_PKT - overlay_targ_pkt_t
+ *
+ * This ioctl can be used to copy data from a given request into a
+ * user buffer. This can be used in combination with
+ * OVERLAY_TARG_INJECT to implement services such as a proxy-arp.
+ *
+ *
+ * OVERLAY_TARG_RESEND - overlay_targ_pkt_t
+ *
+ * This ioctl is similar to the OVERLAY_TARG_INJECT, except instead
+ * of receiving it on the local mac handle, it queues it for
+ * retransmission again. This is useful if you have a packet that
+ * was originally destined for some broadcast or multicast address
+ * that you now want to send to a unicast address.
+ */
+#define OVERLAY_TARG_LOOKUP (OVERLAY_TARG_IOCTL | 0x10)
+#define OVERLAY_TARG_RESPOND (OVERLAY_TARG_IOCTL | 0x11)
+#define OVERLAY_TARG_DROP (OVERLAY_TARG_IOCTL | 0x12)
+#define OVERLAY_TARG_INJECT (OVERLAY_TARG_IOCTL | 0x13)
+#define OVERLAY_TARG_PKT (OVERLAY_TARG_IOCTL | 0x14)
+#define OVERLAY_TARG_RESEND (OVERLAY_TARG_IOCTL | 0x15)
+
+typedef struct overlay_targ_lookup {
+ uint64_t otl_dlid;
+ uint64_t otl_reqid;
+ uint64_t otl_varpdid;
+ uint64_t otl_vnetid;
+ uint64_t otl_hdrsize;
+ uint64_t otl_pktsize;
+ uint8_t otl_srcaddr[ETHERADDRL];
+ uint8_t otl_dstaddr[ETHERADDRL];
+ uint32_t otl_dsttype;
+ uint32_t otl_sap;
+ int32_t otl_vlan;
+} overlay_targ_lookup_t;
+
+typedef struct overlay_targ_resp {
+ uint64_t otr_reqid;
+ overlay_target_point_t otr_answer;
+} overlay_targ_resp_t;
+
+typedef struct overlay_targ_pkt {
+ uint64_t otp_linkid;
+ uint64_t otp_reqid;
+ uint64_t otp_size;
+ void *otp_buf;
+} overlay_targ_pkt_t;
+
+#ifdef _KERNEL
+
+#pragma pack(4)
+typedef struct overlay_targ_pkt32 {
+ uint64_t otp_linkid;
+ uint64_t otp_reqid;
+ uint64_t otp_size;
+ caddr32_t otp_buf;
+} overlay_targ_pkt32_t;
+#pragma pack()
+
+#endif /* _KERNEL */
+
+/*
+ * This provides a way to get a list of active overlay devices independently
+ * from dlmgmtd. At the end of the day the kernel always knows what will exist
+ * and this allows varpd which is an implementation of libdladm not to end up
+ * needing to call back into dlmgmtd via libdladm and create an unfortunate
+ * dependency cycle.
+ */
+
+#define OVERLAY_TARG_LIST (OVERLAY_TARG_IOCTL | 0x20)
+
+typedef struct overlay_targ_list {
+ uint32_t otl_nents;
+ uint32_t otl_ents[];
+} overlay_targ_list_t;
+
+/*
+ * The following family of ioctls all manipulate the target cache of a given
+ * device.
+ *
+ * OVERLAY_TARG_CACHE_GET - overlay_targ_cache_t
+ *
+ * The overlay_targ_cache_t should be have its link identifier and
+ * the desired mac address filled in. On return, it will fill in
+ * the otc_dest member, if the entry exists in the table.
+ *
+ *
+ * OVERLAY_TARG_CACHE_SET - overlay_targ_cache_t
+ *
+ * The cache table entry of the mac address referred to by otc_mac
+ * and otd_linkid will be filled in with the details provided by in
+ * the otc_dest member.
+ *
+ * OVERLAY_TARG_CACHE_REMOVE - overlay_targ_cache_t
+ *
+ * Removes the cache entry identified by otc_mac from the table.
+ * Note that this does not stop any in-flight lookups or deal with
+ * any data that is awaiting a lookup.
+ *
+ *
+ * OVERLAY_TARG_CACHE_FLUSH - overlay_targ_cache_t
+ *
+ * Similar to OVERLAY_TARG_CACHE_REMOVE, but functions on the
+ * entire table identified by otc_linkid. All other parameters are
+ * ignored.
+ *
+ *
+ * OVERLAY_TARG_CACHE_ITER - overlay_targ_cache_iter_t
+ *
+ * Iterates over the contents of a target cache identified by
+ * otci_linkid. Iteration is guaranteed to be exactly once for
+ * items which are in the hashtable at the beginning and end of
+ * iteration. For items which are added or removed after iteration
+ * has begun, only at most once semantics are guaranteed. Consumers
+ * should ensure that otci_marker is zeroed before starting
+ * iteration and should preserve its contents across calls.
+ *
+ * Before calling in, otci_count should be set to the number of
+ * entries that space has been allocated for in otci_ents. The
+ * value will be updated to indicate the total number written out.
+ */
+
+#define OVERLAY_TARG_CACHE_GET (OVERLAY_TARG_IOCTL | 0x30)
+#define OVERLAY_TARG_CACHE_SET (OVERLAY_TARG_IOCTL | 0x31)
+#define OVERLAY_TARG_CACHE_REMOVE (OVERLAY_TARG_IOCTL | 0x32)
+#define OVERLAY_TARG_CACHE_FLUSH (OVERLAY_TARG_IOCTL | 0x33)
+#define OVERLAY_TARG_CACHE_ITER (OVERLAY_TARG_IOCTL | 0x34)
+
+/*
+ * This is a pretty arbitrary number that we're constraining ourselves to
+ * for iteration. Basically the goal is to make sure that we can't have a user
+ * ask us to allocate too much memory on their behalf at any time. A more
+ * dynamic form may be necessary some day.
+ */
+#define OVERLAY_TARGET_ITER_MAX 500
+
+#define OVERLAY_TARGET_CACHE_DROP 0x01
+
+typedef struct overlay_targ_cache_entry {
+ uint8_t otce_mac[ETHERADDRL];
+ uint16_t otce_flags;
+ overlay_target_point_t otce_dest;
+} overlay_targ_cache_entry_t;
+
+typedef struct overlay_targ_cache {
+ datalink_id_t otc_linkid;
+ overlay_targ_cache_entry_t otc_entry;
+} overlay_targ_cache_t;
+
+typedef struct overlay_targ_cache_iter {
+ datalink_id_t otci_linkid;
+ uint32_t otci_pad;
+ uint64_t otci_marker;
+ uint16_t otci_count;
+ uint8_t otci_pad2[3];
+ overlay_targ_cache_entry_t otci_ents[];
+} overlay_targ_cache_iter_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OVERLAY_TARGET_H */
diff --git a/usr/src/uts/common/sys/plat/pci_prd.h b/usr/src/uts/common/sys/plat/pci_prd.h
new file mode 100644
index 0000000000..aa0a7932b8
--- /dev/null
+++ b/usr/src/uts/common/sys/plat/pci_prd.h
@@ -0,0 +1,130 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2022 Oxide Computer Company
+ */
+
+#ifndef _SYS_PLAT_PCI_PRD_H
+#define _SYS_PLAT_PCI_PRD_H
+
+/*
+ * PCI Platform Resource Discovery (PRD)
+ *
+ * This file forms the platform-specific interfaces that a given platform must
+ * implement to support the discovery of PCI resources. In particular:
+ *
+ * o Any root complexes that do not show up through the use of normal scanning
+ * o Available resources per root-port including:
+ * + I/O ports
+ * + Prefetchable Memory
+ * + Normal Memory
+ * + PCI buses
+ * o The naming of slots (the platform uses the PCIe default)
+ *
+ * These interfaces are all expected to be implemented by a platform's 'pci_prd'
+ * module. This is left as a module and not a part of say, unix, so that it can
+ * in turn depend on other modules that a platform might require, such as ACPI.
+ *
+ * In general, unless otherwise indicated, these interfaces will always be
+ * called from kernel context, typically during boot. The interfaces will only
+ * be called from a single thread at this time and any locking is managed at a
+ * layer outside of the pci_prd interfaces. If the subsystem is using some other
+ * interfaces that may be used by multiple consumers and needs locking (e.g.
+ * ACPI), then that still must be considered in the design and implementation.
+ */
+
+#include <sys/types.h>
+#include <sys/memlist.h>
+#include <sys/sunddi.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Resource types that can be asked after.
+ */
+typedef enum pci_prd_rsrc {
+ PCI_PRD_R_IO,
+ PCI_PRD_R_MMIO,
+ PCI_PRD_R_PREFETCH,
+ PCI_PRD_R_BUS
+} pci_prd_rsrc_t;
+
+typedef struct pci_prd_upcalls {
+ /*
+ * Return a dev_info_t, if one exists, for this PCI bus.
+ */
+ dev_info_t *(*pru_bus2dip_f)(uint32_t);
+} pci_prd_upcalls_t;
+
+/*
+ * Initialization and teardown functions that will be used by the PCI
+ * enumeration code when it attaches and detaches. If all work is done before
+ * these come up, there is nothing to do; however, after a call to the _init()
+ * function, it is expected that the platform module will be ready to respond to
+ * all function calls.
+ *
+ * Note that the _fini function may never be called as on a typical system, as
+ * any PCI(e) devices with attached drivers will result in the PRD consumer
+ * remaining loaded.
+ */
+extern int pci_prd_init(pci_prd_upcalls_t *);
+extern void pci_prd_fini(void);
+
+/*
+ * Return the maximum PCI bus on this platform that should be searched. This
+ * number is the last bus number that should be scanned. e.g. a value of 0x10
+ * indicates that we will search buses [0, 0x10]. In general, it is expected
+ * that platforms will just return 0xff (PCI_MAX_BUS_NUM - 1) unless for some
+ * reason it has other knowledge here.
+ */
+extern uint32_t pci_prd_max_bus(void);
+
+/*
+ * Look up a set of resources that should be assigned to the PCI bus. In
+ * general, it is expected that these are only the buses that are assigned to
+ * root complexes.
+ */
+extern struct memlist *pci_prd_find_resource(uint32_t, pci_prd_rsrc_t);
+
+/*
+ * Originally when only using BIOS-derived (pre-ACPI) sources on i86pc, the
+ * ability to utilize data about multiple buses was considered suspect. As such,
+ * this exists as a way to indicate that resources on each root complex are
+ * actually valid.
+ */
+extern boolean_t pci_prd_multi_root_ok(void);
+
+/*
+ * This is used to allow the PCI enumeration code to ask the platform about any
+ * PCI root complexes that it might know about which might not be discovered
+ * through the normal scanning process. One callback will be emitted for each
+ * PCI bus via a call to the callback function. The return value of the callback
+ * function determines whether we should continue iterating (B_TRUE) or
+ * terminate (B_FALSE).
+ */
+typedef boolean_t (*pci_prd_root_complex_f)(uint32_t, void *);
+extern void pci_prd_root_complex_iter(pci_prd_root_complex_f, void *);
+
+/*
+ * Give the chance for a platform file to go through and use knowledge that it
+ * has (such as the traditional BIOS PCI IRQ routing table) to name the PCI(e)
+ * slot.
+ */
+extern void pci_prd_slot_name(uint32_t, dev_info_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_PLAT_PCI_PRD_H */
diff --git a/usr/src/uts/common/sys/ptms.h b/usr/src/uts/common/sys/ptms.h
index 55987fe6d7..23594fdc13 100644
--- a/usr/src/uts/common/sys/ptms.h
+++ b/usr/src/uts/common/sys/ptms.h
@@ -35,18 +35,17 @@ extern "C" {
#ifdef _KERNEL
/*
- * Structures and definitions supporting the pseudo terminal
- * drivers. This structure is private and should not be used by any
- * applications.
+ * Structures and definitions supporting the pseudo-terminal drivers. This
+ * structure is private and should not be used by any applications.
*/
struct pt_ttys {
- queue_t *ptm_rdq; /* master's read queue pointer */
- queue_t *pts_rdq; /* slave's read queue pointer */
+ queue_t *ptm_rdq; /* manager's read queue pointer */
+ queue_t *pts_rdq; /* subsidiary's read queue pointer */
mblk_t *pt_nullmsg; /* 0-bytes message block for pts close */
pid_t pt_pid; /* process id (for debugging) */
minor_t pt_minor; /* Minor number of this pty */
int pt_refcnt; /* reference count for ptm_rdq/pts_rdq uses */
- ushort_t pt_state; /* state of master/slave pair */
+ ushort_t pt_state; /* state of manager/subsidiary pair */
kcondvar_t pt_cv; /* condition variable for exclusive access */
kmutex_t pt_lock; /* Per-element lock */
zoneid_t pt_zoneid; /* Zone membership for this pty */
@@ -57,10 +56,10 @@ struct pt_ttys {
/*
* pt_state values
*/
-#define PTLOCK 0x01 /* master/slave pair is locked */
-#define PTMOPEN 0x02 /* master side is open */
-#define PTSOPEN 0x04 /* slave side is open */
-#define PTSTTY 0x08 /* slave side is tty */
+#define PTLOCK 0x01 /* manager/subsidiary pair is locked */
+#define PTMOPEN 0x02 /* manager side is open */
+#define PTSOPEN 0x04 /* subsidiary side is open */
+#define PTSTTY 0x08 /* subsidiary side is tty */
/*
* Multi-threading primitives.
@@ -104,17 +103,17 @@ struct pt_ttys {
* ptms_lock and pt_cnt are defined in ptms_conf.c
*/
extern kmutex_t ptms_lock;
-extern dev_info_t *pts_dip; /* private copy of devinfo ptr */
+extern dev_info_t *pts_dip; /* private copy of devinfo ptr */
extern void ptms_init(void);
extern struct pt_ttys *pt_ttys_alloc(void);
extern void ptms_close(struct pt_ttys *, uint_t);
extern struct pt_ttys *ptms_minor2ptty(minor_t);
-extern int ptms_attach_slave(void);
+extern int ptms_attach_subsidiary(void);
extern int ptms_minor_valid(minor_t ptmin, uid_t *uid, gid_t *gid);
extern int ptms_minor_exists(minor_t ptmin);
extern void ptms_set_owner(minor_t ptmin, uid_t uid, gid_t gid);
-extern major_t ptms_slave_attached(void);
+extern major_t ptms_subsidiary_attached(void);
#ifdef DEBUG
extern void ptms_log(char *, uint_t);
@@ -134,28 +133,32 @@ typedef struct pt_own {
} pt_own_t;
/*
- * ioctl commands
+ * IOCTL COMMANDS
*
- * ISPTM: Determines whether the file descriptor is that of an open master
- * device. Return code of zero indicates that the file descriptor
- * represents master device.
+ * ISPTM
+ * Determines whether the file descriptor is that of an open
+ * manager device. Return code of zero indicates that the file
+ * descriptor represents a manager device.
*
- * UNLKPT: Unlocks the master and slave devices. It returns 0 on success. On
- * failure, the errno is set to EINVAL indicating that the master
- * device is not open.
+ * UNLKPT
+ * Unlocks the manager and subsidiary devices. It returns 0 on
+ * success. On failure, the errno is set to EINVAL indicating
+ * that the manager device is not open.
*
- * ZONEPT: Sets the zoneid of the pair of master and slave devices. It
- * returns 0 upon success. Used to force a pty 'into' a zone upon
- * zone entry.
- *
- * PT_OWNER: Sets uid and gid for slave device. It returns 0 on success.
+ * ZONEPT
+ * Sets the zoneid of the pair of manager and subsidiary devices.
+ * It returns 0 upon success. Used to force a pty 'into' a zone
+ * upon zone entry.
*
+ * PT_OWNER
+ * Sets uid and gid for subsidiary device. It returns 0 on
+ * success.
*/
-#define ISPTM (('P'<<8)|1) /* query for master */
-#define UNLKPT (('P'<<8)|2) /* unlock master/slave pair */
-#define PTSSTTY (('P'<<8)|3) /* set tty flag */
-#define ZONEPT (('P'<<8)|4) /* set zone of master/slave pair */
-#define OWNERPT (('P'<<8)|5) /* set owner/group for slave device */
+#define ISPTM (('P'<<8)|1) /* query for manager */
+#define UNLKPT (('P'<<8)|2) /* unlock manager/subsidiary pair */
+#define PTSSTTY (('P'<<8)|3) /* set tty flag */
+#define ZONEPT (('P'<<8)|4) /* set zone of manager/subsidiary pair */
+#define OWNERPT (('P'<<8)|5) /* set owner/group for subsidiary */
#ifdef __cplusplus
}
diff --git a/usr/src/uts/common/sys/ptyvar.h b/usr/src/uts/common/sys/ptyvar.h
index 76bc74c36a..ee00379fd8 100644
--- a/usr/src/uts/common/sys/ptyvar.h
+++ b/usr/src/uts/common/sys/ptyvar.h
@@ -25,14 +25,12 @@
*/
/*
- * Pseudo-tty driver data structures.
+ * Pseudo-terminal driver data structures.
*/
#ifndef _SYS_PTYVAR_H
#define _SYS_PTYVAR_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/tty.h>
#ifdef __cplusplus
@@ -49,8 +47,8 @@ struct pty {
struct proc *pt_selr; /* proc selecting on controller read */
struct proc *pt_selw; /* proc selecting on controller write */
struct proc *pt_sele; /* proc selecting on exception */
- dev_t pt_sdev; /* XXX dev no for the slave */
- struct vnode *pt_vnode; /* XXX vnode for the slave */
+ dev_t pt_sdev; /* XXX dev no for the subsidiary */
+ struct vnode *pt_vnode; /* XXX vnode for the subsidiary */
short pt_pgrp; /* controller side process group */
uchar_t pt_send; /* pending message to controller */
uchar_t pt_ucntl; /* pending iocontrol for controller */
@@ -67,11 +65,11 @@ struct pty {
#define PF_ASYNC 0x00000010 /* asynchronous I/O on controller */
#define PF_WOPEN 0x00000020 /* waiting for open to complete */
#define PF_CARR_ON 0x00000040 /* "carrier" is on (cntlr. is open) */
-#define PF_SLAVEGONE 0x00000080 /* slave was open, but is now closed */
+#define PF_SUBSIDGONE 0x00000080 /* subsidiary was open, now closed */
#define PF_PKT 0x00000100 /* packet mode */
#define PF_STOPPED 0x00000200 /* user told stopped */
#define PF_REMOTE 0x00000400 /* remote and flow controlled input */
-#define PF_NOSTOP 0x00000800 /* slave is doing XON/XOFF */
+#define PF_NOSTOP 0x00000800 /* subsidiary is doing XON/XOFF */
#define PF_UCNTL 0x00001000 /* user control mode */
#define PF_43UCNTL 0x00002000 /* real 4.3 user control mode */
#define PF_IOCTL 0x00004000 /* ioctl call in progress */
diff --git a/usr/src/uts/common/sys/scsi/adapters/smrt/smrt.h b/usr/src/uts/common/sys/scsi/adapters/smrt/smrt.h
new file mode 100644
index 0000000000..5aba743834
--- /dev/null
+++ b/usr/src/uts/common/sys/scsi/adapters/smrt/smrt.h
@@ -0,0 +1,750 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+#ifndef _SMRT_H
+#define _SMRT_H
+
+#include <sys/types.h>
+#include <sys/pci.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/conf.h>
+#include <sys/map.h>
+#include <sys/modctl.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+#include <sys/stat.h>
+#include <sys/scsi/scsi.h>
+#include <sys/scsi/impl/spc3_types.h>
+#include <sys/devops.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sdt.h>
+#include <sys/policy.h>
+#include <sys/ctype.h>
+
+#if !defined(_LITTLE_ENDIAN) || !defined(_BIT_FIELDS_LTOH)
+/*
+ * This driver contains a number of multi-byte bit fields and other structs
+ * that are only correct on a system with the same ordering as x86.
+ */
+#error "smrt: driver works only on little endian systems"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Some structures are statically sized based on the expected number of logical
+ * drives and controllers in the system. These definitions are used throughout
+ * other driver-specific header files, and must appear prior to their
+ * inclusion.
+ */
+#define SMRT_MAX_LOGDRV 64 /* Maximum number of logical drives */
+#define SMRT_MAX_PHYSDEV 128 /* Maximum number of physical devices */
+
+#include <sys/scsi/adapters/smrt/smrt_ciss.h>
+#include <sys/scsi/adapters/smrt/smrt_scsi.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern ddi_device_acc_attr_t smrt_dev_attributes;
+
+typedef enum smrt_init_level {
+ SMRT_INITLEVEL_BASIC = (0x1 << 0),
+ SMRT_INITLEVEL_I2O_MAPPED = (0x1 << 1),
+ SMRT_INITLEVEL_CFGTBL_MAPPED = (0x1 << 2),
+ SMRT_INITLEVEL_PERIODIC = (0x1 << 3),
+ SMRT_INITLEVEL_INT_ALLOC = (0x1 << 4),
+ SMRT_INITLEVEL_INT_ADDED = (0x1 << 5),
+ SMRT_INITLEVEL_INT_ENABLED = (0x1 << 6),
+ SMRT_INITLEVEL_SCSA = (0x1 << 7),
+ SMRT_INITLEVEL_MUTEX = (0x1 << 8),
+ SMRT_INITLEVEL_TASKQ = (0x1 << 9),
+ SMRT_INITLEVEL_ASYNC_EVENT = (0x1 << 10),
+} smrt_init_level_t;
+
+/*
+ * Commands issued to the controller carry a (generally 32-bit, though with
+ * two reserved signalling bits) identifying tag number. In order to avoid
+ * having the controller confuse us by double-reporting the completion of a
+ * particular tag, we try to reuse them as infrequently as possible. In
+ * practice, this means looping through a range of values. The minimum and
+ * maximum value are defined below. A single command tag value is set aside
+ * for polled commands sent prior to full initialisation of the driver.
+ */
+#define SMRT_PRE_TAG_NUMBER 0x00000bad
+#define SMRT_MIN_TAG_NUMBER 0x00001000
+#define SMRT_MAX_TAG_NUMBER 0x0fffffff
+
+/*
+ * Character strings that represent the names of the iports used for both
+ * physical and virtual volumes.
+ */
+#define SMRT_IPORT_PHYS "p0"
+#define SMRT_IPORT_VIRT "v0"
+
+/*
+ * Definitions to support waiting for the controller to converge on a
+ * particular state: ready or not ready. These are used with
+ * smrt_ctlr_wait_for_state().
+ */
+#define SMRT_WAIT_DELAY_SECONDS 120
+typedef enum smrt_wait_state {
+ SMRT_WAIT_STATE_READY = 1,
+ SMRT_WAIT_STATE_UNREADY
+} smrt_wait_state_t;
+
+typedef enum smrt_ctlr_mode {
+ SMRT_CTLR_MODE_UNKNOWN = 0,
+ SMRT_CTLR_MODE_SIMPLE
+} smrt_ctlr_mode_t;
+
+/*
+ * In addition to Logical Volumes, we also expose the controller at a
+ * pseudo target address on the SCSI bus we are essentially pretending to be.
+ */
+#define SMRT_CONTROLLER_TARGET 128
+
+/*
+ * When waiting for volume discovery to complete, we wait for a maximum
+ * duration (in seconds) before giving up.
+ */
+#define SMRT_DISCOVER_TIMEOUT 30
+
+/*
+ * The maintenance routine which checks for controller lockup and aborts
+ * commands that have passed their timeout runs periodically. The time is
+ * expressed in seconds.
+ */
+#define SMRT_PERIODIC_RATE 5
+
+/*
+ * At times, we need to check if the controller is still responding. To do
+ * that, we send a Nop message to the controller and make sure it completes
+ * successfully. So that we don't wait forever, we set a timeout (in seconds).
+ */
+#define SMRT_PING_CHECK_TIMEOUT 60
+
+/*
+ * When detaching the device, we may need to have an asynchronous event
+ * cancellation be issued. While this should be relatively smooth, we don't
+ * want to wait forever for it. As such we set a timeout in seconds.
+ */
+#define SMRT_ASYNC_CANCEL_TIMEOUT 60
+
+/*
+ * HP PCI vendor ID and Generation 9 device ID. Used to identify generations of
+ * supported controllers.
+ */
+#define SMRT_VENDOR_HP 0x103c
+#define SMRT_DEVICE_GEN9 0x3238
+
+typedef enum smrt_controller_status {
+ /*
+ * An attempt is being made to detach the controller instance.
+ */
+ SMRT_CTLR_STATUS_DETACHING = (0x1 << 0),
+
+ /*
+ * The controller is believed to be functioning correctly. The driver
+ * is to allow command submission, process interrupts, and perform
+ * periodic background maintenance.
+ */
+ SMRT_CTLR_STATUS_RUNNING = (0x1 << 1),
+
+ /*
+ * The controller is currently being reset.
+ */
+ SMRT_CTLR_STATUS_RESETTING = (0x1 << 2),
+
+ /*
+ * Our async event notification command is currently in need of help
+ * from the broader driver. This will be set by smrt_event_complete()
+ * to indicate that the command is not being processed due to a
+ * controller reset or because another fatal error occurred. The
+ * periodic will have to pick up and recover this for us. It is only
+ * safe for the driver to manipulate the event command outside of
+ * smrt_event_complete() if this flag is set.
+ */
+ SMRT_CTLR_ASYNC_INTERVENTION = (0x1 << 3),
+
+ /*
+ * See the theory statement on discovery and resets in smrt_ciss.c for
+ * an explanation of these values.
+ */
+ SMRT_CTLR_DISCOVERY_REQUESTED = (0x1 << 4),
+ SMRT_CTLR_DISCOVERY_RUNNING = (0x1 << 5),
+ SMRT_CTLR_DISCOVERY_PERIODIC = (0x1 << 6),
+ SMRT_CTLR_DISCOVERY_REQUIRED = (0x1 << 7),
+} smrt_controller_status_t;
+
+#define SMRT_CTLR_DISCOVERY_MASK (SMRT_CTLR_DISCOVERY_REQUESTED | \
+ SMRT_CTLR_DISCOVERY_RUNNING | SMRT_CTLR_DISCOVERY_PERIODIC)
+
+typedef struct smrt_stats {
+ uint64_t smrts_tran_aborts;
+ uint64_t smrts_tran_resets;
+ uint64_t smrts_tran_starts;
+ uint64_t smrts_ctlr_resets;
+ unsigned smrts_max_inflight;
+ uint64_t smrts_unclaimed_interrupts;
+ uint64_t smrts_claimed_interrupts;
+ uint64_t smrts_ignored_scsi_cmds;
+ uint64_t smrts_events_received;
+ uint64_t smrts_events_errors;
+ uint64_t smrts_events_intervened;
+ uint64_t smrts_discovery_tq_errors;
+} smrt_stats_t;
+
+typedef struct smrt_versions {
+ uint8_t smrtv_hardware_version;
+
+ /*
+ * These strings must be large enough to hold the 4 byte version string
+ * retrieved from an IDENTIFY CONTROLLER response, as well as the
+ * terminating NUL byte:
+ */
+ char smrtv_firmware_rev[5];
+ char smrtv_recovery_rev[5];
+ char smrtv_bootblock_rev[5];
+} smrt_versions_t;
+
+typedef struct smrt smrt_t;
+typedef struct smrt_command smrt_command_t;
+typedef struct smrt_command_internal smrt_command_internal_t;
+typedef struct smrt_command_scsa smrt_command_scsa_t;
+typedef struct smrt_pkt smrt_pkt_t;
+
+/*
+ * Per-Controller Structure
+ */
+struct smrt {
+ dev_info_t *smrt_dip;
+ int smrt_instance;
+ smrt_controller_status_t smrt_status;
+ smrt_stats_t smrt_stats;
+
+ /*
+ * Controller configuration discovered during initialisation.
+ */
+ uint32_t smrt_host_support;
+ uint32_t smrt_bus_support;
+ uint32_t smrt_maxcmds;
+ uint32_t smrt_sg_cnt;
+ smrt_versions_t smrt_versions;
+ uint16_t smrt_pci_vendor;
+ uint16_t smrt_pci_device;
+
+ /*
+ * iport specific data
+ */
+ dev_info_t *smrt_virt_iport;
+ dev_info_t *smrt_phys_iport;
+ scsi_hba_tgtmap_t *smrt_virt_tgtmap;
+ scsi_hba_tgtmap_t *smrt_phys_tgtmap;
+
+ /*
+ * The transport mode of the controller.
+ */
+ smrt_ctlr_mode_t smrt_ctlr_mode;
+
+ /*
+ * The current initialisation level of the driver. Bits in this field
+ * are set during initialisation and unset during cleanup of the
+ * allocated resources.
+ */
+ smrt_init_level_t smrt_init_level;
+
+ /*
+ * Essentially everything is protected by "smrt_mutex". When the
+ * completion queue is updated, threads sleeping on "smrt_cv_finishq"
+ * are awoken.
+ */
+ kmutex_t smrt_mutex;
+ kcondvar_t smrt_cv_finishq;
+
+ /*
+ * List of enumerated logical volumes (smrt_volume_t).
+ */
+ list_t smrt_volumes;
+
+ /*
+ * List of enumerated physical devices (smrt_physical_t).
+ */
+ list_t smrt_physicals;
+
+ /*
+ * List of attached SCSA target drivers (smrt_target_t).
+ */
+ list_t smrt_targets;
+
+ /*
+ * Controller Heartbeat Tracking
+ */
+ uint32_t smrt_last_heartbeat;
+ hrtime_t smrt_last_heartbeat_time;
+
+ hrtime_t smrt_last_interrupt_claimed;
+ hrtime_t smrt_last_interrupt_unclaimed;
+ hrtime_t smrt_last_reset_start;
+ hrtime_t smrt_last_reset_finish;
+
+ /*
+ * Command object tracking. These lists, and all commands within the
+ * lists, are protected by "smrt_mutex".
+ */
+ uint32_t smrt_next_tag;
+ avl_tree_t smrt_inflight;
+ list_t smrt_commands; /* List of all commands. */
+ list_t smrt_finishq; /* List of completed commands. */
+ list_t smrt_abortq; /* List of commands to abort. */
+
+ /*
+ * Discovery coordination
+ */
+ ddi_taskq_t *smrt_discover_taskq;
+ hrtime_t smrt_last_phys_discovery;
+ hrtime_t smrt_last_log_discovery;
+ uint64_t smrt_discover_gen;
+
+ /*
+ * Controller interrupt handler registration.
+ */
+ int smrt_interrupt_type;
+ int smrt_interrupt_cap;
+ uint_t smrt_interrupt_pri;
+ ddi_intr_handle_t smrt_interrupts[1];
+ int smrt_ninterrupts;
+
+ ddi_periodic_t smrt_periodic;
+
+ scsi_hba_tran_t *smrt_hba_tran;
+
+ ddi_dma_attr_t smrt_dma_attr;
+
+ /*
+ * Access to the I2O Registers:
+ */
+ unsigned smrt_i2o_bar;
+ caddr_t smrt_i2o_space;
+ ddi_acc_handle_t smrt_i2o_handle;
+
+ /*
+ * Access to the Configuration Table:
+ */
+ unsigned smrt_ct_bar;
+ uint32_t smrt_ct_baseaddr;
+ CfgTable_t *smrt_ct;
+ ddi_acc_handle_t smrt_ct_handle;
+
+ /*
+ * Asynchronous Event State
+ */
+ uint32_t smrt_event_count;
+ smrt_command_t *smrt_event_cmd;
+ smrt_command_t *smrt_event_cancel_cmd;
+ kcondvar_t smrt_event_queue;
+};
+
+/*
+ * Logical Volume Structure
+ */
+typedef enum smrt_volume_flags {
+ SMRT_VOL_FLAG_WWN = (0x1 << 0),
+} smrt_volume_flags_t;
+
+typedef struct smrt_volume {
+ LUNAddr_t smlv_addr;
+ smrt_volume_flags_t smlv_flags;
+
+ uint8_t smlv_wwn[16];
+ uint64_t smlv_gen;
+
+ smrt_t *smlv_ctlr;
+ list_node_t smlv_link;
+
+ /*
+ * List of SCSA targets currently attached to this Logical Volume:
+ */
+ list_t smlv_targets;
+} smrt_volume_t;
+
+typedef struct smrt_physical {
+ LUNAddr_t smpt_addr;
+ uint64_t smpt_wwn;
+ uint8_t smpt_dtype;
+ uint16_t smpt_bmic;
+ uint64_t smpt_gen;
+ boolean_t smpt_supported;
+ boolean_t smpt_visible;
+ boolean_t smpt_unsup_warn;
+ list_node_t smpt_link;
+ list_t smpt_targets;
+ smrt_t *smpt_ctlr;
+ smrt_identify_physical_drive_t *smpt_info;
+} smrt_physical_t;
+
+/*
+ * Per-Target Structure
+ */
+typedef struct smrt_target {
+ struct scsi_device *smtg_scsi_dev;
+
+ boolean_t smtg_physical;
+
+ /*
+ * This is only used when performing discovery during panic, as we need
+ * a mechanism to determine if the set of drives has shifted.
+ */
+ boolean_t smtg_gone;
+
+ /*
+ * Linkage back to the device that this target represents. This may be
+ * either a smrt_volume_t or a smrt_physical_t. We keep a pointer to the
+ * address, as that's the one thing we generally care about.
+ */
+ union {
+ smrt_physical_t *smtg_phys;
+ smrt_volume_t *smtg_vol;
+ } smtg_lun;
+ list_node_t smtg_link_lun;
+ LUNAddr_t *smtg_addr;
+
+ /*
+ * Linkage back to the controller:
+ */
+ smrt_t *smtg_ctlr;
+ list_node_t smtg_link_ctlr;
+} smrt_target_t;
+
+/*
+ * DMA Resource Tracking Structure
+ */
+typedef enum smrt_dma_level {
+ SMRT_DMALEVEL_HANDLE_ALLOC = (0x1 << 0),
+ SMRT_DMALEVEL_MEMORY_ALLOC = (0x1 << 1),
+ SMRT_DMALEVEL_HANDLE_BOUND = (0x1 << 2),
+} smrt_dma_level_t;
+
+typedef struct smrt_dma {
+ smrt_dma_level_t smdma_level;
+ size_t smdma_real_size;
+ ddi_dma_handle_t smdma_dma_handle;
+ ddi_acc_handle_t smdma_acc_handle;
+ ddi_dma_cookie_t smdma_dma_cookies[1];
+ uint_t smdma_dma_ncookies;
+} smrt_dma_t;
+
+
+typedef enum smrt_command_status {
+ /*
+ * When a command is submitted to the controller, it is marked USED
+ * to avoid accidental reuse of the command without reinitialising
+ * critical fields. The submitted command is also marked INFLIGHT
+ * to reflect its inclusion in the "smrt_inflight" AVL tree. When
+ * the command is completed by the controller, INFLIGHT is unset.
+ */
+ SMRT_CMD_STATUS_USED = (0x1 << 0),
+ SMRT_CMD_STATUS_INFLIGHT = (0x1 << 1),
+
+ /*
+ * This flag is set during abort queue processing to record that this
+ * command was aborted in response to an expired timeout, and not some
+ * other cancellation. If the controller is able to abort the command,
+ * we use this flag to let the SCSI framework know that the command
+ * timed out.
+ */
+ SMRT_CMD_STATUS_TIMEOUT = (0x1 << 2),
+
+ /*
+ * The controller set the error bit when completing this command.
+ * Details of the particular fault may be read from the error
+ * information written by the controller.
+ */
+ SMRT_CMD_STATUS_ERROR = (0x1 << 3),
+
+ /*
+ * This command has been abandoned by the original submitter. This
+ * could happen if the command did not complete in a timely fashion.
+ * When it reaches the finish queue it will be freed without further
+ * processing.
+ */
+ SMRT_CMD_STATUS_ABANDONED = (0x1 << 4),
+
+ /*
+ * This command has made it through the completion queue and had final
+ * processing performed.
+ */
+ SMRT_CMD_STATUS_COMPLETE = (0x1 << 5),
+
+ /*
+ * A polled message will be ignored by the regular processing of the
+ * completion queue. The blocking function doing the polling is
+ * responsible for watching the command on which it has set the POLLED
+ * flag. Regular completion queue processing (which might happen in
+ * the polling function, or it might happen in the interrupt handler)
+ * will set POLL_COMPLETE once it is out of the finish queue
+ * altogether.
+ */
+ SMRT_CMD_STATUS_POLLED = (0x1 << 6),
+ SMRT_CMD_STATUS_POLL_COMPLETE = (0x1 << 7),
+
+ /*
+ * An abort message has been sent to the controller in an attempt to
+ * cancel this command.
+ */
+ SMRT_CMD_STATUS_ABORT_SENT = (0x1 << 8),
+
+ /*
+ * This command has been passed to our tran_start(9E) handler.
+ */
+ SMRT_CMD_STATUS_TRAN_START = (0x1 << 9),
+
+ /*
+ * This command was for a SCSI command that we are explicitly avoiding
+ * sending to the controller.
+ */
+ SMRT_CMD_STATUS_TRAN_IGNORED = (0x1 << 10),
+
+ /*
+ * This command has been submitted once, and subsequently passed to
+ * smrt_command_reuse().
+ */
+ SMRT_CMD_STATUS_REUSED = (0x1 << 11),
+
+ /*
+ * A controller reset has been issued, so a response for this command
+ * is not expected. If one arrives before the controller reset has
+ * taken effect, it likely cannot be trusted.
+ */
+ SMRT_CMD_STATUS_RESET_SENT = (0x1 << 12),
+
+ /*
+ * Certain commands related to discovery and pinging need to be run
+ * during the context after a reset has occurred, but before the
+ * controller is considered. Such commands can use this flag to bypass
+ * the normal smrt_submit() check.
+ */
+ SMRT_CMD_IGNORE_RUNNING = (0x1 << 13),
+} smrt_command_status_t;
+
+typedef enum smrt_command_type {
+ SMRT_CMDTYPE_INTERNAL = 1,
+ SMRT_CMDTYPE_EVENT,
+ SMRT_CMDTYPE_ABORTQ,
+ SMRT_CMDTYPE_SCSA,
+ SMRT_CMDTYPE_PREINIT,
+} smrt_command_type_t;
+
+struct smrt_command {
+ uint32_t smcm_tag;
+ smrt_command_type_t smcm_type;
+ smrt_command_status_t smcm_status;
+
+ smrt_t *smcm_ctlr;
+ smrt_target_t *smcm_target;
+
+ list_node_t smcm_link; /* Linkage for allocated list. */
+ list_node_t smcm_link_finish; /* Linkage for completion list. */
+ list_node_t smcm_link_abort; /* Linkage for abort list. */
+ avl_node_t smcm_node; /* Inflight AVL membership. */
+
+ hrtime_t smcm_time_submit;
+ hrtime_t smcm_time_complete;
+
+ hrtime_t smcm_expiry;
+
+ /*
+ * The time at which an abort message was sent to try and terminate
+ * this command, as well as the tag of the abort message itself:
+ */
+ hrtime_t smcm_abort_time;
+ uint32_t smcm_abort_tag;
+
+ /*
+ * Ancillary data objects. Only one of these will be allocated for any
+ * given command, but we nonetheless resist the temptation to use a
+ * union of pointers in order to make incorrect usage obvious.
+ */
+ smrt_command_scsa_t *smcm_scsa;
+ smrt_command_internal_t *smcm_internal;
+
+ /*
+ * Physical allocation tracking for the actual command to send to the
+ * controller.
+ */
+ smrt_dma_t smcm_contig;
+
+ CommandList_t *smcm_va_cmd;
+ uint32_t smcm_pa_cmd;
+
+ ErrorInfo_t *smcm_va_err;
+ uint32_t smcm_pa_err;
+};
+
+/*
+ * Commands issued internally to the driver (as opposed to by the HBA
+ * framework) generally require a buffer in which to assemble the command body,
+ * and for receiving the response from the controller. The following object
+ * tracks this (optional) extra buffer.
+ */
+struct smrt_command_internal {
+ smrt_dma_t smcmi_contig;
+
+ void *smcmi_va;
+ uint32_t smcmi_pa;
+ size_t smcmi_len;
+};
+
+/*
+ * Commands issued via the SCSI framework have a number of additional
+ * properties.
+ */
+struct smrt_command_scsa {
+ struct scsi_pkt *smcms_pkt;
+ smrt_command_t *smcms_command;
+};
+
+
+/*
+ * CISS transport routines.
+ */
+void smrt_periodic(void *);
+void smrt_lockup_check(smrt_t *);
+int smrt_submit(smrt_t *, smrt_command_t *);
+void smrt_submit_simple(smrt_t *, smrt_command_t *);
+int smrt_retrieve(smrt_t *);
+void smrt_retrieve_simple(smrt_t *);
+int smrt_poll_for(smrt_t *, smrt_command_t *);
+int smrt_preinit_command_simple(smrt_t *, smrt_command_t *);
+
+/*
+ * Interrupt service routines.
+ */
+int smrt_interrupts_setup(smrt_t *);
+int smrt_interrupts_enable(smrt_t *);
+void smrt_interrupts_teardown(smrt_t *);
+uint32_t smrt_isr_hw_simple(caddr_t, caddr_t);
+
+/*
+ * Interrupt enable/disable routines.
+ */
+void smrt_intr_set(smrt_t *, boolean_t);
+
+/*
+ * Controller initialisation routines.
+ */
+int smrt_ctlr_init(smrt_t *);
+void smrt_ctlr_teardown(smrt_t *);
+int smrt_ctlr_reset(smrt_t *);
+int smrt_ctlr_wait_for_state(smrt_t *, smrt_wait_state_t);
+int smrt_ctlr_init_simple(smrt_t *);
+void smrt_ctlr_teardown_simple(smrt_t *);
+int smrt_cfgtbl_flush(smrt_t *);
+int smrt_cfgtbl_transport_has_support(smrt_t *, int);
+void smrt_cfgtbl_transport_set(smrt_t *, int);
+int smrt_cfgtbl_transport_confirm(smrt_t *, int);
+uint32_t smrt_ctlr_get_cmdsoutmax(smrt_t *);
+uint32_t smrt_ctlr_get_maxsgelements(smrt_t *);
+
+/*
+ * Device enumeration and lookup routines.
+ */
+void smrt_discover_request(smrt_t *);
+
+int smrt_logvol_discover(smrt_t *, uint16_t, uint64_t);
+void smrt_logvol_teardown(smrt_t *);
+smrt_volume_t *smrt_logvol_lookup_by_id(smrt_t *, unsigned long);
+void smrt_logvol_tgtmap_activate(void *, char *, scsi_tgtmap_tgt_type_t,
+ void **);
+boolean_t smrt_logvol_tgtmap_deactivate(void *, char *, scsi_tgtmap_tgt_type_t,
+ void *, scsi_tgtmap_deact_rsn_t);
+
+int smrt_phys_discover(smrt_t *, uint16_t, uint64_t);
+smrt_physical_t *smrt_phys_lookup_by_ua(smrt_t *, const char *);
+void smrt_phys_teardown(smrt_t *);
+void smrt_phys_tgtmap_activate(void *, char *, scsi_tgtmap_tgt_type_t,
+ void **);
+boolean_t smrt_phys_tgtmap_deactivate(void *, char *, scsi_tgtmap_tgt_type_t,
+ void *, scsi_tgtmap_deact_rsn_t);
+
+/*
+ * SCSI framework routines.
+ */
+int smrt_ctrl_hba_setup(smrt_t *);
+void smrt_ctrl_hba_teardown(smrt_t *);
+
+int smrt_logvol_hba_setup(smrt_t *, dev_info_t *);
+void smrt_logvol_hba_teardown(smrt_t *, dev_info_t *);
+int smrt_phys_hba_setup(smrt_t *, dev_info_t *);
+void smrt_phys_hba_teardown(smrt_t *, dev_info_t *);
+
+void smrt_hba_complete(smrt_command_t *);
+
+void smrt_process_finishq(smrt_t *);
+void smrt_process_abortq(smrt_t *);
+
+/*
+ * Command block management.
+ */
+smrt_command_t *smrt_command_alloc(smrt_t *, smrt_command_type_t,
+ int);
+smrt_command_t *smrt_command_alloc_preinit(smrt_t *, size_t, int);
+int smrt_command_attach_internal(smrt_t *, smrt_command_t *, size_t,
+ int);
+void smrt_command_free(smrt_command_t *);
+smrt_command_t *smrt_lookup_inflight(smrt_t *, uint32_t);
+void smrt_command_reuse(smrt_command_t *);
+
+/*
+ * Device message construction routines.
+ */
+void smrt_write_lun_addr_phys(LUNAddr_t *, boolean_t, unsigned, unsigned);
+void smrt_write_controller_lun_addr(LUNAddr_t *);
+uint16_t smrt_lun_addr_to_bmic(PhysDevAddr_t *);
+void smrt_write_message_abort_one(smrt_command_t *, uint32_t);
+void smrt_write_message_abort_all(smrt_command_t *, LUNAddr_t *);
+void smrt_write_message_nop(smrt_command_t *, int);
+void smrt_write_message_event_notify(smrt_command_t *);
+
+/*
+ * Device management routines.
+ */
+int smrt_device_setup(smrt_t *);
+void smrt_device_teardown(smrt_t *);
+uint32_t smrt_get32(smrt_t *, offset_t);
+void smrt_put32(smrt_t *, offset_t, uint32_t);
+
+/*
+ * SATA related routines.
+ */
+int smrt_sata_determine_wwn(smrt_t *, PhysDevAddr_t *, uint64_t *, uint16_t);
+
+/*
+ * Asynchronous Event Notification
+ */
+int smrt_event_init(smrt_t *);
+void smrt_event_fini(smrt_t *);
+void smrt_event_complete(smrt_command_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMRT_H */
diff --git a/usr/src/uts/common/sys/scsi/adapters/smrt/smrt_ciss.h b/usr/src/uts/common/sys/scsi/adapters/smrt/smrt_ciss.h
new file mode 100644
index 0000000000..e1f1db68b3
--- /dev/null
+++ b/usr/src/uts/common/sys/scsi/adapters/smrt/smrt_ciss.h
@@ -0,0 +1,345 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
+ * Copyright (c) 2017, Joyent, Inc.
+ */
+
+#ifndef _SMRT_CISS_H
+#define _SMRT_CISS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Maximum number of Scatter/Gather List entries. These entries are statically
+ * allocated for all commands.
+ */
+#define CISS_MAXSGENTRIES 64
+
+/*
+ * If the controller advertises a value of 0 for the maximum S/G list length it
+ * supports, the specification states that we should assume a value of 31.
+ */
+#define CISS_SGCNT_FALLBACK 31
+
+/*
+ * The CDB field in the request block is fixed at 16 bytes in length. (See
+ * "3.2. Request Block" in the CISS specification.)
+ */
+#define CISS_CDBLEN 16
+
+/*
+ * Command Status Values. These are listed in "Table 2 Command Status" in "3.3
+ * Error Info" of the CISS specification.
+ */
+#define CISS_CMD_SUCCESS 0x00
+#define CISS_CMD_TARGET_STATUS 0x01
+#define CISS_CMD_DATA_UNDERRUN 0x02
+#define CISS_CMD_DATA_OVERRUN 0x03
+#define CISS_CMD_INVALID 0x04
+#define CISS_CMD_PROTOCOL_ERR 0x05
+#define CISS_CMD_HARDWARE_ERR 0x06
+#define CISS_CMD_CONNECTION_LOST 0x07
+#define CISS_CMD_ABORTED 0x08
+#define CISS_CMD_ABORT_FAILED 0x09
+#define CISS_CMD_UNSOLICITED_ABORT 0x0a
+#define CISS_CMD_TIMEOUT 0x0b
+#define CISS_CMD_UNABORTABLE 0x0c
+
+/*
+ * Request Transfer Directions, used in "RequestBlock.Type.Direction":
+ */
+#define CISS_XFER_NONE 0x00
+#define CISS_XFER_WRITE 0x01
+#define CISS_XFER_READ 0x02
+#define CISS_XFER_RSVD 0x03
+
+/*
+ * Request Attributes, used in "RequestBlock.Type.Attribute":
+ */
+#define CISS_ATTR_UNTAGGED 0x00
+#define CISS_ATTR_SIMPLE 0x04
+#define CISS_ATTR_HEADOFQUEUE 0x05
+#define CISS_ATTR_ORDERED 0x06
+
+/*
+ * Request Type, used in "RequestBlock.Type.Type":
+ */
+#define CISS_TYPE_CMD 0x00
+#define CISS_TYPE_MSG 0x01
+
+/*
+ * I2O Space Register Offsets
+ *
+ * The name "I2O", and these register offsets, appear to be amongst the last
+ * vestiges of a long-defunct attempt at standardising mainframe-style I/O
+ * channels in the Intel server space: the Intelligent Input/Output (I2O)
+ * Architecture Specification.
+ *
+ * The draft of version 1.5 of this specification, in section "4.2.1.5.1
+ * Extensions for PCI", suggests that the following are memory offsets into
+ * "the memory region specified by the first base address configuration
+ * register indicating memory space (offset 10h, 14h, and so forth)". These
+ * match up with the offsets of the first two BARs in a PCI configuration space
+ * type 0 header.
+ *
+ * The specification also calls out the Inbound Post List FIFO, write-only at
+ * offset 40h; the Outbound Post List FIFO, read-only at offset 44h; the
+ * Interrupt Status Register, at offset 30h; and the Interrupt Mask Register,
+ * at offset 34h.
+ *
+ * This ill-fated attempt to increase the proprietary complexity of (and
+ * presumably, thus, the gross margin on) computer systems is all but extinct.
+ * The transport layer of this storage controller is all that's left of their
+ * religion.
+ */
+#define CISS_I2O_INBOUND_DOORBELL 0x20
+#define CISS_I2O_INTERRUPT_STATUS 0x30
+#define CISS_I2O_INTERRUPT_MASK 0x34
+#define CISS_I2O_INBOUND_POST_Q 0x40
+#define CISS_I2O_OUTBOUND_POST_Q 0x44
+#define CISS_I2O_OUTBOUND_DOORBELL_STATUS 0x9c
+#define CISS_I2O_OUTBOUND_DOORBELL_CLEAR 0xa0
+#define CISS_I2O_SCRATCHPAD 0xb0
+#define CISS_I2O_CFGTBL_CFG_OFFSET 0xb4
+#define CISS_I2O_CFGTBL_MEM_OFFSET 0xb8
+
+/*
+ * Rather than make a lot of small mappings for each part of the address
+ * space we wish to access, we will make one large mapping. If more
+ * offsets are added to the I2O list above, this space should be extended
+ * appropriately.
+ */
+#define CISS_I2O_MAP_BASE 0x20
+#define CISS_I2O_MAP_LIMIT 0x100
+
+/*
+ * The Scratchpad Register (I2O_SCRATCHPAD) is not mentioned in the CISS
+ * specification. It serves at least two known functions:
+ * - Signalling controller readiness
+ * - Exposing a debugging code when the controller firmware locks up
+ */
+#define CISS_SCRATCHPAD_INITIALISED 0xffff0000
+
+/*
+ * Outbound Doorbell Register Values.
+ *
+ * These are read from the Outbound Doorbell Set/Status Register
+ * (CISS_I2O_OUTBOUND_DOORBELL_STATUS), but cleared by writing to the Clear
+ * Register (CISS_I2O_OUTBOUND_DOORBELL_CLEAR).
+ */
+#define CISS_ODR_BIT_INTERRUPT (1UL << 0)
+#define CISS_ODR_BIT_LOCKUP (1UL << 1)
+
+/*
+ * Inbound Doorbell Register Values.
+ *
+ * These are written to and read from the Inbound Doorbell Register
+ * (CISS_I2O_INBOUND_DOORBELL).
+ */
+#define CISS_IDR_BIT_CFGTBL_CHANGE (1UL << 0)
+
+/*
+ * Interrupt Mask Register Values.
+ *
+ * These are written to and read from the Interrupt Mask Register
+ * (CISS_I2O_INTERRUPT_MASK). Note that a 1 bit in this register masks or
+ * disables the interrupt in question; to enable the interrupt the bit must be
+ * set to 0.
+ */
+#define CISS_IMR_BIT_SIMPLE_INTR_DISABLE (1UL << 3)
+
+/*
+ * Interrupt Status Register Values.
+ *
+ * These are read from the Interrupt Status Register
+ * (CISS_I2O_INTERRUPT_STATUS).
+ */
+#define CISS_ISR_BIT_SIMPLE_INTR (1UL << 3)
+
+/*
+ * Transport Methods.
+ *
+ * These bit positions are used in the Configuration Table to detect controller
+ * support for a particular method, via "TransportSupport"; to request that the
+ * controller enable a particular method, via "TransportRequest"; and to detect
+ * whether the controller has acknowledged the request and enabled the desired
+ * method, via "TransportActive".
+ *
+ * See: "9.1 Configuration Table" in the CISS Specification.
+ */
+#define CISS_CFGTBL_READY_FOR_COMMANDS (1UL << 0)
+#define CISS_CFGTBL_XPORT_SIMPLE (1UL << 1)
+#define CISS_CFGTBL_XPORT_PERFORMANT (1UL << 2)
+#define CISS_CFGTBL_XPORT_MEMQ (1UL << 4)
+
+/*
+ * In the Simple Transport Method, when the appropriate interrupt status bit is
+ * set (CISS_ISR_BIT_SIMPLE_INTR), the Outbound Post Queue register is
+ * repeatedly read for notifications of the completion of commands previously
+ * submitted to the controller. These macros help break up the read value into
+ * its component fields: the tag number, and whether or not the command
+ * completed in error.
+ */
+#define CISS_OPQ_READ_TAG(x) ((x) >> 2)
+#define CISS_OPQ_READ_ERROR(x) ((x) & (1UL << 1))
+
+/*
+ * Physical devices that are reported may be marked as 'masked'. A masked device
+ * is one that the driver can see, but must not perform any I/O to.
+ */
+#define SMRT_CISS_MODE_MASKED 3
+
+/*
+ * The following packed structures are used to ease the manipulation of
+ * requests and responses from the controller.
+ */
+#pragma pack(1)
+
+typedef struct smrt_tag {
+ uint32_t reserved:1;
+ uint32_t error:1;
+ uint32_t tag_value:30;
+ uint32_t unused;
+} smrt_tag_t;
+
+typedef union SCSI3Addr {
+ struct {
+ uint8_t Dev;
+ uint8_t Bus:6;
+ uint8_t Mode:2;
+ } PeripDev;
+ struct {
+ uint8_t DevLSB;
+ uint8_t DevMSB:6;
+ uint8_t Mode:2;
+ } LogDev;
+ struct {
+ uint8_t Dev:5;
+ uint8_t Bus:3;
+ uint8_t Targ:6;
+ uint8_t Mode:2;
+ } LogUnit;
+} SCSI3Addr_t;
+
+typedef struct PhysDevAddr {
+ uint32_t TargetId:24;
+ uint32_t Bus:6;
+ uint32_t Mode:2;
+ SCSI3Addr_t Target[2];
+} PhysDevAddr_t;
+
+typedef struct LogDevAddr {
+ uint32_t VolId:30;
+ uint32_t Mode:2;
+ uint8_t reserved[4];
+} LogDevAddr_t;
+
+typedef union LUNAddr {
+ uint8_t LunAddrBytes[8];
+ SCSI3Addr_t SCSI3Lun[4];
+ PhysDevAddr_t PhysDev;
+ LogDevAddr_t LogDev;
+} LUNAddr_t;
+
+typedef struct CommandListHeader {
+ uint8_t ReplyQueue;
+ uint8_t SGList;
+ uint16_t SGTotal;
+ smrt_tag_t Tag;
+ LUNAddr_t LUN;
+} CommandListHeader_t;
+
+typedef struct RequestBlock {
+ uint8_t CDBLen;
+ struct {
+ uint8_t Type:3;
+ uint8_t Attribute:3;
+ uint8_t Direction:2;
+ } Type;
+ uint16_t Timeout;
+ uint8_t CDB[CISS_CDBLEN];
+} RequestBlock_t;
+
+typedef struct ErrDescriptor {
+ uint64_t Addr;
+ uint32_t Len;
+} ErrDescriptor_t;
+
+typedef struct SGDescriptor {
+ uint64_t Addr;
+ uint32_t Len;
+ uint32_t Ext;
+} SGDescriptor_t;
+
+typedef struct CommandList {
+ CommandListHeader_t Header;
+ RequestBlock_t Request;
+ ErrDescriptor_t ErrDesc;
+ SGDescriptor_t SG[CISS_MAXSGENTRIES];
+} CommandList_t;
+
+typedef union MoreErrInfo {
+ struct {
+ uint8_t Reserved[3];
+ uint8_t Type;
+ uint32_t ErrorInfo;
+ } Common_Info;
+ struct {
+ uint8_t Reserved[2];
+ uint8_t offense_size;
+ uint8_t offense_num;
+ uint32_t offense_value;
+ } Invalid_Cmd;
+} MoreErrInfo_t;
+
+typedef struct ErrorInfo {
+ uint8_t ScsiStatus;
+ uint8_t SenseLen;
+ uint16_t CommandStatus;
+ uint32_t ResidualCnt;
+ MoreErrInfo_t MoreErrInfo;
+ uint8_t SenseInfo[MAX_SENSE_LENGTH];
+} ErrorInfo_t;
+
+typedef struct CfgTable {
+ uint8_t Signature[4];
+ uint32_t SpecValence;
+ uint32_t TransportSupport;
+ uint32_t TransportActive;
+ uint32_t TransportRequest;
+ uint32_t Upper32Addr;
+ uint32_t CoalIntDelay;
+ uint32_t CoalIntCount;
+ uint32_t CmdsOutMax;
+ uint32_t BusTypes;
+ uint32_t TransportMethodOffset;
+ uint8_t ServerName[16];
+ uint32_t HeartBeat;
+ uint32_t HostDrvrSupport;
+ uint32_t MaxSGElements;
+ uint32_t MaxLunSupport;
+ uint32_t MaxPhyDevSupport;
+ uint32_t MaxPhyDrvPerLun;
+ uint32_t MaxPerfModeCmdsOutMax;
+ uint32_t MaxBlockFetchCount;
+} CfgTable_t;
+
+#pragma pack()
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMRT_CISS_H */
diff --git a/usr/src/uts/common/sys/scsi/adapters/smrt/smrt_scsi.h b/usr/src/uts/common/sys/scsi/adapters/smrt/smrt_scsi.h
new file mode 100644
index 0000000000..45c4c84407
--- /dev/null
+++ b/usr/src/uts/common/sys/scsi/adapters/smrt/smrt_scsi.h
@@ -0,0 +1,371 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
+ * Copyright (c) 2017 Joyent, Inc.
+ */
+
+#ifndef _SMRT_SCSI_H
+#define _SMRT_SCSI_H
+
+#include <sys/types.h>
+
+#include <sys/scsi/adapters/smrt/smrt_ciss.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* CISS LUN Addressing MODEs */
+#define PERIPHERIAL_DEV_ADDR 0x0
+#define LOGICAL_VOL_ADDR 0x1
+#define MASK_PERIPHERIAL_DEV_ADDR 0x3
+#define CISS_PHYS_MODE 0x0
+
+/*
+ * Vendor-specific SCSI Commands
+ *
+ * These command opcodes are for use in the opcode byte of the CDB in a request
+ * of type CISS_TYPE_CMD. They are custom SCSI commands, using the
+ * vendor-specific part of the opcode space; i.e., 0xC0 through 0xFF.
+ */
+#define CISS_SCMD_READ 0xC0
+#define CISS_SCMD_WRITE 0xC1
+#define CISS_SCMD_REPORT_LOGICAL_LUNS 0xC2
+#define CISS_SCMD_REPORT_PHYSICAL_LUNS 0xC3
+
+/*
+ * These command opcodes are _not_ in the usual vendor-specific space, but are
+ * nonetheless vendor-specific. They allow BMIC commands to be written to and
+ * read from the controller. If a command transfers no data, the specification
+ * suggests that BMIC_WRITE (0x27) is appropriate.
+ */
+#define CISS_SCMD_BMIC_READ 0x26
+#define CISS_SCMD_BMIC_WRITE 0x27
+
+/*
+ * CISS Messages
+ *
+ * The CISS specification describes several directives that do not behave like
+ * SCSI commands. They are sent in requests of type CISS_TYPE_MSG.
+ *
+ * The Abort, Reset, and Nop, messages are defined in "8. Messages" in the CISS
+ * Specification.
+ */
+#define CISS_MSG_ABORT 0x0
+#define CISS_ABORT_TASK 0x0
+#define CISS_ABORT_TASKSET 0x1
+
+#define CISS_MSG_RESET 0x1
+#define CISS_RESET_CTLR 0x0
+#define CISS_RESET_BUS 0x1
+#define CISS_RESET_TGT 0x3
+#define CISS_RESET_LUN 0x4
+
+#define CISS_MSG_NOP 0x3
+
+/*
+ * BMIC Commands
+ *
+ * These commands allow for the use of non-standard facilities specific to the
+ * Smart Array firmware. They are sent to the controller through a specially
+ * constructed CDB with the CISS_SCMD_BMIC_READ or CISS_SCMD_BMIC_WRITE opcode.
+ */
+#define CISS_BMIC_IDENTIFY_CONTROLLER 0x11
+#define CISS_BMIC_IDENTIFY_PHYSICAL_DEVICE 0x15
+#define CISS_BMIC_NOTIFY_ON_EVENT 0xD0
+#define CISS_BMIC_NOTIFY_ON_EVENT_CANCEL 0xD1
+
+/*
+ * Device and Phy type codes. These are used across many commands, including
+ * IDENTIFY PHYSICAL DEVICE and the REPORT PHYSICAL LUN extended reporting.
+ */
+#define SMRT_DTYPE_PSCSI 0x00
+#define SMRT_DTYPE_SATA 0x01
+#define SMRT_DTYPE_SAS 0x02
+#define SMRT_DTYPE_SATA_BW 0x03
+#define SMRT_DTYPE_SAS_BW 0x04
+#define SMRT_DTYPE_EXPANDER 0x05
+#define SMRT_DTYPE_SES 0x06
+#define SMRT_DTYPE_CONTROLLER 0x07
+#define SMRT_DTYPE_SGPIO 0x08
+#define SMRT_DTYPE_NVME 0x09
+#define SMRT_DTYPE_NOPHY 0xFF
+
+/*
+ * The following packed structures are used to ease the manipulation of SCSI
+ * and BMIC commands sent to, and status information returned from, the
+ * controller.
+ */
+#pragma pack(1)
+
+typedef struct smrt_report_logical_lun_ent {
+ LogDevAddr_t smrle_addr;
+} smrt_report_logical_lun_ent_t;
+
+typedef struct smrt_report_logical_lun_extent {
+ LogDevAddr_t smrle_addr;
+ uint8_t smrle_wwn[16];
+} smrt_report_logical_lun_extent_t;
+
+typedef struct smrt_report_logical_lun {
+ uint32_t smrll_datasize; /* Big Endian */
+ uint8_t smrll_extflag;
+ uint8_t smrll_reserved1[3];
+ union {
+ smrt_report_logical_lun_ent_t ents[SMRT_MAX_LOGDRV];
+ smrt_report_logical_lun_extent_t extents[SMRT_MAX_LOGDRV];
+ } smrll_data;
+} smrt_report_logical_lun_t;
+
+typedef struct smrt_report_logical_lun_req {
+ uint8_t smrllr_opcode;
+ uint8_t smrllr_extflag;
+ uint8_t smrllr_reserved1[4];
+ uint32_t smrllr_datasize; /* Big Endian */
+ uint8_t smrllr_reserved2;
+ uint8_t smrllr_control;
+} smrt_report_logical_lun_req_t;
+
+typedef struct smrt_report_physical_lun_ent {
+ PhysDevAddr_t srple_addr;
+} smrt_report_physical_lun_ent_t;
+
+/*
+ * This structure represents the 'physical node identifier' extended option for
+ * REPORT PHYSICAL LUNS. This is triggered when the extended flags is set to
+ * 0x1. Note that for SAS the other structure should always be used.
+ */
+typedef struct smrt_report_physical_pnid {
+ uint8_t srpp_node[8];
+ uint8_t srpp_port[8];
+} smrt_report_physical_pnid_t;
+
+/*
+ * This structure represents the 'other physical device info' extended option
+ * for report physical luns. This is triggered when the extended flags is set
+ * to 0x2.
+ */
+typedef struct smrt_report_physical_opdi {
+ uint8_t srpo_wwid[8];
+ uint8_t srpo_dtype;
+ uint8_t srpo_flags;
+ uint8_t srpo_multilun;
+ uint8_t srpo_paths;
+ uint32_t srpo_iohdl;
+} smrt_report_physical_opdi_t;
+
+typedef struct smrt_report_physical_lun_extent {
+ PhysDevAddr_t srple_addr;
+ union {
+ smrt_report_physical_pnid_t srple_pnid;
+ smrt_report_physical_opdi_t srple_opdi;
+ } srple_extdata;
+} smrt_report_physical_lun_extent_t;
+
+/*
+ * Values that can be ORed together into smrllr_extflag. smprl_extflag indicates
+ * if any extended processing was done or not.
+ */
+#define SMRT_REPORT_PHYSICAL_LUN_EXT_NONE 0x00
+#define SMRT_REPORT_PHYSICAL_LUN_EXT_PNID 0x01
+#define SMRT_REPORT_PHYSICAL_LUN_EXT_OPDI 0x02
+#define SMRT_REPORT_PHYSICAL_LUN_EXT_MASK 0x0f
+#define SMRT_REPORT_PHYSICAL_LUN_CTRL_ONLY (1 << 6)
+#define SMRT_REPORT_PHYSICAL_LUN_ALL_PATHS (1 << 7)
+
+typedef struct smrt_report_physical_lun {
+ uint32_t smrpl_datasize; /* Big Endian */
+ uint8_t smrpl_extflag;
+ uint8_t smrpl_reserved1[3];
+ union {
+ smrt_report_physical_lun_ent_t ents[SMRT_MAX_PHYSDEV];
+ smrt_report_physical_lun_extent_t extents[SMRT_MAX_PHYSDEV];
+ } smrpl_data;
+} smrt_report_physical_lun_t;
+
+
+typedef struct smrt_report_physical_lun_req {
+ uint8_t smrplr_opcode;
+ uint8_t smrplr_extflag;
+ uint8_t smrplr_reserved[1];
+ uint32_t smrplr_datasize; /* Big Endian */
+ uint8_t smrplr_reserved2;
+ uint8_t smrplr_control;
+} smrt_report_physical_lun_req_t;
+
+/*
+ * Request structure for the BMIC command IDENTIFY CONTROLLER. This structure
+ * is written into the CDB with the CISS_SCMD_BMIC_READ SCSI opcode. Reserved
+ * fields should be filled with zeroes.
+ */
+typedef struct smrt_identify_controller_req {
+ uint8_t smicr_opcode;
+ uint8_t smicr_lun;
+ uint8_t smicr_reserved1[4];
+ uint8_t smicr_command;
+ uint8_t smicr_reserved2[2];
+ uint8_t smicr_reserved3[1];
+ uint8_t smicr_reserved4[6];
+} smrt_identify_controller_req_t;
+
+/*
+ * Response structure for IDENTIFY CONTROLLER. This structure is used to
+ * interpret the response the controller will write into the data buffer.
+ */
+typedef struct smrt_identify_controller {
+ uint8_t smic_logical_drive_count;
+ uint32_t smic_config_signature;
+ uint8_t smic_firmware_rev[4];
+ uint8_t smic_recovery_rev[4];
+ uint8_t smic_hardware_version;
+ uint8_t smic_bootblock_rev[4];
+
+ /*
+ * These are obsolete for SAS controllers:
+ */
+ uint32_t smic_drive_present_map;
+ uint32_t smic_external_drive_map;
+
+ uint32_t smic_board_id;
+} smrt_identify_controller_t;
+
+/*
+ * Request structure for IDENTIFY PHYSICAL DEVICE. This structure is written
+ * into the CDB with the CISS_SCMD_BMIC_READ SCSI opcode. Reserved fields
+ * should be filled with zeroes. Note, the lower 8 bits of the BMIC ID are in
+ * index1, whereas the upper 8 bites are in index2; however, the controller may
+ * only support 8 bits worth of devices (and this driver does not support that
+ * many devices).
+ */
+typedef struct smrt_identify_physical_drive_req {
+ uint8_t sipdr_opcode;
+ uint8_t sipdr_lun;
+ uint8_t sipdr_bmic_index1;
+ uint8_t sipdr_reserved1[3];
+ uint8_t sipdr_command;
+ uint8_t sipdr_reserved2[2];
+ uint8_t sipdr_bmic_index2;
+ uint8_t sipdr_reserved4[6];
+} smrt_identify_physical_drive_req_t;
+
+/*
+ * Relevant values for the sipd_more_flags member.
+ */
+#define SMRT_MORE_FLAGS_LOGVOL (1 << 5)
+#define SMRT_MORE_FLAGS_SPARE (1 << 6)
+
+/*
+ * Response structure for IDENTIFY PHYSICAL DEVICE. This structure is used to
+ * describe aspects of a physical drive. Note, not all fields are valid in all
+ * firmware revisions.
+ */
+typedef struct smrt_identify_physical_drive {
+ uint8_t sipd_scsi_bus; /* Invalid for SAS */
+ uint8_t sipd_scsi_id; /* Invalid for SAS */
+ uint16_t sipd_lblk_size;
+ uint32_t sipd_nblocks;
+ uint32_t sipd_rsrvd_blocsk;
+ uint8_t sipd_model[40];
+ uint8_t sipd_serial[40];
+ uint8_t sipd_firmware[8];
+ uint8_t sipd_scsi_inquiry;
+ uint8_t sipd_compaq_stamp;
+ uint8_t sipd_last_failure;
+ uint8_t sipd_flags;
+ uint8_t sipd_more_flags;
+ uint8_t sipd_scsi_lun; /* Invalid for SAS */
+ uint8_t sipd_yet_more_flags;
+ uint8_t sipd_even_more_flags;
+ uint32_t sipd_spi_speed_rules;
+ uint8_t sipd_phys_connector[2];
+ uint8_t sipd_phys_box_on_bus;
+ uint8_t sipd_phys_bay_in_box;
+ uint32_t sipd_rpm;
+ uint8_t sipd_device_type;
+ uint8_t sipd_sata_version;
+ uint64_t sipd_big_nblocks;
+ uint64_t sipd_ris_slba;
+ uint32_t sipd_ris_size;
+ uint8_t sipd_wwid[20];
+ uint8_t sipd_controller_phy_map[32];
+ uint16_t sipd_phy_count;
+ uint8_t sipd_phy_connected_dev_type[256];
+ uint8_t sipd_phy_to_drive_bay[256];
+ uint16_t sipd_phy_to_attached_dev[256];
+ uint8_t sipd_box_index;
+ uint8_t sipd_drive_support;
+ uint16_t sipd_extra_flags;
+ uint8_t sipd_neogiated_link_rate[256];
+ uint8_t sipd_phy_to_phy_map[256];
+ uint8_t sipd_pad[312];
+} smrt_identify_physical_drive_t;
+
+/*
+ * Note that this structure describes the CISS version of the command. There
+ * also exists a BMIC version, but it has a slightly different structure. This
+ * structure is also used for the cancellation request; however, in that case,
+ * the senr_flags field is reserved.
+ */
+typedef struct smrt_event_notify_req {
+ uint8_t senr_opcode;
+ uint8_t senr_subcode;
+ uint8_t senr_reserved1[2];
+ uint32_t senr_flags; /* Big Endian */
+ uint32_t senr_size; /* Big Endian */
+ uint8_t senr_control;
+} smrt_event_notify_req_t;
+
+/*
+ * When receiving event notifications, the buffer size must be 512 bytes large.
+ * We make sure that we always allocate a buffer of this size, even though we
+ * define a structure that is much shorter and only uses the fields that we end
+ * up caring about. This size requirement comes from the specification.
+ */
+#define SMRT_EVENT_NOTIFY_BUFLEN 512
+
+#define SMRT_EVENT_CLASS_PROTOCOL 0
+#define SMRT_EVENT_PROTOCOL_SUBCLASS_ERROR 1
+
+#define SMRT_EVENT_CLASS_HOTPLUG 1
+#define SMRT_EVENT_HOTPLUG_SUBCLASS_DRIVE 0
+
+#define SMRT_EVENT_CLASS_HWERROR 2
+#define SMRT_EVENT_CLASS_ENVIRONMENT 3
+
+#define SMRT_EVENT_CLASS_PHYS 4
+#define SMRT_EVENT_PHYS_SUBCLASS_STATE 0
+
+#define SMRT_EVENT_CLASS_LOGVOL 5
+
+typedef struct smrt_event_notify {
+ uint32_t sen_timestamp;
+ uint16_t sen_class;
+ uint16_t sen_subclass;
+ uint16_t sen_detail;
+ uint8_t sen_data[64];
+ char sen_message[80];
+ uint32_t sen_tag;
+ uint16_t sen_date;
+ uint16_t sen_year;
+ uint32_t sen_time;
+ uint16_t sen_pre_power_time;
+ LUNAddr_t sen_addr;
+} smrt_event_notify_t;
+
+#pragma pack()
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMRT_SCSI_H */
diff --git a/usr/src/uts/common/sys/termios.h b/usr/src/uts/common/sys/termios.h
index 86ee3980c4..39106a14fc 100644
--- a/usr/src/uts/common/sys/termios.h
+++ b/usr/src/uts/common/sys/termios.h
@@ -478,7 +478,7 @@ struct ppsclockev32 {
/* pseudo-tty */
#define TIOCREMOTE (tIOC|30) /* remote input editing */
-#define TIOCSIGNAL (tIOC|31) /* pty: send signal to slave */
+#define TIOCSIGNAL (tIOC|31) /* pty: send signal to subsidiary */
/* Some more 386 xenix stuff */
diff --git a/usr/src/uts/common/sys/ucode.h b/usr/src/uts/common/sys/ucode.h
index 50db604b48..c770f14419 100644
--- a/usr/src/uts/common/sys/ucode.h
+++ b/usr/src/uts/common/sys/ucode.h
@@ -23,6 +23,7 @@
* Use is subject to license terms.
*
* Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2022 Joyent, Inc.
*/
#ifndef _SYS_UCODE_H
@@ -199,7 +200,7 @@ typedef union ucode_file {
#define UCODE_DEFAULT_BODY_SIZE (UCODE_KB(2) - UCODE_HEADER_SIZE_INTEL)
/*
- * For a single microcode file, the minimum size is 1K, maximum size is 280K.
+ * For a single microcode file, the minimum size is 1K, maximum size is 384K.
* Such limitations, while somewhat artificial, are not only to provide better
* sanity checks, but also avoid wasting precious memory at startup time as the
* microcode buffer for the first processor has to be statically allocated.
@@ -208,7 +209,7 @@ typedef union ucode_file {
* is 16M.
*/
#define UCODE_MIN_SIZE UCODE_KB(1)
-#define UCODE_MAX_SIZE UCODE_KB(280)
+#define UCODE_MAX_SIZE UCODE_KB(384)
#define UCODE_MAX_COMBINED_SIZE UCODE_MB(16)
#define UCODE_SIZE_CONVERT(size, default_size) \
diff --git a/usr/src/uts/common/sys/usb/clients/hid/hidminor.h b/usr/src/uts/common/sys/usb/clients/hid/hidminor.h
index c96f914a70..f1b209faad 100644
--- a/usr/src/uts/common/sys/usb/clients/hid/hidminor.h
+++ b/usr/src/uts/common/sys/usb/clients/hid/hidminor.h
@@ -20,7 +20,7 @@
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright 2017 Joyent, Inc.
*/
#ifndef _SYS_USB_HIDMINOR_H
@@ -44,21 +44,28 @@ extern "C" {
* transparent.
*
* So we change minor node numbering scheme to be:
- * external node minor num == instance << 1
- * internal node minor num == instance << 1 | 0x1
+ * external node minor num == instance << 9
+ * internal node minor num == instance << 9 | 0x100
* (There are only internal nodes for keyboard/mouse now.)
+ *
+ * The 8 bits of the LSB are used for ugen minor numbering (hence the use
+ * of the first bit of the next byte for the "internal" flag)
*/
-#define HID_MINOR_BITS_MASK 0x1
+#define HID_MINOR_BITS_MASK 0x1ff
+#define HID_MINOR_UGEN_BITS_MASK 0xff
#define HID_MINOR_INSTANCE_MASK ~HID_MINOR_BITS_MASK
-#define HID_MINOR_INSTANCE_SHIFT 1
+#define HID_MINOR_INSTANCE_SHIFT 9
-#define HID_MINOR_INTERNAL 0x1
+#define HID_MINOR_INTERNAL 0x100
#define HID_MINOR_MAKE_INTERNAL(minor) \
((minor) | HID_MINOR_INTERNAL)
#define HID_IS_INTERNAL_OPEN(minor) \
(((minor) & HID_MINOR_INTERNAL))
+#define HID_IS_UGEN_OPEN(minor) \
+ (((minor) & HID_MINOR_UGEN_BITS_MASK))
+
#define HID_MINOR_TO_INSTANCE(minor) \
(((minor) & HID_MINOR_INSTANCE_MASK) >> \
HID_MINOR_INSTANCE_SHIFT)
diff --git a/usr/src/uts/common/sys/usb/clients/hid/hidvar.h b/usr/src/uts/common/sys/usb/clients/hid/hidvar.h
index e9a25ea894..61ac49800a 100644
--- a/usr/src/uts/common/sys/usb/clients/hid/hidvar.h
+++ b/usr/src/uts/common/sys/usb/clients/hid/hidvar.h
@@ -21,7 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright 2017 Joyent, Inc.
*/
#ifndef _SYS_USB_HIDVAR_H
@@ -33,6 +33,7 @@ extern "C" {
#endif
#include <sys/usb/usba/usbai_private.h>
+#include <sys/usb/usba/usba_ugen.h>
/*
* HID : This header file contains the internal structures
@@ -83,10 +84,10 @@ extern "C" {
* If the hid descriptor is not valid, the following values are
* used.
*/
-#define USBKPSZ 8 /* keyboard packet size */
-#define USBMSSZ 3 /* mouse packet size */
-#define USB_KB_HID_DESCR_LENGTH 0x3f /* keyboard Report descr length */
-#define USB_MS_HID_DESCR_LENGTH 0x32 /* mouse Report descr length */
+#define USBKPSZ 8 /* keyboard packet size */
+#define USBMSSZ 3 /* mouse packet size */
+#define USB_KB_HID_DESCR_LENGTH 0x3f /* keyboard Report descr length */
+#define USB_MS_HID_DESCR_LENGTH 0x32 /* mouse Report descr length */
/*
* Flags for the default pipe.
@@ -118,12 +119,12 @@ extern "C" {
/* Attach/detach states */
#define HID_LOCK_INIT 0x01 /* Initial attach state */
-#define HID_MINOR_NODES 0x02 /* Set after minor node is created */
+#define HID_MINOR_NODES 0x02 /* Set after minor node is created */
/* HID Protocol Requests */
-#define SET_IDLE 0x0a /* bRequest value to set idle request */
-#define DURATION (0<<8) /* no. of repeat reports (HID 7.2.4) */
-#define SET_PROTOCOL 0x0b /* bRequest value for boot protocol */
+#define SET_IDLE 0x0a /* bRequest value to set idle request */
+#define DURATION (0<<8) /* no. of repeat reports (HID 7.2.4) */
+#define SET_PROTOCOL 0x0b /* bRequest value for boot protocol */
/* Hid PM scheme */
typedef enum {
@@ -222,6 +223,8 @@ typedef struct hid_state {
queue_t *hid_inuse_rq;
int hid_internal_flag; /* see below */
int hid_external_flag; /* see below */
+
+ usb_ugen_hdl_t hid_ugen_hdl; /* ugen support */
} hid_state_t;
/* warlock directives, stable data */
@@ -246,7 +249,7 @@ _NOTE(SCHEME_PROTECTS_DATA("stable data", usb_ep_descr))
* handle is used when the kernel is in the single thread mode
* so the field is tagged with this note.
*/
-_NOTE(SCHEME_PROTECTS_DATA("unique per call",
+_NOTE(SCHEME_PROTECTS_DATA("unique per call",
hid_state_t::hid_polled_console_info))
/*
@@ -313,7 +316,7 @@ _NOTE(SCHEME_PROTECTS_DATA("unique per call", hid_default_pipe_arg_t))
* Debug message Masks
*/
#define PRINT_MASK_ATTA 0x00000001
-#define PRINT_MASK_OPEN 0x00000002
+#define PRINT_MASK_OPEN 0x00000002
#define PRINT_MASK_CLOSE 0x00000004
#define PRINT_MASK_EVENTS 0x00000008
#define PRINT_MASK_PM 0x00000010
diff --git a/usr/src/uts/common/sys/zcons.h b/usr/src/uts/common/sys/zcons.h
index 218d1a67ad..84abdc12fb 100644
--- a/usr/src/uts/common/sys/zcons.h
+++ b/usr/src/uts/common/sys/zcons.h
@@ -33,19 +33,19 @@ extern "C" {
#endif
/*
- * Minor node name of the global zone side (often called the "master" side)
+ * Minor node name of the global zone side (often called the "manager" side)
* of the zcons driver.
*/
-#define ZCONS_MASTER_NAME "masterconsole"
+#define ZCONS_MANAGER_NAME "globalconsole"
/*
- * Minor node name of the non-global zone side (often called the "slave"
- * side) of the zcons driver. We name it "zoneconsole" since that nameo
+ * Minor node name of the non-global zone side (often called the "subsidiary"
+ * side) of the zcons driver. We name it "zoneconsole" since that name
* will show up in 'ps' output, and will make some sense to the global zone
* user. Inside the zone, it will simply show up as "console" due to the
* links we create.
*/
-#define ZCONS_SLAVE_NAME "zoneconsole"
+#define ZCONS_SUBSIDIARY_NAME "zoneconsole"
/*
* ZC_IOC forms the base for all zcons ioctls.
@@ -53,18 +53,18 @@ extern "C" {
#define ZC_IOC (('Z' << 24) | ('o' << 16) | ('n' << 8))
/*
- * These ioctls instruct the master side of the console to hold or release
- * a reference to the slave side's vnode. They are meant to be issued by
+ * These ioctls instruct the manager side of the console to hold or release
+ * a reference to the subsidiary side's vnode. They are meant to be issued by
* zoneadmd after the console device node is created and before it is destroyed
- * so that the slave's STREAMS anchor, ptem, is preserved when ttymon starts
- * popping STREAMS modules from within the associated zone. This guarantees
- * that the zone slave console will always have terminal semantics while the
- * zone is running.
+ * so that the subsidiary's STREAMS anchor, ptem, is preserved when ttymon
+ * starts popping STREAMS modules from within the associated zone. This
+ * guarantees that the zone subsidiary console will always have terminal
+ * semantics while the zone is running.
*
* A more detailed description can be found in uts/common/io/zcons.c.
*/
-#define ZC_HOLDSLAVE (ZC_IOC | 0) /* get and save slave side reference */
-#define ZC_RELEASESLAVE (ZC_IOC | 1) /* release slave side reference */
+#define ZC_HOLDSUBSID (ZC_IOC | 0)
+#define ZC_RELEASESUBSID (ZC_IOC | 1)
#ifdef __cplusplus
}
diff --git a/usr/src/uts/common/syscall/chmod.c b/usr/src/uts/common/syscall/chmod.c
index bed521f0b3..925219515b 100644
--- a/usr/src/uts/common/syscall/chmod.c
+++ b/usr/src/uts/common/syscall/chmod.c
@@ -24,7 +24,7 @@
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
#include <sys/param.h>
#include <sys/isa_defs.h>
@@ -55,9 +55,6 @@ fchmodat(int fd, char *path, int mode, int flag)
if (flag & ~AT_SYMLINK_NOFOLLOW)
return (set_errno(EINVAL));
- if (flag & AT_SYMLINK_NOFOLLOW)
- return (set_errno(EOPNOTSUPP));
-
vattr.va_mode = mode & MODEMASK;
vattr.va_mask = AT_MODE;
error = fsetattrat(fd, path, flag, &vattr);
diff --git a/usr/src/uts/common/syscall/poll.c b/usr/src/uts/common/syscall/poll.c
index ae34556f14..ea5285ad28 100644
--- a/usr/src/uts/common/syscall/poll.c
+++ b/usr/src/uts/common/syscall/poll.c
@@ -2814,9 +2814,12 @@ checkpolldat(pollstate_t *ps)
refp = &pdp->pd_ref[j];
if (refp->xf_refcnt > 0) {
pcsp = &ps->ps_pcacheset[j];
- ASSERT(refp->xf_position < pcsp->pcs_nfds);
+ ASSERT(refp->xf_position <
+ pcsp->pcs_nfds);
pollfd = pcsp->pcs_pollfd;
- ASSERT(pdp->pd_fd == pollfd[refp->xf_position].fd);
+ ASSERT(pdp->pd_fd ==
+ pollfd[refp->xf_position].
+ fd);
}
}
}
diff --git a/usr/src/uts/common/vm/page.h b/usr/src/uts/common/vm/page.h
index 5b98acd24f..b2f61429e9 100644
--- a/usr/src/uts/common/vm/page.h
+++ b/usr/src/uts/common/vm/page.h
@@ -635,7 +635,7 @@ typedef page_t devpage_t;
extern pad_mutex_t ph_mutex[];
#define PAGE_HASH_MUTEX(x) \
- &(ph_mutex[((x) ^ ((x) >> PH_SHIFT_SIZE) + ((x) << 3)) & \
+ &(ph_mutex[((x) ^ (((x) >> PH_SHIFT_SIZE) + ((x) << 3))) & \
(PH_TABLE_SIZE - 1)].pad_mutex)
/*
diff --git a/usr/src/uts/common/vm/page_retire.c b/usr/src/uts/common/vm/page_retire.c
index dcfb04e9fb..26def2eb27 100644
--- a/usr/src/uts/common/vm/page_retire.c
+++ b/usr/src/uts/common/vm/page_retire.c
@@ -603,7 +603,7 @@ page_clear_transient_ue(page_t *pp)
uint64_t pa;
uint32_t pa_hi, pa_lo;
on_trap_data_t otd;
- int errors = 0;
+ int errors;
int i;
ASSERT(PAGE_EXCL(pp));
@@ -647,6 +647,7 @@ page_clear_transient_ue(page_t *pp)
PR_MESSAGE(CE_WARN, 1, MSG_UE, pa);
errors = 1;
} else {
+ errors = 0;
for (wb = 0xff; wb > 0; wb--) {
for (i = 0; i < PAGESIZE; i++) {
kaddr[i] = wb;
diff --git a/usr/src/uts/common/vm/seg_kmem.c b/usr/src/uts/common/vm/seg_kmem.c
index 540f2b251b..0bab4eb76d 100644
--- a/usr/src/uts/common/vm/seg_kmem.c
+++ b/usr/src/uts/common/vm/seg_kmem.c
@@ -163,14 +163,14 @@ static segkmem_lpcb_t segkmem_lpcb;
* we allow for large page heap.
*/
size_t segkmem_kmemlp_max;
-static uint_t segkmem_kmemlp_pcnt;
+uint_t segkmem_kmemlp_pcnt;
/*
* Getting large pages for kernel heap could be problematic due to
* physical memory fragmentation. That's why we allow to preallocate
* "segkmem_kmemlp_min" bytes at boot time.
*/
-static size_t segkmem_kmemlp_min;
+size_t segkmem_kmemlp_min;
/*
* Throttling is used to avoid expensive tries to allocate large pages
diff --git a/usr/src/uts/common/vm/seg_map.c b/usr/src/uts/common/vm/seg_map.c
index f08afe1066..6c41b04344 100644
--- a/usr/src/uts/common/vm/seg_map.c
+++ b/usr/src/uts/common/vm/seg_map.c
@@ -333,7 +333,7 @@ segmap_create(struct seg *seg, void *argsp)
nfreelist = a->nfreelist;
if (nfreelist == 0)
nfreelist = max_ncpus;
- else if (nfreelist < 0 || nfreelist > 4 * max_ncpus) {
+ else if (nfreelist > 4 * max_ncpus) {
cmn_err(CE_WARN, "segmap_create: nfreelist out of range "
"%d, using %d", nfreelist, max_ncpus);
nfreelist = max_ncpus;
diff --git a/usr/src/uts/common/vm/vm_as.c b/usr/src/uts/common/vm/vm_as.c
index e4accd6fc8..e353692471 100644
--- a/usr/src/uts/common/vm/vm_as.c
+++ b/usr/src/uts/common/vm/vm_as.c
@@ -452,7 +452,6 @@ as_addseg(struct as *as, struct seg *newseg)
addr = newseg->s_base;
eaddr = addr + newseg->s_size;
-again:
seg = avl_find(&as->a_segtree, &addr, &where);
@@ -473,19 +472,6 @@ again:
*/
if (base + seg->s_size > addr) {
if (addr >= base || eaddr > base) {
-#ifdef __sparc
- extern struct seg_ops segnf_ops;
-
- /*
- * no-fault segs must disappear if overlaid.
- * XXX need new segment type so
- * we don't have to check s_ops
- */
- if (seg->s_ops == &segnf_ops) {
- seg_unmap(seg);
- goto again;
- }
-#endif
return (-1); /* overlapping segment */
}
}
diff --git a/usr/src/uts/common/vm/vm_page.c b/usr/src/uts/common/vm/vm_page.c
index d93400c343..131ee0ba1c 100644
--- a/usr/src/uts/common/vm/vm_page.c
+++ b/usr/src/uts/common/vm/vm_page.c
@@ -3654,7 +3654,7 @@ page_add_common(page_t **ppp, page_t *pp)
void
page_sub(page_t **ppp, page_t *pp)
{
- ASSERT((PP_ISFREE(pp)) ? 1 :
+ ASSERT(pp != NULL && (PP_ISFREE(pp)) ? 1 :
(PAGE_EXCL(pp)) || (PAGE_SHARED(pp) && page_iolock_assert(pp)));
if (*ppp == NULL || pp == NULL) {
diff --git a/usr/src/uts/common/vm/vm_pagelist.c b/usr/src/uts/common/vm/vm_pagelist.c
index 965d939ebc..394d9b97fb 100644
--- a/usr/src/uts/common/vm/vm_pagelist.c
+++ b/usr/src/uts/common/vm/vm_pagelist.c
@@ -1866,7 +1866,7 @@ mach_page_add(page_t **ppp, page_t *pp)
void
mach_page_sub(page_t **ppp, page_t *pp)
{
- ASSERT(PP_ISFREE(pp));
+ ASSERT(pp != NULL && PP_ISFREE(pp));
if (*ppp == NULL || pp == NULL)
panic("mach_page_sub");
@@ -2278,9 +2278,6 @@ page_freelist_coalesce(int mnode, uchar_t szc, uint_t color, uint_t ceq_mask,
pgcnt_t cands = 0, szcpgcnt = page_get_pagecnt(szc);
page_t *ret_pp;
MEM_NODE_ITERATOR_DECL(it);
-#if defined(__sparc)
- pfn_t pfnum0, nlo, nhi;
-#endif
if (mpss_coalesce_disable) {
ASSERT(szc < MMU_PAGE_SIZES);
@@ -2380,40 +2377,8 @@ page_freelist_coalesce(int mnode, uchar_t szc, uint_t color, uint_t ceq_mask,
idx0 = PNUM_TO_IDX(mnode, r, pfnum);
ASSERT(idx0 < len);
-#if defined(__sparc)
- pfnum0 = pfnum; /* page corresponding to idx0 */
- nhi = 0; /* search kcage ranges */
-#endif
-
for (idx = idx0; wrap == 0 || (idx < idx0 && wrap < 2); ) {
-#if defined(__sparc)
- /*
- * Find lowest intersection of kcage ranges and mnode.
- * MTYPE_NORELOC means look in the cage, otherwise outside.
- */
- if (nhi <= pfnum) {
- if (kcage_next_range(mtype == MTYPE_NORELOC, pfnum,
- (wrap == 0 ? hi : pfnum0), &nlo, &nhi))
- goto wrapit;
-
- /* jump to the next page in the range */
- if (pfnum < nlo) {
- pfnum = P2ROUNDUP(nlo, szcpgcnt);
- MEM_NODE_ITERATOR_INIT(pfnum, mnode, szc, &it);
- idx = PNUM_TO_IDX(mnode, r, pfnum);
- if (idx >= len || pfnum >= hi)
- goto wrapit;
- if ((PFN_2_COLOR(pfnum, szc, &it) ^ color) &
- ceq_mask)
- goto next;
- if (interleaved_mnodes &&
- PFN_2_MEM_NODE(pfnum) != mnode)
- goto next;
- }
- }
-#endif
-
if (PAGE_COUNTERS(mnode, r, idx) != full)
goto next;
@@ -2432,14 +2397,7 @@ page_freelist_coalesce(int mnode, uchar_t szc, uint_t color, uint_t ceq_mask,
PFN_2_COLOR(pfnum, szc, &it), mrange) = idx;
page_freelist_unlock(mnode);
rw_exit(&page_ctrs_rwlock[mnode]);
-#if defined(__sparc)
- if (PP_ISNORELOC(ret_pp)) {
- pgcnt_t npgs;
- npgs = page_get_pagecnt(ret_pp->p_szc);
- kcage_freemem_sub(npgs);
- }
-#endif
return (ret_pp);
}
} else {
@@ -2467,14 +2425,10 @@ next:
color_mask, &it);
idx = PNUM_TO_IDX(mnode, r, pfnum);
if (idx >= len || pfnum >= hi) {
-wrapit:
pfnum = lo;
MEM_NODE_ITERATOR_INIT(pfnum, mnode, szc, &it);
idx = PNUM_TO_IDX(mnode, r, pfnum);
wrap++;
-#if defined(__sparc)
- nhi = 0; /* search kcage ranges */
-#endif
}
}
diff --git a/usr/src/uts/i86pc/Makefile.files b/usr/src/uts/i86pc/Makefile.files
index 3f387f508c..e29d11b64b 100644
--- a/usr/src/uts/i86pc/Makefile.files
+++ b/usr/src/uts/i86pc/Makefile.files
@@ -25,7 +25,7 @@
# Copyright (c) 2010, Intel Corporation.
# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
# Copyright 2020 Joyent, Inc.
-# Copyright 2021 Oxide Computer Company
+# Copyright 2022 Oxide Computer Company
# Copyright 2021 Jason King
#
# This Makefile defines file modules in the directory uts/i86pc
@@ -287,6 +287,8 @@ VIONA_OBJS += viona_main.o \
PPT_OBJS += ppt.o
+PCI_PRD_OBJS += pci_prd_i86pc.o pci_memlist.o
+
#
# Build up defines and paths.
#
diff --git a/usr/src/uts/i86pc/Makefile.i86pc b/usr/src/uts/i86pc/Makefile.i86pc
index e803d33801..d23b092b0f 100644
--- a/usr/src/uts/i86pc/Makefile.i86pc
+++ b/usr/src/uts/i86pc/Makefile.i86pc
@@ -293,7 +293,7 @@ SYS_KMODS +=
#
# 'Misc' Modules (/kernel/misc):
#
-MISC_KMODS += gfx_private pcie
+MISC_KMODS += gfx_private pcie pci_prd
MISC_KMODS += acpidev
MISC_KMODS += drmach_acpi
diff --git a/usr/src/uts/i86pc/boot/boot_console.c b/usr/src/uts/i86pc/boot/boot_console.c
index cfd4da40d0..541d974d1a 100644
--- a/usr/src/uts/i86pc/boot/boot_console.c
+++ b/usr/src/uts/i86pc/boot/boot_console.c
@@ -1203,7 +1203,6 @@ bcons_post_bootenvrc(char *inputdev, char *outputdev, char *consoledev)
int cons = CONS_INVALID;
int ttyn;
char *devnames[] = { consoledev, outputdev, inputdev, NULL };
- console_value_t *consolep;
int i;
extern int post_fastreboot;
diff --git a/usr/src/uts/i86pc/dboot/dboot_startkern.c b/usr/src/uts/i86pc/dboot/dboot_startkern.c
index e6a1127941..6621356133 100644
--- a/usr/src/uts/i86pc/dboot/dboot_startkern.c
+++ b/usr/src/uts/i86pc/dboot/dboot_startkern.c
@@ -721,7 +721,6 @@ dboot_loader_mmap_get_type(int index)
{
#if !defined(__xpv)
mb_memory_map_t *mp, *mpend;
- caddr32_t mmap_addr;
int i;
switch (multiboot_version) {
@@ -1375,13 +1374,13 @@ fixup_modules(void)
return;
if (modules[0].bm_type != BMT_FILE ||
- modules_used > 1 && modules[1].bm_type != BMT_FILE) {
+ (modules_used > 1 && modules[1].bm_type != BMT_FILE)) {
return;
}
if (modules[0].bm_hash != (native_ptr_t)(uintptr_t)NULL ||
- modules_used > 1 &&
- modules[1].bm_hash != (native_ptr_t)(uintptr_t)NULL) {
+ (modules_used > 1 &&
+ modules[1].bm_hash != (native_ptr_t)(uintptr_t)NULL)) {
return;
}
diff --git a/usr/src/uts/i86pc/dboot/dboot_xboot.h b/usr/src/uts/i86pc/dboot/dboot_xboot.h
index 5c9af24325..7d0876c79c 100644
--- a/usr/src/uts/i86pc/dboot/dboot_xboot.h
+++ b/usr/src/uts/i86pc/dboot/dboot_xboot.h
@@ -27,8 +27,6 @@
#ifndef _DBOOT_XBOOT_H
#define _DBOOT_XBOOT_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/mach_mmu.h>
#ifdef __cplusplus
@@ -65,7 +63,7 @@ extern uint_t prom_debug;
extern void dboot_halt(void);
extern void *mem_alloc(uint32_t size);
-#define RNDUP(x, y) ((x) + ((y) - 1ul) & ~((y) - 1ul))
+#define RNDUP(x, y) (((x) + ((y) - 1ul)) & ~((y) - 1ul))
#endif /* _ASM */
diff --git a/usr/src/uts/i86pc/io/hrtimers.c b/usr/src/uts/i86pc/io/hrtimers.c
index 59f4b90842..d5e20e1a9e 100644
--- a/usr/src/uts/i86pc/io/hrtimers.c
+++ b/usr/src/uts/i86pc/io/hrtimers.c
@@ -28,8 +28,6 @@
* All rights reserved.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/param.h>
#include <sys/types.h>
#include <sys/sysmacros.h>
@@ -181,7 +179,7 @@ hrtalarm(uap, rvp)
struct itimerval itv;
u_int which;
- if (error = hrt_checkclock(cp->hrtc_clk))
+ if ((error = hrt_checkclock(cp->hrtc_clk)) != 0)
break;
switch (cp->hrtc_clk) {
case CLK_STD:
@@ -265,7 +263,7 @@ hrtalarm(uap, rvp)
break;
case HRT_BSD_CANCEL:
- if (error = hrt_checkclock(cp->hrtc_clk))
+ if ((error = hrt_checkclock(cp->hrtc_clk)) != 0)
break;
error = hrt_bsd_cancel(cp->hrtc_clk);
diff --git a/usr/src/uts/intel/io/pci/mps_table.h b/usr/src/uts/i86pc/io/pci/mps_table.h
index 8f8c1dc24e..df693eb091 100644
--- a/usr/src/uts/intel/io/pci/mps_table.h
+++ b/usr/src/uts/i86pc/io/pci/mps_table.h
@@ -29,8 +29,6 @@
#ifndef _MPS_TABLE_H
#define _MPS_TABLE_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -42,7 +40,7 @@ struct mps_fps_hdr { /* MP Floating Pointer Structure */
uchar_t fps_len; /* in paragraph (16-bytes units) */
uchar_t fps_spec_rev; /* MP Spec. version no. */
uchar_t fps_cksum; /* checksum of complete structure */
- uchar_t fps_featinfo1; /* mp feature info byte 1 */
+ uchar_t fps_featinfo1; /* mp feature info byte 1 */
uchar_t fps_featinfo2; /* mp feature info byte 2 */
uchar_t fps_featinfo3; /* mp feature info byte 3 */
uchar_t fps_featinfo4; /* mp feature info byte 4 */
@@ -51,7 +49,7 @@ struct mps_fps_hdr { /* MP Floating Pointer Structure */
struct mps_ct_hdr { /* MP Configuration Table Header */
uint32_t ct_sig; /* "PCMP" */
- uint16_t ct_len; /* base configuration in bytes */
+ uint16_t ct_len; /* base configuration in bytes */
uchar_t ct_spec_rev; /* MP Spec. version no. */
uchar_t ct_cksum; /* base configuration table checksum */
char ct_oem_id[8]; /* string identifies the manufacturer */
@@ -60,7 +58,7 @@ struct mps_ct_hdr { /* MP Configuration Table Header */
uint16_t ct_oem_tbl_len; /* size of base OEM table in bytes */
uint16_t ct_entry_cnt; /* no. of entries in the base table */
uint32_t ct_local_apic; /* paddr of local APIC */
- uint16_t ct_ext_tbl_len; /* extended table in bytes */
+ uint16_t ct_ext_tbl_len; /* extended table in bytes */
uchar_t ct_ext_cksum; /* checksum for the extended table */
};
diff --git a/usr/src/uts/intel/io/pci/pci_resource.c b/usr/src/uts/i86pc/io/pci/pci_prd_i86pc.c
index 57dbe12427..5ba872655c 100644
--- a/usr/src/uts/intel/io/pci/pci_resource.c
+++ b/usr/src/uts/i86pc/io/pci/pci_prd_i86pc.c
@@ -19,54 +19,63 @@
* CDDL HEADER END
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- *
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2016 Joyent, Inc.
+ * Copyright 2019 Western Digital Corporation
* Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2022 Oxide Computer Company
+ */
+
+/*
+ * This file contains the x86 PCI platform resource discovery backend. This uses
+ * data from a combination of sources, preferring ACPI, if present, and if not,
+ * falling back to either the PCI hot-plug resource table or the mps tables.
*
- * pci_resource.c -- routines to retrieve available bus resources from
- * the MP Spec. Table and Hotplug Resource Table
+ * Today, to get information from ACPI we need to start from a dev_info_t. This
+ * is partly why the PRD interface has a callback for getting information about
+ * a dev_info_t. It also means we cannot initialize the tables with information
+ * until all devices have been initially scanned.
*/
#include <sys/types.h>
#include <sys/memlist.h>
+#include <sys/pci.h>
#include <sys/pci_impl.h>
+#include <sys/pci_cfgspace_impl.h>
+#include <sys/sunndi.h>
#include <sys/systm.h>
#include <sys/cmn_err.h>
#include <sys/acpi/acpi.h>
#include <sys/acpica.h>
+#include <sys/plat/pci_prd.h>
#include "mps_table.h"
#include "pcihrt.h"
-extern int pci_boot_debug;
extern int pci_bios_maxbus;
-#define dprintf if (pci_boot_debug) printf
+
+int pci_prd_debug = 0;
+#define dprintf if (pci_prd_debug) printf
+#define dcmn_err if (pci_prd_debug != 0) cmn_err
static int tbl_init = 0;
static uchar_t *mps_extp = NULL;
static uchar_t *mps_ext_endp = NULL;
static struct php_entry *hrt_hpep;
-static int hrt_entry_cnt = 0;
+static uint_t hrt_entry_cnt = 0;
static int acpi_cb_cnt = 0;
+static pci_prd_upcalls_t *prd_upcalls;
static void mps_probe(void);
static void acpi_pci_probe(void);
-static int mps_find_bus_res(int, int, struct memlist **);
+static int mps_find_bus_res(uint32_t, pci_prd_rsrc_t, struct memlist **);
static void hrt_probe(void);
-static int hrt_find_bus_res(int, int, struct memlist **);
-static int acpi_find_bus_res(int, int, struct memlist **);
+static int hrt_find_bus_res(uint32_t, pci_prd_rsrc_t, struct memlist **);
+static int acpi_find_bus_res(uint32_t, pci_prd_rsrc_t, struct memlist **);
static uchar_t *find_sig(uchar_t *cp, int len, char *sig);
static int checksum(unsigned char *cp, int len);
static ACPI_STATUS acpi_wr_cb(ACPI_RESOURCE *rp, void *context);
-void bus_res_fini(void);
static void acpi_trim_bus_ranges(void);
-struct memlist *acpi_io_res[256];
-struct memlist *acpi_mem_res[256];
-struct memlist *acpi_pmem_res[256];
-struct memlist *acpi_bus_res[256];
-
/*
* -1 = attempt ACPI resource discovery
* 0 = don't attempt ACPI resource discovery
@@ -74,53 +83,35 @@ struct memlist *acpi_bus_res[256];
*/
volatile int acpi_resource_discovery = -1;
-struct memlist *
-find_bus_res(int bus, int type)
-{
- struct memlist *res = NULL;
- boolean_t bios = B_TRUE;
-
- /* if efi-systab property exist, there is no BIOS */
- if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS,
- "efi-systab")) {
- bios = B_FALSE;
- }
-
- if (tbl_init == 0) {
- tbl_init = 1;
- acpi_pci_probe();
- if (bios) {
- hrt_probe();
- mps_probe();
- }
- }
-
- if (acpi_find_bus_res(bus, type, &res) > 0)
- return (res);
-
- if (bios && hrt_find_bus_res(bus, type, &res) > 0)
- return (res);
+struct memlist *acpi_io_res[PCI_MAX_BUS_NUM];
+struct memlist *acpi_mem_res[PCI_MAX_BUS_NUM];
+struct memlist *acpi_pmem_res[PCI_MAX_BUS_NUM];
+struct memlist *acpi_bus_res[PCI_MAX_BUS_NUM];
- if (bios)
- (void) mps_find_bus_res(bus, type, &res);
- return (res);
-}
+/*
+ * This indicates whether or not we have a traditional x86 BIOS present or not.
+ */
+static boolean_t pci_prd_have_bios = B_TRUE;
+/*
+ * This value is set up as part of PCI configuration space initialization.
+ */
+extern int pci_bios_maxbus;
static void
acpi_pci_probe(void)
{
ACPI_HANDLE ah;
- dev_info_t *dip;
int bus;
if (acpi_resource_discovery == 0)
return;
for (bus = 0; bus <= pci_bios_maxbus; bus++) {
- /* if no dip or no ACPI handle, no resources to discover */
- dip = pci_bus_res[bus].dip;
- if ((dip == NULL) ||
+ dev_info_t *dip;
+
+ dip = prd_upcalls->pru_bus2dip_f(bus);
+ if (dip == NULL ||
(ACPI_FAILURE(acpica_get_handle(dip, &ah))))
continue;
@@ -142,7 +133,7 @@ acpi_pci_probe(void)
* be trimmed to "0..7", in the example).
*/
static void
-acpi_trim_bus_ranges()
+acpi_trim_bus_ranges(void)
{
struct memlist *ranges, *current;
int bus;
@@ -154,7 +145,7 @@ acpi_trim_bus_ranges()
* - there exists at most 1 bus range entry for each bus number
* - there are no (broken) ranges that start at the same bus number
*/
- for (bus = 0; bus < 256; bus++) {
+ for (bus = 0; bus < PCI_MAX_BUS_NUM; bus++) {
struct memlist *prev, *orig, *new;
/* skip buses with no range entry */
if ((orig = acpi_bus_res[bus]) == NULL)
@@ -211,20 +202,21 @@ acpi_trim_bus_ranges()
}
static int
-acpi_find_bus_res(int bus, int type, struct memlist **res)
+acpi_find_bus_res(uint32_t bus, pci_prd_rsrc_t type, struct memlist **res)
{
+ ASSERT3U(bus, <, PCI_MAX_BUS_NUM);
switch (type) {
- case IO_TYPE:
+ case PCI_PRD_R_IO:
*res = acpi_io_res[bus];
break;
- case MEM_TYPE:
+ case PCI_PRD_R_MMIO:
*res = acpi_mem_res[bus];
break;
- case PREFETCH_TYPE:
+ case PCI_PRD_R_PREFETCH:
*res = acpi_pmem_res[bus];
break;
- case BUSRANGE_TYPE:
+ case PCI_PRD_R_BUS:
*res = acpi_bus_res[bus];
break;
default:
@@ -236,19 +228,6 @@ acpi_find_bus_res(int bus, int type, struct memlist **res)
return (memlist_count(*res));
}
-void
-bus_res_fini(void)
-{
- int bus;
-
- for (bus = 0; bus <= pci_bios_maxbus; bus++) {
- memlist_free_all(&acpi_io_res[bus]);
- memlist_free_all(&acpi_mem_res[bus]);
- memlist_free_all(&acpi_pmem_res[bus]);
- memlist_free_all(&acpi_bus_res[bus]);
- }
-}
-
static struct memlist **
rlistpp(UINT8 t, UINT8 caching, int bus)
{
@@ -298,7 +277,7 @@ acpi_dbg(uint_t bus, uint64_t addr, uint64_t len, uint8_t caching, uint8_t type,
}
-ACPI_STATUS
+static ACPI_STATUS
acpi_wr_cb(ACPI_RESOURCE *rp, void *context)
{
int bus = (intptr_t)context;
@@ -332,7 +311,7 @@ acpi_wr_cb(ACPI_RESOURCE *rp, void *context)
acpi_cb_cnt++;
memlist_insert(&acpi_io_res[bus], rp->Data.Io.Minimum,
rp->Data.Io.AddressLength);
- if (pci_boot_debug != 0) {
+ if (pci_prd_debug != 0) {
acpi_dbg(bus, rp->Data.Io.Minimum,
rp->Data.Io.AddressLength, 0, ACPI_IO_RANGE, "IO");
}
@@ -374,7 +353,7 @@ acpi_wr_cb(ACPI_RESOURCE *rp, void *context)
rp->Data.Address.Info.Mem.Caching, bus),
rp->Data.Address16.Address.Minimum,
rp->Data.Address16.Address.AddressLength);
- if (pci_boot_debug != 0) {
+ if (pci_prd_debug != 0) {
acpi_dbg(bus,
rp->Data.Address16.Address.Minimum,
rp->Data.Address16.Address.AddressLength,
@@ -391,7 +370,7 @@ acpi_wr_cb(ACPI_RESOURCE *rp, void *context)
rp->Data.Address.Info.Mem.Caching, bus),
rp->Data.Address32.Address.Minimum,
rp->Data.Address32.Address.AddressLength);
- if (pci_boot_debug != 0) {
+ if (pci_prd_debug != 0) {
acpi_dbg(bus,
rp->Data.Address32.Address.Minimum,
rp->Data.Address32.Address.AddressLength,
@@ -409,7 +388,7 @@ acpi_wr_cb(ACPI_RESOURCE *rp, void *context)
rp->Data.Address.Info.Mem.Caching, bus),
rp->Data.Address64.Address.Minimum,
rp->Data.Address64.Address.AddressLength);
- if (pci_boot_debug != 0) {
+ if (pci_prd_debug != 0) {
acpi_dbg(bus,
rp->Data.Address64.Address.Minimum,
rp->Data.Address64.Address.AddressLength,
@@ -426,7 +405,7 @@ acpi_wr_cb(ACPI_RESOURCE *rp, void *context)
rp->Data.Address.Info.Mem.Caching, bus),
rp->Data.ExtAddress64.Address.Minimum,
rp->Data.ExtAddress64.Address.AddressLength);
- if (pci_boot_debug != 0) {
+ if (pci_prd_debug != 0) {
acpi_dbg(bus,
rp->Data.ExtAddress64.Address.Minimum,
rp->Data.ExtAddress64.Address.AddressLength,
@@ -450,7 +429,7 @@ acpi_wr_cb(ACPI_RESOURCE *rp, void *context)
}
static void
-mps_probe()
+mps_probe(void)
{
uchar_t *extp;
struct mps_fps_hdr *fpp = NULL;
@@ -521,22 +500,43 @@ mps_probe()
static int
-mps_find_bus_res(int bus, int type, struct memlist **res)
+mps_find_bus_res(uint32_t bus, pci_prd_rsrc_t rsrc, struct memlist **res)
{
struct sasm *sasmp;
uchar_t *extp;
- int res_cnt;
+ int res_cnt, type;
+
+ ASSERT3U(bus, <, PCI_MAX_BUS_NUM);
if (mps_extp == NULL)
return (0);
+
+ switch (rsrc) {
+ case PCI_PRD_R_IO:
+ type = IO_TYPE;
+ break;
+ case PCI_PRD_R_MMIO:
+ type = MEM_TYPE;
+ break;
+ case PCI_PRD_R_PREFETCH:
+ type = PREFETCH_TYPE;
+ break;
+ case PCI_PRD_R_BUS:
+ type = BUSRANGE_TYPE;
+ break;
+ default:
+ *res = NULL;
+ return (0);
+ }
+
extp = mps_extp;
res_cnt = 0;
while (extp < mps_ext_endp) {
switch (*extp) {
case SYS_AS_MAPPING:
sasmp = (struct sasm *)extp;
- if (((int)sasmp->sasm_as_type) == type &&
- ((int)sasmp->sasm_bus_id) == bus) {
+ if (sasmp->sasm_as_type == type &&
+ sasmp->sasm_bus_id == bus) {
uint64_t base, len;
base = (uint64_t)sasmp->sasm_as_base |
@@ -558,11 +558,7 @@ mps_find_bus_res(int bus, int type, struct memlist **res)
cmn_err(CE_WARN, "Unknown descriptor type %d"
" in BIOS Multiprocessor Spec table.",
*extp);
- while (*res) {
- struct memlist *tmp = *res;
- *res = tmp->ml_next;
- memlist_free(tmp);
- }
+ memlist_free_all(res);
return (0);
}
}
@@ -570,7 +566,7 @@ mps_find_bus_res(int bus, int type, struct memlist **res)
}
static void
-hrt_probe()
+hrt_probe(void)
{
struct hrt_hdr *hrtp;
@@ -585,44 +581,46 @@ hrt_probe()
dprintf("PCI Hot-Plug Resource Table version no. <> 1\n");
return;
}
- hrt_entry_cnt = (int)hrtp->hrt_entry_cnt;
+ hrt_entry_cnt = (uint_t)hrtp->hrt_entry_cnt;
dprintf("No. of PCI hot-plug slot entries = 0x%x\n", hrt_entry_cnt);
hrt_hpep = (struct php_entry *)(hrtp + 1);
}
static int
-hrt_find_bus_res(int bus, int type, struct memlist **res)
+hrt_find_bus_res(uint32_t bus, pci_prd_rsrc_t type, struct memlist **res)
{
- int res_cnt, i;
+ int res_cnt;
struct php_entry *hpep;
+ ASSERT3U(bus, <, PCI_MAX_BUS_NUM);
+
if (hrt_hpep == NULL || hrt_entry_cnt == 0)
return (0);
hpep = hrt_hpep;
res_cnt = 0;
- for (i = 0; i < hrt_entry_cnt; i++, hpep++) {
+ for (uint_t i = 0; i < hrt_entry_cnt; i++, hpep++) {
if (hpep->php_pri_bus != bus)
continue;
- if (type == IO_TYPE) {
+ if (type == PCI_PRD_R_IO) {
if (hpep->php_io_start == 0 || hpep->php_io_size == 0)
continue;
memlist_insert(res, (uint64_t)hpep->php_io_start,
(uint64_t)hpep->php_io_size);
res_cnt++;
- } else if (type == MEM_TYPE) {
+ } else if (type == PCI_PRD_R_MMIO) {
if (hpep->php_mem_start == 0 || hpep->php_mem_size == 0)
continue;
memlist_insert(res,
- (uint64_t)(((int)hpep->php_mem_start) << 16),
- (uint64_t)(((int)hpep->php_mem_size) << 16));
+ ((uint64_t)hpep->php_mem_start) << 16,
+ ((uint64_t)hpep->php_mem_size) << 16);
res_cnt++;
- } else if (type == PREFETCH_TYPE) {
+ } else if (type == PCI_PRD_R_PREFETCH) {
if (hpep->php_pfmem_start == 0 ||
hpep->php_pfmem_size == 0)
continue;
memlist_insert(res,
- (uint64_t)(((int)hpep->php_pfmem_start) << 16),
- (uint64_t)(((int)hpep->php_pfmem_size) << 16));
+ ((uint64_t)hpep->php_pfmem_start) << 16,
+ ((uint64_t)hpep->php_pfmem_size) << 16);
res_cnt++;
}
}
@@ -656,67 +654,226 @@ checksum(unsigned char *cp, int len)
return ((int)(cksum & 0xFF));
}
-#ifdef UNUSED_BUS_HIERARY_INFO
+uint32_t
+pci_prd_max_bus(void)
+{
+ return ((uint32_t)pci_bios_maxbus);
+}
+
+struct memlist *
+pci_prd_find_resource(uint32_t bus, pci_prd_rsrc_t rsrc)
+{
+ struct memlist *res = NULL;
+
+ if (bus > pci_bios_maxbus)
+ return (NULL);
+
+ if (tbl_init == 0) {
+ tbl_init = 1;
+ acpi_pci_probe();
+ if (pci_prd_have_bios) {
+ hrt_probe();
+ mps_probe();
+ }
+ }
+
+ if (acpi_find_bus_res(bus, rsrc, &res) > 0)
+ return (res);
+
+ if (pci_prd_have_bios && hrt_find_bus_res(bus, rsrc, &res) > 0)
+ return (res);
+
+ if (pci_prd_have_bios)
+ (void) mps_find_bus_res(bus, rsrc, &res);
+ return (res);
+}
+
+typedef struct {
+ pci_prd_root_complex_f ppac_func;
+ void *ppac_arg;
+} pci_prd_acpi_cb_t;
+
+static ACPI_STATUS
+pci_process_acpi_device(ACPI_HANDLE hdl, UINT32 level, void *ctx, void **rv)
+{
+ ACPI_DEVICE_INFO *adi;
+ int busnum;
+ pci_prd_acpi_cb_t *cb = ctx;
+
+ /*
+ * Use AcpiGetObjectInfo() to find the device _HID
+ * If not a PCI root-bus, ignore this device and continue
+ * the walk
+ */
+ if (ACPI_FAILURE(AcpiGetObjectInfo(hdl, &adi)))
+ return (AE_OK);
+
+ if (!(adi->Valid & ACPI_VALID_HID)) {
+ AcpiOsFree(adi);
+ return (AE_OK);
+ }
+
+ if (strncmp(adi->HardwareId.String, PCI_ROOT_HID_STRING,
+ sizeof (PCI_ROOT_HID_STRING)) &&
+ strncmp(adi->HardwareId.String, PCI_EXPRESS_ROOT_HID_STRING,
+ sizeof (PCI_EXPRESS_ROOT_HID_STRING))) {
+ AcpiOsFree(adi);
+ return (AE_OK);
+ }
+
+ AcpiOsFree(adi);
+
+ /*
+ * acpica_get_busno() will check the presence of _BBN and
+ * fail if not present. It will then use the _CRS method to
+ * retrieve the actual bus number assigned, it will fall back
+ * to _BBN should the _CRS method fail.
+ */
+ if (ACPI_SUCCESS(acpica_get_busno(hdl, &busnum))) {
+ /*
+ * Ignore invalid _BBN return values here (rather
+ * than panic) and emit a warning; something else
+ * may suffer failure as a result of the broken BIOS.
+ */
+ if (busnum < 0) {
+ dcmn_err(CE_NOTE,
+ "pci_process_acpi_device: invalid _BBN 0x%x",
+ busnum);
+ return (AE_CTRL_DEPTH);
+ }
+
+ if (cb->ppac_func((uint32_t)busnum, cb->ppac_arg))
+ return (AE_CTRL_DEPTH);
+ return (AE_CTRL_TERMINATE);
+ }
+
+ /* PCI and no _BBN, continue walk */
+ return (AE_OK);
+}
+
+void
+pci_prd_root_complex_iter(pci_prd_root_complex_f func, void *arg)
+{
+ void *rv;
+ pci_prd_acpi_cb_t cb;
+
+ cb.ppac_func = func;
+ cb.ppac_arg = arg;
+
+ /*
+ * First scan ACPI devices for anything that might be here. After that,
+ * go through and check the old BIOS IRQ routing table for additional
+ * buses. Note, slot naming from the IRQ table comes later.
+ */
+ (void) AcpiGetDevices(NULL, pci_process_acpi_device, &cb, &rv);
+ pci_bios_bus_iter(func, arg);
+
+}
+
/*
- * At this point, the bus hierarchy entries do not appear to
- * provide anything we can't find out from PCI config space.
- * The only interesting bit is the ISA bus number, which we
- * don't care.
+ * If there is actually a PCI IRQ routing table present, then we want to use
+ * this to go back and update the slot name. In particular, if we have no PCI
+ * IRQ routing table, then we use the existing slot names that were already set
+ * up for us in picex_slot_names_prop() from the capability register. Otherwise,
+ * we actually delete all slot-names properties from buses and instead use
+ * something from the IRQ routing table if it exists.
+ *
+ * Note, the property is always deleted regardless of whether or not it exists
+ * in the IRQ routing table. Finally, we have traditionally kept "pcie0" names
+ * as special as apparently that can't be represented in the IRQ routing table.
*/
-int
-mps_find_parent_bus(int bus)
+void
+pci_prd_slot_name(uint32_t bus, dev_info_t *dip)
{
- struct sasm *sasmp;
- uchar_t *extp;
+ char slotprop[256];
+ int len;
+ char *slotcap_name;
- if (mps_extp == NULL)
- return (-1);
+ if (pci_irq_nroutes == 0)
+ return;
- extp = mps_extp;
- while (extp < mps_ext_endp) {
- bhdp = (struct bhd *)extp;
- switch (*extp) {
- case SYS_AS_MAPPING:
- extp += SYS_AS_MAPPING_SIZE;
- break;
- case BUS_HIERARCHY_DESC:
- if (bhdp->bhd_bus_id == bus)
- return (bhdp->bhd_parent);
- extp += BUS_HIERARCHY_DESC_SIZE;
- break;
- case COMP_BUS_AS_MODIFIER:
- extp += COMP_BUS_AS_MODIFIER_SIZE;
- break;
- default:
- cmn_err(CE_WARN, "Unknown descriptor type %d"
- " in BIOS Multiprocessor Spec table.",
- *extp);
- return (-1);
+ if (dip != NULL) {
+ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pci_bus_res[bus].dip,
+ DDI_PROP_DONTPASS, "slot-names", &slotcap_name) !=
+ DDI_SUCCESS || strcmp(slotcap_name, "pcie0") != 0) {
+ (void) ndi_prop_remove(DDI_DEV_T_NONE,
+ pci_bus_res[bus].dip, "slot-names");
+ }
+ }
+
+
+ len = pci_slot_names_prop(bus, slotprop, sizeof (slotprop));
+ if (len > 0) {
+ if (dip != NULL) {
+ ASSERT((len % sizeof (int)) == 0);
+ (void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
+ pci_bus_res[bus].dip, "slot-names",
+ (int *)slotprop, len / sizeof (int));
+ } else {
+ cmn_err(CE_NOTE, "!BIOS BUG: Invalid bus number in PCI "
+ "IRQ routing table; Not adding slot-names "
+ "property for incorrect bus %d", bus);
}
}
- return (-1);
}
-int
-hrt_find_bus_range(int bus)
+boolean_t
+pci_prd_multi_root_ok(void)
{
- int i, max_bus, sub_bus;
- struct php_entry *hpep;
+ return (acpi_resource_discovery > 0);
+}
- if (hrt_hpep == NULL || hrt_entry_cnt == 0) {
- return (-1);
+int
+pci_prd_init(pci_prd_upcalls_t *upcalls)
+{
+ if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS,
+ "efi-systab")) {
+ pci_prd_have_bios = B_FALSE;
}
- hpep = hrt_hpep;
- max_bus = -1;
- for (i = 0; i < hrt_entry_cnt; i++, hpep++) {
- if (hpep->php_pri_bus != bus)
- continue;
- sub_bus = (int)hpep->php_subord_bus;
- if (sub_bus > max_bus)
- max_bus = sub_bus;
+
+ prd_upcalls = upcalls;
+
+ return (0);
+}
+
+void
+pci_prd_fini(void)
+{
+ int bus;
+
+ for (bus = 0; bus <= pci_bios_maxbus; bus++) {
+ memlist_free_all(&acpi_io_res[bus]);
+ memlist_free_all(&acpi_mem_res[bus]);
+ memlist_free_all(&acpi_pmem_res[bus]);
+ memlist_free_all(&acpi_bus_res[bus]);
}
- return (max_bus);
}
-#endif /* UNUSED_BUS_HIERARY_INFO */
+static struct modlmisc pci_prd_modlmisc_i86pc = {
+ .misc_modops = &mod_miscops,
+ .misc_linkinfo = "i86pc PCI Resource Discovery"
+};
+
+static struct modlinkage pci_prd_modlinkage_i86pc = {
+ .ml_rev = MODREV_1,
+ .ml_linkage = { &pci_prd_modlmisc_i86pc, NULL }
+};
+
+int
+_init(void)
+{
+ return (mod_install(&pci_prd_modlinkage_i86pc));
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&pci_prd_modlinkage_i86pc, modinfop));
+}
+
+int
+_fini(void)
+{
+ return (mod_remove(&pci_prd_modlinkage_i86pc));
+}
diff --git a/usr/src/uts/intel/io/pci/pcihrt.h b/usr/src/uts/i86pc/io/pci/pcihrt.h
index 7192eca2c5..7857e0314f 100644
--- a/usr/src/uts/intel/io/pci/pcihrt.h
+++ b/usr/src/uts/i86pc/io/pci/pcihrt.h
@@ -31,16 +31,14 @@
#ifndef _PCIHRT_H
#define _PCIHRT_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
struct hrt_hdr { /* PCI Hot-Plug Configuration Resource Table header */
- uint32_t hrt_sig; /* $HRT */
+ uint32_t hrt_sig; /* $HRT */
uint16_t hrt_avail_imap; /* Bitmap of unused IRQs */
- uint16_t hrt_used_imap; /* Bitmap of IRQs used by PCI */
+ uint16_t hrt_used_imap; /* Bitmap of IRQs used by PCI */
uchar_t hrt_entry_cnt; /* no. of PCI hot-plug slot entries */
uchar_t hrt_ver; /* version no. = 1 */
uchar_t hrt_resv0; /* reserved */
@@ -58,7 +56,7 @@ struct php_entry { /* PCI hot-plug slot entry */
uchar_t php_subord_bus; /* Max Subordinate bus of this slot */
uint16_t php_io_start; /* allocated I/O space starting addr */
uint16_t php_io_size; /* allocated I/O space size in bytes */
- uint16_t php_mem_start; /* allocated Memory space start addr */
+ uint16_t php_mem_start; /* allocated Memory space start addr */
uint16_t php_mem_size; /* allocated Memory space size in 64k */
uint16_t php_pfmem_start; /* allocated Prefetchable Memory start */
uint16_t php_pfmem_size; /* allocated Prefetchable size in 64k */
diff --git a/usr/src/uts/i86pc/io/vmm/intel/vmx_msr.c b/usr/src/uts/i86pc/io/vmm/intel/vmx_msr.c
index cf00426300..844e8b9708 100644
--- a/usr/src/uts/i86pc/io/vmm/intel/vmx_msr.c
+++ b/usr/src/uts/i86pc/io/vmm/intel/vmx_msr.c
@@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$");
#include <machine/clock.h>
#include <machine/cpufunc.h>
#include <machine/md_var.h>
-#include <machine/pcb.h>
#include <machine/specialreg.h>
#include <machine/vmm.h>
diff --git a/usr/src/uts/i86pc/io/vmm/io/ppt.c b/usr/src/uts/i86pc/io/vmm/io/ppt.c
index ce6e6eb735..e79842d8a8 100644
--- a/usr/src/uts/i86pc/io/vmm/io/ppt.c
+++ b/usr/src/uts/i86pc/io/vmm/io/ppt.c
@@ -322,21 +322,21 @@ ppt_ioctl(dev_t dev, int cmd, intptr_t arg, int md, cred_t *cr, int *rv)
}
static int
-ppt_find_pba_bar(struct pptdev *ppt)
+ppt_find_msix_table_bar(struct pptdev *ppt)
{
uint16_t base;
- uint32_t pba_off;
+ uint32_t off;
if (PCI_CAP_LOCATE(ppt->pptd_cfg, PCI_CAP_ID_MSI_X, &base) !=
DDI_SUCCESS)
return (-1);
- pba_off = pci_config_get32(ppt->pptd_cfg, base + PCI_MSIX_PBA_OFFSET);
+ off = pci_config_get32(ppt->pptd_cfg, base + PCI_MSIX_TBL_OFFSET);
- if (pba_off == PCI_EINVAL32)
+ if (off == PCI_EINVAL32)
return (-1);
- return (pba_off & PCI_MSIX_PBA_BIR_MASK);
+ return (off & PCI_MSIX_TBL_BIR_MASK);
}
static int
@@ -361,7 +361,7 @@ ppt_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
if (off < 0 || off != P2ALIGN(off, PAGESIZE))
return (EINVAL);
- if ((bar = ppt_find_pba_bar(ppt)) == -1)
+ if ((bar = ppt_find_msix_table_bar(ppt)) == -1)
return (EINVAL);
ddireg = ppt->pptd_bars[bar].ddireg;
@@ -378,7 +378,6 @@ ppt_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
return (err);
}
-
static void
ppt_bar_wipe(struct pptdev *ppt)
{
diff --git a/usr/src/uts/i86pc/io/vmm/io/vatpic.c b/usr/src/uts/i86pc/io/vmm/io/vatpic.c
index 0b611b19e2..63306de731 100644
--- a/usr/src/uts/i86pc/io/vmm/io/vatpic.c
+++ b/usr/src/uts/i86pc/io/vmm/io/vatpic.c
@@ -66,32 +66,41 @@ static MALLOC_DEFINE(M_VATPIC, "atpic", "bhyve virtual atpic (8259)");
#define VATPIC_UNLOCK(vatpic) mtx_unlock_spin(&((vatpic)->mtx))
#define VATPIC_LOCKED(vatpic) mtx_owned(&((vatpic)->mtx))
+#define IRQ_BASE_MASK 0xf8
+
enum irqstate {
IRQSTATE_ASSERT,
IRQSTATE_DEASSERT,
IRQSTATE_PULSE
};
+enum icw_state {
+ IS_ICW1 = 0,
+ IS_ICW2,
+ IS_ICW3,
+ IS_ICW4,
+};
+
struct atpic {
- bool ready;
- int icw_num;
- int rd_cmd_reg;
+ enum icw_state icw_state;
- bool aeoi;
+ bool ready;
+ bool auto_eoi;
bool poll;
bool rotate;
- bool sfn; /* special fully-nested mode */
+ bool special_full_nested;
+ bool read_isr_next;
+ bool intr_raised;
+ bool special_mask_mode;
- int irq_base;
- uint8_t request; /* Interrupt Request Register (IIR) */
- uint8_t service; /* Interrupt Service (ISR) */
- uint8_t mask; /* Interrupt Mask Register (IMR) */
- uint8_t smm; /* special mask mode */
+ uint8_t reg_irr; /* Interrupt Request Register (IIR) */
+ uint8_t reg_isr; /* Interrupt Service (ISR) */
+ uint8_t reg_imr; /* Interrupt Mask Register (IMR) */
+ uint8_t irq_base; /* base interrupt vector */
+ uint8_t lowprio; /* lowest priority irq */
+ uint8_t elc; /* level-triggered mode bits */
uint_t acnt[8]; /* sum of pin asserts and deasserts */
- int lowprio; /* lowest priority irq */
-
- bool intr_raised;
};
struct atpic_stats {
@@ -104,7 +113,6 @@ struct vatpic {
struct vm *vm;
struct mtx mtx;
struct atpic atpic[2];
- uint8_t elc[2];
struct atpic_stats stats;
};
@@ -152,15 +160,17 @@ vatpic_get_highest_isrpin(struct atpic *atpic)
ATPIC_PIN_FOREACH(pin, atpic, i) {
bit = (1 << pin);
- if (atpic->service & bit) {
+ if (atpic->reg_isr & bit) {
/*
* An IS bit that is masked by an IMR bit will not be
* cleared by a non-specific EOI in Special Mask Mode.
*/
- if (atpic->smm && (atpic->mask & bit) != 0)
+ if (atpic->special_mask_mode &&
+ (atpic->reg_imr & bit) != 0) {
continue;
- else
+ } else {
return (pin);
+ }
}
}
@@ -178,8 +188,8 @@ vatpic_get_highest_irrpin(struct atpic *atpic)
* a slave is in service, the slave is not locked out from the
* master's priority logic.
*/
- serviced = atpic->service;
- if (atpic->sfn)
+ serviced = atpic->reg_isr;
+ if (atpic->special_full_nested)
serviced &= ~(1 << 2);
/*
@@ -188,7 +198,7 @@ vatpic_get_highest_irrpin(struct atpic *atpic)
* other levels that are not masked. In other words the ISR has no
* bearing on the levels that can generate interrupts.
*/
- if (atpic->smm)
+ if (atpic->special_mask_mode)
serviced = 0;
ATPIC_PIN_FOREACH(pin, atpic, tmp) {
@@ -205,7 +215,7 @@ vatpic_get_highest_irrpin(struct atpic *atpic)
* If an interrupt is asserted and not masked then return
* the corresponding 'pin' to the caller.
*/
- if ((atpic->request & bit) != 0 && (atpic->mask & bit) == 0)
+ if ((atpic->reg_irr & bit) != 0 && (atpic->reg_imr & bit) == 0)
return (pin);
}
@@ -228,7 +238,7 @@ vatpic_notify_intr(struct vatpic *vatpic)
(pin = vatpic_get_highest_irrpin(atpic)) != -1) {
VATPIC_CTR4(vatpic, "atpic slave notify pin = %d "
"(imr 0x%x irr 0x%x isr 0x%x)", pin,
- atpic->mask, atpic->request, atpic->service);
+ atpic->reg_imr, atpic->reg_irr, atpic->reg_isr);
/*
* Cascade the request from the slave to the master.
@@ -240,7 +250,7 @@ vatpic_notify_intr(struct vatpic *vatpic)
} else {
VATPIC_CTR3(vatpic, "atpic slave no eligible interrupts "
"(imr 0x%x irr 0x%x isr 0x%x)",
- atpic->mask, atpic->request, atpic->service);
+ atpic->reg_imr, atpic->reg_irr, atpic->reg_isr);
}
/*
@@ -251,7 +261,7 @@ vatpic_notify_intr(struct vatpic *vatpic)
(pin = vatpic_get_highest_irrpin(atpic)) != -1) {
VATPIC_CTR4(vatpic, "atpic master notify pin = %d "
"(imr 0x%x irr 0x%x isr 0x%x)", pin,
- atpic->mask, atpic->request, atpic->service);
+ atpic->reg_imr, atpic->reg_irr, atpic->reg_isr);
/*
* From Section 3.6.2, "Interrupt Modes", in the
@@ -285,24 +295,22 @@ vatpic_notify_intr(struct vatpic *vatpic)
} else {
VATPIC_CTR3(vatpic, "atpic master no eligible interrupts "
"(imr 0x%x irr 0x%x isr 0x%x)",
- atpic->mask, atpic->request, atpic->service);
+ atpic->reg_imr, atpic->reg_irr, atpic->reg_isr);
}
}
static int
vatpic_icw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
{
- VATPIC_CTR1(vatpic, "atpic icw1 0x%x", val);
-
atpic->ready = false;
- atpic->icw_num = 1;
- atpic->request = 0;
- atpic->mask = 0;
+ atpic->icw_state = IS_ICW1;
+ atpic->reg_irr = 0;
+ atpic->reg_imr = 0;
atpic->lowprio = 7;
- atpic->rd_cmd_reg = 0;
- atpic->poll = 0;
- atpic->smm = 0;
+ atpic->read_isr_next = false;
+ atpic->poll = false;
+ atpic->special_mask_mode = false;
if ((val & ICW1_SNGL) != 0) {
VATPIC_CTR0(vatpic, "vatpic cascade mode required");
@@ -314,7 +322,7 @@ vatpic_icw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
return (-1);
}
- atpic->icw_num++;
+ atpic->icw_state = IS_ICW2;
return (0);
}
@@ -322,11 +330,8 @@ vatpic_icw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
static int
vatpic_icw2(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
{
- VATPIC_CTR1(vatpic, "atpic icw2 0x%x", val);
-
- atpic->irq_base = val & 0xf8;
-
- atpic->icw_num++;
+ atpic->irq_base = val & IRQ_BASE_MASK;
+ atpic->icw_state = IS_ICW3;
return (0);
}
@@ -334,9 +339,7 @@ vatpic_icw2(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
static int
vatpic_icw3(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
{
- VATPIC_CTR1(vatpic, "atpic icw3 0x%x", val);
-
- atpic->icw_num++;
+ atpic->icw_state = IS_ICW4;
return (0);
}
@@ -344,26 +347,17 @@ vatpic_icw3(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
static int
vatpic_icw4(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
{
- VATPIC_CTR1(vatpic, "atpic icw4 0x%x", val);
-
if ((val & ICW4_8086) == 0) {
VATPIC_CTR0(vatpic, "vatpic microprocessor mode required");
return (-1);
}
- if ((val & ICW4_AEOI) != 0)
- atpic->aeoi = true;
-
- if ((val & ICW4_SFNM) != 0) {
- if (master_atpic(vatpic, atpic)) {
- atpic->sfn = true;
- } else {
- VATPIC_CTR1(vatpic, "Ignoring special fully nested "
- "mode on slave atpic: %#x", val);
- }
+ atpic->auto_eoi = (val & ICW4_AEOI) != 0;
+ if (master_atpic(vatpic, atpic)) {
+ atpic->special_full_nested = (val & ICW4_SFNM) != 0;
}
- atpic->icw_num = 0;
+ atpic->icw_state = IS_ICW1;
atpic->ready = true;
return (0);
@@ -372,9 +366,7 @@ vatpic_icw4(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
static int
vatpic_ocw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
{
- VATPIC_CTR1(vatpic, "atpic ocw1 0x%x", val);
-
- atpic->mask = val & 0xff;
+ atpic->reg_imr = val;
return (0);
}
@@ -382,9 +374,7 @@ vatpic_ocw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
static int
vatpic_ocw2(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
{
- VATPIC_CTR1(vatpic, "atpic ocw2 0x%x", val);
-
- atpic->rotate = ((val & OCW2_R) != 0);
+ atpic->rotate = (val & OCW2_R) != 0;
if ((val & OCW2_EOI) != 0) {
int isr_bit;
@@ -398,12 +388,12 @@ vatpic_ocw2(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
}
if (isr_bit != -1) {
- atpic->service &= ~(1 << isr_bit);
+ atpic->reg_isr &= ~(1 << isr_bit);
if (atpic->rotate)
atpic->lowprio = isr_bit;
}
- } else if ((val & OCW2_SL) != 0 && atpic->rotate == true) {
+ } else if ((val & OCW2_SL) != 0 && atpic->rotate) {
/* specific priority */
atpic->lowprio = val & 0x7;
}
@@ -414,21 +404,14 @@ vatpic_ocw2(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
static int
vatpic_ocw3(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
{
- VATPIC_CTR1(vatpic, "atpic ocw3 0x%x", val);
-
- if (val & OCW3_ESMM) {
- atpic->smm = val & OCW3_SMM ? 1 : 0;
- VATPIC_CTR2(vatpic, "%s atpic special mask mode %s",
- master_atpic(vatpic, atpic) ? "master" : "slave",
- atpic->smm ? "enabled" : "disabled");
+ if ((val & OCW3_ESMM) != 0) {
+ atpic->special_mask_mode = (val & OCW3_SMM) != 0;
}
-
- if (val & OCW3_RR) {
- /* read register command */
- atpic->rd_cmd_reg = val & OCW3_RIS;
-
- /* Polling mode */
- atpic->poll = ((val & OCW3_P) != 0);
+ if ((val & OCW3_RR) != 0) {
+ atpic->read_isr_next = (val & OCW3_RIS) != 0;
+ }
+ if ((val & OCW3_P) != 0) {
+ atpic->poll = true;
}
return (0);
@@ -444,9 +427,8 @@ vatpic_set_pinstate(struct vatpic *vatpic, int pin, bool newstate)
VERIFY(pin >= 0 && pin < 16);
ASSERT(VATPIC_LOCKED(vatpic));
- const int chip = pin >> 3;
const int lpin = pin & 0x7;
- atpic = &vatpic->atpic[chip];
+ atpic = &vatpic->atpic[pin >> 3];
oldcnt = newcnt = atpic->acnt[lpin];
if (newstate) {
@@ -470,18 +452,18 @@ vatpic_set_pinstate(struct vatpic *vatpic, int pin, bool newstate)
}
atpic->acnt[lpin] = newcnt;
- const bool level = ((vatpic->elc[chip] & (1 << (lpin))) != 0);
+ const bool level = ((atpic->elc & (1 << (lpin))) != 0);
if ((oldcnt == 0 && newcnt == 1) || (newcnt > 0 && level == true)) {
/* rising edge or level */
DTRACE_PROBE2(vatpic__assert, struct vatpic *, vatpic,
int, pin);
- atpic->request |= (1 << lpin);
+ atpic->reg_irr |= (1 << lpin);
} else if (oldcnt == 1 && newcnt == 0) {
/* falling edge */
DTRACE_PROBE2(vatpic__deassert, struct vatpic *, vatpic,
int, pin);
if (level) {
- atpic->request &= ~(1 << lpin);
+ atpic->reg_irr &= ~(1 << lpin);
}
}
@@ -502,7 +484,7 @@ vatpic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate)
vatpic = vm_atpic(vm);
atpic = &vatpic->atpic[irq >> 3];
- if (atpic->ready == false)
+ if (!atpic->ready)
return (0);
VATPIC_LOCK(vatpic);
@@ -548,14 +530,12 @@ vatpic_pulse_irq(struct vm *vm, int irq)
int
vatpic_set_irq_trigger(struct vm *vm, int irq, enum vm_intr_trigger trigger)
{
- struct vatpic *vatpic;
-
if (irq < 0 || irq > 15)
return (EINVAL);
/*
- * See comment in vatpic_elc_handler. These IRQs must be
- * edge triggered.
+ * See comments in vatpic_elc_handler.
+ * These IRQs must be edge triggered.
*/
if (trigger == LEVEL_TRIGGER) {
switch (irq) {
@@ -568,15 +548,16 @@ vatpic_set_irq_trigger(struct vm *vm, int irq, enum vm_intr_trigger trigger)
}
}
- vatpic = vm_atpic(vm);
+ struct vatpic *vatpic = vm_atpic(vm);
+ struct atpic *atpic = &vatpic->atpic[irq >> 3];
+ const int pin = irq & 0x7;
VATPIC_LOCK(vatpic);
-
- if (trigger == LEVEL_TRIGGER)
- vatpic->elc[irq >> 3] |= 1 << (irq & 0x7);
- else
- vatpic->elc[irq >> 3] &= ~(1 << (irq & 0x7));
-
+ if (trigger == LEVEL_TRIGGER) {
+ atpic->elc |= (1 << pin);
+ } else {
+ atpic->elc &= ~(1 << pin);
+ }
VATPIC_UNLOCK(vatpic);
return (0);
@@ -622,13 +603,13 @@ vatpic_pin_accepted(struct atpic *atpic, int pin)
atpic->intr_raised = false;
if (atpic->acnt[pin] == 0)
- atpic->request &= ~(1 << pin);
+ atpic->reg_irr &= ~(1 << pin);
- if (atpic->aeoi == true) {
- if (atpic->rotate == true)
+ if (atpic->auto_eoi) {
+ if (atpic->rotate)
atpic->lowprio = pin;
} else {
- atpic->service |= (1 << pin);
+ atpic->reg_isr |= (1 << pin);
}
}
@@ -644,7 +625,7 @@ vatpic_intr_accepted(struct vm *vm, int vector)
pin = vector & 0x7;
- if ((vector & ~0x7) == vatpic->atpic[1].irq_base) {
+ if ((vector & IRQ_BASE_MASK) == vatpic->atpic[1].irq_base) {
vatpic_pin_accepted(&vatpic->atpic[1], pin);
/*
* If this vector originated from the slave,
@@ -669,7 +650,7 @@ vatpic_read(struct vatpic *vatpic, struct atpic *atpic, bool in, int port,
VATPIC_LOCK(vatpic);
if (atpic->poll) {
- atpic->poll = 0;
+ atpic->poll = false;
pin = vatpic_get_highest_irrpin(atpic);
if (pin >= 0) {
vatpic_pin_accepted(atpic, pin);
@@ -680,14 +661,14 @@ vatpic_read(struct vatpic *vatpic, struct atpic *atpic, bool in, int port,
} else {
if (port & ICU_IMR_OFFSET) {
/* read interrrupt mask register */
- *eax = atpic->mask;
+ *eax = atpic->reg_imr;
} else {
- if (atpic->rd_cmd_reg == OCW3_RIS) {
+ if (atpic->read_isr_next) {
/* read interrupt service register */
- *eax = atpic->service;
+ *eax = atpic->reg_isr;
} else {
/* read interrupt request register */
- *eax = atpic->request;
+ *eax = atpic->reg_irr;
}
}
}
@@ -711,14 +692,14 @@ vatpic_write(struct vatpic *vatpic, struct atpic *atpic, bool in, int port,
VATPIC_LOCK(vatpic);
if (port & ICU_IMR_OFFSET) {
- switch (atpic->icw_num) {
- case 2:
+ switch (atpic->icw_state) {
+ case IS_ICW2:
error = vatpic_icw2(vatpic, atpic, val);
break;
- case 3:
+ case IS_ICW3:
error = vatpic_icw3(vatpic, atpic, val);
break;
- case 4:
+ case IS_ICW4:
error = vatpic_icw4(vatpic, atpic, val);
break;
default:
@@ -784,37 +765,41 @@ vatpic_elc_handler(void *arg, bool in, uint16_t port, uint8_t bytes,
uint32_t *eax)
{
struct vatpic *vatpic = arg;
- bool is_master;
+ struct atpic *atpic = NULL;
+ uint8_t elc_mask = 0;
- is_master = (port == IO_ELCR1);
+ switch (port) {
+ case IO_ELCR1:
+ atpic = &vatpic->atpic[0];
+ /*
+ * For the master PIC the cascade channel (IRQ2), the heart beat
+ * timer (IRQ0), and the keyboard controller (IRQ1) cannot be
+ * programmed for level mode.
+ */
+ elc_mask = 0xf8;
+ break;
+ case IO_ELCR2:
+ atpic = &vatpic->atpic[1];
+ /*
+ * For the slave PIC the real time clock (IRQ8) and the floating
+ * point error interrupt (IRQ13) cannot be programmed for level
+ * mode.
+ */
+ elc_mask = 0xde;
+ break;
+ default:
+ return (-1);
+ }
if (bytes != 1)
return (-1);
VATPIC_LOCK(vatpic);
-
if (in) {
- if (is_master)
- *eax = vatpic->elc[0];
- else
- *eax = vatpic->elc[1];
+ *eax = atpic->elc;
} else {
- /*
- * For the master PIC the cascade channel (IRQ2), the
- * heart beat timer (IRQ0), and the keyboard
- * controller (IRQ1) cannot be programmed for level
- * mode.
- *
- * For the slave PIC the real time clock (IRQ8) and
- * the floating point error interrupt (IRQ13) cannot
- * be programmed for level mode.
- */
- if (is_master)
- vatpic->elc[0] = (*eax & 0xf8);
- else
- vatpic->elc[1] = (*eax & 0xde);
+ atpic->elc = *eax & elc_mask;
}
-
VATPIC_UNLOCK(vatpic);
return (0);
diff --git a/usr/src/uts/i86pc/io/vmm/io/vlapic.c b/usr/src/uts/i86pc/io/vmm/io/vlapic.c
index 06ee46c8e2..55f491b664 100644
--- a/usr/src/uts/i86pc/io/vmm/io/vlapic.c
+++ b/usr/src/uts/i86pc/io/vmm/io/vlapic.c
@@ -99,6 +99,7 @@ __FBSDID("$FreeBSD$");
#define VLAPIC_BUS_FREQ (128 * 1024 * 1024)
static void vlapic_set_error(struct vlapic *, uint32_t, bool);
+static void vlapic_callout_handler(void *arg);
#ifdef __ISRVEC_DEBUG
static void vlapic_isrstk_accept(struct vlapic *, int);
@@ -728,6 +729,13 @@ vlapic_trigger_lvt(struct vlapic *vlapic, int vector)
}
static void
+vlapic_callout_reset(struct vlapic *vlapic, sbintime_t t)
+{
+ callout_reset_sbt(&vlapic->callout, t, 0,
+ vlapic_callout_handler, vlapic, 0);
+}
+
+static void
vlapic_callout_handler(void *arg)
{
struct vlapic *vlapic;
@@ -783,8 +791,7 @@ vlapic_callout_handler(void *arg)
}
bintime_add(&vlapic->timer_fire_bt, &vlapic->timer_period_bt);
- callout_reset_sbt(&vlapic->callout, rem_sbt, 0,
- vlapic_callout_handler, vlapic, 0);
+ vlapic_callout_reset(vlapic, rem_sbt);
}
done:
VLAPIC_TIMER_UNLOCK(vlapic);
@@ -810,8 +817,7 @@ vlapic_icrtmr_write_handler(struct vlapic *vlapic)
bintime_add(&vlapic->timer_fire_bt, &vlapic->timer_period_bt);
sbt = bttosbt(vlapic->timer_period_bt);
- callout_reset_sbt(&vlapic->callout, sbt, 0,
- vlapic_callout_handler, vlapic, 0);
+ vlapic_callout_reset(vlapic, sbt);
} else
callout_stop(&vlapic->callout);
diff --git a/usr/src/uts/i86pc/io/vmm/sys/vmm_kernel.h b/usr/src/uts/i86pc/io/vmm/sys/vmm_kernel.h
index 7584213d39..e94f7a876b 100644
--- a/usr/src/uts/i86pc/io/vmm/sys/vmm_kernel.h
+++ b/usr/src/uts/i86pc/io/vmm/sys/vmm_kernel.h
@@ -39,7 +39,7 @@
*
* Copyright 2015 Pluribus Networks Inc.
* Copyright 2019 Joyent, Inc.
- * Copyright 2021 Oxide Computer Company
+ * Copyright 2022 Oxide Computer Company
* Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
*/
@@ -161,6 +161,8 @@ int vm_get_run_state(struct vm *vm, int vcpuid, uint32_t *state,
uint8_t *sipi_vec);
int vm_set_run_state(struct vm *vm, int vcpuid, uint32_t state,
uint8_t sipi_vec);
+int vm_get_fpu(struct vm *vm, int vcpuid, void *buf, size_t len);
+int vm_set_fpu(struct vm *vm, int vcpuid, void *buf, size_t len);
int vm_run(struct vm *vm, int vcpuid, const struct vm_entry *);
int vm_suspend(struct vm *vm, enum vm_suspend_how how);
int vm_inject_nmi(struct vm *vm, int vcpu);
diff --git a/usr/src/uts/i86pc/io/vmm/vmm.c b/usr/src/uts/i86pc/io/vmm/vmm.c
index 16acc1ea2c..78a810880d 100644
--- a/usr/src/uts/i86pc/io/vmm/vmm.c
+++ b/usr/src/uts/i86pc/io/vmm/vmm.c
@@ -60,8 +60,8 @@ __FBSDID("$FreeBSD$");
#include <sys/sched.h>
#include <sys/systm.h>
#include <sys/sunddi.h>
+#include <sys/hma.h>
-#include <machine/pcb.h>
#include <machine/md_var.h>
#include <x86/psl.h>
#include <x86/apicreg.h>
@@ -132,7 +132,7 @@ struct vcpu {
int exc_errcode_valid;
uint32_t exc_errcode;
uint8_t sipi_vector; /* (i) SIPI vector */
- struct savefpu *guestfpu; /* (a,i) guest fpu state */
+ hma_fpu_t *guestfpu; /* (a,i) guest fpu state */
uint64_t guest_xcr0; /* (i) guest %xcr0 register */
void *stats; /* (a,i) statistics */
struct vm_exit exitinfo; /* (x) exit reason and collateral */
@@ -318,7 +318,8 @@ vcpu_cleanup(struct vm *vm, int i, bool destroy)
VLAPIC_CLEANUP(vm->cookie, vcpu->vlapic);
if (destroy) {
vmm_stat_free(vcpu->stats);
- fpu_save_area_free(vcpu->guestfpu);
+ hma_fpu_free(vcpu->guestfpu);
+ vcpu->guestfpu = NULL;
vie_free(vcpu->vie_ctx);
vcpu->vie_ctx = NULL;
vmc_destroy(vcpu->vmclient);
@@ -342,7 +343,7 @@ vcpu_init(struct vm *vm, int vcpu_id, bool create)
vcpu->state = VCPU_IDLE;
vcpu->hostcpu = NOCPU;
vcpu->lastloccpu = NOCPU;
- vcpu->guestfpu = fpu_save_area_alloc();
+ vcpu->guestfpu = hma_fpu_alloc(KM_SLEEP);
vcpu->stats = vmm_stat_alloc();
vcpu->vie_ctx = vie_alloc();
@@ -369,7 +370,7 @@ vcpu_init(struct vm *vm, int vcpu_id, bool create)
vcpu->extint_pending = 0;
vcpu->exception_pending = 0;
vcpu->guest_xcr0 = XFEATURE_ENABLED_X87;
- fpu_save_area_reset(vcpu->guestfpu);
+ hma_fpu_init(vcpu->guestfpu);
vmm_stat_init(vcpu->stats);
vcpu->tsc_offset = 0;
}
@@ -1168,6 +1169,50 @@ vm_set_seg_desc(struct vm *vm, int vcpu, int reg, const struct seg_desc *desc)
return (VMSETDESC(vm->cookie, vcpu, reg, desc));
}
+static int
+translate_hma_xsave_result(hma_fpu_xsave_result_t res)
+{
+ switch (res) {
+ case HFXR_OK:
+ return (0);
+ case HFXR_NO_SPACE:
+ return (ENOSPC);
+ case HFXR_BAD_ALIGN:
+ case HFXR_UNSUP_FMT:
+ case HFXR_UNSUP_FEAT:
+ case HFXR_INVALID_DATA:
+ return (EINVAL);
+ default:
+ panic("unexpected xsave result");
+ }
+}
+
+int
+vm_get_fpu(struct vm *vm, int vcpuid, void *buf, size_t len)
+{
+ if (vcpuid < 0 || vcpuid >= vm->maxcpus)
+ return (EINVAL);
+
+ struct vcpu *vcpu = &vm->vcpu[vcpuid];
+ hma_fpu_xsave_result_t res;
+
+ res = hma_fpu_get_xsave_state(vcpu->guestfpu, buf, len);
+ return (translate_hma_xsave_result(res));
+}
+
+int
+vm_set_fpu(struct vm *vm, int vcpuid, void *buf, size_t len)
+{
+ if (vcpuid < 0 || vcpuid >= vm->maxcpus)
+ return (EINVAL);
+
+ struct vcpu *vcpu = &vm->vcpu[vcpuid];
+ hma_fpu_xsave_result_t res;
+
+ res = hma_fpu_set_xsave_state(vcpu->guestfpu, buf, len);
+ return (translate_hma_xsave_result(res));
+}
+
int
vm_get_run_state(struct vm *vm, int vcpuid, uint32_t *state, uint8_t *sipi_vec)
{
@@ -1220,13 +1265,9 @@ vm_track_dirty_pages(struct vm *vm, uint64_t gpa, size_t len, uint8_t *bitmap)
static void
restore_guest_fpustate(struct vcpu *vcpu)
{
-
- /* flush host state to the pcb */
- fpuexit(curthread);
-
- /* restore guest FPU state */
+ /* Save host FPU and restore guest FPU */
fpu_stop_emulating();
- fpurestore(vcpu->guestfpu);
+ hma_fpu_start_guest(vcpu->guestfpu);
/* restore guest XCR0 if XSAVE is enabled in the host */
if (rcr4() & CR4_XSAVE)
@@ -1252,9 +1293,9 @@ save_guest_fpustate(struct vcpu *vcpu)
load_xcr(0, vmm_get_host_xcr0());
}
- /* save guest FPU state */
+ /* save guest FPU and restore host FPU */
fpu_stop_emulating();
- fpusave(vcpu->guestfpu);
+ hma_fpu_stop_guest(vcpu->guestfpu);
/*
* When the host state has been restored, we should not re-enable
* CR0.TS on illumos for eager FPU.
@@ -2912,7 +2953,7 @@ vcpu_arch_reset(struct vm *vm, int vcpuid, bool init_only)
*/
if (!init_only) {
vcpu->guest_xcr0 = XFEATURE_ENABLED_X87;
- fpu_save_area_reset(vcpu->guestfpu);
+ hma_fpu_init(vcpu->guestfpu);
/* XXX: clear MSRs and other pieces */
}
diff --git a/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c b/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
index a83989e9eb..4ef2e5f583 100644
--- a/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
+++ b/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
@@ -414,6 +414,8 @@ vmmdev_do_ioctl(vmm_softc_t *sc, int cmd, intptr_t arg, int md,
case VM_RESET_CPU:
case VM_GET_RUN_STATE:
case VM_SET_RUN_STATE:
+ case VM_GET_FPU:
+ case VM_SET_FPU:
/*
* Copy in the ID of the vCPU chosen for this operation.
* Since a nefarious caller could update their struct between
@@ -469,6 +471,7 @@ vmmdev_do_ioctl(vmm_softc_t *sc, int cmd, intptr_t arg, int md,
case VM_GET_GPA_PMAP:
case VM_IOAPIC_PINCOUNT:
case VM_SUSPEND:
+ case VM_DESC_FPU_AREA:
default:
break;
}
@@ -755,6 +758,53 @@ vmmdev_do_ioctl(vmm_softc_t *sc, int cmd, intptr_t arg, int md,
}
break;
}
+ case VM_DESC_FPU_AREA: {
+ struct vm_fpu_desc desc;
+ void *buf = NULL;
+
+ if (ddi_copyin(datap, &desc, sizeof (desc), md)) {
+ error = EFAULT;
+ break;
+ }
+ if (desc.vfd_num_entries > 64) {
+ error = EINVAL;
+ break;
+ }
+ const size_t buf_sz = sizeof (struct vm_fpu_desc_entry) *
+ desc.vfd_num_entries;
+ if (buf_sz != 0) {
+ buf = kmem_zalloc(buf_sz, KM_SLEEP);
+ }
+
+ /*
+ * For now, we are depending on vm_fpu_desc_entry and
+ * hma_xsave_state_desc_t having the same format.
+ */
+ CTASSERT(sizeof (struct vm_fpu_desc_entry) ==
+ sizeof (hma_xsave_state_desc_t));
+
+ size_t req_size;
+ const uint_t max_entries = hma_fpu_describe_xsave_state(
+ (hma_xsave_state_desc_t *)buf,
+ desc.vfd_num_entries,
+ &req_size);
+
+ desc.vfd_req_size = req_size;
+ desc.vfd_num_entries = max_entries;
+ if (buf_sz != 0) {
+ if (ddi_copyout(buf, desc.vfd_entry_data, buf_sz, md)) {
+ error = EFAULT;
+ }
+ kmem_free(buf, buf_sz);
+ }
+
+ if (error == 0) {
+ if (ddi_copyout(&desc, datap, sizeof (desc), md)) {
+ error = EFAULT;
+ }
+ }
+ break;
+ }
case VM_ISA_ASSERT_IRQ: {
struct vm_isa_irq isa_irq;
@@ -1040,6 +1090,51 @@ vmmdev_do_ioctl(vmm_softc_t *sc, int cmd, intptr_t arg, int md,
vrs.sipi_vector);
break;
}
+ case VM_GET_FPU: {
+ struct vm_fpu_state req;
+ const size_t max_len = (PAGESIZE * 2);
+ void *kbuf;
+
+ if (ddi_copyin(datap, &req, sizeof (req), md)) {
+ error = EFAULT;
+ break;
+ }
+ if (req.len > max_len || req.len == 0) {
+ error = EINVAL;
+ break;
+ }
+ kbuf = kmem_zalloc(req.len, KM_SLEEP);
+ error = vm_get_fpu(sc->vmm_vm, vcpu, kbuf, req.len);
+ if (error == 0) {
+ if (ddi_copyout(kbuf, req.buf, req.len, md)) {
+ error = EFAULT;
+ }
+ }
+ kmem_free(kbuf, req.len);
+ break;
+ }
+ case VM_SET_FPU: {
+ struct vm_fpu_state req;
+ const size_t max_len = (PAGESIZE * 2);
+ void *kbuf;
+
+ if (ddi_copyin(datap, &req, sizeof (req), md)) {
+ error = EFAULT;
+ break;
+ }
+ if (req.len > max_len || req.len == 0) {
+ error = EINVAL;
+ break;
+ }
+ kbuf = kmem_alloc(req.len, KM_SLEEP);
+ if (ddi_copyin(req.buf, kbuf, req.len, md)) {
+ error = EFAULT;
+ } else {
+ error = vm_set_fpu(sc->vmm_vm, vcpu, kbuf, req.len);
+ }
+ kmem_free(kbuf, req.len);
+ break;
+ }
case VM_SET_KERNEMU_DEV:
case VM_GET_KERNEMU_DEV: {
diff --git a/usr/src/uts/i86pc/io/vmm/vmm_sol_glue.c b/usr/src/uts/i86pc/io/vmm/vmm_sol_glue.c
index f78db731d6..cdcebc71d4 100644
--- a/usr/src/uts/i86pc/io/vmm/vmm_sol_glue.c
+++ b/usr/src/uts/i86pc/io/vmm/vmm_sol_glue.c
@@ -58,7 +58,6 @@
#include <sys/x86_archext.h>
#include <machine/cpufunc.h>
-#include <machine/fpu.h>
#include <machine/md_var.h>
#include <machine/specialreg.h>
#include <machine/vmm.h>
@@ -434,67 +433,6 @@ vmm_cpuid_init(void)
cpu_exthigh = regs[0];
}
-/*
- * FreeBSD uses the struct savefpu for managing the FPU state. That is mimicked
- * by our hypervisor multiplexor framework structure.
- */
-struct savefpu *
-fpu_save_area_alloc(void)
-{
- return ((struct savefpu *)hma_fpu_alloc(KM_SLEEP));
-}
-
-void
-fpu_save_area_free(struct savefpu *fsa)
-{
- hma_fpu_t *fpu = (hma_fpu_t *)fsa;
- hma_fpu_free(fpu);
-}
-
-void
-fpu_save_area_reset(struct savefpu *fsa)
-{
- hma_fpu_t *fpu = (hma_fpu_t *)fsa;
- hma_fpu_init(fpu);
-}
-
-/*
- * This glue function is supposed to save the host's FPU state. This is always
- * paired in the general bhyve code with a call to fpusave. Therefore, we treat
- * this as a nop and do all the work in fpusave(), which will have the context
- * argument that we want anyways.
- */
-void
-fpuexit(kthread_t *td)
-{
-}
-
-/*
- * This glue function is supposed to restore the guest's FPU state from the save
- * area back to the host. In FreeBSD, it is assumed that the host state has
- * already been saved by a call to fpuexit(); however, we do both here.
- */
-void
-fpurestore(void *arg)
-{
- hma_fpu_t *fpu = arg;
-
- hma_fpu_start_guest(fpu);
-}
-
-/*
- * This glue function is supposed to save the guest's FPU state. The host's FPU
- * state is not expected to be restored necessarily due to the use of FPU
- * emulation through CR0.TS. However, we can and do restore it here.
- */
-void
-fpusave(void *arg)
-{
- hma_fpu_t *fpu = arg;
-
- hma_fpu_stop_guest(fpu);
-}
-
void
vmm_sol_glue_init(void)
{
diff --git a/usr/src/uts/i86pc/os/cmi_hw.c b/usr/src/uts/i86pc/os/cmi_hw.c
index fb59826431..094f5d2bff 100644
--- a/usr/src/uts/i86pc/os/cmi_hw.c
+++ b/usr/src/uts/i86pc/os/cmi_hw.c
@@ -302,7 +302,7 @@ cmi_inj_tainted(void)
#define CMI_MSRI_HASHSZ 16
#define CMI_MSRI_HASHIDX(hdl, msr) \
- (((uintptr_t)(hdl) >> 3 + (msr)) % (CMI_MSRI_HASHSZ - 1))
+ ((((uintptr_t)(hdl) >> 3) + (msr)) % (CMI_MSRI_HASHSZ - 1))
struct cmi_msri_bkt {
kmutex_t msrib_lock;
diff --git a/usr/src/uts/i86pc/os/cpuid.c b/usr/src/uts/i86pc/os/cpuid.c
index bdaa26681d..364881ebf3 100644
--- a/usr/src/uts/i86pc/os/cpuid.c
+++ b/usr/src/uts/i86pc/os/cpuid.c
@@ -2832,7 +2832,6 @@ cpuid_patch_retpolines(x86_spectrev2_mitigation_t mit)
uintptr_t source, dest;
int ssize, dsize;
char sourcebuf[64], destbuf[64];
- size_t len;
(void) snprintf(destbuf, sizeof (destbuf),
"__x86_indirect_thunk%s", thunks[i]);
@@ -4295,9 +4294,9 @@ cpuid_pass1(cpu_t *cpu, uchar_t *featureset)
if (cpi->cpi_family == 0xf || cpi->cpi_family == 0x11) {
add_x86_feature(featureset, X86FSET_LFENCE_SER);
} else if (cpi->cpi_family >= 0x10) {
- uint64_t val = 0;
-
#if !defined(__xpv)
+ uint64_t val;
+
/*
* Be careful when attempting to enable the bit, and
* verify that it was actually set in case we are
@@ -4310,13 +4309,15 @@ cpuid_pass1(cpu_t *cpu, uchar_t *featureset)
val |= AMD_DE_CFG_LFENCE_DISPATCH;
wrmsr(MSR_AMD_DE_CFG, val);
val = rdmsr(MSR_AMD_DE_CFG);
+ } else {
+ val = 0;
}
no_trap();
-#endif
if ((val & AMD_DE_CFG_LFENCE_DISPATCH) != 0) {
add_x86_feature(featureset, X86FSET_LFENCE_SER);
}
+#endif
}
} else if (cpi->cpi_vendor == X86_VENDOR_Intel &&
is_x86_feature(featureset, X86FSET_SSE2)) {
@@ -4769,8 +4770,8 @@ cpuid_pass2(cpu_t *cpu)
* Before then, don't trust the data.
*/
if (cpi->cpi_family < 6 ||
- cpi->cpi_family == 6 &&
- cpi->cpi_model < 1)
+ (cpi->cpi_family == 6 &&
+ cpi->cpi_model < 1))
cp->cp_eax = cp->cp_ebx = 0;
/*
* AMD Duron rev A0 reports L2
diff --git a/usr/src/uts/i86pc/os/cpuid_subr.c b/usr/src/uts/i86pc/os/cpuid_subr.c
index 18d242eb55..1c79138139 100644
--- a/usr/src/uts/i86pc/os/cpuid_subr.c
+++ b/usr/src/uts/i86pc/os/cpuid_subr.c
@@ -91,10 +91,11 @@
* 18 for family 0x18, models 00 - 0f
* 19 for family 0x19, models 00 - 0f
* 20 for family 0x19, models 20 - 2f
+ * 21 for family 0x19, models 50 - 5f
* Second index by (model & 0x3) for family 0fh,
* CPUID pkg bits (Fn8000_0001_EBX[31:28]) for later families.
*/
-static uint32_t amd_skts[21][8] = {
+static uint32_t amd_skts[22][8] = {
/*
* Family 0xf revisions B through E
*/
@@ -408,7 +409,22 @@ static uint32_t amd_skts[21][8] = {
X86_SOCKET_UNKNOWN, /* 0b101 */
X86_SOCKET_UNKNOWN, /* 0b110 */
X86_SOCKET_UNKNOWN /* 0b111 */
- }
+ },
+
+ /*
+ * Family 0x19 models 50-5f (Zen 3 - Cezanne)
+ */
+#define A_SKTS_21 21
+ {
+ X86_SOCKET_FP6, /* 0b000 */
+ X86_SOCKET_UNKNOWN, /* 0b001 */
+ X86_SOCKET_AM4, /* 0b010 */
+ X86_SOCKET_UNKNOWN, /* 0b011 */
+ X86_SOCKET_UNKNOWN, /* 0b100 */
+ X86_SOCKET_UNKNOWN, /* 0b101 */
+ X86_SOCKET_UNKNOWN, /* 0b110 */
+ X86_SOCKET_UNKNOWN /* 0b111 */
+ },
};
struct amd_sktmap_s {
@@ -480,7 +496,8 @@ static const struct amd_skt_mapent {
{ 0x17, 0x70, 0x7f, A_SKTS_17 },
{ 0x18, 0x00, 0x0f, A_SKTS_18 },
{ 0x19, 0x00, 0x0f, A_SKTS_19 },
- { 0x19, 0x20, 0x2f, A_SKTS_20 }
+ { 0x19, 0x20, 0x2f, A_SKTS_20 },
+ { 0x19, 0x50, 0x5f, A_SKTS_21 }
};
/*
diff --git a/usr/src/uts/i86pc/os/ddi_impl.c b/usr/src/uts/i86pc/os/ddi_impl.c
index e10e676c3c..1eff8e6135 100644
--- a/usr/src/uts/i86pc/os/ddi_impl.c
+++ b/usr/src/uts/i86pc/os/ddi_impl.c
@@ -832,12 +832,6 @@ impl_ddi_sunbus_removechild(dev_info_t *dip)
int ignore_hardware_nodes = 0;
/*
- * Local data
- */
-static struct impl_bus_promops *impl_busp;
-
-
-/*
* New DDI interrupt framework
*/
@@ -1424,7 +1418,8 @@ kalloca(size_t size, size_t align, int cansleep, int physcontig,
rsize = P2ROUNDUP_TYPED(size + align, KA_ALIGN, size_t);
if (physcontig && rsize > PAGESIZE) {
- if (addr = contig_alloc(size, attr, align, cansleep)) {
+ if ((addr = contig_alloc(size, attr, align, cansleep)) !=
+ NULL) {
if (!putctgas(addr, size))
contig_free(addr, size);
else
@@ -2187,12 +2182,13 @@ x86_old_bootpath_name_addr_match(dev_info_t *cdip, char *caddr, char *naddr)
*
* bootpath assumed to be of the form /bus/module@name_addr
*/
- if (busp = strchr(bp1275, '/')) {
- if (modp = strchr(busp + 1, '/')) {
- if (atp = strchr(modp + 1, '@')) {
+ if ((busp = strchr(bp1275, '/')) != NULL) {
+ if ((modp = strchr(busp + 1, '/')) != NULL) {
+ if ((atp = strchr(modp + 1, '@')) != NULL) {
*atp = '\0';
addrp = atp + 1;
- if (eoaddrp = strchr(addrp, '/'))
+ if ((eoaddrp = strchr(addrp, '/')) !=
+ NULL)
*eoaddrp = '\0';
}
}
@@ -2222,12 +2218,13 @@ x86_old_bootpath_name_addr_match(dev_info_t *cdip, char *caddr, char *naddr)
* bootpath assumed to be of the form /bus/module@name_addr
*/
addrp = NULL;
- if (busp = strchr(bp, '/')) {
- if (modp = strchr(busp + 1, '/')) {
- if (atp = strchr(modp + 1, '@')) {
+ if ((busp = strchr(bp, '/')) != NULL) {
+ if ((modp = strchr(busp + 1, '/')) != NULL) {
+ if ((atp = strchr(modp + 1, '@')) != NULL) {
*atp = '\0';
addrp = atp + 1;
- if (eoaddrp = strchr(addrp, '/'))
+ if ((eoaddrp = strchr(addrp, '/')) !=
+ NULL)
*eoaddrp = '\0';
}
}
@@ -2296,11 +2293,12 @@ e_ddi_copytodev(dev_info_t *devi,
static int
poke_mem(peekpoke_ctlops_t *in_args)
{
- int err = DDI_SUCCESS;
+ int err;
on_trap_data_t otd;
/* Set up protected environment. */
if (!on_trap(&otd, OT_DATA_ACCESS)) {
+ err = DDI_SUCCESS;
switch (in_args->size) {
case sizeof (uint8_t):
*(uint8_t *)(in_args->dev_addr) =
@@ -2326,8 +2324,9 @@ poke_mem(peekpoke_ctlops_t *in_args)
err = DDI_FAILURE;
break;
}
- } else
+ } else {
err = DDI_FAILURE;
+ }
/* Take down protected environment. */
no_trap();
@@ -2339,10 +2338,11 @@ poke_mem(peekpoke_ctlops_t *in_args)
static int
peek_mem(peekpoke_ctlops_t *in_args)
{
- int err = DDI_SUCCESS;
+ int err;
on_trap_data_t otd;
if (!on_trap(&otd, OT_DATA_ACCESS)) {
+ err = DDI_SUCCESS;
switch (in_args->size) {
case sizeof (uint8_t):
*(uint8_t *)in_args->host_addr =
@@ -2368,8 +2368,9 @@ peek_mem(peekpoke_ctlops_t *in_args)
err = DDI_FAILURE;
break;
}
- } else
+ } else {
err = DDI_FAILURE;
+ }
no_trap();
return (err);
diff --git a/usr/src/uts/i86pc/os/fakebop.c b/usr/src/uts/i86pc/os/fakebop.c
index 4ae1d27056..eb91d4a56a 100644
--- a/usr/src/uts/i86pc/os/fakebop.c
+++ b/usr/src/uts/i86pc/os/fakebop.c
@@ -2922,7 +2922,8 @@ build_firmware_properties(struct xboot_info *xbp)
find_fw_table(rsdp, ACPI_SIG_SRAT)) != NULL)
process_srat(srat_ptr);
- if (slit_ptr = (ACPI_TABLE_SLIT *)find_fw_table(rsdp, ACPI_SIG_SLIT))
+ if ((slit_ptr = (ACPI_TABLE_SLIT *)find_fw_table(rsdp,
+ ACPI_SIG_SLIT)) != NULL)
process_slit(slit_ptr);
tp = find_fw_table(rsdp, ACPI_SIG_MCFG);
diff --git a/usr/src/uts/i86pc/os/hma_fpu.c b/usr/src/uts/i86pc/os/hma_fpu.c
index 14cfa8baed..138af7a32a 100644
--- a/usr/src/uts/i86pc/os/hma_fpu.c
+++ b/usr/src/uts/i86pc/os/hma_fpu.c
@@ -11,6 +11,7 @@
/*
* Copyright (c) 2018, Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -28,6 +29,12 @@
#include <sys/hma.h>
#include <sys/x86_archext.h>
#include <sys/archsystm.h>
+#include <sys/controlregs.h>
+#include <sys/sysmacros.h>
+#include <sys/stdbool.h>
+#include <sys/ontrap.h>
+#include <sys/cpuvar.h>
+#include <sys/disp.h>
struct hma_fpu {
fpu_ctx_t hf_guest_fpu;
@@ -57,7 +64,7 @@ hma_fpu_init(hma_fpu_t *fpu)
xs = fpu->hf_guest_fpu.fpu_regs.kfpu_u.kfpu_xs;
bzero(xs, cpuid_get_xsave_size());
bcopy(&avx_initial, xs, sizeof (*xs));
- xs->xs_xstate_bv = XFEATURE_LEGACY_FP | XFEATURE_SSE;
+ xs->xs_header.xsh_xstate_bv = XFEATURE_LEGACY_FP | XFEATURE_SSE;
fpu->hf_guest_fpu.fpu_xsave_mask = XFEATURE_FP_ALL;
break;
default:
@@ -140,6 +147,36 @@ hma_fpu_start_guest(hma_fpu_t *fpu)
fpu->hf_guest_fpu.fpu_flags &= ~FPU_VALID;
}
+/*
+ * Since fp_save() assumes a thread-centric view of the FPU usage -- it will
+ * assert if attempting to save elsewhere than the thread PCB, and will elide
+ * action if the FPU is not enabled -- we cannot use it for the manual saving of
+ * FPU contents. To work around that, we call the save mechanism directly.
+ */
+static void
+do_fp_save(fpu_ctx_t *fpu)
+{
+ /*
+ * For our manual saving, we expect that the thread PCB never be the
+ * landing zone for the data.
+ */
+ ASSERT(curthread->t_lwp == NULL ||
+ fpu != &curthread->t_lwp->lwp_pcb.pcb_fpu);
+
+ switch (fp_save_mech) {
+ case FP_FXSAVE:
+ fpxsave(fpu->fpu_regs.kfpu_u.kfpu_fx);
+ break;
+ case FP_XSAVE:
+ xsavep(fpu->fpu_regs.kfpu_u.kfpu_xs, fpu->fpu_xsave_mask);
+ break;
+ default:
+ panic("Invalid fp_save_mech");
+ }
+ fpu->fpu_flags |= FPU_VALID;
+}
+
+
void
hma_fpu_stop_guest(hma_fpu_t *fpu)
{
@@ -148,29 +185,232 @@ hma_fpu_stop_guest(hma_fpu_t *fpu)
ASSERT3U(fpu->hf_guest_fpu.fpu_flags & FPU_EN, !=, 0);
ASSERT3U(fpu->hf_guest_fpu.fpu_flags & FPU_VALID, ==, 0);
+ do_fp_save(&fpu->hf_guest_fpu);
+
+ fp_restore(&curthread->t_lwp->lwp_pcb.pcb_fpu);
+
+ fpu->hf_inguest = B_FALSE;
+ fpu->hf_curthread = NULL;
+}
+
+/*
+ * Will output up to `ndesc` records into `descp`. The required size for an
+ * XSAVE area containing all of the data fields supported by the host will be
+ * placed in `req_sizep` (if non-NULL). Returns the number of feature bits
+ * supported by the host.
+ */
+uint_t
+hma_fpu_describe_xsave_state(hma_xsave_state_desc_t *descp, uint_t ndesc,
+ size_t *req_sizep)
+{
+ uint64_t features;
+
+ switch (fp_save_mech) {
+ case FP_FXSAVE:
+ /*
+ * Even without xsave support, the FPU will have legacy x87
+ * float and SSE state contained within.
+ */
+ features = XFEATURE_LEGACY_FP | XFEATURE_SSE;
+ break;
+ case FP_XSAVE:
+ features = get_xcr(XFEATURE_ENABLED_MASK);
+ break;
+ default:
+ panic("Invalid fp_save_mech");
+ }
+
+ uint_t count, pos;
+ uint_t max_size = MIN_XSAVE_SIZE;
+ for (count = 0, pos = 0; pos <= 63; pos++) {
+ const uint64_t bit = (1 << pos);
+ uint32_t size, off;
+
+ if ((features & bit) == 0) {
+ continue;
+ }
+
+ if (bit == XFEATURE_LEGACY_FP || bit == XFEATURE_SSE) {
+ size = sizeof (struct fxsave_state);
+ off = 0;
+ } else {
+ /*
+ * Size and position of data types within the XSAVE area
+ * is described in leaf 0xD in the subfunction
+ * corresponding to the bit position (for pos > 1).
+ */
+ struct cpuid_regs regs = {
+ .cp_eax = 0xD,
+ .cp_ecx = pos,
+ };
+
+ ASSERT3U(pos, >, 1);
+
+ (void) __cpuid_insn(&regs);
+ size = regs.cp_eax;
+ off = regs.cp_ebx;
+ }
+ max_size = MAX(max_size, off + size);
+
+ if (count < ndesc) {
+ hma_xsave_state_desc_t *desc = &descp[count];
+
+ desc->hxsd_bit = bit;
+ desc->hxsd_size = size;
+ desc->hxsd_off = off;
+ }
+ count++;
+ }
+ if (req_sizep != NULL) {
+ *req_sizep = max_size;
+ }
+ return (count);
+}
+
+hma_fpu_xsave_result_t
+hma_fpu_get_xsave_state(const hma_fpu_t *fpu, void *buf, size_t len)
+{
+ ASSERT(!fpu->hf_inguest);
+
+ size_t valid_len;
+ switch (fp_save_mech) {
+ case FP_FXSAVE: {
+ if (len < MIN_XSAVE_SIZE) {
+ return (HFXR_NO_SPACE);
+ }
+ bcopy(fpu->hf_guest_fpu.fpu_regs.kfpu_u.kfpu_generic, buf,
+ sizeof (struct fxsave_state));
+
+ struct xsave_header hdr = {
+ .xsh_xstate_bv = XFEATURE_LEGACY_FP | XFEATURE_SSE,
+ };
+ bcopy(&hdr, buf + sizeof (struct fxsave_state), sizeof (hdr));
+
+ break;
+ }
+ case FP_XSAVE:
+ (void) hma_fpu_describe_xsave_state(NULL, 0, &valid_len);
+ if (len < valid_len) {
+ return (HFXR_NO_SPACE);
+ }
+ bcopy(fpu->hf_guest_fpu.fpu_regs.kfpu_u.kfpu_generic, buf,
+ valid_len);
+ break;
+ default:
+ panic("Invalid fp_save_mech");
+ }
+
+ return (HFXR_OK);
+}
+
+hma_fpu_xsave_result_t
+hma_fpu_set_xsave_state(hma_fpu_t *fpu, void *buf, size_t len)
+{
+ ASSERT(!fpu->hf_inguest);
+
+ if (len < MIN_XSAVE_SIZE) {
+ return (HFXR_NO_SPACE);
+ }
+ /* 64-byte alignment is demanded of the FPU-related operations */
+ if (((uintptr_t)buf & 63) != 0) {
+ return (HFXR_BAD_ALIGN);
+ }
+
+ struct xsave_header *hdr = buf + sizeof (struct fxsave_state);
+ if (hdr->xsh_xcomp_bv != 0) {
+ /* XSAVEC formatting not supported at this time */
+ return (HFXR_UNSUP_FMT);
+ }
+
+ uint64_t allowed_bits;
+ size_t save_area_size;
+ switch (fp_save_mech) {
+ case FP_FXSAVE:
+ allowed_bits = XFEATURE_LEGACY_FP | XFEATURE_SSE;
+ save_area_size = sizeof (struct fxsave_state);
+ break;
+ case FP_XSAVE:
+ allowed_bits = get_xcr(XFEATURE_ENABLED_MASK);
+ save_area_size = cpuid_get_xsave_size();
+ break;
+ default:
+ panic("Invalid fp_save_mech");
+ }
+ if ((hdr->xsh_xstate_bv & ~(allowed_bits)) != 0) {
+ return (HFXR_UNSUP_FEAT);
+ }
+
/*
- * Note, we can't use fp_save because it assumes that we're saving to
- * the thread's PCB and not somewhere else. Because this is a different
- * FPU context, we instead have to do this ourselves.
+ * We validate the incoming state with the FPU itself prior to saving it
+ * into the guest FPU context area. In order to preserve any state
+ * currently housed in the FPU, we save it to a temporarily allocated
+ * FPU context. It is important to note that we are not following the
+ * normal rules around state management detailed in uts/intel/os/fpu.c.
+ * This saving is unconditional, uncaring about the state in the FPU or
+ * the value of CR0_TS, simplifying our process before returning to the
+ * caller (without needing to chcek of an lwp, etc). To prevent
+ * interrupting threads from encountering this unusual FPU state, we
+ * keep interrupts disabled for the duration.
*/
+ fpu_ctx_t temp_ctx = {
+ .fpu_xsave_mask = XFEATURE_FP_ALL,
+ };
+ temp_ctx.fpu_regs.kfpu_u.kfpu_generic =
+ kmem_cache_alloc(fpsave_cachep, KM_SLEEP);
+ bzero(temp_ctx.fpu_regs.kfpu_u.kfpu_generic, save_area_size);
+
+ ulong_t iflag;
+ iflag = intr_clear();
+ bool disable_when_done = (getcr0() & CR0_TS) != 0;
+ do_fp_save(&temp_ctx);
+
+ /*
+ * If the provided data is invalid, it will cause a #GP when we attempt
+ * to load it into the FPU, so protect against that with on_trap().
+ * Should the data load successfully, we can then be confident that its
+ * later use in via hma_fpu_start_guest() will be safe.
+ */
+ on_trap_data_t otd;
+ volatile hma_fpu_xsave_result_t res = HFXR_OK;
+ if (on_trap(&otd, OT_DATA_EC) != 0) {
+ res = HFXR_INVALID_DATA;
+ goto done;
+ }
+
switch (fp_save_mech) {
case FP_FXSAVE:
- fpxsave(fpu->hf_guest_fpu.fpu_regs.kfpu_u.kfpu_fx);
+ if (hdr->xsh_xstate_bv == 0) {
+ /*
+ * An empty xstate_bv means we can simply load the
+ * legacy FP/SSE area with their initial state.
+ */
+ bcopy(&sse_initial,
+ fpu->hf_guest_fpu.fpu_regs.kfpu_u.kfpu_fx,
+ sizeof (sse_initial));
+ } else {
+ fpxrestore(buf);
+ fpxsave(fpu->hf_guest_fpu.fpu_regs.kfpu_u.kfpu_fx);
+ }
break;
case FP_XSAVE:
+ xrestore(buf, XFEATURE_FP_ALL);
xsavep(fpu->hf_guest_fpu.fpu_regs.kfpu_u.kfpu_xs,
fpu->hf_guest_fpu.fpu_xsave_mask);
break;
default:
panic("Invalid fp_save_mech");
- /*NOTREACHED*/
}
- fpu->hf_guest_fpu.fpu_flags |= FPU_VALID;
- fp_restore(&curthread->t_lwp->lwp_pcb.pcb_fpu);
+done:
+ no_trap();
+ fp_restore(&temp_ctx);
+ if (disable_when_done) {
+ fpdisable();
+ }
+ intr_restore(iflag);
+ kmem_cache_free(fpsave_cachep, temp_ctx.fpu_regs.kfpu_u.kfpu_generic);
- fpu->hf_inguest = B_FALSE;
- fpu->hf_curthread = NULL;
+ return (res);
}
void
@@ -214,11 +454,11 @@ hma_fpu_set_fxsave_state(hma_fpu_t *fpu, const struct fxsave_state *fx)
gxs = fpu->hf_guest_fpu.fpu_regs.kfpu_u.kfpu_xs;
bzero(gxs, cpuid_get_xsave_size());
bcopy(fx, &gxs->xs_fxsave, sizeof (*fx));
- gxs->xs_xstate_bv = XFEATURE_LEGACY_FP | XFEATURE_SSE;
+ gxs->xs_header.xsh_xstate_bv =
+ XFEATURE_LEGACY_FP | XFEATURE_SSE;
break;
default:
panic("Invalid fp_save_mech");
- /* NOTREACHED */
}
return (0);
diff --git a/usr/src/uts/i86pc/os/lgrpplat.c b/usr/src/uts/i86pc/os/lgrpplat.c
index d398a19291..ed463fba8f 100644
--- a/usr/src/uts/i86pc/os/lgrpplat.c
+++ b/usr/src/uts/i86pc/os/lgrpplat.c
@@ -1070,7 +1070,7 @@ lgrp_plat_latency(lgrp_handle_t from, lgrp_handle_t to)
/*
* Return 0 for nodes (lgroup platform handles) out of range
*/
- if (src < 0 || src >= MAX_NODES || dest < 0 || dest >= MAX_NODES)
+ if (src >= MAX_NODES || dest >= MAX_NODES)
return (0);
/*
diff --git a/usr/src/uts/i86pc/os/mp_startup.c b/usr/src/uts/i86pc/os/mp_startup.c
index 824cd8d9d5..e90dc6466a 100644
--- a/usr/src/uts/i86pc/os/mp_startup.c
+++ b/usr/src/uts/i86pc/os/mp_startup.c
@@ -803,7 +803,7 @@ do_erratum_298(struct cpu *cpu)
uint_t
workaround_errata(struct cpu *cpu)
{
- uint_t missing = 0;
+ volatile uint_t missing = 0;
ASSERT(cpu == CPU);
diff --git a/usr/src/uts/i86pc/os/pci_bios.c b/usr/src/uts/i86pc/os/pci_bios.c
index a24064b8cb..84653435ad 100644
--- a/usr/src/uts/i86pc/os/pci_bios.c
+++ b/usr/src/uts/i86pc/os/pci_bios.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2022 Oxide Computer Company
*/
#include <sys/types.h>
@@ -218,3 +219,23 @@ pci_slot_names_prop(int bus, char *buf, int len)
*(buf + plen) = 0;
return (plen);
}
+
+/*
+ * This is used to discover additional PCI buses that may exist in the system in
+ * addition to the ACPI _BBN method. Historically these were discovered by
+ * asking if there was a valid slot property, e.g. pci_slot_names_prop()
+ * returned valid data. In this case we return any entry that has a bus number
+ * and a non-zero slot value. We rely on the core PCI code to do dedup for us.
+ */
+void
+pci_bios_bus_iter(pci_prd_root_complex_f cbfunc, void *arg)
+{
+ int i;
+ for (i = 0; i < pci_irq_nroutes; i++) {
+ if (pci_irq_routes[i].pir_slot != 0) {
+ if (!cbfunc(pci_irq_routes[i].pir_bus, arg)) {
+ return;
+ }
+ }
+ }
+}
diff --git a/usr/src/uts/i86pc/os/smt.c b/usr/src/uts/i86pc/os/smt.c
index d3ce5333e6..7ba9d3025d 100644
--- a/usr/src/uts/i86pc/os/smt.c
+++ b/usr/src/uts/i86pc/os/smt.c
@@ -744,8 +744,6 @@ smt_init(void)
void
smt_late_init(void)
{
- int err;
-
if (smt_boot_disable) {
int err;
diff --git a/usr/src/uts/i86pc/os/startup.c b/usr/src/uts/i86pc/os/startup.c
index 75e305c0fa..f1ef7c105c 100644
--- a/usr/src/uts/i86pc/os/startup.c
+++ b/usr/src/uts/i86pc/os/startup.c
@@ -2397,8 +2397,8 @@ release_bootstrap(void)
continue;
}
- if (root_is_ramdisk && pp_in_range(pp, ramdisk_start,
- ramdisk_end) || pp_in_module(pp, modranges)) {
+ if ((root_is_ramdisk && pp_in_range(pp, ramdisk_start,
+ ramdisk_end)) || pp_in_module(pp, modranges)) {
pp->p_next = rd_pages;
rd_pages = pp;
continue;
@@ -2818,7 +2818,6 @@ set_soft_hostid(void)
int i;
int32_t hostid = (int32_t)HW_INVALID_HOSTID;
unsigned char *c;
- hrtime_t tsc;
smbios_system_t smsys;
/*
diff --git a/usr/src/uts/i86pc/os/trap.c b/usr/src/uts/i86pc/os/trap.c
index d3eb318b84..6c85fcb135 100644
--- a/usr/src/uts/i86pc/os/trap.c
+++ b/usr/src/uts/i86pc/os/trap.c
@@ -966,7 +966,7 @@ trap(struct regs *rp, caddr_t addr, processorid_t cpuid)
case T_EXTERRFLT + USER: /* x87 floating point exception pending */
if (tudebug && tudebugfpe)
showregs(type, rp, addr);
- if (sicode = fpexterrflt(rp)) {
+ if ((sicode = fpexterrflt(rp)) != 0) {
siginfo.si_signo = SIGFPE;
siginfo.si_code = sicode;
siginfo.si_addr = (caddr_t)rp->r_pc;
@@ -1917,7 +1917,7 @@ dump_ttrace(void)
trap_trace_ctl_t *ttc;
trap_trace_rec_t *rec;
uintptr_t current;
- int i, j, k;
+ int i, j;
int n = NCPU;
const char banner[] =
"CPU ADDRESS TIMESTAMP TYPE VC HANDLER PC\n";
@@ -1993,6 +1993,7 @@ dump_ttrace(void)
stype = "syse"; /* sysenter */
break;
default:
+ stype = "";
break;
}
(void) snprintf(data2, sizeof (data2), fmt2,
diff --git a/usr/src/uts/i86pc/pci_prd/Makefile b/usr/src/uts/i86pc/pci_prd/Makefile
new file mode 100644
index 0000000000..ca262cc4a4
--- /dev/null
+++ b/usr/src/uts/i86pc/pci_prd/Makefile
@@ -0,0 +1,66 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2022 Oxide Computer Company
+#
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = pci_prd
+OBJECTS = $(PCI_PRD_OBJS:%=$(OBJS_DIR)/%)
+ROOTMODULE = $(ROOT_PSM_MISC_DIR)/$(MODULE)
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/i86pc/Makefile.i86pc
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+
+LDFLAGS += -Nmisc/acpica
+
+#
+# Overrides
+#
+
+ALL_BUILDS = $(ALL_BUILDSONLY64)
+DEF_BUILDS = $(DEF_BUILDSONLY64)
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/i86pc/Makefile.targ
diff --git a/usr/src/uts/i86pc/sys/hma.h b/usr/src/uts/i86pc/sys/hma.h
index 16ab708896..e15cd60d5e 100644
--- a/usr/src/uts/i86pc/sys/hma.h
+++ b/usr/src/uts/i86pc/sys/hma.h
@@ -11,6 +11,7 @@
/*
* Copyright 2019 Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
#ifndef _SYS_HMA_H
@@ -117,6 +118,43 @@ extern void hma_fpu_start_guest(hma_fpu_t *);
*/
extern void hma_fpu_stop_guest(hma_fpu_t *);
+typedef enum {
+ HFXR_OK = 0,
+ HFXR_NO_SPACE, /* buffer is not large enough */
+ HFXR_BAD_ALIGN, /* buffer is not properly (64-byte) aligned */
+ HFXR_UNSUP_FMT, /* data using unsupported (compressed) format */
+ HFXR_UNSUP_FEAT, /* data has unsupported features set */
+ HFXR_INVALID_DATA, /* CPU determined xsave data is invalid */
+} hma_fpu_xsave_result_t;
+
+/*
+ * Get and set the contents of the FPU save area, formatted as XSAVE-style
+ * information. If XSAVE is not supported by the host, the input and output
+ * values will be translated to and from the FXSAVE format. Attempts to set
+ * XSAVE values not supported by the host will result in an error.
+ *
+ * These functions cannot be called while the FPU is in use by the guest. It is
+ * up to callers to guarantee this invariant.
+ */
+extern hma_fpu_xsave_result_t hma_fpu_get_xsave_state(const hma_fpu_t *, void *,
+ size_t);
+extern hma_fpu_xsave_result_t hma_fpu_set_xsave_state(hma_fpu_t *, void *,
+ size_t);
+
+typedef struct hma_xsave_state_desc {
+ uint64_t hxsd_bit;
+ uint32_t hxsd_size;
+ uint32_t hxsd_off;
+} hma_xsave_state_desc_t;
+
+/*
+ * Get a description of the data fields supported by the host via the XSAVE APIs
+ * for getting/setting guest FPU data. See the function definition for more
+ * detailed parameter usage.
+ */
+extern uint_t hma_fpu_describe_xsave_state(hma_xsave_state_desc_t *, uint_t,
+ size_t *);
+
/*
* Get and set the contents of the FPU save area. This sets the fxsave style
* information. In all cases when this is in use, if an XSAVE state is actually
diff --git a/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h b/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h
index 6cec63bcfd..05e0710bbe 100644
--- a/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h
+++ b/usr/src/uts/i86pc/sys/pci_cfgspace_impl.h
@@ -21,16 +21,18 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2021 Oxide Computer Company
+ * Copyright 2022 Oxide Computer Company
*/
#ifndef _SYS_PCI_CFGSPACE_IMPL_H
#define _SYS_PCI_CFGSPACE_IMPL_H
/*
- * Routines to support particular PCI chipsets
+ * Routines to support particular PCI chipsets and the PCI BIOS.
*/
+#include <sys/plat/pci_prd.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -183,6 +185,11 @@ typedef struct pci_irq_route_hdr {
} pci_irq_route_hdr_t;
#pragma pack()
+extern int pci_irq_nroutes;
+
+extern int pci_slot_names_prop(int, char *, int);
+extern void pci_bios_bus_iter(pci_prd_root_complex_f, void *);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/i86pc/sys/vmm_dev.h b/usr/src/uts/i86pc/sys/vmm_dev.h
index 3282fa86bf..027a7da214 100644
--- a/usr/src/uts/i86pc/sys/vmm_dev.h
+++ b/usr/src/uts/i86pc/sys/vmm_dev.h
@@ -302,6 +302,25 @@ struct vm_run_state {
uint8_t _pad[3];
};
+/* Transfer data for VM_GET_FPU and VM_SET_FPU */
+struct vm_fpu_state {
+ int vcpuid;
+ void *buf;
+ size_t len;
+};
+
+struct vm_fpu_desc_entry {
+ uint64_t vfde_feature;
+ uint32_t vfde_size;
+ uint32_t vfde_off;
+};
+
+struct vm_fpu_desc {
+ struct vm_fpu_desc_entry *vfd_entry_data;
+ size_t vfd_req_size;
+ uint32_t vfd_num_entries;
+};
+
struct vmm_resv_query {
size_t vrq_free_sz;
size_t vrq_alloc_sz;
@@ -370,6 +389,8 @@ struct vmm_dirty_tracker {
#define VM_RESET_CPU (VMM_CPU_IOC_BASE | 0x16)
#define VM_GET_RUN_STATE (VMM_CPU_IOC_BASE | 0x17)
#define VM_SET_RUN_STATE (VMM_CPU_IOC_BASE | 0x18)
+#define VM_GET_FPU (VMM_CPU_IOC_BASE | 0x19)
+#define VM_SET_FPU (VMM_CPU_IOC_BASE | 0x1a)
/* Operations requiring write-locking the VM */
#define VM_REINIT (VMM_LOCK_IOC_BASE | 0x01)
@@ -428,6 +449,7 @@ struct vmm_dirty_tracker {
/* Note: forces a barrier on a flush operation before returning. */
#define VM_TRACK_DIRTY_PAGES (VMM_IOC_BASE | 0x20)
+#define VM_DESC_FPU_AREA (VMM_IOC_BASE | 0x21)
#define VM_DEVMEM_GETOFFSET (VMM_IOC_BASE | 0xff)
diff --git a/usr/src/uts/i86pc/unix/Makefile b/usr/src/uts/i86pc/unix/Makefile
index 066edbadb0..a20add0e3d 100644
--- a/usr/src/uts/i86pc/unix/Makefile
+++ b/usr/src/uts/i86pc/unix/Makefile
@@ -125,25 +125,15 @@ CFLAGS += -DDIS_MEM
# to investigate and remove these for maximum coverage.
# Please do not carry these forward to new Makefiles.
#
-CERRWARN += -_gcc=-Wno-parentheses
-CERRWARN += $(CNOWARN_UNINIT)
CERRWARN += -_gcc=-Wno-char-subscripts
-CERRWARN += -_gcc=-Wno-unused-variable
CERRWARN += -_gcc=-Wno-unused-function
-CERRWARN += -_gcc=-Wno-unused-label
-CERRWARN += -_gcc=-Wno-type-limits
-CERRWARN += -_gcc=-Wno-clobbered
-CERRWARN += -_gcc=-Wno-empty-body
-CERRWARN += -_gcc=-Wno-unused-value
# false positives
SMOFF += index_overflow
# needs work
-SMOFF += all_func_returns,deref_check,signed
+SMOFF += all_func_returns
-$(OBJS_DIR)/fmsmb.o := SMOFF += indenting
-$(OBJS_DIR)/zutil.o := SMOFF += indenting
$(OBJS_DIR)/bootrd_cpio.o := SMOFF += allocating_enough_data
# too hairy
diff --git a/usr/src/uts/i86pc/vm/hat_i86.c b/usr/src/uts/i86pc/vm/hat_i86.c
index 6f681cb196..1558af9482 100644
--- a/usr/src/uts/i86pc/vm/hat_i86.c
+++ b/usr/src/uts/i86pc/vm/hat_i86.c
@@ -4206,8 +4206,8 @@ try_again:
/*
* can stop short if we found a ref'd or mod'd page
*/
- if ((flags & HAT_SYNC_STOPON_MOD) && PP_ISMOD(save_pp) ||
- (flags & HAT_SYNC_STOPON_REF) && PP_ISREF(save_pp)) {
+ if (((flags & HAT_SYNC_STOPON_MOD) && PP_ISMOD(save_pp)) ||
+ ((flags & HAT_SYNC_STOPON_REF) && PP_ISREF(save_pp))) {
x86_hm_exit(pp);
goto done;
}
diff --git a/usr/src/uts/i86pc/vm/vm_machdep.c b/usr/src/uts/i86pc/vm/vm_machdep.c
index 6bca3d2540..225628b1c8 100644
--- a/usr/src/uts/i86pc/vm/vm_machdep.c
+++ b/usr/src/uts/i86pc/vm/vm_machdep.c
@@ -1399,12 +1399,12 @@ void
mnode_range_setup(mnoderange_t *mnoderanges)
{
mnoderange_t *mp;
- size_t nr_ranges;
+ ssize_t nr_ranges;
size_t mnode;
for (mnode = 0, nr_ranges = 0, mp = mnoderanges;
mnode < max_mem_nodes; mnode++) {
- size_t mri = nranges - 1;
+ ssize_t mri = nranges - 1;
if (mem_node_config[mnode].exists == 0)
continue;
@@ -3794,9 +3794,8 @@ ppcopy(page_t *frompp, page_t *topp)
caddr_t pp_addr2;
hat_mempte_t pte1;
hat_mempte_t pte2;
- kmutex_t *ppaddr_mutex;
label_t ljb;
- int ret = 1;
+ int ret;
ASSERT_STACK_ALIGNED();
ASSERT(PAGE_LOCKED(frompp));
@@ -3817,8 +3816,7 @@ ppcopy(page_t *frompp, page_t *topp)
pte1 = CPU->cpu_caddr1pte;
pte2 = CPU->cpu_caddr2pte;
- ppaddr_mutex = &CPU->cpu_ppaddr_mutex;
- mutex_enter(ppaddr_mutex);
+ mutex_enter(&CPU->cpu_ppaddr_mutex);
hat_mempte_remap(page_pptonum(frompp), pp_addr1, pte1,
PROT_READ | HAT_STORECACHING_OK, HAT_LOAD_NOCONSIST);
@@ -3830,6 +3828,8 @@ ppcopy(page_t *frompp, page_t *topp)
if (on_fault(&ljb)) {
ret = 0;
goto faulted;
+ } else {
+ ret = 1;
}
if (use_sse_pagecopy)
#ifdef __xpv
@@ -3855,7 +3855,7 @@ faulted:
UVMF_INVLPG | UVMF_LOCAL) < 0)
panic("HYPERVISOR_update_va_mapping() failed");
#endif
- mutex_exit(ppaddr_mutex);
+ mutex_exit(&CPU->cpu_ppaddr_mutex);
}
kpreempt_enable();
return (ret);
diff --git a/usr/src/uts/intel/Makefile.files b/usr/src/uts/intel/Makefile.files
index 2e7455a93a..7f464e2ec8 100644
--- a/usr/src/uts/intel/Makefile.files
+++ b/usr/src/uts/intel/Makefile.files
@@ -141,7 +141,7 @@ PCIEB_OBJS += pcieb_x86.o
PIT_BEEP_OBJS += pit_beep.o
POWER_OBJS += power.o
PCI_AUTOCONFIG_OBJS += pci_autoconfig.o pci_boot.o pcie_nvidia.o \
- pci_memlist.o pci_resource.o
+ pci_memlist.o
RADEON_OBJS += r300_cmdbuf.o radeon_cp.o radeon_drv.o \
radeon_state.o radeon_irq.o radeon_mem.o
SD_OBJS += sd.o sd_xbuf.o
diff --git a/usr/src/uts/intel/Makefile.intel b/usr/src/uts/intel/Makefile.intel
index 3fafc22c66..290eae88ff 100644
--- a/usr/src/uts/intel/Makefile.intel
+++ b/usr/src/uts/intel/Makefile.intel
@@ -360,6 +360,7 @@ DRV_KMODS += yge
DRV_KMODS += zcons
DRV_KMODS += zyd
DRV_KMODS += simnet
+DRV_KMODS += smrt
DRV_KMODS += stmf
DRV_KMODS += stmf_sbd
DRV_KMODS += fct
@@ -705,6 +706,12 @@ MAC_KMODS += mac_wifi
MAC_KMODS += mac_ib
#
+# Overlay related modules (/kernel/overlay)
+#
+DRV_KMODS += overlay
+OVERLAY_KMODS += vxlan
+
+#
# socketmod (kernel/socketmod)
#
SOCKET_KMODS += sockpfp
diff --git a/usr/src/uts/intel/genunix/Makefile b/usr/src/uts/intel/genunix/Makefile
index 9ce92ebd49..dab6e3f686 100644
--- a/usr/src/uts/intel/genunix/Makefile
+++ b/usr/src/uts/intel/genunix/Makefile
@@ -79,13 +79,10 @@ CPPFLAGS += -I$(SRC)/uts/common/fs/zfs
CPPFLAGS += -I$(UTSBASE)/i86pc
-CERRWARN += -_gcc=-Wno-unused-label
CERRWARN += -_gcc=-Wno-unused-variable
CERRWARN += -_gcc=-Wno-unused-value
CERRWARN += -_gcc=-Wno-unused-function
CERRWARN += -_gcc=-Wno-parentheses
-CERRWARN += -_gcc=-Wno-switch
-CERRWARN += -_gcc=-Wno-type-limits
CERRWARN += $(CNOWARN_UNINIT)
CERRWARN += -_gcc=-Wno-clobbered
CERRWARN += -_gcc=-Wno-empty-body
@@ -106,7 +103,7 @@ $(OBJS_DIR)/seg_vn.o := SMOFF += deref_check
$(OBJS_DIR)/ddi_intr_irm.o := SMOFF += deref_check
# need work still
-SMOFF += signed,indenting,all_func_returns
+SMOFF += signed,all_func_returns
$(OBJS_DIR)/clock_highres.o := SMOFF += signed_integer_overflow_check
$(OBJS_DIR)/evchannels.o := SMOFF += allocating_enough_data
$(OBJS_DIR)/klpd.o := SMOFF += cast_assign
@@ -115,8 +112,8 @@ $(OBJS_DIR)/process.o := SMOFF += or_vs_and
$(OBJS_DIR)/sunpci.o := SMOFF += deref_check
$(OBJS_DIR)/timers.o := SMOFF += signed_integer_overflow_check
-# definitely wrong
-$(OBJS_DIR)/acl_common.o := SMOFF += or_vs_and
+# 3rd party code
+$(OBJS_DIR)/bz2bzlib.o := SMOFF += indenting
#
# Default build targets.
diff --git a/usr/src/uts/intel/io/acpica/acpi_enum.c b/usr/src/uts/intel/io/acpica/acpi_enum.c
index 492195a627..2ac211f0d7 100644
--- a/usr/src/uts/intel/io/acpica/acpi_enum.c
+++ b/usr/src/uts/intel/io/acpica/acpi_enum.c
@@ -24,6 +24,8 @@
*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2021 Racktop Systems, Inc.
*/
/*
@@ -37,7 +39,19 @@
#include <sys/acpi/acpi.h>
#include <sys/acpica.h>
#include <util/sscanf.h>
+#include <util/qsort.h>
+/*
+ * Used to track the interrupts used by a resource, as well as the set of
+ * interrupts used overall. The IRQ values are ints for historical purposes
+ * (the "interrupts" property has traditionally been an array of ints) even
+ * though negative IRQ values do not make much sense.
+ */
+typedef struct intrs {
+ int *i_intrs;
+ uint_t i_num;
+ uint_t i_alloc;
+} intrs_t;
static char keyboard_alias[] = "keyboard";
static char mouse_alias[] = "mouse";
@@ -56,7 +70,7 @@ static unsigned long acpi_enum_debug = 0x00;
static char USED_RESOURCES[] = "used-resources";
static dev_info_t *usedrdip = NULL;
-static unsigned short used_interrupts = 0;
+static intrs_t used_interrupts;
static unsigned short used_dmas = 0;
typedef struct used_io_mem {
unsigned int start_addr;
@@ -70,10 +84,48 @@ static int used_mem_count = 0;
#define MAX_PARSED_ACPI_RESOURCES 255
#define ACPI_ISA_LIMIT 16
-static int interrupt[ACPI_ISA_LIMIT], dma[ACPI_ISA_LIMIT];
+static int dma[ACPI_ISA_LIMIT];
#define ACPI_ELEMENT_PACKAGE_LIMIT 32
#define EISA_ID_SIZE 7
+static void
+add_interrupt(intrs_t *intrs, int irq)
+{
+ /* We only want to add the value once */
+ for (uint_t i = 0; i < intrs->i_num; i++) {
+ if (intrs->i_intrs[i] == irq)
+ return;
+ }
+
+ /*
+ * Initially, i_num and i_alloc will be 0, and we allocate
+ * i_intrs to hold ACPI_ISA_LIMIT values on the initial add attempt.
+ * Since ISA buses could only use at most ACPI_ISA_LIMIT (16)
+ * interrupts, this seems like a reasonable size. The extended IRQ
+ * resource however exists explicitly to support IRQ values beyond
+ * 16. That suggests it may be possible on some hardware to exceed
+ * the initial allocation. If we do exceed the initial allocation, we
+ * grow i_intrs in chunks of ACPI_ISA_LIMIT since that's as good an
+ * amount as any.
+ */
+ if (intrs->i_num == intrs->i_alloc) {
+ uint_t newlen = intrs->i_alloc + ACPI_ISA_LIMIT;
+ size_t newsz = newlen * sizeof (int);
+ size_t oldsz = intrs->i_alloc * sizeof (int);
+ int *newar = kmem_alloc(newsz, KM_SLEEP);
+
+ if (intrs->i_num > 0) {
+ bcopy(intrs->i_intrs, newar, oldsz);
+ kmem_free(intrs->i_intrs, oldsz);
+ }
+
+ intrs->i_intrs = newar;
+ intrs->i_alloc = newlen;
+ }
+
+ intrs->i_intrs[intrs->i_num++] = irq;
+}
+
/*
* insert used io/mem in increasing order
*/
@@ -127,18 +179,52 @@ add_used_io_mem(struct regspec *io, int io_count)
}
static void
-parse_resources_irq(ACPI_RESOURCE *resource_ptr, int *interrupt_count)
+parse_resources_irq(ACPI_RESOURCE *resource_ptr, intrs_t *intrs)
{
- int i;
+ uint_t i;
for (i = 0; i < resource_ptr->Data.Irq.InterruptCount; i++) {
- interrupt[(*interrupt_count)++] =
- resource_ptr->Data.Irq.Interrupts[i];
- used_interrupts |= 1 << resource_ptr->Data.Irq.Interrupts[i];
+ uint8_t irq = resource_ptr->Data.Irq.Interrupts[i];
+
+ add_interrupt(intrs, irq);
+ add_interrupt(&used_interrupts, irq);
+
if (acpi_enum_debug & PARSE_RES_IRQ) {
- cmn_err(CE_NOTE, "!parse_resources() "\
- "IRQ num %u, intr # = %u",
- i, resource_ptr->Data.Irq.Interrupts[i]);
+ cmn_err(CE_NOTE, "!%s() IRQ num %u, intr # = %u",
+ __func__, i, irq);
+ }
+ }
+}
+
+static void
+parse_resources_extended_irq(ACPI_RESOURCE *resource_ptr, intrs_t *intrs)
+{
+ uint_t i;
+
+ for (i = 0; i < resource_ptr->Data.ExtendedIrq.InterruptCount; i++) {
+ uint32_t irq = resource_ptr->Data.ExtendedIrq.Interrupts[i];
+
+ /*
+ * As noted in the definition of intrs_t above, traditionally
+ * the "interrupts" property is an array of ints. This is
+ * more precautionary than anything since it seems unlikely
+ * that anything will have an irq value > 2^31 anytime soon.
+ */
+ if (irq > INT32_MAX) {
+ if (acpi_enum_debug & PARSE_RES_IRQ) {
+ cmn_err(CE_NOTE,
+ "!%s() intr # = %u out of range",
+ __func__, irq);
+ }
+ continue;
+ }
+
+ add_interrupt(intrs, irq);
+ add_interrupt(&used_interrupts, irq);
+
+ if (acpi_enum_debug & PARSE_RES_IRQ) {
+ cmn_err(CE_NOTE, "!%s() IRQ num %u, intr # = %u",
+ __func__, i, irq);
}
}
}
@@ -446,7 +532,8 @@ parse_resources(ACPI_HANDLE handle, dev_info_t *xdip, char *path)
ACPI_STATUS status;
char *current_ptr, *last_ptr;
struct regspec *io;
- int io_count = 0, interrupt_count = 0, dma_count = 0;
+ intrs_t intrs = { 0 };
+ int io_count = 0, dma_count = 0;
int i;
buf.Length = ACPI_ALLOCATE_BUFFER;
@@ -509,7 +596,7 @@ parse_resources(ACPI_HANDLE handle, dev_info_t *xdip, char *path)
parse_resources_addr64(resource_ptr, io, &io_count);
break;
case ACPI_RESOURCE_TYPE_IRQ:
- parse_resources_irq(resource_ptr, &interrupt_count);
+ parse_resources_irq(resource_ptr, &intrs);
break;
case ACPI_RESOURCE_TYPE_DMA:
parse_resources_dma(resource_ptr, &dma_count);
@@ -539,10 +626,7 @@ parse_resources(ACPI_HANDLE handle, dev_info_t *xdip, char *path)
" not supported");
break;
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
- cmn_err(CE_NOTE,
- "!ACPI source type"
- " ACPI_RESOURCE_TYPE_EXT_IRQ"
- " not supported");
+ parse_resources_extended_irq(resource_ptr, &intrs);
break;
default:
/* Some types are not yet implemented (See CA 6.4) */
@@ -563,13 +647,11 @@ parse_resources(ACPI_HANDLE handle, dev_info_t *xdip, char *path)
io[1].regspec_addr == 0x64) ||
(io[0].regspec_addr == 0x64 &&
io[1].regspec_addr == 0x60)) {
- interrupt[0] = 0x1;
- interrupt[1] = 0xc;
- interrupt_count = 2;
- used_interrupts |=
- 1 << interrupt[0];
- used_interrupts |=
- 1 << interrupt[1];
+ intrs.i_num = 0;
+ add_interrupt(&intrs, 0x1);
+ add_interrupt(&intrs, 0xc);
+ add_interrupt(&used_interrupts, 0x1);
+ add_interrupt(&used_interrupts, 0xc);
}
}
add_used_io_mem(io, io_count);
@@ -578,9 +660,12 @@ parse_resources(ACPI_HANDLE handle, dev_info_t *xdip, char *path)
"reg", (int *)io, 3*io_count);
}
}
- if (interrupt_count && (xdip != NULL)) {
- (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
- "interrupts", (int *)interrupt, interrupt_count);
+ if (intrs.i_num > 0) {
+ if (xdip != NULL) {
+ (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
+ "interrupts", intrs.i_intrs, intrs.i_num);
+ }
+ kmem_free(intrs.i_intrs, intrs.i_alloc * sizeof (int));
}
if (dma_count && (xdip != NULL)) {
(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, xdip,
@@ -984,20 +1069,42 @@ done:
return (AE_OK);
}
+static int
+irq_cmp(const void *a, const void *b)
+{
+ const int *l = a;
+ const int *r = b;
+
+ if (*l < *r)
+ return (-1);
+ if (*l > *r)
+ return (1);
+ return (0);
+}
+
static void
used_res_interrupts(void)
{
- int intr[ACPI_ISA_LIMIT];
- int count = 0;
- int i;
+ if (used_interrupts.i_num == 0)
+ return;
+
+ /*
+ * add_known_used_resources() in usr/src/uts/i86pc.io/isa.c (used
+ * when ACPI enumeration is disabled) states that the interrupt values
+ * in the interrupts property of usedrdip should be in increasing order.
+ * It does not state the reason for the requirement, however out of
+ * an abundance of caution, we ensure the interrupt values are also
+ * stored in the interrupts property in increasing order.
+ */
+ qsort(used_interrupts.i_intrs, used_interrupts.i_num, sizeof (int),
+ irq_cmp);
- for (i = 0; i < ACPI_ISA_LIMIT; i++) {
- if ((used_interrupts >> i) & 1) {
- intr[count++] = i;
- }
- }
(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, usedrdip,
- "interrupts", (int *)intr, count);
+ "interrupts", used_interrupts.i_intrs, used_interrupts.i_num);
+
+ kmem_free(used_interrupts.i_intrs,
+ used_interrupts.i_alloc * sizeof (int));
+ bzero(&used_interrupts, sizeof (used_interrupts));
}
static void
diff --git a/usr/src/uts/intel/io/amdzen/amdzen.c b/usr/src/uts/intel/io/amdzen/amdzen.c
index 99670abfec..3715a2c035 100644
--- a/usr/src/uts/intel/io/amdzen/amdzen.c
+++ b/usr/src/uts/intel/io/amdzen/amdzen.c
@@ -146,7 +146,7 @@ static const uint16_t amdzen_nb_ids[] = {
0x15d0,
/* Family 17h/19h Rome, Milan, Matisse, Vermeer Zen 2/Zen 3 uarch */
0x1480,
- /* Family 17h Renoir Models 60-6fh (Zen 2 uarch) */
+ /* Family 17h/19h Renoir, Cezanne Zen 2/3 uarch) */
0x1630
};
diff --git a/usr/src/uts/intel/io/imc/imc.c b/usr/src/uts/intel/io/imc/imc.c
index e1dbfbfc2e..67a14528f0 100644
--- a/usr/src/uts/intel/io/imc/imc.c
+++ b/usr/src/uts/intel/io/imc/imc.c
@@ -1405,7 +1405,7 @@ imc_nvl_pack(imc_socket_t *sock, boolean_t sleep)
if (sleep) {
kmflag = KM_SLEEP;
} else {
- kmflag = KM_NOSLEEP | KM_NORMALPRI;
+ kmflag = KM_NOSLEEP_LAZY;
}
if (nvlist_pack(sock->isock_nvl, &buf, &len, NV_ENCODE_XDR,
@@ -1432,7 +1432,7 @@ imc_decoder_pack(imc_t *imc)
}
if (nvlist_pack(imc->imc_decoder_dump, &buf, &len, NV_ENCODE_XDR,
- KM_NOSLEEP | KM_NORMALPRI) != 0) {
+ KM_NOSLEEP_LAZY) != 0) {
return;
}
diff --git a/usr/src/uts/intel/io/pci/pci_autoconfig.c b/usr/src/uts/intel/io/pci/pci_autoconfig.c
index 713493eedb..af7ba637d8 100644
--- a/usr/src/uts/intel/io/pci/pci_autoconfig.c
+++ b/usr/src/uts/intel/io/pci/pci_autoconfig.c
@@ -21,6 +21,7 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -40,8 +41,10 @@
#include <sys/reboot.h>
#include <sys/pci_cfgspace_impl.h>
#include <sys/mutex.h>
+#include <sys/plat/pci_prd.h>
extern int pci_boot_debug;
+extern int pci_boot_maxbus;
/*
* Interface routines
@@ -49,7 +52,7 @@ extern int pci_boot_debug;
void pci_enumerate(int);
void pci_setup_tree(void);
void pci_reprogram(void);
-void bus_res_fini(void);
+dev_info_t *pci_boot_bus_to_dip(uint32_t);
static struct modlmisc modlmisc = {
&mod_miscops, "PCI BIOS interface"
@@ -59,13 +62,23 @@ static struct modlinkage modlinkage = {
MODREV_1, (void *)&modlmisc, NULL
};
+static pci_prd_upcalls_t pci_upcalls = {
+ .pru_bus2dip_f = pci_boot_bus_to_dip
+};
+
int
_init(void)
{
int err;
- if ((err = mod_install(&modlinkage)) != 0)
+ if ((err = pci_prd_init(&pci_upcalls)) != 0) {
+ return (err);
+ }
+
+ if ((err = mod_install(&modlinkage)) != 0) {
+ pci_prd_fini();
return (err);
+ }
impl_bus_add_probe(pci_enumerate);
return (0);
@@ -80,7 +93,7 @@ _fini(void)
return (err);
impl_bus_delete_probe(pci_enumerate);
- bus_res_fini();
+ pci_prd_fini();
return (0);
}
@@ -102,6 +115,14 @@ pci_enumerate(int reprogram)
extern void add_pci_fixes(void);
extern void undo_pci_fixes(void);
+ /*
+ * On our first pass through here actually determine what the maximum
+ * bus that we should use is.
+ */
+ if (reprogram == 0) {
+ pci_boot_maxbus = pci_prd_max_bus();
+ }
+
add_pci_fixes();
if (reprogram) {
diff --git a/usr/src/uts/intel/io/pci/pci_boot.c b/usr/src/uts/intel/io/pci/pci_boot.c
index f2cff30ed3..25bae81079 100644
--- a/usr/src/uts/intel/io/pci/pci_boot.c
+++ b/usr/src/uts/intel/io/pci/pci_boot.c
@@ -23,6 +23,7 @@
* Copyright 2019 Joyent, Inc.
* Copyright 2019 Western Digital Corporation
* Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -101,18 +102,21 @@
* add_pci_fixes()
* As for first pass.
* pci_reprogram()
- * pci_scan_bbn()
- * The ACPI namespace is scanned for top-level
- * instances of _BBN in order to enumerate the
- * root-bridges in the system. If a root bridge is
- * found that has not been previously discovered
- * (existence inferred through its children) then
- * it is added to the system.
+ * pci_prd_root_complex_iter()
+ * The platform is asked to tell us of all root
+ * complexes that it knows about (e.g. using the
+ * _BBN method via ACPI). This will include buses
+ * that we've already discovered and those that we
+ * potentially haven't. Anything that has not been
+ * previously discovered (or inferred to exist) is
+ * then added to the system.
* <foreach ROOT bus>
* populate_bus_res()
* Find resources associated with this root bus
- * from either ACPI or BIOS tables. See
- * find_bus_res() in pci_resource.c
+ * based on what the platform provideds through the
+ * pci platform interfaces defined in
+ * sys/plat/pci_prd.h. On i86pc this is driven by
+ * ACPI and BIOS tables.
* <foreach bus>
* fix_ppb_res()
* Reprogram pci(e) bridges which have not already
@@ -158,7 +162,6 @@
#include <sys/pcie_impl.h>
#include <sys/memlist.h>
#include <sys/bootconf.h>
-#include <io/pci/mps_table.h>
#include <sys/pci_cfgacc.h>
#include <sys/pci_cfgspace.h>
#include <sys/pci_cfgspace_impl.h>
@@ -172,6 +175,7 @@
#include <sys/iommulib.h>
#include <sys/devcache.h>
#include <sys/pci_cfgacc_x86.h>
+#include <sys/plat/pci_prd.h>
#define pci_getb (*pci_getb_func)
#define pci_getw (*pci_getw_func)
@@ -242,16 +246,13 @@ struct pci_devfunc {
extern int apic_nvidia_io_max;
extern int pseudo_isa;
-extern int pci_bios_maxbus;
static uchar_t max_dev_pci = 32; /* PCI standard */
+int pci_boot_maxbus;
int pci_boot_debug = 0;
int pci_debug_bus_start = -1;
int pci_debug_bus_end = -1;
-extern struct memlist *find_bus_res(int, int);
static struct pci_fixundo *undolist = NULL;
static int num_root_bus = 0; /* count of root buses */
-extern volatile int acpi_resource_discovery;
-extern uint64_t mcfg_mem_base;
extern void pci_cfgacc_add_workaround(uint16_t, uchar_t, uchar_t);
extern dev_info_t *pcie_get_rc_dip(dev_info_t *);
@@ -269,12 +270,11 @@ static void add_ppb_props(dev_info_t *, uchar_t, uchar_t, uchar_t, int,
ushort_t);
static void add_model_prop(dev_info_t *, uint_t);
static void add_bus_range_prop(int);
-static void add_bus_slot_names_prop(int);
static void add_ranges_prop(int, int);
static void add_bus_available_prop(int);
static int get_pci_cap(uchar_t bus, uchar_t dev, uchar_t func, uint8_t cap_id);
static void fix_ppb_res(uchar_t, boolean_t);
-static void alloc_res_array();
+static void alloc_res_array(void);
static void create_ioapic_node(int bus, int dev, int fn, ushort_t vendorid,
ushort_t deviceid);
static void pciex_slot_names_prop(dev_info_t *, ushort_t);
@@ -283,7 +283,6 @@ static void memlist_remove_list(struct memlist **list,
struct memlist *remove_list);
static void ck804_fix_aer_ptr(dev_info_t *, pcie_req_id_t);
-static void pci_scan_bbn(void);
static int pci_unitaddr_cache_valid(void);
static int pci_bus_unitaddr(int);
static void pci_unitaddr_cache_create(void);
@@ -292,8 +291,6 @@ static int pci_cache_unpack_nvlist(nvf_handle_t, nvlist_t *, char *);
static int pci_cache_pack_nvlist(nvf_handle_t, nvlist_t **);
static void pci_cache_free_list(nvf_handle_t);
-extern int pci_slot_names_prop(int, char *, int);
-
/* set non-zero to force PCI peer-bus renumbering */
int pci_bus_always_renumber = 0;
@@ -326,6 +323,13 @@ typedef struct {
nvf_handle_t puafd_handle;
int pua_cache_valid = 0;
+dev_info_t *
+pci_boot_bus_to_dip(uint32_t busno)
+{
+ ASSERT3U(busno, <=, pci_boot_maxbus);
+ return (pci_bus_res[busno].dip);
+}
+
static void
dump_memlists_impl(const char *tag, int bus)
{
@@ -356,80 +360,21 @@ dump_memlists_impl(const char *tag, int bus)
}
}
-/*ARGSUSED*/
-static ACPI_STATUS
-pci_process_acpi_device(ACPI_HANDLE hdl, UINT32 level, void *ctx, void **rv)
+static boolean_t
+pci_rc_scan_cb(uint32_t busno, void *arg)
{
- ACPI_DEVICE_INFO *adi;
- int busnum;
-
- /*
- * Use AcpiGetObjectInfo() to find the device _HID
- * If not a PCI root-bus, ignore this device and continue
- * the walk
- */
- if (ACPI_FAILURE(AcpiGetObjectInfo(hdl, &adi)))
- return (AE_OK);
-
- if (!(adi->Valid & ACPI_VALID_HID)) {
- AcpiOsFree(adi);
- return (AE_OK);
- }
-
- if (strncmp(adi->HardwareId.String, PCI_ROOT_HID_STRING,
- sizeof (PCI_ROOT_HID_STRING)) &&
- strncmp(adi->HardwareId.String, PCI_EXPRESS_ROOT_HID_STRING,
- sizeof (PCI_EXPRESS_ROOT_HID_STRING))) {
- AcpiOsFree(adi);
- return (AE_OK);
+ if (busno > pci_boot_maxbus) {
+ dcmn_err(CE_NOTE, "platform root complex scan returned bus "
+ "with invalid bus id: 0x%x", busno);
+ return (B_TRUE);
}
- AcpiOsFree(adi);
-
- /*
- * acpica_get_busno() will check the presence of _BBN and
- * fail if not present. It will then use the _CRS method to
- * retrieve the actual bus number assigned, it will fall back
- * to _BBN should the _CRS method fail.
- */
- if (ACPI_SUCCESS(acpica_get_busno(hdl, &busnum))) {
- /*
- * Ignore invalid _BBN return values here (rather
- * than panic) and emit a warning; something else
- * may suffer failure as a result of the broken BIOS.
- */
- if ((busnum < 0) || (busnum > pci_bios_maxbus)) {
- dcmn_err(CE_NOTE,
- "pci_process_acpi_device: invalid _BBN 0x%x",
- busnum);
- return (AE_CTRL_DEPTH);
- }
-
- /* PCI with valid _BBN */
- if (pci_bus_res[busnum].par_bus == (uchar_t)-1 &&
- pci_bus_res[busnum].dip == NULL)
- create_root_bus_dip((uchar_t)busnum);
- return (AE_CTRL_DEPTH);
+ if (pci_bus_res[busno].par_bus == (uchar_t)-1 &&
+ pci_bus_res[busno].dip == NULL) {
+ create_root_bus_dip((uchar_t)busno);
}
- /* PCI and no _BBN, continue walk */
- return (AE_OK);
-}
-
-/*
- * Scan the ACPI namespace for all top-level instances of _BBN
- * in order to discover childless root-bridges (which enumeration
- * may not find; root-bridges are inferred by the existence of
- * children). This scan should find all root-bridges that have
- * been enumerated, and any childless root-bridges not enumerated.
- * Root-bridge for bus 0 may not have a _BBN object.
- */
-static void
-pci_scan_bbn()
-{
- void *rv;
-
- (void) AcpiGetDevices(NULL, pci_process_acpi_device, NULL, &rv);
+ return (B_TRUE);
}
static void
@@ -596,7 +541,7 @@ pci_unitaddr_cache_create(void)
index = 0;
listp = nvf_list(puafd_handle);
- for (i = 0; i <= pci_bios_maxbus; i++) {
+ for (i = 0; i <= pci_boot_maxbus; i++) {
/* skip non-root (peer) PCI busses */
if ((pci_bus_res[i].par_bus != (uchar_t)-1) ||
(pci_bus_res[i].dip == NULL))
@@ -622,7 +567,7 @@ pci_setup_tree(void)
uint_t i, root_bus_addr = 0;
alloc_res_array();
- for (i = 0; i <= pci_bios_maxbus; i++) {
+ for (i = 0; i <= pci_boot_maxbus; i++) {
pci_bus_res[i].par_bus = (uchar_t)-1;
pci_bus_res[i].root_addr = (uchar_t)-1;
pci_bus_res[i].sub_bus = i;
@@ -635,7 +580,7 @@ pci_setup_tree(void)
/*
* Now enumerate peer busses
*
- * We loop till pci_bios_maxbus. On most systems, there is
+ * We loop till pci_boot_maxbus. On most systems, there is
* one more bus at the high end, which implements the ISA
* compatibility bus. We don't care about that.
*
@@ -646,144 +591,11 @@ pci_setup_tree(void)
* However, we stop enumerating phantom peers with no
* device below.
*/
- for (i = 1; i <= pci_bios_maxbus; i++) {
+ for (i = 1; i <= pci_boot_maxbus; i++) {
if (pci_bus_res[i].dip == NULL) {
pci_bus_res[i].root_addr = root_bus_addr++;
}
enumerate_bus_devs(i, CONFIG_INFO);
-
- /* add slot-names property for named pci hot-plug slots */
- add_bus_slot_names_prop(i);
- }
-}
-
-/*
- * >0 = present, 0 = not present, <0 = error
- */
-static int
-pci_bbn_present(int bus)
-{
- ACPI_HANDLE hdl;
- int rv;
-
- /* no dip means no _BBN */
- if (pci_bus_res[bus].dip == NULL)
- return (0);
-
- rv = -1; /* default return value in case of error below */
- if (ACPI_SUCCESS(acpica_get_handle(pci_bus_res[bus].dip, &hdl))) {
- switch (AcpiEvaluateObject(hdl, "_BBN", NULL, NULL)) {
- case AE_OK:
- rv = 1;
- break;
- case AE_NOT_FOUND:
- rv = 0;
- break;
- default:
- break;
- }
- }
-
- return (rv);
-}
-
-/*
- * Return non-zero if any PCI bus in the system has an associated
- * _BBN object, 0 otherwise.
- */
-static int
-pci_roots_have_bbn(void)
-{
- int i;
-
- /*
- * Scan the PCI busses and look for at least 1 _BBN
- */
- for (i = 0; i <= pci_bios_maxbus; i++) {
- /* skip non-root (peer) PCI busses */
- if (pci_bus_res[i].par_bus != (uchar_t)-1)
- continue;
-
- if (pci_bbn_present(i) > 0)
- return (1);
- }
- return (0);
-
-}
-
-/*
- * return non-zero if the machine is one on which we renumber
- * the internal pci unit-addresses
- */
-static int
-pci_bus_renumber()
-{
- ACPI_TABLE_HEADER *fadt;
-
- if (pci_bus_always_renumber)
- return (1);
-
- /* get the FADT */
- if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **)&fadt) !=
- AE_OK)
- return (0);
-
- /* compare OEM Table ID to "SUNm31" */
- if (strncmp("SUNm31", fadt->OemId, 6))
- return (0);
- else
- return (1);
-}
-
-/*
- * Initial enumeration of the physical PCI bus hierarchy can
- * leave 'gaps' in the order of peer PCI bus unit-addresses.
- * Systems with more than one peer PCI bus *must* have an ACPI
- * _BBN object associated with each peer bus; use the presence
- * of this object to remove gaps in the numbering of the peer
- * PCI bus unit-addresses - only peer busses with an associated
- * _BBN are counted.
- */
-static void
-pci_renumber_root_busses(void)
-{
- int pci_regs[] = {0, 0, 0};
- int i, root_addr = 0;
-
- /*
- * Currently, we only enable the re-numbering on specific
- * Sun machines; this is a work-around for the more complicated
- * issue of upgrade changing physical device paths
- */
- if (!pci_bus_renumber())
- return;
-
- /*
- * If we find no _BBN objects at all, we either don't need
- * to do anything or can't do anything anyway
- */
- if (!pci_roots_have_bbn())
- return;
-
- for (i = 0; i <= pci_bios_maxbus; i++) {
- /* skip non-root (peer) PCI busses */
- if (pci_bus_res[i].par_bus != (uchar_t)-1)
- continue;
-
- if (pci_bbn_present(i) < 1) {
- pci_bus_res[i].root_addr = (uchar_t)-1;
- continue;
- }
-
- ASSERT(pci_bus_res[i].dip != NULL);
- if (pci_bus_res[i].root_addr != root_addr) {
- /* update reg property for node */
- pci_bus_res[i].root_addr = root_addr;
- pci_regs[0] = pci_bus_res[i].root_addr;
- (void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
- pci_bus_res[i].dip, "reg", (int *)pci_regs, 3);
- }
- root_addr++;
}
}
@@ -810,12 +622,12 @@ remove_subtractive_res()
int i, j;
struct memlist *list;
- for (i = 0; i <= pci_bios_maxbus; i++) {
+ for (i = 0; i <= pci_boot_maxbus; i++) {
if (pci_bus_res[i].subtractive) {
/* remove used io ports */
list = pci_bus_res[i].io_used;
while (list) {
- for (j = 0; j <= pci_bios_maxbus; j++)
+ for (j = 0; j <= pci_boot_maxbus; j++)
(void) memlist_remove(
&pci_bus_res[j].io_avail,
list->ml_address, list->ml_size);
@@ -824,7 +636,7 @@ remove_subtractive_res()
/* remove used mem resource */
list = pci_bus_res[i].mem_used;
while (list) {
- for (j = 0; j <= pci_bios_maxbus; j++) {
+ for (j = 0; j <= pci_boot_maxbus; j++) {
(void) memlist_remove(
&pci_bus_res[j].mem_avail,
list->ml_address, list->ml_size);
@@ -837,7 +649,7 @@ remove_subtractive_res()
/* remove used prefetchable mem resource */
list = pci_bus_res[i].pmem_used;
while (list) {
- for (j = 0; j <= pci_bios_maxbus; j++) {
+ for (j = 0; j <= pci_boot_maxbus; j++) {
(void) memlist_remove(
&pci_bus_res[j].pmem_avail,
list->ml_address, list->ml_size);
@@ -905,7 +717,7 @@ get_parbus_res(uchar_t parbus, uchar_t bus, uint64_t size, uint64_t align,
* accounted for in this case.
*/
if ((pci_bus_res[parbus].par_bus == (uchar_t)-1) &&
- (num_root_bus > 1) && (acpi_resource_discovery <= 0)) {
+ (num_root_bus > 1) && !pci_prd_multi_root_ok()) {
return (0);
}
@@ -1593,10 +1405,16 @@ pci_reprogram(void)
int bus;
/*
- * Scan ACPI namespace for _BBN objects, make sure that
- * childless root-bridges appear in devinfo tree
+ * Ask platform code for all of the root complexes it knows about in
+ * case we have missed anything in the scan. This is to ensure that we
+ * have them show up in the devinfo tree. This scan should find any
+ * existing entries as well. After this, go through each bus and
+ * ask the platform if it wants to change the name of the slot.
*/
- pci_scan_bbn();
+ pci_prd_root_complex_iter(pci_rc_scan_cb, NULL);
+ for (bus = 0; bus <= pci_boot_maxbus; bus++) {
+ pci_prd_slot_name(bus, pci_bus_res[bus].dip);
+ }
pci_unitaddr_cache_init();
/*
@@ -1607,7 +1425,7 @@ pci_reprogram(void)
int new_addr;
int index = 0;
- for (bus = 0; bus <= pci_bios_maxbus; bus++) {
+ for (bus = 0; bus <= pci_boot_maxbus; bus++) {
/* skip non-root (peer) PCI busses */
if ((pci_bus_res[bus].par_bus != (uchar_t)-1) ||
(pci_bus_res[bus].dip == NULL))
@@ -1626,14 +1444,13 @@ pci_reprogram(void)
}
} else {
/* perform legacy processing */
- pci_renumber_root_busses();
pci_unitaddr_cache_create();
}
/*
* Do root-bus resource discovery
*/
- for (bus = 0; bus <= pci_bios_maxbus; bus++) {
+ for (bus = 0; bus <= pci_boot_maxbus; bus++) {
/* skip non-root (peer) PCI busses */
if (pci_bus_res[bus].par_bus != (uchar_t)-1)
continue;
@@ -1683,7 +1500,7 @@ pci_reprogram(void)
memlist_free_all(&isa_res.mem_used);
/* add bus-range property for root/peer bus nodes */
- for (i = 0; i <= pci_bios_maxbus; i++) {
+ for (i = 0; i <= pci_boot_maxbus; i++) {
/* create bus-range property on root/peer buses */
if (pci_bus_res[i].par_bus == (uchar_t)-1)
add_bus_range_prop(i);
@@ -1705,10 +1522,10 @@ pci_reprogram(void)
/* reprogram the non-subtractive PPB */
if (pci_reconfig)
- for (i = 0; i <= pci_bios_maxbus; i++)
+ for (i = 0; i <= pci_boot_maxbus; i++)
fix_ppb_res(i, B_FALSE);
- for (i = 0; i <= pci_bios_maxbus; i++) {
+ for (i = 0; i <= pci_boot_maxbus; i++) {
/* configure devices not configured by BIOS */
if (pci_reconfig) {
/*
@@ -1722,7 +1539,7 @@ pci_reprogram(void)
}
/* All dev programmed, so we can create available prop */
- for (i = 0; i <= pci_bios_maxbus; i++)
+ for (i = 0; i <= pci_boot_maxbus; i++)
add_bus_available_prop(i);
}
@@ -1734,10 +1551,11 @@ populate_bus_res(uchar_t bus)
{
/* scan BIOS structures */
- pci_bus_res[bus].pmem_avail = find_bus_res(bus, PREFETCH_TYPE);
- pci_bus_res[bus].mem_avail = find_bus_res(bus, MEM_TYPE);
- pci_bus_res[bus].io_avail = find_bus_res(bus, IO_TYPE);
- pci_bus_res[bus].bus_avail = find_bus_res(bus, BUSRANGE_TYPE);
+ pci_bus_res[bus].pmem_avail = pci_prd_find_resource(bus,
+ PCI_PRD_R_PREFETCH);
+ pci_bus_res[bus].mem_avail = pci_prd_find_resource(bus, PCI_PRD_R_MMIO);
+ pci_bus_res[bus].io_avail = pci_prd_find_resource(bus, PCI_PRD_R_IO);
+ pci_bus_res[bus].bus_avail = pci_prd_find_resource(bus, PCI_PRD_R_BUS);
/*
* attempt to initialize sub_bus from the largest range-end
@@ -2054,7 +1872,7 @@ add_pci_fixes(void)
{
int i;
- for (i = 0; i <= pci_bios_maxbus; i++) {
+ for (i = 0; i <= pci_boot_maxbus; i++) {
/*
* For each bus, apply needed fixes to the appropriate devices.
* This must be done before the main enumeration loop because
@@ -3197,8 +3015,8 @@ add_ppb_props(dev_info_t *dip, uchar_t bus, uchar_t dev, uchar_t func,
* Some BIOSes lie about max pci busses, we allow for
* such mistakes here
*/
- if (subbus > pci_bios_maxbus) {
- pci_bios_maxbus = subbus;
+ if (subbus > pci_boot_maxbus) {
+ pci_boot_maxbus = subbus;
alloc_res_array();
}
@@ -3436,66 +3254,6 @@ add_bus_range_prop(int bus)
}
/*
- * Add slot-names property for any named pci hot-plug slots
- */
-static void
-add_bus_slot_names_prop(int bus)
-{
- char slotprop[256];
- int len;
- extern int pci_irq_nroutes;
- char *slotcap_name;
-
- /*
- * If no irq routing table, then go with the slot-names as set up
- * in pciex_slot_names_prop() from slot capability register (if any).
- */
- if (pci_irq_nroutes == 0)
- return;
-
- /*
- * Otherise delete the slot-names we already have and use the irq
- * routing table values as returned by pci_slot_names_prop() instead,
- * but keep any property of value "pcie0" as that can't be represented
- * in the irq routing table.
- */
- if (pci_bus_res[bus].dip != NULL) {
- if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pci_bus_res[bus].dip,
- DDI_PROP_DONTPASS, "slot-names", &slotcap_name) !=
- DDI_SUCCESS || strcmp(slotcap_name, "pcie0") != 0)
- (void) ndi_prop_remove(DDI_DEV_T_NONE,
- pci_bus_res[bus].dip, "slot-names");
- }
-
- len = pci_slot_names_prop(bus, slotprop, sizeof (slotprop));
- if (len > 0) {
- /*
- * Only create a peer bus node if this bus may be a peer bus.
- * It may be a peer bus if the dip is NULL and if par_bus is
- * -1 (par_bus is -1 if this bus was not found to be
- * subordinate to any PCI-PCI bridge).
- * If it's not a peer bus, then the ACPI BBN-handling code
- * will remove it later.
- */
- if (pci_bus_res[bus].par_bus == (uchar_t)-1 &&
- pci_bus_res[bus].dip == NULL) {
-
- create_root_bus_dip(bus);
- }
- if (pci_bus_res[bus].dip != NULL) {
- ASSERT((len % sizeof (int)) == 0);
- (void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
- pci_bus_res[bus].dip, "slot-names",
- (int *)slotprop, len / sizeof (int));
- } else {
- cmn_err(CE_NOTE, "!BIOS BUG: Invalid bus number in PCI "
- "IRQ routing table; Not adding slot-names "
- "property for incorrect bus %d", bus);
- }
- }
-}
-
-/*
* Handle both PCI root and PCI-PCI bridge range properties;
* non-zero 'ppb' argument select PCI-PCI bridges versus root.
*/
@@ -3652,11 +3410,11 @@ add_bus_available_prop(int bus)
static void
alloc_res_array(void)
{
- static int array_size = 0;
- int old_size;
+ static uint_t array_size = 0;
+ uint_t old_size;
void *old_res;
- if (array_size > pci_bios_maxbus + 1)
+ if (array_size > pci_boot_maxbus + 1)
return; /* array is big enough */
old_size = array_size;
@@ -3665,7 +3423,7 @@ alloc_res_array(void)
if (array_size == 0)
array_size = 16; /* start with a reasonable number */
- while (array_size <= pci_bios_maxbus + 1)
+ while (array_size <= pci_boot_maxbus + 1)
array_size <<= 1;
pci_bus_res = (struct pci_bus_resource *)kmem_zalloc(
array_size * sizeof (struct pci_bus_resource), KM_SLEEP);
diff --git a/usr/src/uts/intel/io/pci/pci_memlist.c b/usr/src/uts/intel/io/pci/pci_memlist.c
index 5786591420..4da76951e9 100644
--- a/usr/src/uts/intel/io/pci/pci_memlist.c
+++ b/usr/src/uts/intel/io/pci/pci_memlist.c
@@ -40,8 +40,8 @@
#include <sys/pci_impl.h>
#include <sys/debug.h>
-extern int pci_boot_debug;
-#define dprintf if (pci_boot_debug) printf
+int pci_memlist_debug;
+#define dprintf if (pci_memlist_debug) printf
void
memlist_dump(struct memlist *listp)
diff --git a/usr/src/uts/intel/os/archdep.c b/usr/src/uts/intel/os/archdep.c
index 3d2996880d..9ef480a69a 100644
--- a/usr/src/uts/intel/os/archdep.c
+++ b/usr/src/uts/intel/os/archdep.c
@@ -269,7 +269,7 @@ setfpregs(klwp_t *lwp, fpregset_t *fp)
&fpu->fpu_regs.kfpu_u.kfpu_xs->xs_fxsave);
fpu->fpu_regs.kfpu_xstatus =
fp->fp_reg_set.fpchip_state.xstatus;
- fpu->fpu_regs.kfpu_u.kfpu_xs->xs_xstate_bv |=
+ fpu->fpu_regs.kfpu_u.kfpu_xs->xs_header.xsh_xstate_bv |=
(XFEATURE_LEGACY_FP | XFEATURE_SSE);
break;
default:
diff --git a/usr/src/uts/intel/os/cpc_subr.c b/usr/src/uts/intel/os/cpc_subr.c
index e98a8e3d81..ed9eea6c83 100644
--- a/usr/src/uts/intel/os/cpc_subr.c
+++ b/usr/src/uts/intel/os/cpc_subr.c
@@ -44,7 +44,6 @@
#include <sys/spl.h>
#include <sys/apic.h>
-static const uint64_t allstopped = 0;
static kcpc_ctx_t *(*overflow_intr_handler)(caddr_t);
/* Do threads share performance monitoring hardware? */
diff --git a/usr/src/uts/intel/os/fpu.c b/usr/src/uts/intel/os/fpu.c
index 6f0345b391..9644282429 100644
--- a/usr/src/uts/intel/os/fpu.c
+++ b/usr/src/uts/intel/os/fpu.c
@@ -22,7 +22,7 @@
* Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2021 Joyent, Inc.
* Copyright 2021 RackTop Systems, Inc.
- * Copyright 2021 Oxide Computer Company
+ * Copyright 2022 Oxide Computer Company
*/
/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
@@ -528,23 +528,18 @@ const struct xsave_state avx_initial = {
* The definition below needs to be identical with sse_initial
* defined above.
*/
- {
- FPU_CW_INIT, /* fx_fcw */
- 0, /* fx_fsw */
- 0, /* fx_fctw */
- 0, /* fx_fop */
- 0, /* fx_rip */
- 0, /* fx_rdp */
- SSE_MXCSR_INIT /* fx_mxcsr */
- /* rest of structure is zero */
+ .xs_fxsave = {
+ .fx_fcw = FPU_CW_INIT,
+ .fx_mxcsr = SSE_MXCSR_INIT,
+ },
+ .xs_header = {
+ /*
+ * bit0 = 1 for XSTATE_BV to indicate that legacy fields are
+ * valid, and CPU should initialize XMM/YMM.
+ */
+ .xsh_xstate_bv = 1,
+ .xsh_xcomp_bv = 0,
},
- /*
- * bit0 = 1 for XSTATE_BV to indicate that legacy fields are valid,
- * and CPU should initialize XMM/YMM.
- */
- 1,
- 0 /* xs_xcomp_bv */
- /* rest of structure is zero */
};
/*
@@ -656,8 +651,8 @@ fp_new_lwp(void *parent, void *child)
bcopy(&avx_initial, cxs, sizeof (*cxs));
cfx->fx_mxcsr = fx->fx_mxcsr & ~SSE_MXCSR_EFLAGS;
cfx->fx_fcw = fx->fx_fcw;
- cxs->xs_xstate_bv |= (get_xcr(XFEATURE_ENABLED_MASK) &
- XFEATURE_FP_INITIAL);
+ cxs->xs_header.xsh_xstate_bv |=
+ (get_xcr(XFEATURE_ENABLED_MASK) & XFEATURE_FP_INITIAL);
break;
default:
panic("Invalid fp_save_mech");
@@ -973,7 +968,8 @@ fpexterrflt(struct regs *rp)
* Always set LEGACY_FP as it may have been cleared by XSAVE
* instruction
*/
- fp->fpu_regs.kfpu_u.kfpu_xs->xs_xstate_bv |= XFEATURE_LEGACY_FP;
+ fp->fpu_regs.kfpu_u.kfpu_xs->xs_header.xsh_xstate_bv |=
+ XFEATURE_LEGACY_FP;
break;
default:
panic("Invalid fp_save_mech");
@@ -1154,7 +1150,8 @@ fpsetcw(uint16_t fcw, uint32_t mxcsr)
* Always set LEGACY_FP as it may have been cleared by XSAVE
* instruction
*/
- fp->fpu_regs.kfpu_u.kfpu_xs->xs_xstate_bv |= XFEATURE_LEGACY_FP;
+ fp->fpu_regs.kfpu_u.kfpu_xs->xs_header.xsh_xstate_bv |=
+ XFEATURE_LEGACY_FP;
break;
default:
panic("Invalid fp_save_mech");
@@ -1177,7 +1174,7 @@ kernel_fpu_fpstate_init(kfpu_state_t *kfpu)
xs = kfpu->kfpu_ctx.fpu_regs.kfpu_u.kfpu_xs;
bzero(xs, cpuid_get_xsave_size());
bcopy(&avx_initial, xs, sizeof (*xs));
- xs->xs_xstate_bv = XFEATURE_LEGACY_FP | XFEATURE_SSE;
+ xs->xs_header.xsh_xstate_bv = XFEATURE_LEGACY_FP | XFEATURE_SSE;
kfpu->kfpu_ctx.fpu_xsave_mask = XFEATURE_FP_ALL;
break;
default:
@@ -1438,8 +1435,6 @@ kernel_fpu_begin(kfpu_state_t *kfpu, uint_t flags)
void
kernel_fpu_end(kfpu_state_t *kfpu, uint_t flags)
{
- ulong_t iflags;
-
if ((curthread->t_flag & T_KFPU) == 0) {
panic("curthread attempting to clear kernel FPU state "
"without using it");
diff --git a/usr/src/uts/intel/os/sundep.c b/usr/src/uts/intel/os/sundep.c
index 8938dfa0c6..2fd7b5ab21 100644
--- a/usr/src/uts/intel/os/sundep.c
+++ b/usr/src/uts/intel/os/sundep.c
@@ -511,10 +511,10 @@ update_sregs(struct regs *rp, klwp_t *lwp)
pcb_t *pcb = &lwp->lwp_pcb;
ulong_t kgsbase;
on_trap_data_t otd;
- int rc = 0;
+ int rc;
if (!on_trap(&otd, OT_SEGMENT_ACCESS)) {
-
+ rc = 0;
#if defined(__xpv)
/*
* On the hyervisor this is easy. The hypercall below will
@@ -728,8 +728,6 @@ static void
lwp_segregs_restore32(void *arg)
{
klwp_t *lwp = arg;
- /*LINTED*/
- cpu_t *cpu = CPU;
pcb_t *pcb = &lwp->lwp_pcb;
ASSERT(VALID_LWP_DESC(&lwp->lwp_pcb.pcb_fsdesc));
diff --git a/usr/src/uts/intel/overlay/Makefile b/usr/src/uts/intel/overlay/Makefile
new file mode 100644
index 0000000000..deb77fcd6d
--- /dev/null
+++ b/usr/src/uts/intel/overlay/Makefile
@@ -0,0 +1,46 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2019 Joyent, Inc.
+#
+
+UTSBASE = ../..
+
+MODULE = overlay
+OBJECTS = $(OVERLAY_OBJS:%=$(OBJS_DIR)/%)
+ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
+
+include $(UTSBASE)/intel/Makefile.intel
+
+ALL_TARGET = $(BINARY) $(SRC_CONFFILE)
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+CONF_SRCDIR = $(UTSBASE)/common/io/overlay
+MAPFILE = $(UTSBASE)/common/io/overlay/overlay.mapfile
+
+LDFLAGS += -Nmisc/mac -Ndrv/dld -Nmisc/dls -Nmisc/ksocket
+
+# needs work
+SMATCH=off
+
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+install: $(INSTALL_DEPS)
+
+include $(UTSBASE)/intel/Makefile.targ
diff --git a/usr/src/uts/intel/pcbe/opteron_pcbe.c b/usr/src/uts/intel/pcbe/opteron_pcbe.c
index 6fb22b1751..2cae323ee5 100644
--- a/usr/src/uts/intel/pcbe/opteron_pcbe.c
+++ b/usr/src/uts/intel/pcbe/opteron_pcbe.c
@@ -631,7 +631,8 @@ opt_pcbe_init(void)
amd_events = opteron_pcbe_f17h_zen2_events;
amd_generic_events = family_17h_zen2_papi_events;
} else if (amd_family == 0x19 && (amd_model <= 0xf ||
- (amd_model >= 0x20 && amd_model <= 0x2f))) {
+ (amd_model >= 0x20 && amd_model <= 0x2f) ||
+ (amd_model >= 0x50 && amd_model <= 0x5f))) {
amd_pcbe_cpuref = amd_fam_19h_zen3_reg;
amd_events = opteron_pcbe_f19h_zen3_events;
amd_generic_events = family_19h_zen3_papi_events;
diff --git a/usr/src/uts/intel/pci_autoconfig/Makefile b/usr/src/uts/intel/pci_autoconfig/Makefile
index 74498aea94..f3c034cb03 100644
--- a/usr/src/uts/intel/pci_autoconfig/Makefile
+++ b/usr/src/uts/intel/pci_autoconfig/Makefile
@@ -57,9 +57,9 @@ ALL_TARGET = $(BINARY)
INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
#
-# Depends on acpica ACPI CA interpreter and PCI-E framework
+# Depends on the platform's resource discovery and PCI-E framework
#
-LDFLAGS += -Nmisc/acpica -Nmisc/pcie
+LDFLAGS += -Nmisc/pcie -Nmisc/pci_prd
#
# Default build targets.
diff --git a/usr/src/uts/intel/smrt/Makefile b/usr/src/uts/intel/smrt/Makefile
new file mode 100644
index 0000000000..37d47e1395
--- /dev/null
+++ b/usr/src/uts/intel/smrt/Makefile
@@ -0,0 +1,64 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2017, Joyent, Inc.
+#
+
+#
+# Path to the base of the uts directory tree
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = smrt
+OBJECTS = $(SMRT_OBJS:%=$(OBJS_DIR)/%)
+ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR = $(UTSBASE)/common/io/scsi/adapters/smrt
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY) $(CONFMOD)
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+# Kernel Module Dependencies
+#
+LDFLAGS += -Nmisc/scsi
+
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
diff --git a/usr/src/uts/intel/sys/fp.h b/usr/src/uts/intel/sys/fp.h
index dfbcf7dc1c..7423444c60 100644
--- a/usr/src/uts/intel/sys/fp.h
+++ b/usr/src/uts/intel/sys/fp.h
@@ -21,6 +21,7 @@
/*
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2018, Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*
* Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
*/
@@ -230,11 +231,23 @@ struct fxsave_state {
} __aligned(16); /* 512 bytes */
/*
+ * This structure represents the header portion of the data layout used by the
+ * 'xsave' instruction variants. It is documented in section 13.4.2 of the
+ * Intel 64 and IA-32 Architectures Software Developer’s Manual, Volume 1
+ * (IASDv1). Although "header" is somewhat of a misnomer, considering the data
+ * begins at offset 512 of the xsave area, its contents dictate which portions
+ * of the area are present and how they may be formatted.
+ */
+struct xsave_header {
+ uint64_t xsh_xstate_bv;
+ uint64_t xsh_xcomp_bv;
+ uint64_t xsh_reserved[6];
+};
+
+/*
* This structure is written to memory by one of the 'xsave' instruction
* variants. The first 512 bytes are compatible with the format of the 'fxsave'
- * area. The header portion of the xsave layout is documented in section
- * 13.4.2 of the Intel 64 and IA-32 Architectures Software Developer’s Manual,
- * Volume 1 (IASDv1). The extended portion is documented in section 13.4.3.
+ * area. The extended portion is documented in section 13.4.3.
*
* Our size is at least AVX_XSAVE_SIZE (832 bytes), which is asserted
* statically. Enabling additional xsave-related CPU features requires an
@@ -245,9 +258,10 @@ struct fxsave_state {
* determined dynamically by querying the CPU. See the xsave_info structure in
* cpuid.c.
*
- * xsave component usage is tracked using bits in the xs_xstate_bv field. The
- * components are documented in section 13.1 of IASDv1. For easy reference,
- * this is a summary of the currently defined component bit definitions:
+ * xsave component usage is tracked using bits in the xstate_bv field of the
+ * header. The components are documented in section 13.1 of IASDv1. For easy
+ * reference, this is a summary of the currently defined component bit
+ * definitions:
* x87 0x0001
* SSE 0x0002
* AVX 0x0004
@@ -259,21 +273,28 @@ struct fxsave_state {
* PT 0x0100
* PKRU 0x0200
* When xsaveopt_ctxt is being used to save into the xsave_state area, the
- * xs_xstate_bv field is updated by the xsaveopt instruction to indicate which
+ * xstate_bv field is updated by the xsaveopt instruction to indicate which
* elements of the xsave area are active.
*
- * xs_xcomp_bv should always be 0, since we do not currently use the compressed
- * form of xsave (xsavec).
+ * The xcomp_bv field should always be 0, since we do not currently use the
+ * compressed form of xsave (xsavec).
*/
struct xsave_state {
struct fxsave_state xs_fxsave; /* 0-511 legacy region */
- uint64_t xs_xstate_bv; /* 512-519 start xsave header */
- uint64_t xs_xcomp_bv; /* 520-527 */
- uint64_t xs_reserved[6]; /* 528-575 end xsave header */
+ struct xsave_header xs_header; /* 512-575 XSAVE header */
upad128_t xs_ymm[16]; /* 576 AVX component */
} __aligned(64);
/*
+ * While AVX_XSTATE_SIZE is the smallest the kernel will allocate for FPU
+ * state-saving, other consumers may constrain themselves to the minimum
+ * possible xsave state structure, which features only the legacy area and the
+ * bare xsave header.
+ */
+#define MIN_XSAVE_SIZE (sizeof (struct fxsave_state) + \
+ sizeof (struct xsave_header))
+
+/*
* Kernel's FPU save area
*/
typedef struct {
diff --git a/usr/src/uts/intel/vxlan/Makefile b/usr/src/uts/intel/vxlan/Makefile
new file mode 100644
index 0000000000..530c66ee4c
--- /dev/null
+++ b/usr/src/uts/intel/vxlan/Makefile
@@ -0,0 +1,41 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+UTSBASE = ../..
+
+MODULE = vxlan
+OBJECTS = $(OVERLAY_VXLAN_OBJS:%=$(OBJS_DIR)/%)
+ROOTMODULE = $(ROOT_OVERLAY_DIR)/$(MODULE)
+
+include $(UTSBASE)/intel/Makefile.intel
+
+ALL_TARGET = $(BINARY)
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+
+LDFLAGS += -Ndrv/overlay -Ndrv/ip
+
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+install: $(INSTALL_DEPS)
+
+include $(UTSBASE)/intel/Makefile.targ