summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.inc110
-rw-r--r--cddl/contrib/opensolaris/cmd/sgs/tools/common/sgsmsg.c2
-rw-r--r--cddl/contrib/opensolaris/cmd/zdb/zdb.c4
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs.818
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs_main.c6
-rw-r--r--cddl/lib/libdtrace/ip.d5
-rw-r--r--cddl/lib/libdtrace/tcp.d133
-rw-r--r--include/Makefile2
-rw-r--r--lib/libc/db/recno/rec_open.c2
-rw-r--r--lib/libc/gen/fts-compat.c39
-rw-r--r--lib/libc/gen/getgrent.c4
-rw-r--r--lib/libc/gen/getloadavg.c4
-rw-r--r--lib/libc/gen/getmntinfo.c4
-rw-r--r--lib/libc/gen/getpwent.c5
-rw-r--r--lib/libc/gen/nlist.c25
-rw-r--r--lib/libc/gen/strtofflags.c9
-rw-r--r--lib/libc/gmon/gmon.c9
-rw-r--r--lib/libc/stdlib/heapsort.c11
-rw-r--r--lib/libc/stdlib/merge.c18
-rw-r--r--lib/libc/stdlib/radixsort.c30
-rw-r--r--lib/libc/sys/setuid.29
-rw-r--r--release/Makefile7
-rw-r--r--sbin/geom/class/nop/geom_nop.c6
-rw-r--r--sbin/geom/class/nop/gnop.88
-rw-r--r--sbin/ifconfig/ifconfig.c15
-rwxr-xr-xshare/dtrace/tcpdebug165
-rw-r--r--share/man/man4/ctl.459
-rw-r--r--share/man/man4/dtrace_ip.44
-rw-r--r--share/man/man4/geom_fox.49
-rw-r--r--share/man/man4/ng_pppoe.418
-rw-r--r--share/man/man9/Makefile1
-rw-r--r--share/man/man9/timeout.923
-rw-r--r--share/mk/local.meta.sys.mk18
-rw-r--r--sys/arm64/conf/GENERIC3
-rw-r--r--sys/boot/usb/usbcore.mk1
-rw-r--r--sys/cam/ctl/README.ctl.txt17
-rw-r--r--sys/cam/ctl/ctl.c520
-rw-r--r--sys/cam/ctl/ctl.h17
-rw-r--r--sys/cam/ctl/ctl_backend_block.c85
-rw-r--r--sys/cam/ctl/ctl_cmd_table.c6
-rw-r--r--sys/cam/ctl/ctl_error.c188
-rw-r--r--sys/cam/ctl/ctl_error.h2
-rw-r--r--sys/cam/ctl/ctl_frontend.c20
-rw-r--r--sys/cam/ctl/ctl_frontend_cam_sim.c23
-rw-r--r--sys/cam/ctl/ctl_frontend_ioctl.c15
-rw-r--r--sys/cam/ctl/ctl_frontend_iscsi.c80
-rw-r--r--sys/cam/ctl/ctl_ha.c17
-rw-r--r--sys/cam/ctl/ctl_io.h16
-rw-r--r--sys/cam/ctl/ctl_tpc.c47
-rw-r--r--sys/cam/ctl/ctl_tpc_local.c4
-rw-r--r--sys/cam/ctl/ctl_util.c5
-rw-r--r--sys/cam/scsi/scsi_all.c19
-rw-r--r--sys/cam/scsi/scsi_all.h4
-rw-r--r--sys/cam/scsi/scsi_ch.c9
-rw-r--r--sys/cddl/contrib/opensolaris/common/avl/avl.c10
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c111
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c21
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c32
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_zfetch.c730
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode.c4
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c19
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/arc.h41
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h5
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_zfetch.h37
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev.c9
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/sys/sysevent/eventdefs.h7
-rw-r--r--sys/conf/files.arm641
-rw-r--r--sys/conf/files.sparc641
-rw-r--r--sys/dev/dwc/if_dwc.c4
-rw-r--r--sys/dev/e1000/e1000_80003es2lan.c33
-rw-r--r--sys/dev/e1000/e1000_82540.c10
-rw-r--r--sys/dev/e1000/e1000_82541.c7
-rw-r--r--sys/dev/e1000/e1000_82542.c4
-rw-r--r--sys/dev/e1000/e1000_82543.c4
-rw-r--r--sys/dev/e1000/e1000_82571.h5
-rw-r--r--sys/dev/e1000/e1000_82575.c63
-rw-r--r--sys/dev/e1000/e1000_82575.h4
-rw-r--r--sys/dev/e1000/e1000_api.c37
-rw-r--r--sys/dev/e1000/e1000_api.h1
-rw-r--r--sys/dev/e1000/e1000_defines.h48
-rw-r--r--sys/dev/e1000/e1000_hw.h8
-rw-r--r--sys/dev/e1000/e1000_i210.c99
-rw-r--r--sys/dev/e1000/e1000_i210.h2
-rw-r--r--sys/dev/e1000/e1000_ich8lan.c1058
-rw-r--r--sys/dev/e1000/e1000_ich8lan.h47
-rw-r--r--sys/dev/e1000/e1000_mac.c12
-rw-r--r--sys/dev/e1000/e1000_mac.h3
-rw-r--r--sys/dev/e1000/e1000_nvm.c146
-rw-r--r--sys/dev/e1000/e1000_nvm.h21
-rw-r--r--sys/dev/e1000/e1000_osdep.h7
-rw-r--r--sys/dev/e1000/e1000_phy.c4
-rw-r--r--sys/dev/e1000/e1000_regs.h10
-rw-r--r--sys/dev/e1000/if_igb.c8
-rw-r--r--sys/dev/ral/rt2860.c2
-rw-r--r--sys/dev/re/if_re.c2
-rw-r--r--sys/dev/rl/if_rlreg.h1
-rw-r--r--sys/dev/uart/uart_bus_pci.c1
-rw-r--r--sys/dev/usb/controller/uhci_pci.c2
-rw-r--r--sys/dev/usb/controller/xhci_pci.c3
-rw-r--r--sys/dev/usb/serial/u3g.c1
-rw-r--r--sys/dev/usb/usbdevs1
-rw-r--r--sys/dev/usb/wlan/if_rsu.c180
-rw-r--r--sys/dev/usb/wlan/if_run.c2
-rw-r--r--sys/dev/usb/wlan/if_ural.c5
-rw-r--r--sys/geom/nop/g_nop.c42
-rw-r--r--sys/geom/nop/g_nop.h2
-rw-r--r--sys/gnu/fs/reiserfs/reiserfs_vfsops.c1
-rw-r--r--sys/kern/kern_linker.c8
-rw-r--r--sys/kern/kern_proc.c2
-rw-r--r--sys/kern/kern_rmlock.c6
-rw-r--r--sys/kern/kern_sysctl.c204
-rw-r--r--sys/kern/kern_timeout.c39
-rw-r--r--sys/kern/subr_syscall.c10
-rw-r--r--sys/kern/vfs_init.c4
-rw-r--r--sys/kern/vfs_subr.c15
-rw-r--r--sys/kern/vnode_if.src1
-rw-r--r--sys/net/if.c75
-rw-r--r--sys/net/if_arcsubr.c22
-rw-r--r--sys/net/if_ethersubr.c31
-rw-r--r--sys/net/if_fddisubr.c18
-rw-r--r--sys/net/if_fwsubr.c13
-rw-r--r--sys/net/if_iso88025subr.c4
-rw-r--r--sys/net/if_llatbl.c59
-rw-r--r--sys/net/if_llatbl.h18
-rw-r--r--sys/net/if_var.h13
-rw-r--r--sys/net/route.c24
-rw-r--r--sys/netinet/if_ether.c148
-rw-r--r--sys/netinet/if_ether.h1
-rw-r--r--sys/netinet/in.c138
-rw-r--r--sys/netinet/in_kdtrace.c19
-rw-r--r--sys/netinet/in_kdtrace.h10
-rw-r--r--sys/netinet/ip_carp.c2
-rw-r--r--sys/netinet/sctp.h20
-rw-r--r--sys/netinet/sctp_auth.c25
-rw-r--r--sys/netinet/sctp_header.h51
-rw-r--r--sys/netinet/sctp_indata.c64
-rw-r--r--sys/netinet/sctp_input.c80
-rw-r--r--sys/netinet/sctp_sysctl.h2
-rw-r--r--sys/netinet/tcp_input.c8
-rw-r--r--sys/netinet/tcp_output.c13
-rw-r--r--sys/netinet/tcp_subr.c130
-rw-r--r--sys/netinet/tcp_timer.c7
-rw-r--r--sys/netinet/tcp_usrreq.c19
-rw-r--r--sys/netinet6/icmp6.c34
-rw-r--r--sys/netinet6/in6.c76
-rw-r--r--sys/netinet6/ip6_forward.c2
-rw-r--r--sys/netinet6/ip6_output.c4
-rw-r--r--sys/netinet6/nd6.c487
-rw-r--r--sys/netinet6/nd6.h21
-rw-r--r--sys/netinet6/nd6_rtr.c2
-rw-r--r--sys/netpfil/pf/pf.c2
-rw-r--r--sys/ofed/drivers/infiniband/core/addr.c2
-rw-r--r--sys/ofed/drivers/infiniband/core/mad.c2
-rw-r--r--sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c2
-rw-r--r--sys/sparc64/ebus/ebus.c35
-rw-r--r--sys/sparc64/include/smp.h20
-rw-r--r--sys/sparc64/pci/fire.c332
-rw-r--r--sys/sparc64/pci/firereg.h1
-rw-r--r--sys/sparc64/pci/firevar.h20
-rw-r--r--sys/sparc64/pci/ofw_pci.c406
-rw-r--r--sys/sparc64/pci/ofw_pci.h43
-rw-r--r--sys/sparc64/pci/psycho.c337
-rw-r--r--sys/sparc64/pci/psychoreg.h6
-rw-r--r--sys/sparc64/pci/psychovar.h47
-rw-r--r--sys/sparc64/pci/schizo.c346
-rw-r--r--sys/sparc64/pci/schizoreg.h5
-rw-r--r--sys/sparc64/pci/schizovar.h37
-rw-r--r--sys/sys/_callout.h2
-rw-r--r--sys/sys/callout.h1
-rw-r--r--sys/sys/sysctl.h4
-rw-r--r--sys/sys/vnode.h1
-rw-r--r--sys/x86/acpica/madt.c14
-rw-r--r--tools/tools/usbtest/Makefile1
-rw-r--r--usr.bin/rctl/rctl.84
-rw-r--r--usr.sbin/bsdconfig/share/common.subr6
-rwxr-xr-xusr.sbin/bsdinstall/scripts/auto28
-rwxr-xr-xusr.sbin/bsdinstall/scripts/config4
-rwxr-xr-xusr.sbin/bsdinstall/scripts/docsinstall4
-rwxr-xr-xusr.sbin/bsdinstall/scripts/hostname6
-rwxr-xr-xusr.sbin/bsdinstall/scripts/jail3
-rwxr-xr-xusr.sbin/bsdinstall/scripts/keymap3
-rwxr-xr-xusr.sbin/bsdinstall/scripts/netconfig_ipv410
-rwxr-xr-xusr.sbin/bsdinstall/scripts/netconfig_ipv610
-rwxr-xr-xusr.sbin/bsdinstall/scripts/rootpass1
-rwxr-xr-xusr.sbin/bsdinstall/scripts/script5
-rwxr-xr-xusr.sbin/bsdinstall/scripts/wlanconfig4
-rwxr-xr-xusr.sbin/bsdinstall/scripts/zfsboot2
-rw-r--r--usr.sbin/ctladm/ctladm.87
-rw-r--r--usr.sbin/ctld/ctl.conf.56
-rw-r--r--usr.sbin/ctld/ctld.c3
-rw-r--r--usr.sbin/ctld/ctld.h2
-rw-r--r--usr.sbin/ctld/kernel.c15
-rw-r--r--usr.sbin/ctld/login.c5
-rw-r--r--usr.sbin/ctld/parse.y26
-rw-r--r--usr.sbin/ctld/token.l1
-rw-r--r--usr.sbin/i2c/i2c.c107
-rw-r--r--usr.sbin/pw/pw_user.c3
197 files changed, 4896 insertions, 3662 deletions
diff --git a/Makefile.inc1 b/Makefile.inc1
index 397c1af..f88c547 100644
--- a/Makefile.inc1
+++ b/Makefile.inc1
@@ -1258,7 +1258,7 @@ _elftoolchain_libs= lib/libelf lib/libdwarf
legacy:
.if ${BOOTSTRAPPING} < 800107 && ${BOOTSTRAPPING} != 0
- @echo "ERROR: Source upgrades from versions prior to 8.0 not supported."; \
+ @echo "ERROR: Source upgrades from versions prior to 8.0 are not supported."; \
false
.endif
.for _tool in tools/build ${_elftoolchain_libs}
@@ -1355,11 +1355,8 @@ ${_bt}-usr.bin/clang/clang-tblgen: ${_bt}-lib/clang/libllvmtablegen ${_bt}-lib/c
${_bt}-usr.bin/clang/tblgen: ${_bt}-lib/clang/libllvmtablegen ${_bt}-lib/clang/libllvmsupport
.endif
-# ELF Tool Chain libraries are needed for ELF tools and dtrace tools.
-# dtrace tools are required for older bootstrap env and cross-build
-# pre libdwarf
-.if ${BOOTSTRAPPING} < 1100006 || (${MACHINE} != ${TARGET} || \
- ${MACHINE_ARCH} != ${TARGET_ARCH})
+# Rebuild ctfconvert and ctfmerge to avoid difficult-to-diagnose failures
+# resulting from missing bug fixes or ELF Toolchain updates.
.if ${MK_CDDL} != "no"
_dtrace_tools= cddl/usr.bin/sgsmsg cddl/lib/libctf cddl/usr.bin/ctfconvert \
cddl/usr.bin/ctfmerge
@@ -1367,7 +1364,6 @@ _dtrace_tools= cddl/usr.bin/sgsmsg cddl/lib/libctf cddl/usr.bin/ctfconvert \
${_bt}-cddl/usr.bin/ctfconvert: ${_bt}-cddl/lib/libctf
${_bt}-cddl/usr.bin/ctfmerge: ${_bt}-cddl/lib/libctf
.endif
-.endif
# Default to building the GPL DTC, but build the BSDL one if users explicitly
# request it.
diff --git a/cddl/contrib/opensolaris/cmd/sgs/tools/common/sgsmsg.c b/cddl/contrib/opensolaris/cmd/sgs/tools/common/sgsmsg.c
index 9b2e37b..9432161 100644
--- a/cddl/contrib/opensolaris/cmd/sgs/tools/common/sgsmsg.c
+++ b/cddl/contrib/opensolaris/cmd/sgs/tools/common/sgsmsg.c
@@ -132,6 +132,8 @@ typedef struct msg_string {
static msg_string *msg_head;
static msg_string *msg_tail;
+int aok;
+
/*
* message_append() is responsible for both inserting strings into
* the master Str_tbl as well as maintaining a list of the
diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb.c b/cddl/contrib/opensolaris/cmd/zdb/zdb.c
index 4f5c372..7f25880 100644
--- a/cddl/contrib/opensolaris/cmd/zdb/zdb.c
+++ b/cddl/contrib/opensolaris/cmd/zdb/zdb.c
@@ -1205,7 +1205,9 @@ snprintf_blkptr_compact(char *blkbuf, size_t buflen, const blkptr_t *bp)
if (BP_IS_HOLE(bp)) {
(void) snprintf(blkbuf + strlen(blkbuf),
- buflen - strlen(blkbuf), "B=%llu",
+ buflen - strlen(blkbuf),
+ "%llxL B=%llu",
+ (u_longlong_t)BP_GET_LSIZE(bp),
(u_longlong_t)bp->blk_birth);
} else {
(void) snprintf(blkbuf + strlen(blkbuf),
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs.8 b/cddl/contrib/opensolaris/cmd/zfs/zfs.8
index 4da6d0b..e534ae9 100644
--- a/cddl/contrib/opensolaris/cmd/zfs/zfs.8
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs.8
@@ -31,7 +31,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 30, 2015
+.Dd September 14, 2015
.Dt ZFS 8
.Os
.Sh NAME
@@ -2144,7 +2144,8 @@ Property name
.It value
Property value
.It source
-Property source. Can either be local, default, temporary, inherited, or none
+Property source. Can either be local, default, temporary, inherited, received,
+or none
(\&-).
.El
.Pp
@@ -2210,8 +2211,11 @@ The default value is all sources.
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot Ns ...
.Xc
.Pp
-Clears the specified property, causing it to be inherited from an ancestor. If
-no ancestor has the property set, then the default value is used. See the
+Clears the specified property, causing it to be inherited from an ancestor,
+restored to default if no ancestor has the property set, or with the
+.Fl S
+option reverted to the received value if one exists.
+See the
.Qq Sx Properties
section for a listing of default values, and details on which properties can be
inherited.
@@ -2219,8 +2223,10 @@ inherited.
.It Fl r
Recursively inherit the given property for all children.
.It Fl S
-For properties with a received value, revert to this value. This flag has no
-effect on properties that do not have a received value.
+Revert the property to the received value if one exists; otherwise operate as
+if the
+.Fl S
+option was not specified.
.El
.It Xo
.Nm
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c b/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
index 9d80b9b..9ea178e 100644
--- a/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
@@ -1928,9 +1928,13 @@ zfs_do_inherit(int argc, char **argv)
if (prop == ZFS_PROP_QUOTA ||
prop == ZFS_PROP_RESERVATION ||
prop == ZFS_PROP_REFQUOTA ||
- prop == ZFS_PROP_REFRESERVATION)
+ prop == ZFS_PROP_REFRESERVATION) {
(void) fprintf(stderr, gettext("use 'zfs set "
"%s=none' to clear\n"), propname);
+ (void) fprintf(stderr, gettext("use 'zfs "
+ "inherit -S %s' to revert to received "
+ "value\n"), propname);
+ }
return (1);
}
if (received && (prop == ZFS_PROP_VOLSIZE ||
diff --git a/cddl/lib/libdtrace/ip.d b/cddl/lib/libdtrace/ip.d
index 33fb007..eb3846b 100644
--- a/cddl/lib/libdtrace/ip.d
+++ b/cddl/lib/libdtrace/ip.d
@@ -110,7 +110,6 @@ typedef struct ipv4info {
* These values are NULL if the packet is not IPv6.
*/
typedef struct in6_addr in6_addr_t;
-typedef struct ip6_hdr ip6_t;
typedef struct ipv6info {
uint8_t ipv6_ver; /* IP version (6) */
uint8_t ipv6_tclass; /* traffic class */
@@ -123,7 +122,7 @@ typedef struct ipv6info {
in6_addr_t *ipv6_dst; /* destination address */
string ipv6_saddr; /* source address, string */
string ipv6_daddr; /* destination address, string */
- ip6_t *ipv6_hdr; /* pointer to raw header */
+ struct ip6_hdr *ipv6_hdr; /* pointer to raw header */
} ipv6info_t;
#pragma D binding "1.5" IPPROTO_IP
@@ -282,5 +281,5 @@ translator ipv6info_t < struct ip6_hdr *p > {
ipv6_dst = p == NULL ? 0 : (in6_addr_t *)&p->ip6_dst;
ipv6_saddr = p == NULL ? 0 : inet_ntoa6(&p->ip6_src);
ipv6_daddr = p == NULL ? 0 : inet_ntoa6(&p->ip6_dst);
- ipv6_hdr = (ip6_t *)p;
+ ipv6_hdr = p;
};
diff --git a/cddl/lib/libdtrace/tcp.d b/cddl/lib/libdtrace/tcp.d
index 8398cd3..da55c1d 100644
--- a/cddl/lib/libdtrace/tcp.d
+++ b/cddl/lib/libdtrace/tcp.d
@@ -103,11 +103,15 @@ typedef struct tcpsinfo {
int32_t tcps_state; /* TCP state */
uint32_t tcps_iss; /* Initial sequence # sent */
uint32_t tcps_suna; /* sequence # sent but unacked */
+ uint32_t tcps_smax; /* highest sequence number sent */
uint32_t tcps_snxt; /* next sequence # to send */
uint32_t tcps_rack; /* sequence # we have acked */
uint32_t tcps_rnxt; /* next sequence # expected */
uint32_t tcps_swnd; /* send window size */
int32_t tcps_snd_ws; /* send window scaling */
+ uint32_t tcps_swl1; /* window update seg seq number */
+ uint32_t tcps_swl2; /* window update seg ack number */
+ uint32_t tcps_rup; /* receive urgent pointer */
uint32_t tcps_rwnd; /* receive window size */
int32_t tcps_rcv_ws; /* receive window scaling */
uint32_t tcps_cwnd; /* congestion window */
@@ -117,7 +121,8 @@ typedef struct tcpsinfo {
uint32_t tcps_rto; /* round-trip timeout, msec */
uint32_t tcps_mss; /* max segment size */
int tcps_retransmit; /* retransmit send event, boolean */
- int tcps_srtt; /* smoothed RTT in units of (TCP_RTT_SCALE*hz) */
+ int tcps_srtt; /* smoothed RTT in units of (TCP_RTT_SCALE*hz) */
+ int tcps_debug; /* socket has SO_DEBUG set */
} tcpsinfo_t;
/*
@@ -188,12 +193,16 @@ translator tcpsinfo_t < struct tcpcb *p > {
tcps_state = p == NULL ? -1 : p->t_state;
tcps_iss = p == NULL ? 0 : p->iss;
tcps_suna = p == NULL ? 0 : p->snd_una;
+ tcps_smax = p == NULL ? 0 : p->snd_max;
tcps_snxt = p == NULL ? 0 : p->snd_nxt;
tcps_rack = p == NULL ? 0 : p->last_ack_sent;
tcps_rnxt = p == NULL ? 0 : p->rcv_nxt;
tcps_swnd = p == NULL ? -1 : p->snd_wnd;
tcps_snd_ws = p == NULL ? -1 : p->snd_scale;
+ tcps_swl1 = p == NULL ? -1 : p->snd_wl1;
+ tcps_swl2 = p == NULL ? -1 : p->snd_wl2;
tcps_rwnd = p == NULL ? -1 : p->rcv_wnd;
+ tcps_rup = p == NULL ? -1 : p->rcv_up;
tcps_rcv_ws = p == NULL ? -1 : p->rcv_scale;
tcps_cwnd = p == NULL ? -1 : p->snd_cwnd;
tcps_cwnd_ssthresh = p == NULL ? -1 : p->snd_ssthresh;
@@ -203,6 +212,8 @@ translator tcpsinfo_t < struct tcpcb *p > {
tcps_mss = p == NULL ? -1 : p->t_maxseg;
tcps_retransmit = p == NULL ? -1 : p->t_rxtshift > 0 ? 1 : 0;
tcps_srtt = p == NULL ? -1 : p->t_srtt; /* smoothed RTT in units of (TCP_RTT_SCALE*hz) */
+ tcps_debug = p == NULL ? 0 :
+ p->t_inpcb->inp_socket->so_options & 1;
};
#pragma D binding "1.6.3" translator
@@ -242,3 +253,123 @@ translator tcpinfoh_t < struct tcphdr *p > {
translator tcplsinfo_t < int s > {
tcps_state = s;
};
+
+
+/* Support for TCP debug */
+
+#pragma D binding "1.12.1" TA_INPUT
+inline int TA_INPUT = 0;
+#pragma D binding "1.12.1" TA_OUTPUT
+inline int TA_OUTPUT = 1;
+#pragma D binding "1.12.1" TA_USER
+inline int TA_USER = 2;
+#pragma D binding "1.12.1" TA_RESPOND
+inline int TA_RESPOND = 3;
+#pragma D binding "1.12.1" TA_DROP
+inline int TA_DROP = 4;
+
+/* direction strings. */
+
+#pragma D binding "1.12.1" tcpdebug_dir_string
+inline string tcpdebug_dir_string[uint8_t direction] =
+ direction == TA_INPUT ? "input" :
+ direction == TA_OUTPUT ? "output" :
+ direction == TA_USER ? "user" :
+ direction == TA_RESPOND ? "respond" :
+ direction == TA_OUTPUT ? "drop" :
+ "unknown" ;
+
+#pragma D binding "1.12.1" tcpflag_string
+inline string tcpflag_string[uint8_t flags] =
+ flags & TH_FIN ? "FIN" :
+ flags & TH_SYN ? "SYN" :
+ flags & TH_RST ? "RST" :
+ flags & TH_PUSH ? "PUSH" :
+ flags & TH_ACK ? "ACK" :
+ flags & TH_URG ? "URG" :
+ flags & TH_ECE ? "ECE" :
+ flags & TH_CWR ? "CWR" :
+ "unknown" ;
+
+#pragma D binding "1.12.1" PRU_ATTACH
+inline int PRU_ATTACH = 0;
+#pragma D binding "1.12.1" PRU_DETACH
+inline int PRU_DETACH = 1;
+#pragma D binding "1.12.1" PRU_BIND
+inline int PRU_BIND = 2;
+#pragma D binding "1.12.1" PRU_LISTEN
+inline int PRU_LISTEN = 3;
+#pragma D binding "1.12.1" PRU_CONNECT
+inline int PRU_CONNECT = 4;
+#pragma D binding "1.12.1" PRU_ACCEPT
+inline int PRU_ACCEPT = 5 ;
+#pragma D binding "1.12.1" PRU_DISCONNECT
+inline int PRU_DISCONNECT= 6;
+#pragma D binding "1.12.1" PRU_SHUTDOWN
+inline int PRU_SHUTDOWN = 7;
+#pragma D binding "1.12.1" PRU_RCVD
+inline int PRU_RCVD = 8;
+#pragma D binding "1.12.1" PRU_SEND
+inline int PRU_SEND = 9;
+#pragma D binding "1.12.1" PRU_ABORT
+inline int PRU_ABORT = 10;
+#pragma D binding "1.12.1" PRU_CONTROL
+inline int PRU_CONTROL = 11;
+#pragma D binding "1.12.1" PRU_SENSE
+inline int PRU_SENSE = 12;
+#pragma D binding "1.12.1" PRU_RCVOOB
+inline int PRU_RCVOOB = 13;
+#pragma D binding "1.12.1" PRU_SENDOOB
+inline int PRU_SENDOOB = 14;
+#pragma D binding "1.12.1" PRU_SOCKADDR
+inline int PRU_SOCKADDR = 15;
+#pragma D binding "1.12.1" PRU_PEERADDR
+inline int PRU_PEERADDR = 16;
+#pragma D binding "1.12.1" PRU_CONNECT2
+inline int PRU_CONNECT2 = 17;
+#pragma D binding "1.12.1" PRU_FASTTIMO
+inline int PRU_FASTTIMO = 18;
+#pragma D binding "1.12.1" PRU_SLOWTIMO
+inline int PRU_SLOWTIMO = 19;
+#pragma D binding "1.12.1" PRU_PROTORCV
+inline int PRU_PROTORCV = 20;
+#pragma D binding "1.12.1" PRU_PROTOSEND
+inline int PRU_PROTOSEND = 21;
+#pragma D binding "1.12.1" PRU_SEND_EOF
+inline int PRU_SEND_EOF = 22;
+#pragma D binding "1.12.1" PRU_SOSETLABEL
+inline int PRU_SOSETLABEL = 23;
+#pragma D binding "1.12.1" PRU_CLOSE
+inline int PRU_CLOSE = 24;
+#pragma D binding "1.12.1" PRU_FLUSH
+inline int PRU_FLUSH = 25;
+
+#pragma D binding "1.12.1" prureq_string
+inline string prureq_string[uint8_t req] =
+ req == PRU_ATTACH ? "ATTACH" :
+ req == PRU_DETACH ? "DETACH" :
+ req == PRU_BIND ? "BIND" :
+ req == PRU_LISTEN ? "LISTEN" :
+ req == PRU_CONNECT ? "CONNECT" :
+ req == PRU_ACCEPT ? "ACCEPT" :
+ req == PRU_DISCONNECT ? "DISCONNECT" :
+ req == PRU_SHUTDOWN ? "SHUTDOWN" :
+ req == PRU_RCVD ? "RCVD" :
+ req == PRU_SEND ? "SEND" :
+ req == PRU_ABORT ? "ABORT" :
+ req == PRU_CONTROL ? "CONTROL" :
+ req == PRU_SENSE ? "SENSE" :
+ req == PRU_RCVOOB ? "RCVOOB" :
+ req == PRU_SENDOOB ? "SENDOOB" :
+ req == PRU_SOCKADDR ? "SOCKADDR" :
+ req == PRU_PEERADDR ? "PEERADDR" :
+ req == PRU_CONNECT2 ? "CONNECT2" :
+ req == PRU_FASTTIMO ? "FASTTIMO" :
+ req == PRU_SLOWTIMO ? "SLOWTIMO" :
+ req == PRU_PROTORCV ? "PROTORCV" :
+ req == PRU_PROTOSEND ? "PROTOSEND" :
+ req == PRU_SEND ? "SEND_EOF" :
+ req == PRU_SOSETLABEL ? "SOSETLABEL" :
+ req == PRU_CLOSE ? "CLOSE" :
+ req == PRU_FLUSH ? "FLUSE" :
+ "unknown" ;
diff --git a/include/Makefile b/include/Makefile
index ccdc8aa..5d585a1 100644
--- a/include/Makefile
+++ b/include/Makefile
@@ -255,6 +255,7 @@ copies:
${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 teken.h \
${DESTDIR}${INCLUDEDIR}/teken
.if ${MK_META_MODE} == "yes"
+ cd ${.OBJDIR}
touch ${.TARGET}
.endif
@@ -372,6 +373,7 @@ symlinks:
${DESTDIR}${INCLUDEDIR}/rpc; \
done
.if ${MK_META_MODE} == "yes"
+ cd ${.OBJDIR}
touch ${.TARGET}
.endif
diff --git a/lib/libc/db/recno/rec_open.c b/lib/libc/db/recno/rec_open.c
index dd286c0..8fce730 100644
--- a/lib/libc/db/recno/rec_open.c
+++ b/lib/libc/db/recno/rec_open.c
@@ -64,7 +64,7 @@ __rec_open(const char *fname, int flags, int mode, const RECNOINFO *openinfo,
int rfd, sverrno;
/* Open the user's file -- if this fails, we're done. */
- if (fname != NULL && (rfd = _open(fname, flags, mode)) < 0)
+ if (fname != NULL && (rfd = _open(fname, flags | O_CLOEXEC, mode)) < 0)
return (NULL);
/* Create a btree in memory (backed by disk). */
diff --git a/lib/libc/gen/fts-compat.c b/lib/libc/gen/fts-compat.c
index 1be41da..105b064 100644
--- a/lib/libc/gen/fts-compat.c
+++ b/lib/libc/gen/fts-compat.c
@@ -635,9 +635,7 @@ __fts_set_clientptr_44bsd(FTS *sp, void *clientptr)
* been found, cutting the stat calls by about 2/3.
*/
static FTSENT *
-fts_build(sp, type)
- FTS *sp;
- int type;
+fts_build(FTS *sp, int type)
{
struct dirent *dp;
FTSENT *p, *head;
@@ -901,10 +899,7 @@ mem1: saved_errno = errno;
}
static u_short
-fts_stat(sp, p, follow)
- FTS *sp;
- FTSENT *p;
- int follow;
+fts_stat(FTS *sp, FTSENT *p, int follow)
{
FTSENT *t;
dev_t dev;
@@ -999,10 +994,7 @@ fts_compar(const void *a, const void *b)
}
static FTSENT *
-fts_sort(sp, head, nitems)
- FTS *sp;
- FTSENT *head;
- int nitems;
+fts_sort(FTS *sp, FTSENT *head, int nitems)
{
FTSENT **ap, *p;
@@ -1031,10 +1023,7 @@ fts_sort(sp, head, nitems)
}
static FTSENT *
-fts_alloc(sp, name, namelen)
- FTS *sp;
- char *name;
- int namelen;
+fts_alloc(FTS *sp, char *name, int namelen)
{
FTSENT *p;
size_t len;
@@ -1081,8 +1070,7 @@ fts_alloc(sp, name, namelen)
}
static void
-fts_lfree(head)
- FTSENT *head;
+fts_lfree(FTSENT *head)
{
FTSENT *p;
@@ -1100,9 +1088,7 @@ fts_lfree(head)
* plus 256 bytes so don't realloc the path 2 bytes at a time.
*/
static int
-fts_palloc(sp, more)
- FTS *sp;
- size_t more;
+fts_palloc(FTS *sp, size_t more)
{
sp->fts_pathlen += more + 256;
@@ -1127,9 +1113,7 @@ fts_palloc(sp, more)
* already returned.
*/
static void
-fts_padjust(sp, head)
- FTS *sp;
- FTSENT *head;
+fts_padjust(FTS *sp, FTSENT *head)
{
FTSENT *p;
char *addr = sp->fts_path;
@@ -1153,8 +1137,7 @@ fts_padjust(sp, head)
}
static size_t
-fts_maxarglen(argv)
- char * const *argv;
+fts_maxarglen(char * const *argv)
{
size_t len, max;
@@ -1170,11 +1153,7 @@ fts_maxarglen(argv)
* Assumes p->fts_dev and p->fts_ino are filled in.
*/
static int
-fts_safe_changedir(sp, p, fd, path)
- FTS *sp;
- FTSENT *p;
- int fd;
- char *path;
+fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path)
{
int ret, oerrno, newfd;
struct stat sb;
diff --git a/lib/libc/gen/getgrent.c b/lib/libc/gen/getgrent.c
index 1f4d7e9..93a82c2 100644
--- a/lib/libc/gen/getgrent.c
+++ b/lib/libc/gen/getgrent.c
@@ -1238,7 +1238,7 @@ compat_setgrent(void *retval, void *mdata, va_list ap)
int rv, stayopen;
#define set_setent(x, y) do { \
- int i; \
+ unsigned int i; \
\
for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \
x[i].mdata = (void *)y; \
@@ -1308,7 +1308,7 @@ compat_group(void *retval, void *mdata, va_list ap)
int rv, stayopen, *errnop;
#define set_lookup_type(x, y) do { \
- int i; \
+ unsigned int i; \
\
for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \
x[i].mdata = (void *)y; \
diff --git a/lib/libc/gen/getloadavg.c b/lib/libc/gen/getloadavg.c
index 127d3e8..9c06d0a 100644
--- a/lib/libc/gen/getloadavg.c
+++ b/lib/libc/gen/getloadavg.c
@@ -48,9 +48,7 @@ __FBSDID("$FreeBSD$");
* Return number of samples retrieved, or -1 on error.
*/
int
-getloadavg(loadavg, nelem)
- double loadavg[];
- int nelem;
+getloadavg(double loadavg[], int nelem)
{
struct loadavg loadinfo;
int i, mib[2];
diff --git a/lib/libc/gen/getmntinfo.c b/lib/libc/gen/getmntinfo.c
index 2b532f6..99f82aa 100644
--- a/lib/libc/gen/getmntinfo.c
+++ b/lib/libc/gen/getmntinfo.c
@@ -42,9 +42,7 @@ __FBSDID("$FreeBSD$");
* Return information about mounted filesystems.
*/
int
-getmntinfo(mntbufp, flags)
- struct statfs **mntbufp;
- int flags;
+getmntinfo(struct statfs **mntbufp, int flags)
{
static struct statfs *mntbuf;
static int mntsize;
diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c
index 09a6247..6546f587 100644
--- a/lib/libc/gen/getpwent.c
+++ b/lib/libc/gen/getpwent.c
@@ -1607,7 +1607,8 @@ compat_redispatch(struct compat_state *st, enum nss_lookup_type how,
{ NULL, NULL, NULL }
};
void *discard;
- int rv, e, i;
+ int rv, e;
+ unsigned int i;
for (i = 0; i < sizeof(dtab)/sizeof(dtab[0]) - 1; i++)
dtab[i].mdata = (void *)lookup_how;
@@ -1702,7 +1703,7 @@ compat_setpwent(void *retval, void *mdata, va_list ap)
int rv, stayopen;
#define set_setent(x, y) do { \
- int i; \
+ unsigned int i; \
\
for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \
x[i].mdata = (void *)y; \
diff --git a/lib/libc/gen/nlist.c b/lib/libc/gen/nlist.c
index ec878c5..88254cd 100644
--- a/lib/libc/gen/nlist.c
+++ b/lib/libc/gen/nlist.c
@@ -63,9 +63,7 @@ int __aout_fdnlist(int, struct nlist *);
int __elf_fdnlist(int, struct nlist *);
int
-nlist(name, list)
- const char *name;
- struct nlist *list;
+nlist(const char *name, struct nlist *list)
{
int fd, n;
@@ -89,11 +87,10 @@ static struct nlist_handlers {
};
int
-__fdnlist(fd, list)
- int fd;
- struct nlist *list;
+__fdnlist(int fd, struct nlist *list)
{
- int n = -1, i;
+ int n = -1;
+ unsigned int i;
for (i = 0; i < sizeof(nlist_fn) / sizeof(nlist_fn[0]); i++) {
n = (nlist_fn[i].fn)(fd, list);
@@ -107,9 +104,7 @@ __fdnlist(fd, list)
#ifdef _NLIST_DO_AOUT
int
-__aout_fdnlist(fd, list)
- int fd;
- struct nlist *list;
+__aout_fdnlist(int fd, struct nlist *list)
{
struct nlist *p, *symtab;
caddr_t strtab, a_out_mmap;
@@ -235,9 +230,7 @@ __elf_is_okay__(Elf_Ehdr *ehdr)
}
int
-__elf_fdnlist(fd, list)
- int fd;
- struct nlist *list;
+__elf_fdnlist(int fd, struct nlist *list)
{
struct nlist *p;
Elf_Off symoff = 0, symstroff = 0;
@@ -377,11 +370,7 @@ __elf_fdnlist(fd, list)
* n_value and n_type members.
*/
static void
-elf_sym_to_nlist(nl, s, shdr, shnum)
- struct nlist *nl;
- Elf_Sym *s;
- Elf_Shdr *shdr;
- int shnum;
+elf_sym_to_nlist(struct nlist *nl, Elf_Sym *s, Elf_Shdr *shdr, int shnum)
{
nl->n_value = s->st_value;
diff --git a/lib/libc/gen/strtofflags.c b/lib/libc/gen/strtofflags.c
index 55e9945..dba9cd2 100644
--- a/lib/libc/gen/strtofflags.c
+++ b/lib/libc/gen/strtofflags.c
@@ -94,14 +94,13 @@ static struct {
* are set, return the empty string.
*/
char *
-fflagstostr(flags)
- u_long flags;
+fflagstostr(u_long flags)
{
char *string;
const char *sp;
char *dp;
u_long setflags;
- int i;
+ u_int i;
if ((string = (char *)malloc(nmappings * (longestflaglen + 1))) == NULL)
return (NULL);
@@ -128,9 +127,7 @@ fflagstostr(flags)
* to the offending token.
*/
int
-strtofflags(stringp, setp, clrp)
- char **stringp;
- u_long *setp, *clrp;
+strtofflags(char **stringp, u_long *setp, u_long *clrp)
{
char *string, *p;
int i;
diff --git a/lib/libc/gmon/gmon.c b/lib/libc/gmon/gmon.c
index 1f56bc2..b17a18f 100644
--- a/lib/libc/gmon/gmon.c
+++ b/lib/libc/gmon/gmon.c
@@ -70,9 +70,7 @@ void moncontrol(int);
static int hertz(void);
void
-monstartup(lowpc, highpc)
- u_long lowpc;
- u_long highpc;
+monstartup(u_long lowpc, u_long highpc)
{
int o;
char *cp;
@@ -218,8 +216,7 @@ _mcleanup(void)
* all the data structures are ready.
*/
void
-moncontrol(mode)
- int mode;
+moncontrol(int mode)
{
struct gmonparam *p = &_gmonparam;
@@ -239,7 +236,7 @@ moncontrol(mode)
* if something goes wrong, we return 0, an impossible hertz.
*/
static int
-hertz()
+hertz(void)
{
struct itimerval tim;
diff --git a/lib/libc/stdlib/heapsort.c b/lib/libc/stdlib/heapsort.c
index 673a6a1..16c1bfe 100644
--- a/lib/libc/stdlib/heapsort.c
+++ b/lib/libc/stdlib/heapsort.c
@@ -147,16 +147,11 @@ typedef DECLARE_BLOCK(int, heapsort_block, const void *, const void *);
*/
#ifdef I_AM_HEAPSORT_B
int
-heapsort_b(vbase, nmemb, size, compar)
- void *vbase;
- size_t nmemb, size;
- heapsort_block compar;
+heapsort_b(void *vbase, size_t nmemb, size_t size, heapsort_block compar)
#else
int
-heapsort(vbase, nmemb, size, compar)
- void *vbase;
- size_t nmemb, size;
- int (*compar)(const void *, const void *);
+heapsort(void *vbase, size_t nmemb, size_t size,
+ int (*compar)(const void *, const void *))
#endif
{
size_t cnt, i, j, l;
diff --git a/lib/libc/stdlib/merge.c b/lib/libc/stdlib/merge.c
index 6b368c3..17f07eb 100644
--- a/lib/libc/stdlib/merge.c
+++ b/lib/libc/stdlib/merge.c
@@ -104,14 +104,10 @@ static void insertionsort(u_char *, size_t, size_t, cmp_t);
*/
int
#ifdef I_AM_MERGESORT_B
-mergesort_b(base, nmemb, size, cmp)
+mergesort_b(void *base, size_t nmemb, size_t size, cmp_t cmp)
#else
-mergesort(base, nmemb, size, cmp)
+mergesort(void *base, size_t nmemb, size_t size, cmp_t cmp)
#endif
- void *base;
- size_t nmemb;
- size_t size;
- cmp_t cmp;
{
size_t i;
int sense;
@@ -271,10 +267,7 @@ COPY: b = t;
* is defined. Otherwise simple pairwise merging is used.)
*/
void
-setup(list1, list2, n, size, cmp)
- size_t n, size;
- u_char *list1, *list2;
- cmp_t cmp;
+setup(u_char *list1, u_char *list2, size_t n, size_t size, cmp_t cmp)
{
int i, length, size2, tmp, sense;
u_char *f1, *f2, *s, *l2, *last, *p2;
@@ -345,10 +338,7 @@ setup(list1, list2, n, size, cmp)
* last 4 elements.
*/
static void
-insertionsort(a, n, size, cmp)
- u_char *a;
- size_t n, size;
- cmp_t cmp;
+insertionsort(u_char *a, size_t n, size_t size, cmp_t cmp)
{
u_char *ai, *s, *t, *u, tmp;
int i;
diff --git a/lib/libc/stdlib/radixsort.c b/lib/libc/stdlib/radixsort.c
index 8310e6d..205f776 100644
--- a/lib/libc/stdlib/radixsort.c
+++ b/lib/libc/stdlib/radixsort.c
@@ -88,10 +88,7 @@ static void r_sort_b(const u_char **, const u_char **, int, int,
}
int
-radixsort(a, n, tab, endch)
- const u_char **a, *tab;
- int n;
- u_int endch;
+radixsort(const u_char **a, int n, const u_char *tab, u_int endch)
{
const u_char *tr;
int c;
@@ -103,10 +100,7 @@ radixsort(a, n, tab, endch)
}
int
-sradixsort(a, n, tab, endch)
- const u_char **a, *tab;
- int n;
- u_int endch;
+sradixsort(const u_char **a, int n, const u_char *tab, u_int endch)
{
const u_char *tr, **ta;
int c;
@@ -131,11 +125,7 @@ sradixsort(a, n, tab, endch)
/* Unstable, in-place sort. */
static void
-r_sort_a(a, n, i, tr, endch)
- const u_char **a;
- int n, i;
- const u_char *tr;
- u_int endch;
+r_sort_a(const u_char **a, int n, int i, const u_char *tr, u_int endch)
{
static int count[256], nc, bmin;
int c;
@@ -233,11 +223,8 @@ r_sort_a(a, n, i, tr, endch)
/* Stable sort, requiring additional memory. */
static void
-r_sort_b(a, ta, n, i, tr, endch)
- const u_char **a, **ta;
- int n, i;
- const u_char *tr;
- u_int endch;
+r_sort_b(const u_char **a, const u_char **ta, int n, int i, const u_char *tr,
+ u_int endch)
{
static int count[256], nc, bmin;
int c;
@@ -304,12 +291,9 @@ r_sort_b(a, ta, n, i, tr, endch)
}
}
+/* insertion sort */
static inline void
-simplesort(a, n, b, tr, endch) /* insertion sort */
- const u_char **a;
- int n, b;
- const u_char *tr;
- u_int endch;
+simplesort(const u_char **a, int n, int b, const u_char *tr, u_int endch)
{
u_char ch;
const u_char **ak, **ai, *s, *t;
diff --git a/lib/libc/sys/setuid.2 b/lib/libc/sys/setuid.2
index 4c7d5ad..54d89bc 100644
--- a/lib/libc/sys/setuid.2
+++ b/lib/libc/sys/setuid.2
@@ -28,7 +28,7 @@
.\" @(#)setuid.2 8.1 (Berkeley) 6/4/93
.\" $FreeBSD$
.\"
-.Dd June 4, 1993
+.Dd September 13, 2015
.Dt SETUID 2
.Os
.Sh NAME
@@ -178,15 +178,10 @@ pseudocode(void)
int fd;
/* ... */
- fd = open("/path/to/sensitive/data", O_RDWR);
+ fd = open("/path/to/sensitive/data", O_RDWR | O_CLOEXEC);
if (fd == -1)
err(1, "open");
- /*
- * Set close-on-exec flag; see fcntl(2) for more information.
- */
- if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
- err(1, "fcntl(F_SETFD)");
/* ... */
execve(path, argv, environ);
}
diff --git a/release/Makefile b/release/Makefile
index e3485f2..1dbb5a7 100644
--- a/release/Makefile
+++ b/release/Makefile
@@ -21,6 +21,7 @@
# (by default, the directory above this one)
# PORTSDIR: location of ports tree to distribute (default: /usr/ports)
# DOCDIR: location of doc tree (default: /usr/doc)
+# XTRADIR: xtra-bits-dir argument for <arch>/mkisoimages.sh
# NOPKG: if set, do not distribute third-party packages
# NOPORTS: if set, do not distribute ports tree
# NOSRC: if set, do not distribute source tree
@@ -242,13 +243,13 @@ dvd: packagesystem
release.iso: disc1.iso
disc1.iso: disc1
- sh ${.CURDIR}/${TARGET}/mkisoimages.sh -b ${VOLUME_LABEL}_CD ${.TARGET} disc1
+ sh ${.CURDIR}/${TARGET}/mkisoimages.sh -b ${VOLUME_LABEL}_CD ${.TARGET} disc1 ${XTRADIR}
dvd1.iso: dvd pkg-stage
- sh ${.CURDIR}/${TARGET}/mkisoimages.sh -b ${VOLUME_LABEL}_DVD ${.TARGET} dvd
+ sh ${.CURDIR}/${TARGET}/mkisoimages.sh -b ${VOLUME_LABEL}_DVD ${.TARGET} dvd ${XTRADIR}
bootonly.iso: bootonly
- sh ${.CURDIR}/${TARGET}/mkisoimages.sh -b ${VOLUME_LABEL}_BO ${.TARGET} bootonly
+ sh ${.CURDIR}/${TARGET}/mkisoimages.sh -b ${VOLUME_LABEL}_BO ${.TARGET} bootonly ${XTRADIR}
memstick: memstick.img
memstick.img: disc1
diff --git a/sbin/geom/class/nop/geom_nop.c b/sbin/geom/class/nop/geom_nop.c
index 25163cc..f05a522 100644
--- a/sbin/geom/class/nop/geom_nop.c
+++ b/sbin/geom/class/nop/geom_nop.c
@@ -43,14 +43,16 @@ struct g_command class_commands[] = {
{
{ 'e', "error", "-1", G_TYPE_NUMBER },
{ 'o', "offset", "0", G_TYPE_NUMBER },
+ { 'p', "stripesize", "0", G_TYPE_NUMBER },
+ { 'P', "stripeoffset", "0", G_TYPE_NUMBER },
{ 'r', "rfailprob", "-1", G_TYPE_NUMBER },
{ 's', "size", "0", G_TYPE_NUMBER },
{ 'S', "secsize", "0", G_TYPE_NUMBER },
{ 'w', "wfailprob", "-1", G_TYPE_NUMBER },
G_OPT_SENTINEL
},
- "[-v] [-e error] [-o offset] [-r rfailprob] [-s size] "
- "[-S secsize] [-w wfailprob] dev ..."
+ "[-v] [-e error] [-o offset] [-p stripesize] [-P stripeoffset] "
+ "[-r rfailprob] [-s size] [-S secsize] [-w wfailprob] dev ..."
},
{ "configure", G_FLAG_VERBOSE, NULL,
{
diff --git a/sbin/geom/class/nop/gnop.8 b/sbin/geom/class/nop/gnop.8
index 4770090..c83c2f5 100644
--- a/sbin/geom/class/nop/gnop.8
+++ b/sbin/geom/class/nop/gnop.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 14, 2013
+.Dd September 15, 2015
.Dt GNOP 8
.Os
.Sh NAME
@@ -36,6 +36,8 @@
.Op Fl v
.Op Fl e Ar error
.Op Fl o Ar offset
+.Op Fl p Ar stripesize
+.Op Fl P Ar stripeoffset
.Op Fl r Ar rfailprob
.Op Fl s Ar size
.Op Fl S Ar secsize
@@ -115,6 +117,10 @@ Specifies the error number to return on failure.
Force the removal of the specified provider.
.It Fl o Ar offset
Where to begin on the original provider.
+.It Fl p Ar stripesize
+Value of the stripesize property of the transparent provider.
+.It Fl P Ar stripeoffset
+Value of the stripeoffset property of the transparent provider.
.It Fl r Ar rfailprob
Specifies read failure probability in percent.
.It Fl s Ar size
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index 4a79992..52de660 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -995,7 +995,7 @@ setifmetric(const char *val, int dummy __unused, int s,
strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
ifr.ifr_metric = atoi(val);
if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
- warn("ioctl (set metric)");
+ err(1, "ioctl SIOCSIFMETRIC (set metric)");
}
static void
@@ -1005,7 +1005,7 @@ setifmtu(const char *val, int dummy __unused, int s,
strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
ifr.ifr_mtu = atoi(val);
if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
- warn("ioctl (set mtu)");
+ err(1, "ioctl SIOCSIFMTU (set mtu)");
}
static void
@@ -1015,15 +1015,12 @@ setifname(const char *val, int dummy __unused, int s,
char *newname;
newname = strdup(val);
- if (newname == NULL) {
- warn("no memory to set ifname");
- return;
- }
+ if (newname == NULL)
+ err(1, "no memory to set ifname");
ifr.ifr_data = newname;
if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
- warn("ioctl (set name)");
free(newname);
- return;
+ err(1, "ioctl SIOCSIFNAME (set name)");
}
strlcpy(name, newname, sizeof(name));
free(newname);
@@ -1050,7 +1047,7 @@ setifdescr(const char *val, int dummy __unused, int s,
}
if (ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0)
- warn("ioctl (set descr)");
+ err(1, "ioctl SIOCSIFDESCR (set descr)");
free(newdescr);
}
diff --git a/share/dtrace/tcpdebug b/share/dtrace/tcpdebug
new file mode 100755
index 0000000..411aaf3
--- /dev/null
+++ b/share/dtrace/tcpdebug
@@ -0,0 +1,165 @@
+#!/usr/sbin/dtrace -s
+/*
+ * Copyright (c) 2015 George V. Neville-Neil
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * The tcpdebug D script uses the tcp:kernel::debug tracepoints
+ * to replicate the action of turning on TCPDEBUG in a kernel configuration.
+ *
+ * A TCP debug statement shows a connection's
+ *
+ * direction: input, output, user, drop
+ * state: CLOSED, LISTEN, SYN_SENT, SYN_RCVD, ESTABLISHED,
+ * CLOSE_WAIT, FIN_WAIT_1, CLOSING, LAST_ACK, FIN_WAIT_2,TIME_WAIT
+ * sequence: sequence space
+ *
+ * congestion: rcv_nxt, rcv_wnd, rcv_up, snd_una, snd_nxt, snx_max,
+ * snd_wl1, snd_wl2, snd_wnd
+ *
+ * NOTE: Only sockets with SO_DEBUG set will be shown.
+ *
+ * Usage: tcpdebug
+ */
+
+#pragma D option quiet
+tcp:kernel::debug-input
+/args[0]->tcps_debug/
+{
+ seq = args[1]->tcp_seq;
+ ack = args[1]->tcp_ack;
+ len = args[2]->ip_plength - sizeof(struct tcphdr);
+ flags = args[1]->tcp_flags;
+
+ printf("%p %s: input [%xu..%xu]", arg0,
+ tcp_state_string[args[0]->tcps_state], seq, seq + len);
+
+ printf("@%x, urp=%x", ack, args[1]->tcp_urgent);
+
+ printf("%s", flags != 0 ? "<" : "");
+ printf("%s", flags & TH_SYN ? "SYN," :"");
+ printf("%s", flags & TH_ACK ? "ACK," :"");
+ printf("%s", flags & TH_FIN ? "FIN," :"");
+ printf("%s", flags & TH_RST ? "RST," :"");
+ printf("%s", flags & TH_PUSH ? "PUSH," :"");
+ printf("%s", flags & TH_URG ? "URG," :"");
+ printf("%s", flags & TH_ECE ? "ECE," :"");
+ printf("%s", flags & TH_CWR ? "CWR" :"");
+ printf("%s", flags != 0 ? ">" : "");
+
+ printf("\n");
+ printf("\trcv_(nxt,wnd,up) (%x,%x,%x) snd_(una,nxt,max) (%x,%x,%x)\n",
+ args[0]->tcps_rnxt, args[0]->tcps_rwnd, args[0]->tcps_rup,
+ args[0]->tcps_suna, args[0]->tcps_snxt, args[0]->tcps_smax);
+ printf("\tsnd_(wl1,wl2,wnd) (%x,%x,%x)\n",
+ args[0]->tcps_swl1, args[0]->tcps_swl2, args[0]->tcps_swnd);
+
+}
+
+tcp:kernel::debug-output
+/args[0]->tcps_debug/
+{
+ seq = args[1]->tcp_seq;
+ ack = args[1]->tcp_ack;
+ len = args[2]->ip_plength - 20;
+
+ printf("%p %s: output [%x..%x]", arg0,
+ tcp_state_string[args[0]->tcps_state], seq, seq + len);
+
+ printf("@%x, urp=%x", ack, args[1]->tcp_urgent);
+
+ printf("%s", flags != 0 ? "<" : "");
+ printf("%s", flags & TH_SYN ? "SYN," :"");
+ printf("%s", flags & TH_ACK ? "ACK," :"");
+ printf("%s", flags & TH_FIN ? "FIN," :"");
+ printf("%s", flags & TH_RST ? "RST," :"");
+ printf("%s", flags & TH_PUSH ? "PUSH," :"");
+ printf("%s", flags & TH_URG ? "URG," :"");
+ printf("%s", flags & TH_ECE ? "ECE," :"");
+ printf("%s", flags & TH_CWR ? "CWR" :"");
+ printf("%s", flags != 0 ? ">" : "");
+
+ printf("\n");
+ printf("\trcv_(nxt,wnd,up) (%u,%x,%x) snd_(una,nxt,max) (%x,%x,%x)\n",
+ args[0]->tcps_rnxt, args[0]->tcps_rwnd, args[0]->tcps_rup,
+ args[0]->tcps_suna, args[0]->tcps_snxt, args[0]->tcps_smax);
+ printf("\tsnd_(wl1,wl2,wnd) (%x,%x,%x)\n",
+ args[0]->tcps_swl1, args[0]->tcps_swl2, args[0]->tcps_swnd);
+
+}
+
+tcp:kernel::debug-drop
+/args[0]->tcps_debug/
+{
+ printf("%p %s: output [x..x] @%x, urp=%x\n", arg0,
+ tcp_state_string[args[0]->tcps_state],
+ args[1]->tcp_ack,
+ args[1]->tcp_urgent);
+
+ seq = args[1]->tcp_seq;
+ ack = args[1]->tcp_ack;
+ len = args[2]->ip_plength;
+
+ printf("%p %s: drop [%x..%x]", arg0,
+ tcp_state_string[args[0]->tcps_state], seq, seq + len);
+
+ printf("@%x, urp=%x", ack, args[1]->tcp_urgent);
+
+ printf("%s", flags != 0 ? "<" : "");
+ printf("%s", flags & TH_SYN ? "SYN," :"");
+ printf("%s", flags & TH_ACK ? "ACK," :"");
+ printf("%s", flags & TH_FIN ? "FIN," :"");
+ printf("%s", flags & TH_RST ? "RST," :"");
+ printf("%s", flags & TH_PUSH ? "PUSH," :"");
+ printf("%s", flags & TH_URG ? "URG," :"");
+ printf("%s", flags & TH_ECE ? "ECE," :"");
+ printf("%s", flags & TH_CWR ? "CWR" :"");
+ printf("%s", flags != 0 ? ">" : "");
+
+ printf("\n");
+ printf("\trcv_(nxt,wnd,up) (%x,%x,%x) snd_(una,nxt,max) (%x,%x,%x)\n",
+ args[0]->tcps_rnxt, args[0]->tcps_rwnd, args[0]->tcps_rup,
+ args[0]->tcps_suna, args[0]->tcps_snxt, args[0]->tcps_smax);
+ printf("\tsnd_(wl1,wl2,wnd) (%x,%x,%x)\n",
+ args[0]->tcps_swl1, args[0]->tcps_swl2, args[0]->tcps_swnd);
+
+}
+
+tcp:kernel::debug-user
+/args[0]->tcps_debug/
+{
+ printf("%p %s: user ", arg0,
+ tcp_state_string[args[0]->tcps_state]);
+
+ printf("%s", prureq_string[arg1]);
+ printf("\n");
+ printf("\trcv_(nxt,wnd,up) (%x,%x,%x) snd_(una,nxt,max) (%x,%x,%x)\n",
+ args[0]->tcps_rnxt, args[0]->tcps_rwnd, args[0]->tcps_rup,
+ args[0]->tcps_suna, args[0]->tcps_snxt, args[0]->tcps_smax);
+ printf("\tsnd_(wl1,wl2,wnd) (%x,%x,%x)\n",
+ args[0]->tcps_swl1, args[0]->tcps_swl2, args[0]->tcps_swnd);
+
+}
+
diff --git a/share/man/man4/ctl.4 b/share/man/man4/ctl.4
index 5a852d0..e2485b9 100644
--- a/share/man/man4/ctl.4
+++ b/share/man/man4/ctl.4
@@ -1,4 +1,5 @@
.\" Copyright (c) 2013 Edward Tomasz Napierala
+.\" Copyright (c) 2015 Alexander Motin <mav@FreeBSD.org>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -23,7 +24,7 @@
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
-.Dd August 9, 2015
+.Dd September 12, 2015
.Dt CTL 4
.Os
.Sh NAME
@@ -80,6 +81,8 @@ Mode sense/select support
.It
Error injection support
.It
+High Availability clustering support with ALUA
+.It
All I/O handled in-kernel, no userland context switch overhead
.El
.Pp
@@ -99,9 +102,57 @@ log commands with errors;
.It 2
log all commands;
.It 4
-log received data for commands except READ/WRITE.
+log data for commands other then READ/WRITE.
.El
Defaults to 0.
+.It Va kern.cam.ctl.ha_id
+Specifies unique position of this node within High Availability cluster.
+Default is 0 -- no HA, 1 and 2 -- HA enabled at specified position.
+.It Va kern.cam.ctl.ha_mode
+Specifies High Availability cluster operation mode:
+.Bl -tag -offset indent -compact
+.It 0
+Active/Standby -- primary node has backend access and processes requests,
+while secondary can only do basic LUN discovery and reservation;
+.It 1
+Active/Active -- both nodes have backend access and process requests,
+while secondary node synchronizes processing with primary one;
+.It 2
+Active/Active -- primary node has backend access and processes requests,
+while secondary node forwards all requests and data to primary one;
+.El
+All above modes require established connection between HA cluster nodes.
+If connection is not configured, secondary node will report Unavailable
+state; if configured but not established -- Transitioning state.
+Defaults to 0.
+.It Va kern.cam.ctl.ha_peer
+String value, specifying method to establish connection to peer HA node.
+Can be "listen IP:port", "connect IP:port" or empty.
+.It Va kern.cam.ctl.ha_link
+Reports present state of connection between HA cluster nodes:
+.Bl -tag -offset indent -compact
+.It 0
+not configured;
+.It 1
+configured but not established;
+.It 2
+established.
+.El
+.It Va kern.cam.ctl.ha_role
+Specifies default role of this node:
+.Bl -tag -offset indent -compact
+.It 0
+primary;
+.It 1
+secondary.
+.El
+This role can be overriden on per-LUN basis using "ha_role" LUN option,
+so that for one LUN one node is primary, while for another -- another.
+Role change from primary to secondary for HA modes 0 and 2 closes backends,
+the opposite change -- opens.
+If there is no primary node (both nodes are secondary, or secondary node has
+no connection to primary one), secondary node(s) report Transitioning state.
+State with two primary nodes is illegal (split brain condition).
.It Va kern.cam.ctl.iscsi.debug
Verbosity level for log messages from the kernel part of iSCSI target.
Set to 0 to disable logging or 1 to warn about potential problems.
@@ -132,5 +183,7 @@ subsystem first appeared in
.Sh AUTHORS
The
.Nm
-subsystem was written by
+subsystem was originally written by
.An Kenneth Merry Aq Mt ken@FreeBSD.org .
+Later work was done by
+.An Alexander Motin Aq Mt mav@FreeBSD.org .
diff --git a/share/man/man4/dtrace_ip.4 b/share/man/man4/dtrace_ip.4
index 62148e9..164114e 100644
--- a/share/man/man4/dtrace_ip.4
+++ b/share/man/man4/dtrace_ip.4
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 18, 2015
+.Dd September 14, 2015
.Dt DTRACE_IP 4
.Os
.Sh NAME
@@ -212,7 +212,7 @@ IPv6 destination address.
A string representation of the source address.
.It Vt string ipv6_daddr
A string representation of the destination address.
-.It Vt ip6_t *ipv6_hdr
+.It Vt struct ip6_hdr *ipv6_hdr
A pointer to the raw IPv6 header.
.El
.Sh FILES
diff --git a/share/man/man4/geom_fox.4 b/share/man/man4/geom_fox.4
index 55d84f1..09d16e4 100644
--- a/share/man/man4/geom_fox.4
+++ b/share/man/man4/geom_fox.4
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 2, 2005
+.Dd September 12, 2015
.Dt GEOM_FOX 4
.Os
.Sh NAME
@@ -46,6 +46,13 @@ module at boot time, place the following line in
geom_fox_load="YES"
.Ed
.Sh DESCRIPTION
+.Bf -symbolic
+This driver is obsolete.
+Users are advised to use
+.Xr gmultipath 8
+instead.
+.Ef
+.Pp
The intent of the
.Nm
framework is to provide basic multipathing support to access direct
diff --git a/share/man/man4/ng_pppoe.4 b/share/man/man4/ng_pppoe.4
index c2cf63f..2b367b8 100644
--- a/share/man/man4/ng_pppoe.4
+++ b/share/man/man4/ng_pppoe.4
@@ -35,7 +35,7 @@
.\" $FreeBSD$
.\" $Whistle: ng_pppoe.8,v 1.1 1999/01/25 23:46:27 archie Exp $
.\"
-.Dd November 13, 2012
+.Dd September 15, 2015
.Dt NG_PPPOE 4
.Os
.Sh NAME
@@ -187,7 +187,7 @@ above messages, and reports the Access Concentrator Name.
The four commands above use a common data structure:
.Bd -literal -offset 4n
struct ngpppoe_sts {
- char hook[NG_HOOKSIZ]; /* hook associated with event session */
+ char hook[NG_HOOKSIZ];
};
.Ed
.Bl -tag -width 3n
@@ -244,6 +244,20 @@ hook, or when user wants to override this address with another one.
.Tn ASCII
form of this message is
.Qq Li setenaddr .
+.It Dv NGM_PPPOE_SETMAXP Pq Ic setmaxp
+Set the node PPP-Max-Payload value as described in RFC 4638.
+This message applies only to a client configuration.
+.Tn ASCII
+form of this message is
+.Qq Li setmaxp .
+.Pp
+Data structure returned to client is:
+.Bd -literal -offset 4n
+struct ngpppoe_maxp {
+ char hook[NG_HOOKSIZ];
+ uint16_t data;
+};
+.Ed
.El
.Sh SHUTDOWN
This node shuts down upon receipt of a
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
index 2a10157..268361a 100644
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -1641,6 +1641,7 @@ MLINKS+=timeout.9 callout.9 \
timeout.9 callout_active.9 \
timeout.9 callout_deactivate.9 \
timeout.9 callout_drain.9 \
+ timeout.9 callout_drain_async.9 \
timeout.9 callout_handle_init.9 \
timeout.9 callout_init.9 \
timeout.9 callout_init_mtx.9 \
diff --git a/share/man/man9/timeout.9 b/share/man/man9/timeout.9
index 7202815..b179856 100644
--- a/share/man/man9/timeout.9
+++ b/share/man/man9/timeout.9
@@ -29,13 +29,14 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 8, 2014
+.Dd September 14, 2015
.Dt TIMEOUT 9
.Os
.Sh NAME
.Nm callout_active ,
.Nm callout_deactivate ,
.Nm callout_drain ,
+.Nm callout_drain_async ,
.Nm callout_handle_init ,
.Nm callout_init ,
.Nm callout_init_mtx ,
@@ -70,6 +71,8 @@ typedef void timeout_t (void *);
.Fn callout_deactivate "struct callout *c"
.Ft int
.Fn callout_drain "struct callout *c"
+.Ft int
+.Fn callout_drain_async "struct callout *c" "callout_func_t *fn" "void *arg"
.Ft void
.Fn callout_handle_init "struct callout_handle *handle"
.Bd -literal
@@ -264,6 +267,24 @@ fully stopped before
.Fn callout_drain
returns.
.Pp
+The function
+.Fn callout_drain_async
+is non-blocking and works the same as the
+.Fn callout_stop
+function.
+When this function returns non-zero, do not call it again until the callback function given by
+.Fa fn
+has been called with argument
+.Fa arg .
+Only one of
+.Fn callout_drain
+or
+.Fn callout_drain_async
+should be called at a time to drain a callout.
+If this function returns zero, it is safe to free the callout structure pointed to by the
+.Fa c
+argument immediately.
+.Pp
The
.Fn callout_reset
and
diff --git a/share/mk/local.meta.sys.mk b/share/mk/local.meta.sys.mk
index 09805dd..691c48b 100644
--- a/share/mk/local.meta.sys.mk
+++ b/share/mk/local.meta.sys.mk
@@ -7,6 +7,8 @@
# we need this until there is an alternative
MK_INSTALL_AS_USER= yes
+_default_makeobjdir=$${.CURDIR:S,$${SRCTOP},$${OBJTOP},}
+
.if empty(OBJROOT) || ${.MAKE.LEVEL} == 0
.if !make(showconfig)
.if defined(MAKEOBJDIRPREFIX) && exists(${MAKEOBJDIRPREFIX})
@@ -16,9 +18,9 @@ OBJROOT:=${MAKEOBJDIRPREFIX}${SRCTOP:S,/src,,}/
MAKEOBJDIRPREFIX=
.export MAKEOBJDIRPREFIX
.endif
-.if empty(MAKEOBJDIR) || ${MAKEOBJDIR:M*/*} == ""
+.if empty(MAKEOBJDIR)
# OBJTOP set below
-MAKEOBJDIR=$${.CURDIR:S,$${SRCTOP},$${OBJTOP},}
+MAKEOBJDIR=${_default_makeobjdir}
# export but do not track
.export-env MAKEOBJDIR
# now for our own use
@@ -32,7 +34,7 @@ OBJROOT ?= ${SB_OBJROOT}
.endif
OBJROOT ?= ${SRCTOP:H}/obj/
.if ${OBJROOT:M*/} != ""
-OBJROOT:= ${OBJROOT:tA}/
+OBJROOT:= ${OBJROOT:H:tA}/
.else
OBJROOT:= ${OBJROOT:H:tA}/${OBJROOT:T}
.endif
@@ -106,6 +108,12 @@ TARGET_SPEC = ${TARGET_SPEC_VARS:@v@${$v:U}@:ts,}
TARGET_OBJ_SPEC:= ${TARGET_SPEC:S;,;.;g}
OBJTOP:= ${OBJROOT}${TARGET_OBJ_SPEC}
+.if defined(MAKEOBJDIR)
+.if ${MAKEOBJDIR:M*/*} == ""
+.error Cannot use MAKEOBJDIR=${MAKEOBJDIR}${.newline}Unset MAKEOBJDIR to get default: MAKEOBJDIR='${_default_makeobjdir}'
+.endif
+.endif
+
.if ${.CURDIR} == ${SRCTOP}
RELDIR = .
.elif ${.CURDIR:M${SRCTOP}/*}
@@ -186,6 +194,10 @@ UPDATE_DEPENDFILE= NO
# define the list of places that contain files we are responsible for
.MAKE.META.BAILIWICK = ${SB} ${OBJROOT} ${STAGE_ROOT}
+.if defined(CCACHE_DIR)
+.MAKE.META.IGNORE_PATHS += ${CCACHE_DIR}
+.endif
+
CSU_DIR.${MACHINE_ARCH} ?= csu/${MACHINE_ARCH}
CSU_DIR := ${CSU_DIR.${MACHINE_ARCH}}
diff --git a/sys/arm64/conf/GENERIC b/sys/arm64/conf/GENERIC
index eb46c11..17f9bc9 100644
--- a/sys/arm64/conf/GENERIC
+++ b/sys/arm64/conf/GENERIC
@@ -119,7 +119,10 @@ device pl011
# USB support
options USB_DEBUG # enable debug msgs
device dwcotg # DWC OTG controller
+device xhci # XHCI PCI->USB interface (USB 3.0)
device usb # USB Bus (required)
+device ukbd # Keyboard
+device umass # Disks/Mass storage - Requires scbus and da
# Pseudo devices.
device loop # Network loopback
diff --git a/sys/boot/usb/usbcore.mk b/sys/boot/usb/usbcore.mk
index e99fe87..121e036 100644
--- a/sys/boot/usb/usbcore.mk
+++ b/sys/boot/usb/usbcore.mk
@@ -143,6 +143,7 @@ KSRCS+= usb_template_kbd.c
KSRCS+= usb_template_audio.c
KSRCS+= usb_template_phone.c
KSRCS+= usb_template_serialnet.c
+KSRCS+= usb_template_midi.c
#
# USB mass storage support
diff --git a/sys/cam/ctl/README.ctl.txt b/sys/cam/ctl/README.ctl.txt
index dd38cb5..c37527b 100644
--- a/sys/cam/ctl/README.ctl.txt
+++ b/sys/cam/ctl/README.ctl.txt
@@ -40,25 +40,24 @@ Features:
- Support for multiple ports
- Support for multiple simultaneous initiators
- Support for multiple simultaneous backing stores
+ - Support for VMWare VAAI: COMPARE AND WRITE, XCOPY, WRITE SAME and
+ UNMAP commands
+ - Support for Microsoft ODX: POPULATE TOKEN/WRITE USING TOKEN, WRITE SAME
+ and UNMAP commands
- Persistent reservation support
- Mode sense/select support
- Error injection support
- - High Availability support
+ - High Availability clustering support with ALUA
- All I/O handled in-kernel, no userland context switch overhead.
Configuring and Running CTL:
===========================
- - After applying the CTL patchset to your tree, build world and install it
- on your target system.
-
- - Add 'device ctl' to your kernel configuration file.
+ - Add 'device ctl' to your kernel configuration file or load the module.
- If you're running with a 8Gb or 4Gb Qlogic FC board, add
- 'options ISP_TARGET_MODE' to your kernel config file. Keep in mind that
- the isp(4) driver can run in target or initiator mode, but not both on
- the same machine. 'device ispfw' or loading the ispfw module is also
- recommended.
+ 'options ISP_TARGET_MODE' to your kernel config file. 'device ispfw' or
+ loading the ispfw module is also recommended.
- Rebuild and install a new kernel.
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index ddac04f..2087706 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -405,12 +405,6 @@ static int ctl_scsiio_lun_check(struct ctl_lun *lun,
const struct ctl_cmd_entry *entry,
struct ctl_scsiio *ctsio);
static void ctl_failover_lun(struct ctl_lun *lun);
-static void ctl_est_ua(struct ctl_lun *lun, uint32_t initidx, ctl_ua_type ua);
-static void ctl_est_ua_all(struct ctl_lun *lun, uint32_t except, ctl_ua_type ua);
-static void ctl_clr_ua(struct ctl_lun *lun, uint32_t initidx, ctl_ua_type ua);
-static void ctl_clr_ua_all(struct ctl_lun *lun, uint32_t except, ctl_ua_type ua);
-static void ctl_clr_ua_allluns(struct ctl_softc *ctl_softc, uint32_t initidx,
- ctl_ua_type ua_type);
static int ctl_scsiio_precheck(struct ctl_softc *ctl_softc,
struct ctl_scsiio *ctsio);
static int ctl_scsiio(struct ctl_scsiio *ctsio);
@@ -418,11 +412,14 @@ static int ctl_scsiio(struct ctl_scsiio *ctsio);
static int ctl_bus_reset(struct ctl_softc *ctl_softc, union ctl_io *io);
static int ctl_target_reset(struct ctl_softc *ctl_softc, union ctl_io *io,
ctl_ua_type ua_type);
-static int ctl_lun_reset(struct ctl_lun *lun, union ctl_io *io,
+static int ctl_do_lun_reset(struct ctl_lun *lun, union ctl_io *io,
ctl_ua_type ua_type);
+static int ctl_lun_reset(struct ctl_softc *ctl_softc, union ctl_io *io);
static int ctl_abort_task(union ctl_io *io);
static int ctl_abort_task_set(union ctl_io *io);
+static int ctl_query_task(union ctl_io *io, int task_set);
static int ctl_i_t_nexus_reset(union ctl_io *io);
+static int ctl_query_async_event(union ctl_io *io);
static void ctl_run_task(union ctl_io *io);
#ifdef CTL_IO_DELAY
static void ctl_datamove_timer_wakeup(void *arg);
@@ -519,8 +516,6 @@ ctl_isc_handler_finish_xfer(struct ctl_softc *ctl_softc,
ctsio->residual = msg_info->scsi.residual;
memcpy(&ctsio->sense_data, &msg_info->scsi.sense_data,
msg_info->scsi.sense_len);
- memcpy(&ctsio->io_hdr.ctl_private[CTL_PRIV_LBA_LEN].bytes,
- &msg_info->scsi.lbalen, sizeof(msg_info->scsi.lbalen));
ctl_enqueue_isc((union ctl_io *)ctsio);
}
@@ -673,7 +668,10 @@ ctl_isc_ha_link_down(struct ctl_softc *softc)
mtx_lock(&softc->ctl_lock);
STAILQ_FOREACH(lun, &softc->lun_list, links) {
mtx_lock(&lun->lun_lock);
- lun->flags &= ~CTL_LUN_PEER_SC_PRIMARY;
+ if (lun->flags & CTL_LUN_PEER_SC_PRIMARY) {
+ lun->flags &= ~CTL_LUN_PEER_SC_PRIMARY;
+ ctl_est_ua_all(lun, -1, CTL_UA_ASYM_ACC_CHANGE);
+ }
mtx_unlock(&lun->lun_lock);
mtx_unlock(&softc->ctl_lock);
@@ -700,8 +698,11 @@ ctl_isc_ua(struct ctl_softc *softc, union ctl_ha_msg *msg, int len)
struct ctl_lun *lun;
uint32_t iid = ctl_get_initindex(&msg->hdr.nexus);
+ mtx_lock(&softc->ctl_lock);
if (msg->hdr.nexus.targ_lun < CTL_MAX_LUNS &&
- (lun = softc->ctl_luns[msg->hdr.nexus.targ_lun]) != NULL) {
+ (lun = softc->ctl_luns[msg->hdr.nexus.targ_mapped_lun]) != NULL) {
+ mtx_lock(&lun->lun_lock);
+ mtx_unlock(&softc->ctl_lock);
if (msg->ua.ua_all) {
if (msg->ua.ua_set)
ctl_est_ua_all(lun, iid, msg->ua.ua_type);
@@ -713,7 +714,9 @@ ctl_isc_ua(struct ctl_softc *softc, union ctl_ha_msg *msg, int len)
else
ctl_clr_ua(lun, iid, msg->ua.ua_type);
}
- }
+ mtx_unlock(&lun->lun_lock);
+ } else
+ mtx_unlock(&softc->ctl_lock);
}
static void
@@ -722,58 +725,69 @@ ctl_isc_lun_sync(struct ctl_softc *softc, union ctl_ha_msg *msg, int len)
struct ctl_lun *lun;
struct ctl_ha_msg_lun_pr_key pr_key;
int i, k;
+ ctl_lun_flags oflags;
+ uint32_t targ_lun;
- lun = softc->ctl_luns[msg->hdr.nexus.targ_lun];
- if (lun == NULL) {
- CTL_DEBUG_PRINT(("%s: Unknown LUN %d\n", __func__,
- msg->hdr.nexus.targ_lun));
+ targ_lun = msg->hdr.nexus.targ_mapped_lun;
+ mtx_lock(&softc->ctl_lock);
+ if ((targ_lun >= CTL_MAX_LUNS) ||
+ ((lun = softc->ctl_luns[targ_lun]) == NULL)) {
+ mtx_unlock(&softc->ctl_lock);
+ return;
+ }
+ mtx_lock(&lun->lun_lock);
+ mtx_unlock(&softc->ctl_lock);
+ if (lun->flags & CTL_LUN_DISABLED) {
+ mtx_unlock(&lun->lun_lock);
+ return;
+ }
+ i = (lun->lun_devid != NULL) ? lun->lun_devid->len : 0;
+ if (msg->lun.lun_devid_len != i || (i > 0 &&
+ memcmp(&msg->lun.data[0], lun->lun_devid->data, i) != 0)) {
+ mtx_unlock(&lun->lun_lock);
+ printf("%s: Received conflicting HA LUN %d\n",
+ __func__, msg->hdr.nexus.targ_lun);
+ return;
} else {
- mtx_lock(&lun->lun_lock);
- i = (lun->lun_devid != NULL) ? lun->lun_devid->len : 0;
- if (msg->lun.lun_devid_len != i || (i > 0 &&
- memcmp(&msg->lun.data[0], lun->lun_devid->data, i) != 0)) {
- mtx_unlock(&lun->lun_lock);
- printf("%s: Received conflicting HA LUN %d\n",
- __func__, msg->hdr.nexus.targ_lun);
- return;
- } else {
- /* Record whether peer is primary. */
- if ((msg->lun.flags & CTL_LUN_PRIMARY_SC) &&
- (msg->lun.flags & CTL_LUN_DISABLED) == 0)
- lun->flags |= CTL_LUN_PEER_SC_PRIMARY;
- else
- lun->flags &= ~CTL_LUN_PEER_SC_PRIMARY;
-
- /* If peer is primary and we are not -- use data */
- if ((lun->flags & CTL_LUN_PRIMARY_SC) == 0 &&
- (lun->flags & CTL_LUN_PEER_SC_PRIMARY)) {
- lun->PRGeneration = msg->lun.pr_generation;
- lun->pr_res_idx = msg->lun.pr_res_idx;
- lun->res_type = msg->lun.pr_res_type;
- lun->pr_key_count = msg->lun.pr_key_count;
- for (k = 0; k < CTL_MAX_INITIATORS; k++)
- ctl_clr_prkey(lun, k);
- for (k = 0; k < msg->lun.pr_key_count; k++) {
- memcpy(&pr_key, &msg->lun.data[i],
- sizeof(pr_key));
- ctl_alloc_prkey(lun, pr_key.pr_iid);
- ctl_set_prkey(lun, pr_key.pr_iid,
- pr_key.pr_key);
- i += sizeof(pr_key);
- }
+ /* Record whether peer is primary. */
+ oflags = lun->flags;
+ if ((msg->lun.flags & CTL_LUN_PRIMARY_SC) &&
+ (msg->lun.flags & CTL_LUN_DISABLED) == 0)
+ lun->flags |= CTL_LUN_PEER_SC_PRIMARY;
+ else
+ lun->flags &= ~CTL_LUN_PEER_SC_PRIMARY;
+ if (oflags != lun->flags)
+ ctl_est_ua_all(lun, -1, CTL_UA_ASYM_ACC_CHANGE);
+
+ /* If peer is primary and we are not -- use data */
+ if ((lun->flags & CTL_LUN_PRIMARY_SC) == 0 &&
+ (lun->flags & CTL_LUN_PEER_SC_PRIMARY)) {
+ lun->PRGeneration = msg->lun.pr_generation;
+ lun->pr_res_idx = msg->lun.pr_res_idx;
+ lun->res_type = msg->lun.pr_res_type;
+ lun->pr_key_count = msg->lun.pr_key_count;
+ for (k = 0; k < CTL_MAX_INITIATORS; k++)
+ ctl_clr_prkey(lun, k);
+ for (k = 0; k < msg->lun.pr_key_count; k++) {
+ memcpy(&pr_key, &msg->lun.data[i],
+ sizeof(pr_key));
+ ctl_alloc_prkey(lun, pr_key.pr_iid);
+ ctl_set_prkey(lun, pr_key.pr_iid,
+ pr_key.pr_key);
+ i += sizeof(pr_key);
}
+ }
- mtx_unlock(&lun->lun_lock);
- CTL_DEBUG_PRINT(("%s: Known LUN %d, peer is %s\n",
- __func__, msg->hdr.nexus.targ_lun,
- (msg->lun.flags & CTL_LUN_PRIMARY_SC) ?
- "primary" : "secondary"));
+ mtx_unlock(&lun->lun_lock);
+ CTL_DEBUG_PRINT(("%s: Known LUN %d, peer is %s\n",
+ __func__, msg->hdr.nexus.targ_lun,
+ (msg->lun.flags & CTL_LUN_PRIMARY_SC) ?
+ "primary" : "secondary"));
- /* If we are primary but peer doesn't know -- notify */
- if ((lun->flags & CTL_LUN_PRIMARY_SC) &&
- (msg->lun.flags & CTL_LUN_PEER_SC_PRIMARY) == 0)
- ctl_isc_announce_lun(lun);
- }
+ /* If we are primary but peer doesn't know -- notify */
+ if ((lun->flags & CTL_LUN_PRIMARY_SC) &&
+ (msg->lun.flags & CTL_LUN_PEER_SC_PRIMARY) == 0)
+ ctl_isc_announce_lun(lun);
}
}
@@ -781,6 +795,7 @@ static void
ctl_isc_port_sync(struct ctl_softc *softc, union ctl_ha_msg *msg, int len)
{
struct ctl_port *port;
+ struct ctl_lun *lun;
int i, new;
port = softc->ctl_ports[msg->hdr.nexus.targ_port];
@@ -856,6 +871,15 @@ ctl_isc_port_sync(struct ctl_softc *softc, union ctl_ha_msg *msg, int len)
__func__);
}
}
+ mtx_lock(&softc->ctl_lock);
+ STAILQ_FOREACH(lun, &softc->lun_list, links) {
+ if (ctl_lun_map_to_port(port, lun->lun) >= CTL_MAX_LUNS)
+ continue;
+ mtx_lock(&lun->lun_lock);
+ ctl_est_ua_all(lun, -1, CTL_UA_INQ_CHANGE);
+ mtx_unlock(&lun->lun_lock);
+ }
+ mtx_unlock(&softc->ctl_lock);
}
/*
@@ -954,6 +978,8 @@ ctl_isc_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param)
* when the datamove is complete.
*/
io->io_hdr.serializing_sc = msg->hdr.serializing_sc;
+ if (msg->hdr.status == CTL_SUCCESS)
+ io->io_hdr.status = msg->hdr.status;
if (msg->dt.sg_sequence == 0) {
i = msg->dt.kern_sg_entries +
@@ -1036,6 +1062,8 @@ ctl_isc_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param)
memcpy(&io->scsiio.sense_data,
&msg->scsi.sense_data,
msg->scsi.sense_len);
+ if (msg->hdr.status == CTL_SUCCESS)
+ io->io_hdr.flags |= CTL_FLAG_STATUS_SENT;
}
ctl_enqueue_isc(io);
break;
@@ -1178,7 +1206,7 @@ ctl_copy_sense_data_back(union ctl_io *src, union ctl_ha_msg *dest)
dest->hdr.status = src->io_hdr.status;
}
-static void
+void
ctl_est_ua(struct ctl_lun *lun, uint32_t initidx, ctl_ua_type ua)
{
struct ctl_softc *softc = lun->ctl_softc;
@@ -1193,25 +1221,33 @@ ctl_est_ua(struct ctl_lun *lun, uint32_t initidx, ctl_ua_type ua)
pu[initidx % CTL_MAX_INIT_PER_PORT] |= ua;
}
-static void
-ctl_est_ua_all(struct ctl_lun *lun, uint32_t except, ctl_ua_type ua)
+void
+ctl_est_ua_port(struct ctl_lun *lun, int port, uint32_t except, ctl_ua_type ua)
{
- struct ctl_softc *softc = lun->ctl_softc;
- int i, j;
+ int i;
mtx_assert(&lun->lun_lock, MA_OWNED);
- for (i = softc->port_min; i < softc->port_max; i++) {
- if (lun->pending_ua[i] == NULL)
+ if (lun->pending_ua[port] == NULL)
+ return;
+ for (i = 0; i < CTL_MAX_INIT_PER_PORT; i++) {
+ if (port * CTL_MAX_INIT_PER_PORT + i == except)
continue;
- for (j = 0; j < CTL_MAX_INIT_PER_PORT; j++) {
- if (i * CTL_MAX_INIT_PER_PORT + j == except)
- continue;
- lun->pending_ua[i][j] |= ua;
- }
+ lun->pending_ua[port][i] |= ua;
}
}
-static void
+void
+ctl_est_ua_all(struct ctl_lun *lun, uint32_t except, ctl_ua_type ua)
+{
+ struct ctl_softc *softc = lun->ctl_softc;
+ int i;
+
+ mtx_assert(&lun->lun_lock, MA_OWNED);
+ for (i = softc->port_min; i < softc->port_max; i++)
+ ctl_est_ua_port(lun, i, except, ua);
+}
+
+void
ctl_clr_ua(struct ctl_lun *lun, uint32_t initidx, ctl_ua_type ua)
{
struct ctl_softc *softc = lun->ctl_softc;
@@ -1226,7 +1262,7 @@ ctl_clr_ua(struct ctl_lun *lun, uint32_t initidx, ctl_ua_type ua)
pu[initidx % CTL_MAX_INIT_PER_PORT] &= ~ua;
}
-static void
+void
ctl_clr_ua_all(struct ctl_lun *lun, uint32_t except, ctl_ua_type ua)
{
struct ctl_softc *softc = lun->ctl_softc;
@@ -1244,7 +1280,7 @@ ctl_clr_ua_all(struct ctl_lun *lun, uint32_t except, ctl_ua_type ua)
}
}
-static void
+void
ctl_clr_ua_allluns(struct ctl_softc *ctl_softc, uint32_t initidx,
ctl_ua_type ua_type)
{
@@ -1730,20 +1766,24 @@ ctl_serialize_other_sc_cmd(struct ctl_scsiio *ctsio)
softc = control_softc;
targ_lun = ctsio->io_hdr.nexus.targ_mapped_lun;
+ mtx_lock(&softc->ctl_lock);
if ((targ_lun < CTL_MAX_LUNS) &&
((lun = softc->ctl_luns[targ_lun]) != NULL)) {
+ mtx_lock(&lun->lun_lock);
+ mtx_unlock(&softc->ctl_lock);
/*
* If the LUN is invalid, pretend that it doesn't exist.
* It will go away as soon as all pending I/O has been
* completed.
*/
- mtx_lock(&lun->lun_lock);
if (lun->flags & CTL_LUN_DISABLED) {
mtx_unlock(&lun->lun_lock);
lun = NULL;
}
- } else
+ } else {
+ mtx_unlock(&softc->ctl_lock);
lun = NULL;
+ }
if (lun == NULL) {
/*
* The other node would not send this request to us unless
@@ -2092,6 +2132,7 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
struct thread *td)
{
struct ctl_softc *softc;
+ struct ctl_lun *lun;
int retval;
softc = control_softc;
@@ -2250,7 +2291,6 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
break;
}
case CTL_DUMP_OOA: {
- struct ctl_lun *lun;
union ctl_io *io;
char printbuf[128];
struct sbuf sb;
@@ -2287,7 +2327,6 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
break;
}
case CTL_GET_OOA: {
- struct ctl_lun *lun;
struct ctl_ooa *ooa_hdr;
struct ctl_ooa_entry *entries;
uint32_t cur_fill_num;
@@ -2379,7 +2418,6 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
}
case CTL_CHECK_OOA: {
union ctl_io *io;
- struct ctl_lun *lun;
struct ctl_ooa_info *ooa_info;
@@ -2412,9 +2450,6 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
}
case CTL_DELAY_IO: {
struct ctl_io_delay_info *delay_info;
-#ifdef CTL_IO_DELAY
- struct ctl_lun *lun;
-#endif /* CTL_IO_DELAY */
delay_info = (struct ctl_io_delay_info *)addr;
@@ -2505,7 +2540,6 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
case CTL_SETSYNC:
case CTL_GETSYNC: {
struct ctl_sync_info *sync_info;
- struct ctl_lun *lun;
sync_info = (struct ctl_sync_info *)addr;
@@ -2514,6 +2548,7 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
if (lun == NULL) {
mtx_unlock(&softc->ctl_lock);
sync_info->status = CTL_GS_SYNC_NO_LUN;
+ break;
}
/*
* Get or set the sync interval. We're not bounds checking
@@ -2534,7 +2569,6 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
}
case CTL_GETSTATS: {
struct ctl_stats *stats;
- struct ctl_lun *lun;
int i;
stats = (struct ctl_stats *)addr;
@@ -2570,7 +2604,6 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
}
case CTL_ERROR_INJECT: {
struct ctl_error_desc *err_desc, *new_err_desc;
- struct ctl_lun *lun;
err_desc = (struct ctl_error_desc *)addr;
@@ -2617,7 +2650,6 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
}
case CTL_ERROR_INJECT_DELETE: {
struct ctl_error_desc *delete_desc, *desc, *desc2;
- struct ctl_lun *lun;
int delete_done;
delete_desc = (struct ctl_error_desc *)addr;
@@ -2661,8 +2693,6 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
mtx_lock(&softc->ctl_lock);
printf("CTL Persistent Reservation information start:\n");
for (i = 0; i < CTL_MAX_LUNS; i++) {
- struct ctl_lun *lun;
-
lun = softc->ctl_luns[i];
if ((lun == NULL)
@@ -2756,7 +2786,6 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
}
case CTL_LUN_LIST: {
struct sbuf *sb;
- struct ctl_lun *lun;
struct ctl_lun_list *list;
struct ctl_option *opt;
@@ -3129,6 +3158,17 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
mtx_unlock(&softc->ctl_lock);
return (ENXIO);
}
+ if (port->status & CTL_PORT_STATUS_ONLINE) {
+ STAILQ_FOREACH(lun, &softc->lun_list, links) {
+ if (ctl_lun_map_to_port(port, lun->lun) >=
+ CTL_MAX_LUNS)
+ continue;
+ mtx_lock(&lun->lun_lock);
+ ctl_est_ua_port(lun, lm->port, -1,
+ CTL_UA_LUN_CHANGE);
+ mtx_unlock(&lun->lun_lock);
+ }
+ }
mtx_unlock(&softc->ctl_lock); // XXX: port_enable sleeps
if (lm->plun < CTL_MAX_LUNS) {
if (lm->lun == UINT32_MAX)
@@ -3145,6 +3185,8 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
retval = ctl_lun_map_init(port);
} else
return (ENXIO);
+ if (port->status & CTL_PORT_STATUS_ONLINE)
+ ctl_isc_announce_port(port);
break;
}
default: {
@@ -4531,8 +4573,8 @@ ctl_lun_primary(struct ctl_be_lun *be_lun)
mtx_lock(&lun->lun_lock);
lun->flags |= CTL_LUN_PRIMARY_SC;
- mtx_unlock(&lun->lun_lock);
ctl_est_ua_all(lun, -1, CTL_UA_ASYM_ACC_CHANGE);
+ mtx_unlock(&lun->lun_lock);
ctl_isc_announce_lun(lun);
return (0);
}
@@ -4544,8 +4586,8 @@ ctl_lun_secondary(struct ctl_be_lun *be_lun)
mtx_lock(&lun->lun_lock);
lun->flags &= ~CTL_LUN_PRIMARY_SC;
- mtx_unlock(&lun->lun_lock);
ctl_est_ua_all(lun, -1, CTL_UA_ASYM_ACC_CHANGE);
+ mtx_unlock(&lun->lun_lock);
ctl_isc_announce_lun(lun);
return (0);
}
@@ -7325,8 +7367,9 @@ ctl_report_supported_tmf(struct ctl_scsiio *ctsio)
ctsio->kern_rel_offset = 0;
data = (struct scsi_report_supported_tmf_data *)ctsio->kern_data_ptr;
- data->byte1 |= RST_ATS | RST_ATSS | RST_CTSS | RST_LURS | RST_TRS;
- data->byte2 |= RST_ITNRS;
+ data->byte1 |= RST_ATS | RST_ATSS | RST_CTSS | RST_LURS | RST_QTS |
+ RST_TRS;
+ data->byte2 |= RST_QAES | RST_QTSS | RST_ITNRS;
ctl_set_success(ctsio);
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
@@ -8380,13 +8423,23 @@ ctl_hndl_per_res_out_on_other_sc(union ctl_ha_msg *msg)
struct ctl_lun *lun;
struct ctl_softc *softc;
int i;
- uint32_t targ_lun;
+ uint32_t residx, targ_lun;
softc = control_softc;
-
targ_lun = msg->hdr.nexus.targ_mapped_lun;
- lun = softc->ctl_luns[targ_lun];
+ mtx_lock(&softc->ctl_lock);
+ if ((targ_lun >= CTL_MAX_LUNS) ||
+ ((lun = softc->ctl_luns[targ_lun]) == NULL)) {
+ mtx_unlock(&softc->ctl_lock);
+ return;
+ }
mtx_lock(&lun->lun_lock);
+ mtx_unlock(&softc->ctl_lock);
+ if (lun->flags & CTL_LUN_DISABLED) {
+ mtx_unlock(&lun->lun_lock);
+ return;
+ }
+ residx = ctl_get_initindex(&msg->hdr.nexus);
switch(msg->pr.pr_info.action) {
case CTL_PR_REG_KEY:
ctl_alloc_prkey(lun, msg->pr.pr_info.residx);
@@ -8451,8 +8504,9 @@ ctl_hndl_per_res_out_on_other_sc(union ctl_ha_msg *msg)
if (lun->res_type != SPR_TYPE_EX_AC
&& lun->res_type != SPR_TYPE_WR_EX) {
for (i = softc->init_min; i < softc->init_max; i++)
- if (ctl_get_prkey(lun, i) != 0)
- ctl_est_ua(lun, i, CTL_UA_RES_RELEASE);
+ if (i == residx || ctl_get_prkey(lun, i) == 0)
+ continue;
+ ctl_est_ua(lun, i, CTL_UA_RES_RELEASE);
}
lun->flags &= ~CTL_LUN_PR_RESERVED;
@@ -10798,9 +10852,7 @@ ctl_scsiio_lun_check(struct ctl_lun *lun,
if (entry->pattern & CTL_LUN_PAT_WRITE) {
if (lun->be_lun &&
lun->be_lun->flags & CTL_LUN_FLAG_READONLY) {
- ctl_set_sense(ctsio, /*current_error*/ 1,
- /*sense_key*/ SSD_KEY_DATA_PROTECT,
- /*asc*/ 0x27, /*ascq*/ 0x01, SSD_ELEM_NONE);
+ ctl_set_hw_write_protected(ctsio);
retval = 1;
goto bailout;
}
@@ -10898,6 +10950,7 @@ ctl_failover_lun(struct ctl_lun *lun)
if (io->flags & CTL_FLAG_FROM_OTHER_SC) {
if (io->flags & CTL_FLAG_IO_ACTIVE) {
io->flags |= CTL_FLAG_ABORT;
+ io->flags |= CTL_FLAG_FAILOVER;
} else { /* This can be only due to DATAMOVE */
io->msg_type = CTL_MSG_DATAMOVE_DONE;
io->flags |= CTL_FLAG_IO_ACTIVE;
@@ -11301,6 +11354,7 @@ static int
ctl_target_reset(struct ctl_softc *softc, union ctl_io *io,
ctl_ua_type ua_type)
{
+ struct ctl_port *port;
struct ctl_lun *lun;
int retval;
@@ -11321,10 +11375,15 @@ ctl_target_reset(struct ctl_softc *softc, union ctl_io *io,
retval = 0;
mtx_lock(&softc->ctl_lock);
- STAILQ_FOREACH(lun, &softc->lun_list, links)
- retval += ctl_lun_reset(lun, io, ua_type);
+ port = softc->ctl_ports[io->io_hdr.nexus.targ_port];
+ STAILQ_FOREACH(lun, &softc->lun_list, links) {
+ if (port != NULL &&
+ ctl_lun_map_to_port(port, lun->lun) >= CTL_MAX_LUNS)
+ continue;
+ retval += ctl_do_lun_reset(lun, io, ua_type);
+ }
mtx_unlock(&softc->ctl_lock);
-
+ io->taskio.task_status = CTL_TASK_FUNCTION_COMPLETE;
return (retval);
}
@@ -11350,7 +11409,7 @@ ctl_target_reset(struct ctl_softc *softc, union ctl_io *io,
* XXX KDM for now, we're setting unit attention for all initiators.
*/
static int
-ctl_lun_reset(struct ctl_lun *lun, union ctl_io *io, ctl_ua_type ua_type)
+ctl_do_lun_reset(struct ctl_lun *lun, union ctl_io *io, ctl_ua_type ua_type)
{
union ctl_io *xio;
#if 0
@@ -11398,6 +11457,39 @@ ctl_lun_reset(struct ctl_lun *lun, union ctl_io *io, ctl_ua_type ua_type)
return (0);
}
+static int
+ctl_lun_reset(struct ctl_softc *softc, union ctl_io *io)
+{
+ struct ctl_lun *lun;
+ uint32_t targ_lun;
+ int retval;
+
+ targ_lun = io->io_hdr.nexus.targ_mapped_lun;
+ mtx_lock(&softc->ctl_lock);
+ if ((targ_lun >= CTL_MAX_LUNS) ||
+ (lun = softc->ctl_luns[targ_lun]) == NULL) {
+ mtx_unlock(&softc->ctl_lock);
+ io->taskio.task_status = CTL_TASK_LUN_DOES_NOT_EXIST;
+ return (1);
+ }
+ retval = ctl_do_lun_reset(lun, io, CTL_UA_LUN_RESET);
+ mtx_unlock(&softc->ctl_lock);
+ io->taskio.task_status = CTL_TASK_FUNCTION_COMPLETE;
+
+ if ((io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC) == 0) {
+ union ctl_ha_msg msg_info;
+
+ msg_info.hdr.msg_type = CTL_MSG_MANAGE_TASKS;
+ msg_info.hdr.nexus = io->io_hdr.nexus;
+ msg_info.task.task_action = CTL_TASK_LUN_RESET;
+ msg_info.hdr.original_sc = NULL;
+ msg_info.hdr.serializing_sc = NULL;
+ ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info,
+ sizeof(msg_info.task), M_WAITOK);
+ }
+ return (retval);
+}
+
static void
ctl_abort_tasks_lun(struct ctl_lun *lun, uint32_t targ_port, uint32_t init_id,
int other_sc)
@@ -11453,10 +11545,10 @@ ctl_abort_task_set(union ctl_io *io)
*/
targ_lun = io->io_hdr.nexus.targ_mapped_lun;
mtx_lock(&softc->ctl_lock);
- if ((targ_lun < CTL_MAX_LUNS) && (softc->ctl_luns[targ_lun] != NULL))
- lun = softc->ctl_luns[targ_lun];
- else {
+ if ((targ_lun >= CTL_MAX_LUNS) ||
+ (lun = softc->ctl_luns[targ_lun]) == NULL) {
mtx_unlock(&softc->ctl_lock);
+ io->taskio.task_status = CTL_TASK_LUN_DOES_NOT_EXIST;
return (1);
}
@@ -11471,6 +11563,7 @@ ctl_abort_task_set(union ctl_io *io)
(io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC) != 0);
}
mtx_unlock(&lun->lun_lock);
+ io->taskio.task_status = CTL_TASK_FUNCTION_COMPLETE;
return (0);
}
@@ -11481,13 +11574,24 @@ ctl_i_t_nexus_reset(union ctl_io *io)
struct ctl_lun *lun;
uint32_t initidx;
+ if (!(io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC)) {
+ union ctl_ha_msg msg_info;
+
+ msg_info.hdr.nexus = io->io_hdr.nexus;
+ msg_info.task.task_action = CTL_TASK_I_T_NEXUS_RESET;
+ msg_info.hdr.msg_type = CTL_MSG_MANAGE_TASKS;
+ msg_info.hdr.original_sc = NULL;
+ msg_info.hdr.serializing_sc = NULL;
+ ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info,
+ sizeof(msg_info.task), M_WAITOK);
+ }
+
initidx = ctl_get_initindex(&io->io_hdr.nexus);
mtx_lock(&softc->ctl_lock);
STAILQ_FOREACH(lun, &softc->lun_list, links) {
mtx_lock(&lun->lun_lock);
ctl_abort_tasks_lun(lun, io->io_hdr.nexus.targ_port,
- io->io_hdr.nexus.initid,
- (io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC) != 0);
+ io->io_hdr.nexus.initid, 1);
#ifdef CTL_WITH_CA
ctl_clear_mask(lun->have_ca, initidx);
#endif
@@ -11497,6 +11601,7 @@ ctl_i_t_nexus_reset(union ctl_io *io)
mtx_unlock(&lun->lun_lock);
}
mtx_unlock(&softc->ctl_lock);
+ io->taskio.task_status = CTL_TASK_FUNCTION_COMPLETE;
return (0);
}
@@ -11521,11 +11626,10 @@ ctl_abort_task(union ctl_io *io)
*/
targ_lun = io->io_hdr.nexus.targ_mapped_lun;
mtx_lock(&softc->ctl_lock);
- if ((targ_lun < CTL_MAX_LUNS)
- && (softc->ctl_luns[targ_lun] != NULL))
- lun = softc->ctl_luns[targ_lun];
- else {
+ if ((targ_lun >= CTL_MAX_LUNS) ||
+ (lun = softc->ctl_luns[targ_lun]) == NULL) {
mtx_unlock(&softc->ctl_lock);
+ io->taskio.task_status = CTL_TASK_LUN_DOES_NOT_EXIST;
return (1);
}
@@ -11631,6 +11735,77 @@ ctl_abort_task(union ctl_io *io)
io->taskio.tag_type);
#endif
}
+ io->taskio.task_status = CTL_TASK_FUNCTION_COMPLETE;
+ return (0);
+}
+
+static int
+ctl_query_task(union ctl_io *io, int task_set)
+{
+ union ctl_io *xio;
+ struct ctl_lun *lun;
+ struct ctl_softc *softc;
+ int found = 0;
+ uint32_t targ_lun;
+
+ softc = control_softc;
+ targ_lun = io->io_hdr.nexus.targ_mapped_lun;
+ mtx_lock(&softc->ctl_lock);
+ if ((targ_lun >= CTL_MAX_LUNS) ||
+ (lun = softc->ctl_luns[targ_lun]) == NULL) {
+ mtx_unlock(&softc->ctl_lock);
+ io->taskio.task_status = CTL_TASK_LUN_DOES_NOT_EXIST;
+ return (1);
+ }
+ mtx_lock(&lun->lun_lock);
+ mtx_unlock(&softc->ctl_lock);
+ for (xio = (union ctl_io *)TAILQ_FIRST(&lun->ooa_queue); xio != NULL;
+ xio = (union ctl_io *)TAILQ_NEXT(&xio->io_hdr, ooa_links)) {
+
+ if ((xio->io_hdr.nexus.targ_port != io->io_hdr.nexus.targ_port)
+ || (xio->io_hdr.nexus.initid != io->io_hdr.nexus.initid)
+ || (xio->io_hdr.flags & CTL_FLAG_ABORT))
+ continue;
+
+ if (task_set || xio->scsiio.tag_num == io->taskio.tag_num) {
+ found = 1;
+ break;
+ }
+ }
+ mtx_unlock(&lun->lun_lock);
+ if (found)
+ io->taskio.task_status = CTL_TASK_FUNCTION_SUCCEEDED;
+ else
+ io->taskio.task_status = CTL_TASK_FUNCTION_COMPLETE;
+ return (0);
+}
+
+static int
+ctl_query_async_event(union ctl_io *io)
+{
+ struct ctl_lun *lun;
+ struct ctl_softc *softc;
+ ctl_ua_type ua;
+ uint32_t targ_lun, initidx;
+
+ softc = control_softc;
+ targ_lun = io->io_hdr.nexus.targ_mapped_lun;
+ mtx_lock(&softc->ctl_lock);
+ if ((targ_lun >= CTL_MAX_LUNS) ||
+ (lun = softc->ctl_luns[targ_lun]) == NULL) {
+ mtx_unlock(&softc->ctl_lock);
+ io->taskio.task_status = CTL_TASK_LUN_DOES_NOT_EXIST;
+ return (1);
+ }
+ mtx_lock(&lun->lun_lock);
+ mtx_unlock(&softc->ctl_lock);
+ initidx = ctl_get_initindex(&io->io_hdr.nexus);
+ ua = ctl_build_qae(lun, initidx, io->taskio.task_resp);
+ mtx_unlock(&lun->lun_lock);
+ if (ua != CTL_UA_NONE)
+ io->taskio.task_status = CTL_TASK_FUNCTION_SUCCEEDED;
+ else
+ io->taskio.task_status = CTL_TASK_FUNCTION_COMPLETE;
return (0);
}
@@ -11639,41 +11814,12 @@ ctl_run_task(union ctl_io *io)
{
struct ctl_softc *softc = control_softc;
int retval = 1;
- const char *task_desc;
CTL_DEBUG_PRINT(("ctl_run_task\n"));
-
KASSERT(io->io_hdr.io_type == CTL_IO_TASK,
- ("ctl_run_task: Unextected io_type %d\n",
- io->io_hdr.io_type));
-
- task_desc = ctl_scsi_task_string(&io->taskio);
- if (task_desc != NULL) {
-#ifdef NEEDTOPORT
- csevent_log(CSC_CTL | CSC_SHELF_SW |
- CTL_TASK_REPORT,
- csevent_LogType_Trace,
- csevent_Severity_Information,
- csevent_AlertLevel_Green,
- csevent_FRU_Firmware,
- csevent_FRU_Unknown,
- "CTL: received task: %s",task_desc);
-#endif
- } else {
-#ifdef NEEDTOPORT
- csevent_log(CSC_CTL | CSC_SHELF_SW |
- CTL_TASK_REPORT,
- csevent_LogType_Trace,
- csevent_Severity_Information,
- csevent_AlertLevel_Green,
- csevent_FRU_Firmware,
- csevent_FRU_Unknown,
- "CTL: received unknown task "
- "type: %d (%#x)",
- io->taskio.task_action,
- io->taskio.task_action);
-#endif
- }
+ ("ctl_run_task: Unextected io_type %d\n", io->io_hdr.io_type));
+ io->taskio.task_status = CTL_TASK_FUNCTION_NOT_SUPPORTED;
+ bzero(io->taskio.task_resp, sizeof(io->taskio.task_resp));
switch (io->taskio.task_action) {
case CTL_TASK_ABORT_TASK:
retval = ctl_abort_task(io);
@@ -11687,36 +11833,9 @@ ctl_run_task(union ctl_io *io)
case CTL_TASK_I_T_NEXUS_RESET:
retval = ctl_i_t_nexus_reset(io);
break;
- case CTL_TASK_LUN_RESET: {
- struct ctl_lun *lun;
- uint32_t targ_lun;
-
- targ_lun = io->io_hdr.nexus.targ_mapped_lun;
- mtx_lock(&softc->ctl_lock);
- if ((targ_lun < CTL_MAX_LUNS)
- && (softc->ctl_luns[targ_lun] != NULL))
- lun = softc->ctl_luns[targ_lun];
- else {
- mtx_unlock(&softc->ctl_lock);
- retval = 1;
- break;
- }
- retval = ctl_lun_reset(lun, io, CTL_UA_LUN_RESET);
- mtx_unlock(&softc->ctl_lock);
-
- if ((io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC) == 0) {
- union ctl_ha_msg msg_info;
-
- msg_info.hdr.msg_type = CTL_MSG_MANAGE_TASKS;
- msg_info.hdr.nexus = io->io_hdr.nexus;
- msg_info.task.task_action = CTL_TASK_LUN_RESET;
- msg_info.hdr.original_sc = NULL;
- msg_info.hdr.serializing_sc = NULL;
- ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info,
- sizeof(msg_info.task), M_WAITOK);
- }
+ case CTL_TASK_LUN_RESET:
+ retval = ctl_lun_reset(softc, io);
break;
- }
case CTL_TASK_TARGET_RESET:
retval = ctl_target_reset(softc, io, CTL_UA_TARG_RESET);
break;
@@ -11727,9 +11846,18 @@ ctl_run_task(union ctl_io *io)
break;
case CTL_TASK_PORT_LOGOUT:
break;
+ case CTL_TASK_QUERY_TASK:
+ retval = ctl_query_task(io, 0);
+ break;
+ case CTL_TASK_QUERY_TASK_SET:
+ retval = ctl_query_task(io, 1);
+ break;
+ case CTL_TASK_QUERY_ASYNC_EVENT:
+ retval = ctl_query_async_event(io);
+ break;
default:
- printf("ctl_run_task: got unknown task management event %d\n",
- io->taskio.task_action);
+ printf("%s: got unknown task management event %d\n",
+ __func__, io->taskio.task_action);
break;
}
if (retval == 0)
@@ -11975,12 +12103,14 @@ ctl_datamove_timer_wakeup(void *arg)
void
ctl_datamove(union ctl_io *io)
{
+ struct ctl_lun *lun;
void (*fe_datamove)(union ctl_io *io);
mtx_assert(&control_softc->ctl_lock, MA_NOTOWNED);
CTL_DEBUG_PRINT(("ctl_datamove\n"));
+ lun = (struct ctl_lun *)io->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
#ifdef CTL_TIME_IO
if ((time_uptime - io->io_hdr.start_time) > ctl_time_io_secs) {
char str[256];
@@ -12021,9 +12151,6 @@ ctl_datamove(union ctl_io *io)
if (io->io_hdr.flags & CTL_FLAG_DELAY_DONE) {
io->io_hdr.flags &= ~CTL_FLAG_DELAY_DONE;
} else {
- struct ctl_lun *lun;
-
- lun =(struct ctl_lun *)io->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
if ((lun != NULL)
&& (lun->delay_info.datamove_delay > 0)) {
@@ -12084,6 +12211,7 @@ ctl_datamove(union ctl_io *io)
msg.hdr.original_sc = io->io_hdr.original_sc;
msg.hdr.serializing_sc = io;
msg.hdr.nexus = io->io_hdr.nexus;
+ msg.hdr.status = io->io_hdr.status;
msg.dt.flags = io->io_hdr.flags;
/*
* We convert everything into a S/G list here. We can't
@@ -12198,7 +12326,24 @@ ctl_datamove(union ctl_io *io)
msg.dt.sent_sg_entries = sg_entries_sent;
}
+
+ /*
+ * Officially handover the request from us to peer.
+ * If failover has just happened, then we must return error.
+ * If failover happen just after, then it is not our problem.
+ */
+ if (lun)
+ mtx_lock(&lun->lun_lock);
+ if (io->io_hdr.flags & CTL_FLAG_FAILOVER) {
+ if (lun)
+ mtx_unlock(&lun->lun_lock);
+ io->io_hdr.port_status = 31342;
+ io->scsiio.be_move_done(io);
+ return;
+ }
io->io_hdr.flags &= ~CTL_FLAG_IO_ACTIVE;
+ if (lun)
+ mtx_unlock(&lun->lun_lock);
} else {
/*
@@ -12467,10 +12612,12 @@ ctl_datamove_remote_xfer(union ctl_io *io, unsigned command,
* failure.
*/
if ((rq == NULL)
- && ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE))
+ && ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE &&
+ (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS))
ctl_set_busy(&io->scsiio);
- if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE) {
+ if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE &&
+ (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) {
if (rq != NULL)
ctl_dt_req_free(rq);
@@ -12851,15 +12998,6 @@ bailout:
msg.scsi.residual = io->scsiio.residual;
memcpy(&msg.scsi.sense_data, &io->scsiio.sense_data,
io->scsiio.sense_len);
- /*
- * We copy this whether or not this is an I/O-related
- * command. Otherwise, we'd have to go and check to see
- * whether it's a read/write command, and it really isn't
- * worth it.
- */
- memcpy(&msg.scsi.lbalen,
- &io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN].bytes,
- sizeof(msg.scsi.lbalen));
ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg,
sizeof(msg.scsi) - sizeof(msg.scsi.sense_data) +
diff --git a/sys/cam/ctl/ctl.h b/sys/cam/ctl/ctl.h
index 630e3bb..d10bdf6 100644
--- a/sys/cam/ctl/ctl.h
+++ b/sys/cam/ctl/ctl.h
@@ -120,6 +120,7 @@ typedef enum {
CTL_UA_LUN_CHANGE = 0x0020,
CTL_UA_MODE_CHANGE = 0x0040,
CTL_UA_LOG_CHANGE = 0x0080,
+ CTL_UA_INQ_CHANGE = 0x0100,
CTL_UA_RES_PREEMPT = 0x0400,
CTL_UA_RES_RELEASE = 0x0800,
CTL_UA_REG_PREEMPT = 0x1000,
@@ -138,6 +139,10 @@ struct ctl_page_index;
SYSCTL_DECL(_kern_cam_ctl);
#endif
+struct ctl_lun;
+struct ctl_port;
+struct ctl_softc;
+
/*
* Put a string into an sbuf, escaping characters that are illegal or not
* recommended in XML. Note this doesn't escape everything, just > < and &.
@@ -174,9 +179,17 @@ void ctl_config_write_done(union ctl_io *io);
void ctl_portDB_changed(int portnum);
int ctl_ioctl_io(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
struct thread *td);
-struct ctl_lun;
+
+void ctl_est_ua(struct ctl_lun *lun, uint32_t initidx, ctl_ua_type ua);
+void ctl_est_ua_port(struct ctl_lun *lun, int port, uint32_t except,
+ ctl_ua_type ua);
+void ctl_est_ua_all(struct ctl_lun *lun, uint32_t except, ctl_ua_type ua);
+void ctl_clr_ua(struct ctl_lun *lun, uint32_t initidx, ctl_ua_type ua);
+void ctl_clr_ua_all(struct ctl_lun *lun, uint32_t except, ctl_ua_type ua);
+void ctl_clr_ua_allluns(struct ctl_softc *ctl_softc, uint32_t initidx,
+ ctl_ua_type ua_type);
+
void ctl_isc_announce_lun(struct ctl_lun *lun);
-struct ctl_port;
void ctl_isc_announce_port(struct ctl_port *port);
/*
diff --git a/sys/cam/ctl/ctl_backend_block.c b/sys/cam/ctl/ctl_backend_block.c
index c9d2a57..975de2c 100644
--- a/sys/cam/ctl/ctl_backend_block.c
+++ b/sys/cam/ctl/ctl_backend_block.c
@@ -351,6 +351,48 @@ ctl_complete_beio(struct ctl_be_block_io *beio)
}
}
+static size_t
+cmp(uint8_t *a, uint8_t *b, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; i++) {
+ if (a[i] != b[i])
+ break;
+ }
+ return (i);
+}
+
+static void
+ctl_be_block_compare(union ctl_io *io)
+{
+ struct ctl_be_block_io *beio;
+ uint64_t off, res;
+ int i;
+ uint8_t info[8];
+
+ beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
+ off = 0;
+ for (i = 0; i < beio->num_segs; i++) {
+ res = cmp(beio->sg_segs[i].addr,
+ beio->sg_segs[i + CTLBLK_HALF_SEGS].addr,
+ beio->sg_segs[i].len);
+ off += res;
+ if (res < beio->sg_segs[i].len)
+ break;
+ }
+ if (i < beio->num_segs) {
+ scsi_u64to8b(off, info);
+ ctl_set_sense(&io->scsiio, /*current_error*/ 1,
+ /*sense_key*/ SSD_KEY_MISCOMPARE,
+ /*asc*/ 0x1D, /*ascq*/ 0x00,
+ /*type*/ SSD_ELEM_INFO,
+ /*size*/ sizeof(info), /*data*/ &info,
+ /*type*/ SSD_ELEM_NONE);
+ } else
+ ctl_set_success(&io->scsiio);
+}
+
static int
ctl_be_block_move_done(union ctl_io *io)
{
@@ -360,7 +402,6 @@ ctl_be_block_move_done(union ctl_io *io)
#ifdef CTL_TIME_IO
struct bintime cur_bt;
#endif
- int i;
beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
be_lun = beio->lun;
@@ -388,21 +429,7 @@ ctl_be_block_move_done(union ctl_io *io)
ctl_set_success(&io->scsiio);
} else if (lbalen->flags & CTL_LLF_COMPARE) {
/* We have two data blocks ready for comparison. */
- for (i = 0; i < beio->num_segs; i++) {
- if (memcmp(beio->sg_segs[i].addr,
- beio->sg_segs[i + CTLBLK_HALF_SEGS].addr,
- beio->sg_segs[i].len) != 0)
- break;
- }
- if (i < beio->num_segs)
- ctl_set_sense(&io->scsiio,
- /*current_error*/ 1,
- /*sense_key*/ SSD_KEY_MISCOMPARE,
- /*asc*/ 0x1D,
- /*ascq*/ 0x00,
- SSD_ELEM_NONE);
- else
- ctl_set_success(&io->scsiio);
+ ctl_be_block_compare(io);
}
} else if ((io->io_hdr.port_status != 0) &&
((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE ||
@@ -508,6 +535,8 @@ ctl_be_block_biodone(struct bio *bio)
ctl_set_invalid_opcode(&io->scsiio);
} else if (error == ENOSPC || error == EDQUOT) {
ctl_set_space_alloc_fail(&io->scsiio);
+ } else if (error == EROFS || error == EACCES) {
+ ctl_set_hw_write_protected(&io->scsiio);
} else if (beio->bio_cmd == BIO_FLUSH) {
/* XXX KDM is there is a better error here? */
ctl_set_internal_failure(&io->scsiio,
@@ -603,8 +632,8 @@ ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun,
union ctl_io *io;
struct uio xuio;
struct iovec *xiovec;
- int flags;
- int error, i;
+ size_t s;
+ int error, flags, i;
DPRINTF("entered\n");
@@ -665,6 +694,22 @@ ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun,
VOP_UNLOCK(be_lun->vn, 0);
SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0);
+ if (error == 0 && xuio.uio_resid > 0) {
+ /*
+ * If we red less then requested (EOF), then
+ * we should clean the rest of the buffer.
+ */
+ s = beio->io_len - xuio.uio_resid;
+ for (i = 0; i < beio->num_segs; i++) {
+ if (s >= beio->sg_segs[i].len) {
+ s -= beio->sg_segs[i].len;
+ continue;
+ }
+ bzero((uint8_t *)beio->sg_segs[i].addr + s,
+ beio->sg_segs[i].len - s);
+ s = 0;
+ }
+ }
} else {
struct mount *mountpoint;
int lock_flags;
@@ -720,6 +765,8 @@ ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun,
(beio->bio_cmd == BIO_READ) ? "READ" : "WRITE", error);
if (error == ENOSPC || error == EDQUOT) {
ctl_set_space_alloc_fail(&io->scsiio);
+ } else if (error == EROFS || error == EACCES) {
+ ctl_set_hw_write_protected(&io->scsiio);
} else
ctl_set_medium_error(&io->scsiio);
ctl_complete_beio(beio);
@@ -885,6 +932,8 @@ ctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun,
if (error != 0) {
if (error == ENOSPC || error == EDQUOT) {
ctl_set_space_alloc_fail(&io->scsiio);
+ } else if (error == EROFS || error == EACCES) {
+ ctl_set_hw_write_protected(&io->scsiio);
} else
ctl_set_medium_error(&io->scsiio);
ctl_complete_beio(beio);
diff --git a/sys/cam/ctl/ctl_cmd_table.c b/sys/cam/ctl/ctl_cmd_table.c
index 5b75468..f910201 100644
--- a/sys/cam/ctl/ctl_cmd_table.c
+++ b/sys/cam/ctl/ctl_cmd_table.c
@@ -486,7 +486,7 @@ const struct ctl_cmd_entry ctl_cmd_table_a3[32] =
CTL_FLAG_DATA_IN |
CTL_CMD_FLAG_ALLOW_ON_PR_RESV,
CTL_LUN_PAT_NONE,
- 12, {0x0a, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
+ 12, {0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
/* 0B */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
@@ -768,7 +768,7 @@ const struct ctl_cmd_entry ctl_cmd_table[256] =
/* 35 SYNCHRONIZE CACHE(10) */
{ctl_sync_cache, CTL_SERIDX_SYNC, CTL_CMD_FLAG_OK_ON_SLUN |
CTL_FLAG_DATA_NONE,
- CTL_LUN_PAT_NONE,
+ CTL_LUN_PAT_WRITE,
10, {0x02, 0xff, 0xff, 0xff, 0xff, 0, 0xff, 0xff, 0x07}},
/* 36 LOCK UNLOCK CACHE(10) */
@@ -1117,7 +1117,7 @@ const struct ctl_cmd_entry ctl_cmd_table[256] =
/* 91 SYNCHRONIZE CACHE(16) */
{ctl_sync_cache, CTL_SERIDX_SYNC, CTL_CMD_FLAG_OK_ON_SLUN |
CTL_FLAG_DATA_NONE,
- CTL_LUN_PAT_NONE,
+ CTL_LUN_PAT_WRITE,
16, {0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
diff --git a/sys/cam/ctl/ctl_error.c b/sys/cam/ctl/ctl_error.c
index 8ef5176..4eec276 100644
--- a/sys/cam/ctl/ctl_error.c
+++ b/sys/cam/ctl/ctl_error.c
@@ -365,62 +365,35 @@ ctl_set_ua(struct ctl_scsiio *ctsio, int asc, int ascq)
SSD_ELEM_NONE);
}
-ctl_ua_type
-ctl_build_ua(struct ctl_lun *lun, uint32_t initidx,
- struct scsi_sense_data *sense, scsi_sense_data_type sense_format)
+static void
+ctl_ua_to_acsq(ctl_ua_type ua_to_build, int *asc, int *ascq,
+ ctl_ua_type *ua_to_clear)
{
- ctl_ua_type *ua;
- ctl_ua_type ua_to_build, ua_to_clear;
- int asc, ascq;
- uint32_t p, i;
-
- mtx_assert(&lun->lun_lock, MA_OWNED);
- p = initidx / CTL_MAX_INIT_PER_PORT;
- if ((ua = lun->pending_ua[p]) == NULL) {
- mtx_unlock(&lun->lun_lock);
- ua = malloc(sizeof(ctl_ua_type) * CTL_MAX_INIT_PER_PORT,
- M_CTL, M_WAITOK);
- mtx_lock(&lun->lun_lock);
- if (lun->pending_ua[p] == NULL) {
- lun->pending_ua[p] = ua;
- for (i = 0; i < CTL_MAX_INIT_PER_PORT; i++)
- ua[i] = CTL_UA_POWERON;
- } else {
- free(ua, M_CTL);
- ua = lun->pending_ua[p];
- }
- }
- i = initidx % CTL_MAX_INIT_PER_PORT;
- if (ua[i] == CTL_UA_NONE)
- return (CTL_UA_NONE);
-
- ua_to_build = (1 << (ffs(ua[i]) - 1));
- ua_to_clear = ua_to_build;
switch (ua_to_build) {
case CTL_UA_POWERON:
/* 29h/01h POWER ON OCCURRED */
- asc = 0x29;
- ascq = 0x01;
- ua_to_clear = ~0;
+ *asc = 0x29;
+ *ascq = 0x01;
+ *ua_to_clear = ~0;
break;
case CTL_UA_BUS_RESET:
/* 29h/02h SCSI BUS RESET OCCURRED */
- asc = 0x29;
- ascq = 0x02;
- ua_to_clear = ~0;
+ *asc = 0x29;
+ *ascq = 0x02;
+ *ua_to_clear = ~0;
break;
case CTL_UA_TARG_RESET:
/* 29h/03h BUS DEVICE RESET FUNCTION OCCURRED*/
- asc = 0x29;
- ascq = 0x03;
- ua_to_clear = ~0;
+ *asc = 0x29;
+ *ascq = 0x03;
+ *ua_to_clear = ~0;
break;
case CTL_UA_I_T_NEXUS_LOSS:
/* 29h/07h I_T NEXUS LOSS OCCURRED */
- asc = 0x29;
- ascq = 0x07;
- ua_to_clear = ~0;
+ *asc = 0x29;
+ *ascq = 0x07;
+ *ua_to_clear = ~0;
break;
case CTL_UA_LUN_RESET:
/* 29h/00h POWER ON, RESET, OR BUS DEVICE RESET OCCURRED */
@@ -428,57 +401,128 @@ ctl_build_ua(struct ctl_lun *lun, uint32_t initidx,
* Since we don't have a specific ASC/ASCQ pair for a LUN
* reset, just return the generic reset code.
*/
- asc = 0x29;
- ascq = 0x00;
+ *asc = 0x29;
+ *ascq = 0x00;
break;
case CTL_UA_LUN_CHANGE:
/* 3Fh/0Eh REPORTED LUNS DATA HAS CHANGED */
- asc = 0x3F;
- ascq = 0x0E;
+ *asc = 0x3F;
+ *ascq = 0x0E;
break;
case CTL_UA_MODE_CHANGE:
/* 2Ah/01h MODE PARAMETERS CHANGED */
- asc = 0x2A;
- ascq = 0x01;
+ *asc = 0x2A;
+ *ascq = 0x01;
break;
case CTL_UA_LOG_CHANGE:
/* 2Ah/02h LOG PARAMETERS CHANGED */
- asc = 0x2A;
- ascq = 0x02;
+ *asc = 0x2A;
+ *ascq = 0x02;
+ break;
+ case CTL_UA_INQ_CHANGE:
+ /* 3Fh/03h INQUIRY DATA HAS CHANGED */
+ *asc = 0x3F;
+ *ascq = 0x03;
break;
case CTL_UA_RES_PREEMPT:
/* 2Ah/03h RESERVATIONS PREEMPTED */
- asc = 0x2A;
- ascq = 0x03;
+ *asc = 0x2A;
+ *ascq = 0x03;
break;
case CTL_UA_RES_RELEASE:
/* 2Ah/04h RESERVATIONS RELEASED */
- asc = 0x2A;
- ascq = 0x04;
+ *asc = 0x2A;
+ *ascq = 0x04;
break;
case CTL_UA_REG_PREEMPT:
/* 2Ah/05h REGISTRATIONS PREEMPTED */
- asc = 0x2A;
- ascq = 0x05;
+ *asc = 0x2A;
+ *ascq = 0x05;
break;
case CTL_UA_ASYM_ACC_CHANGE:
- /* 2Ah/06n ASYMMETRIC ACCESS STATE CHANGED */
- asc = 0x2A;
- ascq = 0x06;
+ /* 2Ah/06h ASYMMETRIC ACCESS STATE CHANGED */
+ *asc = 0x2A;
+ *ascq = 0x06;
break;
case CTL_UA_CAPACITY_CHANGED:
- /* 2Ah/09n CAPACITY DATA HAS CHANGED */
- asc = 0x2A;
- ascq = 0x09;
+ /* 2Ah/09h CAPACITY DATA HAS CHANGED */
+ *asc = 0x2A;
+ *ascq = 0x09;
break;
case CTL_UA_THIN_PROV_THRES:
- /* 38h/07n THIN PROVISIONING SOFT THRESHOLD REACHED */
- asc = 0x38;
- ascq = 0x07;
+ /* 38h/07h THIN PROVISIONING SOFT THRESHOLD REACHED */
+ *asc = 0x38;
+ *ascq = 0x07;
break;
default:
- panic("ctl_build_ua: Unknown UA %x", ua_to_build);
+ panic("%s: Unknown UA %x", __func__, ua_to_build);
+ }
+}
+
+ctl_ua_type
+ctl_build_qae(struct ctl_lun *lun, uint32_t initidx, uint8_t *resp)
+{
+ ctl_ua_type ua;
+ ctl_ua_type ua_to_build, ua_to_clear;
+ int asc, ascq;
+ uint32_t p, i;
+
+ mtx_assert(&lun->lun_lock, MA_OWNED);
+ p = initidx / CTL_MAX_INIT_PER_PORT;
+ i = initidx % CTL_MAX_INIT_PER_PORT;
+ if (lun->pending_ua[p] == NULL)
+ ua = CTL_UA_POWERON;
+ else
+ ua = lun->pending_ua[p][i];
+ if (ua == CTL_UA_NONE)
+ return (CTL_UA_NONE);
+
+ ua_to_build = (1 << (ffs(ua) - 1));
+ ua_to_clear = ua_to_build;
+ ctl_ua_to_acsq(ua_to_build, &asc, &ascq, &ua_to_clear);
+
+ resp[0] = SSD_KEY_UNIT_ATTENTION;
+ if (ua_to_build == ua)
+ resp[0] |= 0x10;
+ else
+ resp[0] |= 0x20;
+ resp[1] = asc;
+ resp[2] = ascq;
+ return (ua);
+}
+
+ctl_ua_type
+ctl_build_ua(struct ctl_lun *lun, uint32_t initidx,
+ struct scsi_sense_data *sense, scsi_sense_data_type sense_format)
+{
+ ctl_ua_type *ua;
+ ctl_ua_type ua_to_build, ua_to_clear;
+ int asc, ascq;
+ uint32_t p, i;
+
+ mtx_assert(&lun->lun_lock, MA_OWNED);
+ p = initidx / CTL_MAX_INIT_PER_PORT;
+ if ((ua = lun->pending_ua[p]) == NULL) {
+ mtx_unlock(&lun->lun_lock);
+ ua = malloc(sizeof(ctl_ua_type) * CTL_MAX_INIT_PER_PORT,
+ M_CTL, M_WAITOK);
+ mtx_lock(&lun->lun_lock);
+ if (lun->pending_ua[p] == NULL) {
+ lun->pending_ua[p] = ua;
+ for (i = 0; i < CTL_MAX_INIT_PER_PORT; i++)
+ ua[i] = CTL_UA_POWERON;
+ } else {
+ free(ua, M_CTL);
+ ua = lun->pending_ua[p];
+ }
}
+ i = initidx % CTL_MAX_INIT_PER_PORT;
+ if (ua[i] == CTL_UA_NONE)
+ return (CTL_UA_NONE);
+
+ ua_to_build = (1 << (ffs(ua[i]) - 1));
+ ua_to_clear = ua_to_build;
+ ctl_ua_to_acsq(ua_to_build, &asc, &ascq, &ua_to_clear);
ctl_set_sense_data(sense,
/*lun*/ NULL,
@@ -843,6 +887,18 @@ ctl_set_task_aborted(struct ctl_scsiio *ctsio)
}
void
+ctl_set_hw_write_protected(struct ctl_scsiio *ctsio)
+{
+ /* "Hardware write protected" */
+ ctl_set_sense(ctsio,
+ /*current_error*/ 1,
+ /*sense_key*/ SSD_KEY_DATA_PROTECT,
+ /*asc*/ 0x27,
+ /*ascq*/ 0x01,
+ SSD_ELEM_NONE);
+}
+
+void
ctl_set_space_alloc_fail(struct ctl_scsiio *ctsio)
{
/* "Space allocation failed write protect" */
diff --git a/sys/cam/ctl/ctl_error.h b/sys/cam/ctl/ctl_error.h
index 4fa8060..942def1 100644
--- a/sys/cam/ctl/ctl_error.h
+++ b/sys/cam/ctl/ctl_error.h
@@ -57,6 +57,7 @@ void ctl_sense_to_desc(struct scsi_sense_data_fixed *sense_src,
void ctl_sense_to_fixed(struct scsi_sense_data_desc *sense_src,
struct scsi_sense_data_fixed *sense_dest);
void ctl_set_ua(struct ctl_scsiio *ctsio, int asc, int ascq);
+ctl_ua_type ctl_build_qae(struct ctl_lun *lun, uint32_t initidx, uint8_t *resp);
ctl_ua_type ctl_build_ua(struct ctl_lun *lun, uint32_t initidx,
struct scsi_sense_data *sense, scsi_sense_data_type sense_format);
void ctl_set_overlapped_cmd(struct ctl_scsiio *ctsio);
@@ -85,6 +86,7 @@ void ctl_set_reservation_conflict(struct ctl_scsiio *ctsio);
void ctl_set_queue_full(struct ctl_scsiio *ctsio);
void ctl_set_busy(struct ctl_scsiio *ctsio);
void ctl_set_task_aborted(struct ctl_scsiio *ctsio);
+void ctl_set_hw_write_protected(struct ctl_scsiio *ctsio);
void ctl_set_space_alloc_fail(struct ctl_scsiio *ctsio);
void ctl_set_success(struct ctl_scsiio *ctsio);
diff --git a/sys/cam/ctl/ctl_frontend.c b/sys/cam/ctl/ctl_frontend.c
index c9c75d4..1caab65 100644
--- a/sys/cam/ctl/ctl_frontend.c
+++ b/sys/cam/ctl/ctl_frontend.c
@@ -328,8 +328,16 @@ ctl_port_online(struct ctl_port *port)
}
if (port->port_online != NULL)
port->port_online(port->onoff_arg);
- /* XXX KDM need a lock here? */
+ mtx_lock(&softc->ctl_lock);
port->status |= CTL_PORT_STATUS_ONLINE;
+ STAILQ_FOREACH(lun, &softc->lun_list, links) {
+ if (ctl_lun_map_to_port(port, lun->lun) >= CTL_MAX_LUNS)
+ continue;
+ mtx_lock(&lun->lun_lock);
+ ctl_est_ua_all(lun, -1, CTL_UA_INQ_CHANGE);
+ mtx_unlock(&lun->lun_lock);
+ }
+ mtx_unlock(&softc->ctl_lock);
ctl_isc_announce_port(port);
}
@@ -355,8 +363,16 @@ ctl_port_offline(struct ctl_port *port)
port->lun_disable(port->targ_lun_arg, lun->lun);
}
}
- /* XXX KDM need a lock here? */
+ mtx_lock(&softc->ctl_lock);
port->status &= ~CTL_PORT_STATUS_ONLINE;
+ STAILQ_FOREACH(lun, &softc->lun_list, links) {
+ if (ctl_lun_map_to_port(port, lun->lun) >= CTL_MAX_LUNS)
+ continue;
+ mtx_lock(&lun->lun_lock);
+ ctl_est_ua_all(lun, -1, CTL_UA_INQ_CHANGE);
+ mtx_unlock(&lun->lun_lock);
+ }
+ mtx_unlock(&softc->ctl_lock);
ctl_isc_announce_port(port);
}
diff --git a/sys/cam/ctl/ctl_frontend_cam_sim.c b/sys/cam/ctl/ctl_frontend_cam_sim.c
index 01807de..5423a17 100644
--- a/sys/cam/ctl/ctl_frontend_cam_sim.c
+++ b/sys/cam/ctl/ctl_frontend_cam_sim.c
@@ -435,6 +435,14 @@ cfcs_datamove(union ctl_io *io)
io->scsiio.ext_data_filled += len_copied;
+ if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) {
+ io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = NULL;
+ io->io_hdr.flags |= CTL_FLAG_STATUS_SENT;
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ ccb->ccb_h.status |= CAM_REQ_CMP;
+ xpt_done(ccb);
+ }
+
io->scsiio.be_move_done(io);
}
@@ -458,12 +466,13 @@ cfcs_done(union ctl_io *io)
/*
* Translate CTL status to CAM status.
*/
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
switch (io->io_hdr.status & CTL_STATUS_MASK) {
case CTL_SUCCESS:
- ccb->ccb_h.status = CAM_REQ_CMP;
+ ccb->ccb_h.status |= CAM_REQ_CMP;
break;
case CTL_SCSI_ERROR:
- ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
+ ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
ccb->csio.scsi_status = io->scsiio.scsi_status;
bcopy(&io->scsiio.sense_data, &ccb->csio.sense_data,
min(io->scsiio.sense_len, ccb->csio.sense_len));
@@ -479,14 +488,18 @@ cfcs_done(union ctl_io *io)
}
break;
case CTL_CMD_ABORTED:
- ccb->ccb_h.status = CAM_REQ_ABORTED;
+ ccb->ccb_h.status |= CAM_REQ_ABORTED;
break;
case CTL_ERROR:
default:
- ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+ ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
break;
}
-
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP &&
+ (ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
+ xpt_freeze_devq(ccb->ccb_h.path, 1);
+ ccb->ccb_h.status |= CAM_DEV_QFRZN;
+ }
xpt_done(ccb);
ctl_free_io(io);
}
diff --git a/sys/cam/ctl/ctl_frontend_ioctl.c b/sys/cam/ctl/ctl_frontend_ioctl.c
index 67156bc..fc3d15a 100644
--- a/sys/cam/ctl/ctl_frontend_ioctl.c
+++ b/sys/cam/ctl/ctl_frontend_ioctl.c
@@ -157,11 +157,8 @@ ctl_ioctl_do_datamove(struct ctl_scsiio *ctsio)
ext_sglist = (struct ctl_sg_entry *)malloc(ext_sglen, M_CTL,
M_WAITOK);
ext_sglist_malloced = 1;
- if (copyin(ctsio->ext_data_ptr, ext_sglist,
- ext_sglen) != 0) {
- ctl_set_internal_failure(ctsio,
- /*sks_valid*/ 0,
- /*retry_count*/ 0);
+ if (copyin(ctsio->ext_data_ptr, ext_sglist, ext_sglen) != 0) {
+ ctsio->io_hdr.port_status = 31343;
goto bailout;
}
ext_sg_entries = ctsio->ext_sg_entries;
@@ -229,9 +226,7 @@ ctl_ioctl_do_datamove(struct ctl_scsiio *ctsio)
CTL_DEBUG_PRINT(("ctl_ioctl_do_datamove: from %p "
"to %p\n", kern_ptr, ext_ptr));
if (copyout(kern_ptr, ext_ptr, len_to_copy) != 0) {
- ctl_set_internal_failure(ctsio,
- /*sks_valid*/ 0,
- /*retry_count*/ 0);
+ ctsio->io_hdr.port_status = 31344;
goto bailout;
}
} else {
@@ -240,9 +235,7 @@ ctl_ioctl_do_datamove(struct ctl_scsiio *ctsio)
CTL_DEBUG_PRINT(("ctl_ioctl_do_datamove: from %p "
"to %p\n", ext_ptr, kern_ptr));
if (copyin(ext_ptr, kern_ptr, len_to_copy)!= 0){
- ctl_set_internal_failure(ctsio,
- /*sks_valid*/ 0,
- /*retry_count*/0);
+ ctsio->io_hdr.port_status = 31345;
goto bailout;
}
}
diff --git a/sys/cam/ctl/ctl_frontend_iscsi.c b/sys/cam/ctl/ctl_frontend_iscsi.c
index 6ea862f..f993691 100644
--- a/sys/cam/ctl/ctl_frontend_iscsi.c
+++ b/sys/cam/ctl/ctl_frontend_iscsi.c
@@ -639,6 +639,12 @@ cfiscsi_pdu_handle_task_request(struct icl_pdu *request)
#endif
io->taskio.task_action = CTL_TASK_ABORT_TASK_SET;
break;
+ case BHSTMR_FUNCTION_CLEAR_TASK_SET:
+#if 0
+ CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_CLEAR_TASK_SET");
+#endif
+ io->taskio.task_action = CTL_TASK_CLEAR_TASK_SET;
+ break;
case BHSTMR_FUNCTION_LOGICAL_UNIT_RESET:
#if 0
CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_LOGICAL_UNIT_RESET");
@@ -651,6 +657,37 @@ cfiscsi_pdu_handle_task_request(struct icl_pdu *request)
#endif
io->taskio.task_action = CTL_TASK_TARGET_RESET;
break;
+ case BHSTMR_FUNCTION_TARGET_COLD_RESET:
+#if 0
+ CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_TARGET_COLD_RESET");
+#endif
+ io->taskio.task_action = CTL_TASK_TARGET_RESET;
+ break;
+ case BHSTMR_FUNCTION_QUERY_TASK:
+#if 0
+ CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_QUERY_TASK");
+#endif
+ io->taskio.task_action = CTL_TASK_QUERY_TASK;
+ io->taskio.tag_num = bhstmr->bhstmr_referenced_task_tag;
+ break;
+ case BHSTMR_FUNCTION_QUERY_TASK_SET:
+#if 0
+ CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_QUERY_TASK_SET");
+#endif
+ io->taskio.task_action = CTL_TASK_QUERY_TASK_SET;
+ break;
+ case BHSTMR_FUNCTION_I_T_NEXUS_RESET:
+#if 0
+ CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_I_T_NEXUS_RESET");
+#endif
+ io->taskio.task_action = CTL_TASK_I_T_NEXUS_RESET;
+ break;
+ case BHSTMR_FUNCTION_QUERY_ASYNC_EVENT:
+#if 0
+ CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_QUERY_ASYNC_EVENT");
+#endif
+ io->taskio.task_action = CTL_TASK_QUERY_ASYNC_EVENT;
+ break;
default:
CFISCSI_SESSION_DEBUG(cs, "unsupported function 0x%x",
bhstmr->bhstmr_function & ~0x80);
@@ -2842,7 +2879,9 @@ cfiscsi_task_management_done(union ctl_io *io)
struct iscsi_bhs_task_management_request *bhstmr;
struct iscsi_bhs_task_management_response *bhstmr2;
struct cfiscsi_data_wait *cdw, *tmpcdw;
- struct cfiscsi_session *cs;
+ struct cfiscsi_session *cs, *tcs;
+ struct cfiscsi_softc *softc;
+ int cold_reset = 0;
request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
cs = PDU_SESSION(request);
@@ -2880,29 +2919,48 @@ cfiscsi_task_management_done(union ctl_io *io)
}
CFISCSI_SESSION_UNLOCK(cs);
}
+ if ((bhstmr->bhstmr_function & ~0x80) ==
+ BHSTMR_FUNCTION_TARGET_COLD_RESET &&
+ io->io_hdr.status == CTL_SUCCESS)
+ cold_reset = 1;
response = cfiscsi_pdu_new_response(request, M_WAITOK);
bhstmr2 = (struct iscsi_bhs_task_management_response *)
response->ip_bhs;
bhstmr2->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_RESPONSE;
bhstmr2->bhstmr_flags = 0x80;
- if (io->io_hdr.status == CTL_SUCCESS) {
+ switch (io->taskio.task_status) {
+ case CTL_TASK_FUNCTION_COMPLETE:
bhstmr2->bhstmr_response = BHSTMR_RESPONSE_FUNCTION_COMPLETE;
- } else {
- /*
- * XXX: How to figure out what exactly went wrong? iSCSI spec
- * expects us to provide detailed error, e.g. "Task does
- * not exist" or "LUN does not exist".
- */
- CFISCSI_SESSION_DEBUG(cs, "BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED");
- bhstmr2->bhstmr_response =
- BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED;
+ break;
+ case CTL_TASK_FUNCTION_SUCCEEDED:
+ bhstmr2->bhstmr_response = BHSTMR_RESPONSE_FUNCTION_SUCCEEDED;
+ break;
+ case CTL_TASK_LUN_DOES_NOT_EXIST:
+ bhstmr2->bhstmr_response = BHSTMR_RESPONSE_LUN_DOES_NOT_EXIST;
+ break;
+ case CTL_TASK_FUNCTION_NOT_SUPPORTED:
+ default:
+ bhstmr2->bhstmr_response = BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED;
+ break;
}
+ memcpy(bhstmr2->bhstmr_additional_reponse_information,
+ io->taskio.task_resp, sizeof(io->taskio.task_resp));
bhstmr2->bhstmr_initiator_task_tag = bhstmr->bhstmr_initiator_task_tag;
ctl_free_io(io);
icl_pdu_free(request);
cfiscsi_pdu_queue(response);
+
+ if (cold_reset) {
+ softc = cs->cs_target->ct_softc;
+ mtx_lock(&softc->lock);
+ TAILQ_FOREACH(tcs, &softc->sessions, cs_next) {
+ if (tcs->cs_target == cs->cs_target)
+ cfiscsi_session_terminate(tcs);
+ }
+ mtx_unlock(&softc->lock);
+ }
}
static void
diff --git a/sys/cam/ctl/ctl_ha.c b/sys/cam/ctl/ctl_ha.c
index 8d6604f..952e92a 100644
--- a/sys/cam/ctl/ctl_ha.c
+++ b/sys/cam/ctl/ctl_ha.c
@@ -622,28 +622,33 @@ ctl_ha_peer_sysctl(SYSCTL_HANDLER_ARGS)
struct ha_softc *softc = (struct ha_softc *)arg1;
struct sockaddr_in *sa;
int error, b1, b2, b3, b4, p, num;
+ char buf[128];
- error = sysctl_handle_string(oidp, softc->ha_peer,
- sizeof(softc->ha_peer), req);
- if ((error != 0) || (req->newptr == NULL))
+ strlcpy(buf, softc->ha_peer, sizeof(buf));
+ error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
+ if ((error != 0) || (req->newptr == NULL) ||
+ strncmp(buf, softc->ha_peer, sizeof(buf)) == 0)
return (error);
sa = &softc->ha_peer_in;
mtx_lock(&softc->ha_lock);
- if ((num = sscanf(softc->ha_peer, "connect %d.%d.%d.%d:%d",
+ if ((num = sscanf(buf, "connect %d.%d.%d.%d:%d",
&b1, &b2, &b3, &b4, &p)) >= 4) {
softc->ha_connect = 1;
softc->ha_listen = 0;
- } else if ((num = sscanf(softc->ha_peer, "listen %d.%d.%d.%d:%d",
+ } else if ((num = sscanf(buf, "listen %d.%d.%d.%d:%d",
&b1, &b2, &b3, &b4, &p)) >= 4) {
softc->ha_connect = 0;
softc->ha_listen = 1;
} else {
softc->ha_connect = 0;
softc->ha_listen = 0;
- if (softc->ha_peer[0] != 0)
+ if (buf[0] != 0) {
+ buf[0] = 0;
error = EINVAL;
+ }
}
+ strlcpy(softc->ha_peer, buf, sizeof(softc->ha_peer));
if (softc->ha_connect || softc->ha_listen) {
memset(sa, 0, sizeof(*sa));
sa->sin_len = sizeof(struct sockaddr_in);
diff --git a/sys/cam/ctl/ctl_io.h b/sys/cam/ctl/ctl_io.h
index e85d0a5..18eb93e 100644
--- a/sys/cam/ctl/ctl_io.h
+++ b/sys/cam/ctl/ctl_io.h
@@ -328,9 +328,20 @@ typedef enum {
CTL_TASK_TARGET_RESET,
CTL_TASK_BUS_RESET,
CTL_TASK_PORT_LOGIN,
- CTL_TASK_PORT_LOGOUT
+ CTL_TASK_PORT_LOGOUT,
+ CTL_TASK_QUERY_TASK,
+ CTL_TASK_QUERY_TASK_SET,
+ CTL_TASK_QUERY_ASYNC_EVENT
} ctl_task_type;
+typedef enum {
+ CTL_TASK_FUNCTION_COMPLETE,
+ CTL_TASK_FUNCTION_SUCCEEDED,
+ CTL_TASK_FUNCTION_REJECTED,
+ CTL_TASK_LUN_DOES_NOT_EXIST,
+ CTL_TASK_FUNCTION_NOT_SUPPORTED
+} ctl_task_status;
+
/*
* Task management I/O structure. Aborts, bus resets, etc., are sent using
* this structure.
@@ -343,6 +354,8 @@ struct ctl_taskio {
ctl_task_type task_action; /* Target Reset, Abort, etc. */
uint32_t tag_num; /* tag number */
ctl_tag_type tag_type; /* simple, ordered, etc. */
+ uint8_t task_status; /* Complete, Succeeded, etc. */
+ uint8_t task_resp[3];/* Response information */
};
typedef enum {
@@ -439,7 +452,6 @@ struct ctl_ha_msg_scsi {
uint32_t residual; /* data residual length */
uint32_t fetd_status; /* trans status, set by FETD,
0 = good*/
- struct ctl_lba_len lbalen; /* used for stats */
struct scsi_sense_data sense_data; /* sense data */
};
diff --git a/sys/cam/ctl/ctl_tpc.c b/sys/cam/ctl/ctl_tpc.c
index e4722fe..887fe59 100644
--- a/sys/cam/ctl/ctl_tpc.c
+++ b/sys/cam/ctl/ctl_tpc.c
@@ -394,8 +394,7 @@ ctl_inquiry_evpd_tpc(struct ctl_scsiio *ctsio, int alloc_len)
scsi_ulto2b(0, rtfb_ptr->optimal_length_granularity);
scsi_u64to8b(0, rtfb_ptr->maximum_bytes);
scsi_u64to8b(0, rtfb_ptr->optimal_bytes);
- scsi_u64to8b(TPC_MAX_IOCHUNK_SIZE,
- rtfb_ptr->optimal_bytes_to_token_per_segment);
+ scsi_u64to8b(UINT64_MAX, rtfb_ptr->optimal_bytes_to_token_per_segment);
scsi_u64to8b(TPC_MAX_IOCHUNK_SIZE,
rtfb_ptr->optimal_bytes_from_token_per_segment);
@@ -1590,6 +1589,10 @@ ctl_extended_copy_lid1(struct ctl_scsiio *ctsio)
cdb = (struct scsi_extended_copy *)ctsio->cdb;
len = scsi_4btoul(cdb->length);
+ if (len == 0) {
+ ctl_set_success(ctsio);
+ goto done;
+ }
if (len < sizeof(struct scsi_extended_copy_lid1_data) ||
len > sizeof(struct scsi_extended_copy_lid1_data) +
TPC_MAX_LIST + TPC_MAX_INLINE) {
@@ -1620,20 +1623,22 @@ ctl_extended_copy_lid1(struct ctl_scsiio *ctsio)
lencscd = scsi_2btoul(data->cscd_list_length);
lenseg = scsi_4btoul(data->segment_list_length);
leninl = scsi_4btoul(data->inline_data_length);
- if (len < sizeof(struct scsi_extended_copy_lid1_data) +
- lencscd + lenseg + leninl ||
- leninl > TPC_MAX_INLINE) {
- ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 0,
- /*field*/ 2, /*bit_valid*/ 0, /*bit*/ 0);
- goto done;
- }
if (lencscd > TPC_MAX_CSCDS * sizeof(struct scsi_ec_cscd)) {
ctl_set_sense(ctsio, /*current_error*/ 1,
/*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
/*asc*/ 0x26, /*ascq*/ 0x06, SSD_ELEM_NONE);
goto done;
}
- if (lencscd + lenseg > TPC_MAX_LIST) {
+ if (lenseg > TPC_MAX_SEGS * sizeof(struct scsi_ec_segment)) {
+ ctl_set_sense(ctsio, /*current_error*/ 1,
+ /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
+ /*asc*/ 0x26, /*ascq*/ 0x08, SSD_ELEM_NONE);
+ goto done;
+ }
+ if (lencscd + lenseg > TPC_MAX_LIST ||
+ leninl > TPC_MAX_INLINE ||
+ len < sizeof(struct scsi_extended_copy_lid1_data) +
+ lencscd + lenseg + leninl) {
ctl_set_param_len_error(ctsio);
goto done;
}
@@ -1717,6 +1722,10 @@ ctl_extended_copy_lid4(struct ctl_scsiio *ctsio)
cdb = (struct scsi_extended_copy *)ctsio->cdb;
len = scsi_4btoul(cdb->length);
+ if (len == 0) {
+ ctl_set_success(ctsio);
+ goto done;
+ }
if (len < sizeof(struct scsi_extended_copy_lid4_data) ||
len > sizeof(struct scsi_extended_copy_lid4_data) +
TPC_MAX_LIST + TPC_MAX_INLINE) {
@@ -1747,20 +1756,22 @@ ctl_extended_copy_lid4(struct ctl_scsiio *ctsio)
lencscd = scsi_2btoul(data->cscd_list_length);
lenseg = scsi_2btoul(data->segment_list_length);
leninl = scsi_2btoul(data->inline_data_length);
- if (len < sizeof(struct scsi_extended_copy_lid4_data) +
- lencscd + lenseg + leninl ||
- leninl > TPC_MAX_INLINE) {
- ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 0,
- /*field*/ 2, /*bit_valid*/ 0, /*bit*/ 0);
- goto done;
- }
if (lencscd > TPC_MAX_CSCDS * sizeof(struct scsi_ec_cscd)) {
ctl_set_sense(ctsio, /*current_error*/ 1,
/*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
/*asc*/ 0x26, /*ascq*/ 0x06, SSD_ELEM_NONE);
goto done;
}
- if (lencscd + lenseg > TPC_MAX_LIST) {
+ if (lenseg > TPC_MAX_SEGS * sizeof(struct scsi_ec_segment)) {
+ ctl_set_sense(ctsio, /*current_error*/ 1,
+ /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
+ /*asc*/ 0x26, /*ascq*/ 0x08, SSD_ELEM_NONE);
+ goto done;
+ }
+ if (lencscd + lenseg > TPC_MAX_LIST ||
+ leninl > TPC_MAX_INLINE ||
+ len < sizeof(struct scsi_extended_copy_lid1_data) +
+ lencscd + lenseg + leninl) {
ctl_set_param_len_error(ctsio);
goto done;
}
diff --git a/sys/cam/ctl/ctl_tpc_local.c b/sys/cam/ctl/ctl_tpc_local.c
index 7664cb9..ce7c3e8 100644
--- a/sys/cam/ctl/ctl_tpc_local.c
+++ b/sys/cam/ctl/ctl_tpc_local.c
@@ -281,7 +281,9 @@ tpcl_resolve(struct ctl_softc *softc, int init_port,
struct ctl_lun *lun;
uint64_t lunid = UINT64_MAX;
- if (cscd->type_code != EC_CSCD_ID)
+ if (cscd->type_code != EC_CSCD_ID ||
+ (cscd->luidt_pdt & EC_LUIDT_MASK) != EC_LUIDT_LUN ||
+ (cscd->luidt_pdt & EC_NUL) != 0)
return (lunid);
cscdid = (struct scsi_ec_cscd_id *)cscd;
diff --git a/sys/cam/ctl/ctl_util.c b/sys/cam/ctl/ctl_util.c
index 8c57a22..e5d79df 100644
--- a/sys/cam/ctl/ctl_util.c
+++ b/sys/cam/ctl/ctl_util.c
@@ -89,7 +89,10 @@ static struct ctl_task_desc ctl_task_table[] = {
{CTL_TASK_TARGET_RESET, "Target Reset"},
{CTL_TASK_BUS_RESET, "Bus Reset"},
{CTL_TASK_PORT_LOGIN, "Port Login"},
- {CTL_TASK_PORT_LOGOUT, "Port Logout"}
+ {CTL_TASK_PORT_LOGOUT, "Port Logout"},
+ {CTL_TASK_QUERY_TASK, "Query Task"},
+ {CTL_TASK_QUERY_TASK_SET, "Query Task Set"},
+ {CTL_TASK_QUERY_ASYNC_EVENT, "Query Async Event"}
};
void
diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c
index a54c03b..a4a8ffa 100644
--- a/sys/cam/scsi/scsi_all.c
+++ b/sys/cam/scsi/scsi_all.c
@@ -509,7 +509,8 @@ static struct op_table_entry scsi_op_codes[] = {
/* 99 */
/* 9A */
/* 9B */
- /* 9C */
+ /* 9C O WRITE ATOMIC(16) */
+ { 0x9C, D, "WRITE ATOMIC(16)" },
/* 9D */
/* XXX KDM ALL for this? op-num.txt defines it for none.. */
/* 9E SERVICE ACTION IN(16) */
@@ -1079,7 +1080,7 @@ static struct asc_table_entry asc_table[] = {
{ SST(0x04, 0x00, SS_RDEF,
"Logical unit not ready, cause not reportable") },
/* DTLPWROMAEBKVF */
- { SST(0x04, 0x01, SS_TUR | SSQ_MANY | SSQ_DECREMENT_COUNT | EBUSY,
+ { SST(0x04, 0x01, SS_WAIT | EBUSY,
"Logical unit is in process of becoming ready") },
/* DTLPWROMAEBKVF */
{ SST(0x04, 0x02, SS_START | SSQ_DECREMENT_COUNT | ENXIO,
@@ -1106,7 +1107,7 @@ static struct asc_table_entry asc_table[] = {
{ SST(0x04, 0x09, SS_RDEF, /* XXX TBD */
"Logical unit not ready, self-test in progress") },
/* DTLPWROMAEBKVF */
- { SST(0x04, 0x0A, SS_TUR | SSQ_MANY | SSQ_DECREMENT_COUNT | ENXIO,
+ { SST(0x04, 0x0A, SS_WAIT | ENXIO,
"Logical unit not accessible, asymmetric access state transition")},
/* DTLPWROMAEBKVF */
{ SST(0x04, 0x0B, SS_FATAL | ENXIO,
@@ -1121,7 +1122,7 @@ static struct asc_table_entry asc_table[] = {
{ SST(0x04, 0x10, SS_RDEF, /* XXX TBD */
"Logical unit not ready, auxiliary memory not accessible") },
/* DT WRO AEB VF */
- { SST(0x04, 0x11, SS_TUR | SSQ_MANY | SSQ_DECREMENT_COUNT | EBUSY,
+ { SST(0x04, 0x11, SS_WAIT | EBUSY,
"Logical unit not ready, notify (enable spinup) required") },
/* M V */
{ SST(0x04, 0x12, SS_RDEF, /* XXX TBD */
@@ -3803,8 +3804,6 @@ scsi_set_sense_data_va(struct scsi_sense_data *sense_data,
*/
sense->extra_len = 10;
sense_len = (int)va_arg(ap, int);
- len_to_copy = MIN(sense_len, SSD_EXTRA_MAX -
- sense->extra_len);
data = (uint8_t *)va_arg(ap, uint8_t *);
switch (elem_type) {
@@ -3822,10 +3821,14 @@ scsi_set_sense_data_va(struct scsi_sense_data *sense_data,
uint8_t *data_dest;
int i;
- if (elem_type == SSD_ELEM_COMMAND)
+ if (elem_type == SSD_ELEM_COMMAND) {
data_dest = &sense->cmd_spec_info[0];
- else {
+ len_to_copy = MIN(sense_len,
+ sizeof(sense->cmd_spec_info));
+ } else {
data_dest = &sense->info[0];
+ len_to_copy = MIN(sense_len,
+ sizeof(sense->info));
/*
* We're setting the info field, so
* set the valid bit.
diff --git a/sys/cam/scsi/scsi_all.h b/sys/cam/scsi/scsi_all.h
index 253e28e..f860624 100644
--- a/sys/cam/scsi/scsi_all.h
+++ b/sys/cam/scsi/scsi_all.h
@@ -103,6 +103,9 @@ typedef enum {
/* The retyable, error action, with table specified error code */
#define SS_RET SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE
+/* Wait for transient error status to change */
+#define SS_WAIT SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE
+
/* Fatal error action, with table specified error code */
#define SS_FATAL SS_FAIL|SSQ_PRINT_SENSE
@@ -1666,6 +1669,7 @@ struct scsi_ec_cscd
uint8_t type_code;
#define EC_CSCD_EXT 0xff
uint8_t luidt_pdt;
+#define EC_NUL 0x20
#define EC_LUIDT_MASK 0xc0
#define EC_LUIDT_LUN 0x00
#define EC_LUIDT_PROXY_TOKEN 0x40
diff --git a/sys/cam/scsi/scsi_ch.c b/sys/cam/scsi/scsi_ch.c
index 38acb01..bc398e7 100644
--- a/sys/cam/scsi/scsi_ch.c
+++ b/sys/cam/scsi/scsi_ch.c
@@ -655,11 +655,13 @@ chdone(struct cam_periph *periph, union ccb *done_ccb)
*/
return;
} else if (error != 0) {
- int retry_scheduled;
struct scsi_mode_sense_6 *sms;
+ int frozen, retry_scheduled;
sms = (struct scsi_mode_sense_6 *)
done_ccb->csio.cdb_io.cdb_bytes;
+ frozen = (done_ccb->ccb_h.status &
+ CAM_DEV_QFRZN) != 0;
/*
* Check to see if block descriptors were
@@ -670,7 +672,8 @@ chdone(struct cam_periph *periph, union ccb *done_ccb)
* block descriptors were disabled, enable
* them and re-send the command.
*/
- if (sms->byte2 & SMS_DBD) {
+ if ((sms->byte2 & SMS_DBD) != 0 &&
+ (periph->flags & CAM_PERIPH_INVALID) == 0) {
sms->byte2 &= ~SMS_DBD;
xpt_action(done_ccb);
softc->quirks |= CH_Q_NO_DBD;
@@ -679,7 +682,7 @@ chdone(struct cam_periph *periph, union ccb *done_ccb)
retry_scheduled = 0;
/* Don't wedge this device's queue */
- if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
+ if (frozen)
cam_release_devq(done_ccb->ccb_h.path,
/*relsim_flags*/0,
/*reduction*/0,
diff --git a/sys/cddl/contrib/opensolaris/common/avl/avl.c b/sys/cddl/contrib/opensolaris/common/avl/avl.c
index 9d86242..2349aba 100644
--- a/sys/cddl/contrib/opensolaris/common/avl/avl.c
+++ b/sys/cddl/contrib/opensolaris/common/avl/avl.c
@@ -25,6 +25,7 @@
/*
* Copyright (c) 2014 by Delphix. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -635,14 +636,17 @@ avl_add(avl_tree_t *tree, void *new_node)
/*
* This is unfortunate. We want to call panic() here, even for
* non-DEBUG kernels. In userland, however, we can't depend on anything
- * in libc or else the rtld build process gets confused. So, all we can
- * do in userland is resort to a normal ASSERT().
+ * in libc or else the rtld build process gets confused.
+ * Thankfully, rtld provides us with its own assfail() so we can use
+ * that here. We use assfail() directly to get a nice error message
+ * in the core - much like what panic() does for crashdumps.
*/
if (avl_find(tree, new_node, &where) != NULL)
#ifdef _KERNEL
panic("avl_find() succeeded inside avl_add()");
#else
- ASSERT(0);
+ (void) assfail("avl_find() succeeded inside avl_add()",
+ __FILE__, __LINE__);
#endif
avl_insert(tree, new_node, where);
}
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
index a233ab2..6d1792c 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
@@ -213,7 +213,7 @@ static int arc_min_prefetch_lifespan;
int arc_lotsfree_percent = 10;
static int arc_dead;
-extern int zfs_prefetch_disable;
+extern boolean_t zfs_prefetch_disable;
/*
* The arc has filled available memory and has now warmed up.
@@ -582,6 +582,8 @@ typedef struct arc_stats {
kstat_named_t arcstat_meta_limit;
kstat_named_t arcstat_meta_max;
kstat_named_t arcstat_meta_min;
+ kstat_named_t arcstat_sync_wait_for_async;
+ kstat_named_t arcstat_demand_hit_predictive_prefetch;
} arc_stats_t;
static arc_stats_t arc_stats = {
@@ -680,7 +682,9 @@ static arc_stats_t arc_stats = {
{ "arc_meta_used", KSTAT_DATA_UINT64 },
{ "arc_meta_limit", KSTAT_DATA_UINT64 },
{ "arc_meta_max", KSTAT_DATA_UINT64 },
- { "arc_meta_min", KSTAT_DATA_UINT64 }
+ { "arc_meta_min", KSTAT_DATA_UINT64 },
+ { "sync_wait_for_async", KSTAT_DATA_UINT64 },
+ { "demand_hit_predictive_prefetch", KSTAT_DATA_UINT64 },
};
#define ARCSTAT(stat) (arc_stats.stat.value.ui64)
@@ -844,6 +848,7 @@ typedef struct l2arc_buf_hdr {
uint64_t b_daddr; /* disk address, offset byte */
/* real alloc'd buffer size depending on b_compress applied */
int32_t b_asize;
+ uint8_t b_compress;
list_node_t b_l2node;
} l2arc_buf_hdr_t;
@@ -923,15 +928,6 @@ static arc_buf_hdr_t arc_eviction_hdr;
#define HDR_HAS_L1HDR(hdr) ((hdr)->b_flags & ARC_FLAG_HAS_L1HDR)
#define HDR_HAS_L2HDR(hdr) ((hdr)->b_flags & ARC_FLAG_HAS_L2HDR)
-/* For storing compression mode in b_flags */
-#define HDR_COMPRESS_OFFSET 24
-#define HDR_COMPRESS_NBITS 7
-
-#define HDR_GET_COMPRESS(hdr) ((enum zio_compress)BF32_GET(hdr->b_flags, \
- HDR_COMPRESS_OFFSET, HDR_COMPRESS_NBITS))
-#define HDR_SET_COMPRESS(hdr, cmp) BF32_SET(hdr->b_flags, \
- HDR_COMPRESS_OFFSET, HDR_COMPRESS_NBITS, (cmp))
-
/*
* Other sizes
*/
@@ -2222,7 +2218,7 @@ arc_buf_l2_cdata_free(arc_buf_hdr_t *hdr)
* separately compressed buffer, so there's nothing to free (it
* points to the same buffer as the arc_buf_t's b_data field).
*/
- if (HDR_GET_COMPRESS(hdr) == ZIO_COMPRESS_OFF) {
+ if (hdr->b_l2hdr.b_compress == ZIO_COMPRESS_OFF) {
hdr->b_l1hdr.b_tmp_cdata = NULL;
return;
}
@@ -2231,12 +2227,12 @@ arc_buf_l2_cdata_free(arc_buf_hdr_t *hdr)
* There's nothing to free since the buffer was all zero's and
* compressed to a zero length buffer.
*/
- if (HDR_GET_COMPRESS(hdr) == ZIO_COMPRESS_EMPTY) {
+ if (hdr->b_l2hdr.b_compress == ZIO_COMPRESS_EMPTY) {
ASSERT3P(hdr->b_l1hdr.b_tmp_cdata, ==, NULL);
return;
}
- ASSERT(L2ARC_IS_VALID_COMPRESS(HDR_GET_COMPRESS(hdr)));
+ ASSERT(L2ARC_IS_VALID_COMPRESS(hdr->b_l2hdr.b_compress));
arc_buf_free_on_write(hdr->b_l1hdr.b_tmp_cdata,
hdr->b_size, zio_data_buf_free);
@@ -4250,6 +4246,36 @@ top:
if (HDR_IO_IN_PROGRESS(hdr)) {
+ if ((hdr->b_flags & ARC_FLAG_PRIO_ASYNC_READ) &&
+ priority == ZIO_PRIORITY_SYNC_READ) {
+ /*
+ * This sync read must wait for an
+ * in-progress async read (e.g. a predictive
+ * prefetch). Async reads are queued
+ * separately at the vdev_queue layer, so
+ * this is a form of priority inversion.
+ * Ideally, we would "inherit" the demand
+ * i/o's priority by moving the i/o from
+ * the async queue to the synchronous queue,
+ * but there is currently no mechanism to do
+ * so. Track this so that we can evaluate
+ * the magnitude of this potential performance
+ * problem.
+ *
+ * Note that if the prefetch i/o is already
+ * active (has been issued to the device),
+ * the prefetch improved performance, because
+ * we issued it sooner than we would have
+ * without the prefetch.
+ */
+ DTRACE_PROBE1(arc__sync__wait__for__async,
+ arc_buf_hdr_t *, hdr);
+ ARCSTAT_BUMP(arcstat_sync_wait_for_async);
+ }
+ if (hdr->b_flags & ARC_FLAG_PREDICTIVE_PREFETCH) {
+ hdr->b_flags &= ~ARC_FLAG_PREDICTIVE_PREFETCH;
+ }
+
if (*arc_flags & ARC_FLAG_WAIT) {
cv_wait(&hdr->b_l1hdr.b_cv, hash_lock);
mutex_exit(hash_lock);
@@ -4258,7 +4284,7 @@ top:
ASSERT(*arc_flags & ARC_FLAG_NOWAIT);
if (done) {
- arc_callback_t *acb = NULL;
+ arc_callback_t *acb = NULL;
acb = kmem_zalloc(sizeof (arc_callback_t),
KM_SLEEP);
@@ -4283,6 +4309,19 @@ top:
hdr->b_l1hdr.b_state == arc_mfu);
if (done) {
+ if (hdr->b_flags & ARC_FLAG_PREDICTIVE_PREFETCH) {
+ /*
+ * This is a demand read which does not have to
+ * wait for i/o because we did a predictive
+ * prefetch i/o for it, which has completed.
+ */
+ DTRACE_PROBE1(
+ arc__demand__hit__predictive__prefetch,
+ arc_buf_hdr_t *, hdr);
+ ARCSTAT_BUMP(
+ arcstat_demand_hit_predictive_prefetch);
+ hdr->b_flags &= ~ARC_FLAG_PREDICTIVE_PREFETCH;
+ }
add_reference(hdr, hash_lock, private);
/*
* If this block is already in use, create a new
@@ -4345,12 +4384,16 @@ top:
goto top; /* restart the IO request */
}
- /* if this is a prefetch, we don't have a reference */
- if (*arc_flags & ARC_FLAG_PREFETCH) {
+ /*
+ * If there is a callback, we pass our reference to
+ * it; otherwise we remove our reference.
+ */
+ if (done == NULL) {
(void) remove_reference(hdr, hash_lock,
private);
- hdr->b_flags |= ARC_FLAG_PREFETCH;
}
+ if (*arc_flags & ARC_FLAG_PREFETCH)
+ hdr->b_flags |= ARC_FLAG_PREFETCH;
if (*arc_flags & ARC_FLAG_L2CACHE)
hdr->b_flags |= ARC_FLAG_L2CACHE;
if (*arc_flags & ARC_FLAG_L2COMPRESS)
@@ -4373,11 +4416,13 @@ top:
ASSERT(refcount_is_zero(&hdr->b_l1hdr.b_refcnt));
ASSERT3P(hdr->b_l1hdr.b_buf, ==, NULL);
- /* if this is a prefetch, we don't have a reference */
+ /*
+ * If there is a callback, we pass a reference to it.
+ */
+ if (done != NULL)
+ add_reference(hdr, hash_lock, private);
if (*arc_flags & ARC_FLAG_PREFETCH)
hdr->b_flags |= ARC_FLAG_PREFETCH;
- else
- add_reference(hdr, hash_lock, private);
if (*arc_flags & ARC_FLAG_L2CACHE)
hdr->b_flags |= ARC_FLAG_L2CACHE;
if (*arc_flags & ARC_FLAG_L2COMPRESS)
@@ -4395,6 +4440,8 @@ top:
arc_access(hdr, hash_lock);
}
+ if (*arc_flags & ARC_FLAG_PREDICTIVE_PREFETCH)
+ hdr->b_flags |= ARC_FLAG_PREDICTIVE_PREFETCH;
ASSERT(!GHOST_STATE(hdr->b_l1hdr.b_state));
acb = kmem_zalloc(sizeof (arc_callback_t), KM_SLEEP);
@@ -4409,7 +4456,7 @@ top:
(vd = hdr->b_l2hdr.b_dev->l2ad_vdev) != NULL) {
devw = hdr->b_l2hdr.b_dev->l2ad_writing;
addr = hdr->b_l2hdr.b_daddr;
- b_compress = HDR_GET_COMPRESS(hdr);
+ b_compress = hdr->b_l2hdr.b_compress;
b_asize = hdr->b_l2hdr.b_asize;
/*
* Lock out device removal.
@@ -4437,6 +4484,11 @@ top:
curthread->td_ru.ru_inblock++;
#endif
+ if (priority == ZIO_PRIORITY_ASYNC_READ)
+ hdr->b_flags |= ARC_FLAG_PRIO_ASYNC_READ;
+ else
+ hdr->b_flags &= ~ARC_FLAG_PRIO_ASYNC_READ;
+
if (vd != NULL && l2arc_ndev != 0 && !(l2arc_norw && devw)) {
/*
* Read from the L2ARC if the following are true:
@@ -5965,6 +6017,8 @@ l2arc_read_done(zio_t *zio)
if (cb->l2rcb_compress != ZIO_COMPRESS_OFF)
l2arc_decompress_zio(zio, hdr, cb->l2rcb_compress);
ASSERT(zio->io_data != NULL);
+ ASSERT3U(zio->io_size, ==, hdr->b_size);
+ ASSERT3U(BP_GET_LSIZE(&cb->l2rcb_bp), ==, hdr->b_size);
/*
* Check this survived the L2ARC journey.
@@ -6001,7 +6055,7 @@ l2arc_read_done(zio_t *zio)
ASSERT(!pio || pio->io_child_type == ZIO_CHILD_LOGICAL);
zio_nowait(zio_read(pio, cb->l2rcb_spa, &cb->l2rcb_bp,
- buf->b_data, zio->io_size, arc_read_done, buf,
+ buf->b_data, hdr->b_size, arc_read_done, buf,
zio->io_priority, cb->l2rcb_flags, &cb->l2rcb_zb));
}
}
@@ -6318,7 +6372,7 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz,
* can't access without holding the ARC list locks
* (which we want to avoid during compression/writing).
*/
- HDR_SET_COMPRESS(hdr, ZIO_COMPRESS_OFF);
+ hdr->b_l2hdr.b_compress = ZIO_COMPRESS_OFF;
hdr->b_l2hdr.b_asize = hdr->b_size;
hdr->b_l1hdr.b_tmp_cdata = hdr->b_l1hdr.b_buf->b_data;
@@ -6520,7 +6574,7 @@ l2arc_compress_buf(arc_buf_hdr_t *hdr)
l2arc_buf_hdr_t *l2hdr = &hdr->b_l2hdr;
ASSERT(HDR_HAS_L1HDR(hdr));
- ASSERT(HDR_GET_COMPRESS(hdr) == ZIO_COMPRESS_OFF);
+ ASSERT3S(l2hdr->b_compress, ==, ZIO_COMPRESS_OFF);
ASSERT(hdr->b_l1hdr.b_tmp_cdata != NULL);
len = l2hdr->b_asize;
@@ -6532,7 +6586,7 @@ l2arc_compress_buf(arc_buf_hdr_t *hdr)
if (csize == 0) {
/* zero block, indicate that there's nothing to write */
zio_data_buf_free(cdata, len);
- HDR_SET_COMPRESS(hdr, ZIO_COMPRESS_EMPTY);
+ l2hdr->b_compress = ZIO_COMPRESS_EMPTY;
l2hdr->b_asize = 0;
hdr->b_l1hdr.b_tmp_cdata = NULL;
ARCSTAT_BUMP(arcstat_l2_compress_zeros);
@@ -6550,7 +6604,7 @@ l2arc_compress_buf(arc_buf_hdr_t *hdr)
bzero((char *)cdata + csize, rounded - csize);
csize = rounded;
}
- HDR_SET_COMPRESS(hdr, ZIO_COMPRESS_LZ4);
+ l2hdr->b_compress = ZIO_COMPRESS_LZ4;
l2hdr->b_asize = csize;
hdr->b_l1hdr.b_tmp_cdata = cdata;
ARCSTAT_BUMP(arcstat_l2_compress_successes);
@@ -6637,7 +6691,8 @@ l2arc_decompress_zio(zio_t *zio, arc_buf_hdr_t *hdr, enum zio_compress c)
static void
l2arc_release_cdata_buf(arc_buf_hdr_t *hdr)
{
- enum zio_compress comp = HDR_GET_COMPRESS(hdr);
+ ASSERT(HDR_HAS_L2HDR(hdr));
+ enum zio_compress comp = hdr->b_l2hdr.b_compress;
ASSERT(HDR_HAS_L1HDR(hdr));
ASSERT(comp == ZIO_COMPRESS_OFF || L2ARC_IS_VALID_COMPRESS(comp));
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c
index 16d8a2e..4ca1356 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c
@@ -618,7 +618,7 @@ dbuf_read_done(zio_t *zio, arc_buf_t *buf, void *vdb)
}
static void
-dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags)
+dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
{
dnode_t *dn;
zbookmark_phys_t zb;
@@ -664,7 +664,6 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags)
db->db.db_size, db, type));
bzero(db->db.db_data, db->db.db_size);
db->db_state = DB_CACHED;
- *flags |= DB_RF_CACHED;
mutex_exit(&db->db_mtx);
return;
}
@@ -687,10 +686,8 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags)
(void) arc_read(zio, db->db_objset->os_spa, db->db_blkptr,
dbuf_read_done, db, ZIO_PRIORITY_SYNC_READ,
- (*flags & DB_RF_CANFAIL) ? ZIO_FLAG_CANFAIL : ZIO_FLAG_MUSTSUCCEED,
+ (flags & DB_RF_CANFAIL) ? ZIO_FLAG_CANFAIL : ZIO_FLAG_MUSTSUCCEED,
&aflags, &zb);
- if (aflags & ARC_FLAG_CACHED)
- *flags |= DB_RF_CACHED;
}
int
@@ -723,8 +720,7 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
if (db->db_state == DB_CACHED) {
mutex_exit(&db->db_mtx);
if (prefetch)
- dmu_zfetch(&dn->dn_zfetch, db->db.db_offset,
- db->db.db_size, TRUE);
+ dmu_zfetch(&dn->dn_zfetch, db->db_blkid, 1);
if ((flags & DB_RF_HAVESTRUCT) == 0)
rw_exit(&dn->dn_struct_rwlock);
DB_DNODE_EXIT(db);
@@ -733,13 +729,12 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
if (zio == NULL)
zio = zio_root(spa, NULL, NULL, ZIO_FLAG_CANFAIL);
- dbuf_read_impl(db, zio, &flags);
+ dbuf_read_impl(db, zio, flags);
/* dbuf_read_impl has dropped db_mtx for us */
if (prefetch)
- dmu_zfetch(&dn->dn_zfetch, db->db.db_offset,
- db->db.db_size, flags & DB_RF_CACHED);
+ dmu_zfetch(&dn->dn_zfetch, db->db_blkid, 1);
if ((flags & DB_RF_HAVESTRUCT) == 0)
rw_exit(&dn->dn_struct_rwlock);
@@ -758,8 +753,7 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
*/
mutex_exit(&db->db_mtx);
if (prefetch)
- dmu_zfetch(&dn->dn_zfetch, db->db.db_offset,
- db->db.db_size, TRUE);
+ dmu_zfetch(&dn->dn_zfetch, db->db_blkid, 1);
if ((flags & DB_RF_HAVESTRUCT) == 0)
rw_exit(&dn->dn_struct_rwlock);
DB_DNODE_EXIT(db);
@@ -2059,6 +2053,9 @@ dbuf_prefetch(dnode_t *dn, int64_t level, uint64_t blkid, zio_priority_t prio,
ASSERT(blkid != DMU_BONUS_BLKID);
ASSERT(RW_LOCK_HELD(&dn->dn_struct_rwlock));
+ if (blkid > dn->dn_maxblkid)
+ return;
+
if (dnode_block_freed(dn, blkid))
return;
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c
index 4a9e6c4..326b03e 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
*/
/* Copyright (c) 2013 by Saso Kiselkov. All rights reserved. */
/* Copyright (c) 2013, Joyent, Inc. All rights reserved. */
@@ -389,7 +389,7 @@ dmu_spill_hold_by_bonus(dmu_buf_t *bonus, void *tag, dmu_buf_t **dbp)
*/
static int
dmu_buf_hold_array_by_dnode(dnode_t *dn, uint64_t offset, uint64_t length,
- int read, void *tag, int *numbufsp, dmu_buf_t ***dbpp, uint32_t flags)
+ boolean_t read, void *tag, int *numbufsp, dmu_buf_t ***dbpp, uint32_t flags)
{
dmu_buf_t **dbp;
uint64_t blkid, nblks, i;
@@ -399,15 +399,19 @@ dmu_buf_hold_array_by_dnode(dnode_t *dn, uint64_t offset, uint64_t length,
ASSERT(length <= DMU_MAX_ACCESS);
- dbuf_flags = DB_RF_CANFAIL | DB_RF_NEVERWAIT | DB_RF_HAVESTRUCT;
- if (flags & DMU_READ_NO_PREFETCH || length > zfetch_array_rd_sz)
- dbuf_flags |= DB_RF_NOPREFETCH;
+ /*
+ * Note: We directly notify the prefetch code of this read, so that
+ * we can tell it about the multi-block read. dbuf_read() only knows
+ * about the one block it is accessing.
+ */
+ dbuf_flags = DB_RF_CANFAIL | DB_RF_NEVERWAIT | DB_RF_HAVESTRUCT |
+ DB_RF_NOPREFETCH;
rw_enter(&dn->dn_struct_rwlock, RW_READER);
if (dn->dn_datablkshift) {
int blkshift = dn->dn_datablkshift;
- nblks = (P2ROUNDUP(offset+length, 1ULL<<blkshift) -
- P2ALIGN(offset, 1ULL<<blkshift)) >> blkshift;
+ nblks = (P2ROUNDUP(offset + length, 1ULL << blkshift) -
+ P2ALIGN(offset, 1ULL << blkshift)) >> blkshift;
} else {
if (offset + length > dn->dn_datablksz) {
zfs_panic_recover("zfs: accessing past end of object "
@@ -426,13 +430,14 @@ dmu_buf_hold_array_by_dnode(dnode_t *dn, uint64_t offset, uint64_t length,
zio = zio_root(dn->dn_objset->os_spa, NULL, NULL, ZIO_FLAG_CANFAIL);
blkid = dbuf_whichblock(dn, 0, offset);
for (i = 0; i < nblks; i++) {
- dmu_buf_impl_t *db = dbuf_hold(dn, blkid+i, tag);
+ dmu_buf_impl_t *db = dbuf_hold(dn, blkid + i, tag);
if (db == NULL) {
rw_exit(&dn->dn_struct_rwlock);
dmu_buf_rele_array(dbp, nblks, tag);
zio_nowait(zio);
return (SET_ERROR(EIO));
}
+
/* initiate async i/o */
if (read)
(void) dbuf_read(db, zio, dbuf_flags);
@@ -442,6 +447,11 @@ dmu_buf_hold_array_by_dnode(dnode_t *dn, uint64_t offset, uint64_t length,
#endif
dbp[i] = &db->db;
}
+
+ if ((flags & DMU_READ_NO_PREFETCH) == 0 && read &&
+ length < zfetch_array_rd_sz) {
+ dmu_zfetch(&dn->dn_zfetch, blkid, nblks);
+ }
rw_exit(&dn->dn_struct_rwlock);
/* wait for async i/o */
@@ -495,7 +505,8 @@ dmu_buf_hold_array(objset_t *os, uint64_t object, uint64_t offset,
int
dmu_buf_hold_array_by_bonus(dmu_buf_t *db_fake, uint64_t offset,
- uint64_t length, int read, void *tag, int *numbufsp, dmu_buf_t ***dbpp)
+ uint64_t length, boolean_t read, void *tag, int *numbufsp,
+ dmu_buf_t ***dbpp)
{
dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
dnode_t *dn;
@@ -543,9 +554,6 @@ dmu_prefetch(objset_t *os, uint64_t object, int64_t level, uint64_t offset,
uint64_t blkid;
int nblks, err;
- if (zfs_prefetch_disable)
- return;
-
if (len == 0) { /* they're interested in the bonus buffer */
dn = DMU_META_DNODE(os);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_zfetch.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_zfetch.c
index 65ce914..47ac287 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_zfetch.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_zfetch.c
@@ -24,7 +24,7 @@
*/
/*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013, 2014 by Delphix. All rights reserved.
*/
#include <sys/zfs_context.h>
@@ -36,19 +36,20 @@
#include <sys/kstat.h>
/*
- * I'm against tune-ables, but these should probably exist as tweakable globals
- * until we can get this working the way we want it to.
+ * This tunable disables predictive prefetch. Note that it leaves "prescient"
+ * prefetch (e.g. prefetch for zfs send) intact. Unlike predictive prefetch,
+ * prescient prefetch never issues i/os that end up not being needed,
+ * so it can't hurt performance.
*/
-
-int zfs_prefetch_disable = 0;
+boolean_t zfs_prefetch_disable = B_FALSE;
/* max # of streams per zfetch */
uint32_t zfetch_max_streams = 8;
/* min time before stream reclaim */
uint32_t zfetch_min_sec_reap = 2;
-/* max number of blocks to fetch at a time */
-uint32_t zfetch_block_cap = 256;
-/* number of bytes in a array_read at which we stop prefetching (1Mb) */
+/* max bytes to prefetch per stream (default 8MB) */
+uint32_t zfetch_max_distance = 8 * 1024 * 1024;
+/* number of bytes in a array_read at which we stop prefetching (1MB) */
uint64_t zfetch_array_rd_sz = 1024 * 1024;
SYSCTL_DECL(_vfs_zfs);
@@ -59,198 +60,32 @@ SYSCTL_UINT(_vfs_zfs_zfetch, OID_AUTO, max_streams, CTLFLAG_RWTUN,
&zfetch_max_streams, 0, "Max # of streams per zfetch");
SYSCTL_UINT(_vfs_zfs_zfetch, OID_AUTO, min_sec_reap, CTLFLAG_RWTUN,
&zfetch_min_sec_reap, 0, "Min time before stream reclaim");
-SYSCTL_UINT(_vfs_zfs_zfetch, OID_AUTO, block_cap, CTLFLAG_RWTUN,
- &zfetch_block_cap, 0, "Max number of blocks to fetch at a time");
+SYSCTL_UINT(_vfs_zfs_zfetch, OID_AUTO, max_distance, CTLFLAG_RWTUN,
+ &zfetch_max_distance, 0, "Max bytes to prefetch per stream");
SYSCTL_UQUAD(_vfs_zfs_zfetch, OID_AUTO, array_rd_sz, CTLFLAG_RWTUN,
&zfetch_array_rd_sz, 0,
"Number of bytes in a array_read at which we stop prefetching");
-/* forward decls for static routines */
-static boolean_t dmu_zfetch_colinear(zfetch_t *, zstream_t *);
-static void dmu_zfetch_dofetch(zfetch_t *, zstream_t *);
-static uint64_t dmu_zfetch_fetch(dnode_t *, uint64_t, uint64_t);
-static uint64_t dmu_zfetch_fetchsz(dnode_t *, uint64_t, uint64_t);
-static boolean_t dmu_zfetch_find(zfetch_t *, zstream_t *, int);
-static int dmu_zfetch_stream_insert(zfetch_t *, zstream_t *);
-static zstream_t *dmu_zfetch_stream_reclaim(zfetch_t *);
-static void dmu_zfetch_stream_remove(zfetch_t *, zstream_t *);
-static int dmu_zfetch_streams_equal(zstream_t *, zstream_t *);
-
typedef struct zfetch_stats {
kstat_named_t zfetchstat_hits;
kstat_named_t zfetchstat_misses;
- kstat_named_t zfetchstat_colinear_hits;
- kstat_named_t zfetchstat_colinear_misses;
- kstat_named_t zfetchstat_stride_hits;
- kstat_named_t zfetchstat_stride_misses;
- kstat_named_t zfetchstat_reclaim_successes;
- kstat_named_t zfetchstat_reclaim_failures;
- kstat_named_t zfetchstat_stream_resets;
- kstat_named_t zfetchstat_stream_noresets;
- kstat_named_t zfetchstat_bogus_streams;
+ kstat_named_t zfetchstat_max_streams;
} zfetch_stats_t;
static zfetch_stats_t zfetch_stats = {
{ "hits", KSTAT_DATA_UINT64 },
{ "misses", KSTAT_DATA_UINT64 },
- { "colinear_hits", KSTAT_DATA_UINT64 },
- { "colinear_misses", KSTAT_DATA_UINT64 },
- { "stride_hits", KSTAT_DATA_UINT64 },
- { "stride_misses", KSTAT_DATA_UINT64 },
- { "reclaim_successes", KSTAT_DATA_UINT64 },
- { "reclaim_failures", KSTAT_DATA_UINT64 },
- { "streams_resets", KSTAT_DATA_UINT64 },
- { "streams_noresets", KSTAT_DATA_UINT64 },
- { "bogus_streams", KSTAT_DATA_UINT64 },
+ { "max_streams", KSTAT_DATA_UINT64 },
};
-#define ZFETCHSTAT_INCR(stat, val) \
- atomic_add_64(&zfetch_stats.stat.value.ui64, (val));
-
-#define ZFETCHSTAT_BUMP(stat) ZFETCHSTAT_INCR(stat, 1);
+#define ZFETCHSTAT_BUMP(stat) \
+ atomic_inc_64(&zfetch_stats.stat.value.ui64);
kstat_t *zfetch_ksp;
-/*
- * Given a zfetch structure and a zstream structure, determine whether the
- * blocks to be read are part of a co-linear pair of existing prefetch
- * streams. If a set is found, coalesce the streams, removing one, and
- * configure the prefetch so it looks for a strided access pattern.
- *
- * In other words: if we find two sequential access streams that are
- * the same length and distance N appart, and this read is N from the
- * last stream, then we are probably in a strided access pattern. So
- * combine the two sequential streams into a single strided stream.
- *
- * Returns whether co-linear streams were found.
- */
-static boolean_t
-dmu_zfetch_colinear(zfetch_t *zf, zstream_t *zh)
-{
- zstream_t *z_walk;
- zstream_t *z_comp;
-
- if (! rw_tryenter(&zf->zf_rwlock, RW_WRITER))
- return (0);
-
- if (zh == NULL) {
- rw_exit(&zf->zf_rwlock);
- return (0);
- }
-
- for (z_walk = list_head(&zf->zf_stream); z_walk;
- z_walk = list_next(&zf->zf_stream, z_walk)) {
- for (z_comp = list_next(&zf->zf_stream, z_walk); z_comp;
- z_comp = list_next(&zf->zf_stream, z_comp)) {
- int64_t diff;
-
- if (z_walk->zst_len != z_walk->zst_stride ||
- z_comp->zst_len != z_comp->zst_stride) {
- continue;
- }
-
- diff = z_comp->zst_offset - z_walk->zst_offset;
- if (z_comp->zst_offset + diff == zh->zst_offset) {
- z_walk->zst_offset = zh->zst_offset;
- z_walk->zst_direction = diff < 0 ? -1 : 1;
- z_walk->zst_stride =
- diff * z_walk->zst_direction;
- z_walk->zst_ph_offset =
- zh->zst_offset + z_walk->zst_stride;
- dmu_zfetch_stream_remove(zf, z_comp);
- mutex_destroy(&z_comp->zst_lock);
- kmem_free(z_comp, sizeof (zstream_t));
-
- dmu_zfetch_dofetch(zf, z_walk);
-
- rw_exit(&zf->zf_rwlock);
- return (1);
- }
-
- diff = z_walk->zst_offset - z_comp->zst_offset;
- if (z_walk->zst_offset + diff == zh->zst_offset) {
- z_walk->zst_offset = zh->zst_offset;
- z_walk->zst_direction = diff < 0 ? -1 : 1;
- z_walk->zst_stride =
- diff * z_walk->zst_direction;
- z_walk->zst_ph_offset =
- zh->zst_offset + z_walk->zst_stride;
- dmu_zfetch_stream_remove(zf, z_comp);
- mutex_destroy(&z_comp->zst_lock);
- kmem_free(z_comp, sizeof (zstream_t));
-
- dmu_zfetch_dofetch(zf, z_walk);
-
- rw_exit(&zf->zf_rwlock);
- return (1);
- }
- }
- }
-
- rw_exit(&zf->zf_rwlock);
- return (0);
-}
-
-/*
- * Given a zstream_t, determine the bounds of the prefetch. Then call the
- * routine that actually prefetches the individual blocks.
- */
-static void
-dmu_zfetch_dofetch(zfetch_t *zf, zstream_t *zs)
-{
- uint64_t prefetch_tail;
- uint64_t prefetch_limit;
- uint64_t prefetch_ofst;
- uint64_t prefetch_len;
- uint64_t blocks_fetched;
-
- zs->zst_stride = MAX((int64_t)zs->zst_stride, zs->zst_len);
- zs->zst_cap = MIN(zfetch_block_cap, 2 * zs->zst_cap);
-
- prefetch_tail = MAX((int64_t)zs->zst_ph_offset,
- (int64_t)(zs->zst_offset + zs->zst_stride));
- /*
- * XXX: use a faster division method?
- */
- prefetch_limit = zs->zst_offset + zs->zst_len +
- (zs->zst_cap * zs->zst_stride) / zs->zst_len;
-
- while (prefetch_tail < prefetch_limit) {
- prefetch_ofst = zs->zst_offset + zs->zst_direction *
- (prefetch_tail - zs->zst_offset);
-
- prefetch_len = zs->zst_len;
-
- /*
- * Don't prefetch beyond the end of the file, if working
- * backwards.
- */
- if ((zs->zst_direction == ZFETCH_BACKWARD) &&
- (prefetch_ofst > prefetch_tail)) {
- prefetch_len += prefetch_ofst;
- prefetch_ofst = 0;
- }
-
- /* don't prefetch more than we're supposed to */
- if (prefetch_len > zs->zst_len)
- break;
-
- blocks_fetched = dmu_zfetch_fetch(zf->zf_dnode,
- prefetch_ofst, zs->zst_len);
-
- prefetch_tail += zs->zst_stride;
- /* stop if we've run out of stuff to prefetch */
- if (blocks_fetched < zs->zst_len)
- break;
- }
- zs->zst_ph_offset = prefetch_tail;
- zs->zst_last = ddi_get_lbolt();
-}
-
void
zfetch_init(void)
{
-
zfetch_ksp = kstat_create("zfs", 0, "zfetchstats", "misc",
KSTAT_TYPE_NAMED, sizeof (zfetch_stats) / sizeof (kstat_named_t),
KSTAT_FLAG_VIRTUAL);
@@ -278,285 +113,41 @@ zfetch_fini(void)
void
dmu_zfetch_init(zfetch_t *zf, dnode_t *dno)
{
- if (zf == NULL) {
+ if (zf == NULL)
return;
- }
zf->zf_dnode = dno;
- zf->zf_stream_cnt = 0;
- zf->zf_alloc_fail = 0;
list_create(&zf->zf_stream, sizeof (zstream_t),
- offsetof(zstream_t, zst_node));
+ offsetof(zstream_t, zs_node));
rw_init(&zf->zf_rwlock, NULL, RW_DEFAULT, NULL);
}
-/*
- * This function computes the actual size, in blocks, that can be prefetched,
- * and fetches it.
- */
-static uint64_t
-dmu_zfetch_fetch(dnode_t *dn, uint64_t blkid, uint64_t nblks)
-{
- uint64_t fetchsz;
- uint64_t i;
-
- fetchsz = dmu_zfetch_fetchsz(dn, blkid, nblks);
-
- for (i = 0; i < fetchsz; i++) {
- dbuf_prefetch(dn, 0, blkid + i, ZIO_PRIORITY_ASYNC_READ,
- ARC_FLAG_PREFETCH);
- }
-
- return (fetchsz);
-}
-
-/*
- * this function returns the number of blocks that would be prefetched, based
- * upon the supplied dnode, blockid, and nblks. This is used so that we can
- * update streams in place, and then prefetch with their old value after the
- * fact. This way, we can delay the prefetch, but subsequent accesses to the
- * stream won't result in the same data being prefetched multiple times.
- */
-static uint64_t
-dmu_zfetch_fetchsz(dnode_t *dn, uint64_t blkid, uint64_t nblks)
-{
- uint64_t fetchsz;
-
- if (blkid > dn->dn_maxblkid) {
- return (0);
- }
-
- /* compute fetch size */
- if (blkid + nblks + 1 > dn->dn_maxblkid) {
- fetchsz = (dn->dn_maxblkid - blkid) + 1;
- ASSERT(blkid + fetchsz - 1 <= dn->dn_maxblkid);
- } else {
- fetchsz = nblks;
- }
-
-
- return (fetchsz);
-}
-
-/*
- * given a zfetch and a zstream structure, see if there is an associated zstream
- * for this block read. If so, it starts a prefetch for the stream it
- * located and returns true, otherwise it returns false
- */
-static boolean_t
-dmu_zfetch_find(zfetch_t *zf, zstream_t *zh, int prefetched)
+static void
+dmu_zfetch_stream_remove(zfetch_t *zf, zstream_t *zs)
{
- zstream_t *zs;
- int64_t diff;
- int reset = !prefetched;
- int rc = 0;
-
- if (zh == NULL)
- return (0);
-
- /*
- * XXX: This locking strategy is a bit coarse; however, it's impact has
- * yet to be tested. If this turns out to be an issue, it can be
- * modified in a number of different ways.
- */
-
- rw_enter(&zf->zf_rwlock, RW_READER);
-top:
-
- for (zs = list_head(&zf->zf_stream); zs;
- zs = list_next(&zf->zf_stream, zs)) {
-
- /*
- * XXX - should this be an assert?
- */
- if (zs->zst_len == 0) {
- /* bogus stream */
- ZFETCHSTAT_BUMP(zfetchstat_bogus_streams);
- continue;
- }
-
- /*
- * We hit this case when we are in a strided prefetch stream:
- * we will read "len" blocks before "striding".
- */
- if (zh->zst_offset >= zs->zst_offset &&
- zh->zst_offset < zs->zst_offset + zs->zst_len) {
- if (prefetched) {
- /* already fetched */
- ZFETCHSTAT_BUMP(zfetchstat_stride_hits);
- rc = 1;
- goto out;
- } else {
- ZFETCHSTAT_BUMP(zfetchstat_stride_misses);
- }
- }
-
- /*
- * This is the forward sequential read case: we increment
- * len by one each time we hit here, so we will enter this
- * case on every read.
- */
- if (zh->zst_offset == zs->zst_offset + zs->zst_len) {
-
- reset = !prefetched && zs->zst_len > 1;
-
- if (mutex_tryenter(&zs->zst_lock) == 0) {
- rc = 1;
- goto out;
- }
-
- if (zh->zst_offset != zs->zst_offset + zs->zst_len) {
- mutex_exit(&zs->zst_lock);
- goto top;
- }
- zs->zst_len += zh->zst_len;
- diff = zs->zst_len - zfetch_block_cap;
- if (diff > 0) {
- zs->zst_offset += diff;
- zs->zst_len = zs->zst_len > diff ?
- zs->zst_len - diff : 0;
- }
- zs->zst_direction = ZFETCH_FORWARD;
-
- break;
-
- /*
- * Same as above, but reading backwards through the file.
- */
- } else if (zh->zst_offset == zs->zst_offset - zh->zst_len) {
- /* backwards sequential access */
-
- reset = !prefetched && zs->zst_len > 1;
-
- if (mutex_tryenter(&zs->zst_lock) == 0) {
- rc = 1;
- goto out;
- }
-
- if (zh->zst_offset != zs->zst_offset - zh->zst_len) {
- mutex_exit(&zs->zst_lock);
- goto top;
- }
-
- zs->zst_offset = zs->zst_offset > zh->zst_len ?
- zs->zst_offset - zh->zst_len : 0;
- zs->zst_ph_offset = zs->zst_ph_offset > zh->zst_len ?
- zs->zst_ph_offset - zh->zst_len : 0;
- zs->zst_len += zh->zst_len;
-
- diff = zs->zst_len - zfetch_block_cap;
- if (diff > 0) {
- zs->zst_ph_offset = zs->zst_ph_offset > diff ?
- zs->zst_ph_offset - diff : 0;
- zs->zst_len = zs->zst_len > diff ?
- zs->zst_len - diff : zs->zst_len;
- }
- zs->zst_direction = ZFETCH_BACKWARD;
-
- break;
-
- } else if ((zh->zst_offset - zs->zst_offset - zs->zst_stride <
- zs->zst_len) && (zs->zst_len != zs->zst_stride)) {
- /* strided forward access */
-
- if (mutex_tryenter(&zs->zst_lock) == 0) {
- rc = 1;
- goto out;
- }
-
- if ((zh->zst_offset - zs->zst_offset - zs->zst_stride >=
- zs->zst_len) || (zs->zst_len == zs->zst_stride)) {
- mutex_exit(&zs->zst_lock);
- goto top;
- }
-
- zs->zst_offset += zs->zst_stride;
- zs->zst_direction = ZFETCH_FORWARD;
-
- break;
-
- } else if ((zh->zst_offset - zs->zst_offset + zs->zst_stride <
- zs->zst_len) && (zs->zst_len != zs->zst_stride)) {
- /* strided reverse access */
-
- if (mutex_tryenter(&zs->zst_lock) == 0) {
- rc = 1;
- goto out;
- }
-
- if ((zh->zst_offset - zs->zst_offset + zs->zst_stride >=
- zs->zst_len) || (zs->zst_len == zs->zst_stride)) {
- mutex_exit(&zs->zst_lock);
- goto top;
- }
-
- zs->zst_offset = zs->zst_offset > zs->zst_stride ?
- zs->zst_offset - zs->zst_stride : 0;
- zs->zst_ph_offset = (zs->zst_ph_offset >
- (2 * zs->zst_stride)) ?
- (zs->zst_ph_offset - (2 * zs->zst_stride)) : 0;
- zs->zst_direction = ZFETCH_BACKWARD;
-
- break;
- }
- }
-
- if (zs) {
- if (reset) {
- zstream_t *remove = zs;
-
- ZFETCHSTAT_BUMP(zfetchstat_stream_resets);
- rc = 0;
- mutex_exit(&zs->zst_lock);
- rw_exit(&zf->zf_rwlock);
- rw_enter(&zf->zf_rwlock, RW_WRITER);
- /*
- * Relocate the stream, in case someone removes
- * it while we were acquiring the WRITER lock.
- */
- for (zs = list_head(&zf->zf_stream); zs;
- zs = list_next(&zf->zf_stream, zs)) {
- if (zs == remove) {
- dmu_zfetch_stream_remove(zf, zs);
- mutex_destroy(&zs->zst_lock);
- kmem_free(zs, sizeof (zstream_t));
- break;
- }
- }
- } else {
- ZFETCHSTAT_BUMP(zfetchstat_stream_noresets);
- rc = 1;
- dmu_zfetch_dofetch(zf, zs);
- mutex_exit(&zs->zst_lock);
- }
- }
-out:
- rw_exit(&zf->zf_rwlock);
- return (rc);
+ ASSERT(RW_WRITE_HELD(&zf->zf_rwlock));
+ list_remove(&zf->zf_stream, zs);
+ mutex_destroy(&zs->zs_lock);
+ kmem_free(zs, sizeof (*zs));
}
/*
- * Clean-up state associated with a zfetch structure. This frees allocated
- * structure members, empties the zf_stream tree, and generally makes things
- * nice. This doesn't free the zfetch_t itself, that's left to the caller.
+ * Clean-up state associated with a zfetch structure (e.g. destroy the
+ * streams). This doesn't free the zfetch_t itself, that's left to the caller.
*/
void
-dmu_zfetch_rele(zfetch_t *zf)
+dmu_zfetch_fini(zfetch_t *zf)
{
- zstream_t *zs;
- zstream_t *zs_next;
+ zstream_t *zs;
ASSERT(!RW_LOCK_HELD(&zf->zf_rwlock));
- for (zs = list_head(&zf->zf_stream); zs; zs = zs_next) {
- zs_next = list_next(&zf->zf_stream, zs);
-
- list_remove(&zf->zf_stream, zs);
- mutex_destroy(&zs->zst_lock);
- kmem_free(zs, sizeof (zstream_t));
- }
+ rw_enter(&zf->zf_rwlock, RW_WRITER);
+ while ((zs = list_head(&zf->zf_stream)) != NULL)
+ dmu_zfetch_stream_remove(zf, zs);
+ rw_exit(&zf->zf_rwlock);
list_destroy(&zf->zf_stream);
rw_destroy(&zf->zf_rwlock);
@@ -564,103 +155,55 @@ dmu_zfetch_rele(zfetch_t *zf)
}
/*
- * Given a zfetch and zstream structure, insert the zstream structure into the
- * AVL tree contained within the zfetch structure. Peform the appropriate
- * book-keeping. It is possible that another thread has inserted a stream which
- * matches one that we are about to insert, so we must be sure to check for this
- * case. If one is found, return failure, and let the caller cleanup the
- * duplicates.
+ * If there aren't too many streams already, create a new stream.
+ * The "blkid" argument is the next block that we expect this stream to access.
+ * While we're here, clean up old streams (which haven't been
+ * accessed for at least zfetch_min_sec_reap seconds).
*/
-static int
-dmu_zfetch_stream_insert(zfetch_t *zf, zstream_t *zs)
+static void
+dmu_zfetch_stream_create(zfetch_t *zf, uint64_t blkid)
{
- zstream_t *zs_walk;
- zstream_t *zs_next;
+ zstream_t *zs_next;
+ int numstreams = 0;
ASSERT(RW_WRITE_HELD(&zf->zf_rwlock));
- for (zs_walk = list_head(&zf->zf_stream); zs_walk; zs_walk = zs_next) {
- zs_next = list_next(&zf->zf_stream, zs_walk);
-
- if (dmu_zfetch_streams_equal(zs_walk, zs)) {
- return (0);
- }
- }
-
- list_insert_head(&zf->zf_stream, zs);
- zf->zf_stream_cnt++;
- return (1);
-}
-
-
-/*
- * Walk the list of zstreams in the given zfetch, find an old one (by time), and
- * reclaim it for use by the caller.
- */
-static zstream_t *
-dmu_zfetch_stream_reclaim(zfetch_t *zf)
-{
- zstream_t *zs;
- clock_t ticks;
-
- ticks = zfetch_min_sec_reap * hz;
- if (! rw_tryenter(&zf->zf_rwlock, RW_WRITER))
- return (0);
-
- for (zs = list_head(&zf->zf_stream); zs;
- zs = list_next(&zf->zf_stream, zs)) {
-
- if (ddi_get_lbolt() - zs->zst_last > ticks)
- break;
+ /*
+ * Clean up old streams.
+ */
+ for (zstream_t *zs = list_head(&zf->zf_stream);
+ zs != NULL; zs = zs_next) {
+ zs_next = list_next(&zf->zf_stream, zs);
+ if (((gethrtime() - zs->zs_atime) / NANOSEC) >
+ zfetch_min_sec_reap)
+ dmu_zfetch_stream_remove(zf, zs);
+ else
+ numstreams++;
}
- if (zs) {
- dmu_zfetch_stream_remove(zf, zs);
- mutex_destroy(&zs->zst_lock);
- bzero(zs, sizeof (zstream_t));
- } else {
- zf->zf_alloc_fail++;
+ /*
+ * The maximum number of streams is normally zfetch_max_streams,
+ * but for small files we lower it such that it's at least possible
+ * for all the streams to be non-overlapping.
+ *
+ * If we are already at the maximum number of streams for this file,
+ * even after removing old streams, then don't create this stream.
+ */
+ uint32_t max_streams = MAX(1, MIN(zfetch_max_streams,
+ zf->zf_dnode->dn_maxblkid * zf->zf_dnode->dn_datablksz /
+ zfetch_max_distance));
+ if (numstreams >= max_streams) {
+ ZFETCHSTAT_BUMP(zfetchstat_max_streams);
+ return;
}
- rw_exit(&zf->zf_rwlock);
-
- return (zs);
-}
-
-/*
- * Given a zfetch and zstream structure, remove the zstream structure from its
- * container in the zfetch structure. Perform the appropriate book-keeping.
- */
-static void
-dmu_zfetch_stream_remove(zfetch_t *zf, zstream_t *zs)
-{
- ASSERT(RW_WRITE_HELD(&zf->zf_rwlock));
-
- list_remove(&zf->zf_stream, zs);
- zf->zf_stream_cnt--;
-}
-
-static int
-dmu_zfetch_streams_equal(zstream_t *zs1, zstream_t *zs2)
-{
- if (zs1->zst_offset != zs2->zst_offset)
- return (0);
- if (zs1->zst_len != zs2->zst_len)
- return (0);
+ zstream_t *zs = kmem_zalloc(sizeof (*zs), KM_SLEEP);
+ zs->zs_blkid = blkid;
+ zs->zs_pf_blkid = blkid;
+ zs->zs_atime = gethrtime();
+ mutex_init(&zs->zs_lock, NULL, MUTEX_DEFAULT, NULL);
- if (zs1->zst_stride != zs2->zst_stride)
- return (0);
-
- if (zs1->zst_ph_offset != zs2->zst_ph_offset)
- return (0);
-
- if (zs1->zst_cap != zs2->zst_cap)
- return (0);
-
- if (zs1->zst_direction != zs2->zst_direction)
- return (0);
-
- return (1);
+ list_insert_head(&zf->zf_stream, zs);
}
/*
@@ -668,91 +211,86 @@ dmu_zfetch_streams_equal(zstream_t *zs1, zstream_t *zs2)
* routines to create, delete, find, or operate upon prefetch streams.
*/
void
-dmu_zfetch(zfetch_t *zf, uint64_t offset, uint64_t size, int prefetched)
+dmu_zfetch(zfetch_t *zf, uint64_t blkid, uint64_t nblks)
{
- zstream_t zst;
- zstream_t *newstream;
- boolean_t fetched;
- int inserted;
- unsigned int blkshft;
- uint64_t blksz;
+ zstream_t *zs;
if (zfs_prefetch_disable)
return;
- /* files that aren't ln2 blocksz are only one block -- nothing to do */
- if (!zf->zf_dnode->dn_datablkshift)
+ /*
+ * As a fast path for small (single-block) files, ignore access
+ * to the first block.
+ */
+ if (blkid == 0)
return;
- /* convert offset and size, into blockid and nblocks */
- blkshft = zf->zf_dnode->dn_datablkshift;
- blksz = (1 << blkshft);
-
- bzero(&zst, sizeof (zstream_t));
- zst.zst_offset = offset >> blkshft;
- zst.zst_len = (P2ROUNDUP(offset + size, blksz) -
- P2ALIGN(offset, blksz)) >> blkshft;
+ rw_enter(&zf->zf_rwlock, RW_READER);
- fetched = dmu_zfetch_find(zf, &zst, prefetched);
- if (fetched) {
- ZFETCHSTAT_BUMP(zfetchstat_hits);
- } else {
- ZFETCHSTAT_BUMP(zfetchstat_misses);
- fetched = dmu_zfetch_colinear(zf, &zst);
- if (fetched) {
- ZFETCHSTAT_BUMP(zfetchstat_colinear_hits);
- } else {
- ZFETCHSTAT_BUMP(zfetchstat_colinear_misses);
+ for (zs = list_head(&zf->zf_stream); zs != NULL;
+ zs = list_next(&zf->zf_stream, zs)) {
+ if (blkid == zs->zs_blkid) {
+ mutex_enter(&zs->zs_lock);
+ /*
+ * zs_blkid could have changed before we
+ * acquired zs_lock; re-check them here.
+ */
+ if (blkid != zs->zs_blkid) {
+ mutex_exit(&zs->zs_lock);
+ continue;
+ }
+ break;
}
}
- if (!fetched) {
- newstream = dmu_zfetch_stream_reclaim(zf);
-
+ if (zs == NULL) {
/*
- * we still couldn't find a stream, drop the lock, and allocate
- * one if possible. Otherwise, give up and go home.
+ * This access is not part of any existing stream. Create
+ * a new stream for it.
*/
- if (newstream) {
- ZFETCHSTAT_BUMP(zfetchstat_reclaim_successes);
- } else {
- uint64_t maxblocks;
- uint32_t max_streams;
- uint32_t cur_streams;
-
- ZFETCHSTAT_BUMP(zfetchstat_reclaim_failures);
- cur_streams = zf->zf_stream_cnt;
- maxblocks = zf->zf_dnode->dn_maxblkid;
-
- max_streams = MIN(zfetch_max_streams,
- (maxblocks / zfetch_block_cap));
- if (max_streams == 0) {
- max_streams++;
- }
-
- if (cur_streams >= max_streams) {
- return;
- }
- newstream = kmem_zalloc(sizeof (zstream_t), KM_SLEEP);
- }
+ ZFETCHSTAT_BUMP(zfetchstat_misses);
+ if (rw_tryupgrade(&zf->zf_rwlock))
+ dmu_zfetch_stream_create(zf, blkid + nblks);
+ rw_exit(&zf->zf_rwlock);
+ return;
+ }
- newstream->zst_offset = zst.zst_offset;
- newstream->zst_len = zst.zst_len;
- newstream->zst_stride = zst.zst_len;
- newstream->zst_ph_offset = zst.zst_len + zst.zst_offset;
- newstream->zst_cap = zst.zst_len;
- newstream->zst_direction = ZFETCH_FORWARD;
- newstream->zst_last = ddi_get_lbolt();
+ /*
+ * This access was to a block that we issued a prefetch for on
+ * behalf of this stream. Issue further prefetches for this stream.
+ *
+ * Normally, we start prefetching where we stopped
+ * prefetching last (zs_pf_blkid). But when we get our first
+ * hit on this stream, zs_pf_blkid == zs_blkid, we don't
+ * want to prefetch to block we just accessed. In this case,
+ * start just after the block we just accessed.
+ */
+ int64_t pf_start = MAX(zs->zs_pf_blkid, blkid + nblks);
- mutex_init(&newstream->zst_lock, NULL, MUTEX_DEFAULT, NULL);
+ /*
+ * Double our amount of prefetched data, but don't let the
+ * prefetch get further ahead than zfetch_max_distance.
+ */
+ int pf_nblks =
+ MIN((int64_t)zs->zs_pf_blkid - zs->zs_blkid + nblks,
+ zs->zs_blkid + nblks +
+ (zfetch_max_distance >> zf->zf_dnode->dn_datablkshift) - pf_start);
- rw_enter(&zf->zf_rwlock, RW_WRITER);
- inserted = dmu_zfetch_stream_insert(zf, newstream);
- rw_exit(&zf->zf_rwlock);
+ zs->zs_pf_blkid = pf_start + pf_nblks;
+ zs->zs_atime = gethrtime();
+ zs->zs_blkid = blkid + nblks;
- if (!inserted) {
- mutex_destroy(&newstream->zst_lock);
- kmem_free(newstream, sizeof (zstream_t));
- }
+ /*
+ * dbuf_prefetch() issues the prefetch i/o
+ * asynchronously, but it may need to wait for an
+ * indirect block to be read from disk. Therefore
+ * we do not want to hold any locks while we call it.
+ */
+ mutex_exit(&zs->zs_lock);
+ rw_exit(&zf->zf_rwlock);
+ for (int i = 0; i < pf_nblks; i++) {
+ dbuf_prefetch(zf->zf_dnode, 0, pf_start + i,
+ ZIO_PRIORITY_ASYNC_READ, ARC_FLAG_PREDICTIVE_PREFETCH);
}
+ ZFETCHSTAT_BUMP(zfetchstat_hits);
}
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode.c
index 0fdcde4..01f2d14 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode.c
@@ -526,7 +526,7 @@ dnode_destroy(dnode_t *dn)
dn->dn_id_flags = 0;
dn->dn_unlisted_l0_blkid = 0;
- dmu_zfetch_rele(&dn->dn_zfetch);
+ dmu_zfetch_fini(&dn->dn_zfetch);
kmem_cache_free(dnode_cache, dn);
arc_space_return(sizeof (dnode_t), ARC_SPACE_OTHER);
@@ -774,8 +774,6 @@ dnode_move_impl(dnode_t *odn, dnode_t *ndn)
dmu_zfetch_init(&ndn->dn_zfetch, NULL);
list_move_tail(&ndn->dn_zfetch.zf_stream, &odn->dn_zfetch.zf_stream);
ndn->dn_zfetch.zf_dnode = odn->dn_zfetch.zf_dnode;
- ndn->dn_zfetch.zf_stream_cnt = odn->dn_zfetch.zf_stream_cnt;
- ndn->dn_zfetch.zf_alloc_fail = odn->dn_zfetch.zf_alloc_fail;
/*
* Update back pointers. Updating the handle fixes the back pointer of
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
index d2085bb..61c83c1 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
@@ -22,7 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
- * Copyright (c) 2013, 2014, Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2015, Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
*/
@@ -1633,6 +1633,7 @@ load_nvlist(spa_t *spa, uint64_t obj, nvlist_t **value)
error = dmu_bonus_hold(spa->spa_meta_objset, obj, FTAG, &db);
if (error != 0)
return (error);
+
nvsize = *(uint64_t *)db->db_data;
dmu_buf_rele(db, FTAG);
@@ -3773,6 +3774,7 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
txg_wait_synced(spa->spa_dsl_pool, txg);
spa_config_sync(spa, B_FALSE, B_TRUE);
+ spa_event_notify(spa, NULL, ESC_ZFS_POOL_CREATE);
spa_history_log_version(spa, "create");
@@ -4233,6 +4235,7 @@ spa_import(const char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags)
spa_configfile_set(spa, props, B_FALSE);
spa_config_sync(spa, B_FALSE, B_TRUE);
+ spa_event_notify(spa, NULL, ESC_ZFS_POOL_IMPORT);
mutex_exit(&spa_namespace_lock);
return (0);
@@ -4363,9 +4366,12 @@ spa_import(const char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags)
*/
spa_async_request(spa, SPA_ASYNC_AUTOEXPAND);
- mutex_exit(&spa_namespace_lock);
spa_history_log_version(spa, "import");
+ spa_event_notify(spa, NULL, ESC_ZFS_POOL_IMPORT);
+
+ mutex_exit(&spa_namespace_lock);
+
#ifdef __FreeBSD__
#ifdef _KERNEL
zvol_create_minors(pool);
@@ -4711,6 +4717,7 @@ spa_vdev_add(spa_t *spa, nvlist_t *nvroot)
mutex_enter(&spa_namespace_lock);
spa_config_update(spa, SPA_CONFIG_UPDATE_POOL);
+ spa_event_notify(spa, NULL, ESC_ZFS_VDEV_ADD);
mutex_exit(&spa_namespace_lock);
return (0);
@@ -4905,6 +4912,11 @@ spa_vdev_attach(spa_t *spa, uint64_t guid, nvlist_t *nvroot, int replacing)
*/
dsl_resilver_restart(spa->spa_dsl_pool, dtl_max_txg);
+ if (spa->spa_bootfs)
+ spa_event_notify(spa, newvd, ESC_ZFS_BOOTFS_VDEV_ATTACH);
+
+ spa_event_notify(spa, newvd, ESC_ZFS_VDEV_ATTACH);
+
/*
* Commit the config
*/
@@ -4919,9 +4931,6 @@ spa_vdev_attach(spa_t *spa, uint64_t guid, nvlist_t *nvroot, int replacing)
spa_strfree(oldvdpath);
spa_strfree(newvdpath);
- if (spa->spa_bootfs)
- spa_event_notify(spa, newvd, ESC_ZFS_BOOTFS_VDEV_ATTACH);
-
return (0);
}
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/arc.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/arc.h
index a26d8f8..04a80f7 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/arc.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/arc.h
@@ -64,41 +64,30 @@ typedef enum arc_flags
ARC_FLAG_CACHED = 1 << 4, /* I/O was in cache */
ARC_FLAG_L2CACHE = 1 << 5, /* cache in L2ARC */
ARC_FLAG_L2COMPRESS = 1 << 6, /* compress in L2ARC */
+ ARC_FLAG_PREDICTIVE_PREFETCH = 1 << 7, /* I/O from zfetch */
/*
* Private ARC flags. These flags are private ARC only flags that
* will show up in b_flags in the arc_hdr_buf_t. These flags should
* only be set by ARC code.
*/
- ARC_FLAG_IN_HASH_TABLE = 1 << 7, /* buffer is hashed */
- ARC_FLAG_IO_IN_PROGRESS = 1 << 8, /* I/O in progress */
- ARC_FLAG_IO_ERROR = 1 << 9, /* I/O failed for buf */
- ARC_FLAG_FREED_IN_READ = 1 << 10, /* freed during read */
- ARC_FLAG_BUF_AVAILABLE = 1 << 11, /* block not in use */
- ARC_FLAG_INDIRECT = 1 << 12, /* indirect block */
- ARC_FLAG_L2_WRITING = 1 << 13, /* write in progress */
- ARC_FLAG_L2_EVICTED = 1 << 14, /* evicted during I/O */
- ARC_FLAG_L2_WRITE_HEAD = 1 << 15, /* head of write list */
+ ARC_FLAG_IN_HASH_TABLE = 1 << 8, /* buffer is hashed */
+ ARC_FLAG_IO_IN_PROGRESS = 1 << 9, /* I/O in progress */
+ ARC_FLAG_IO_ERROR = 1 << 10, /* I/O failed for buf */
+ ARC_FLAG_FREED_IN_READ = 1 << 11, /* freed during read */
+ ARC_FLAG_BUF_AVAILABLE = 1 << 12, /* block not in use */
+ ARC_FLAG_INDIRECT = 1 << 13, /* indirect block */
+ /* Indicates that block was read with ASYNC priority. */
+ ARC_FLAG_PRIO_ASYNC_READ = 1 << 14,
+ ARC_FLAG_L2_WRITING = 1 << 15, /* write in progress */
+ ARC_FLAG_L2_EVICTED = 1 << 16, /* evicted during I/O */
+ ARC_FLAG_L2_WRITE_HEAD = 1 << 17, /* head of write list */
/* indicates that the buffer contains metadata (otherwise, data) */
- ARC_FLAG_BUFC_METADATA = 1 << 16,
+ ARC_FLAG_BUFC_METADATA = 1 << 18,
/* Flags specifying whether optional hdr struct fields are defined */
- ARC_FLAG_HAS_L1HDR = 1 << 17,
- ARC_FLAG_HAS_L2HDR = 1 << 18,
-
- /*
- * The arc buffer's compression mode is stored in the top 7 bits of the
- * flags field, so these dummy flags are included so that MDB can
- * interpret the enum properly.
- */
- ARC_FLAG_COMPRESS_0 = 1 << 24,
- ARC_FLAG_COMPRESS_1 = 1 << 25,
- ARC_FLAG_COMPRESS_2 = 1 << 26,
- ARC_FLAG_COMPRESS_3 = 1 << 27,
- ARC_FLAG_COMPRESS_4 = 1 << 28,
- ARC_FLAG_COMPRESS_5 = 1 << 29,
- ARC_FLAG_COMPRESS_6 = 1 << 30
-
+ ARC_FLAG_HAS_L1HDR = 1 << 19,
+ ARC_FLAG_HAS_L2HDR = 1 << 20,
} arc_flags_t;
struct arc_buf {
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h
index 9ed311f..56f98ff 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h
@@ -492,7 +492,8 @@ uint64_t dmu_buf_refcount(dmu_buf_t *db);
* individually with dmu_buf_rele.
*/
int dmu_buf_hold_array_by_bonus(dmu_buf_t *db, uint64_t offset,
- uint64_t length, int read, void *tag, int *numbufsp, dmu_buf_t ***dbpp);
+ uint64_t length, boolean_t read, void *tag,
+ int *numbufsp, dmu_buf_t ***dbpp);
void dmu_buf_rele_array(dmu_buf_t **, int numbufs, void *tag);
typedef void dmu_buf_evict_func_t(void *user_ptr);
@@ -743,7 +744,7 @@ void dmu_xuio_clear(struct xuio *uio, int i);
void xuio_stat_wbuf_copied();
void xuio_stat_wbuf_nocopy();
-extern int zfs_prefetch_disable;
+extern boolean_t zfs_prefetch_disable;
extern int zfs_max_recordsize;
/*
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_zfetch.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_zfetch.h
index 78cadd2..6f61198 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_zfetch.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_zfetch.h
@@ -23,8 +23,12 @@
* Use is subject to license terms.
*/
-#ifndef _DFETCH_H
-#define _DFETCH_H
+/*
+ * Copyright (c) 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef _DMU_ZFETCH_H
+#define _DMU_ZFETCH_H
#include <sys/zfs_context.h>
@@ -36,41 +40,30 @@ extern uint64_t zfetch_array_rd_sz;
struct dnode; /* so we can reference dnode */
-typedef enum zfetch_dirn {
- ZFETCH_FORWARD = 1, /* prefetch increasing block numbers */
- ZFETCH_BACKWARD = -1 /* prefetch decreasing block numbers */
-} zfetch_dirn_t;
-
typedef struct zstream {
- uint64_t zst_offset; /* offset of starting block in range */
- uint64_t zst_len; /* length of range, in blocks */
- zfetch_dirn_t zst_direction; /* direction of prefetch */
- uint64_t zst_stride; /* length of stride, in blocks */
- uint64_t zst_ph_offset; /* prefetch offset, in blocks */
- uint64_t zst_cap; /* prefetch limit (cap), in blocks */
- kmutex_t zst_lock; /* protects stream */
- clock_t zst_last; /* lbolt of last prefetch */
- avl_node_t zst_node; /* embed avl node here */
+ uint64_t zs_blkid; /* expect next access at this blkid */
+ uint64_t zs_pf_blkid; /* next block to prefetch */
+ kmutex_t zs_lock; /* protects stream */
+ hrtime_t zs_atime; /* time last prefetch issued */
+ list_node_t zs_node; /* link for zf_stream */
} zstream_t;
typedef struct zfetch {
krwlock_t zf_rwlock; /* protects zfetch structure */
- list_t zf_stream; /* AVL tree of zstream_t's */
+ list_t zf_stream; /* list of zstream_t's */
struct dnode *zf_dnode; /* dnode that owns this zfetch */
- uint32_t zf_stream_cnt; /* # of active streams */
- uint64_t zf_alloc_fail; /* # of failed attempts to alloc strm */
} zfetch_t;
void zfetch_init(void);
void zfetch_fini(void);
void dmu_zfetch_init(zfetch_t *, struct dnode *);
-void dmu_zfetch_rele(zfetch_t *);
-void dmu_zfetch(zfetch_t *, uint64_t, uint64_t, int);
+void dmu_zfetch_fini(zfetch_t *);
+void dmu_zfetch(zfetch_t *, uint64_t, uint64_t);
#ifdef __cplusplus
}
#endif
-#endif /* _DFETCH_H */
+#endif /* _DMU_ZFETCH_H */
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev.c
index 663b395..a8f1c5f 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev.c
@@ -2503,6 +2503,7 @@ int
vdev_online(spa_t *spa, uint64_t guid, uint64_t flags, vdev_state_t *newstate)
{
vdev_t *vd, *tvd, *pvd, *rvd = spa->spa_root_vdev;
+ boolean_t postevent = B_FALSE;
spa_vdev_state_enter(spa, SCL_NONE);
@@ -2512,6 +2513,10 @@ vdev_online(spa_t *spa, uint64_t guid, uint64_t flags, vdev_state_t *newstate)
if (!vd->vdev_ops->vdev_op_leaf)
return (spa_vdev_state_exit(spa, NULL, ENOTSUP));
+ postevent =
+ (vd->vdev_offline == B_TRUE || vd->vdev_tmpoffline == B_TRUE) ?
+ B_TRUE : B_FALSE;
+
tvd = vd->vdev_top;
vd->vdev_offline = B_FALSE;
vd->vdev_tmpoffline = B_FALSE;
@@ -2547,6 +2552,10 @@ vdev_online(spa_t *spa, uint64_t guid, uint64_t flags, vdev_state_t *newstate)
return (spa_vdev_state_exit(spa, vd, ENOTSUP));
spa_async_request(spa, SPA_ASYNC_CONFIG_UPDATE);
}
+
+ if (postevent)
+ spa_event_notify(spa, vd, ESC_ZFS_VDEV_ONLINE);
+
return (spa_vdev_state_exit(spa, vd, 0));
}
diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/sysevent/eventdefs.h b/sys/cddl/contrib/opensolaris/uts/common/sys/sysevent/eventdefs.h
index 89bb06e..5760a85 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/sys/sysevent/eventdefs.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/sys/sysevent/eventdefs.h
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SYS_SYSEVENT_EVENTDEFS_H
@@ -249,9 +249,14 @@ extern "C" {
#define ESC_ZFS_RESILVER_START "ESC_ZFS_resilver_start"
#define ESC_ZFS_RESILVER_FINISH "ESC_ZFS_resilver_finish"
#define ESC_ZFS_VDEV_REMOVE "ESC_ZFS_vdev_remove"
+#define ESC_ZFS_POOL_CREATE "ESC_ZFS_pool_create"
#define ESC_ZFS_POOL_DESTROY "ESC_ZFS_pool_destroy"
+#define ESC_ZFS_POOL_IMPORT "ESC_ZFS_pool_import"
+#define ESC_ZFS_VDEV_ADD "ESC_ZFS_vdev_add"
+#define ESC_ZFS_VDEV_ATTACH "ESC_ZFS_vdev_attach"
#define ESC_ZFS_VDEV_CLEAR "ESC_ZFS_vdev_clear"
#define ESC_ZFS_VDEV_CHECK "ESC_ZFS_vdev_check"
+#define ESC_ZFS_VDEV_ONLINE "ESC_ZFS_vdev_online"
#define ESC_ZFS_CONFIG_SYNC "ESC_ZFS_config_sync"
#define ESC_ZFS_SCRUB_START "ESC_ZFS_scrub_start"
#define ESC_ZFS_SCRUB_FINISH "ESC_ZFS_scrub_finish"
diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
index 399a35e..bcbcf00 100644
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -59,6 +59,7 @@ dev/acpica/acpi_if.m optional acpi
dev/fdt/fdt_arm64.c optional fdt
dev/hwpmc/hwpmc_arm64.c optional hwpmc
dev/hwpmc/hwpmc_arm64_md.c optional hwpmc
+dev/kbd/kbd.c optional atkbd | sc | ukbd | vt
dev/mmc/host/dwmmc.c optional dwmmc
dev/mmc/host/dwmmc_hisi.c optional dwmmc soc_hisi_hi6220
dev/ofw/ofw_cpu.c optional fdt
diff --git a/sys/conf/files.sparc64 b/sys/conf/files.sparc64
index 0c160d4..78f0428 100644
--- a/sys/conf/files.sparc64
+++ b/sys/conf/files.sparc64
@@ -82,6 +82,7 @@ sparc64/isa/isa_dma.c optional isa
sparc64/isa/ofw_isa.c optional ebus | isa
sparc64/pci/apb.c optional pci
sparc64/pci/fire.c optional pci
+sparc64/pci/ofw_pci.c optional pci
sparc64/pci/ofw_pcib.c optional pci
sparc64/pci/ofw_pcib_subr.c optional pci
sparc64/pci/ofw_pcibus.c optional pci
diff --git a/sys/dev/dwc/if_dwc.c b/sys/dev/dwc/if_dwc.c
index 939ce54..5d28f9f 100644
--- a/sys/dev/dwc/if_dwc.c
+++ b/sys/dev/dwc/if_dwc.c
@@ -821,10 +821,8 @@ dwc_intr(void *arg)
DWC_LOCK(sc);
reg = READ4(sc, INTERRUPT_STATUS);
- if (reg) {
- mii_mediachg(sc->mii_softc);
+ if (reg)
READ4(sc, SGMII_RGMII_SMII_CTRL_STATUS);
- }
reg = READ4(sc, DMA_STATUS);
if (reg & DMA_STATUS_NIS) {
diff --git a/sys/dev/e1000/e1000_80003es2lan.c b/sys/dev/e1000/e1000_80003es2lan.c
index b948bb4..e7c42d5 100644
--- a/sys/dev/e1000/e1000_80003es2lan.c
+++ b/sys/dev/e1000/e1000_80003es2lan.c
@@ -851,11 +851,17 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
e1000_release_phy_80003es2lan(hw);
/* Disable IBIST slave mode (far-end loopback) */
- e1000_read_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
- &kum_reg_data);
- kum_reg_data |= E1000_KMRNCTRLSTA_IBIST_DISABLE;
- e1000_write_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
- kum_reg_data);
+ ret_val = e1000_read_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_INBAND_PARAM, &kum_reg_data);
+ if (!ret_val) {
+ kum_reg_data |= E1000_KMRNCTRLSTA_IBIST_DISABLE;
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_INBAND_PARAM,
+ kum_reg_data);
+ if (ret_val)
+ DEBUGOUT("Error disabling far-end loopback\n");
+ } else
+ DEBUGOUT("Error disabling far-end loopback\n");
ret_val = e1000_get_auto_rd_done_generic(hw);
if (ret_val)
@@ -911,11 +917,18 @@ static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
return ret_val;
/* Disable IBIST slave mode (far-end loopback) */
- e1000_read_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
- &kum_reg_data);
- kum_reg_data |= E1000_KMRNCTRLSTA_IBIST_DISABLE;
- e1000_write_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
- kum_reg_data);
+ ret_val =
+ e1000_read_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
+ &kum_reg_data);
+ if (!ret_val) {
+ kum_reg_data |= E1000_KMRNCTRLSTA_IBIST_DISABLE;
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_INBAND_PARAM,
+ kum_reg_data);
+ if (ret_val)
+ DEBUGOUT("Error disabling far-end loopback\n");
+ } else
+ DEBUGOUT("Error disabling far-end loopback\n");
/* Set the transmit descriptor write-back policy */
reg_data = E1000_READ_REG(hw, E1000_TXDCTL(0));
diff --git a/sys/dev/e1000/e1000_82540.c b/sys/dev/e1000/e1000_82540.c
index 68f92c6..2d03b8f 100644
--- a/sys/dev/e1000/e1000_82540.c
+++ b/sys/dev/e1000/e1000_82540.c
@@ -66,7 +66,7 @@ static s32 e1000_read_mac_addr_82540(struct e1000_hw *hw);
static s32 e1000_init_phy_params_82540(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
phy->addr = 1;
phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
@@ -329,7 +329,7 @@ static s32 e1000_init_hw_82540(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
u32 txdctl, ctrl_ext;
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
u16 i;
DEBUGFUNC("e1000_init_hw_82540");
@@ -411,7 +411,7 @@ static s32 e1000_init_hw_82540(struct e1000_hw *hw)
static s32 e1000_setup_copper_link_82540(struct e1000_hw *hw)
{
u32 ctrl;
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
u16 data;
DEBUGFUNC("e1000_setup_copper_link_82540");
@@ -498,7 +498,7 @@ out:
**/
static s32 e1000_adjust_serdes_amplitude_82540(struct e1000_hw *hw)
{
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
u16 nvm_data;
DEBUGFUNC("e1000_adjust_serdes_amplitude_82540");
@@ -528,7 +528,7 @@ out:
**/
static s32 e1000_set_vco_speed_82540(struct e1000_hw *hw)
{
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
u16 default_page = 0;
u16 phy_data;
diff --git a/sys/dev/e1000/e1000_82541.c b/sys/dev/e1000/e1000_82541.c
index 5961555..55d51087 100644
--- a/sys/dev/e1000/e1000_82541.c
+++ b/sys/dev/e1000/e1000_82541.c
@@ -85,7 +85,7 @@ static const u16 e1000_igp_cable_length_table[] = {
static s32 e1000_init_phy_params_82541(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
DEBUGFUNC("e1000_init_phy_params_82541");
@@ -295,7 +295,7 @@ void e1000_init_function_pointers_82541(struct e1000_hw *hw)
**/
static s32 e1000_reset_hw_82541(struct e1000_hw *hw)
{
- u32 ledctl, ctrl, icr, manc;
+ u32 ledctl, ctrl, manc;
DEBUGFUNC("e1000_reset_hw_82541");
@@ -317,6 +317,7 @@ static s32 e1000_reset_hw_82541(struct e1000_hw *hw)
/* Must reset the Phy before resetting the MAC */
if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_PHY_RST));
+ E1000_WRITE_FLUSH(hw);
msec_delay(5);
}
@@ -359,7 +360,7 @@ static s32 e1000_reset_hw_82541(struct e1000_hw *hw)
E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
/* Clear any pending interrupt events. */
- icr = E1000_READ_REG(hw, E1000_ICR);
+ E1000_READ_REG(hw, E1000_ICR);
return E1000_SUCCESS;
}
diff --git a/sys/dev/e1000/e1000_82542.c b/sys/dev/e1000/e1000_82542.c
index b2d676e..4cca9b2 100644
--- a/sys/dev/e1000/e1000_82542.c
+++ b/sys/dev/e1000/e1000_82542.c
@@ -317,7 +317,7 @@ static s32 e1000_init_hw_82542(struct e1000_hw *hw)
static s32 e1000_setup_link_82542(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
- s32 ret_val = E1000_SUCCESS;
+ s32 ret_val;
DEBUGFUNC("e1000_setup_link_82542");
@@ -565,7 +565,7 @@ static void e1000_clear_hw_cntrs_82542(struct e1000_hw *hw)
*
* Reads the device MAC address from the EEPROM and stores the value.
**/
-static s32 e1000_read_mac_addr_82542(struct e1000_hw *hw)
+s32 e1000_read_mac_addr_82542(struct e1000_hw *hw)
{
s32 ret_val = E1000_SUCCESS;
u16 offset, nvm_data, i;
diff --git a/sys/dev/e1000/e1000_82543.c b/sys/dev/e1000/e1000_82543.c
index b9a53bd..474387d 100644
--- a/sys/dev/e1000/e1000_82543.c
+++ b/sys/dev/e1000/e1000_82543.c
@@ -900,7 +900,7 @@ static s32 e1000_phy_hw_reset_82543(struct e1000_hw *hw)
**/
static s32 e1000_reset_hw_82543(struct e1000_hw *hw)
{
- u32 ctrl, icr;
+ u32 ctrl;
s32 ret_val = E1000_SUCCESS;
DEBUGFUNC("e1000_reset_hw_82543");
@@ -942,7 +942,7 @@ static s32 e1000_reset_hw_82543(struct e1000_hw *hw)
/* Masking off and clearing any pending interrupts */
E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
- icr = E1000_READ_REG(hw, E1000_ICR);
+ E1000_READ_REG(hw, E1000_ICR);
return ret_val;
}
diff --git a/sys/dev/e1000/e1000_82571.h b/sys/dev/e1000/e1000_82571.h
index 1d7718e..8e5ca56 100644
--- a/sys/dev/e1000/e1000_82571.h
+++ b/sys/dev/e1000/e1000_82571.h
@@ -50,9 +50,10 @@
#define E1000_EIAC_82574 0x000DC /* Ext. Interrupt Auto Clear - RW */
#define E1000_EIAC_MASK_82574 0x01F00000
-#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */
+#define E1000_IVAR_INT_ALLOC_VALID 0x8
-#define E1000_RXCFGL 0x0B634 /* TimeSync Rx EtherType & Msg Type Reg - RW */
+/* Manageability Operation Mode mask */
+#define E1000_NVM_INIT_CTRL2_MNGM 0x6000
#define E1000_BASE1000T_STATUS 10
#define E1000_IDLE_ERROR_COUNT_MASK 0xFF
diff --git a/sys/dev/e1000/e1000_82575.c b/sys/dev/e1000/e1000_82575.c
index 10653f8..04afc74 100644
--- a/sys/dev/e1000/e1000_82575.c
+++ b/sys/dev/e1000/e1000_82575.c
@@ -1235,7 +1235,7 @@ static s32 e1000_check_for_link_media_swap(struct e1000_hw *hw)
DEBUGFUNC("e1000_check_for_link_media_swap");
- /* Check the copper medium. */
+ /* Check for copper. */
ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0);
if (ret_val)
return ret_val;
@@ -1247,7 +1247,7 @@ static s32 e1000_check_for_link_media_swap(struct e1000_hw *hw)
if (data & E1000_M88E1112_STATUS_LINK)
port = E1000_MEDIA_PORT_COPPER;
- /* Check the other medium. */
+ /* Check for other. */
ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 1);
if (ret_val)
return ret_val;
@@ -1256,11 +1256,6 @@ static s32 e1000_check_for_link_media_swap(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- /* reset page to 0 */
- ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0);
- if (ret_val)
- return ret_val;
-
if (data & E1000_M88E1112_STATUS_LINK)
port = E1000_MEDIA_PORT_OTHER;
@@ -1268,8 +1263,20 @@ static s32 e1000_check_for_link_media_swap(struct e1000_hw *hw)
if (port && (hw->dev_spec._82575.media_port != port)) {
hw->dev_spec._82575.media_port = port;
hw->dev_spec._82575.media_changed = TRUE;
+ }
+
+ if (port == E1000_MEDIA_PORT_COPPER) {
+ /* reset page to 0 */
+ ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0);
+ if (ret_val)
+ return ret_val;
+ e1000_check_for_link_82575(hw);
} else {
- ret_val = e1000_check_for_link_82575(hw);
+ e1000_check_for_link_82575(hw);
+ /* reset page to 0 */
+ ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0);
+ if (ret_val)
+ return ret_val;
}
return E1000_SUCCESS;
@@ -2136,7 +2143,13 @@ void e1000_rx_fifo_flush_82575(struct e1000_hw *hw)
u32 rctl, rlpml, rxdctl[4], rfctl, temp_rctl, rx_enabled;
int i, ms_wait;
- DEBUGFUNC("e1000_rx_fifo_workaround_82575");
+ DEBUGFUNC("e1000_rx_fifo_flush_82575");
+
+ /* disable IPv6 options as per hardware errata */
+ rfctl = E1000_READ_REG(hw, E1000_RFCTL);
+ rfctl |= E1000_RFCTL_IPV6_EX_DIS;
+ E1000_WRITE_REG(hw, E1000_RFCTL, rfctl);
+
if (hw->mac.type != e1000_82575 ||
!(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_RCV_TCO_EN))
return;
@@ -2164,7 +2177,6 @@ void e1000_rx_fifo_flush_82575(struct e1000_hw *hw)
* incoming packets are rejected. Set enable and wait 2ms so that
* any packet that was coming in as RCTL.EN was set is flushed
*/
- rfctl = E1000_READ_REG(hw, E1000_RFCTL);
E1000_WRITE_REG(hw, E1000_RFCTL, rfctl & ~E1000_RFCTL_LEF);
rlpml = E1000_READ_REG(hw, E1000_RLPML);
@@ -2894,11 +2906,13 @@ out:
/**
* e1000_set_eee_i350 - Enable/disable EEE support
* @hw: pointer to the HW structure
+ * @adv1g: boolean flag enabling 1G EEE advertisement
+ * @adv100m: boolean flag enabling 100M EEE advertisement
*
* Enable/disable EEE based on setting in dev_spec structure.
*
**/
-s32 e1000_set_eee_i350(struct e1000_hw *hw)
+s32 e1000_set_eee_i350(struct e1000_hw *hw, bool adv1G, bool adv100M)
{
u32 ipcnfg, eeer;
@@ -2914,7 +2928,16 @@ s32 e1000_set_eee_i350(struct e1000_hw *hw)
if (!(hw->dev_spec._82575.eee_disable)) {
u32 eee_su = E1000_READ_REG(hw, E1000_EEE_SU);
- ipcnfg |= (E1000_IPCNFG_EEE_1G_AN | E1000_IPCNFG_EEE_100M_AN);
+ if (adv100M)
+ ipcnfg |= E1000_IPCNFG_EEE_100M_AN;
+ else
+ ipcnfg &= ~E1000_IPCNFG_EEE_100M_AN;
+
+ if (adv1G)
+ ipcnfg |= E1000_IPCNFG_EEE_1G_AN;
+ else
+ ipcnfg &= ~E1000_IPCNFG_EEE_1G_AN;
+
eeer |= (E1000_EEER_TX_LPI_EN | E1000_EEER_RX_LPI_EN |
E1000_EEER_LPI_FC);
@@ -2938,11 +2961,13 @@ out:
/**
* e1000_set_eee_i354 - Enable/disable EEE support
* @hw: pointer to the HW structure
+ * @adv1g: boolean flag enabling 1G EEE advertisement
+ * @adv100m: boolean flag enabling 100M EEE advertisement
*
* Enable/disable EEE legacy mode based on setting in dev_spec structure.
*
**/
-s32 e1000_set_eee_i354(struct e1000_hw *hw)
+s32 e1000_set_eee_i354(struct e1000_hw *hw, bool adv1G, bool adv100M)
{
struct e1000_phy_info *phy = &hw->phy;
s32 ret_val = E1000_SUCCESS;
@@ -2984,8 +3009,16 @@ s32 e1000_set_eee_i354(struct e1000_hw *hw)
if (ret_val)
goto out;
- phy_data |= E1000_EEE_ADV_100_SUPPORTED |
- E1000_EEE_ADV_1000_SUPPORTED;
+ if (adv100M)
+ phy_data |= E1000_EEE_ADV_100_SUPPORTED;
+ else
+ phy_data &= ~E1000_EEE_ADV_100_SUPPORTED;
+
+ if (adv1G)
+ phy_data |= E1000_EEE_ADV_1000_SUPPORTED;
+ else
+ phy_data &= ~E1000_EEE_ADV_1000_SUPPORTED;
+
ret_val = e1000_write_xmdio_reg(hw, E1000_EEE_ADV_ADDR_I354,
E1000_EEE_ADV_DEV_I354,
phy_data);
diff --git a/sys/dev/e1000/e1000_82575.h b/sys/dev/e1000/e1000_82575.h
index 503fdce..ef2b074 100644
--- a/sys/dev/e1000/e1000_82575.h
+++ b/sys/dev/e1000/e1000_82575.h
@@ -495,8 +495,8 @@ void e1000_rlpml_set_vf(struct e1000_hw *, u16);
s32 e1000_promisc_set_vf(struct e1000_hw *, enum e1000_promisc_type type);
u16 e1000_rxpbs_adjust_82580(u32 data);
s32 e1000_read_emi_reg(struct e1000_hw *hw, u16 addr, u16 *data);
-s32 e1000_set_eee_i350(struct e1000_hw *);
-s32 e1000_set_eee_i354(struct e1000_hw *);
+s32 e1000_set_eee_i350(struct e1000_hw *hw, bool adv1G, bool adv100M);
+s32 e1000_set_eee_i354(struct e1000_hw *hw, bool adv1G, bool adv100M);
s32 e1000_get_eee_status_i354(struct e1000_hw *, bool *);
s32 e1000_initialize_M88E1512_phy(struct e1000_hw *hw);
diff --git a/sys/dev/e1000/e1000_api.c b/sys/dev/e1000/e1000_api.c
index 5db22db..9cd0adf 100644
--- a/sys/dev/e1000/e1000_api.c
+++ b/sys/dev/e1000/e1000_api.c
@@ -299,6 +299,12 @@ s32 e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_PCH_I218_V3:
mac->type = e1000_pch_lpt;
break;
+ case E1000_DEV_ID_PCH_SPT_I219_LM:
+ case E1000_DEV_ID_PCH_SPT_I219_V:
+ case E1000_DEV_ID_PCH_SPT_I219_LM2:
+ case E1000_DEV_ID_PCH_SPT_I219_V2:
+ mac->type = e1000_pch_spt;
+ break;
case E1000_DEV_ID_82575EB_COPPER:
case E1000_DEV_ID_82575EB_FIBER_SERDES:
case E1000_DEV_ID_82575GB_QUAD_COPPER:
@@ -449,6 +455,7 @@ s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device)
case e1000_pchlan:
case e1000_pch2lan:
case e1000_pch_lpt:
+ case e1000_pch_spt:
e1000_init_function_pointers_ich8lan(hw);
break;
case e1000_82575:
@@ -929,21 +936,6 @@ s32 e1000_mng_enable_host_if(struct e1000_hw *hw)
}
/**
- * e1000_set_obff_timer - Set Optimized Buffer Flush/Fill timer
- * @hw: pointer to the HW structure
- * @itr: u32 indicating itr value
- *
- * Set the OBFF timer based on the given interrupt rate.
- **/
-s32 e1000_set_obff_timer(struct e1000_hw *hw, u32 itr)
-{
- if (hw->mac.ops.set_obff_timer)
- return hw->mac.ops.set_obff_timer(hw, itr);
-
- return E1000_SUCCESS;
-}
-
-/**
* e1000_check_reset_block - Verifies PHY can be reset
* @hw: pointer to the HW structure
*
@@ -1216,6 +1208,21 @@ s32 e1000_read_pba_length(struct e1000_hw *hw, u32 *pba_num_size)
}
/**
+ * e1000_read_pba_num - Read device part number
+ * @hw: pointer to the HW structure
+ * @pba_num: pointer to device part number
+ *
+ * Reads the product board assembly (PBA) number from the EEPROM and stores
+ * the value in pba_num.
+ * Currently no func pointer exists and all implementations are handled in the
+ * generic version of this function.
+ **/
+s32 e1000_read_pba_num(struct e1000_hw *hw, u32 *pba_num)
+{
+ return e1000_read_pba_num_generic(hw, pba_num);
+}
+
+/**
* e1000_validate_nvm_checksum - Verifies NVM (EEPROM) checksum
* @hw: pointer to the HW structure
*
diff --git a/sys/dev/e1000/e1000_api.h b/sys/dev/e1000/e1000_api.h
index 074197b..86075f8 100644
--- a/sys/dev/e1000/e1000_api.h
+++ b/sys/dev/e1000/e1000_api.h
@@ -97,6 +97,7 @@ s32 e1000_phy_commit(struct e1000_hw *hw);
void e1000_power_up_phy(struct e1000_hw *hw);
void e1000_power_down_phy(struct e1000_hw *hw);
s32 e1000_read_mac_addr(struct e1000_hw *hw);
+s32 e1000_read_pba_num(struct e1000_hw *hw, u32 *part_num);
s32 e1000_read_pba_string(struct e1000_hw *hw, u8 *pba_num, u32 pba_num_size);
s32 e1000_read_pba_length(struct e1000_hw *hw, u32 *pba_num_size);
void e1000_reload_nvm(struct e1000_hw *hw);
diff --git a/sys/dev/e1000/e1000_defines.h b/sys/dev/e1000/e1000_defines.h
index 9472ca4..eb62604 100644
--- a/sys/dev/e1000/e1000_defines.h
+++ b/sys/dev/e1000/e1000_defines.h
@@ -197,6 +197,8 @@
#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */
#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */
#define E1000_RCTL_RDMTS_HALF 0x00000000 /* Rx desc min thresh size */
+#define E1000_RCTL_RDMTS_HEX 0x00010000
+#define E1000_RCTL_RDMTS1_HEX E1000_RCTL_RDMTS_HEX
#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */
#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */
#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */
@@ -565,9 +567,6 @@
#define E1000_ICR_THS 0x00800000 /* ICR.THS: Thermal Sensor Event*/
#define E1000_ICR_MDDET 0x10000000 /* Malicious Driver Detect */
-#define E1000_ITR_MASK 0x000FFFFF /* ITR value bitfield */
-#define E1000_ITR_MULT 256 /* ITR mulitplier in nsec */
-
/* PBA ECC Register */
#define E1000_PBA_ECC_COUNTER_MASK 0xFFF00000 /* ECC counter mask */
#define E1000_PBA_ECC_COUNTER_SHIFT 20 /* ECC counter shift value */
@@ -753,6 +752,12 @@
#define E1000_TSYNCTXCTL_VALID 0x00000001 /* Tx timestamp valid */
#define E1000_TSYNCTXCTL_ENABLED 0x00000010 /* enable Tx timestamping */
+/* HH Time Sync */
+#define E1000_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK 0x0000F000 /* max delay */
+#define E1000_TSYNCTXCTL_SYNC_COMP_ERR 0x20000000 /* sync err */
+#define E1000_TSYNCTXCTL_SYNC_COMP 0x40000000 /* sync complete */
+#define E1000_TSYNCTXCTL_START_SYNC 0x80000000 /* initiate sync */
+
#define E1000_TSYNCRXCTL_VALID 0x00000001 /* Rx timestamp valid */
#define E1000_TSYNCRXCTL_TYPE_MASK 0x0000000E /* Rx type mask */
#define E1000_TSYNCRXCTL_TYPE_L2_V2 0x00
@@ -1020,9 +1025,7 @@
/* NVM Addressing bits based on type 0=small, 1=large */
#define E1000_EECD_ADDR_BITS 0x00000400
#define E1000_EECD_TYPE 0x00002000 /* NVM Type (1-SPI, 0-Microwire) */
-#ifndef E1000_NVM_GRANT_ATTEMPTS
#define E1000_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */
-#endif
#define E1000_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */
#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */
#define E1000_EECD_SIZE_EX_SHIFT 11
@@ -1059,11 +1062,44 @@
/* NVM Word Offsets */
#define NVM_COMPAT 0x0003
#define NVM_ID_LED_SETTINGS 0x0004
+#define NVM_VERSION 0x0005
#define NVM_SERDES_AMPLITUDE 0x0006 /* SERDES output amplitude */
#define NVM_PHY_CLASS_WORD 0x0007
#define E1000_I210_NVM_FW_MODULE_PTR 0x0010
#define E1000_I350_NVM_FW_MODULE_PTR 0x0051
#define NVM_FUTURE_INIT_WORD1 0x0019
+#define NVM_ETRACK_WORD 0x0042
+#define NVM_ETRACK_HIWORD 0x0043
+#define NVM_COMB_VER_OFF 0x0083
+#define NVM_COMB_VER_PTR 0x003d
+
+/* NVM version defines */
+#define NVM_MAJOR_MASK 0xF000
+#define NVM_MINOR_MASK 0x0FF0
+#define NVM_IMAGE_ID_MASK 0x000F
+#define NVM_COMB_VER_MASK 0x00FF
+#define NVM_MAJOR_SHIFT 12
+#define NVM_MINOR_SHIFT 4
+#define NVM_COMB_VER_SHFT 8
+#define NVM_VER_INVALID 0xFFFF
+#define NVM_ETRACK_SHIFT 16
+#define NVM_ETRACK_VALID 0x8000
+#define NVM_NEW_DEC_MASK 0x0F00
+#define NVM_HEX_CONV 16
+#define NVM_HEX_TENS 10
+
+/* FW version defines */
+/* Offset of "Loader patch ptr" in Firmware Header */
+#define E1000_I350_NVM_FW_LOADER_PATCH_PTR_OFFSET 0x01
+/* Patch generation hour & minutes */
+#define E1000_I350_NVM_FW_VER_WORD1_OFFSET 0x04
+/* Patch generation month & day */
+#define E1000_I350_NVM_FW_VER_WORD2_OFFSET 0x05
+/* Patch generation year */
+#define E1000_I350_NVM_FW_VER_WORD3_OFFSET 0x06
+/* Patch major & minor numbers */
+#define E1000_I350_NVM_FW_VER_WORD4_OFFSET 0x07
+
#define NVM_MAC_ADDR 0x0000
#define NVM_SUB_DEV_ID 0x000B
#define NVM_SUB_VEN_ID 0x000C
@@ -1440,8 +1476,6 @@
#define I210_RXPBSIZE_DEFAULT 0x000000A2 /* RXPBSIZE default */
#define I210_TXPBSIZE_DEFAULT 0x04000014 /* TXPBSIZE default */
-#define E1000_DOBFFCTL_OBFFTHR_MASK 0x000000FF /* OBFF threshold */
-#define E1000_DOBFFCTL_EXIT_ACT_MASK 0x01000000 /* Exit active CB */
/* Proxy Filter Control */
#define E1000_PROXYFC_D0 0x00000001 /* Enable offload in D0 */
diff --git a/sys/dev/e1000/e1000_hw.h b/sys/dev/e1000/e1000_hw.h
index 8ae4b20..8e945f6 100644
--- a/sys/dev/e1000/e1000_hw.h
+++ b/sys/dev/e1000/e1000_hw.h
@@ -137,6 +137,10 @@ struct e1000_hw;
#define E1000_DEV_ID_PCH_I218_V2 0x15A1
#define E1000_DEV_ID_PCH_I218_LM3 0x15A2 /* Wildcat Point PCH */
#define E1000_DEV_ID_PCH_I218_V3 0x15A3 /* Wildcat Point PCH */
+#define E1000_DEV_ID_PCH_SPT_I219_LM 0x156F /* Sunrise Point PCH */
+#define E1000_DEV_ID_PCH_SPT_I219_V 0x1570 /* Sunrise Point PCH */
+#define E1000_DEV_ID_PCH_SPT_I219_LM2 0x15B7 /* Sunrise Point-H PCH */
+#define E1000_DEV_ID_PCH_SPT_I219_V2 0x15B8 /* Sunrise Point-H PCH */
#define E1000_DEV_ID_82576 0x10C9
#define E1000_DEV_ID_82576_FIBER 0x10E6
#define E1000_DEV_ID_82576_SERDES 0x10E7
@@ -222,6 +226,7 @@ enum e1000_mac_type {
e1000_pchlan,
e1000_pch2lan,
e1000_pch_lpt,
+ e1000_pch_spt,
e1000_82575,
e1000_82576,
e1000_82580,
@@ -703,7 +708,6 @@ struct e1000_mac_operations {
int (*rar_set)(struct e1000_hw *, u8*, u32);
s32 (*read_mac_addr)(struct e1000_hw *);
s32 (*validate_mdi_setting)(struct e1000_hw *);
- s32 (*set_obff_timer)(struct e1000_hw *, u32);
s32 (*acquire_swfw_sync)(struct e1000_hw *, u16);
void (*release_swfw_sync)(struct e1000_hw *, u16);
};
@@ -805,7 +809,7 @@ struct e1000_mac_info {
enum e1000_serdes_link_state serdes_link_state;
bool serdes_has_link;
bool tx_pkt_filtering;
- u32 max_frame_size;
+ u32 max_frame_size;
};
struct e1000_phy_info {
diff --git a/sys/dev/e1000/e1000_i210.c b/sys/dev/e1000/e1000_i210.c
index 563f11a..2c03660 100644
--- a/sys/dev/e1000/e1000_i210.c
+++ b/sys/dev/e1000/e1000_i210.c
@@ -489,6 +489,105 @@ static s32 e1000_read_invm_i210(struct e1000_hw *hw, u16 offset,
}
/**
+ * e1000_read_invm_version - Reads iNVM version and image type
+ * @hw: pointer to the HW structure
+ * @invm_ver: version structure for the version read
+ *
+ * Reads iNVM version and image type.
+ **/
+s32 e1000_read_invm_version(struct e1000_hw *hw,
+ struct e1000_fw_version *invm_ver)
+{
+ u32 *record = NULL;
+ u32 *next_record = NULL;
+ u32 i = 0;
+ u32 invm_dword = 0;
+ u32 invm_blocks = E1000_INVM_SIZE - (E1000_INVM_ULT_BYTES_SIZE /
+ E1000_INVM_RECORD_SIZE_IN_BYTES);
+ u32 buffer[E1000_INVM_SIZE];
+ s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND;
+ u16 version = 0;
+
+ DEBUGFUNC("e1000_read_invm_version");
+
+ /* Read iNVM memory */
+ for (i = 0; i < E1000_INVM_SIZE; i++) {
+ invm_dword = E1000_READ_REG(hw, E1000_INVM_DATA_REG(i));
+ buffer[i] = invm_dword;
+ }
+
+ /* Read version number */
+ for (i = 1; i < invm_blocks; i++) {
+ record = &buffer[invm_blocks - i];
+ next_record = &buffer[invm_blocks - i + 1];
+
+ /* Check if we have first version location used */
+ if ((i == 1) && ((*record & E1000_INVM_VER_FIELD_ONE) == 0)) {
+ version = 0;
+ status = E1000_SUCCESS;
+ break;
+ }
+ /* Check if we have second version location used */
+ else if ((i == 1) &&
+ ((*record & E1000_INVM_VER_FIELD_TWO) == 0)) {
+ version = (*record & E1000_INVM_VER_FIELD_ONE) >> 3;
+ status = E1000_SUCCESS;
+ break;
+ }
+ /*
+ * Check if we have odd version location
+ * used and it is the last one used
+ */
+ else if ((((*record & E1000_INVM_VER_FIELD_ONE) == 0) &&
+ ((*record & 0x3) == 0)) || (((*record & 0x3) != 0) &&
+ (i != 1))) {
+ version = (*next_record & E1000_INVM_VER_FIELD_TWO)
+ >> 13;
+ status = E1000_SUCCESS;
+ break;
+ }
+ /*
+ * Check if we have even version location
+ * used and it is the last one used
+ */
+ else if (((*record & E1000_INVM_VER_FIELD_TWO) == 0) &&
+ ((*record & 0x3) == 0)) {
+ version = (*record & E1000_INVM_VER_FIELD_ONE) >> 3;
+ status = E1000_SUCCESS;
+ break;
+ }
+ }
+
+ if (status == E1000_SUCCESS) {
+ invm_ver->invm_major = (version & E1000_INVM_MAJOR_MASK)
+ >> E1000_INVM_MAJOR_SHIFT;
+ invm_ver->invm_minor = version & E1000_INVM_MINOR_MASK;
+ }
+ /* Read Image Type */
+ for (i = 1; i < invm_blocks; i++) {
+ record = &buffer[invm_blocks - i];
+ next_record = &buffer[invm_blocks - i + 1];
+
+ /* Check if we have image type in first location used */
+ if ((i == 1) && ((*record & E1000_INVM_IMGTYPE_FIELD) == 0)) {
+ invm_ver->invm_img_type = 0;
+ status = E1000_SUCCESS;
+ break;
+ }
+ /* Check if we have image type in first location used */
+ else if ((((*record & 0x3) == 0) &&
+ ((*record & E1000_INVM_IMGTYPE_FIELD) == 0)) ||
+ ((((*record & 0x3) != 0) && (i != 1)))) {
+ invm_ver->invm_img_type =
+ (*next_record & E1000_INVM_IMGTYPE_FIELD) >> 23;
+ status = E1000_SUCCESS;
+ break;
+ }
+ }
+ return status;
+}
+
+/**
* e1000_validate_nvm_checksum_i210 - Validate EEPROM checksum
* @hw: pointer to the HW structure
*
diff --git a/sys/dev/e1000/e1000_i210.h b/sys/dev/e1000/e1000_i210.h
index f940915..b0f94ba 100644
--- a/sys/dev/e1000/e1000_i210.h
+++ b/sys/dev/e1000/e1000_i210.h
@@ -43,6 +43,8 @@ s32 e1000_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset,
u16 words, u16 *data);
s32 e1000_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset,
u16 words, u16 *data);
+s32 e1000_read_invm_version(struct e1000_hw *hw,
+ struct e1000_fw_version *invm_ver);
s32 e1000_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask);
void e1000_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask);
s32 e1000_read_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr,
diff --git a/sys/dev/e1000/e1000_ich8lan.c b/sys/dev/e1000/e1000_ich8lan.c
index 75fcade..5b60d19 100644
--- a/sys/dev/e1000/e1000_ich8lan.c
+++ b/sys/dev/e1000/e1000_ich8lan.c
@@ -92,10 +92,13 @@ static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw,
bool active);
static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
u16 words, u16 *data);
+static s32 e1000_read_nvm_spt(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data);
static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
u16 words, u16 *data);
static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw);
static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw);
+static s32 e1000_update_nvm_checksum_spt(struct e1000_hw *hw);
static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw,
u16 *data);
static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw);
@@ -123,6 +126,14 @@ static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw,
u32 offset, u8 *data);
static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
u8 size, u16 *data);
+static s32 e1000_read_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset,
+ u32 *data);
+static s32 e1000_read_flash_dword_ich8lan(struct e1000_hw *hw,
+ u32 offset, u32 *data);
+static s32 e1000_write_flash_data32_ich8lan(struct e1000_hw *hw,
+ u32 offset, u32 data);
+static s32 e1000_retry_write_flash_dword_ich8lan(struct e1000_hw *hw,
+ u32 offset, u32 dword);
static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw,
u32 offset, u16 *data);
static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
@@ -133,7 +144,6 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw);
static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
static s32 e1000_k1_workaround_lv(struct e1000_hw *hw);
static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate);
-static s32 e1000_set_obff_timer_pch_lpt(struct e1000_hw *hw, u32 itr);
/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
/* Offset 04h HSFSTS */
@@ -232,16 +242,21 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
if (ret_val)
return FALSE;
out:
- if (hw->mac.type == e1000_pch_lpt) {
- /* Unforce SMBus mode in PHY */
- hw->phy.ops.read_reg_locked(hw, CV_SMB_CTRL, &phy_reg);
- phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
- hw->phy.ops.write_reg_locked(hw, CV_SMB_CTRL, phy_reg);
+ if ((hw->mac.type == e1000_pch_lpt) ||
+ (hw->mac.type == e1000_pch_spt)) {
+ /* Only unforce SMBus if ME is not active */
+ if (!(E1000_READ_REG(hw, E1000_FWSM) &
+ E1000_ICH_FWSM_FW_VALID)) {
+ /* Unforce SMBus mode in PHY */
+ hw->phy.ops.read_reg_locked(hw, CV_SMB_CTRL, &phy_reg);
+ phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
+ hw->phy.ops.write_reg_locked(hw, CV_SMB_CTRL, phy_reg);
- /* Unforce SMBus mode in MAC */
- mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
- mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
- E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
+ /* Unforce SMBus mode in MAC */
+ mac_reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
+ }
}
return TRUE;
@@ -328,6 +343,7 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
*/
switch (hw->mac.type) {
case e1000_pch_lpt:
+ case e1000_pch_spt:
if (e1000_phy_is_accessible_pchlan(hw))
break;
@@ -475,6 +491,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
/* fall-through */
case e1000_pch2lan:
case e1000_pch_lpt:
+ case e1000_pch_spt:
/* In case the PHY needs to be in mdio slow mode,
* set slow mode and try to get the PHY id again.
*/
@@ -617,36 +634,53 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
u32 gfpreg, sector_base_addr, sector_end_addr;
u16 i;
+ u32 nvm_size;
DEBUGFUNC("e1000_init_nvm_params_ich8lan");
/* Can't read flash registers if the register set isn't mapped. */
nvm->type = e1000_nvm_flash_sw;
- if (!hw->flash_address) {
- DEBUGOUT("ERROR: Flash registers not mapped\n");
- return -E1000_ERR_CONFIG;
- }
+ /* in SPT, gfpreg doesn't exist. NVM size is taken from the
+ * STRAP register
+ */
+ if (hw->mac.type == e1000_pch_spt) {
+ nvm->flash_base_addr = 0;
+ nvm_size =
+ (((E1000_READ_REG(hw, E1000_STRAP) >> 1) & 0x1F) + 1)
+ * NVM_SIZE_MULTIPLIER;
+ nvm->flash_bank_size = nvm_size / 2;
+ /* Adjust to word count */
+ nvm->flash_bank_size /= sizeof(u16);
+ /* Set the base address for flash register access */
+ hw->flash_address = hw->hw_addr + E1000_FLASH_BASE_ADDR;
+ } else {
+ if (!hw->flash_address) {
+ DEBUGOUT("ERROR: Flash registers not mapped\n");
+ return -E1000_ERR_CONFIG;
+ }
- gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG);
+ gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG);
- /* sector_X_addr is a "sector"-aligned address (4096 bytes)
- * Add 1 to sector_end_addr since this sector is included in
- * the overall size.
- */
- sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
- sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
+ /* sector_X_addr is a "sector"-aligned address (4096 bytes)
+ * Add 1 to sector_end_addr since this sector is included in
+ * the overall size.
+ */
+ sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
+ sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
- /* flash_base_addr is byte-aligned */
- nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
+ /* flash_base_addr is byte-aligned */
+ nvm->flash_base_addr = sector_base_addr
+ << FLASH_SECTOR_ADDR_SHIFT;
- /* find total size of the NVM, then cut in half since the total
- * size represents two separate NVM banks.
- */
- nvm->flash_bank_size = ((sector_end_addr - sector_base_addr)
- << FLASH_SECTOR_ADDR_SHIFT);
- nvm->flash_bank_size /= 2;
- /* Adjust to word count */
- nvm->flash_bank_size /= sizeof(u16);
+ /* find total size of the NVM, then cut in half since the total
+ * size represents two separate NVM banks.
+ */
+ nvm->flash_bank_size = ((sector_end_addr - sector_base_addr)
+ << FLASH_SECTOR_ADDR_SHIFT);
+ nvm->flash_bank_size /= 2;
+ /* Adjust to word count */
+ nvm->flash_bank_size /= sizeof(u16);
+ }
nvm->word_size = E1000_SHADOW_RAM_WORDS;
@@ -662,8 +696,13 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
/* Function Pointers */
nvm->ops.acquire = e1000_acquire_nvm_ich8lan;
nvm->ops.release = e1000_release_nvm_ich8lan;
- nvm->ops.read = e1000_read_nvm_ich8lan;
- nvm->ops.update = e1000_update_nvm_checksum_ich8lan;
+ if (hw->mac.type == e1000_pch_spt) {
+ nvm->ops.read = e1000_read_nvm_spt;
+ nvm->ops.update = e1000_update_nvm_checksum_spt;
+ } else {
+ nvm->ops.read = e1000_read_nvm_ich8lan;
+ nvm->ops.update = e1000_update_nvm_checksum_ich8lan;
+ }
nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan;
nvm->ops.validate = e1000_validate_nvm_checksum_ich8lan;
nvm->ops.write = e1000_write_nvm_ich8lan;
@@ -681,9 +720,7 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
-#if defined(QV_RELEASE) || !defined(NO_PCH_LPT_B0_SUPPORT)
u16 pci_cfg;
-#endif /* QV_RELEASE || !defined(NO_PCH_LPT_B0_SUPPORT) */
DEBUGFUNC("e1000_init_mac_params_ich8lan");
@@ -752,15 +789,21 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
mac->ops.rar_set = e1000_rar_set_pch2lan;
/* fall-through */
case e1000_pch_lpt:
+ case e1000_pch_spt:
/* multicast address update for pch2 */
mac->ops.update_mc_addr_list =
e1000_update_mc_addr_list_pch2lan;
+ /* fall-through */
case e1000_pchlan:
-#if defined(QV_RELEASE) || !defined(NO_PCH_LPT_B0_SUPPORT)
/* save PCH revision_id */
e1000_read_pci_cfg(hw, E1000_PCI_REVISION_ID_REG, &pci_cfg);
- hw->revision_id = (u8)(pci_cfg &= 0x000F);
-#endif /* QV_RELEASE || !defined(NO_PCH_LPT_B0_SUPPORT) */
+ /* SPT uses full byte for revision ID,
+ * as opposed to previous generations
+ */
+ if (hw->mac.type >= e1000_pch_spt)
+ hw->revision_id = (u8)(pci_cfg &= 0x00FF);
+ else
+ hw->revision_id = (u8)(pci_cfg &= 0x000F);
/* check management mode */
mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan;
/* ID LED init */
@@ -777,11 +820,11 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
break;
}
- if (mac->type == e1000_pch_lpt) {
+ if ((mac->type == e1000_pch_lpt) ||
+ (mac->type == e1000_pch_spt)) {
mac->rar_entry_count = E1000_PCH_LPT_RAR_ENTRIES;
mac->ops.rar_set = e1000_rar_set_pch_lpt;
mac->ops.setup_physical_interface = e1000_setup_copper_link_pch_lpt;
- mac->ops.set_obff_timer = e1000_set_obff_timer_pch_lpt;
}
/* Enable PCS Lock-loss workaround for ICH8 */
@@ -1007,8 +1050,9 @@ release:
/* clear FEXTNVM6 bit 8 on link down or 10/100 */
fextnvm6 &= ~E1000_FEXTNVM6_REQ_PLL_CLK;
- if (!link || ((status & E1000_STATUS_SPEED_100) &&
- (status & E1000_STATUS_FD)))
+ if ((hw->phy.revision > 5) || !link ||
+ ((status & E1000_STATUS_SPEED_100) &&
+ (status & E1000_STATUS_FD)))
goto update_fextnvm6;
ret_val = hw->phy.ops.read_reg(hw, I217_INBAND_CTRL, &reg);
@@ -1044,168 +1088,6 @@ update_fextnvm6:
return ret_val;
}
-static u64 e1000_ltr2ns(u16 ltr)
-{
- u32 value, scale;
-
- /* Determine the latency in nsec based on the LTR value & scale */
- value = ltr & E1000_LTRV_VALUE_MASK;
- scale = (ltr & E1000_LTRV_SCALE_MASK) >> E1000_LTRV_SCALE_SHIFT;
-
- return value * (1 << (scale * E1000_LTRV_SCALE_FACTOR));
-}
-
-/**
- * e1000_platform_pm_pch_lpt - Set platform power management values
- * @hw: pointer to the HW structure
- * @link: bool indicating link status
- *
- * Set the Latency Tolerance Reporting (LTR) values for the "PCIe-like"
- * GbE MAC in the Lynx Point PCH based on Rx buffer size and link speed
- * when link is up (which must not exceed the maximum latency supported
- * by the platform), otherwise specify there is no LTR requirement.
- * Unlike TRUE-PCIe devices which set the LTR maximum snoop/no-snoop
- * latencies in the LTR Extended Capability Structure in the PCIe Extended
- * Capability register set, on this device LTR is set by writing the
- * equivalent snoop/no-snoop latencies in the LTRV register in the MAC and
- * set the SEND bit to send an Intel On-chip System Fabric sideband (IOSF-SB)
- * message to the PMC.
- *
- * Use the LTR value to calculate the Optimized Buffer Flush/Fill (OBFF)
- * high-water mark.
- **/
-static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link)
-{
- u32 reg = link << (E1000_LTRV_REQ_SHIFT + E1000_LTRV_NOSNOOP_SHIFT) |
- link << E1000_LTRV_REQ_SHIFT | E1000_LTRV_SEND;
- u16 lat_enc = 0; /* latency encoded */
- s32 obff_hwm = 0;
-
- DEBUGFUNC("e1000_platform_pm_pch_lpt");
-
- if (link) {
- u16 speed, duplex, scale = 0;
- u16 max_snoop, max_nosnoop;
- u16 max_ltr_enc; /* max LTR latency encoded */
- s64 lat_ns;
- s64 value;
- u32 rxa;
-
- if (!hw->mac.max_frame_size) {
- DEBUGOUT("max_frame_size not set.\n");
- return -E1000_ERR_CONFIG;
- }
-
- hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
- if (!speed) {
- DEBUGOUT("Speed not set.\n");
- return -E1000_ERR_CONFIG;
- }
-
- /* Rx Packet Buffer Allocation size (KB) */
- rxa = E1000_READ_REG(hw, E1000_PBA) & E1000_PBA_RXA_MASK;
-
- /* Determine the maximum latency tolerated by the device.
- *
- * Per the PCIe spec, the tolerated latencies are encoded as
- * a 3-bit encoded scale (only 0-5 are valid) multiplied by
- * a 10-bit value (0-1023) to provide a range from 1 ns to
- * 2^25*(2^10-1) ns. The scale is encoded as 0=2^0ns,
- * 1=2^5ns, 2=2^10ns,...5=2^25ns.
- */
- lat_ns = ((s64)rxa * 1024 -
- (2 * (s64)hw->mac.max_frame_size)) * 8 * 1000;
- if (lat_ns < 0)
- lat_ns = 0;
- else
- lat_ns /= speed;
- value = lat_ns;
-
- while (value > E1000_LTRV_VALUE_MASK) {
- scale++;
- value = E1000_DIVIDE_ROUND_UP(value, (1 << 5));
- }
- if (scale > E1000_LTRV_SCALE_MAX) {
- DEBUGOUT1("Invalid LTR latency scale %d\n", scale);
- return -E1000_ERR_CONFIG;
- }
- lat_enc = (u16)((scale << E1000_LTRV_SCALE_SHIFT) | value);
-
- /* Determine the maximum latency tolerated by the platform */
- e1000_read_pci_cfg(hw, E1000_PCI_LTR_CAP_LPT, &max_snoop);
- e1000_read_pci_cfg(hw, E1000_PCI_LTR_CAP_LPT + 2, &max_nosnoop);
- max_ltr_enc = E1000_MAX(max_snoop, max_nosnoop);
-
- if (lat_enc > max_ltr_enc) {
- lat_enc = max_ltr_enc;
- lat_ns = e1000_ltr2ns(max_ltr_enc);
- }
-
- if (lat_ns) {
- lat_ns *= speed * 1000;
- lat_ns /= 8;
- lat_ns /= 1000000000;
- obff_hwm = (s32)(rxa - lat_ns);
- }
- if ((obff_hwm < 0) || (obff_hwm > E1000_SVT_OFF_HWM_MASK)) {
- DEBUGOUT1("Invalid high water mark %d\n", obff_hwm);
- return -E1000_ERR_CONFIG;
- }
- }
-
- /* Set Snoop and No-Snoop latencies the same */
- reg |= lat_enc | (lat_enc << E1000_LTRV_NOSNOOP_SHIFT);
- E1000_WRITE_REG(hw, E1000_LTRV, reg);
-
- /* Set OBFF high water mark */
- reg = E1000_READ_REG(hw, E1000_SVT) & ~E1000_SVT_OFF_HWM_MASK;
- reg |= obff_hwm;
- E1000_WRITE_REG(hw, E1000_SVT, reg);
-
- /* Enable OBFF */
- reg = E1000_READ_REG(hw, E1000_SVCR);
- reg |= E1000_SVCR_OFF_EN;
- /* Always unblock interrupts to the CPU even when the system is
- * in OBFF mode. This ensures that small round-robin traffic
- * (like ping) does not get dropped or experience long latency.
- */
- reg |= E1000_SVCR_OFF_MASKINT;
- E1000_WRITE_REG(hw, E1000_SVCR, reg);
-
- return E1000_SUCCESS;
-}
-
-/**
- * e1000_set_obff_timer_pch_lpt - Update Optimized Buffer Flush/Fill timer
- * @hw: pointer to the HW structure
- * @itr: interrupt throttling rate
- *
- * Configure OBFF with the updated interrupt rate.
- **/
-static s32 e1000_set_obff_timer_pch_lpt(struct e1000_hw *hw, u32 itr)
-{
- u32 svcr;
- s32 timer;
-
- DEBUGFUNC("e1000_set_obff_timer_pch_lpt");
-
- /* Convert ITR value into microseconds for OBFF timer */
- timer = itr & E1000_ITR_MASK;
- timer = (timer * E1000_ITR_MULT) / 1000;
-
- if ((timer < 0) || (timer > E1000_ITR_MASK)) {
- DEBUGOUT1("Invalid OBFF timer %d\n", timer);
- return -E1000_ERR_CONFIG;
- }
-
- svcr = E1000_READ_REG(hw, E1000_SVCR);
- svcr &= ~E1000_SVCR_OFF_TIMER_MASK;
- svcr |= timer << E1000_SVCR_OFF_TIMER_SHIFT;
- E1000_WRITE_REG(hw, E1000_SVCR, svcr);
-
- return E1000_SUCCESS;
-}
-
/**
* e1000_enable_ulp_lpt_lp - configure Ultra Low Power mode for LynxPoint-LP
* @hw: pointer to the HW structure
@@ -1221,6 +1103,7 @@ s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
u32 mac_reg;
s32 ret_val = E1000_SUCCESS;
u16 phy_reg;
+ u16 oem_reg = 0;
if ((hw->mac.type < e1000_pch_lpt) ||
(hw->device_id == E1000_DEV_ID_PCH_LPT_I217_LM) ||
@@ -1276,6 +1159,25 @@ s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
E1000_WRITE_REG(hw, E1000_CTRL_EXT, mac_reg);
+ /* Si workaround for ULP entry flow on i127/rev6 h/w. Enable
+ * LPLU and disable Gig speed when entering ULP
+ */
+ if ((hw->phy.type == e1000_phy_i217) && (hw->phy.revision == 6)) {
+ ret_val = e1000_read_phy_reg_hv_locked(hw, HV_OEM_BITS,
+ &oem_reg);
+ if (ret_val)
+ goto release;
+
+ phy_reg = oem_reg;
+ phy_reg |= HV_OEM_BITS_LPLU | HV_OEM_BITS_GBE_DIS;
+
+ ret_val = e1000_write_phy_reg_hv_locked(hw, HV_OEM_BITS,
+ phy_reg);
+
+ if (ret_val)
+ goto release;
+ }
+
/* Set Inband ULP Exit, Reset to SMBus mode and
* Disable SMBus Release on PERST# in PHY
*/
@@ -1287,10 +1189,15 @@ s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
if (to_sx) {
if (E1000_READ_REG(hw, E1000_WUFC) & E1000_WUFC_LNKC)
phy_reg |= I218_ULP_CONFIG1_WOL_HOST;
+ else
+ phy_reg &= ~I218_ULP_CONFIG1_WOL_HOST;
phy_reg |= I218_ULP_CONFIG1_STICKY_ULP;
+ phy_reg &= ~I218_ULP_CONFIG1_INBAND_EXIT;
} else {
phy_reg |= I218_ULP_CONFIG1_INBAND_EXIT;
+ phy_reg &= ~I218_ULP_CONFIG1_STICKY_ULP;
+ phy_reg &= ~I218_ULP_CONFIG1_WOL_HOST;
}
e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
@@ -1302,6 +1209,16 @@ s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
/* Commit ULP changes in PHY by starting auto ULP configuration */
phy_reg |= I218_ULP_CONFIG1_START;
e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+
+ if ((hw->phy.type == e1000_phy_i217) && (hw->phy.revision == 6) &&
+ to_sx && (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
+
+ ret_val = e1000_write_phy_reg_hv_locked(hw, HV_OEM_BITS,
+ oem_reg);
+ if (ret_val)
+ goto release;
+ }
+
release:
hw->phy.ops.release(hw);
out:
@@ -1467,7 +1384,8 @@ out:
static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
- s32 ret_val;
+ s32 ret_val, tipg_reg = 0;
+ u16 emi_addr, emi_val = 0;
bool link;
u16 phy_reg;
@@ -1500,35 +1418,92 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
* the IPG and reduce Rx latency in the PHY.
*/
if (((hw->mac.type == e1000_pch2lan) ||
- (hw->mac.type == e1000_pch_lpt)) && link) {
- u32 reg;
- reg = E1000_READ_REG(hw, E1000_STATUS);
- if (!(reg & (E1000_STATUS_FD | E1000_STATUS_SPEED_MASK))) {
- u16 emi_addr;
+ (hw->mac.type == e1000_pch_lpt) ||
+ (hw->mac.type == e1000_pch_spt)) && link) {
+ u16 speed, duplex;
- reg = E1000_READ_REG(hw, E1000_TIPG);
- reg &= ~E1000_TIPG_IPGT_MASK;
- reg |= 0xFF;
- E1000_WRITE_REG(hw, E1000_TIPG, reg);
+ e1000_get_speed_and_duplex_copper_generic(hw, &speed, &duplex);
+ tipg_reg = E1000_READ_REG(hw, E1000_TIPG);
+ tipg_reg &= ~E1000_TIPG_IPGT_MASK;
+ if (duplex == HALF_DUPLEX && speed == SPEED_10) {
+ tipg_reg |= 0xFF;
/* Reduce Rx latency in analog PHY */
- ret_val = hw->phy.ops.acquire(hw);
- if (ret_val)
- return ret_val;
+ emi_val = 0;
+ } else if (hw->mac.type == e1000_pch_spt &&
+ duplex == FULL_DUPLEX && speed != SPEED_1000) {
+ tipg_reg |= 0xC;
+ emi_val = 1;
+ } else {
+ /* Roll back the default values */
+ tipg_reg |= 0x08;
+ emi_val = 1;
+ }
- if (hw->mac.type == e1000_pch2lan)
- emi_addr = I82579_RX_CONFIG;
- else
- emi_addr = I217_RX_CONFIG;
- ret_val = e1000_write_emi_reg_locked(hw, emi_addr, 0);
+ E1000_WRITE_REG(hw, E1000_TIPG, tipg_reg);
- hw->phy.ops.release(hw);
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
- if (ret_val)
- return ret_val;
+ if (hw->mac.type == e1000_pch2lan)
+ emi_addr = I82579_RX_CONFIG;
+ else
+ emi_addr = I217_RX_CONFIG;
+ ret_val = e1000_write_emi_reg_locked(hw, emi_addr, emi_val);
+
+ hw->phy.ops.release(hw);
+
+ if (ret_val)
+ return ret_val;
+
+ if (hw->mac.type == e1000_pch_spt) {
+ u16 data;
+ u16 ptr_gap;
+
+ if (speed == SPEED_1000) {
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = hw->phy.ops.read_reg_locked(hw,
+ PHY_REG(776, 20),
+ &data);
+ if (ret_val) {
+ hw->phy.ops.release(hw);
+ return ret_val;
+ }
+
+ ptr_gap = (data & (0x3FF << 2)) >> 2;
+ if (ptr_gap < 0x18) {
+ data &= ~(0x3FF << 2);
+ data |= (0x18 << 2);
+ ret_val =
+ hw->phy.ops.write_reg_locked(hw,
+ PHY_REG(776, 20), data);
+ }
+ hw->phy.ops.release(hw);
+ if (ret_val)
+ return ret_val;
+ }
}
}
+ /* I217 Packet Loss issue:
+ * ensure that FEXTNVM4 Beacon Duration is set correctly
+ * on power up.
+ * Set the Beacon Duration for I217 to 8 usec
+ */
+ if ((hw->mac.type == e1000_pch_lpt) ||
+ (hw->mac.type == e1000_pch_spt)) {
+ u32 mac_reg;
+
+ mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4);
+ mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
+ mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC;
+ E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg);
+ }
+
/* Work-around I218 hang issue */
if ((hw->device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) ||
(hw->device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) ||
@@ -1538,19 +1513,22 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
if (ret_val)
return ret_val;
}
- if (hw->mac.type == e1000_pch_lpt) {
- /* Set platform power management values for
- * Latency Tolerance Reporting (LTR)
- * Optimized Buffer Flush/Fill (OBFF)
- */
- ret_val = e1000_platform_pm_pch_lpt(hw, link);
- if (ret_val)
- return ret_val;
- }
-
/* Clear link partner's EEE ability */
hw->dev_spec.ich8lan.eee_lp_ability = 0;
+ /* FEXTNVM6 K1-off workaround */
+ if (hw->mac.type == e1000_pch_spt) {
+ u32 pcieanacfg = E1000_READ_REG(hw, E1000_PCIEANACFG);
+ u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6);
+
+ if (pcieanacfg & E1000_FEXTNVM6_K1_OFF_ENABLE)
+ fextnvm6 |= E1000_FEXTNVM6_K1_OFF_ENABLE;
+ else
+ fextnvm6 &= ~E1000_FEXTNVM6_K1_OFF_ENABLE;
+
+ E1000_WRITE_REG(hw, E1000_FEXTNVM6, fextnvm6);
+ }
+
if (!link)
return E1000_SUCCESS; /* No link detected */
@@ -1644,6 +1622,7 @@ void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw)
case e1000_pchlan:
case e1000_pch2lan:
case e1000_pch_lpt:
+ case e1000_pch_spt:
hw->phy.ops.init_params = e1000_init_phy_params_pchlan;
break;
default:
@@ -2107,6 +2086,7 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
case e1000_pchlan:
case e1000_pch2lan:
case e1000_pch_lpt:
+ case e1000_pch_spt:
sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
break;
default:
@@ -3222,6 +3202,20 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
DEBUGFUNC("e1000_valid_nvm_bank_detect_ich8lan");
switch (hw->mac.type) {
+ /* In SPT, read from the CTRL_EXT reg instead of
+ * accessing the sector valid bits from the nvm
+ */
+ case e1000_pch_spt:
+ *bank = E1000_READ_REG(hw, E1000_CTRL_EXT)
+ & E1000_CTRL_EXT_NVMVS;
+ if ((*bank == 0) || (*bank == 1)) {
+ DEBUGOUT("ERROR: No valid NVM bank present\n");
+ return -E1000_ERR_NVM;
+ } else {
+ *bank = *bank - 2;
+ return E1000_SUCCESS;
+ }
+ break;
case e1000_ich8lan:
case e1000_ich9lan:
eecd = E1000_READ_REG(hw, E1000_EECD);
@@ -3269,6 +3263,99 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
}
/**
+ * e1000_read_nvm_spt - NVM access for SPT
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the word(s) to read.
+ * @words: Size of data to read in words.
+ * @data: pointer to the word(s) to read at offset.
+ *
+ * Reads a word(s) from the NVM
+ **/
+static s32 e1000_read_nvm_spt(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ u32 act_offset;
+ s32 ret_val = E1000_SUCCESS;
+ u32 bank = 0;
+ u32 dword = 0;
+ u16 offset_to_read;
+ u16 i;
+
+ DEBUGFUNC("e1000_read_nvm_spt");
+
+ if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
+ (words == 0)) {
+ DEBUGOUT("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ nvm->ops.acquire(hw);
+
+ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
+ if (ret_val != E1000_SUCCESS) {
+ DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
+ bank = 0;
+ }
+
+ act_offset = (bank) ? nvm->flash_bank_size : 0;
+ act_offset += offset;
+
+ ret_val = E1000_SUCCESS;
+
+ for (i = 0; i < words; i += 2) {
+ if (words - i == 1) {
+ if (dev_spec->shadow_ram[offset+i].modified) {
+ data[i] = dev_spec->shadow_ram[offset+i].value;
+ } else {
+ offset_to_read = act_offset + i -
+ ((act_offset + i) % 2);
+ ret_val =
+ e1000_read_flash_dword_ich8lan(hw,
+ offset_to_read,
+ &dword);
+ if (ret_val)
+ break;
+ if ((act_offset + i) % 2 == 0)
+ data[i] = (u16)(dword & 0xFFFF);
+ else
+ data[i] = (u16)((dword >> 16) & 0xFFFF);
+ }
+ } else {
+ offset_to_read = act_offset + i;
+ if (!(dev_spec->shadow_ram[offset+i].modified) ||
+ !(dev_spec->shadow_ram[offset+i+1].modified)) {
+ ret_val =
+ e1000_read_flash_dword_ich8lan(hw,
+ offset_to_read,
+ &dword);
+ if (ret_val)
+ break;
+ }
+ if (dev_spec->shadow_ram[offset+i].modified)
+ data[i] = dev_spec->shadow_ram[offset+i].value;
+ else
+ data[i] = (u16) (dword & 0xFFFF);
+ if (dev_spec->shadow_ram[offset+i].modified)
+ data[i+1] =
+ dev_spec->shadow_ram[offset+i+1].value;
+ else
+ data[i+1] = (u16) (dword >> 16 & 0xFFFF);
+ }
+ }
+
+ nvm->ops.release(hw);
+
+out:
+ if (ret_val)
+ DEBUGOUT1("NVM read error: %d\n", ret_val);
+
+ return ret_val;
+}
+
+/**
* e1000_read_nvm_ich8lan - Read word(s) from the NVM
* @hw: pointer to the HW structure
* @offset: The offset (in bytes) of the word(s) to read.
@@ -3355,7 +3442,11 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
/* Clear FCERR and DAEL in hw status by writing 1 */
hsfsts.hsf_status.flcerr = 1;
hsfsts.hsf_status.dael = 1;
- E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
+ if (hw->mac.type == e1000_pch_spt)
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
+ hsfsts.regval & 0xFFFF);
+ else
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
/* Either we should have a hardware SPI cycle in progress
* bit to check against, in order to start a new cycle or
@@ -3371,7 +3462,12 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
* Begin by setting Flash Cycle Done.
*/
hsfsts.hsf_status.flcdone = 1;
- E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
+ if (hw->mac.type == e1000_pch_spt)
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
+ hsfsts.regval & 0xFFFF);
+ else
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
+ hsfsts.regval);
ret_val = E1000_SUCCESS;
} else {
s32 i;
@@ -3393,8 +3489,12 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
* now set the Flash Cycle Done.
*/
hsfsts.hsf_status.flcdone = 1;
- E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
- hsfsts.regval);
+ if (hw->mac.type == e1000_pch_spt)
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
+ hsfsts.regval & 0xFFFF);
+ else
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
+ hsfsts.regval);
} else {
DEBUGOUT("Flash controller busy, cannot get access\n");
}
@@ -3419,10 +3519,17 @@ static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
DEBUGFUNC("e1000_flash_cycle_ich8lan");
/* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
- hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
+ if (hw->mac.type == e1000_pch_spt)
+ hsflctl.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16;
+ else
+ hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
hsflctl.hsf_ctrl.flcgo = 1;
- E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
+ if (hw->mac.type == e1000_pch_spt)
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
+ hsflctl.regval << 16);
+ else
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
/* wait till FDONE bit is set to 1 */
do {
@@ -3439,6 +3546,29 @@ static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
}
/**
+ * e1000_read_flash_dword_ich8lan - Read dword from flash
+ * @hw: pointer to the HW structure
+ * @offset: offset to data location
+ * @data: pointer to the location for storing the data
+ *
+ * Reads the flash dword at offset into data. Offset is converted
+ * to bytes before read.
+ **/
+static s32 e1000_read_flash_dword_ich8lan(struct e1000_hw *hw, u32 offset,
+ u32 *data)
+{
+ DEBUGFUNC("e1000_read_flash_dword_ich8lan");
+
+ if (!data)
+ return -E1000_ERR_NVM;
+
+ /* Must convert word offset into bytes. */
+ offset <<= 1;
+
+ return e1000_read_flash_data32_ich8lan(hw, offset, data);
+}
+
+/**
* e1000_read_flash_word_ich8lan - Read word from flash
* @hw: pointer to the HW structure
* @offset: offset to data location
@@ -3475,7 +3605,13 @@ static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
s32 ret_val;
u16 word = 0;
- ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
+ /* In SPT, only 32 bits access is supported,
+ * so this function should not be called.
+ */
+ if (hw->mac.type == e1000_pch_spt)
+ return -E1000_ERR_NVM;
+ else
+ ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
if (ret_val)
return ret_val;
@@ -3563,6 +3699,84 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
/**
+ * e1000_read_flash_data32_ich8lan - Read dword from NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the dword to read.
+ * @data: Pointer to the dword to store the value read.
+ *
+ * Reads a byte or word from the NVM using the flash access registers.
+ **/
+
+static s32 e1000_read_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset,
+ u32 *data)
+{
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ u32 flash_linear_addr;
+ s32 ret_val = -E1000_ERR_NVM;
+ u8 count = 0;
+
+ DEBUGFUNC("e1000_read_flash_data_ich8lan");
+
+ if (offset > ICH_FLASH_LINEAR_ADDR_MASK ||
+ hw->mac.type != e1000_pch_spt)
+ return -E1000_ERR_NVM;
+ flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+ hw->nvm.flash_base_addr);
+
+ do {
+ usec_delay(1);
+ /* Steps */
+ ret_val = e1000_flash_cycle_init_ich8lan(hw);
+ if (ret_val != E1000_SUCCESS)
+ break;
+ /* In SPT, This register is in Lan memory space, not flash.
+ * Therefore, only 32 bit access is supported
+ */
+ hsflctl.regval = E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16;
+
+ /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+ hsflctl.hsf_ctrl.fldbcount = sizeof(u32) - 1;
+ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
+ /* In SPT, This register is in Lan memory space, not flash.
+ * Therefore, only 32 bit access is supported
+ */
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
+ (u32)hsflctl.regval << 16);
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
+
+ ret_val = e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_READ_COMMAND_TIMEOUT);
+
+ /* Check if FCERR is set to 1, if set to 1, clear it
+ * and try the whole sequence a few more times, else
+ * read in (shift in) the Flash Data0, the order is
+ * least significant byte first msb to lsb
+ */
+ if (ret_val == E1000_SUCCESS) {
+ *data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0);
+ break;
+ } else {
+ /* If we've gotten here, then things are probably
+ * completely hosed, but if the error condition is
+ * detected, it won't hurt to give it another try...
+ * ICH_FLASH_CYCLE_REPEAT_COUNT times.
+ */
+ hsfsts.regval = E1000_READ_FLASH_REG16(hw,
+ ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr) {
+ /* Repeat for some time before giving up. */
+ continue;
+ } else if (!hsfsts.hsf_status.flcdone) {
+ DEBUGOUT("Timeout error - flash cycle did not complete.\n");
+ break;
+ }
+ }
+ } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
+
+ return ret_val;
+}
+/**
* e1000_write_nvm_ich8lan - Write word(s) to the NVM
* @hw: pointer to the HW structure
* @offset: The offset (in bytes) of the word(s) to write.
@@ -3599,6 +3813,175 @@ static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
}
/**
+ * e1000_update_nvm_checksum_spt - Update the checksum for NVM
+ * @hw: pointer to the HW structure
+ *
+ * The NVM checksum is updated by calling the generic update_nvm_checksum,
+ * which writes the checksum to the shadow ram. The changes in the shadow
+ * ram are then committed to the EEPROM by processing each bank at a time
+ * checking for the modified bit and writing only the pending changes.
+ * After a successful commit, the shadow ram is cleared and is ready for
+ * future writes.
+ **/
+static s32 e1000_update_nvm_checksum_spt(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
+ s32 ret_val;
+ u32 dword = 0;
+
+ DEBUGFUNC("e1000_update_nvm_checksum_spt");
+
+ ret_val = e1000_update_nvm_checksum_generic(hw);
+ if (ret_val)
+ goto out;
+
+ if (nvm->type != e1000_nvm_flash_sw)
+ goto out;
+
+ nvm->ops.acquire(hw);
+
+ /* We're writing to the opposite bank so if we're on bank 1,
+ * write to bank 0 etc. We also need to erase the segment that
+ * is going to be written
+ */
+ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
+ if (ret_val != E1000_SUCCESS) {
+ DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
+ bank = 0;
+ }
+
+ if (bank == 0) {
+ new_bank_offset = nvm->flash_bank_size;
+ old_bank_offset = 0;
+ ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
+ if (ret_val)
+ goto release;
+ } else {
+ old_bank_offset = nvm->flash_bank_size;
+ new_bank_offset = 0;
+ ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
+ if (ret_val)
+ goto release;
+ }
+ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i += 2) {
+ /* Determine whether to write the value stored
+ * in the other NVM bank or a modified value stored
+ * in the shadow RAM
+ */
+ ret_val = e1000_read_flash_dword_ich8lan(hw,
+ i + old_bank_offset,
+ &dword);
+
+ if (dev_spec->shadow_ram[i].modified) {
+ dword &= 0xffff0000;
+ dword |= (dev_spec->shadow_ram[i].value & 0xffff);
+ }
+ if (dev_spec->shadow_ram[i + 1].modified) {
+ dword &= 0x0000ffff;
+ dword |= ((dev_spec->shadow_ram[i + 1].value & 0xffff)
+ << 16);
+ }
+ if (ret_val)
+ break;
+
+ /* If the word is 0x13, then make sure the signature bits
+ * (15:14) are 11b until the commit has completed.
+ * This will allow us to write 10b which indicates the
+ * signature is valid. We want to do this after the write
+ * has completed so that we don't mark the segment valid
+ * while the write is still in progress
+ */
+ if (i == E1000_ICH_NVM_SIG_WORD - 1)
+ dword |= E1000_ICH_NVM_SIG_MASK << 16;
+
+ /* Convert offset to bytes. */
+ act_offset = (i + new_bank_offset) << 1;
+
+ usec_delay(100);
+
+ /* Write the data to the new bank. Offset in words*/
+ act_offset = i + new_bank_offset;
+ ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset,
+ dword);
+ if (ret_val)
+ break;
+ }
+
+ /* Don't bother writing the segment valid bits if sector
+ * programming failed.
+ */
+ if (ret_val) {
+ DEBUGOUT("Flash commit failed.\n");
+ goto release;
+ }
+
+ /* Finally validate the new segment by setting bit 15:14
+ * to 10b in word 0x13 , this can be done without an
+ * erase as well since these bits are 11 to start with
+ * and we need to change bit 14 to 0b
+ */
+ act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
+
+ /*offset in words but we read dword*/
+ --act_offset;
+ ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword);
+
+ if (ret_val)
+ goto release;
+
+ dword &= 0xBFFFFFFF;
+ ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword);
+
+ if (ret_val)
+ goto release;
+
+ /* And invalidate the previously valid segment by setting
+ * its signature word (0x13) high_byte to 0b. This can be
+ * done without an erase because flash erase sets all bits
+ * to 1's. We can write 1's to 0's without an erase
+ */
+ act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
+
+ /* offset in words but we read dword*/
+ act_offset = old_bank_offset + E1000_ICH_NVM_SIG_WORD - 1;
+ ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword);
+
+ if (ret_val)
+ goto release;
+
+ dword &= 0x00FFFFFF;
+ ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword);
+
+ if (ret_val)
+ goto release;
+
+ /* Great! Everything worked, we can now clear the cached entries. */
+ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+ dev_spec->shadow_ram[i].modified = FALSE;
+ dev_spec->shadow_ram[i].value = 0xFFFF;
+ }
+
+release:
+ nvm->ops.release(hw);
+
+ /* Reload the EEPROM, or else modifications will not appear
+ * until after the next adapter reset.
+ */
+ if (!ret_val) {
+ nvm->ops.reload(hw);
+ msec_delay(10);
+ }
+
+out:
+ if (ret_val)
+ DEBUGOUT1("NVM update error: %d\n", ret_val);
+
+ return ret_val;
+}
+
+/**
* e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
* @hw: pointer to the HW structure
*
@@ -3775,6 +4158,7 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
*/
switch (hw->mac.type) {
case e1000_pch_lpt:
+ case e1000_pch_spt:
word = NVM_COMPAT;
valid_csum_mask = NVM_COMPAT_VALID_CSUM;
break;
@@ -3822,8 +4206,13 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
DEBUGFUNC("e1000_write_ich8_data");
- if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
- return -E1000_ERR_NVM;
+ if (hw->mac.type == e1000_pch_spt) {
+ if (size != 4 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
+ return -E1000_ERR_NVM;
+ } else {
+ if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
+ return -E1000_ERR_NVM;
+ }
flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
hw->nvm.flash_base_addr);
@@ -3834,12 +4223,29 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
ret_val = e1000_flash_cycle_init_ich8lan(hw);
if (ret_val != E1000_SUCCESS)
break;
- hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
+ /* In SPT, This register is in Lan memory space, not
+ * flash. Therefore, only 32 bit access is supported
+ */
+ if (hw->mac.type == e1000_pch_spt)
+ hsflctl.regval =
+ E1000_READ_FLASH_REG(hw, ICH_FLASH_HSFSTS)>>16;
+ else
+ hsflctl.regval =
+ E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
hsflctl.hsf_ctrl.fldbcount = size - 1;
hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
- E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
+ /* In SPT, This register is in Lan memory space,
+ * not flash. Therefore, only 32 bit access is
+ * supported
+ */
+ if (hw->mac.type == e1000_pch_spt)
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
+ hsflctl.regval << 16);
+ else
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
+ hsflctl.regval);
E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
@@ -3877,6 +4283,94 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
return ret_val;
}
+/**
+* e1000_write_flash_data32_ich8lan - Writes 4 bytes to the NVM
+* @hw: pointer to the HW structure
+* @offset: The offset (in bytes) of the dwords to read.
+* @data: The 4 bytes to write to the NVM.
+*
+* Writes one/two/four bytes to the NVM using the flash access registers.
+**/
+static s32 e1000_write_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset,
+ u32 data)
+{
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ u32 flash_linear_addr;
+ s32 ret_val;
+ u8 count = 0;
+
+ DEBUGFUNC("e1000_write_flash_data32_ich8lan");
+
+ if (hw->mac.type == e1000_pch_spt) {
+ if (offset > ICH_FLASH_LINEAR_ADDR_MASK)
+ return -E1000_ERR_NVM;
+ }
+ flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+ hw->nvm.flash_base_addr);
+ do {
+ usec_delay(1);
+ /* Steps */
+ ret_val = e1000_flash_cycle_init_ich8lan(hw);
+ if (ret_val != E1000_SUCCESS)
+ break;
+
+ /* In SPT, This register is in Lan memory space, not
+ * flash. Therefore, only 32 bit access is supported
+ */
+ if (hw->mac.type == e1000_pch_spt)
+ hsflctl.regval = E1000_READ_FLASH_REG(hw,
+ ICH_FLASH_HSFSTS)
+ >> 16;
+ else
+ hsflctl.regval = E1000_READ_FLASH_REG16(hw,
+ ICH_FLASH_HSFCTL);
+
+ hsflctl.hsf_ctrl.fldbcount = sizeof(u32) - 1;
+ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
+
+ /* In SPT, This register is in Lan memory space,
+ * not flash. Therefore, only 32 bit access is
+ * supported
+ */
+ if (hw->mac.type == e1000_pch_spt)
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
+ hsflctl.regval << 16);
+ else
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
+ hsflctl.regval);
+
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
+
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, data);
+
+ /* check if FCERR is set to 1 , if set to 1, clear it
+ * and try the whole sequence a few more times else done
+ */
+ ret_val = e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_WRITE_COMMAND_TIMEOUT);
+
+ if (ret_val == E1000_SUCCESS)
+ break;
+
+ /* If we're here, then things are most likely
+ * completely hosed, but if the error condition
+ * is detected, it won't hurt to give it another
+ * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
+ */
+ hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
+
+ if (hsfsts.hsf_status.flcerr)
+ /* Repeat for some time before giving up. */
+ continue;
+ if (!hsfsts.hsf_status.flcdone) {
+ DEBUGOUT("Timeout error - flash cycle did not complete.\n");
+ break;
+ }
+ } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
+
+ return ret_val;
+}
/**
* e1000_write_flash_byte_ich8lan - Write a single byte to NVM
@@ -3899,6 +4393,44 @@ static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
/**
+* e1000_retry_write_flash_dword_ich8lan - Writes a dword to NVM
+* @hw: pointer to the HW structure
+* @offset: The offset of the word to write.
+* @dword: The dword to write to the NVM.
+*
+* Writes a single dword to the NVM using the flash access registers.
+* Goes through a retry algorithm before giving up.
+**/
+static s32 e1000_retry_write_flash_dword_ich8lan(struct e1000_hw *hw,
+ u32 offset, u32 dword)
+{
+ s32 ret_val;
+ u16 program_retries;
+
+ DEBUGFUNC("e1000_retry_write_flash_dword_ich8lan");
+
+ /* Must convert word offset into bytes. */
+ offset <<= 1;
+
+ ret_val = e1000_write_flash_data32_ich8lan(hw, offset, dword);
+
+ if (!ret_val)
+ return ret_val;
+ for (program_retries = 0; program_retries < 100; program_retries++) {
+ DEBUGOUT2("Retrying Byte %8.8X at offset %u\n", dword, offset);
+ usec_delay(100);
+ ret_val = e1000_write_flash_data32_ich8lan(hw, offset, dword);
+ if (ret_val == E1000_SUCCESS)
+ break;
+ }
+ if (program_retries == 100)
+ return -E1000_ERR_NVM;
+
+ return E1000_SUCCESS;
+}
+
+
+/**
* e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
* @hw: pointer to the HW structure
* @offset: The offset of the byte to write.
@@ -4006,12 +4538,22 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
/* Write a value 11 (block Erase) in Flash
* Cycle field in hw flash control
*/
- hsflctl.regval =
- E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
+ if (hw->mac.type == e1000_pch_spt)
+ hsflctl.regval =
+ E1000_READ_FLASH_REG(hw,
+ ICH_FLASH_HSFSTS)>>16;
+ else
+ hsflctl.regval =
+ E1000_READ_FLASH_REG16(hw,
+ ICH_FLASH_HSFCTL);
hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
- E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
- hsflctl.regval);
+ if (hw->mac.type == e1000_pch_spt)
+ E1000_WRITE_FLASH_REG(hw, ICH_FLASH_HSFSTS,
+ hsflctl.regval << 16);
+ else
+ E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
+ hsflctl.regval);
/* Write the last 24 bits of an index within the
* block into Flash Linear address field in Flash
@@ -4444,7 +4986,8 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
E1000_WRITE_REG(hw, E1000_RFCTL, reg);
/* Enable ECC on Lynxpoint */
- if (hw->mac.type == e1000_pch_lpt) {
+ if ((hw->mac.type == e1000_pch_lpt) ||
+ (hw->mac.type == e1000_pch_spt)) {
reg = E1000_READ_REG(hw, E1000_PBECCSTS);
reg |= E1000_PBECCSTS_ECC_ENABLE;
E1000_WRITE_REG(hw, E1000_PBECCSTS, reg);
@@ -4876,7 +5419,8 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
if ((device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) ||
(device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) ||
(device_id == E1000_DEV_ID_PCH_I218_LM3) ||
- (device_id == E1000_DEV_ID_PCH_I218_V3)) {
+ (device_id == E1000_DEV_ID_PCH_I218_V3) ||
+ (hw->mac.type == e1000_pch_spt)) {
u32 fextnvm6 = E1000_READ_REG(hw, E1000_FEXTNVM6);
E1000_WRITE_REG(hw, E1000_FEXTNVM6,
@@ -4992,18 +5536,18 @@ out:
* the PHY.
* On i217, setup Intel Rapid Start Technology.
**/
-void e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
+u32 e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
{
s32 ret_val;
DEBUGFUNC("e1000_resume_workarounds_pchlan");
if (hw->mac.type < e1000_pch2lan)
- return;
+ return E1000_SUCCESS;
ret_val = e1000_init_phy_workarounds_pchlan(hw);
if (ret_val) {
DEBUGOUT1("Failed to init PHY flow ret_val=%d\n", ret_val);
- return;
+ return ret_val;
}
/* For i217 Intel Rapid Start Technology support when the system
@@ -5017,7 +5561,7 @@ void e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
ret_val = hw->phy.ops.acquire(hw);
if (ret_val) {
DEBUGOUT("Failed to setup iRST\n");
- return;
+ return ret_val;
}
/* Clear Auto Enable LPI after link up */
@@ -5051,7 +5595,9 @@ release:
if (ret_val)
DEBUGOUT1("Error %d in resume workarounds\n", ret_val);
hw->phy.ops.release(hw);
+ return ret_val;
}
+ return E1000_SUCCESS;
}
/**
diff --git a/sys/dev/e1000/e1000_ich8lan.h b/sys/dev/e1000/e1000_ich8lan.h
index 9cb79c0..b2d0991 100644
--- a/sys/dev/e1000/e1000_ich8lan.h
+++ b/sys/dev/e1000/e1000_ich8lan.h
@@ -107,9 +107,25 @@
#define E1000_FEXTNVM6_REQ_PLL_CLK 0x00000100
#define E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION 0x00000200
-
+#define E1000_FEXTNVM6_K1_OFF_ENABLE 0x80000000
+/* bit for disabling packet buffer read */
+#define E1000_FEXTNVM7_DISABLE_PB_READ 0x00040000
+#define E1000_FEXTNVM7_SIDE_CLK_UNGATE 0x00000004
#define E1000_FEXTNVM7_DISABLE_SMB_PERST 0x00000020
-
+#define E1000_FEXTNVM9_IOSFSB_CLKGATE_DIS 0x00000800
+#define E1000_FEXTNVM9_IOSFSB_CLKREQ_DIS 0x00001000
+#define E1000_FEXTNVM11_DISABLE_PB_READ 0x00000200
+#define E1000_FEXTNVM11_DISABLE_MULR_FIX 0x00002000
+
+/* bit24: RXDCTL thresholds granularity: 0 - cache lines, 1 - descriptors */
+#define E1000_RXDCTL_THRESH_UNIT_DESC 0x01000000
+
+#define NVM_SIZE_MULTIPLIER 4096 /*multiplier for NVMS field*/
+#define E1000_FLASH_BASE_ADDR 0xE000 /*offset of NVM access regs*/
+#define E1000_CTRL_EXT_NVMVS 0x3 /*NVM valid sector */
+#define E1000_SPT_B_STEP_REV 0x10 /*SPT B step Rev ID*/
+#define E1000_TARC0_CB_MULTIQ_2_REQ (1 << 29)
+#define E1000_TARC0_CB_MULTIQ_3_REQ (1 << 28 | 1 << 29)
#define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL
#define E1000_ICH_RAR_ENTRIES 7
@@ -171,6 +187,8 @@
#define E1000_NVM_K1_CONFIG 0x1B /* NVM K1 Config Word */
#define E1000_NVM_K1_ENABLE 0x1 /* NVM Enable K1 bit */
+#define K1_ENTRY_LATENCY 0
+#define K1_MIN_TIME 1
/* SMBus Control Phy Register */
#define CV_SMB_CTRL PHY_REG(769, 23)
@@ -281,36 +299,13 @@
/* Receive Address Initial CRC Calculation */
#define E1000_PCH_RAICC(_n) (0x05F50 + ((_n) * 4))
-/* Latency Tolerance Reporting */
-#define E1000_LTRV 0x000F8
-#define E1000_LTRV_VALUE_MASK 0x000003FF
-#define E1000_LTRV_SCALE_MAX 5
-#define E1000_LTRV_SCALE_FACTOR 5
-#define E1000_LTRV_SCALE_SHIFT 10
-#define E1000_LTRV_SCALE_MASK 0x00001C00
-#define E1000_LTRV_REQ_SHIFT 15
-#define E1000_LTRV_NOSNOOP_SHIFT 16
-#define E1000_LTRV_SEND (1 << 30)
-
-/* Proprietary Latency Tolerance Reporting PCI Capability */
-#define E1000_PCI_LTR_CAP_LPT 0xA8
-
-/* OBFF Control & Threshold Defines */
-#define E1000_SVCR_OFF_EN 0x00000001
-#define E1000_SVCR_OFF_MASKINT 0x00001000
-#define E1000_SVCR_OFF_TIMER_MASK 0xFFFF0000
-#define E1000_SVCR_OFF_TIMER_SHIFT 16
-#define E1000_SVT_OFF_HWM_MASK 0x0000001F
-
-#if defined(QV_RELEASE) || !defined(NO_PCH_LPT_B0_SUPPORT)
#define E1000_PCI_REVISION_ID_REG 0x08
-#endif /* defined(QV_RELEASE) || !defined(NO_PCH_LPT_B0_SUPPORT) */
void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
bool state);
void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw);
-void e1000_resume_workarounds_pchlan(struct e1000_hw *hw);
+u32 e1000_resume_workarounds_pchlan(struct e1000_hw *hw);
s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable);
void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw);
s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
diff --git a/sys/dev/e1000/e1000_mac.c b/sys/dev/e1000/e1000_mac.c
index 1c86307..58137b1 100644
--- a/sys/dev/e1000/e1000_mac.c
+++ b/sys/dev/e1000/e1000_mac.c
@@ -70,7 +70,6 @@ void e1000_init_mac_ops_generic(struct e1000_hw *hw)
mac->ops.setup_link = e1000_null_ops_generic;
mac->ops.get_link_up_info = e1000_null_link_info;
mac->ops.check_for_link = e1000_null_ops_generic;
- mac->ops.set_obff_timer = e1000_null_set_obff_timer;
/* Management */
mac->ops.check_mng_mode = e1000_null_mng_mode;
/* VLAN, MC, etc. */
@@ -156,17 +155,6 @@ int e1000_null_rar_set(struct e1000_hw E1000_UNUSEDARG *hw,
}
/**
- * e1000_null_set_obff_timer - No-op function, return 0
- * @hw: pointer to the HW structure
- **/
-s32 e1000_null_set_obff_timer(struct e1000_hw E1000_UNUSEDARG *hw,
- u32 E1000_UNUSEDARG a)
-{
- DEBUGFUNC("e1000_null_set_obff_timer");
- return E1000_SUCCESS;
-}
-
-/**
* e1000_get_bus_info_pci_generic - Get PCI(x) bus information
* @hw: pointer to the HW structure
*
diff --git a/sys/dev/e1000/e1000_mac.h b/sys/dev/e1000/e1000_mac.h
index 1daed9b..2445f46 100644
--- a/sys/dev/e1000/e1000_mac.h
+++ b/sys/dev/e1000/e1000_mac.h
@@ -36,9 +36,7 @@
#define _E1000_MAC_H_
void e1000_init_mac_ops_generic(struct e1000_hw *hw);
-#ifndef E1000_REMOVED
#define E1000_REMOVED(a) (0)
-#endif /* E1000_REMOVED */
void e1000_null_mac_generic(struct e1000_hw *hw);
s32 e1000_null_ops_generic(struct e1000_hw *hw);
s32 e1000_null_link_info(struct e1000_hw *hw, u16 *s, u16 *d);
@@ -46,7 +44,6 @@ bool e1000_null_mng_mode(struct e1000_hw *hw);
void e1000_null_update_mc(struct e1000_hw *hw, u8 *h, u32 a);
void e1000_null_write_vfta(struct e1000_hw *hw, u32 a, u32 b);
int e1000_null_rar_set(struct e1000_hw *hw, u8 *h, u32 a);
-s32 e1000_null_set_obff_timer(struct e1000_hw *hw, u32 a);
s32 e1000_blink_led_generic(struct e1000_hw *hw);
s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw);
s32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw);
diff --git a/sys/dev/e1000/e1000_nvm.c b/sys/dev/e1000/e1000_nvm.c
index 0a1a18d..6eafbb2 100644
--- a/sys/dev/e1000/e1000_nvm.c
+++ b/sys/dev/e1000/e1000_nvm.c
@@ -930,6 +930,41 @@ s32 e1000_read_pba_length_generic(struct e1000_hw *hw, u32 *pba_num_size)
return E1000_SUCCESS;
}
+/**
+ * e1000_read_pba_num_generic - Read device part number
+ * @hw: pointer to the HW structure
+ * @pba_num: pointer to device part number
+ *
+ * Reads the product board assembly (PBA) number from the EEPROM and stores
+ * the value in pba_num.
+ **/
+s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num)
+{
+ s32 ret_val;
+ u16 nvm_data;
+
+ DEBUGFUNC("e1000_read_pba_num_generic");
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ return ret_val;
+ } else if (nvm_data == NVM_PBA_PTR_GUARD) {
+ DEBUGOUT("NVM Not Supported\n");
+ return -E1000_NOT_IMPLEMENTED;
+ }
+ *pba_num = (u32)(nvm_data << 16);
+
+ ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
+ if (ret_val) {
+ DEBUGOUT("NVM Read Error\n");
+ return ret_val;
+ }
+ *pba_num |= nvm_data;
+
+ return E1000_SUCCESS;
+}
+
/**
* e1000_read_pba_raw
@@ -1232,4 +1267,115 @@ static void e1000_reload_nvm_generic(struct e1000_hw *hw)
E1000_WRITE_FLUSH(hw);
}
+/**
+ * e1000_get_fw_version - Get firmware version information
+ * @hw: pointer to the HW structure
+ * @fw_vers: pointer to output version structure
+ *
+ * unsupported/not present features return 0 in version structure
+ **/
+void e1000_get_fw_version(struct e1000_hw *hw, struct e1000_fw_version *fw_vers)
+{
+ u16 eeprom_verh, eeprom_verl, etrack_test, fw_version;
+ u8 q, hval, rem, result;
+ u16 comb_verh, comb_verl, comb_offset;
+
+ memset(fw_vers, 0, sizeof(struct e1000_fw_version));
+
+ /* basic eeprom version numbers, bits used vary by part and by tool
+ * used to create the nvm images */
+ /* Check which data format we have */
+ switch (hw->mac.type) {
+ case e1000_i211:
+ e1000_read_invm_version(hw, fw_vers);
+ return;
+ case e1000_82575:
+ case e1000_82576:
+ case e1000_82580:
+ hw->nvm.ops.read(hw, NVM_ETRACK_HIWORD, 1, &etrack_test);
+ /* Use this format, unless EETRACK ID exists,
+ * then use alternate format
+ */
+ if ((etrack_test & NVM_MAJOR_MASK) != NVM_ETRACK_VALID) {
+ hw->nvm.ops.read(hw, NVM_VERSION, 1, &fw_version);
+ fw_vers->eep_major = (fw_version & NVM_MAJOR_MASK)
+ >> NVM_MAJOR_SHIFT;
+ fw_vers->eep_minor = (fw_version & NVM_MINOR_MASK)
+ >> NVM_MINOR_SHIFT;
+ fw_vers->eep_build = (fw_version & NVM_IMAGE_ID_MASK);
+ goto etrack_id;
+ }
+ break;
+ case e1000_i210:
+ if (!(e1000_get_flash_presence_i210(hw))) {
+ e1000_read_invm_version(hw, fw_vers);
+ return;
+ }
+ /* fall through */
+ case e1000_i350:
+ hw->nvm.ops.read(hw, NVM_ETRACK_HIWORD, 1, &etrack_test);
+ /* find combo image version */
+ hw->nvm.ops.read(hw, NVM_COMB_VER_PTR, 1, &comb_offset);
+ if ((comb_offset != 0x0) &&
+ (comb_offset != NVM_VER_INVALID)) {
+
+ hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset
+ + 1), 1, &comb_verh);
+ hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset),
+ 1, &comb_verl);
+
+ /* get Option Rom version if it exists and is valid */
+ if ((comb_verh && comb_verl) &&
+ ((comb_verh != NVM_VER_INVALID) &&
+ (comb_verl != NVM_VER_INVALID))) {
+
+ fw_vers->or_valid = TRUE;
+ fw_vers->or_major =
+ comb_verl >> NVM_COMB_VER_SHFT;
+ fw_vers->or_build =
+ (comb_verl << NVM_COMB_VER_SHFT)
+ | (comb_verh >> NVM_COMB_VER_SHFT);
+ fw_vers->or_patch =
+ comb_verh & NVM_COMB_VER_MASK;
+ }
+ }
+ break;
+ default:
+ hw->nvm.ops.read(hw, NVM_ETRACK_HIWORD, 1, &etrack_test);
+ return;
+ }
+ hw->nvm.ops.read(hw, NVM_VERSION, 1, &fw_version);
+ fw_vers->eep_major = (fw_version & NVM_MAJOR_MASK)
+ >> NVM_MAJOR_SHIFT;
+
+ /* check for old style version format in newer images*/
+ if ((fw_version & NVM_NEW_DEC_MASK) == 0x0) {
+ eeprom_verl = (fw_version & NVM_COMB_VER_MASK);
+ } else {
+ eeprom_verl = (fw_version & NVM_MINOR_MASK)
+ >> NVM_MINOR_SHIFT;
+ }
+ /* Convert minor value to hex before assigning to output struct
+ * Val to be converted will not be higher than 99, per tool output
+ */
+ q = eeprom_verl / NVM_HEX_CONV;
+ hval = q * NVM_HEX_TENS;
+ rem = eeprom_verl % NVM_HEX_CONV;
+ result = hval + rem;
+ fw_vers->eep_minor = result;
+
+etrack_id:
+ if ((etrack_test & NVM_MAJOR_MASK) == NVM_ETRACK_VALID) {
+ hw->nvm.ops.read(hw, NVM_ETRACK_WORD, 1, &eeprom_verl);
+ hw->nvm.ops.read(hw, (NVM_ETRACK_WORD + 1), 1, &eeprom_verh);
+ fw_vers->etrack_id = (eeprom_verh << NVM_ETRACK_SHIFT)
+ | eeprom_verl;
+ } else if ((etrack_test & NVM_ETRACK_VALID) == 0) {
+ hw->nvm.ops.read(hw, NVM_ETRACK_WORD, 1, &eeprom_verh);
+ hw->nvm.ops.read(hw, (NVM_ETRACK_WORD + 1), 1, &eeprom_verl);
+ fw_vers->etrack_id = (eeprom_verh << NVM_ETRACK_SHIFT) |
+ eeprom_verl;
+ }
+}
+
diff --git a/sys/dev/e1000/e1000_nvm.h b/sys/dev/e1000/e1000_nvm.h
index 31f2180..66461c7 100644
--- a/sys/dev/e1000/e1000_nvm.h
+++ b/sys/dev/e1000/e1000_nvm.h
@@ -35,12 +35,26 @@
#ifndef _E1000_NVM_H_
#define _E1000_NVM_H_
-#if !defined(NO_READ_PBA_RAW) || !defined(NO_WRITE_PBA_RAW)
struct e1000_pba {
u16 word[2];
u16 *pba_block;
};
-#endif
+
+struct e1000_fw_version {
+ u32 etrack_id;
+ u16 eep_major;
+ u16 eep_minor;
+ u16 eep_build;
+
+ u8 invm_major;
+ u8 invm_minor;
+ u8 invm_img_type;
+
+ bool or_valid;
+ u16 or_major;
+ u16 or_build;
+ u16 or_patch;
+};
void e1000_init_nvm_ops_generic(struct e1000_hw *hw);
@@ -52,6 +66,7 @@ s32 e1000_acquire_nvm_generic(struct e1000_hw *hw);
s32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
s32 e1000_read_mac_addr_generic(struct e1000_hw *hw);
+s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num);
s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num,
u32 pba_num_size);
s32 e1000_read_pba_length_generic(struct e1000_hw *hw, u32 *pba_num_size);
@@ -76,6 +91,8 @@ s32 e1000_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words,
s32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw);
void e1000_stop_nvm(struct e1000_hw *hw);
void e1000_release_nvm_generic(struct e1000_hw *hw);
+void e1000_get_fw_version(struct e1000_hw *hw,
+ struct e1000_fw_version *fw_vers);
#define E1000_STM_OPCODE 0xDB00
diff --git a/sys/dev/e1000/e1000_osdep.h b/sys/dev/e1000/e1000_osdep.h
index fc46f48..1664ef0 100644
--- a/sys/dev/e1000/e1000_osdep.h
+++ b/sys/dev/e1000/e1000_osdep.h
@@ -74,10 +74,6 @@
#define STATIC static
#define FALSE 0
#define TRUE 1
-#ifndef __bool_true_false_are_defined
-#define false FALSE
-#define true TRUE
-#endif
#define CMD_MEM_WRT_INVALIDATE 0x0010 /* BIT_4 */
#define PCI_COMMAND_REGISTER PCIR_COMMAND
@@ -99,9 +95,6 @@ typedef int64_t s64;
typedef int32_t s32;
typedef int16_t s16;
typedef int8_t s8;
-#ifndef __bool_true_false_are_defined
-typedef boolean_t bool;
-#endif
#define __le16 u16
#define __le32 u32
diff --git a/sys/dev/e1000/e1000_phy.c b/sys/dev/e1000/e1000_phy.c
index 0c8ccd2..49cdec3 100644
--- a/sys/dev/e1000/e1000_phy.c
+++ b/sys/dev/e1000/e1000_phy.c
@@ -1827,9 +1827,9 @@ s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
phy_data);
if (ret_val)
return ret_val;
- }
- DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data);
+ DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data);
+ }
ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
if (ret_val)
diff --git a/sys/dev/e1000/e1000_regs.h b/sys/dev/e1000/e1000_regs.h
index 7c81a89..e07ec05 100644
--- a/sys/dev/e1000/e1000_regs.h
+++ b/sys/dev/e1000/e1000_regs.h
@@ -65,6 +65,9 @@
#define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */
#define E1000_FEXTNVM6 0x00010 /* Future Extended NVM 6 - RW */
#define E1000_FEXTNVM7 0x000E4 /* Future Extended NVM 7 - RW */
+#define E1000_FEXTNVM9 0x5BB4 /* Future Extended NVM 9 - RW */
+#define E1000_FEXTNVM11 0x5BBC /* Future Extended NVM 11 - RW */
+#define E1000_PCIEANACFG 0x00F18 /* PCIE Analog Config */
#define E1000_FCT 0x00030 /* Flow Control Type - RW */
#define E1000_CONNSW 0x00034 /* Copper/Fiber switch control - RW */
#define E1000_VET 0x00038 /* VLAN Ether Type - RW */
@@ -107,6 +110,8 @@
#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */
#define E1000_PBS 0x01008 /* Packet Buffer Size */
#define E1000_PBECCSTS 0x0100C /* Packet Buffer ECC Status - RW */
+#define E1000_IOSFPC 0x00F28 /* TX corrupted data */
+#define E1000_IOSFPC 0x00F28 /* TX corrupted data */
#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */
#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */
#define E1000_EEARBC_I210 0x12024 /* EEPROM Auto Read Bus Control */
@@ -588,6 +593,10 @@
#define E1000_TIMADJL 0x0B60C /* Time sync time adjustment offset Low - RW */
#define E1000_TIMADJH 0x0B610 /* Time sync time adjustment offset High - RW */
#define E1000_TSAUXC 0x0B640 /* Timesync Auxiliary Control register */
+#define E1000_SYSSTMPL 0x0B648 /* HH Timesync system stamp low register */
+#define E1000_SYSSTMPH 0x0B64C /* HH Timesync system stamp hi register */
+#define E1000_PLTSTMPL 0x0B640 /* HH Timesync platform stamp low register */
+#define E1000_PLTSTMPH 0x0B644 /* HH Timesync platform stamp hi register */
#define E1000_SYSTIMR 0x0B6F8 /* System time register Residue */
#define E1000_TSICR 0x0B66C /* Interrupt Cause Register */
#define E1000_TSIM 0x0B674 /* Interrupt Mask Register */
@@ -680,7 +689,6 @@
#define E1000_O2BGPTC 0x08FE4 /* OS2BMC packets received by BMC */
#define E1000_O2BSPC 0x0415C /* OS2BMC packets transmitted by host */
-#define E1000_DOBFFCTL 0x3F24 /* DMA OBFF Control Register */
#endif
diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c
index 696fec4..beb42f1 100644
--- a/sys/dev/e1000/if_igb.c
+++ b/sys/dev/e1000/if_igb.c
@@ -541,9 +541,9 @@ igb_attach(device_t dev)
"Disable Energy Efficient Ethernet");
if (adapter->hw.phy.media_type == e1000_media_type_copper) {
if (adapter->hw.mac.type == e1000_i354)
- e1000_set_eee_i354(&adapter->hw);
+ e1000_set_eee_i354(&adapter->hw, TRUE, TRUE);
else
- e1000_set_eee_i350(&adapter->hw);
+ e1000_set_eee_i350(&adapter->hw, TRUE, TRUE);
}
}
@@ -1330,9 +1330,9 @@ igb_init_locked(struct adapter *adapter)
/* Set Energy Efficient Ethernet */
if (adapter->hw.phy.media_type == e1000_media_type_copper) {
if (adapter->hw.mac.type == e1000_i354)
- e1000_set_eee_i354(&adapter->hw);
+ e1000_set_eee_i354(&adapter->hw, TRUE, TRUE);
else
- e1000_set_eee_i350(&adapter->hw);
+ e1000_set_eee_i350(&adapter->hw, TRUE, TRUE);
}
}
diff --git a/sys/dev/ral/rt2860.c b/sys/dev/ral/rt2860.c
index b3c737d..48c3ed8 100644
--- a/sys/dev/ral/rt2860.c
+++ b/sys/dev/ral/rt2860.c
@@ -3351,7 +3351,7 @@ rt2860_read_eeprom(struct rt2860_softc *sc, uint8_t macaddr[IEEE80211_ADDR_LEN])
/* read EEPROM version */
val = rt2860_srom_read(sc, RT2860_EEPROM_VERSION);
- DPRINTF(("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8));
+ DPRINTF(("EEPROM rev=%d, FAE=%d\n", val >> 8, val & 0xff));
/* read MAC address */
val = rt2860_srom_read(sc, RT2860_EEPROM_MAC01);
diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c
index 677d397..88fa5fc 100644
--- a/sys/dev/re/if_re.c
+++ b/sys/dev/re/if_re.c
@@ -238,6 +238,7 @@ static const struct rl_hwrev re_hwrevs[] = {
{ RL_HWREV_8168F, RL_8169, "8168F/8111F", RL_JUMBO_MTU_9K},
{ RL_HWREV_8168G, RL_8169, "8168G/8111G", RL_JUMBO_MTU_9K},
{ RL_HWREV_8168GU, RL_8169, "8168GU/8111GU", RL_JUMBO_MTU_9K},
+ { RL_HWREV_8168H, RL_8169, "8168H/8111H", RL_JUMBO_MTU_9K},
{ RL_HWREV_8411, RL_8169, "8411", RL_JUMBO_MTU_9K},
{ RL_HWREV_8411B, RL_8169, "8411B", RL_JUMBO_MTU_9K},
{ 0, 0, NULL, 0 }
@@ -1485,6 +1486,7 @@ re_attach(device_t dev)
break;
case RL_HWREV_8168EP:
case RL_HWREV_8168G:
+ case RL_HWREV_8168H:
case RL_HWREV_8411B:
sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PAR |
RL_FLAG_DESCV2 | RL_FLAG_MACSTAT | RL_FLAG_CMDSTOP |
diff --git a/sys/dev/rl/if_rlreg.h b/sys/dev/rl/if_rlreg.h
index b0de60f..4f02dcf 100644
--- a/sys/dev/rl/if_rlreg.h
+++ b/sys/dev/rl/if_rlreg.h
@@ -195,6 +195,7 @@
#define RL_HWREV_8168G 0x4C000000
#define RL_HWREV_8168EP 0x50000000
#define RL_HWREV_8168GU 0x50800000
+#define RL_HWREV_8168H 0x54000000
#define RL_HWREV_8411B 0x5C800000
#define RL_HWREV_8139 0x60000000
#define RL_HWREV_8139A 0x70000000
diff --git a/sys/dev/uart/uart_bus_pci.c b/sys/dev/uart/uart_bus_pci.c
index 48954a5..4166222 100644
--- a/sys/dev/uart/uart_bus_pci.c
+++ b/sys/dev/uart/uart_bus_pci.c
@@ -127,6 +127,7 @@ static const struct pci_id pci_ns8250_ids[] = {
24 * DEFAULT_RCLK, 2 },
{ 0x8086, 0x1c3d, 0xffff, 0, "Intel AMT - KT Controller", 0x10 },
{ 0x8086, 0x1d3d, 0xffff, 0, "Intel C600/X79 Series Chipset KT Controller", 0x10 },
+{ 0x8086, 0x1e3d, 0xffff, 0, "Intel Panther Point KT Controller", 0x10 },
{ 0x8086, 0x2a07, 0xffff, 0, "Intel AMT - PM965/GM965 KT Controller", 0x10 },
{ 0x8086, 0x2a47, 0xffff, 0, "Mobile 4 Series Chipset KT Controller", 0x10 },
{ 0x8086, 0x2e17, 0xffff, 0, "4 Series Chipset Serial KT Controller", 0x10 },
diff --git a/sys/dev/usb/controller/uhci_pci.c b/sys/dev/usb/controller/uhci_pci.c
index cd08e89..e7e4412 100644
--- a/sys/dev/usb/controller/uhci_pci.c
+++ b/sys/dev/usb/controller/uhci_pci.c
@@ -223,7 +223,7 @@ uhci_pci_match(device_t self)
case 0x76028086:
return ("Intel 82372FB/82468GX USB controller");
- case 0x3309103c:
+ case 0x3300103c:
return ("HP iLO Standard Virtual USB controller");
case 0x30381106:
diff --git a/sys/dev/usb/controller/xhci_pci.c b/sys/dev/usb/controller/xhci_pci.c
index 0ad7357..0df2e9f 100644
--- a/sys/dev/usb/controller/xhci_pci.c
+++ b/sys/dev/usb/controller/xhci_pci.c
@@ -113,6 +113,9 @@ xhci_pci_match(device_t self)
case 0x8cb18086:
return ("Intel Wildcat Point USB 3.0 controller");
+ case 0xa01b177d:
+ return ("Cavium ThunderX USB 3.0 controller");
+
default:
break;
}
diff --git a/sys/dev/usb/serial/u3g.c b/sys/dev/usb/serial/u3g.c
index ba825aa..065da28 100644
--- a/sys/dev/usb/serial/u3g.c
+++ b/sys/dev/usb/serial/u3g.c
@@ -525,6 +525,7 @@ static const STRUCT_USB_HOST_ID u3g_devs[] = {
U3G_DEV(SIERRA, MC5727_2, 0),
U3G_DEV(SIERRA, MC5728, 0),
U3G_DEV(SIERRA, MC7354, 0),
+ U3G_DEV(SIERRA, MC7355, 0),
U3G_DEV(SIERRA, MC8700, 0),
U3G_DEV(SIERRA, MC8755, 0),
U3G_DEV(SIERRA, MC8755_2, 0),
diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs
index 7b7373c5..1666b43 100644
--- a/sys/dev/usb/usbdevs
+++ b/sys/dev/usb/usbdevs
@@ -4044,6 +4044,7 @@ product SIERRA E6892 0x6892 E6892
product SIERRA E6893 0x6893 E6893
product SIERRA MC8700 0x68A3 MC8700
product SIERRA MC7354 0x68C0 MC7354
+product SIERRA MC7355 0x9041 MC7355
product SIERRA AC313U 0x68aa Sierra Wireless AirCard 313U
product SIERRA TRUINSTALL 0x0fff Aircard Tru Installer
diff --git a/sys/dev/usb/wlan/if_rsu.c b/sys/dev/usb/wlan/if_rsu.c
index 463a9bd..aadc948 100644
--- a/sys/dev/usb/wlan/if_rsu.c
+++ b/sys/dev/usb/wlan/if_rsu.c
@@ -26,6 +26,7 @@ __FBSDID("$FreeBSD$");
* o h/w crypto
* o hostap / ibss / mesh
*/
+
#include <sys/param.h>
#include <sys/endian.h>
#include <sys/sockio.h>
@@ -74,8 +75,27 @@ static int rsu_debug = 0;
SYSCTL_NODE(_hw_usb, OID_AUTO, rsu, CTLFLAG_RW, 0, "USB rsu");
SYSCTL_INT(_hw_usb_rsu, OID_AUTO, debug, CTLFLAG_RWTUN, &rsu_debug, 0,
"Debug level");
+#define RSU_DPRINTF(_sc, _flg, ...) \
+ do \
+ if (((_flg) == (RSU_DEBUG_ANY)) || (rsu_debug & (_flg))) \
+ device_printf((_sc)->sc_dev, __VA_ARGS__); \
+ while (0)
+#else
+#define RSU_DPRINTF(_sc, _flg, ...)
#endif
+#define RSU_DEBUG_ANY 0xffffffff
+#define RSU_DEBUG_TX 0x00000001
+#define RSU_DEBUG_RX 0x00000002
+#define RSU_DEBUG_RESET 0x00000004
+#define RSU_DEBUG_CALIB 0x00000008
+#define RSU_DEBUG_STATE 0x00000010
+#define RSU_DEBUG_SCAN 0x00000020
+#define RSU_DEBUG_FWCMD 0x00000040
+#define RSU_DEBUG_TXDONE 0x00000080
+#define RSU_DEBUG_FW 0x00000100
+#define RSU_DEBUG_FWDBG 0x00000200
+
static const STRUCT_USB_HOST_ID rsu_devs[] = {
#define RSU_HT_NOT_SUPPORTED 0
#define RSU_HT_SUPPORTED 1
@@ -279,6 +299,13 @@ rsu_match(device_t self)
}
static int
+rsu_send_mgmt(struct ieee80211_node *ni, int type, int arg)
+{
+
+ return (ENOTSUP);
+}
+
+static int
rsu_attach(device_t self)
{
struct usb_attach_arg *uaa = device_get_ivars(self);
@@ -342,7 +369,9 @@ rsu_attach(device_t self)
/* Set device capabilities. */
ic->ic_caps =
IEEE80211_C_STA | /* station mode */
+#if 0
IEEE80211_C_BGSCAN | /* Background scan. */
+#endif
IEEE80211_C_SHPREAMBLE | /* Short preamble supported. */
IEEE80211_C_SHSLOT | /* Short slot time supported. */
IEEE80211_C_WPA; /* WPA/RSN. */
@@ -376,6 +405,7 @@ rsu_attach(device_t self)
ic->ic_update_mcast = rsu_update_mcast;
ic->ic_parent = rsu_parent;
ic->ic_transmit = rsu_transmit;
+ ic->ic_send_mgmt = rsu_send_mgmt;
ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr,
sizeof(sc->sc_txtap), RSU_TX_RADIOTAP_PRESENT,
@@ -866,7 +896,9 @@ rsu_fw_cmd(struct rsu_softc *sc, uint8_t code, void *buf, int len)
/* Copy command payload. */
memcpy(&cmd[1], buf, len);
- DPRINTFN(2, "Tx cmd code=0x%x len=0x%x\n", code, cmdsz);
+ RSU_DPRINTF(sc, RSU_DEBUG_TX | RSU_DEBUG_FWCMD,
+ "%s: Tx cmd code=0x%x len=0x%x\n",
+ __func__, code, cmdsz);
data->buflen = xferlen;
STAILQ_INSERT_TAIL(&sc->sc_tx_pending[which], data, next);
usbd_transfer_start(sc->sc_xfer[which]);
@@ -881,7 +913,8 @@ rsu_calib_task(void *arg, int pending __unused)
struct rsu_softc *sc = arg;
uint32_t reg;
- DPRINTFN(6, "running calibration task\n");
+ RSU_DPRINTF(sc, RSU_DEBUG_CALIB, "%s: running calibration task\n",
+ __func__);
RSU_LOCK(sc);
#ifdef notyet
@@ -897,7 +930,8 @@ rsu_calib_task(void *arg, int pending __unused)
/* Read current signal level. */
if (rsu_fw_iocmd(sc, 0xf4000001) == 0) {
reg = rsu_read_4(sc, R92S_IOCMD_DATA);
- DPRINTFN(8, "RSSI=%d%%\n", reg >> 4);
+ RSU_DPRINTF(sc, RSU_DEBUG_CALIB, "%s: RSSI=%d%%\n",
+ __func__, reg >> 4);
}
if (sc->sc_calibrating)
taskqueue_enqueue_timeout(taskqueue_thread, &sc->calib_task, hz);
@@ -916,7 +950,9 @@ rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
int error, startcal = 0;
ostate = vap->iv_state;
- DPRINTF("%s -> %s\n", ieee80211_state_name[ostate],
+ RSU_DPRINTF(sc, RSU_DEBUG_STATE, "%s: %s -> %s\n",
+ __func__,
+ ieee80211_state_name[ostate],
ieee80211_state_name[nstate]);
IEEE80211_UNLOCK(ic);
@@ -1039,7 +1075,9 @@ rsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni)
/* Let the FW decide the opmode based on the capinfo field. */
opmode = NDIS802_11AUTOUNKNOWN;
- DPRINTF("setting operating mode to %d\n", opmode);
+ RSU_DPRINTF(sc, RSU_DEBUG_RESET,
+ "%s: setting operating mode to %d\n",
+ __func__, opmode);
error = rsu_fw_cmd(sc, R92S_CMD_SET_OPMODE, &opmode, sizeof(opmode));
if (error != 0)
return (error);
@@ -1050,7 +1088,9 @@ rsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni)
auth.dot1x = (ni->ni_authmode == IEEE80211_AUTH_8021X);
} else
auth.mode = R92S_AUTHMODE_OPEN;
- DPRINTF("setting auth mode to %d\n", auth.mode);
+ RSU_DPRINTF(sc, RSU_DEBUG_RESET,
+ "%s: setting auth mode to %d\n",
+ __func__, auth.mode);
error = rsu_fw_cmd(sc, R92S_CMD_SET_AUTH, &auth, sizeof(auth));
if (error != 0)
return (error);
@@ -1071,6 +1111,7 @@ rsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni)
bss->config.bintval = htole32(ni->ni_intval);
bss->config.dsconfig = htole32(ieee80211_chan2ieee(ic, ni->ni_chan));
bss->inframode = htole32(NDIS802_11INFRASTRUCTURE);
+ /* XXX verify how this is supposed to look! */
memcpy(bss->supprates, ni->ni_rates.rs_rates,
ni->ni_rates.rs_nrates);
/* Write the fixed fields of the beacon frame. */
@@ -1087,7 +1128,9 @@ rsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni)
frm = ieee80211_add_htcap(frm, ni);
bss->ieslen = htole32(frm - (uint8_t *)fixed);
bss->len = htole32(((frm - buf) + 3) & ~3);
- DPRINTF("sending join bss command to %s chan %d\n",
+ RSU_DPRINTF(sc, RSU_DEBUG_RESET | RSU_DEBUG_FWCMD,
+ "%s: sending join bss command to %s chan %d\n",
+ __func__,
ether_sprintf(bss->macaddr), le32toh(bss->config.dsconfig));
return (rsu_fw_cmd(sc, R92S_CMD_JOIN_BSS, buf, sizeof(buf)));
}
@@ -1098,7 +1141,8 @@ rsu_disconnect(struct rsu_softc *sc)
uint32_t zero = 0; /* :-) */
/* Disassociate from our current BSS. */
- DPRINTF("sending disconnect command\n");
+ RSU_DPRINTF(sc, RSU_DEBUG_STATE | RSU_DEBUG_FWCMD,
+ "%s: sending disconnect command\n", __func__);
return (rsu_fw_cmd(sc, R92S_CMD_DISCONNECT, &zero, sizeof(zero)));
}
@@ -1107,8 +1151,8 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len)
{
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_frame *wh;
- struct ieee80211_channel *c;
struct ndis_wlan_bssid_ex *bss;
+ struct ieee80211_rx_stats rxs;
struct mbuf *m;
int pktlen;
@@ -1118,13 +1162,17 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len)
if (__predict_false(len < sizeof(*bss) + le32toh(bss->ieslen)))
return;
- DPRINTFN(2, "found BSS %s: len=%d chan=%d inframode=%d "
- "networktype=%d privacy=%d\n",
+ RSU_DPRINTF(sc, RSU_DEBUG_SCAN,
+ "%s: found BSS %s: len=%d chan=%d inframode=%d "
+ "networktype=%d privacy=%d, RSSI=%d\n",
+ __func__,
ether_sprintf(bss->macaddr), le32toh(bss->len),
le32toh(bss->config.dsconfig), le32toh(bss->inframode),
- le32toh(bss->networktype), le32toh(bss->privacy));
+ le32toh(bss->networktype), le32toh(bss->privacy),
+ le32toh(bss->rssi));
/* Build a fake beacon frame to let net80211 do all the parsing. */
+ /* XXX TODO: just call the new scan API methods! */
pktlen = sizeof(*wh) + le32toh(bss->ieslen);
if (__predict_false(pktlen > MCLBYTES))
return;
@@ -1144,17 +1192,19 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len)
/* Finalize mbuf. */
m->m_pkthdr.len = m->m_len = pktlen;
- /* Fix the channel. */
- c = ieee80211_find_channel_byieee(ic,
- le32toh(bss->config.dsconfig),
- IEEE80211_CHAN_G);
- if (c) {
- ic->ic_curchan = c;
- ieee80211_radiotap_chan_change(ic);
- }
+
+ /* Set channel flags for input path */
+ bzero(&rxs, sizeof(rxs));
+ rxs.r_flags |= IEEE80211_R_IEEE | IEEE80211_R_FREQ;
+ rxs.r_flags |= IEEE80211_R_NF | IEEE80211_R_RSSI;
+ rxs.c_ieee = le32toh(bss->config.dsconfig);
+ rxs.c_freq = ieee80211_ieee2mhz(rxs.c_ieee, IEEE80211_CHAN_2GHZ);
+ rxs.rssi = le32toh(bss->rssi);
+ rxs.nf = 0; /* XXX */
+
/* XXX avoid a LOR */
RSU_UNLOCK(sc);
- ieee80211_input_all(ic, m, le32toh(bss->rssi), 0);
+ ieee80211_input_mimo_all(ic, m, &rxs);
RSU_LOCK(sc);
}
@@ -1173,7 +1223,9 @@ rsu_event_join_bss(struct rsu_softc *sc, uint8_t *buf, int len)
rsp = (struct r92s_event_join_bss *)buf;
res = (int)le32toh(rsp->join_res);
- DPRINTF("Rx join BSS event len=%d res=%d\n", len, res);
+ RSU_DPRINTF(sc, RSU_DEBUG_STATE | RSU_DEBUG_FWCMD,
+ "%s: Rx join BSS event len=%d res=%d\n",
+ __func__, len, res);
if (res <= 0) {
RSU_UNLOCK(sc);
ieee80211_new_state(vap, IEEE80211_S_SCAN, -1);
@@ -1185,8 +1237,10 @@ rsu_event_join_bss(struct rsu_softc *sc, uint8_t *buf, int len)
DPRINTF("Assoc ID overflow\n");
tmp = 1;
}
- DPRINTF("associated with %s associd=%d\n",
- ether_sprintf(rsp->bss.macaddr), tmp);
+ RSU_DPRINTF(sc, RSU_DEBUG_STATE | RSU_DEBUG_FWCMD,
+ "%s: associated with %s associd=%d\n",
+ __func__, ether_sprintf(rsp->bss.macaddr), tmp);
+ /* XXX is this required? What's the top two bits for again? */
ni->ni_associd = tmp | 0xc000;
RSU_UNLOCK(sc);
ieee80211_new_state(vap, IEEE80211_S_RUN,
@@ -1200,15 +1254,17 @@ rsu_rx_event(struct rsu_softc *sc, uint8_t code, uint8_t *buf, int len)
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
- DPRINTFN(4, "Rx event code=%d len=%d\n", code, len);
+ RSU_DPRINTF(sc, RSU_DEBUG_RX | RSU_DEBUG_FWCMD,
+ "%s: Rx event code=%d len=%d\n", __func__, code, len);
switch (code) {
case R92S_EVT_SURVEY:
if (vap->iv_state == IEEE80211_S_SCAN)
rsu_event_survey(sc, buf, len);
break;
case R92S_EVT_SURVEY_DONE:
- DPRINTF("site survey pass %d done, found %d BSS\n",
- sc->sc_scan_pass, le32toh(*(uint32_t *)buf));
+ RSU_DPRINTF(sc, RSU_DEBUG_SCAN,
+ "%s: site survey pass %d done, found %d BSS\n",
+ __func__, sc->sc_scan_pass, le32toh(*(uint32_t *)buf));
if (vap->iv_state != IEEE80211_S_SCAN)
break; /* Ignore if not scanning. */
if (sc->sc_scan_pass == 0 && vap->iv_des_nssid != 0) {
@@ -1225,11 +1281,10 @@ rsu_rx_event(struct rsu_softc *sc, uint8_t code, uint8_t *buf, int len)
if (vap->iv_state == IEEE80211_S_AUTH)
rsu_event_join_bss(sc, buf, len);
break;
-#if 0
-XXX This event is occurring regularly, possibly due to some power saving event
-XXX and disrupts the WLAN traffic. Disable for now.
case R92S_EVT_DEL_STA:
- DPRINTF("disassociated from %s\n", ether_sprintf(buf));
+ RSU_DPRINTF(sc, RSU_DEBUG_FWCMD | RSU_DEBUG_STATE,
+ "%s: disassociated from %s\n", __func__,
+ ether_sprintf(buf));
if (vap->iv_state == IEEE80211_S_RUN &&
IEEE80211_ADDR_EQ(vap->iv_bss->ni_bssid, buf)) {
RSU_UNLOCK(sc);
@@ -1237,17 +1292,17 @@ XXX and disrupts the WLAN traffic. Disable for now.
RSU_LOCK(sc);
}
break;
-#endif
case R92S_EVT_WPS_PBC:
- DPRINTF("WPS PBC pushed.\n");
+ RSU_DPRINTF(sc, RSU_DEBUG_RX | RSU_DEBUG_FWCMD,
+ "%s: WPS PBC pushed.\n", __func__);
break;
case R92S_EVT_FWDBG:
- if (vap->iv_ifp->if_flags & IFF_DEBUG) {
- buf[60] = '\0';
- printf("FWDBG: %s\n", (char *)buf);
- }
+ buf[60] = '\0';
+ RSU_DPRINTF(sc, RSU_DEBUG_FWDBG, "FWDBG: %s\n", (char *)buf);
break;
default:
+ RSU_DPRINTF(sc, RSU_DEBUG_ANY, "%s: unhandled code (%d)\n",
+ __func__, code);
break;
}
}
@@ -1258,7 +1313,7 @@ rsu_rx_multi_event(struct rsu_softc *sc, uint8_t *buf, int len)
struct r92s_fw_cmd_hdr *cmd;
int cmdsz;
- DPRINTFN(6, "Rx events len=%d\n", len);
+ RSU_DPRINTF(sc, RSU_DEBUG_RX, "%s: Rx events len=%d\n", __func__, len);
/* Skip Rx status. */
buf += sizeof(struct r92s_rx_stat);
@@ -1339,7 +1394,9 @@ rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen, int *rssi)
else
*rssi = 0;
- DPRINTFN(5, "Rx frame len=%d rate=%d infosz=%d rssi=%d\n",
+ RSU_DPRINTF(sc, RSU_DEBUG_RX,
+ "%s: Rx frame len=%d rate=%d infosz=%d rssi=%d\n",
+ __func__,
pktlen, rate, infosz, *rssi);
m = m_get2(pktlen, M_NOWAIT, MT_DATA, M_PKTHDR);
@@ -1401,7 +1458,8 @@ rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf, int len, int *rssi)
/* Get the number of encapsulated frames. */
stat = (struct r92s_rx_stat *)buf;
npkts = MS(le32toh(stat->rxdw2), R92S_RXDW2_PKTCNT);
- DPRINTFN(6, "Rx %d frames in one chunk\n", npkts);
+ RSU_DPRINTF(sc, RSU_DEBUG_RX,
+ "%s: Rx %d frames in one chunk\n", __func__, npkts);
/* Process all of them. */
while (npkts-- > 0) {
@@ -1540,6 +1598,13 @@ tr_setup:
static void
rsu_txeof(struct usb_xfer *xfer, struct rsu_data *data)
{
+#ifdef USB_DEBUG
+ struct rsu_softc *sc = usbd_xfer_softc(xfer);
+#endif
+
+ RSU_DPRINTF(sc, RSU_DEBUG_TXDONE, "%s: called; data=%p\n",
+ __func__,
+ data);
if (data->m) {
/* XXX status? */
@@ -1564,7 +1629,8 @@ rsu_bulk_tx_callback_sub(struct usb_xfer *xfer, usb_error_t error,
data = STAILQ_FIRST(&sc->sc_tx_active[which]);
if (data == NULL)
goto tr_setup;
- DPRINTF("transfer done %p\n", data);
+ RSU_DPRINTF(sc, RSU_DEBUG_TXDONE, "%s: transfer done %p\n",
+ __func__, data);
STAILQ_REMOVE_HEAD(&sc->sc_tx_active[which], next);
rsu_txeof(xfer, data);
STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next);
@@ -1573,13 +1639,17 @@ rsu_bulk_tx_callback_sub(struct usb_xfer *xfer, usb_error_t error,
tr_setup:
data = STAILQ_FIRST(&sc->sc_tx_pending[which]);
if (data == NULL) {
- DPRINTF("empty pending queue sc %p\n", sc);
+ RSU_DPRINTF(sc, RSU_DEBUG_TXDONE,
+ "%s: empty pending queue sc %p\n", __func__, sc);
return;
}
STAILQ_REMOVE_HEAD(&sc->sc_tx_pending[which], next);
STAILQ_INSERT_TAIL(&sc->sc_tx_active[which], data, next);
usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen);
- DPRINTF("submitting transfer %p\n", data);
+ RSU_DPRINTF(sc, RSU_DEBUG_TXDONE,
+ "%s: submitting transfer %p\n",
+ __func__,
+ data);
usbd_transfer_submit(xfer);
break;
default:
@@ -1631,6 +1701,9 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni,
wh = mtod(m0, struct ieee80211_frame *);
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+ RSU_DPRINTF(sc, RSU_DEBUG_TX, "%s: data=%p, m=%p\n",
+ __func__, data, m0);
+
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
k = ieee80211_crypto_encap(ni, m0);
if (k == NULL) {
@@ -1704,6 +1777,7 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni,
tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
ieee80211_radiotap_tx(vap, m0);
}
+
xferlen = sizeof(*txd) + m0->m_pkthdr.len;
m_copydata(m0, 0, m0->m_pkthdr.len, (caddr_t)&txd[1]);
@@ -1979,7 +2053,9 @@ rsu_power_on_bcut(struct rsu_softc *sc)
rsu_ms_delay(sc);
}
if (ntries == 20) {
- DPRINTF("TxDMA is not ready\n");
+ RSU_DPRINTF(sc, RSU_DEBUG_RESET | RSU_DEBUG_TX,
+ "%s: TxDMA is not ready\n",
+ __func__);
/* Reset TxDMA. */
reg = rsu_read_1(sc, R92S_CR);
rsu_write_1(sc, R92S_CR, reg & ~R92S_CR_TXDMA_EN);
@@ -2041,7 +2117,9 @@ rsu_fw_loadsection(struct rsu_softc *sc, const uint8_t *buf, int len)
txd->txdw0 |= htole32(SM(R92S_TXDW0_PKTLEN, mlen));
memcpy(&txd[1], buf, mlen);
data->buflen = sizeof(*txd) + mlen;
- DPRINTF("starting transfer %p\n", data);
+ RSU_DPRINTF(sc, RSU_DEBUG_TX | RSU_DEBUG_FW | RSU_DEBUG_RESET,
+ "%s: starting transfer %p\n",
+ __func__, data);
STAILQ_INSERT_TAIL(&sc->sc_tx_pending[which], data, next);
buf += mlen;
len -= mlen;
@@ -2063,7 +2141,9 @@ rsu_load_firmware(struct rsu_softc *sc)
int ntries, error;
if (rsu_read_1(sc, R92S_TCR) & R92S_TCR_FWRDY) {
- DPRINTF("Firmware already loaded\n");
+ RSU_DPRINTF(sc, RSU_DEBUG_FW | RSU_DEBUG_RESET,
+ "%s: Firmware already loaded\n",
+ __func__);
return (0);
}
@@ -2319,7 +2399,9 @@ rsu_init(struct rsu_softc *sc)
/* It really takes 1.5 seconds for the firmware to boot: */
usb_pause_mtx(&sc->sc_mtx, (3 * hz) / 2);
- DPRINTF("setting MAC address to %s\n", ether_sprintf(macaddr));
+ RSU_DPRINTF(sc, RSU_DEBUG_RESET, "%s: setting MAC address to %s\n",
+ __func__,
+ ether_sprintf(macaddr));
error = rsu_fw_cmd(sc, R92S_CMD_SET_MAC_ADDRESS, macaddr,
IEEE80211_ADDR_LEN);
if (error != 0) {
@@ -2330,9 +2412,11 @@ rsu_init(struct rsu_softc *sc)
rsu_write_1(sc, R92S_USB_HRPWM,
R92S_USB_HRPWM_PS_ST_ACTIVE | R92S_USB_HRPWM_PS_ALL_ON);
+ /* Set PS mode fully active */
memset(&cmd, 0, sizeof(cmd));
cmd.mode = R92S_PS_MODE_ACTIVE;
- DPRINTF("setting ps mode to %d\n", cmd.mode);
+ RSU_DPRINTF(sc, RSU_DEBUG_RESET, "%s: setting ps mode to %d\n",
+ __func__, cmd.mode);
error = rsu_fw_cmd(sc, R92S_CMD_SET_PWR_MODE, &cmd, sizeof(cmd));
if (error != 0) {
device_printf(sc->sc_dev, "could not set PS mode\n");
diff --git a/sys/dev/usb/wlan/if_run.c b/sys/dev/usb/wlan/if_run.c
index b787c03..87088c1 100644
--- a/sys/dev/usb/wlan/if_run.c
+++ b/sys/dev/usb/wlan/if_run.c
@@ -1730,7 +1730,7 @@ run_read_eeprom(struct run_softc *sc)
/* read ROM version */
run_srom_read(sc, RT2860_EEPROM_VERSION, &val);
- DPRINTF("EEPROM rev=%d, FAE=%d\n", val & 0xff, val >> 8);
+ DPRINTF("EEPROM rev=%d, FAE=%d\n", val >> 8, val & 0xff);
/* read MAC address */
run_srom_read(sc, RT2860_EEPROM_MAC01, &val);
diff --git a/sys/dev/usb/wlan/if_ural.c b/sys/dev/usb/wlan/if_ural.c
index e8224ba..187a47a 100644
--- a/sys/dev/usb/wlan/if_ural.c
+++ b/sys/dev/usb/wlan/if_ural.c
@@ -566,10 +566,7 @@ ural_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */
return NULL;
- uvp = (struct ural_vap *) malloc(sizeof(struct ural_vap),
- M_80211_VAP, M_NOWAIT | M_ZERO);
- if (uvp == NULL)
- return NULL;
+ uvp = malloc(sizeof(struct ural_vap), M_80211_VAP, M_WAITOK | M_ZERO);
vap = &uvp->vap;
/* enable s/w bmiss handling for sta mode */
diff --git a/sys/geom/nop/g_nop.c b/sys/geom/nop/g_nop.c
index bd72d78..837f3f4 100644
--- a/sys/geom/nop/g_nop.c
+++ b/sys/geom/nop/g_nop.c
@@ -162,7 +162,7 @@ g_nop_access(struct g_provider *pp, int dr, int dw, int de)
static int
g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp,
int ioerror, u_int rfailprob, u_int wfailprob, off_t offset, off_t size,
- u_int secsize)
+ u_int secsize, u_int stripesize, u_int stripeoffset)
{
struct g_nop_softc *sc;
struct g_geom *gp;
@@ -208,6 +208,18 @@ g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp,
return (EINVAL);
}
size -= size % secsize;
+ if ((stripesize % pp->sectorsize) != 0) {
+ gctl_error(req, "Invalid stripesize for provider %s.", pp->name);
+ return (EINVAL);
+ }
+ if ((stripeoffset % pp->sectorsize) != 0) {
+ gctl_error(req, "Invalid stripeoffset for provider %s.", pp->name);
+ return (EINVAL);
+ }
+ if (stripesize != 0 && stripeoffset >= stripesize) {
+ gctl_error(req, "stripeoffset is too big.");
+ return (EINVAL);
+ }
snprintf(name, sizeof(name), "%s%s", pp->name, G_NOP_SUFFIX);
LIST_FOREACH(gp, &mp->geom, geom) {
if (strcmp(gp->name, name) == 0) {
@@ -219,6 +231,8 @@ g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp,
sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
sc->sc_offset = offset;
sc->sc_explicitsize = explicitsize;
+ sc->sc_stripesize = stripesize;
+ sc->sc_stripeoffset = stripeoffset;
sc->sc_error = ioerror;
sc->sc_rfailprob = rfailprob;
sc->sc_wfailprob = wfailprob;
@@ -238,6 +252,8 @@ g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp,
newpp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE;
newpp->mediasize = size;
newpp->sectorsize = secsize;
+ newpp->stripesize = stripesize;
+ newpp->stripeoffset = stripeoffset;
cp = g_new_consumer(gp);
cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
@@ -304,7 +320,8 @@ static void
g_nop_ctl_create(struct gctl_req *req, struct g_class *mp)
{
struct g_provider *pp;
- intmax_t *error, *rfailprob, *wfailprob, *offset, *secsize, *size;
+ intmax_t *error, *rfailprob, *wfailprob, *offset, *secsize, *size,
+ *stripesize, *stripeoffset;
const char *name;
char param[16];
int i, *nargs;
@@ -370,6 +387,24 @@ g_nop_ctl_create(struct gctl_req *req, struct g_class *mp)
gctl_error(req, "Invalid '%s' argument", "secsize");
return;
}
+ stripesize = gctl_get_paraml(req, "stripesize", sizeof(*stripesize));
+ if (stripesize == NULL) {
+ gctl_error(req, "No '%s' argument", "stripesize");
+ return;
+ }
+ if (*stripesize < 0) {
+ gctl_error(req, "Invalid '%s' argument", "stripesize");
+ return;
+ }
+ stripeoffset = gctl_get_paraml(req, "stripeoffset", sizeof(*stripeoffset));
+ if (stripeoffset == NULL) {
+ gctl_error(req, "No '%s' argument", "stripeoffset");
+ return;
+ }
+ if (*stripeoffset < 0) {
+ gctl_error(req, "Invalid '%s' argument", "stripeoffset");
+ return;
+ }
for (i = 0; i < *nargs; i++) {
snprintf(param, sizeof(param), "arg%d", i);
@@ -390,7 +425,8 @@ g_nop_ctl_create(struct gctl_req *req, struct g_class *mp)
*error == -1 ? EIO : (int)*error,
*rfailprob == -1 ? 0 : (u_int)*rfailprob,
*wfailprob == -1 ? 0 : (u_int)*wfailprob,
- (off_t)*offset, (off_t)*size, (u_int)*secsize) != 0) {
+ (off_t)*offset, (off_t)*size, (u_int)*secsize,
+ (u_int)*stripesize, (u_int)*stripeoffset) != 0) {
return;
}
}
diff --git a/sys/geom/nop/g_nop.h b/sys/geom/nop/g_nop.h
index 3e37c05..b5e954a 100644
--- a/sys/geom/nop/g_nop.h
+++ b/sys/geom/nop/g_nop.h
@@ -59,6 +59,8 @@ struct g_nop_softc {
int sc_error;
off_t sc_offset;
off_t sc_explicitsize;
+ off_t sc_stripesize;
+ off_t sc_stripeoffset;
u_int sc_rfailprob;
u_int sc_wfailprob;
uintmax_t sc_reads;
diff --git a/sys/gnu/fs/reiserfs/reiserfs_vfsops.c b/sys/gnu/fs/reiserfs/reiserfs_vfsops.c
index ad2aab0..0c351dc 100644
--- a/sys/gnu/fs/reiserfs/reiserfs_vfsops.c
+++ b/sys/gnu/fs/reiserfs/reiserfs_vfsops.c
@@ -1022,6 +1022,7 @@ uint32_t find_hash_out(struct reiserfs_mount *rmp)
}
} while (0);
+ free(ip, M_REISERFSNODE);
pathrelse(&path);
return (hash);
}
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
index a4fde06..bb92e18 100644
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -292,10 +292,10 @@ linker_file_register_sysctls(linker_file_t lf)
return;
sx_xunlock(&kld_sx);
- sysctl_xlock();
+ sysctl_wlock();
for (oidp = start; oidp < stop; oidp++)
sysctl_register_oid(*oidp);
- sysctl_xunlock();
+ sysctl_wunlock();
sx_xlock(&kld_sx);
}
@@ -313,10 +313,10 @@ linker_file_unregister_sysctls(linker_file_t lf)
return;
sx_xunlock(&kld_sx);
- sysctl_xlock();
+ sysctl_wlock();
for (oidp = start; oidp < stop; oidp++)
sysctl_unregister_oid(*oidp);
- sysctl_xunlock();
+ sysctl_wunlock();
sx_xlock(&kld_sx);
}
diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c
index aa4c904..02ece28 100644
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -694,7 +694,7 @@ orphanpg(pg)
LIST_FOREACH(p, &pg->pg_members, p_pglist) {
PROC_LOCK(p);
- if (P_SHOULDSTOP(p)) {
+ if (P_SHOULDSTOP(p) == P_STOPPED_SIG) {
PROC_UNLOCK(p);
LIST_FOREACH(p, &pg->pg_members, p_pglist) {
PROC_LOCK(p);
diff --git a/sys/kern/kern_rmlock.c b/sys/kern/kern_rmlock.c
index 2667e6e..b6df53e 100644
--- a/sys/kern/kern_rmlock.c
+++ b/sys/kern/kern_rmlock.c
@@ -407,9 +407,11 @@ _rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker, int trylock)
return (0);
}
} else {
- if (rm->lock_object.lo_flags & LO_SLEEPABLE)
+ if (rm->lock_object.lo_flags & LO_SLEEPABLE) {
+ THREAD_SLEEPING_OK();
sx_xlock(&rm->rm_lock_sx);
- else
+ THREAD_NO_SLEEPING();
+ } else
mtx_lock(&rm->rm_lock_mtx);
}
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index b32198f..52075e4 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <sys/jail.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/rmlock.h>
#include <sys/sbuf.h>
#include <sys/sx.h>
#include <sys/sysproto.h>
@@ -77,7 +78,7 @@ static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buffer");
* The sysctllock protects the MIB tree. It also protects sysctl
* contexts used with dynamic sysctls. The sysctl_register_oid() and
* sysctl_unregister_oid() routines require the sysctllock to already
- * be held, so the sysctl_xlock() and sysctl_xunlock() routines are
+ * be held, so the sysctl_wlock() and sysctl_wunlock() routines are
* provided for the few places in the kernel which need to use that
* API rather than using the dynamic API. Use of the dynamic API is
* strongly encouraged for most code.
@@ -86,20 +87,21 @@ static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buffer");
* sysctl requests. This is implemented by serializing any userland
* sysctl requests larger than a single page via an exclusive lock.
*/
-static struct sx sysctllock;
+static struct rmlock sysctllock;
static struct sx sysctlmemlock;
-#define SYSCTL_XLOCK() sx_xlock(&sysctllock)
-#define SYSCTL_XUNLOCK() sx_xunlock(&sysctllock)
-#define SYSCTL_SLOCK() sx_slock(&sysctllock)
-#define SYSCTL_SUNLOCK() sx_sunlock(&sysctllock)
-#define SYSCTL_XLOCKED() sx_xlocked(&sysctllock)
-#define SYSCTL_ASSERT_LOCKED() sx_assert(&sysctllock, SA_LOCKED)
-#define SYSCTL_ASSERT_XLOCKED() sx_assert(&sysctllock, SA_XLOCKED)
-#define SYSCTL_ASSERT_SLOCKED() sx_assert(&sysctllock, SA_SLOCKED)
-#define SYSCTL_INIT() sx_init(&sysctllock, "sysctl lock")
+#define SYSCTL_WLOCK() rm_wlock(&sysctllock)
+#define SYSCTL_WUNLOCK() rm_wunlock(&sysctllock)
+#define SYSCTL_RLOCK(tracker) rm_rlock(&sysctllock, (tracker))
+#define SYSCTL_RUNLOCK(tracker) rm_runlock(&sysctllock, (tracker))
+#define SYSCTL_WLOCKED() rm_wowned(&sysctllock)
+#define SYSCTL_ASSERT_LOCKED() rm_assert(&sysctllock, RA_LOCKED)
+#define SYSCTL_ASSERT_WLOCKED() rm_assert(&sysctllock, RA_WLOCKED)
+#define SYSCTL_ASSERT_RLOCKED() rm_assert(&sysctllock, RA_RLOCKED)
+#define SYSCTL_INIT() rm_init_flags(&sysctllock, "sysctl lock", \
+ RM_SLEEPABLE)
#define SYSCTL_SLEEP(ch, wmesg, timo) \
- sx_sleep(ch, &sysctllock, 0, wmesg, timo)
+ rm_sleep(ch, &sysctllock, 0, wmesg, timo)
static int sysctl_root(SYSCTL_HANDLER_ARGS);
@@ -111,29 +113,6 @@ static int sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del,
static int sysctl_old_kernel(struct sysctl_req *, const void *, size_t);
static int sysctl_new_kernel(struct sysctl_req *, void *, size_t);
-static void
-sysctl_lock(bool xlock)
-{
-
- if (xlock)
- SYSCTL_XLOCK();
- else
- SYSCTL_SLOCK();
-}
-
-static bool
-sysctl_unlock(void)
-{
- bool xlocked;
-
- xlocked = SYSCTL_XLOCKED();
- if (xlocked)
- SYSCTL_XUNLOCK();
- else
- SYSCTL_SUNLOCK();
- return (xlocked);
-}
-
static struct sysctl_oid *
sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
{
@@ -154,29 +133,32 @@ sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
* Order by number in each list.
*/
void
-sysctl_xlock(void)
+sysctl_wlock(void)
{
- SYSCTL_XLOCK();
+ SYSCTL_WLOCK();
}
void
-sysctl_xunlock(void)
+sysctl_wunlock(void)
{
- SYSCTL_XUNLOCK();
+ SYSCTL_WUNLOCK();
}
static int
sysctl_root_handler_locked(struct sysctl_oid *oid, void *arg1, intptr_t arg2,
- struct sysctl_req *req)
+ struct sysctl_req *req, struct rm_priotracker *tracker)
{
int error;
- bool xlocked;
if (oid->oid_kind & CTLFLAG_DYN)
atomic_add_int(&oid->oid_running, 1);
- xlocked = sysctl_unlock();
+
+ if (tracker != NULL)
+ SYSCTL_RUNLOCK(tracker);
+ else
+ SYSCTL_WUNLOCK();
if (!(oid->oid_kind & CTLFLAG_MPSAFE))
mtx_lock(&Giant);
@@ -184,7 +166,11 @@ sysctl_root_handler_locked(struct sysctl_oid *oid, void *arg1, intptr_t arg2,
if (!(oid->oid_kind & CTLFLAG_MPSAFE))
mtx_unlock(&Giant);
- sysctl_lock(xlocked);
+ if (tracker != NULL)
+ SYSCTL_RLOCK(tracker);
+ else
+ SYSCTL_WLOCK();
+
if (oid->oid_kind & CTLFLAG_DYN) {
if (atomic_fetchadd_int(&oid->oid_running, -1) == 1 &&
(oid->oid_kind & CTLFLAG_DYING) != 0)
@@ -283,7 +269,7 @@ sysctl_load_tunable_by_oid_locked(struct sysctl_oid *oidp)
return;
}
error = sysctl_root_handler_locked(oidp, oidp->oid_arg1,
- oidp->oid_arg2, &req);
+ oidp->oid_arg2, &req, NULL);
if (error != 0)
printf("Setting sysctl %s failed: %d\n", path + rem, error);
if (penv != NULL)
@@ -303,7 +289,7 @@ sysctl_register_oid(struct sysctl_oid *oidp)
* First check if another oid with the same name already
* exists in the parent's list.
*/
- SYSCTL_ASSERT_XLOCKED();
+ SYSCTL_ASSERT_WLOCKED();
p = sysctl_find_oidname(oidp->oid_name, parent);
if (p != NULL) {
if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
@@ -397,7 +383,7 @@ sysctl_unregister_oid(struct sysctl_oid *oidp)
struct sysctl_oid *p;
int error;
- SYSCTL_ASSERT_XLOCKED();
+ SYSCTL_ASSERT_WLOCKED();
error = ENOENT;
if (oidp->oid_number == OID_AUTO) {
error = EINVAL;
@@ -453,7 +439,7 @@ sysctl_ctx_free(struct sysctl_ctx_list *clist)
* XXX This algorithm is a hack. But I don't know any
* XXX better solution for now...
*/
- SYSCTL_XLOCK();
+ SYSCTL_WLOCK();
TAILQ_FOREACH(e, clist, link) {
error = sysctl_remove_oid_locked(e->entry, 0, 0);
if (error)
@@ -473,7 +459,7 @@ sysctl_ctx_free(struct sysctl_ctx_list *clist)
e1 = TAILQ_PREV(e1, sysctl_ctx_list, link);
}
if (error) {
- SYSCTL_XUNLOCK();
+ SYSCTL_WUNLOCK();
return(EBUSY);
}
/* Now really delete the entries */
@@ -487,7 +473,7 @@ sysctl_ctx_free(struct sysctl_ctx_list *clist)
free(e, M_SYSCTLOID);
e = e1;
}
- SYSCTL_XUNLOCK();
+ SYSCTL_WUNLOCK();
return (error);
}
@@ -497,7 +483,7 @@ sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
{
struct sysctl_ctx_entry *e;
- SYSCTL_ASSERT_XLOCKED();
+ SYSCTL_ASSERT_WLOCKED();
if (clist == NULL || oidp == NULL)
return(NULL);
e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK);
@@ -512,7 +498,7 @@ sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
{
struct sysctl_ctx_entry *e;
- SYSCTL_ASSERT_XLOCKED();
+ SYSCTL_ASSERT_WLOCKED();
if (clist == NULL || oidp == NULL)
return(NULL);
TAILQ_FOREACH(e, clist, link) {
@@ -534,15 +520,15 @@ sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
if (clist == NULL || oidp == NULL)
return (EINVAL);
- SYSCTL_XLOCK();
+ SYSCTL_WLOCK();
e = sysctl_ctx_entry_find(clist, oidp);
if (e != NULL) {
TAILQ_REMOVE(clist, e, link);
- SYSCTL_XUNLOCK();
+ SYSCTL_WUNLOCK();
free(e, M_SYSCTLOID);
return (0);
} else {
- SYSCTL_XUNLOCK();
+ SYSCTL_WUNLOCK();
return (ENOENT);
}
}
@@ -558,9 +544,9 @@ sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse)
{
int error;
- SYSCTL_XLOCK();
+ SYSCTL_WLOCK();
error = sysctl_remove_oid_locked(oidp, del, recurse);
- SYSCTL_XUNLOCK();
+ SYSCTL_WUNLOCK();
return (error);
}
@@ -572,14 +558,14 @@ sysctl_remove_name(struct sysctl_oid *parent, const char *name,
int error;
error = ENOENT;
- SYSCTL_XLOCK();
+ SYSCTL_WLOCK();
SLIST_FOREACH_SAFE(p, SYSCTL_CHILDREN(parent), oid_link, tmp) {
if (strcmp(p->oid_name, name) == 0) {
error = sysctl_remove_oid_locked(p, del, recurse);
break;
}
}
- SYSCTL_XUNLOCK();
+ SYSCTL_WUNLOCK();
return (error);
}
@@ -591,7 +577,7 @@ sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del, int recurse)
struct sysctl_oid *p, *tmp;
int error;
- SYSCTL_ASSERT_XLOCKED();
+ SYSCTL_ASSERT_WLOCKED();
if (oidp == NULL)
return(EINVAL);
if ((oidp->oid_kind & CTLFLAG_DYN) == 0) {
@@ -666,7 +652,7 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
if (parent == NULL)
return(NULL);
/* Check if the node already exists, otherwise create it */
- SYSCTL_XLOCK();
+ SYSCTL_WLOCK();
oidp = sysctl_find_oidname(name, parent);
if (oidp != NULL) {
if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
@@ -674,10 +660,10 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
/* Update the context */
if (clist != NULL)
sysctl_ctx_entry_add(clist, oidp);
- SYSCTL_XUNLOCK();
+ SYSCTL_WUNLOCK();
return (oidp);
} else {
- SYSCTL_XUNLOCK();
+ SYSCTL_WUNLOCK();
printf("can't re-use a leaf (%s)!\n", name);
return (NULL);
}
@@ -700,7 +686,7 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
sysctl_ctx_entry_add(clist, oidp);
/* Register this oid */
sysctl_register_oid(oidp);
- SYSCTL_XUNLOCK();
+ SYSCTL_WUNLOCK();
return (oidp);
}
@@ -714,10 +700,10 @@ sysctl_rename_oid(struct sysctl_oid *oidp, const char *name)
char *oldname;
newname = strdup(name, M_SYSCTLOID);
- SYSCTL_XLOCK();
+ SYSCTL_WLOCK();
oldname = __DECONST(char *, oidp->oid_name);
oidp->oid_name = newname;
- SYSCTL_XUNLOCK();
+ SYSCTL_WUNLOCK();
free(oldname, M_SYSCTLOID);
}
@@ -729,21 +715,21 @@ sysctl_move_oid(struct sysctl_oid *oid, struct sysctl_oid_list *parent)
{
struct sysctl_oid *oidp;
- SYSCTL_XLOCK();
+ SYSCTL_WLOCK();
if (oid->oid_parent == parent) {
- SYSCTL_XUNLOCK();
+ SYSCTL_WUNLOCK();
return (0);
}
oidp = sysctl_find_oidname(oid->oid_name, parent);
if (oidp != NULL) {
- SYSCTL_XUNLOCK();
+ SYSCTL_WUNLOCK();
return (EEXIST);
}
sysctl_unregister_oid(oid);
oid->oid_parent = parent;
oid->oid_number = OID_AUTO;
sysctl_register_oid(oid);
- SYSCTL_XUNLOCK();
+ SYSCTL_WUNLOCK();
return (0);
}
@@ -759,10 +745,10 @@ sysctl_register_all(void *arg)
sx_init(&sysctlmemlock, "sysctl mem");
SYSCTL_INIT();
- SYSCTL_XLOCK();
+ SYSCTL_WLOCK();
SET_FOREACH(oidp, sysctl_set)
sysctl_register_oid(*oidp);
- SYSCTL_XUNLOCK();
+ SYSCTL_WUNLOCK();
}
SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_FIRST, sysctl_register_all, 0);
@@ -832,14 +818,15 @@ sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
static int
sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS)
{
+ struct rm_priotracker tracker;
int error;
error = priv_check(req->td, PRIV_SYSCTL_DEBUG);
if (error)
return (error);
- SYSCTL_SLOCK();
+ SYSCTL_RLOCK(&tracker);
sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
- SYSCTL_SUNLOCK();
+ SYSCTL_RUNLOCK(&tracker);
return (ENOENT);
}
@@ -855,9 +842,10 @@ sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
int error = 0;
struct sysctl_oid *oid;
struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
+ struct rm_priotracker tracker;
char buf[10];
- SYSCTL_SLOCK();
+ SYSCTL_RLOCK(&tracker);
while (namelen) {
if (!lsp) {
snprintf(buf,sizeof(buf),"%d",*name);
@@ -900,7 +888,7 @@ sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
}
error = SYSCTL_OUT(req, "", 1);
out:
- SYSCTL_SUNLOCK();
+ SYSCTL_RUNLOCK(&tracker);
return (error);
}
@@ -979,11 +967,12 @@ sysctl_sysctl_next(SYSCTL_HANDLER_ARGS)
int i, j, error;
struct sysctl_oid *oid;
struct sysctl_oid_list *lsp = &sysctl__children;
+ struct rm_priotracker tracker;
int newoid[CTL_MAXNAME];
- SYSCTL_SLOCK();
+ SYSCTL_RLOCK(&tracker);
i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
- SYSCTL_SUNLOCK();
+ SYSCTL_RUNLOCK(&tracker);
if (i)
return (ENOENT);
error = SYSCTL_OUT(req, newoid, j * sizeof (int));
@@ -1042,6 +1031,7 @@ sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
char *p;
int error, oid[CTL_MAXNAME], len = 0;
struct sysctl_oid *op = 0;
+ struct rm_priotracker tracker;
if (!req->newlen)
return (ENOENT);
@@ -1058,9 +1048,9 @@ sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
p [req->newlen] = '\0';
- SYSCTL_SLOCK();
+ SYSCTL_RLOCK(&tracker);
error = name2oid(p, oid, &len, &op);
- SYSCTL_SUNLOCK();
+ SYSCTL_RUNLOCK(&tracker);
free(p, M_SYSCTL);
@@ -1083,9 +1073,10 @@ static int
sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
{
struct sysctl_oid *oid;
+ struct rm_priotracker tracker;
int error;
- SYSCTL_SLOCK();
+ SYSCTL_RLOCK(&tracker);
error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
if (error)
goto out;
@@ -1099,7 +1090,7 @@ sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
goto out;
error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1);
out:
- SYSCTL_SUNLOCK();
+ SYSCTL_RUNLOCK(&tracker);
return (error);
}
@@ -1111,9 +1102,10 @@ static int
sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS)
{
struct sysctl_oid *oid;
+ struct rm_priotracker tracker;
int error;
- SYSCTL_SLOCK();
+ SYSCTL_RLOCK(&tracker);
error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
if (error)
goto out;
@@ -1124,7 +1116,7 @@ sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS)
}
error = SYSCTL_OUT(req, oid->oid_descr, strlen(oid->oid_descr) + 1);
out:
- SYSCTL_SUNLOCK();
+ SYSCTL_RUNLOCK(&tracker);
return (error);
}
@@ -1429,9 +1421,7 @@ kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
req.newfunc = sysctl_new_kernel;
req.lock = REQ_UNWIRED;
- SYSCTL_SLOCK();
error = sysctl_root(0, name, namelen, &req);
- SYSCTL_SUNLOCK();
if (req.lock == REQ_WIRED && req.validlen > 0)
vsunlock(req.oldptr, req.validlen);
@@ -1608,13 +1598,14 @@ static int
sysctl_root(SYSCTL_HANDLER_ARGS)
{
struct sysctl_oid *oid;
+ struct rm_priotracker tracker;
int error, indx, lvl;
- SYSCTL_ASSERT_SLOCKED();
+ SYSCTL_RLOCK(&tracker);
error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
if (error)
- return (error);
+ goto out;
if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
/*
@@ -1622,13 +1613,17 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
* no handler. Inform the user that it's a node.
* The indx may or may not be the same as namelen.
*/
- if (oid->oid_handler == NULL)
- return (EISDIR);
+ if (oid->oid_handler == NULL) {
+ error = EISDIR;
+ goto out;
+ }
}
/* Is this sysctl writable? */
- if (req->newptr && !(oid->oid_kind & CTLFLAG_WR))
- return (EPERM);
+ if (req->newptr && !(oid->oid_kind & CTLFLAG_WR)) {
+ error = EPERM;
+ goto out;
+ }
KASSERT(req->td != NULL, ("sysctl_root(): req->td == NULL"));
@@ -1638,10 +1633,11 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
* writing unless specifically granted for the node.
*/
if (IN_CAPABILITY_MODE(req->td)) {
- if (req->oldptr && !(oid->oid_kind & CTLFLAG_CAPRD))
- return (EPERM);
- if (req->newptr && !(oid->oid_kind & CTLFLAG_CAPWR))
- return (EPERM);
+ if ((req->oldptr && !(oid->oid_kind & CTLFLAG_CAPRD)) ||
+ (req->newptr && !(oid->oid_kind & CTLFLAG_CAPWR))) {
+ error = EPERM;
+ goto out;
+ }
}
#endif
@@ -1650,7 +1646,7 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
lvl = (oid->oid_kind & CTLMASK_SECURE) >> CTLSHIFT_SECURE;
error = securelevel_gt(req->td->td_ucred, lvl);
if (error)
- return (error);
+ goto out;
}
/* Is this sysctl writable by only privileged users? */
@@ -1668,11 +1664,13 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
priv = PRIV_SYSCTL_WRITE;
error = priv_check(req->td, priv);
if (error)
- return (error);
+ goto out;
}
- if (!oid->oid_handler)
- return (EINVAL);
+ if (!oid->oid_handler) {
+ error = EINVAL;
+ goto out;
+ }
if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
arg1 = (int *)arg1 + indx;
@@ -1685,16 +1683,18 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
error = mac_system_check_sysctl(req->td->td_ucred, oid, arg1, arg2,
req);
if (error != 0)
- return (error);
+ goto out;
#endif
#ifdef VIMAGE
if ((oid->oid_kind & CTLFLAG_VNET) && arg1 != NULL)
arg1 = (void *)(curvnet->vnet_data_base + (uintptr_t)arg1);
#endif
- error = sysctl_root_handler_locked(oid, arg1, arg2, req);
+ error = sysctl_root_handler_locked(oid, arg1, arg2, req, &tracker);
KFAIL_POINT_ERROR(_debug_fail_point, sysctl_running, error);
+out:
+ SYSCTL_RUNLOCK(&tracker);
return (error);
}
@@ -1794,9 +1794,7 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
for (;;) {
req.oldidx = 0;
req.newidx = 0;
- SYSCTL_SLOCK();
error = sysctl_root(0, name, namelen, &req);
- SYSCTL_SUNLOCK();
if (error != EAGAIN)
break;
kern_yield(PRI_USER);
diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c
index 71c88e0..950cb0e 100644
--- a/sys/kern/kern_timeout.c
+++ b/sys/kern/kern_timeout.c
@@ -1145,6 +1145,45 @@ callout_schedule(struct callout *c, int to_ticks)
}
int
+callout_drain_async(struct callout *c, callout_func_t *func, void *arg)
+{
+ struct callout_cpu *cc;
+ struct lock_class *class;
+ int retval;
+ int direct;
+
+ /* stop callout */
+ callout_stop(c);
+
+ /* check if callback is being called */
+ cc = callout_lock(c);
+ if (c->c_iflags & CALLOUT_DIRECT) {
+ direct = 1;
+ } else {
+ direct = 0;
+ }
+ retval = (cc_exec_curr(cc, direct) == c);
+
+ /* drop locks, if any */
+ if (retval && c->c_lock != NULL &&
+ c->c_lock != &Giant.lock_object) {
+ /* ensure we are properly locked */
+ class = LOCK_CLASS(c->c_lock);
+ class->lc_assert(c->c_lock, LA_XLOCKED);
+ /* the final callback should not be called locked */
+ c->c_lock = NULL;
+ c->c_iflags |= CALLOUT_RETURNUNLOCKED;
+ }
+ CC_UNLOCK(cc);
+
+ /* check if we should queue final callback */
+ if (retval)
+ callout_reset(c, 1, func, arg);
+
+ return (retval);
+}
+
+int
_callout_stop_safe(struct callout *c, int safe)
{
struct callout_cpu *cc, *old_cc;
diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c
index 6d12b61..af09613 100644
--- a/sys/kern/subr_syscall.c
+++ b/sys/kern/subr_syscall.c
@@ -63,14 +63,14 @@ syscallenter(struct thread *td, struct syscall_args *sa)
td->td_pticks = 0;
if (td->td_cowgen != p->p_cowgen)
thread_cow_update(td);
- if (p->p_flag & P_TRACED) {
- traced = 1;
+ traced = (p->p_flag & P_TRACED) != 0;
+ if (traced || td->td_dbgflags & TDB_USERWR) {
PROC_LOCK(p);
td->td_dbgflags &= ~TDB_USERWR;
- td->td_dbgflags |= TDB_SCE;
+ if (traced)
+ td->td_dbgflags |= TDB_SCE;
PROC_UNLOCK(p);
- } else
- traced = 0;
+ }
error = (p->p_sysent->sv_fetch_syscall_args)(td, sa);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL))
diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c
index f935954..9ac193a 100644
--- a/sys/kern/vfs_init.c
+++ b/sys/kern/vfs_init.c
@@ -291,7 +291,7 @@ vfs_register(struct vfsconf *vfc)
* preserved by re-registering the oid after modifying its
* number.
*/
- sysctl_xlock();
+ sysctl_wlock();
SLIST_FOREACH(oidp, SYSCTL_CHILDREN(&sysctl___vfs), oid_link) {
if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
sysctl_unregister_oid(oidp);
@@ -300,7 +300,7 @@ vfs_register(struct vfsconf *vfc)
break;
}
}
- sysctl_xunlock();
+ sysctl_wunlock();
return (0);
}
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 410d198..29ca5b1 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -4345,6 +4345,15 @@ vop_mknod_post(void *ap, int rc)
}
void
+vop_reclaim_post(void *ap, int rc)
+{
+ struct vop_reclaim_args *a = ap;
+
+ if (!rc)
+ VFS_KNOTE_LOCKED(a->a_vp, NOTE_REVOKE);
+}
+
+void
vop_remove_post(void *ap, int rc)
{
struct vop_remove_args *a = ap;
@@ -4624,7 +4633,7 @@ filt_vfsread(struct knote *kn, long hint)
* filesystem is gone, so set the EOF flag and schedule
* the knote for deletion.
*/
- if (hint == NOTE_REVOKE) {
+ if (hint == NOTE_REVOKE || (hint == 0 && vp->v_type == VBAD)) {
VI_LOCK(vp);
kn->kn_flags |= (EV_EOF | EV_ONESHOT);
VI_UNLOCK(vp);
@@ -4653,7 +4662,7 @@ filt_vfswrite(struct knote *kn, long hint)
* filesystem is gone, so set the EOF flag and schedule
* the knote for deletion.
*/
- if (hint == NOTE_REVOKE)
+ if (hint == NOTE_REVOKE || (hint == 0 && vp->v_type == VBAD))
kn->kn_flags |= (EV_EOF | EV_ONESHOT);
kn->kn_data = 0;
@@ -4670,7 +4679,7 @@ filt_vfsvnode(struct knote *kn, long hint)
VI_LOCK(vp);
if (kn->kn_sfflags & hint)
kn->kn_fflags |= hint;
- if (hint == NOTE_REVOKE) {
+ if (hint == NOTE_REVOKE || (hint == 0 && vp->v_type == VBAD)) {
kn->kn_flags |= EV_EOF;
VI_UNLOCK(vp);
return (1);
diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src
index c3c8ed3..63f8eb9 100644
--- a/sys/kern/vnode_if.src
+++ b/sys/kern/vnode_if.src
@@ -355,6 +355,7 @@ vop_inactive {
%% reclaim vp E E E
+%! reclaim post vop_reclaim_post
vop_reclaim {
IN struct vnode *vp;
diff --git a/sys/net/if.c b/sys/net/if.c
index 27fdbd9..a68d54a 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -1545,76 +1545,53 @@ ifa_free(struct ifaddr *ifa)
}
}
-int
-ifa_add_loopback_route(struct ifaddr *ifa, struct sockaddr *ia)
+static int
+ifa_maintain_loopback_route(int cmd, const char *otype, struct ifaddr *ifa,
+ struct sockaddr *ia)
{
- int error = 0;
- struct rtentry *rt = NULL;
+ int error;
struct rt_addrinfo info;
- static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
+ struct sockaddr_dl null_sdl;
+ struct ifnet *ifp;
+
+ ifp = ifa->ifa_ifp;
bzero(&info, sizeof(info));
- info.rti_ifp = V_loif;
+ if (cmd != RTM_DELETE)
+ info.rti_ifp = V_loif;
info.rti_flags = ifa->ifa_flags | RTF_HOST | RTF_STATIC;
info.rti_info[RTAX_DST] = ia;
info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl;
- error = rtrequest1_fib(RTM_ADD, &info, &rt, ifa->ifa_ifp->if_fib);
-
- if (error == 0 && rt != NULL) {
- RT_LOCK(rt);
- ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type =
- ifa->ifa_ifp->if_type;
- ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index =
- ifa->ifa_ifp->if_index;
- RT_REMREF(rt);
- RT_UNLOCK(rt);
- } else if (error != 0)
- log(LOG_DEBUG, "%s: insertion failed: %u\n", __func__, error);
+ link_init_sdl(ifp, (struct sockaddr *)&null_sdl, ifp->if_type);
+
+ error = rtrequest1_fib(cmd, &info, NULL, ifp->if_fib);
+
+ if (error != 0)
+ log(LOG_DEBUG, "%s: %s failed for interface %s: %u\n",
+ __func__, otype, if_name(ifp), error);
return (error);
}
int
-ifa_del_loopback_route(struct ifaddr *ifa, struct sockaddr *ia)
+ifa_add_loopback_route(struct ifaddr *ifa, struct sockaddr *ia)
{
- int error = 0;
- struct rt_addrinfo info;
- struct sockaddr_dl null_sdl;
- bzero(&null_sdl, sizeof(null_sdl));
- null_sdl.sdl_len = sizeof(null_sdl);
- null_sdl.sdl_family = AF_LINK;
- null_sdl.sdl_type = ifa->ifa_ifp->if_type;
- null_sdl.sdl_index = ifa->ifa_ifp->if_index;
- bzero(&info, sizeof(info));
- info.rti_flags = ifa->ifa_flags | RTF_HOST | RTF_STATIC;
- info.rti_info[RTAX_DST] = ia;
- info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&null_sdl;
- error = rtrequest1_fib(RTM_DELETE, &info, NULL, ifa->ifa_ifp->if_fib);
+ return (ifa_maintain_loopback_route(RTM_ADD, "insertion", ifa, ia));
+}
- if (error != 0)
- log(LOG_DEBUG, "%s: deletion failed: %u\n", __func__, error);
+int
+ifa_del_loopback_route(struct ifaddr *ifa, struct sockaddr *ia)
+{
- return (error);
+ return (ifa_maintain_loopback_route(RTM_DELETE, "deletion", ifa, ia));
}
int
-ifa_switch_loopback_route(struct ifaddr *ifa, struct sockaddr *sa, int fib)
+ifa_switch_loopback_route(struct ifaddr *ifa, struct sockaddr *ia)
{
- struct rtentry *rt;
- rt = rtalloc1_fib(sa, 0, 0, fib);
- if (rt == NULL) {
- log(LOG_DEBUG, "%s: fail", __func__);
- return (EHOSTUNREACH);
- }
- ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type =
- ifa->ifa_ifp->if_type;
- ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index =
- ifa->ifa_ifp->if_index;
- RTFREE_LOCKED(rt);
-
- return (0);
+ return (ifa_maintain_loopback_route(RTM_CHANGE, "switch", ifa, ia));
}
/*
diff --git a/sys/net/if_arcsubr.c b/sys/net/if_arcsubr.c
index d6724cf..d59c4a0 100644
--- a/sys/net/if_arcsubr.c
+++ b/sys/net/if_arcsubr.c
@@ -103,8 +103,8 @@ arc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
u_int8_t atype, adst;
int loop_copy = 0;
int isphds;
-#ifdef INET
- int is_gw;
+#if defined(INET) || defined(INET6)
+ int is_gw = 0;
#endif
if (!((ifp->if_flags & IFF_UP) &&
@@ -112,6 +112,11 @@ arc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
return(ENETDOWN); /* m, m1 aren't initialized yet */
error = 0;
+#if defined(INET) || defined(INET6)
+ if (ro != NULL && ro->ro_rt != NULL &&
+ (ro->ro_rt->rt_flags & RTF_GATEWAY) != 0)
+ is_gw = 1;
+#endif
switch (dst->sa_family) {
#ifdef INET
@@ -125,10 +130,6 @@ arc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
else if (ifp->if_flags & IFF_NOARP)
adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF;
else {
- is_gw = 0;
- if (ro != NULL && ro->ro_rt != NULL &&
- (ro->ro_rt->rt_flags & RTF_GATEWAY) != 0)
- is_gw = 1;
error = arpresolve(ifp, is_gw, m, dst, &adst, NULL);
if (error)
return (error == EWOULDBLOCK ? 0 : error);
@@ -169,10 +170,11 @@ arc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
case AF_INET6:
if ((m->m_flags & M_MCAST) != 0)
adst = arcbroadcastaddr; /* ARCnet broadcast address */
- else
- error = nd6_storelladdr(ifp, m, dst, (u_char *)&adst, NULL);
- if (error)
- return (error);
+ else {
+ error = nd6_resolve(ifp, is_gw, m, dst, &adst, NULL);
+ if (error != 0)
+ return (error == EWOULDBLOCK ? 0 : error);
+ }
atype = ARCTYPE_INET6;
break;
#endif
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 1842930..7bb3d99 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -225,10 +225,10 @@ ether_output(struct ifnet *ifp, struct mbuf *m,
if (lle != NULL && (pflags & LLE_VALID))
memcpy(edst, &lle->ll_addr.mac16, sizeof(edst));
else
- error = nd6_storelladdr(ifp, m, dst, (u_char *)edst,
+ error = nd6_resolve(ifp, is_gw, m, dst, (u_char *)edst,
&pflags);
if (error)
- return error;
+ return (error == EWOULDBLOCK ? 0 : error);
type = htons(ETHERTYPE_IPV6);
break;
#endif
@@ -392,16 +392,6 @@ ether_input_internal(struct ifnet *ifp, struct mbuf *m)
return;
}
#endif
- /*
- * Do consistency checks to verify assumptions
- * made by code past this point.
- */
- if ((m->m_flags & M_PKTHDR) == 0) {
- if_printf(ifp, "discard frame w/o packet header\n");
- if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
- m_freem(m);
- return;
- }
if (m->m_len < ETHER_HDR_LEN) {
/* XXX maybe should pullup? */
if_printf(ifp, "discard frame w/o leading ethernet "
@@ -413,19 +403,6 @@ ether_input_internal(struct ifnet *ifp, struct mbuf *m)
}
eh = mtod(m, struct ether_header *);
etype = ntohs(eh->ether_type);
- if (m->m_pkthdr.rcvif == NULL) {
- if_printf(ifp, "discard frame w/o interface pointer\n");
- if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
- m_freem(m);
- return;
- }
-#ifdef DIAGNOSTIC
- if (m->m_pkthdr.rcvif != ifp) {
- if_printf(ifp, "Warning, frame marked as received on %s\n",
- m->m_pkthdr.rcvif->if_xname);
- }
-#endif
-
random_harvest_queue(m, sizeof(*m), 2, RANDOM_NET_ETHER);
CURVNET_SET_QUIET(ifp->if_vnet);
@@ -499,7 +476,6 @@ ether_input_internal(struct ifnet *ifp, struct mbuf *m)
if_printf(ifp, "cannot pullup VLAN header\n");
#endif
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
- m_freem(m);
CURVNET_RESTORE();
return;
}
@@ -599,6 +575,9 @@ static void
ether_nh_input(struct mbuf *m)
{
+ M_ASSERTPKTHDR(m);
+ KASSERT(m->m_pkthdr.rcvif != NULL,
+ ("%s: NULL interface pointer", __func__));
ether_input_internal(m->m_pkthdr.rcvif, m);
}
diff --git a/sys/net/if_fddisubr.c b/sys/net/if_fddisubr.c
index 9066c0d..4a09fcd 100644
--- a/sys/net/if_fddisubr.c
+++ b/sys/net/if_fddisubr.c
@@ -101,8 +101,8 @@ fddi_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
int loop_copy = 0, error = 0, hdrcmplt = 0;
u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN];
struct fddi_header *fh;
-#ifdef INET
- int is_gw;
+#if defined(INET) || defined(INET6)
+ int is_gw = 0;
#endif
#ifdef MAC
@@ -118,13 +118,15 @@ fddi_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
senderr(ENETDOWN);
getmicrotime(&ifp->if_lastchange);
+#if defined(INET) || defined(INET6)
+ if (ro != NULL && ro->ro_rt != NULL &&
+ (ro->ro_rt->rt_flags & RTF_GATEWAY) != 0)
+ is_gw = 1;
+#endif
+
switch (dst->sa_family) {
#ifdef INET
case AF_INET: {
- is_gw = 0;
- if (ro != NULL && ro->ro_rt != NULL &&
- (ro->ro_rt->rt_flags & RTF_GATEWAY) != 0)
- is_gw = 1;
error = arpresolve(ifp, is_gw, m, dst, edst, NULL);
if (error)
return (error == EWOULDBLOCK ? 0 : error);
@@ -161,9 +163,9 @@ fddi_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
#endif /* INET */
#ifdef INET6
case AF_INET6:
- error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, NULL);
+ error = nd6_resolve(ifp, is_gw, m, dst, edst, NULL);
if (error)
- return (error); /* Something bad happened */
+ return (error == EWOULDBLOCK ? 0 : error);
type = htons(ETHERTYPE_IPV6);
break;
#endif /* INET6 */
diff --git a/sys/net/if_fwsubr.c b/sys/net/if_fwsubr.c
index 5bb12f9..f8ec120 100644
--- a/sys/net/if_fwsubr.c
+++ b/sys/net/if_fwsubr.c
@@ -89,8 +89,8 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
struct mbuf *mtail;
int unicast, dgl, foff;
static int next_dgl;
-#ifdef INET
- int is_gw;
+#if defined(INET) || defined(INET6)
+ int is_gw = 0;
#endif
#ifdef MAC
@@ -105,6 +105,11 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
goto bad;
}
+#if defined(INET) || defined(INET6)
+ if (ro != NULL && ro->ro_rt != NULL &&
+ (ro->ro_rt->rt_flags & RTF_GATEWAY) != 0)
+ is_gw = 1;
+#endif
/*
* For unicast, we make a tag to store the lladdr of the
* destination. This might not be the first time we have seen
@@ -173,10 +178,10 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
#ifdef INET6
case AF_INET6:
if (unicast) {
- error = nd6_storelladdr(fc->fc_ifp, m, dst,
+ error = nd6_resolve(fc->fc_ifp, is_gw, m, dst,
(u_char *) destfw, NULL);
if (error)
- return (error);
+ return (error == EWOULDBLOCK ? 0 : error);
}
type = ETHERTYPE_IPV6;
break;
diff --git a/sys/net/if_iso88025subr.c b/sys/net/if_iso88025subr.c
index 727df37..976e410 100644
--- a/sys/net/if_iso88025subr.c
+++ b/sys/net/if_iso88025subr.c
@@ -293,9 +293,9 @@ iso88025_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
#endif /* INET */
#ifdef INET6
case AF_INET6:
- error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, NULL);
+ error = nd6_resolve(ifp, is_gw, m, dst, edst, NULL);
if (error)
- return (error);
+ return (error == EWOULDBLOCK ? 0 : error);
snap_type = ETHERTYPE_IPV6;
break;
#endif /* INET6 */
diff --git a/sys/net/if_llatbl.c b/sys/net/if_llatbl.c
index 1e246d4..bb43be9a 100644
--- a/sys/net/if_llatbl.c
+++ b/sys/net/if_llatbl.c
@@ -186,7 +186,7 @@ htable_unlink_entry(struct llentry *lle)
}
struct prefix_match_data {
- const struct sockaddr *prefix;
+ const struct sockaddr *addr;
const struct sockaddr *mask;
struct llentries dchain;
u_int flags;
@@ -199,7 +199,7 @@ htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
pmd = (struct prefix_match_data *)farg;
- if (llt->llt_match_prefix(pmd->prefix, pmd->mask, pmd->flags, lle)) {
+ if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) {
LLE_WLOCK(lle);
LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain);
}
@@ -208,14 +208,14 @@ htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
}
static void
-htable_prefix_free(struct lltable *llt, const struct sockaddr *prefix,
+htable_prefix_free(struct lltable *llt, const struct sockaddr *addr,
const struct sockaddr *mask, u_int flags)
{
struct llentry *lle, *next;
struct prefix_match_data pmd;
bzero(&pmd, sizeof(pmd));
- pmd.prefix = prefix;
+ pmd.addr = addr;
pmd.mask = mask;
pmd.flags = flags;
LIST_INIT(&pmd.dchain);
@@ -291,17 +291,11 @@ lltable_drop_entry_queue(struct llentry *lle)
size_t
llentry_free(struct llentry *lle)
{
- struct lltable *llt;
size_t pkts_dropped;
LLE_WLOCK_ASSERT(lle);
- if ((lle->la_flags & LLE_LINKED) != 0) {
- llt = lle->lle_tbl;
-
- IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
- llt->llt_unlink_entry(lle);
- }
+ KASSERT((lle->la_flags & LLE_LINKED) == 0, ("freeing linked lle"));
pkts_dropped = lltable_drop_entry_queue(lle);
@@ -427,8 +421,42 @@ lltable_drain(int af)
}
#endif
+/*
+ * Deletes an address from given lltable.
+ * Used for userland interaction to remove
+ * individual entries. Skips entries added by OS.
+ */
+int
+lltable_delete_addr(struct lltable *llt, u_int flags,
+ const struct sockaddr *l3addr)
+{
+ struct llentry *lle;
+ struct ifnet *ifp;
+
+ ifp = llt->llt_ifp;
+ IF_AFDATA_WLOCK(ifp);
+ lle = lla_lookup(llt, LLE_EXCLUSIVE, l3addr);
+
+ if (lle == NULL) {
+ IF_AFDATA_WUNLOCK(ifp);
+ return (ENOENT);
+ }
+ if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) {
+ IF_AFDATA_WUNLOCK(ifp);
+ LLE_WUNLOCK(lle);
+ return (EPERM);
+ }
+
+ lltable_unlink_entry(llt, lle);
+ IF_AFDATA_WUNLOCK(ifp);
+
+ llt->llt_delete_entry(llt, lle);
+
+ return (0);
+}
+
void
-lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask,
+lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask,
u_int flags)
{
struct lltable *llt;
@@ -438,7 +466,7 @@ lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask,
if (llt->llt_af != af)
continue;
- llt->llt_prefix_free(llt, prefix, mask, flags);
+ llt->llt_prefix_free(llt, addr, mask, flags);
}
LLTABLE_RUNLOCK();
}
@@ -651,10 +679,7 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
break;
case RTM_DELETE:
- IF_AFDATA_WLOCK(ifp);
- error = lla_delete(llt, 0, dst);
- IF_AFDATA_WUNLOCK(ifp);
- return (error == 0 ? 0 : ENOENT);
+ return (lltable_delete_addr(llt, 0, dst));
default:
error = EINVAL;
diff --git a/sys/net/if_llatbl.h b/sys/net/if_llatbl.h
index 0571bf0..98d28f2 100644
--- a/sys/net/if_llatbl.h
+++ b/sys/net/if_llatbl.h
@@ -135,10 +135,9 @@ typedef struct llentry *(llt_lookup_t)(struct lltable *, u_int flags,
const struct sockaddr *l3addr);
typedef struct llentry *(llt_alloc_t)(struct lltable *, u_int flags,
const struct sockaddr *l3addr);
-typedef int (llt_delete_t)(struct lltable *, u_int flags,
- const struct sockaddr *l3addr);
+typedef void (llt_delete_t)(struct lltable *, struct llentry *);
typedef void (llt_prefix_free_t)(struct lltable *,
- const struct sockaddr *prefix, const struct sockaddr *mask, u_int flags);
+ const struct sockaddr *addr, const struct sockaddr *mask, u_int flags);
typedef int (llt_dump_entry_t)(struct lltable *, struct llentry *,
struct sysctl_req *);
typedef uint32_t (llt_hash_t)(const struct llentry *, uint32_t);
@@ -162,7 +161,7 @@ struct lltable {
llt_lookup_t *llt_lookup;
llt_alloc_t *llt_alloc_entry;
- llt_delete_t *llt_delete;
+ llt_delete_t *llt_delete_entry;
llt_prefix_free_t *llt_prefix_free;
llt_dump_entry_t *llt_dump_entry;
llt_hash_t *llt_hash;
@@ -184,6 +183,7 @@ MALLOC_DECLARE(M_LLTABLE);
#define LLE_STATIC 0x0002 /* entry is static */
#define LLE_IFADDR 0x0004 /* entry is interface addr */
#define LLE_VALID 0x0008 /* ll_addr is valid */
+#define LLE_REDIRECT 0x0010 /* installed by redirect; has host rtentry */
#define LLE_PUB 0x0020 /* publish entry ??? */
#define LLE_LINKED 0x0040 /* linked to lookup structure */
/* LLE request flags */
@@ -212,6 +212,8 @@ size_t lltable_drop_entry_queue(struct llentry *);
struct llentry *lltable_alloc_entry(struct lltable *llt, u_int flags,
const struct sockaddr *l4addr);
void lltable_free_entry(struct lltable *llt, struct llentry *lle);
+int lltable_delete_addr(struct lltable *llt, u_int flags,
+ const struct sockaddr *l3addr);
void lltable_link_entry(struct lltable *llt, struct llentry *lle);
void lltable_unlink_entry(struct lltable *llt, struct llentry *lle);
void lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa);
@@ -230,14 +232,6 @@ lla_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
return (llt->llt_lookup(llt, flags, l3addr));
}
-static __inline int
-lla_delete(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
-{
-
- return (llt->llt_delete(llt, flags, l3addr));
-}
-
-
int lla_rt_output(struct rt_msghdr *, struct rt_addrinfo *);
#include <sys/eventhandler.h>
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index 572e413..9dfc459 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -243,11 +243,12 @@ struct ifnet {
* count limit does not apply. If all three fields are zero,
* there is no TSO limit.
*
- * NOTE: The TSO limits only apply to the data payload part of
- * a TCP/IP packet. That means there is no need to subtract
- * space for ethernet-, vlan-, IP- or TCP- headers from the
- * TSO limits unless the hardware driver in question requires
- * so.
+ * NOTE: The TSO limits should reflect the values used in the
+ * BUSDMA tag a network adapter is using to load a mbuf chain
+ * for transmission. The TCP/IP network stack will subtract
+ * space for all linklevel and protocol level headers and
+ * ensure that the full mbuf chain passed to the network
+ * adapter fits within the given limits.
*/
u_int if_hw_tsomax; /* TSO maximum size in bytes */
u_int if_hw_tsomaxsegcount; /* TSO maximum segment count */
@@ -503,7 +504,7 @@ struct ifnet *ifunit_ref(const char *);
int ifa_add_loopback_route(struct ifaddr *, struct sockaddr *);
int ifa_del_loopback_route(struct ifaddr *, struct sockaddr *);
-int ifa_switch_loopback_route(struct ifaddr *, struct sockaddr *, int fib);
+int ifa_switch_loopback_route(struct ifaddr *, struct sockaddr *);
struct ifaddr *ifa_ifwithaddr(const struct sockaddr *);
int ifa_ifwithaddr_check(const struct sockaddr *);
diff --git a/sys/net/route.c b/sys/net/route.c
index 1517dca..4035b03 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -584,13 +584,20 @@ rtredirect_fib(struct sockaddr *dst,
* we have a routing loop, perhaps as a result of an interface
* going down recently.
*/
- if (!(flags & RTF_DONE) && rt &&
- (!sa_equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
- error = EINVAL;
- else if (ifa_ifwithaddr_check(gateway))
+ if (!(flags & RTF_DONE) && rt) {
+ if (!sa_equal(src, rt->rt_gateway)) {
+ error = EINVAL;
+ goto done;
+ }
+ if (rt->rt_ifa != ifa && ifa->ifa_addr->sa_family != AF_LINK) {
+ error = EINVAL;
+ goto done;
+ }
+ }
+ if ((flags & RTF_GATEWAY) && ifa_ifwithaddr_check(gateway)) {
error = EHOSTUNREACH;
- if (error)
goto done;
+ }
/*
* Create a new entry if we just got back a wildcard entry
* or the lookup failed. This is necessary for hosts
@@ -613,7 +620,7 @@ rtredirect_fib(struct sockaddr *dst,
rt0 = rt;
rt = NULL;
- flags |= RTF_GATEWAY | RTF_DYNAMIC;
+ flags |= RTF_DYNAMIC;
bzero((caddr_t)&info, sizeof(info));
info.rti_info[RTAX_DST] = dst;
info.rti_info[RTAX_GATEWAY] = gateway;
@@ -640,6 +647,8 @@ rtredirect_fib(struct sockaddr *dst,
* Smash the current notion of the gateway to
* this destination. Should check about netmask!!!
*/
+ if ((flags & RTF_GATEWAY) == 0)
+ rt->rt_flags &= ~RTF_GATEWAY;
rt->rt_flags |= RTF_MODIFIED;
flags |= RTF_MODIFIED;
stat = &V_rtstat.rts_newgateway;
@@ -653,7 +662,8 @@ rtredirect_fib(struct sockaddr *dst,
gwrt = rtalloc1(gateway, 1, RTF_RNH_LOCKED);
RADIX_NODE_HEAD_UNLOCK(rnh);
EVENTHANDLER_INVOKE(route_redirect_event, rt, gwrt, dst);
- RTFREE_LOCKED(gwrt);
+ if (gwrt)
+ RTFREE_LOCKED(gwrt);
}
} else
error = EHOSTUNREACH;
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c
index ded6564..ad07473 100644
--- a/sys/netinet/if_ether.c
+++ b/sys/netinet/if_ether.c
@@ -58,7 +58,6 @@ __FBSDID("$FreeBSD$");
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/netisr.h>
-#include <net/if_llc.h>
#include <net/ethernet.h>
#include <net/route.h>
#include <net/vnet.h>
@@ -71,13 +70,13 @@ __FBSDID("$FreeBSD$");
#include <netinet/ip_carp.h>
#endif
-#include <net/if_arc.h>
-#include <net/iso88025.h>
-
#include <security/mac/mac_framework.h>
#define SIN(s) ((const struct sockaddr_in *)(s))
-#define SDL(s) ((struct sockaddr_dl *)s)
+
+static struct timeval arp_lastlog;
+static int arp_curpps;
+static int arp_maxpps = 1;
SYSCTL_DECL(_net_link_ether);
static SYSCTL_NODE(_net_link_ether, PF_INET, inet, CTLFLAG_RW, 0, "");
@@ -122,6 +121,16 @@ SYSCTL_VNET_PCPUSTAT(_net_link_ether_arp, OID_AUTO, stats, struct arpstat,
SYSCTL_INT(_net_link_ether_inet, OID_AUTO, maxhold, CTLFLAG_VNET | CTLFLAG_RW,
&VNET_NAME(arp_maxhold), 0,
"Number of packets to hold per ARP entry");
+SYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_log_per_second,
+ CTLFLAG_RW, &arp_maxpps, 0,
+ "Maximum number of remotely triggered ARP messages that can be "
+ "logged per second");
+
+#define ARP_LOG(pri, ...) do { \
+ if (ppsratecheck(&arp_lastlog, &arp_curpps, arp_maxpps)) \
+ log((pri), "arp: " __VA_ARGS__); \
+} while (0)
+
static void arp_init(void);
static void arpintr(struct mbuf *);
@@ -144,26 +153,6 @@ static const struct netisr_handler arp_nh = {
.nh_policy = NETISR_POLICY_SOURCE,
};
-#ifdef AF_INET
-/*
- * called by in_scrubprefix() to remove entry from the table when
- * the interface goes away
- */
-void
-arp_ifscrub(struct ifnet *ifp, uint32_t addr)
-{
- struct sockaddr_in addr4;
-
- bzero((void *)&addr4, sizeof(addr4));
- addr4.sin_len = sizeof(addr4);
- addr4.sin_family = AF_INET;
- addr4.sin_addr.s_addr = addr;
- IF_AFDATA_WLOCK(ifp);
- lla_delete(LLTABLE(ifp), LLE_IFADDR, (struct sockaddr *)&addr4);
- IF_AFDATA_WUNLOCK(ifp);
-}
-#endif
-
/*
* Timeout routine. Age arp_tab entries periodically.
*/
@@ -218,16 +207,14 @@ arptimer(void *arg)
/* Guard against race with other llentry_free(). */
if (lle->la_flags & LLE_LINKED) {
-
- size_t pkts_dropped;
LLE_REMREF(lle);
- pkts_dropped = llentry_free(lle);
- ARPSTAT_ADD(dropped, pkts_dropped);
- } else
- LLE_FREE_LOCKED(lle);
-
+ lltable_unlink_entry(lle->lle_tbl, lle);
+ }
IF_AFDATA_UNLOCK(ifp);
+ size_t pkts_dropped = llentry_free(lle);
+
+ ARPSTAT_ADD(dropped, pkts_dropped);
ARPSTAT_INC(timeouts);
CURVNET_RESTORE();
@@ -529,34 +516,73 @@ static void
arpintr(struct mbuf *m)
{
struct arphdr *ar;
+ struct ifnet *ifp;
+ char *layer;
+ int hlen;
+
+ ifp = m->m_pkthdr.rcvif;
if (m->m_len < sizeof(struct arphdr) &&
((m = m_pullup(m, sizeof(struct arphdr))) == NULL)) {
- log(LOG_NOTICE, "arp: runt packet -- m_pullup failed\n");
+ ARP_LOG(LOG_NOTICE, "packet with short header received on %s\n",
+ if_name(ifp));
+ return;
+ }
+ ar = mtod(m, struct arphdr *);
+
+ /* Check if length is sufficient */
+ if ((m = m_pullup(m, arphdr_len(ar))) == NULL) {
+ ARP_LOG(LOG_NOTICE, "short packet received on %s\n",
+ if_name(ifp));
return;
}
ar = mtod(m, struct arphdr *);
- if (ntohs(ar->ar_hrd) != ARPHRD_ETHER &&
- ntohs(ar->ar_hrd) != ARPHRD_IEEE802 &&
- ntohs(ar->ar_hrd) != ARPHRD_ARCNET &&
- ntohs(ar->ar_hrd) != ARPHRD_IEEE1394 &&
- ntohs(ar->ar_hrd) != ARPHRD_INFINIBAND) {
- log(LOG_NOTICE, "arp: unknown hardware address format (0x%2D)"
- " (from %*D to %*D)\n", (unsigned char *)&ar->ar_hrd, "",
- ETHER_ADDR_LEN, (u_char *)ar_sha(ar), ":",
- ETHER_ADDR_LEN, (u_char *)ar_tha(ar), ":");
+ hlen = 0;
+ layer = "";
+ switch (ntohs(ar->ar_hrd)) {
+ case ARPHRD_ETHER:
+ hlen = ETHER_ADDR_LEN; /* RFC 826 */
+ layer = "ethernet";
+ break;
+ case ARPHRD_IEEE802:
+ hlen = 6; /* RFC 1390, FDDI_ADDR_LEN */
+ layer = "fddi";
+ break;
+ case ARPHRD_ARCNET:
+ hlen = 1; /* RFC 1201, ARC_ADDR_LEN */
+ layer = "arcnet";
+ break;
+ case ARPHRD_INFINIBAND:
+ hlen = 20; /* RFC 4391, INFINIBAND_ALEN */
+ layer = "infiniband";
+ break;
+ case ARPHRD_IEEE1394:
+ hlen = 0; /* SHALL be 16 */ /* RFC 2734 */
+ layer = "firewire";
+
+ /*
+ * Restrict too long harware addresses.
+ * Currently we are capable of handling 20-byte
+ * addresses ( sizeof(lle->ll_addr) )
+ */
+ if (ar->ar_hln >= 20)
+ hlen = 16;
+ break;
+ default:
+ ARP_LOG(LOG_NOTICE,
+ "packet with unknown harware format 0x%02d received on %s\n",
+ ntohs(ar->ar_hrd), if_name(ifp));
m_freem(m);
return;
}
- if (m->m_len < arphdr_len(ar)) {
- if ((m = m_pullup(m, arphdr_len(ar))) == NULL) {
- log(LOG_NOTICE, "arp: runt packet\n");
- m_freem(m);
- return;
- }
- ar = mtod(m, struct arphdr *);
+ if (hlen != 0 && hlen != ar->ar_hln) {
+ ARP_LOG(LOG_NOTICE,
+ "packet with invalid %s address length %d received on %s\n",
+ layer, ar->ar_hln, if_name(ifp));
+ m_freem(m);
+ return;
}
ARPSTAT_INC(received);
@@ -589,9 +615,6 @@ static int log_arp_wrong_iface = 1;
static int log_arp_movements = 1;
static int log_arp_permanent_modify = 1;
static int allow_multicast = 0;
-static struct timeval arp_lastlog;
-static int arp_curpps;
-static int arp_maxpps = 1;
SYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_wrong_iface, CTLFLAG_RW,
&log_arp_wrong_iface, 0,
@@ -604,15 +627,6 @@ SYSCTL_INT(_net_link_ether_inet, OID_AUTO, log_arp_permanent_modify, CTLFLAG_RW,
"log arp replies from MACs different than the one in the permanent arp entry");
SYSCTL_INT(_net_link_ether_inet, OID_AUTO, allow_multicast, CTLFLAG_RW,
&allow_multicast, 0, "accept multicast addresses");
-SYSCTL_INT(_net_link_ether_inet, OID_AUTO, max_log_per_second,
- CTLFLAG_RW, &arp_maxpps, 0,
- "Maximum number of remotely triggered ARP messages that can be "
- "logged per second");
-
-#define ARP_LOG(pri, ...) do { \
- if (ppsratecheck(&arp_lastlog, &arp_curpps, arp_maxpps)) \
- log((pri), "arp: " __VA_ARGS__); \
-} while (0)
static void
in_arpinput(struct mbuf *m)
@@ -628,7 +642,6 @@ in_arpinput(struct mbuf *m)
struct in_addr isaddr, itaddr, myaddr;
u_int8_t *enaddr = NULL;
int op;
- int req_len;
int bridged = 0, is_bridge = 0;
int carped;
struct sockaddr_in sin;
@@ -642,13 +655,12 @@ in_arpinput(struct mbuf *m)
if (ifp->if_type == IFT_BRIDGE)
is_bridge = 1;
- req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr));
- if (m->m_len < req_len && (m = m_pullup(m, req_len)) == NULL) {
- ARP_LOG(LOG_NOTICE, "runt packet -- m_pullup failed\n");
- return;
- }
-
+ /*
+ * We already have checked that mbuf contains enough contiguous data
+ * to hold entire arp message according to the arp header.
+ */
ah = mtod(m, struct arphdr *);
+
/*
* ARP is only for IPv4 so we can reject packets with
* a protocol length not equal to an IPv4 address.
diff --git a/sys/netinet/if_ether.h b/sys/netinet/if_ether.h
index 39fc386..f23da5b 100644
--- a/sys/netinet/if_ether.h
+++ b/sys/netinet/if_ether.h
@@ -120,7 +120,6 @@ void arprequest(struct ifnet *, const struct in_addr *,
const struct in_addr *, u_char *);
void arp_ifinit(struct ifnet *, struct ifaddr *);
void arp_ifinit2(struct ifnet *, struct ifaddr *, u_char *);
-void arp_ifscrub(struct ifnet *, uint32_t);
#endif
#endif
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index bc00012..b582ba1 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -724,6 +724,38 @@ in_addprefix(struct in_ifaddr *target, int flags)
}
/*
+ * Removes either all lle entries for given @ia, or lle
+ * corresponding to @ia address.
+ */
+static void
+in_scrubprefixlle(struct in_ifaddr *ia, int all, u_int flags)
+{
+ struct sockaddr_in addr, mask;
+ struct sockaddr *saddr, *smask;
+ struct ifnet *ifp;
+
+ /*
+ * remove all L2 entries on the given prefix
+ */
+ saddr = (struct sockaddr *)&addr;
+ bzero(&addr, sizeof(addr));
+ addr.sin_len = sizeof(addr);
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = ntohl(ia->ia_addr.sin_addr.s_addr);
+ smask = (struct sockaddr *)&mask;
+ bzero(&mask, sizeof(mask));
+ mask.sin_len = sizeof(mask);
+ mask.sin_family = AF_INET;
+ mask.sin_addr.s_addr = ia->ia_subnetmask;
+ ifp = ia->ia_ifp;
+
+ if (all)
+ lltable_prefix_free(AF_INET, saddr, smask, flags);
+ else
+ lltable_delete_addr(LLTABLE(ifp), LLE_IFADDR, saddr);
+}
+
+/*
* If there is no other address in the system that can serve a route to the
* same prefix, remove the route. Hand over the route to the new address
* otherwise.
@@ -735,7 +767,6 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags)
struct in_ifaddr *ia;
struct in_addr prefix, mask, p, m;
int error = 0;
- struct sockaddr_in prefix0, mask0;
/*
* Remove the loopback route to the interface address.
@@ -745,23 +776,21 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags)
(flags & LLE_STATIC)) {
struct in_ifaddr *eia;
+ /*
+ * XXXME: add fib-aware in_localip.
+ * We definitely don't want to switch between
+ * prefixes in different fibs.
+ */
eia = in_localip_more(target);
if (eia != NULL) {
- int fibnum = target->ia_ifp->if_fib;
-
error = ifa_switch_loopback_route((struct ifaddr *)eia,
- (struct sockaddr *)&target->ia_addr, fibnum);
+ (struct sockaddr *)&target->ia_addr);
ifa_free(&eia->ia_ifa);
} else {
error = ifa_del_loopback_route((struct ifaddr *)target,
(struct sockaddr *)&target->ia_addr);
}
-
- if (!(target->ia_ifp->if_flags & IFF_NOARP))
- /* remove arp cache */
- arp_ifscrub(target->ia_ifp,
- IA_SIN(target)->sin_addr.s_addr);
}
if (rtinitflags(target)) {
@@ -817,6 +846,9 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags)
else
log(LOG_INFO, "in_scrubprefix: err=%d, old prefix delete failed\n",
error);
+ /* Scrub all entries IFF interface is different */
+ in_scrubprefixlle(target, target->ia_ifp != ia->ia_ifp,
+ flags);
error = rtinit(&ia->ia_ifa, (int)RTM_ADD,
rtinitflags(ia) | RTF_UP);
if (error == 0)
@@ -833,16 +865,7 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags)
/*
* remove all L2 entries on the given prefix
*/
- bzero(&prefix0, sizeof(prefix0));
- prefix0.sin_len = sizeof(prefix0);
- prefix0.sin_family = AF_INET;
- prefix0.sin_addr.s_addr = target->ia_subnet;
- bzero(&mask0, sizeof(mask0));
- mask0.sin_len = sizeof(mask0);
- mask0.sin_family = AF_INET;
- mask0.sin_addr.s_addr = target->ia_subnetmask;
- lltable_prefix_free(AF_INET, (struct sockaddr *)&prefix0,
- (struct sockaddr *)&mask0, flags);
+ in_scrubprefixlle(target, 1, flags);
/*
* As no-one seem to have this prefix, we can remove the route.
@@ -1001,22 +1024,38 @@ in_lltable_new(struct in_addr addr4, u_int flags)
return (&lle->base);
}
-#define IN_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \
- (((ntohl((d).s_addr) ^ (a)->sin_addr.s_addr) & (m)->sin_addr.s_addr)) == 0 )
+#define IN_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \
+ ((((d).s_addr ^ (a).s_addr) & (m).s_addr)) == 0 )
static int
-in_lltable_match_prefix(const struct sockaddr *prefix,
- const struct sockaddr *mask, u_int flags, struct llentry *lle)
+in_lltable_match_prefix(const struct sockaddr *saddr,
+ const struct sockaddr *smask, u_int flags, struct llentry *lle)
{
- const struct sockaddr_in *pfx = (const struct sockaddr_in *)prefix;
- const struct sockaddr_in *msk = (const struct sockaddr_in *)mask;
+ struct in_addr addr, mask, lle_addr;
- /*
- * (flags & LLE_STATIC) means deleting all entries
- * including static ARP entries.
- */
- if (IN_ARE_MASKED_ADDR_EQUAL(lle->r_l3addr.addr4, pfx, msk) &&
- ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC)))
+ addr = ((const struct sockaddr_in *)saddr)->sin_addr;
+ mask = ((const struct sockaddr_in *)smask)->sin_addr;
+ lle_addr.s_addr = ntohl(lle->r_l3addr.addr4.s_addr);
+
+ if (IN_ARE_MASKED_ADDR_EQUAL(lle_addr, addr, mask) == 0)
+ return (0);
+
+ if (lle->la_flags & LLE_IFADDR) {
+
+ /*
+ * Delete LLE_IFADDR records IFF address & flag matches.
+ * Note that addr is the interface address within prefix
+ * being matched.
+ * Note also we should handle 'ifdown' cases without removing
+ * ifaddr macs.
+ */
+ if (addr.s_addr == lle_addr.s_addr && (flags & LLE_STATIC) != 0)
+ return (1);
+ return (0);
+ }
+
+ /* flags & LLE_STATIC means deleting both dynamic and static entries */
+ if ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC))
return (1);
return (0);
@@ -1166,39 +1205,16 @@ in_lltable_find_dst(struct lltable *llt, struct in_addr dst)
return (lle);
}
-static int
-in_lltable_delete(struct lltable *llt, u_int flags,
- const struct sockaddr *l3addr)
+static void
+in_lltable_delete_entry(struct lltable *llt, struct llentry *lle)
{
- const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr;
- struct llentry *lle;
-
- IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
- KASSERT(l3addr->sa_family == AF_INET,
- ("sin_family %d", l3addr->sa_family));
- lle = in_lltable_find_dst(llt, sin->sin_addr);
- if (lle == NULL) {
+ lle->la_flags |= LLE_DELETED;
+ EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
#ifdef DIAGNOSTIC
- log(LOG_INFO, "interface address is missing from cache = %p in delete\n", lle);
+ log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
#endif
- return (ENOENT);
- }
-
- if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
- LLE_WLOCK(lle);
- lle->la_flags |= LLE_DELETED;
- EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
-#ifdef DIAGNOSTIC
- log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
-#endif
- if ((lle->la_flags & (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC)
- llentry_free(lle);
- else
- LLE_WUNLOCK(lle);
- }
-
- return (0);
+ llentry_free(lle);
}
static struct llentry *
@@ -1334,7 +1350,7 @@ in_lltattach(struct ifnet *ifp)
llt->llt_lookup = in_lltable_lookup;
llt->llt_alloc_entry = in_lltable_alloc;
- llt->llt_delete = in_lltable_delete;
+ llt->llt_delete_entry = in_lltable_delete_entry;
llt->llt_dump_entry = in_lltable_dump_entry;
llt->llt_hash = in_lltable_hash;
llt->llt_fill_sa_entry = in_lltable_fill_sa_entry;
diff --git a/sys/netinet/in_kdtrace.c b/sys/netinet/in_kdtrace.c
index edcc853..f39f0e8 100644
--- a/sys/netinet/in_kdtrace.c
+++ b/sys/netinet/in_kdtrace.c
@@ -105,6 +105,25 @@ SDT_PROBE_DEFINE5_XLATE(tcp, , , send,
SDT_PROBE_DEFINE1_XLATE(tcp, , , siftr,
"struct pkt_node *", "siftrinfo_t *");
+SDT_PROBE_DEFINE3_XLATE(tcp, , , debug__input,
+ "struct tcpcb *", "tcpsinfo_t *" ,
+ "struct tcphdr *", "tcpinfo_t *",
+ "uint8_t *", "ipinfo_t *");
+
+SDT_PROBE_DEFINE3_XLATE(tcp, , , debug__output,
+ "struct tcpcb *", "tcpsinfo_t *" ,
+ "struct tcphdr *", "tcpinfo_t *",
+ "uint8_t *", "ipinfo_t *");
+
+SDT_PROBE_DEFINE2_XLATE(tcp, , , debug__user,
+ "struct tcpcb *", "tcpsinfo_t *" ,
+ "int", "int");
+
+SDT_PROBE_DEFINE3_XLATE(tcp, , , debug__drop,
+ "struct tcpcb *", "tcpsinfo_t *" ,
+ "struct tcphdr *", "tcpinfo_t *",
+ "uint8_t *", "ipinfo_t *")
+
SDT_PROBE_DEFINE6_XLATE(tcp, , , state__change,
"void *", "void *",
"struct tcpcb *", "csinfo_t *",
diff --git a/sys/netinet/in_kdtrace.h b/sys/netinet/in_kdtrace.h
index c0511d0..ba8355a 100644
--- a/sys/netinet/in_kdtrace.h
+++ b/sys/netinet/in_kdtrace.h
@@ -34,6 +34,12 @@
SDT_PROBE5(udp, , , probe, arg0, arg1, arg2, arg3, arg4)
#define TCP_PROBE1(probe, arg0) \
SDT_PROBE1(tcp, , , probe, arg0)
+#define TCP_PROBE2(probe, arg0, arg1) \
+ SDT_PROBE2(tcp, , , probe, arg0, arg1)
+#define TCP_PROBE3(probe, arg0, arg1, arg2) \
+ SDT_PROBE3(tcp, , , probe, arg0, arg1, arg2)
+#define TCP_PROBE4(probe, arg0, arg1, arg2, arg3) \
+ SDT_PROBE4(tcp, , , probe, arg0, arg1, arg2, arg3)
#define TCP_PROBE5(probe, arg0, arg1, arg2, arg3, arg4) \
SDT_PROBE5(tcp, , , probe, arg0, arg1, arg2, arg3, arg4)
#define TCP_PROBE6(probe, arg0, arg1, arg2, arg3, arg4, arg5) \
@@ -55,6 +61,10 @@ SDT_PROBE_DECLARE(tcp, , , receive);
SDT_PROBE_DECLARE(tcp, , , send);
SDT_PROBE_DECLARE(tcp, , , siftr);
SDT_PROBE_DECLARE(tcp, , , state__change);
+SDT_PROBE_DECLARE(tcp, , , debug__input);
+SDT_PROBE_DECLARE(tcp, , , debug__output);
+SDT_PROBE_DECLARE(tcp, , , debug__user);
+SDT_PROBE_DECLARE(tcp, , , debug__drop);
SDT_PROBE_DECLARE(udp, , , receive);
SDT_PROBE_DECLARE(udp, , , send);
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
index 2fa8820..7e45069 100644
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -985,7 +985,7 @@ carp_ifa_delroute(struct ifaddr *ifa)
case AF_INET6:
ifa_del_loopback_route(ifa,
(struct sockaddr *)&ifatoia6(ifa)->ia_addr);
- nd6_rem_ifa_lle(ifatoia6(ifa));
+ nd6_rem_ifa_lle(ifatoia6(ifa), 1);
break;
#endif
}
diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h
index 8a033d8..784c1d4 100644
--- a/sys/netinet/sctp.h
+++ b/sys/netinet/sctp.h
@@ -388,33 +388,32 @@ struct sctp_error_cause {
} SCTP_PACKED;
struct sctp_error_invalid_stream {
- struct sctp_error_cause cause; /* code=SCTP_ERROR_INVALID_STREAM */
+ struct sctp_error_cause cause; /* code=SCTP_CAUSE_INVALID_STREAM */
uint16_t stream_id; /* stream id of the DATA in error */
uint16_t reserved;
} SCTP_PACKED;
struct sctp_error_missing_param {
- struct sctp_error_cause cause; /* code=SCTP_ERROR_MISSING_PARAM */
+ struct sctp_error_cause cause; /* code=SCTP_CAUSE_MISSING_PARAM */
uint32_t num_missing_params; /* number of missing parameters */
- /* uint16_t param_type's follow */
+ uint16_t type[];
} SCTP_PACKED;
struct sctp_error_stale_cookie {
- struct sctp_error_cause cause; /* code=SCTP_ERROR_STALE_COOKIE */
+ struct sctp_error_cause cause; /* code=SCTP_CAUSE_STALE_COOKIE */
uint32_t stale_time; /* time in usec of staleness */
} SCTP_PACKED;
struct sctp_error_out_of_resource {
- struct sctp_error_cause cause; /* code=SCTP_ERROR_OUT_OF_RESOURCES */
+ struct sctp_error_cause cause; /* code=SCTP_CAUSE_OUT_OF_RESOURCES */
} SCTP_PACKED;
struct sctp_error_unresolv_addr {
- struct sctp_error_cause cause; /* code=SCTP_ERROR_UNRESOLVABLE_ADDR */
-
+ struct sctp_error_cause cause; /* code=SCTP_CAUSE_UNRESOLVABLE_ADDR */
} SCTP_PACKED;
struct sctp_error_unrecognized_chunk {
- struct sctp_error_cause cause; /* code=SCTP_ERROR_UNRECOG_CHUNK */
+ struct sctp_error_cause cause; /* code=SCTP_CAUSE_UNRECOG_CHUNK */
struct sctp_chunkhdr ch;/* header from chunk in error */
} SCTP_PACKED;
@@ -423,6 +422,11 @@ struct sctp_error_no_user_data {
uint32_t tsn; /* TSN of the empty data chunk */
} SCTP_PACKED;
+struct sctp_error_auth_invalid_hmac {
+ struct sctp_error_cause cause; /* code=SCTP_CAUSE_UNSUPPORTED_HMACID */
+ uint16_t hmac_id;
+} SCTP_PACKED;
+
/*
* Main SCTP chunk types we place these here so natd and f/w's in user land
* can find them.
diff --git a/sys/netinet/sctp_auth.c b/sys/netinet/sctp_auth.c
index 7c2e194..13454df 100644
--- a/sys/netinet/sctp_auth.c
+++ b/sys/netinet/sctp_auth.c
@@ -1651,8 +1651,8 @@ sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth,
/* is the indicated HMAC supported? */
if (!sctp_auth_is_supported_hmac(stcb->asoc.local_hmacs, hmac_id)) {
- struct mbuf *m_err;
- struct sctp_auth_invalid_hmac *err;
+ struct mbuf *op_err;
+ struct sctp_error_auth_invalid_hmac *cause;
SCTP_STAT_INCR(sctps_recvivalhmacid);
SCTPDBG(SCTP_DEBUG_AUTH1,
@@ -1662,20 +1662,19 @@ sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth,
* report this in an Error Chunk: Unsupported HMAC
* Identifier
*/
- m_err = sctp_get_mbuf_for_msg(sizeof(*err), 0, M_NOWAIT,
- 1, MT_HEADER);
- if (m_err != NULL) {
+ op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_auth_invalid_hmac),
+ 0, M_NOWAIT, 1, MT_HEADER);
+ if (op_err != NULL) {
/* pre-reserve some space */
- SCTP_BUF_RESV_UF(m_err, sizeof(struct sctp_chunkhdr));
+ SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
/* fill in the error */
- err = mtod(m_err, struct sctp_auth_invalid_hmac *);
- bzero(err, sizeof(*err));
- err->ph.param_type = htons(SCTP_CAUSE_UNSUPPORTED_HMACID);
- err->ph.param_length = htons(sizeof(*err));
- err->hmac_id = ntohs(hmac_id);
- SCTP_BUF_LEN(m_err) = sizeof(*err);
+ cause = mtod(op_err, struct sctp_error_auth_invalid_hmac *);
+ cause->cause.code = htons(SCTP_CAUSE_UNSUPPORTED_HMACID);
+ cause->cause.length = htons(sizeof(struct sctp_error_auth_invalid_hmac));
+ cause->hmac_id = ntohs(hmac_id);
+ SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_auth_invalid_hmac);
/* queue it */
- sctp_queue_op_err(stcb, m_err);
+ sctp_queue_op_err(stcb, op_err);
}
return (-1);
}
diff --git a/sys/netinet/sctp_header.h b/sys/netinet/sctp_header.h
index f322e04..dc05b3d 100644
--- a/sys/netinet/sctp_header.h
+++ b/sys/netinet/sctp_header.h
@@ -202,34 +202,6 @@ struct sctp_state_cookie { /* this is our definition... */
*/
} SCTP_PACKED;
-
-/* Used for NAT state error cause */
-struct sctp_missing_nat_state {
- uint16_t cause;
- uint16_t length;
- uint8_t data[];
-} SCTP_PACKED;
-
-
-struct sctp_inv_mandatory_param {
- uint16_t cause;
- uint16_t length;
- uint32_t num_param;
- uint16_t param;
- /*
- * We include this to 0 it since only a missing cookie will cause
- * this error.
- */
- uint16_t resv;
-} SCTP_PACKED;
-
-struct sctp_unresolv_addr {
- uint16_t cause;
- uint16_t length;
- uint16_t addr_type;
- uint16_t reserved; /* Only one invalid addr type */
-} SCTP_PACKED;
-
/* state cookie parameter */
struct sctp_state_cookie_param {
struct sctp_paramhdr ph;
@@ -370,28 +342,11 @@ struct sctp_shutdown_complete_chunk {
struct sctp_chunkhdr ch;
} SCTP_PACKED;
-/* Oper error holding a stale cookie */
-struct sctp_stale_cookie_msg {
- struct sctp_paramhdr ph;/* really an error cause */
- uint32_t time_usec;
-} SCTP_PACKED;
-
struct sctp_adaptation_layer_indication {
struct sctp_paramhdr ph;
uint32_t indication;
} SCTP_PACKED;
-struct sctp_cookie_while_shutting_down {
- struct sctphdr sh;
- struct sctp_chunkhdr ch;
- struct sctp_paramhdr ph;/* really an error cause */
-} SCTP_PACKED;
-
-struct sctp_shutdown_complete_msg {
- struct sctphdr sh;
- struct sctp_shutdown_complete_chunk shut_cmp;
-} SCTP_PACKED;
-
/*
* draft-ietf-tsvwg-addip-sctp
*/
@@ -554,12 +509,6 @@ struct sctp_auth_chunk {
uint8_t hmac[];
} SCTP_PACKED;
-struct sctp_auth_invalid_hmac {
- struct sctp_paramhdr ph;
- uint16_t hmac_id;
- uint16_t padding;
-} SCTP_PACKED;
-
/*
* we pre-reserve enough room for a ECNE or CWR AND a SACK with no missing
* pieces. If ENCE is missing we could have a couple of blocks. This way we
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index d9ca669..34f4bfd 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -1426,30 +1426,25 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
strmno = ntohs(ch->dp.stream_id);
if (strmno >= asoc->streamincnt) {
- struct sctp_paramhdr *phdr;
- struct mbuf *mb;
+ struct sctp_error_invalid_stream *cause;
- mb = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) * 2),
+ op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_invalid_stream),
0, M_NOWAIT, 1, MT_DATA);
- if (mb != NULL) {
+ if (op_err != NULL) {
/* add some space up front so prepend will work well */
- SCTP_BUF_RESV_UF(mb, sizeof(struct sctp_chunkhdr));
- phdr = mtod(mb, struct sctp_paramhdr *);
+ SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
+ cause = mtod(op_err, struct sctp_error_invalid_stream *);
/*
* Error causes are just param's and this one has
* two back to back phdr, one with the error type
* and size, the other with the streamid and a rsvd
*/
- SCTP_BUF_LEN(mb) = (sizeof(struct sctp_paramhdr) * 2);
- phdr->param_type = htons(SCTP_CAUSE_INVALID_STREAM);
- phdr->param_length =
- htons(sizeof(struct sctp_paramhdr) * 2);
- phdr++;
- /* We insert the stream in the type field */
- phdr->param_type = ch->dp.stream_id;
- /* And set the length to 0 for the rsvd field */
- phdr->param_length = 0;
- sctp_queue_op_err(stcb, mb);
+ SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_invalid_stream);
+ cause->cause.code = htons(SCTP_CAUSE_INVALID_STREAM);
+ cause->cause.length = htons(sizeof(struct sctp_error_invalid_stream));
+ cause->stream_id = ch->dp.stream_id;
+ cause->reserved = htons(0);
+ sctp_queue_op_err(stcb, op_err);
}
SCTP_STAT_INCR(sctps_badsid);
SCTP_TCB_LOCK_ASSERT(stcb);
@@ -2492,30 +2487,21 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
/* unknown chunk type, use bit rules */
if (ch->ch.chunk_type & 0x40) {
/* Add a error report to the queue */
- struct mbuf *merr;
- struct sctp_paramhdr *phd;
-
- merr = sctp_get_mbuf_for_msg(sizeof(*phd), 0, M_NOWAIT, 1, MT_DATA);
- if (merr) {
- phd = mtod(merr, struct sctp_paramhdr *);
- /*
- * We cheat and use param
- * type since we did not
- * bother to define a error
- * cause struct. They are
- * the same basic format
- * with different names.
- */
- phd->param_type =
- htons(SCTP_CAUSE_UNRECOG_CHUNK);
- phd->param_length =
- htons(chk_length + sizeof(*phd));
- SCTP_BUF_LEN(merr) = sizeof(*phd);
- SCTP_BUF_NEXT(merr) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT);
- if (SCTP_BUF_NEXT(merr)) {
- sctp_queue_op_err(stcb, merr);
+ struct mbuf *op_err;
+ struct sctp_gen_error_cause *cause;
+
+ op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_gen_error_cause),
+ 0, M_NOWAIT, 1, MT_DATA);
+ if (op_err != NULL) {
+ cause = mtod(op_err, struct sctp_gen_error_cause *);
+ cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK);
+ cause->length = htons(chk_length + sizeof(struct sctp_gen_error_cause));
+ SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause);
+ SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT);
+ if (SCTP_BUF_NEXT(op_err) != NULL) {
+ sctp_queue_op_err(stcb, op_err);
} else {
- sctp_m_freem(merr);
+ sctp_m_freem(op_err);
}
}
}
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index 9f8d032..37d9e60 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -530,25 +530,21 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
* abandon the peer, its broke.
*/
if (retval == -3) {
+ uint16_t len;
+
+ len = (uint16_t) (sizeof(struct sctp_error_missing_param) + sizeof(uint16_t));
/* We abort with an error of missing mandatory param */
- op_err = sctp_generate_cause(SCTP_CAUSE_MISSING_PARAM, "");
- if (op_err) {
- /*
- * Expand beyond to include the mandatory
- * param cookie
- */
- struct sctp_inv_mandatory_param *mp;
+ op_err = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
+ if (op_err != NULL) {
+ struct sctp_error_missing_param *cause;
- SCTP_BUF_LEN(op_err) =
- sizeof(struct sctp_inv_mandatory_param);
- mp = mtod(op_err,
- struct sctp_inv_mandatory_param *);
+ SCTP_BUF_LEN(op_err) = len;
+ cause = mtod(op_err, struct sctp_error_missing_param *);
/* Subtract the reserved param */
- mp->length =
- htons(sizeof(struct sctp_inv_mandatory_param) - 2);
- mp->num_param = htonl(1);
- mp->param = htons(SCTP_STATE_COOKIE);
- mp->resv = 0;
+ cause->cause.code = htons(SCTP_CAUSE_MISSING_PARAM);
+ cause->cause.length = htons(len);
+ cause->num_missing_params = htonl(1);
+ cause->type[0] = htons(SCTP_STATE_COOKIE);
}
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
src, dst, sh, op_err,
@@ -781,10 +777,10 @@ sctp_handle_abort(struct sctp_abort_chunk *abort,
* Need to check the cause codes for our two magic nat
* aborts which don't kill the assoc necessarily.
*/
- struct sctp_missing_nat_state *natc;
+ struct sctp_gen_error_cause *cause;
- natc = (struct sctp_missing_nat_state *)(abort + 1);
- error = ntohs(natc->cause);
+ cause = (struct sctp_gen_error_cause *)(abort + 1);
+ error = ntohs(cause->code);
if (error == SCTP_CAUSE_NAT_COLLIDING_STATE) {
SCTPDBG(SCTP_DEBUG_INPUT2, "Received Colliding state abort flags:%x\n",
abort->ch.chunk_flags);
@@ -2558,27 +2554,27 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
if (timevalcmp(&now, &time_expires, >)) {
/* cookie is stale! */
struct mbuf *op_err;
- struct sctp_stale_cookie_msg *scm;
+ struct sctp_error_stale_cookie *cause;
uint32_t tim;
- op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_stale_cookie_msg),
+ op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_stale_cookie),
0, M_NOWAIT, 1, MT_DATA);
if (op_err == NULL) {
/* FOOBAR */
return (NULL);
}
/* Set the len */
- SCTP_BUF_LEN(op_err) = sizeof(struct sctp_stale_cookie_msg);
- scm = mtod(op_err, struct sctp_stale_cookie_msg *);
- scm->ph.param_type = htons(SCTP_CAUSE_STALE_COOKIE);
- scm->ph.param_length = htons((sizeof(struct sctp_paramhdr) +
+ SCTP_BUF_LEN(op_err) = sizeof(struct sctp_error_stale_cookie);
+ cause = mtod(op_err, struct sctp_error_stale_cookie *);
+ cause->cause.code = htons(SCTP_CAUSE_STALE_COOKIE);
+ cause->cause.length = htons((sizeof(struct sctp_paramhdr) +
(sizeof(uint32_t))));
/* seconds to usec */
tim = (now.tv_sec - time_expires.tv_sec) * 1000000;
/* add in usec */
if (tim == 0)
tim = now.tv_usec - cookie->time_entered.tv_usec;
- scm->time_usec = htonl(tim);
+ cause->stale_time = htonl(tim);
sctp_send_operr_to(src, dst, sh, cookie->peers_vtag, op_err,
mflowtype, mflowid, l_inp->fibnum,
vrf_id, port);
@@ -5581,35 +5577,27 @@ process_control_chunks:
unknown_chunk:
/* it's an unknown chunk! */
if ((ch->chunk_type & 0x40) && (stcb != NULL)) {
- struct mbuf *mm;
- struct sctp_paramhdr *phd;
+ struct sctp_gen_error_cause *cause;
int len;
- mm = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr),
+ op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_gen_error_cause),
0, M_NOWAIT, 1, MT_DATA);
- if (mm) {
+ if (op_err != NULL) {
len = min(SCTP_SIZE32(chk_length), (uint32_t) (length - *offset));
- phd = mtod(mm, struct sctp_paramhdr *);
- /*
- * We cheat and use param type since
- * we did not bother to define a
- * error cause struct. They are the
- * same basic format with different
- * names.
- */
- phd->param_type = htons(SCTP_CAUSE_UNRECOG_CHUNK);
- phd->param_length = htons(len + sizeof(*phd));
- SCTP_BUF_LEN(mm) = sizeof(*phd);
- SCTP_BUF_NEXT(mm) = SCTP_M_COPYM(m, *offset, len, M_NOWAIT);
- if (SCTP_BUF_NEXT(mm)) {
+ cause = mtod(op_err, struct sctp_gen_error_cause *);
+ cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK);
+ cause->length = htons(len + sizeof(struct sctp_gen_error_cause));
+ SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause);
+ SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, len, M_NOWAIT);
+ if (SCTP_BUF_NEXT(op_err) != NULL) {
#ifdef SCTP_MBUF_LOGGING
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
- sctp_log_mbc(SCTP_BUF_NEXT(mm), SCTP_MBUF_ICOPY);
+ sctp_log_mbc(SCTP_BUF_NEXT(op_err), SCTP_MBUF_ICOPY);
}
#endif
- sctp_queue_op_err(stcb, mm);
+ sctp_queue_op_err(stcb, op_err);
} else {
- sctp_m_freem(mm);
+ sctp_m_freem(op_err);
}
}
}
diff --git a/sys/netinet/sctp_sysctl.h b/sys/netinet/sctp_sysctl.h
index 5055110..38494ad 100644
--- a/sys/netinet/sctp_sysctl.h
+++ b/sys/netinet/sctp_sysctl.h
@@ -545,7 +545,7 @@ struct sctp_sysctl {
#define SCTPCTL_RTTVAR_DCCCECN_MAX 1
#define SCTPCTL_RTTVAR_DCCCECN_DEFAULT 1 /* 0 means disable feature */
-#define SCTPCTL_BLACKHOLE_DESC "Enable SCTP blackholing. See blackhole(4) man page for more details."
+#define SCTPCTL_BLACKHOLE_DESC "Enable SCTP blackholing. See blackhole(4) for more details."
#define SCTPCTL_BLACKHOLE_MIN 0
#define SCTPCTL_BLACKHOLE_MAX 2
#define SCTPCTL_BLACKHOLE_DEFAULT SCTPCTL_BLACKHOLE_MIN
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index e7ef6db..83a7d31 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1377,6 +1377,7 @@ relocked:
tcp_trace(TA_INPUT, ostate, tp,
(void *)tcp_saveipgen, &tcp_savetcp, 0);
#endif
+ TCP_PROBE3(debug__input, tp, th, mtod(m, const char *));
tcp_dooptions(&to, optp, optlen, TO_SYN);
syncache_add(&inc, &to, th, inp, &so, m, NULL, NULL);
/*
@@ -1779,6 +1780,8 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
(void *)tcp_saveipgen,
&tcp_savetcp, 0);
#endif
+ TCP_PROBE3(debug__input, tp, th,
+ mtod(m, const char *));
if (tp->snd_una == tp->snd_max)
tcp_timer_activate(tp, TT_REXMT, 0);
else if (!tcp_timer_active(tp, TT_PERSIST))
@@ -1825,6 +1828,8 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
tcp_trace(TA_INPUT, ostate, tp,
(void *)tcp_saveipgen, &tcp_savetcp, 0);
#endif
+ TCP_PROBE3(debug__input, tp, th, mtod(m, const char *));
+
/*
* Automatic sizing of receive socket buffer. Often the send
* buffer size is not optimally adjusted to the actual network
@@ -3022,6 +3027,7 @@ dodata: /* XXX */
tcp_trace(TA_INPUT, ostate, tp, (void *)tcp_saveipgen,
&tcp_savetcp, 0);
#endif
+ TCP_PROBE3(debug__input, tp, th, mtod(m, const char *));
/*
* Return any desired output.
@@ -3069,6 +3075,7 @@ dropafterack:
tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen,
&tcp_savetcp, 0);
#endif
+ TCP_PROBE3(debug__input, tp, th, mtod(m, const char *));
if (ti_locked == TI_RLOCKED)
INP_INFO_RUNLOCK(&V_tcbinfo);
ti_locked = TI_UNLOCKED;
@@ -3109,6 +3116,7 @@ drop:
tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen,
&tcp_savetcp, 0);
#endif
+ TCP_PROBE3(debug__input, tp, th, mtod(m, const char *));
if (tp != NULL)
INP_WUNLOCK(tp->t_inpcb);
m_freem(m);
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index 342990e..fc90b06 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -811,7 +811,8 @@ send:
*/
if (if_hw_tsomax != 0) {
/* compute maximum TSO length */
- max_len = (if_hw_tsomax - hdrlen);
+ max_len = (if_hw_tsomax - hdrlen -
+ max_linkhdr);
if (max_len <= 0) {
len = 0;
} else if (len > max_len) {
@@ -826,6 +827,15 @@ send:
*/
if (if_hw_tsomaxsegcount != 0 &&
if_hw_tsomaxsegsize != 0) {
+ /*
+ * Subtract one segment for the LINK
+ * and TCP/IP headers mbuf that will
+ * be prepended to this mbuf chain
+ * after the code in this section
+ * limits the number of mbufs in the
+ * chain to if_hw_tsomaxsegcount.
+ */
+ if_hw_tsomaxsegcount -= 1;
max_len = 0;
mb = sbsndmbuf(&so->so_snd, off, &moff);
@@ -1253,6 +1263,7 @@ send:
ipov->ih_len = save;
}
#endif /* TCPDEBUG */
+ TCP_PROBE3(debug__input, tp, th, mtod(m, const char *));
/*
* Fill in IP length and desired time to live and
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 207ad03..c8395e5 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -720,6 +720,7 @@ tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, struct mbuf *m,
if (tp == NULL || (inp->inp_socket->so_options & SO_DEBUG))
tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0);
#endif
+ TCP_PROBE3(debug__input, tp, th, mtod(m, const char *));
if (flags & TH_RST)
TCP_PROBE5(accept__refused, NULL, NULL, mtod(m, const char *),
tp, nth);
@@ -1514,74 +1515,75 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
ip = NULL;
else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)
return;
- if (ip != NULL) {
- icp = (struct icmp *)((caddr_t)ip
- - offsetof(struct icmp, icmp_ip));
- th = (struct tcphdr *)((caddr_t)ip
- + (ip->ip_hl << 2));
- INP_INFO_RLOCK(&V_tcbinfo);
- inp = in_pcblookup(&V_tcbinfo, faddr, th->th_dport,
- ip->ip_src, th->th_sport, INPLOOKUP_WLOCKPCB, NULL);
- if (inp != NULL) {
- if (!(inp->inp_flags & INP_TIMEWAIT) &&
- !(inp->inp_flags & INP_DROPPED) &&
- !(inp->inp_socket == NULL)) {
- icmp_tcp_seq = htonl(th->th_seq);
- tp = intotcpcb(inp);
- if (SEQ_GEQ(icmp_tcp_seq, tp->snd_una) &&
- SEQ_LT(icmp_tcp_seq, tp->snd_max)) {
- if (cmd == PRC_MSGSIZE) {
- /*
- * MTU discovery:
- * If we got a needfrag set the MTU
- * in the route to the suggested new
- * value (if given) and then notify.
- */
- bzero(&inc, sizeof(inc));
- inc.inc_faddr = faddr;
- inc.inc_fibnum =
- inp->inp_inc.inc_fibnum;
-
- mtu = ntohs(icp->icmp_nextmtu);
- /*
- * If no alternative MTU was
- * proposed, try the next smaller
- * one.
- */
- if (!mtu)
+
+ if (ip == NULL) {
+ in_pcbnotifyall(&V_tcbinfo, faddr, inetctlerrmap[cmd], notify);
+ return;
+ }
+
+ icp = (struct icmp *)((caddr_t)ip - offsetof(struct icmp, icmp_ip));
+ th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
+ INP_INFO_RLOCK(&V_tcbinfo);
+ inp = in_pcblookup(&V_tcbinfo, faddr, th->th_dport, ip->ip_src,
+ th->th_sport, INPLOOKUP_WLOCKPCB, NULL);
+ if (inp != NULL) {
+ if (!(inp->inp_flags & INP_TIMEWAIT) &&
+ !(inp->inp_flags & INP_DROPPED) &&
+ !(inp->inp_socket == NULL)) {
+ icmp_tcp_seq = htonl(th->th_seq);
+ tp = intotcpcb(inp);
+ if (SEQ_GEQ(icmp_tcp_seq, tp->snd_una) &&
+ SEQ_LT(icmp_tcp_seq, tp->snd_max)) {
+ if (cmd == PRC_MSGSIZE) {
+ /*
+ * MTU discovery:
+ * If we got a needfrag set the MTU
+ * in the route to the suggested new
+ * value (if given) and then notify.
+ */
+ bzero(&inc, sizeof(inc));
+ inc.inc_faddr = faddr;
+ inc.inc_fibnum =
+ inp->inp_inc.inc_fibnum;
+
+ mtu = ntohs(icp->icmp_nextmtu);
+ /*
+ * If no alternative MTU was
+ * proposed, try the next smaller
+ * one.
+ */
+ if (!mtu)
mtu = ip_next_mtu(
- ntohs(ip->ip_len), 1);
- if (mtu < V_tcp_minmss
- + sizeof(struct tcpiphdr))
- mtu = V_tcp_minmss
- + sizeof(struct tcpiphdr);
- /*
- * Only cache the MTU if it
- * is smaller than the interface
- * or route MTU. tcp_mtudisc()
- * will do right thing by itself.
- */
- if (mtu <= tcp_maxmtu(&inc, NULL))
+ ntohs(ip->ip_len), 1);
+ if (mtu < V_tcp_minmss +
+ sizeof(struct tcpiphdr))
+ mtu = V_tcp_minmss +
+ sizeof(struct tcpiphdr);
+ /*
+ * Only cache the MTU if it
+ * is smaller than the interface
+ * or route MTU. tcp_mtudisc()
+ * will do right thing by itself.
+ */
+ if (mtu <= tcp_maxmtu(&inc, NULL))
tcp_hc_updatemtu(&inc, mtu);
- tcp_mtudisc(inp, mtu);
- } else
- inp = (*notify)(inp,
- inetctlerrmap[cmd]);
- }
+ tcp_mtudisc(inp, mtu);
+ } else
+ inp = (*notify)(inp,
+ inetctlerrmap[cmd]);
}
- if (inp != NULL)
- INP_WUNLOCK(inp);
- } else {
- bzero(&inc, sizeof(inc));
- inc.inc_fport = th->th_dport;
- inc.inc_lport = th->th_sport;
- inc.inc_faddr = faddr;
- inc.inc_laddr = ip->ip_src;
- syncache_unreach(&inc, th);
}
- INP_INFO_RUNLOCK(&V_tcbinfo);
- } else
- in_pcbnotifyall(&V_tcbinfo, faddr, inetctlerrmap[cmd], notify);
+ if (inp != NULL)
+ INP_WUNLOCK(inp);
+ } else {
+ bzero(&inc, sizeof(inc));
+ inc.inc_fport = th->th_dport;
+ inc.inc_lport = th->th_sport;
+ inc.inc_faddr = faddr;
+ inc.inc_laddr = ip->ip_src;
+ syncache_unreach(&inc, th);
+ }
+ INP_INFO_RUNLOCK(&V_tcbinfo);
}
#endif /* INET */
diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c
index 7990646..60b882f 100644
--- a/sys/netinet/tcp_timer.c
+++ b/sys/netinet/tcp_timer.c
@@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/cc.h>
#include <netinet/in.h>
+#include <netinet/in_kdtrace.h>
#include <netinet/in_pcb.h>
#include <netinet/in_rss.h>
#include <netinet/in_systm.h>
@@ -369,6 +370,8 @@ tcp_timer_2msl(void *xtp)
tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0,
PRU_SLOWTIMO);
#endif
+ TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO);
+
if (tp != NULL)
INP_WUNLOCK(inp);
INP_INFO_RUNLOCK(&V_tcbinfo);
@@ -454,6 +457,7 @@ tcp_timer_keep(void *xtp)
tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0,
PRU_SLOWTIMO);
#endif
+ TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO);
INP_WUNLOCK(inp);
INP_INFO_RUNLOCK(&V_tcbinfo);
CURVNET_RESTORE();
@@ -468,6 +472,7 @@ dropit:
tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0,
PRU_SLOWTIMO);
#endif
+ TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO);
if (tp != NULL)
INP_WUNLOCK(tp->t_inpcb);
INP_INFO_RUNLOCK(&V_tcbinfo);
@@ -546,6 +551,7 @@ out:
if (tp != NULL && tp->t_inpcb->inp_socket->so_options & SO_DEBUG)
tcp_trace(TA_USER, ostate, tp, NULL, NULL, PRU_SLOWTIMO);
#endif
+ TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO);
if (tp != NULL)
INP_WUNLOCK(inp);
INP_INFO_RUNLOCK(&V_tcbinfo);
@@ -792,6 +798,7 @@ out:
tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0,
PRU_SLOWTIMO);
#endif
+ TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO);
if (tp != NULL)
INP_WUNLOCK(inp);
if (headlocked)
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index fe390e0..7d1ec6a 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/cc.h>
#include <netinet/in.h>
+#include <netinet/in_kdtrace.h>
#include <netinet/in_pcb.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
@@ -146,6 +147,7 @@ tcp_usr_attach(struct socket *so, int proto, struct thread *td)
tp = intotcpcb(inp);
out:
TCPDEBUG2(PRU_ATTACH);
+ TCP_PROBE2(debug__user, tp, PRU_ATTACH);
return error;
}
@@ -295,6 +297,7 @@ tcp_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
INP_HASH_WUNLOCK(&V_tcbinfo);
out:
TCPDEBUG2(PRU_BIND);
+ TCP_PROBE2(debug__user, tp, PRU_BIND);
INP_WUNLOCK(inp);
return (error);
@@ -355,6 +358,7 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
INP_HASH_WUNLOCK(&V_tcbinfo);
out:
TCPDEBUG2(PRU_BIND);
+ TCP_PROBE2(debug__user, tp, PRU_BIND);
INP_WUNLOCK(inp);
return (error);
}
@@ -399,6 +403,7 @@ tcp_usr_listen(struct socket *so, int backlog, struct thread *td)
out:
TCPDEBUG2(PRU_LISTEN);
+ TCP_PROBE2(debug__user, tp, PRU_LISTEN);
INP_WUNLOCK(inp);
return (error);
}
@@ -444,6 +449,7 @@ tcp6_usr_listen(struct socket *so, int backlog, struct thread *td)
out:
TCPDEBUG2(PRU_LISTEN);
+ TCP_PROBE2(debug__user, tp, PRU_LISTEN);
INP_WUNLOCK(inp);
return (error);
}
@@ -592,6 +598,7 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
out:
TCPDEBUG2(PRU_CONNECT);
+ TCP_PROBE2(debug__user, tp, PRU_CONNECT);
INP_WUNLOCK(inp);
return (error);
}
@@ -631,6 +638,7 @@ tcp_usr_disconnect(struct socket *so)
tcp_disconnect(tp);
out:
TCPDEBUG2(PRU_DISCONNECT);
+ TCP_PROBE2(debug__user, tp, PRU_DISCONNECT);
INP_WUNLOCK(inp);
INP_INFO_RUNLOCK(&V_tcbinfo);
return (error);
@@ -674,6 +682,7 @@ tcp_usr_accept(struct socket *so, struct sockaddr **nam)
out:
TCPDEBUG2(PRU_ACCEPT);
+ TCP_PROBE2(debug__user, tp, PRU_ACCEPT);
INP_WUNLOCK(inp);
if (error == 0)
*nam = in_sockaddr(port, &addr);
@@ -724,6 +733,7 @@ tcp6_usr_accept(struct socket *so, struct sockaddr **nam)
out:
TCPDEBUG2(PRU_ACCEPT);
+ TCP_PROBE2(debug__user, tp, PRU_ACCEPT);
INP_WUNLOCK(inp);
INP_INFO_RUNLOCK(&V_tcbinfo);
if (error == 0) {
@@ -764,6 +774,7 @@ tcp_usr_shutdown(struct socket *so)
out:
TCPDEBUG2(PRU_SHUTDOWN);
+ TCP_PROBE2(debug__user, tp, PRU_SHUTDOWN);
INP_WUNLOCK(inp);
INP_INFO_RUNLOCK(&V_tcbinfo);
@@ -799,6 +810,7 @@ tcp_usr_rcvd(struct socket *so, int flags)
out:
TCPDEBUG2(PRU_RCVD);
+ TCP_PROBE2(debug__user, tp, PRU_RCVD);
INP_WUNLOCK(inp);
return (error);
}
@@ -953,6 +965,8 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
out:
TCPDEBUG2((flags & PRUS_OOB) ? PRU_SENDOOB :
((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND));
+ TCP_PROBE2(debug__user, tp, (flags & PRUS_OOB) ? PRU_SENDOOB :
+ ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND));
INP_WUNLOCK(inp);
if (flags & PRUS_EOF)
INP_INFO_RUNLOCK(&V_tcbinfo);
@@ -1013,6 +1027,7 @@ tcp_usr_abort(struct socket *so)
TCPDEBUG1();
tcp_drop(tp, ECONNABORTED);
TCPDEBUG2(PRU_ABORT);
+ TCP_PROBE2(debug__user, tp, PRU_ABORT);
}
if (!(inp->inp_flags & INP_DROPPED)) {
SOCK_LOCK(so);
@@ -1052,6 +1067,7 @@ tcp_usr_close(struct socket *so)
TCPDEBUG1();
tcp_disconnect(tp);
TCPDEBUG2(PRU_CLOSE);
+ TCP_PROBE2(debug__user, tp, PRU_CLOSE);
}
if (!(inp->inp_flags & INP_DROPPED)) {
SOCK_LOCK(so);
@@ -1101,6 +1117,7 @@ tcp_usr_rcvoob(struct socket *so, struct mbuf *m, int flags)
out:
TCPDEBUG2(PRU_RCVOOB);
+ TCP_PROBE2(debug__user, tp, PRU_RCVOOB);
INP_WUNLOCK(inp);
return (error);
}
@@ -1748,9 +1765,9 @@ tcp_usrclosed(struct tcpcb *tp)
#ifdef TCP_OFFLOAD
tcp_offload_listen_stop(tp);
#endif
+ tcp_state_change(tp, TCPS_CLOSED);
/* FALLTHROUGH */
case TCPS_CLOSED:
- tcp_state_change(tp, TCPS_CLOSED);
tp = tcp_close(tp);
/*
* tcp_close() should never return NULL here as the socket is
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index 29dd3ed..c918e69 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -2434,27 +2434,39 @@ icmp6_redirect_input(struct mbuf *m, int off)
nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT,
is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER);
- if (!is_onlink) { /* better router case. perform rtredirect. */
- /* perform rtredirect */
+ /*
+ * Install a gateway route in the better-router case or an interface
+ * route in the on-link-destination case.
+ */
+ {
struct sockaddr_in6 sdst;
struct sockaddr_in6 sgw;
struct sockaddr_in6 ssrc;
+ struct sockaddr *gw;
+ int rt_flags;
u_int fibnum;
bzero(&sdst, sizeof(sdst));
- bzero(&sgw, sizeof(sgw));
bzero(&ssrc, sizeof(ssrc));
- sdst.sin6_family = sgw.sin6_family = ssrc.sin6_family = AF_INET6;
- sdst.sin6_len = sgw.sin6_len = ssrc.sin6_len =
- sizeof(struct sockaddr_in6);
- bcopy(&redtgt6, &sgw.sin6_addr, sizeof(struct in6_addr));
+ sdst.sin6_family = ssrc.sin6_family = AF_INET6;
+ sdst.sin6_len = ssrc.sin6_len = sizeof(struct sockaddr_in6);
bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
bcopy(&src6, &ssrc.sin6_addr, sizeof(struct in6_addr));
+ rt_flags = RTF_HOST;
+ if (is_router) {
+ bzero(&sgw, sizeof(sgw));
+ sgw.sin6_family = AF_INET6;
+ sgw.sin6_len = sizeof(struct sockaddr_in6);
+ bcopy(&redtgt6, &sgw.sin6_addr,
+ sizeof(struct in6_addr));
+ gw = (struct sockaddr *)&sgw;
+ rt_flags |= RTF_GATEWAY;
+ } else
+ gw = ifp->if_addr->ifa_addr;
for (fibnum = 0; fibnum < rt_numfibs; fibnum++)
- in6_rtredirect((struct sockaddr *)&sdst,
- (struct sockaddr *)&sgw, (struct sockaddr *)NULL,
- RTF_GATEWAY | RTF_HOST, (struct sockaddr *)&ssrc,
- fibnum);
+ in6_rtredirect((struct sockaddr *)&sdst, gw,
+ (struct sockaddr *)NULL, rt_flags,
+ (struct sockaddr *)&ssrc, fibnum);
}
/* finally update cached route in each socket via pfctlinput */
{
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index b14af01..9996dbf 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -1307,9 +1307,6 @@ in6_purgeaddr(struct ifaddr *ifa)
/* stop DAD processing */
nd6_dad_stop(ifa);
- /* Remove local address entry from lltable. */
- nd6_rem_ifa_lle(ia);
-
/* Leave multicast groups. */
while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
LIST_REMOVE(imm, i6mm_chain);
@@ -1333,6 +1330,7 @@ static void
in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
{
char ip6buf[INET6_ADDRSTRLEN];
+ int remove_lle;
IF_ADDR_WLOCK(ifp);
TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
@@ -1353,15 +1351,21 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
* Release the reference to the base prefix. There should be a
* positive reference.
*/
+ remove_lle = 0;
if (ia->ia6_ndpr == NULL) {
nd6log((LOG_NOTICE,
"in6_unlink_ifa: autoconf'ed address "
"%s has no prefix\n", ip6_sprintf(ip6buf, IA6_IN6(ia))));
} else {
ia->ia6_ndpr->ndpr_refcnt--;
+ /* Do not delete lles within prefix if refcont != 0 */
+ if (ia->ia6_ndpr->ndpr_refcnt == 0)
+ remove_lle = 1;
ia->ia6_ndpr = NULL;
}
+ nd6_rem_ifa_lle(ia, remove_lle);
+
/*
* Also, if the address being removed is autoconf'ed, call
* pfxlist_onlink_check() since the release might affect the status of
@@ -2081,15 +2085,33 @@ in6_lltable_new(const struct in6_addr *addr6, u_int flags)
}
static int
-in6_lltable_match_prefix(const struct sockaddr *prefix,
- const struct sockaddr *mask, u_int flags, struct llentry *lle)
+in6_lltable_match_prefix(const struct sockaddr *saddr,
+ const struct sockaddr *smask, u_int flags, struct llentry *lle)
{
- const struct sockaddr_in6 *pfx = (const struct sockaddr_in6 *)prefix;
- const struct sockaddr_in6 *msk = (const struct sockaddr_in6 *)mask;
+ const struct in6_addr *addr, *mask, *lle_addr;
+
+ addr = &((const struct sockaddr_in6 *)saddr)->sin6_addr;
+ mask = &((const struct sockaddr_in6 *)smask)->sin6_addr;
+ lle_addr = &lle->r_l3addr.addr6;
+
+ if (IN6_ARE_MASKED_ADDR_EQUAL(lle_addr, addr, mask) == 0)
+ return (0);
+
+ if (lle->la_flags & LLE_IFADDR) {
+
+ /*
+ * Delete LLE_IFADDR records IFF address & flag matches.
+ * Note that addr is the interface address within prefix
+ * being matched.
+ */
+ if (IN6_ARE_ADDR_EQUAL(addr, lle_addr) &&
+ (flags & LLE_STATIC) != 0)
+ return (1);
+ return (0);
+ }
- if (IN6_ARE_MASKED_ADDR_EQUAL(&lle->r_l3addr.addr6,
- &pfx->sin6_addr, &msk->sin6_addr) &&
- ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC)))
+ /* flags & LLE_STATIC means deleting both dynamic and static entries */
+ if ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC))
return (1);
return (0);
@@ -2200,36 +2222,16 @@ in6_lltable_find_dst(struct lltable *llt, const struct in6_addr *dst)
return (lle);
}
-static int
-in6_lltable_delete(struct lltable *llt, u_int flags,
- const struct sockaddr *l3addr)
+static void
+in6_lltable_delete_entry(struct lltable *llt, struct llentry *lle)
{
- const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr;
- struct llentry *lle;
-
- IF_AFDATA_LOCK_ASSERT(llt->llt_ifp);
- KASSERT(l3addr->sa_family == AF_INET6,
- ("sin_family %d", l3addr->sa_family));
-
- lle = in6_lltable_find_dst(llt, &sin6->sin6_addr);
- if (lle == NULL)
- return (ENOENT);
-
- if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
- LLE_WLOCK(lle);
- lle->la_flags |= LLE_DELETED;
- EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
+ lle->la_flags |= LLE_DELETED;
+ EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
#ifdef DIAGNOSTIC
- log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
+ log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
#endif
- if ((lle->la_flags & (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC)
- llentry_free(lle);
- else
- LLE_WUNLOCK(lle);
- }
-
- return (0);
+ llentry_free(lle);
}
static struct llentry *
@@ -2369,7 +2371,7 @@ in6_lltattach(struct ifnet *ifp)
llt->llt_lookup = in6_lltable_lookup;
llt->llt_alloc_entry = in6_lltable_alloc;
- llt->llt_delete = in6_lltable_delete;
+ llt->llt_delete_entry = in6_lltable_delete_entry;
llt->llt_dump_entry = in6_lltable_dump_entry;
llt->llt_hash = in6_lltable_hash;
llt->llt_fill_sa_entry = in6_lltable_fill_sa_entry;
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c
index 83e58c1..9df8e4c 100644
--- a/sys/netinet6/ip6_forward.c
+++ b/sys/netinet6/ip6_forward.c
@@ -571,7 +571,7 @@ pass:
goto bad;
}
- error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
+ error = nd6_output_ifp(rt->rt_ifp, origifp, m, dst);
if (error) {
in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
IP6STAT_INC(ip6s_cantforward);
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 09d0925..181340f 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -935,7 +935,7 @@ passout:
m->m_pkthdr.len);
ifa_free(&ia6->ia_ifa);
}
- error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
+ error = nd6_output_ifp(ifp, origifp, m, dst);
goto done;
}
@@ -1034,7 +1034,7 @@ sendorfree:
counter_u64_add(ia->ia_ifa.ifa_obytes,
m->m_pkthdr.len);
}
- error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
+ error = nd6_output_ifp(ifp, origifp, m, dst);
} else
m_freem(m);
}
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index 11276a5..5d4d594 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -126,19 +126,20 @@ VNET_DEFINE(int, nd6_recalc_reachtm_interval) = ND6_RECALC_REACHTM_INTERVAL;
int (*send_sendso_input_hook)(struct mbuf *, struct ifnet *, int, int);
-static int nd6_is_new_addr_neighbor(struct sockaddr_in6 *,
+static int nd6_is_new_addr_neighbor(const struct sockaddr_in6 *,
struct ifnet *);
static void nd6_setmtu0(struct ifnet *, struct nd_ifinfo *);
static void nd6_slowtimo(void *);
static int regen_tmpaddr(struct in6_ifaddr *);
-static struct llentry *nd6_free(struct llentry *, int);
+static void nd6_free(struct llentry *, int);
+static void nd6_free_redirect(const struct llentry *);
static void nd6_llinfo_timer(void *);
static void clear_llinfo_pqueue(struct llentry *);
static void nd6_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
-static int nd6_output_lle(struct ifnet *, struct ifnet *, struct mbuf *,
- struct sockaddr_in6 *);
-static int nd6_output_ifp(struct ifnet *, struct ifnet *, struct mbuf *,
- struct sockaddr_in6 *);
+static int nd6_resolve_slow(struct ifnet *, struct mbuf *,
+ const struct sockaddr_in6 *, u_char *, uint32_t *);
+static int nd6_need_cache(struct ifnet *);
+
static VNET_DEFINE(struct callout, nd6_slowtimo_ch);
#define V_nd6_slowtimo_ch VNET(nd6_slowtimo_ch)
@@ -602,7 +603,7 @@ nd6_llinfo_timer(void *arg)
}
if (ln->la_flags & LLE_DELETED) {
- (void)nd6_free(ln, 0);
+ nd6_free(ln, 0);
ln = NULL;
goto done;
}
@@ -629,7 +630,7 @@ nd6_llinfo_timer(void *arg)
clear_llinfo_pqueue(ln);
}
EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_TIMEDOUT);
- (void)nd6_free(ln, 0);
+ nd6_free(ln, 0);
ln = NULL;
if (m != NULL)
icmp6_error2(m, ICMP6_DST_UNREACH,
@@ -647,7 +648,7 @@ nd6_llinfo_timer(void *arg)
/* Garbage Collection(RFC 2461 5.3) */
if (!ND6_LLINFO_PERMANENT(ln)) {
EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_EXPIRED);
- (void)nd6_free(ln, 1);
+ nd6_free(ln, 1);
ln = NULL;
}
break;
@@ -669,7 +670,7 @@ nd6_llinfo_timer(void *arg)
send_ns = 1;
} else {
EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_EXPIRED);
- (void)nd6_free(ln, 0);
+ nd6_free(ln, 0);
ln = NULL;
}
break;
@@ -952,7 +953,7 @@ nd6_purge(struct ifnet *ifp)
* Returns the llentry locked
*/
struct llentry *
-nd6_lookup(struct in6_addr *addr6, int flags, struct ifnet *ifp)
+nd6_lookup(const struct in6_addr *addr6, int flags, struct ifnet *ifp)
{
struct sockaddr_in6 sin6;
struct llentry *ln;
@@ -972,7 +973,7 @@ nd6_lookup(struct in6_addr *addr6, int flags, struct ifnet *ifp)
}
struct llentry *
-nd6_alloc(struct in6_addr *addr6, int flags, struct ifnet *ifp)
+nd6_alloc(const struct in6_addr *addr6, int flags, struct ifnet *ifp)
{
struct sockaddr_in6 sin6;
struct llentry *ln;
@@ -995,7 +996,7 @@ nd6_alloc(struct in6_addr *addr6, int flags, struct ifnet *ifp)
* to not reenter the routing code from within itself.
*/
static int
-nd6_is_new_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
+nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp)
{
struct nd_prefix *pr;
struct ifaddr *dstaddr;
@@ -1068,7 +1069,7 @@ nd6_is_new_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
* If the address is assigned on the node of the other side of
* a p2p interface, the address should be a neighbor.
*/
- dstaddr = ifa_ifwithdstaddr((struct sockaddr *)addr, RT_ALL_FIBS);
+ dstaddr = ifa_ifwithdstaddr((const struct sockaddr *)addr, RT_ALL_FIBS);
if (dstaddr != NULL) {
if (dstaddr->ifa_ifp == ifp) {
ifa_free(dstaddr);
@@ -1096,7 +1097,7 @@ nd6_is_new_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
* XXX: should take care of the destination of a p2p link?
*/
int
-nd6_is_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
+nd6_is_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp)
{
struct llentry *lle;
int rc = 0;
@@ -1124,10 +1125,9 @@ nd6_is_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
* make it global, unless you have a strong reason for the change, and are sure
* that the change is safe.
*/
-static struct llentry *
+static void
nd6_free(struct llentry *ln, int gc)
{
- struct llentry *next;
struct nd_defrouter *dr;
struct ifnet *ifp;
@@ -1167,10 +1167,9 @@ nd6_free(struct llentry *ln, int gc)
nd6_llinfo_settimer_locked(ln,
(long)V_nd6_gctimer * hz);
- next = LIST_NEXT(ln, lle_next);
LLE_REMREF(ln);
LLE_WUNLOCK(ln);
- return (next);
+ return;
}
if (dr) {
@@ -1223,36 +1222,63 @@ nd6_free(struct llentry *ln, int gc)
defrouter_select();
}
+ /*
+ * If this entry was added by an on-link redirect, remove the
+ * corresponding host route.
+ */
+ if (ln->la_flags & LLE_REDIRECT)
+ nd6_free_redirect(ln);
+
if (ln->ln_router || dr)
LLE_WLOCK(ln);
}
/*
- * Before deleting the entry, remember the next entry as the
- * return value. We need this because pfxlist_onlink_check() above
- * might have freed other entries (particularly the old next entry) as
- * a side effect (XXX).
- */
- next = LIST_NEXT(ln, lle_next);
-
- /*
* Save to unlock. We still hold an extra reference and will not
* free(9) in llentry_free() if someone else holds one as well.
*/
LLE_WUNLOCK(ln);
IF_AFDATA_LOCK(ifp);
LLE_WLOCK(ln);
-
/* Guard against race with other llentry_free(). */
if (ln->la_flags & LLE_LINKED) {
+ /* Remove callout reference */
LLE_REMREF(ln);
- llentry_free(ln);
- } else
- LLE_FREE_LOCKED(ln);
-
+ lltable_unlink_entry(ln->lle_tbl, ln);
+ }
IF_AFDATA_UNLOCK(ifp);
- return (next);
+ llentry_free(ln);
+}
+
+/*
+ * Remove the rtentry for the given llentry,
+ * both of which were installed by a redirect.
+ */
+static void
+nd6_free_redirect(const struct llentry *ln)
+{
+ int fibnum;
+ struct rtentry *rt;
+ struct radix_node_head *rnh;
+ struct sockaddr_in6 sin6;
+
+ lltable_fill_sa_entry(ln, (struct sockaddr *)&sin6);
+ for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+ rnh = rt_tables_get_rnh(fibnum, AF_INET6);
+ if (rnh == NULL)
+ continue;
+
+ RADIX_NODE_HEAD_LOCK(rnh);
+ rt = in6_rtalloc1((struct sockaddr *)&sin6, 0,
+ RTF_RNH_LOCKED, fibnum);
+ if (rt) {
+ if (rt->rt_flags == (RTF_UP | RTF_HOST | RTF_DYNAMIC))
+ rt_expunge(rnh, rt);
+ RTFREE_LOCKED(rt);
+ }
+ RADIX_NODE_HEAD_UNLOCK(rnh);
+ }
}
/*
@@ -1567,17 +1593,93 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
}
/*
+ * Calculates new isRouter value based on provided parameters and
+ * returns it.
+ */
+static int
+nd6_is_router(int type, int code, int is_new, int old_addr, int new_addr,
+ int ln_router)
+{
+
+ /*
+ * ICMP6 type dependent behavior.
+ *
+ * NS: clear IsRouter if new entry
+ * RS: clear IsRouter
+ * RA: set IsRouter if there's lladdr
+ * redir: clear IsRouter if new entry
+ *
+ * RA case, (1):
+ * The spec says that we must set IsRouter in the following cases:
+ * - If lladdr exist, set IsRouter. This means (1-5).
+ * - If it is old entry (!newentry), set IsRouter. This means (7).
+ * So, based on the spec, in (1-5) and (7) cases we must set IsRouter.
+ * A quetion arises for (1) case. (1) case has no lladdr in the
+ * neighbor cache, this is similar to (6).
+ * This case is rare but we figured that we MUST NOT set IsRouter.
+ *
+ * newentry olladdr lladdr llchange NS RS RA redir
+ * D R
+ * 0 n n -- (1) c ? s
+ * 0 y n -- (2) c s s
+ * 0 n y -- (3) c s s
+ * 0 y y n (4) c s s
+ * 0 y y y (5) c s s
+ * 1 -- n -- (6) c c c s
+ * 1 -- y -- (7) c c s c s
+ *
+ * (c=clear s=set)
+ */
+ switch (type & 0xff) {
+ case ND_NEIGHBOR_SOLICIT:
+ /*
+ * New entry must have is_router flag cleared.
+ */
+ if (is_new) /* (6-7) */
+ ln_router = 0;
+ break;
+ case ND_REDIRECT:
+ /*
+ * If the icmp is a redirect to a better router, always set the
+ * is_router flag. Otherwise, if the entry is newly created,
+ * clear the flag. [RFC 2461, sec 8.3]
+ */
+ if (code == ND_REDIRECT_ROUTER)
+ ln_router = 1;
+ else {
+ if (is_new) /* (6-7) */
+ ln_router = 0;
+ }
+ break;
+ case ND_ROUTER_SOLICIT:
+ /*
+ * is_router flag must always be cleared.
+ */
+ ln_router = 0;
+ break;
+ case ND_ROUTER_ADVERT:
+ /*
+ * Mark an entry with lladdr as a router.
+ */
+ if ((!is_new && (old_addr || new_addr)) || /* (2-5) */
+ (is_new && new_addr)) { /* (7) */
+ ln_router = 1;
+ }
+ break;
+ }
+
+ return (ln_router);
+}
+
+/*
* Create neighbor cache entry and cache link-layer address,
* on reception of inbound ND6 packets. (RS/RA/NS/redirect)
*
* type - ICMP6 type
* code - type dependent information
*
- * XXXXX
- * The caller of this function already acquired the ndp
- * cache table lock because the cache entry is returned.
*/
-struct llentry *
+void
nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
int lladdrlen, int type, int code)
{
@@ -1591,7 +1693,6 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
uint16_t router = 0;
struct sockaddr_in6 sin6;
struct mbuf *chain = NULL;
- int static_route = 0;
IF_AFDATA_UNLOCK_ASSERT(ifp);
@@ -1600,7 +1701,7 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
/* nothing must be updated for unspecified address */
if (IN6_IS_ADDR_UNSPECIFIED(from))
- return NULL;
+ return;
/*
* Validation about ifp->if_addrlen and lladdrlen must be done in
@@ -1620,7 +1721,7 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
flags |= ND6_EXCLUSIVE;
ln = nd6_alloc(from, 0, ifp);
if (ln == NULL)
- return (NULL);
+ return;
IF_AFDATA_WLOCK(ifp);
LLE_WLOCK(ln);
/* Prefer any existing lle over newly-created one */
@@ -1639,8 +1740,11 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
}
/* do nothing if static ndp is set */
if ((ln->la_flags & LLE_STATIC)) {
- static_route = 1;
- goto done;
+ if (flags & ND6_EXCLUSIVE)
+ LLE_WUNLOCK(ln);
+ else
+ LLE_RUNLOCK(ln);
+ return;
}
olladdr = (ln->la_flags & LLE_VALID) ? 1 : 0;
@@ -1701,82 +1805,20 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
}
}
- /*
- * ICMP6 type dependent behavior.
- *
- * NS: clear IsRouter if new entry
- * RS: clear IsRouter
- * RA: set IsRouter if there's lladdr
- * redir: clear IsRouter if new entry
- *
- * RA case, (1):
- * The spec says that we must set IsRouter in the following cases:
- * - If lladdr exist, set IsRouter. This means (1-5).
- * - If it is old entry (!newentry), set IsRouter. This means (7).
- * So, based on the spec, in (1-5) and (7) cases we must set IsRouter.
- * A quetion arises for (1) case. (1) case has no lladdr in the
- * neighbor cache, this is similar to (6).
- * This case is rare but we figured that we MUST NOT set IsRouter.
- *
- * newentry olladdr lladdr llchange NS RS RA redir
- * D R
- * 0 n n -- (1) c ? s
- * 0 y n -- (2) c s s
- * 0 n y -- (3) c s s
- * 0 y y n (4) c s s
- * 0 y y y (5) c s s
- * 1 -- n -- (6) c c c s
- * 1 -- y -- (7) c c s c s
- *
- * (c=clear s=set)
- */
- switch (type & 0xff) {
- case ND_NEIGHBOR_SOLICIT:
- /*
- * New entry must have is_router flag cleared.
- */
- if (is_newentry) /* (6-7) */
- ln->ln_router = 0;
- break;
- case ND_REDIRECT:
- /*
- * If the icmp is a redirect to a better router, always set the
- * is_router flag. Otherwise, if the entry is newly created,
- * clear the flag. [RFC 2461, sec 8.3]
- */
- if (code == ND_REDIRECT_ROUTER)
- ln->ln_router = 1;
- else if (is_newentry) /* (6-7) */
- ln->ln_router = 0;
- break;
- case ND_ROUTER_SOLICIT:
- /*
- * is_router flag must always be cleared.
- */
- ln->ln_router = 0;
- break;
- case ND_ROUTER_ADVERT:
- /*
- * Mark an entry with lladdr as a router.
- */
- if ((!is_newentry && (olladdr || lladdr)) || /* (2-5) */
- (is_newentry && lladdr)) { /* (7) */
- ln->ln_router = 1;
- }
- break;
- }
+ /* Calculates new router status */
+ router = nd6_is_router(type, code, is_newentry, olladdr,
+ lladdr != NULL ? 1 : 0, ln->ln_router);
- if (ln != NULL) {
- static_route = (ln->la_flags & LLE_STATIC);
- router = ln->ln_router;
+ ln->ln_router = router;
+ /* Mark non-router redirects with special flag */
+ if ((type & 0xFF) == ND_REDIRECT && code != ND_REDIRECT_ROUTER)
+ ln->la_flags |= LLE_REDIRECT;
+
+ if (flags & ND6_EXCLUSIVE)
+ LLE_WUNLOCK(ln);
+ else
+ LLE_RUNLOCK(ln);
- if (flags & ND6_EXCLUSIVE)
- LLE_WUNLOCK(ln);
- else
- LLE_RUNLOCK(ln);
- if (static_route)
- ln = NULL;
- }
if (chain != NULL)
nd6_flush_holdchain(ifp, ifp, chain, &sin6);
@@ -1802,18 +1844,6 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
*/
defrouter_select();
}
-
- return (ln);
-done:
- if (ln != NULL) {
- if (flags & ND6_EXCLUSIVE)
- LLE_WUNLOCK(ln);
- else
- LLE_RUNLOCK(ln);
- if (static_route)
- ln = NULL;
- }
- return (ln);
}
static void
@@ -1874,7 +1904,7 @@ nd6_grab_holdchain(struct llentry *ln, struct mbuf **chain,
}
}
-static int
+int
nd6_output_ifp(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
struct sockaddr_in6 *dst)
{
@@ -1920,16 +1950,29 @@ nd6_output_ifp(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
}
/*
- * IPv6 packet output - light version.
- * Checks if destination LLE exists and is in proper state
- * (e.g no modification required). If not true, fall back to
- * "heavy" version.
+ * Do L2 address resolution for @sa_dst address. Stores found
+ * address in @desten buffer. Copy of lle ln_flags can be also
+ * saved in @pflags if @pflags is non-NULL.
+ *
+ * If destination LLE does not exists or lle state modification
+ * is required, call "slow" version.
+ *
+ * Return values:
+ * - 0 on success (address copied to buffer).
+ * - EWOULDBLOCK (no local error, but address is still unresolved)
+ * - other errors (alloc failure, etc)
*/
int
-nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
- struct sockaddr_in6 *dst, struct rtentry *rt0)
+nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
+ const struct sockaddr *sa_dst, u_char *desten, uint32_t *pflags)
{
struct llentry *ln = NULL;
+ const struct sockaddr_in6 *dst6;
+
+ if (pflags != NULL)
+ *pflags = 0;
+
+ dst6 = (const struct sockaddr_in6 *)sa_dst;
/* discard the packet if IPv6 operation is disabled on the interface */
if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) {
@@ -1937,14 +1980,25 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
return (ENETDOWN); /* better error? */
}
- if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr))
- goto sendpkt;
-
- if (nd6_need_cache(ifp) == 0)
- goto sendpkt;
+ if (m != NULL && m->m_flags & M_MCAST) {
+ switch (ifp->if_type) {
+ case IFT_ETHER:
+ case IFT_FDDI:
+ case IFT_L2VLAN:
+ case IFT_IEEE80211:
+ case IFT_BRIDGE:
+ case IFT_ISO88025:
+ ETHER_MAP_IPV6_MULTICAST(&dst6->sin6_addr,
+ desten);
+ return (0);
+ default:
+ m_freem(m);
+ return (EAFNOSUPPORT);
+ }
+ }
IF_AFDATA_RLOCK(ifp);
- ln = nd6_lookup(&dst->sin6_addr, 0, ifp);
+ ln = nd6_lookup(&dst6->sin6_addr, 0, ifp);
IF_AFDATA_RUNLOCK(ifp);
/*
@@ -1960,45 +2014,33 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
/* Fall back to slow processing path */
if (ln != NULL)
LLE_RUNLOCK(ln);
- return (nd6_output_lle(ifp, origifp, m, dst));
+ return (nd6_resolve_slow(ifp, m, dst6, desten, pflags));
}
-sendpkt:
- if (ln != NULL)
- LLE_RUNLOCK(ln);
- return (nd6_output_ifp(ifp, origifp, m, dst));
+ bcopy(&ln->ll_addr, desten, ifp->if_addrlen);
+ if (pflags != NULL)
+ *pflags = ln->la_flags;
+ LLE_RUNLOCK(ln);
+ return (0);
}
/*
- * Output IPv6 packet - heavy version.
- * Function assume that either
- * 1) destination LLE does not exist, is invalid or stale, so
- * ND6_EXCLUSIVE lock needs to be acquired
- * 2) destination lle is provided (with ND6_EXCLUSIVE lock),
- * in that case packets are queued in &chain.
+ * Do L2 address resolution for @sa_dst address. Stores found
+ * address in @desten buffer. Copy of lle ln_flags can be also
+ * saved in @pflags if @pflags is non-NULL.
*
+ * Heavy version.
+ * Function assume that destination LLE does not exist,
+ * is invalid or stale, so ND6_EXCLUSIVE lock needs to be acquired.
*/
static int
-nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
- struct sockaddr_in6 *dst)
+nd6_resolve_slow(struct ifnet *ifp, struct mbuf *m,
+ const struct sockaddr_in6 *dst, u_char *desten, uint32_t *pflags)
{
struct llentry *lle = NULL, *lle_tmp;
- KASSERT(m != NULL, ("NULL mbuf, nothing to send"));
- /* discard the packet if IPv6 operation is disabled on the interface */
- if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)) {
- m_freem(m);
- return (ENETDOWN); /* better error? */
- }
-
- if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr))
- goto sendpkt;
-
- if (nd6_need_cache(ifp) == 0)
- goto sendpkt;
-
/*
* Address resolution or Neighbor Unreachability Detection
* for the next hop.
@@ -2042,23 +2084,18 @@ nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
}
}
if (lle == NULL) {
- if ((ifp->if_flags & IFF_POINTOPOINT) == 0 &&
- !(ND_IFINFO(ifp)->flags & ND6_IFF_PERFORMNUD)) {
+ if (!(ND_IFINFO(ifp)->flags & ND6_IFF_PERFORMNUD)) {
m_freem(m);
return (ENOBUFS);
}
- goto sendpkt; /* send anyway */
+
+ if (m != NULL)
+ m_freem(m);
+ return (ENOBUFS);
}
LLE_WLOCK_ASSERT(lle);
- /* We don't have to do link-layer address resolution on a p2p link. */
- if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
- lle->ln_state < ND6_LLINFO_REACHABLE) {
- lle->ln_state = ND6_LLINFO_STALE;
- nd6_llinfo_settimer_locked(lle, (long)V_nd6_gctimer * hz);
- }
-
/*
* The first time we send a packet to a neighbor whose entry is
* STALE, we have to change the state to DELAY and a sets a timer to
@@ -2077,8 +2114,13 @@ nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
* (i.e. its link-layer address is already resolved), just
* send the packet.
*/
- if (lle->ln_state > ND6_LLINFO_INCOMPLETE)
- goto sendpkt;
+ if (lle->ln_state > ND6_LLINFO_INCOMPLETE) {
+ bcopy(&lle->ll_addr, desten, ifp->if_addrlen);
+ if (pflags != NULL)
+ *pflags = lle->la_flags;
+ LLE_WUNLOCK(lle);
+ return (0);
+ }
/*
* There is a neighbor cache entry, but no ethernet address
@@ -2130,13 +2172,7 @@ nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
LLE_WUNLOCK(lle);
}
- return (0);
-
- sendpkt:
- if (lle != NULL)
- LLE_WUNLOCK(lle);
-
- return (nd6_output_ifp(ifp, origifp, m, dst));
+ return (EWOULDBLOCK);
}
@@ -2162,15 +2198,12 @@ nd6_flush_holdchain(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *chain
/*
* XXX
- * note that intermediate errors are blindly ignored - but this is
- * the same convention as used with nd6_output when called by
- * nd6_cache_lladdr
+ * note that intermediate errors are blindly ignored
*/
return (error);
}
-
-int
+static int
nd6_need_cache(struct ifnet *ifp)
{
/*
@@ -2245,78 +2278,26 @@ nd6_add_ifa_lle(struct in6_ifaddr *ia)
}
/*
- * Removes ALL lle records for interface address prefix.
- * XXXME: That's probably not we really want to do, we need
- * to remove address record only and keep other records
- * until we determine if given prefix is really going
- * to be removed.
+ * Removes either all lle entries for given @ia, or lle
+ * corresponding to @ia address.
*/
void
-nd6_rem_ifa_lle(struct in6_ifaddr *ia)
+nd6_rem_ifa_lle(struct in6_ifaddr *ia, int all)
{
struct sockaddr_in6 mask, addr;
+ struct sockaddr *saddr, *smask;
struct ifnet *ifp;
ifp = ia->ia_ifa.ifa_ifp;
memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
- lltable_prefix_free(AF_INET6, (struct sockaddr *)&addr,
- (struct sockaddr *)&mask, LLE_STATIC);
-}
+ saddr = (struct sockaddr *)&addr;
+ smask = (struct sockaddr *)&mask;
-/*
- * the callers of this function need to be re-worked to drop
- * the lle lock, drop here for now
- */
-int
-nd6_storelladdr(struct ifnet *ifp, struct mbuf *m,
- const struct sockaddr *dst, u_char *desten, uint32_t *pflags)
-{
- struct llentry *ln;
-
- if (pflags != NULL)
- *pflags = 0;
- IF_AFDATA_UNLOCK_ASSERT(ifp);
- if (m != NULL && m->m_flags & M_MCAST) {
- switch (ifp->if_type) {
- case IFT_ETHER:
- case IFT_FDDI:
- case IFT_L2VLAN:
- case IFT_IEEE80211:
- case IFT_BRIDGE:
- case IFT_ISO88025:
- ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr,
- desten);
- return (0);
- default:
- m_freem(m);
- return (EAFNOSUPPORT);
- }
- }
-
-
- /*
- * the entry should have been created in nd6_store_lladdr
- */
- IF_AFDATA_RLOCK(ifp);
- ln = lla_lookup(LLTABLE6(ifp), 0, dst);
- IF_AFDATA_RUNLOCK(ifp);
- if ((ln == NULL) || !(ln->la_flags & LLE_VALID)) {
- if (ln != NULL)
- LLE_RUNLOCK(ln);
- /* this could happen, if we could not allocate memory */
- m_freem(m);
- return (1);
- }
-
- bcopy(&ln->ll_addr, desten, ifp->if_addrlen);
- if (pflags != NULL)
- *pflags = ln->la_flags;
- LLE_RUNLOCK(ln);
- /*
- * A *small* use after free race exists here
- */
- return (0);
+ if (all != 0)
+ lltable_prefix_free(AF_INET6, saddr, smask, LLE_STATIC);
+ else
+ lltable_delete_addr(LLTABLE6(ifp), LLE_IFADDR, saddr);
}
static void
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
index f4f7f65..41df9e4 100644
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -402,34 +402,31 @@ void nd6_destroy(void);
#endif
struct nd_ifinfo *nd6_ifattach(struct ifnet *);
void nd6_ifdetach(struct nd_ifinfo *);
-int nd6_is_addr_neighbor(struct sockaddr_in6 *, struct ifnet *);
+int nd6_is_addr_neighbor(const struct sockaddr_in6 *, struct ifnet *);
void nd6_option_init(void *, int, union nd_opts *);
struct nd_opt_hdr *nd6_option(union nd_opts *);
int nd6_options(union nd_opts *);
-struct llentry *nd6_lookup(struct in6_addr *, int, struct ifnet *);
-struct llentry *nd6_alloc(struct in6_addr *, int, struct ifnet *);
+struct llentry *nd6_lookup(const struct in6_addr *, int, struct ifnet *);
+struct llentry *nd6_alloc(const struct in6_addr *, int, struct ifnet *);
void nd6_setmtu(struct ifnet *);
void nd6_llinfo_settimer(struct llentry *, long);
void nd6_llinfo_settimer_locked(struct llentry *, long);
void nd6_timer(void *);
void nd6_purge(struct ifnet *);
void nd6_nud_hint(struct rtentry *, struct in6_addr *, int);
-int nd6_resolve(struct ifnet *, struct rtentry *, struct mbuf *,
- struct sockaddr *, u_char *);
+int nd6_resolve(struct ifnet *, int, struct mbuf *,
+ const struct sockaddr *, u_char *, uint32_t *);
int nd6_ioctl(u_long, caddr_t, struct ifnet *);
-struct llentry *nd6_cache_lladdr(struct ifnet *, struct in6_addr *,
+void nd6_cache_lladdr(struct ifnet *, struct in6_addr *,
char *, int, int, int);
-int nd6_output(struct ifnet *, struct ifnet *, struct mbuf *,
- struct sockaddr_in6 *, struct rtentry *);
void nd6_grab_holdchain(struct llentry *, struct mbuf **,
struct sockaddr_in6 *);
int nd6_flush_holdchain(struct ifnet *, struct ifnet *, struct mbuf *,
struct sockaddr_in6 *);
-int nd6_need_cache(struct ifnet *);
int nd6_add_ifa_lle(struct in6_ifaddr *);
-void nd6_rem_ifa_lle(struct in6_ifaddr *);
-int nd6_storelladdr(struct ifnet *, struct mbuf *,
- const struct sockaddr *, u_char *, uint32_t *);
+void nd6_rem_ifa_lle(struct in6_ifaddr *, int);
+int nd6_output_ifp(struct ifnet *, struct ifnet *, struct mbuf *,
+ struct sockaddr_in6 *);
/* nd6_nbr.c */
void nd6_na_input(struct mbuf *, int, int);
diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c
index aa0ff47..cbcca46 100644
--- a/sys/netinet6/nd6_rtr.c
+++ b/sys/netinet6/nd6_rtr.c
@@ -2105,7 +2105,7 @@ rt6_deleteroute(struct rtentry *rt, void *arg)
return (0);
return (in6_rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
- rt_mask(rt), rt->rt_flags, NULL, rt->rt_fibnum));
+ rt_mask(rt), rt->rt_flags | RTF_RNH_LOCKED, NULL, rt->rt_fibnum));
#undef SIN6
}
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 2afd77f..1f6d5a2 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -5534,7 +5534,7 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
if (IN6_IS_SCOPE_EMBED(&dst.sin6_addr))
dst.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu)
- nd6_output(ifp, ifp, m0, &dst, NULL);
+ nd6_output_ifp(ifp, ifp, m0, &dst);
else {
in6_ifstat_inc(ifp, ifs6_in_toobig);
if (r->rt != PF_DUPTO)
diff --git a/sys/ofed/drivers/infiniband/core/addr.c b/sys/ofed/drivers/infiniband/core/addr.c
index e85b554..2a918cb 100644
--- a/sys/ofed/drivers/infiniband/core/addr.c
+++ b/sys/ofed/drivers/infiniband/core/addr.c
@@ -332,7 +332,7 @@ mcast:
#endif
#ifdef INET6
case AF_INET6:
- error = nd6_storelladdr(ifp, NULL, dst_in, (u_char *)edst, NULL);
+ error = nd6_resolve(ifp, is_gw, NULL, dst_in, edst, NULL);
break;
#endif
default:
diff --git a/sys/ofed/drivers/infiniband/core/mad.c b/sys/ofed/drivers/infiniband/core/mad.c
index 3eedca1..a78dd3a 100644
--- a/sys/ofed/drivers/infiniband/core/mad.c
+++ b/sys/ofed/drivers/infiniband/core/mad.c
@@ -1053,7 +1053,7 @@ static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv)
*/
cancel_mads(mad_agent_priv);
port_priv = mad_agent_priv->qp_info->port_priv;
- cancel_delayed_work(&mad_agent_priv->timed_work);
+ cancel_delayed_work_sync(&mad_agent_priv->timed_work);
spin_lock_irqsave(&port_priv->reg_lock, flags);
remove_mad_reg_req(mad_agent_priv);
diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 35e16417..53ac66d 100644
--- a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -1333,7 +1333,7 @@ ipoib_output(struct ifnet *ifp, struct mbuf *m,
else if (m->m_flags & M_MCAST)
ipv6_ib_mc_map(&((struct sockaddr_in6 *)dst)->sin6_addr, ifp->if_broadcastaddr, edst);
else
- error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, NULL);
+ error = nd6_resolve(ifp, is_gw, m, dst, edst, NULL);
if (error)
return error;
type = htons(ETHERTYPE_IPV6);
diff --git a/sys/sparc64/ebus/ebus.c b/sys/sparc64/ebus/ebus.c
index 93ad342..0967c5d 100644
--- a/sys/sparc64/ebus/ebus.c
+++ b/sys/sparc64/ebus/ebus.c
@@ -69,7 +69,6 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
-
#include <sys/rman.h>
#include <dev/ofw/ofw_bus.h>
@@ -294,7 +293,7 @@ ebus_nexus_attach(device_t dev)
sc->sc_nrange = OF_getprop_alloc(node, "ranges",
sizeof(struct ebus_nexus_ranges), &sc->sc_range);
if (sc->sc_nrange == -1) {
- printf("%s: could not get ranges property\n", __func__);
+ device_printf(dev, "could not get ranges property\n");
return (ENXIO);
}
return (ebus_attach(dev, sc, node));
@@ -306,6 +305,7 @@ ebus_pci_attach(device_t dev)
struct ebus_softc *sc;
struct ebus_rinfo *eri;
struct resource *res;
+ struct isa_ranges *range;
phandle_t node;
int i, rnum, rid;
@@ -322,7 +322,7 @@ ebus_pci_attach(device_t dev)
sc->sc_nrange = OF_getprop_alloc(node, "ranges",
sizeof(struct isa_ranges), &sc->sc_range);
if (sc->sc_nrange == -1) {
- printf("%s: could not get ranges property\n", __func__);
+ device_printf(dev, "could not get ranges property\n");
return (ENXIO);
}
@@ -332,21 +332,34 @@ ebus_pci_attach(device_t dev)
/* For every range, there must be a matching resource. */
for (rnum = 0; rnum < sc->sc_nrange; rnum++) {
eri = &sc->sc_rinfo[rnum];
- eri->eri_rtype = ofw_isa_range_restype(
- &((struct isa_ranges *)sc->sc_range)[rnum]);
+ range = &((struct isa_ranges *)sc->sc_range)[rnum];
+ eri->eri_rtype = ofw_isa_range_restype(range);
rid = PCIR_BAR(rnum);
res = bus_alloc_resource_any(dev, eri->eri_rtype, &rid,
RF_ACTIVE);
if (res == NULL) {
- printf("%s: failed to allocate range resource!\n",
- __func__);
+ device_printf(dev,
+ "could not allocate range resource %d\n", rnum);
+ goto fail;
+ }
+ if (rman_get_start(res) != ISA_RANGE_PHYS(range)) {
+ device_printf(dev,
+ "mismatch in start of range %d (0x%lx/0x%lx)\n",
+ rnum, rman_get_start(res), ISA_RANGE_PHYS(range));
+ goto fail;
+ }
+ if (rman_get_size(res) != range->size) {
+ device_printf(dev,
+ "mismatch in size of range %d (0x%lx/0x%x)\n",
+ rnum, rman_get_size(res), range->size);
goto fail;
}
eri->eri_res = res;
eri->eri_rman.rm_type = RMAN_ARRAY;
eri->eri_rman.rm_descr = "EBus range";
if (rman_init_from_resource(&eri->eri_rman, res) != 0) {
- printf("%s: failed to initialize rman!", __func__);
+ device_printf(dev,
+ "could not initialize rman for range %d", rnum);
goto fail;
}
}
@@ -452,7 +465,7 @@ ebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
* Map EBus ranges to PCI ranges. This may include
* changing the allocation type.
*/
- (void)ofw_isa_range_map(sc->sc_range, sc->sc_nrange,
+ type = ofw_isa_range_map(sc->sc_range, sc->sc_nrange,
&start, &end, &ridx);
eri = &sc->sc_rinfo[ridx];
res = rman_reserve_resource(&eri->eri_rman, start,
@@ -507,7 +520,7 @@ ebus_activate_resource(device_t bus, device_t child, int type, int rid,
int i, rv;
sc = device_get_softc(bus);
- if ((sc->sc_flags & EBUS_PCI) != 0 && type == SYS_RES_MEMORY) {
+ if ((sc->sc_flags & EBUS_PCI) != 0 && type != SYS_RES_IRQ) {
for (i = 0; i < sc->sc_nrange; i++) {
eri = &sc->sc_rinfo[i];
if (rman_is_region_manager(res, &eri->eri_rman) != 0) {
@@ -550,7 +563,7 @@ ebus_release_resource(device_t bus, device_t child, int type, int rid,
passthrough = (device_get_parent(child) != bus);
rl = BUS_GET_RESOURCE_LIST(bus, child);
sc = device_get_softc(bus);
- if ((sc->sc_flags & EBUS_PCI) != 0 && type == SYS_RES_MEMORY) {
+ if ((sc->sc_flags & EBUS_PCI) != 0 && type != SYS_RES_IRQ) {
if ((rman_get_flags(res) & RF_ACTIVE) != 0 ){
rv = bus_deactivate_resource(child, type, rid, res);
if (rv != 0)
diff --git a/sys/sparc64/include/smp.h b/sys/sparc64/include/smp.h
index c46c4f8..266187e 100644
--- a/sys/sparc64/include/smp.h
+++ b/sys/sparc64/include/smp.h
@@ -47,6 +47,7 @@
#include <sys/sched.h>
#include <sys/smp.h>
+#include <machine/atomic.h>
#include <machine/intr_machdep.h>
#include <machine/tte.h>
@@ -143,7 +144,7 @@ ipi_all_but_self(u_int ipi)
{
cpuset_t cpus;
- if (__predict_false(smp_started == 0))
+ if (__predict_false(atomic_load_acq_int(&smp_started) == 0))
return;
cpus = all_cpus;
sched_pin();
@@ -158,7 +159,8 @@ static __inline void
ipi_selected(cpuset_t cpus, u_int ipi)
{
- if (__predict_false(smp_started == 0 || CPU_EMPTY(&cpus)))
+ if (__predict_false(atomic_load_acq_int(&smp_started) == 0 ||
+ CPU_EMPTY(&cpus)))
return;
mtx_lock_spin(&ipi_mtx);
cpu_ipi_selected(cpus, 0, (u_long)tl_ipi_level, ipi);
@@ -169,7 +171,7 @@ static __inline void
ipi_cpu(int cpu, u_int ipi)
{
- if (__predict_false(smp_started == 0))
+ if (__predict_false(atomic_load_acq_int(&smp_started) == 0))
return;
mtx_lock_spin(&ipi_mtx);
cpu_ipi_single(cpu, 0, (u_long)tl_ipi_level, ipi);
@@ -183,7 +185,7 @@ ipi_dcache_page_inval(void *func, vm_paddr_t pa)
{
struct ipi_cache_args *ica;
- if (__predict_false(smp_started == 0))
+ if (__predict_false(atomic_load_acq_int(&smp_started) == 0))
return (NULL);
sched_pin();
ica = &ipi_cache_args;
@@ -200,7 +202,7 @@ ipi_icache_page_inval(void *func, vm_paddr_t pa)
{
struct ipi_cache_args *ica;
- if (__predict_false(smp_started == 0))
+ if (__predict_false(atomic_load_acq_int(&smp_started) == 0))
return (NULL);
sched_pin();
ica = &ipi_cache_args;
@@ -217,7 +219,7 @@ ipi_rd(u_int cpu, void *func, u_long *val)
{
struct ipi_rd_args *ira;
- if (__predict_false(smp_started == 0))
+ if (__predict_false(atomic_load_acq_int(&smp_started) == 0))
return (NULL);
sched_pin();
ira = &ipi_rd_args;
@@ -234,7 +236,7 @@ ipi_tlb_context_demap(struct pmap *pm)
struct ipi_tlb_args *ita;
cpuset_t cpus;
- if (__predict_false(smp_started == 0))
+ if (__predict_false(atomic_load_acq_int(&smp_started) == 0))
return (NULL);
sched_pin();
cpus = pm->pm_active;
@@ -259,7 +261,7 @@ ipi_tlb_page_demap(struct pmap *pm, vm_offset_t va)
struct ipi_tlb_args *ita;
cpuset_t cpus;
- if (__predict_false(smp_started == 0))
+ if (__predict_false(atomic_load_acq_int(&smp_started) == 0))
return (NULL);
sched_pin();
cpus = pm->pm_active;
@@ -284,7 +286,7 @@ ipi_tlb_range_demap(struct pmap *pm, vm_offset_t start, vm_offset_t end)
struct ipi_tlb_args *ita;
cpuset_t cpus;
- if (__predict_false(smp_started == 0))
+ if (__predict_false(atomic_load_acq_int(&smp_started) == 0))
return (NULL);
sched_pin();
cpus = pm->pm_active;
diff --git a/sys/sparc64/pci/fire.c b/sys/sparc64/pci/fire.c
index 2755260..be0c64b 100644
--- a/sys/sparc64/pci/fire.c
+++ b/sys/sparc64/pci/fire.c
@@ -59,7 +59,6 @@ __FBSDID("$FreeBSD$");
#include <sys/timetc.h>
#include <dev/ofw/ofw_bus.h>
-#include <dev/ofw/ofw_pci.h>
#include <dev/ofw/openfirm.h>
#include <vm/vm.h>
@@ -68,7 +67,6 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/bus_common.h>
#include <machine/bus_private.h>
-#include <machine/fsr.h>
#include <machine/iommureg.h>
#include <machine/iommuvar.h>
#include <machine/pmap.h>
@@ -111,19 +109,14 @@ static driver_filter_t fire_xcb;
/*
* Methods
*/
-static bus_activate_resource_t fire_activate_resource;
-static bus_adjust_resource_t fire_adjust_resource;
static pcib_alloc_msi_t fire_alloc_msi;
static pcib_alloc_msix_t fire_alloc_msix;
static bus_alloc_resource_t fire_alloc_resource;
static device_attach_t fire_attach;
-static bus_get_dma_tag_t fire_get_dma_tag;
-static ofw_bus_get_node_t fire_get_node;
static pcib_map_msi_t fire_map_msi;
static pcib_maxslots_t fire_maxslots;
static device_probe_t fire_probe;
static pcib_read_config_t fire_read_config;
-static bus_read_ivar_t fire_read_ivar;
static pcib_release_msi_t fire_release_msi;
static pcib_release_msix_t fire_release_msix;
static pcib_route_interrupt_t fire_route_interrupt;
@@ -140,15 +133,15 @@ static device_method_t fire_methods[] = {
DEVMETHOD(device_resume, bus_generic_resume),
/* Bus interface */
- DEVMETHOD(bus_read_ivar, fire_read_ivar),
+ DEVMETHOD(bus_read_ivar, ofw_pci_read_ivar),
DEVMETHOD(bus_setup_intr, fire_setup_intr),
DEVMETHOD(bus_teardown_intr, fire_teardown_intr),
DEVMETHOD(bus_alloc_resource, fire_alloc_resource),
- DEVMETHOD(bus_activate_resource, fire_activate_resource),
+ DEVMETHOD(bus_activate_resource, ofw_pci_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
- DEVMETHOD(bus_adjust_resource, fire_adjust_resource),
+ DEVMETHOD(bus_adjust_resource, ofw_pci_adjust_resource),
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
- DEVMETHOD(bus_get_dma_tag, fire_get_dma_tag),
+ DEVMETHOD(bus_get_dma_tag, ofw_pci_get_dma_tag),
/* pcib interface */
DEVMETHOD(pcib_maxslots, fire_maxslots),
@@ -162,7 +155,7 @@ static device_method_t fire_methods[] = {
DEVMETHOD(pcib_map_msi, fire_map_msi),
/* ofw_bus interface */
- DEVMETHOD(ofw_bus_get_node, fire_get_node),
+ DEVMETHOD(ofw_bus_get_node, ofw_pci_get_node),
DEVMETHOD_END
};
@@ -296,7 +289,7 @@ fire_attach(device_t dev)
struct ofw_pci_msi_eq_to_devino msi_eq_to_devino;
struct fire_msiqarg *fmqa;
struct timecounter *tc;
- struct ofw_pci_ranges *range;
+ bus_dma_tag_t dmat;
uint64_t ino_bitmap, val;
phandle_t node;
uint32_t prop, prop_array[2];
@@ -310,7 +303,6 @@ fire_attach(device_t dev)
mode = desc->fd_mode;
sc->sc_dev = dev;
- sc->sc_node = node;
sc->sc_mode = mode;
sc->sc_flags = 0;
@@ -715,79 +707,21 @@ fire_attach(device_t dev)
sc->sc_is.is_bushandle = rman_get_bushandle(sc->sc_mem_res[FIRE_PCI]);
sc->sc_is.is_iommu = FO_PCI_MMU;
val = FIRE_PCI_READ_8(sc, FO_PCI_MMU + IMR_CTL);
- iommu_init(device_get_nameunit(sc->sc_dev), &sc->sc_is, 7, -1, 0);
+ iommu_init(device_get_nameunit(dev), &sc->sc_is, 7, -1, 0);
#ifdef FIRE_DEBUG
device_printf(dev, "FO_PCI_MMU + IMR_CTL 0x%016llx -> 0x%016llx\n",
(long long unsigned)val, (long long unsigned)sc->sc_is.is_cr);
#endif
-
- /* Initialize memory and I/O rmans. */
- sc->sc_pci_io_rman.rm_type = RMAN_ARRAY;
- sc->sc_pci_io_rman.rm_descr = "Fire PCI I/O Ports";
- if (rman_init(&sc->sc_pci_io_rman) != 0 ||
- rman_manage_region(&sc->sc_pci_io_rman, 0, FO_IO_SIZE) != 0)
- panic("%s: failed to set up I/O rman", __func__);
- sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY;
- sc->sc_pci_mem_rman.rm_descr = "Fire PCI Memory";
- if (rman_init(&sc->sc_pci_mem_rman) != 0 ||
- rman_manage_region(&sc->sc_pci_mem_rman, 0, FO_MEM_SIZE) != 0)
- panic("%s: failed to set up memory rman", __func__);
-
- i = OF_getprop_alloc(node, "ranges", sizeof(*range), (void **)&range);
- /*
- * Make sure that the expected ranges are present. The
- * OFW_PCI_CS_MEM64 one is not currently used though.
- */
- if (i != FIRE_NRANGE)
- panic("%s: unsupported number of ranges", __func__);
- /*
- * Find the addresses of the various bus spaces.
- * There should not be multiple ones of one kind.
- * The physical start addresses of the ranges are the configuration,
- * memory and I/O handles.
- */
- for (i = 0; i < FIRE_NRANGE; i++) {
- j = OFW_PCI_RANGE_CS(&range[i]);
- if (sc->sc_pci_bh[j] != 0)
- panic("%s: duplicate range for space %d",
- __func__, j);
- sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]);
- }
- free(range, M_OFWPROP);
-
- /* Allocate our tags. */
- sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, PCI_IO_BUS_SPACE);
- if (sc->sc_pci_iot == NULL)
- panic("%s: could not allocate PCI I/O tag", __func__);
- sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, PCI_CONFIG_BUS_SPACE);
- if (sc->sc_pci_cfgt == NULL)
- panic("%s: could not allocate PCI configuration space tag",
- __func__);
+ /* Create our DMA tag. */
if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0x100000000,
sc->sc_is.is_pmaxaddr, ~0, NULL, NULL, sc->sc_is.is_pmaxaddr,
- 0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_pci_dmat) != 0)
+ 0xff, 0xffffffff, 0, NULL, NULL, &dmat) != 0)
panic("%s: could not create PCI DMA tag", __func__);
- /* Customize the tag. */
- sc->sc_pci_dmat->dt_cookie = &sc->sc_is;
- sc->sc_pci_dmat->dt_mt = &sc->sc_dma_methods;
-
- /*
- * Get the bus range from the firmware.
- * NB: Neither Fire nor Oberon support PCI bus reenumeration.
- */
- i = OF_getprop(node, "bus-range", (void *)prop_array,
- sizeof(prop_array));
- if (i == -1)
- panic("%s: could not get bus-range", __func__);
- if (i != sizeof(prop_array))
- panic("%s: broken bus-range (%d)", __func__, i);
- sc->sc_pci_secbus = prop_array[0];
- sc->sc_pci_subbus = prop_array[1];
- if (bootverbose != 0)
- device_printf(dev, "bus range %u to %u; PCI bus %d\n",
- sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus);
+ dmat->dt_cookie = &sc->sc_is;
+ dmat->dt_mt = &sc->sc_dma_methods;
- ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t));
+ if (ofw_pci_attach_common(dev, dmat, FO_IO_SIZE, FO_MEM_SIZE) != 0)
+ panic("%s: ofw_pci_attach_common() failed", __func__);
#define FIRE_SYSCTL_ADD_UINT(name, arg, desc) \
SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), \
@@ -1390,136 +1324,44 @@ static uint32_t
fire_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
int width)
{
- struct fire_softc *sc;
- bus_space_handle_t bh;
- u_long offset = 0;
- uint32_t r, wrd;
- int i;
- uint16_t shrt;
- uint8_t byte;
-
- sc = device_get_softc(dev);
- if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus ||
- slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX)
- return (-1);
-
- offset = FO_CONF_OFF(bus, slot, func, reg);
- bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG];
- switch (width) {
- case 1:
- i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte);
- r = byte;
- break;
- case 2:
- i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt);
- r = shrt;
- break;
- case 4:
- i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd);
- r = wrd;
- break;
- default:
- panic("%s: bad width", __func__);
- /* NOTREACHED */
- }
- if (i) {
-#ifdef FIRE_DEBUG
- printf("%s: read data error reading: %d.%d.%d: 0x%x\n",
- __func__, bus, slot, func, reg);
-#endif
- r = -1;
- }
- return (r);
+ return (ofw_pci_read_config_common(dev, PCIE_REGMAX, FO_CONF_OFF(bus,
+ slot, func, reg), bus, slot, func, reg, width));
}
static void
fire_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
uint32_t val, int width)
{
- struct fire_softc *sc;
- bus_space_handle_t bh;
- u_long offset = 0;
-
- sc = device_get_softc(dev);
- if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus ||
- slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX)
- return;
- offset = FO_CONF_OFF(bus, slot, func, reg);
- bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG];
- switch (width) {
- case 1:
- bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val);
- break;
- case 2:
- bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val);
- break;
- case 4:
- bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val);
- break;
- default:
- panic("%s: bad width", __func__);
- /* NOTREACHED */
- }
+ ofw_pci_write_config_common(dev, PCIE_REGMAX, FO_CONF_OFF(bus, slot,
+ func, reg), bus, slot, func, reg, val, width);
}
static int
fire_route_interrupt(device_t bridge, device_t dev, int pin)
{
- struct fire_softc *sc;
- struct ofw_pci_register reg;
- ofw_pci_intr_t pintr, mintr;
-
- sc = device_get_softc(bridge);
- pintr = pin;
- if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo,
- &reg, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
- NULL) != 0)
- return (mintr);
-
- device_printf(bridge, "could not route pin %d for device %d.%d\n",
- pin, pci_get_slot(dev), pci_get_function(dev));
- return (PCI_INVALID_IRQ);
-}
-
-static int
-fire_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
-{
- struct fire_softc *sc;
-
- sc = device_get_softc(dev);
- switch (which) {
- case PCIB_IVAR_DOMAIN:
- *result = device_get_unit(dev);
- return (0);
- case PCIB_IVAR_BUS:
- *result = sc->sc_pci_secbus;
- return (0);
- }
- return (ENOENT);
+ ofw_pci_intr_t mintr;
+
+ mintr = ofw_pci_route_interrupt_common(bridge, dev, pin);
+ if (!PCI_INTERRUPT_VALID(mintr))
+ device_printf(bridge,
+ "could not route pin %d for device %d.%d\n",
+ pin, pci_get_slot(dev), pci_get_function(dev));
+ return (mintr);
}
static void
fire_dmamap_sync(bus_dma_tag_t dt __unused, bus_dmamap_t map,
bus_dmasync_op_t op)
{
- static u_char buf[VIS_BLOCKSIZE] __aligned(VIS_BLOCKSIZE);
- register_t reg, s;
if ((map->dm_flags & DMF_LOADED) == 0)
return;
- if ((op & BUS_DMASYNC_POSTREAD) != 0) {
- s = intr_disable();
- reg = rd(fprs);
- wr(fprs, reg | FPRS_FEF, 0);
- __asm __volatile("stda %%f0, [%0] %1"
- : : "r" (buf), "n" (ASI_BLK_COMMIT_S));
- membar(Sync);
- wr(fprs, reg, 0);
- intr_restore(s);
- } else if ((op & BUS_DMASYNC_PREWRITE) != 0)
+ if ((op & BUS_DMASYNC_POSTREAD) != 0)
+ ofw_pci_dmamap_sync_stst_order_common();
+ else if ((op & BUS_DMASYNC_PREWRITE) != 0)
membar(Sync);
}
@@ -2013,121 +1855,13 @@ fire_alloc_resource(device_t bus, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
struct fire_softc *sc;
- struct resource *rv;
- struct rman *rm;
-
- sc = device_get_softc(bus);
- switch (type) {
- case SYS_RES_IRQ:
- /*
- * XXX: Don't accept blank ranges for now, only single
- * interrupts. The other case should not happen with
- * the MI PCI code...
- * XXX: This may return a resource that is out of the
- * range that was specified. Is this correct...?
- */
- if (start != end)
- panic("%s: XXX: interrupt range", __func__);
- if (*rid == 0)
- start = end = INTMAP_VEC(sc->sc_ign, end);
- return (bus_generic_alloc_resource(bus, child, type, rid,
- start, end, count, flags));
- case SYS_RES_MEMORY:
- rm = &sc->sc_pci_mem_rman;
- break;
- case SYS_RES_IOPORT:
- rm = &sc->sc_pci_io_rman;
- break;
- default:
- return (NULL);
- }
-
- rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
- child);
- if (rv == NULL)
- return (NULL);
- rman_set_rid(rv, *rid);
-
- if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type,
- *rid, rv) != 0) {
- rman_release_resource(rv);
- return (NULL);
- }
- return (rv);
-}
-
-static int
-fire_activate_resource(device_t bus, device_t child, int type, int rid,
- struct resource *r)
-{
- struct fire_softc *sc;
- struct bus_space_tag *tag;
-
- sc = device_get_softc(bus);
- switch (type) {
- case SYS_RES_IRQ:
- return (bus_generic_activate_resource(bus, child, type, rid,
- r));
- case SYS_RES_MEMORY:
- tag = sparc64_alloc_bus_tag(r, PCI_MEMORY_BUS_SPACE);
- if (tag == NULL)
- return (ENOMEM);
- rman_set_bustag(r, tag);
- rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] +
- rman_get_start(r));
- break;
- case SYS_RES_IOPORT:
- rman_set_bustag(r, sc->sc_pci_iot);
- rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] +
- rman_get_start(r));
- break;
- }
- return (rman_activate_resource(r));
-}
-static int
-fire_adjust_resource(device_t bus, device_t child, int type,
- struct resource *r, u_long start, u_long end)
-{
- struct fire_softc *sc;
- struct rman *rm;
-
- sc = device_get_softc(bus);
- switch (type) {
- case SYS_RES_IRQ:
- return (bus_generic_adjust_resource(bus, child, type, r,
- start, end));
- case SYS_RES_MEMORY:
- rm = &sc->sc_pci_mem_rman;
- break;
- case SYS_RES_IOPORT:
- rm = &sc->sc_pci_io_rman;
- break;
- default:
- return (EINVAL);
+ if (type == SYS_RES_IRQ && *rid == 0) {
+ sc = device_get_softc(bus);
+ start = end = INTMAP_VEC(sc->sc_ign, end);
}
- if (rman_is_region_manager(r, rm) == 0)
- return (EINVAL);
- return (rman_adjust_resource(r, start, end));
-}
-
-static bus_dma_tag_t
-fire_get_dma_tag(device_t bus, device_t child __unused)
-{
- struct fire_softc *sc;
-
- sc = device_get_softc(bus);
- return (sc->sc_pci_dmat);
-}
-
-static phandle_t
-fire_get_node(device_t bus, device_t child __unused)
-{
- struct fire_softc *sc;
-
- sc = device_get_softc(bus);
- /* We only have one child, the PCI bus, which needs our own node. */
- return (sc->sc_node);
+ return (ofw_pci_alloc_resource(bus, child, type, rid, start, end,
+ count, flags));
}
static u_int
diff --git a/sys/sparc64/pci/firereg.h b/sys/sparc64/pci/firereg.h
index 247a3f7..715d3b7 100644
--- a/sys/sparc64/pci/firereg.h
+++ b/sys/sparc64/pci/firereg.h
@@ -30,7 +30,6 @@
#define _SPARC64_PCI_FIREREG_H_
#define FIRE_NINTR 3 /* 2 OFW + 1 MSIq */
-#define FIRE_NRANGE 4
#define FIRE_NREG 2
#define FIRE_PCI 0
diff --git a/sys/sparc64/pci/firevar.h b/sys/sparc64/pci/firevar.h
index d414c1a..36fd8ea 100644
--- a/sys/sparc64/pci/firevar.h
+++ b/sys/sparc64/pci/firevar.h
@@ -32,6 +32,12 @@
#define _SPARC64_PCI_FIREVAR_H_
struct fire_softc {
+ /*
+ * This is here so that we can hook up the common bus interface
+ * methods in ofw_pci.c directly.
+ */
+ struct ofw_pci_softc sc_ops;
+
struct iommu_state sc_is;
struct bus_dma_methods sc_dma_methods;
@@ -42,13 +48,6 @@ struct fire_softc {
struct resource *sc_irq_res[FIRE_NINTR];
void *sc_ihand[FIRE_NINTR];
- struct rman sc_pci_mem_rman;
- struct rman sc_pci_io_rman;
- bus_space_handle_t sc_pci_bh[FIRE_NRANGE];
- bus_space_tag_t sc_pci_cfgt;
- bus_space_tag_t sc_pci_iot;
- bus_dma_tag_t sc_pci_dmat;
-
device_t sc_dev;
uint64_t *sc_msiq;
@@ -66,8 +65,6 @@ struct fire_softc {
uint32_t sc_msiq_first;
uint32_t sc_msiq_ino_first;
- phandle_t sc_node;
-
u_int sc_mode;
#define FIRE_MODE_FIRE 0
#define FIRE_MODE_OBERON 1
@@ -87,11 +84,6 @@ struct fire_softc {
uint32_t sc_stats_tlu_oe_rx_err;
uint32_t sc_stats_tlu_oe_tx_err;
uint32_t sc_stats_ubc_dmardue;
-
- uint8_t sc_pci_secbus;
- uint8_t sc_pci_subbus;
-
- struct ofw_bus_iinfo sc_pci_iinfo;
};
#endif /* !_SPARC64_PCI_FIREVAR_H_ */
diff --git a/sys/sparc64/pci/ofw_pci.c b/sys/sparc64/pci/ofw_pci.c
new file mode 100644
index 0000000..a18052f
--- /dev/null
+++ b/sys/sparc64/pci/ofw_pci.c
@@ -0,0 +1,406 @@
+/*-
+ * Copyright (c) 1999, 2000 Matthew R. Green
+ * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>
+ * Copyright (c) 2005 - 2015 by Marius Strobl <marius@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: NetBSD: psycho.c,v 1.35 2001/09/10 16:17:06 eeh Exp
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ofw_pci.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/rman.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_pci.h>
+#include <dev/ofw/openfirm.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <machine/asi.h>
+#include <machine/bus.h>
+#include <machine/bus_private.h>
+#include <machine/cpufunc.h>
+#include <machine/fsr.h>
+#include <machine/resource.h>
+
+#include <sparc64/pci/ofw_pci.h>
+
+int
+ofw_pci_attach_common(device_t dev, bus_dma_tag_t dmat, u_long iosize,
+ u_long memsize)
+{
+ struct ofw_pci_softc *sc;
+ struct ofw_pci_ranges *range;
+ phandle_t node;
+ uint32_t prop_array[2];
+ u_int i, j, nrange;
+
+ sc = device_get_softc(dev);
+ node = ofw_bus_get_node(dev);
+ sc->sc_node = node;
+ sc->sc_pci_dmat = dmat;
+
+ /* Initialize memory and I/O rmans. */
+ sc->sc_pci_io_rman.rm_type = RMAN_ARRAY;
+ sc->sc_pci_io_rman.rm_descr = "PCI I/O Ports";
+ if (rman_init(&sc->sc_pci_io_rman) != 0 ||
+ rman_manage_region(&sc->sc_pci_io_rman, 0, iosize) != 0) {
+ device_printf(dev, "failed to set up I/O rman\n");
+ return (ENXIO);
+ }
+ sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY;
+ sc->sc_pci_mem_rman.rm_descr = "PCI Memory";
+ if (rman_init(&sc->sc_pci_mem_rman) != 0 ||
+ rman_manage_region(&sc->sc_pci_mem_rman, 0, memsize) != 0) {
+ device_printf(dev, "failed to set up memory rman\n");
+ return (ENXIO);
+ }
+
+ /*
+ * Find the addresses of the various bus spaces. The physical
+ * start addresses of the ranges are the configuration, I/O and
+ * memory handles. There should not be multiple ones of one kind.
+ */
+ nrange = OF_getprop_alloc(node, "ranges", sizeof(*range),
+ (void **)&range);
+ for (i = 0; i < nrange; i++) {
+ j = OFW_PCI_RANGE_CS(&range[i]);
+ if (sc->sc_pci_bh[j] != 0) {
+ device_printf(dev, "duplicate range for space %d\n",
+ j);
+ free(range, M_OFWPROP);
+ return (EINVAL);
+ }
+ sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]);
+ }
+ free(range, M_OFWPROP);
+
+ /*
+ * Make sure that the expected ranges are actually present.
+ * The OFW_PCI_CS_MEM64 one is not currently used.
+ */
+ if (sc->sc_pci_bh[OFW_PCI_CS_CONFIG] == 0) {
+ device_printf(dev, "missing CONFIG range\n");
+ return (ENXIO);
+ }
+ if (sc->sc_pci_bh[OFW_PCI_CS_IO] == 0) {
+ device_printf(dev, "missing IO range\n");
+ return (ENXIO);
+ }
+ if (sc->sc_pci_bh[OFW_PCI_CS_MEM32] == 0) {
+ device_printf(dev, "missing MEM32 range\n");
+ return (ENXIO);
+ }
+
+ /* Allocate our tags. */
+ sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, PCI_IO_BUS_SPACE);
+ if (sc->sc_pci_iot == NULL) {
+ device_printf(dev, "could not allocate PCI I/O tag\n");
+ return (ENXIO);
+ }
+ sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, PCI_CONFIG_BUS_SPACE);
+ if (sc->sc_pci_cfgt == NULL) {
+ device_printf(dev,
+ "could not allocate PCI configuration space tag\n");
+ return (ENXIO);
+ }
+
+ /*
+ * Get the bus range from the firmware.
+ */
+ i = OF_getprop(node, "bus-range", (void *)prop_array,
+ sizeof(prop_array));
+ if (i == -1) {
+ device_printf(dev, "could not get bus-range\n");
+ return (ENXIO);
+ }
+ if (i != sizeof(prop_array)) {
+ device_printf(dev, "broken bus-range (%d)", i);
+ return (EINVAL);
+ }
+ sc->sc_pci_secbus = prop_array[0];
+ sc->sc_pci_subbus = prop_array[1];
+ if (bootverbose != 0)
+ device_printf(dev, "bus range %u to %u; PCI bus %d\n",
+ sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus);
+
+ ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t));
+
+ return (0);
+}
+
+uint32_t
+ofw_pci_read_config_common(device_t dev, u_int regmax, u_long offset,
+ u_int bus, u_int slot, u_int func, u_int reg, int width)
+{
+ struct ofw_pci_softc *sc;
+ bus_space_handle_t bh;
+ uint32_t r, wrd;
+ int i;
+ uint16_t shrt;
+ uint8_t byte;
+
+ sc = device_get_softc(dev);
+ if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus ||
+ slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > regmax)
+ return (-1);
+
+ bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG];
+ switch (width) {
+ case 1:
+ i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte);
+ r = byte;
+ break;
+ case 2:
+ i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt);
+ r = shrt;
+ break;
+ case 4:
+ i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd);
+ r = wrd;
+ break;
+ default:
+ panic("%s: bad width %d", __func__, width);
+ /* NOTREACHED */
+ }
+
+ if (i) {
+#ifdef OFW_PCI_DEBUG
+ printf("%s: read data error reading: %d.%d.%d: 0x%x\n",
+ __func__, bus, slot, func, reg);
+#endif
+ r = -1;
+ }
+ return (r);
+}
+
+void
+ofw_pci_write_config_common(device_t dev, u_int regmax, u_long offset,
+ u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width)
+{
+ struct ofw_pci_softc *sc;
+ bus_space_handle_t bh;
+
+ sc = device_get_softc(dev);
+ if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus ||
+ slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > regmax)
+ return;
+
+ bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG];
+ switch (width) {
+ case 1:
+ bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val);
+ break;
+ case 2:
+ bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val);
+ break;
+ case 4:
+ bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val);
+ break;
+ default:
+ panic("%s: bad width %d", __func__, width);
+ /* NOTREACHED */
+ }
+}
+
+ofw_pci_intr_t
+ofw_pci_route_interrupt_common(device_t bridge, device_t dev, int pin)
+{
+ struct ofw_pci_softc *sc;
+ struct ofw_pci_register reg;
+ ofw_pci_intr_t pintr, mintr;
+
+ sc = device_get_softc(bridge);
+ pintr = pin;
+ if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo,
+ &reg, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
+ NULL) != 0)
+ return (mintr);
+ return (PCI_INVALID_IRQ);
+}
+
+void
+ofw_pci_dmamap_sync_stst_order_common(void)
+{
+ static u_char buf[VIS_BLOCKSIZE] __aligned(VIS_BLOCKSIZE);
+ register_t reg, s;
+
+ s = intr_disable();
+ reg = rd(fprs);
+ wr(fprs, reg | FPRS_FEF, 0);
+ __asm __volatile("stda %%f0, [%0] %1"
+ : : "r" (buf), "n" (ASI_BLK_COMMIT_S));
+ membar(Sync);
+ wr(fprs, reg, 0);
+ intr_restore(s);
+}
+
+int
+ofw_pci_read_ivar(device_t dev, device_t child __unused, int which,
+ uintptr_t *result)
+{
+ struct ofw_pci_softc *sc;
+
+ switch (which) {
+ case PCIB_IVAR_DOMAIN:
+ *result = device_get_unit(dev);
+ return (0);
+ case PCIB_IVAR_BUS:
+ sc = device_get_softc(dev);
+ *result = sc->sc_pci_secbus;
+ return (0);
+ }
+ return (ENOENT);
+}
+
+struct resource *
+ofw_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct ofw_pci_softc *sc;
+ struct resource *rv;
+ struct rman *rm;
+
+ sc = device_get_softc(bus);
+ switch (type) {
+ case SYS_RES_IRQ:
+ /*
+ * XXX: Don't accept blank ranges for now, only single
+ * interrupts. The other case should not happen with
+ * the MI PCI code ...
+ * XXX: This may return a resource that is out of the
+ * range that was specified. Is this correct ...?
+ */
+ if (start != end)
+ panic("%s: XXX: interrupt range", __func__);
+ return (bus_generic_alloc_resource(bus, child, type, rid,
+ start, end, count, flags));
+ case SYS_RES_MEMORY:
+ rm = &sc->sc_pci_mem_rman;
+ break;
+ case SYS_RES_IOPORT:
+ rm = &sc->sc_pci_io_rman;
+ break;
+ default:
+ return (NULL);
+ }
+
+ rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
+ child);
+ if (rv == NULL)
+ return (NULL);
+ rman_set_rid(rv, *rid);
+
+ if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type,
+ *rid, rv) != 0) {
+ rman_release_resource(rv);
+ return (NULL);
+ }
+ return (rv);
+}
+
+int
+ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+ struct ofw_pci_softc *sc;
+ struct bus_space_tag *tag;
+
+ sc = device_get_softc(bus);
+ switch (type) {
+ case SYS_RES_IRQ:
+ return (bus_generic_activate_resource(bus, child, type, rid,
+ r));
+ case SYS_RES_MEMORY:
+ tag = sparc64_alloc_bus_tag(r, PCI_MEMORY_BUS_SPACE);
+ if (tag == NULL)
+ return (ENOMEM);
+ rman_set_bustag(r, tag);
+ rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] +
+ rman_get_start(r));
+ break;
+ case SYS_RES_IOPORT:
+ rman_set_bustag(r, sc->sc_pci_iot);
+ rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] +
+ rman_get_start(r));
+ break;
+ }
+ return (rman_activate_resource(r));
+}
+
+int
+ofw_pci_adjust_resource(device_t bus, device_t child, int type,
+ struct resource *r, u_long start, u_long end)
+{
+ struct ofw_pci_softc *sc;
+ struct rman *rm;
+
+ sc = device_get_softc(bus);
+ switch (type) {
+ case SYS_RES_IRQ:
+ return (bus_generic_adjust_resource(bus, child, type, r,
+ start, end));
+ case SYS_RES_MEMORY:
+ rm = &sc->sc_pci_mem_rman;
+ break;
+ case SYS_RES_IOPORT:
+ rm = &sc->sc_pci_io_rman;
+ break;
+ default:
+ return (EINVAL);
+ }
+ if (rman_is_region_manager(r, rm) == 0)
+ return (EINVAL);
+ return (rman_adjust_resource(r, start, end));
+}
+
+bus_dma_tag_t
+ofw_pci_get_dma_tag(device_t bus, device_t child __unused)
+{
+ struct ofw_pci_softc *sc;
+
+ sc = device_get_softc(bus);
+ return (sc->sc_pci_dmat);
+}
+
+phandle_t
+ofw_pci_get_node(device_t bus, device_t child __unused)
+{
+ struct ofw_pci_softc *sc;
+
+ sc = device_get_softc(bus);
+ /* We only have one child, the PCI bus, which needs our own node. */
+ return (sc->sc_node);
+}
diff --git a/sys/sparc64/pci/ofw_pci.h b/sys/sparc64/pci/ofw_pci.h
index 3915fa7..6d1e5d9 100644
--- a/sys/sparc64/pci/ofw_pci.h
+++ b/sys/sparc64/pci/ofw_pci.h
@@ -62,6 +62,8 @@
#ifndef _SPARC64_PCI_OFW_PCI_H_
#define _SPARC64_PCI_OFW_PCI_H_
+#include <sys/rman.h>
+
#include <dev/ofw/ofw_bus_subr.h>
#include "ofw_pci_if.h"
@@ -73,6 +75,7 @@ typedef uint32_t ofw_pci_intr_t;
#define OFW_PCI_CS_IO 0x01
#define OFW_PCI_CS_MEM32 0x02
#define OFW_PCI_CS_MEM64 0x03
+#define OFW_PCI_NUM_CS 4
/* OFW device types */
#define OFW_TYPE_PCI "pci"
@@ -124,4 +127,44 @@ struct ofw_pci_ranges {
/* default values */
#define OFW_PCI_LATENCY 64
+/*
+ * Common and generic parts of host-PCI-bridge support
+ */
+
+struct ofw_pci_softc {
+ struct rman sc_pci_mem_rman;
+ struct rman sc_pci_io_rman;
+
+ bus_space_handle_t sc_pci_bh[OFW_PCI_NUM_CS];
+ bus_space_tag_t sc_pci_cfgt;
+ bus_space_tag_t sc_pci_iot;
+ bus_dma_tag_t sc_pci_dmat;
+
+ struct ofw_bus_iinfo sc_pci_iinfo;
+
+ phandle_t sc_node;
+
+ uint8_t sc_pci_secbus;
+ uint8_t sc_pci_subbus;
+};
+
+int ofw_pci_attach_common(device_t dev, bus_dma_tag_t dmat, u_long iosize,
+ u_long memsize);
+uint32_t ofw_pci_read_config_common(device_t dev, u_int regmax, u_long offset,
+ u_int bus, u_int slot, u_int func, u_int reg, int width);
+void ofw_pci_write_config_common(device_t dev, u_int regmax, u_long offset,
+ u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width);
+ofw_pci_intr_t ofw_pci_route_interrupt_common(device_t bridge, device_t dev,
+ int pin);
+
+void ofw_pci_dmamap_sync_stst_order_common(void);
+
+bus_activate_resource_t ofw_pci_activate_resource;
+bus_adjust_resource_t ofw_pci_adjust_resource;
+bus_alloc_resource_t ofw_pci_alloc_resource;
+bus_get_dma_tag_t ofw_pci_get_dma_tag;
+bus_read_ivar_t ofw_pci_read_ivar;
+
+ofw_bus_get_node_t ofw_pci_get_node;
+
#endif /* ! _SPARC64_PCI_OFW_PCI_H_ */
diff --git a/sys/sparc64/pci/psycho.c b/sys/sparc64/pci/psycho.c
index 57e0f48..38f4656 100644
--- a/sys/sparc64/pci/psycho.c
+++ b/sys/sparc64/pci/psycho.c
@@ -57,7 +57,6 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <dev/ofw/ofw_bus.h>
-#include <dev/ofw/ofw_pci.h>
#include <dev/ofw/openfirm.h>
#include <machine/bus.h>
@@ -110,17 +109,12 @@ static void psycho_iommu_init(struct psycho_softc *, int, uint32_t);
*/
static device_probe_t psycho_probe;
static device_attach_t psycho_attach;
-static bus_read_ivar_t psycho_read_ivar;
static bus_setup_intr_t psycho_setup_intr;
static bus_alloc_resource_t psycho_alloc_resource;
-static bus_activate_resource_t psycho_activate_resource;
-static bus_adjust_resource_t psycho_adjust_resource;
-static bus_get_dma_tag_t psycho_get_dma_tag;
static pcib_maxslots_t psycho_maxslots;
static pcib_read_config_t psycho_read_config;
static pcib_write_config_t psycho_write_config;
static pcib_route_interrupt_t psycho_route_interrupt;
-static ofw_bus_get_node_t psycho_get_node;
static ofw_pci_setup_device_t psycho_setup_device;
static device_method_t psycho_methods[] = {
@@ -132,15 +126,15 @@ static device_method_t psycho_methods[] = {
DEVMETHOD(device_resume, bus_generic_resume),
/* Bus interface */
- DEVMETHOD(bus_read_ivar, psycho_read_ivar),
+ DEVMETHOD(bus_read_ivar, ofw_pci_read_ivar),
DEVMETHOD(bus_setup_intr, psycho_setup_intr),
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
DEVMETHOD(bus_alloc_resource, psycho_alloc_resource),
- DEVMETHOD(bus_activate_resource, psycho_activate_resource),
+ DEVMETHOD(bus_activate_resource, ofw_pci_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
- DEVMETHOD(bus_adjust_resource, psycho_adjust_resource),
+ DEVMETHOD(bus_adjust_resource, ofw_pci_adjust_resource),
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
- DEVMETHOD(bus_get_dma_tag, psycho_get_dma_tag),
+ DEVMETHOD(bus_get_dma_tag, ofw_pci_get_dma_tag),
/* pcib interface */
DEVMETHOD(pcib_maxslots, psycho_maxslots),
@@ -149,7 +143,7 @@ static device_method_t psycho_methods[] = {
DEVMETHOD(pcib_route_interrupt, psycho_route_interrupt),
/* ofw_bus interface */
- DEVMETHOD(ofw_bus_get_node, psycho_get_node),
+ DEVMETHOD(ofw_bus_get_node, ofw_pci_get_node),
/* ofw_pci interface */
DEVMETHOD(ofw_pci_setup_device, psycho_setup_device),
@@ -287,12 +281,12 @@ psycho_attach(device_t dev)
{
struct psycho_icarg *pica;
struct psycho_softc *asc, *sc, *osc;
- struct ofw_pci_ranges *range;
const struct psycho_desc *desc;
bus_addr_t intrclr, intrmap;
+ bus_dma_tag_t dmat;
uint64_t csr, dr;
phandle_t node;
- uint32_t dvmabase, prop, prop_array[2];
+ uint32_t dvmabase, prop;
u_int rerun, ver;
int i, j;
@@ -300,7 +294,6 @@ psycho_attach(device_t dev)
sc = device_get_softc(dev);
desc = psycho_get_desc(dev);
- sc->sc_node = node;
sc->sc_dev = dev;
sc->sc_mode = desc->pd_mode;
@@ -366,6 +359,7 @@ psycho_attach(device_t dev)
panic("%s: mutex not initialized", __func__);
sc->sc_mtx = osc->sc_mtx;
}
+ SLIST_INSERT_HEAD(&psycho_softcs, sc, sc_link);
csr = PSYCHO_READ8(sc, PSR_CS);
ver = PSYCHO_GCSR_VERS(csr);
@@ -434,43 +428,6 @@ psycho_attach(device_t dev)
} else
dvmabase = -1;
- /* Initialize memory and I/O rmans. */
- sc->sc_pci_io_rman.rm_type = RMAN_ARRAY;
- sc->sc_pci_io_rman.rm_descr = "Psycho PCI I/O Ports";
- if (rman_init(&sc->sc_pci_io_rman) != 0 ||
- rman_manage_region(&sc->sc_pci_io_rman, 0, PSYCHO_IO_SIZE) != 0)
- panic("%s: failed to set up I/O rman", __func__);
- sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY;
- sc->sc_pci_mem_rman.rm_descr = "Psycho PCI Memory";
- if (rman_init(&sc->sc_pci_mem_rman) != 0 ||
- rman_manage_region(&sc->sc_pci_mem_rman, 0, PSYCHO_MEM_SIZE) != 0)
- panic("%s: failed to set up memory rman", __func__);
-
- i = OF_getprop_alloc(node, "ranges", sizeof(*range), (void **)&range);
- /*
- * Make sure that the expected ranges are present. The
- * OFW_PCI_CS_MEM64 one is not currently used though.
- */
- if (i != PSYCHO_NRANGE)
- panic("%s: unsupported number of ranges", __func__);
- /*
- * Find the addresses of the various bus spaces.
- * There should not be multiple ones of one kind.
- * The physical start addresses of the ranges are the configuration,
- * memory and I/O handles.
- */
- for (i = 0; i < PSYCHO_NRANGE; i++) {
- j = OFW_PCI_RANGE_CS(&range[i]);
- if (sc->sc_pci_bh[j] != 0)
- panic("%s: duplicate range for space %d",
- __func__, j);
- sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]);
- }
- free(range, M_OFWPROP);
-
- /* Register the softc, this is needed for paired Psychos. */
- SLIST_INSERT_HEAD(&psycho_softcs, sc, sc_link);
-
/*
* If we're a Hummingbird/Sabre or the first of a pair of Psychos
* to arrive here, do the interrupt setup and start up the IOMMU.
@@ -571,37 +528,21 @@ psycho_attach(device_t dev)
iommu_reset(sc->sc_is);
}
- /* Allocate our tags. */
- sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, PCI_IO_BUS_SPACE);
- if (sc->sc_pci_iot == NULL)
- panic("%s: could not allocate PCI I/O tag", __func__);
- sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, PCI_CONFIG_BUS_SPACE);
- if (sc->sc_pci_cfgt == NULL)
- panic("%s: could not allocate PCI configuration space tag",
- __func__);
+ /* Create our DMA tag. */
if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0,
sc->sc_is->is_pmaxaddr, ~0, NULL, NULL, sc->sc_is->is_pmaxaddr,
- 0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_pci_dmat) != 0)
+ 0xff, 0xffffffff, 0, NULL, NULL, &dmat) != 0)
panic("%s: could not create PCI DMA tag", __func__);
- /* Customize the tag. */
- sc->sc_pci_dmat->dt_cookie = sc->sc_is;
- sc->sc_pci_dmat->dt_mt = sc->sc_dma_methods;
-
- i = OF_getprop(node, "bus-range", (void *)prop_array,
- sizeof(prop_array));
- if (i == -1)
- panic("%s: could not get bus-range", __func__);
- if (i != sizeof(prop_array))
- panic("%s: broken bus-range (%d)", __func__, i);
- sc->sc_pci_secbus = prop_array[0];
- sc->sc_pci_subbus = prop_array[1];
- if (bootverbose)
- device_printf(dev, "bus range %u to %u; PCI bus %d\n",
- sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus);
+ dmat->dt_cookie = sc->sc_is;
+ dmat->dt_mt = sc->sc_dma_methods;
+
+ if (ofw_pci_attach_common(dev, dmat, PSYCHO_IO_SIZE,
+ PSYCHO_MEM_SIZE) != 0)
+ panic("%s: ofw_pci_attach_common() failed", __func__);
/* Clear any pending PCI error bits. */
- PCIB_WRITE_CONFIG(dev, sc->sc_pci_secbus, PCS_DEVICE, PCS_FUNC,
- PCIR_STATUS, PCIB_READ_CONFIG(dev, sc->sc_pci_secbus,
+ PCIB_WRITE_CONFIG(dev, sc->sc_ops.sc_pci_secbus, PCS_DEVICE, PCS_FUNC,
+ PCIR_STATUS, PCIB_READ_CONFIG(dev, sc->sc_ops.sc_pci_secbus,
PCS_DEVICE, PCS_FUNC, PCIR_STATUS, 2), 2);
PCICTL_WRITE8(sc, PCR_CS, PCICTL_READ8(sc, PCR_CS));
PCICTL_WRITE8(sc, PCR_AFS, PCICTL_READ8(sc, PCR_AFS));
@@ -664,20 +605,20 @@ psycho_attach(device_t dev)
* Set the latency timer register as this isn't always done by the
* firmware.
*/
- PCIB_WRITE_CONFIG(dev, sc->sc_pci_secbus, PCS_DEVICE, PCS_FUNC,
+ PCIB_WRITE_CONFIG(dev, sc->sc_ops.sc_pci_secbus, PCS_DEVICE, PCS_FUNC,
PCIR_LATTIMER, OFW_PCI_LATENCY, 1);
for (i = PCIR_VENDOR; i < PCIR_STATUS; i += sizeof(uint16_t))
- le16enc(&sc->sc_pci_hpbcfg[i], bus_space_read_2(
- sc->sc_pci_cfgt, sc->sc_pci_bh[OFW_PCI_CS_CONFIG],
- PSYCHO_CONF_OFF(sc->sc_pci_secbus, PCS_DEVICE,
+ le16enc(&sc->sc_pci_hpbcfg[i],
+ bus_space_read_2(sc->sc_ops.sc_pci_cfgt,
+ sc->sc_ops.sc_pci_bh[OFW_PCI_CS_CONFIG],
+ PSYCHO_CONF_OFF(sc->sc_ops.sc_pci_secbus, PCS_DEVICE,
PCS_FUNC, i)));
for (i = PCIR_REVID; i <= PCIR_BIST; i += sizeof(uint8_t))
- sc->sc_pci_hpbcfg[i] = bus_space_read_1(sc->sc_pci_cfgt,
- sc->sc_pci_bh[OFW_PCI_CS_CONFIG], PSYCHO_CONF_OFF(
- sc->sc_pci_secbus, PCS_DEVICE, PCS_FUNC, i));
+ sc->sc_pci_hpbcfg[i] = bus_space_read_1(sc->sc_ops.sc_pci_cfgt,
+ sc->sc_ops.sc_pci_bh[OFW_PCI_CS_CONFIG], PSYCHO_CONF_OFF(
+ sc->sc_ops.sc_pci_secbus, PCS_DEVICE, PCS_FUNC, i));
- ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t));
/*
* On E250 the interrupt map entry for the EBus bridge is wrong,
* causing incorrect interrupts to be assigned to some devices on
@@ -688,9 +629,9 @@ psycho_attach(device_t dev)
* EBus devices will be used directly instead.
*/
if (strcmp(sparc64_model, "SUNW,Ultra-250") == 0 &&
- sc->sc_pci_iinfo.opi_imapmsk != NULL)
- *(ofw_pci_intr_t *)(&sc->sc_pci_iinfo.opi_imapmsk[
- sc->sc_pci_iinfo.opi_addrc]) = INTMAP_INO_MASK;
+ sc->sc_ops.sc_pci_iinfo.opi_imapmsk != NULL)
+ *(ofw_pci_intr_t *)(&sc->sc_ops.sc_pci_iinfo.opi_imapmsk[
+ sc->sc_ops.sc_pci_iinfo.opi_addrc]) = INTMAP_INO_MASK;
device_add_child(dev, "pci", -1);
return (bus_generic_attach(dev));
@@ -924,20 +865,8 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
int width)
{
struct psycho_softc *sc;
- bus_space_handle_t bh;
- u_long offset = 0;
- uint8_t byte;
- uint16_t shrt;
- uint32_t r, wrd;
- int i;
sc = device_get_softc(dev);
- if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus ||
- slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCI_REGMAX)
- return (-1);
-
- bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG];
-
/*
* The Hummingbird and Sabre bridges are picky in that they
* only allow their config space to be accessed using the
@@ -953,9 +882,9 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
* The Psycho bridges contain a dupe of their header at 0x80
* which we nullify that way also.
*/
- if (bus == sc->sc_pci_secbus && slot == PCS_DEVICE &&
+ if (bus == sc->sc_ops.sc_pci_secbus && slot == PCS_DEVICE &&
func == PCS_FUNC) {
- if (offset % width != 0)
+ if (reg % width != 0)
return (-1);
if (reg >= sizeof(sc->sc_pci_hpbcfg))
@@ -964,8 +893,9 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
if ((reg < PCIR_STATUS && reg + width > PCIR_STATUS) ||
reg == PCIR_STATUS || reg == PCIR_STATUS + 1)
le16enc(&sc->sc_pci_hpbcfg[PCIR_STATUS],
- bus_space_read_2(sc->sc_pci_cfgt, bh,
- PSYCHO_CONF_OFF(sc->sc_pci_secbus,
+ bus_space_read_2(sc->sc_ops.sc_pci_cfgt,
+ sc->sc_ops.sc_pci_bh[OFW_PCI_CS_CONFIG],
+ PSYCHO_CONF_OFF(sc->sc_ops.sc_pci_secbus,
PCS_DEVICE, PCS_FUNC, PCIR_STATUS)));
switch (width) {
@@ -978,79 +908,29 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
}
}
- offset = PSYCHO_CONF_OFF(bus, slot, func, reg);
- switch (width) {
- case 1:
- i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte);
- r = byte;
- break;
- case 2:
- i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt);
- r = shrt;
- break;
- case 4:
- i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd);
- r = wrd;
- break;
- default:
- panic("%s: bad width", __func__);
- /* NOTREACHED */
- }
-
- if (i) {
-#ifdef PSYCHO_DEBUG
- printf("%s: read data error reading: %d.%d.%d: 0x%x\n",
- __func__, bus, slot, func, reg);
-#endif
- r = -1;
- }
- return (r);
+ return (ofw_pci_read_config_common(dev, PCI_REGMAX,
+ PSYCHO_CONF_OFF(bus, slot, func, reg), bus, slot, func, reg,
+ width));
}
static void
psycho_write_config(device_t dev, u_int bus, u_int slot, u_int func,
u_int reg, uint32_t val, int width)
{
- struct psycho_softc *sc;
- bus_space_handle_t bh;
- u_long offset = 0;
- sc = device_get_softc(dev);
- if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus ||
- slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCI_REGMAX)
- return;
-
- offset = PSYCHO_CONF_OFF(bus, slot, func, reg);
- bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG];
- switch (width) {
- case 1:
- bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val);
- break;
- case 2:
- bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val);
- break;
- case 4:
- bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val);
- break;
- default:
- panic("%s: bad width", __func__);
- /* NOTREACHED */
- }
+ ofw_pci_write_config_common(dev, PCI_REGMAX, PSYCHO_CONF_OFF(bus,
+ slot, func, reg), bus, slot, func, reg, val, width);
}
static int
psycho_route_interrupt(device_t bridge, device_t dev, int pin)
{
struct psycho_softc *sc;
- struct ofw_pci_register reg;
bus_addr_t intrmap;
- ofw_pci_intr_t pintr, mintr;
+ ofw_pci_intr_t mintr;
- sc = device_get_softc(bridge);
- pintr = pin;
- if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo,
- &reg, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
- NULL))
+ mintr = ofw_pci_route_interrupt_common(bridge, dev, pin);
+ if (PCI_INTERRUPT_VALID(mintr))
return (mintr);
/*
* If this is outside of the range for an intpin, it's likely a full
@@ -1069,6 +949,7 @@ psycho_route_interrupt(device_t bridge, device_t dev, int pin)
* for bus A are one-based, while those for bus B seemingly have an
* offset of 2 (hence the factor of 3 below).
*/
+ sc = device_get_softc(dev);
intrmap = PSR_PCIA0_INT_MAP +
8 * (pci_get_slot(dev) - 1 + 3 * sc->sc_half);
mintr = INTINO(PSYCHO_READ8(sc, intrmap)) + pin - 1;
@@ -1078,23 +959,6 @@ psycho_route_interrupt(device_t bridge, device_t dev, int pin)
return (mintr);
}
-static int
-psycho_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
-{
- struct psycho_softc *sc;
-
- sc = device_get_softc(dev);
- switch (which) {
- case PCIB_IVAR_DOMAIN:
- *result = device_get_unit(dev);
- return (0);
- case PCIB_IVAR_BUS:
- *result = sc->sc_pci_secbus;
- return (0);
- }
- return (ENOENT);
-}
-
static void
sabre_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map, bus_dmasync_op_t op)
{
@@ -1177,120 +1041,13 @@ psycho_alloc_resource(device_t bus, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
struct psycho_softc *sc;
- struct resource *rv;
- struct rman *rm;
- sc = device_get_softc(bus);
- switch (type) {
- case SYS_RES_IRQ:
- /*
- * XXX: Don't accept blank ranges for now, only single
- * interrupts. The other case should not happen with
- * the MI PCI code...
- * XXX: This may return a resource that is out of the
- * range that was specified. Is this correct...?
- */
- if (start != end)
- panic("%s: XXX: interrupt range", __func__);
+ if (type == SYS_RES_IRQ) {
+ sc = device_get_softc(bus);
start = end = INTMAP_VEC(sc->sc_ign, end);
- return (bus_generic_alloc_resource(bus, child, type, rid,
- start, end, count, flags));
- case SYS_RES_MEMORY:
- rm = &sc->sc_pci_mem_rman;
- break;
- case SYS_RES_IOPORT:
- rm = &sc->sc_pci_io_rman;
- break;
- default:
- return (NULL);
- }
-
- rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
- child);
- if (rv == NULL)
- return (NULL);
- rman_set_rid(rv, *rid);
-
- if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type,
- *rid, rv) != 0) {
- rman_release_resource(rv);
- return (NULL);
- }
- return (rv);
-}
-
-static int
-psycho_activate_resource(device_t bus, device_t child, int type, int rid,
- struct resource *r)
-{
- struct psycho_softc *sc;
- struct bus_space_tag *tag;
-
- sc = device_get_softc(bus);
- switch (type) {
- case SYS_RES_IRQ:
- return (bus_generic_activate_resource(bus, child, type, rid,
- r));
- case SYS_RES_MEMORY:
- tag = sparc64_alloc_bus_tag(r, PCI_MEMORY_BUS_SPACE);
- if (tag == NULL)
- return (ENOMEM);
- rman_set_bustag(r, tag);
- rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] +
- rman_get_start(r));
- break;
- case SYS_RES_IOPORT:
- rman_set_bustag(r, sc->sc_pci_iot);
- rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] +
- rman_get_start(r));
- break;
- }
- return (rman_activate_resource(r));
-}
-
-static int
-psycho_adjust_resource(device_t bus, device_t child, int type,
- struct resource *r, u_long start, u_long end)
-{
- struct psycho_softc *sc;
- struct rman *rm;
-
- sc = device_get_softc(bus);
- switch (type) {
- case SYS_RES_IRQ:
- return (bus_generic_adjust_resource(bus, child, type, r,
- start, end));
- case SYS_RES_MEMORY:
- rm = &sc->sc_pci_mem_rman;
- break;
- case SYS_RES_IOPORT:
- rm = &sc->sc_pci_io_rman;
- break;
- default:
- return (EINVAL);
}
- if (rman_is_region_manager(r, rm) == 0)
- return (EINVAL);
- return (rman_adjust_resource(r, start, end));
-}
-
-static bus_dma_tag_t
-psycho_get_dma_tag(device_t bus, device_t child __unused)
-{
- struct psycho_softc *sc;
-
- sc = device_get_softc(bus);
- return (sc->sc_pci_dmat);
-}
-
-static phandle_t
-psycho_get_node(device_t bus, device_t child __unused)
-{
- struct psycho_softc *sc;
-
- sc = device_get_softc(bus);
- /* We only have one child, the PCI bus, which needs our own node. */
- return (sc->sc_node);
+ return (ofw_pci_alloc_resource(bus, child, type, rid, start, end,
+ count, flags));
}
static void
diff --git a/sys/sparc64/pci/psychoreg.h b/sys/sparc64/pci/psychoreg.h
index ede593a..6e4ea39 100644
--- a/sys/sparc64/pci/psychoreg.h
+++ b/sys/sparc64/pci/psychoreg.h
@@ -73,7 +73,6 @@
*/
#define PSYCHO_NINTR 6
-#define PSYCHO_NRANGE 4
/*
* Psycho register offsets
@@ -121,7 +120,7 @@
#define PSR_PWRMGT_INT_MAP 0x1090 /* power mgmt wake interrupt map reg */
#define PSR_FFB0_INT_MAP 0x1098 /* FFB0 graphics interrupt map reg */
#define PSR_FFB1_INT_MAP 0x10a0 /* FFB1 graphics interrupt map reg */
-/* Note: clear interrupt 0 registers are not really used */
+/* Note: Clear interrupt 0 registers are not really used. */
#define PSR_PCIA0_INT_CLR 0x1400 /* PCI a slot 0 clear int regs 0..3 */
#define PSR_PCIA1_INT_CLR 0x1420 /* PCI a slot 1 clear int regs 0..3 */
#define PSR_PCIA2_INT_CLR 0x1440 /* PCI a slot 2 clear int regs 0..3 */
@@ -165,6 +164,7 @@
#define PSR_PCI_INT_DIAG 0xa800 /* PCI int state diag reg */
#define PSR_OBIO_INT_DIAG 0xa808 /* OBIO and misc int state diag reg */
#define PSR_STRBUF_DIAG 0xb000 /* Streaming buffer diag regs */
+
/*
* Here is the rest of the map, which we're not specifying:
*
@@ -176,7 +176,7 @@
* 1ff.0000.0000 - 1ff.7fff.ffff PCI A memory space
* 1ff.8000.0000 - 1ff.ffff.ffff PCI B memory space
*
- * NB: config and I/O space can use 1-4 byte accesses, not 8 byte
+ * NB: Config and I/O space can use 1-4 byte accesses, not 8 byte
* accesses. Memory space can use any sized accesses.
*
* Note that the SUNW,sabre/SUNW,simba combinations found on the
diff --git a/sys/sparc64/pci/psychovar.h b/sys/sparc64/pci/psychovar.h
index 5532d16..0f828ee 100644
--- a/sys/sparc64/pci/psychovar.h
+++ b/sys/sparc64/pci/psychovar.h
@@ -36,49 +36,38 @@
* per pair of psychos.
*/
struct psycho_softc {
- struct bus_dma_methods *sc_dma_methods;
+ /*
+ * This is here so that we can hook up the common bus interface
+ * methods in ofw_pci.c directly.
+ */
+ struct ofw_pci_softc sc_ops;
- device_t sc_dev;
+ struct iommu_state *sc_is;
+ struct bus_dma_methods *sc_dma_methods;
struct mtx *sc_mtx;
- /* Interrupt Group Number for this device */
- uint32_t sc_ign;
-
- bus_addr_t sc_pcictl;
-
- phandle_t sc_node; /* Firmware node */
- u_int sc_mode;
-#define PSYCHO_MODE_SABRE 0
-#define PSYCHO_MODE_PSYCHO 1
-
- /* Bus A or B of a psycho pair? */
- u_int sc_half;
-
- struct iommu_state *sc_is;
-
struct resource *sc_mem_res;
struct resource *sc_irq_res[PSYCHO_NINTR];
void *sc_ihand[PSYCHO_NINTR];
- struct ofw_bus_iinfo sc_pci_iinfo;
+ uint8_t sc_pci_hpbcfg[16];
- /* Tags for PCI access */
- bus_space_tag_t sc_pci_cfgt;
- bus_space_tag_t sc_pci_iot;
- bus_dma_tag_t sc_pci_dmat;
+ SLIST_ENTRY(psycho_softc) sc_link;
- bus_space_handle_t sc_pci_bh[PSYCHO_NRANGE];
+ device_t sc_dev;
- struct rman sc_pci_mem_rman;
- struct rman sc_pci_io_rman;
+ bus_addr_t sc_pcictl;
- uint8_t sc_pci_secbus;
- uint8_t sc_pci_subbus;
+ u_int sc_mode;
+#define PSYCHO_MODE_SABRE 0
+#define PSYCHO_MODE_PSYCHO 1
- uint8_t sc_pci_hpbcfg[16];
+ /* Bus A or B of a psycho pair? */
+ u_int sc_half;
- SLIST_ENTRY(psycho_softc) sc_link;
+ /* Interrupt Group Number for this device */
+ uint32_t sc_ign;
};
#endif /* !_SPARC64_PCI_PSYCHOVAR_H_ */
diff --git a/sys/sparc64/pci/schizo.c b/sys/sparc64/pci/schizo.c
index e7ebaf1..ed1cccd 100644
--- a/sys/sparc64/pci/schizo.c
+++ b/sys/sparc64/pci/schizo.c
@@ -57,13 +57,11 @@ __FBSDID("$FreeBSD$");
#include <sys/timetc.h>
#include <dev/ofw/ofw_bus.h>
-#include <dev/ofw/ofw_pci.h>
#include <dev/ofw/openfirm.h>
#include <machine/bus.h>
#include <machine/bus_common.h>
#include <machine/bus_private.h>
-#include <machine/fsr.h>
#include <machine/iommureg.h>
#include <machine/iommuvar.h>
#include <machine/resource.h>
@@ -108,17 +106,12 @@ static void schizo_iommu_init(struct schizo_softc *, int, uint32_t);
*/
static device_probe_t schizo_probe;
static device_attach_t schizo_attach;
-static bus_read_ivar_t schizo_read_ivar;
static bus_setup_intr_t schizo_setup_intr;
static bus_alloc_resource_t schizo_alloc_resource;
-static bus_activate_resource_t schizo_activate_resource;
-static bus_adjust_resource_t schizo_adjust_resource;
-static bus_get_dma_tag_t schizo_get_dma_tag;
static pcib_maxslots_t schizo_maxslots;
static pcib_read_config_t schizo_read_config;
static pcib_write_config_t schizo_write_config;
static pcib_route_interrupt_t schizo_route_interrupt;
-static ofw_bus_get_node_t schizo_get_node;
static ofw_pci_setup_device_t schizo_setup_device;
static device_method_t schizo_methods[] = {
@@ -130,15 +123,15 @@ static device_method_t schizo_methods[] = {
DEVMETHOD(device_resume, bus_generic_resume),
/* Bus interface */
- DEVMETHOD(bus_read_ivar, schizo_read_ivar),
+ DEVMETHOD(bus_read_ivar, ofw_pci_read_ivar),
DEVMETHOD(bus_setup_intr, schizo_setup_intr),
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
DEVMETHOD(bus_alloc_resource, schizo_alloc_resource),
- DEVMETHOD(bus_activate_resource, schizo_activate_resource),
+ DEVMETHOD(bus_activate_resource, ofw_pci_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
- DEVMETHOD(bus_adjust_resource, schizo_adjust_resource),
+ DEVMETHOD(bus_adjust_resource, ofw_pci_adjust_resource),
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
- DEVMETHOD(bus_get_dma_tag, schizo_get_dma_tag),
+ DEVMETHOD(bus_get_dma_tag, ofw_pci_get_dma_tag),
/* pcib interface */
DEVMETHOD(pcib_maxslots, schizo_maxslots),
@@ -147,7 +140,7 @@ static device_method_t schizo_methods[] = {
DEVMETHOD(pcib_route_interrupt, schizo_route_interrupt),
/* ofw_bus interface */
- DEVMETHOD(ofw_bus_get_node, schizo_get_node),
+ DEVMETHOD(ofw_bus_get_node, ofw_pci_get_node),
/* ofw_pci interface */
DEVMETHOD(ofw_pci_setup_device, schizo_setup_device),
@@ -270,10 +263,10 @@ schizo_probe(device_t dev)
static int
schizo_attach(device_t dev)
{
- struct ofw_pci_ranges *range;
const struct schizo_desc *desc;
struct schizo_softc *asc, *sc, *osc;
struct timecounter *tc;
+ bus_dma_tag_t dmat;
uint64_t ino_bitmap, reg;
phandle_t node;
uint32_t prop, prop_array[2];
@@ -285,7 +278,6 @@ schizo_attach(device_t dev)
mode = desc->sd_mode;
sc->sc_dev = dev;
- sc->sc_node = node;
sc->sc_mode = mode;
sc->sc_flags = 0;
@@ -347,6 +339,7 @@ schizo_attach(device_t dev)
panic("%s: mutex not initialized", __func__);
sc->sc_mtx = osc->sc_mtx;
}
+ SLIST_INSERT_HEAD(&schizo_softcs, sc, sc_link);
if (OF_getprop(node, "portid", &sc->sc_ign, sizeof(sc->sc_ign)) == -1)
panic("%s: could not determine IGN", __func__);
@@ -542,80 +535,23 @@ schizo_attach(device_t dev)
#undef TSBCASE
- /* Initialize memory and I/O rmans. */
- sc->sc_pci_io_rman.rm_type = RMAN_ARRAY;
- sc->sc_pci_io_rman.rm_descr = "Schizo PCI I/O Ports";
- if (rman_init(&sc->sc_pci_io_rman) != 0 ||
- rman_manage_region(&sc->sc_pci_io_rman, 0, STX_IO_SIZE) != 0)
- panic("%s: failed to set up I/O rman", __func__);
- sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY;
- sc->sc_pci_mem_rman.rm_descr = "Schizo PCI Memory";
- if (rman_init(&sc->sc_pci_mem_rman) != 0 ||
- rman_manage_region(&sc->sc_pci_mem_rman, 0, STX_MEM_SIZE) != 0)
- panic("%s: failed to set up memory rman", __func__);
-
- i = OF_getprop_alloc(node, "ranges", sizeof(*range), (void **)&range);
- /*
- * Make sure that the expected ranges are present. The
- * OFW_PCI_CS_MEM64 one is not currently used though.
- */
- if (i != STX_NRANGE)
- panic("%s: unsupported number of ranges", __func__);
- /*
- * Find the addresses of the various bus spaces.
- * There should not be multiple ones of one kind.
- * The physical start addresses of the ranges are the configuration,
- * memory and I/O handles.
- */
- for (i = 0; i < STX_NRANGE; i++) {
- j = OFW_PCI_RANGE_CS(&range[i]);
- if (sc->sc_pci_bh[j] != 0)
- panic("%s: duplicate range for space %d",
- __func__, j);
- sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]);
- }
- free(range, M_OFWPROP);
-
- /* Register the softc, this is needed for paired Schizos. */
- SLIST_INSERT_HEAD(&schizo_softcs, sc, sc_link);
-
- /* Allocate our tags. */
- sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, PCI_IO_BUS_SPACE);
- if (sc->sc_pci_iot == NULL)
- panic("%s: could not allocate PCI I/O tag", __func__);
- sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, PCI_CONFIG_BUS_SPACE);
- if (sc->sc_pci_cfgt == NULL)
- panic("%s: could not allocate PCI configuration space tag",
- __func__);
+ /* Create our DMA tag. */
if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0,
sc->sc_is.sis_is.is_pmaxaddr, ~0, NULL, NULL,
sc->sc_is.sis_is.is_pmaxaddr, 0xff, 0xffffffff, 0, NULL, NULL,
- &sc->sc_pci_dmat) != 0)
+ &dmat) != 0)
panic("%s: could not create PCI DMA tag", __func__);
- /* Customize the tag. */
- sc->sc_pci_dmat->dt_cookie = &sc->sc_is;
- sc->sc_pci_dmat->dt_mt = &sc->sc_dma_methods;
+ dmat->dt_cookie = &sc->sc_is;
+ dmat->dt_mt = &sc->sc_dma_methods;
- /*
- * Get the bus range from the firmware.
- * NB: Tomatillos don't support PCI bus reenumeration.
- */
- i = OF_getprop(node, "bus-range", (void *)prop_array,
- sizeof(prop_array));
- if (i == -1)
- panic("%s: could not get bus-range", __func__);
- if (i != sizeof(prop_array))
- panic("%s: broken bus-range (%d)", __func__, i);
- sc->sc_pci_secbus = prop_array[0];
- sc->sc_pci_subbus = prop_array[1];
- if (bootverbose)
- device_printf(dev, "bus range %u to %u; PCI bus %d\n",
- sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus);
+ if (ofw_pci_attach_common(dev, dmat, STX_IO_SIZE, STX_MEM_SIZE) != 0)
+ panic("%s: ofw_pci_attach_common() failed", __func__);
/* Clear any pending PCI error bits. */
- PCIB_WRITE_CONFIG(dev, sc->sc_pci_secbus, STX_CS_DEVICE, STX_CS_FUNC,
- PCIR_STATUS, PCIB_READ_CONFIG(dev, sc->sc_pci_secbus,
- STX_CS_DEVICE, STX_CS_FUNC, PCIR_STATUS, 2), 2);
+ PCIB_WRITE_CONFIG(dev, sc->sc_ops.sc_pci_secbus, STX_CS_DEVICE,
+ STX_CS_FUNC, PCIR_STATUS, PCIB_READ_CONFIG(dev,
+ sc->sc_ops.sc_pci_secbus, STX_CS_DEVICE, STX_CS_FUNC, PCIR_STATUS,
+ 2), 2);
SCHIZO_PCI_SET(sc, STX_PCI_CTRL, SCHIZO_PCI_READ_8(sc, STX_PCI_CTRL));
SCHIZO_PCI_SET(sc, STX_PCI_AFSR, SCHIZO_PCI_READ_8(sc, STX_PCI_AFSR));
@@ -743,10 +679,8 @@ schizo_attach(device_t dev)
* Set the latency timer register as this isn't always done by the
* firmware.
*/
- PCIB_WRITE_CONFIG(dev, sc->sc_pci_secbus, STX_CS_DEVICE, STX_CS_FUNC,
- PCIR_LATTIMER, OFW_PCI_LATENCY, 1);
-
- ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t));
+ PCIB_WRITE_CONFIG(dev, sc->sc_ops.sc_pci_secbus, STX_CS_DEVICE,
+ STX_CS_FUNC, PCIR_LATTIMER, OFW_PCI_LATENCY, 1);
#define SCHIZO_SYSCTL_ADD_UINT(name, arg, desc) \
SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), \
@@ -870,7 +804,7 @@ schizo_pci_bus(void *arg)
xstat = SCHIZO_PCI_READ_8(sc, XMS_PCI_X_ERR_STAT);
else
xstat = 0;
- status = PCIB_READ_CONFIG(sc->sc_dev, sc->sc_pci_secbus,
+ status = PCIB_READ_CONFIG(sc->sc_dev, sc->sc_ops.sc_pci_secbus,
STX_CS_DEVICE, STX_CS_FUNC, PCIR_STATUS, 2);
/*
@@ -911,7 +845,7 @@ schizo_pci_bus(void *arg)
(unsigned long long)iommu, (unsigned long long)xstat, status);
/* Clear the error bits that we caught. */
- PCIB_WRITE_CONFIG(sc->sc_dev, sc->sc_pci_secbus, STX_CS_DEVICE,
+ PCIB_WRITE_CONFIG(sc->sc_dev, sc->sc_ops.sc_pci_secbus, STX_CS_DEVICE,
STX_CS_FUNC, PCIR_STATUS, status, 2);
SCHIZO_PCI_WRITE_8(sc, STX_PCI_CTRL, csr);
SCHIZO_PCI_WRITE_8(sc, STX_PCI_AFSR, afsr);
@@ -1032,121 +966,40 @@ schizo_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
int width)
{
struct schizo_softc *sc;
- bus_space_handle_t bh;
- u_long offset = 0;
- uint32_t r, wrd;
- int i;
- uint16_t shrt;
- uint8_t byte;
sc = device_get_softc(dev);
- if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus ||
- slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCI_REGMAX)
- return (-1);
-
/*
* The Schizo bridges contain a dupe of their header at 0x80.
*/
- if (sc->sc_mode == SCHIZO_MODE_SCZ && bus == sc->sc_pci_secbus &&
- slot == STX_CS_DEVICE && func == STX_CS_FUNC &&
- reg + width > 0x80)
+ if (sc->sc_mode == SCHIZO_MODE_SCZ &&
+ bus == sc->sc_ops.sc_pci_secbus && slot == STX_CS_DEVICE &&
+ func == STX_CS_FUNC && reg + width > 0x80)
return (0);
- offset = STX_CONF_OFF(bus, slot, func, reg);
- bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG];
- switch (width) {
- case 1:
- i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte);
- r = byte;
- break;
- case 2:
- i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt);
- r = shrt;
- break;
- case 4:
- i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd);
- r = wrd;
- break;
- default:
- panic("%s: bad width", __func__);
- /* NOTREACHED */
- }
-
- if (i) {
-#ifdef SCHIZO_DEBUG
- printf("%s: read data error reading: %d.%d.%d: 0x%x\n",
- __func__, bus, slot, func, reg);
-#endif
- r = -1;
- }
- return (r);
+ return (ofw_pci_read_config_common(dev, PCI_REGMAX, STX_CONF_OFF(bus,
+ slot, func, reg), bus, slot, func, reg, width));
}
static void
schizo_write_config(device_t dev, u_int bus, u_int slot, u_int func,
u_int reg, uint32_t val, int width)
{
- struct schizo_softc *sc;
- bus_space_handle_t bh;
- u_long offset = 0;
-
- sc = device_get_softc(dev);
- if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus ||
- slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCI_REGMAX)
- return;
- offset = STX_CONF_OFF(bus, slot, func, reg);
- bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG];
- switch (width) {
- case 1:
- bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val);
- break;
- case 2:
- bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val);
- break;
- case 4:
- bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val);
- break;
- default:
- panic("%s: bad width", __func__);
- /* NOTREACHED */
- }
+ ofw_pci_write_config_common(dev, PCI_REGMAX, STX_CONF_OFF(bus, slot,
+ func, reg), bus, slot, func, reg, val, width);
}
static int
schizo_route_interrupt(device_t bridge, device_t dev, int pin)
{
- struct schizo_softc *sc;
- struct ofw_pci_register reg;
- ofw_pci_intr_t pintr, mintr;
-
- sc = device_get_softc(bridge);
- pintr = pin;
- if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo,
- &reg, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
- NULL))
- return (mintr);
-
- device_printf(bridge, "could not route pin %d for device %d.%d\n",
- pin, pci_get_slot(dev), pci_get_function(dev));
- return (PCI_INVALID_IRQ);
-}
-
-static int
-schizo_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
-{
- struct schizo_softc *sc;
-
- sc = device_get_softc(dev);
- switch (which) {
- case PCIB_IVAR_DOMAIN:
- *result = device_get_unit(dev);
- return (0);
- case PCIB_IVAR_BUS:
- *result = sc->sc_pci_secbus;
- return (0);
- }
- return (ENOENT);
+ ofw_pci_intr_t mintr;
+
+ mintr = ofw_pci_route_interrupt_common(bridge, dev, pin);
+ if (!PCI_INTERRUPT_VALID(mintr))
+ device_printf(bridge,
+ "could not route pin %d for device %d.%d\n",
+ pin, pci_get_slot(dev), pci_get_function(dev));
+ return (mintr);
}
static void
@@ -1214,11 +1067,10 @@ schizo_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map, bus_dmasync_op_t op)
static void
ichip_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map, bus_dmasync_op_t op)
{
- static u_char buf[VIS_BLOCKSIZE] __aligned(VIS_BLOCKSIZE);
struct timeval cur, end;
struct schizo_iommu_state *sis = dt->dt_cookie;
struct schizo_softc *sc = sis->sis_sc;
- register_t reg, s;
+ uint64_t reg;
if ((map->dm_flags & DMF_STREAMED) != 0) {
iommu_dma_methods.dm_dmamap_sync(dt, map, op);
@@ -1246,14 +1098,7 @@ ichip_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map, bus_dmasync_op_t op)
if (sc->sc_mode == SCHIZO_MODE_XMS)
mtx_unlock_spin(&sc->sc_sync_mtx);
else if ((sc->sc_flags & SCHIZO_FLAGS_BSWAR) != 0) {
- s = intr_disable();
- reg = rd(fprs);
- wr(fprs, reg | FPRS_FEF, 0);
- __asm __volatile("stda %%f0, [%0] %1"
- : : "r" (buf), "n" (ASI_BLK_COMMIT_S));
- membar(Sync);
- wr(fprs, reg, 0);
- intr_restore(s);
+ ofw_pci_dmamap_sync_stst_order_common();
return;
}
}
@@ -1354,120 +1199,13 @@ schizo_alloc_resource(device_t bus, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
struct schizo_softc *sc;
- struct resource *rv;
- struct rman *rm;
- sc = device_get_softc(bus);
- switch (type) {
- case SYS_RES_IRQ:
- /*
- * XXX: Don't accept blank ranges for now, only single
- * interrupts. The other case should not happen with
- * the MI PCI code...
- * XXX: This may return a resource that is out of the
- * range that was specified. Is this correct...?
- */
- if (start != end)
- panic("%s: XXX: interrupt range", __func__);
+ if (type == SYS_RES_IRQ) {
+ sc = device_get_softc(bus);
start = end = INTMAP_VEC(sc->sc_ign, end);
- return (bus_generic_alloc_resource(bus, child, type, rid,
- start, end, count, flags));
- case SYS_RES_MEMORY:
- rm = &sc->sc_pci_mem_rman;
- break;
- case SYS_RES_IOPORT:
- rm = &sc->sc_pci_io_rman;
- break;
- default:
- return (NULL);
- }
-
- rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
- child);
- if (rv == NULL)
- return (NULL);
- rman_set_rid(rv, *rid);
-
- if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type,
- *rid, rv) != 0) {
- rman_release_resource(rv);
- return (NULL);
- }
- return (rv);
-}
-
-static int
-schizo_activate_resource(device_t bus, device_t child, int type, int rid,
- struct resource *r)
-{
- struct schizo_softc *sc;
- struct bus_space_tag *tag;
-
- sc = device_get_softc(bus);
- switch (type) {
- case SYS_RES_IRQ:
- return (bus_generic_activate_resource(bus, child, type, rid,
- r));
- case SYS_RES_MEMORY:
- tag = sparc64_alloc_bus_tag(r, PCI_MEMORY_BUS_SPACE);
- if (tag == NULL)
- return (ENOMEM);
- rman_set_bustag(r, tag);
- rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] +
- rman_get_start(r));
- break;
- case SYS_RES_IOPORT:
- rman_set_bustag(r, sc->sc_pci_iot);
- rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] +
- rman_get_start(r));
- break;
- }
- return (rman_activate_resource(r));
-}
-
-static int
-schizo_adjust_resource(device_t bus, device_t child, int type,
- struct resource *r, u_long start, u_long end)
-{
- struct schizo_softc *sc;
- struct rman *rm;
-
- sc = device_get_softc(bus);
- switch (type) {
- case SYS_RES_IRQ:
- return (bus_generic_adjust_resource(bus, child, type, r,
- start, end));
- case SYS_RES_MEMORY:
- rm = &sc->sc_pci_mem_rman;
- break;
- case SYS_RES_IOPORT:
- rm = &sc->sc_pci_io_rman;
- break;
- default:
- return (EINVAL);
}
- if (rman_is_region_manager(r, rm) == 0)
- return (EINVAL);
- return (rman_adjust_resource(r, start, end));
-}
-
-static bus_dma_tag_t
-schizo_get_dma_tag(device_t bus, device_t child __unused)
-{
- struct schizo_softc *sc;
-
- sc = device_get_softc(bus);
- return (sc->sc_pci_dmat);
-}
-
-static phandle_t
-schizo_get_node(device_t bus, device_t child __unused)
-{
- struct schizo_softc *sc;
-
- sc = device_get_softc(bus);
- /* We only have one child, the PCI bus, which needs our own node. */
- return (sc->sc_node);
+ return (ofw_pci_alloc_resource(bus, child, type, rid, start, end,
+ count, flags));
}
static void
diff --git a/sys/sparc64/pci/schizoreg.h b/sys/sparc64/pci/schizoreg.h
index cd816b5..59c00b6 100644
--- a/sys/sparc64/pci/schizoreg.h
+++ b/sys/sparc64/pci/schizoreg.h
@@ -32,7 +32,6 @@
#define _SPARC64_PCI_SCHIZOREG_H_
#define STX_NINTR 5 /* 4 via OFW + 1 CDMA */
-#define STX_NRANGE 4
#define SCZ_NREG 3
#define TOM_NREG 4
@@ -279,7 +278,7 @@
/*
* Safari/JBus performance control register
- * NB: for Tomatillo only events 0x00 through 0x08 are documented as
+ * NB: For Tomatillo only events 0x00 through 0x08 are documented as
* implemented.
*/
#define SCZ_CTRL_PERF_ZDATA_OUT 0x0000000000000016ULL
@@ -345,7 +344,7 @@
/* Non-Standard registers in the configration space */
/*
- * NB: for Tomatillo the secondary and subordinate bus number registers
+ * NB: For Tomatillo the secondary and subordinate bus number registers
* apparently are read-only although documented otherwise; writing to
* them just triggers a PCI bus error interrupt or has no effect at best.
*/
diff --git a/sys/sparc64/pci/schizovar.h b/sys/sparc64/pci/schizovar.h
index ab339c8..1b58cf4 100644
--- a/sys/sparc64/pci/schizovar.h
+++ b/sys/sparc64/pci/schizovar.h
@@ -39,16 +39,27 @@ struct schizo_iommu_state {
};
struct schizo_softc {
- struct bus_dma_methods sc_dma_methods;
+ /*
+ * This is here so that we can hook up the common bus interface
+ * methods in ofw_pci.c directly.
+ */
+ struct ofw_pci_softc sc_ops;
- device_t sc_dev;
+ struct schizo_iommu_state sc_is;
+ struct bus_dma_methods sc_dma_methods;
struct mtx sc_sync_mtx;
uint64_t sc_sync_val;
struct mtx *sc_mtx;
- phandle_t sc_node;
+ struct resource *sc_mem_res[TOM_NREG];
+ struct resource *sc_irq_res[STX_NINTR];
+ void *sc_ihand[STX_NINTR];
+
+ SLIST_ENTRY(schizo_softc) sc_link;
+
+ device_t sc_dev;
u_int sc_mode;
#define SCHIZO_MODE_SCZ 0
@@ -72,28 +83,8 @@ struct schizo_softc {
uint32_t sc_ver;
uint32_t sc_mrev;
- struct resource *sc_mem_res[TOM_NREG];
- struct resource *sc_irq_res[STX_NINTR];
- void *sc_ihand[STX_NINTR];
-
- struct schizo_iommu_state sc_is;
-
- struct rman sc_pci_mem_rman;
- struct rman sc_pci_io_rman;
- bus_space_handle_t sc_pci_bh[STX_NRANGE];
- bus_space_tag_t sc_pci_cfgt;
- bus_space_tag_t sc_pci_iot;
- bus_dma_tag_t sc_pci_dmat;
-
uint32_t sc_stats_dma_ce;
uint32_t sc_stats_pci_non_fatal;
-
- uint8_t sc_pci_secbus;
- uint8_t sc_pci_subbus;
-
- struct ofw_bus_iinfo sc_pci_iinfo;
-
- SLIST_ENTRY(schizo_softc) sc_link;
};
#endif /* !_SPARC64_PCI_SCHIZOVAR_H_ */
diff --git a/sys/sys/_callout.h b/sys/sys/_callout.h
index a9134c8..80fef2a 100644
--- a/sys/sys/_callout.h
+++ b/sys/sys/_callout.h
@@ -46,6 +46,8 @@ LIST_HEAD(callout_list, callout);
SLIST_HEAD(callout_slist, callout);
TAILQ_HEAD(callout_tailq, callout);
+typedef void callout_func_t(void *);
+
struct callout {
union {
LIST_ENTRY(callout) le;
diff --git a/sys/sys/callout.h b/sys/sys/callout.h
index 5e21164..f2841e8 100644
--- a/sys/sys/callout.h
+++ b/sys/sys/callout.h
@@ -82,6 +82,7 @@ struct callout_handle {
#define callout_active(c) ((c)->c_flags & CALLOUT_ACTIVE)
#define callout_deactivate(c) ((c)->c_flags &= ~CALLOUT_ACTIVE)
#define callout_drain(c) _callout_stop_safe(c, 1)
+int callout_drain_async(struct callout *, callout_func_t *, void *);
void callout_init(struct callout *, int);
void _callout_init_lock(struct callout *, struct lock_object *, int);
#define callout_init_mtx(c, mtx, flags) \
diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h
index 988dbae..4c66431 100644
--- a/sys/sys/sysctl.h
+++ b/sys/sys/sysctl.h
@@ -807,8 +807,8 @@ int userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
size_t *retval, int flags);
int sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
int *nindx, struct sysctl_req *req);
-void sysctl_xlock(void);
-void sysctl_xunlock(void);
+void sysctl_wlock(void);
+void sysctl_wunlock(void);
int sysctl_wire_old_buffer(struct sysctl_req *req, size_t len);
struct sbuf;
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index 800d340..f37fd05 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -781,6 +781,7 @@ void vop_lookup_post(void *a, int rc);
void vop_lookup_pre(void *a);
void vop_mkdir_post(void *a, int rc);
void vop_mknod_post(void *a, int rc);
+void vop_reclaim_post(void *a, int rc);
void vop_remove_post(void *a, int rc);
void vop_rename_post(void *a, int rc);
void vop_rename_pre(void *a);
diff --git a/sys/x86/acpica/madt.c b/sys/x86/acpica/madt.c
index 9b99651..62554bd 100644
--- a/sys/x86/acpica/madt.c
+++ b/sys/x86/acpica/madt.c
@@ -182,7 +182,19 @@ madt_setup_local(void)
CPUID_TO_FAMILY(cpu_id) == 0x6 &&
CPUID_TO_MODEL(cpu_id) == 0x2a) {
x2apic_mode = 0;
- reason = "for a suspected Lenovo SandyBridge BIOS bug";
+ reason =
+ "for a suspected Lenovo SandyBridge BIOS bug";
+ }
+ /*
+ * Same reason, ASUS SandyBridge.
+ */
+ if (hw_vendor != NULL &&
+ !strcmp(hw_vendor, "ASUSTeK Computer Inc.") &&
+ CPUID_TO_FAMILY(cpu_id) == 0x6 &&
+ CPUID_TO_MODEL(cpu_id) == 0x2a) {
+ x2apic_mode = 0;
+ reason =
+ "for a suspected ASUS SandyBridge BIOS bug";
}
freeenv(hw_vendor);
}
diff --git a/tools/tools/usbtest/Makefile b/tools/tools/usbtest/Makefile
index c674498..f9b16bc 100644
--- a/tools/tools/usbtest/Makefile
+++ b/tools/tools/usbtest/Makefile
@@ -26,6 +26,7 @@
#
PROG= usbtest
MAN=
+BINDIR?= /usr/sbin
SRCS+= usbtest.c
SRCS+= usb_msc_test.c
SRCS+= usb_modem_test.c
diff --git a/usr.bin/rctl/rctl.8 b/usr.bin/rctl/rctl.8
index bebf4fd..9fc1c1c 100644
--- a/usr.bin/rctl/rctl.8
+++ b/usr.bin/rctl/rctl.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 11, 2014
+.Dd September 14, 2015
.Dt RCTL 8
.Os
.Sh NAME
@@ -193,7 +193,7 @@ resource would be
.It Sy openfiles Ta "file descriptor table size"
.It Sy vmemoryuse Ta "address space limit, in bytes"
.It Sy pseudoterminals Ta "number of PTYs"
-.It Sy swapuse Ta "swap usage, in bytes"
+.It Sy swapuse Ta "swap space that may be reserved or used, in bytes"
.It Sy nthr Ta "number of threads"
.It Sy msgqqueued Ta "number of queued SysV messages"
.It Sy msgqsize Ta "SysV message queue size, in bytes"
diff --git a/usr.sbin/bsdconfig/share/common.subr b/usr.sbin/bsdconfig/share/common.subr
index b7f4ee7..5996446 100644
--- a/usr.sbin/bsdconfig/share/common.subr
+++ b/usr.sbin/bsdconfig/share/common.subr
@@ -1,7 +1,7 @@
if [ ! "$_COMMON_SUBR" ]; then _COMMON_SUBR=1
#
# Copyright (c) 2012 Ron McDowell
-# Copyright (c) 2012-2014 Devin Teske
+# Copyright (c) 2012-2015 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,8 @@ if [ ! "$_COMMON_SUBR" ]; then _COMMON_SUBR=1
# Default file descriptors to link to stdout/stderr for passthru allowing
# redirection within a sub-shell to bypass directly to the terminal.
#
-: ${TERMINAL_STDOUT_PASSTHRU:=3}}
-: ${TERMINAL_STDERR_PASSTHRU:=4}}
+: ${TERMINAL_STDOUT_PASSTHRU:=3}
+: ${TERMINAL_STDERR_PASSTHRU:=4}
############################################################ GLOBALS
diff --git a/usr.sbin/bsdinstall/scripts/auto b/usr.sbin/bsdinstall/scripts/auto
index 166823d..5ac16cd 100755
--- a/usr.sbin/bsdinstall/scripts/auto
+++ b/usr.sbin/bsdinstall/scripts/auto
@@ -201,6 +201,19 @@ if f_interactive; then
;;
esac
;;
+ "Hewlett-Packard")
+ case "$sys_model" in
+ "HP ProBook 4330s")
+ dialog_workaround "$msg_gpt_active_fix"
+ retval=$?
+ f_dprintf "gpt_active_fix_prompt=[%s]" "$retval"
+ if [ $retval -eq $DIALOG_OK ]; then
+ export ZFSBOOT_PARTITION_SCHEME="GPT + Active"
+ export WORKAROUND_GPTACTIVE=1
+ fi
+ ;;
+ esac
+ ;;
esac
#
# Motherboard Models
@@ -208,7 +221,20 @@ if f_interactive; then
case "$sys_mb_maker" in
"Intel Corporation")
case "$sys_mb_product" in
- "DP965LT")
+ "DP965LT"|"D510MO")
+ dialog_workaround "$msg_gpt_active_fix"
+ retval=$?
+ f_dprintf "gpt_active_fix_prompt=[%s]" "$retval"
+ if [ $retval -eq $DIALOG_OK ]; then
+ export ZFSBOOT_PARTITION_SCHEME="GPT + Active"
+ export WORKAROUND_GPTACTIVE=1
+ fi
+ ;;
+ esac
+ ;;
+ "Acer")
+ case "$sys_mb_product" in
+ "Veriton M6630G")
dialog_workaround "$msg_gpt_active_fix"
retval=$?
f_dprintf "gpt_active_fix_prompt=[%s]" "$retval"
diff --git a/usr.sbin/bsdinstall/scripts/config b/usr.sbin/bsdinstall/scripts/config
index bc3d723..ebb1dff 100755
--- a/usr.sbin/bsdinstall/scripts/config
+++ b/usr.sbin/bsdinstall/scripts/config
@@ -1,7 +1,7 @@
#!/bin/sh
#-
# Copyright (c) 2011 Nathan Whitehorn
-# Copyright (c) 2013 Devin Teske
+# Copyright (c) 2013-2015 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -45,6 +45,8 @@ cp $BSDINSTALL_TMPBOOT/* $BSDINSTALL_CHROOT/boot
# Set up other things from installed config
chroot $BSDINSTALL_CHROOT /usr/bin/newaliases > /dev/null 2>&1
+exit $SUCCESS
+
################################################################################
# END
################################################################################
diff --git a/usr.sbin/bsdinstall/scripts/docsinstall b/usr.sbin/bsdinstall/scripts/docsinstall
index 4836507..a600054 100755
--- a/usr.sbin/bsdinstall/scripts/docsinstall
+++ b/usr.sbin/bsdinstall/scripts/docsinstall
@@ -1,7 +1,7 @@
#!/bin/sh
#-
# Copyright (c) 2011 Marc Fonvieille
-# Copyright (c) 2013 Devin Teske
+# Copyright (c) 2013-2015 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -159,7 +159,7 @@ for lang in $selected; do
docsets="$docsets $lang-freebsd-doc"
done
-ASSUME_ALWAYS_YES=YES chroot $BSDINSTALL_CHROOT pkg install $docsets || return $FAILURE
+ASSUME_ALWAYS_YES=YES chroot $BSDINSTALL_CHROOT pkg install $docsets
################################################################################
# END
diff --git a/usr.sbin/bsdinstall/scripts/hostname b/usr.sbin/bsdinstall/scripts/hostname
index a53fd80..511db67 100755
--- a/usr.sbin/bsdinstall/scripts/hostname
+++ b/usr.sbin/bsdinstall/scripts/hostname
@@ -1,6 +1,7 @@
#!/bin/sh
#-
# Copyright (c) 2011 Nathan Whitehorn
+# Copyright (c) 2015 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -43,6 +44,9 @@ if [ $? -eq $DIALOG_CANCEL ]; then exit 1; fi
exec 3>&-
echo "hostname=\"$HOSTNAME\"" > $BSDINSTALL_TMPETC/rc.conf.hostname
-if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
+retval=$?
+if [ "$BSDINSTALL_CONFIGCURRENT" ]; then
hostname -s "$HOSTNAME"
+ retval=$?
fi
+exit $retval
diff --git a/usr.sbin/bsdinstall/scripts/jail b/usr.sbin/bsdinstall/scripts/jail
index cb86060..ecfbb78 100755
--- a/usr.sbin/bsdinstall/scripts/jail
+++ b/usr.sbin/bsdinstall/scripts/jail
@@ -1,7 +1,7 @@
#!/bin/sh
#-
# Copyright (c) 2011 Nathan Whitehorn
-# Copyright (c) 2013 Devin Teske
+# Copyright (c) 2013-2015 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -125,6 +125,7 @@ cp /etc/localtime $1/etc
bsdinstall entropy
f_dprintf "Installation Completed at %s" "$(date)"
+exit $SUCCESS
################################################################################
# END
diff --git a/usr.sbin/bsdinstall/scripts/keymap b/usr.sbin/bsdinstall/scripts/keymap
index c36651f..7b42571 100755
--- a/usr.sbin/bsdinstall/scripts/keymap
+++ b/usr.sbin/bsdinstall/scripts/keymap
@@ -1,7 +1,7 @@
#!/bin/sh
#-
# Copyright (c) 2011 Nathan Whitehorn
-# Copyright (c) 2013 Devin Teske
+# Copyright (c) 2013-2015 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -231,6 +231,7 @@ while :; do
done
f_quietly f_keymap_kbdcontrol "$keymap"
+exit $SUCCESS
################################################################################
# END
diff --git a/usr.sbin/bsdinstall/scripts/netconfig_ipv4 b/usr.sbin/bsdinstall/scripts/netconfig_ipv4
index 856c999..88a0fa2 100755
--- a/usr.sbin/bsdinstall/scripts/netconfig_ipv4
+++ b/usr.sbin/bsdinstall/scripts/netconfig_ipv4
@@ -1,7 +1,7 @@
#!/bin/sh
#-
# Copyright (c) 2011 Nathan Whitehorn
-# Copyright (c) 2013 Devin Teske
+# Copyright (c) 2013-2015 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -80,16 +80,20 @@ echo $INTERFACE $IF_CONFIG |
printf("ifconfig_%s=\"%s\inet %s netmask %s\"\n", $1, prefix, $2, $3);
printf("defaultrouter=\"%s\"\n", $4);
}' >> $BSDINSTALL_TMPETC/._rc.conf.net
+retval=$?
-if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
+if [ "$BSDINSTALL_CONFIGCURRENT" ]; then
. $BSDINSTALL_TMPETC/._rc.conf.net
ifconfig $INTERFACE `eval echo \\\$ifconfig_$INTERFACE`
- if [ -n "${defaultrouter}" ]; then
+ if [ "$defaultrouter" ]; then
route delete -inet default
route add -inet default $defaultrouter
+ retval=$?
fi
fi
+exit $retval
+
################################################################################
# END
################################################################################
diff --git a/usr.sbin/bsdinstall/scripts/netconfig_ipv6 b/usr.sbin/bsdinstall/scripts/netconfig_ipv6
index aa1a579..ff4258f 100755
--- a/usr.sbin/bsdinstall/scripts/netconfig_ipv6
+++ b/usr.sbin/bsdinstall/scripts/netconfig_ipv6
@@ -2,7 +2,7 @@
#-
# Copyright (c) 2011 Nathan Whitehorn
# Copyright (c) 2011 The FreeBSD Foundation
-# Copyright (c) 2013 Devin Teske
+# Copyright (c) 2013-2015 Devin Teske
# All rights reserved.
#
# Portions of this software were developed by Bjoern Zeeb
@@ -141,16 +141,20 @@ BEGIN {
}
printf("ifconfig_%s_ipv6=\"inet6 %s\"\n", iface, $1);
}' >> $BSDINSTALL_TMPETC/._rc.conf.net
+retval=$?
-if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
+if [ "$BSDINSTALL_CONFIGCURRENT" ]; then
. $BSDINSTALL_TMPETC/._rc.conf.net
ifconfig ${INTERFACE} `eval echo \\\$ifconfig_${INTERFACE}_ipv6`
- if [ -n "${ipv6_defaultrouter}" ]; then
+ if [ "$ipv6_defaultrouter" ]; then
route delete -inet6 default
route add -inet6 default ${ipv6_defaultrouter}
+ retval=$?
fi
fi
+exit $retval
+
################################################################################
# END
################################################################################
diff --git a/usr.sbin/bsdinstall/scripts/rootpass b/usr.sbin/bsdinstall/scripts/rootpass
index b3dde22..7bfd823 100755
--- a/usr.sbin/bsdinstall/scripts/rootpass
+++ b/usr.sbin/bsdinstall/scripts/rootpass
@@ -34,4 +34,3 @@ echo
echo "Please select a password for the system management account (root):"
chroot $BSDINSTALL_CHROOT passwd root 2>&1
-
diff --git a/usr.sbin/bsdinstall/scripts/script b/usr.sbin/bsdinstall/scripts/script
index 19cd392..bb48873 100755
--- a/usr.sbin/bsdinstall/scripts/script
+++ b/usr.sbin/bsdinstall/scripts/script
@@ -1,7 +1,7 @@
#!/bin/sh
#-
# Copyright (c) 2013 Nathan Whitehorn
-# Copyright (c) 2013 Devin Teske
+# Copyright (c) 2013-2015 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -129,7 +129,8 @@ bsdinstall umount
f_dprintf "Installation Completed at %s" "$( date )"
-trap true EXIT
+trap - EXIT
+exit $SUCCESS
################################################################################
# END
diff --git a/usr.sbin/bsdinstall/scripts/wlanconfig b/usr.sbin/bsdinstall/scripts/wlanconfig
index cefc2cb..4eba2b0 100755
--- a/usr.sbin/bsdinstall/scripts/wlanconfig
+++ b/usr.sbin/bsdinstall/scripts/wlanconfig
@@ -1,7 +1,7 @@
#!/bin/sh
#-
# Copyright (c) 2011 Nathan Whitehorn
-# Copyright (c) 2013 Devin Teske
+# Copyright (c) 2013-2015 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -168,7 +168,7 @@ if [ "$BSDINSTALL_CONFIGCURRENT" ]; then
f_dprintf "%s" "$output"
fi
-exit 0
+exit $SUCCESS
################################################################################
# END
diff --git a/usr.sbin/bsdinstall/scripts/zfsboot b/usr.sbin/bsdinstall/scripts/zfsboot
index e6124da..b42591b 100755
--- a/usr.sbin/bsdinstall/scripts/zfsboot
+++ b/usr.sbin/bsdinstall/scripts/zfsboot
@@ -1647,7 +1647,7 @@ while :; do
esac
done
-return $SUCCESS
+exit $SUCCESS
################################################################################
# END
diff --git a/usr.sbin/ctladm/ctladm.8 b/usr.sbin/ctladm/ctladm.8
index deb6763..61b6d42 100644
--- a/usr.sbin/ctladm/ctladm.8
+++ b/usr.sbin/ctladm/ctladm.8
@@ -1,5 +1,6 @@
.\"
.\" Copyright (c) 2003 Silicon Graphics International Corp.
+.\" Copyright (c) 2015 Alexander Motin <mav@FreeBSD.org>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -34,7 +35,7 @@
.\" $Id: //depot/users/kenm/FreeBSD-test2/usr.sbin/ctladm/ctladm.8#3 $
.\" $FreeBSD$
.\"
-.Dd September 10, 2015
+.Dd September 12, 2015
.Dt CTLADM 8
.Os
.Sh NAME
@@ -964,6 +965,9 @@ Specifies LUN NAA identifier.
Either EUI or NAA identifier should be set to UNIQUE value to allow
EXTENDED COPY command access the LUN.
Non-unique LUN identifiers may lead to data corruption.
+.It Va ha_role
+Setting to "primary" or "secondary" overrides default role of the node
+in HA cluster, set by kern.cam.ctl.ha_role sysctl.
.It Va insecure_tpc
Setting to "on" allows EXTENDED COPY command sent to this LUN access
other LUNs on this host, not accessible otherwise.
@@ -995,7 +999,6 @@ Specify physical block size and offset of the device.
.It Va ublockoffset
Specify UNMAP block size and offset of the device.
.It Va rpm
-.It Va rpm
Specifies medium rotation rate of the device: 0 -- not reported,
1 -- non-rotating (SSD), >1024 -- value in revolutions per minute.
.It Va formfactor
diff --git a/usr.sbin/ctld/ctl.conf.5 b/usr.sbin/ctld/ctl.conf.5
index 121daa7..ea1d07a 100644
--- a/usr.sbin/ctld/ctl.conf.5
+++ b/usr.sbin/ctld/ctl.conf.5
@@ -28,7 +28,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 7, 2015
+.Dd September 15, 2015
.Dt CTL.CONF 5
.Os
.Sh NAME
@@ -388,6 +388,10 @@ The default backend is block.
.It Ic blocksize Ar size
The blocksize visible to the initiator.
The default blocksize is 512.
+.It Ic ctl-lun Ar lun_id
+Global numeric identifier to use for a given LUN inside CTL.
+By default CTL allocates those IDs dynamically, but explicit specification
+may be needed for consistency in HA configurations.
.It Ic device-id Ar string
The SCSI Device Identification string presented to the initiator.
.It Ic option Ar name Ar value
diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c
index 9803a5d..143f2e3 100644
--- a/usr.sbin/ctld/ctld.c
+++ b/usr.sbin/ctld/ctld.c
@@ -1397,6 +1397,7 @@ lun_new(struct conf *conf, const char *name)
lun->l_name = checked_strdup(name);
TAILQ_INIT(&lun->l_options);
TAILQ_INSERT_TAIL(&conf->conf_luns, lun, l_next);
+ lun->l_ctl_lun = -1;
return (lun);
}
@@ -2002,7 +2003,7 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
} else {
log_debugx("updating port \"%s\"", newport->p_name);
newport->p_ctl_port = oldport->p_ctl_port;
- error = kernel_port_update(newport);
+ error = kernel_port_update(newport, oldport);
}
if (error != 0) {
log_warnx("failed to %s port %s",
diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h
index 4f43c4e..782db15 100644
--- a/usr.sbin/ctld/ctld.h
+++ b/usr.sbin/ctld/ctld.h
@@ -399,7 +399,7 @@ void kernel_handoff(struct connection *conn);
void kernel_limits(const char *offload,
size_t *max_data_segment_length);
int kernel_port_add(struct port *port);
-int kernel_port_update(struct port *port);
+int kernel_port_update(struct port *port, struct port *old);
int kernel_port_remove(struct port *port);
void kernel_capsicate(void);
diff --git a/usr.sbin/ctld/kernel.c b/usr.sbin/ctld/kernel.c
index b75527f..2ecc70f 100644
--- a/usr.sbin/ctld/kernel.c
+++ b/usr.sbin/ctld/kernel.c
@@ -656,6 +656,11 @@ kernel_lun_add(struct lun *lun)
if (lun->l_size != 0)
req.reqdata.create.lun_size_bytes = lun->l_size;
+ if (lun->l_ctl_lun >= 0) {
+ req.reqdata.create.req_lun_id = lun->l_ctl_lun;
+ req.reqdata.create.flags |= CTL_LUN_FLAG_ID_REQ;
+ }
+
req.reqdata.create.flags |= CTL_LUN_FLAG_DEV_TYPE;
req.reqdata.create.device_type = T_DIRECT;
@@ -1024,11 +1029,13 @@ kernel_port_add(struct port *port)
}
int
-kernel_port_update(struct port *port)
+kernel_port_update(struct port *port, struct port *oport)
{
struct ctl_lun_map lm;
struct target *targ = port->p_target;
+ struct target *otarg = oport->p_target;
int error, i;
+ uint32_t olun;
/* Map configured LUNs and unmap others */
for (i = 0; i < MAX_LUNS; i++) {
@@ -1038,6 +1045,12 @@ kernel_port_update(struct port *port)
lm.lun = UINT32_MAX;
else
lm.lun = targ->t_luns[i]->l_ctl_lun;
+ if (otarg->t_luns[i] == NULL)
+ olun = UINT32_MAX;
+ else
+ olun = otarg->t_luns[i]->l_ctl_lun;
+ if (lm.lun == olun)
+ continue;
error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
if (error != 0)
log_warn("CTL_LUN_MAP ioctl failed");
diff --git a/usr.sbin/ctld/login.c b/usr.sbin/ctld/login.c
index 3e52a6a..72c23ce 100644
--- a/usr.sbin/ctld/login.c
+++ b/usr.sbin/ctld/login.c
@@ -602,6 +602,11 @@ login_negotiate_key(struct pdu *request, const char *name,
keys_add(response_keys, name, "No");
} else if (strcmp(name, "IFMarker") == 0) {
keys_add(response_keys, name, "No");
+ } else if (strcmp(name, "iSCSIProtocolLevel") == 0) {
+ tmp = strtoul(value, NULL, 10);
+ if (tmp > 2)
+ tmp = 2;
+ keys_add_int(response_keys, name, tmp);
} else {
log_debugx("unknown key \"%s\"; responding "
"with NotUnderstood", name);
diff --git a/usr.sbin/ctld/parse.y b/usr.sbin/ctld/parse.y
index 677b5d5..6907b48 100644
--- a/usr.sbin/ctld/parse.y
+++ b/usr.sbin/ctld/parse.y
@@ -57,8 +57,8 @@ extern void yyrestart(FILE *);
%}
%token ALIAS AUTH_GROUP AUTH_TYPE BACKEND BLOCKSIZE CHAP CHAP_MUTUAL
-%token CLOSING_BRACKET DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP DISCOVERY_FILTER
-%token FOREIGN
+%token CLOSING_BRACKET CTL_LUN DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP
+%token DISCOVERY_FILTER FOREIGN
%token INITIATOR_NAME INITIATOR_PORTAL ISNS_SERVER ISNS_PERIOD ISNS_TIMEOUT
%token LISTEN LISTEN_ISER LUN MAXPROC OFFLOAD OPENING_BRACKET OPTION
%token PATH PIDFILE PORT PORTAL_GROUP REDIRECT SEMICOLON SERIAL SIZE STR
@@ -855,6 +855,8 @@ lun_entry:
|
lun_device_id
|
+ lun_ctl_lun
+ |
lun_option
|
lun_path
@@ -912,6 +914,26 @@ lun_device_id: DEVICE_ID STR
}
;
+lun_ctl_lun: CTL_LUN STR
+ {
+ uint64_t tmp;
+
+ if (expand_number($2, &tmp) != 0) {
+ yyerror("invalid numeric value");
+ free($2);
+ return (1);
+ }
+
+ if (lun->l_ctl_lun >= 0) {
+ log_warnx("ctl_lun for lun \"%s\" "
+ "specified more than once",
+ lun->l_name);
+ return (1);
+ }
+ lun_set_ctl_lun(lun, tmp);
+ }
+ ;
+
lun_option: OPTION STR STR
{
struct lun_option *clo;
diff --git a/usr.sbin/ctld/token.l b/usr.sbin/ctld/token.l
index 19535f7..37989ce 100644
--- a/usr.sbin/ctld/token.l
+++ b/usr.sbin/ctld/token.l
@@ -54,6 +54,7 @@ backend { return BACKEND; }
blocksize { return BLOCKSIZE; }
chap { return CHAP; }
chap-mutual { return CHAP_MUTUAL; }
+ctl-lun { return CTL_LUN; }
debug { return DEBUG; }
device-id { return DEVICE_ID; }
discovery-auth-group { return DISCOVERY_AUTH_GROUP; }
diff --git a/usr.sbin/i2c/i2c.c b/usr.sbin/i2c/i2c.c
index 920dda2..3021b86 100644
--- a/usr.sbin/i2c/i2c.c
+++ b/usr.sbin/i2c/i2c.c
@@ -280,9 +280,6 @@ i2c_write(char *dev, struct options i2c_opt, char *i2c_buf)
err(1, "open failed");
}
- /*
- * Write offset where the data will go
- */
cmd.slave = i2c_opt.addr;
error = ioctl(fd, I2CSTART, &cmd);
if (error == -1) {
@@ -297,20 +294,24 @@ i2c_write(char *dev, struct options i2c_opt, char *i2c_buf)
err_msg = "error: offset malloc";
goto err1;
}
+ }
- cmd.count = bufsize;
- cmd.buf = buf;
- error = ioctl(fd, I2CWRITE, &cmd);
- free(buf);
- if (error == -1) {
- err_msg = "ioctl: error when write offset";
- goto err1;
+ switch(i2c_opt.mode) {
+ case I2C_MODE_STOP_START:
+ /*
+ * Write offset where the data will go
+ */
+ if (i2c_opt.width) {
+ cmd.count = bufsize;
+ cmd.buf = buf;
+ error = ioctl(fd, I2CWRITE, &cmd);
+ free(buf);
+ if (error == -1) {
+ err_msg = "ioctl: error when write offset";
+ goto err1;
+ }
}
- }
- /* Mode - stop start */
- if (i2c_opt.mode == I2C_MODE_STOP_START) {
- cmd.slave = i2c_opt.addr;
error = ioctl(fd, I2CSTOP, &cmd);
if (error == -1) {
err_msg = "ioctl: error sending stop condition";
@@ -322,9 +323,35 @@ i2c_write(char *dev, struct options i2c_opt, char *i2c_buf)
err_msg = "ioctl: error sending start condition";
goto err1;
}
- }
- /* Mode - repeated start */
- if (i2c_opt.mode == I2C_MODE_REPEATED_START) {
+
+ /*
+ * Write the data
+ */
+ cmd.count = i2c_opt.count;
+ cmd.buf = i2c_buf;
+ cmd.last = 0;
+ error = ioctl(fd, I2CWRITE, &cmd);
+ if (error == -1) {
+ err_msg = "ioctl: error when write";
+ goto err1;
+ }
+ break;
+
+ case I2C_MODE_REPEATED_START:
+ /*
+ * Write offset where the data will go
+ */
+ if (i2c_opt.width) {
+ cmd.count = bufsize;
+ cmd.buf = buf;
+ error = ioctl(fd, I2CWRITE, &cmd);
+ free(buf);
+ if (error == -1) {
+ err_msg = "ioctl: error when write offset";
+ goto err1;
+ }
+ }
+
cmd.slave = i2c_opt.addr;
error = ioctl(fd, I2CRPTSTART, &cmd);
if (error == -1) {
@@ -332,18 +359,42 @@ i2c_write(char *dev, struct options i2c_opt, char *i2c_buf)
"condition";
goto err1;
}
- }
- /*
- * Write the data
- */
- cmd.count = i2c_opt.count;
- cmd.buf = i2c_buf;
- cmd.last = 0;
- error = ioctl(fd, I2CWRITE, &cmd);
- if (error == -1) {
- err_msg = "ioctl: error when write";
- goto err1;
+ /*
+ * Write the data
+ */
+ cmd.count = i2c_opt.count;
+ cmd.buf = i2c_buf;
+ cmd.last = 0;
+ error = ioctl(fd, I2CWRITE, &cmd);
+ if (error == -1) {
+ err_msg = "ioctl: error when write";
+ goto err1;
+ }
+ break;
+
+ case I2C_MODE_NONE: /* fall through */
+ default:
+ buf = realloc(buf, bufsize + i2c_opt.count);
+ if (buf == NULL) {
+ err_msg = "error: data malloc";
+ goto err1;
+ }
+
+ memcpy(buf + bufsize, i2c_buf, i2c_opt.count);
+ /*
+ * Write offset and data
+ */
+ cmd.count = bufsize + i2c_opt.count;
+ cmd.buf = buf;
+ cmd.last = 0;
+ error = ioctl(fd, I2CWRITE, &cmd);
+ free(buf);
+ if (error == -1) {
+ err_msg = "ioctl: error when write";
+ goto err1;
+ }
+ break;
}
cmd.slave = i2c_opt.addr;
error = ioctl(fd, I2CSTOP, &cmd);
diff --git a/usr.sbin/pw/pw_user.c b/usr.sbin/pw/pw_user.c
index 61d468a..1af8f81 100644
--- a/usr.sbin/pw/pw_user.c
+++ b/usr.sbin/pw/pw_user.c
@@ -804,7 +804,7 @@ pw_user_show(int argc, char **argv, char *arg1)
case 'a':
all = true;
break;
- case 7:
+ case '7':
v7 = true;
break;
}
@@ -1694,6 +1694,7 @@ pw_user_mod(int argc, char **argv, char *arg1)
if (homedir && strcmp(pwd->pw_dir, homedir) != 0) {
pwd->pw_dir = homedir;
+ edited = true;
if (fstatat(conf.rootfd, pwd->pw_dir, &st, 0) == -1) {
if (!createhome)
warnx("WARNING: home `%s' does not exist",
OpenPOWER on IntegriCloud