diff options
author | dim <dim@FreeBSD.org> | 2015-09-11 17:20:03 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2015-09-11 17:20:03 +0000 |
commit | 5cc32d7f18f18fb3a5f4155b7f748cc7be60d2da (patch) | |
tree | 09add9017de3c98451b1eaf85a24b608cf228e4b | |
parent | a8fd1565ce9f3593ba962863828175715c3dede0 (diff) | |
parent | 2a0c9817c795eaf2bf7607d8cc9b36975aaca160 (diff) | |
download | FreeBSD-src-5cc32d7f18f18fb3a5f4155b7f748cc7be60d2da.zip FreeBSD-src-5cc32d7f18f18fb3a5f4155b7f748cc7be60d2da.tar.gz |
Merge ^/head r287527 through r287679.
171 files changed, 4253 insertions, 3947 deletions
diff --git a/etc/rc.d/bgfsck b/etc/rc.d/bgfsck index d15744c..c1d1a4d 100755 --- a/etc/rc.d/bgfsck +++ b/etc/rc.d/bgfsck @@ -12,17 +12,24 @@ name="background_fsck" rcvar="background_fsck" start_cmd="bgfsck_start" +start_precmd="bgfsck_start_precmd" stop_cmd=":" +bgfsck_start_precmd() +{ + if [ $($ID -u) != 0 ]; then + err 1 "Must be root." + fi +} + bgfsck_start() { - if [ -z "${rc_force}" ]; then - background_fsck_delay=${background_fsck_delay:-0} - else + : ${background_fsck_delay=0} + if [ -n "${rc_force}" ]; then background_fsck_delay=0 fi if [ ${background_fsck_delay} -lt 0 ]; then - echo "Background file system checks delayed indefinitely" + warn "Background file system checks delayed indefinitely" return 0 fi diff --git a/etc/rc.d/jail b/etc/rc.d/jail index d486118..3c55edf 100755 --- a/etc/rc.d/jail +++ b/etc/rc.d/jail @@ -419,7 +419,7 @@ jail_status() jail_start() { - local _j _jid _jl + local _j _jid _jl _id _name if [ $# = 0 ]; then return @@ -432,10 +432,9 @@ jail_start() command_args="-f $jail_conf -c" _tmp=`mktemp -t jail` || exit 3 if $command $rc_flags $command_args >> $_tmp 2>&1; then - $jail_jls jid name | while read IN; do - set -- $IN - echo -n " $2" - echo $1 > /var/run/jail_$2.id + $jail_jls jid name | while read _id _name; do + echo -n " $_name" + echo $_id > /var/run/jail_${_name}.id done else tail -1 $_tmp diff --git a/etc/rc.d/netif b/etc/rc.d/netif index 00e05b2..5ed9562 100755 --- a/etc/rc.d/netif +++ b/etc/rc.d/netif @@ -88,7 +88,7 @@ netif_start() fi if [ -f /etc/rc.d/routing -a -n "$cmdifn" ] ; then for _if in $cmdifn; do - /etc/rc.d/routing start any $_if + /etc/rc.d/routing static any $_if done fi } diff --git a/games/fortune/datfiles/freebsd-tips b/games/fortune/datfiles/freebsd-tips index f3406a2..9767586 100644 --- a/games/fortune/datfiles/freebsd-tips +++ b/games/fortune/datfiles/freebsd-tips @@ -234,7 +234,7 @@ To erase a line you've written at the command prompt, use "Ctrl-U". To find the hostname associated with an IP address, use drill -x IP_address - -- Allan Jude <allanjude@freebsd.org> + -- Allan Jude <allanjude@FreeBSD.org> % To obtain a neat PostScript rendering of a manual page, use ``-t'' switch of the man(1) utility: ``man -t <topic>''. For example: diff --git a/lib/libc/gen/sysctl.3 b/lib/libc/gen/sysctl.3 index 7d7b90a..4594d9a 100644 --- a/lib/libc/gen/sysctl.3 +++ b/lib/libc/gen/sysctl.3 @@ -28,7 +28,7 @@ .\" @(#)sysctl.3 8.4 (Berkeley) 5/9/95 .\" $FreeBSD$ .\" -.Dd May 17, 2013 +.Dd September 10, 2015 .Dt SYSCTL 3 .Os .Sh NAME @@ -736,8 +736,6 @@ privilege may change the value. .It "VM_LOADAVG struct loadavg no" .It "VM_TOTAL struct vmtotal no" .It "VM_SWAPPING_ENABLED integer maybe" -.It "VM_V_CACHE_MAX integer yes" -.It "VM_V_CACHE_MIN integer yes" .It "VM_V_FREE_MIN integer yes" .It "VM_V_FREE_RESERVED integer yes" .It "VM_V_FREE_TARGET integer yes" @@ -757,12 +755,6 @@ The returned data consists of a 1 if process swapping is enabled or 0 if disabled. This variable is permanently set to 0 if the kernel was built with swapping disabled. -.It Li VM_V_CACHE_MAX -Maximum desired size of the cache queue. -.It Li VM_V_CACHE_MIN -Minimum desired size of the cache queue. -If the cache queue size -falls very far below this value, the pageout daemon is awakened. .It Li VM_V_FREE_MIN Minimum amount of memory (cache memory plus free memory) required to be available before a process waiting on memory will be diff --git a/lib/libc/net/getnameinfo.c b/lib/libc/net/getnameinfo.c index f83d0e2..d7e7971 100644 --- a/lib/libc/net/getnameinfo.c +++ b/lib/libc/net/getnameinfo.c @@ -78,6 +78,8 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) { + if (sa == NULL) + return (EAI_FAIL); switch (sa->sa_family) { case AF_INET: @@ -124,25 +126,19 @@ getnameinfo_inet(const struct sockaddr *sa, socklen_t salen, struct servent *sp; struct hostent *hp; u_short port; - int family, i; const char *addr; u_int32_t v4a; int h_error; char numserv[512]; char numaddr[512]; - if (sa == NULL) - return EAI_FAIL; - - family = sa->sa_family; - for (i = 0; afdl[i].a_af; i++) - if (afdl[i].a_af == family) { - afd = &afdl[i]; - goto found; - } - return EAI_FAMILY; + for (afd = &afdl[0]; afd->a_af > 0; afd++) { + if (afd->a_af == sa->sa_family) + break; + } + if (afd->a_af == 0) + return (EAI_FAMILY); - found: if (salen != afd->a_socklen) return EAI_FAIL; diff --git a/lib/libc/net/if_nametoindex.c b/lib/libc/net/if_nametoindex.c index 8f04921..debf3fa 100644 --- a/lib/libc/net/if_nametoindex.c +++ b/lib/libc/net/if_nametoindex.c @@ -70,9 +70,7 @@ if_nametoindex(const char *ifname) s = _socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (s != -1) { -#ifdef PURIFY memset(&ifr, 0, sizeof(ifr)); -#endif strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (_ioctl(s, SIOCGIFINDEX, &ifr) != -1) { _close(s); diff --git a/lib/libc/posix1e/acl_entry.c b/lib/libc/posix1e/acl_entry.c index 3f8ca62..2cffaa3 100644 --- a/lib/libc/posix1e/acl_entry.c +++ b/lib/libc/posix1e/acl_entry.c @@ -91,7 +91,7 @@ acl_create_entry_np(acl_t *acl_p, acl_entry_t *entry_p, int offset) return (-1); } - if (offset < 0 || offset >= acl_int->acl_cnt) { + if (offset < 0 || offset > acl_int->acl_cnt) { errno = EINVAL; return (-1); } diff --git a/lib/libc/tests/sys/Makefile b/lib/libc/tests/sys/Makefile index 7ecf1d6..89431bc 100644 --- a/lib/libc/tests/sys/Makefile +++ b/lib/libc/tests/sys/Makefile @@ -25,10 +25,7 @@ NETBSD_ATF_TESTS_C+= kevent_test NETBSD_ATF_TESTS_C+= kill_test NETBSD_ATF_TESTS_C+= link_test NETBSD_ATF_TESTS_C+= listen_test -# On arm64 triggers panic ARM64TODO: pmap_mincore (PR202307). -.if ${MACHINE_CPUARCH} != "aarch64" NETBSD_ATF_TESTS_C+= mincore_test -.endif NETBSD_ATF_TESTS_C+= mkdir_test NETBSD_ATF_TESTS_C+= mkfifo_test NETBSD_ATF_TESTS_C+= mknod_test diff --git a/lib/libthr/thread/thr_once.c b/lib/libthr/thread/thr_once.c index 4f70374..208b703 100644 --- a/lib/libthr/thread/thr_once.c +++ b/lib/libthr/thread/thr_once.c @@ -50,9 +50,11 @@ __weak_reference(_pthread_once, pthread_once); static void once_cancel_handler(void *arg) { - pthread_once_t *once_control = arg; + pthread_once_t *once_control; - if (atomic_cmpset_rel_int(&once_control->state, ONCE_IN_PROGRESS, ONCE_NEVER_DONE)) + once_control = arg; + if (atomic_cmpset_rel_int(&once_control->state, ONCE_IN_PROGRESS, + ONCE_NEVER_DONE)) return; atomic_store_rel_int(&once_control->state, ONCE_NEVER_DONE); _thr_umtx_wake(&once_control->state, INT_MAX, 0); @@ -68,16 +70,22 @@ _pthread_once(pthread_once_t *once_control, void (*init_routine) (void)) for (;;) { state = once_control->state; - if (state == ONCE_DONE) + if (state == ONCE_DONE) { + atomic_thread_fence_acq(); return (0); + } if (state == ONCE_NEVER_DONE) { - if (atomic_cmpset_acq_int(&once_control->state, state, ONCE_IN_PROGRESS)) + if (atomic_cmpset_int(&once_control->state, state, + ONCE_IN_PROGRESS)) break; } else if (state == ONCE_IN_PROGRESS) { - if (atomic_cmpset_acq_int(&once_control->state, state, ONCE_WAIT)) - _thr_umtx_wait_uint(&once_control->state, ONCE_WAIT, NULL, 0); + if (atomic_cmpset_int(&once_control->state, state, + ONCE_WAIT)) + _thr_umtx_wait_uint(&once_control->state, + ONCE_WAIT, NULL, 0); } else if (state == ONCE_WAIT) { - _thr_umtx_wait_uint(&once_control->state, state, NULL, 0); + _thr_umtx_wait_uint(&once_control->state, state, + NULL, 0); } else return (EINVAL); } @@ -86,7 +94,8 @@ _pthread_once(pthread_once_t *once_control, void (*init_routine) (void)) THR_CLEANUP_PUSH(curthread, once_cancel_handler, once_control); init_routine(); THR_CLEANUP_POP(curthread, 0); - if (atomic_cmpset_rel_int(&once_control->state, ONCE_IN_PROGRESS, ONCE_DONE)) + if (atomic_cmpset_rel_int(&once_control->state, ONCE_IN_PROGRESS, + ONCE_DONE)) return (0); atomic_store_rel_int(&once_control->state, ONCE_DONE); _thr_umtx_wake(&once_control->state, INT_MAX, 0); @@ -94,6 +103,6 @@ _pthread_once(pthread_once_t *once_control, void (*init_routine) (void)) } void -_thr_once_init() +_thr_once_init(void) { } diff --git a/release/amd64/mkisoimages.sh b/release/amd64/mkisoimages.sh index 2b89d89..755fb52 100644 --- a/release/amd64/mkisoimages.sh +++ b/release/amd64/mkisoimages.sh @@ -34,7 +34,7 @@ if [ "x$1" = "x-b" ]; then mkdir efi mount -t msdosfs /dev/$device efi mkdir -p efi/efi/boot - cp ${4}/boot/loader.efi efi/efi/boot/bootx64.efi + cp "$4/boot/loader.efi" efi/efi/boot/bootx64.efi umount efi rmdir efi mdconfig -d -u $device @@ -46,15 +46,15 @@ else fi if [ $# -lt 3 ]; then - echo Usage: $0 '[-b] image-label image-name base-bits-dir [extra-bits-dir]' + echo "Usage: $0 [-b] image-label image-name base-bits-dir [extra-bits-dir]" exit 1 fi -LABEL=`echo $1 | tr '[:lower:]' '[:upper:]'`; shift -NAME=$1; shift +LABEL=`echo "$1" | tr '[:lower:]' '[:upper:]'`; shift +NAME="$1"; shift publisher="The FreeBSD Project. http://www.FreeBSD.org/" -echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > $1/etc/fstab -makefs -t cd9660 $bootable -o rockridge -o label=$LABEL -o publisher="$publisher" $NAME $* -rm $1/etc/fstab +echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > "$1/etc/fstab" +makefs -t cd9660 $bootable -o rockridge -o label="$LABEL" -o publisher="$publisher" "$NAME" "$@" +rm "$1/etc/fstab" rm -f efiboot.img diff --git a/release/i386/mkisoimages.sh b/release/i386/mkisoimages.sh index e4093d7..a250105 100644 --- a/release/i386/mkisoimages.sh +++ b/release/i386/mkisoimages.sh @@ -32,14 +32,14 @@ else fi if [ $# -lt 3 ]; then - echo Usage: $0 '[-b] image-label image-name base-bits-dir [extra-bits-dir]' + echo "Usage: $0 [-b] image-label image-name base-bits-dir [extra-bits-dir]" exit 1 fi -LABEL=`echo $1 | tr '[:lower:]' '[:upper:]'`; shift -NAME=$1; shift +LABEL=`echo "$1" | tr '[:lower:]' '[:upper:]'`; shift +NAME="$1"; shift publisher="The FreeBSD Project. http://www.FreeBSD.org/" -echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > $1/etc/fstab -makefs -t cd9660 $bootable -o rockridge -o label=$LABEL -o publisher="$publisher" $NAME $* -rm $1/etc/fstab +echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > "$1/etc/fstab" +makefs -t cd9660 $bootable -o rockridge -o label="$LABEL" -o publisher="$publisher" "$NAME" "$@" +rm "$1/etc/fstab" diff --git a/release/pc98/mkisoimages.sh b/release/pc98/mkisoimages.sh index 5a19b4d..074fe09 100644 --- a/release/pc98/mkisoimages.sh +++ b/release/pc98/mkisoimages.sh @@ -32,14 +32,14 @@ else fi if [ $# -lt 3 ]; then - echo Usage: $0 '[-b] image-label image-name base-bits-dir [extra-bits-dir]' + echo "Usage: $0 [-b] image-label image-name base-bits-dir [extra-bits-dir]" exit 1 fi -LABEL=`echo $1 | tr '[:lower:]' '[:upper:]'`; shift -NAME=$1; shift +LABEL=`echo "$1" | tr '[:lower:]' '[:upper:]'`; shift +NAME="$1"; shift publisher="The FreeBSD Project. http://www.FreeBSD.org/" -echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > $1/etc/fstab -makefs -t cd9660 $bootable -o rockridge -o label=$LABEL -o publisher="$publisher" $NAME $* -rm $1/etc/fstab +echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > "$1/etc/fstab" +makefs -t cd9660 $bootable -o rockridge -o label="$LABEL" -o publisher="$publisher" "$NAME" "$@" +rm "$1/etc/fstab" diff --git a/release/powerpc/mkisoimages.sh b/release/powerpc/mkisoimages.sh index b38d5ef..c92072d 100644 --- a/release/powerpc/mkisoimages.sh +++ b/release/powerpc/mkisoimages.sh @@ -25,18 +25,18 @@ if [ "x$1" = "x-b" ]; then # Apple boot code - uudecode -o /tmp/hfs-boot-block.bz2 `dirname $0`/hfs-boot.bz2.uu + uudecode -o /tmp/hfs-boot-block.bz2 "`dirname "$0"`/hfs-boot.bz2.uu" bzip2 -d /tmp/hfs-boot-block.bz2 OFFSET=$(hd /tmp/hfs-boot-block | grep 'Loader START' | cut -f 1 -d ' ') OFFSET=0x$(echo 0x$OFFSET | awk '{printf("%x\n",$1/512);}') - dd if=$4/boot/loader of=/tmp/hfs-boot-block seek=$OFFSET conv=notrunc + dd if="$4/boot/loader" of=/tmp/hfs-boot-block seek=$OFFSET conv=notrunc bootable="-o bootimage=macppc;/tmp/hfs-boot-block -o no-emul-boot" # pSeries/PAPR boot code - mkdir -p $4/ppc/chrp - cp $4/boot/loader $4/ppc/chrp - cat > $4/ppc/bootinfo.txt << EOF + mkdir -p "$4/ppc/chrp" + cp "$4/boot/loader" "$4/ppc/chrp" + cat > "$4/ppc/bootinfo.txt" << EOF <chrp-boot> <description>FreeBSD Install</description> <os-name>FreeBSD</os-name> @@ -46,7 +46,7 @@ EOF bootable="$bootable -o chrp-boot" # Playstation 3 boot code - echo "FreeBSD Install='/boot/loader.ps3'" > $4/etc/kboot.conf + echo "FreeBSD Install='/boot/loader.ps3'" > "$4/etc/kboot.conf" shift else @@ -54,16 +54,16 @@ else fi if [ $# -lt 3 ]; then - echo Usage: $0 '[-b] image-label image-name base-bits-dir [extra-bits-dir]' + echo "Usage: $0 [-b] image-label image-name base-bits-dir [extra-bits-dir]" exit 1 fi -LABEL=`echo $1 | tr '[:lower:]' '[:upper:]'`; shift -NAME=$1; shift +LABEL=`echo "$1" | tr '[:lower:]' '[:upper:]'`; shift +NAME="$1"; shift publisher="The FreeBSD Project. http://www.FreeBSD.org/" -echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > $1/etc/fstab -makefs -t cd9660 $bootable -o rockridge -o label=$LABEL -o publisher="$publisher" $NAME $* -rm $1/etc/fstab +echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > "$1/etc/fstab" +makefs -t cd9660 $bootable -o rockridge -o label="$LABEL" -o publisher="$publisher" "$NAME" "$@" +rm "$1/etc/fstab" rm /tmp/hfs-boot-block -rm -rf $1/ppc +rm -rf "$1/ppc" diff --git a/release/sparc64/mkisoimages.sh b/release/sparc64/mkisoimages.sh index 9c60cb2..337db40 100644 --- a/release/sparc64/mkisoimages.sh +++ b/release/sparc64/mkisoimages.sh @@ -23,62 +23,62 @@ # extra-bits-dir, if provided, contains additional files to be merged # into base-bits-dir as part of making the image. if [ $# -lt 3 ]; then - echo Usage: $0 '[-b] image-label image-name base-bits-dir [extra-bits-dir]' > /dev/stderr + echo "Usage: $0 [-b] image-label image-name base-bits-dir [extra-bits-dir]" > /dev/stderr exit 1 fi -case $1 in --b) BOPT=$1; shift ;; +case "$1" in +-b) BOPT="$1"; shift ;; esac -LABEL=`echo $1 | tr '[:lower:]' '[:upper:]'`; shift -NAME=$1; shift -BASEBITSDIR=$1 +LABEL=`echo "$1" | tr '[:lower:]' '[:upper:]'`; shift +NAME="$1"; shift +BASEBITSDIR="$1" # Create an ISO image publisher="The FreeBSD Project. http://www.FreeBSD.org/" -echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > "${BASEBITSDIR}/etc/fstab" -makefs -t cd9660 -o rockridge -o label="$LABEL" -o publisher="$publisher" ${NAME}.tmp $* -rm "${BASEBITSDIR}/etc/fstab" +echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > "$BASEBITSDIR/etc/fstab" +makefs -t cd9660 -o rockridge -o label="$LABEL" -o publisher="$publisher" "$NAME.tmp" "$@" +rm "$BASEBITSDIR/etc/fstab" if [ "x$BOPT" != "x-b" ]; then - mv ${NAME}.tmp ${NAME} + mv "$NAME.tmp" "$NAME" exit 0 fi TMPIMGDIR=`mktemp -d /tmp/bootfs.XXXXXXXX` || exit 1 -BOOTFSDIR="${TMPIMGDIR}/bootfs" -BOOTFSIMG="${TMPIMGDIR}/bootfs.img" +BOOTFSDIR="$TMPIMGDIR/bootfs" +BOOTFSIMG="$TMPIMGDIR/bootfs.img" # Create a boot filesystem -mkdir -p "${BOOTFSDIR}/boot" -cp -p "${BASEBITSDIR}/boot/loader" "${BOOTFSDIR}/boot" -makefs -t ffs -B be -M 512k "${BOOTFSIMG}" "${BOOTFSDIR}" -dd if="${BASEBITSDIR}/boot/boot1" of="${BOOTFSIMG}" bs=512 conv=notrunc,sync +mkdir -p "$BOOTFSDIR/boot" +cp -p "$BASEBITSDIR/boot/loader" "$BOOTFSDIR/boot" +makefs -t ffs -B be -M 512k "$BOOTFSIMG" "$BOOTFSDIR" +dd if="$BASEBITSDIR/boot/boot1" of="$BOOTFSIMG" bs=512 conv=notrunc,sync # Create a boot ISO image : ${CYLSIZE:=640} -ISOSIZE=$(stat -f %z ${NAME}.tmp) -ISOBLKS=$(((${ISOSIZE} + 511) / 512)) -ISOCYLS=$(((${ISOBLKS} + (${CYLSIZE} - 1)) / ${CYLSIZE})) +ISOSIZE=$(stat -f %z "$NAME.tmp") +ISOBLKS=$((($ISOSIZE + 511) / 512)) +ISOCYLS=$((($ISOBLKS + ($CYLSIZE - 1)) / $CYLSIZE)) -BOOTFSSIZE=$(stat -f %z "${BOOTFSIMG}") -BOOTFSBLKS=$(((${BOOTFSSIZE} + 511) / 512)) -BOOTFSCYLS=$(((${BOOTFSBLKS} + (${CYLSIZE} - 1)) / ${CYLSIZE})) +BOOTFSSIZE=$(stat -f %z "$BOOTFSIMG") +BOOTFSBLKS=$((($BOOTFSSIZE + 511) / 512)) +BOOTFSCYLS=$((($BOOTFSBLKS + ($CYLSIZE - 1)) / $CYLSIZE)) -ENDCYL=$((${ISOCYLS} + ${BOOTFSCYLS})) -NSECTS=$((${ENDCYL} * 1 * ${CYLSIZE})) +ENDCYL=$(($ISOCYLS + $BOOTFSCYLS)) +NSECTS=$(($ENDCYL * 1 * $CYLSIZE)) -dd if=${NAME}.tmp of=${NAME} bs=${CYLSIZE}b conv=notrunc,sync -dd if=${BOOTFSIMG} of=${NAME} bs=${CYLSIZE}b seek=${ISOCYLS} conv=notrunc,sync +dd if="$NAME.tmp" of="$NAME" bs="${CYLSIZE}b" conv=notrunc,sync +dd if="$BOOTFSIMG" of="$NAME" bs="${CYLSIZE}b" seek=$ISOCYLS conv=notrunc,sync # The number of alternative cylinders is always 2. -dd if=/dev/zero of=${NAME} bs=${CYLSIZE}b seek=${ENDCYL} count=2 conv=notrunc,sync -rm -rf ${NAME}.tmp ${TMPIMGDIR} +dd if=/dev/zero of="$NAME" bs="${CYLSIZE}b" seek=$ENDCYL count=2 conv=notrunc,sync +rm -rf "$NAME.tmp" "$TMPIMGDIR" # Write VTOC8 label to boot ISO image -MD=`mdconfig -a -t vnode -S 512 -y 1 -x ${CYLSIZE} -f ${NAME}` -gpart create -s VTOC8 ${MD} +MD=`mdconfig -a -t vnode -S 512 -y 1 -x "$CYLSIZE" -f "$NAME"` +gpart create -s VTOC8 $MD # !4: usr, for ISO image part -gpart add -i 1 -s $((${ISOCYLS} * ${CYLSIZE} * 512))b -t \!4 ${MD} +gpart add -i 1 -s "$(($ISOCYLS * $CYLSIZE * 512))b" -t \!4 $MD # !2: root, for bootfs part. -gpart add -i 6 -s $((${BOOTFSCYLS} * ${CYLSIZE} * 512))b -t \!2 ${MD} +gpart add -i 6 -s "$(($BOOTFSCYLS * $CYLSIZE * 512))b" -t \!2 $MD mdconfig -d -u ${MD#md} diff --git a/sbin/ifconfig/ifgif.c b/sbin/ifconfig/ifgif.c index 91c433c..72ceb1b 100644 --- a/sbin/ifconfig/ifgif.c +++ b/sbin/ifconfig/ifgif.c @@ -51,7 +51,7 @@ static const char rcsid[] = #include "ifconfig.h" -#define GIFBITS "\020\1ACCEPT_REV_ETHIP_VER\2IGNORE_SOURCE\5SEND_REV_ETHIP_VER" +#define GIFBITS "\020\2IGNORE_SOURCE" static void gif_status(int); @@ -70,8 +70,7 @@ gif_status(int s) } static void -setgifopts(const char *val, - int d, int s, const struct afswtch *afp) +setgifopts(const char *val, int d, int s, const struct afswtch *afp) { int opts; @@ -93,12 +92,8 @@ setgifopts(const char *val, } static struct cmd gif_cmds[] = { - DEF_CMD("accept_rev_ethip_ver", GIF_ACCEPT_REVETHIP, setgifopts), - DEF_CMD("-accept_rev_ethip_ver",-GIF_ACCEPT_REVETHIP, setgifopts), DEF_CMD("ignore_source", GIF_IGNORE_SOURCE, setgifopts), DEF_CMD("-ignore_source", -GIF_IGNORE_SOURCE, setgifopts), - DEF_CMD("send_rev_ethip_ver", GIF_SEND_REVETHIP, setgifopts), - DEF_CMD("-send_rev_ethip_ver", -GIF_SEND_REVETHIP, setgifopts), }; static struct afswtch af_gif = { @@ -110,11 +105,9 @@ static struct afswtch af_gif = { static __constructor void gif_ctor(void) { -#define N(a) (sizeof(a) / sizeof(a[0])) size_t i; - for (i = 0; i < N(gif_cmds); i++) + for (i = 0; i < nitems(gif_cmds); i++) cmd_register(&gif_cmds[i]); af_register(&af_gif); -#undef N } diff --git a/sbin/rtsol/Makefile b/sbin/rtsol/Makefile index d738008..a2bd040 100644 --- a/sbin/rtsol/Makefile +++ b/sbin/rtsol/Makefile @@ -14,15 +14,13 @@ # # $FreeBSD$ -SRCDIR= ${.CURDIR}/../../usr.sbin/rtsold - -.PATH: ${SRCDIR} +.PATH: ${.CURDIR}/../../usr.sbin/rtsold PROG= rtsol SRCS= rtsold.c rtsol.c if.c probe.c dump.c rtsock.c MAN= WARNS?= 3 -CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H -DSMALL +CFLAGS+= -DHAVE_ARC4RANDOM -DSMALL .include <bsd.prog.mk> diff --git a/share/dtrace/nfsattrstats b/share/dtrace/nfsattrstats index 63ca9318c..8aaf1fc 100755 --- a/share/dtrace/nfsattrstats +++ b/share/dtrace/nfsattrstats @@ -56,7 +56,7 @@ syscall:::return self->syscallname = ""; } -nfsclient::: +nfscl::: /self->syscallname != 0 && self->syscallname != ""/ { @@ -64,7 +64,7 @@ nfsclient::: self->syscallname); } -nfsclient::: +nfscl::: /self->syscallname == 0 || self->syscallname == ""/ { diff --git a/share/dtrace/nfsclienttime b/share/dtrace/nfsclienttime index 2422305..61c20d6 100755 --- a/share/dtrace/nfsclienttime +++ b/share/dtrace/nfsclienttime @@ -53,13 +53,13 @@ syscall:::entry self->count = 0; } -nfsclient:nfs3::start +nfscl:nfs3::start { self->timestamp = timestamp; } -nfsclient:nfs3::done +nfscl:nfs3::done { self->count += (timestamp - self->timestamp); diff --git a/share/man/man4/blackhole.4 b/share/man/man4/blackhole.4 index 668f92d..f662ec3 100644 --- a/share/man/man4/blackhole.4 +++ b/share/man/man4/blackhole.4 @@ -12,25 +12,35 @@ .\" .\" .\" $FreeBSD$ -.Dd January 1, 2007 +.Dd September 6, 2015 .Dt BLACKHOLE 4 .Os .Sh NAME .Nm blackhole .Nd a .Xr sysctl 8 -MIB for manipulating behaviour in respect of refused TCP or UDP connection +MIB for manipulating behaviour in respect of refused SCTP, TCP, or UDP connection attempts .Sh SYNOPSIS -.Cd sysctl net.inet.tcp.blackhole[=[0 | 1 | 2]] -.Cd sysctl net.inet.udp.blackhole[=[0 | 1]] +.Cd sysctl net.inet.sctp.blackhole Ns Op = Ns Brq "0 | 1 | 2" +.Cd sysctl net.inet.tcp.blackhole Ns Op = Ns Brq "0 | 1 | 2" +.Cd sysctl net.inet.udp.blackhole Ns Op = Ns Brq "0 | 1" .Sh DESCRIPTION The .Nm .Xr sysctl 8 MIB is used to control system behaviour when connection requests -are received on TCP or UDP ports where there is no socket listening. +are received on SCTP, TCP, or UDP ports where there is no socket listening. .Pp +The blackhole behaviour is useful to slow down an attacker who is port-scanning +a system in an attempt to detect vulnerable services. +It might also slow down an attempted denial of service attack. +.Ss SCTP +Setting the SCTP blackhole MIB to a numeric value of one +will prevent sending an ABORT packet in response to an incoming INIT. +A MIB value of two will do the same, but will also prevent sending an ABORT packet +when unexpected packets are received. +.Ss TCP Normal behaviour, when a TCP SYN segment is received on a port where there is no socket accepting connections, is for the system to return a RST segment, and drop the connection. @@ -44,20 +54,15 @@ as a blackhole. By setting the MIB value to two, any segment arriving on a closed port is dropped without returning a RST. This provides some degree of protection against stealth port scans. -.Pp -In the UDP instance, enabling blackhole behaviour turns off the sending +.Ss UDP +Enabling blackhole behaviour turns off the sending of an ICMP port unreachable message in response to a UDP datagram which arrives on a port where there is no socket listening. It must be noted that this behaviour will prevent remote systems from running .Xr traceroute 8 to a system. -.Pp -The blackhole behaviour is useful to slow down anyone who is port scanning -a system, attempting to detect vulnerable services on a system. -It could potentially also slow down someone who is attempting a denial -of service attack. .Sh WARNING -The TCP and UDP blackhole features should not be regarded as a replacement +The SCTP, TCP, and UDP blackhole features should not be regarded as a replacement for firewall solutions. Better security would consist of the .Nm @@ -68,6 +73,7 @@ This mechanism is not a substitute for securing a system. It should be used together with other security mechanisms. .Sh SEE ALSO .Xr ip 4 , +.Xr sctp 4 , .Xr tcp 4 , .Xr udp 4 , .Xr ipf 8 , @@ -80,5 +86,10 @@ The TCP and UDP MIBs first appeared in .Fx 4.0 . +.Pp +The SCTP +.Nm +MIB first appeared in +.Fx 9.1 . .Sh AUTHORS .An Geoffrey M. Rehmet diff --git a/share/man/man4/gif.4 b/share/man/man4/gif.4 index 27ee61b..76b7976 100644 --- a/share/man/man4/gif.4 +++ b/share/man/man4/gif.4 @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 14, 2014 +.Dd September 10, 2015 .Dt GIF 4 .Os .Sh NAME @@ -246,32 +246,3 @@ had a multi-destination behavior, configurable via .Dv IFF_LINK0 flag. The behavior is obsolete and is no longer supported. -.Pp -On -.Fx -6.1, 6.2, 6.3, 7.0, 7.1, and 7.2 -the -.Nm -sends and receives incorrect EtherIP packets with reversed version -field when -.Xr if_bridge 4 -is used together. As a workaround on this interoperability issue, the -following two -.Xr ifconfig 8 -flags can be used: -.Bl -tag -width "accept_rev_ethip_ver" -offset indent -.It accept_rev_ethip_ver -accepts both correct EtherIP packets and ones with reversed version -field, if enabled. If disabled, the -.Nm -accepts the correct packets only. This flag is enabled by default. -.It send_rev_ethip_ver -sends EtherIP packets with reversed version field intentionally, if -enabled. If disabled, the -.Nm -sends the correct packets only. This flag is disabled by default. -.El -.Pp -If interoperability with the older -.Fx -machines is needed, both of these two flags must be enabled. diff --git a/share/man/man9/stack.9 b/share/man/man9/stack.9 index fee6b8f..85640df 100644 --- a/share/man/man9/stack.9 +++ b/share/man/man9/stack.9 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 16, 2011 +.Dd September 10, 2015 .Dt STACK 9 .Os .Sh NAME @@ -36,9 +36,11 @@ .Sh SYNOPSIS .In sys/param.h .In sys/stack.h +.Pp In the kernel configuration file: .Cd "options DDB" .Cd "options STACK" +.Pp .Ft struct stack * .Fn stack_create "void" .Ft void @@ -63,6 +65,10 @@ In the kernel configuration file: .Fn stack_sbuf_print_ddb "struct sbuf sb*" "const struct stack *st" .Ft void .Fn stack_save "struct stack *st" +.Ft void +.Fn stack_save_td "struct stack *st" "struct thread *td" +.Ft int +.Fn stack_save_td_running "struct stack *st" "struct thread *td" .Sh DESCRIPTION The .Nm @@ -86,6 +92,16 @@ Memory associated with a trace is freed by calling .Pp A trace of the current kernel thread's call stack may be captured using .Fn stack_save . +.Fn stack_save_td +and +.Fn stack_save_td_running +can also be used to capture the stack of a caller-specified thread. +Callers of these functions must own the thread lock of the specified thread. +.Fn stack_save_td +can capture the stack of a kernel thread that is not running or +swapped out at the time of the call. +.Fn stack_save_td_running +can capture the stack of a running kernel thread. .Pp .Fn stack_print and @@ -130,6 +146,23 @@ The utility functions and .Nm stack_put may be used to manipulate stack data structures directly. +.Sh RETURN VALUES +.Fn stack_put +returns 0 on success. +Otherwise the +.Dv struct stack +does not contain space to record additional frames, and a non-zero value is +returned. +.Pp +.Fn stack_save_td_running +returns 0 when the stack capture was successful and a non-zero error number +otherwise. +In particular, +.Er EAGAIN +is returned if the thread was running in user mode at the time that the +capture was attempted, and +.Er EOPNOTSUPP +is returned if the operation is not implemented. .Sh SEE ALSO .Xr ddb 4 , .Xr printf 9 , diff --git a/share/mk/local.meta.sys.mk b/share/mk/local.meta.sys.mk index f927b67..09805dd 100644 --- a/share/mk/local.meta.sys.mk +++ b/share/mk/local.meta.sys.mk @@ -13,11 +13,14 @@ MK_INSTALL_AS_USER= yes .warning MAKEOBJDIRPREFIX not supported; setting MAKEOBJDIR... # put things approximately where they want OBJROOT:=${MAKEOBJDIRPREFIX}${SRCTOP:S,/src,,}/ +MAKEOBJDIRPREFIX= +.export MAKEOBJDIRPREFIX +.endif +.if empty(MAKEOBJDIR) || ${MAKEOBJDIR:M*/*} == "" # OBJTOP set below MAKEOBJDIR=$${.CURDIR:S,$${SRCTOP},$${OBJTOP},} -MAKEOBJDIRPREFIX= # export but do not track -.export-env MAKEOBJDIRPREFIX MAKEOBJDIR +.export-env MAKEOBJDIR # now for our own use MAKEOBJDIR= ${.CURDIR:S,${SRCTOP},${OBJTOP},} .endif diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index fa74eb2..776f90c 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include "opt_hwpmc_hooks.h" #include "opt_isa.h" #include "opt_kdb.h" +#include "opt_stack.h" #include <sys/param.h> #include <sys/bus.h> @@ -91,6 +92,7 @@ PMC_SOFT_DEFINE( , , page_fault, write); #ifdef SMP #include <machine/smp.h> #endif +#include <machine/stack.h> #include <machine/tss.h> #ifdef KDTRACE_HOOKS @@ -202,17 +204,24 @@ trap(struct trapframe *frame) goto out; } -#ifdef HWPMC_HOOKS - /* - * CPU PMCs interrupt using an NMI. If the PMC module is - * active, pass the 'rip' value to the PMC module's interrupt - * handler. A return value of '1' from the handler means that - * the NMI was handled by it and we can return immediately. - */ - if (type == T_NMI && pmc_intr && - (*pmc_intr)(PCPU_GET(cpuid), frame)) - goto out; + if (type == T_NMI) { +#ifdef HWPMC_HOOKS + /* + * CPU PMCs interrupt using an NMI. If the PMC module is + * active, pass the 'rip' value to the PMC module's interrupt + * handler. A non-zero return value from the handler means that + * the NMI was consumed by it and we can return immediately. + */ + if (pmc_intr != NULL && + (*pmc_intr)(PCPU_GET(cpuid), frame) != 0) + goto out; +#endif + +#ifdef STACK + if (stack_nmi_handler(frame) != 0) + goto out; #endif + } if (type == T_MCHK) { mca_intr(); @@ -625,7 +634,6 @@ trap_pfault(frame, usermode) int usermode; { vm_offset_t va; - struct vmspace *vm; vm_map_t map; int rv = 0; vm_prot_t ftype; @@ -687,14 +695,7 @@ trap_pfault(frame, usermode) map = kernel_map; } else { - /* - * This is a fault on non-kernel virtual memory. If either - * p or p->p_vmspace is NULL, then the fault is fatal. - */ - if (p == NULL || (vm = p->p_vmspace) == NULL) - goto nogo; - - map = &vm->vm_map; + map = &p->p_vmspace->vm_map; /* * When accessing a usermode address, kernel must be @@ -729,28 +730,8 @@ trap_pfault(frame, usermode) else ftype = VM_PROT_READ; - if (map != kernel_map) { - /* - * Keep swapout from messing with us during this - * critical time. - */ - PROC_LOCK(p); - ++p->p_lock; - PROC_UNLOCK(p); - - /* Fault in the user page: */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); - - PROC_LOCK(p); - --p->p_lock; - PROC_UNLOCK(p); - } else { - /* - * Don't have to worry about process locking or stacks in the - * kernel. - */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); - } + /* Fault in the page. */ + rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); if (rv == KERN_SUCCESS) { #ifdef HWPMC_HOOKS if (ftype == VM_PROT_READ || ftype == VM_PROT_WRITE) { diff --git a/sys/amd64/include/stack.h b/sys/amd64/include/stack.h index 8297eae..091ae33 100644 --- a/sys/amd64/include/stack.h +++ b/sys/amd64/include/stack.h @@ -1,42 +1,6 @@ -/*- - * Mach Operating System - * Copyright (c) 1991,1990 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - * - * $FreeBSD$ - */ - -#ifndef _MACHINE_STACK_H_ -#define _MACHINE_STACK_H_ - /* - * Stack trace. + * This file is in the public domain. */ +/* $FreeBSD$ */ -struct amd64_frame { - struct amd64_frame *f_frame; - long f_retaddr; - long f_arg0; -}; - -#endif /* !_MACHINE_STACK_H_ */ +#include <x86/stack.h> diff --git a/sys/arm/arm/stack_machdep.c b/sys/arm/arm/stack_machdep.c index 9e68023..6d23be6 100644 --- a/sys/arm/arm/stack_machdep.c +++ b/sys/arm/arm/stack_machdep.c @@ -71,6 +71,13 @@ stack_save_td(struct stack *st, struct thread *td) stack_capture(st, frame); } +int +stack_save_td_running(struct stack *st, struct thread *td) +{ + + return (EOPNOTSUPP); +} + void stack_save(struct stack *st) { diff --git a/sys/arm/arm/trap-v6.c b/sys/arm/arm/trap-v6.c index 09fc0fc..b7b6629 100644 --- a/sys/arm/arm/trap-v6.c +++ b/sys/arm/arm/trap-v6.c @@ -500,28 +500,9 @@ abort_handler(struct trapframe *tf, int prefetch) onfault = pcb->pcb_onfault; pcb->pcb_onfault = NULL; #endif - if (map != kernel_map) { - /* - * Keep swapout from messing with us during this - * critical time. - */ - PROC_LOCK(p); - ++p->p_lock; - PROC_UNLOCK(p); - /* Fault in the user page: */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); - - PROC_LOCK(p); - --p->p_lock; - PROC_UNLOCK(p); - } else { - /* - * Don't have to worry about process locking or stacks in the - * kernel. - */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); - } + /* Fault in the page. */ + rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); #ifdef INVARIANTS pcb->pcb_onfault = onfault; diff --git a/sys/arm/arm/trap.c b/sys/arm/arm/trap.c index 52a5baa..9660286 100644 --- a/sys/arm/arm/trap.c +++ b/sys/arm/arm/trap.c @@ -365,19 +365,8 @@ abort_handler(struct trapframe *tf, int type) onfault = pcb->pcb_onfault; pcb->pcb_onfault = NULL; - if (map != kernel_map) { - PROC_LOCK(p); - p->p_lock++; - PROC_UNLOCK(p); - } error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); pcb->pcb_onfault = onfault; - - if (map != kernel_map) { - PROC_LOCK(p); - p->p_lock--; - PROC_UNLOCK(p); - } if (__predict_true(error == 0)) goto out; fatal_pagefault: @@ -682,20 +671,8 @@ prefetch_abort_handler(struct trapframe *tf) if (pmap_fault_fixup(map->pmap, va, VM_PROT_READ, 1)) goto out; - if (map != kernel_map) { - PROC_LOCK(p); - p->p_lock++; - PROC_UNLOCK(p); - } - error = vm_fault(map, va, VM_PROT_READ | VM_PROT_EXECUTE, VM_FAULT_NORMAL); - if (map != kernel_map) { - PROC_LOCK(p); - p->p_lock--; - PROC_UNLOCK(p); - } - if (__predict_true(error == 0)) goto out; diff --git a/sys/arm64/arm64/copyinout.S b/sys/arm64/arm64/copyinout.S index 56512ec..0982c70 100644 --- a/sys/arm64/arm64/copyinout.S +++ b/sys/arm64/arm64/copyinout.S @@ -95,6 +95,7 @@ END(copyin) */ ENTRY(copyinstr) mov x5, xzr /* count = 0 */ + mov w4, #1 /* If zero return faulure */ cbz x2, 3f /* If len == 0 then skip loop */ adr x6, copyio_fault /* Get the handler address */ @@ -102,17 +103,18 @@ ENTRY(copyinstr) 1: ldrb w4, [x0], #1 /* Load from uaddr */ strb w4, [x1], #1 /* Store in kaddr */ - cbz w4, 2f /* If == 0 then break */ - sub x2, x2, #1 /* len-- */ add x5, x5, #1 /* count++ */ + cbz w4, 2f /* Break when NUL-terminated */ + sub x2, x2, #1 /* len-- */ cbnz x2, 1b 2: SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */ 3: cbz x3, 4f /* Check if done != NULL */ - add x5, x5, #1 /* count++ */ str x5, [x3] /* done = count */ -4: mov x0, xzr /* return 0 */ +4: mov w1, #ENAMETOOLONG /* Load ENAMETOOLONG to return if failed */ + cmp w4, #0 /* Check if we saved the NUL-terminator */ + csel w0, wzr, w1, eq /* If so return success, else failure */ ret END(copyinstr) diff --git a/sys/arm64/arm64/locore.S b/sys/arm64/arm64/locore.S index d424567..c5da907 100644 --- a/sys/arm64/arm64/locore.S +++ b/sys/arm64/arm64/locore.S @@ -246,11 +246,11 @@ drop_to_el1: mrs x2, icc_sre_el2 orr x2, x2, #ICC_SRE_EL2_EN /* Enable access from insecure EL1 */ msr icc_sre_el2, x2 - isb 2: /* Set the address to return to our return address */ msr elr_el2, x30 + isb eret diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c index 578ca59..62fe394 100644 --- a/sys/arm64/arm64/pmap.c +++ b/sys/arm64/arm64/pmap.c @@ -3032,8 +3032,74 @@ pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma) int pmap_mincore(pmap_t pmap, vm_offset_t addr, vm_paddr_t *locked_pa) { + pd_entry_t *l1p, l1; + pd_entry_t *l2p, l2; + pt_entry_t *l3p, l3; + vm_paddr_t pa; + bool managed; + int val; + + PMAP_LOCK(pmap); +retry: + pa = 0; + val = 0; + managed = false; + + l1p = pmap_l1(pmap, addr); + if (l1p == NULL) /* No l1 */ + goto done; + l1 = pmap_load(l1p); + if ((l1 & ATTR_DESCR_MASK) == L1_BLOCK) { + pa = (l1 & ~ATTR_MASK) | (addr & L1_OFFSET); + managed = (l1 & ATTR_SW_MANAGED) == ATTR_SW_MANAGED; + val = MINCORE_SUPER | MINCORE_INCORE; + if (pmap_page_dirty(l1)) + val |= MINCORE_MODIFIED | MINCORE_MODIFIED_OTHER; + if ((l1 & ATTR_AF) == ATTR_AF) + val |= MINCORE_REFERENCED | MINCORE_REFERENCED_OTHER; + goto done; + } + + l2p = pmap_l1_to_l2(l1p, addr); + if (l2p == NULL) /* No l2 */ + goto done; + l2 = pmap_load(l2p); + if ((l2 & ATTR_DESCR_MASK) == L2_BLOCK) { + pa = (l2 & ~ATTR_MASK) | (addr & L2_OFFSET); + managed = (l2 & ATTR_SW_MANAGED) == ATTR_SW_MANAGED; + val = MINCORE_SUPER | MINCORE_INCORE; + if (pmap_page_dirty(l2)) + val |= MINCORE_MODIFIED | MINCORE_MODIFIED_OTHER; + if ((l2 & ATTR_AF) == ATTR_AF) + val |= MINCORE_REFERENCED | MINCORE_REFERENCED_OTHER; + goto done; + } + + l3p = pmap_l2_to_l3(l2p, addr); + if (l3p == NULL) /* No l3 */ + goto done; + l3 = pmap_load(l2p); + if ((l3 & ATTR_DESCR_MASK) == L3_PAGE) { + pa = (l3 & ~ATTR_MASK) | (addr & L3_OFFSET); + managed = (l3 & ATTR_SW_MANAGED) == ATTR_SW_MANAGED; + val = MINCORE_INCORE; + if (pmap_page_dirty(l3)) + val |= MINCORE_MODIFIED | MINCORE_MODIFIED_OTHER; + if ((l3 & ATTR_AF) == ATTR_AF) + val |= MINCORE_REFERENCED | MINCORE_REFERENCED_OTHER; + } + +done: + if ((val & (MINCORE_MODIFIED_OTHER | MINCORE_REFERENCED_OTHER)) != + (MINCORE_MODIFIED_OTHER | MINCORE_REFERENCED_OTHER) && managed) { + /* Ensure that "PHYS_TO_VM_PAGE(pa)->object" doesn't change. */ + if (vm_page_pa_tryrelock(pmap, pa, locked_pa)) + goto retry; + } else + PA_UNLOCK_COND(*locked_pa); + PMAP_UNLOCK(pmap); - panic("ARM64TODO: pmap_mincore"); + return (val); } void diff --git a/sys/arm64/arm64/stack_machdep.c b/sys/arm64/arm64/stack_machdep.c index 72a9ab9..0212c63 100644 --- a/sys/arm64/arm64/stack_machdep.c +++ b/sys/arm64/arm64/stack_machdep.c @@ -72,6 +72,13 @@ stack_save_td(struct stack *st, struct thread *td) stack_capture(st, &frame); } +int +stack_save_td_running(struct stack *st, struct thread *td) +{ + + return (EOPNOTSUPP); +} + void stack_save(struct stack *st) { diff --git a/sys/arm64/arm64/swtch.S b/sys/arm64/arm64/swtch.S index fbffaed..bc2e521 100644 --- a/sys/arm64/arm64/swtch.S +++ b/sys/arm64/arm64/swtch.S @@ -160,17 +160,18 @@ ENTRY(cpu_switch) dsb sy isb - /* Release the old thread */ + /* + * Release the old thread. This doesn't need to be a store-release + * as the above dsb instruction will provide release semantics. + */ str x2, [x0, #TD_LOCK] #if defined(SCHED_ULE) && defined(SMP) /* Read the value in blocked_lock */ ldr x0, =_C_LABEL(blocked_lock) - ldr x1, [x0] - /* Load curthread */ - ldr x2, [x18, #PC_CURTHREAD] + ldr x2, [x0] 1: - ldr x3, [x2, #TD_LOCK] - cmp x3, x1 + ldar x3, [x1, #TD_LOCK] + cmp x3, x2 b.eq 1b #endif diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c index 249322e..2a3cfb9 100644 --- a/sys/arm64/arm64/trap.c +++ b/sys/arm64/arm64/trap.c @@ -190,29 +190,8 @@ data_abort(struct trapframe *frame, uint64_t esr, int lower) va = trunc_page(far); ftype = ((esr >> 6) & 1) ? VM_PROT_READ | VM_PROT_WRITE : VM_PROT_READ; - if (map != kernel_map) { - /* - * Keep swapout from messing with us during this - * critical time. - */ - PROC_LOCK(p); - ++p->p_lock; - PROC_UNLOCK(p); - - /* Fault in the user page: */ - error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); - - PROC_LOCK(p); - --p->p_lock; - PROC_UNLOCK(p); - } else { - /* - * Don't have to worry about process locking or stacks in the - * kernel. - */ - error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); - } - + /* Fault in the page. */ + error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); if (error != KERN_SUCCESS) { if (lower) { sig = SIGSEGV; diff --git a/sys/boot/efi/loader/arch/amd64/framebuffer.c b/sys/boot/efi/loader/arch/amd64/framebuffer.c index bd9b5eb..9a8dfdb 100644 --- a/sys/boot/efi/loader/arch/amd64/framebuffer.c +++ b/sys/boot/efi/loader/arch/amd64/framebuffer.c @@ -269,8 +269,10 @@ efifb_from_uga(struct efi_fb *efifb, EFI_UGA_DRAW_PROTOCOL *uga) EFI_PCI_IO_PROTOCOL *pciio; char *ev, *p; EFI_STATUS status; - ssize_t ofs; - uint32_t np, horiz, vert, depth, refresh; + ssize_t offset; + uint64_t fbaddr, fbsize; + uint32_t horiz, vert, stride; + uint32_t np, depth, refresh; status = uga->GetMode(uga, &horiz, &vert, &depth, &refresh); if (EFI_ERROR(status)) @@ -285,6 +287,63 @@ efifb_from_uga(struct efi_fb *efifb, EFI_UGA_DRAW_PROTOCOL *uga) efifb_mask_from_pixfmt(efifb, PixelBlueGreenRedReserved8BitPerColor, NULL); + /* pciio can be NULL on return! */ + pciio = efifb_uga_get_pciio(); + + /* Try to find the frame buffer. */ + status = efifb_uga_locate_framebuffer(pciio, &efifb->fb_addr, + &efifb->fb_size); + if (EFI_ERROR(status)) { + efifb->fb_addr = 0; + efifb->fb_size = 0; + } + + /* + * There's no reliable way to detect the frame buffer or the + * offset within the frame buffer of the visible region, nor + * the stride. Our only option is to look at the system and + * fill in the blanks based on that. Luckily, UGA was mostly + * only used on Apple hardware. + */ + offset = -1; + ev = getenv("smbios.system.maker"); + if (ev != NULL && !strcmp(ev, "Apple Inc.")) { + ev = getenv("smbios.system.product"); + if (ev != NULL && !strcmp(ev, "iMac7,1")) { + /* These are the expected values we should have. */ + horiz = 1680; + vert = 1050; + fbaddr = 0xc0000000; + /* These are the missing bits. */ + offset = 0x10000; + stride = 1728; + } else if (ev != NULL && !strcmp(ev, "MacBook3,1")) { + /* These are the expected values we should have. */ + horiz = 1280; + vert = 800; + fbaddr = 0xc0000000; + /* These are the missing bits. */ + offset = 0x0; + stride = 2048; + } + } + + /* + * If this is hardware we know, make sure that it looks familiar + * before we accept our hardcoded values. + */ + if (offset >= 0 && efifb->fb_width == horiz && + efifb->fb_height == vert && efifb->fb_addr == fbaddr) { + efifb->fb_addr += offset; + efifb->fb_size -= offset; + efifb->fb_stride = stride; + return (0); + } else if (offset >= 0) { + printf("Hardware make/model known, but graphics not " + "as expected.\n"); + printf("Console may not work!\n"); + } + /* * The stride is equal or larger to the width. Often it's the * next larger power of two. We'll start with that... @@ -298,16 +357,11 @@ efifb_from_uga(struct efi_fb *efifb, EFI_UGA_DRAW_PROTOCOL *uga) } } while (np); - /* pciio can be NULL on return! */ - pciio = efifb_uga_get_pciio(); - - ev = getenv("uga_framebuffer"); + ev = getenv("hw.efifb.address"); if (ev == NULL) { - /* Try to find the frame buffer. */ - status = efifb_uga_locate_framebuffer(pciio, &efifb->fb_addr, - &efifb->fb_size); - if (EFI_ERROR(status)) { - printf("Please set uga_framebuffer!\n"); + if (efifb->fb_addr == 0) { + printf("Please set hw.efifb.address and " + "hw.efifb.stride.\n"); return (1); } @@ -328,30 +382,30 @@ efifb_from_uga(struct efi_fb *efifb, EFI_UGA_DRAW_PROTOCOL *uga) * to not appear to hang when we can't read from the * frame buffer. */ - ofs = efifb_uga_find_pixel(uga, 0, pciio, efifb->fb_addr, + offset = efifb_uga_find_pixel(uga, 0, pciio, efifb->fb_addr, efifb->fb_size >> 8); - if (ofs == -1) { + if (offset == -1) { printf("Unable to reliably detect frame buffer.\n"); - } else if (ofs > 0) { - efifb->fb_addr += ofs; - efifb->fb_size -= ofs; + } else if (offset > 0) { + efifb->fb_addr += offset; + efifb->fb_size -= offset; } } else { - ofs = 0; + offset = 0; efifb->fb_size = efifb->fb_height * efifb->fb_stride * 4; efifb->fb_addr = strtoul(ev, &p, 0); if (*p != '\0') return (1); } - ev = getenv("uga_stride"); + ev = getenv("hw.efifb.stride"); if (ev == NULL) { - if (pciio != NULL && ofs != -1) { + if (pciio != NULL && offset != -1) { /* Determine the stride. */ - ofs = efifb_uga_find_pixel(uga, 1, pciio, + offset = efifb_uga_find_pixel(uga, 1, pciio, efifb->fb_addr, horiz * 8); - if (ofs != -1) - efifb->fb_stride = ofs >> 2; + if (offset != -1) + efifb->fb_stride = offset >> 2; } else { printf("Unable to reliably detect the stride.\n"); } diff --git a/sys/cam/ctl/README.ctl.txt b/sys/cam/ctl/README.ctl.txt index b3b08f5..dd38cb5 100644 --- a/sys/cam/ctl/README.ctl.txt +++ b/sys/cam/ctl/README.ctl.txt @@ -43,12 +43,9 @@ Features: - Persistent reservation support - Mode sense/select support - Error injection support - - High Availability support (1) + - High Availability support - All I/O handled in-kernel, no userland context switch overhead. -(1) HA Support is just an API stub, and needs much more to be fully - functional. See the to-do list below. - Configuring and Running CTL: =========================== @@ -245,27 +242,6 @@ To Do List: another data structure in the stack, more memory allocations, etc. This will also require changes to the CAM CCB structure to support CTL. - - Full-featured High Availability support. The HA API that is in ctl_ha.h - is essentially a renamed version of Copan's HA API. There is no - substance to it, but it remains in CTL to show what needs to be done to - implement active/active HA from a CTL standpoint. The things that would - need to be done include: - - A kernel level software API for message passing as well as DMA - between at least two nodes. - - Hardware support and drivers for inter-node communication. This - could be as simples as ethernet hardware and drivers. - - A "supervisor", or startup framework to control and coordinate - HA startup, failover (going from active/active to single mode), - and failback (going from single mode to active/active). - - HA support in other components of the stack. The goal behind HA - is that one node can fail and another node can seamlessly take - over handling I/O requests. This requires support from pretty - much every component in the storage stack, from top to bottom. - CTL is one piece of it, but you also need support in the RAID - stack/filesystem/backing store. You also need full configuration - mirroring, and all peer nodes need to be able to talk to the - underlying storage hardware. - Code Roadmap: ============ @@ -365,11 +341,11 @@ This is a CTL frontend port that is also a CAM SIM. The idea is that this frontend allows for using CTL without any target-capable hardware. So any LUNs you create in CTL are visible via this port. +ctl_ha.c: ctl_ha.h: -------- -This is a stubbed-out High Availability API. See the comments in the -header and the description of what is needed as far as HA support above. +This is a High Availability API and TCP-based interlink implementation. ctl_io.h: -------- diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c index 073f338..ddac04f 100644 --- a/sys/cam/ctl/ctl.c +++ b/sys/cam/ctl/ctl.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2003-2009 Silicon Graphics International Corp. * Copyright (c) 2012 The FreeBSD Foundation + * Copyright (c) 2015 Alexander Motin <mav@FreeBSD.org> * All rights reserved. * * Portions of this software were developed by Edward Tomasz Napierala @@ -84,25 +85,6 @@ __FBSDID("$FreeBSD$"); struct ctl_softc *control_softc = NULL; /* - * Size and alignment macros needed for Copan-specific HA hardware. These - * can go away when the HA code is re-written, and uses busdma for any - * hardware. - */ -#define CTL_ALIGN_8B(target, source, type) \ - if (((uint32_t)source & 0x7) != 0) \ - target = (type)(source + (0x8 - ((uint32_t)source & 0x7)));\ - else \ - target = (type)source; - -#define CTL_SIZE_8B(target, size) \ - if ((size & 0x7) != 0) \ - target = size + (0x8 - (size & 0x7)); \ - else \ - target = size; - -#define CTL_ALIGN_8B_MARGIN 16 - -/* * Template mode pages. */ @@ -351,12 +333,6 @@ const static struct ctl_logical_block_provisioning_page lbp_page_changeable = {{ } }; -/* - * XXX KDM move these into the softc. - */ -static int rcv_sync_msg; -static uint8_t ctl_pause_rtr; - SYSCTL_NODE(_kern_cam, OID_AUTO, ctl, CTLFLAG_RD, 0, "CAM Target Layer"); static int worker_threads = -1; SYSCTL_INT(_kern_cam_ctl, OID_AUTO, worker_threads, CTLFLAG_RDTUN, @@ -373,11 +349,10 @@ SYSCTL_INT(_kern_cam_ctl, OID_AUTO, debug, CTLFLAG_RWTUN, */ #define SCSI_EVPD_NUM_SUPPORTED_PAGES 10 -#ifdef notyet static void ctl_isc_event_handler(ctl_ha_channel chanel, ctl_ha_event event, int param); static void ctl_copy_sense_data(union ctl_ha_msg *src, union ctl_io *dest); -#endif +static void ctl_copy_sense_data_back(union ctl_io *src, union ctl_ha_msg *dest); static int ctl_init(void); void ctl_shutdown(void); static int ctl_open(struct cdev *dev, int flags, int fmt, struct thread *td); @@ -393,10 +368,6 @@ static int ctl_alloc_lun(struct ctl_softc *ctl_softc, struct ctl_lun *lun, static int ctl_free_lun(struct ctl_lun *lun); static void ctl_create_lun(struct ctl_be_lun *be_lun); static struct ctl_port * ctl_io_port(struct ctl_io_hdr *io_hdr); -/** -static void ctl_failover_change_pages(struct ctl_softc *softc, - struct ctl_scsiio *ctsio, int master); -**/ static int ctl_do_mode_select(union ctl_io *io); static int ctl_pro_preempt(struct ctl_softc *softc, struct ctl_lun *lun, @@ -433,10 +404,11 @@ static int ctl_check_blocked(struct ctl_lun *lun); static int ctl_scsiio_lun_check(struct ctl_lun *lun, const struct ctl_cmd_entry *entry, struct ctl_scsiio *ctsio); -//static int ctl_check_rtr(union ctl_io *pending_io, struct ctl_softc *softc); -#ifdef notyet -static void ctl_failover(void); -#endif +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, @@ -475,9 +447,7 @@ static void ctl_work_thread(void *arg); static void ctl_enqueue_incoming(union ctl_io *io); static void ctl_enqueue_rtr(union ctl_io *io); static void ctl_enqueue_done(union ctl_io *io); -#ifdef notyet static void ctl_enqueue_isc(union ctl_io *io); -#endif static const struct ctl_cmd_entry * ctl_get_cmd_entry(struct ctl_scsiio *ctsio, int *sa); static const struct ctl_cmd_entry * @@ -485,6 +455,11 @@ static const struct ctl_cmd_entry * static int ctl_cmd_applicable(uint8_t lun_type, const struct ctl_cmd_entry *entry); +static uint64_t ctl_get_prkey(struct ctl_lun *lun, uint32_t residx); +static void ctl_clr_prkey(struct ctl_lun *lun, uint32_t residx); +static void ctl_alloc_prkey(struct ctl_lun *lun, uint32_t residx); +static void ctl_set_prkey(struct ctl_lun *lun, uint32_t residx, uint64_t key); + /* * Load the serialization table. This isn't very pretty, but is probably * the easiest way to do it. @@ -517,7 +492,11 @@ static moduledata_t ctl_moduledata = { DECLARE_MODULE(ctl, ctl_moduledata, SI_SUB_CONFIGURE, SI_ORDER_THIRD); MODULE_VERSION(ctl, 1); -#ifdef notyet +static struct ctl_frontend ha_frontend = +{ + .name = "ha", +}; + static void ctl_isc_handler_finish_xfer(struct ctl_softc *ctl_softc, union ctl_ha_msg *msg_info) @@ -539,7 +518,7 @@ ctl_isc_handler_finish_xfer(struct ctl_softc *ctl_softc, ctsio->sense_residual = msg_info->scsi.sense_residual; ctsio->residual = msg_info->scsi.residual; memcpy(&ctsio->sense_data, &msg_info->scsi.sense_data, - sizeof(ctsio->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); @@ -558,39 +537,327 @@ ctl_isc_handler_finish_ser_only(struct ctl_softc *ctl_softc, } ctsio = &msg_info->hdr.serializing_sc->scsiio; -#if 0 - /* - * Attempt to catch the situation where an I/O has - * been freed, and we're using it again. - */ - if (ctsio->io_hdr.io_type == 0xff) { - union ctl_io *tmp_io; - tmp_io = (union ctl_io *)ctsio; - printf("%s: %p use after free!\n", __func__, - ctsio); - printf("%s: type %d msg %d cdb %x iptl: " - "%d:%d:%d:%d tag 0x%04x " - "flag %#x status %x\n", - __func__, - tmp_io->io_hdr.io_type, - tmp_io->io_hdr.msg_type, - tmp_io->scsiio.cdb[0], - tmp_io->io_hdr.nexus.initid.id, - tmp_io->io_hdr.nexus.targ_port, - tmp_io->io_hdr.nexus.targ_target.id, - tmp_io->io_hdr.nexus.targ_lun, - (tmp_io->io_hdr.io_type == - CTL_IO_TASK) ? - tmp_io->taskio.tag_num : - tmp_io->scsiio.tag_num, - tmp_io->io_hdr.flags, - tmp_io->io_hdr.status); - } -#endif ctsio->io_hdr.msg_type = CTL_MSG_FINISH_IO; ctl_enqueue_isc((union ctl_io *)ctsio); } +void +ctl_isc_announce_lun(struct ctl_lun *lun) +{ + struct ctl_softc *softc = lun->ctl_softc; + union ctl_ha_msg *msg; + struct ctl_ha_msg_lun_pr_key pr_key; + int i, k; + + if (softc->ha_link != CTL_HA_LINK_ONLINE) + return; + mtx_lock(&lun->lun_lock); + i = sizeof(msg->lun); + if (lun->lun_devid) + i += lun->lun_devid->len; + i += sizeof(pr_key) * lun->pr_key_count; +alloc: + mtx_unlock(&lun->lun_lock); + msg = malloc(i, M_CTL, M_WAITOK); + mtx_lock(&lun->lun_lock); + k = sizeof(msg->lun); + if (lun->lun_devid) + k += lun->lun_devid->len; + k += sizeof(pr_key) * lun->pr_key_count; + if (i < k) { + free(msg, M_CTL); + i = k; + goto alloc; + } + bzero(&msg->lun, sizeof(msg->lun)); + msg->hdr.msg_type = CTL_MSG_LUN_SYNC; + msg->hdr.nexus.targ_lun = lun->lun; + msg->hdr.nexus.targ_mapped_lun = lun->lun; + msg->lun.flags = lun->flags; + msg->lun.pr_generation = lun->PRGeneration; + msg->lun.pr_res_idx = lun->pr_res_idx; + msg->lun.pr_res_type = lun->res_type; + msg->lun.pr_key_count = lun->pr_key_count; + i = 0; + if (lun->lun_devid) { + msg->lun.lun_devid_len = lun->lun_devid->len; + memcpy(&msg->lun.data[i], lun->lun_devid->data, + msg->lun.lun_devid_len); + i += msg->lun.lun_devid_len; + } + for (k = 0; k < CTL_MAX_INITIATORS; k++) { + if ((pr_key.pr_key = ctl_get_prkey(lun, k)) == 0) + continue; + pr_key.pr_iid = k; + memcpy(&msg->lun.data[i], &pr_key, sizeof(pr_key)); + i += sizeof(pr_key); + } + mtx_unlock(&lun->lun_lock); + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg->port, sizeof(msg->port) + i, + M_WAITOK); + free(msg, M_CTL); +} + +void +ctl_isc_announce_port(struct ctl_port *port) +{ + struct ctl_softc *softc = control_softc; + union ctl_ha_msg *msg; + int i; + + if (port->targ_port < softc->port_min || + port->targ_port >= softc->port_max || + softc->ha_link != CTL_HA_LINK_ONLINE) + return; + i = sizeof(msg->port) + strlen(port->port_name) + 1; + if (port->lun_map) + i += sizeof(uint32_t) * CTL_MAX_LUNS; + if (port->port_devid) + i += port->port_devid->len; + if (port->target_devid) + i += port->target_devid->len; + msg = malloc(i, M_CTL, M_WAITOK); + bzero(&msg->port, sizeof(msg->port)); + msg->hdr.msg_type = CTL_MSG_PORT_SYNC; + msg->hdr.nexus.targ_port = port->targ_port; + msg->port.port_type = port->port_type; + msg->port.physical_port = port->physical_port; + msg->port.virtual_port = port->virtual_port; + msg->port.status = port->status; + i = 0; + msg->port.name_len = sprintf(&msg->port.data[i], + "%d:%s", softc->ha_id, port->port_name) + 1; + i += msg->port.name_len; + if (port->lun_map) { + msg->port.lun_map_len = sizeof(uint32_t) * CTL_MAX_LUNS; + memcpy(&msg->port.data[i], port->lun_map, + msg->port.lun_map_len); + i += msg->port.lun_map_len; + } + if (port->port_devid) { + msg->port.port_devid_len = port->port_devid->len; + memcpy(&msg->port.data[i], port->port_devid->data, + msg->port.port_devid_len); + i += msg->port.port_devid_len; + } + if (port->target_devid) { + msg->port.target_devid_len = port->target_devid->len; + memcpy(&msg->port.data[i], port->target_devid->data, + msg->port.target_devid_len); + i += msg->port.target_devid_len; + } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg->port, sizeof(msg->port) + i, + M_WAITOK); + free(msg, M_CTL); +} + +static void +ctl_isc_ha_link_up(struct ctl_softc *softc) +{ + struct ctl_port *port; + struct ctl_lun *lun; + + STAILQ_FOREACH(port, &softc->port_list, links) + ctl_isc_announce_port(port); + STAILQ_FOREACH(lun, &softc->lun_list, links) + ctl_isc_announce_lun(lun); +} + +static void +ctl_isc_ha_link_down(struct ctl_softc *softc) +{ + struct ctl_port *port; + struct ctl_lun *lun; + union ctl_io *io; + + mtx_lock(&softc->ctl_lock); + STAILQ_FOREACH(lun, &softc->lun_list, links) { + mtx_lock(&lun->lun_lock); + lun->flags &= ~CTL_LUN_PEER_SC_PRIMARY; + mtx_unlock(&lun->lun_lock); + + mtx_unlock(&softc->ctl_lock); + io = ctl_alloc_io(softc->othersc_pool); + mtx_lock(&softc->ctl_lock); + ctl_zero_io(io); + io->io_hdr.msg_type = CTL_MSG_FAILOVER; + io->io_hdr.nexus.targ_mapped_lun = lun->lun; + ctl_enqueue_isc(io); + } + + STAILQ_FOREACH(port, &softc->port_list, links) { + if (port->targ_port >= softc->port_min && + port->targ_port < softc->port_max) + continue; + port->status &= ~CTL_PORT_STATUS_ONLINE; + } + mtx_unlock(&softc->ctl_lock); +} + +static void +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); + + if (msg->hdr.nexus.targ_lun < CTL_MAX_LUNS && + (lun = softc->ctl_luns[msg->hdr.nexus.targ_lun]) != NULL) { + if (msg->ua.ua_all) { + if (msg->ua.ua_set) + ctl_est_ua_all(lun, iid, msg->ua.ua_type); + else + ctl_clr_ua_all(lun, iid, msg->ua.ua_type); + } else { + if (msg->ua.ua_set) + ctl_est_ua(lun, iid, msg->ua.ua_type); + else + ctl_clr_ua(lun, iid, msg->ua.ua_type); + } + } +} + +static void +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; + + 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)); + } 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); + } + } + + 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); + } + } +} + +static void +ctl_isc_port_sync(struct ctl_softc *softc, union ctl_ha_msg *msg, int len) +{ + struct ctl_port *port; + int i, new; + + port = softc->ctl_ports[msg->hdr.nexus.targ_port]; + if (port == NULL) { + CTL_DEBUG_PRINT(("%s: New port %d\n", __func__, + msg->hdr.nexus.targ_port)); + new = 1; + port = malloc(sizeof(*port), M_CTL, M_WAITOK | M_ZERO); + port->frontend = &ha_frontend; + port->targ_port = msg->hdr.nexus.targ_port; + } else if (port->frontend == &ha_frontend) { + CTL_DEBUG_PRINT(("%s: Updated port %d\n", __func__, + msg->hdr.nexus.targ_port)); + new = 0; + } else { + printf("%s: Received conflicting HA port %d\n", + __func__, msg->hdr.nexus.targ_port); + return; + } + port->port_type = msg->port.port_type; + port->physical_port = msg->port.physical_port; + port->virtual_port = msg->port.virtual_port; + port->status = msg->port.status; + i = 0; + free(port->port_name, M_CTL); + port->port_name = strndup(&msg->port.data[i], msg->port.name_len, + M_CTL); + i += msg->port.name_len; + if (msg->port.lun_map_len != 0) { + if (port->lun_map == NULL) + port->lun_map = malloc(sizeof(uint32_t) * CTL_MAX_LUNS, + M_CTL, M_WAITOK); + memcpy(port->lun_map, &msg->port.data[i], + sizeof(uint32_t) * CTL_MAX_LUNS); + i += msg->port.lun_map_len; + } else { + free(port->lun_map, M_CTL); + port->lun_map = NULL; + } + if (msg->port.port_devid_len != 0) { + if (port->port_devid == NULL || + port->port_devid->len != msg->port.port_devid_len) { + free(port->port_devid, M_CTL); + port->port_devid = malloc(sizeof(struct ctl_devid) + + msg->port.port_devid_len, M_CTL, M_WAITOK); + } + memcpy(port->port_devid->data, &msg->port.data[i], + msg->port.port_devid_len); + port->port_devid->len = msg->port.port_devid_len; + i += msg->port.port_devid_len; + } else { + free(port->port_devid, M_CTL); + port->port_devid = NULL; + } + if (msg->port.target_devid_len != 0) { + if (port->target_devid == NULL || + port->target_devid->len != msg->port.target_devid_len) { + free(port->target_devid, M_CTL); + port->target_devid = malloc(sizeof(struct ctl_devid) + + msg->port.target_devid_len, M_CTL, M_WAITOK); + } + memcpy(port->target_devid->data, &msg->port.data[i], + msg->port.target_devid_len); + port->target_devid->len = msg->port.target_devid_len; + i += msg->port.target_devid_len; + } else { + free(port->port_devid, M_CTL); + port->port_devid = NULL; + } + if (new) { + if (ctl_port_register(port) != 0) { + printf("%s: ctl_port_register() failed with error\n", + __func__); + } + } +} + /* * ISC (Inter Shelf Communication) event handler. Events from the HA * subsystem come in here. @@ -604,54 +871,33 @@ ctl_isc_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param) ctl_ha_status isc_status; softc = control_softc; - io = NULL; - - -#if 0 - printf("CTL: Isc Msg event %d\n", event); -#endif + CTL_DEBUG_PRINT(("CTL: Isc Msg event %d\n", event)); if (event == CTL_HA_EVT_MSG_RECV) { - union ctl_ha_msg msg_info; + union ctl_ha_msg *msg, msgbuf; - isc_status = ctl_ha_msg_recv(CTL_HA_CHAN_CTL, &msg_info, - sizeof(msg_info), /*wait*/ 0); -#if 0 - printf("CTL: msg_type %d\n", msg_info.msg_type); -#endif - if (isc_status != 0) { - printf("Error receiving message, status = %d\n", - isc_status); + if (param > sizeof(msgbuf)) + msg = malloc(param, M_CTL, M_WAITOK); + else + msg = &msgbuf; + isc_status = ctl_ha_msg_recv(CTL_HA_CHAN_CTL, msg, param, + M_WAITOK); + if (isc_status != CTL_HA_STATUS_SUCCESS) { + printf("%s: Error receiving message: %d\n", + __func__, isc_status); + if (msg != &msgbuf) + free(msg, M_CTL); return; } - switch (msg_info.hdr.msg_type) { + CTL_DEBUG_PRINT(("CTL: msg_type %d\n", msg->msg_type)); + switch (msg->hdr.msg_type) { case CTL_MSG_SERIALIZE: -#if 0 - printf("Serialize\n"); -#endif - io = ctl_alloc_io_nowait(softc->othersc_pool); - if (io == NULL) { - printf("ctl_isc_event_handler: can't allocate " - "ctl_io!\n"); - /* Bad Juju */ - /* Need to set busy and send msg back */ - msg_info.hdr.msg_type = CTL_MSG_BAD_JUJU; - msg_info.hdr.status = CTL_SCSI_ERROR; - msg_info.scsi.scsi_status = SCSI_STATUS_BUSY; - msg_info.scsi.sense_len = 0; - if (ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, - sizeof(msg_info), 0) > CTL_HA_STATUS_SUCCESS){ - } - goto bailout; - } + io = ctl_alloc_io(softc->othersc_pool); ctl_zero_io(io); - // populate ctsio from msg_info + // populate ctsio from msg io->io_hdr.io_type = CTL_IO_SCSI; io->io_hdr.msg_type = CTL_MSG_SERIALIZE; - io->io_hdr.original_sc = msg_info.hdr.original_sc; -#if 0 - printf("pOrig %x\n", (int)msg_info.original_sc); -#endif + io->io_hdr.original_sc = msg->hdr.original_sc; io->io_hdr.flags |= CTL_FLAG_FROM_OTHER_SC | CTL_FLAG_IO_ACTIVE; /* @@ -661,19 +907,23 @@ ctl_isc_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param) * * XXX KDM add another flag that is more specific. */ - if (softc->ha_mode == CTL_HA_MODE_SER_ONLY) + if (softc->ha_mode != CTL_HA_MODE_XFER) io->io_hdr.flags |= CTL_FLAG_INT_COPY; - io->io_hdr.nexus = msg_info.hdr.nexus; + io->io_hdr.nexus = msg->hdr.nexus; #if 0 - printf("targ %d, port %d, iid %d, lun %d\n", - io->io_hdr.nexus.targ_target.id, + printf("port %u, iid %u, lun %u\n", io->io_hdr.nexus.targ_port, - io->io_hdr.nexus.initid.id, + io->io_hdr.nexus.initid, io->io_hdr.nexus.targ_lun); #endif - io->scsiio.tag_num = msg_info.scsi.tag_num; - io->scsiio.tag_type = msg_info.scsi.tag_type; - memcpy(io->scsiio.cdb, msg_info.scsi.cdb, + io->scsiio.tag_num = msg->scsi.tag_num; + io->scsiio.tag_type = msg->scsi.tag_type; +#ifdef CTL_TIME_IO + io->io_hdr.start_time = time_uptime; + getbintime(&io->io_hdr.start_bt); +#endif /* CTL_TIME_IO */ + io->scsiio.cdb_len = msg->scsi.cdb_len; + memcpy(io->scsiio.cdb, msg->scsi.cdb, CTL_MAX_CDBLEN); if (softc->ha_mode == CTL_HA_MODE_XFER) { const struct ctl_cmd_entry *entry; @@ -691,7 +941,7 @@ ctl_isc_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param) struct ctl_sg_entry *sgl; int i, j; - io = msg_info.hdr.original_sc; + io = msg->hdr.original_sc; if (io == NULL) { printf("%s: original_sc == NULL!\n", __func__); /* XXX KDM do something here */ @@ -703,97 +953,66 @@ ctl_isc_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param) * Keep track of this, we need to send it back over * when the datamove is complete. */ - io->io_hdr.serializing_sc = msg_info.hdr.serializing_sc; - - if (msg_info.dt.sg_sequence == 0) { - /* - * XXX KDM we use the preallocated S/G list - * here, but we'll need to change this to - * dynamic allocation if we need larger S/G - * lists. - */ - if (msg_info.dt.kern_sg_entries > - sizeof(io->io_hdr.remote_sglist) / - sizeof(io->io_hdr.remote_sglist[0])) { - printf("%s: number of S/G entries " - "needed %u > allocated num %zd\n", - __func__, - msg_info.dt.kern_sg_entries, - sizeof(io->io_hdr.remote_sglist)/ - sizeof(io->io_hdr.remote_sglist[0])); - - /* - * XXX KDM send a message back to - * the other side to shut down the - * DMA. The error will come back - * through via the normal channel. - */ - break; - } - sgl = io->io_hdr.remote_sglist; - memset(sgl, 0, - sizeof(io->io_hdr.remote_sglist)); + io->io_hdr.serializing_sc = msg->hdr.serializing_sc; + + if (msg->dt.sg_sequence == 0) { + i = msg->dt.kern_sg_entries + + io->scsiio.kern_data_len / + CTL_HA_DATAMOVE_SEGMENT + 1; + sgl = malloc(sizeof(*sgl) * i, M_CTL, + M_WAITOK | M_ZERO); + io->io_hdr.remote_sglist = sgl; + io->io_hdr.local_sglist = + &sgl[msg->dt.kern_sg_entries]; io->scsiio.kern_data_ptr = (uint8_t *)sgl; io->scsiio.kern_sg_entries = - msg_info.dt.kern_sg_entries; + msg->dt.kern_sg_entries; io->scsiio.rem_sg_entries = - msg_info.dt.kern_sg_entries; + msg->dt.kern_sg_entries; io->scsiio.kern_data_len = - msg_info.dt.kern_data_len; + msg->dt.kern_data_len; io->scsiio.kern_total_len = - msg_info.dt.kern_total_len; + msg->dt.kern_total_len; io->scsiio.kern_data_resid = - msg_info.dt.kern_data_resid; + msg->dt.kern_data_resid; io->scsiio.kern_rel_offset = - msg_info.dt.kern_rel_offset; - /* - * Clear out per-DMA flags. - */ - io->io_hdr.flags &= ~CTL_FLAG_RDMA_MASK; - /* - * Add per-DMA flags that are set for this - * particular DMA request. - */ - io->io_hdr.flags |= msg_info.dt.flags & - CTL_FLAG_RDMA_MASK; + msg->dt.kern_rel_offset; + io->io_hdr.flags &= ~CTL_FLAG_BUS_ADDR; + io->io_hdr.flags |= msg->dt.flags & + CTL_FLAG_BUS_ADDR; } else sgl = (struct ctl_sg_entry *) io->scsiio.kern_data_ptr; - for (i = msg_info.dt.sent_sg_entries, j = 0; - i < (msg_info.dt.sent_sg_entries + - msg_info.dt.cur_sg_entries); i++, j++) { - sgl[i].addr = msg_info.dt.sg_list[j].addr; - sgl[i].len = msg_info.dt.sg_list[j].len; + for (i = msg->dt.sent_sg_entries, j = 0; + i < (msg->dt.sent_sg_entries + + msg->dt.cur_sg_entries); i++, j++) { + sgl[i].addr = msg->dt.sg_list[j].addr; + sgl[i].len = msg->dt.sg_list[j].len; #if 0 printf("%s: L: %p,%d -> %p,%d j=%d, i=%d\n", __func__, - msg_info.dt.sg_list[j].addr, - msg_info.dt.sg_list[j].len, + msg->dt.sg_list[j].addr, + msg->dt.sg_list[j].len, sgl[i].addr, sgl[i].len, j, i); #endif } -#if 0 - memcpy(&sgl[msg_info.dt.sent_sg_entries], - msg_info.dt.sg_list, - sizeof(*sgl) * msg_info.dt.cur_sg_entries); -#endif /* * If this is the last piece of the I/O, we've got * the full S/G list. Queue processing in the thread. * Otherwise wait for the next piece. */ - if (msg_info.dt.sg_last != 0) + if (msg->dt.sg_last != 0) ctl_enqueue_isc(io); break; } /* Performed on the Serializing (primary) SC, XFER mode only */ case CTL_MSG_DATAMOVE_DONE: { - if (msg_info.hdr.serializing_sc == NULL) { + if (msg->hdr.serializing_sc == NULL) { printf("%s: serializing_sc == NULL!\n", __func__); /* XXX KDM now what? */ @@ -804,33 +1023,35 @@ ctl_isc_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param) * there was a failure, so we can return status * back to the initiator. */ - io = msg_info.hdr.serializing_sc; + io = msg->hdr.serializing_sc; io->io_hdr.msg_type = CTL_MSG_DATAMOVE_DONE; - io->io_hdr.status = msg_info.hdr.status; - io->scsiio.scsi_status = msg_info.scsi.scsi_status; - io->scsiio.sense_len = msg_info.scsi.sense_len; - io->scsiio.sense_residual =msg_info.scsi.sense_residual; - io->io_hdr.port_status = msg_info.scsi.fetd_status; - io->scsiio.residual = msg_info.scsi.residual; - memcpy(&io->scsiio.sense_data,&msg_info.scsi.sense_data, - sizeof(io->scsiio.sense_data)); + io->io_hdr.flags |= CTL_FLAG_IO_ACTIVE; + io->io_hdr.port_status = msg->scsi.fetd_status; + io->scsiio.residual = msg->scsi.residual; + if (msg->hdr.status != CTL_STATUS_NONE) { + io->io_hdr.status = msg->hdr.status; + io->scsiio.scsi_status = msg->scsi.scsi_status; + io->scsiio.sense_len = msg->scsi.sense_len; + io->scsiio.sense_residual =msg->scsi.sense_residual; + memcpy(&io->scsiio.sense_data, + &msg->scsi.sense_data, + msg->scsi.sense_len); + } ctl_enqueue_isc(io); break; } /* Preformed on Originating SC, SER_ONLY mode */ case CTL_MSG_R2R: - io = msg_info.hdr.original_sc; + io = msg->hdr.original_sc; if (io == NULL) { - printf("%s: Major Bummer\n", __func__); - return; - } else { -#if 0 - printf("pOrig %x\n",(int) ctsio); -#endif + printf("%s: original_sc == NULL!\n", + __func__); + break; } + io->io_hdr.flags |= CTL_FLAG_IO_ACTIVE; io->io_hdr.msg_type = CTL_MSG_R2R; - io->io_hdr.serializing_sc = msg_info.hdr.serializing_sc; + io->io_hdr.serializing_sc = msg->hdr.serializing_sc; ctl_enqueue_isc(io); break; @@ -842,22 +1063,20 @@ ctl_isc_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param) */ case CTL_MSG_FINISH_IO: if (softc->ha_mode == CTL_HA_MODE_XFER) - ctl_isc_handler_finish_xfer(softc, - &msg_info); + ctl_isc_handler_finish_xfer(softc, msg); else - ctl_isc_handler_finish_ser_only(softc, - &msg_info); + ctl_isc_handler_finish_ser_only(softc, msg); break; /* Preformed on Originating SC */ case CTL_MSG_BAD_JUJU: - io = msg_info.hdr.original_sc; + io = msg->hdr.original_sc; if (io == NULL) { printf("%s: Bad JUJU!, original_sc is NULL!\n", __func__); break; } - ctl_copy_sense_data(&msg_info, io); + ctl_copy_sense_data(msg, io); /* * IO should have already been cleaned up on other * SC so clear this flag so we won't send a message @@ -866,7 +1085,7 @@ ctl_isc_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param) io->io_hdr.flags &= ~CTL_FLAG_SENT_2OTHER_SC; io->io_hdr.flags |= CTL_FLAG_IO_ACTIVE; - /* io = msg_info.hdr.serializing_sc; */ + /* io = msg->hdr.serializing_sc; */ io->io_hdr.msg_type = CTL_MSG_BAD_JUJU; ctl_enqueue_isc(io); break; @@ -874,91 +1093,99 @@ ctl_isc_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param) /* Handle resets sent from the other side */ case CTL_MSG_MANAGE_TASKS: { struct ctl_taskio *taskio; - taskio = (struct ctl_taskio *)ctl_alloc_io_nowait( + taskio = (struct ctl_taskio *)ctl_alloc_io( softc->othersc_pool); - if (taskio == NULL) { - printf("ctl_isc_event_handler: can't allocate " - "ctl_io!\n"); - /* Bad Juju */ - /* should I just call the proper reset func - here??? */ - goto bailout; - } ctl_zero_io((union ctl_io *)taskio); taskio->io_hdr.io_type = CTL_IO_TASK; taskio->io_hdr.flags |= CTL_FLAG_FROM_OTHER_SC; - taskio->io_hdr.nexus = msg_info.hdr.nexus; - taskio->task_action = msg_info.task.task_action; - taskio->tag_num = msg_info.task.tag_num; - taskio->tag_type = msg_info.task.tag_type; + taskio->io_hdr.nexus = msg->hdr.nexus; + taskio->task_action = msg->task.task_action; + taskio->tag_num = msg->task.tag_num; + taskio->tag_type = msg->task.tag_type; #ifdef CTL_TIME_IO taskio->io_hdr.start_time = time_uptime; getbintime(&taskio->io_hdr.start_bt); -#if 0 - cs_prof_gettime(&taskio->io_hdr.start_ticks); -#endif #endif /* CTL_TIME_IO */ ctl_run_task((union ctl_io *)taskio); break; } /* Persistent Reserve action which needs attention */ case CTL_MSG_PERS_ACTION: - presio = (struct ctl_prio *)ctl_alloc_io_nowait( + presio = (struct ctl_prio *)ctl_alloc_io( softc->othersc_pool); - if (presio == NULL) { - printf("ctl_isc_event_handler: can't allocate " - "ctl_io!\n"); - /* Bad Juju */ - /* Need to set busy and send msg back */ - goto bailout; - } ctl_zero_io((union ctl_io *)presio); presio->io_hdr.msg_type = CTL_MSG_PERS_ACTION; - presio->pr_msg = msg_info.pr; + presio->io_hdr.flags |= CTL_FLAG_FROM_OTHER_SC; + presio->io_hdr.nexus = msg->hdr.nexus; + presio->pr_msg = msg->pr; ctl_enqueue_isc((union ctl_io *)presio); break; - case CTL_MSG_SYNC_FE: - rcv_sync_msg = 1; + case CTL_MSG_UA: + ctl_isc_ua(softc, msg, param); + break; + case CTL_MSG_PORT_SYNC: + ctl_isc_port_sync(softc, msg, param); + break; + case CTL_MSG_LUN_SYNC: + ctl_isc_lun_sync(softc, msg, param); break; default: - printf("How did I get here?\n"); + printf("Received HA message of unknown type %d\n", + msg->hdr.msg_type); + break; } - } else if (event == CTL_HA_EVT_MSG_SENT) { - if (param != CTL_HA_STATUS_SUCCESS) { - printf("Bad status from ctl_ha_msg_send status %d\n", - param); + if (msg != &msgbuf) + free(msg, M_CTL); + } else if (event == CTL_HA_EVT_LINK_CHANGE) { + printf("CTL: HA link status changed from %d to %d\n", + softc->ha_link, param); + if (param == softc->ha_link) + return; + if (softc->ha_link == CTL_HA_LINK_ONLINE) { + softc->ha_link = param; + ctl_isc_ha_link_down(softc); + } else { + softc->ha_link = param; + if (softc->ha_link == CTL_HA_LINK_ONLINE) + ctl_isc_ha_link_up(softc); } return; - } else if (event == CTL_HA_EVT_DISCONNECT) { - printf("CTL: Got a disconnect from Isc\n"); - return; } else { printf("ctl_isc_event_handler: Unknown event %d\n", event); return; } - -bailout: - return; } static void ctl_copy_sense_data(union ctl_ha_msg *src, union ctl_io *dest) { - struct scsi_sense_data *sense; - sense = &dest->scsiio.sense_data; - bcopy(&src->scsi.sense_data, sense, sizeof(*sense)); + memcpy(&dest->scsiio.sense_data, &src->scsi.sense_data, + src->scsi.sense_len); dest->scsiio.scsi_status = src->scsi.scsi_status; dest->scsiio.sense_len = src->scsi.sense_len; dest->io_hdr.status = src->hdr.status; } -#endif + +static void +ctl_copy_sense_data_back(union ctl_io *src, union ctl_ha_msg *dest) +{ + + memcpy(&dest->scsi.sense_data, &src->scsiio.sense_data, + src->scsiio.sense_len); + dest->scsi.scsi_status = src->scsiio.scsi_status; + dest->scsi.sense_len = src->scsiio.sense_len; + dest->hdr.status = src->io_hdr.status; +} static void ctl_est_ua(struct ctl_lun *lun, uint32_t initidx, ctl_ua_type ua) { + struct ctl_softc *softc = lun->ctl_softc; ctl_ua_type *pu; + if (initidx < softc->init_min || initidx >= softc->init_max) + return; mtx_assert(&lun->lun_lock, MA_OWNED); pu = lun->pending_ua[initidx / CTL_MAX_INIT_PER_PORT]; if (pu == NULL) @@ -969,10 +1196,11 @@ 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) { + struct ctl_softc *softc = lun->ctl_softc; int i, j; mtx_assert(&lun->lun_lock, MA_OWNED); - for (i = 0; i < CTL_MAX_PORTS; i++) { + for (i = softc->port_min; i < softc->port_max; i++) { if (lun->pending_ua[i] == NULL) continue; for (j = 0; j < CTL_MAX_INIT_PER_PORT; j++) { @@ -986,8 +1214,11 @@ 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) { + struct ctl_softc *softc = lun->ctl_softc; ctl_ua_type *pu; + if (initidx < softc->init_min || initidx >= softc->init_max) + return; mtx_assert(&lun->lun_lock, MA_OWNED); pu = lun->pending_ua[initidx / CTL_MAX_INIT_PER_PORT]; if (pu == NULL) @@ -998,10 +1229,11 @@ 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) { + struct ctl_softc *softc = lun->ctl_softc; int i, j; mtx_assert(&lun->lun_lock, MA_OWNED); - for (i = 0; i < CTL_MAX_PORTS; i++) { + for (i = softc->port_min; i < softc->port_max; i++) { if (lun->pending_ua[i] == NULL) continue; for (j = 0; j < CTL_MAX_INIT_PER_PORT; j++) { @@ -1027,17 +1259,14 @@ ctl_clr_ua_allluns(struct ctl_softc *ctl_softc, uint32_t initidx, } static int -ctl_ha_state_sysctl(SYSCTL_HANDLER_ARGS) +ctl_ha_role_sysctl(SYSCTL_HANDLER_ARGS) { struct ctl_softc *softc = (struct ctl_softc *)arg1; struct ctl_lun *lun; + struct ctl_lun_req ireq; int error, value; - if (softc->flags & CTL_FLAG_ACTIVE_SHELF) - value = 0; - else - value = 1; - + value = (softc->flags & CTL_FLAG_ACTIVE_SHELF) ? 0 : 1; error = sysctl_handle_int(oidp, &value, 0, req); if ((error != 0) || (req->newptr == NULL)) return (error); @@ -1048,9 +1277,17 @@ ctl_ha_state_sysctl(SYSCTL_HANDLER_ARGS) else softc->flags &= ~CTL_FLAG_ACTIVE_SHELF; STAILQ_FOREACH(lun, &softc->lun_list, links) { - mtx_lock(&lun->lun_lock); - ctl_est_ua_all(lun, -1, CTL_UA_ASYM_ACC_CHANGE); - mtx_unlock(&lun->lun_lock); + mtx_unlock(&softc->ctl_lock); + bzero(&ireq, sizeof(ireq)); + ireq.reqtype = CTL_LUNREQ_MODIFY; + ireq.reqdata.modify.lun_id = lun->lun; + lun->backend->ioctl(NULL, CTL_LUN_REQ, (caddr_t)&ireq, 0, + curthread); + if (ireq.status != CTL_LUN_OK) { + printf("%s: CTL_LUNREQ_MODIFY returned %d '%s'\n", + __func__, ireq.status, ireq.error_str); + } + mtx_lock(&softc->ctl_lock); } mtx_unlock(&softc->ctl_lock); return (0); @@ -1062,12 +1299,8 @@ ctl_init(void) struct ctl_softc *softc; void *other_pool; int i, error, retval; - //int isc_retval; retval = 0; - ctl_pause_rtr = 0; - rcv_sync_msg = 0; - control_softc = malloc(sizeof(*control_softc), M_DEVBUF, M_WAITOK | M_ZERO); softc = control_softc; @@ -1077,14 +1310,6 @@ ctl_init(void) softc->dev->si_drv1 = softc; - /* - * By default, return a "bad LUN" peripheral qualifier for unknown - * LUNs. The user can override this default using the tunable or - * sysctl. See the comment in ctl_inquiry_std() for more details. - */ - softc->inquiry_pq_no_lun = 1; - TUNABLE_INT_FETCH("kern.cam.ctl.inquiry_pq_no_lun", - &softc->inquiry_pq_no_lun); sysctl_ctx_init(&softc->sysctl_ctx); softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, SYSCTL_STATIC_CHILDREN(_kern_cam), OID_AUTO, "ctl", @@ -1098,12 +1323,6 @@ ctl_init(void) return (ENOMEM); } - SYSCTL_ADD_INT(&softc->sysctl_ctx, - SYSCTL_CHILDREN(softc->sysctl_tree), OID_AUTO, - "inquiry_pq_no_lun", CTLFLAG_RW, - &softc->inquiry_pq_no_lun, 0, - "Report no lun possible for invalid LUNs"); - mtx_init(&softc->ctl_lock, "CTL mutex", NULL, MTX_DEF); softc->io_zone = uma_zcreate("CTL IO", sizeof(union ctl_io), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); @@ -1115,6 +1334,10 @@ ctl_init(void) */ softc->flags = CTL_FLAG_REAL_SYNC; + SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), + OID_AUTO, "ha_mode", CTLFLAG_RDTUN, (int *)&softc->ha_mode, 0, + "HA mode (0 - act/stby, 1 - serialize only, 2 - xfer)"); + /* * In Copan's HA scheme, the "master" and "slave" roles are * figured out through the slot the controller is in. Although it @@ -1123,13 +1346,22 @@ ctl_init(void) SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), OID_AUTO, "ha_id", CTLFLAG_RDTUN, &softc->ha_id, 0, "HA head ID (0 - no HA)"); - if (softc->ha_id == 0) { + if (softc->ha_id == 0 || softc->ha_id > NUM_TARGET_PORT_GROUPS) { softc->flags |= CTL_FLAG_ACTIVE_SHELF; softc->is_single = 1; - softc->port_offset = 0; - } else - softc->port_offset = (softc->ha_id - 1) * CTL_MAX_PORTS; - softc->persis_offset = softc->port_offset * CTL_MAX_INIT_PER_PORT; + softc->port_cnt = CTL_MAX_PORTS; + softc->port_min = 0; + } else { + softc->port_cnt = CTL_MAX_PORTS / NUM_TARGET_PORT_GROUPS; + softc->port_min = (softc->ha_id - 1) * softc->port_cnt; + } + softc->port_max = softc->port_min + softc->port_cnt; + softc->init_min = softc->port_min * CTL_MAX_INIT_PER_PORT; + softc->init_max = softc->port_max * CTL_MAX_INIT_PER_PORT; + + SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), + OID_AUTO, "ha_link", CTLFLAG_RD, (int *)&softc->ha_link, 0, + "HA link state (0 - offline, 1 - unknown, 2 - online)"); STAILQ_INIT(&softc->lun_list); STAILQ_INIT(&softc->pending_lun_queue); @@ -1186,17 +1418,21 @@ ctl_init(void) } SYSCTL_ADD_PROC(&softc->sysctl_ctx,SYSCTL_CHILDREN(softc->sysctl_tree), - OID_AUTO, "ha_state", CTLTYPE_INT | CTLFLAG_RWTUN, - softc, 0, ctl_ha_state_sysctl, "I", "HA state for this head"); + OID_AUTO, "ha_role", CTLTYPE_INT | CTLFLAG_RWTUN, + softc, 0, ctl_ha_role_sysctl, "I", "HA role for this head"); -#ifdef CTL_IO_DELAY - if (sizeof(struct callout) > CTL_TIMER_BYTES) { - printf("sizeof(struct callout) %zd > CTL_TIMER_BYTES %zd\n", - sizeof(struct callout), CTL_TIMER_BYTES); - return (EINVAL); + if (softc->is_single == 0) { + ctl_frontend_register(&ha_frontend); + if (ctl_ha_msg_init(softc) != CTL_HA_STATUS_SUCCESS) { + printf("ctl_init: ctl_ha_msg_init failed.\n"); + softc->is_single = 1; + } else + if (ctl_ha_msg_register(CTL_HA_CHAN_CTL, ctl_isc_event_handler) + != CTL_HA_STATUS_SUCCESS) { + printf("ctl_init: ctl_ha_msg_register failed.\n"); + softc->is_single = 1; + } } -#endif /* CTL_IO_DELAY */ - return (0); } @@ -1208,6 +1444,17 @@ ctl_shutdown(void) softc = (struct ctl_softc *)control_softc; + if (softc->is_single == 0) { + if (ctl_ha_msg_deregister(CTL_HA_CHAN_CTL) + != CTL_HA_STATUS_SUCCESS) { + printf("ctl_shutdown: ctl_ha_msg_deregister failed.\n"); + } + if (ctl_ha_msg_shutdown(softc) != CTL_HA_STATUS_SUCCESS) { + printf("ctl_shutdown: ctl_ha_msg_shutdown failed.\n"); + } + ctl_frontend_deregister(&ha_frontend); + } + mtx_lock(&softc->ctl_lock); /* @@ -1267,130 +1514,6 @@ ctl_close(struct cdev *dev, int flags, int fmt, struct thread *td) return (0); } -int -ctl_port_enable(ctl_port_type port_type) -{ - struct ctl_softc *softc = control_softc; - struct ctl_port *port; - - if (softc->is_single == 0) { - union ctl_ha_msg msg_info; - int isc_retval; - -#if 0 - printf("%s: HA mode, synchronizing frontend enable\n", - __func__); -#endif - msg_info.hdr.msg_type = CTL_MSG_SYNC_FE; - if ((isc_retval=ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, - sizeof(msg_info), 1 )) > CTL_HA_STATUS_SUCCESS) { - printf("Sync msg send error retval %d\n", isc_retval); - } - if (!rcv_sync_msg) { - isc_retval=ctl_ha_msg_recv(CTL_HA_CHAN_CTL, &msg_info, - sizeof(msg_info), 1); - } -#if 0 - printf("CTL:Frontend Enable\n"); - } else { - printf("%s: single mode, skipping frontend synchronization\n", - __func__); -#endif - } - - STAILQ_FOREACH(port, &softc->port_list, links) { - if (port_type & port->port_type) - { -#if 0 - printf("port %d\n", port->targ_port); -#endif - ctl_port_online(port); - } - } - - return (0); -} - -int -ctl_port_disable(ctl_port_type port_type) -{ - struct ctl_softc *softc; - struct ctl_port *port; - - softc = control_softc; - - STAILQ_FOREACH(port, &softc->port_list, links) { - if (port_type & port->port_type) - ctl_port_offline(port); - } - - return (0); -} - -/* - * Returns 0 for success, 1 for failure. - * Currently the only failure mode is if there aren't enough entries - * allocated. So, in case of a failure, look at num_entries_dropped, - * reallocate and try again. - */ -int -ctl_port_list(struct ctl_port_entry *entries, int num_entries_alloced, - int *num_entries_filled, int *num_entries_dropped, - ctl_port_type port_type, int no_virtual) -{ - struct ctl_softc *softc; - struct ctl_port *port; - int entries_dropped, entries_filled; - int retval; - int i; - - softc = control_softc; - - retval = 0; - entries_filled = 0; - entries_dropped = 0; - - i = 0; - mtx_lock(&softc->ctl_lock); - STAILQ_FOREACH(port, &softc->port_list, links) { - struct ctl_port_entry *entry; - - if ((port->port_type & port_type) == 0) - continue; - - if ((no_virtual != 0) - && (port->virtual_port != 0)) - continue; - - if (entries_filled >= num_entries_alloced) { - entries_dropped++; - continue; - } - entry = &entries[i]; - - entry->port_type = port->port_type; - strlcpy(entry->port_name, port->port_name, - sizeof(entry->port_name)); - entry->physical_port = port->physical_port; - entry->virtual_port = port->virtual_port; - entry->wwnn = port->wwnn; - entry->wwpn = port->wwpn; - - i++; - entries_filled++; - } - - mtx_unlock(&softc->ctl_lock); - - if (entries_dropped > 0) - retval = 1; - - *num_entries_dropped = entries_dropped; - *num_entries_filled = entries_filled; - - return (retval); -} - /* * Remove an initiator by port number and initiator ID. * Returns 0 for success, -1 for failure. @@ -1600,46 +1723,68 @@ ctl_serialize_other_sc_cmd(struct ctl_scsiio *ctsio) struct ctl_softc *softc; union ctl_ha_msg msg_info; struct ctl_lun *lun; + const struct ctl_cmd_entry *entry; int retval = 0; uint32_t targ_lun; softc = control_softc; targ_lun = ctsio->io_hdr.nexus.targ_mapped_lun; - lun = softc->ctl_luns[targ_lun]; - if (lun==NULL) - { + if ((targ_lun < CTL_MAX_LUNS) && + ((lun = softc->ctl_luns[targ_lun]) != NULL)) { + /* + * 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 + lun = NULL; + if (lun == NULL) { /* - * Why isn't LUN defined? The other side wouldn't - * send a cmd if the LUN is undefined. + * The other node would not send this request to us unless + * received announce that we are primary node for this LUN. + * If this LUN does not exist now, it is probably result of + * a race, so respond to initiator in the most opaque way. */ - printf("%s: Bad JUJU!, LUN is NULL!\n", __func__); - - /* "Logical unit not supported" */ - ctl_set_sense_data(&msg_info.scsi.sense_data, - lun, - /*sense_format*/SSD_TYPE_NONE, - /*current_error*/ 1, - /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, - /*asc*/ 0x25, - /*ascq*/ 0x00, - SSD_ELEM_NONE); - - msg_info.scsi.sense_len = SSD_FULL_SIZE; - msg_info.scsi.scsi_status = SCSI_STATUS_CHECK_COND; - msg_info.hdr.status = CTL_SCSI_ERROR | CTL_AUTOSENSE; + ctl_set_busy(ctsio); + ctl_copy_sense_data_back((union ctl_io *)ctsio, &msg_info); msg_info.hdr.original_sc = ctsio->io_hdr.original_sc; msg_info.hdr.serializing_sc = NULL; msg_info.hdr.msg_type = CTL_MSG_BAD_JUJU; - if (ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, - sizeof(msg_info), 0 ) > CTL_HA_STATUS_SUCCESS) { - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, + sizeof(msg_info.scsi), M_WAITOK); return(1); + } + entry = ctl_get_cmd_entry(ctsio, NULL); + if (ctl_scsiio_lun_check(lun, entry, ctsio) != 0) { + mtx_unlock(&lun->lun_lock); + ctl_copy_sense_data_back((union ctl_io *)ctsio, &msg_info); + msg_info.hdr.original_sc = ctsio->io_hdr.original_sc; + msg_info.hdr.serializing_sc = NULL; + msg_info.hdr.msg_type = CTL_MSG_BAD_JUJU; + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, + sizeof(msg_info.scsi), M_WAITOK); + return(1); } - mtx_lock(&lun->lun_lock); - TAILQ_INSERT_TAIL(&lun->ooa_queue, &ctsio->io_hdr, ooa_links); + ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr = lun; + ctsio->io_hdr.ctl_private[CTL_PRIV_BACKEND_LUN].ptr = lun->be_lun; + + /* + * Every I/O goes into the OOA queue for a + * particular LUN, and stays there until completion. + */ +#ifdef CTL_TIME_IO + if (TAILQ_EMPTY(&lun->ooa_queue)) + lun->idle_time += getsbinuptime() - lun->last_busy; +#endif + TAILQ_INSERT_TAIL(&lun->ooa_queue, &ctsio->io_hdr, ooa_links); switch (ctl_check_ooa(lun, (union ctl_io *)ctsio, (union ctl_io *)TAILQ_PREV(&ctsio->io_hdr, ctl_ooaq, @@ -1648,107 +1793,67 @@ ctl_serialize_other_sc_cmd(struct ctl_scsiio *ctsio) ctsio->io_hdr.flags |= CTL_FLAG_BLOCKED; TAILQ_INSERT_TAIL(&lun->blocked_queue, &ctsio->io_hdr, blocked_links); + mtx_unlock(&lun->lun_lock); break; case CTL_ACTION_PASS: case CTL_ACTION_SKIP: if (softc->ha_mode == CTL_HA_MODE_XFER) { ctsio->io_hdr.flags |= CTL_FLAG_IS_WAS_ON_RTR; ctl_enqueue_rtr((union ctl_io *)ctsio); + mtx_unlock(&lun->lun_lock); } else { + ctsio->io_hdr.flags &= ~CTL_FLAG_IO_ACTIVE; + mtx_unlock(&lun->lun_lock); /* send msg back to other side */ msg_info.hdr.original_sc = ctsio->io_hdr.original_sc; msg_info.hdr.serializing_sc = (union ctl_io *)ctsio; msg_info.hdr.msg_type = CTL_MSG_R2R; -#if 0 - printf("2. pOrig %x\n", (int)msg_info.hdr.original_sc); -#endif - if (ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, - sizeof(msg_info), 0 ) > CTL_HA_STATUS_SUCCESS) { - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, + sizeof(msg_info.hdr), M_WAITOK); } break; case CTL_ACTION_OVERLAP: - /* OVERLAPPED COMMANDS ATTEMPTED */ - ctl_set_sense_data(&msg_info.scsi.sense_data, - lun, - /*sense_format*/SSD_TYPE_NONE, - /*current_error*/ 1, - /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, - /*asc*/ 0x4E, - /*ascq*/ 0x00, - SSD_ELEM_NONE); - - msg_info.scsi.sense_len = SSD_FULL_SIZE; - msg_info.scsi.scsi_status = SCSI_STATUS_CHECK_COND; - msg_info.hdr.status = CTL_SCSI_ERROR | CTL_AUTOSENSE; + TAILQ_REMOVE(&lun->ooa_queue, &ctsio->io_hdr, ooa_links); + mtx_unlock(&lun->lun_lock); + retval = 1; + + ctl_set_overlapped_cmd(ctsio); + ctl_copy_sense_data_back((union ctl_io *)ctsio, &msg_info); msg_info.hdr.original_sc = ctsio->io_hdr.original_sc; msg_info.hdr.serializing_sc = NULL; msg_info.hdr.msg_type = CTL_MSG_BAD_JUJU; -#if 0 - printf("BAD JUJU:Major Bummer Overlap\n"); -#endif - TAILQ_REMOVE(&lun->ooa_queue, &ctsio->io_hdr, ooa_links); - retval = 1; - if (ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, - sizeof(msg_info), 0 ) > CTL_HA_STATUS_SUCCESS) { - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, + sizeof(msg_info.scsi), M_WAITOK); break; case CTL_ACTION_OVERLAP_TAG: - /* TAGGED OVERLAPPED COMMANDS (NN = QUEUE TAG) */ - ctl_set_sense_data(&msg_info.scsi.sense_data, - lun, - /*sense_format*/SSD_TYPE_NONE, - /*current_error*/ 1, - /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, - /*asc*/ 0x4D, - /*ascq*/ ctsio->tag_num & 0xff, - SSD_ELEM_NONE); - - msg_info.scsi.sense_len = SSD_FULL_SIZE; - msg_info.scsi.scsi_status = SCSI_STATUS_CHECK_COND; - msg_info.hdr.status = CTL_SCSI_ERROR | CTL_AUTOSENSE; + TAILQ_REMOVE(&lun->ooa_queue, &ctsio->io_hdr, ooa_links); + mtx_unlock(&lun->lun_lock); + retval = 1; + ctl_set_overlapped_tag(ctsio, ctsio->tag_num); + ctl_copy_sense_data_back((union ctl_io *)ctsio, &msg_info); msg_info.hdr.original_sc = ctsio->io_hdr.original_sc; msg_info.hdr.serializing_sc = NULL; msg_info.hdr.msg_type = CTL_MSG_BAD_JUJU; -#if 0 - printf("BAD JUJU:Major Bummer Overlap Tag\n"); -#endif - TAILQ_REMOVE(&lun->ooa_queue, &ctsio->io_hdr, ooa_links); - retval = 1; - if (ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, - sizeof(msg_info), 0 ) > CTL_HA_STATUS_SUCCESS) { - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, + sizeof(msg_info.scsi), M_WAITOK); break; case CTL_ACTION_ERROR: default: - /* "Internal target failure" */ - ctl_set_sense_data(&msg_info.scsi.sense_data, - lun, - /*sense_format*/SSD_TYPE_NONE, - /*current_error*/ 1, - /*sense_key*/ SSD_KEY_HARDWARE_ERROR, - /*asc*/ 0x44, - /*ascq*/ 0x00, - SSD_ELEM_NONE); - - msg_info.scsi.sense_len = SSD_FULL_SIZE; - msg_info.scsi.scsi_status = SCSI_STATUS_CHECK_COND; - msg_info.hdr.status = CTL_SCSI_ERROR | CTL_AUTOSENSE; + TAILQ_REMOVE(&lun->ooa_queue, &ctsio->io_hdr, ooa_links); + mtx_unlock(&lun->lun_lock); + retval = 1; + + ctl_set_internal_failure(ctsio, /*sks_valid*/ 0, + /*retry_count*/ 0); + ctl_copy_sense_data_back((union ctl_io *)ctsio, &msg_info); msg_info.hdr.original_sc = ctsio->io_hdr.original_sc; msg_info.hdr.serializing_sc = NULL; msg_info.hdr.msg_type = CTL_MSG_BAD_JUJU; -#if 0 - printf("BAD JUJU:Major Bummer HW Error\n"); -#endif - TAILQ_REMOVE(&lun->ooa_queue, &ctsio->io_hdr, ooa_links); - retval = 1; - if (ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, - sizeof(msg_info), 0 ) > CTL_HA_STATUS_SUCCESS) { - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, + sizeof(msg_info.scsi), M_WAITOK); break; } - mtx_unlock(&lun->lun_lock); return (retval); } @@ -2009,9 +2114,12 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, STAILQ_FOREACH(port, &softc->port_list, links) { int action, done; + if (port->targ_port < softc->port_min || + port->targ_port >= softc->port_max) + continue; + action = 0; done = 0; - if ((entry->port_type == CTL_PORT_NONE) && (entry->targ_port == port->targ_port)) { /* @@ -2041,30 +2149,29 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, break; } } - if (action != 0) { - /* - * XXX KDM we have to drop the lock here, - * because the online/offline operations - * can potentially block. We need to - * reference count the frontends so they - * can't go away, - */ - mtx_unlock(&softc->ctl_lock); - - if (cmd == CTL_ENABLE_PORT) { - ctl_port_online(port); - } else if (cmd == CTL_DISABLE_PORT) { - ctl_port_offline(port); - } + if (action == 0) + continue; + /* + * XXX KDM we have to drop the lock here, because + * the online/offline operations can potentially + * block. We need to reference count the frontends + * so they can't go away, + */ + if (cmd == CTL_ENABLE_PORT) { + mtx_unlock(&softc->ctl_lock); + ctl_port_online(port); mtx_lock(&softc->ctl_lock); - - if (cmd == CTL_SET_PORT_WWNS) - ctl_port_set_wwns(port, - (entry->flags & CTL_PORT_WWNN_VALID) ? - 1 : 0, entry->wwnn, - (entry->flags & CTL_PORT_WWPN_VALID) ? - 1 : 0, entry->wwpn); + } else if (cmd == CTL_DISABLE_PORT) { + mtx_unlock(&softc->ctl_lock); + ctl_port_offline(port); + mtx_lock(&softc->ctl_lock); + } else if (cmd == CTL_SET_PORT_WWNS) { + ctl_port_set_wwns(port, + (entry->flags & CTL_PORT_WWNN_VALID) ? + 1 : 0, entry->wwnn, + (entry->flags & CTL_PORT_WWPN_VALID) ? + 1 : 0, entry->wwpn); } if (done != 0) break; @@ -2562,7 +2669,7 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, || ((lun->flags & CTL_LUN_DISABLED) != 0)) continue; - for (j = 0; j < (CTL_MAX_PORTS * 2); j++) { + for (j = 0; j < CTL_MAX_PORTS; j++) { if (lun->pr_keys[j] == NULL) continue; for (k = 0; k < CTL_MAX_INIT_PER_PORT; k++){ @@ -2854,7 +2961,10 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, } } - retval = fe->ioctl(dev, cmd, addr, flag, td); + if (fe->ioctl) + retval = fe->ioctl(dev, cmd, addr, flag, td); + else + retval = ENODEV; if (req->num_args > 0) { ctl_copyout_args(req->num_args, req->kern_args); @@ -3013,7 +3123,8 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct ctl_port *port; mtx_lock(&softc->ctl_lock); - if (lm->port >= CTL_MAX_PORTS || + if (lm->port < softc->port_min || + lm->port >= softc->port_max || (port = softc->ctl_ports[lm->port]) == NULL) { mtx_unlock(&softc->ctl_lock); return (ENXIO); @@ -3076,28 +3187,7 @@ ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, uint32_t ctl_get_initindex(struct ctl_nexus *nexus) { - if (nexus->targ_port < CTL_MAX_PORTS) - return (nexus->initid.id + - (nexus->targ_port * CTL_MAX_INIT_PER_PORT)); - else - return (nexus->initid.id + - ((nexus->targ_port - CTL_MAX_PORTS) * - CTL_MAX_INIT_PER_PORT)); -} - -uint32_t -ctl_get_resindex(struct ctl_nexus *nexus) -{ - return (nexus->initid.id + (nexus->targ_port * CTL_MAX_INIT_PER_PORT)); -} - -uint32_t -ctl_port_idx(int port_num) -{ - if (port_num < CTL_MAX_PORTS) - return(port_num); - else - return(port_num - CTL_MAX_PORTS); + return (nexus->initid + (nexus->targ_port * CTL_MAX_INIT_PER_PORT)); } int @@ -3114,10 +3204,12 @@ ctl_lun_map_init(struct ctl_port *port) return (ENOMEM); for (i = 0; i < CTL_MAX_LUNS; i++) port->lun_map[i] = UINT32_MAX; - if (port->status & CTL_PORT_STATUS_ONLINE && - port->lun_disable != NULL) { - STAILQ_FOREACH(lun, &softc->lun_list, links) - port->lun_disable(port->targ_lun_arg, lun->lun); + if (port->status & CTL_PORT_STATUS_ONLINE) { + if (port->lun_disable != NULL) { + STAILQ_FOREACH(lun, &softc->lun_list, links) + port->lun_disable(port->targ_lun_arg, lun->lun); + } + ctl_isc_announce_port(port); } return (0); } @@ -3132,10 +3224,12 @@ ctl_lun_map_deinit(struct ctl_port *port) return (0); free(port->lun_map, M_CTL); port->lun_map = NULL; - if (port->status & CTL_PORT_STATUS_ONLINE && - port->lun_enable != NULL) { - STAILQ_FOREACH(lun, &softc->lun_list, links) - port->lun_enable(port->targ_lun_arg, lun->lun); + if (port->status & CTL_PORT_STATUS_ONLINE) { + if (port->lun_enable != NULL) { + STAILQ_FOREACH(lun, &softc->lun_list, links) + port->lun_enable(port->targ_lun_arg, lun->lun); + } + ctl_isc_announce_port(port); } return (0); } @@ -3153,9 +3247,11 @@ ctl_lun_map_set(struct ctl_port *port, uint32_t plun, uint32_t glun) } old = port->lun_map[plun]; port->lun_map[plun] = glun; - if ((port->status & CTL_PORT_STATUS_ONLINE) && old >= CTL_MAX_LUNS && - port->lun_enable != NULL) - port->lun_enable(port->targ_lun_arg, plun); + if ((port->status & CTL_PORT_STATUS_ONLINE) && old >= CTL_MAX_LUNS) { + if (port->lun_enable != NULL) + port->lun_enable(port->targ_lun_arg, plun); + ctl_isc_announce_port(port); + } return (0); } @@ -3168,9 +3264,11 @@ ctl_lun_map_unset(struct ctl_port *port, uint32_t plun) return (0); old = port->lun_map[plun]; port->lun_map[plun] = UINT32_MAX; - if ((port->status & CTL_PORT_STATUS_ONLINE) && old < CTL_MAX_LUNS && - port->lun_disable != NULL) - port->lun_disable(port->targ_lun_arg, plun); + if ((port->status & CTL_PORT_STATUS_ONLINE) && old < CTL_MAX_LUNS) { + if (port->lun_disable != NULL) + port->lun_disable(port->targ_lun_arg, plun); + ctl_isc_announce_port(port); + } return (0); } @@ -3204,34 +3302,19 @@ ctl_lun_map_to_port(struct ctl_port *port, uint32_t lun_id) static struct ctl_port * ctl_io_port(struct ctl_io_hdr *io_hdr) { - int port_num; - port_num = io_hdr->nexus.targ_port; - return (control_softc->ctl_ports[ctl_port_idx(port_num)]); + return (control_softc->ctl_ports[io_hdr->nexus.targ_port]); } -/* - * Note: This only works for bitmask sizes that are at least 32 bits, and - * that are a power of 2. - */ int -ctl_ffz(uint32_t *mask, uint32_t size) +ctl_ffz(uint32_t *mask, uint32_t first, uint32_t last) { - uint32_t num_chunks, num_pieces; - int i, j; - - num_chunks = (size >> 5); - if (num_chunks == 0) - num_chunks++; - num_pieces = MIN((sizeof(uint32_t) * 8), size); + int i; - for (i = 0; i < num_chunks; i++) { - for (j = 0; j < num_pieces; j++) { - if ((mask[i] & (1 << j)) == 0) - return ((i << 5) + j); - } + for (i = first; i < last; i++) { + if ((mask[i / 32] & (1 << (i % 32))) == 0) + return (i); } - return (-1); } @@ -4130,7 +4213,7 @@ ctl_alloc_lun(struct ctl_softc *ctl_softc, struct ctl_lun *ctl_lun, } lun_number = be_lun->req_lun_id; } else { - lun_number = ctl_ffz(ctl_softc->ctl_lun_mask, CTL_MAX_LUNS); + lun_number = ctl_ffz(ctl_softc->ctl_lun_mask, 0, CTL_MAX_LUNS); if (lun_number == -1) { mtx_unlock(&ctl_softc->ctl_lock); printf("ctl: can't allocate LUN, out of LUNs\n"); @@ -4253,7 +4336,7 @@ ctl_free_lun(struct ctl_lun *lun) free(lun->lun_devid, M_CTL); for (i = 0; i < CTL_MAX_PORTS; i++) free(lun->pending_ua[i], M_CTL); - for (i = 0; i < 2 * CTL_MAX_PORTS; i++) + for (i = 0; i < CTL_MAX_PORTS; i++) free(lun->pr_keys[i], M_CTL); free(lun->write_buffer, M_CTL); if (lun->flags & CTL_LUN_MALLOCED) @@ -4342,6 +4425,7 @@ ctl_enable_lun(struct ctl_be_lun *be_lun) } mtx_unlock(&softc->ctl_lock); + ctl_isc_announce_lun(lun); return (0); } @@ -4391,6 +4475,7 @@ ctl_disable_lun(struct ctl_be_lun *be_lun) } mtx_unlock(&softc->ctl_lock); + ctl_isc_announce_lun(lun); return (0); } @@ -4440,6 +4525,32 @@ ctl_lun_online(struct ctl_be_lun *be_lun) } int +ctl_lun_primary(struct ctl_be_lun *be_lun) +{ + struct ctl_lun *lun = (struct ctl_lun *)be_lun->ctl_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); + ctl_isc_announce_lun(lun); + return (0); +} + +int +ctl_lun_secondary(struct ctl_be_lun *be_lun) +{ + struct ctl_lun *lun = (struct ctl_lun *)be_lun->ctl_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); + ctl_isc_announce_lun(lun); + return (0); +} + +int ctl_invalidate_lun(struct ctl_be_lun *be_lun) { struct ctl_softc *softc; @@ -4504,10 +4615,25 @@ void ctl_lun_capacity_changed(struct ctl_be_lun *be_lun) { struct ctl_lun *lun = (struct ctl_lun *)be_lun->ctl_lun; + union ctl_ha_msg msg; mtx_lock(&lun->lun_lock); ctl_est_ua_all(lun, -1, CTL_UA_CAPACITY_CHANGED); mtx_unlock(&lun->lun_lock); + if (lun->ctl_softc->ha_mode == CTL_HA_MODE_XFER) { + /* Send msg to other side. */ + bzero(&msg.ua, sizeof(msg.ua)); + msg.hdr.msg_type = CTL_MSG_UA; + msg.hdr.nexus.initid = -1; + msg.hdr.nexus.targ_port = -1; + msg.hdr.nexus.targ_lun = lun->lun; + msg.hdr.nexus.targ_mapped_lun = lun->lun; + msg.ua.ua_all = 1; + msg.ua.ua_set = 1; + msg.ua.ua_type = CTL_UA_CAPACITY_CHANGED; + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg, sizeof(msg.ua), + M_WAITOK); + } } /* @@ -4540,6 +4666,8 @@ ctl_config_move_done(union ctl_io *io) io->io_hdr.port_status); } + if (ctl_debug & CTL_DEBUG_CDB_DATA) + ctl_data_print(io); if (((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN) || ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE && (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) || @@ -4566,8 +4694,6 @@ ctl_config_move_done(union ctl_io *io) * * - Call some other function once the data is in? */ - if (ctl_debug & CTL_DEBUG_CDB_DATA) - ctl_data_print(io); /* * XXX KDM call ctl_scsiio() again for now, and check flag @@ -4690,7 +4816,7 @@ ctl_scsi_release(struct ctl_scsiio *ctsio) CTL_DEBUG_PRINT(("ctl_scsi_release\n")); - residx = ctl_get_resindex(&ctsio->io_hdr.nexus); + residx = ctl_get_initindex(&ctsio->io_hdr.nexus); lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr; switch (ctsio->cdb[0]) { @@ -4780,7 +4906,7 @@ ctl_scsi_reserve(struct ctl_scsiio *ctsio) CTL_DEBUG_PRINT(("ctl_reserve\n")); - residx = ctl_get_resindex(&ctsio->io_hdr.nexus); + residx = ctl_get_initindex(&ctsio->io_hdr.nexus); lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr; switch (ctsio->cdb[0]) { @@ -4896,7 +5022,7 @@ ctl_start_stop(struct ctl_scsiio *ctsio) && ((cdb->how & SSS_START)==0)) { uint32_t residx; - residx = ctl_get_resindex(&ctsio->io_hdr.nexus); + residx = ctl_get_initindex(&ctsio->io_hdr.nexus); if (ctl_get_prkey(lun, residx) == 0 || (lun->pr_res_idx!=residx && lun->res_type < 4)) { @@ -6862,7 +6988,7 @@ ctl_report_tagret_port_groups(struct ctl_scsiio *ctsio) { struct scsi_maintenance_in *cdb; int retval; - int alloc_len, ext, total_len = 0, g, p, pc, pg, gs, os; + int alloc_len, ext, total_len = 0, g, pc, pg, gs, os; int num_target_port_groups, num_target_ports; struct ctl_lun *lun; struct ctl_softc *softc; @@ -6918,8 +7044,7 @@ ctl_report_tagret_port_groups(struct ctl_scsiio *ctsio) total_len = sizeof(struct scsi_target_group_data); total_len += sizeof(struct scsi_target_port_group_descriptor) * num_target_port_groups + - sizeof(struct scsi_target_port_descriptor) * - num_target_ports * num_target_port_groups; + sizeof(struct scsi_target_port_descriptor) * num_target_ports; alloc_len = scsi_4btoul(cdb->length); @@ -6954,35 +7079,36 @@ ctl_report_tagret_port_groups(struct ctl_scsiio *ctsio) } mtx_lock(&softc->ctl_lock); - pg = softc->port_offset / CTL_MAX_PORTS; - if (softc->flags & CTL_FLAG_ACTIVE_SHELF) { - if (softc->ha_mode == CTL_HA_MODE_ACT_STBY) { - gs = TPG_ASYMMETRIC_ACCESS_OPTIMIZED; - os = TPG_ASYMMETRIC_ACCESS_STANDBY; - } else if (lun->flags & CTL_LUN_PRIMARY_SC) { - gs = TPG_ASYMMETRIC_ACCESS_OPTIMIZED; - os = TPG_ASYMMETRIC_ACCESS_NONOPTIMIZED; - } else { - gs = TPG_ASYMMETRIC_ACCESS_NONOPTIMIZED; - os = TPG_ASYMMETRIC_ACCESS_OPTIMIZED; - } - } else { + pg = softc->port_min / softc->port_cnt; + if (softc->ha_link == CTL_HA_LINK_OFFLINE) + gs = TPG_ASYMMETRIC_ACCESS_UNAVAILABLE; + else if (softc->ha_link == CTL_HA_LINK_UNKNOWN) + gs = TPG_ASYMMETRIC_ACCESS_TRANSITIONING; + else if (softc->ha_mode == CTL_HA_MODE_ACT_STBY) gs = TPG_ASYMMETRIC_ACCESS_STANDBY; + else + gs = TPG_ASYMMETRIC_ACCESS_NONOPTIMIZED; + if (lun->flags & CTL_LUN_PRIMARY_SC) { + os = gs; + gs = TPG_ASYMMETRIC_ACCESS_OPTIMIZED; + } else os = TPG_ASYMMETRIC_ACCESS_OPTIMIZED; - } for (g = 0; g < num_target_port_groups; g++) { tpg_desc->pref_state = (g == pg) ? gs : os; - tpg_desc->support = TPG_AO_SUP | TPG_AN_SUP | TPG_S_SUP; + tpg_desc->support = TPG_AO_SUP | TPG_AN_SUP | TPG_S_SUP | + TPG_U_SUP | TPG_T_SUP; scsi_ulto2b(g + 1, tpg_desc->target_port_group); tpg_desc->status = TPG_IMPLICIT; pc = 0; STAILQ_FOREACH(port, &softc->port_list, links) { + if (port->targ_port < g * softc->port_cnt || + port->targ_port >= (g + 1) * softc->port_cnt) + continue; if ((port->status & CTL_PORT_STATUS_ONLINE) == 0) continue; if (ctl_lun_map_to_port(port, lun->lun) >= CTL_MAX_LUNS) continue; - p = port->targ_port % CTL_MAX_PORTS + g * CTL_MAX_PORTS; - scsi_ulto2b(p, tpg_desc->descriptors[pc]. + scsi_ulto2b(port->targ_port, tpg_desc->descriptors[pc]. relative_target_port_identifier); pc++; } @@ -7351,7 +7477,7 @@ retry: scsi_ulto4b(sizeof(struct scsi_per_res_key) * lun->pr_key_count, res_keys->header.length); - for (i = 0, key_count = 0; i < 2*CTL_MAX_INITIATORS; i++) { + for (i = 0, key_count = 0; i < CTL_MAX_INITIATORS; i++) { if ((key = ctl_get_prkey(lun, i)) == 0) continue; @@ -7480,7 +7606,7 @@ retry: scsi_ulto4b(lun->PRGeneration, res_status->header.generation); res_desc = &res_status->desc[0]; - for (i = 0; i < 2*CTL_MAX_INITIATORS; i++) { + for (i = 0; i < CTL_MAX_INITIATORS; i++) { if ((key = ctl_get_prkey(lun, i)) == 0) continue; @@ -7494,8 +7620,7 @@ retry: scsi_ulto2b(i / CTL_MAX_INIT_PER_PORT, res_desc->rel_trgt_port_id); len = 0; - port = softc->ctl_ports[ - ctl_port_idx(i / CTL_MAX_INIT_PER_PORT)]; + port = softc->ctl_ports[i / CTL_MAX_INIT_PER_PORT]; if (port != NULL) len = ctl_create_iid(port, i % CTL_MAX_INIT_PER_PORT, @@ -7525,15 +7650,6 @@ retry: return (CTL_RETVAL_COMPLETE); } -static void -ctl_est_res_ua(struct ctl_lun *lun, uint32_t residx, ctl_ua_type ua) -{ - int off = lun->ctl_softc->persis_offset; - - if (residx >= off && residx < off + CTL_MAX_INITIATORS) - ctl_est_ua(lun, residx - off, ua); -} - /* * Returns 0 if ctl_persistent_reserve_out() should continue, non-zero if * it should return. @@ -7545,10 +7661,7 @@ ctl_pro_preempt(struct ctl_softc *softc, struct ctl_lun *lun, uint64_t res_key, struct scsi_per_res_out_parms* param) { union ctl_ha_msg persis_io; - int retval, i; - int isc_retval; - - retval = 0; + int i; mtx_lock(&lun->lun_lock); if (sa_res_key == 0) { @@ -7583,18 +7696,20 @@ ctl_pro_preempt(struct ctl_softc *softc, struct ctl_lun *lun, uint64_t res_key, * Unregister everybody else and build UA for * them */ - for(i=0; i < 2*CTL_MAX_INITIATORS; i++) { + for(i = 0; i < CTL_MAX_INITIATORS; i++) { if (i == residx || ctl_get_prkey(lun, i) == 0) continue; ctl_clr_prkey(lun, i); - ctl_est_res_ua(lun, i, CTL_UA_REG_PREEMPT); + ctl_est_ua(lun, i, CTL_UA_REG_PREEMPT); } lun->pr_key_count = 1; lun->res_type = type; if (lun->res_type != SPR_TYPE_WR_EX_AR && lun->res_type != SPR_TYPE_EX_AC_AR) lun->pr_res_idx = residx; + lun->PRGeneration++; + mtx_unlock(&lun->lun_lock); /* send msg to other side */ persis_io.hdr.nexus = ctsio->io_hdr.nexus; @@ -7605,13 +7720,8 @@ ctl_pro_preempt(struct ctl_softc *softc, struct ctl_lun *lun, uint64_t res_key, memcpy(persis_io.pr.pr_info.sa_res_key, param->serv_act_res_key, sizeof(param->serv_act_res_key)); - if ((isc_retval=ctl_ha_msg_send(CTL_HA_CHAN_CTL, - &persis_io, sizeof(persis_io), 0)) > - CTL_HA_STATUS_SUCCESS) { - printf("CTL:Persis Out error returned " - "from ctl_ha_msg_send %d\n", - isc_retval); - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &persis_io, + sizeof(persis_io.pr), M_WAITOK); } else { /* not all registrants */ mtx_unlock(&lun->lun_lock); @@ -7652,14 +7762,14 @@ ctl_pro_preempt(struct ctl_softc *softc, struct ctl_lun *lun, uint64_t res_key, return (1); } - for (i=0; i < 2*CTL_MAX_INITIATORS; i++) { + for (i = 0; i < CTL_MAX_INITIATORS; i++) { if (ctl_get_prkey(lun, i) != sa_res_key) continue; found = 1; ctl_clr_prkey(lun, i); lun->pr_key_count--; - ctl_est_res_ua(lun, i, CTL_UA_REG_PREEMPT); + ctl_est_ua(lun, i, CTL_UA_REG_PREEMPT); } if (!found) { mtx_unlock(&lun->lun_lock); @@ -7668,6 +7778,9 @@ ctl_pro_preempt(struct ctl_softc *softc, struct ctl_lun *lun, uint64_t res_key, ctl_done((union ctl_io *)ctsio); return (CTL_RETVAL_COMPLETE); } + lun->PRGeneration++; + mtx_unlock(&lun->lun_lock); + /* send msg to other side */ persis_io.hdr.nexus = ctsio->io_hdr.nexus; persis_io.hdr.msg_type = CTL_MSG_PERS_ACTION; @@ -7677,12 +7790,8 @@ ctl_pro_preempt(struct ctl_softc *softc, struct ctl_lun *lun, uint64_t res_key, memcpy(persis_io.pr.pr_info.sa_res_key, param->serv_act_res_key, sizeof(param->serv_act_res_key)); - if ((isc_retval=ctl_ha_msg_send(CTL_HA_CHAN_CTL, - &persis_io, sizeof(persis_io), 0)) > - CTL_HA_STATUS_SUCCESS) { - printf("CTL:Persis Out error returned from " - "ctl_ha_msg_send %d\n", isc_retval); - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &persis_io, + sizeof(persis_io.pr), M_WAITOK); } else { /* Reserved but not all registrants */ /* sa_res_key is res holder */ @@ -7727,18 +7836,18 @@ ctl_pro_preempt(struct ctl_softc *softc, struct ctl_lun *lun, uint64_t res_key, * except don't unregister the res holder. */ - for(i=0; i < 2*CTL_MAX_INITIATORS; i++) { + for(i = 0; i < CTL_MAX_INITIATORS; i++) { if (i == residx || ctl_get_prkey(lun, i) == 0) continue; if (sa_res_key == ctl_get_prkey(lun, i)) { ctl_clr_prkey(lun, i); lun->pr_key_count--; - ctl_est_res_ua(lun, i, CTL_UA_REG_PREEMPT); + ctl_est_ua(lun, i, CTL_UA_REG_PREEMPT); } else if (type != lun->res_type && (lun->res_type == SPR_TYPE_WR_EX_RO || lun->res_type ==SPR_TYPE_EX_AC_RO)){ - ctl_est_res_ua(lun, i, CTL_UA_RES_RELEASE); + ctl_est_ua(lun, i, CTL_UA_RES_RELEASE); } } lun->res_type = type; @@ -7747,6 +7856,8 @@ ctl_pro_preempt(struct ctl_softc *softc, struct ctl_lun *lun, uint64_t res_key, lun->pr_res_idx = residx; else lun->pr_res_idx = CTL_PR_ALL_REGISTRANTS; + lun->PRGeneration++; + mtx_unlock(&lun->lun_lock); persis_io.hdr.nexus = ctsio->io_hdr.nexus; persis_io.hdr.msg_type = CTL_MSG_PERS_ACTION; @@ -7756,13 +7867,8 @@ ctl_pro_preempt(struct ctl_softc *softc, struct ctl_lun *lun, uint64_t res_key, memcpy(persis_io.pr.pr_info.sa_res_key, param->serv_act_res_key, sizeof(param->serv_act_res_key)); - if ((isc_retval=ctl_ha_msg_send(CTL_HA_CHAN_CTL, - &persis_io, sizeof(persis_io), 0)) > - CTL_HA_STATUS_SUCCESS) { - printf("CTL:Persis Out error returned " - "from ctl_ha_msg_send %d\n", - isc_retval); - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &persis_io, + sizeof(persis_io.pr), M_WAITOK); } else { /* * sa_res_key is not the res holder just @@ -7770,14 +7876,14 @@ ctl_pro_preempt(struct ctl_softc *softc, struct ctl_lun *lun, uint64_t res_key, */ int found=0; - for (i=0; i < 2*CTL_MAX_INITIATORS; i++) { + for (i = 0; i < CTL_MAX_INITIATORS; i++) { if (sa_res_key != ctl_get_prkey(lun, i)) continue; found = 1; ctl_clr_prkey(lun, i); lun->pr_key_count--; - ctl_est_res_ua(lun, i, CTL_UA_REG_PREEMPT); + ctl_est_ua(lun, i, CTL_UA_REG_PREEMPT); } if (!found) { @@ -7787,6 +7893,9 @@ ctl_pro_preempt(struct ctl_softc *softc, struct ctl_lun *lun, uint64_t res_key, ctl_done((union ctl_io *)ctsio); return (1); } + lun->PRGeneration++; + mtx_unlock(&lun->lun_lock); + persis_io.hdr.nexus = ctsio->io_hdr.nexus; persis_io.hdr.msg_type = CTL_MSG_PERS_ACTION; persis_io.pr.pr_info.action = CTL_PR_PREEMPT; @@ -7795,20 +7904,11 @@ ctl_pro_preempt(struct ctl_softc *softc, struct ctl_lun *lun, uint64_t res_key, memcpy(persis_io.pr.pr_info.sa_res_key, param->serv_act_res_key, sizeof(param->serv_act_res_key)); - if ((isc_retval=ctl_ha_msg_send(CTL_HA_CHAN_CTL, - &persis_io, sizeof(persis_io), 0)) > - CTL_HA_STATUS_SUCCESS) { - printf("CTL:Persis Out error returned " - "from ctl_ha_msg_send %d\n", - isc_retval); - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &persis_io, + sizeof(persis_io.pr), M_WAITOK); } } - - lun->PRGeneration++; - mtx_unlock(&lun->lun_lock); - - return (retval); + return (0); } static void @@ -7827,13 +7927,13 @@ ctl_pro_preempt_other(struct ctl_lun *lun, union ctl_ha_msg *msg) * Unregister everybody else and build UA for * them */ - for(i=0; i < 2*CTL_MAX_INITIATORS; i++) { + for(i = 0; i < CTL_MAX_INITIATORS; i++) { if (i == msg->pr.pr_info.residx || ctl_get_prkey(lun, i) == 0) continue; ctl_clr_prkey(lun, i); - ctl_est_res_ua(lun, i, CTL_UA_REG_PREEMPT); + ctl_est_ua(lun, i, CTL_UA_REG_PREEMPT); } lun->pr_key_count = 1; @@ -7842,17 +7942,17 @@ ctl_pro_preempt_other(struct ctl_lun *lun, union ctl_ha_msg *msg) && lun->res_type != SPR_TYPE_EX_AC_AR) lun->pr_res_idx = msg->pr.pr_info.residx; } else { - for (i=0; i < 2*CTL_MAX_INITIATORS; i++) { + for (i = 0; i < CTL_MAX_INITIATORS; i++) { if (sa_res_key == ctl_get_prkey(lun, i)) continue; ctl_clr_prkey(lun, i); lun->pr_key_count--; - ctl_est_res_ua(lun, i, CTL_UA_REG_PREEMPT); + ctl_est_ua(lun, i, CTL_UA_REG_PREEMPT); } } } else { - for (i=0; i < 2*CTL_MAX_INITIATORS; i++) { + for (i = 0; i < CTL_MAX_INITIATORS; i++) { if (i == msg->pr.pr_info.residx || ctl_get_prkey(lun, i) == 0) continue; @@ -7860,11 +7960,11 @@ ctl_pro_preempt_other(struct ctl_lun *lun, union ctl_ha_msg *msg) if (sa_res_key == ctl_get_prkey(lun, i)) { ctl_clr_prkey(lun, i); lun->pr_key_count--; - ctl_est_res_ua(lun, i, CTL_UA_REG_PREEMPT); + ctl_est_ua(lun, i, CTL_UA_REG_PREEMPT); } else if (msg->pr.pr_info.res_type != lun->res_type && (lun->res_type == SPR_TYPE_WR_EX_RO || lun->res_type == SPR_TYPE_EX_AC_RO)) { - ctl_est_res_ua(lun, i, CTL_UA_RES_RELEASE); + ctl_est_ua(lun, i, CTL_UA_RES_RELEASE); } } lun->res_type = msg->pr.pr_info.res_type; @@ -7883,7 +7983,6 @@ int ctl_persistent_reserve_out(struct ctl_scsiio *ctsio) { int retval; - int isc_retval; u_int32_t param_len; struct scsi_per_res_out *cdb; struct ctl_lun *lun; @@ -7953,7 +8052,7 @@ ctl_persistent_reserve_out(struct ctl_scsiio *ctsio) param = (struct scsi_per_res_out_parms *)ctsio->kern_data_ptr; - residx = ctl_get_resindex(&ctsio->io_hdr.nexus); + residx = ctl_get_initindex(&ctsio->io_hdr.nexus); res_key = scsi_8btou64(param->res_key.key); sa_res_key = scsi_8btou64(param->serv_act_res_key); @@ -8068,9 +8167,8 @@ ctl_persistent_reserve_out(struct ctl_scsiio *ctsio) * RELEASED */ - for (i = 0; i < CTL_MAX_INITIATORS;i++){ - if (ctl_get_prkey(lun, i + - softc->persis_offset) == 0) + for (i = softc->init_min; i < softc->init_max; i++){ + if (ctl_get_prkey(lun, i) == 0) continue; ctl_est_ua(lun, i, CTL_UA_RES_RELEASE); @@ -8084,16 +8182,15 @@ ctl_persistent_reserve_out(struct ctl_scsiio *ctsio) lun->pr_res_idx = CTL_PR_NO_RESERVATION; } } + lun->PRGeneration++; + mtx_unlock(&lun->lun_lock); + persis_io.hdr.nexus = ctsio->io_hdr.nexus; persis_io.hdr.msg_type = CTL_MSG_PERS_ACTION; persis_io.pr.pr_info.action = CTL_PR_UNREG_KEY; persis_io.pr.pr_info.residx = residx; - if ((isc_retval = ctl_ha_msg_send(CTL_HA_CHAN_CTL, - &persis_io, sizeof(persis_io), 0 )) > - CTL_HA_STATUS_SUCCESS) { - printf("CTL:Persis Out error returned from " - "ctl_ha_msg_send %d\n", isc_retval); - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &persis_io, + sizeof(persis_io.pr), M_WAITOK); } else /* sa_res_key != 0 */ { /* @@ -8104,6 +8201,8 @@ ctl_persistent_reserve_out(struct ctl_scsiio *ctsio) if (ctl_get_prkey(lun, residx) == 0) lun->pr_key_count++; ctl_set_prkey(lun, residx, sa_res_key); + lun->PRGeneration++; + mtx_unlock(&lun->lun_lock); persis_io.hdr.nexus = ctsio->io_hdr.nexus; persis_io.hdr.msg_type = CTL_MSG_PERS_ACTION; @@ -8112,15 +8211,9 @@ ctl_persistent_reserve_out(struct ctl_scsiio *ctsio) memcpy(persis_io.pr.pr_info.sa_res_key, param->serv_act_res_key, sizeof(param->serv_act_res_key)); - if ((isc_retval=ctl_ha_msg_send(CTL_HA_CHAN_CTL, - &persis_io, sizeof(persis_io), 0)) > - CTL_HA_STATUS_SUCCESS) { - printf("CTL:Persis Out error returned from " - "ctl_ha_msg_send %d\n", isc_retval); - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &persis_io, + sizeof(persis_io.pr), M_WAITOK); } - lun->PRGeneration++; - mtx_unlock(&lun->lun_lock); break; } @@ -8167,12 +8260,8 @@ ctl_persistent_reserve_out(struct ctl_scsiio *ctsio) persis_io.pr.pr_info.action = CTL_PR_RESERVE; persis_io.pr.pr_info.residx = lun->pr_res_idx; persis_io.pr.pr_info.res_type = type; - if ((isc_retval=ctl_ha_msg_send(CTL_HA_CHAN_CTL, - &persis_io, sizeof(persis_io), 0)) > - CTL_HA_STATUS_SUCCESS) { - printf("CTL:Persis Out error returned from " - "ctl_ha_msg_send %d\n", isc_retval); - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &persis_io, + sizeof(persis_io.pr), M_WAITOK); } break; @@ -8216,24 +8305,20 @@ ctl_persistent_reserve_out(struct ctl_scsiio *ctsio) */ if (type != SPR_TYPE_EX_AC && type != SPR_TYPE_WR_EX) { - for (i = 0; i < CTL_MAX_INITIATORS; i++) { - if (i == residx || - ctl_get_prkey(lun, - i + softc->persis_offset) == 0) + for (i = softc->init_min; i < softc->init_max; i++) { + if (i == residx || ctl_get_prkey(lun, i) == 0) continue; ctl_est_ua(lun, i, CTL_UA_RES_RELEASE); } } mtx_unlock(&lun->lun_lock); + /* Send msg to other side */ persis_io.hdr.nexus = ctsio->io_hdr.nexus; persis_io.hdr.msg_type = CTL_MSG_PERS_ACTION; persis_io.pr.pr_info.action = CTL_PR_RELEASE; - if ((isc_retval=ctl_ha_msg_send( CTL_HA_CHAN_CTL, &persis_io, - sizeof(persis_io), 0)) > CTL_HA_STATUS_SUCCESS) { - printf("CTL:Persis Out error returned from " - "ctl_ha_msg_send %d\n", isc_retval); - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &persis_io, + sizeof(persis_io.pr), M_WAITOK); break; case SPRO_CLEAR: @@ -8246,21 +8331,19 @@ ctl_persistent_reserve_out(struct ctl_scsiio *ctsio) lun->pr_res_idx = CTL_PR_NO_RESERVATION; ctl_clr_prkey(lun, residx); - for (i=0; i < 2*CTL_MAX_INITIATORS; i++) + for (i = 0; i < CTL_MAX_INITIATORS; i++) if (ctl_get_prkey(lun, i) != 0) { ctl_clr_prkey(lun, i); - ctl_est_res_ua(lun, i, CTL_UA_REG_PREEMPT); + ctl_est_ua(lun, i, CTL_UA_REG_PREEMPT); } lun->PRGeneration++; mtx_unlock(&lun->lun_lock); + persis_io.hdr.nexus = ctsio->io_hdr.nexus; persis_io.hdr.msg_type = CTL_MSG_PERS_ACTION; persis_io.pr.pr_info.action = CTL_PR_CLEAR; - if ((isc_retval=ctl_ha_msg_send(CTL_HA_CHAN_CTL, &persis_io, - sizeof(persis_io), 0)) > CTL_HA_STATUS_SUCCESS) { - printf("CTL:Persis Out error returned from " - "ctl_ha_msg_send %d\n", isc_retval); - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &persis_io, + sizeof(persis_io.pr), M_WAITOK); break; case SPRO_PREEMPT: @@ -8335,9 +8418,8 @@ ctl_hndl_per_res_out_on_other_sc(union ctl_ha_msg *msg) * RELEASED */ - for (i = 0; i < CTL_MAX_INITIATORS; i++) { - if (ctl_get_prkey(lun, i + - softc->persis_offset) == 0) + for (i = softc->init_min; i < softc->init_max; i++) { + if (ctl_get_prkey(lun, i) == 0) continue; ctl_est_ua(lun, i, CTL_UA_RES_RELEASE); @@ -8368,8 +8450,8 @@ 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 = 0; i < CTL_MAX_INITIATORS; i++) - if (ctl_get_prkey(lun, i + softc->persis_offset) != 0) + 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); } @@ -8387,11 +8469,11 @@ ctl_hndl_per_res_out_on_other_sc(union ctl_ha_msg *msg) lun->pr_key_count = 0; lun->pr_res_idx = CTL_PR_NO_RESERVATION; - for (i=0; i < 2*CTL_MAX_INITIATORS; i++) { + for (i=0; i < CTL_MAX_INITIATORS; i++) { if (ctl_get_prkey(lun, i) == 0) continue; ctl_clr_prkey(lun, i); - ctl_est_res_ua(lun, i, CTL_UA_REG_PREEMPT); + ctl_est_ua(lun, i, CTL_UA_REG_PREEMPT); } lun->PRGeneration++; break; @@ -9163,14 +9245,6 @@ ctl_tur(struct ctl_scsiio *ctsio) return (CTL_RETVAL_COMPLETE); } -#ifdef notyet -static int -ctl_cmddt_inquiry(struct ctl_scsiio *ctsio) -{ - -} -#endif - /* * SCSI VPD page 0x00, the Supported VPD Pages page. */ @@ -9446,7 +9520,7 @@ ctl_inquiry_evpd_devid(struct ctl_scsiio *ctsio, int alloc_len) softc = control_softc; - port = softc->ctl_ports[ctl_port_idx(ctsio->io_hdr.nexus.targ_port)]; + port = ctl_io_port(&ctsio->io_hdr); lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr; data_len = sizeof(struct scsi_vpd_device_id) + @@ -9456,9 +9530,9 @@ ctl_inquiry_evpd_devid(struct ctl_scsiio *ctsio, int alloc_len) sizeof(struct scsi_vpd_id_trgt_port_grp_id); if (lun && lun->lun_devid) data_len += lun->lun_devid->len; - if (port->port_devid) + if (port && port->port_devid) data_len += port->port_devid->len; - if (port->target_devid) + if (port && port->target_devid) data_len += port->target_devid->len; ctsio->kern_data_ptr = malloc(data_len, M_CTL, M_WAITOK | M_ZERO); @@ -9490,9 +9564,9 @@ ctl_inquiry_evpd_devid(struct ctl_scsiio *ctsio, int alloc_len) devid_ptr->page_code = SVPD_DEVICE_ID; scsi_ulto2b(data_len - 4, devid_ptr->length); - if (port->port_type == CTL_PORT_FC) + if (port && port->port_type == CTL_PORT_FC) proto = SCSI_PROTO_FC << 4; - else if (port->port_type == CTL_PORT_ISCSI) + else if (port && port->port_type == CTL_PORT_ISCSI) proto = SCSI_PROTO_ISCSI << 4; else proto = SCSI_PROTO_SPI << 4; @@ -9511,7 +9585,7 @@ ctl_inquiry_evpd_devid(struct ctl_scsiio *ctsio, int alloc_len) /* * This is for the WWPN which is a port association. */ - if (port->port_devid) { + if (port && port->port_devid) { memcpy(desc, port->port_devid->data, port->port_devid->len); desc = (struct scsi_vpd_id_descriptor *)((uint8_t *)desc + port->port_devid->len); @@ -9535,7 +9609,7 @@ ctl_inquiry_evpd_devid(struct ctl_scsiio *ctsio, int alloc_len) desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_PORT | SVPD_ID_TYPE_TPORTGRP; desc->length = 4; - scsi_ulto2b(ctsio->io_hdr.nexus.targ_port / CTL_MAX_PORTS + 1, + scsi_ulto2b(ctsio->io_hdr.nexus.targ_port / softc->port_cnt + 1, &desc->identifier[2]); desc = (struct scsi_vpd_id_descriptor *)(&desc->identifier[0] + sizeof(struct scsi_vpd_id_trgt_port_grp_id)); @@ -9543,7 +9617,7 @@ ctl_inquiry_evpd_devid(struct ctl_scsiio *ctsio, int alloc_len) /* * This is for the Target identifier */ - if (port->target_devid) { + if (port && port->target_devid) { memcpy(desc, port->target_devid->data, port->target_devid->len); } @@ -9563,15 +9637,10 @@ ctl_inquiry_evpd_scsi_ports(struct ctl_scsiio *ctsio, int alloc_len) struct scsi_vpd_port_designation_cont *pdc; struct ctl_lun *lun; struct ctl_port *port; - int data_len, num_target_ports, iid_len, id_len, g, pg, p; - int num_target_port_groups; + int data_len, num_target_ports, iid_len, id_len; lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr; - if (softc->is_single) - num_target_port_groups = 1; - else - num_target_port_groups = NUM_TARGET_PORT_GROUPS; num_target_ports = 0; iid_len = 0; id_len = 0; @@ -9590,7 +9659,7 @@ ctl_inquiry_evpd_scsi_ports(struct ctl_scsiio *ctsio, int alloc_len) } mtx_unlock(&softc->ctl_lock); - data_len = sizeof(struct scsi_vpd_scsi_ports) + num_target_port_groups * + data_len = sizeof(struct scsi_vpd_scsi_ports) + num_target_ports * (sizeof(struct scsi_vpd_port_designation) + sizeof(struct scsi_vpd_port_designation_cont)) + iid_len + id_len; ctsio->kern_data_ptr = malloc(data_len, M_CTL, M_WAITOK | M_ZERO); @@ -9627,35 +9696,31 @@ ctl_inquiry_evpd_scsi_ports(struct ctl_scsiio *ctsio, int alloc_len) pd = &sp->design[0]; mtx_lock(&softc->ctl_lock); - pg = softc->port_offset / CTL_MAX_PORTS; - for (g = 0; g < num_target_port_groups; g++) { - STAILQ_FOREACH(port, &softc->port_list, links) { - if ((port->status & CTL_PORT_STATUS_ONLINE) == 0) - continue; - if (lun != NULL && - ctl_lun_map_to_port(port, lun->lun) >= CTL_MAX_LUNS) - continue; - p = port->targ_port % CTL_MAX_PORTS + g * CTL_MAX_PORTS; - scsi_ulto2b(p, pd->relative_port_id); - if (port->init_devid && g == pg) { - iid_len = port->init_devid->len; - memcpy(pd->initiator_transportid, - port->init_devid->data, port->init_devid->len); - } else - iid_len = 0; - scsi_ulto2b(iid_len, pd->initiator_transportid_length); - pdc = (struct scsi_vpd_port_designation_cont *) - (&pd->initiator_transportid[iid_len]); - if (port->port_devid && g == pg) { - id_len = port->port_devid->len; - memcpy(pdc->target_port_descriptors, - port->port_devid->data, port->port_devid->len); - } else - id_len = 0; - scsi_ulto2b(id_len, pdc->target_port_descriptors_length); - pd = (struct scsi_vpd_port_designation *) - ((uint8_t *)pdc->target_port_descriptors + id_len); - } + STAILQ_FOREACH(port, &softc->port_list, links) { + if ((port->status & CTL_PORT_STATUS_ONLINE) == 0) + continue; + if (lun != NULL && + ctl_lun_map_to_port(port, lun->lun) >= CTL_MAX_LUNS) + continue; + scsi_ulto2b(port->targ_port, pd->relative_port_id); + if (port->init_devid) { + iid_len = port->init_devid->len; + memcpy(pd->initiator_transportid, + port->init_devid->data, port->init_devid->len); + } else + iid_len = 0; + scsi_ulto2b(iid_len, pd->initiator_transportid_length); + pdc = (struct scsi_vpd_port_designation_cont *) + (&pd->initiator_transportid[iid_len]); + if (port->port_devid) { + id_len = port->port_devid->len; + memcpy(pdc->target_port_descriptors, + port->port_devid->data, port->port_devid->len); + } else + id_len = 0; + scsi_ulto2b(id_len, pdc->target_port_descriptors_length); + pd = (struct scsi_vpd_port_designation *) + ((uint8_t *)pdc->target_port_descriptors + id_len); } mtx_unlock(&softc->ctl_lock); @@ -9922,6 +9987,7 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio) struct scsi_inquiry_data *inq_ptr; struct scsi_inquiry *cdb; struct ctl_softc *softc; + struct ctl_port *port; struct ctl_lun *lun; char *val; uint32_t alloc_len, data_len; @@ -9934,8 +10000,11 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio) * We treat the ioctl front end, and any SCSI adapters, as packetized * SCSI front ends. */ - port_type = softc->ctl_ports[ - ctl_port_idx(ctsio->io_hdr.nexus.targ_port)]->port_type; + port = ctl_io_port(&ctsio->io_hdr); + if (port != NULL) + port_type = port->port_type; + else + port_type = CTL_PORT_SCSI; if (port_type == CTL_PORT_IOCTL || port_type == CTL_PORT_INTERNAL) port_type = CTL_PORT_SCSI; @@ -9965,55 +10034,16 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio) ctsio->kern_total_len = alloc_len; } - /* - * If we have a LUN configured, report it as connected. Otherwise, - * report that it is offline or no device is supported, depending - * on the value of inquiry_pq_no_lun. - * - * According to the spec (SPC-4 r34), the peripheral qualifier - * SID_QUAL_LU_OFFLINE (001b) is used in the following scenario: - * - * "A peripheral device having the specified peripheral device type - * is not connected to this logical unit. However, the device - * server is capable of supporting the specified peripheral device - * type on this logical unit." - * - * According to the same spec, the peripheral qualifier - * SID_QUAL_BAD_LU (011b) is used in this scenario: - * - * "The device server is not capable of supporting a peripheral - * device on this logical unit. For this peripheral qualifier the - * peripheral device type shall be set to 1Fh. All other peripheral - * device type values are reserved for this peripheral qualifier." - * - * Given the text, it would seem that we probably want to report that - * the LUN is offline here. There is no LUN connected, but we can - * support a LUN at the given LUN number. - * - * In the real world, though, it sounds like things are a little - * different: - * - * - Linux, when presented with a LUN with the offline peripheral - * qualifier, will create an sg driver instance for it. So when - * you attach it to CTL, you wind up with a ton of sg driver - * instances. (One for every LUN that Linux bothered to probe.) - * Linux does this despite the fact that it issues a REPORT LUNs - * to LUN 0 to get the inventory of supported LUNs. - * - * - There is other anecdotal evidence (from Emulex folks) about - * arrays that use the offline peripheral qualifier for LUNs that - * are on the "passive" path in an active/passive array. - * - * So the solution is provide a hopefully reasonable default - * (return bad/no LUN) and allow the user to change the behavior - * with a tunable/sysctl variable. - */ - if (lun != NULL) - inq_ptr->device = (SID_QUAL_LU_CONNECTED << 5) | - lun->be_lun->lun_type; - else if (softc->inquiry_pq_no_lun == 0) - inq_ptr->device = (SID_QUAL_LU_OFFLINE << 5) | T_DIRECT; - else + if (lun != NULL) { + if ((lun->flags & CTL_LUN_PRIMARY_SC) || + softc->ha_link >= CTL_HA_LINK_UNKNOWN) { + inq_ptr->device = (SID_QUAL_LU_CONNECTED << 5) | + lun->be_lun->lun_type; + } else { + inq_ptr->device = (SID_QUAL_LU_OFFLINE << 5) | + lun->be_lun->lun_type; + } + } else inq_ptr->device = (SID_QUAL_BAD_LU << 5) | T_NODEVICE; /* RMB in byte 2 is 0 */ @@ -10441,8 +10471,8 @@ ctl_check_for_blockage(struct ctl_lun *lun, union ctl_io *pending_io, && (ooa_io->scsiio.tag_type == CTL_TAG_UNTAGGED) && ((pending_io->io_hdr.nexus.targ_port == ooa_io->io_hdr.nexus.targ_port) - && (pending_io->io_hdr.nexus.initid.id == - ooa_io->io_hdr.nexus.initid.id)) + && (pending_io->io_hdr.nexus.initid == + ooa_io->io_hdr.nexus.initid)) && ((ooa_io->io_hdr.flags & (CTL_FLAG_ABORT | CTL_FLAG_STATUS_SENT)) == 0)) return (CTL_ACTION_OVERLAP); @@ -10463,8 +10493,8 @@ ctl_check_for_blockage(struct ctl_lun *lun, union ctl_io *pending_io, && (pending_io->scsiio.tag_num == ooa_io->scsiio.tag_num) && ((pending_io->io_hdr.nexus.targ_port == ooa_io->io_hdr.nexus.targ_port) - && (pending_io->io_hdr.nexus.initid.id == - ooa_io->io_hdr.nexus.initid.id)) + && (pending_io->io_hdr.nexus.initid == + ooa_io->io_hdr.nexus.initid)) && ((ooa_io->io_hdr.flags & (CTL_FLAG_ABORT | CTL_FLAG_STATUS_SENT)) == 0)) return (CTL_ACTION_OVERLAP_TAG); @@ -10603,6 +10633,7 @@ ctl_check_ooa(struct ctl_lun *lun, union ctl_io *pending_io, static int ctl_check_blocked(struct ctl_lun *lun) { + struct ctl_softc *softc = lun->ctl_softc; union ctl_io *cur_blocked, *next_blocked; mtx_assert(&lun->lun_lock, MA_OWNED); @@ -10648,7 +10679,6 @@ ctl_check_blocked(struct ctl_lun *lun) case CTL_ACTION_PASS: case CTL_ACTION_SKIP: { const struct ctl_cmd_entry *entry; - int isc_retval; /* * The skip case shouldn't happen, this transaction @@ -10664,24 +10694,21 @@ ctl_check_blocked(struct ctl_lun *lun) blocked_links); cur_blocked->io_hdr.flags &= ~CTL_FLAG_BLOCKED; - if (cur_blocked->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC){ + if ((softc->ha_mode != CTL_HA_MODE_XFER) && + (cur_blocked->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC)){ /* * Need to send IO back to original side to * run */ union ctl_ha_msg msg_info; + cur_blocked->io_hdr.flags &= ~CTL_FLAG_IO_ACTIVE; msg_info.hdr.original_sc = cur_blocked->io_hdr.original_sc; msg_info.hdr.serializing_sc = cur_blocked; msg_info.hdr.msg_type = CTL_MSG_R2R; - if ((isc_retval=ctl_ha_msg_send(CTL_HA_CHAN_CTL, - &msg_info, sizeof(msg_info), 0)) > - CTL_HA_STATUS_SUCCESS) { - printf("CTL:Check Blocked error from " - "ctl_ha_msg_send %d\n", - isc_retval); - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, + sizeof(msg_info.hdr), M_NOWAIT); break; } entry = ctl_get_cmd_entry(&cur_blocked->scsiio, NULL); @@ -10740,14 +10767,32 @@ ctl_scsiio_lun_check(struct ctl_lun *lun, mtx_assert(&lun->lun_lock, MA_OWNED); /* - * If this shelf is a secondary shelf controller, we have to reject - * any media access commands. + * If this shelf is a secondary shelf controller, we may have to + * reject some commands disallowed by HA mode and link state. */ - if ((softc->flags & CTL_FLAG_ACTIVE_SHELF) == 0 && - (entry->flags & CTL_CMD_FLAG_OK_ON_SECONDARY) == 0) { - ctl_set_lun_standby(ctsio); - retval = 1; - goto bailout; + if ((lun->flags & CTL_LUN_PRIMARY_SC) == 0) { + if (softc->ha_link == CTL_HA_LINK_OFFLINE && + (entry->flags & CTL_CMD_FLAG_OK_ON_UNAVAIL) == 0) { + ctl_set_lun_unavail(ctsio); + retval = 1; + goto bailout; + } + if ((lun->flags & CTL_LUN_PEER_SC_PRIMARY) == 0 && + (entry->flags & CTL_CMD_FLAG_OK_ON_UNAVAIL) == 0) { + ctl_set_lun_transit(ctsio); + retval = 1; + goto bailout; + } + if (softc->ha_mode == CTL_HA_MODE_ACT_STBY && + (entry->flags & CTL_CMD_FLAG_OK_ON_STANDBY) == 0) { + ctl_set_lun_standby(ctsio); + retval = 1; + goto bailout; + } + + /* The rest of checks are only done on executing side */ + if (softc->ha_mode == CTL_HA_MODE_XFER) + goto bailout; } if (entry->pattern & CTL_LUN_PAT_WRITE) { @@ -10774,7 +10819,7 @@ ctl_scsiio_lun_check(struct ctl_lun *lun, * even on reserved LUNs, and if this initiator isn't the one who * reserved us, reject the command with a reservation conflict. */ - residx = ctl_get_resindex(&ctsio->io_hdr.nexus); + residx = ctl_get_initindex(&ctsio->io_hdr.nexus); if ((lun->flags & CTL_LUN_RESERVED) && ((entry->flags & CTL_CMD_FLAG_ALLOW_ON_RESV) == 0)) { if (lun->res_idx != residx) { @@ -10804,20 +10849,15 @@ ctl_scsiio_lun_check(struct ctl_lun *lun, retval = 1; goto bailout; } - } if ((lun->flags & CTL_LUN_OFFLINE) - && ((entry->flags & CTL_CMD_FLAG_OK_ON_OFFLINE) == 0)) { + && ((entry->flags & CTL_CMD_FLAG_OK_ON_STANDBY) == 0)) { ctl_set_lun_not_ready(ctsio); retval = 1; goto bailout; } - /* - * If the LUN is stopped, see if this particular command is allowed - * for a stopped lun. Otherwise, reject it with 0x04,0x02. - */ if ((lun->flags & CTL_LUN_STOPPED) && ((entry->flags & CTL_CMD_FLAG_OK_ON_STOPPED) == 0)) { /* "Logical unit not ready, initializing cmd. required" */ @@ -10836,7 +10876,6 @@ ctl_scsiio_lun_check(struct ctl_lun *lun, bailout: return (retval); - } static void @@ -10846,248 +10885,69 @@ ctl_failover_io(union ctl_io *io, int have_lock) ctl_done(io); } -#ifdef notyet static void -ctl_failover(void) +ctl_failover_lun(struct ctl_lun *lun) { - struct ctl_lun *lun; - struct ctl_softc *softc; - union ctl_io *next_io, *pending_io; - union ctl_io *io; - int lun_idx; - - softc = control_softc; - - mtx_lock(&softc->ctl_lock); - /* - * Remove any cmds from the other SC from the rtr queue. These - * will obviously only be for LUNs for which we're the primary. - * We can't send status or get/send data for these commands. - * Since they haven't been executed yet, we can just remove them. - * We'll either abort them or delete them below, depending on - * which HA mode we're in. - */ -#ifdef notyet - mtx_lock(&softc->queue_lock); - for (io = (union ctl_io *)STAILQ_FIRST(&softc->rtr_queue); - io != NULL; io = next_io) { - next_io = (union ctl_io *)STAILQ_NEXT(&io->io_hdr, links); - if (io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC) - STAILQ_REMOVE(&softc->rtr_queue, &io->io_hdr, - ctl_io_hdr, links); - } - mtx_unlock(&softc->queue_lock); -#endif - - for (lun_idx=0; lun_idx < softc->num_luns; lun_idx++) { - lun = softc->ctl_luns[lun_idx]; - if (lun==NULL) - continue; - - /* - * Processor LUNs are primary on both sides. - * XXX will this always be true? - */ - if (lun->be_lun->lun_type == T_PROCESSOR) - continue; - - if ((lun->flags & CTL_LUN_PRIMARY_SC) - && (softc->ha_mode == CTL_HA_MODE_SER_ONLY)) { - printf("FAILOVER: primary lun %d\n", lun_idx); - /* - * Remove all commands from the other SC. First from the - * blocked queue then from the ooa queue. Once we have - * removed them. Call ctl_check_blocked to see if there - * is anything that can run. - */ - for (io = (union ctl_io *)TAILQ_FIRST( - &lun->blocked_queue); io != NULL; io = next_io) { - - next_io = (union ctl_io *)TAILQ_NEXT( - &io->io_hdr, blocked_links); - - if (io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC) { - TAILQ_REMOVE(&lun->blocked_queue, - &io->io_hdr,blocked_links); - io->io_hdr.flags &= ~CTL_FLAG_BLOCKED; - TAILQ_REMOVE(&lun->ooa_queue, - &io->io_hdr, ooa_links); - - ctl_free_io(io); - } - } - - for (io = (union ctl_io *)TAILQ_FIRST(&lun->ooa_queue); - io != NULL; io = next_io) { - - next_io = (union ctl_io *)TAILQ_NEXT( - &io->io_hdr, ooa_links); - - if (io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC) { - - TAILQ_REMOVE(&lun->ooa_queue, - &io->io_hdr, - ooa_links); - - ctl_free_io(io); + struct ctl_softc *softc = lun->ctl_softc; + struct ctl_io_hdr *io, *next_io; + + CTL_DEBUG_PRINT(("FAILOVER for lun %ju\n", lun->lun)); + if (softc->ha_mode == CTL_HA_MODE_XFER) { + TAILQ_FOREACH_SAFE(io, &lun->ooa_queue, ooa_links, next_io) { + /* We are master */ + if (io->flags & CTL_FLAG_FROM_OTHER_SC) { + if (io->flags & CTL_FLAG_IO_ACTIVE) { + io->flags |= CTL_FLAG_ABORT; + } else { /* This can be only due to DATAMOVE */ + io->msg_type = CTL_MSG_DATAMOVE_DONE; + io->flags |= CTL_FLAG_IO_ACTIVE; + io->port_status = 31340; + ctl_enqueue_isc((union ctl_io *)io); } } - ctl_check_blocked(lun); - } else if ((lun->flags & CTL_LUN_PRIMARY_SC) - && (softc->ha_mode == CTL_HA_MODE_XFER)) { - - printf("FAILOVER: primary lun %d\n", lun_idx); - /* - * Abort all commands from the other SC. We can't - * send status back for them now. These should get - * cleaned up when they are completed or come out - * for a datamove operation. - */ - for (io = (union ctl_io *)TAILQ_FIRST(&lun->ooa_queue); - io != NULL; io = next_io) { - next_io = (union ctl_io *)TAILQ_NEXT( - &io->io_hdr, ooa_links); - - if (io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC) - io->io_hdr.flags |= CTL_FLAG_ABORT; - } - } else if (((lun->flags & CTL_LUN_PRIMARY_SC) == 0) - && (softc->ha_mode == CTL_HA_MODE_XFER)) { - - printf("FAILOVER: secondary lun %d\n", lun_idx); - - lun->flags |= CTL_LUN_PRIMARY_SC; - - /* - * We send all I/O that was sent to this controller - * and redirected to the other side back with - * busy status, and have the initiator retry it. - * Figuring out how much data has been transferred, - * etc. and picking up where we left off would be - * very tricky. - * - * XXX KDM need to remove I/O from the blocked - * queue as well! - */ - for (pending_io = (union ctl_io *)TAILQ_FIRST( - &lun->ooa_queue); pending_io != NULL; - pending_io = next_io) { - - next_io = (union ctl_io *)TAILQ_NEXT( - &pending_io->io_hdr, ooa_links); - - pending_io->io_hdr.flags &= - ~CTL_FLAG_SENT_2OTHER_SC; - - if (pending_io->io_hdr.flags & - CTL_FLAG_IO_ACTIVE) { - pending_io->io_hdr.flags |= - CTL_FLAG_FAILOVER; + /* We are slave */ + if (io->flags & CTL_FLAG_SENT_2OTHER_SC) { + io->flags &= ~CTL_FLAG_SENT_2OTHER_SC; + if (io->flags & CTL_FLAG_IO_ACTIVE) { + io->flags |= CTL_FLAG_FAILOVER; } else { - ctl_set_busy(&pending_io->scsiio); - ctl_done(pending_io); + ctl_set_busy(&((union ctl_io *)io)-> + scsiio); + ctl_done((union ctl_io *)io); } } - - ctl_est_ua_all(lun, -1, CTL_UA_ASYM_ACC_CHANGE); - } else if (((lun->flags & CTL_LUN_PRIMARY_SC) == 0) - && (softc->ha_mode == CTL_HA_MODE_SER_ONLY)) { - printf("FAILOVER: secondary lun %d\n", lun_idx); - /* - * if the first io on the OOA is not on the RtR queue - * add it. - */ - lun->flags |= CTL_LUN_PRIMARY_SC; - - pending_io = (union ctl_io *)TAILQ_FIRST( - &lun->ooa_queue); - if (pending_io==NULL) { - printf("Nothing on OOA queue\n"); - continue; - } - - pending_io->io_hdr.flags &= ~CTL_FLAG_SENT_2OTHER_SC; - if ((pending_io->io_hdr.flags & - CTL_FLAG_IS_WAS_ON_RTR) == 0) { - pending_io->io_hdr.flags |= - CTL_FLAG_IS_WAS_ON_RTR; - ctl_enqueue_rtr(pending_io); + } + } else { /* SERIALIZE modes */ + TAILQ_FOREACH_SAFE(io, &lun->blocked_queue, blocked_links, + next_io) { + /* We are master */ + if (io->flags & CTL_FLAG_FROM_OTHER_SC) { + TAILQ_REMOVE(&lun->blocked_queue, io, + blocked_links); + io->flags &= ~CTL_FLAG_BLOCKED; + TAILQ_REMOVE(&lun->ooa_queue, io, ooa_links); + ctl_free_io((union ctl_io *)io); } -#if 0 - else - { - printf("Tag 0x%04x is running\n", - pending_io->scsiio.tag_num); + } + TAILQ_FOREACH_SAFE(io, &lun->ooa_queue, ooa_links, next_io) { + /* We are master */ + if (io->flags & CTL_FLAG_FROM_OTHER_SC) { + TAILQ_REMOVE(&lun->ooa_queue, io, ooa_links); + ctl_free_io((union ctl_io *)io); } -#endif - - next_io = (union ctl_io *)TAILQ_NEXT( - &pending_io->io_hdr, ooa_links); - for (pending_io=next_io; pending_io != NULL; - pending_io = next_io) { - pending_io->io_hdr.flags &= - ~CTL_FLAG_SENT_2OTHER_SC; - next_io = (union ctl_io *)TAILQ_NEXT( - &pending_io->io_hdr, ooa_links); - if (pending_io->io_hdr.flags & - CTL_FLAG_IS_WAS_ON_RTR) { -#if 0 - printf("Tag 0x%04x is running\n", - pending_io->scsiio.tag_num); -#endif - continue; - } - - switch (ctl_check_ooa(lun, pending_io, - (union ctl_io *)TAILQ_PREV( - &pending_io->io_hdr, ctl_ooaq, - ooa_links))) { - - case CTL_ACTION_BLOCK: - TAILQ_INSERT_TAIL(&lun->blocked_queue, - &pending_io->io_hdr, - blocked_links); - pending_io->io_hdr.flags |= - CTL_FLAG_BLOCKED; - break; - case CTL_ACTION_PASS: - case CTL_ACTION_SKIP: - pending_io->io_hdr.flags |= - CTL_FLAG_IS_WAS_ON_RTR; - ctl_enqueue_rtr(pending_io); - break; - case CTL_ACTION_OVERLAP: - ctl_set_overlapped_cmd( - (struct ctl_scsiio *)pending_io); - ctl_done(pending_io); - break; - case CTL_ACTION_OVERLAP_TAG: - ctl_set_overlapped_tag( - (struct ctl_scsiio *)pending_io, - pending_io->scsiio.tag_num & 0xff); - ctl_done(pending_io); - break; - case CTL_ACTION_ERROR: - default: - ctl_set_internal_failure( - (struct ctl_scsiio *)pending_io, - 0, // sks_valid - 0); //retry count - ctl_done(pending_io); - break; + /* We are slave */ + if (io->flags & CTL_FLAG_SENT_2OTHER_SC) { + io->flags &= ~CTL_FLAG_SENT_2OTHER_SC; + if (!(io->flags & CTL_FLAG_IO_ACTIVE)) { + ctl_set_busy(&((union ctl_io *)io)-> + scsiio); + ctl_done((union ctl_io *)io); } } - - ctl_est_ua_all(lun, -1, CTL_UA_ASYM_ACC_CHANGE); - } else { - panic("Unhandled HA mode failover, LUN flags = %#x, " - "ha_mode = #%x", lun->flags, softc->ha_mode); } + ctl_check_blocked(lun); } - ctl_pause_rtr = 0; - mtx_unlock(&softc->ctl_lock); } -#endif static int ctl_scsiio_precheck(struct ctl_softc *softc, struct ctl_scsiio *ctsio) @@ -11119,9 +10979,6 @@ ctl_scsiio_precheck(struct ctl_softc *softc, struct ctl_scsiio *ctsio) ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr = lun; ctsio->io_hdr.ctl_private[CTL_PRIV_BACKEND_LUN].ptr = lun->be_lun; - if (lun->be_lun->lun_type == T_PROCESSOR) { - ctsio->io_hdr.flags |= CTL_FLAG_CONTROL_DEV; - } /* * Every I/O goes into the OOA queue for a @@ -11256,45 +11113,31 @@ ctl_scsiio_precheck(struct ctl_softc *softc, struct ctl_scsiio *ctsio) * find it easily. Something similar will need be done on the other * side so when we are done we can find the copy. */ - if ((lun->flags & CTL_LUN_PRIMARY_SC) == 0) { + if ((lun->flags & CTL_LUN_PRIMARY_SC) == 0 && + (lun->flags & CTL_LUN_PEER_SC_PRIMARY) != 0) { union ctl_ha_msg msg_info; int isc_retval; ctsio->io_hdr.flags |= CTL_FLAG_SENT_2OTHER_SC; + ctsio->io_hdr.flags &= ~CTL_FLAG_IO_ACTIVE; + mtx_unlock(&lun->lun_lock); msg_info.hdr.msg_type = CTL_MSG_SERIALIZE; msg_info.hdr.original_sc = (union ctl_io *)ctsio; -#if 0 - printf("1. ctsio %p\n", ctsio); -#endif msg_info.hdr.serializing_sc = NULL; msg_info.hdr.nexus = ctsio->io_hdr.nexus; msg_info.scsi.tag_num = ctsio->tag_num; msg_info.scsi.tag_type = ctsio->tag_type; + msg_info.scsi.cdb_len = ctsio->cdb_len; memcpy(msg_info.scsi.cdb, ctsio->cdb, CTL_MAX_CDBLEN); - ctsio->io_hdr.flags &= ~CTL_FLAG_IO_ACTIVE; - - if ((isc_retval=ctl_ha_msg_send(CTL_HA_CHAN_CTL, - (void *)&msg_info, sizeof(msg_info), 0)) > - CTL_HA_STATUS_SUCCESS) { - printf("CTL:precheck, ctl_ha_msg_send returned %d\n", - isc_retval); - printf("CTL:opcode is %x\n", ctsio->cdb[0]); - } else { -#if 0 - printf("CTL:Precheck sent msg, opcode is %x\n",opcode); -#endif + if ((isc_retval = ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, + sizeof(msg_info.scsi) - sizeof(msg_info.scsi.sense_data), + M_WAITOK)) > CTL_HA_STATUS_SUCCESS) { + ctl_set_busy(ctsio); + ctl_done((union ctl_io *)ctsio); + return (retval); } - - /* - * XXX KDM this I/O is off the incoming queue, but hasn't - * been inserted on any other queue. We may need to come - * up with a holding queue while we wait for serialization - * so that we have an idea of what we're waiting for from - * the other side. - */ - mtx_unlock(&lun->lun_lock); return (retval); } @@ -11464,7 +11307,6 @@ ctl_target_reset(struct ctl_softc *softc, union ctl_io *io, if (!(io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC)) { union ctl_ha_msg msg_info; - io->io_hdr.flags |= CTL_FLAG_SENT_2OTHER_SC; msg_info.hdr.nexus = io->io_hdr.nexus; if (ua_type==CTL_UA_TARG_RESET) msg_info.task.task_action = CTL_TASK_TARGET_RESET; @@ -11473,9 +11315,8 @@ ctl_target_reset(struct ctl_softc *softc, union ctl_io *io, msg_info.hdr.msg_type = CTL_MSG_MANAGE_TASKS; msg_info.hdr.original_sc = NULL; msg_info.hdr.serializing_sc = NULL; - if (CTL_HA_STATUS_SUCCESS != ctl_ha_msg_send(CTL_HA_CHAN_CTL, - (void *)&msg_info, sizeof(msg_info), 0)) { - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, + sizeof(msg_info.task), M_WAITOK); } retval = 0; @@ -11578,9 +11419,9 @@ ctl_abort_tasks_lun(struct ctl_lun *lun, uint32_t targ_port, uint32_t init_id, if ((targ_port == UINT32_MAX || targ_port == xio->io_hdr.nexus.targ_port) && (init_id == UINT32_MAX || - init_id == xio->io_hdr.nexus.initid.id)) { + init_id == xio->io_hdr.nexus.initid)) { if (targ_port != xio->io_hdr.nexus.targ_port || - init_id != xio->io_hdr.nexus.initid.id) + init_id != xio->io_hdr.nexus.initid) xio->io_hdr.flags |= CTL_FLAG_ABORT_STATUS; xio->io_hdr.flags |= CTL_FLAG_ABORT; if (!other_sc && !(lun->flags & CTL_LUN_PRIMARY_SC)) { @@ -11593,8 +11434,8 @@ ctl_abort_tasks_lun(struct ctl_lun *lun, uint32_t targ_port, uint32_t init_id, 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, - (void *)&msg_info, sizeof(msg_info), 0); + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, + sizeof(msg_info.task), M_NOWAIT); } } } @@ -11623,7 +11464,7 @@ ctl_abort_task_set(union ctl_io *io) mtx_unlock(&softc->ctl_lock); if (io->taskio.task_action == CTL_TASK_ABORT_TASK_SET) { ctl_abort_tasks_lun(lun, io->io_hdr.nexus.targ_port, - io->io_hdr.nexus.initid.id, + io->io_hdr.nexus.initid, (io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC) != 0); } else { /* CTL_TASK_CLEAR_TASK_SET */ ctl_abort_tasks_lun(lun, UINT32_MAX, UINT32_MAX, @@ -11638,20 +11479,19 @@ ctl_i_t_nexus_reset(union ctl_io *io) { struct ctl_softc *softc = control_softc; struct ctl_lun *lun; - uint32_t initidx, residx; + uint32_t initidx; initidx = ctl_get_initindex(&io->io_hdr.nexus); - residx = ctl_get_resindex(&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.id, + io->io_hdr.nexus.initid, (io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC) != 0); #ifdef CTL_WITH_CA ctl_clear_mask(lun->have_ca, initidx); #endif - if ((lun->flags & CTL_LUN_RESERVED) && (lun->res_idx == residx)) + if ((lun->flags & CTL_LUN_RESERVED) && (lun->res_idx == initidx)) lun->flags &= ~CTL_LUN_RESERVED; ctl_est_ua(lun, initidx, CTL_UA_I_T_NEXUS_LOSS); mtx_unlock(&lun->lun_lock); @@ -11725,7 +11565,7 @@ ctl_abort_task(union ctl_io *io) #endif if ((xio->io_hdr.nexus.targ_port != io->io_hdr.nexus.targ_port) - || (xio->io_hdr.nexus.initid.id != io->io_hdr.nexus.initid.id) + || (xio->io_hdr.nexus.initid != io->io_hdr.nexus.initid) || (xio->io_hdr.flags & CTL_FLAG_ABORT)) continue; @@ -11756,7 +11596,6 @@ ctl_abort_task(union ctl_io *io) !(lun->flags & CTL_LUN_PRIMARY_SC)) { union ctl_ha_msg msg_info; - io->io_hdr.flags |= CTL_FLAG_SENT_2OTHER_SC; msg_info.hdr.nexus = io->io_hdr.nexus; msg_info.task.task_action = CTL_TASK_ABORT_TASK; msg_info.task.tag_num = io->taskio.tag_num; @@ -11767,10 +11606,8 @@ ctl_abort_task(union ctl_io *io) #if 0 printf("Sent Abort to other side\n"); #endif - if (ctl_ha_msg_send(CTL_HA_CHAN_CTL, - (void *)&msg_info, sizeof(msg_info), 0) != - CTL_HA_STATUS_SUCCESS) { - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, + sizeof(msg_info.task), M_NOWAIT); } #if 0 printf("ctl_abort_task: found I/O to abort\n"); @@ -11787,10 +11624,9 @@ ctl_abort_task(union ctl_io *io) */ #if 0 printf("ctl_abort_task: ABORT sent for nonexistent I/O: " - "%d:%d:%d:%d tag %d type %d\n", - io->io_hdr.nexus.initid.id, + "%u:%u:%u tag %d type %d\n", + io->io_hdr.nexus.initid, io->io_hdr.nexus.targ_port, - io->io_hdr.nexus.targ_target.id, io->io_hdr.nexus.targ_lun, io->taskio.tag_num, io->taskio.tag_type); #endif @@ -11865,30 +11701,20 @@ ctl_run_task(union ctl_io *io) 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)) { + if ((io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC) == 0) { union ctl_ha_msg msg_info; - io->io_hdr.flags |= - CTL_FLAG_SENT_2OTHER_SC; - msg_info.hdr.msg_type = - CTL_MSG_MANAGE_TASKS; + 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.task.task_action = CTL_TASK_LUN_RESET; msg_info.hdr.original_sc = NULL; msg_info.hdr.serializing_sc = NULL; - if (CTL_HA_STATUS_SUCCESS != - ctl_ha_msg_send(CTL_HA_CHAN_CTL, - (void *)&msg_info, - sizeof(msg_info), 0)) { - } + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info, + sizeof(msg_info.task), M_WAITOK); } - - retval = ctl_lun_reset(lun, io, - CTL_UA_LUN_RESET); - mtx_unlock(&softc->ctl_lock); break; } case CTL_TASK_TARGET_RESET: @@ -11986,6 +11812,12 @@ ctl_handle_isc(union ctl_io *io) free_io = 0; io->scsiio.be_move_done(io); break; + case CTL_MSG_FAILOVER: + mtx_lock(&lun->lun_lock); + ctl_failover_lun(lun); + mtx_unlock(&lun->lun_lock); + free_io = 1; + break; default: free_io = 1; printf("%s: Invalid message type %d\n", @@ -12187,10 +12019,6 @@ ctl_datamove(union ctl_io *io) #ifdef CTL_IO_DELAY if (io->io_hdr.flags & CTL_FLAG_DELAY_DONE) { - struct ctl_lun *lun; - - lun =(struct ctl_lun *)io->io_hdr.ctl_private[CTL_PRIV_LUN].ptr; - io->io_hdr.flags &= ~CTL_FLAG_DELAY_DONE; } else { struct ctl_lun *lun; @@ -12198,12 +12026,10 @@ ctl_datamove(union ctl_io *io) lun =(struct ctl_lun *)io->io_hdr.ctl_private[CTL_PRIV_LUN].ptr; if ((lun != NULL) && (lun->delay_info.datamove_delay > 0)) { - struct callout *callout; - callout = (struct callout *)&io->io_hdr.timer_bytes; - callout_init(callout, /*mpsafe*/ 1); + callout_init(&io->io_hdr.delay_callout, /*mpsafe*/ 1); io->io_hdr.flags |= CTL_FLAG_DELAY_DONE; - callout_reset(callout, + callout_reset(&io->io_hdr.delay_callout, lun->delay_info.datamove_delay * hz, ctl_datamove_timer_wakeup, io); if (lun->delay_info.datamove_type == @@ -12219,10 +12045,9 @@ ctl_datamove(union ctl_io *io) * the data move. */ if (io->io_hdr.flags & CTL_FLAG_ABORT) { - printf("ctl_datamove: tag 0x%04x on (%ju:%d:%ju:%d) aborted\n", - io->scsiio.tag_num,(uintmax_t)io->io_hdr.nexus.initid.id, + printf("ctl_datamove: tag 0x%04x on (%u:%u:%u) aborted\n", + io->scsiio.tag_num, io->io_hdr.nexus.initid, io->io_hdr.nexus.targ_port, - (uintmax_t)io->io_hdr.nexus.targ_target.id, io->io_hdr.nexus.targ_lun); io->io_hdr.port_status = 31337; /* @@ -12270,21 +12095,7 @@ ctl_datamove(union ctl_io *io) */ if (io->scsiio.kern_sg_entries == 0) { msg.dt.kern_sg_entries = 1; - /* - * If this is in cached memory, flush the cache - * before we send the DMA request to the other - * controller. We want to do this in either the - * read or the write case. The read case is - * straightforward. In the write case, we want to - * make sure nothing is in the local cache that - * could overwrite the DMAed data. - */ - if ((io->io_hdr.flags & CTL_FLAG_NO_DATASYNC) == 0) { - /* - * XXX KDM use bus_dmamap_sync() here. - */ - } - +#if 0 /* * Convert to a physical address if this is a * virtual address. @@ -12296,25 +12107,20 @@ ctl_datamove(union ctl_io *io) /* * XXX KDM use busdma here! */ -#if 0 msg.dt.sg_list[0].addr = (void *) vtophys(io->scsiio.kern_data_ptr); -#endif } +#else + KASSERT((io->io_hdr.flags & CTL_FLAG_BUS_ADDR) == 0, + ("HA does not support BUS_ADDR")); + msg.dt.sg_list[0].addr = io->scsiio.kern_data_ptr; +#endif msg.dt.sg_list[0].len = io->scsiio.kern_data_len; do_sg_copy = 0; } else { - struct ctl_sg_entry *sgl; - - do_sg_copy = 1; msg.dt.kern_sg_entries = io->scsiio.kern_sg_entries; - sgl = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; - if ((io->io_hdr.flags & CTL_FLAG_NO_DATASYNC) == 0) { - /* - * XXX KDM use bus_dmamap_sync() here. - */ - } + do_sg_copy = 1; } msg.dt.kern_data_len = io->scsiio.kern_data_len; @@ -12353,25 +12159,24 @@ ctl_datamove(union ctl_io *io) for (i = sg_entries_sent, j = 0; i < msg.dt.cur_sg_entries; i++, j++) { - if ((io->io_hdr.flags & - CTL_FLAG_NO_DATASYNC) == 0) { - /* - * XXX KDM use bus_dmamap_sync() - */ - } +#if 0 if ((io->io_hdr.flags & CTL_FLAG_BUS_ADDR) == 0) { /* * XXX KDM use busdma. */ -#if 0 msg.dt.sg_list[j].addr =(void *) vtophys(sgl[i].addr); -#endif } else { msg.dt.sg_list[j].addr = sgl[i].addr; } +#else + KASSERT((io->io_hdr.flags & + CTL_FLAG_BUS_ADDR) == 0, + ("HA does not support BUS_ADDR")); + msg.dt.sg_list[j].addr = sgl[i].addr; +#endif msg.dt.sg_list[j].len = sgl[i].len; } } @@ -12382,30 +12187,25 @@ ctl_datamove(union ctl_io *io) else msg.dt.sg_last = 0; - /* - * XXX KDM drop and reacquire the lock here? - */ if (ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg, - sizeof(msg), 0) > CTL_HA_STATUS_SUCCESS) { - /* - * XXX do something here. - */ + sizeof(msg.dt) - sizeof(msg.dt.sg_list) + + sizeof(struct ctl_sg_entry)*msg.dt.cur_sg_entries, + M_WAITOK) > CTL_HA_STATUS_SUCCESS) { + io->io_hdr.port_status = 31341; + io->scsiio.be_move_done(io); + return; } msg.dt.sent_sg_entries = sg_entries_sent; } io->io_hdr.flags &= ~CTL_FLAG_IO_ACTIVE; - if (io->io_hdr.flags & CTL_FLAG_FAILOVER) - ctl_failover_io(io, /*have_lock*/ 0); - } else { /* * Lookup the fe_datamove() function for this particular * front end. */ - fe_datamove = - control_softc->ctl_ports[ctl_port_idx(io->io_hdr.nexus.targ_port)]->fe_datamove; + fe_datamove = ctl_io_port(&io->io_hdr)->fe_datamove; fe_datamove(io); } @@ -12415,7 +12215,6 @@ static void ctl_send_datamove_done(union ctl_io *io, int have_lock) { union ctl_ha_msg msg; - int isc_status; memset(&msg, 0, sizeof(msg)); @@ -12428,7 +12227,7 @@ ctl_send_datamove_done(union ctl_io *io, int have_lock) msg.scsi.tag_type = io->scsiio.tag_type; msg.scsi.scsi_status = io->scsiio.scsi_status; memcpy(&msg.scsi.sense_data, &io->scsiio.sense_data, - sizeof(io->scsiio.sense_data)); + io->scsiio.sense_len); msg.scsi.sense_len = io->scsiio.sense_len; msg.scsi.sense_residual = io->scsiio.sense_residual; msg.scsi.fetd_status = io->io_hdr.port_status; @@ -12440,11 +12239,9 @@ ctl_send_datamove_done(union ctl_io *io, int have_lock) return; } - isc_status = ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg, sizeof(msg), 0); - if (isc_status > CTL_HA_STATUS_SUCCESS) { - /* XXX do something if this fails */ - } - + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg, + sizeof(msg.scsi) - sizeof(msg.scsi.sense_data) + + msg.scsi.sense_len, M_WAITOK); } /* @@ -12455,6 +12252,7 @@ static void ctl_datamove_remote_write_cb(struct ctl_ha_dt_req *rq) { union ctl_io *io; + int i; io = rq->context; @@ -12468,14 +12266,12 @@ ctl_datamove_remote_write_cb(struct ctl_ha_dt_req *rq) ctl_dt_req_free(rq); - /* - * In this case, we had to malloc the memory locally. Free it. - */ - if ((io->io_hdr.flags & CTL_FLAG_AUTO_MIRROR) == 0) { - int i; - for (i = 0; i < io->scsiio.kern_sg_entries; i++) - free(io->io_hdr.local_sglist[i].addr, M_CTL); - } + for (i = 0; i < io->scsiio.kern_sg_entries; i++) + free(io->io_hdr.local_sglist[i].addr, M_CTL); + free(io->io_hdr.remote_sglist, M_CTL); + io->io_hdr.remote_sglist = NULL; + io->io_hdr.local_sglist = NULL; + /* * The data is in local and remote memory, so now we need to send * status (good or back) back to the other side. @@ -12525,7 +12321,7 @@ ctl_datamove_remote_write(union ctl_io *io) */ io->scsiio.be_move_done = ctl_datamove_remote_dm_write_cb; - fe_datamove = control_softc->ctl_ports[ctl_port_idx(io->io_hdr.nexus.targ_port)]->fe_datamove; + fe_datamove = ctl_io_port(&io->io_hdr)->fe_datamove; fe_datamove(io); @@ -12541,15 +12337,13 @@ ctl_datamove_remote_dm_read_cb(union ctl_io *io) char path_str[64]; struct sbuf sb; #endif + int i; - /* - * In this case, we had to malloc the memory locally. Free it. - */ - if ((io->io_hdr.flags & CTL_FLAG_AUTO_MIRROR) == 0) { - int i; - for (i = 0; i < io->scsiio.kern_sg_entries; i++) - free(io->io_hdr.local_sglist[i].addr, M_CTL); - } + for (i = 0; i < io->scsiio.kern_sg_entries; i++) + free(io->io_hdr.local_sglist[i].addr, M_CTL); + free(io->io_hdr.remote_sglist, M_CTL); + io->io_hdr.remote_sglist = NULL; + io->io_hdr.local_sglist = NULL; #if 0 scsi_path_string(io, path_str, sizeof(path_str)); @@ -12586,7 +12380,7 @@ ctl_datamove_remote_read_cb(struct ctl_ha_dt_req *rq) io = rq->context; if (rq->ret != CTL_HA_STATUS_SUCCESS) { - printf("%s: ISC DMA read failed with error %d", __func__, + printf("%s: ISC DMA read failed with error %d\n", __func__, rq->ret); ctl_set_internal_failure(&io->scsiio, /*sks_valid*/ 1, @@ -12606,7 +12400,7 @@ ctl_datamove_remote_read_cb(struct ctl_ha_dt_req *rq) /* XXX KDM add checks like the ones in ctl_datamove? */ - fe_datamove = control_softc->ctl_ports[ctl_port_idx(io->io_hdr.nexus.targ_port)]->fe_datamove; + fe_datamove = ctl_io_port(&io->io_hdr)->fe_datamove; fe_datamove(io); } @@ -12615,134 +12409,43 @@ static int ctl_datamove_remote_sgl_setup(union ctl_io *io) { struct ctl_sg_entry *local_sglist, *remote_sglist; - struct ctl_sg_entry *local_dma_sglist, *remote_dma_sglist; struct ctl_softc *softc; + uint32_t len_to_go; int retval; int i; retval = 0; softc = control_softc; - local_sglist = io->io_hdr.local_sglist; - local_dma_sglist = io->io_hdr.local_dma_sglist; remote_sglist = io->io_hdr.remote_sglist; - remote_dma_sglist = io->io_hdr.remote_dma_sglist; - - if (io->io_hdr.flags & CTL_FLAG_AUTO_MIRROR) { - for (i = 0; i < io->scsiio.kern_sg_entries; i++) { - local_sglist[i].len = remote_sglist[i].len; - - /* - * XXX Detect the situation where the RS-level I/O - * redirector on the other side has already read the - * data off of the AOR RS on this side, and - * transferred it to remote (mirror) memory on the - * other side. Since we already have the data in - * memory here, we just need to use it. - * - * XXX KDM this can probably be removed once we - * get the cache device code in and take the - * current AOR implementation out. - */ -#ifdef NEEDTOPORT - if ((remote_sglist[i].addr >= - (void *)vtophys(softc->mirr->addr)) - && (remote_sglist[i].addr < - ((void *)vtophys(softc->mirr->addr) + - CacheMirrorOffset))) { - local_sglist[i].addr = remote_sglist[i].addr - - CacheMirrorOffset; - if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == - CTL_FLAG_DATA_IN) - io->io_hdr.flags |= CTL_FLAG_REDIR_DONE; - } else { - local_sglist[i].addr = remote_sglist[i].addr + - CacheMirrorOffset; - } -#endif -#if 0 - printf("%s: local %p, remote %p, len %d\n", - __func__, local_sglist[i].addr, - remote_sglist[i].addr, local_sglist[i].len); -#endif - } - } else { - uint32_t len_to_go; - - /* - * In this case, we don't have automatically allocated - * memory for this I/O on this controller. This typically - * happens with internal CTL I/O -- e.g. inquiry, mode - * sense, etc. Anything coming from RAIDCore will have - * a mirror area available. - */ - len_to_go = io->scsiio.kern_data_len; - - /* - * Clear the no datasync flag, we have to use malloced - * buffers. - */ - io->io_hdr.flags &= ~CTL_FLAG_NO_DATASYNC; + len_to_go = io->scsiio.kern_data_len; - /* - * The difficult thing here is that the size of the various - * S/G segments may be different than the size from the - * remote controller. That'll make it harder when DMAing - * the data back to the other side. - */ - for (i = 0; (i < sizeof(io->io_hdr.remote_sglist) / - sizeof(io->io_hdr.remote_sglist[0])) && - (len_to_go > 0); i++) { - local_sglist[i].len = MIN(len_to_go, 131072); - CTL_SIZE_8B(local_dma_sglist[i].len, - local_sglist[i].len); - local_sglist[i].addr = - malloc(local_dma_sglist[i].len, M_CTL,M_WAITOK); - - local_dma_sglist[i].addr = local_sglist[i].addr; - - if (local_sglist[i].addr == NULL) { - int j; - - printf("malloc failed for %zd bytes!", - local_dma_sglist[i].len); - for (j = 0; j < i; j++) { - free(local_sglist[j].addr, M_CTL); - } - ctl_set_internal_failure(&io->scsiio, - /*sks_valid*/ 1, - /*retry_count*/ 4857); - retval = 1; - goto bailout_error; - - } - /* XXX KDM do we need a sync here? */ + /* + * The difficult thing here is that the size of the various + * S/G segments may be different than the size from the + * remote controller. That'll make it harder when DMAing + * the data back to the other side. + */ + for (i = 0; len_to_go > 0; i++) { + local_sglist[i].len = MIN(len_to_go, CTL_HA_DATAMOVE_SEGMENT); + local_sglist[i].addr = + malloc(local_sglist[i].len, M_CTL, M_WAITOK); - len_to_go -= local_sglist[i].len; - } - /* - * Reset the number of S/G entries accordingly. The - * original number of S/G entries is available in - * rem_sg_entries. - */ - io->scsiio.kern_sg_entries = i; + len_to_go -= local_sglist[i].len; + } + /* + * Reset the number of S/G entries accordingly. The original + * number of S/G entries is available in rem_sg_entries. + */ + io->scsiio.kern_sg_entries = i; #if 0 - printf("%s: kern_sg_entries = %d\n", __func__, - io->scsiio.kern_sg_entries); - for (i = 0; i < io->scsiio.kern_sg_entries; i++) - printf("%s: sg[%d] = %p, %d (DMA: %d)\n", __func__, i, - local_sglist[i].addr, local_sglist[i].len, - local_dma_sglist[i].len); + printf("%s: kern_sg_entries = %d\n", __func__, + io->scsiio.kern_sg_entries); + for (i = 0; i < io->scsiio.kern_sg_entries; i++) + printf("%s: sg[%d] = %p, %d\n", __func__, i, + local_sglist[i].addr, local_sglist[i].len); #endif - } - - - return (retval); - -bailout_error: - - ctl_send_datamove_done(io, /*have_lock*/ 0); return (retval); } @@ -12753,12 +12456,8 @@ ctl_datamove_remote_xfer(union ctl_io *io, unsigned command, { struct ctl_ha_dt_req *rq; struct ctl_sg_entry *remote_sglist, *local_sglist; - struct ctl_sg_entry *remote_dma_sglist, *local_dma_sglist; uint32_t local_used, remote_used, total_used; - int retval; - int i, j; - - retval = 0; + int i, j, isc_ret; rq = ctl_dt_req_alloc(); @@ -12784,26 +12483,15 @@ ctl_datamove_remote_xfer(union ctl_io *io, unsigned command, ctl_send_datamove_done(io, /*have_lock*/ 0); - retval = 1; - - goto bailout; + return (1); } local_sglist = io->io_hdr.local_sglist; - local_dma_sglist = io->io_hdr.local_dma_sglist; remote_sglist = io->io_hdr.remote_sglist; - remote_dma_sglist = io->io_hdr.remote_dma_sglist; local_used = 0; remote_used = 0; total_used = 0; - if (io->io_hdr.flags & CTL_FLAG_REDIR_DONE) { - rq->ret = CTL_HA_STATUS_SUCCESS; - rq->context = io; - callback(rq); - goto bailout; - } - /* * Pull/push the data over the wire from/to the other controller. * This takes into account the possibility that the local and @@ -12814,12 +12502,11 @@ ctl_datamove_remote_xfer(union ctl_io *io, unsigned command, * both the local and remote sglists is identical. Otherwise, we've * essentially got a coding error of some sort. */ + isc_ret = CTL_HA_STATUS_SUCCESS; for (i = 0, j = 0; total_used < io->scsiio.kern_data_len; ) { - int isc_ret; - uint32_t cur_len, dma_length; + uint32_t cur_len; uint8_t *tmp_ptr; - rq->id = CTL_HA_DATA_CTL; rq->command = command; rq->context = io; @@ -12831,52 +12518,23 @@ ctl_datamove_remote_xfer(union ctl_io *io, unsigned command, */ cur_len = MIN(local_sglist[i].len - local_used, remote_sglist[j].len - remote_used); - - /* - * In this case, we have a size issue and need to decrease - * the size, except in the case where we actually have less - * than 8 bytes left. In that case, we need to increase - * the DMA length to get the last bit. - */ - if ((cur_len & 0x7) != 0) { - if (cur_len > 0x7) { - cur_len = cur_len - (cur_len & 0x7); - dma_length = cur_len; - } else { - CTL_SIZE_8B(dma_length, cur_len); - } - - } else - dma_length = cur_len; - - /* - * If we had to allocate memory for this I/O, instead of using - * the non-cached mirror memory, we'll need to flush the cache - * before trying to DMA to the other controller. - * - * We could end up doing this multiple times for the same - * segment if we have a larger local segment than remote - * segment. That shouldn't be an issue. - */ - if ((io->io_hdr.flags & CTL_FLAG_NO_DATASYNC) == 0) { - /* - * XXX KDM use bus_dmamap_sync() here. - */ - } - - rq->size = dma_length; + rq->size = cur_len; tmp_ptr = (uint8_t *)local_sglist[i].addr; tmp_ptr += local_used; +#if 0 /* Use physical addresses when talking to ISC hardware */ if ((io->io_hdr.flags & CTL_FLAG_BUS_ADDR) == 0) { /* XXX KDM use busdma */ -#if 0 rq->local = vtophys(tmp_ptr); -#endif } else rq->local = tmp_ptr; +#else + KASSERT((io->io_hdr.flags & CTL_FLAG_BUS_ADDR) == 0, + ("HA does not support BUS_ADDR")); + rq->local = tmp_ptr; +#endif tmp_ptr = (uint8_t *)remote_sglist[j].addr; tmp_ptr += remote_used; @@ -12900,18 +12558,6 @@ ctl_datamove_remote_xfer(union ctl_io *io, unsigned command, if (total_used >= io->scsiio.kern_data_len) rq->callback = callback; - if ((rq->size & 0x7) != 0) { - printf("%s: warning: size %d is not on 8b boundary\n", - __func__, rq->size); - } - if (((uintptr_t)rq->local & 0x7) != 0) { - printf("%s: warning: local %p not on 8b boundary\n", - __func__, rq->local); - } - if (((uintptr_t)rq->remote & 0x7) != 0) { - printf("%s: warning: remote %p not on 8b boundary\n", - __func__, rq->local); - } #if 0 printf("%s: %s: local %#x remote %#x size %d\n", __func__, (command == CTL_HA_DT_CMD_WRITE) ? "WRITE" : "READ", @@ -12919,21 +12565,15 @@ ctl_datamove_remote_xfer(union ctl_io *io, unsigned command, #endif isc_ret = ctl_dt_single(rq); - if (isc_ret == CTL_HA_STATUS_WAIT) - continue; - - if (isc_ret == CTL_HA_STATUS_DISCONNECT) { - rq->ret = CTL_HA_STATUS_SUCCESS; - } else { - rq->ret = isc_ret; - } + if (isc_ret > CTL_HA_STATUS_SUCCESS) + break; + } + if (isc_ret != CTL_HA_STATUS_WAIT) { + rq->ret = isc_ret; callback(rq); - goto bailout; } -bailout: - return (retval); - + return (0); } static void @@ -12952,8 +12592,7 @@ ctl_datamove_remote_read(union ctl_io *io) retval = ctl_datamove_remote_xfer(io, CTL_HA_DT_CMD_READ, ctl_datamove_remote_read_cb); - if ((retval != 0) - && ((io->io_hdr.flags & CTL_FLAG_AUTO_MIRROR) == 0)) { + if (retval != 0) { /* * Make sure we free memory if there was an error.. The * ctl_datamove_remote_xfer() function will send the @@ -12962,6 +12601,9 @@ ctl_datamove_remote_read(union ctl_io *io) */ for (i = 0; i < io->scsiio.kern_sg_entries; i++) free(io->io_hdr.local_sglist[i].addr, M_CTL); + free(io->io_hdr.remote_sglist, M_CTL); + io->io_hdr.remote_sglist = NULL; + io->io_hdr.local_sglist = NULL; } return; @@ -12977,11 +12619,13 @@ ctl_datamove_remote_read(union ctl_io *io) static void ctl_datamove_remote(union ctl_io *io) { - struct ctl_softc *softc; - softc = control_softc; + mtx_assert(&control_softc->ctl_lock, MA_NOTOWNED); - mtx_assert(&softc->ctl_lock, MA_NOTOWNED); + if (io->io_hdr.flags & CTL_FLAG_FAILOVER) { + ctl_failover_io(io, /*have_lock*/ 0); + return; + } /* * Note that we look for an aborted I/O here, but don't do some of @@ -12990,64 +12634,23 @@ ctl_datamove_remote(union ctl_io *io) * have been done if need be on the other controller. */ if (io->io_hdr.flags & CTL_FLAG_ABORT) { - printf("%s: tag 0x%04x on (%d:%d:%d:%d) aborted\n", __func__, - io->scsiio.tag_num, io->io_hdr.nexus.initid.id, + printf("%s: tag 0x%04x on (%u:%u:%u) aborted\n", __func__, + io->scsiio.tag_num, io->io_hdr.nexus.initid, io->io_hdr.nexus.targ_port, - io->io_hdr.nexus.targ_target.id, io->io_hdr.nexus.targ_lun); io->io_hdr.port_status = 31338; ctl_send_datamove_done(io, /*have_lock*/ 0); return; } - if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_OUT) { + if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_OUT) ctl_datamove_remote_write(io); - } else if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN){ + else if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN) ctl_datamove_remote_read(io); - } else { - union ctl_ha_msg msg; - struct scsi_sense_data *sense; - uint8_t sks[3]; - int retry_count; - - memset(&msg, 0, sizeof(msg)); - - msg.hdr.msg_type = CTL_MSG_BAD_JUJU; - msg.hdr.status = CTL_SCSI_ERROR; - msg.scsi.scsi_status = SCSI_STATUS_CHECK_COND; - - retry_count = 4243; - - sense = &msg.scsi.sense_data; - sks[0] = SSD_SCS_VALID; - sks[1] = (retry_count >> 8) & 0xff; - sks[2] = retry_count & 0xff; - - /* "Internal target failure" */ - scsi_set_sense_data(sense, - /*sense_format*/ SSD_TYPE_NONE, - /*current_error*/ 1, - /*sense_key*/ SSD_KEY_HARDWARE_ERROR, - /*asc*/ 0x44, - /*ascq*/ 0x00, - /*type*/ SSD_ELEM_SKS, - /*size*/ sizeof(sks), - /*data*/ sks, - SSD_ELEM_NONE); - - io->io_hdr.flags &= ~CTL_FLAG_IO_ACTIVE; - if (io->io_hdr.flags & CTL_FLAG_FAILOVER) { - ctl_failover_io(io, /*have_lock*/ 1); - return; - } - - if (ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg, sizeof(msg), 0) > - CTL_HA_STATUS_SUCCESS) { - /* XXX KDM what to do if this fails? */ - } - return; + else { + io->io_hdr.port_status = 31339; + ctl_send_datamove_done(io, /*have_lock*/ 0); } - } static int @@ -13056,11 +12659,15 @@ ctl_process_done(union ctl_io *io) struct ctl_lun *lun; struct ctl_softc *softc = control_softc; void (*fe_done)(union ctl_io *io); - uint32_t targ_port = ctl_port_idx(io->io_hdr.nexus.targ_port); + union ctl_ha_msg msg; + uint32_t targ_port = io->io_hdr.nexus.targ_port; CTL_DEBUG_PRINT(("ctl_process_done\n")); - fe_done = softc->ctl_ports[targ_port]->fe_done; + if ((io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC) == 0) + fe_done = softc->ctl_ports[targ_port]->fe_done; + else + fe_done = NULL; #ifdef CTL_TIME_IO if ((time_uptime - io->io_hdr.start_time) > ctl_time_io_secs) { @@ -13218,20 +12825,19 @@ bailout: * Tell the FETD or the other shelf controller we're done with this * command. Note that only SCSI commands get to this point. Task * management commands are completed above. - * - * We only send status to the other controller if we're in XFER - * mode. In SER_ONLY mode, the I/O is done on the controller that - * received the I/O (from CTL's perspective), and so the status is - * generated there. - * - * XXX KDM if we hold the lock here, we could cause a deadlock - * if the frontend comes back in in this context to queue - * something. */ + if ((softc->ha_mode != CTL_HA_MODE_XFER) && + (io->io_hdr.flags & CTL_FLAG_SENT_2OTHER_SC)) { + memset(&msg, 0, sizeof(msg)); + msg.hdr.msg_type = CTL_MSG_FINISH_IO; + msg.hdr.serializing_sc = io->io_hdr.serializing_sc; + msg.hdr.nexus = io->io_hdr.nexus; + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg, + sizeof(msg.scsi) - sizeof(msg.scsi.sense_data), + M_WAITOK); + } if ((softc->ha_mode == CTL_HA_MODE_XFER) && (io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC)) { - union ctl_ha_msg msg; - memset(&msg, 0, sizeof(msg)); msg.hdr.msg_type = CTL_MSG_FINISH_IO; msg.hdr.original_sc = io->io_hdr.original_sc; @@ -13244,7 +12850,7 @@ bailout: msg.scsi.sense_residual = io->scsiio.sense_residual; msg.scsi.residual = io->scsiio.residual; memcpy(&msg.scsi.sense_data, &io->scsiio.sense_data, - sizeof(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 @@ -13255,11 +12861,9 @@ bailout: &io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN].bytes, sizeof(msg.scsi.lbalen)); - if (ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg, - sizeof(msg), 0) > CTL_HA_STATUS_SUCCESS) { - /* XXX do something here */ - } - + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg, + sizeof(msg.scsi) - sizeof(msg.scsi.sense_data) + + msg.scsi.sense_len, M_WAITOK); ctl_free_io(io); } else fe_done(io); @@ -13388,15 +12992,14 @@ ctl_done(union ctl_io *io) #if 0 if (io->io_hdr.flags & CTL_FLAG_ALREADY_DONE) { printf("%s: type %d msg %d cdb %x iptl: " - "%d:%d:%d:%d tag 0x%04x " + "%u:%u:%u tag 0x%04x " "flag %#x status %x\n", __func__, io->io_hdr.io_type, io->io_hdr.msg_type, io->scsiio.cdb[0], - io->io_hdr.nexus.initid.id, + io->io_hdr.nexus.initid, io->io_hdr.nexus.targ_port, - io->io_hdr.nexus.targ_target.id, io->io_hdr.nexus.targ_lun, (io->io_hdr.io_type == CTL_IO_TASK) ? @@ -13415,25 +13018,6 @@ ctl_done(union ctl_io *io) if (io->io_hdr.flags & CTL_FLAG_INT_COPY) return; - /* - * We need to send a msg to the serializing shelf to finish the IO - * as well. We don't send a finish message to the other shelf if - * this is a task management command. Task management commands - * aren't serialized in the OOA queue, but rather just executed on - * both shelf controllers for commands that originated on that - * controller. - */ - if ((io->io_hdr.flags & CTL_FLAG_SENT_2OTHER_SC) - && (io->io_hdr.io_type != CTL_IO_TASK)) { - union ctl_ha_msg msg_io; - - msg_io.hdr.msg_type = CTL_MSG_FINISH_IO; - msg_io.hdr.serializing_sc = io->io_hdr.serializing_sc; - if (ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_io, - sizeof(msg_io), 0 ) != CTL_HA_STATUS_SUCCESS) { - } - /* continue on to finish IO */ - } #ifdef CTL_IO_DELAY if (io->io_hdr.flags & CTL_FLAG_DELAY_DONE) { struct ctl_lun *lun; @@ -13448,12 +13032,10 @@ ctl_done(union ctl_io *io) if ((lun != NULL) && (lun->delay_info.done_delay > 0)) { - struct callout *callout; - callout = (struct callout *)&io->io_hdr.timer_bytes; - callout_init(callout, /*mpsafe*/ 1); + callout_init(&io->io_hdr.delay_callout, /*mpsafe*/ 1); io->io_hdr.flags |= CTL_FLAG_DELAY_DONE; - callout_reset(callout, + callout_reset(&io->io_hdr.delay_callout, lun->delay_info.done_delay * hz, ctl_done_timer_wakeup, io); if (lun->delay_info.done_type == CTL_DELAY_TYPE_ONESHOT) @@ -13466,24 +13048,6 @@ ctl_done(union ctl_io *io) ctl_enqueue_done(io); } -int -ctl_isc(struct ctl_scsiio *ctsio) -{ - struct ctl_lun *lun; - int retval; - - lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr; - - CTL_DEBUG_PRINT(("ctl_isc: command: %02x\n", ctsio->cdb[0])); - - CTL_DEBUG_PRINT(("ctl_isc: calling data_submit()\n")); - - retval = lun->backend->data_submit((union ctl_io *)ctsio); - - return (retval); -} - - static void ctl_work_thread(void *arg) { @@ -13533,16 +13097,14 @@ ctl_work_thread(void *arg) ctl_scsiio_precheck(softc, &io->scsiio); continue; } - if (!ctl_pause_rtr) { - io = (union ctl_io *)STAILQ_FIRST(&thr->rtr_queue); - if (io != NULL) { - STAILQ_REMOVE_HEAD(&thr->rtr_queue, links); - mtx_unlock(&thr->queue_lock); - retval = ctl_scsiio(&io->scsiio); - if (retval != CTL_RETVAL_COMPLETE) - CTL_DEBUG_PRINT(("ctl_scsiio failed\n")); - continue; - } + io = (union ctl_io *)STAILQ_FIRST(&thr->rtr_queue); + if (io != NULL) { + STAILQ_REMOVE_HEAD(&thr->rtr_queue, links); + mtx_unlock(&thr->queue_lock); + retval = ctl_scsiio(&io->scsiio); + if (retval != CTL_RETVAL_COMPLETE) + CTL_DEBUG_PRINT(("ctl_scsiio failed\n")); + continue; } /* Sleep until we have something to do. */ @@ -13585,8 +13147,9 @@ ctl_thresh_thread(void *arg) struct scsi_da_rw_recovery_page *rwpage; struct ctl_logical_block_provisioning_page *page; const char *attr; + union ctl_ha_msg msg; uint64_t thres, val; - int i, e; + int i, e, set; CTL_DEBUG_PRINT(("ctl_thresh_thread starting\n")); @@ -13598,6 +13161,9 @@ ctl_thresh_thread(void *arg) (lun->flags & CTL_LUN_OFFLINE) || lun->backend->lun_attr == NULL) continue; + if ((lun->flags & CTL_LUN_PRIMARY_SC) == 0 && + softc->ha_mode == CTL_HA_MODE_XFER) + continue; rwpage = &lun->mode_pages.rw_er_page[CTL_PAGE_CURRENT]; if ((rwpage->byte8 & SMS_RWER_LBPERE) == 0) continue; @@ -13642,12 +13208,32 @@ ctl_thresh_thread(void *arg) time_uptime - lun->lasttpt >= CTL_LBP_UA_PERIOD) { lun->lasttpt = time_uptime; ctl_est_ua_all(lun, -1, CTL_UA_THIN_PROV_THRES); - } + set = 1; + } else + set = 0; } else { lun->lasttpt = 0; ctl_clr_ua_all(lun, -1, CTL_UA_THIN_PROV_THRES); + set = -1; } mtx_unlock(&lun->lun_lock); + if (set != 0 && + lun->ctl_softc->ha_mode == CTL_HA_MODE_XFER) { + /* Send msg to other side. */ + bzero(&msg.ua, sizeof(msg.ua)); + msg.hdr.msg_type = CTL_MSG_UA; + msg.hdr.nexus.initid = -1; + msg.hdr.nexus.targ_port = -1; + msg.hdr.nexus.targ_lun = lun->lun; + msg.hdr.nexus.targ_mapped_lun = lun->lun; + msg.ua.ua_all = 1; + msg.ua.ua_set = (set > 0); + msg.ua.ua_type = CTL_UA_THIN_PROV_THRES; + mtx_unlock(&softc->ctl_lock); // XXX + ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg, + sizeof(msg.ua), M_WAITOK); + mtx_lock(&softc->ctl_lock); + } } mtx_unlock(&softc->ctl_lock); pause("-", CTL_LBP_PERIOD * hz); @@ -13662,7 +13248,7 @@ ctl_enqueue_incoming(union ctl_io *io) u_int idx; idx = (io->io_hdr.nexus.targ_port * 127 + - io->io_hdr.nexus.initid.id) % worker_threads; + io->io_hdr.nexus.initid) % worker_threads; thr = &softc->threads[idx]; mtx_lock(&thr->queue_lock); STAILQ_INSERT_TAIL(&thr->incoming_queue, &io->io_hdr, links); @@ -13696,7 +13282,6 @@ ctl_enqueue_done(union ctl_io *io) wakeup(thr); } -#ifdef notyet static void ctl_enqueue_isc(union ctl_io *io) { @@ -13710,107 +13295,6 @@ ctl_enqueue_isc(union ctl_io *io) wakeup(thr); } -/* Initialization and failover */ - -void -ctl_init_isc_msg(void) -{ - printf("CTL: Still calling this thing\n"); -} - -/* - * Init component - * Initializes component into configuration defined by bootMode - * (see hasc-sv.c) - * returns hasc_Status: - * OK - * ERROR - fatal error - */ -static ctl_ha_comp_status -ctl_isc_init(struct ctl_ha_component *c) -{ - ctl_ha_comp_status ret = CTL_HA_COMP_STATUS_OK; - - c->status = ret; - return ret; -} - -/* Start component - * Starts component in state requested. If component starts successfully, - * it must set its own state to the requestrd state - * When requested state is HASC_STATE_HA, the component may refine it - * by adding _SLAVE or _MASTER flags. - * Currently allowed state transitions are: - * UNKNOWN->HA - initial startup - * UNKNOWN->SINGLE - initial startup when no parter detected - * HA->SINGLE - failover - * returns ctl_ha_comp_status: - * OK - component successfully started in requested state - * FAILED - could not start the requested state, failover may - * be possible - * ERROR - fatal error detected, no future startup possible - */ -static ctl_ha_comp_status -ctl_isc_start(struct ctl_ha_component *c, ctl_ha_state state) -{ - ctl_ha_comp_status ret = CTL_HA_COMP_STATUS_OK; - - printf("%s: go\n", __func__); - - // UNKNOWN->HA or UNKNOWN->SINGLE (bootstrap) - if (c->state == CTL_HA_STATE_UNKNOWN ) { - control_softc->is_single = 0; - if (ctl_ha_msg_create(CTL_HA_CHAN_CTL, ctl_isc_event_handler) - != CTL_HA_STATUS_SUCCESS) { - printf("ctl_isc_start: ctl_ha_msg_create failed.\n"); - ret = CTL_HA_COMP_STATUS_ERROR; - } - } else if (CTL_HA_STATE_IS_HA(c->state) - && CTL_HA_STATE_IS_SINGLE(state)){ - // HA->SINGLE transition - ctl_failover(); - control_softc->is_single = 1; - } else { - printf("ctl_isc_start:Invalid state transition %X->%X\n", - c->state, state); - ret = CTL_HA_COMP_STATUS_ERROR; - } - if (CTL_HA_STATE_IS_SINGLE(state)) - control_softc->is_single = 1; - - c->state = state; - c->status = ret; - return ret; -} - -/* - * Quiesce component - * The component must clear any error conditions (set status to OK) and - * prepare itself to another Start call - * returns ctl_ha_comp_status: - * OK - * ERROR - */ -static ctl_ha_comp_status -ctl_isc_quiesce(struct ctl_ha_component *c) -{ - int ret = CTL_HA_COMP_STATUS_OK; - - ctl_pause_rtr = 1; - c->status = ret; - return ret; -} - -struct ctl_ha_component ctl_ha_component_ctlisc = -{ - .name = "CTL ISC", - .state = CTL_HA_STATE_UNKNOWN, - .init = ctl_isc_init, - .start = ctl_isc_start, - .quiesce = ctl_isc_quiesce -}; -#endif - /* * vim: ts=8 */ diff --git a/sys/cam/ctl/ctl.h b/sys/cam/ctl/ctl.h index 0e0bfb6..630e3bb 100644 --- a/sys/cam/ctl/ctl.h +++ b/sys/cam/ctl/ctl.h @@ -139,24 +139,12 @@ SYSCTL_DECL(_kern_cam_ctl); #endif /* - * Call these routines to enable or disable front end ports. - */ -int ctl_port_enable(ctl_port_type port_type); -int ctl_port_disable(ctl_port_type port_type); -/* - * This routine grabs a list of frontend ports. - */ -int ctl_port_list(struct ctl_port_entry *entries, int num_entries_alloced, - int *num_entries_filled, int *num_entries_dropped, - ctl_port_type port_type, int no_virtual); - -/* * Put a string into an sbuf, escaping characters that are illegal or not * recommended in XML. Note this doesn't escape everything, just > < and &. */ int ctl_sbuf_printf_esc(struct sbuf *sb, char *str, int size); -int ctl_ffz(uint32_t *mask, uint32_t size); +int ctl_ffz(uint32_t *mask, uint32_t first, uint32_t last); int ctl_set_mask(uint32_t *mask, uint32_t bit); int ctl_clear_mask(uint32_t *mask, uint32_t bit); int ctl_is_set(uint32_t *mask, uint32_t bit); @@ -165,11 +153,6 @@ int ctl_caching_sp_handler(struct ctl_scsiio *ctsio, int ctl_control_page_handler(struct ctl_scsiio *ctsio, struct ctl_page_index *page_index, uint8_t *page_ptr); -/** -int ctl_failover_sp_handler(struct ctl_scsiio *ctsio, - struct ctl_page_index *page_index, - uint8_t *page_ptr); -**/ int ctl_debugconf_sp_sense_handler(struct ctl_scsiio *ctsio, struct ctl_page_index *page_index, int pc); @@ -189,11 +172,12 @@ void ctl_data_submit_done(union ctl_io *io); void ctl_config_read_done(union ctl_io *io); void ctl_config_write_done(union ctl_io *io); void ctl_portDB_changed(int portnum); -#ifdef notyet -void ctl_init_isc_msg(void); -#endif int ctl_ioctl_io(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td); +struct ctl_lun; +void ctl_isc_announce_lun(struct ctl_lun *lun); +struct ctl_port; +void ctl_isc_announce_port(struct ctl_port *port); /* * KPI to manipulate LUN/port options diff --git a/sys/cam/ctl/ctl_backend.h b/sys/cam/ctl/ctl_backend.h index e7d544a..f5bfd83 100644 --- a/sys/cam/ctl/ctl_backend.h +++ b/sys/cam/ctl/ctl_backend.h @@ -308,6 +308,12 @@ int ctl_lun_offline(struct ctl_be_lun *be_lun); int ctl_lun_online(struct ctl_be_lun *be_lun); /* + * Called on LUN HA role change. + */ +int ctl_lun_primary(struct ctl_be_lun *be_lun); +int ctl_lun_secondary(struct ctl_be_lun *be_lun); + +/* * Let the backend notify the initiator about changed capacity. */ void ctl_lun_capacity_changed(struct ctl_be_lun *be_lun); diff --git a/sys/cam/ctl/ctl_backend_block.c b/sys/cam/ctl/ctl_backend_block.c index 799f742..c9d2a57 100644 --- a/sys/cam/ctl/ctl_backend_block.c +++ b/sys/cam/ctl/ctl_backend_block.c @@ -85,7 +85,9 @@ __FBSDID("$FreeBSD$"); #include <cam/ctl/ctl.h> #include <cam/ctl/ctl_backend.h> #include <cam/ctl/ctl_ioctl.h> +#include <cam/ctl/ctl_ha.h> #include <cam/ctl/ctl_scsi_all.h> +#include <cam/ctl/ctl_private.h> #include <cam/ctl/ctl_error.h> /* @@ -124,18 +126,11 @@ typedef enum { CTL_BE_BLOCK_FILE } ctl_be_block_type; -struct ctl_be_block_devdata { - struct cdev *cdev; - struct cdevsw *csw; - int dev_ref; -}; - struct ctl_be_block_filedata { struct ucred *cred; }; union ctl_be_block_bedata { - struct ctl_be_block_devdata dev; struct ctl_be_block_filedata file; }; @@ -217,6 +212,8 @@ struct ctl_be_block_io { void (*beio_cont)(struct ctl_be_block_io *beio); /* to continue processing */ }; +extern struct ctl_softc *control_softc; + static int cbb_num_threads = 14; SYSCTL_NODE(_kern_cam_ctl, OID_AUTO, block, CTLFLAG_RD, 0, "CAM Target Layer Block Backend"); @@ -819,16 +816,15 @@ static void ctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun, struct ctl_be_block_io *beio) { - struct ctl_be_block_devdata *dev_data; union ctl_io *io; + struct cdevsw *csw; + struct cdev *dev; struct uio xuio; struct iovec *xiovec; - int flags; - int error, i; + int error, flags, i, ref; DPRINTF("entered\n"); - dev_data = &be_lun->backend.dev; io = beio->io; flags = 0; if (ARGS(io)->flags & CTL_LLF_DPO) @@ -861,13 +857,20 @@ ctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun, devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); mtx_unlock(&be_lun->io_lock); - if (beio->bio_cmd == BIO_READ) { - error = (*dev_data->csw->d_read)(dev_data->cdev, &xuio, flags); + csw = devvn_refthread(be_lun->vn, &dev, &ref); + if (csw) { + if (beio->bio_cmd == BIO_READ) + error = csw->d_read(dev, &xuio, flags); + else + error = csw->d_write(dev, &xuio, flags); + dev_relthread(dev, ref); + } else + error = ENXIO; + + if (beio->bio_cmd == BIO_READ) SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0); - } else { - error = (*dev_data->csw->d_write)(dev_data->cdev, &xuio, flags); + else SDT_PROBE(cbb, kernel, write, file_done, 0, 0, 0, 0, 0); - } mtx_lock(&be_lun->io_lock); devstat_end_transaction(beio->lun->disk_stats, beio->io_len, @@ -911,23 +914,30 @@ static void ctl_be_block_gls_zvol(struct ctl_be_block_lun *be_lun, struct ctl_be_block_io *beio) { - struct ctl_be_block_devdata *dev_data = &be_lun->backend.dev; union ctl_io *io = beio->io; + struct cdevsw *csw; + struct cdev *dev; struct ctl_lba_len_flags *lbalen = ARGS(io); struct scsi_get_lba_status_data *data; off_t roff, off; - int error, status; + int error, ref, status; DPRINTF("entered\n"); + csw = devvn_refthread(be_lun->vn, &dev, &ref); + if (csw == NULL) { + status = 0; /* unknown up to the end */ + off = be_lun->size_bytes; + goto done; + } off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize; - error = (*dev_data->csw->d_ioctl)(dev_data->cdev, FIOSEEKHOLE, - (caddr_t)&off, FREAD, curthread); + error = csw->d_ioctl(dev, FIOSEEKHOLE, (caddr_t)&off, FREAD, + curthread); if (error == 0 && off > roff) status = 0; /* mapped up to off */ else { - error = (*dev_data->csw->d_ioctl)(dev_data->cdev, FIOSEEKDATA, - (caddr_t)&off, FREAD, curthread); + error = csw->d_ioctl(dev, FIOSEEKDATA, (caddr_t)&off, FREAD, + curthread); if (error == 0 && off > roff) status = 1; /* deallocated up to off */ else { @@ -935,7 +945,9 @@ ctl_be_block_gls_zvol(struct ctl_be_block_lun *be_lun, off = be_lun->size_bytes; } } + dev_relthread(dev, ref); +done: data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; scsi_u64to8b(lbalen->lba, data->descr[0].addr); scsi_ulto4b(MIN(UINT32_MAX, off / be_lun->cbe_lun.blocksize - @@ -951,9 +963,10 @@ ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun, { struct bio *bio; union ctl_io *io; - struct ctl_be_block_devdata *dev_data; + struct cdevsw *csw; + struct cdev *dev; + int ref; - dev_data = &be_lun->backend.dev; io = beio->io; DPRINTF("entered\n"); @@ -962,7 +975,6 @@ ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun, bio = g_alloc_bio(); bio->bio_cmd = BIO_FLUSH; - bio->bio_dev = dev_data->cdev; bio->bio_offset = 0; bio->bio_data = 0; bio->bio_done = ctl_be_block_biodone; @@ -982,7 +994,15 @@ ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun, devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); mtx_unlock(&be_lun->io_lock); - (*dev_data->csw->d_strategy)(bio); + csw = devvn_refthread(be_lun->vn, &dev, &ref); + if (csw) { + bio->bio_dev = dev; + csw->d_strategy(bio); + dev_relthread(dev, ref); + } else { + bio->bio_error = ENXIO; + ctl_be_block_biodone(bio); + } } static void @@ -991,15 +1011,17 @@ ctl_be_block_unmap_dev_range(struct ctl_be_block_lun *be_lun, uint64_t off, uint64_t len, int last) { struct bio *bio; - struct ctl_be_block_devdata *dev_data; uint64_t maxlen; + struct cdevsw *csw; + struct cdev *dev; + int ref; - dev_data = &be_lun->backend.dev; + csw = devvn_refthread(be_lun->vn, &dev, &ref); maxlen = LONG_MAX - (LONG_MAX % be_lun->cbe_lun.blocksize); while (len > 0) { bio = g_alloc_bio(); bio->bio_cmd = BIO_DELETE; - bio->bio_dev = dev_data->cdev; + bio->bio_dev = dev; bio->bio_offset = off; bio->bio_length = MIN(len, maxlen); bio->bio_data = 0; @@ -1016,8 +1038,15 @@ ctl_be_block_unmap_dev_range(struct ctl_be_block_lun *be_lun, beio->send_complete = 1; mtx_unlock(&be_lun->io_lock); - (*dev_data->csw->d_strategy)(bio); + if (csw) { + csw->d_strategy(bio); + } else { + bio->bio_error = ENXIO; + ctl_be_block_biodone(bio); + } } + if (csw) + dev_relthread(dev, ref); } static void @@ -1025,12 +1054,10 @@ ctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun, struct ctl_be_block_io *beio) { union ctl_io *io; - struct ctl_be_block_devdata *dev_data; struct ctl_ptr_len_flags *ptrlen; struct scsi_unmap_desc *buf, *end; uint64_t len; - dev_data = &be_lun->backend.dev; io = beio->io; DPRINTF("entered\n"); @@ -1063,23 +1090,25 @@ ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun, struct ctl_be_block_io *beio) { TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue); - int i; struct bio *bio; - struct ctl_be_block_devdata *dev_data; + struct cdevsw *csw; + struct cdev *dev; off_t cur_offset; - int max_iosize; + int i, max_iosize, ref; DPRINTF("entered\n"); - - dev_data = &be_lun->backend.dev; + csw = devvn_refthread(be_lun->vn, &dev, &ref); /* * We have to limit our I/O size to the maximum supported by the * backend device. Hopefully it is MAXPHYS. If the driver doesn't * set it properly, use DFLTPHYS. */ - max_iosize = dev_data->cdev->si_iosize_max; - if (max_iosize < PAGE_SIZE) + if (csw) { + max_iosize = dev->si_iosize_max; + if (max_iosize < PAGE_SIZE) + max_iosize = DFLTPHYS; + } else max_iosize = DFLTPHYS; cur_offset = beio->io_offset; @@ -1097,7 +1126,7 @@ ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun, KASSERT(bio != NULL, ("g_alloc_bio() failed!\n")); bio->bio_cmd = beio->bio_cmd; - bio->bio_dev = dev_data->cdev; + bio->bio_dev = dev; bio->bio_caller1 = beio; bio->bio_length = min(cur_size, max_iosize); bio->bio_offset = cur_offset; @@ -1124,23 +1153,36 @@ ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun, */ while ((bio = TAILQ_FIRST(&queue)) != NULL) { TAILQ_REMOVE(&queue, bio, bio_queue); - (*dev_data->csw->d_strategy)(bio); + if (csw) + csw->d_strategy(bio); + else { + bio->bio_error = ENXIO; + ctl_be_block_biodone(bio); + } } + if (csw) + dev_relthread(dev, ref); } static uint64_t ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, const char *attrname) { - struct ctl_be_block_devdata *dev_data = &be_lun->backend.dev; struct diocgattr_arg arg; - int error; + struct cdevsw *csw; + struct cdev *dev; + int error, ref; - if (dev_data->csw == NULL || dev_data->csw->d_ioctl == NULL) + csw = devvn_refthread(be_lun->vn, &dev, &ref); + if (csw == NULL) return (UINT64_MAX); strlcpy(arg.name, attrname, sizeof(arg.name)); arg.len = sizeof(arg.value.off); - error = dev_data->csw->d_ioctl(dev_data->cdev, - DIOCGATTR, (caddr_t)&arg, FREAD, curthread); + if (csw->d_ioctl) { + error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD, + curthread); + } else + error = ENODEV; + dev_relthread(dev, ref); if (error != 0) return (UINT64_MAX); return (arg.value.off); @@ -1573,33 +1615,32 @@ ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun, static void ctl_be_block_worker(void *context, int pending) { - struct ctl_be_block_lun *be_lun; - struct ctl_be_block_softc *softc; + struct ctl_be_block_lun *be_lun = (struct ctl_be_block_lun *)context; + struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; union ctl_io *io; - - be_lun = (struct ctl_be_block_lun *)context; - softc = be_lun->softc; + struct ctl_be_block_io *beio; DPRINTF("entered\n"); - - mtx_lock(&be_lun->queue_lock); + /* + * Fetch and process I/Os from all queues. If we detect LUN + * CTL_LUN_FLAG_OFFLINE status here -- it is result of a race, + * so make response maximally opaque to not confuse initiator. + */ for (;;) { + mtx_lock(&be_lun->queue_lock); io = (union ctl_io *)STAILQ_FIRST(&be_lun->datamove_queue); if (io != NULL) { - struct ctl_be_block_io *beio; - DPRINTF("datamove queue\n"); - STAILQ_REMOVE(&be_lun->datamove_queue, &io->io_hdr, ctl_io_hdr, links); - mtx_unlock(&be_lun->queue_lock); - beio = (struct ctl_be_block_io *)PRIV(io)->ptr; - + if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) { + ctl_set_busy(&io->scsiio); + ctl_complete_beio(beio); + return; + } be_lun->dispatch(be_lun, beio); - - mtx_lock(&be_lun->queue_lock); continue; } io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_write_queue); @@ -1608,8 +1649,12 @@ ctl_be_block_worker(void *context, int pending) STAILQ_REMOVE(&be_lun->config_write_queue, &io->io_hdr, ctl_io_hdr, links); mtx_unlock(&be_lun->queue_lock); + if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) { + ctl_set_busy(&io->scsiio); + ctl_config_write_done(io); + return; + } ctl_be_block_cw_dispatch(be_lun, io); - mtx_lock(&be_lun->queue_lock); continue; } io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_read_queue); @@ -1618,25 +1663,26 @@ ctl_be_block_worker(void *context, int pending) STAILQ_REMOVE(&be_lun->config_read_queue, &io->io_hdr, ctl_io_hdr, links); mtx_unlock(&be_lun->queue_lock); + if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) { + ctl_set_busy(&io->scsiio); + ctl_config_read_done(io); + return; + } ctl_be_block_cr_dispatch(be_lun, io); - mtx_lock(&be_lun->queue_lock); continue; } io = (union ctl_io *)STAILQ_FIRST(&be_lun->input_queue); if (io != NULL) { DPRINTF("input queue\n"); - STAILQ_REMOVE(&be_lun->input_queue, &io->io_hdr, ctl_io_hdr, links); mtx_unlock(&be_lun->queue_lock); - - /* - * We must drop the lock, since this routine and - * its children may sleep. - */ + if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) { + ctl_set_busy(&io->scsiio); + ctl_data_submit_done(io); + return; + } ctl_be_block_dispatch(be_lun, io); - - mtx_lock(&be_lun->queue_lock); continue; } @@ -1644,9 +1690,9 @@ ctl_be_block_worker(void *context, int pending) * If we get here, there is no work left in the queues, so * just break out and let the task queue go to sleep. */ + mtx_unlock(&be_lun->queue_lock); break; } - mtx_unlock(&be_lun->queue_lock); } /* @@ -1849,22 +1895,19 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) { struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; struct ctl_lun_create_params *params; - struct vattr vattr; + struct cdevsw *csw; struct cdev *dev; - struct cdevsw *devsw; char *value; - int error, atomic, maxio, unmap, tmp; + int error, atomic, maxio, ref, unmap, tmp; off_t ps, pss, po, pos, us, uss, uo, uos, otmp; params = &be_lun->params; be_lun->dev_type = CTL_BE_BLOCK_DEV; - be_lun->backend.dev.cdev = be_lun->vn->v_rdev; - be_lun->backend.dev.csw = dev_refthread(be_lun->backend.dev.cdev, - &be_lun->backend.dev.dev_ref); - if (be_lun->backend.dev.csw == NULL) - panic("Unable to retrieve device switch"); - if (strcmp(be_lun->backend.dev.csw->d_name, "zvol") == 0) { + csw = devvn_refthread(be_lun->vn, &dev, &ref); + if (csw == NULL) + return (ENXIO); + if (strcmp(csw->d_name, "zvol") == 0) { be_lun->dispatch = ctl_be_block_dispatch_zvol; be_lun->get_lba_status = ctl_be_block_gls_zvol; atomic = maxio = CTLBLK_MAX_IO_SIZE; @@ -1872,7 +1915,7 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) be_lun->dispatch = ctl_be_block_dispatch_dev; be_lun->get_lba_status = NULL; atomic = 0; - maxio = be_lun->backend.dev.cdev->si_iosize_max; + maxio = dev->si_iosize_max; if (maxio <= 0) maxio = DFLTPHYS; if (maxio > CTLBLK_MAX_IO_SIZE) @@ -1882,26 +1925,17 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) be_lun->getattr = ctl_be_block_getattr_dev; be_lun->unmap = ctl_be_block_unmap_dev; - error = VOP_GETATTR(be_lun->vn, &vattr, NOCRED); - if (error) { - snprintf(req->error_str, sizeof(req->error_str), - "error getting vnode attributes for device %s", - be_lun->dev_path); - return (error); - } - - dev = be_lun->vn->v_rdev; - devsw = dev->si_devsw; - if (!devsw->d_ioctl) { + if (!csw->d_ioctl) { + dev_relthread(dev, ref); snprintf(req->error_str, sizeof(req->error_str), - "no d_ioctl for device %s!", - be_lun->dev_path); + "no d_ioctl for device %s!", be_lun->dev_path); return (ENODEV); } - error = devsw->d_ioctl(dev, DIOCGSECTORSIZE, (caddr_t)&tmp, FREAD, + error = csw->d_ioctl(dev, DIOCGSECTORSIZE, (caddr_t)&tmp, FREAD, curthread); if (error) { + dev_relthread(dev, ref); snprintf(req->error_str, sizeof(req->error_str), "error %d returned for DIOCGSECTORSIZE ioctl " "on %s!", error, be_lun->dev_path); @@ -1919,14 +1953,15 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) if (params->blocksize_bytes % tmp == 0) { cbe_lun->blocksize = params->blocksize_bytes; } else { + dev_relthread(dev, ref); snprintf(req->error_str, sizeof(req->error_str), "requested blocksize %u is not an even " "multiple of backing device blocksize %u", params->blocksize_bytes, tmp); return (EINVAL); - } } else if (params->blocksize_bytes != 0) { + dev_relthread(dev, ref); snprintf(req->error_str, sizeof(req->error_str), "requested blocksize %u < backing device " "blocksize %u", params->blocksize_bytes, tmp); @@ -1934,9 +1969,10 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) } else cbe_lun->blocksize = tmp; - error = devsw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&otmp, FREAD, - curthread); + error = csw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&otmp, FREAD, + curthread); if (error) { + dev_relthread(dev, ref); snprintf(req->error_str, sizeof(req->error_str), "error %d returned for DIOCGMEDIASIZE " " ioctl on %s!", error, @@ -1946,6 +1982,7 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) if (params->lun_size_bytes != 0) { if (params->lun_size_bytes > otmp) { + dev_relthread(dev, ref); snprintf(req->error_str, sizeof(req->error_str), "requested LUN size %ju > backing device " "size %ju", @@ -1961,13 +1998,13 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 0 : (be_lun->size_blocks - 1); - error = devsw->d_ioctl(dev, DIOCGSTRIPESIZE, - (caddr_t)&ps, FREAD, curthread); + error = csw->d_ioctl(dev, DIOCGSTRIPESIZE, (caddr_t)&ps, FREAD, + curthread); if (error) ps = po = 0; else { - error = devsw->d_ioctl(dev, DIOCGSTRIPEOFFSET, - (caddr_t)&po, FREAD, curthread); + error = csw->d_ioctl(dev, DIOCGSTRIPEOFFSET, (caddr_t)&po, + FREAD, curthread); if (error) po = 0; } @@ -2012,8 +2049,8 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) strlcpy(arg.name, "GEOM::candelete", sizeof(arg.name)); arg.len = sizeof(arg.value.i); - error = devsw->d_ioctl(dev, DIOCGATTR, - (caddr_t)&arg, FREAD, curthread); + error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD, + curthread); unmap = (error == 0) ? arg.value.i : 0; } value = ctl_get_opt(&cbe_lun->options, "unmap"); @@ -2024,6 +2061,7 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) else cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP; + dev_relthread(dev, ref); return (0); } @@ -2034,24 +2072,6 @@ ctl_be_block_close(struct ctl_be_block_lun *be_lun) int flags; if (be_lun->vn) { - switch (be_lun->dev_type) { - case CTL_BE_BLOCK_DEV: - if (be_lun->backend.dev.csw) { - dev_relthread(be_lun->backend.dev.cdev, - be_lun->backend.dev.dev_ref); - be_lun->backend.dev.csw = NULL; - be_lun->backend.dev.cdev = NULL; - } - break; - case CTL_BE_BLOCK_FILE: - break; - case CTL_BE_BLOCK_NONE: - break; - default: - panic("Unexpected backend type."); - break; - } - flags = FREAD; if ((cbe_lun->flags & CTL_LUN_FLAG_READONLY) == 0) flags |= FWRITE; @@ -2214,7 +2234,13 @@ ctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) else cbe_lun->lun_type = T_DIRECT; be_lun->flags = CTL_BE_BLOCK_LUN_UNCONFIGURED; - cbe_lun->flags = CTL_LUN_FLAG_PRIMARY; + cbe_lun->flags = 0; + value = ctl_get_opt(&cbe_lun->options, "ha_role"); + if (value != NULL) { + if (strcmp(value, "primary") == 0) + cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; + } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) + cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; if (cbe_lun->lun_type == T_DIRECT) { be_lun->size_bytes = params->lun_size_bytes; @@ -2226,10 +2252,13 @@ ctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 0 : (be_lun->size_blocks - 1); - retval = ctl_be_block_open(softc, be_lun, req); - if (retval != 0) { - retval = 0; - req->status = CTL_LUN_WARNING; + if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) || + control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) { + retval = ctl_be_block_open(softc, be_lun, req); + if (retval != 0) { + retval = 0; + req->status = CTL_LUN_WARNING; + } } num_threads = cbb_num_threads; } else { @@ -2418,6 +2447,7 @@ ctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) { struct ctl_lun_rm_params *params; struct ctl_be_block_lun *be_lun; + struct ctl_be_lun *cbe_lun; int retval; params = &req->reqdata.rm; @@ -2435,18 +2465,24 @@ ctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) params->lun_id); goto bailout_error; } + cbe_lun = &be_lun->cbe_lun; - retval = ctl_disable_lun(&be_lun->cbe_lun); - + retval = ctl_disable_lun(cbe_lun); if (retval != 0) { snprintf(req->error_str, sizeof(req->error_str), "error %d returned from ctl_disable_lun() for " "LUN %d", retval, params->lun_id); goto bailout_error; + } + if (be_lun->vn != NULL) { + cbe_lun->flags |= CTL_LUN_FLAG_OFFLINE; + ctl_lun_offline(cbe_lun); + taskqueue_drain_all(be_lun->io_taskqueue); + ctl_be_block_close(be_lun); } - retval = ctl_invalidate_lun(&be_lun->cbe_lun); + retval = ctl_invalidate_lun(cbe_lun); if (retval != 0) { snprintf(req->error_str, sizeof(req->error_str), "error %d returned from ctl_invalidate_lun() for " @@ -2455,15 +2491,12 @@ ctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) } mtx_lock(&softc->lock); - be_lun->flags |= CTL_BE_BLOCK_LUN_WAITING; - while ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) { retval = msleep(be_lun, &softc->lock, PCATCH, "ctlblk", 0); if (retval == EINTR) break; } - be_lun->flags &= ~CTL_BE_BLOCK_LUN_WAITING; if ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) { @@ -2478,18 +2511,15 @@ ctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) softc->num_luns--; mtx_unlock(&softc->lock); - taskqueue_drain(be_lun->io_taskqueue, &be_lun->io_task); - + taskqueue_drain_all(be_lun->io_taskqueue); taskqueue_free(be_lun->io_taskqueue); - ctl_be_block_close(be_lun); - if (be_lun->disk_stats != NULL) devstat_remove_entry(be_lun->disk_stats); uma_zdestroy(be_lun->lun_zone); - ctl_free_opts(&be_lun->cbe_lun.options); + ctl_free_opts(&cbe_lun->options); free(be_lun->dev_path, M_CTLBLK); mtx_destroy(&be_lun->queue_lock); mtx_destroy(&be_lun->io_lock); @@ -2540,21 +2570,25 @@ ctl_be_block_modify_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) { struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; - struct ctl_be_block_devdata *dev_data; - int error; struct ctl_lun_create_params *params = &be_lun->params; + struct cdevsw *csw; + struct cdev *dev; uint64_t size_bytes; + int error, ref; - dev_data = &be_lun->backend.dev; - if (!dev_data->csw->d_ioctl) { + csw = devvn_refthread(be_lun->vn, &dev, &ref); + if (csw == NULL) + return (ENXIO); + if (csw->d_ioctl == NULL) { + dev_relthread(dev, ref); snprintf(req->error_str, sizeof(req->error_str), "no d_ioctl for device %s!", be_lun->dev_path); return (ENODEV); } - error = dev_data->csw->d_ioctl(dev_data->cdev, DIOCGMEDIASIZE, - (caddr_t)&size_bytes, FREAD, - curthread); + error = csw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&size_bytes, FREAD, + curthread); + dev_relthread(dev, ref); if (error) { snprintf(req->error_str, sizeof(req->error_str), "error %d returned for DIOCGMEDIASIZE ioctl " @@ -2587,8 +2621,9 @@ ctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) struct ctl_lun_modify_params *params; struct ctl_be_block_lun *be_lun; struct ctl_be_lun *cbe_lun; + char *value; uint64_t oldsize; - int error; + int error, wasprim; params = &req->reqdata.modify; @@ -2611,23 +2646,51 @@ ctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) be_lun->params.lun_size_bytes = params->lun_size_bytes; ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); - oldsize = be_lun->size_blocks; - if (be_lun->vn == NULL) - error = ctl_be_block_open(softc, be_lun, req); - else if (vn_isdisk(be_lun->vn, &error)) - error = ctl_be_block_modify_dev(be_lun, req); - else if (be_lun->vn->v_type == VREG) - error = ctl_be_block_modify_file(be_lun, req); + wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY); + value = ctl_get_opt(&cbe_lun->options, "ha_role"); + if (value != NULL) { + if (strcmp(value, "primary") == 0) + cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; + else + cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; + } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) + cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; else - error = EINVAL; + cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; + if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) { + if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) + ctl_lun_primary(cbe_lun); + else + ctl_lun_secondary(cbe_lun); + } + oldsize = be_lun->size_blocks; + if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) || + control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) { + if (be_lun->vn == NULL) + error = ctl_be_block_open(softc, be_lun, req); + else if (vn_isdisk(be_lun->vn, &error)) + error = ctl_be_block_modify_dev(be_lun, req); + else if (be_lun->vn->v_type == VREG) + error = ctl_be_block_modify_file(be_lun, req); + else + error = EINVAL; + if ((cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) && + be_lun->vn != NULL) { + cbe_lun->flags &= ~CTL_LUN_FLAG_OFFLINE; + ctl_lun_online(cbe_lun); + } + } else { + if (be_lun->vn != NULL) { + cbe_lun->flags |= CTL_LUN_FLAG_OFFLINE; + ctl_lun_offline(cbe_lun); + taskqueue_drain_all(be_lun->io_taskqueue); + error = ctl_be_block_close(be_lun); + } else + error = 0; + } if (be_lun->size_blocks != oldsize) ctl_lun_capacity_changed(cbe_lun); - if ((cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) && - be_lun->vn != NULL) { - cbe_lun->flags &= ~CTL_LUN_FLAG_OFFLINE; - ctl_lun_online(cbe_lun); - } /* Tell the user the exact size we ended up using */ params->lun_size_bytes = be_lun->size_bytes; diff --git a/sys/cam/ctl/ctl_backend_ramdisk.c b/sys/cam/ctl/ctl_backend_ramdisk.c index c39d1b6..073b167 100644 --- a/sys/cam/ctl/ctl_backend_ramdisk.c +++ b/sys/cam/ctl/ctl_backend_ramdisk.c @@ -56,14 +56,18 @@ __FBSDID("$FreeBSD$"); #include <sys/conf.h> #include <sys/ioccom.h> #include <sys/module.h> +#include <sys/sysctl.h> #include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_da.h> #include <cam/ctl/ctl_io.h> #include <cam/ctl/ctl.h> #include <cam/ctl/ctl_util.h> #include <cam/ctl/ctl_backend.h> #include <cam/ctl/ctl_debug.h> #include <cam/ctl/ctl_ioctl.h> +#include <cam/ctl/ctl_ha.h> +#include <cam/ctl/ctl_private.h> #include <cam/ctl/ctl_error.h> typedef enum { @@ -101,6 +105,7 @@ struct ctl_be_ramdisk_softc { }; static struct ctl_be_ramdisk_softc rd_softc; +extern struct ctl_softc *control_softc; int ctl_backend_ramdisk_init(void); void ctl_backend_ramdisk_shutdown(void); @@ -502,7 +507,7 @@ ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, mtx_unlock(&softc->lock); if (retval == 0) { - taskqueue_drain(be_lun->io_taskqueue, &be_lun->io_task); + taskqueue_drain_all(be_lun->io_taskqueue); taskqueue_free(be_lun->io_taskqueue); ctl_free_opts(&be_lun->cbe_lun.options); mtx_destroy(&be_lun->queue_lock); @@ -546,7 +551,13 @@ ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, else cbe_lun->lun_type = T_DIRECT; be_lun->flags = CTL_BE_RAMDISK_LUN_UNCONFIGURED; - cbe_lun->flags = CTL_LUN_FLAG_PRIMARY; + cbe_lun->flags = 0; + value = ctl_get_opt(&cbe_lun->options, "ha_role"); + if (value != NULL) { + if (strcmp(value, "primary") == 0) + cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; + } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) + cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; if (cbe_lun->lun_type == T_DIRECT) { if (params->blocksize_bytes != 0) @@ -717,7 +728,9 @@ ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, struct ctl_be_ramdisk_lun *be_lun; struct ctl_be_lun *cbe_lun; struct ctl_lun_modify_params *params; + char *value; uint32_t blocksize; + int wasprim; params = &req->reqdata.modify; @@ -739,15 +752,32 @@ ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, if (params->lun_size_bytes != 0) be_lun->params.lun_size_bytes = params->lun_size_bytes; ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); - blocksize = be_lun->cbe_lun.blocksize; + wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY); + value = ctl_get_opt(&cbe_lun->options, "ha_role"); + if (value != NULL) { + if (strcmp(value, "primary") == 0) + cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; + else + cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; + } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) + cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; + else + cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; + if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) { + if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) + ctl_lun_primary(cbe_lun); + else + ctl_lun_secondary(cbe_lun); + } + + blocksize = be_lun->cbe_lun.blocksize; if (be_lun->params.lun_size_bytes < blocksize) { snprintf(req->error_str, sizeof(req->error_str), "%s: LUN size %ju < blocksize %u", __func__, be_lun->params.lun_size_bytes, blocksize); goto bailout_error; } - be_lun->size_blocks = be_lun->params.lun_size_bytes / blocksize; be_lun->size_bytes = be_lun->size_blocks * blocksize; be_lun->cbe_lun.maxlba = be_lun->size_blocks - 1; diff --git a/sys/cam/ctl/ctl_cmd_table.c b/sys/cam/ctl/ctl_cmd_table.c index 9a7d70e..5b75468 100644 --- a/sys/cam/ctl/ctl_cmd_table.c +++ b/sys/cam/ctl/ctl_cmd_table.c @@ -69,8 +69,7 @@ const struct ctl_cmd_entry ctl_cmd_table_5e[32] = CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_IN | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -81,8 +80,7 @@ const struct ctl_cmd_entry ctl_cmd_table_5e[32] = CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_IN | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -93,8 +91,7 @@ const struct ctl_cmd_entry ctl_cmd_table_5e[32] = CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_IN | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -105,8 +102,7 @@ const struct ctl_cmd_entry ctl_cmd_table_5e[32] = CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_IN | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -123,8 +119,7 @@ const struct ctl_cmd_entry ctl_cmd_table_5f[32] = CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_OUT | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -135,8 +130,7 @@ const struct ctl_cmd_entry ctl_cmd_table_5f[32] = CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_OUT | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -147,8 +141,7 @@ const struct ctl_cmd_entry ctl_cmd_table_5f[32] = CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_OUT | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -159,8 +152,7 @@ const struct ctl_cmd_entry ctl_cmd_table_5f[32] = CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_OUT | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -171,8 +163,7 @@ const struct ctl_cmd_entry ctl_cmd_table_5f[32] = CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_OUT | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -183,8 +174,7 @@ const struct ctl_cmd_entry ctl_cmd_table_5f[32] = CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_OUT | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -195,8 +185,7 @@ const struct ctl_cmd_entry ctl_cmd_table_5f[32] = CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_OUT | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -339,7 +328,7 @@ const struct ctl_cmd_entry ctl_cmd_table_84[32] = CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_IN | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -436,7 +425,6 @@ const struct ctl_cmd_entry ctl_cmd_table_9e[32] = {ctl_read_capacity_16, CTL_SERIDX_RD_CAP, CTL_CMD_FLAG_OK_ON_SLUN | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_SECONDARY | CTL_FLAG_DATA_IN | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_READCAP, @@ -493,8 +481,8 @@ const struct ctl_cmd_entry ctl_cmd_table_a3[32] = {ctl_report_tagret_port_groups, CTL_SERIDX_INQ, CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | + CTL_CMD_FLAG_OK_ON_UNAVAIL | CTL_FLAG_DATA_IN | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -507,8 +495,8 @@ const struct ctl_cmd_entry ctl_cmd_table_a3[32] = {ctl_report_supported_opcodes, CTL_SERIDX_INQ, CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | + CTL_CMD_FLAG_OK_ON_UNAVAIL | CTL_FLAG_DATA_IN | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -518,8 +506,8 @@ const struct ctl_cmd_entry ctl_cmd_table_a3[32] = {ctl_report_supported_tmf, CTL_SERIDX_INQ, CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | + CTL_CMD_FLAG_OK_ON_UNAVAIL | CTL_FLAG_DATA_IN | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -532,8 +520,8 @@ const struct ctl_cmd_entry ctl_cmd_table_a3[32] = {ctl_report_timestamp, CTL_SERIDX_INQ, CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | + CTL_CMD_FLAG_OK_ON_UNAVAIL | CTL_FLAG_DATA_IN | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -563,8 +551,8 @@ const struct ctl_cmd_entry ctl_cmd_table[256] = CTL_CMD_FLAG_NO_SENSE | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | + CTL_CMD_FLAG_OK_ON_UNAVAIL | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, 6, {0x01, 0, 0, 0xff, 0x07}}, @@ -624,8 +612,8 @@ const struct ctl_cmd_entry ctl_cmd_table[256] = CTL_CMD_FLAG_NO_SENSE | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | + CTL_CMD_FLAG_OK_ON_UNAVAIL | CTL_FLAG_DATA_IN | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, 6, {0xe1, 0xff, 0xff, 0xff, 0x07}}, @@ -640,8 +628,7 @@ const struct ctl_cmd_entry ctl_cmd_table[256] = {ctl_mode_select, CTL_SERIDX_MD_SEL, CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_OUT, CTL_LUN_PAT_NONE, 6, {0x11, 0, 0, 0xff, 0x07}}, @@ -650,8 +637,7 @@ const struct ctl_cmd_entry ctl_cmd_table[256] = CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_OUT, CTL_LUN_PAT_NONE, 6, {0, 0, 0, 0, 0x07}}, @@ -660,8 +646,7 @@ const struct ctl_cmd_entry ctl_cmd_table[256] = CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_NONE, CTL_LUN_PAT_NONE, 6, {0, 0, 0, 0, 0x07}}, @@ -675,8 +660,7 @@ const struct ctl_cmd_entry ctl_cmd_table[256] = {ctl_mode_sense, CTL_SERIDX_MD_SNS, CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_IN | CTL_CMD_FLAG_ALLOW_ON_PR_WRESV, CTL_LUN_PAT_NONE, 6, {0x08, 0xff, 0xff, 0xff, 0x07}}, @@ -685,7 +669,6 @@ const struct ctl_cmd_entry ctl_cmd_table[256] = {ctl_start_stop, CTL_SERIDX_START, CTL_CMD_FLAG_OK_ON_SLUN | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | CTL_FLAG_DATA_NONE | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, 6, {0x01, 0, 0, 0x03, 0x07}}, @@ -721,7 +704,6 @@ const struct ctl_cmd_entry ctl_cmd_table[256] = {ctl_read_capacity, CTL_SERIDX_RD_CAP, CTL_CMD_FLAG_OK_ON_SLUN| CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_SECONDARY | CTL_FLAG_DATA_IN | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_READCAP, 10, {0, 0, 0, 0, 0, 0, 0, 0, 0x07}}, @@ -812,7 +794,7 @@ const struct ctl_cmd_entry ctl_cmd_table[256] = {ctl_write_buffer, CTL_SERIDX_MD_SEL, CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_OUT, CTL_LUN_PAT_NONE, 10, {0x1f, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07}}, @@ -821,7 +803,7 @@ const struct ctl_cmd_entry ctl_cmd_table[256] = {ctl_read_buffer, CTL_SERIDX_MD_SNS, CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_IN | CTL_CMD_FLAG_ALLOW_ON_PR_WRESV, CTL_LUN_PAT_NONE, @@ -911,8 +893,7 @@ const struct ctl_cmd_entry ctl_cmd_table[256] = {ctl_mode_select, CTL_SERIDX_MD_SEL, CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_OUT, CTL_LUN_PAT_NONE, 10, {0x11, 0, 0, 0, 0, 0, 0xff, 0xff, 0x07} }, @@ -921,8 +902,7 @@ const struct ctl_cmd_entry ctl_cmd_table[256] = CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_OUT, CTL_LUN_PAT_NONE, 10, {0x02, 0, 0xff, 0, 0, 0, 0xff, 0xff, 0x07} }, @@ -931,8 +911,7 @@ const struct ctl_cmd_entry ctl_cmd_table[256] = CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_OUT, CTL_LUN_PAT_NONE, 10, {0x02, 0, 0xff, 0, 0, 0, 0xff, 0xff, 0x07} }, @@ -946,8 +925,7 @@ const struct ctl_cmd_entry ctl_cmd_table[256] = {ctl_mode_sense, CTL_SERIDX_MD_SNS, CTL_CMD_FLAG_OK_ON_BOTH | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | CTL_FLAG_DATA_IN | CTL_CMD_FLAG_ALLOW_ON_PR_WRESV, CTL_LUN_PAT_NONE, 10, {0x18, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0x07} }, @@ -1199,8 +1177,8 @@ const struct ctl_cmd_entry ctl_cmd_table[256] = CTL_CMD_FLAG_NO_SENSE | CTL_CMD_FLAG_OK_ON_STOPPED | CTL_CMD_FLAG_OK_ON_INOPERABLE | - CTL_CMD_FLAG_OK_ON_OFFLINE | - CTL_CMD_FLAG_OK_ON_SECONDARY | + CTL_CMD_FLAG_OK_ON_STANDBY | + CTL_CMD_FLAG_OK_ON_UNAVAIL | CTL_FLAG_DATA_IN | CTL_CMD_FLAG_ALLOW_ON_PR_RESV, CTL_LUN_PAT_NONE, @@ -1315,33 +1293,17 @@ const struct ctl_cmd_entry ctl_cmd_table[256] = /* BF VOLUME SET OUT */ {NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE}, -/* C0 - ISC_SEND_MSG_SHORT */ -//{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE}, -{ctl_isc, CTL_SERIDX_READ, CTL_CMD_FLAG_OK_ON_PROC | CTL_FLAG_DATA_NONE, - CTL_LUN_PAT_NONE, - 16, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, +/* C0 */ +{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE}, -/* C1 - ISC_SEND_MSG */ -//{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE}, -{ctl_isc, CTL_SERIDX_READ, CTL_CMD_FLAG_OK_ON_PROC | CTL_FLAG_DATA_OUT, - CTL_LUN_PAT_NONE, - 16, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, +/* C1 */ +{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE}, -/* C2 - ISC_WRITE */ -//{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE}, -{ctl_isc, CTL_SERIDX_READ, CTL_CMD_FLAG_OK_ON_PROC | CTL_FLAG_DATA_OUT, - CTL_LUN_PAT_NONE, - 16, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, +/* C2 */ +{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE}, -/* C3 - ISC_READ */ -//{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE}, -{ctl_isc, CTL_SERIDX_READ, CTL_CMD_FLAG_OK_ON_PROC | CTL_FLAG_DATA_IN, - CTL_LUN_PAT_NONE, - 16, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, +/* C3 */ +{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE}, /* C4 */ {NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE}, diff --git a/sys/cam/ctl/ctl_error.c b/sys/cam/ctl/ctl_error.c index 8d98204..8ef5176 100644 --- a/sys/cam/ctl/ctl_error.c +++ b/sys/cam/ctl/ctl_error.c @@ -723,6 +723,18 @@ ctl_set_illegal_pr_release(struct ctl_scsiio *ctsio) } void +ctl_set_lun_transit(struct ctl_scsiio *ctsio) +{ + /* "Logical unit not ready, asymmetric access state transition" */ + ctl_set_sense(ctsio, + /*current_error*/ 1, + /*sense_key*/ SSD_KEY_NOT_READY, + /*asc*/ 0x04, + /*ascq*/ 0x0a, + SSD_ELEM_NONE); +} + +void ctl_set_lun_standby(struct ctl_scsiio *ctsio) { /* "Logical unit not ready, target port in standby state" */ @@ -735,6 +747,18 @@ ctl_set_lun_standby(struct ctl_scsiio *ctsio) } void +ctl_set_lun_unavail(struct ctl_scsiio *ctsio) +{ + /* "Logical unit not ready, target port in unavailable state" */ + ctl_set_sense(ctsio, + /*current_error*/ 1, + /*sense_key*/ SSD_KEY_NOT_READY, + /*asc*/ 0x04, + /*ascq*/ 0x0c, + SSD_ELEM_NONE); +} + +void ctl_set_medium_format_corrupted(struct ctl_scsiio *ctsio) { /* "Medium format corrupted" */ diff --git a/sys/cam/ctl/ctl_error.h b/sys/cam/ctl/ctl_error.h index 8430eef..4fa8060 100644 --- a/sys/cam/ctl/ctl_error.h +++ b/sys/cam/ctl/ctl_error.h @@ -67,7 +67,9 @@ void ctl_set_invalid_opcode(struct ctl_scsiio *ctsio); void ctl_set_param_len_error(struct ctl_scsiio *ctsio); void ctl_set_already_locked(struct ctl_scsiio *ctsio); void ctl_set_unsupported_lun(struct ctl_scsiio *ctsio); +void ctl_set_lun_transit(struct ctl_scsiio *ctsio); void ctl_set_lun_standby(struct ctl_scsiio *ctsio); +void ctl_set_lun_unavail(struct ctl_scsiio *ctsio); void ctl_set_internal_failure(struct ctl_scsiio *ctsio, int sks_valid, uint16_t retry_count); void ctl_set_medium_error(struct ctl_scsiio *ctsio); diff --git a/sys/cam/ctl/ctl_frontend.c b/sys/cam/ctl/ctl_frontend.c index 5554951..c9c75d4 100644 --- a/sys/cam/ctl/ctl_frontend.c +++ b/sys/cam/ctl/ctl_frontend.c @@ -140,6 +140,7 @@ int ctl_port_register(struct ctl_port *port) { struct ctl_softc *softc = control_softc; + struct ctl_port *tport, *nport; void *pool; int port_num; int retval; @@ -149,10 +150,13 @@ ctl_port_register(struct ctl_port *port) KASSERT(softc != NULL, ("CTL is not initialized")); mtx_lock(&softc->ctl_lock); - port_num = ctl_ffz(softc->ctl_port_mask, CTL_MAX_PORTS); - if ((port_num == -1) - || (ctl_set_mask(softc->ctl_port_mask, port_num) == -1)) { - port->targ_port = -1; + if (port->targ_port >= 0) + port_num = port->targ_port; + else + port_num = ctl_ffz(softc->ctl_port_mask, + softc->port_min, softc->port_max); + if ((port_num < 0) || + (ctl_set_mask(softc->ctl_port_mask, port_num) < 0)) { mtx_unlock(&softc->ctl_lock); return (1); } @@ -195,10 +199,17 @@ error: STAILQ_INIT(&port->options); mtx_lock(&softc->ctl_lock); - port->targ_port = port_num + softc->port_offset; + port->targ_port = port_num; STAILQ_INSERT_TAIL(&port->frontend->port_list, port, fe_links); - STAILQ_INSERT_TAIL(&softc->port_list, port, links); - softc->ctl_ports[port_num] = port; + for (tport = NULL, nport = STAILQ_FIRST(&softc->port_list); + nport != NULL && nport->targ_port < port_num; + tport = nport, nport = STAILQ_NEXT(tport, links)) { + } + if (tport) + STAILQ_INSERT_AFTER(&softc->port_list, tport, port, links); + else + STAILQ_INSERT_HEAD(&softc->port_list, port, links); + softc->ctl_ports[port->targ_port] = port; mtx_unlock(&softc->ctl_lock); return (retval); @@ -209,7 +220,7 @@ ctl_port_deregister(struct ctl_port *port) { struct ctl_softc *softc = control_softc; struct ctl_io_pool *pool; - int port_num, retval, i; + int retval, i; retval = 0; @@ -224,10 +235,8 @@ ctl_port_deregister(struct ctl_port *port) STAILQ_REMOVE(&softc->port_list, port, ctl_port, links); STAILQ_REMOVE(&port->frontend->port_list, port, ctl_port, fe_links); softc->num_ports--; - port_num = (port->targ_port < CTL_MAX_PORTS) ? port->targ_port : - port->targ_port - CTL_MAX_PORTS; - ctl_clear_mask(softc->ctl_port_mask, port_num); - softc->ctl_ports[port_num] = NULL; + ctl_clear_mask(softc->ctl_port_mask, port->targ_port); + softc->ctl_ports[port->targ_port] = NULL; mtx_unlock(&softc->ctl_lock); ctl_pool_free(pool); @@ -321,6 +330,7 @@ ctl_port_online(struct ctl_port *port) port->port_online(port->onoff_arg); /* XXX KDM need a lock here? */ port->status |= CTL_PORT_STATUS_ONLINE; + ctl_isc_announce_port(port); } void @@ -347,6 +357,7 @@ ctl_port_offline(struct ctl_port *port) } /* XXX KDM need a lock here? */ port->status &= ~CTL_PORT_STATUS_ONLINE; + ctl_isc_announce_port(port); } /* diff --git a/sys/cam/ctl/ctl_frontend.h b/sys/cam/ctl/ctl_frontend.h index 470d7a7..a6ca9e1 100644 --- a/sys/cam/ctl/ctl_frontend.h +++ b/sys/cam/ctl/ctl_frontend.h @@ -125,12 +125,12 @@ struct ctl_wwpn_iid { * port_online(): This function is called, with onoff_arg as its * argument, by the CTL layer when it wants the FETD * to start responding to selections on the specified - * target ID. (targ_target) + * target ID. * * port_offline(): This function is called, with onoff_arg as its * argument, by the CTL layer when it wants the FETD * to stop responding to selection on the specified - * target ID. (targ_target) + * target ID. * * onoff_arg: This is supplied as an argument to port_online() * and port_offline(). This is specified by the diff --git a/sys/cam/ctl/ctl_frontend_cam_sim.c b/sys/cam/ctl/ctl_frontend_cam_sim.c index 88dcb29..01807de 100644 --- a/sys/cam/ctl/ctl_frontend_cam_sim.c +++ b/sys/cam/ctl/ctl_frontend_cam_sim.c @@ -157,6 +157,7 @@ cfcs_init(void) /* XXX These should probably be fetched from CTL. */ port->max_targets = 1; port->max_target_id = 15; + port->targ_port = -1; retval = ctl_port_register(port); if (retval != 0) { @@ -546,12 +547,8 @@ cfcs_action(struct cam_sim *sim, union ccb *ccb) * down via the XPT_RESET_BUS/LUN CCBs below. */ io->io_hdr.io_type = CTL_IO_SCSI; - io->io_hdr.nexus.initid.id = 1; + io->io_hdr.nexus.initid = 1; io->io_hdr.nexus.targ_port = softc->port.targ_port; - /* - * XXX KDM how do we handle target IDs? - */ - io->io_hdr.nexus.targ_target.id = ccb->ccb_h.target_id; io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun; /* * This tag scheme isn't the best, since we could in theory @@ -639,9 +636,8 @@ cfcs_action(struct cam_sim *sim, union ccb *ccb) ccb->ccb_h.io_ptr = io; io->io_hdr.io_type = CTL_IO_TASK; - io->io_hdr.nexus.initid.id = 1; + io->io_hdr.nexus.initid = 1; io->io_hdr.nexus.targ_port = softc->port.targ_port; - io->io_hdr.nexus.targ_target.id = ccb->ccb_h.target_id; io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun; io->taskio.task_action = CTL_TASK_ABORT_TASK; io->taskio.tag_num = abort_ccb->csio.tag_id; @@ -735,9 +731,8 @@ cfcs_action(struct cam_sim *sim, union ccb *ccb) ccb->ccb_h.io_ptr = io; io->io_hdr.io_type = CTL_IO_TASK; - io->io_hdr.nexus.initid.id = 0; + io->io_hdr.nexus.initid = 1; io->io_hdr.nexus.targ_port = softc->port.targ_port; - io->io_hdr.nexus.targ_target.id = ccb->ccb_h.target_id; io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun; if (ccb->ccb_h.func_code == XPT_RESET_BUS) io->taskio.task_action = CTL_TASK_BUS_RESET; diff --git a/sys/cam/ctl/ctl_frontend_ioctl.c b/sys/cam/ctl/ctl_frontend_ioctl.c index 51e8508..67156bc 100644 --- a/sys/cam/ctl/ctl_frontend_ioctl.c +++ b/sys/cam/ctl/ctl_frontend_ioctl.c @@ -93,6 +93,7 @@ cfi_init(void) port->fe_done = cfi_done; port->max_targets = 1; port->max_target_id = 0; + port->targ_port = -1; port->max_initiators = 1; if (ctl_port_register(port) != 0) { diff --git a/sys/cam/ctl/ctl_frontend_iscsi.c b/sys/cam/ctl/ctl_frontend_iscsi.c index 5443946..6ea862f 100644 --- a/sys/cam/ctl/ctl_frontend_iscsi.c +++ b/sys/cam/ctl/ctl_frontend_iscsi.c @@ -564,9 +564,8 @@ cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request) ctl_zero_io(io); io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = request; io->io_hdr.io_type = CTL_IO_SCSI; - io->io_hdr.nexus.initid.id = cs->cs_ctl_initid; + io->io_hdr.nexus.initid = cs->cs_ctl_initid; io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port; - io->io_hdr.nexus.targ_target.id = 0; io->io_hdr.nexus.targ_lun = cfiscsi_decode_lun(bhssc->bhssc_lun); io->scsiio.tag_num = bhssc->bhssc_initiator_task_tag; switch ((bhssc->bhssc_flags & BHSSC_FLAGS_ATTR)) { @@ -621,9 +620,8 @@ cfiscsi_pdu_handle_task_request(struct icl_pdu *request) ctl_zero_io(io); io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = request; io->io_hdr.io_type = CTL_IO_TASK; - io->io_hdr.nexus.initid.id = cs->cs_ctl_initid; + io->io_hdr.nexus.initid = cs->cs_ctl_initid; io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port; - io->io_hdr.nexus.targ_target.id = 0; io->io_hdr.nexus.targ_lun = cfiscsi_decode_lun(bhstmr->bhstmr_lun); io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */ @@ -1120,9 +1118,8 @@ cfiscsi_session_terminate_tasks(struct cfiscsi_session *cs) ctl_zero_io(io); io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = cs; io->io_hdr.io_type = CTL_IO_TASK; - io->io_hdr.nexus.initid.id = cs->cs_ctl_initid; + io->io_hdr.nexus.initid = cs->cs_ctl_initid; io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port; - io->io_hdr.nexus.targ_target.id = 0; io->io_hdr.nexus.targ_lun = 0; io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */ io->taskio.task_action = CTL_TASK_I_T_NEXUS_RESET; @@ -2105,6 +2102,7 @@ cfiscsi_ioctl_port_create(struct ctl_req *req) /* XXX These should probably be fetched from CTL. */ port->max_targets = 1; port->max_target_id = 15; + port->targ_port = -1; port->options = opts; STAILQ_INIT(&opts); diff --git a/sys/cam/ctl/ctl_ha.c b/sys/cam/ctl/ctl_ha.c new file mode 100644 index 0000000..8d6604f --- /dev/null +++ b/sys/cam/ctl/ctl_ha.c @@ -0,0 +1,958 @@ +/*- + * Copyright (c) 2015 Alexander Motin <mav@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, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/kthread.h> +#include <sys/types.h> +#include <sys/limits.h> +#include <sys/lock.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/condvar.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/proc.h> +#include <sys/conf.h> +#include <sys/queue.h> +#include <sys/sysctl.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/uio.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <vm/uma.h> + +#include <cam/cam.h> +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_da.h> +#include <cam/ctl/ctl_io.h> +#include <cam/ctl/ctl.h> +#include <cam/ctl/ctl_frontend.h> +#include <cam/ctl/ctl_util.h> +#include <cam/ctl/ctl_backend.h> +#include <cam/ctl/ctl_ioctl.h> +#include <cam/ctl/ctl_ha.h> +#include <cam/ctl/ctl_private.h> +#include <cam/ctl/ctl_debug.h> +#include <cam/ctl/ctl_error.h> + +#if (__FreeBSD_version < 1100000) +struct mbufq { + struct mbuf *head; + struct mbuf *tail; +}; + +static void +mbufq_init(struct mbufq *q, int limit) +{ + + q->head = q->tail = NULL; +} + +static void +mbufq_drain(struct mbufq *q) +{ + struct mbuf *m; + + while ((m = q->head) != NULL) { + q->head = m->m_nextpkt; + m_freem(m); + } + q->tail = NULL; +} + +static struct mbuf * +mbufq_dequeue(struct mbufq *q) +{ + struct mbuf *m; + + m = q->head; + if (m) { + if (q->tail == m) + q->tail = NULL; + q->head = m->m_nextpkt; + m->m_nextpkt = NULL; + } + return (m); +} + +static void +mbufq_enqueue(struct mbufq *q, struct mbuf *m) +{ + + m->m_nextpkt = NULL; + if (q->tail) + q->tail->m_nextpkt = m; + else + q->head = m; + q->tail = m; +} + +static u_int +sbavail(struct sockbuf *sb) +{ + return (sb->sb_cc); +} + +#if (__FreeBSD_version < 1000000) +#define mtodo(m, o) ((void *)(((m)->m_data) + (o))) +#endif +#endif + +struct ha_msg_wire { + uint32_t channel; + uint32_t length; +}; + +struct ha_dt_msg_wire { + ctl_ha_dt_cmd command; + uint32_t size; + uint8_t *local; + uint8_t *remote; +}; + +struct ha_softc { + struct ctl_softc *ha_ctl_softc; + ctl_evt_handler ha_handler[CTL_HA_CHAN_MAX]; + char ha_peer[128]; + struct sockaddr_in ha_peer_in; + struct socket *ha_lso; + struct socket *ha_so; + struct mbufq ha_sendq; + struct mbuf *ha_sending; + struct mtx ha_lock; + int ha_connect; + int ha_listen; + int ha_connected; + int ha_receiving; + int ha_wakeup; + int ha_disconnect; + TAILQ_HEAD(, ctl_ha_dt_req) ha_dts; +} ha_softc; + +extern struct ctl_softc *control_softc; + +static void +ctl_ha_conn_wake(struct ha_softc *softc) +{ + + mtx_lock(&softc->ha_lock); + softc->ha_wakeup = 1; + mtx_unlock(&softc->ha_lock); + wakeup(&softc->ha_wakeup); +} + +static int +ctl_ha_lupcall(struct socket *so, void *arg, int waitflag) +{ + struct ha_softc *softc = arg; + + ctl_ha_conn_wake(softc); + return (SU_OK); +} + +static int +ctl_ha_rupcall(struct socket *so, void *arg, int waitflag) +{ + struct ha_softc *softc = arg; + + wakeup(&softc->ha_receiving); + return (SU_OK); +} + +static int +ctl_ha_supcall(struct socket *so, void *arg, int waitflag) +{ + struct ha_softc *softc = arg; + + ctl_ha_conn_wake(softc); + return (SU_OK); +} + +static void +ctl_ha_evt(struct ha_softc *softc, ctl_ha_channel ch, ctl_ha_event evt, + int param) +{ + int i; + + if (ch < CTL_HA_CHAN_MAX) { + if (softc->ha_handler[ch]) + softc->ha_handler[ch](ch, evt, param); + return; + } + for (i = 0; i < CTL_HA_CHAN_MAX; i++) { + if (softc->ha_handler[i]) + softc->ha_handler[i](i, evt, param); + } +} + +static void +ctl_ha_close(struct ha_softc *softc) +{ + struct socket *so = softc->ha_so; + int report = 0; + + if (softc->ha_connected || softc->ha_disconnect) { + softc->ha_connected = 0; + mbufq_drain(&softc->ha_sendq); + m_freem(softc->ha_sending); + softc->ha_sending = NULL; + report = 1; + } + if (so) { + SOCKBUF_LOCK(&so->so_rcv); + soupcall_clear(so, SO_RCV); + while (softc->ha_receiving) { + wakeup(&softc->ha_receiving); + msleep(&softc->ha_receiving, SOCKBUF_MTX(&so->so_rcv), + 0, "ha_rx exit", 0); + } + SOCKBUF_UNLOCK(&so->so_rcv); + SOCKBUF_LOCK(&so->so_snd); + soupcall_clear(so, SO_SND); + SOCKBUF_UNLOCK(&so->so_snd); + softc->ha_so = NULL; + if (softc->ha_connect) + pause("reconnect", hz / 2); + soclose(so); + } + if (report) { + ctl_ha_evt(softc, CTL_HA_CHAN_MAX, CTL_HA_EVT_LINK_CHANGE, + (softc->ha_connect || softc->ha_listen) ? + CTL_HA_LINK_UNKNOWN : CTL_HA_LINK_OFFLINE); + } +} + +static void +ctl_ha_lclose(struct ha_softc *softc) +{ + + if (softc->ha_lso) { + SOCKBUF_LOCK(&softc->ha_lso->so_rcv); + soupcall_clear(softc->ha_lso, SO_RCV); + SOCKBUF_UNLOCK(&softc->ha_lso->so_rcv); + soclose(softc->ha_lso); + softc->ha_lso = NULL; + } +} + +static void +ctl_ha_rx_thread(void *arg) +{ + struct ha_softc *softc = arg; + struct socket *so = softc->ha_so; + struct ha_msg_wire wire_hdr; + struct uio uio; + struct iovec iov; + int error, flags, next; + + bzero(&wire_hdr, sizeof(wire_hdr)); + while (1) { + if (wire_hdr.length > 0) + next = wire_hdr.length; + else + next = sizeof(wire_hdr); + SOCKBUF_LOCK(&so->so_rcv); + while (sbavail(&so->so_rcv) < next) { + if (softc->ha_connected == 0 || so->so_error || + (so->so_rcv.sb_state & SBS_CANTRCVMORE)) { + goto errout; + } + so->so_rcv.sb_lowat = next; + msleep(&softc->ha_receiving, SOCKBUF_MTX(&so->so_rcv), + 0, "-", 0); + } + SOCKBUF_UNLOCK(&so->so_rcv); + + if (wire_hdr.length == 0) { + iov.iov_base = &wire_hdr; + iov.iov_len = sizeof(wire_hdr); + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_rw = UIO_READ; + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_td = curthread; + uio.uio_resid = sizeof(wire_hdr); + flags = MSG_DONTWAIT; + error = soreceive(softc->ha_so, NULL, &uio, NULL, + NULL, &flags); + if (error != 0) { + printf("%s: header receive error %d\n", + __func__, error); + SOCKBUF_LOCK(&so->so_rcv); + goto errout; + } + } else { + ctl_ha_evt(softc, wire_hdr.channel, + CTL_HA_EVT_MSG_RECV, wire_hdr.length); + wire_hdr.length = 0; + } + } + +errout: + softc->ha_receiving = 0; + wakeup(&softc->ha_receiving); + SOCKBUF_UNLOCK(&so->so_rcv); + ctl_ha_conn_wake(softc); + kthread_exit(); +} + +static void +ctl_ha_send(struct ha_softc *softc) +{ + struct socket *so = softc->ha_so; + int error; + + while (1) { + if (softc->ha_sending == NULL) { + mtx_lock(&softc->ha_lock); + softc->ha_sending = mbufq_dequeue(&softc->ha_sendq); + mtx_unlock(&softc->ha_lock); + if (softc->ha_sending == NULL) { + so->so_snd.sb_lowat = so->so_snd.sb_hiwat + 1; + break; + } + } + SOCKBUF_LOCK(&so->so_snd); + if (sbspace(&so->so_snd) < softc->ha_sending->m_pkthdr.len) { + so->so_snd.sb_lowat = softc->ha_sending->m_pkthdr.len; + SOCKBUF_UNLOCK(&so->so_snd); + break; + } + SOCKBUF_UNLOCK(&so->so_snd); + error = sosend(softc->ha_so, NULL, NULL, softc->ha_sending, + NULL, MSG_DONTWAIT, curthread); + softc->ha_sending = NULL; + if (error != 0) { + printf("%s: sosend() error %d\n", __func__, error); + return; + } + }; +} + +static void +ctl_ha_sock_setup(struct ha_softc *softc) +{ + struct sockopt opt; + struct socket *so = softc->ha_so; + int error, val; + + val = 1024 * 1024; + error = soreserve(so, val, val); + if (error) + printf("%s: soreserve failed %d\n", __func__, error); + + SOCKBUF_LOCK(&so->so_rcv); + so->so_rcv.sb_lowat = sizeof(struct ha_msg_wire); + soupcall_set(so, SO_RCV, ctl_ha_rupcall, softc); + SOCKBUF_UNLOCK(&so->so_rcv); + SOCKBUF_LOCK(&so->so_snd); + so->so_snd.sb_lowat = sizeof(struct ha_msg_wire); + soupcall_set(so, SO_SND, ctl_ha_supcall, softc); + SOCKBUF_UNLOCK(&so->so_snd); + + bzero(&opt, sizeof(struct sockopt)); + opt.sopt_dir = SOPT_SET; + opt.sopt_level = SOL_SOCKET; + opt.sopt_name = SO_KEEPALIVE; + opt.sopt_val = &val; + opt.sopt_valsize = sizeof(val); + val = 1; + error = sosetopt(so, &opt); + if (error) + printf("%s: KEEPALIVE setting failed %d\n", __func__, error); + + opt.sopt_level = IPPROTO_TCP; + opt.sopt_name = TCP_NODELAY; + val = 1; + error = sosetopt(so, &opt); + if (error) + printf("%s: NODELAY setting failed %d\n", __func__, error); + + opt.sopt_name = TCP_KEEPINIT; + val = 3; + error = sosetopt(so, &opt); + if (error) + printf("%s: KEEPINIT setting failed %d\n", __func__, error); + + opt.sopt_name = TCP_KEEPIDLE; + val = 1; + error = sosetopt(so, &opt); + if (error) + printf("%s: KEEPIDLE setting failed %d\n", __func__, error); + + opt.sopt_name = TCP_KEEPINTVL; + val = 1; + error = sosetopt(so, &opt); + if (error) + printf("%s: KEEPINTVL setting failed %d\n", __func__, error); + + opt.sopt_name = TCP_KEEPCNT; + val = 5; + error = sosetopt(so, &opt); + if (error) + printf("%s: KEEPCNT setting failed %d\n", __func__, error); +} + +static int +ctl_ha_connect(struct ha_softc *softc) +{ + struct thread *td = curthread; + struct socket *so; + int error; + + /* Create the socket */ + error = socreate(PF_INET, &so, SOCK_STREAM, + IPPROTO_TCP, td->td_ucred, td); + if (error != 0) { + printf("%s: socreate() error %d\n", __func__, error); + return (error); + } + softc->ha_so = so; + ctl_ha_sock_setup(softc); + + error = soconnect(so, (struct sockaddr *)&softc->ha_peer_in, td); + if (error != 0) { + printf("%s: soconnect() error %d\n", __func__, error); + goto out; + } + return (0); + +out: + ctl_ha_close(softc); + return (error); +} + +static int +ctl_ha_accept(struct ha_softc *softc) +{ + struct socket *so; + struct sockaddr *sap; + int error; + + ACCEPT_LOCK(); + if (softc->ha_lso->so_rcv.sb_state & SBS_CANTRCVMORE) + softc->ha_lso->so_error = ECONNABORTED; + if (softc->ha_lso->so_error) { + error = softc->ha_lso->so_error; + softc->ha_lso->so_error = 0; + ACCEPT_UNLOCK(); + printf("%s: socket error %d\n", __func__, error); + goto out; + } + so = TAILQ_FIRST(&softc->ha_lso->so_comp); + if (so == NULL) { + ACCEPT_UNLOCK(); + return (EWOULDBLOCK); + } + KASSERT(!(so->so_qstate & SQ_INCOMP), ("accept1: so SQ_INCOMP")); + KASSERT(so->so_qstate & SQ_COMP, ("accept1: so not SQ_COMP")); + + /* + * Before changing the flags on the socket, we have to bump the + * reference count. Otherwise, if the protocol calls sofree(), + * the socket will be released due to a zero refcount. + */ + SOCK_LOCK(so); /* soref() and so_state update */ + soref(so); /* file descriptor reference */ + + TAILQ_REMOVE(&softc->ha_lso->so_comp, so, so_list); + softc->ha_lso->so_qlen--; + so->so_state |= SS_NBIO; + so->so_qstate &= ~SQ_COMP; + so->so_head = NULL; + + SOCK_UNLOCK(so); + ACCEPT_UNLOCK(); + + sap = NULL; + error = soaccept(so, &sap); + if (error != 0) { + printf("%s: soaccept() error %d\n", __func__, error); + if (sap != NULL) + free(sap, M_SONAME); + goto out; + } + if (sap != NULL) + free(sap, M_SONAME); + softc->ha_so = so; + ctl_ha_sock_setup(softc); + return (0); + +out: + ctl_ha_lclose(softc); + return (error); +} + +static int +ctl_ha_listen(struct ha_softc *softc) +{ + struct thread *td = curthread; + struct sockopt opt; + int error, val; + + /* Create the socket */ + if (softc->ha_lso == NULL) { + error = socreate(PF_INET, &softc->ha_lso, SOCK_STREAM, + IPPROTO_TCP, td->td_ucred, td); + if (error != 0) { + printf("%s: socreate() error %d\n", __func__, error); + return (error); + } + bzero(&opt, sizeof(struct sockopt)); + opt.sopt_dir = SOPT_SET; + opt.sopt_level = SOL_SOCKET; + opt.sopt_name = SO_REUSEADDR; + opt.sopt_val = &val; + opt.sopt_valsize = sizeof(val); + val = 1; + error = sosetopt(softc->ha_lso, &opt); + if (error) { + printf("%s: REUSEADDR setting failed %d\n", + __func__, error); + } + SOCKBUF_LOCK(&softc->ha_lso->so_rcv); + soupcall_set(softc->ha_lso, SO_RCV, ctl_ha_lupcall, softc); + SOCKBUF_UNLOCK(&softc->ha_lso->so_rcv); + } + + error = sobind(softc->ha_lso, (struct sockaddr *)&softc->ha_peer_in, td); + if (error != 0) { + printf("%s: sobind() error %d\n", __func__, error); + goto out; + } + error = solisten(softc->ha_lso, 1, td); + if (error != 0) { + printf("%s: solisten() error %d\n", __func__, error); + goto out; + } + return (0); + +out: + ctl_ha_lclose(softc); + return (error); +} + +static void +ctl_ha_conn_thread(void *arg) +{ + struct ha_softc *softc = arg; + int error; + + while (1) { + if (softc->ha_disconnect) { + ctl_ha_close(softc); + ctl_ha_lclose(softc); + softc->ha_disconnect = 0; + } else if (softc->ha_so != NULL && + (softc->ha_so->so_error || + softc->ha_so->so_rcv.sb_state & SBS_CANTRCVMORE)) + ctl_ha_close(softc); + if (softc->ha_so == NULL) { + if (softc->ha_lso != NULL) + ctl_ha_accept(softc); + else if (softc->ha_listen) + ctl_ha_listen(softc); + else if (softc->ha_connect) + ctl_ha_connect(softc); + } + if (softc->ha_so != NULL) { + if (softc->ha_connected == 0 && + softc->ha_so->so_error == 0 && + (softc->ha_so->so_state & SS_ISCONNECTING) == 0) { + softc->ha_connected = 1; + ctl_ha_evt(softc, CTL_HA_CHAN_MAX, + CTL_HA_EVT_LINK_CHANGE, + CTL_HA_LINK_ONLINE); + softc->ha_receiving = 1; + error = kproc_kthread_add(ctl_ha_rx_thread, + softc, &softc->ha_ctl_softc->ctl_proc, + NULL, 0, 0, "ctl", "ha_rx"); + if (error != 0) { + printf("Error creating CTL HA rx thread!\n"); + softc->ha_receiving = 0; + softc->ha_disconnect = 1; + } + } + ctl_ha_send(softc); + } + mtx_lock(&softc->ha_lock); + if (softc->ha_so != NULL && + (softc->ha_so->so_error || + softc->ha_so->so_rcv.sb_state & SBS_CANTRCVMORE)) + ; + else if (!softc->ha_wakeup) + msleep(&softc->ha_wakeup, &softc->ha_lock, 0, "-", hz); + softc->ha_wakeup = 0; + mtx_unlock(&softc->ha_lock); + } +} + +static int +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; + + error = sysctl_handle_string(oidp, softc->ha_peer, + sizeof(softc->ha_peer), req); + if ((error != 0) || (req->newptr == NULL)) + return (error); + + sa = &softc->ha_peer_in; + mtx_lock(&softc->ha_lock); + if ((num = sscanf(softc->ha_peer, "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", + &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) + error = EINVAL; + } + if (softc->ha_connect || softc->ha_listen) { + memset(sa, 0, sizeof(*sa)); + sa->sin_len = sizeof(struct sockaddr_in); + sa->sin_family = AF_INET; + sa->sin_port = htons((num >= 5) ? p : 999); + sa->sin_addr.s_addr = + htonl((b1 << 24) + (b2 << 16) + (b3 << 8) + b4); + } + softc->ha_disconnect = 1; + softc->ha_wakeup = 1; + mtx_unlock(&softc->ha_lock); + wakeup(&softc->ha_wakeup); + return (error); +} + +ctl_ha_status +ctl_ha_msg_register(ctl_ha_channel channel, ctl_evt_handler handler) +{ + struct ha_softc *softc = &ha_softc; + + KASSERT(channel < CTL_HA_CHAN_MAX, + ("Wrong CTL HA channel %d", channel)); + softc->ha_handler[channel] = handler; + return (CTL_HA_STATUS_SUCCESS); +} + +ctl_ha_status +ctl_ha_msg_deregister(ctl_ha_channel channel) +{ + struct ha_softc *softc = &ha_softc; + + KASSERT(channel < CTL_HA_CHAN_MAX, + ("Wrong CTL HA channel %d", channel)); + softc->ha_handler[channel] = NULL; + return (CTL_HA_STATUS_SUCCESS); +} + +/* + * Receive a message of the specified size. + */ +ctl_ha_status +ctl_ha_msg_recv(ctl_ha_channel channel, void *addr, size_t len, + int wait) +{ + struct ha_softc *softc = &ha_softc; + struct uio uio; + struct iovec iov; + int error, flags; + + if (!softc->ha_connected) + return (CTL_HA_STATUS_DISCONNECT); + + iov.iov_base = addr; + iov.iov_len = len; + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_rw = UIO_READ; + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_td = curthread; + uio.uio_resid = len; + flags = wait ? 0 : MSG_DONTWAIT; + error = soreceive(softc->ha_so, NULL, &uio, NULL, NULL, &flags); + if (error == 0) + return (CTL_HA_STATUS_SUCCESS); + + /* Consider all errors fatal for HA sanity. */ + mtx_lock(&softc->ha_lock); + if (softc->ha_connected) { + softc->ha_disconnect = 1; + softc->ha_wakeup = 1; + wakeup(&softc->ha_wakeup); + } + mtx_unlock(&softc->ha_lock); + return (CTL_HA_STATUS_ERROR); +} + +/* + * Send a message of the specified size. + */ +ctl_ha_status +ctl_ha_msg_send2(ctl_ha_channel channel, const void *addr, size_t len, + const void *addr2, size_t len2, int wait) +{ + struct ha_softc *softc = &ha_softc; + struct mbuf *mb, *newmb; + struct ha_msg_wire hdr; + size_t copylen, off; + + if (!softc->ha_connected) + return (CTL_HA_STATUS_DISCONNECT); + + newmb = m_getm2(NULL, sizeof(hdr) + len + len2, wait, MT_DATA, + M_PKTHDR); + if (newmb == NULL) { + /* Consider all errors fatal for HA sanity. */ + mtx_lock(&softc->ha_lock); + if (softc->ha_connected) { + softc->ha_disconnect = 1; + softc->ha_wakeup = 1; + wakeup(&softc->ha_wakeup); + } + mtx_unlock(&softc->ha_lock); + printf("%s: Can't allocate mbuf chain\n", __func__); + return (CTL_HA_STATUS_ERROR); + } + hdr.channel = channel; + hdr.length = len + len2; + mb = newmb; + memcpy(mtodo(mb, 0), &hdr, sizeof(hdr)); + mb->m_len += sizeof(hdr); + off = 0; + for (; mb != NULL && off < len; mb = mb->m_next) { + copylen = min(M_TRAILINGSPACE(mb), len - off); + memcpy(mtodo(mb, mb->m_len), (const char *)addr + off, copylen); + mb->m_len += copylen; + off += copylen; + if (off == len) + break; + } + KASSERT(off == len, ("%s: off (%zu) != len (%zu)", __func__, + off, len)); + off = 0; + for (; mb != NULL && off < len2; mb = mb->m_next) { + copylen = min(M_TRAILINGSPACE(mb), len2 - off); + memcpy(mtodo(mb, mb->m_len), (const char *)addr2 + off, copylen); + mb->m_len += copylen; + off += copylen; + } + KASSERT(off == len2, ("%s: off (%zu) != len2 (%zu)", __func__, + off, len2)); + newmb->m_pkthdr.len = sizeof(hdr) + len + len2; + + mtx_lock(&softc->ha_lock); + if (!softc->ha_connected) { + mtx_unlock(&softc->ha_lock); + m_freem(newmb); + return (CTL_HA_STATUS_DISCONNECT); + } + mbufq_enqueue(&softc->ha_sendq, newmb); + softc->ha_wakeup = 1; + mtx_unlock(&softc->ha_lock); + wakeup(&softc->ha_wakeup); + return (CTL_HA_STATUS_SUCCESS); +} + +ctl_ha_status +ctl_ha_msg_send(ctl_ha_channel channel, const void *addr, size_t len, + int wait) +{ + + return (ctl_ha_msg_send2(channel, addr, len, NULL, 0, wait)); +} + +/* + * Allocate a data transfer request structure. + */ +struct ctl_ha_dt_req * +ctl_dt_req_alloc(void) +{ + + return (malloc(sizeof(struct ctl_ha_dt_req), M_CTL, M_WAITOK | M_ZERO)); +} + +/* + * Free a data transfer request structure. + */ +void +ctl_dt_req_free(struct ctl_ha_dt_req *req) +{ + + free(req, M_CTL); +} + +/* + * Issue a DMA request for a single buffer. + */ +ctl_ha_status +ctl_dt_single(struct ctl_ha_dt_req *req) +{ + struct ha_softc *softc = &ha_softc; + struct ha_dt_msg_wire wire_dt; + ctl_ha_status status; + + wire_dt.command = req->command; + wire_dt.size = req->size; + wire_dt.local = req->local; + wire_dt.remote = req->remote; + if (req->command == CTL_HA_DT_CMD_READ && req->callback != NULL) { + mtx_lock(&softc->ha_lock); + TAILQ_INSERT_TAIL(&softc->ha_dts, req, links); + mtx_unlock(&softc->ha_lock); + ctl_ha_msg_send(CTL_HA_CHAN_DATA, &wire_dt, sizeof(wire_dt), + M_WAITOK); + return (CTL_HA_STATUS_WAIT); + } + if (req->command == CTL_HA_DT_CMD_READ) { + status = ctl_ha_msg_send(CTL_HA_CHAN_DATA, &wire_dt, + sizeof(wire_dt), M_WAITOK); + } else { + status = ctl_ha_msg_send2(CTL_HA_CHAN_DATA, &wire_dt, + sizeof(wire_dt), req->local, req->size, M_WAITOK); + } + return (status); +} + +static void +ctl_dt_event_handler(ctl_ha_channel channel, ctl_ha_event event, int param) +{ + struct ha_softc *softc = &ha_softc; + struct ctl_ha_dt_req *req; + ctl_ha_status isc_status; + + if (event == CTL_HA_EVT_MSG_RECV) { + struct ha_dt_msg_wire wire_dt; + uint8_t *tmp; + int size; + + size = min(sizeof(wire_dt), param); + isc_status = ctl_ha_msg_recv(CTL_HA_CHAN_DATA, &wire_dt, + size, M_WAITOK); + if (isc_status != CTL_HA_STATUS_SUCCESS) { + printf("%s: Error receiving message: %d\n", + __func__, isc_status); + return; + } + + if (wire_dt.command == CTL_HA_DT_CMD_READ) { + wire_dt.command = CTL_HA_DT_CMD_WRITE; + tmp = wire_dt.local; + wire_dt.local = wire_dt.remote; + wire_dt.remote = tmp; + ctl_ha_msg_send2(CTL_HA_CHAN_DATA, &wire_dt, + sizeof(wire_dt), wire_dt.local, wire_dt.size, + M_WAITOK); + } else if (wire_dt.command == CTL_HA_DT_CMD_WRITE) { + isc_status = ctl_ha_msg_recv(CTL_HA_CHAN_DATA, + wire_dt.remote, wire_dt.size, M_WAITOK); + mtx_lock(&softc->ha_lock); + TAILQ_FOREACH(req, &softc->ha_dts, links) { + if (req->local == wire_dt.remote) { + TAILQ_REMOVE(&softc->ha_dts, req, links); + break; + } + } + mtx_unlock(&softc->ha_lock); + if (req) { + req->ret = isc_status; + req->callback(req); + } + } + } else if (event == CTL_HA_EVT_LINK_CHANGE) { + CTL_DEBUG_PRINT(("%s: Link state change to %d\n", __func__, + param)); + if (param != CTL_HA_LINK_ONLINE) { + mtx_lock(&softc->ha_lock); + while ((req = TAILQ_FIRST(&softc->ha_dts)) != NULL) { + TAILQ_REMOVE(&softc->ha_dts, req, links); + mtx_unlock(&softc->ha_lock); + req->ret = CTL_HA_STATUS_DISCONNECT; + req->callback(req); + mtx_lock(&softc->ha_lock); + } + mtx_unlock(&softc->ha_lock); + } + } else { + printf("%s: Unknown event %d\n", __func__, event); + } +} + + +ctl_ha_status +ctl_ha_msg_init(struct ctl_softc *ctl_softc) +{ + struct ha_softc *softc = &ha_softc; + int error; + + softc->ha_ctl_softc = ctl_softc; + mtx_init(&softc->ha_lock, "CTL HA mutex", NULL, MTX_DEF); + mbufq_init(&softc->ha_sendq, INT_MAX); + TAILQ_INIT(&softc->ha_dts); + error = kproc_kthread_add(ctl_ha_conn_thread, softc, + &ctl_softc->ctl_proc, NULL, 0, 0, "ctl", "ha_tx"); + if (error != 0) { + printf("error creating CTL HA connection thread!\n"); + mtx_destroy(&softc->ha_lock); + return (CTL_HA_STATUS_ERROR); + } + SYSCTL_ADD_PROC(&ctl_softc->sysctl_ctx, + SYSCTL_CHILDREN(ctl_softc->sysctl_tree), + OID_AUTO, "ha_peer", CTLTYPE_STRING | CTLFLAG_RWTUN, + softc, 0, ctl_ha_peer_sysctl, "A", "HA peer connection method"); + + if (ctl_ha_msg_register(CTL_HA_CHAN_DATA, ctl_dt_event_handler) + != CTL_HA_STATUS_SUCCESS) { + printf("%s: ctl_ha_msg_register failed.\n", __func__); + } + + return (CTL_HA_STATUS_SUCCESS); +}; + +ctl_ha_status +ctl_ha_msg_shutdown(struct ctl_softc *ctl_softc) +{ + struct ha_softc *softc = &ha_softc; + + if (ctl_ha_msg_deregister(CTL_HA_CHAN_DATA) != CTL_HA_STATUS_SUCCESS) { + printf("%s: ctl_ha_msg_deregister failed.\n", __func__); + } + + mtx_destroy(&softc->ha_lock); + return (CTL_HA_STATUS_SUCCESS); +}; diff --git a/sys/cam/ctl/ctl_ha.h b/sys/cam/ctl/ctl_ha.h index 0c004b3..072492a 100644 --- a/sys/cam/ctl/ctl_ha.h +++ b/sys/cam/ctl/ctl_ha.h @@ -1,6 +1,7 @@ /*- * Copyright (c) 2003-2009 Silicon Graphics International Corp. * Copyright (c) 2011 Spectra Logic Corporation + * Copyright (c) 2015 Alexander Motin <mav@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,80 +39,27 @@ /* * CTL High Availability Modes: * - * CTL_HA_MODE_ACT_STBY: One side is in Active state and processing commands, - * the other side is in Standby state, returning errors. - * CTL_HA_MODE_SER_ONLY: Commands are serialized to the other side. Write - * mirroring and read re-direction are assumed to - * happen in the back end. - * CTL_HA_MODE_XFER: Commands are serialized and data is transferred - * for write mirroring and read re-direction. + * CTL_HA_MODE_ACT_STBY: Commands are serialized to the master side. + * No media access commands on slave side (Standby). + * CTL_HA_MODE_SER_ONLY: Commands are serialized to the master side. + * Media can be accessed on both sides. + * CTL_HA_MODE_XFER: Commands and data are forwarded to the + * master side for execution. */ - typedef enum { CTL_HA_MODE_ACT_STBY, CTL_HA_MODE_SER_ONLY, CTL_HA_MODE_XFER } ctl_ha_mode; - -/* - * This is a stubbed out High Availability interface. It assumes two nodes - * staying in sync. - * - * The reason this interface is here, and stubbed out, is that CTL was - * originally written with support for Copan's (now SGI) high availability - * framework. That framework was not released by SGI, and would not have - * been generally applicable to FreeBSD anyway. - * - * The idea here is to show the kind of API that would need to be in place - * in a HA framework to work with CTL's HA hooks. This API is very close - * to the Copan/SGI API, so that the code using it could stay in place - * as-is. - * - * So, in summary, this is a shell without real substance, and much more - * work would be needed to actually make HA work. The implementation - * inside CTL will also need to change to fit the eventual implementation. - * The additional pieces we would need are: - * - * - HA "Supervisor" framework that can startup the components of the - * system, and initiate failover (i.e. active/active to single mode) - * and failback (single to active/active mode) state transitions. - * This framework would be able to recognize when an event happens - * that requires it to initiate state transitions in the components it - * manages. - * - * - HA communication framework. This framework should have the following - * features: - * - Separate channels for separate system components. The CTL - * instance on one node should communicate with the CTL instance - * on another node. - * - Short message passing. These messages would be fixed length, so - * they could be preallocated and easily passed between the nodes. - * i.e. conceptually like an ethernet packet. - * - DMA/large buffer capability. This would require some negotiation - * with the other node to define the destination. It could - * allow for "push" (i.e. initiated by the requesting node) DMA or - * "pull" (i.e. initiated by the target controller) DMA or both. - * - Communication channel status change notification. - * - HA capability in other portions of the storage stack. Having two CTL - * instances communicate is just one part of an overall HA solution. - * State needs to be synchronized at multiple levels of the system in - * order for failover to actually work. For instance, if CTL is using a - * file on a ZFS filesystem as its backing store, the ZFS array state - * should be synchronized with the other node, so that the other node - * can immediately take over if the node that is primary for a particular - * array fails. - */ - /* * Communication channel IDs for various system components. This is to * make sure one CTL instance talks with another, one ZFS instance talks * with another, etc. */ typedef enum { - CTL_HA_CHAN_NONE, CTL_HA_CHAN_CTL, - CTL_HA_CHAN_ZFS, + CTL_HA_CHAN_DATA, CTL_HA_CHAN_MAX } ctl_ha_channel; @@ -120,18 +68,12 @@ typedef enum { * HA communication subsystem. * * CTL_HA_EVT_MSG_RECV: Message received by the other node. - * CTL_HA_EVT_MSG_SENT: Message sent to the other node. - * CTL_HA_EVT_DISCONNECT: Communication channel disconnected. - * CTL_HA_EVT_DMA_SENT: DMA successfully sent to other node (push). - * CTL_HA_EVT_DMA_RECEIVED: DMA successfully received by other node (pull). + * CTL_HA_EVT_LINK_CHANGE: Communication channel status changed. */ typedef enum { CTL_HA_EVT_NONE, CTL_HA_EVT_MSG_RECV, - CTL_HA_EVT_MSG_SENT, - CTL_HA_EVT_DISCONNECT, - CTL_HA_EVT_DMA_SENT, - CTL_HA_EVT_DMA_RECEIVED, + CTL_HA_EVT_LINK_CHANGE, CTL_HA_EVT_MAX } ctl_ha_event; @@ -146,12 +88,6 @@ typedef enum { } ctl_ha_status; typedef enum { - CTL_HA_DATA_CTL, - CTL_HA_DATA_ZFS, - CTL_HA_DATA_MAX -} ctl_ha_dtid; - -typedef enum { CTL_HA_DT_CMD_READ, CTL_HA_DT_CMD_WRITE, } ctl_ha_dt_cmd; @@ -164,110 +100,40 @@ struct ctl_ha_dt_req { ctl_ha_dt_cmd command; void *context; ctl_ha_dt_cb callback; - ctl_ha_dtid id; int ret; uint32_t size; uint8_t *local; uint8_t *remote; + TAILQ_ENTRY(ctl_ha_dt_req) links; }; +struct ctl_softc; +ctl_ha_status ctl_ha_msg_init(struct ctl_softc *softc); +ctl_ha_status ctl_ha_msg_shutdown(struct ctl_softc *softc); + typedef void (*ctl_evt_handler)(ctl_ha_channel channel, ctl_ha_event event, int param); void ctl_ha_register_evthandler(ctl_ha_channel channel, ctl_evt_handler handler); -static inline ctl_ha_status -ctl_ha_msg_create(ctl_ha_channel channel, ctl_evt_handler handler) -{ - return (CTL_HA_STATUS_SUCCESS); -} - -/* - * Receive a message of the specified size. - */ -static inline ctl_ha_status -ctl_ha_msg_recv(ctl_ha_channel channel, void *buffer, unsigned int size, - int wait) -{ - return (CTL_HA_STATUS_SUCCESS); -} - -/* - * Send a message of the specified size. - */ -static inline ctl_ha_status -ctl_ha_msg_send(ctl_ha_channel channel, void *buffer, unsigned int size, - int wait) -{ - return (CTL_HA_STATUS_SUCCESS); -} - -/* - * Allocate a data transfer request structure. - */ -static inline struct ctl_ha_dt_req * -ctl_dt_req_alloc(void) -{ - return (NULL); -} - -/* - * Free a data transfer request structure. - */ -static inline void -ctl_dt_req_free(struct ctl_ha_dt_req *req) -{ - return; -} - -/* - * Issue a DMA request for a single buffer. - */ -static inline ctl_ha_status -ctl_dt_single(struct ctl_ha_dt_req *req) -{ - return (CTL_HA_STATUS_WAIT); -} +ctl_ha_status ctl_ha_msg_register(ctl_ha_channel channel, + ctl_evt_handler handler); +ctl_ha_status ctl_ha_msg_recv(ctl_ha_channel channel, void *addr, + size_t len, int wait); +ctl_ha_status ctl_ha_msg_send(ctl_ha_channel channel, const void *addr, + size_t len, int wait); +ctl_ha_status ctl_ha_msg_send2(ctl_ha_channel channel, const void *addr, + size_t len, const void *addr2, size_t len2, int wait); +ctl_ha_status ctl_ha_msg_deregister(ctl_ha_channel channel); -/* - * SINGLE: One node - * HA: Two nodes (Active/Active implied) - * SLAVE/MASTER: The component can set these flags to indicate which side - * is in control. It has no effect on the HA framework. - */ -typedef enum { - CTL_HA_STATE_UNKNOWN = 0x00, - CTL_HA_STATE_SINGLE = 0x01, - CTL_HA_STATE_HA = 0x02, - CTL_HA_STATE_MASK = 0x0F, - CTL_HA_STATE_SLAVE = 0x10, - CTL_HA_STATE_MASTER = 0x20 -} ctl_ha_state; +struct ctl_ha_dt_req * ctl_dt_req_alloc(void); +void ctl_dt_req_free(struct ctl_ha_dt_req *req); +ctl_ha_status ctl_dt_single(struct ctl_ha_dt_req *req); typedef enum { - CTL_HA_COMP_STATUS_OK, - CTL_HA_COMP_STATUS_FAILED, - CTL_HA_COMP_STATUS_ERROR -} ctl_ha_comp_status; - -struct ctl_ha_component; - -typedef ctl_ha_comp_status (*ctl_hacmp_init_t)(struct ctl_ha_component *); -typedef ctl_ha_comp_status (*ctl_hacmp_start_t)(struct ctl_ha_component *, - ctl_ha_state); - -struct ctl_ha_component { - char *name; - ctl_ha_state state; - ctl_ha_comp_status status; - ctl_hacmp_init_t init; - ctl_hacmp_start_t start; - ctl_hacmp_init_t quiesce; -}; - -#define CTL_HA_STATE_IS_SINGLE(state) ((state & CTL_HA_STATE_MASK) == \ - CTL_HA_STATE_SINGLE) -#define CTL_HA_STATE_IS_HA(state) ((state & CTL_HA_STATE_MASK) == \ - CTL_HA_STATE_HA) + CTL_HA_LINK_OFFLINE = 0x00, + CTL_HA_LINK_UNKNOWN = 0x01, + CTL_HA_LINK_ONLINE = 0x02 +} ctl_ha_link_state; #endif /* _CTL_HA_H_ */ diff --git a/sys/cam/ctl/ctl_io.h b/sys/cam/ctl/ctl_io.h index fc4ddfb..e85d0a5 100644 --- a/sys/cam/ctl/ctl_io.h +++ b/sys/cam/ctl/ctl_io.h @@ -58,13 +58,12 @@ EXTERN(int ctl_time_io_secs, CTL_TIME_IO_DEFAULT_SECS); #endif /* - * Uncomment these next two lines to enable the CTL I/O delay feature. You + * Uncomment this next line to enable the CTL I/O delay feature. You * can delay I/O at two different points -- datamove and done. This is * useful for diagnosing abort conditions (for hosts that send an abort on a * timeout), and for determining how long a host's timeout is. */ -#define CTL_IO_DELAY -#define CTL_TIMER_BYTES sizeof(struct callout) +//#define CTL_IO_DELAY typedef enum { CTL_STATUS_NONE, /* No status */ @@ -93,13 +92,11 @@ typedef enum { CTL_FLAG_EDPTR_SGLIST = 0x00000010, /* ext_data_ptr is S/G list */ CTL_FLAG_DO_AUTOSENSE = 0x00000020, /* grab sense info */ CTL_FLAG_USER_REQ = 0x00000040, /* request came from userland */ - CTL_FLAG_CONTROL_DEV = 0x00000080, /* processor device */ CTL_FLAG_ALLOCATED = 0x00000100, /* data space allocated */ CTL_FLAG_BLOCKED = 0x00000200, /* on the blocked queue */ CTL_FLAG_ABORT_STATUS = 0x00000400, /* return TASK ABORTED status */ CTL_FLAG_ABORT = 0x00000800, /* this I/O should be aborted */ CTL_FLAG_DMA_INPROG = 0x00001000, /* DMA in progress */ - CTL_FLAG_NO_DATASYNC = 0x00002000, /* don't cache flush data */ CTL_FLAG_DELAY_DONE = 0x00004000, /* delay injection done */ CTL_FLAG_INT_COPY = 0x00008000, /* internal copy, no done call*/ CTL_FLAG_SENT_2OTHER_SC = 0x00010000, @@ -109,9 +106,6 @@ typedef enum { addresses, not virtual ones*/ CTL_FLAG_IO_CONT = 0x00100000, /* Continue I/O instead of completing */ - CTL_FLAG_AUTO_MIRROR = 0x00200000, /* Automatically use memory - from the RC cache mirrored - address area. */ #if 0 CTL_FLAG_ALREADY_DONE = 0x00200000 /* I/O already completed */ #endif @@ -119,14 +113,8 @@ typedef enum { CTL_FLAG_DMA_QUEUED = 0x00800000, /* DMA queued but not started*/ CTL_FLAG_STATUS_QUEUED = 0x01000000, /* Status queued but not sent*/ - CTL_FLAG_REDIR_DONE = 0x02000000, /* Redirection has already - been done. */ CTL_FLAG_FAILOVER = 0x04000000, /* Killed by a failover */ CTL_FLAG_IO_ACTIVE = 0x08000000, /* I/O active on this SC */ - CTL_FLAG_RDMA_MASK = CTL_FLAG_NO_DATASYNC | CTL_FLAG_BUS_ADDR | - CTL_FLAG_AUTO_MIRROR | CTL_FLAG_REDIR_DONE, - /* Flags we care about for - remote DMA */ CTL_FLAG_STATUS_SENT = 0x10000000 /* Status sent by datamove */ } ctl_io_flags; @@ -184,11 +172,6 @@ struct ctl_sg_entry { size_t len; }; -struct ctl_id { - uint32_t id; - uint64_t wwid[2]; -}; - typedef enum { CTL_IO_NONE, CTL_IO_SCSI, @@ -196,9 +179,8 @@ typedef enum { } ctl_io_type; struct ctl_nexus { - struct ctl_id initid; /* Initiator ID */ + uint32_t initid; /* Initiator ID */ uint32_t targ_port; /* Target port, filled in by PORT */ - struct ctl_id targ_target; /* Destination target */ uint32_t targ_lun; /* Destination lun */ uint32_t targ_mapped_lun; /* Destination lun CTL-wide */ }; @@ -210,15 +192,16 @@ typedef enum { CTL_MSG_BAD_JUJU, CTL_MSG_MANAGE_TASKS, CTL_MSG_PERS_ACTION, - CTL_MSG_SYNC_FE, CTL_MSG_DATAMOVE, - CTL_MSG_DATAMOVE_DONE + CTL_MSG_DATAMOVE_DONE, + CTL_MSG_UA, /* Set/clear UA on secondary. */ + CTL_MSG_PORT_SYNC, /* Information about port. */ + CTL_MSG_LUN_SYNC, /* Information about LUN. */ + CTL_MSG_FAILOVER /* Fake, never sent though the wire */ } ctl_msg_type; struct ctl_scsiio; -#define CTL_NUM_SG_ENTRIES 9 - struct ctl_io_hdr { uint32_t version; /* interface version XXX */ ctl_io_type io_type; /* task I/O, SCSI I/O, etc. */ @@ -231,7 +214,7 @@ struct ctl_io_hdr { uint32_t timeout; /* timeout in ms */ uint32_t retries; /* retry count */ #ifdef CTL_IO_DELAY - uint8_t timer_bytes[CTL_TIMER_BYTES]; /* timer kludge */ + struct callout delay_callout; #endif /* CTL_IO_DELAY */ #ifdef CTL_TIME_IO time_t start_time; /* I/O start time */ @@ -244,10 +227,8 @@ struct ctl_io_hdr { union ctl_io *serializing_sc; void *pool; /* I/O pool */ union ctl_priv ctl_private[CTL_NUM_PRIV];/* CTL private area */ - struct ctl_sg_entry remote_sglist[CTL_NUM_SG_ENTRIES]; - struct ctl_sg_entry remote_dma_sglist[CTL_NUM_SG_ENTRIES]; - struct ctl_sg_entry local_sglist[CTL_NUM_SG_ENTRIES]; - struct ctl_sg_entry local_dma_sglist[CTL_NUM_SG_ENTRIES]; + struct ctl_sg_entry *remote_sglist; + struct ctl_sg_entry *local_sglist; STAILQ_ENTRY(ctl_io_hdr) links; /* linked list pointer */ TAILQ_ENTRY(ctl_io_hdr) ooa_links; TAILQ_ENTRY(ctl_io_hdr) blocked_links; @@ -393,10 +374,10 @@ struct ctl_ha_msg_hdr { union ctl_io *serializing_sc; struct ctl_nexus nexus; /* Initiator, port, target, lun */ uint32_t status; /* transaction status */ - TAILQ_ENTRY(ctl_ha_msg_hdr) links; }; #define CTL_HA_MAX_SG_ENTRIES 16 +#define CTL_HA_DATAMOVE_SEGMENT 131072 /* * Used for CTL_MSG_PERS_ACTION. @@ -407,6 +388,16 @@ struct ctl_ha_msg_pr { }; /* + * Used for CTL_MSG_UA. + */ +struct ctl_ha_msg_ua { + struct ctl_ha_msg_hdr hdr; + int ua_all; + int ua_set; + int ua_type; +}; + +/* * The S/G handling here is a little different than the standard ctl_scsiio * structure, because we can't pass data by reference in between controllers. * The S/G list in the ctl_scsiio struct is normally passed in the @@ -438,17 +429,18 @@ struct ctl_ha_msg_dt { */ struct ctl_ha_msg_scsi { struct ctl_ha_msg_hdr hdr; - uint8_t cdb[CTL_MAX_CDBLEN]; /* CDB */ uint32_t tag_num; /* tag number */ ctl_tag_type tag_type; /* simple, ordered, etc. */ + uint8_t cdb[CTL_MAX_CDBLEN]; /* CDB */ + uint8_t cdb_len; /* CDB length */ uint8_t scsi_status; /* SCSI status byte */ - struct scsi_sense_data sense_data; /* sense data */ uint8_t sense_len; /* Returned sense length */ uint8_t sense_residual; /* sense residual length */ 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 */ }; /* @@ -461,12 +453,50 @@ struct ctl_ha_msg_task { ctl_tag_type tag_type; /* simple, ordered, etc. */ }; +/* + * Used for CTL_MSG_PORT_SYNC. + */ +struct ctl_ha_msg_port { + struct ctl_ha_msg_hdr hdr; + int port_type; + int physical_port; + int virtual_port; + int status; + int name_len; + int lun_map_len; + int port_devid_len; + int target_devid_len; + uint8_t data[]; +}; + +/* + * Used for CTL_MSG_LUN_SYNC. + */ +struct ctl_ha_msg_lun { + struct ctl_ha_msg_hdr hdr; + int flags; + unsigned int pr_generation; + uint32_t pr_res_idx; + uint8_t pr_res_type; + int lun_devid_len; + int pr_key_count; + uint8_t data[]; +}; + +struct ctl_ha_msg_lun_pr_key { + uint32_t pr_iid; + uint64_t pr_key; +}; + union ctl_ha_msg { struct ctl_ha_msg_hdr hdr; struct ctl_ha_msg_task task; struct ctl_ha_msg_scsi scsi; struct ctl_ha_msg_dt dt; struct ctl_ha_msg_pr pr; + struct ctl_ha_msg_ua ua; + struct ctl_ha_msg_port port; + struct ctl_ha_msg_lun lun; }; diff --git a/sys/cam/ctl/ctl_ioctl.h b/sys/cam/ctl/ctl_ioctl.h index f62bbe1..a691a1d 100644 --- a/sys/cam/ctl/ctl_ioctl.h +++ b/sys/cam/ctl/ctl_ioctl.h @@ -86,7 +86,6 @@ typedef enum { } ctl_ooa_status; struct ctl_ooa_info { - uint32_t target_id; /* Passed in to CTL */ uint32_t lun_id; /* Passed in to CTL */ uint32_t num_entries; /* Returned from CTL */ ctl_ooa_status status; /* Returned from CTL */ @@ -114,7 +113,6 @@ typedef enum { } ctl_delay_status; struct ctl_io_delay_info { - uint32_t target_id; uint32_t lun_id; ctl_delay_type delay_type; ctl_delay_location delay_loc; @@ -133,7 +131,6 @@ typedef enum { * means that we will let through every N SYNCHRONIZE CACHE commands. */ struct ctl_sync_info { - uint32_t target_id; /* passed to kernel */ uint32_t lun_id; /* passed to kernel */ int sync_interval; /* depends on whether get/set */ ctl_gs_sync_status status; /* passed from kernel */ @@ -262,7 +259,6 @@ struct ctl_error_desc_cmd { /* * Error injection descriptor. * - * target_id: Target ID to act on. * lun_id LUN to act on. * lun_error: The type of error to inject. See above for descriptions. * error_pattern: What kind of command to act on. See above. @@ -273,7 +269,6 @@ struct ctl_error_desc_cmd { * links: Kernel use only. */ struct ctl_error_desc { - uint32_t target_id; /* To kernel */ uint32_t lun_id; /* To kernel */ ctl_lun_error lun_error; /* To kernel */ ctl_lun_error_pattern error_pattern; /* To kernel */ diff --git a/sys/cam/ctl/ctl_private.h b/sys/cam/ctl/ctl_private.h index a0bbc36..c42c2c9 100644 --- a/sys/cam/ctl/ctl_private.h +++ b/sys/cam/ctl/ctl_private.h @@ -106,8 +106,8 @@ typedef enum { CTL_CMD_FLAG_OK_ON_BOTH = 0x0300, CTL_CMD_FLAG_OK_ON_STOPPED = 0x0400, CTL_CMD_FLAG_OK_ON_INOPERABLE = 0x0800, - CTL_CMD_FLAG_OK_ON_OFFLINE = 0x1000, - CTL_CMD_FLAG_OK_ON_SECONDARY = 0x2000, + CTL_CMD_FLAG_OK_ON_STANDBY = 0x1000, + CTL_CMD_FLAG_OK_ON_UNAVAIL = 0x2000, CTL_CMD_FLAG_ALLOW_ON_PR_RESV = 0x4000, CTL_CMD_FLAG_SA5 = 0x8000 } ctl_cmd_flags; @@ -157,7 +157,8 @@ typedef enum { CTL_LUN_PR_RESERVED = 0x100, CTL_LUN_PRIMARY_SC = 0x200, CTL_LUN_SENSE_DESC = 0x400, - CTL_LUN_READONLY = 0x800 + CTL_LUN_READONLY = 0x800, + CTL_LUN_PEER_SC_PRIMARY = 0x1000 } ctl_lun_flags; typedef enum { @@ -398,7 +399,7 @@ struct ctl_lun { struct ctl_lun_io_stats stats; uint32_t res_idx; unsigned int PRGeneration; - uint64_t *pr_keys[2 * CTL_MAX_PORTS]; + uint64_t *pr_keys[CTL_MAX_PORTS]; int pr_key_count; uint32_t pr_res_idx; uint8_t res_type; @@ -434,11 +435,13 @@ struct ctl_softc { ctl_gen_flags flags; ctl_ha_mode ha_mode; int ha_id; - int ha_state; int is_single; - int port_offset; - int persis_offset; - int inquiry_pq_no_lun; + ctl_ha_link_state ha_link; + int port_min; + int port_max; + int port_cnt; + int init_min; + int init_max; struct sysctl_ctx_list sysctl_ctx; struct sysctl_oid *sysctl_tree; void *othersc_pool; @@ -469,8 +472,6 @@ struct ctl_softc { extern const struct ctl_cmd_entry ctl_cmd_table[256]; uint32_t ctl_get_initindex(struct ctl_nexus *nexus); -uint32_t ctl_get_resindex(struct ctl_nexus *nexus); -uint32_t ctl_port_idx(int port_num); int ctl_lun_map_init(struct ctl_port *port); int ctl_lun_map_deinit(struct ctl_port *port); int ctl_lun_map_set(struct ctl_port *port, uint32_t plun, uint32_t glun); @@ -508,7 +509,6 @@ int ctl_report_tagret_port_groups(struct ctl_scsiio *ctsio); int ctl_report_supported_opcodes(struct ctl_scsiio *ctsio); int ctl_report_supported_tmf(struct ctl_scsiio *ctsio); int ctl_report_timestamp(struct ctl_scsiio *ctsio); -int ctl_isc(struct ctl_scsiio *ctsio); int ctl_get_lba_status(struct ctl_scsiio *ctsio); void ctl_tpc_init(struct ctl_softc *softc); diff --git a/sys/cam/ctl/ctl_scsi_all.c b/sys/cam/ctl/ctl_scsi_all.c index 815e383..acac6ea 100644 --- a/sys/cam/ctl/ctl_scsi_all.c +++ b/sys/cam/ctl/ctl_scsi_all.c @@ -114,7 +114,7 @@ ctl_scsi_path_string(union ctl_io *io, char *path_str, int len) { snprintf(path_str, len, "(%u:%u:%u/%u): ", - io->io_hdr.nexus.initid.id, io->io_hdr.nexus.targ_port, + io->io_hdr.nexus.initid, io->io_hdr.nexus.targ_port, io->io_hdr.nexus.targ_lun, io->io_hdr.nexus.targ_mapped_lun); } diff --git a/sys/cam/ctl/ctl_tpc.c b/sys/cam/ctl/ctl_tpc.c index b1b674f..e4722fe 100644 --- a/sys/cam/ctl/ctl_tpc.c +++ b/sys/cam/ctl/ctl_tpc.c @@ -534,7 +534,7 @@ ctl_receive_copy_status_lid1(struct ctl_scsiio *ctsio) list_id = cdb->list_identifier; mtx_lock(&lun->lun_lock); list = tpc_find_list(lun, list_id, - ctl_get_resindex(&ctsio->io_hdr.nexus)); + ctl_get_initindex(&ctsio->io_hdr.nexus)); if (list == NULL) { mtx_unlock(&lun->lun_lock); ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, @@ -616,7 +616,7 @@ ctl_receive_copy_failure_details(struct ctl_scsiio *ctsio) list_id = cdb->list_identifier; mtx_lock(&lun->lun_lock); list = tpc_find_list(lun, list_id, - ctl_get_resindex(&ctsio->io_hdr.nexus)); + ctl_get_initindex(&ctsio->io_hdr.nexus)); if (list == NULL || !list->completed) { mtx_unlock(&lun->lun_lock); ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, @@ -688,7 +688,7 @@ ctl_receive_copy_status_lid4(struct ctl_scsiio *ctsio) list_id = scsi_4btoul(cdb->list_identifier); mtx_lock(&lun->lun_lock); list = tpc_find_list(lun, list_id, - ctl_get_resindex(&ctsio->io_hdr.nexus)); + ctl_get_initindex(&ctsio->io_hdr.nexus)); if (list == NULL) { mtx_unlock(&lun->lun_lock); ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, @@ -771,7 +771,7 @@ ctl_copy_operation_abort(struct ctl_scsiio *ctsio) list_id = scsi_4btoul(cdb->list_identifier); mtx_lock(&lun->lun_lock); list = tpc_find_list(lun, list_id, - ctl_get_resindex(&ctsio->io_hdr.nexus)); + ctl_get_initindex(&ctsio->io_hdr.nexus)); if (list == NULL) { mtx_unlock(&lun->lun_lock); ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, @@ -1645,7 +1645,7 @@ ctl_extended_copy_lid1(struct ctl_scsiio *ctsio) list->init_port = -1; else list->init_port = ctsio->io_hdr.nexus.targ_port; - list->init_idx = ctl_get_resindex(&ctsio->io_hdr.nexus); + list->init_idx = ctl_get_initindex(&ctsio->io_hdr.nexus); list->list_id = data->list_identifier; list->flags = data->flags; list->params = ctsio->kern_data_ptr; @@ -1772,7 +1772,7 @@ ctl_extended_copy_lid4(struct ctl_scsiio *ctsio) list->init_port = -1; else list->init_port = ctsio->io_hdr.nexus.targ_port; - list->init_idx = ctl_get_resindex(&ctsio->io_hdr.nexus); + list->init_idx = ctl_get_initindex(&ctsio->io_hdr.nexus); list->list_id = scsi_4btoul(data->list_identifier); list->flags = data->flags; list->params = ctsio->kern_data_ptr; @@ -1890,7 +1890,7 @@ ctl_populate_token(struct ctl_scsiio *ctsio) lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr; softc = lun->ctl_softc; - port = softc->ctl_ports[ctl_port_idx(ctsio->io_hdr.nexus.targ_port)]; + port = softc->ctl_ports[ctsio->io_hdr.nexus.targ_port]; cdb = (struct scsi_populate_token *)ctsio->cdb; len = scsi_4btoul(cdb->length); @@ -1944,7 +1944,7 @@ ctl_populate_token(struct ctl_scsiio *ctsio) list = malloc(sizeof(struct tpc_list), M_CTL, M_WAITOK | M_ZERO); list->service_action = cdb->service_action; list->init_port = ctsio->io_hdr.nexus.targ_port; - list->init_idx = ctl_get_resindex(&ctsio->io_hdr.nexus); + list->init_idx = ctl_get_initindex(&ctsio->io_hdr.nexus); list->list_id = scsi_4btoul(cdb->list_identifier); list->flags = data->flags; list->ctsio = ctsio; @@ -2070,7 +2070,7 @@ ctl_write_using_token(struct ctl_scsiio *ctsio) list = malloc(sizeof(struct tpc_list), M_CTL, M_WAITOK | M_ZERO); list->service_action = cdb->service_action; list->init_port = ctsio->io_hdr.nexus.targ_port; - list->init_idx = ctl_get_resindex(&ctsio->io_hdr.nexus); + list->init_idx = ctl_get_initindex(&ctsio->io_hdr.nexus); list->list_id = scsi_4btoul(cdb->list_identifier); list->flags = data->flags; list->params = ctsio->kern_data_ptr; @@ -2162,7 +2162,7 @@ ctl_receive_rod_token_information(struct ctl_scsiio *ctsio) list_id = scsi_4btoul(cdb->list_identifier); mtx_lock(&lun->lun_lock); list = tpc_find_list(lun, list_id, - ctl_get_resindex(&ctsio->io_hdr.nexus)); + ctl_get_initindex(&ctsio->io_hdr.nexus)); if (list == NULL) { mtx_unlock(&lun->lun_lock); ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, diff --git a/sys/cam/ctl/ctl_tpc_local.c b/sys/cam/ctl/ctl_tpc_local.c index 7e66340..7664cb9 100644 --- a/sys/cam/ctl/ctl_tpc_local.c +++ b/sys/cam/ctl/ctl_tpc_local.c @@ -97,11 +97,11 @@ tpcl_init(void) port->fe_done = tpcl_done; port->max_targets = 1; port->max_target_id = 0; + port->targ_port = -1; port->max_initiators = 1; - if (ctl_port_register(port) != 0) - { - printf("%s: tpc frontend registration failed\n", __func__); + if (ctl_port_register(port) != 0) { + printf("%s: ctl_port_register() failed with error\n", __func__); return (0); } @@ -287,7 +287,7 @@ tpcl_resolve(struct ctl_softc *softc, int init_port, cscdid = (struct scsi_ec_cscd_id *)cscd; mtx_lock(&softc->ctl_lock); if (init_port >= 0) - port = softc->ctl_ports[ctl_port_idx(init_port)]; + port = softc->ctl_ports[init_port]; else port = NULL; STAILQ_FOREACH(lun, &softc->lun_list, links) { @@ -328,9 +328,8 @@ tpcl_queue(union ctl_io *io, uint64_t lun) { struct tpcl_softc *tsoftc = &tpcl_softc; - io->io_hdr.nexus.initid.id = 0; + io->io_hdr.nexus.initid = 0; io->io_hdr.nexus.targ_port = tsoftc->port.targ_port; - io->io_hdr.nexus.targ_target.id = 0; io->io_hdr.nexus.targ_lun = lun; io->scsiio.tag_num = atomic_fetchadd_int(&tsoftc->cur_tag_num, 1); io->scsiio.ext_data_filled = 0; diff --git a/sys/cam/ctl/ctl_util.c b/sys/cam/ctl/ctl_util.c index a991cfb..8c57a22 100644 --- a/sys/cam/ctl/ctl_util.c +++ b/sys/cam/ctl/ctl_util.c @@ -679,7 +679,7 @@ ctl_scsi_maintenance_in(union ctl_io *io, uint8_t *data_ptr, uint32_t data_len, #ifndef _KERNEL union ctl_io * -ctl_scsi_alloc_io(struct ctl_id initid) +ctl_scsi_alloc_io(uint32_t initid) { union ctl_io *io; diff --git a/sys/cam/ctl/ctl_util.h b/sys/cam/ctl/ctl_util.h index af5e55f..b1c0d84 100644 --- a/sys/cam/ctl/ctl_util.h +++ b/sys/cam/ctl/ctl_util.h @@ -94,7 +94,7 @@ void ctl_scsi_maintenance_in(union ctl_io *io, uint8_t *data_ptr, uint32_t data_len, uint8_t action, ctl_tag_type tag_type, uint8_t control); #ifndef _KERNEL -union ctl_io *ctl_scsi_alloc_io(struct ctl_id initid); +union ctl_io *ctl_scsi_alloc_io(uint32_t initid); void ctl_scsi_free_io(union ctl_io *io); #endif /* !_KERNEL */ void ctl_scsi_zero_io(union ctl_io *io); diff --git a/sys/cam/ctl/scsi_ctl.c b/sys/cam/ctl/scsi_ctl.c index 15912e2..655afd8 100644 --- a/sys/cam/ctl/scsi_ctl.c +++ b/sys/cam/ctl/scsi_ctl.c @@ -400,6 +400,7 @@ ctlfeasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) */ port->max_targets = cpi->max_target; port->max_target_id = cpi->max_target; + port->targ_port = -1; /* * XXX KDM need to figure out whether we're the master or @@ -1164,9 +1165,8 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb) * down the immediate notify path below. */ io->io_hdr.io_type = CTL_IO_SCSI; - io->io_hdr.nexus.initid.id = atio->init_id; + io->io_hdr.nexus.initid = atio->init_id; io->io_hdr.nexus.targ_port = bus_softc->port.targ_port; - io->io_hdr.nexus.targ_target.id = atio->ccb_h.target_id; io->io_hdr.nexus.targ_lun = atio->ccb_h.target_lun; io->scsiio.tag_num = atio->tag_id; switch (atio->tag_action) { @@ -1200,10 +1200,9 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb) io->scsiio.cdb_len); #ifdef CTLFEDEBUG - printf("%s: %ju:%d:%ju:%d: tag %04x CDB %02x\n", __func__, - (uintmax_t)io->io_hdr.nexus.initid.id, + printf("%s: %u:%u:%u: tag %04x CDB %02x\n", __func__, + io->io_hdr.nexus.initid, io->io_hdr.nexus.targ_port, - (uintmax_t)io->io_hdr.nexus.targ_target.id, io->io_hdr.nexus.targ_lun, io->scsiio.tag_num, io->scsiio.cdb[0]); #endif @@ -1440,9 +1439,8 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb) io->io_hdr.io_type = CTL_IO_TASK; io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr =done_ccb; inot->ccb_h.io_ptr = io; - io->io_hdr.nexus.initid.id = inot->initiator_id; + io->io_hdr.nexus.initid = inot->initiator_id; io->io_hdr.nexus.targ_port = bus_softc->port.targ_port; - io->io_hdr.nexus.targ_target.id = inot->ccb_h.target_id; io->io_hdr.nexus.targ_lun = inot->ccb_h.target_lun; /* XXX KDM should this be the tag_id? */ io->taskio.tag_num = inot->seq_id; diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c index a3a0bba..cf2f7bb 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c +++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c @@ -23,7 +23,7 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright (c) 2015, Joyent, Inc. All rights reserved. * Copyright (c) 2012, 2014 by Delphix. All rights reserved. */ @@ -2146,7 +2146,7 @@ retry: * this hash chain, or another CPU is deleting an element from this * hash chain. The simplest way to deal with both of these cases * (though not necessarily the most efficient) is to free our - * allocated block and tail-call ourselves. Note that the free is + * allocated block and re-attempt it all. Note that the free is * to the dirty list and _not_ to the free list. This is to prevent * races with allocators, above. */ @@ -2159,7 +2159,7 @@ retry: dvar->dtdv_next = free; } while (dtrace_casptr(&dcpu->dtdsc_dirty, free, dvar) != free); - return (dtrace_dynvar(dstate, nkeys, key, dsize, op, mstate, vstate)); + goto top; } /*ARGSUSED*/ diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c index b44de1d..df48567 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c +++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c @@ -29,7 +29,7 @@ */ /* - * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright (c) 2015, Joyent, Inc. All rights reserved. */ #include <sys/atomic.h> @@ -1190,11 +1190,21 @@ fasttrap_pid_enable(void *arg, dtrace_id_t id, void *parg) mutex_enter(&pidlock); p = prfind(probe->ftp_pid); + if (p == NULL) { + /* + * So it's not that the target process is being born, + * it's that it isn't there at all (and we simply + * happen to be forking). Anyway, we know that the + * target is definitely gone, so bail out. + */ + mutex_exit(&pidlock); + return (0); + } + /* * Confirm that curproc is indeed forking the process in which * we're trying to enable probes. */ - ASSERT(p != NULL); ASSERT(p->p_parent == curproc); ASSERT(p->p_stat == SIDL); diff --git a/sys/cddl/dev/dtrace/amd64/dtrace_isa.c b/sys/cddl/dev/dtrace/amd64/dtrace_isa.c index 07a1b0a..e05932d 100644 --- a/sys/cddl/dev/dtrace/amd64/dtrace_isa.c +++ b/sys/cddl/dev/dtrace/amd64/dtrace_isa.c @@ -440,7 +440,7 @@ dtrace_getarg(int arg, int aframes) } arg -= (inreg + 1); - stack = (uintptr_t *)fp + 2; + stack = (uintptr_t *)&fp[1]; load: DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); diff --git a/sys/conf/files b/sys/conf/files index 280f6a6..df8233f 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -85,6 +85,7 @@ cam/ctl/ctl_frontend.c optional ctl cam/ctl/ctl_frontend_cam_sim.c optional ctl cam/ctl/ctl_frontend_ioctl.c optional ctl cam/ctl/ctl_frontend_iscsi.c optional ctl +cam/ctl/ctl_ha.c optional ctl cam/ctl/ctl_scsi_all.c optional ctl cam/ctl/ctl_tpc.c optional ctl cam/ctl/ctl_tpc_local.c optional ctl diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index bd70825..3def78f 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -130,7 +130,6 @@ amd64/amd64/pmap.c standard amd64/amd64/prof_machdep.c optional profiling-routine amd64/amd64/ptrace_machdep.c standard amd64/amd64/sigtramp.S standard -amd64/amd64/stack_machdep.c optional ddb | stack amd64/amd64/support.S standard amd64/amd64/sys_machdep.c standard amd64/amd64/trap.c standard @@ -612,6 +611,7 @@ x86/x86/mp_x86.c optional smp x86/x86/msi.c optional pci x86/x86/nexus.c standard x86/x86/pvclock.c standard +x86/x86/stack_machdep.c optional ddb | stack x86/x86/tsc.c standard x86/x86/delay.c standard x86/xen/hvm.c optional xenhvm diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index aed5b9d..1fae3a5 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -476,7 +476,6 @@ i386/i386/mpboot.s optional smp i386/i386/perfmon.c optional perfmon i386/i386/pmap.c standard i386/i386/ptrace_machdep.c standard -i386/i386/stack_machdep.c optional ddb | stack i386/i386/support.s standard i386/i386/swtch.s standard i386/i386/sys_machdep.c standard @@ -603,6 +602,7 @@ x86/x86/mptable_pci.c optional apic pci x86/x86/mp_x86.c optional smp x86/x86/msi.c optional apic pci x86/x86/nexus.c standard +x86/x86/stack_machdep.c optional ddb | stack x86/x86/tsc.c standard x86/x86/pvclock.c standard x86/x86/delay.c standard diff --git a/sys/conf/files.pc98 b/sys/conf/files.pc98 index 28a94a8..ee6cf71 100644 --- a/sys/conf/files.pc98 +++ b/sys/conf/files.pc98 @@ -174,7 +174,6 @@ i386/i386/mpboot.s optional smp i386/i386/perfmon.c optional perfmon i386/i386/pmap.c standard i386/i386/ptrace_machdep.c standard -i386/i386/stack_machdep.c optional ddb | stack i386/i386/support.s standard i386/i386/swtch.s standard i386/i386/sys_machdep.c standard @@ -274,5 +273,6 @@ x86/x86/mptable.c optional apic x86/x86/mptable_pci.c optional apic pci x86/x86/msi.c optional apic pci x86/x86/nexus.c standard +x86/x86/stack_machdep.c optional ddb | stack x86/x86/tsc.c standard x86/x86/delay.c standard diff --git a/sys/conf/options b/sys/conf/options index 936abc9..ccbbd80 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -947,11 +947,11 @@ RCTL opt_global.h # Random number generator(s) # Which CSPRNG hash we get. # If Yarrow is not chosen, Fortuna is selected. -RANDOM_YARROW opt_random.h +RANDOM_YARROW opt_global.h # With this, no entropy processor is loaded, but the entropy # harvesting infrastructure is present. This means an entropy # processor may be loaded as a module. -RANDOM_LOADABLE opt_random.h +RANDOM_LOADABLE opt_global.h # This turns on high-rate and potentially expensive harvesting in # the uma slab allocator. RANDOM_ENABLE_UMA opt_global.h diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c index 9c6a244..a3930ea 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.c +++ b/sys/contrib/ipfilter/netinet/ip_state.c @@ -1,4 +1,4 @@ -/* $FreeBSD$ */ +/* $FreeBSD$ */ /* * Copyright (C) 2012 by Darren Reed. @@ -1054,7 +1054,7 @@ ipf_state_putent(softc, softs, data) /* to pointers and adjusts running stats for the hash table as appropriate. */ /* */ /* This function can fail if the filter rule has had a population policy of */ -/* IP addresses used with stateful filteirng assigned to it. */ +/* IP addresses used with stateful filtering assigned to it. */ /* */ /* Locking: it is assumed that some kind of lock on ipf_state is held. */ /* Exits with is_lock initialised and held - *EVEN IF ERROR*. */ @@ -1081,7 +1081,7 @@ ipf_state_insert(softc, is, rev) } /* - * If we could trust is_hv, then the modulous would not be needed, + * If we could trust is_hv, then the modulus would not be needed, * but when running with IPFILTER_SYNC, this stops bad values. */ hv = is->is_hv % softs->ipf_state_size; @@ -1672,6 +1672,10 @@ ipf_state_add(softc, fin, stsave, flags) SBUMPD(ipf_state_stats, iss_bucket_full); return 4; } + + /* + * No existing state; create new + */ KMALLOC(is, ipstate_t *); if (is == NULL) { SBUMPD(ipf_state_stats, iss_nomem); @@ -1683,7 +1687,7 @@ ipf_state_add(softc, fin, stsave, flags) is->is_rule = fr; /* - * Do not do the modulous here, it is done in ipf_state_insert(). + * Do not do the modulus here, it is done in ipf_state_insert(). */ if (fr != NULL) { ipftq_t *tq; @@ -1711,7 +1715,7 @@ ipf_state_add(softc, fin, stsave, flags) /* * It may seem strange to set is_ref to 2, but if stsave is not NULL * then a copy of the pointer is being stored somewhere else and in - * the end, it will expect to be able to do osmething with it. + * the end, it will expect to be able to do something with it. */ is->is_me = stsave; if (stsave != NULL) { @@ -3642,7 +3646,8 @@ ipf_state_del(softc, is, why) is->is_me = NULL; is->is_ref--; } - if (is->is_ref > 1) { + is->is_ref--; + if (is->is_ref > 0) { int refs; is->is_ref--; @@ -3652,7 +3657,6 @@ ipf_state_del(softc, is, why) softs->ipf_state_stats.iss_orphan++; return refs; } - MUTEX_EXIT(&is->is_lock); fr = is->is_rule; is->is_rule = NULL; @@ -3664,6 +3668,7 @@ ipf_state_del(softc, is, why) } is->is_ref = 0; + MUTEX_EXIT(&is->is_lock); if (is->is_tqehead[0] != NULL) { if (ipf_deletetimeoutqueue(is->is_tqehead[0]) == 0) diff --git a/sys/dev/cxgbe/tom/t4_ddp.c b/sys/dev/cxgbe/tom/t4_ddp.c index 7cbb263..244287f 100644 --- a/sys/dev/cxgbe/tom/t4_ddp.c +++ b/sys/dev/cxgbe/tom/t4_ddp.c @@ -405,6 +405,19 @@ handle_ddp_data(struct toepcb *toep, __be32 ddp_report, __be32 rcv_nxt, int len) } tp = intotcpcb(inp); + + /* + * For RX_DDP_COMPLETE, len will be zero and rcv_nxt is the + * sequence number of the next byte to receive. The length of + * the data received for this message must be computed by + * comparing the new and old values of rcv_nxt. + * + * For RX_DATA_DDP, len might be non-zero, but it is only the + * length of the most recent DMA. It does not include the + * total length of the data received since the previous update + * for this DDP buffer. rcv_nxt is the sequence number of the + * first received byte from the most recent DMA. + */ len += be32toh(rcv_nxt) - tp->rcv_nxt; tp->rcv_nxt += len; tp->t_rcvtime = ticks; diff --git a/sys/dev/drm2/radeon/radeon_device.c b/sys/dev/drm2/radeon/radeon_device.c index e5c676b..73b2f4c 100644 --- a/sys/dev/drm2/radeon/radeon_device.c +++ b/sys/dev/drm2/radeon/radeon_device.c @@ -1342,14 +1342,10 @@ int radeon_suspend_kms(struct drm_device *dev) radeon_agp_suspend(rdev); - pci_save_state(device_get_parent(dev->dev)); #ifdef FREEBSD_WIP if (state.event == PM_EVENT_SUSPEND) { /* Shut down the device */ pci_disable_device(dev->pdev); -#endif /* FREEBSD_WIP */ - pci_set_powerstate(dev->dev, PCI_POWERSTATE_D3); -#ifdef FREEBSD_WIP } console_lock(); #endif /* FREEBSD_WIP */ @@ -1380,10 +1376,6 @@ int radeon_resume_kms(struct drm_device *dev) #ifdef FREEBSD_WIP console_lock(); -#endif /* FREEBSD_WIP */ - pci_set_powerstate(device_get_parent(dev->dev), PCI_POWERSTATE_D0); - pci_restore_state(device_get_parent(dev->dev)); -#ifdef FREEBSD_WIP if (pci_enable_device(dev->pdev)) { console_unlock(); return -1; diff --git a/sys/dev/drm2/ttm/ttm_bo.c b/sys/dev/drm2/ttm/ttm_bo.c index 64364d5..70e17c4 100644 --- a/sys/dev/drm2/ttm/ttm_bo.c +++ b/sys/dev/drm2/ttm/ttm_bo.c @@ -789,8 +789,7 @@ int ttm_bo_lock_delayed_workqueue(struct ttm_bo_device *bdev) { int pending; - taskqueue_cancel_timeout(taskqueue_thread, &bdev->wq, &pending); - if (pending) + if (taskqueue_cancel_timeout(taskqueue_thread, &bdev->wq, &pending)) taskqueue_drain_timeout(taskqueue_thread, &bdev->wq); return (pending); } diff --git a/sys/dev/isci/isci.c b/sys/dev/isci/isci.c index 2f0727d..5a1066c 100644 --- a/sys/dev/isci/isci.c +++ b/sys/dev/isci/isci.c @@ -163,6 +163,7 @@ isci_attach(device_t device) g_isci = isci; isci->device = device; + pci_enable_busmaster(device); isci_allocate_pci_memory(isci); @@ -272,6 +273,7 @@ isci_detach(device_t device) pci_release_msi(device); } + pci_disable_busmaster(device); return (0); } diff --git a/sys/dev/isci/isci_interrupt.c b/sys/dev/isci/isci_interrupt.c index 52c64f7..b56fd3a 100644 --- a/sys/dev/isci/isci_interrupt.c +++ b/sys/dev/isci/isci_interrupt.c @@ -136,8 +136,8 @@ isci_interrupt_setup(struct isci_softc *isci) pci_msix_count(isci->device) >= max_msix_messages) { isci->num_interrupts = max_msix_messages; - pci_alloc_msix(isci->device, &isci->num_interrupts); - if (isci->num_interrupts == max_msix_messages) + if (pci_alloc_msix(isci->device, &isci->num_interrupts) == 0 && + isci->num_interrupts == max_msix_messages) use_msix = TRUE; } diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c index 8094fe3..56bbf12 100644 --- a/sys/dev/netmap/netmap.c +++ b/sys/dev/netmap/netmap.c @@ -2841,10 +2841,12 @@ void netmap_detach(struct ifnet *ifp) { struct netmap_adapter *na = NA(ifp); + int skip; if (!na) return; + skip = 0; NMG_LOCK(); netmap_disable_all_rings(ifp); na->ifp = NULL; @@ -2856,10 +2858,11 @@ netmap_detach(struct ifnet *ifp) * the driver is gone. */ if (na->na_flags & NAF_NATIVE) { - netmap_adapter_put(na); + skip = netmap_adapter_put(na); } /* give them a chance to notice */ - netmap_enable_all_rings(ifp); + if (skip == 0) + netmap_enable_all_rings(ifp); NMG_UNLOCK(); } diff --git a/sys/dev/rccgpio/rccgpio.c b/sys/dev/rccgpio/rccgpio.c index dc44ac8..8ce11d3 100644 --- a/sys/dev/rccgpio/rccgpio.c +++ b/sys/dev/rccgpio/rccgpio.c @@ -126,7 +126,7 @@ rcc_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) struct rcc_gpio_softc *sc; sc = device_get_softc(dev); - if (pin > sc->sc_gpio_npins) + if (pin >= sc->sc_gpio_npins) return (EINVAL); *caps = rcc_pins[pin].caps; @@ -140,7 +140,7 @@ rcc_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) struct rcc_gpio_softc *sc; sc = device_get_softc(dev); - if (pin > sc->sc_gpio_npins) + if (pin >= sc->sc_gpio_npins) return (EINVAL); /* Flags cannot be changed. */ @@ -155,7 +155,7 @@ rcc_gpio_pin_getname(device_t dev, uint32_t pin, char *name) struct rcc_gpio_softc *sc; sc = device_get_softc(dev); - if (pin > sc->sc_gpio_npins) + if (pin >= sc->sc_gpio_npins) return (EINVAL); memcpy(name, rcc_pins[pin].name, GPIOMAXNAME); @@ -169,7 +169,7 @@ rcc_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) struct rcc_gpio_softc *sc; sc = device_get_softc(dev); - if (pin > sc->sc_gpio_npins) + if (pin >= sc->sc_gpio_npins) return (EINVAL); /* Flags cannot be changed - risk of short-circuit!!! */ @@ -183,7 +183,10 @@ rcc_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) struct rcc_gpio_softc *sc; sc = device_get_softc(dev); - if (pin > sc->sc_gpio_npins) + if (pin >= sc->sc_gpio_npins) + return (EINVAL); + + if ((rcc_pins[pin].caps & GPIO_PIN_OUTPUT) == 0) return (EINVAL); RCC_GPIO_LOCK(sc); @@ -204,7 +207,7 @@ rcc_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) uint32_t value; sc = device_get_softc(dev); - if (pin > sc->sc_gpio_npins) + if (pin >= sc->sc_gpio_npins) return (EINVAL); RCC_GPIO_LOCK(sc); @@ -224,7 +227,10 @@ rcc_gpio_pin_toggle(device_t dev, uint32_t pin) struct rcc_gpio_softc *sc; sc = device_get_softc(dev); - if (pin > sc->sc_gpio_npins) + if (pin >= sc->sc_gpio_npins) + return (EINVAL); + + if ((rcc_pins[pin].caps & GPIO_PIN_OUTPUT) == 0) return (EINVAL); RCC_GPIO_LOCK(sc); diff --git a/sys/dev/uart/uart_cpu_fdt.c b/sys/dev/uart/uart_cpu_fdt.c index 344aad5..c70b4ca 100644 --- a/sys/dev/uart/uart_cpu_fdt.c +++ b/sys/dev/uart/uart_cpu_fdt.c @@ -134,6 +134,7 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di) phandle_t node, chosen; pcell_t shift, br, rclk; u_long start, size, pbase, psize; + char *cp; int err; uart_bus_space_mem = fdtbus_bs_tag; @@ -148,18 +149,25 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di) if (devtype != UART_DEV_CONSOLE) return (ENXIO); - /* - * Retrieve /chosen/std{in,out}. - */ - node = -1; - if ((chosen = OF_finddevice("/chosen")) != -1) { - for (name = propnames; *name != NULL; name++) { - if (phandle_chosen_propdev(chosen, *name, &node) == 0) - break; + /* Has the user forced a specific device node? */ + cp = kern_getenv("hw.fdt.console"); + if (cp == NULL) { + /* + * Retrieve /chosen/std{in,out}. + */ + node = -1; + if ((chosen = OF_finddevice("/chosen")) != -1) { + for (name = propnames; *name != NULL; name++) { + if (phandle_chosen_propdev(chosen, *name, + &node) == 0) + break; + } } + if (chosen == -1 || *name == NULL) + node = OF_finddevice("serial0"); /* Last ditch */ + } else { + node = OF_finddevice(cp); } - if (chosen == -1 || *name == NULL) - node = OF_finddevice("serial0"); /* Last ditch */ if (node == -1) /* Can't find anything */ return (ENXIO); diff --git a/sys/dev/usb/serial/u3g.c b/sys/dev/usb/serial/u3g.c index 88831f2..ba825aa 100644 --- a/sys/dev/usb/serial/u3g.c +++ b/sys/dev/usb/serial/u3g.c @@ -316,6 +316,7 @@ static const STRUCT_USB_HOST_ID u3g_devs[] = { U3G_DEV(HUAWEI, E220, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, E220BIS, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, E392, U3GINIT_HUAWEISCSI), + U3G_DEV(HUAWEI, ME909U, U3GINIT_HUAWEISCSI2), U3G_DEV(HUAWEI, MOBILE, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, E1752, U3GINIT_HUAWEISCSI), U3G_DEV(HUAWEI, E1820, U3GINIT_HUAWEISCSI), @@ -494,6 +495,7 @@ static const STRUCT_USB_HOST_ID u3g_devs[] = { U3G_DEV(SIERRA, AC595U, 0), U3G_DEV(SIERRA, AC313U, 0), U3G_DEV(SIERRA, AC597E, 0), + U3G_DEV(SIERRA, AC875, 0), U3G_DEV(SIERRA, AC875E, 0), U3G_DEV(SIERRA, AC875U, 0), U3G_DEV(SIERRA, AC875U_2, 0), @@ -508,7 +510,6 @@ static const STRUCT_USB_HOST_ID u3g_devs[] = { U3G_DEV(SIERRA, AC885U, 0), U3G_DEV(SIERRA, AIRCARD580, 0), U3G_DEV(SIERRA, AIRCARD595, 0), - U3G_DEV(SIERRA, AIRCARD875, 0), U3G_DEV(SIERRA, C22, 0), U3G_DEV(SIERRA, C597, 0), U3G_DEV(SIERRA, C888, 0), diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs index 5d91e28..7b7373c5 100644 --- a/sys/dev/usb/usbdevs +++ b/sys/dev/usb/usbdevs @@ -2390,6 +2390,7 @@ product HUAWEI K3765_INIT 0x1520 K3765 Initial product HUAWEI K4505_INIT 0x1521 K4505 Initial product HUAWEI K3772_INIT 0x1526 K3772 Initial product HUAWEI E3272_INIT 0x155b LTE modem initial +product HUAWEI ME909U 0x1573 LTE modem product HUAWEI R215_INIT 0x1582 LTE modem initial product HUAWEI R215 0x1588 LTE modem product HUAWEI ETS2055 0x1803 CDMA modem @@ -4042,8 +4043,7 @@ product SIERRA C22 0x6891 C22 product SIERRA E6892 0x6892 E6892 product SIERRA E6893 0x6893 E6893 product SIERRA MC8700 0x68A3 MC8700 -product SIERRA MC7354 0x6820 MC7354 -product SIERRA AIRCARD875 0x6820 Aircard 875 HSDPA +product SIERRA MC7354 0x68C0 MC7354 product SIERRA AC313U 0x68aa Sierra Wireless AirCard 313U product SIERRA TRUINSTALL 0x0fff Aircard Tru Installer diff --git a/sys/dev/usb/wlan/if_run.c b/sys/dev/usb/wlan/if_run.c index 193b9ad..b787c03 100644 --- a/sys/dev/usb/wlan/if_run.c +++ b/sys/dev/usb/wlan/if_run.c @@ -88,8 +88,7 @@ SYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RWTUN, &run_debug, 0, "run debug level"); #endif -#define IEEE80211_HAS_ADDR4(wh) \ - (((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) +#define IEEE80211_HAS_ADDR4(wh) IEEE80211_IS_DSTODS(wh) /* * Because of LOR in run_key_delete(), use atomic instead. @@ -382,8 +381,6 @@ static int run_media_change(struct ifnet *); static int run_newstate(struct ieee80211vap *, enum ieee80211_state, int); static int run_wme_update(struct ieee80211com *); static void run_wme_update_cb(void *); -static void run_key_update_begin(struct ieee80211vap *); -static void run_key_update_end(struct ieee80211vap *); static void run_key_set_cb(void *); static int run_key_set(struct ieee80211vap *, struct ieee80211_key *, const uint8_t mac[IEEE80211_ADDR_LEN]); @@ -434,6 +431,8 @@ static void run_updateprot_cb(void *); static void run_usb_timeout_cb(void *); static void run_reset_livelock(struct run_softc *); static void run_enable_tsf_sync(struct run_softc *); +static void run_enable_tsf(struct run_softc *); +static void run_get_tsf(struct run_softc *, uint64_t *); static void run_enable_mrr(struct run_softc *); static void run_set_txpreamble(struct run_softc *); static void run_set_basicrates(struct run_softc *); @@ -926,8 +925,6 @@ run_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, return (NULL); } - vap->iv_key_update_begin = run_key_update_begin; - vap->iv_key_update_end = run_key_update_end; vap->iv_update_beacon = run_update_beacon; vap->iv_max_aid = RT2870_WCID_MAX; /* @@ -2002,7 +1999,7 @@ run_media_change(struct ifnet *ifp) if (rt2860_rates[ridx].rate == rate) break; ni = ieee80211_ref_node(vap->iv_bss); - rn = (struct run_node *)ni; + rn = RUN_NODE(ni); rn->fix_ridx = ridx; DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx); ieee80211_free_node(ni); @@ -2130,7 +2127,8 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) ratectl |= bid; - } + } else + run_enable_tsf(sc); /* turn link LED on */ run_set_leds(sc, RT2860_LED_RADIO | @@ -2227,27 +2225,11 @@ run_wme_update(struct ieee80211com *ic) run_wme_update_cb(ic); RUN_UNLOCK(sc); - /* return whatever, upper layer desn't care anyway */ + /* return whatever, upper layer doesn't care anyway */ return (0); } static void -run_key_update_begin(struct ieee80211vap *vap) -{ - /* - * To avoid out-of-order events, both run_key_set() and - * _delete() are deferred and handled by run_cmdq_cb(). - * So, there is nothing we need to do here. - */ -} - -static void -run_key_update_end(struct ieee80211vap *vap) -{ - /* null */ -} - -static void run_key_set_cb(void *arg) { struct run_cmdq *cmdq = arg; @@ -2256,6 +2238,7 @@ run_key_set_cb(void *arg) struct ieee80211com *ic = vap->iv_ic; struct run_softc *sc = ic->ic_softc; struct ieee80211_node *ni; + u_int cipher = k->wk_cipher->ic_cipher; uint32_t attr; uint16_t base, associd; uint8_t mode, wcid, iv[8]; @@ -2269,7 +2252,7 @@ run_key_set_cb(void *arg) associd = (ni != NULL) ? ni->ni_associd : 0; /* map net80211 cipher to RT2860 security mode */ - switch (k->wk_cipher->ic_cipher) { + switch (cipher) { case IEEE80211_CIPHER_WEP: if(k->wk_keylen < 8) mode = RT2860_MODE_WEP40; @@ -2302,7 +2285,7 @@ run_key_set_cb(void *arg) base = RT2860_PKEY(wcid); } - if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { + if (cipher == IEEE80211_CIPHER_TKIP) { if(run_write_region_1(sc, base, k->wk_key, 16)) return; if(run_write_region_1(sc, base + 16, &k->wk_key[16], 8)) /* wk_txmic */ @@ -2318,11 +2301,11 @@ run_key_set_cb(void *arg) if (!(k->wk_flags & IEEE80211_KEY_GROUP) || (k->wk_flags & (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV))) { /* set initial packet number in IV+EIV */ - if (k->wk_cipher == IEEE80211_CIPHER_WEP) { + if (cipher == IEEE80211_CIPHER_WEP) { memset(iv, 0, sizeof iv); iv[3] = vap->iv_def_txkey << 6; } else { - if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { + if (cipher == IEEE80211_CIPHER_TKIP) { iv[0] = k->wk_keytsc >> 8; iv[1] = (iv[0] | 0x20) & 0x7f; iv[2] = k->wk_keytsc; @@ -2576,7 +2559,7 @@ run_iter_func(void *arg, struct ieee80211_node *ni) { struct run_softc *sc = arg; struct ieee80211vap *vap = ni->ni_vap; - struct run_node *rn = (void *)ni; + struct run_node *rn = RUN_NODE(ni); union run_stats sta[2]; uint16_t (*wstat)[3]; int txcnt, success, retrycnt, error; @@ -2650,7 +2633,7 @@ run_newassoc_cb(void *arg) static void run_newassoc(struct ieee80211_node *ni, int isnew) { - struct run_node *rn = (void *)ni; + struct run_node *rn = RUN_NODE(ni); struct ieee80211_rateset *rs = &ni->ni_rates; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = vap->iv_ic; @@ -2831,6 +2814,7 @@ run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) tap->wr_antenna = ant; tap->wr_dbm_antsignal = run_rssi2dbm(sc, rssi, ant); tap->wr_rate = 2; /* in case it can't be found below */ + run_get_tsf(sc, &tap->wr_tsf); phy = le16toh(rxwi->phy); switch (phy & RT2860_PHY_MODE) { case RT2860_PHY_CCK: @@ -3078,6 +3062,7 @@ tr_setup: (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd)); tap->wt_flags = 0; tap->wt_rate = rt2860_rates[data->ridx].rate; + run_get_tsf(sc, &tap->wt_tsf); tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); tap->wt_hwqueue = index; @@ -3243,7 +3228,7 @@ run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) struct ieee80211_frame *wh; struct ieee80211_channel *chan; const struct ieee80211_txparam *tp; - struct run_node *rn = (void *)ni; + struct run_node *rn = RUN_NODE(ni); struct run_tx_data *data; struct rt2870_txd *txd; struct rt2860_txwi *txwi; @@ -3407,7 +3392,7 @@ static int run_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { struct ieee80211com *ic = &sc->sc_ic; - struct run_node *rn = (void *)ni; + struct run_node *rn = RUN_NODE(ni); struct run_tx_data *data; struct ieee80211_frame *wh; struct rt2870_txd *txd; @@ -5067,6 +5052,25 @@ run_enable_tsf_sync(struct run_softc *sc) } static void +run_enable_tsf(struct run_softc *sc) +{ + uint32_t tmp; + + if (run_read(sc, RT2860_BCN_TIME_CFG, &tmp) == 0) { + tmp &= ~(RT2860_BCN_TX_EN | RT2860_TBTT_TIMER_EN); + tmp |= RT2860_TSF_TIMER_EN; + run_write(sc, RT2860_BCN_TIME_CFG, tmp); + } +} + +static void +run_get_tsf(struct run_softc *sc, uint64_t *buf) +{ + run_read_region_1(sc, RT2860_TSF_TIMER_DW0, (uint8_t *)buf, + sizeof(*buf)); +} + +static void run_enable_mrr(struct run_softc *sc) { #define CCK(mcs) (mcs) diff --git a/sys/dev/usb/wlan/if_runvar.h b/sys/dev/usb/wlan/if_runvar.h index b8cb12f..71e29ba 100644 --- a/sys/dev/usb/wlan/if_runvar.h +++ b/sys/dev/usb/wlan/if_runvar.h @@ -45,6 +45,7 @@ struct run_rx_radiotap_header { struct ieee80211_radiotap_header wr_ihdr; + uint64_t wr_tsf; uint8_t wr_flags; uint8_t wr_rate; uint16_t wr_chan_freq; @@ -55,7 +56,8 @@ struct run_rx_radiotap_header { } __packed __aligned(8); #define RUN_RX_RADIOTAP_PRESENT \ - (1 << IEEE80211_RADIOTAP_FLAGS | \ + (1 << IEEE80211_RADIOTAP_TSFT | \ + 1 << IEEE80211_RADIOTAP_FLAGS | \ 1 << IEEE80211_RADIOTAP_RATE | \ 1 << IEEE80211_RADIOTAP_CHANNEL | \ 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL | \ @@ -64,6 +66,7 @@ struct run_rx_radiotap_header { struct run_tx_radiotap_header { struct ieee80211_radiotap_header wt_ihdr; + uint64_t wt_tsf; uint8_t wt_flags; uint8_t wt_rate; uint16_t wt_chan_freq; @@ -74,7 +77,8 @@ struct run_tx_radiotap_header { #define IEEE80211_RADIOTAP_HWQUEUE 15 #define RUN_TX_RADIOTAP_PRESENT \ - (1 << IEEE80211_RADIOTAP_FLAGS | \ + (1 << IEEE80211_RADIOTAP_TSFT | \ + 1 << IEEE80211_RADIOTAP_FLAGS | \ 1 << IEEE80211_RADIOTAP_RATE | \ 1 << IEEE80211_RADIOTAP_CHANNEL | \ 1 << IEEE80211_RADIOTAP_HWQUEUE) @@ -101,6 +105,7 @@ struct run_node { uint8_t mgt_ridx; uint8_t fix_ridx; }; +#define RUN_NODE(ni) ((struct run_node *)(ni)) struct run_cmdq { void *arg0; diff --git a/sys/dev/usb/wlan/if_urtwnreg.h b/sys/dev/usb/wlan/if_urtwnreg.h index 0ca9db7..3c21279 100644 --- a/sys/dev/usb/wlan/if_urtwnreg.h +++ b/sys/dev/usb/wlan/if_urtwnreg.h @@ -451,7 +451,7 @@ #define R92C_RQPN_LD 0x80000000 /* Bits for R92C_TDECTRL. */ -#define R92C_TDECTRL_BLK_DESC_NUM_M 0x0000000f +#define R92C_TDECTRL_BLK_DESC_NUM_M 0x000000f0 #define R92C_TDECTRL_BLK_DESC_NUM_S 4 /* Bits for R92C_FWHW_TXQ_CTRL. */ diff --git a/sys/i386/i386/stack_machdep.c b/sys/i386/i386/stack_machdep.c deleted file mode 100644 index 8dbb9ab..0000000 --- a/sys/i386/i386/stack_machdep.c +++ /dev/null @@ -1,87 +0,0 @@ -/*- - * Copyright (c) 2005 Antoine Brodin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/stack.h> - -#include <machine/pcb.h> -#include <machine/stack.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/pmap.h> - -static void -stack_capture(struct thread *td, struct stack *st, register_t ebp) -{ - struct i386_frame *frame; - vm_offset_t callpc; - - stack_zero(st); - frame = (struct i386_frame *)ebp; - while (1) { - if (!INKERNEL(frame)) - break; - callpc = frame->f_retaddr; - if (!INKERNEL(callpc)) - break; - if (stack_put(st, callpc) == -1) - break; - if (frame->f_frame <= frame || - (vm_offset_t)frame->f_frame >= td->td_kstack + - td->td_kstack_pages * PAGE_SIZE) - break; - frame = frame->f_frame; - } -} - -void -stack_save_td(struct stack *st, struct thread *td) -{ - register_t ebp; - - if (TD_IS_SWAPPED(td)) - panic("stack_save_td: swapped"); - if (TD_IS_RUNNING(td)) - panic("stack_save_td: running"); - - ebp = td->td_pcb->pcb_ebp; - stack_capture(td, st, ebp); -} - -void -stack_save(struct stack *st) -{ - register_t ebp; - - __asm __volatile("movl %%ebp,%0" : "=r" (ebp)); - stack_capture(curthread, st, ebp); -} diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index 1e417bf..40f7204 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$"); #include "opt_isa.h" #include "opt_kdb.h" #include "opt_npx.h" +#include "opt_stack.h" #include "opt_trap.h" #include <sys/param.h> @@ -94,6 +95,7 @@ PMC_SOFT_DEFINE( , , page_fault, write); #ifdef SMP #include <machine/smp.h> #endif +#include <machine/stack.h> #include <machine/tss.h> #include <machine/vm86.h> @@ -219,18 +221,25 @@ trap(struct trapframe *frame) goto out; } -#ifdef HWPMC_HOOKS - /* - * CPU PMCs interrupt using an NMI so we check for that first. - * If the HWPMC module is active, 'pmc_hook' will point to - * the function to be called. A return value of '1' from the - * hook means that the NMI was handled by it and that we can - * return immediately. - */ - if (type == T_NMI && pmc_intr && - (*pmc_intr)(PCPU_GET(cpuid), frame)) - goto out; + if (type == T_NMI) { +#ifdef HWPMC_HOOKS + /* + * CPU PMCs interrupt using an NMI so we check for that first. + * If the HWPMC module is active, 'pmc_hook' will point to + * the function to be called. A non-zero return value from the + * hook means that the NMI was consumed by it and that we can + * return immediately. + */ + if (pmc_intr != NULL && + (*pmc_intr)(PCPU_GET(cpuid), frame) != 0) + goto out; +#endif + +#ifdef STACK + if (stack_nmi_handler(frame) != 0) + goto out; #endif + } if (type == T_MCHK) { mca_intr(); @@ -782,7 +791,6 @@ trap_pfault(frame, usermode, eva) vm_offset_t eva; { vm_offset_t va; - struct vmspace *vm; vm_map_t map; int rv = 0; vm_prot_t ftype; @@ -852,14 +860,7 @@ trap_pfault(frame, usermode, eva) map = kernel_map; } else { - /* - * This is a fault on non-kernel virtual memory. If either - * p or p->p_vmspace is NULL, then the fault is fatal. - */ - if (p == NULL || (vm = p->p_vmspace) == NULL) - goto nogo; - - map = &vm->vm_map; + map = &p->p_vmspace->vm_map; /* * When accessing a user-space address, kernel must be @@ -888,28 +889,8 @@ trap_pfault(frame, usermode, eva) else ftype = VM_PROT_READ; - if (map != kernel_map) { - /* - * Keep swapout from messing with us during this - * critical time. - */ - PROC_LOCK(p); - ++p->p_lock; - PROC_UNLOCK(p); - - /* Fault in the user page: */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); - - PROC_LOCK(p); - --p->p_lock; - PROC_UNLOCK(p); - } else { - /* - * Don't have to worry about process locking or stacks in the - * kernel. - */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); - } + /* Fault in the page. */ + rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); if (rv == KERN_SUCCESS) { #ifdef HWPMC_HOOKS if (ftype == VM_PROT_READ || ftype == VM_PROT_WRITE) { diff --git a/sys/i386/include/stack.h b/sys/i386/include/stack.h index f63fc4b..091ae33 100644 --- a/sys/i386/include/stack.h +++ b/sys/i386/include/stack.h @@ -1,42 +1,6 @@ -/*- - * Mach Operating System - * Copyright (c) 1991,1990 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - * - * $FreeBSD$ - */ - -#ifndef _MACHINE_STACK_H_ -#define _MACHINE_STACK_H_ - /* - * Stack trace. + * This file is in the public domain. */ +/* $FreeBSD$ */ -struct i386_frame { - struct i386_frame *f_frame; - int f_retaddr; - int f_arg0; -}; - -#endif /* !_MACHINE_STACK_H_ */ +#include <x86/stack.h> diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index e89fa91..8023d55 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -1902,11 +1902,6 @@ __elfN(note_procstat_proc)(void *arg, struct sbuf *sb, size_t *sizep) CTASSERT(sizeof(struct kinfo_file) == KINFO_FILE_SIZE); #endif -static int pack_fileinfo = 1; -SYSCTL_INT(_kern, OID_AUTO, coredump_pack_fileinfo, CTLFLAG_RWTUN, - &pack_fileinfo, 0, - "Enable file path packing in 'procstat -f' coredump notes"); - static void note_procstat_files(void *arg, struct sbuf *sb, size_t *sizep) { @@ -1915,7 +1910,7 @@ note_procstat_files(void *arg, struct sbuf *sb, size_t *sizep) ssize_t start_len, sect_len; int structsize, filedesc_flags; - if (pack_fileinfo) + if (coredump_pack_fileinfo) filedesc_flags = KERN_FILEDESC_PACK_KINFO; else filedesc_flags = 0; diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 9277393..23b7d54 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -911,7 +911,7 @@ kern_dup(struct thread *td, u_int mode, int flags, int old, int new) #endif filecaps_free(&newfde->fde_caps); memcpy(newfde, oldfde, fde_change_size); - filecaps_copy(&oldfde->fde_caps, &newfde->fde_caps); + filecaps_copy(&oldfde->fde_caps, &newfde->fde_caps, true); if ((flags & FDDUP_FLAG_CLOEXEC) != 0) newfde->fde_flags = oldfde->fde_flags | UF_EXCLOSE; else @@ -1433,21 +1433,31 @@ filecaps_init(struct filecaps *fcaps) /* * Copy filecaps structure allocating memory for ioctls array if needed. + * + * The last parameter indicates whether the fdtable is locked. If it is not and + * ioctls are encountered, copying fails and the caller must lock the table. + * + * Note that if the table was not locked, the caller has to check the relevant + * sequence counter to determine whether the operation was successful. */ -void -filecaps_copy(const struct filecaps *src, struct filecaps *dst) +int +filecaps_copy(const struct filecaps *src, struct filecaps *dst, bool locked) { size_t size; *dst = *src; - if (src->fc_ioctls != NULL) { - KASSERT(src->fc_nioctls > 0, - ("fc_ioctls != NULL, but fc_nioctls=%hd", src->fc_nioctls)); + if (src->fc_ioctls == NULL) + return (0); + if (!locked) + return (1); - size = sizeof(src->fc_ioctls[0]) * src->fc_nioctls; - dst->fc_ioctls = malloc(size, M_FILECAPS, M_WAITOK); - bcopy(src->fc_ioctls, dst->fc_ioctls, size); - } + KASSERT(src->fc_nioctls > 0, + ("fc_ioctls != NULL, but fc_nioctls=%hd", src->fc_nioctls)); + + size = sizeof(src->fc_ioctls[0]) * src->fc_nioctls; + dst->fc_ioctls = malloc(size, M_FILECAPS, M_WAITOK); + bcopy(src->fc_ioctls, dst->fc_ioctls, size); + return (0); } /* @@ -1956,7 +1966,7 @@ fdcopy(struct filedesc *fdp) } nfde = &newfdp->fd_ofiles[i]; *nfde = *ofde; - filecaps_copy(&ofde->fde_caps, &nfde->fde_caps); + filecaps_copy(&ofde->fde_caps, &nfde->fde_caps, true); fhold(nfde->fde_file); fdused_init(newfdp, i); newfdp->fd_lastfile = i; @@ -2012,7 +2022,7 @@ fdcopy_remapped(struct filedesc *fdp, const int *fds, size_t nfds, } nfde = &newfdp->fd_ofiles[i]; *nfde = *ofde; - filecaps_copy(&ofde->fde_caps, &nfde->fde_caps); + filecaps_copy(&ofde->fde_caps, &nfde->fde_caps, true); fhold(nfde->fde_file); fdused_init(newfdp, i); newfdp->fd_lastfile = i; @@ -2711,11 +2721,9 @@ fgetvp_rights(struct thread *td, int fd, cap_rights_t *needrightsp, return (EBADF); #ifdef CAPABILITIES - if (needrightsp != NULL) { - error = cap_check(cap_rights(fdp, fd), needrightsp); - if (error != 0) - return (error); - } + error = cap_check(cap_rights(fdp, fd), needrightsp); + if (error != 0) + return (error); #endif if (fp->f_vnode == NULL) @@ -2723,7 +2731,7 @@ fgetvp_rights(struct thread *td, int fd, cap_rights_t *needrightsp, *vpp = fp->f_vnode; vref(*vpp); - filecaps_copy(&fdp->fd_ofiles[fd].fde_caps, havecaps); + filecaps_copy(&fdp->fd_ofiles[fd].fde_caps, havecaps, true); return (0); } @@ -2938,7 +2946,7 @@ dupfdopen(struct thread *td, struct filedesc *fdp, int dfd, int mode, seq_write_begin(&newfde->fde_seq); #endif memcpy(newfde, oldfde, fde_change_size); - filecaps_copy(&oldfde->fde_caps, &newfde->fde_caps); + filecaps_copy(&oldfde->fde_caps, &newfde->fde_caps, true); #ifdef CAPABILITIES seq_write_end(&newfde->fde_seq); #endif diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 56207a0..a3fd830b 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -100,6 +100,11 @@ SDT_PROBE_DEFINE1(proc, kernel, , exec__success, "char *"); MALLOC_DEFINE(M_PARGS, "proc-args", "Process arguments"); +int coredump_pack_fileinfo = 1; +SYSCTL_INT(_kern, OID_AUTO, coredump_pack_fileinfo, CTLFLAG_RWTUN, + &coredump_pack_fileinfo, 0, + "Enable file path packing in 'procstat -f' coredump notes"); + static int sysctl_kern_ps_strings(SYSCTL_HANDLER_ARGS); static int sysctl_kern_usrstack(SYSCTL_HANDLER_ARGS); static int sysctl_kern_stackprot(SYSCTL_HANDLER_ARGS); diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 3c88a59..aa4c904 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -2517,11 +2517,14 @@ repeat: sizeof(kkstp->kkst_trace), SBUF_FIXEDLEN); thread_lock(td); kkstp->kkst_tid = td->td_tid; - if (TD_IS_SWAPPED(td)) + if (TD_IS_SWAPPED(td)) { kkstp->kkst_state = KKST_STATE_SWAPPED; - else if (TD_IS_RUNNING(td)) - kkstp->kkst_state = KKST_STATE_RUNNING; - else { + } else if (TD_IS_RUNNING(td)) { + if (stack_save_td_running(st, td) == 0) + kkstp->kkst_state = KKST_STATE_STACKOK; + else + kkstp->kkst_state = KKST_STATE_RUNNING; + } else { kkstp->kkst_state = KKST_STATE_STACKOK; stack_save_td(st, td); } diff --git a/sys/kern/subr_param.c b/sys/kern/subr_param.c index 36608d1..52c6f16 100644 --- a/sys/kern/subr_param.c +++ b/sys/kern/subr_param.c @@ -265,7 +265,8 @@ init_param2(long physpages) if (maxfiles > (physpages / 4)) maxfiles = physpages / 4; maxfilesperproc = (maxfiles / 10) * 9; - + TUNABLE_INT_FETCH("kern.maxfilesperproc", &maxfilesperproc); + /* * Cannot be changed after boot. */ diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index c3a71c8..efed37b 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -1972,7 +1972,7 @@ unp_internalize(struct mbuf **controlp, struct thread *td) fdep[i] = fdev; fdep[i]->fde_file = fde->fde_file; filecaps_copy(&fde->fde_caps, - &fdep[i]->fde_caps); + &fdep[i]->fde_caps, true); unp_internalize_fp(fdep[i]->fde_file); } FILEDESC_SUNLOCK(fdesc); diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 5f68bde..ea7c0a4 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -3768,74 +3768,6 @@ bufwait(struct buf *bp) } } - /* - * Call back function from struct bio back up to struct buf. - */ -static void -bufdonebio(struct bio *bip) -{ - struct buf *bp; - - bp = bip->bio_caller2; - bp->b_resid = bip->bio_resid; - bp->b_ioflags = bip->bio_flags; - bp->b_error = bip->bio_error; - if (bp->b_error) - bp->b_ioflags |= BIO_ERROR; - bufdone(bp); - g_destroy_bio(bip); -} - -void -dev_strategy(struct cdev *dev, struct buf *bp) -{ - struct cdevsw *csw; - int ref; - - KASSERT(dev->si_refcount > 0, - ("dev_strategy on un-referenced struct cdev *(%s) %p", - devtoname(dev), dev)); - - csw = dev_refthread(dev, &ref); - dev_strategy_csw(dev, csw, bp); - dev_relthread(dev, ref); -} - -void -dev_strategy_csw(struct cdev *dev, struct cdevsw *csw, struct buf *bp) -{ - struct bio *bip; - - KASSERT(bp->b_iocmd == BIO_READ || bp->b_iocmd == BIO_WRITE, - ("b_iocmd botch")); - KASSERT(((dev->si_flags & SI_ETERNAL) != 0 && csw != NULL) || - dev->si_threadcount > 0, - ("dev_strategy_csw threadcount cdev *(%s) %p", devtoname(dev), - dev)); - if (csw == NULL) { - bp->b_error = ENXIO; - bp->b_ioflags = BIO_ERROR; - bufdone(bp); - return; - } - for (;;) { - bip = g_new_bio(); - if (bip != NULL) - break; - /* Try again later */ - tsleep(&bp, PRIBIO, "dev_strat", hz/10); - } - bip->bio_cmd = bp->b_iocmd; - bip->bio_offset = bp->b_iooffset; - bip->bio_length = bp->b_bcount; - bip->bio_bcount = bp->b_bcount; /* XXX: remove */ - bdata2bio(bp, bip); - bip->bio_done = bufdonebio; - bip->bio_caller2 = bp; - bip->bio_dev = dev; - (*csw->d_strategy)(bip); -} - /* * bufdone: * diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 740123f..18a9ac3 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -195,7 +195,10 @@ vn_open_cred(struct nameidata *ndp, int *flagp, int cmode, u_int vn_open_flags, restart: fmode = *flagp; - if (fmode & O_CREAT) { + if ((fmode & (O_CREAT | O_EXCL | O_DIRECTORY)) == (O_CREAT | + O_EXCL | O_DIRECTORY)) + return (EINVAL); + else if ((fmode & (O_CREAT | O_DIRECTORY)) == O_CREAT) { ndp->ni_cnd.cn_nameiop = CREATE; /* * Set NOCACHE to avoid flushing the cache when diff --git a/sys/mips/mips/stack_machdep.c b/sys/mips/mips/stack_machdep.c index e7971a2..9b724cb 100644 --- a/sys/mips/mips/stack_machdep.c +++ b/sys/mips/mips/stack_machdep.c @@ -142,6 +142,13 @@ stack_save_td(struct stack *st, struct thread *td) stack_capture(st, pc, sp); } +int +stack_save_td_running(struct stack *st, struct thread *td) +{ + + return (EOPNOTSUPP); +} + void stack_save(struct stack *st) { diff --git a/sys/mips/mips/trap.c b/sys/mips/mips/trap.c index 98fe812..b193463 100644 --- a/sys/mips/mips/trap.c +++ b/sys/mips/mips/trap.c @@ -714,19 +714,7 @@ dofault: goto nogo; } - /* - * Keep swapout from messing with us during this - * critical time. - */ - PROC_LOCK(p); - ++p->p_lock; - PROC_UNLOCK(p); - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); - - PROC_LOCK(p); - --p->p_lock; - PROC_UNLOCK(p); /* * XXXDTRACE: add dtrace_doubletrap_func here? */ diff --git a/sys/modules/ctl/Makefile b/sys/modules/ctl/Makefile index c74f000..c9be22b 100644 --- a/sys/modules/ctl/Makefile +++ b/sys/modules/ctl/Makefile @@ -13,6 +13,7 @@ SRCS+= ctl_frontend.c SRCS+= ctl_frontend_cam_sim.c SRCS+= ctl_frontend_ioctl.c SRCS+= ctl_frontend_iscsi.c +SRCS+= ctl_ha.c SRCS+= ctl_scsi_all.c SRCS+= ctl_tpc.c SRCS+= ctl_tpc_local.c diff --git a/sys/modules/zfs/Makefile b/sys/modules/zfs/Makefile index d8650af..ffbd9ba 100644 --- a/sys/modules/zfs/Makefile +++ b/sys/modules/zfs/Makefile @@ -4,7 +4,7 @@ SYSDIR?=${.CURDIR}/../.. KMOD= zfs -SRCS= bus_if.h device_if.h vnode_if.h opt_kstack_pages.h opt_random.h +SRCS= bus_if.h device_if.h vnode_if.h opt_kstack_pages.h SUNW= ${SYSDIR}/cddl/contrib/opensolaris diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c index 78b4d9d..5903abd 100644 --- a/sys/net/if_gif.c +++ b/sys/net/if_gif.c @@ -421,13 +421,8 @@ gif_transmit(struct ifnet *ifp, struct mbuf *m) } eth = mtod(m, struct etherip_header *); eth->eip_resvh = 0; - if ((sc->gif_options & GIF_SEND_REVETHIP) != 0) { - eth->eip_ver = 0; - eth->eip_resvl = ETHERIP_VERSION; - } else { - eth->eip_ver = ETHERIP_VERSION; - eth->eip_resvl = 0; - } + eth->eip_ver = ETHERIP_VERSION; + eth->eip_resvl = 0; break; default: error = EAFNOSUPPORT; @@ -635,19 +630,10 @@ gif_input(struct mbuf *m, struct ifnet *ifp, int proto, uint8_t ecn) if (m == NULL) goto drop; eip = mtod(m, struct etherip_header *); - /* - * GIF_ACCEPT_REVETHIP (enabled by default) intentionally - * accepts an EtherIP packet with revered version field in - * the header. This is a knob for backward compatibility - * with FreeBSD 7.2R or prior. - */ if (eip->eip_ver != ETHERIP_VERSION) { - if ((gif_options & GIF_ACCEPT_REVETHIP) == 0 || - eip->eip_resvl != ETHERIP_VERSION) { - /* discard unknown versions */ - m_freem(m); - goto drop; - } + /* discard unknown versions */ + m_freem(m); + goto drop; } m_adj(m, sizeof(struct etherip_header)); @@ -768,50 +754,32 @@ gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) goto bad; /* validate sa_len */ + /* check sa_family looks sane for the cmd */ switch (src->sa_family) { #ifdef INET case AF_INET: if (src->sa_len != sizeof(struct sockaddr_in)) goto bad; - break; -#endif -#ifdef INET6 - case AF_INET6: - if (src->sa_len != sizeof(struct sockaddr_in6)) + if (cmd != SIOCSIFPHYADDR) { + error = EAFNOSUPPORT; goto bad; - break; -#endif - default: - error = EAFNOSUPPORT; - goto bad; - } - /* check sa_family looks sane for the cmd */ - error = EAFNOSUPPORT; - switch (cmd) { -#ifdef INET - case SIOCSIFPHYADDR: - if (src->sa_family == AF_INET) - break; - goto bad; -#endif -#ifdef INET6 - case SIOCSIFPHYADDR_IN6: - if (src->sa_family == AF_INET6) - break; - goto bad; -#endif - } - error = EADDRNOTAVAIL; - switch (src->sa_family) { -#ifdef INET - case AF_INET: + } if (satosin(src)->sin_addr.s_addr == INADDR_ANY || - satosin(dst)->sin_addr.s_addr == INADDR_ANY) + satosin(dst)->sin_addr.s_addr == INADDR_ANY) { + error = EADDRNOTAVAIL; goto bad; + } break; #endif #ifdef INET6 case AF_INET6: + if (src->sa_len != sizeof(struct sockaddr_in6)) + goto bad; + if (cmd != SIOCSIFPHYADDR_IN6) { + error = EAFNOSUPPORT; + goto bad; + } + error = EADDRNOTAVAIL; if (IN6_IS_ADDR_UNSPECIFIED(&satosin6(src)->sin6_addr) || IN6_IS_ADDR_UNSPECIFIED(&satosin6(dst)->sin6_addr)) @@ -827,8 +795,12 @@ gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) error = sa6_embedscope(satosin6(dst), 0); if (error != 0) goto bad; + break; #endif - }; + default: + error = EAFNOSUPPORT; + goto bad; + } error = gif_set_tunnel(ifp, src, dst); break; case SIOCDIFPHYADDR: diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h index ed143e8..b71c8e8 100644 --- a/sys/net/if_gif.h +++ b/sys/net/if_gif.h @@ -126,10 +126,7 @@ int in6_gif_attach(struct gif_softc *); #define GIFGOPTS _IOWR('i', 150, struct ifreq) #define GIFSOPTS _IOW('i', 151, struct ifreq) -#define GIF_ACCEPT_REVETHIP 0x0001 #define GIF_IGNORE_SOURCE 0x0002 -#define GIF_SEND_REVETHIP 0x0010 -#define GIF_OPTMASK (GIF_ACCEPT_REVETHIP|GIF_SEND_REVETHIP| \ - GIF_IGNORE_SOURCE) +#define GIF_OPTMASK (GIF_IGNORE_SOURCE) #endif /* _NET_IF_GIF_H_ */ diff --git a/sys/netgraph/ng_pppoe.c b/sys/netgraph/ng_pppoe.c index 6c2ed67..382410c 100644 --- a/sys/netgraph/ng_pppoe.c +++ b/sys/netgraph/ng_pppoe.c @@ -168,6 +168,13 @@ static const struct ng_cmdlist ng_pppoe_cmds[] = { &ng_parse_enaddr_type, NULL }, + { + NGM_PPPOE_COOKIE, + NGM_PPPOE_SETMAXP, + "setmaxp", + &ng_parse_uint16_type, + NULL + }, { 0 } }; @@ -262,6 +269,7 @@ struct PPPoE { struct ether_header eh; LIST_HEAD(, sess_con) listeners; struct sess_hash_entry sesshash[SESSHASHSIZE]; + struct maxptag max_payload; /* PPP-Max-Payload (RFC4638) */ }; typedef struct PPPoE *priv_p; @@ -1004,6 +1012,13 @@ ng_pppoe_rcvmsg(node_p node, item_p item, hook_p lasthook) bcopy(msg->data, &privp->eh.ether_shost, ETHER_ADDR_LEN); break; + case NGM_PPPOE_SETMAXP: + if (msg->header.arglen != sizeof(uint16_t)) + LEAVE(EINVAL); + privp->max_payload.hdr.tag_type = PTT_MAX_PAYL; + privp->max_payload.hdr.tag_len = htons(sizeof(uint16_t)); + privp->max_payload.data = htons(*((uint16_t *)msg->data)); + break; default: LEAVE(EINVAL); } @@ -1071,6 +1086,8 @@ pppoe_start(sessp sp) init_tags(sp); insert_tag(sp, &uniqtag.hdr); insert_tag(sp, &neg->service.hdr); + if (privp->max_payload.data != 0) + insert_tag(sp, &privp->max_payload.hdr); make_packet(sp); /* * Send packet and prepare to retransmit it after timeout. @@ -1124,6 +1141,28 @@ send_sessionid(sessp sp) return (error); } +static int +send_maxp(sessp sp, const struct pppoe_tag *tag) +{ + int error; + struct ng_mesg *msg; + struct ngpppoe_maxp *maxp; + + CTR2(KTR_NET, "%20s: called %d", __func__, sp->Session_ID); + + NG_MKMESSAGE(msg, NGM_PPPOE_COOKIE, NGM_PPPOE_SETMAXP, + sizeof(struct ngpppoe_maxp), M_NOWAIT); + if (msg == NULL) + return (ENOMEM); + + maxp = (struct ngpppoe_maxp *)msg->data; + strncpy(maxp->hook, NG_HOOK_NAME(sp->hook), NG_HOOKSIZ); + maxp->data = ntohs(((const struct maxptag *)tag)->data); + NG_SEND_MSG_ID(error, NG_HOOK_NODE(sp->hook), msg, sp->creator, 0); + + return (error); +} + /* * Receive data from session hook and do something with it. */ @@ -1464,6 +1503,9 @@ ng_pppoe_rcvdata_ether(hook_p hook, item_p item) insert_tag(sp, tag); /* return it */ send_acname(sp, tag); } + if ((tag = get_tag(ph, PTT_MAX_PAYL)) && + (privp->max_payload.data != 0)) + insert_tag(sp, tag); /* return it */ insert_tag(sp, &neg->service.hdr); /* Service */ scan_tags(sp, ph); make_packet(sp); @@ -1602,6 +1644,9 @@ ng_pppoe_rcvdata_ether(hook_p hook, item_p item) m_freem(neg->m); free(sp->neg, M_NETGRAPH_PPPOE); sp->neg = NULL; + if ((tag = get_tag(ph, PTT_MAX_PAYL)) && + (privp->max_payload.data != 0)) + send_maxp(sp, tag); pppoe_send_event(sp, NGM_PPPOE_SUCCESS); break; case PADT_CODE: diff --git a/sys/netgraph/ng_pppoe.h b/sys/netgraph/ng_pppoe.h index 6ef81b7..3b74f07 100644 --- a/sys/netgraph/ng_pppoe.h +++ b/sys/netgraph/ng_pppoe.h @@ -51,6 +51,7 @@ #define NG_PPPOE_NODE_TYPE "pppoe" #define NGM_PPPOE_COOKIE 1089893072 +#define NGM_PPPOE_SETMAXP_COOKIE 1441624322 #define PPPOE_SERVICE_NAME_SIZE 64 /* for now */ @@ -83,6 +84,7 @@ enum cmd { NGM_PPPOE_SETMODE = 12, /* set to standard or compat modes */ NGM_PPPOE_GETMODE = 13, /* see current mode */ NGM_PPPOE_SETENADDR = 14, /* set Ethernet address */ + NGM_PPPOE_SETMAXP = 15 /* Set PPP-Max-Payload value */ }; /*********************** @@ -147,6 +149,13 @@ struct ngpppoe_sts { { NULL } \ } +/* + * This structure is used to send PPP-Max-Payload value from server to client. + */ +struct ngpppoe_maxp { + char hook[NG_HOOKSIZ]; /* hook associated with event session */ + uint16_t data; +}; /******************************************************************** * Constants and definitions specific to pppoe @@ -229,6 +238,10 @@ struct datatag { u_int8_t data[PPPOE_SERVICE_NAME_SIZE]; }; +struct maxptag { + struct pppoe_tag hdr; + uint16_t data; +}; /* * Define the order in which we will place tags in packets diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h index 760c3b4..a26bc5b 100644 --- a/sys/netinet/sctp_constants.h +++ b/sys/netinet/sctp_constants.h @@ -66,6 +66,8 @@ __FBSDID("$FreeBSD$"); */ #define SCTP_LARGEST_INIT_ACCEPTED (65535 - 2048) +/* Largest length of a chunk */ +#define SCTP_MAX_CHUNK_LENGTH 0xffff /* Number of addresses where we just skip the counting */ #define SCTP_COUNT_LIMIT 40 diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index 7d92655..d9ca669 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -2513,11 +2513,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, SCTP_BUF_LEN(merr) = sizeof(*phd); SCTP_BUF_NEXT(merr) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT); if (SCTP_BUF_NEXT(merr)) { - if (sctp_pad_lastmbuf(SCTP_BUF_NEXT(merr), SCTP_SIZE32(chk_length) - chk_length, NULL) == NULL) { - sctp_m_freem(merr); - } else { - sctp_queue_op_err(stcb, merr); - } + sctp_queue_op_err(stcb, merr); } else { sctp_m_freem(merr); } diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index a1e2055..9f8d032 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -4819,13 +4819,11 @@ process_control_chunks: /* The INIT chunk must be the only chunk. */ if ((num_chunks > 1) || (length - *offset > (int)SCTP_SIZE32(chk_length))) { - op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), - "INIT not the only chunk"); - sctp_abort_association(inp, stcb, m, iphlen, - src, dst, sh, op_err, - mflowtype, mflowid, - vrf_id, port); + /* RFC 4960 requires that no ABORT is sent */ *offset = length; + if (locked_tcb) { + SCTP_TCB_UNLOCK(locked_tcb); + } return (NULL); } /* Honor our resource limit. */ @@ -5604,16 +5602,12 @@ process_control_chunks: SCTP_BUF_LEN(mm) = sizeof(*phd); SCTP_BUF_NEXT(mm) = SCTP_M_COPYM(m, *offset, len, M_NOWAIT); if (SCTP_BUF_NEXT(mm)) { - if (sctp_pad_lastmbuf(SCTP_BUF_NEXT(mm), SCTP_SIZE32(len) - len, NULL) == NULL) { - sctp_m_freem(mm); - } else { #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); - } -#endif - sctp_queue_op_err(stcb, mm); + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { + sctp_log_mbc(SCTP_BUF_NEXT(mm), SCTP_MBUF_ICOPY); } +#endif + sctp_queue_op_err(stcb, mm); } else { sctp_m_freem(mm); } diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 772ec94..f515d6a 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -8850,9 +8850,37 @@ sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err) */ struct sctp_chunkhdr *hdr; struct sctp_tmit_chunk *chk; - struct mbuf *mat; + struct mbuf *mat, *last_mbuf; + uint32_t chunk_length; + uint16_t padding_length; SCTP_TCB_LOCK_ASSERT(stcb); + SCTP_BUF_PREPEND(op_err, sizeof(struct sctp_chunkhdr), M_NOWAIT); + if (op_err == NULL) { + return; + } + last_mbuf = NULL; + chunk_length = 0; + for (mat = op_err; mat != NULL; mat = SCTP_BUF_NEXT(mat)) { + chunk_length += SCTP_BUF_LEN(mat); + if (SCTP_BUF_NEXT(mat) == NULL) { + last_mbuf = mat; + } + } + if (chunk_length > SCTP_MAX_CHUNK_LENGTH) { + sctp_m_freem(op_err); + return; + } + padding_length = chunk_length % 4; + if (padding_length != 0) { + padding_length = 4 - padding_length; + } + if (padding_length != 0) { + if (sctp_add_pad_tombuf(last_mbuf, padding_length) == NULL) { + sctp_m_freem(op_err); + return; + } + } sctp_alloc_a_chunk(stcb, chk); if (chk == NULL) { /* no memory */ @@ -8860,15 +8888,7 @@ sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err) return; } chk->copy_by_ref = 0; - SCTP_BUF_PREPEND(op_err, sizeof(struct sctp_chunkhdr), M_NOWAIT); - if (op_err == NULL) { - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); - return; - } - chk->send_size = 0; - for (mat = op_err; mat != NULL; mat = SCTP_BUF_NEXT(mat)) { - chk->send_size += SCTP_BUF_LEN(mat); - } + chk->send_size = (uint16_t) chunk_length; chk->sent = SCTP_DATAGRAM_UNSENT; chk->snd_count = 0; chk->asoc = &stcb->asoc; @@ -8878,9 +8898,7 @@ sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err) hdr->chunk_type = SCTP_OPERATION_ERROR; hdr->chunk_flags = 0; hdr->chunk_length = htons(chk->send_size); - TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, - chk, - sctp_next); + TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); chk->asoc->ctrl_queue_cnt++; } diff --git a/sys/netinet/sctp_sysctl.h b/sys/netinet/sctp_sysctl.h index ef33d9b..5055110 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" +#define SCTPCTL_BLACKHOLE_DESC "Enable SCTP blackholing. See blackhole(4) man page for more details." #define SCTPCTL_BLACKHOLE_MIN 0 #define SCTPCTL_BLACKHOLE_MAX 2 #define SCTPCTL_BLACKHOLE_DEFAULT SCTPCTL_BLACKHOLE_MIN diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index 37ef5f4..b14af01 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -281,8 +281,6 @@ in6_control(struct socket *so, u_long cmd, caddr_t data, /* FALLTHROUGH */ case OSIOCGIFINFO_IN6: case SIOCGIFINFO_IN6: - case SIOCGDRLST_IN6: - case SIOCGPRLST_IN6: case SIOCGNBRINFO_IN6: case SIOCGDEFIFACE_IN6: return (nd6_ioctl(cmd, data, ifp)); @@ -1198,11 +1196,13 @@ in6_update_ifa_internal(struct ifnet *ifp, struct in6_aliasreq *ifra, * source address. */ ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /* safety */ - if (hostIsNew && in6if_do_dad(ifp)) - ia->ia6_flags |= IN6_IFF_TENTATIVE; - /* DAD should be performed after ND6_IFF_IFDISABLED is cleared. */ - if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) + /* + * DAD should be performed for an new address or addresses on + * an interface with ND6_IFF_IFDISABLED. + */ + if (in6if_do_dad(ifp) && + (hostIsNew || (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED))) ia->ia6_flags |= IN6_IFF_TENTATIVE; /* notify other subsystems */ diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index 37bd720..64981b3 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -566,9 +566,6 @@ in6_ifattach_loopback(struct ifnet *ifp) ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; - /* skip registration to the prefix list. XXX should be temporary. */ - ifra.ifra_flags |= IN6_IFF_NOPFX; - /* * We are sure that this is a newly assigned address, so we can set * NULL to the 3rd arg. diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index 4d39a5e..007fd66 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -442,11 +442,6 @@ struct in6_rrenumreq { #define SIOCGIFAFLAG_IN6 _IOWR('i', 73, struct in6_ifreq) -#define SIOCGDRLST_IN6 _IOWR('i', 74, struct in6_drlist) -#ifdef _KERNEL -/* XXX: SIOCGPRLST_IN6 is exposed in KAME but in6_oprlist is not. */ -#define SIOCGPRLST_IN6 _IOWR('i', 75, struct in6_oprlist) -#endif #ifdef _KERNEL #define OSIOCGIFINFO_IN6 _IOWR('i', 76, struct in6_ondireq) #endif @@ -499,9 +494,6 @@ struct in6_rrenumreq { #define IN6_IFF_AUTOCONF 0x40 /* autoconfigurable address. */ #define IN6_IFF_TEMPORARY 0x80 /* temporary (anonymous) address. */ #define IN6_IFF_PREFER_SOURCE 0x0100 /* preferred address for SAS */ -#define IN6_IFF_NOPFX 0x8000 /* skip kernel prefix management. - * XXX: this should be temporary. - */ /* do not input/output */ #define IN6_IFF_NOTREADY (IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED) diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 0d6f9f7..11276a5 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -1344,99 +1344,14 @@ nd6_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) int nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) { - struct in6_drlist *drl = (struct in6_drlist *)data; - struct in6_oprlist *oprl = (struct in6_oprlist *)data; struct in6_ndireq *ndi = (struct in6_ndireq *)data; struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data; struct in6_ndifreq *ndif = (struct in6_ndifreq *)data; - struct nd_defrouter *dr; - struct nd_prefix *pr; - int i = 0, error = 0; + int error = 0; if (ifp->if_afdata[AF_INET6] == NULL) return (EPFNOSUPPORT); switch (cmd) { - case SIOCGDRLST_IN6: - /* - * obsolete API, use sysctl under net.inet6.icmp6 - */ - bzero(drl, sizeof(*drl)); - TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) { - if (i >= DRLSTSIZ) - break; - drl->defrouter[i].rtaddr = dr->rtaddr; - in6_clearscope(&drl->defrouter[i].rtaddr); - - drl->defrouter[i].flags = dr->flags; - drl->defrouter[i].rtlifetime = dr->rtlifetime; - drl->defrouter[i].expire = dr->expire + - (time_second - time_uptime); - drl->defrouter[i].if_index = dr->ifp->if_index; - i++; - } - break; - case SIOCGPRLST_IN6: - /* - * obsolete API, use sysctl under net.inet6.icmp6 - * - * XXX the structure in6_prlist was changed in backward- - * incompatible manner. in6_oprlist is used for SIOCGPRLST_IN6, - * in6_prlist is used for nd6_sysctl() - fill_prlist(). - */ - /* - * XXX meaning of fields, especialy "raflags", is very - * differnet between RA prefix list and RR/static prefix list. - * how about separating ioctls into two? - */ - bzero(oprl, sizeof(*oprl)); - LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { - struct nd_pfxrouter *pfr; - int j; - - if (i >= PRLSTSIZ) - break; - oprl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr; - oprl->prefix[i].raflags = pr->ndpr_raf; - oprl->prefix[i].prefixlen = pr->ndpr_plen; - oprl->prefix[i].vltime = pr->ndpr_vltime; - oprl->prefix[i].pltime = pr->ndpr_pltime; - oprl->prefix[i].if_index = pr->ndpr_ifp->if_index; - if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME) - oprl->prefix[i].expire = 0; - else { - time_t maxexpire; - - /* XXX: we assume time_t is signed. */ - maxexpire = (-1) & - ~((time_t)1 << - ((sizeof(maxexpire) * 8) - 1)); - if (pr->ndpr_vltime < - maxexpire - pr->ndpr_lastupdate) { - oprl->prefix[i].expire = - pr->ndpr_lastupdate + - pr->ndpr_vltime + - (time_second - time_uptime); - } else - oprl->prefix[i].expire = maxexpire; - } - - j = 0; - LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { - if (j < DRLSTSIZ) { -#define RTRADDR oprl->prefix[i].advrtr[j] - RTRADDR = pfr->router->rtaddr; - in6_clearscope(&RTRADDR); -#undef RTRADDR - } - j++; - } - oprl->prefix[i].advrtrs = j; - oprl->prefix[i].origin = PR_ORIG_RA; - - i++; - } - - break; case OSIOCGIFINFO_IN6: #define ND ndi->ndi /* XXX: old ndp(8) assumes a positive value for linkmtu. */ @@ -1496,22 +1411,19 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) * do not clear ND6_IFF_IFDISABLED. * See RFC 4862, Section 5.4.5. */ - int duplicated_linklocal = 0; - IF_ADDR_RLOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; ia = (struct in6_ifaddr *)ifa; if ((ia->ia6_flags & IN6_IFF_DUPLICATED) && - IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) { - duplicated_linklocal = 1; + IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) break; - } } IF_ADDR_RUNLOCK(ifp); - if (duplicated_linklocal) { + if (ifa != NULL) { + /* LLA is duplicated. */ ND.flags |= ND6_IFF_IFDISABLED; log(LOG_ERR, "Cannot enable an interface" " with a link-local address marked" @@ -1527,14 +1439,18 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) /* Mark all IPv6 address as tentative. */ ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED; - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { - if (ifa->ifa_addr->sa_family != AF_INET6) - continue; - ia = (struct in6_ifaddr *)ifa; - ia->ia6_flags |= IN6_IFF_TENTATIVE; + if ((ND_IFINFO(ifp)->flags & ND6_IFF_NO_DAD) == 0) { + IF_ADDR_RLOCK(ifp); + TAILQ_FOREACH(ifa, &ifp->if_addrhead, + ifa_link) { + if (ifa->ifa_addr->sa_family != + AF_INET6) + continue; + ia = (struct in6_ifaddr *)ifa; + ia->ia6_flags |= IN6_IFF_TENTATIVE; + } + IF_ADDR_RUNLOCK(ifp); } - IF_ADDR_RUNLOCK(ifp); } if (ND.flags & ND6_IFF_AUTO_LINKLOCAL) { @@ -1552,20 +1468,19 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) * address is assigned, and IFF_UP, try to * assign one. */ - int haslinklocal = 0; - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { - if (ifa->ifa_addr->sa_family != AF_INET6) + TAILQ_FOREACH(ifa, &ifp->if_addrhead, + ifa_link) { + if (ifa->ifa_addr->sa_family != + AF_INET6) continue; ia = (struct in6_ifaddr *)ifa; - if (IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) { - haslinklocal = 1; + if (IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) break; - } } IF_ADDR_RUNLOCK(ifp); - if (!haslinklocal) + if (ifa != NULL) + /* No LLA is configured. */ in6_ifattach(ifp, NULL); } } diff --git a/sys/powerpc/include/spr.h b/sys/powerpc/include/spr.h index c753f5e..ab48a91 100644 --- a/sys/powerpc/include/spr.h +++ b/sys/powerpc/include/spr.h @@ -190,6 +190,7 @@ #define FSL_E500v2 0x8021 #define FSL_E500mc 0x8023 #define FSL_E5500 0x8024 +#define FSL_E6500 0x8040 #define SPR_IBAT0U 0x210 /* .68 Instruction BAT Reg 0 Upper */ #define SPR_IBAT0U 0x210 /* .6. Instruction BAT Reg 0 Upper */ diff --git a/sys/powerpc/powerpc/stack_machdep.c b/sys/powerpc/powerpc/stack_machdep.c index a6e0364..451e7be 100644 --- a/sys/powerpc/powerpc/stack_machdep.c +++ b/sys/powerpc/powerpc/stack_machdep.c @@ -98,6 +98,13 @@ stack_save_td(struct stack *st, struct thread *td) stack_capture(st, frame); } +int +stack_save_td_running(struct stack *st, struct thread *td) +{ + + return (EOPNOTSUPP); +} + void stack_save(struct stack *st) { diff --git a/sys/powerpc/powerpc/trap.c b/sys/powerpc/powerpc/trap.c index cabf780..29130ea 100644 --- a/sys/powerpc/powerpc/trap.c +++ b/sys/powerpc/powerpc/trap.c @@ -704,9 +704,6 @@ trap_pfault(struct trapframe *frame, int user) #else if ((eva >> ADDR_SR_SHFT) == (USER_ADDR >> ADDR_SR_SHFT)) { #endif - if (p->p_vmspace == NULL) - return (SIGSEGV); - map = &p->p_vmspace->vm_map; #ifdef AIM @@ -720,31 +717,11 @@ trap_pfault(struct trapframe *frame, int user) } va = trunc_page(eva); - if (map != kernel_map) { - /* - * Keep swapout from messing with us during this - * critical time. - */ - PROC_LOCK(p); - ++p->p_lock; - PROC_UNLOCK(p); - - /* Fault in the user page: */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); - - PROC_LOCK(p); - --p->p_lock; - PROC_UNLOCK(p); - /* - * XXXDTRACE: add dtrace_doubletrap_func here? - */ - } else { - /* - * Don't have to worry about process locking or stacks in the - * kernel. - */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); - } + /* Fault in the page. */ + rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); + /* + * XXXDTRACE: add dtrace_doubletrap_func here? + */ if (rv == KERN_SUCCESS) return (0); diff --git a/sys/sparc64/sparc64/stack_machdep.c b/sys/sparc64/sparc64/stack_machdep.c index 923d72c..329368d 100644 --- a/sys/sparc64/sparc64/stack_machdep.c +++ b/sys/sparc64/sparc64/stack_machdep.c @@ -82,6 +82,13 @@ stack_save_td(struct stack *st, struct thread *td) stack_capture(st, (struct frame *)(td->td_pcb->pcb_sp + SPOFF)); } +int +stack_save_td_running(struct stack *st, struct thread *td) +{ + + return (EOPNOTSUPP); +} + void stack_save(struct stack *st) { diff --git a/sys/sparc64/sparc64/trap.c b/sys/sparc64/sparc64/trap.c index e9917e5..96e72ed 100644 --- a/sys/sparc64/sparc64/trap.c +++ b/sys/sparc64/sparc64/trap.c @@ -441,7 +441,7 @@ trap_cecc(void) static int trap_pfault(struct thread *td, struct trapframe *tf) { - struct vmspace *vm; + vm_map_t map; struct proc *p; vm_offset_t va; vm_prot_t prot; @@ -484,28 +484,8 @@ trap_pfault(struct thread *td, struct trapframe *tf) return (0); } - /* - * This is a fault on non-kernel virtual memory. - */ - vm = p->p_vmspace; - - /* - * Keep swapout from messing with us during this - * critical time. - */ - PROC_LOCK(p); - ++p->p_lock; - PROC_UNLOCK(p); - - /* Fault in the user page. */ - rv = vm_fault(&vm->vm_map, va, prot, VM_FAULT_NORMAL); - - /* - * Now the process can be swapped again. - */ - PROC_LOCK(p); - --p->p_lock; - PROC_UNLOCK(p); + /* This is a fault on non-kernel virtual memory. */ + map = &p->p_vmspace->vm_map; } else { /* * This is a fault on kernel virtual memory. Attempts to @@ -527,14 +507,12 @@ trap_pfault(struct thread *td, struct trapframe *tf) } vm_map_unlock_read(kernel_map); } - - /* - * We don't have to worry about process locking or stacks in - * the kernel. - */ - rv = vm_fault(kernel_map, va, prot, VM_FAULT_NORMAL); + map = kernel_map; } + /* Fault in the page. */ + rv = vm_fault(map, va, prot, VM_FAULT_NORMAL); + CTR3(KTR_TRAP, "trap_pfault: return td=%p va=%#lx rv=%d", td, va, rv); if (rv == KERN_SUCCESS) diff --git a/sys/sys/conf.h b/sys/sys/conf.h index d821703..4001822 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -240,8 +240,6 @@ void dev_depends(struct cdev *_pdev, struct cdev *_cdev); void dev_ref(struct cdev *dev); void dev_refl(struct cdev *dev); void dev_rel(struct cdev *dev); -void dev_strategy(struct cdev *dev, struct buf *bp); -void dev_strategy_csw(struct cdev *dev, struct cdevsw *csw, struct buf *bp); struct cdev *make_dev(struct cdevsw *_devsw, int _unit, uid_t _uid, gid_t _gid, int _perms, const char *_fmt, ...) __printflike(6, 7); struct cdev *make_dev_cred(struct cdevsw *_devsw, int _unit, diff --git a/sys/sys/exec.h b/sys/sys/exec.h index cccebfd..a13c1ac 100644 --- a/sys/sys/exec.h +++ b/sys/sys/exec.h @@ -83,6 +83,8 @@ void exec_unmap_first_page(struct image_params *); int exec_register(const struct execsw *); int exec_unregister(const struct execsw *); +extern int coredump_pack_fileinfo; + /* * note: name##_mod cannot be const storage because the * linker_file_sysinit() function modifies _file in the diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h index f75927b..b34a2f1 100644 --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -153,7 +153,8 @@ enum { struct thread; void filecaps_init(struct filecaps *fcaps); -void filecaps_copy(const struct filecaps *src, struct filecaps *dst); +int filecaps_copy(const struct filecaps *src, struct filecaps *dst, + bool locked); void filecaps_move(struct filecaps *src, struct filecaps *dst); void filecaps_free(struct filecaps *fcaps); diff --git a/sys/sys/random.h b/sys/sys/random.h index 53d7243..edad83b 100644 --- a/sys/sys/random.h +++ b/sys/sys/random.h @@ -33,8 +33,6 @@ #include <sys/types.h> -#include "opt_random.h" - #if !defined(KLD_MODULE) #if defined(RANDOM_LOADABLE) && defined(RANDOM_YARROW) #error "Cannot define both RANDOM_LOADABLE and RANDOM_YARROW" diff --git a/sys/sys/stack.h b/sys/sys/stack.h index 5531467..e26b535 100644 --- a/sys/sys/stack.h +++ b/sys/sys/stack.h @@ -56,9 +56,10 @@ void stack_ktr(u_int, const char *, int, const struct stack *, #define CTRSTACK(m, st, depth, cheap) #endif -/* MD Routine. */ +/* MD Routines. */ struct thread; void stack_save(struct stack *); void stack_save_td(struct stack *, struct thread *); +int stack_save_td_running(struct stack *, struct thread *); #endif diff --git a/sys/sys/vmmeter.h b/sys/sys/vmmeter.h index 92d7cc6..4d3df29 100644 --- a/sys/sys/vmmeter.h +++ b/sys/sys/vmmeter.h @@ -97,8 +97,6 @@ struct vmmeter { u_int v_inactive_target; /* (c) pages desired inactive */ u_int v_inactive_count; /* (q) pages inactive */ u_int v_cache_count; /* (f) pages on cache queue */ - u_int v_cache_min; /* (c) min pages desired on cache queue */ - u_int v_cache_max; /* (c) max pages in cached obj (unused) */ u_int v_pageout_free_min; /* (c) min pages reserved for kernel */ u_int v_interrupt_free_min; /* (c) reserved pages for int code */ u_int v_free_severe; /* (c) severe page depletion point */ @@ -113,6 +111,7 @@ struct vmmeter { u_int v_vforkpages; /* (p) VM pages affected by vfork() */ u_int v_rforkpages; /* (p) VM pages affected by rfork() */ u_int v_kthreadpages; /* (p) VM pages affected by fork() by kernel */ + u_int v_spare[2]; }; #ifdef _KERNEL diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c index d79ee40..fd58063 100644 --- a/sys/vm/swap_pager.c +++ b/sys/vm/swap_pager.c @@ -2345,8 +2345,8 @@ swapoff_one(struct swdevt *sp, struct ucred *cred) swap_pager_swapoff(sp); sp->sw_close(curthread, sp); - sp->sw_id = NULL; mtx_lock(&sw_dev_mtx); + sp->sw_id = NULL; TAILQ_REMOVE(&swtailq, sp, sw_list); nswapdev--; if (nswapdev == 0) { @@ -2532,6 +2532,33 @@ swapgeom_close_ev(void *arg, int flags) g_destroy_consumer(cp); } +/* + * Add a reference to the g_consumer for an inflight transaction. + */ +static void +swapgeom_acquire(struct g_consumer *cp) +{ + + mtx_assert(&sw_dev_mtx, MA_OWNED); + cp->index++; +} + +/* + * Remove a reference from the g_consumer. Post a close event if + * all referneces go away. + */ +static void +swapgeom_release(struct g_consumer *cp, struct swdevt *sp) +{ + + mtx_assert(&sw_dev_mtx, MA_OWNED); + cp->index--; + if (cp->index == 0) { + if (g_post_event(swapgeom_close_ev, cp, M_NOWAIT, NULL) == 0) + sp->sw_id = NULL; + } +} + static void swapgeom_done(struct bio *bp2) { @@ -2547,13 +2574,9 @@ swapgeom_done(struct bio *bp2) bp->b_resid = bp->b_bcount - bp2->bio_completed; bp->b_error = bp2->bio_error; bufdone(bp); + sp = bp2->bio_caller1; mtx_lock(&sw_dev_mtx); - if ((--cp->index) == 0 && cp->private) { - if (g_post_event(swapgeom_close_ev, cp, M_NOWAIT, NULL) == 0) { - sp = bp2->bio_caller1; - sp->sw_id = NULL; - } - } + swapgeom_release(cp, sp); mtx_unlock(&sw_dev_mtx); g_destroy_bio(bp2); } @@ -2573,13 +2596,16 @@ swapgeom_strategy(struct buf *bp, struct swdevt *sp) bufdone(bp); return; } - cp->index++; + swapgeom_acquire(cp); mtx_unlock(&sw_dev_mtx); if (bp->b_iocmd == BIO_WRITE) bio = g_new_bio(); else bio = g_alloc_bio(); if (bio == NULL) { + mtx_lock(&sw_dev_mtx); + swapgeom_release(cp, sp); + mtx_unlock(&sw_dev_mtx); bp->b_error = ENOMEM; bp->b_ioflags |= BIO_ERROR; bufdone(bp); @@ -2619,7 +2645,12 @@ swapgeom_orphan(struct g_consumer *cp) break; } } - cp->private = (void *)(uintptr_t)1; + /* + * Drop reference we were created with. Do directly since we're in a + * special context where we don't have to queue the call to + * swapgeom_close_ev(). + */ + cp->index--; destroy = ((sp != NULL) && (cp->index == 0)); if (destroy) sp->sw_id = NULL; @@ -2680,8 +2711,8 @@ swapongeom_ev(void *arg, int flags) if (gp == NULL) gp = g_new_geomf(&g_swap_class, "swap"); cp = g_new_consumer(gp); - cp->index = 0; /* Number of active I/Os. */ - cp->private = NULL; /* Orphanization flag */ + cp->index = 1; /* Number of active I/Os, plus one for being active. */ + cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; g_attach(cp, pp); /* * XXX: Everytime you think you can improve the margin for diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index 65c3e2c..2e69b87 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -3969,12 +3969,10 @@ RetryLookup:; vm_map_unlock_read(map); return (KERN_PROTECTION_FAILURE); } - if ((entry->eflags & MAP_ENTRY_USER_WIRED) && - (entry->eflags & MAP_ENTRY_COW) && - (fault_type & VM_PROT_WRITE)) { - vm_map_unlock_read(map); - return (KERN_PROTECTION_FAILURE); - } + KASSERT((prot & VM_PROT_WRITE) == 0 || (entry->eflags & + (MAP_ENTRY_USER_WIRED | MAP_ENTRY_NEEDS_COPY)) != + (MAP_ENTRY_USER_WIRED | MAP_ENTRY_NEEDS_COPY), + ("entry %p flags %x", entry, entry->eflags)); if ((fault_typea & VM_PROT_COPY) != 0 && (entry->max_protection & VM_PROT_WRITE) == 0 && (entry->eflags & MAP_ENTRY_COW) == 0) { @@ -4128,10 +4126,6 @@ vm_map_lookup_locked(vm_map_t *var_map, /* IN/OUT */ fault_type &= VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; if ((fault_type & prot) != fault_type) return (KERN_PROTECTION_FAILURE); - if ((entry->eflags & MAP_ENTRY_USER_WIRED) && - (entry->eflags & MAP_ENTRY_COW) && - (fault_type & VM_PROT_WRITE)) - return (KERN_PROTECTION_FAILURE); /* * If this page is not pageable, we have to get it for all possible diff --git a/sys/vm/vm_meter.c b/sys/vm/vm_meter.c index 865be71..f1573a3 100644 --- a/sys/vm/vm_meter.c +++ b/sys/vm/vm_meter.c @@ -63,10 +63,6 @@ SYSCTL_UINT(_vm, VM_V_FREE_RESERVED, v_free_reserved, CTLFLAG_RW, &vm_cnt.v_free_reserved, 0, "Pages reserved for deadlock"); SYSCTL_UINT(_vm, VM_V_INACTIVE_TARGET, v_inactive_target, CTLFLAG_RW, &vm_cnt.v_inactive_target, 0, "Pages desired inactive"); -SYSCTL_UINT(_vm, VM_V_CACHE_MIN, v_cache_min, - CTLFLAG_RW, &vm_cnt.v_cache_min, 0, "Min pages on cache queue"); -SYSCTL_UINT(_vm, VM_V_CACHE_MAX, v_cache_max, - CTLFLAG_RW, &vm_cnt.v_cache_max, 0, "Max pages on cache queue"); SYSCTL_UINT(_vm, VM_V_PAGEOUT_FREE_MIN, v_pageout_free_min, CTLFLAG_RW, &vm_cnt.v_pageout_free_min, 0, "Min pages reserved for kernel"); SYSCTL_UINT(_vm, OID_AUTO, v_free_severe, @@ -308,8 +304,6 @@ VM_STATS_VM(v_active_count, "Active pages"); VM_STATS_VM(v_inactive_target, "Desired inactive pages"); VM_STATS_VM(v_inactive_count, "Inactive pages"); VM_STATS_VM(v_cache_count, "Pages on cache queue"); -VM_STATS_VM(v_cache_min, "Min pages on cache queue"); -VM_STATS_VM(v_cache_max, "Max pages on cached queue"); VM_STATS_VM(v_pageout_free_min, "Min pages reserved for kernel"); VM_STATS_VM(v_interrupt_free_min, "Reserved pages for interrupt code"); VM_STATS_VM(v_forks, "Number of fork() calls"); diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index c7bc707..9c4890f 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -3290,7 +3290,6 @@ DB_SHOW_COMMAND(page, vm_page_print_page_info) db_printf("vm_cnt.v_free_reserved: %d\n", vm_cnt.v_free_reserved); db_printf("vm_cnt.v_free_min: %d\n", vm_cnt.v_free_min); db_printf("vm_cnt.v_free_target: %d\n", vm_cnt.v_free_target); - db_printf("vm_cnt.v_cache_min: %d\n", vm_cnt.v_cache_min); db_printf("vm_cnt.v_inactive_target: %d\n", vm_cnt.v_inactive_target); } diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c index c52b384..6641193 100644 --- a/sys/vm/vm_pageout.c +++ b/sys/vm/vm_pageout.c @@ -1178,12 +1178,8 @@ unlock_page: * Invalid pages can be easily freed. They cannot be * mapped, vm_page_free() asserts this. */ - if (m->valid == 0) { - vm_page_free(m); - PCPU_INC(cnt.v_dfree); - --page_shortage; - goto drop_page; - } + if (m->valid == 0) + goto free_page; /* * If the page has been referenced and the object is not dead, @@ -1214,12 +1210,8 @@ unlock_page: */ m->act_count += act_delta + ACT_ADVANCE; goto drop_page; - } else if ((object->flags & OBJ_DEAD) == 0) { - vm_pagequeue_lock(pq); - queues_locked = TRUE; - vm_page_requeue_locked(m); - goto drop_page; - } + } else if ((object->flags & OBJ_DEAD) == 0) + goto requeue_page; } /* @@ -1240,6 +1232,7 @@ unlock_page: /* * Clean pages can be freed. */ +free_page: vm_page_free(m); PCPU_INC(cnt.v_dfree); --page_shortage; @@ -1266,6 +1259,7 @@ unlock_page: * the thrash point for a heavily loaded machine. */ m->flags |= PG_WINATCFLS; +requeue_page: vm_pagequeue_lock(pq); queues_locked = TRUE; vm_page_requeue_locked(m); @@ -1287,12 +1281,8 @@ unlock_page: pageout_ok = vm_page_count_min(); else pageout_ok = TRUE; - if (!pageout_ok) { - vm_pagequeue_lock(pq); - queues_locked = TRUE; - vm_page_requeue_locked(m); - goto drop_page; - } + if (!pageout_ok) + goto requeue_page; error = vm_pageout_clean(m); /* * Decrement page_shortage on success to account for diff --git a/sys/vm/vm_param.h b/sys/vm/vm_param.h index 38456de..68e5cd1 100644 --- a/sys/vm/vm_param.h +++ b/sys/vm/vm_param.h @@ -79,8 +79,8 @@ #define VM_V_FREE_TARGET 4 /* vm_cnt.v_free_target */ #define VM_V_FREE_RESERVED 5 /* vm_cnt.v_free_reserved */ #define VM_V_INACTIVE_TARGET 6 /* vm_cnt.v_inactive_target */ -#define VM_V_CACHE_MIN 7 /* vm_cnt.v_cache_min */ -#define VM_V_CACHE_MAX 8 /* vm_cnt.v_cache_max */ +#define VM_OBSOLETE_7 7 /* unused, formerly v_cache_min */ +#define VM_OBSOLETE_8 8 /* unused, formerly v_cache_max */ #define VM_V_PAGEOUT_FREE_MIN 9 /* vm_cnt.v_pageout_free_min */ #define VM_OBSOLETE_10 10 /* pageout algorithm */ #define VM_SWAPPING_ENABLED 11 /* swapping enabled */ diff --git a/sys/x86/include/apicvar.h b/sys/x86/include/apicvar.h index 0bd9fe5..58fcced 100644 --- a/sys/x86/include/apicvar.h +++ b/sys/x86/include/apicvar.h @@ -129,12 +129,14 @@ #else #define IPI_DYN_FIRST (APIC_IPI_INTS + 8) #endif -#define IPI_DYN_LAST (254) /* IPIs allocated at runtime */ +#define IPI_DYN_LAST (253) /* IPIs allocated at runtime */ /* * IPI_STOP_HARD does not need to occupy a slot in the IPI vector space since * it is delivered using an NMI anyways. */ +#define IPI_NMI_FIRST 254 +#define IPI_TRACE 254 /* Interrupt for tracing. */ #define IPI_STOP_HARD 255 /* Stop CPU with a NMI. */ /* diff --git a/sys/x86/include/stack.h b/sys/x86/include/stack.h new file mode 100644 index 0000000..7f6930a --- /dev/null +++ b/sys/x86/include/stack.h @@ -0,0 +1,61 @@ +/*- + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + * + * $FreeBSD$ + */ + +#ifndef _X86_STACK_H +#define _X86_STACK_H + +/* + * Stack trace. + */ + +#ifdef __i386__ +struct i386_frame { + struct i386_frame *f_frame; + u_int f_retaddr; + u_int f_arg0; +}; +#endif + +#ifdef __amd64__ +struct amd64_frame { + struct amd64_frame *f_frame; + u_long f_retaddr; +}; + +struct i386_frame { + uint32_t f_frame; + uint32_t f_retaddr; + uint32_t f_arg0; +}; +#endif /* __amd64__ */ + +#ifdef _KERNEL +int stack_nmi_handler(struct trapframe *); +#endif + +#endif /* !_X86_STACK_H */ diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c index 8198971..106a842 100644 --- a/sys/x86/x86/local_apic.c +++ b/sys/x86/x86/local_apic.c @@ -1703,11 +1703,10 @@ native_lapic_ipi_vectored(u_int vector, int dest) icrlo = APIC_DESTMODE_PHY | APIC_TRIGMOD_EDGE | APIC_LEVEL_ASSERT; /* - * IPI_STOP_HARD is just a "fake" vector used to send a NMI. - * Use special rules regard NMI if passed, otherwise specify - * the vector. + * NMI IPIs are just fake vectors used to send a NMI. Use special rules + * regarding NMIs if passed, otherwise specify the vector. */ - if (vector == IPI_STOP_HARD) + if (vector >= IPI_NMI_FIRST) icrlo |= APIC_DELMODE_NMI; else icrlo |= vector | APIC_DELMODE_FIXED; diff --git a/sys/x86/x86/mp_x86.c b/sys/x86/x86/mp_x86.c index c23108c..9e1cec2 100644 --- a/sys/x86/x86/mp_x86.c +++ b/sys/x86/x86/mp_x86.c @@ -120,7 +120,7 @@ struct cpu_ops cpu_ops; * Local data and functions. */ -static volatile cpuset_t ipi_nmi_pending; +static volatile cpuset_t ipi_stop_nmi_pending; /* used to hold the AP's until we are ready to release them */ struct mtx ap_boot_mtx; @@ -894,7 +894,7 @@ ipi_selected(cpuset_t cpus, u_int ipi) * Set the mask of receiving CPUs for this purpose. */ if (ipi == IPI_STOP_HARD) - CPU_OR_ATOMIC(&ipi_nmi_pending, &cpus); + CPU_OR_ATOMIC(&ipi_stop_nmi_pending, &cpus); while ((cpu = CPU_FFS(&cpus)) != 0) { cpu--; @@ -917,7 +917,7 @@ ipi_cpu(int cpu, u_int ipi) * Set the mask of receiving CPUs for this purpose. */ if (ipi == IPI_STOP_HARD) - CPU_SET_ATOMIC(cpu, &ipi_nmi_pending); + CPU_SET_ATOMIC(cpu, &ipi_stop_nmi_pending); CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, cpu, ipi); ipi_send_cpu(cpu, ipi); @@ -944,7 +944,7 @@ ipi_all_but_self(u_int ipi) * Set the mask of receiving CPUs for this purpose. */ if (ipi == IPI_STOP_HARD) - CPU_OR_ATOMIC(&ipi_nmi_pending, &other_cpus); + CPU_OR_ATOMIC(&ipi_stop_nmi_pending, &other_cpus); CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi); lapic_ipi_vectored(ipi, APIC_IPI_DEST_OTHERS); @@ -962,10 +962,10 @@ ipi_nmi_handler() * and should be handled. */ cpuid = PCPU_GET(cpuid); - if (!CPU_ISSET(cpuid, &ipi_nmi_pending)) + if (!CPU_ISSET(cpuid, &ipi_stop_nmi_pending)) return (1); - CPU_CLR_ATOMIC(cpuid, &ipi_nmi_pending); + CPU_CLR_ATOMIC(cpuid, &ipi_stop_nmi_pending); cpustop_handler(); return (0); } diff --git a/sys/amd64/amd64/stack_machdep.c b/sys/x86/x86/stack_machdep.c index 2412c93..a56d423 100644 --- a/sys/amd64/amd64/stack_machdep.c +++ b/sys/x86/x86/stack_machdep.c @@ -1,4 +1,5 @@ /*- + * Copyright (c) 2015 EMC Corporation * Copyright (c) 2005 Antoine Brodin * All rights reserved. * @@ -29,24 +30,51 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/mutex.h> #include <sys/proc.h> #include <sys/stack.h> #include <machine/pcb.h> -#include <machine/stack.h> +#include <machine/smp.h> #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/pmap.h> +#include <x86/stack.h> + +#ifdef __i386__ +#define PCB_FP(pcb) ((pcb)->pcb_ebp) +#define TF_FP(tf) ((tf)->tf_ebp) +#define TF_PC(tf) ((tf)->tf_eip) + +typedef struct i386_frame *x86_frame_t; +#else +#define PCB_FP(pcb) ((pcb)->pcb_rbp) +#define TF_FP(tf) ((tf)->tf_rbp) +#define TF_PC(tf) ((tf)->tf_rip) + +typedef struct amd64_frame *x86_frame_t; +#endif + +static struct stack *nmi_stack; +static volatile struct thread *nmi_pending; + +#ifdef SMP +static struct mtx nmi_lock; +MTX_SYSINIT(nmi_lock, &nmi_lock, "stack_nmi", MTX_SPIN); +#endif + static void -stack_capture(struct thread *td, struct stack *st, register_t rbp) +stack_capture(struct thread *td, struct stack *st, register_t fp) { - struct amd64_frame *frame; + x86_frame_t frame; vm_offset_t callpc; stack_zero(st); - frame = (struct amd64_frame *)rbp; + frame = (x86_frame_t)fp; while (1) { if (!INKERNEL((long)frame)) break; @@ -63,25 +91,78 @@ stack_capture(struct thread *td, struct stack *st, register_t rbp) } } +int +stack_nmi_handler(struct trapframe *tf) +{ + + /* Don't consume an NMI that wasn't meant for us. */ + if (nmi_stack == NULL || curthread != nmi_pending) + return (0); + + if (INKERNEL(TF_PC(tf))) + stack_capture(curthread, nmi_stack, TF_FP(tf)); + else + /* We interrupted a thread in user mode. */ + nmi_stack->depth = 0; + + atomic_store_rel_ptr((long *)&nmi_pending, (long)NULL); + return (1); +} + void stack_save_td(struct stack *st, struct thread *td) { - register_t rbp; if (TD_IS_SWAPPED(td)) panic("stack_save_td: swapped"); if (TD_IS_RUNNING(td)) panic("stack_save_td: running"); - rbp = td->td_pcb->pcb_rbp; - stack_capture(td, st, rbp); + stack_capture(td, st, PCB_FP(td->td_pcb)); +} + +int +stack_save_td_running(struct stack *st, struct thread *td) +{ + + THREAD_LOCK_ASSERT(td, MA_OWNED); + MPASS(TD_IS_RUNNING(td)); + + if (td == curthread) { + stack_save(st); + return (0); + } + +#ifdef SMP + mtx_lock_spin(&nmi_lock); + + nmi_stack = st; + nmi_pending = td; + ipi_cpu(td->td_oncpu, IPI_TRACE); + while ((void *)atomic_load_acq_ptr((long *)&nmi_pending) != NULL) + cpu_spinwait(); + nmi_stack = NULL; + + mtx_unlock_spin(&nmi_lock); + + if (st->depth == 0) + /* We interrupted a thread in user mode. */ + return (EAGAIN); +#else + KASSERT(0, ("curthread isn't running")); +#endif + return (0); } void stack_save(struct stack *st) { - register_t rbp; + register_t fp; - __asm __volatile("movq %%rbp,%0" : "=r" (rbp)); - stack_capture(curthread, st, rbp); +#ifdef __i386__ + __asm __volatile("movl %%ebp,%0" : "=g" (fp)); +#else + __asm __volatile("movq %%rbp,%0" : "=g" (fp)); +#endif + stack_capture(curthread, st, fp); } diff --git a/tests/sys/kern/ptrace_test.c b/tests/sys/kern/ptrace_test.c index c10c097..33878a4 100644 --- a/tests/sys/kern/ptrace_test.c +++ b/tests/sys/kern/ptrace_test.c @@ -127,7 +127,7 @@ ATF_TC_BODY(ptrace__parent_wait_after_trace_me, tc) /* Child process. */ trace_me(); - exit(1); + _exit(1); } /* Parent process. */ @@ -173,7 +173,7 @@ ATF_TC_BODY(ptrace__parent_wait_after_attach, tc) /* Wait for the parent to attach. */ CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == 0); - exit(1); + _exit(1); } close(cpipe[1]); @@ -221,7 +221,7 @@ ATF_TC_BODY(ptrace__parent_sees_exit_after_child_debugger, tc) /* Wait for parent to be ready. */ CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c)); - exit(1); + _exit(1); } close(cpipe[1]); @@ -252,7 +252,7 @@ ATF_TC_BODY(ptrace__parent_sees_exit_after_child_debugger, tc) CHILD_REQUIRE(WIFEXITED(status)); CHILD_REQUIRE(WEXITSTATUS(status) == 1); - exit(0); + _exit(0); } close(dpipe[1]); @@ -315,7 +315,7 @@ ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc) /* Wait for parent to be ready. */ CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c)); - exit(1); + _exit(1); } close(cpipe[1]); @@ -331,7 +331,7 @@ ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc) */ CHILD_REQUIRE((fpid = fork()) != -1); if (fpid != 0) - exit(2); + _exit(2); /* Debugger process. */ close(dpipe[0]); @@ -356,7 +356,7 @@ ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc) CHILD_REQUIRE(WIFEXITED(status)); CHILD_REQUIRE(WEXITSTATUS(status) == 1); - exit(0); + _exit(0); } close(dpipe[1]); @@ -418,14 +418,14 @@ follow_fork_parent(void) if (fpid == 0) /* Child */ - exit(2); + _exit(2); wpid = waitpid(fpid, &status, 0); CHILD_REQUIRE(wpid == fpid); CHILD_REQUIRE(WIFEXITED(status)); CHILD_REQUIRE(WEXITSTATUS(status) == 2); - exit(1); + _exit(1); } /* @@ -493,7 +493,7 @@ handle_fork_events(pid_t parent) ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_both_attached); ATF_TC_BODY(ptrace__follow_fork_both_attached, tc) { - pid_t children[0], fpid, wpid; + pid_t children[2], fpid, wpid; int status; ATF_REQUIRE((fpid = fork()) != -1); @@ -549,7 +549,7 @@ ATF_TC_BODY(ptrace__follow_fork_both_attached, tc) ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_child_detached); ATF_TC_BODY(ptrace__follow_fork_child_detached, tc) { - pid_t children[0], fpid, wpid; + pid_t children[2], fpid, wpid; int status; ATF_REQUIRE((fpid = fork()) != -1); @@ -600,7 +600,7 @@ ATF_TC_BODY(ptrace__follow_fork_child_detached, tc) ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_parent_detached); ATF_TC_BODY(ptrace__follow_fork_parent_detached, tc) { - pid_t children[0], fpid, wpid; + pid_t children[2], fpid, wpid; int status; ATF_REQUIRE((fpid = fork()) != -1); @@ -662,7 +662,7 @@ attach_fork_parent(int cpipe[2]) /* Double-fork to disassociate from the debugger. */ CHILD_REQUIRE((fpid = fork()) != -1); if (fpid != 0) - exit(3); + _exit(3); /* Send the pid of the disassociated child to the debugger. */ fpid = getpid(); @@ -681,7 +681,7 @@ attach_fork_parent(int cpipe[2]) ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_both_attached_unrelated_debugger); ATF_TC_BODY(ptrace__follow_fork_both_attached_unrelated_debugger, tc) { - pid_t children[0], fpid, wpid; + pid_t children[2], fpid, wpid; int cpipe[2], status; ATF_REQUIRE(pipe(cpipe) == 0); @@ -749,7 +749,7 @@ ATF_TC_BODY(ptrace__follow_fork_both_attached_unrelated_debugger, tc) ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_child_detached_unrelated_debugger); ATF_TC_BODY(ptrace__follow_fork_child_detached_unrelated_debugger, tc) { - pid_t children[0], fpid, wpid; + pid_t children[2], fpid, wpid; int cpipe[2], status; ATF_REQUIRE(pipe(cpipe) == 0); @@ -812,7 +812,7 @@ ATF_TC_BODY(ptrace__follow_fork_child_detached_unrelated_debugger, tc) ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_parent_detached_unrelated_debugger); ATF_TC_BODY(ptrace__follow_fork_parent_detached_unrelated_debugger, tc) { - pid_t children[0], fpid, wpid; + pid_t children[2], fpid, wpid; int cpipe[2], status; ATF_REQUIRE(pipe(cpipe) == 0); @@ -866,6 +866,92 @@ ATF_TC_BODY(ptrace__follow_fork_parent_detached_unrelated_debugger, tc) ATF_REQUIRE(errno == ECHILD); } +/* + * Verify that a child process does not see an unrelated debugger as its + * parent but sees its original parent process. + */ +ATF_TC_WITHOUT_HEAD(ptrace__getppid); +ATF_TC_BODY(ptrace__getppid, tc) +{ + pid_t child, debugger, ppid, wpid; + int cpipe[2], dpipe[2], status; + char c; + + ATF_REQUIRE(pipe(cpipe) == 0); + ATF_REQUIRE((child = fork()) != -1); + + if (child == 0) { + /* Child process. */ + close(cpipe[0]); + + /* Wait for parent to be ready. */ + CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c)); + + /* Report the parent PID to the parent. */ + ppid = getppid(); + CHILD_REQUIRE(write(cpipe[1], &ppid, sizeof(ppid)) == + sizeof(ppid)); + + _exit(1); + } + close(cpipe[1]); + + ATF_REQUIRE(pipe(dpipe) == 0); + ATF_REQUIRE((debugger = fork()) != -1); + + if (debugger == 0) { + /* Debugger process. */ + close(dpipe[0]); + + CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1); + + wpid = waitpid(child, &status, 0); + CHILD_REQUIRE(wpid == child); + CHILD_REQUIRE(WIFSTOPPED(status)); + CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP); + + CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); + + /* Signal parent that debugger is attached. */ + CHILD_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c)); + + /* Wait for traced child to exit. */ + wpid = waitpid(child, &status, 0); + CHILD_REQUIRE(wpid == child); + CHILD_REQUIRE(WIFEXITED(status)); + CHILD_REQUIRE(WEXITSTATUS(status) == 1); + + _exit(0); + } + close(dpipe[1]); + + /* Parent process. */ + + /* Wait for the debugger to attach to the child. */ + ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c)); + + /* Release the child. */ + ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c)); + + /* Read the parent PID from the child. */ + ATF_REQUIRE(read(cpipe[0], &ppid, sizeof(ppid)) == sizeof(ppid)); + close(cpipe[0]); + + ATF_REQUIRE(ppid == getpid()); + + /* Wait for the debugger. */ + wpid = waitpid(debugger, &status, 0); + ATF_REQUIRE(wpid == debugger); + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE(WEXITSTATUS(status) == 0); + + /* The child process should now be ready. */ + wpid = waitpid(child, &status, WNOHANG); + ATF_REQUIRE(wpid == child); + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE(WEXITSTATUS(status) == 1); +} + ATF_TP_ADD_TCS(tp) { @@ -881,6 +967,7 @@ ATF_TP_ADD_TCS(tp) ptrace__follow_fork_child_detached_unrelated_debugger); ATF_TP_ADD_TC(tp, ptrace__follow_fork_parent_detached_unrelated_debugger); + ATF_TP_ADD_TC(tp, ptrace__getppid); return (atf_no_error()); } diff --git a/usr.bin/login/login.c b/usr.bin/login/login.c index d1d9bbe..525ccfc 100644 --- a/usr.bin/login/login.c +++ b/usr.bin/login/login.c @@ -63,7 +63,6 @@ __FBSDID("$FreeBSD$"); #include <err.h> #include <errno.h> #include <grp.h> -#include <libutil.h> #include <login_cap.h> #include <pwd.h> #include <setjmp.h> diff --git a/usr.bin/login/login_fbtab.c b/usr.bin/login/login_fbtab.c index f642ea7..8faee56 100644 --- a/usr.bin/login/login_fbtab.c +++ b/usr.bin/login/login_fbtab.c @@ -65,7 +65,6 @@ __FBSDID("$FreeBSD$"); #include <sys/stat.h> #include <errno.h> #include <glob.h> -#include <paths.h> #include <stdio.h> #include <string.h> #include <syslog.h> @@ -120,7 +119,7 @@ login_fbtab(char *tty, uid_t uid, gid_t gid) /* login_protect - protect one device entry */ -void +static void login_protect(const char *table, char *pattern, int mask, uid_t uid, gid_t gid) { glob_t gl; diff --git a/usr.bin/netstat/flowtable.c b/usr.bin/netstat/flowtable.c index a232d80..c00dfd6 100644 --- a/usr.bin/netstat/flowtable.c +++ b/usr.bin/netstat/flowtable.c @@ -28,13 +28,15 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); + #include <sys/param.h> -#include <sys/sysctl.h> + #include <net/flowtable.h> -#include <err.h> + #include <stdint.h> #include <stdio.h> #include <stdbool.h> + #include "netstat.h" /* @@ -68,17 +70,18 @@ void flowtable_stats(void) { struct flowtable_stat stat; - size_t len = sizeof(stat); if (!live) return; - if (sysctlbyname("net.flowtable.ip4.stat", &stat, &len, NULL, 0) == 0) { + if (fetch_stats("net.flowtable.ip4.stat", 0, &stat, + sizeof(stat), NULL) == 0) { printf("flowtable for IPv4:\n"); print_stats(&stat); } - if (sysctlbyname("net.flowtable.ip6.stat", &stat, &len, NULL, 0) == 0) { + if (fetch_stats("net.flowtable.ip6.stat", 0, &stat, + sizeof(stat), NULL) == 0) { printf("flowtable for IPv6:\n"); print_stats(&stat); } diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c index e98b011..96606c4 100644 --- a/usr.bin/netstat/if.c +++ b/usr.bin/netstat/if.c @@ -41,7 +41,6 @@ __FBSDID("$FreeBSD$"); #include <sys/protosw.h> #include <sys/socket.h> #include <sys/socketvar.h> -#include <sys/sysctl.h> #include <sys/time.h> #include <net/if.h> @@ -134,20 +133,11 @@ pfsync_acts_stats(const char *list, const char *desc, uint64_t *a) void pfsync_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { - struct pfsyncstats pfsyncstat, zerostat; - size_t len = sizeof(struct pfsyncstats); - - if (live) { - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.pfsync.stats", &pfsyncstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - if (errno != ENOENT) - warn("sysctl: net.pfsync.stats"); - return; - } - } else - kread(off, &pfsyncstat, len); + struct pfsyncstats pfsyncstat; + + if (fetch_stats("net.pfsync.stats", off, &pfsyncstat, + sizeof(pfsyncstat), kread) != 0) + return; xo_emit("{T:/%s}:\n", name); xo_open_container(name); diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c index 4c3675a..5644af3 100644 --- a/usr.bin/netstat/inet.c +++ b/usr.bin/netstat/inet.c @@ -627,8 +627,7 @@ protopr(u_long off, const char *name, int af1, int proto) void tcp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { - struct tcpstat tcpstat, zerostat; - size_t len = sizeof tcpstat; + struct tcpstat tcpstat; #ifdef INET6 if (tcp_done != 0) @@ -637,16 +636,9 @@ tcp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) tcp_done = 1; #endif - if (live) { - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - xo_warn("sysctl: net.inet.tcp.stats"); - return; - } - } else - kread_counters(off, &tcpstat, len); + if (fetch_stats("net.inet.tcp.stats", off, &tcpstat, + sizeof(tcpstat), kread_counters) != 0) + return; xo_open_container("tcp"); xo_emit("{T:/%s}:\n", name); @@ -860,8 +852,7 @@ tcp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) void udp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { - struct udpstat udpstat, zerostat; - size_t len = sizeof udpstat; + struct udpstat udpstat; uint64_t delivered; #ifdef INET6 @@ -871,16 +862,9 @@ udp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) udp_done = 1; #endif - if (live) { - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - xo_warn("sysctl: net.inet.udp.stats"); - return; - } - } else - kread_counters(off, &udpstat, len); + if (fetch_stats("net.inet.udp.stats", off, &udpstat, + sizeof(udpstat), kread_counters) != 0) + return; xo_open_container("udp"); xo_emit("{T:/%s}:\n", name); @@ -933,23 +917,11 @@ udp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) void carp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { - struct carpstats carpstat, zerostat; - size_t len = sizeof(struct carpstats); + struct carpstats carpstat; - if (live) { - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.carp.stats", &carpstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - if (errno != ENOENT) - xo_warn("sysctl: net.inet.carp.stats"); - return; - } - } else { - if (off == 0) - return; - kread_counters(off, &carpstat, len); - } + if (fetch_stats("net.inet.carp.stats", off, &carpstat, + sizeof(carpstat), kread_counters) != 0) + return; xo_open_container(name); xo_emit("{T:/%s}:\n", name); @@ -1000,19 +972,11 @@ carp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) void ip_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { - struct ipstat ipstat, zerostat; - size_t len = sizeof ipstat; + struct ipstat ipstat; - if (live) { - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.ip.stats", &ipstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - xo_warn("sysctl: net.inet.ip.stats"); - return; - } - } else - kread_counters(off, &ipstat, len); + if (fetch_stats("net.inet.ip.stats", off, &ipstat, + sizeof(ipstat), kread_counters) != 0) + return; xo_open_container(name); xo_emit("{T:/%s}:\n", name); @@ -1093,19 +1057,11 @@ ip_stats(u_long off, const char *name, int af1 __unused, int proto __unused) void arp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { - struct arpstat arpstat, zerostat; - size_t len = sizeof(arpstat); + struct arpstat arpstat; - if (live) { - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - xo_warn("sysctl: net.link.ether.arp.stats"); - return; - } - } else - kread_counters(off, &arpstat, len); + if (fetch_stats("net.link.ether.arp.stats", off, &arpstat, + sizeof(arpstat), kread_counters) != 0) + return; xo_open_container(name); xo_emit("{T:/%s}:\n", name); @@ -1186,21 +1142,13 @@ static const char *icmpnames[ICMP_MAXTYPE + 1] = { void icmp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { - struct icmpstat icmpstat, zerostat; - int i, first; + struct icmpstat icmpstat; size_t len; + int i, first; - len = sizeof icmpstat; - if (live) { - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.icmp.stats", &icmpstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - xo_warn("sysctl: net.inet.icmp.stats"); - return; - } - } else - kread_counters(off, &icmpstat, len); + if (fetch_stats("net.inet.icmp.stats", off, &icmpstat, + sizeof(icmpstat), kread_counters) != 0) + return; xo_open_container(name); xo_emit("{T:/%s}:\n", name); @@ -1300,22 +1248,11 @@ icmp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) void igmp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { - struct igmpstat igmpstat, zerostat; - size_t len; + struct igmpstat igmpstat; - len = sizeof(igmpstat); - if (live) { - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - xo_warn("sysctl: net.inet.igmp.stats"); - return; - } - } else { - len = sizeof(igmpstat); - kread(off, &igmpstat, len); - } + if (fetch_stats("net.inet.igmp.stats", 0, &igmpstat, + sizeof(igmpstat), kread) != 0) + return; if (igmpstat.igps_version != IGPS_VERSION_3) { xo_warnx("%s: version mismatch (%d != %d)", __func__, @@ -1380,23 +1317,11 @@ void pim_stats(u_long off __unused, const char *name, int af1 __unused, int proto __unused) { - struct pimstat pimstat, zerostat; - size_t len = sizeof pimstat; + struct pimstat pimstat; - if (live) { - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.pim.stats", &pimstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - if (errno != ENOENT) - xo_warn("sysctl: net.inet.pim.stats"); - return; - } - } else { - if (off == 0) - return; - kread_counters(off, &pimstat, len); - } + if (fetch_stats("net.inet.pim.stats", off, &pimstat, + sizeof(pimstat), kread_counters) != 0) + return; xo_open_container(name); xo_emit("{T:/%s}:\n", name); diff --git a/usr.bin/netstat/inet6.c b/usr.bin/netstat/inet6.c index 6cdc46b..094d25b 100644 --- a/usr.bin/netstat/inet6.c +++ b/usr.bin/netstat/inet6.c @@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$"); #include <sys/ioctl.h> #include <sys/mbuf.h> #include <sys/protosw.h> -#include <sys/sysctl.h> #include <net/route.h> #include <net/if.h> @@ -359,23 +358,13 @@ static const char *srcrule_str[] = { void ip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { - struct ip6stat ip6stat, zerostat; + struct ip6stat ip6stat; int first, i; - size_t len; - - len = sizeof ip6stat; - if (live) { - memset(&ip6stat, 0, len); - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet6.ip6.stats", &ip6stat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - if (errno != ENOENT) - xo_warn("sysctl: net.inet6.ip6.stats"); - return; - } - } else - kread_counters(off, &ip6stat, len); + + if (fetch_stats("net.inet6.ip6.stats", off, &ip6stat, + sizeof(ip6stat), kread_counters) != 0) + return; + xo_open_container(name); xo_emit("{T:/%s}:\n", name); @@ -956,23 +945,12 @@ static const char *icmp6names[] = { void icmp6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { - struct icmp6stat icmp6stat, zerostat; + struct icmp6stat icmp6stat; int i, first; - size_t len; - - len = sizeof icmp6stat; - if (live) { - memset(&icmp6stat, 0, len); - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet6.icmp6.stats", &icmp6stat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - if (errno != ENOENT) - xo_warn("sysctl: net.inet6.icmp6.stats"); - return; - } - } else - kread_counters(off, &icmp6stat, len); + + if (fetch_stats("net.inet6.icmp6.stats", off, &icmp6stat, + sizeof(icmp6stat), kread_counters) != 0) + return; xo_emit("{T:/%s}:\n", name); xo_open_container(name); @@ -1196,23 +1174,11 @@ end: void pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { - struct pim6stat pim6stat, zerostat; - size_t len = sizeof pim6stat; - - if (live) { - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet6.pim.stats", &pim6stat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - if (errno != ENOENT) - xo_warn("sysctl: net.inet6.pim.stats"); - return; - } - } else { - if (off == 0) - return; - kread(off, &pim6stat, len); - } + struct pim6stat pim6stat; + + if (fetch_stats("net.inet6.pim.stats", off, &pim6stat, + sizeof(pim6stat), kread) != 0) + return; xo_emit("{T:/%s}:\n", name); xo_open_container(name); @@ -1244,22 +1210,12 @@ pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) void rip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { - struct rip6stat rip6stat, zerostat; + struct rip6stat rip6stat; u_quad_t delivered; - size_t len; - - len = sizeof(rip6stat); - if (live) { - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet6.ip6.rip6stats", &rip6stat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - if (errno != ENOENT) - xo_warn("sysctl: net.inet6.ip6.rip6stats"); - return; - } - } else - kread_counters(off, &rip6stat, len); + + if (fetch_stats("net.inet6.ip6.rip6stats", off, &rip6stat, + sizeof(rip6stat), kread_counters) != 0) + return; xo_emit("{T:/%s}:\n", name); xo_open_container(name); diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c index c364543..af532a6 100644 --- a/usr.bin/netstat/main.c +++ b/usr.bin/netstat/main.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <sys/protosw.h> #include <sys/socket.h> #include <sys/socketvar.h> +#include <sys/sysctl.h> #include <netinet/in.h> @@ -548,6 +549,29 @@ main(int argc, char *argv[]) exit(0); } +int +fetch_stats(const char *sysctlname, u_long off, void *stats, size_t len, + int (*kreadfn)(u_long, void *, size_t)) +{ + int error; + + if (live) { + memset(stats, 0, len); + if (zflag) + error = sysctlbyname(sysctlname, NULL, NULL, stats, + len); + else + error = sysctlbyname(sysctlname, stats, &len, NULL, 0); + if (error == -1 && errno != ENOENT) + xo_warn("sysctl %s", sysctlname); + } else { + if (off == 0) + return (1); + error = kreadfn(off, stats, len); + } + return (error); +} + /* * Print out protocol statistics or control blocks (per sflag). * If the interface was not specifically requested, and the symbol diff --git a/usr.bin/netstat/mbuf.c b/usr.bin/netstat/mbuf.c index 26b7095..baf7a65 100644 --- a/usr.bin/netstat/mbuf.c +++ b/usr.bin/netstat/mbuf.c @@ -310,27 +310,22 @@ mbpr(void *kvmd, u_long mbaddr) jumbop_failures, jumbo9_failures, jumbo16_failures, jumbop_size / 1024); - if (live) { - mlen = sizeof(nsfbufs); - if (!sysctlbyname("kern.ipc.nsfbufs", &nsfbufs, &mlen, NULL, - 0) && - !sysctlbyname("kern.ipc.nsfbufsused", &nsfbufsused, - &mlen, NULL, 0) && - !sysctlbyname("kern.ipc.nsfbufspeak", &nsfbufspeak, - &mlen, NULL, 0)) - xo_emit("{:nsfbufs-current/%d}/{:nsfbufs-peak/%d}/" - "{:nsfbufs/%d} " - "{N:sfbufs in use (current\\/peak\\/max)}\n", - nsfbufsused, nsfbufspeak, nsfbufs); - mlen = sizeof(sfstat); - if (sysctlbyname("kern.ipc.sfstat", &sfstat, &mlen, NULL, 0)) { - xo_warn("kern.ipc.sfstat"); - goto out; - } - } else { - if (kread_counters(mbaddr, (char *)&sfstat, sizeof sfstat) != 0) - goto out; - } + mlen = sizeof(nsfbufs); + if (live && + sysctlbyname("kern.ipc.nsfbufs", &nsfbufs, &mlen, NULL, 0) == 0 && + sysctlbyname("kern.ipc.nsfbufsused", &nsfbufsused, &mlen, + NULL, 0) == 0 && + sysctlbyname("kern.ipc.nsfbufspeak", &nsfbufspeak, &mlen, + NULL, 0) == 0) + xo_emit("{:nsfbufs-current/%d}/{:nsfbufs-peak/%d}/" + "{:nsfbufs/%d} " + "{N:sfbufs in use (current\\/peak\\/max)}\n", + nsfbufsused, nsfbufspeak, nsfbufs); + + if (fetch_stats("kern.ipc.sfstat", mbaddr, &sfstat, sizeof(sfstat), + kread_counters) != 0) + goto out; + xo_emit("{:sfbufs-alloc-failed/%ju} {N:requests for sfbufs denied}\n", (uintmax_t)sfstat.sf_allocfail); xo_emit("{:sfbufs-alloc-wait/%ju} {N:requests for sfbufs delayed}\n", diff --git a/usr.bin/netstat/mroute.c b/usr.bin/netstat/mroute.c index 93b640c..975473e 100644 --- a/usr.bin/netstat/mroute.c +++ b/usr.bin/netstat/mroute.c @@ -400,7 +400,6 @@ mrt_stats() { struct mrtstat mrtstat; u_long mstaddr; - size_t len = sizeof(mrtstat); mstaddr = nl[N_MRTSTAT].n_value; @@ -409,14 +408,9 @@ mrt_stats() return; } - if (live) { - if (sysctlbyname("net.inet.ip.mrtstat", &mrtstat, &len, NULL, - 0) < 0) { - xo_warn("sysctl: net.inet.ip.mrtstat failed."); - return; - } - } else - kread_counters(mstaddr, &mrtstat, len); + if (fetch_stats("net.inet.ip.mrtstat", mstaddr, &mrtstat, + sizeof(mrtstat), kread_counters) != 0) + return; xo_emit("{T:IPv4 multicast forwarding}:\n"); diff --git a/usr.bin/netstat/mroute6.c b/usr.bin/netstat/mroute6.c index 668add4..8f59c6b 100644 --- a/usr.bin/netstat/mroute6.c +++ b/usr.bin/netstat/mroute6.c @@ -231,13 +231,10 @@ void mrt6_stats() { struct mrt6stat mrtstat; - size_t len = sizeof mrtstat; - if (sysctlbyname("net.inet6.ip6.mrt6stat", &mrtstat, &len, NULL, 0) < - 0) { - xo_warn("sysctl: net.inet6.ip6.mrt6stat"); + if (fetch_stats("net.inet6.ip6.mrt6stat", 0, &mrtstat, + sizeof(mrtstat), kread_counters) != 0) return; - } xo_open_container("multicast-statistics"); xo_emit("{T:IPv6 multicast forwarding}:\n"); diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h index ca6da29..776c4d4 100644 --- a/usr.bin/netstat/netstat.h +++ b/usr.bin/netstat/netstat.h @@ -63,6 +63,8 @@ extern int unit; /* unit number for above */ extern int live; /* true if we are examining a live system */ +int fetch_stats(const char *sysctlname, u_long addr, void *stats, + size_t len, int (*kreadfn)(u_long, void *, size_t)); int kread(u_long addr, void *buf, size_t size); uint64_t kread_counter(u_long addr); int kread_counters(u_long addr, void *buf, size_t size); @@ -131,29 +133,14 @@ void flowtable_stats(void); char *routename(struct sockaddr *, int); const char *netname(struct sockaddr *, struct sockaddr *); -char *ns_print(struct sockaddr *); void routepr(int, int); -void nsprotopr(u_long, const char *, int, int); -void spp_stats(u_long, const char *, int, int); -void idp_stats(u_long, const char *, int, int); -void nserr_stats(u_long, const char *, int, int); - #ifdef NETGRAPH void netgraphprotopr(u_long, const char *, int, int); #endif void unixpr(u_long, u_long, u_long, u_long, u_long, bool *); -void esis_stats(u_long, const char *, int, int); -void clnp_stats(u_long, const char *, int, int); -void cltp_stats(u_long, const char *, int, int); -void iso_protopr(u_long, const char *, int, int); -void iso_protopr1(u_long, int); -void tp_protopr(u_long, const char *, int, int); -void tp_inproto(u_long); -void tp_stats(caddr_t, caddr_t); - void mroutepr(void); void mrt_stats(void); void bpf_stats(char *); diff --git a/usr.bin/netstat/sctp.c b/usr.bin/netstat/sctp.c index f721a96..5f609a0 100644 --- a/usr.bin/netstat/sctp.c +++ b/usr.bin/netstat/sctp.c @@ -658,20 +658,11 @@ sctp_statesprint(uint32_t state) void sctp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { - struct sctpstat sctpstat, zerostat; - size_t len = sizeof(sctpstat); - - if (live) { - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.sctp.stats", &sctpstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - if (errno != ENOENT) - xo_warn("sysctl: net.inet.sctp.stats"); - return; - } - } else - kread(off, &sctpstat, len); + struct sctpstat sctpstat; + + if (fetch_stats("net.inet.sctp.stats", off, &sctpstat, + sizeof(sctpstat), kread) != 0) + return; xo_open_container(name); xo_emit("{T:/%s}:\n", name); diff --git a/usr.bin/systat/iostat.c b/usr.bin/systat/iostat.c index 3384f15..fa275eb 100644 --- a/usr.bin/systat/iostat.c +++ b/usr.bin/systat/iostat.c @@ -112,10 +112,8 @@ initiostat(void) if ((num_devices = devstat_getnumdevs(NULL)) < 0) return(0); - cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); - last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); - bzero(cur.dinfo, sizeof(struct devinfo)); - bzero(last.dinfo, sizeof(struct devinfo)); + cur.dinfo = calloc(1, sizeof(struct devinfo)); + last.dinfo = calloc(1, sizeof(struct devinfo)); /* * This value for maxshowdevs (100) is bogus. I'm not sure exactly @@ -196,7 +194,7 @@ numlabels(int row) char tmpstr[10]; #define COLWIDTH 17 -#define DRIVESPERLINE ((wnd->_maxx - INSET) / COLWIDTH) +#define DRIVESPERLINE ((getmaxx(wnd) - 1 - INSET) / COLWIDTH) for (ndrives = 0, i = 0; i < num_devices; i++) if (dev_select[i].selected) ndrives++; @@ -204,7 +202,7 @@ numlabels(int row) /* * Deduct -regions for blank line after each scrolling region. */ - linesperregion = (wnd->_maxy - row - regions) / regions; + linesperregion = (getmaxy(wnd) - 1 - row - regions) / regions; /* * Minimum region contains space for two * label lines and one line of statistics. @@ -214,9 +212,9 @@ numlabels(int row) _col = INSET; for (i = 0; i < num_devices; i++) if (dev_select[i].selected) { - if (_col + COLWIDTH >= wnd->_maxx - INSET) { + if (_col + COLWIDTH >= getmaxx(wnd) - 1 - INSET) { _col = INSET, row += linesperregion + 1; - if (row > wnd->_maxy - (linesperregion + 1)) + if (row > getmaxy(wnd) - 1 - (linesperregion + 1)) break; } sprintf(tmpstr, "%s%d", dev_select[i].device_name, @@ -241,7 +239,7 @@ barlabels(int row) linesperregion = 2 + kbpt; for (i = 0; i < num_devices; i++) if (dev_select[i].selected) { - if (row > wnd->_maxy - linesperregion) + if (row > getmaxy(wnd) - 1 - linesperregion) break; sprintf(tmpstr, "%s%d", dev_select[i].device_name, dev_select[i].unit_number); @@ -276,7 +274,7 @@ showiostat(void) row += 2; for (i = 0; i < num_devices; i++) if (dev_select[i].selected) { - if (row > wnd->_maxy - linesperregion) + if (row > getmaxy(wnd) - linesperregion) break; row = devstats(row, INSET, i); } @@ -289,9 +287,9 @@ showiostat(void) winsertln(wnd); for (i = 0; i < num_devices; i++) if (dev_select[i].selected) { - if (_col + COLWIDTH >= wnd->_maxx - INSET) { + if (_col + COLWIDTH >= getmaxx(wnd) - 1 - INSET) { _col = INSET, row += linesperregion + 1; - if (row > wnd->_maxy - (linesperregion + 1)) + if (row > getmaxy(wnd) - 1 - (linesperregion + 1)) break; wmove(wnd, row + linesperregion, 0); wdeleteln(wnd); diff --git a/usr.bin/systat/netstat.c b/usr.bin/systat/netstat.c index b5938eb..3f994e8 100644 --- a/usr.bin/systat/netstat.c +++ b/usr.bin/systat/netstat.c @@ -85,7 +85,7 @@ static char *inetname(struct sockaddr *); static void inetprint(struct sockaddr *, const char *); #define streq(a,b) (strcmp(a,b)==0) -#define YMAX(w) ((w)->_maxy-1) +#define YMAX(w) (getmaxy(w)-2) WINDOW * opennetstat(void) diff --git a/usr.bin/systat/pigs.c b/usr.bin/systat/pigs.c index a02a43f..d341f7d 100644 --- a/usr.bin/systat/pigs.c +++ b/usr.bin/systat/pigs.c @@ -94,8 +94,8 @@ showpigs(void) qsort(pt, nproc, sizeof (struct p_times), compar); y = 1; i = nproc; - if (i > wnd->_maxy-1) - i = wnd->_maxy-1; + if (i > getmaxy(wnd)-2) + i = getmaxy(wnd)-2; for (k = 0; i > 0 && pt[k].pt_pctcpu > 0.01; i--, y++, k++) { uname = user_from_uid(pt[k].pt_kp->ki_uid, 0); pname = pt[k].pt_kp->ki_comm; diff --git a/usr.bin/systat/vmstat.c b/usr.bin/systat/vmstat.c index cdb26a7..258e357 100644 --- a/usr.bin/systat/vmstat.c +++ b/usr.bin/systat/vmstat.c @@ -205,12 +205,9 @@ initkre(void) return(0); } - cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); - last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); - run.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); - bzero(cur.dinfo, sizeof(struct devinfo)); - bzero(last.dinfo, sizeof(struct devinfo)); - bzero(run.dinfo, sizeof(struct devinfo)); + cur.dinfo = calloc(1, sizeof(struct devinfo)); + last.dinfo = calloc(1, sizeof(struct devinfo)); + run.dinfo = calloc(1, sizeof(struct devinfo)); if (dsinit(MAXDRIVES, &cur, &last, &run) != 1) return(0); diff --git a/usr.bin/vmstat/vmstat.c b/usr.bin/vmstat/vmstat.c index 0a3054a..4d0224d 100644 --- a/usr.bin/vmstat/vmstat.c +++ b/usr.bin/vmstat/vmstat.c @@ -556,8 +556,6 @@ fill_vmmeter(struct vmmeter *vmmp) GET_VM_STATS(vm, v_inactive_target); GET_VM_STATS(vm, v_inactive_count); GET_VM_STATS(vm, v_cache_count); - GET_VM_STATS(vm, v_cache_min); - GET_VM_STATS(vm, v_cache_max); GET_VM_STATS(vm, v_pageout_free_min); GET_VM_STATS(vm, v_interrupt_free_min); /*GET_VM_STATS(vm, v_free_severe);*/ diff --git a/usr.bin/w/Makefile b/usr.bin/w/Makefile index 0bd09ff..c14f84a 100644 --- a/usr.bin/w/Makefile +++ b/usr.bin/w/Makefile @@ -5,8 +5,6 @@ PROG= w SRCS= fmt.c pr_time.c proc_compare.c w.c MAN= w.1 uptime.1 LIBADD= kvm sbuf xo util -#BINGRP= kmem -#BINMODE=2555 LINKS= ${BINDIR}/w ${BINDIR}/uptime .PATH: ${.CURDIR}/../../bin/ps diff --git a/usr.bin/w/w.c b/usr.bin/w/w.c index 4df4abd..0c955ac 100644 --- a/usr.bin/w/w.c +++ b/usr.bin/w/w.c @@ -135,7 +135,7 @@ main(int argc, char *argv[]) struct kinfo_proc *dkp; struct stat *stp; time_t touched; - int ch, i, nentries, nusers, wcmd, longidle, longattime, dropgid; + int ch, i, nentries, nusers, wcmd, longidle, longattime; const char *memf, *nlistf, *p, *save_p; char *x_suffix; char buf[MAXHOSTNAMELEN], errbuf[_POSIX2_LINE_MAX]; @@ -159,7 +159,6 @@ main(int argc, char *argv[]) p = "dhiflM:N:nsuw"; } - dropgid = 0; memf = _PATH_DEVNULL; nlistf = NULL; while ((ch = getopt(argc, argv, p)) != -1) @@ -176,11 +175,9 @@ main(int argc, char *argv[]) case 'M': header = 0; memf = optarg; - dropgid = 1; break; case 'N': nlistf = optarg; - dropgid = 1; break; case 'n': nflag = 1; @@ -200,13 +197,6 @@ main(int argc, char *argv[]) _res.retrans = 2; /* resolver timeout to 2 seconds per try */ _res.retry = 1; /* only try once.. */ - /* - * Discard setgid privileges if not the running kernel so that bad - * guys can't print interesting stuff from kernel memory. - */ - if (dropgid) - setgid(getgid()); - if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL) errx(1, "%s", errbuf); diff --git a/usr.sbin/bluetooth/hccontrol/le.c b/usr.sbin/bluetooth/hccontrol/le.c index afb151e..c7be20d 100644 --- a/usr.sbin/bluetooth/hccontrol/le.c +++ b/usr.sbin/bluetooth/hccontrol/le.c @@ -88,7 +88,7 @@ le_set_scan_param(int s, int argc, char *argv[]) if (strcmp(argv[3], "public") == 0) adrtype = 0; - else if (strcmp(argv[0], "random") == 0) + else if (strcmp(argv[3], "random") == 0) adrtype = 1; else return USAGE; diff --git a/usr.sbin/ctladm/ctladm.8 b/usr.sbin/ctladm/ctladm.8 index cc1fc1f..deb6763 100644 --- a/usr.sbin/ctladm/ctladm.8 +++ b/usr.sbin/ctladm/ctladm.8 @@ -34,7 +34,7 @@ .\" $Id: //depot/users/kenm/FreeBSD-test2/usr.sbin/ctladm/ctladm.8#3 $ .\" $FreeBSD$ .\" -.Dd September 6, 2015 +.Dd September 10, 2015 .Dt CTLADM 8 .Os .Sh NAME @@ -43,28 +43,28 @@ .Sh SYNOPSIS .Nm .Aq Ar command -.Op target:lun +.Op lun .Op generic args .Op command args .Nm .Ic tur -.Aq target:lun +.Aq lun .Op general options .Nm .Ic inquiry -.Aq target:lun +.Aq lun .Op general options .Nm .Ic reqsense -.Aq target:lun +.Aq lun .Op general options .Nm .Ic reportluns -.Aq target:lun +.Aq lun .Op general options .Nm .Ic read -.Aq target:lun +.Aq lun .Op general options .Aq Fl l Ar lba .Aq Fl d Ar datalen @@ -74,7 +74,7 @@ .Op Fl N .Nm .Ic write -.Aq target:lun +.Aq lun .Op general options .Aq Fl l Ar lba .Aq Fl d Ar datalen @@ -84,12 +84,12 @@ .Op Fl N .Nm .Ic readcap -.Aq target:lun +.Aq lun .Op general options .Op Fl c Ar cdbsize .Nm .Ic modesense -.Aq target:lun +.Aq lun .Aq Fl m Ar page | Fl l .Op Fl P Ar pc .Op Fl d @@ -97,19 +97,19 @@ .Op Fl c Ar size .Nm .Ic start -.Aq target:lun +.Aq lun .Op general options .Op Fl i .Op Fl o .Nm .Ic stop -.Aq target:lun +.Aq lun .Op general options .Op Fl i .Op Fl o .Nm .Ic synccache -.Aq target:lun +.Aq lun .Op general options .Op Fl l Ar lba .Op Fl b Ar blockcount @@ -126,7 +126,7 @@ .Ic lunlist .Nm .Ic delay -.Aq target:lun +.Aq lun .Aq Fl l Ar datamove|done .Aq Fl t Ar secs .Op Fl T Ar oneshot|cont @@ -134,11 +134,11 @@ .Ic realsync Aq on|off|query .Nm .Ic setsync interval -.Aq target:lun +.Aq lun .Aq Fl i Ar interval .Nm .Ic getsync -.Aq target:lun +.Aq lun .Nm .Ic inject .Aq Fl i Ar action @@ -236,8 +236,8 @@ utility has a number of primary functions, many of which require a device identifier. The device identifier takes the following form: .Bl -tag -width 14n -.It target:lun -Specify the target (almost always 0) and LUN number to operate on. +.It lun +Specify the LUN number to operate on. .El Many of the primary functions of the .Nm @@ -570,7 +570,7 @@ sending SYNCHRONIZE cache commands. An interval of 0 means that the cache will be flushed for this LUN every time a SYNCHRONIZE CACHE command is received. .Pp -You must specify the target and LUN you want to modify. +You must specify the LUN you want to modify. .It Ic getsync Get the interval at which we actually service the SYNCHRONIZE CACHE command, as set by the @@ -580,7 +580,7 @@ The reported number means that we will actually flush the cache on every Nth SYNCHRONIZE CACHE command. A value of 0 means that we will flush the cache every time. .Pp -You must specify the target and LUN you want to query. +You must specify the LUN you want to query. .It Ic inject Inject the specified type of error for the LUN specified, when a command that matches the given pattern is seen. @@ -1024,34 +1024,34 @@ Specifies file or device name to use for backing store. Specifies number of backend threads to use for this LUN. .El .Sh EXAMPLES -.Dl ctladm tur 0:1 +.Dl ctladm tur 1 .Pp Send a .Tn SCSI TEST UNIT READY command to LUN 1. .Pp -.Dl ctladm modesense 0:1 -l +.Dl ctladm modesense 1 -l .Pp Display the list of mode pages supported by LUN 1. .Pp -.Dl ctladm modesense 0:0 -m 10 -P 3 -d -c 10 +.Dl ctladm modesense 0 -m 10 -P 3 -d -c 10 .Pp Display the saved version of the Control mode page (page 10) on LUN 0. Disable fetching block descriptors, and use a 10 byte MODE SENSE command instead of the default 6 byte command. .Bd -literal -ctladm read 0:2 -l 0 -d 1 -b 512 -f - > foo +ctladm read 2 -l 0 -d 1 -b 512 -f - > foo .Ed .Pp Read the first 512 byte block from LUN 2 and dump it to the file .Pa foo . .Bd -literal -ctladm write 0:3 -l 0xff432140 -d 20 -b 512 -f /tmp/bar +ctladm write 3 -l 0xff432140 -d 20 -b 512 -f /tmp/bar .Ed .Pp Read 10240 bytes from the file .Pa /tmp/bar -and write it to target 0, LUN 3. +and write it to LUN 3. starting at LBA 0xff432140. .Pp .Dl ctladm create -b ramdisk -s 10485760000000000 @@ -1095,12 +1095,12 @@ List all LUNs in the system, along with their inquiry data and device type. This only works when the FETDs are enabled, since the commands go through the ioctl port. .Pp -.Dl ctladm inject 0:6 -i mediumerr -p read -r 0,512 -c +.Dl ctladm inject 6 -i mediumerr -p read -r 0,512 -c .Pp Inject a medium error on LUN 6 for every read that covers the first 512 blocks of the LUN. .Bd -literal -offset indent -ctladm inject 0:6 -i custom -p tur -s 18 "f0 0 02 s12 04 02" +ctladm inject 6 -i custom -p tur -s 18 "f0 0 02 s12 04 02" .Ed .Pp Inject a custom error on LUN 6 for the next TEST UNIT READY command only. diff --git a/usr.sbin/ctladm/ctladm.c b/usr.sbin/ctladm/ctladm.c index cca46c8..4e5b084 100644 --- a/usr.sbin/ctladm/ctladm.c +++ b/usr.sbin/ctladm/ctladm.c @@ -211,49 +211,47 @@ static struct ctladm_opts option_table[] = { ctladm_optret getoption(struct ctladm_opts *table, char *arg, uint32_t *cmdnum, ctladm_cmdargs *argnum, const char **subopt); -static int cctl_parse_tl(char *str, int *target, int *lun); static int cctl_dump_ooa(int fd, int argc, char **argv); static int cctl_port_dump(int fd, int quiet, int xml, int32_t fe_num, ctl_port_type port_type); static int cctl_port(int fd, int argc, char **argv, char *combinedopt); static int cctl_do_io(int fd, int retries, union ctl_io *io, const char *func); -static int cctl_delay(int fd, int target, int lun, int argc, char **argv, +static int cctl_delay(int fd, int lun, int argc, char **argv, char *combinedopt); static int cctl_lunlist(int fd); -static int cctl_startup_shutdown(int fd, int target, int lun, int iid, +static int cctl_startup_shutdown(int fd, int lun, int iid, ctladm_cmdfunction command); -static int cctl_sync_cache(int fd, int target, int lun, int iid, int retries, +static int cctl_sync_cache(int fd, int lun, int iid, int retries, int argc, char **argv, char *combinedopt); -static int cctl_start_stop(int fd, int target, int lun, int iid, int retries, +static int cctl_start_stop(int fd, int lun, int iid, int retries, int start, int argc, char **argv, char *combinedopt); -static int cctl_mode_sense(int fd, int target, int lun, int iid, int retries, +static int cctl_mode_sense(int fd, int lun, int iid, int retries, int argc, char **argv, char *combinedopt); -static int cctl_read_capacity(int fd, int target, int lun, int iid, +static int cctl_read_capacity(int fd, int lun, int iid, int retries, int argc, char **argv, char *combinedopt); -static int cctl_read_write(int fd, int target, int lun, int iid, int retries, +static int cctl_read_write(int fd, int lun, int iid, int retries, int argc, char **argv, char *combinedopt, ctladm_cmdfunction command); -static int cctl_get_luns(int fd, int target, int lun, int iid, int retries, +static int cctl_get_luns(int fd, int lun, int iid, int retries, struct scsi_report_luns_data **lun_data, uint32_t *num_luns); -static int cctl_report_luns(int fd, int target, int lun, int iid, int retries); -static int cctl_tur(int fd, int target, int lun, int iid, int retries); -static int cctl_get_inquiry(int fd, int target, int lun, int iid, int retries, +static int cctl_report_luns(int fd, int lun, int iid, int retries); +static int cctl_tur(int fd, int lun, int iid, int retries); +static int cctl_get_inquiry(int fd, int lun, int iid, int retries, char *path_str, int path_len, struct scsi_inquiry_data *inq_data); -static int cctl_inquiry(int fd, int target, int lun, int iid, int retries); -static int cctl_req_sense(int fd, int target, int lun, int iid, int retries); -static int cctl_persistent_reserve_in(int fd, int target, int lun, +static int cctl_inquiry(int fd, int lun, int iid, int retries); +static int cctl_req_sense(int fd, int lun, int iid, int retries); +static int cctl_persistent_reserve_in(int fd, int lun, int initiator, int argc, char **argv, char *combinedopt, int retry_count); -static int cctl_persistent_reserve_out(int fd, int target, int lun, +static int cctl_persistent_reserve_out(int fd, int lun, int initiator, int argc, char **argv, char *combinedopt, int retry_count); static int cctl_create_lun(int fd, int argc, char **argv, char *combinedopt); -static int cctl_inquiry_vpd_devid(int fd, int target, int lun, int initiator); -static int cctl_report_target_port_group(int fd, int target, int lun, - int initiator); +static int cctl_inquiry_vpd_devid(int fd, int lun, int initiator); +static int cctl_report_target_port_group(int fd, int lun, int initiator); static int cctl_modify_lun(int fd, int argc, char **argv, char *combinedopt); ctladm_optret @@ -284,50 +282,20 @@ getoption(struct ctladm_opts *table, char *arg, uint32_t *cmdnum, return(CC_OR_NOT_FOUND); } - -static int -cctl_parse_tl(char *str, int *target, int *lun) -{ - char *tmpstr; - int retval; - - retval = 0; - - while (isspace(*str) && (*str != '\0')) - str++; - - tmpstr = (char *)strtok(str, ":"); - if ((tmpstr != NULL) && (*tmpstr != '\0')) { - *target = strtol(tmpstr, NULL, 0); - tmpstr = (char *)strtok(NULL, ":"); - if ((tmpstr != NULL) && (*tmpstr != '\0')) { - *lun = strtol(tmpstr, NULL, 0); - } else - retval = -1; - } else - retval = -1; - - return (retval); -} - static int cctl_dump_ooa(int fd, int argc, char **argv) { struct ctl_ooa ooa; long double cmd_latency; int num_entries, len; - int target = -1, lun = -1; + int lun = -1; int retval; unsigned int i; num_entries = 104; - if ((argc > 2) - && (isdigit(argv[2][0]))) { - retval = cctl_parse_tl(argv[2], &target, &lun); - if (retval != 0) - warnx("invalid target:lun argument %s", argv[2]); - } + if ((argc > 2) && (isdigit(argv[2][0]))) + lun = strtol(argv[2], NULL, 0); retry: len = num_entries * sizeof(struct ctl_ooa_entry); @@ -776,7 +744,7 @@ cctl_do_io(int fd, int retries, union ctl_io *io, const char *func) } static int -cctl_delay(int fd, int target, int lun, int argc, char **argv, +cctl_delay(int fd, int lun, int argc, char **argv, char *combinedopt) { struct ctl_io_delay_info delay_info; @@ -831,7 +799,6 @@ cctl_delay(int fd, int target, int lun, int argc, char **argv, goto bailout; } - delay_info.target_id = target; delay_info.lun_id = lun; delay_info.delay_secs = delaytime; @@ -938,7 +905,7 @@ bailout: } static int -cctl_getsetsync(int fd, int target, int lun, ctladm_cmdfunction command, +cctl_getsetsync(int fd, int lun, ctladm_cmdfunction command, int argc, char **argv, char *combinedopt) { struct ctl_sync_info sync_info; @@ -950,7 +917,6 @@ cctl_getsetsync(int fd, int target, int lun, ctladm_cmdfunction command, retval = 0; memset(&sync_info, 0, sizeof(sync_info)); - sync_info.target_id = target; sync_info.lun_id = lun; while ((c = getopt(argc, argv, combinedopt)) != -1) { @@ -986,12 +952,12 @@ cctl_getsetsync(int fd, int target, int lun, ctladm_cmdfunction command, switch (sync_info.status) { case CTL_GS_SYNC_OK: if (command == CTLADM_CMD_GETSYNC) { - fprintf(stdout, "%d:%d: sync interval: %d\n", - target, lun, sync_info.sync_interval); + fprintf(stdout, "%d: sync interval: %d\n", + lun, sync_info.sync_interval); } break; case CTL_GS_SYNC_NO_LUN: - warnx("%s: unknown target:LUN %d:%d", __func__, target, lun); + warnx("%s: unknown LUN %d", __func__, lun); retval = 1; break; case CTL_GS_SYNC_NONE: @@ -1030,7 +996,7 @@ static struct ctladm_opts cctl_err_patterns[] = { }; static int -cctl_error_inject(int fd, uint32_t target, uint32_t lun, int argc, char **argv, +cctl_error_inject(int fd, uint32_t lun, int argc, char **argv, char *combinedopt) { int retval = 0; @@ -1045,7 +1011,6 @@ cctl_error_inject(int fd, uint32_t target, uint32_t lun, int argc, char **argv, int c; bzero(&err_desc, sizeof(err_desc)); - err_desc.target_id = target; err_desc.lun_id = lun; while ((c = getopt(argc, argv, combinedopt)) != -1) { @@ -1256,7 +1221,6 @@ cctl_lunlist(int fd) struct scsi_report_luns_data *lun_data; struct scsi_inquiry_data *inq_data; uint32_t num_luns; - int target; int initid; unsigned int i; int retval; @@ -1264,14 +1228,13 @@ cctl_lunlist(int fd) retval = 0; inq_data = NULL; - target = 6; initid = 7; /* * XXX KDM assuming LUN 0 is fine, but we may need to change this * if we ever acquire the ability to have multiple targets. */ - if ((retval = cctl_get_luns(fd, target, /*lun*/ 0, initid, + if ((retval = cctl_get_luns(fd, /*lun*/ 0, initid, /*retries*/ 2, &lun_data, &num_luns)) != 0) goto bailout; @@ -1308,7 +1271,7 @@ cctl_lunlist(int fd) if (lun_val == -1) continue; - if ((retval = cctl_get_inquiry(fd, target, lun_val, initid, + if ((retval = cctl_get_inquiry(fd, lun_val, initid, /*retries*/ 2, scsi_path, sizeof(scsi_path), inq_data)) != 0) { @@ -1329,11 +1292,10 @@ bailout: } static int -cctl_startup_shutdown(int fd, int target, int lun, int iid, +cctl_startup_shutdown(int fd, int lun, int iid, ctladm_cmdfunction command) { union ctl_io *io; - struct ctl_id id; struct scsi_report_luns_data *lun_data; struct scsi_inquiry_data *inq_data; uint32_t num_luns; @@ -1353,15 +1315,13 @@ cctl_startup_shutdown(int fd, int target, int lun, int iid, * and reissue the stop with the offline bit set */ - id.id = iid; - - io = ctl_scsi_alloc_io(id); + io = ctl_scsi_alloc_io(iid); if (io == NULL) { warnx("%s: can't allocate memory", __func__); return (1); } - if ((retval = cctl_get_luns(fd, target, lun, iid, /*retries*/ 2, + if ((retval = cctl_get_luns(fd, lun, iid, /*retries*/ 2, &lun_data, &num_luns)) != 0) goto bailout; @@ -1402,7 +1362,7 @@ cctl_startup_shutdown(int fd, int target, int lun, int iid, if (lun_val == -1) continue; - if ((retval = cctl_get_inquiry(fd, target, lun_val, iid, + if ((retval = cctl_get_inquiry(fd, lun_val, iid, /*retries*/ 2, scsi_path, sizeof(scsi_path), inq_data)) != 0) { @@ -1422,7 +1382,6 @@ cctl_startup_shutdown(int fd, int target, int lun, int iid, if (command == CTLADM_CMD_SHUTDOWN) { struct ctl_ooa_info ooa_info; - ooa_info.target_id = target; ooa_info.lun_id = lun_val; if (ioctl(fd, CTL_CHECK_OOA, &ooa_info) == -1) { @@ -1457,9 +1416,8 @@ cctl_startup_shutdown(int fd, int target, int lun, int iid, CTL_TAG_SIMPLE :CTL_TAG_ORDERED, /*control*/ 0); - io->io_hdr.nexus.targ_target.id = target; io->io_hdr.nexus.targ_lun = lun_val; - io->io_hdr.nexus.initid = id; + io->io_hdr.nexus.initid = iid; if (cctl_do_io(fd, /*retries*/ 3, io, __func__) != 0) { retval = 1; @@ -1488,11 +1446,10 @@ bailout: } static int -cctl_sync_cache(int fd, int target, int lun, int iid, int retries, +cctl_sync_cache(int fd, int lun, int iid, int retries, int argc, char **argv, char *combinedopt) { union ctl_io *io; - struct ctl_id id; int cdb_size = -1; int retval; uint64_t our_lba = 0; @@ -1500,10 +1457,9 @@ cctl_sync_cache(int fd, int target, int lun, int iid, int retries, int reladr = 0, immed = 0; int c; - id.id = iid; retval = 0; - io = ctl_scsi_alloc_io(id); + io = ctl_scsi_alloc_io(iid); if (io == NULL) { warnx("%s: can't allocate memory", __func__); return (1); @@ -1555,9 +1511,8 @@ cctl_sync_cache(int fd, int target, int lun, int iid, int retries, /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0); - io->io_hdr.nexus.targ_target.id = target; io->io_hdr.nexus.targ_lun = lun; - io->io_hdr.nexus.initid = id; + io->io_hdr.nexus.initid = iid; if (cctl_do_io(fd, retries, io, __func__) != 0) { retval = 1; @@ -1575,19 +1530,17 @@ bailout: } static int -cctl_start_stop(int fd, int target, int lun, int iid, int retries, int start, +cctl_start_stop(int fd, int lun, int iid, int retries, int start, int argc, char **argv, char *combinedopt) { union ctl_io *io; - struct ctl_id id; char scsi_path[40]; int immed = 0, onoffline = 0; int retval, c; - id.id = iid; retval = 0; - io = ctl_scsi_alloc_io(id); + io = ctl_scsi_alloc_io(iid); if (io == NULL) { warnx("%s: can't allocate memory", __func__); return (1); @@ -1622,9 +1575,8 @@ cctl_start_stop(int fd, int target, int lun, int iid, int retries, int start, CTL_TAG_ORDERED, /*control*/ 0); - io->io_hdr.nexus.targ_target.id = target; io->io_hdr.nexus.targ_lun = lun; - io->io_hdr.nexus.initid = id; + io->io_hdr.nexus.initid = iid; if (cctl_do_io(fd, retries, io, __func__) != 0) { retval = 1; @@ -1645,11 +1597,10 @@ bailout: } static int -cctl_mode_sense(int fd, int target, int lun, int iid, int retries, +cctl_mode_sense(int fd, int lun, int iid, int retries, int argc, char **argv, char *combinedopt) { union ctl_io *io; - struct ctl_id id; uint32_t datalen; uint8_t *dataptr; int pc = -1, cdbsize, retval, dbd = 0, subpage = -1; @@ -1657,12 +1608,11 @@ cctl_mode_sense(int fd, int target, int lun, int iid, int retries, int page_code = -1; int c; - id.id = iid; cdbsize = 0; retval = 0; dataptr = NULL; - io = ctl_scsi_alloc_io(id); + io = ctl_scsi_alloc_io(iid); if (io == NULL) { warn("%s: can't allocate memory", __func__); return (1); @@ -1790,9 +1740,8 @@ cctl_mode_sense(int fd, int target, int lun, int iid, int retries, /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0); - io->io_hdr.nexus.targ_target.id = target; io->io_hdr.nexus.targ_lun = lun; - io->io_hdr.nexus.initid = id; + io->io_hdr.nexus.initid = iid; if (cctl_do_io(fd, retries, io, __func__) != 0) { retval = 1; @@ -1863,11 +1812,10 @@ bailout: } static int -cctl_read_capacity(int fd, int target, int lun, int iid, int retries, +cctl_read_capacity(int fd, int lun, int iid, int retries, int argc, char **argv, char *combinedopt) { union ctl_io *io; - struct ctl_id id; struct scsi_read_capacity_data *data; struct scsi_read_capacity_data_long *longdata; int cdbsize = -1, retval; @@ -1877,9 +1825,8 @@ cctl_read_capacity(int fd, int target, int lun, int iid, int retries, cdbsize = 10; dataptr = NULL; retval = 0; - id.id = iid; - io = ctl_scsi_alloc_io(id); + io = ctl_scsi_alloc_io(iid); if (io == NULL) { warn("%s: can't allocate memory\n", __func__); return (1); @@ -1943,8 +1890,7 @@ retry: break; } - io->io_hdr.nexus.initid = id; - io->io_hdr.nexus.targ_target.id = target; + io->io_hdr.nexus.initid = iid; io->io_hdr.nexus.targ_lun = lun; if (cctl_do_io(fd, retries, io, __func__) != 0) { @@ -1989,12 +1935,11 @@ bailout: } static int -cctl_read_write(int fd, int target, int lun, int iid, int retries, +cctl_read_write(int fd, int lun, int iid, int retries, int argc, char **argv, char *combinedopt, ctladm_cmdfunction command) { union ctl_io *io; - struct ctl_id id; int file_fd, do_stdio; int cdbsize = -1, databytes; uint8_t *dataptr; @@ -2009,9 +1954,8 @@ cctl_read_write(int fd, int target, int lun, int iid, int retries, do_stdio = 0; dataptr = NULL; file_fd = -1; - id.id = iid; - io = ctl_scsi_alloc_io(id); + io = ctl_scsi_alloc_io(iid); if (io == NULL) { warn("%s: can't allocate memory\n", __func__); return (1); @@ -2135,9 +2079,8 @@ cctl_read_write(int fd, int target, int lun, int iid, int retries, /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0); - io->io_hdr.nexus.targ_target.id = target; io->io_hdr.nexus.targ_lun = lun; - io->io_hdr.nexus.initid = id; + io->io_hdr.nexus.initid = iid; if (cctl_do_io(fd, retries, io, __func__) != 0) { retval = 1; @@ -2172,19 +2115,17 @@ bailout: } static int -cctl_get_luns(int fd, int target, int lun, int iid, int retries, struct +cctl_get_luns(int fd, int lun, int iid, int retries, struct scsi_report_luns_data **lun_data, uint32_t *num_luns) { union ctl_io *io; - struct ctl_id id; uint32_t nluns; int lun_datalen; int retval; retval = 0; - id.id = iid; - io = ctl_scsi_alloc_io(id); + io = ctl_scsi_alloc_io(iid); if (io == NULL) { warnx("%s: can't allocate memory", __func__); return (1); @@ -2213,8 +2154,7 @@ retry: /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0); - io->io_hdr.nexus.initid = id; - io->io_hdr.nexus.targ_target.id = target; + io->io_hdr.nexus.initid = iid; io->io_hdr.nexus.targ_lun = lun; if (cctl_do_io(fd, retries, io, __func__) != 0) { @@ -2245,7 +2185,7 @@ bailout: } static int -cctl_report_luns(int fd, int target, int lun, int iid, int retries) +cctl_report_luns(int fd, int lun, int iid, int retries) { struct scsi_report_luns_data *lun_data; uint32_t num_luns, i; @@ -2253,7 +2193,7 @@ cctl_report_luns(int fd, int target, int lun, int iid, int retries) lun_data = NULL; - if ((retval = cctl_get_luns(fd, target, lun, iid, retries, &lun_data, + if ((retval = cctl_get_luns(fd, lun, iid, retries, &lun_data, &num_luns)) != 0) goto bailout; @@ -2298,14 +2238,11 @@ bailout: } static int -cctl_tur(int fd, int target, int lun, int iid, int retries) +cctl_tur(int fd, int lun, int iid, int retries) { union ctl_io *io; - struct ctl_id id; - - id.id = iid; - io = ctl_scsi_alloc_io(id); + io = ctl_scsi_alloc_io(iid); if (io == NULL) { fprintf(stderr, "can't allocate memory\n"); return (1); @@ -2315,9 +2252,8 @@ cctl_tur(int fd, int target, int lun, int iid, int retries) /* tag_type */ CTL_TAG_SIMPLE, /* control */ 0); - io->io_hdr.nexus.targ_target.id = target; io->io_hdr.nexus.targ_lun = lun; - io->io_hdr.nexus.initid = id; + io->io_hdr.nexus.initid = iid; if (cctl_do_io(fd, retries, io, __func__) != 0) { ctl_scsi_free_io(io); @@ -2333,19 +2269,16 @@ cctl_tur(int fd, int target, int lun, int iid, int retries) } static int -cctl_get_inquiry(int fd, int target, int lun, int iid, int retries, +cctl_get_inquiry(int fd, int lun, int iid, int retries, char *path_str, int path_len, struct scsi_inquiry_data *inq_data) { union ctl_io *io; - struct ctl_id id; int retval; retval = 0; - id.id = iid; - - io = ctl_scsi_alloc_io(id); + io = ctl_scsi_alloc_io(iid); if (io == NULL) { warnx("cctl_inquiry: can't allocate memory\n"); return (1); @@ -2359,9 +2292,8 @@ cctl_get_inquiry(int fd, int target, int lun, int iid, int retries, /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0); - io->io_hdr.nexus.targ_target.id = target; io->io_hdr.nexus.targ_lun = lun; - io->io_hdr.nexus.initid = id; + io->io_hdr.nexus.initid = iid; if (cctl_do_io(fd, retries, io, __func__) != 0) { retval = 1; @@ -2381,7 +2313,7 @@ bailout: } static int -cctl_inquiry(int fd, int target, int lun, int iid, int retries) +cctl_inquiry(int fd, int lun, int iid, int retries) { struct scsi_inquiry_data *inq_data; char scsi_path[40]; @@ -2396,7 +2328,7 @@ cctl_inquiry(int fd, int target, int lun, int iid, int retries) goto bailout; } - if ((retval = cctl_get_inquiry(fd, target, lun, iid, retries, scsi_path, + if ((retval = cctl_get_inquiry(fd, lun, iid, retries, scsi_path, sizeof(scsi_path), inq_data)) != 0) goto bailout; @@ -2411,18 +2343,15 @@ bailout: } static int -cctl_req_sense(int fd, int target, int lun, int iid, int retries) +cctl_req_sense(int fd, int lun, int iid, int retries) { union ctl_io *io; struct scsi_sense_data *sense_data; - struct ctl_id id; int retval; retval = 0; - id.id = iid; - - io = ctl_scsi_alloc_io(id); + io = ctl_scsi_alloc_io(iid); if (io == NULL) { warnx("cctl_req_sense: can't allocate memory\n"); return (1); @@ -2437,9 +2366,8 @@ cctl_req_sense(int fd, int target, int lun, int iid, int retries) /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0); - io->io_hdr.nexus.targ_target.id = target; io->io_hdr.nexus.targ_lun = lun; - io->io_hdr.nexus.initid = id; + io->io_hdr.nexus.initid = iid; if (cctl_do_io(fd, retries, io, __func__) != 0) { retval = 1; @@ -2462,19 +2390,17 @@ bailout: } static int -cctl_report_target_port_group(int fd, int target, int lun, int initiator) +cctl_report_target_port_group(int fd, int lun, int iid) { union ctl_io *io; - struct ctl_id id; uint32_t datalen; uint8_t *dataptr; int retval; - id.id = initiator; dataptr = NULL; retval = 0; - io = ctl_scsi_alloc_io(id); + io = ctl_scsi_alloc_io(iid); if (io == NULL) { warn("%s: can't allocate memory", __func__); return (1); @@ -2497,9 +2423,8 @@ cctl_report_target_port_group(int fd, int target, int lun, int initiator) /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0); - io->io_hdr.nexus.targ_target.id = target; io->io_hdr.nexus.targ_lun = lun; - io->io_hdr.nexus.initid = id; + io->io_hdr.nexus.initid = iid; if (cctl_do_io(fd, 0, io, __func__) != 0) { retval = 1; @@ -2530,19 +2455,17 @@ bailout: } static int -cctl_inquiry_vpd_devid(int fd, int target, int lun, int initiator) +cctl_inquiry_vpd_devid(int fd, int lun, int iid) { union ctl_io *io; - struct ctl_id id; uint32_t datalen; uint8_t *dataptr; int retval; - id.id = initiator; retval = 0; dataptr = NULL; - io = ctl_scsi_alloc_io(id); + io = ctl_scsi_alloc_io(iid); if (io == NULL) { warn("%s: can't allocate memory", __func__); return (1); @@ -2566,9 +2489,8 @@ cctl_inquiry_vpd_devid(int fd, int target, int lun, int initiator) /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0); - io->io_hdr.nexus.targ_target.id = target; io->io_hdr.nexus.targ_lun = lun; - io->io_hdr.nexus.initid = id; + io->io_hdr.nexus.initid = iid; if (cctl_do_io(fd, 0, io, __func__) != 0) { retval = 1; @@ -2599,23 +2521,21 @@ bailout: } static int -cctl_persistent_reserve_in(int fd, int target, int lun, int initiator, +cctl_persistent_reserve_in(int fd, int lun, int iid, int argc, char **argv, char *combinedopt, int retry_count) { union ctl_io *io; - struct ctl_id id; uint32_t datalen; uint8_t *dataptr; int action = -1; int retval; int c; - id.id = initiator; retval = 0; dataptr = NULL; - io = ctl_scsi_alloc_io(id); + io = ctl_scsi_alloc_io(iid); if (io == NULL) { warn("%s: can't allocate memory", __func__); return (1); @@ -2655,9 +2575,8 @@ cctl_persistent_reserve_in(int fd, int target, int lun, int initiator, /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0); - io->io_hdr.nexus.targ_target.id = target; io->io_hdr.nexus.targ_lun = lun; - io->io_hdr.nexus.initid = id; + io->io_hdr.nexus.initid = iid; if (cctl_do_io(fd, retry_count, io, __func__) != 0) { retval = 1; @@ -2705,12 +2624,11 @@ bailout: } static int -cctl_persistent_reserve_out(int fd, int target, int lun, int initiator, +cctl_persistent_reserve_out(int fd, int lun, int iid, int argc, char **argv, char *combinedopt, int retry_count) { union ctl_io *io; - struct ctl_id id; uint32_t datalen; uint64_t key = 0, sa_key = 0; int action = -1, restype = -1; @@ -2718,11 +2636,10 @@ cctl_persistent_reserve_out(int fd, int target, int lun, int initiator, int retval; int c; - id.id = initiator; retval = 0; dataptr = NULL; - io = ctl_scsi_alloc_io(id); + io = ctl_scsi_alloc_io(iid); if (io == NULL) { warn("%s: can't allocate memory", __func__); return (1); @@ -2780,9 +2697,8 @@ cctl_persistent_reserve_out(int fd, int target, int lun, int initiator, /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0); - io->io_hdr.nexus.targ_target.id = target; io->io_hdr.nexus.targ_lun = lun; - io->io_hdr.nexus.initid = id; + io->io_hdr.nexus.initid = iid; if (cctl_do_io(fd, retry_count, io, __func__) != 0) { retval = 1; @@ -4512,7 +4428,7 @@ main(int argc, char **argv) const char *mainopt = "C:D:I:"; const char *subopt = NULL; char combinedopt[256]; - int target, lun; + int lun; int optstart = 2; int retval, fd; int retries; @@ -4525,7 +4441,6 @@ main(int argc, char **argv) device = NULL; fd = -1; retries = 0; - target = 0; lun = 0; initid = 7; @@ -4551,16 +4466,13 @@ main(int argc, char **argv) } if (cmdargs & CTLADM_ARG_NEED_TL) { - if ((argc < 3) - || (!isdigit(argv[2][0]))) { - warnx("option %s requires a target:lun argument", + if ((argc < 3) || (!isdigit(argv[2][0]))) { + warnx("option %s requires a lun argument", argv[1]); usage(0); exit(1); } - retval = cctl_parse_tl(argv[2], &target, &lun); - if (retval != 0) - errx(1, "invalid target:lun argument %s", argv[2]); + lun = strtol(argv[2], NULL, 0); cmdargs |= CTLADM_ARG_TARG_LUN; optstart++; @@ -4691,16 +4603,16 @@ main(int argc, char **argv) switch (command) { case CTLADM_CMD_TUR: - retval = cctl_tur(fd, target, lun, initid, retries); + retval = cctl_tur(fd, lun, initid, retries); break; case CTLADM_CMD_INQUIRY: - retval = cctl_inquiry(fd, target, lun, initid, retries); + retval = cctl_inquiry(fd, lun, initid, retries); break; case CTLADM_CMD_REQ_SENSE: - retval = cctl_req_sense(fd, target, lun, initid, retries); + retval = cctl_req_sense(fd, lun, initid, retries); break; case CTLADM_CMD_REPORT_LUNS: - retval = cctl_report_luns(fd, target, lun, initid, retries); + retval = cctl_report_luns(fd, lun, initid, retries); break; case CTLADM_CMD_CREATE: retval = cctl_create_lun(fd, argc, argv, combinedopt); @@ -4713,7 +4625,7 @@ main(int argc, char **argv) break; case CTLADM_CMD_READ: case CTLADM_CMD_WRITE: - retval = cctl_read_write(fd, target, lun, initid, retries, + retval = cctl_read_write(fd, lun, initid, retries, argc, argv, combinedopt, command); break; case CTLADM_CMD_PORT: @@ -4726,44 +4638,44 @@ main(int argc, char **argv) retval = cctl_lunmap(fd, argc, argv, combinedopt); break; case CTLADM_CMD_READCAPACITY: - retval = cctl_read_capacity(fd, target, lun, initid, retries, + retval = cctl_read_capacity(fd, lun, initid, retries, argc, argv, combinedopt); break; case CTLADM_CMD_MODESENSE: - retval = cctl_mode_sense(fd, target, lun, initid, retries, + retval = cctl_mode_sense(fd, lun, initid, retries, argc, argv, combinedopt); break; case CTLADM_CMD_START: case CTLADM_CMD_STOP: - retval = cctl_start_stop(fd, target, lun, initid, retries, + retval = cctl_start_stop(fd, lun, initid, retries, (command == CTLADM_CMD_START) ? 1 : 0, argc, argv, combinedopt); break; case CTLADM_CMD_SYNC_CACHE: - retval = cctl_sync_cache(fd, target, lun, initid, retries, + retval = cctl_sync_cache(fd, lun, initid, retries, argc, argv, combinedopt); break; case CTLADM_CMD_SHUTDOWN: case CTLADM_CMD_STARTUP: - retval = cctl_startup_shutdown(fd, target, lun, initid, + retval = cctl_startup_shutdown(fd, lun, initid, command); break; case CTLADM_CMD_LUNLIST: retval = cctl_lunlist(fd); break; case CTLADM_CMD_DELAY: - retval = cctl_delay(fd, target, lun, argc, argv, combinedopt); + retval = cctl_delay(fd, lun, argc, argv, combinedopt); break; case CTLADM_CMD_REALSYNC: retval = cctl_realsync(fd, argc, argv); break; case CTLADM_CMD_SETSYNC: case CTLADM_CMD_GETSYNC: - retval = cctl_getsetsync(fd, target, lun, command, + retval = cctl_getsetsync(fd, lun, command, argc, argv, combinedopt); break; case CTLADM_CMD_ERR_INJECT: - retval = cctl_error_inject(fd, target, lun, argc, argv, + retval = cctl_error_inject(fd, lun, argc, argv, combinedopt); break; case CTLADM_CMD_DUMPOOA: @@ -4773,20 +4685,20 @@ main(int argc, char **argv) retval = cctl_dump_structs(fd, cmdargs); break; case CTLADM_CMD_PRES_IN: - retval = cctl_persistent_reserve_in(fd, target, lun, initid, + retval = cctl_persistent_reserve_in(fd, lun, initid, argc, argv, combinedopt, retries); break; case CTLADM_CMD_PRES_OUT: - retval = cctl_persistent_reserve_out(fd, target, lun, initid, + retval = cctl_persistent_reserve_out(fd, lun, initid, argc, argv, combinedopt, retries); break; case CTLADM_CMD_INQ_VPD_DEVID: - retval = cctl_inquiry_vpd_devid(fd, target, lun, initid); + retval = cctl_inquiry_vpd_devid(fd, lun, initid); break; case CTLADM_CMD_RTPG: - retval = cctl_report_target_port_group(fd, target, lun, initid); + retval = cctl_report_target_port_group(fd, lun, initid); break; case CTLADM_CMD_MODIFY: retval = cctl_modify_lun(fd, argc, argv, combinedopt); diff --git a/usr.sbin/ctld/ctl.conf.5 b/usr.sbin/ctld/ctl.conf.5 index 16b2aa2..121daa7 100644 --- a/usr.sbin/ctld/ctl.conf.5 +++ b/usr.sbin/ctld/ctl.conf.5 @@ -1,4 +1,5 @@ .\" Copyright (c) 2012 The FreeBSD Foundation +.\" Copyright (c) 2015 Alexander Motin <mav@FreeBSD.org> .\" All rights reserved. .\" .\" This software was developed by Edward Tomasz Napierala under sponsorship @@ -27,7 +28,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 24, 2015 +.Dd September 7, 2015 .Dt CTL.CONF 5 .Os .Sh NAME @@ -236,6 +237,15 @@ Redirection happens before authentication and any or .Sy initiator-portal checks are skipped. +.It Ic tag Ar value +Unique 16-bit tag value of this +.Sy portal-group . +If not specified, the value is generated automatically. +.It Ic foreign +Specifies that this +.Sy portal-group +is listened by some other host. +This host will announce it on discovery stage, but won't listen. .El .Ss target Context .Bl -tag -width indent diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c index f146ee6..9803a5d 100644 --- a/usr.sbin/ctld/ctld.c +++ b/usr.sbin/ctld/ctld.c @@ -59,7 +59,7 @@ static volatile bool sigterm_received = false; static volatile bool sigalrm_received = false; static int nchildren = 0; -static uint16_t last_portal_group_tag = 0; +static uint16_t last_portal_group_tag = 0xff; static void usage(void) @@ -1229,6 +1229,7 @@ port_new(struct conf *conf, struct target *target, struct portal_group *pg) port->p_target = target; TAILQ_INSERT_TAIL(&pg->pg_ports, port, p_pgs); port->p_portal_group = pg; + port->p_foreign = pg->pg_foreign; return (port); } @@ -1734,14 +1735,16 @@ conf_verify(struct conf *conf) if (pg->pg_discovery_filter == PG_FILTER_UNKNOWN) pg->pg_discovery_filter = PG_FILTER_NONE; - if (!TAILQ_EMPTY(&pg->pg_ports)) { - if (pg->pg_redirection != NULL) { + if (pg->pg_redirection != NULL) { + if (!TAILQ_EMPTY(&pg->pg_ports)) { log_debugx("portal-group \"%s\" assigned " "to target, but configured " "for redirection", pg->pg_name); } pg->pg_unassigned = false; + } else if (!TAILQ_EMPTY(&pg->pg_ports)) { + pg->pg_unassigned = false; } else { if (strcmp(pg->pg_name, "default") != 0) log_warnx("portal-group \"%s\" not assigned " @@ -1835,6 +1838,8 @@ conf_apply(struct conf *oldconf, struct conf *newconf) * Go through the new portal groups, assigning tags or preserving old. */ TAILQ_FOREACH(newpg, &newconf->conf_portal_groups, pg_next) { + if (newpg->pg_tag != 0) + continue; oldpg = portal_group_find(oldconf, newpg->pg_name); if (oldpg != NULL) newpg->pg_tag = oldpg->pg_tag; @@ -1864,8 +1869,10 @@ conf_apply(struct conf *oldconf, struct conf *newconf) * and missing in the new one. */ TAILQ_FOREACH_SAFE(oldport, &oldconf->conf_ports, p_next, tmpport) { + if (oldport->p_foreign) + continue; newport = port_find(newconf, oldport->p_name); - if (newport != NULL) + if (newport != NULL && !newport->p_foreign) continue; log_debugx("removing port \"%s\"", oldport->p_name); error = kernel_port_remove(oldport); @@ -1985,9 +1992,11 @@ conf_apply(struct conf *oldconf, struct conf *newconf) * Now add new ports or modify existing ones. */ TAILQ_FOREACH(newport, &newconf->conf_ports, p_next) { + if (newport->p_foreign) + continue; oldport = port_find(oldconf, newport->p_name); - if (oldport == NULL) { + if (oldport == NULL || oldport->p_foreign) { log_debugx("adding port \"%s\"", newport->p_name); error = kernel_port_add(newport); } else { @@ -2011,6 +2020,8 @@ conf_apply(struct conf *oldconf, struct conf *newconf) * Go through the new portals, opening the sockets as neccessary. */ TAILQ_FOREACH(newpg, &newconf->conf_portal_groups, pg_next) { + if (newpg->pg_foreign) + continue; if (newpg->pg_unassigned) { log_debugx("not listening on portal-group \"%s\", " "not assigned to any target", diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h index 8ac8de7..4f43c4e 100644 --- a/usr.sbin/ctld/ctld.h +++ b/usr.sbin/ctld/ctld.h @@ -116,6 +116,7 @@ struct portal_group { char *pg_name; struct auth_group *pg_discovery_auth_group; int pg_discovery_filter; + int pg_foreign; bool pg_unassigned; TAILQ_HEAD(, portal) pg_portals; TAILQ_HEAD(, port) pg_ports; @@ -145,6 +146,7 @@ struct port { struct portal_group *p_portal_group; struct pport *p_pport; struct target *p_target; + int p_foreign; uint32_t p_ctl_port; }; diff --git a/usr.sbin/ctld/parse.y b/usr.sbin/ctld/parse.y index cfc202c..677b5d5 100644 --- a/usr.sbin/ctld/parse.y +++ b/usr.sbin/ctld/parse.y @@ -58,10 +58,11 @@ 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 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 -%token TARGET TIMEOUT +%token TAG TARGET TIMEOUT %union { @@ -337,6 +338,8 @@ portal_group_entry: | portal_group_discovery_filter | + portal_group_foreign + | portal_group_listen | portal_group_listen_iser @@ -344,6 +347,8 @@ portal_group_entry: portal_group_offload | portal_group_redirect + | + portal_group_tag ; portal_group_discovery_auth_group: DISCOVERY_AUTH_GROUP STR @@ -377,6 +382,13 @@ portal_group_discovery_filter: DISCOVERY_FILTER STR } ; +portal_group_foreign: FOREIGN + { + + portal_group->pg_foreign = 1; + } + ; + portal_group_listen: LISTEN STR { int error; @@ -421,6 +433,20 @@ portal_group_redirect: REDIRECT STR } ; +portal_group_tag: TAG STR + { + uint64_t tmp; + + if (expand_number($2, &tmp) != 0) { + yyerror("invalid numeric value"); + free($2); + return (1); + } + + portal_group->pg_tag = tmp; + } + ; + lun: LUN lun_name OPENING_BRACKET lun_entries CLOSING_BRACKET { diff --git a/usr.sbin/ctld/token.l b/usr.sbin/ctld/token.l index caf59cc..19535f7 100644 --- a/usr.sbin/ctld/token.l +++ b/usr.sbin/ctld/token.l @@ -58,6 +58,7 @@ debug { return DEBUG; } device-id { return DEVICE_ID; } discovery-auth-group { return DISCOVERY_AUTH_GROUP; } discovery-filter { return DISCOVERY_FILTER; } +foreign { return FOREIGN; } initiator-name { return INITIATOR_NAME; } initiator-portal { return INITIATOR_PORTAL; } listen { return LISTEN; } @@ -76,6 +77,7 @@ portal-group { return PORTAL_GROUP; } redirect { return REDIRECT; } serial { return SERIAL; } size { return SIZE; } +tag { return TAG; } target { return TARGET; } timeout { return TIMEOUT; } \"[^"]+\" { yylval.str = strndup(yytext + 1, diff --git a/usr.sbin/gstat/gstat.c b/usr.sbin/gstat/gstat.c index d83ef79..8be3775 100644 --- a/usr.sbin/gstat/gstat.c +++ b/usr.sbin/gstat/gstat.c @@ -124,7 +124,7 @@ main(int argc, char **argv) if (regcomp(&f_re, optarg, REG_EXTENDED) != 0) errx(EX_USAGE, "Invalid filter - see re_format(7)"); - strncpy(f_s, optarg, sizeof(f_s)); + strlcpy(f_s, optarg, sizeof(f_s)); break; case 'o': flag_o = 1; @@ -216,7 +216,7 @@ main(int argc, char **argv) getyx(stdscr, cury, curx); getmaxyx(stdscr, maxy, maxx); } - strncpy(pf_s, f_s, sizeof(pf_s)); + strlcpy(pf_s, f_s, sizeof(pf_s)); max_flen = maxx - curx - 1; if ((int)strlen(f_s) > max_flen && max_flen >= 0) { if (max_flen > 3) @@ -406,7 +406,7 @@ main(int argc, char **argv) err(1, "el_gets"); if (line_len > 1) history(hist, &hist_ev, H_ENTER, line); - strncpy(tmp_f_s, line, sizeof(f_s)); + strlcpy(tmp_f_s, line, sizeof(f_s)); if ((p = strchr(tmp_f_s, '\n')) != NULL) *p = '\0'; /* @@ -423,7 +423,7 @@ main(int argc, char **argv) refresh(); sleep(1); } else { - strncpy(f_s, tmp_f_s, sizeof(f_s)); + strlcpy(f_s, tmp_f_s, sizeof(f_s)); f_re = tmp_f_re; } break; diff --git a/usr.sbin/pkg/Makefile b/usr.sbin/pkg/Makefile index 0884b6b..d149fd3 100644 --- a/usr.sbin/pkg/Makefile +++ b/usr.sbin/pkg/Makefile @@ -6,6 +6,6 @@ MAN= pkg.7 CFLAGS+=-I${.CURDIR}/../../contrib/libucl/include .PATH: ${.CURDIR}/../../contrib/libucl/include -LIBADD= archive fetch ucl sbuf crypto +LIBADD= archive fetch ucl sbuf crypto ssl .include <bsd.prog.mk> diff --git a/usr.sbin/pkg/config.c b/usr.sbin/pkg/config.c index 3a1f18d..b0271f5 100644 --- a/usr.sbin/pkg/config.c +++ b/usr.sbin/pkg/config.c @@ -131,6 +131,15 @@ static struct config_entry c[] = { false, true, }, + [PUBKEY] = { + PKG_CONFIG_STRING, + "PUBKEY", + NULL, + NULL, + NULL, + false, + false + } }; static int @@ -231,6 +240,8 @@ config_parse(const ucl_object_t *obj, pkg_conf_file_t conftype) sbuf_cpy(buf, "SIGNATURE_TYPE"); else if (strcasecmp(key, "fingerprints") == 0) sbuf_cpy(buf, "FINGERPRINTS"); + else if (strcasecmp(key, "pubkey") == 0) + sbuf_cpy(buf, "PUBKEY"); else if (strcasecmp(key, "enabled") == 0) { if ((cur->type != UCL_BOOLEAN) || !ucl_object_toboolean(cur)) diff --git a/usr.sbin/pkg/config.h b/usr.sbin/pkg/config.h index ea0d000..4ff0a16 100644 --- a/usr.sbin/pkg/config.h +++ b/usr.sbin/pkg/config.h @@ -40,6 +40,7 @@ typedef enum { SIGNATURE_TYPE, FINGERPRINTS, REPOS_DIR, + PUBKEY, CONFIG_SIZE } pkg_config_key; diff --git a/usr.sbin/pkg/pkg.c b/usr.sbin/pkg/pkg.c index e242638..bd3076c 100644 --- a/usr.sbin/pkg/pkg.c +++ b/usr.sbin/pkg/pkg.c @@ -65,16 +65,21 @@ struct sig_cert { bool trusted; }; +struct pubkey { + unsigned char *sig; + int siglen; +}; + typedef enum { - HASH_UNKNOWN, - HASH_SHA256, + HASH_UNKNOWN, + HASH_SHA256, } hash_t; struct fingerprint { - hash_t type; - char *name; - char hash[BUFSIZ]; - STAILQ_ENTRY(fingerprint) next; + hash_t type; + char *name; + char hash[BUFSIZ]; + STAILQ_ENTRY(fingerprint) next; }; STAILQ_HEAD(fingerprint_list, fingerprint); @@ -470,6 +475,25 @@ cleanup: } static EVP_PKEY * +load_public_key_file(const char *file) +{ + EVP_PKEY *pkey; + BIO *bp; + char errbuf[1024]; + + bp = BIO_new_file(file, "r"); + if (!bp) + errx(EXIT_FAILURE, "Unable to read %s", file); + + if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL) + warnx("ici: %s", ERR_error_string(ERR_get_error(), errbuf)); + + BIO_free(bp); + + return (pkey); +} + +static EVP_PKEY * load_public_key_buf(const unsigned char *cert, int certlen) { EVP_PKEY *pkey; @@ -487,8 +511,8 @@ load_public_key_buf(const unsigned char *cert, int certlen) } static bool -rsa_verify_cert(int fd, const unsigned char *key, int keylen, - unsigned char *sig, int siglen) +rsa_verify_cert(int fd, const char *sigfile, const unsigned char *key, + int keylen, unsigned char *sig, int siglen) { EVP_MD_CTX *mdctx; EVP_PKEY *pkey; @@ -500,6 +524,8 @@ rsa_verify_cert(int fd, const unsigned char *key, int keylen, mdctx = NULL; ret = false; + SSL_load_error_strings(); + /* Compute SHA256 of the package. */ if (lseek(fd, 0, 0) == -1) { warn("lseek"); @@ -510,9 +536,16 @@ rsa_verify_cert(int fd, const unsigned char *key, int keylen, goto cleanup; } - if ((pkey = load_public_key_buf(key, keylen)) == NULL) { - warnx("Error reading public key"); - goto cleanup; + if (sigfile != NULL) { + if ((pkey = load_public_key_file(sigfile)) == NULL) { + warnx("Error reading public key"); + goto cleanup; + } + } else { + if ((pkey = load_public_key_buf(key, keylen)) == NULL) { + warnx("Error reading public key"); + goto cleanup; + } } /* Verify signature of the SHA256(pkg) is valid. */ @@ -552,6 +585,35 @@ cleanup: return (ret); } +static struct pubkey * +read_pubkey(int fd) +{ + struct pubkey *pk; + struct sbuf *sig; + char buf[4096]; + int r; + + if (lseek(fd, 0, 0) == -1) { + warn("lseek"); + return (NULL); + } + + sig = sbuf_new_auto(); + + while ((r = read(fd, buf, sizeof(buf))) >0) { + sbuf_bcat(sig, buf, r); + } + + sbuf_finish(sig); + pk = calloc(1, sizeof(struct pubkey)); + pk->siglen = sbuf_len(sig); + pk->sig = calloc(1, pk->siglen); + memcpy(pk->sig, sbuf_data(sig), pk->siglen); + sbuf_delete(sig); + + return (pk); +} + static struct sig_cert * parse_cert(int fd) { int my_fd; @@ -625,6 +687,45 @@ parse_cert(int fd) { } static bool +verify_pubsignature(int fd_pkg, int fd_sig) +{ + struct pubkey *pk; + const char *pubkey; + bool ret; + + pk = NULL; + pubkey = NULL; + ret = false; + if (config_string(PUBKEY, &pubkey) != 0) { + warnx("No CONFIG_PUBKEY defined"); + goto cleanup; + } + + if ((pk = read_pubkey(fd_sig)) == NULL) { + warnx("Error reading signature"); + goto cleanup; + } + + /* Verify the signature. */ + printf("Verifying signature with public key %s... ", pubkey); + if (rsa_verify_cert(fd_pkg, pubkey, NULL, 0, pk->sig, + pk->siglen) == false) { + fprintf(stderr, "Signature is not valid\n"); + goto cleanup; + } + + ret = true; + +cleanup: + if (pk) { + free(pk->sig); + free(pk); + } + + return (ret); +} + +static bool verify_signature(int fd_pkg, int fd_sig) { struct fingerprint_list *trusted, *revoked; @@ -702,7 +803,7 @@ verify_signature(int fd_pkg, int fd_sig) /* Verify the signature. */ printf("Verifying signature with trusted certificate %s... ", sc->name); - if (rsa_verify_cert(fd_pkg, sc->cert, sc->certlen, sc->sig, + if (rsa_verify_cert(fd_pkg, NULL, sc->cert, sc->certlen, sc->sig, sc->siglen) == false) { fprintf(stderr, "Signature is not valid\n"); goto cleanup; @@ -768,24 +869,42 @@ bootstrap_pkg(bool force) if (signature_type != NULL && strcasecmp(signature_type, "NONE") != 0) { - if (strcasecmp(signature_type, "FINGERPRINTS") != 0) { - warnx("Signature type %s is not supported for " - "bootstrapping.", signature_type); - goto cleanup; - } + if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { - snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX", - getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); - snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig", - packagesite); + snprintf(tmpsig, MAXPATHLEN, "%s/pkg.txz.sig.XXXXXX", + getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); + snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig", + packagesite); - if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { - fprintf(stderr, "Signature for pkg not available.\n"); - goto fetchfail; - } + if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { + fprintf(stderr, "Signature for pkg not " + "available.\n"); + goto fetchfail; + } + + if (verify_signature(fd_pkg, fd_sig) == false) + goto cleanup; + } else if (strcasecmp(signature_type, "PUBKEY") == 0) { - if (verify_signature(fd_pkg, fd_sig) == false) + snprintf(tmpsig, MAXPATHLEN, + "%s/pkg.txz.pubkeysig.XXXXXX", + getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP); + snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.pubkeysig", + packagesite); + + if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) { + fprintf(stderr, "Signature for pkg not " + "available.\n"); + goto fetchfail; + } + + if (verify_pubsignature(fd_pkg, fd_sig) == false) + goto cleanup; + } else { + warnx("Signature type %s is not supported for " + "bootstrapping.", signature_type); goto cleanup; + } } if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) @@ -862,21 +981,37 @@ bootstrap_pkg_local(const char *pkgpath, bool force) } if (signature_type != NULL && strcasecmp(signature_type, "NONE") != 0) { - if (strcasecmp(signature_type, "FINGERPRINTS") != 0) { - warnx("Signature type %s is not supported for " - "bootstrapping.", signature_type); - goto cleanup; - } + if (strcasecmp(signature_type, "FINGERPRINTS") == 0) { - snprintf(path, sizeof(path), "%s.sig", pkgpath); + snprintf(path, sizeof(path), "%s.sig", pkgpath); - if ((fd_sig = open(path, O_RDONLY)) == -1) { - fprintf(stderr, "Signature for pkg not available.\n"); - goto cleanup; - } + if ((fd_sig = open(path, O_RDONLY)) == -1) { + fprintf(stderr, "Signature for pkg not " + "available.\n"); + goto cleanup; + } - if (verify_signature(fd_pkg, fd_sig) == false) + if (verify_signature(fd_pkg, fd_sig) == false) + goto cleanup; + + } else if (strcasecmp(signature_type, "PUBKEY") == 0) { + + snprintf(path, sizeof(path), "%s.pubkeysig", pkgpath); + + if ((fd_sig = open(path, O_RDONLY)) == -1) { + fprintf(stderr, "Signature for pkg not " + "available.\n"); + goto cleanup; + } + + if (verify_pubsignature(fd_pkg, fd_sig) == false) + goto cleanup; + + } else { + warnx("Signature type %s is not supported for " + "bootstrapping.", signature_type); goto cleanup; + } } if ((ret = extract_pkg_static(fd_pkg, pkgstatic, MAXPATHLEN)) == 0) diff --git a/usr.sbin/rtsold/Makefile b/usr.sbin/rtsold/Makefile index a235dfb..caef62c 100644 --- a/usr.sbin/rtsold/Makefile +++ b/usr.sbin/rtsold/Makefile @@ -20,6 +20,6 @@ MLINKS= rtsold.8 rtsol.8 SRCS= rtsold.c rtsol.c if.c probe.c dump.c rtsock.c WARNS?= 3 -CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H +CFLAGS+= -DHAVE_ARC4RANDOM .include <bsd.prog.mk> diff --git a/usr.sbin/rtsold/if.c b/usr.sbin/rtsold/if.c index b8a90b6..cb4b001 100644 --- a/usr.sbin/rtsold/if.c +++ b/usr.sbin/rtsold/if.c @@ -280,18 +280,18 @@ lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) struct sockaddr_dl * if_nametosdl(char *name) { - int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; + int mib[] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; char *buf, *next, *lim; size_t len; struct if_msghdr *ifm; struct sockaddr *sa, *rti_info[RTAX_MAX]; struct sockaddr_dl *sdl = NULL, *ret_sdl; - if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) + if (sysctl(mib, nitems(mib), NULL, &len, NULL, 0) < 0) return(NULL); if ((buf = malloc(len)) == NULL) return(NULL); - if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { + if (sysctl(mib, nitems(mib), buf, &len, NULL, 0) < 0) { free(buf); return (NULL); } @@ -341,7 +341,7 @@ getinet6sysctl(int code) mib[3] = code; size = sizeof(value); - if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) < 0) + if (sysctl(mib, nitems(mib), &value, &size, NULL, 0) < 0) return (-1); else return (value); @@ -356,7 +356,7 @@ setinet6sysctl(int code, int newval) mib[3] = code; size = sizeof(value); - if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, + if (sysctl(mib, nitems(mib), &value, &size, &newval, sizeof(newval)) < 0) return (-1); else diff --git a/usr.sbin/rtsold/rtsold.c b/usr.sbin/rtsold/rtsold.c index bba15bb..18621bd 100644 --- a/usr.sbin/rtsold/rtsold.c +++ b/usr.sbin/rtsold/rtsold.c @@ -57,9 +57,7 @@ #include <err.h> #include <stdarg.h> #include <ifaddrs.h> -#ifdef HAVE_POLL_H #include <poll.h> -#endif #include "rtsold.h" @@ -116,13 +114,7 @@ main(int argc, char **argv) int s, ch, once = 0; struct timespec *timeout; const char *opts; -#ifdef HAVE_POLL_H struct pollfd set[2]; -#else - fd_set *fdsetp, *selectfdp; - int fdmasks; - int maxfd; -#endif int rtsock; char *argv0; @@ -254,40 +246,16 @@ main(int argc, char **argv) warnmsg(LOG_ERR, __func__, "failed to open a socket"); exit(1); } -#ifdef HAVE_POLL_H set[0].fd = s; set[0].events = POLLIN; -#else - maxfd = s; -#endif - -#ifdef HAVE_POLL_H set[1].fd = -1; -#endif if ((rtsock = rtsock_open()) < 0) { warnmsg(LOG_ERR, __func__, "failed to open a socket"); exit(1); } -#ifdef HAVE_POLL_H set[1].fd = rtsock; set[1].events = POLLIN; -#else - if (rtsock > maxfd) - maxfd = rtsock; -#endif - -#ifndef HAVE_POLL_H - fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask); - if ((fdsetp = malloc(fdmasks)) == NULL) { - warnmsg(LOG_ERR, __func__, "malloc"); - exit(1); - } - if ((selectfdp = malloc(fdmasks)) == NULL) { - warnmsg(LOG_ERR, __func__, "malloc"); - exit(1); - } -#endif /* configuration per interface */ if (ifinit()) { @@ -328,18 +296,8 @@ main(int argc, char **argv) fclose(fp); } } -#ifndef HAVE_POLL_H - memset(fdsetp, 0, fdmasks); - FD_SET(s, fdsetp); - FD_SET(rtsock, fdsetp); -#endif while (1) { /* main loop */ int e; - -#ifndef HAVE_POLL_H - memcpy(selectfdp, fdsetp, fdmasks); -#endif - #ifndef SMALL if (do_dump) { /* SIGUSR1 */ do_dump = 0; @@ -364,11 +322,7 @@ main(int argc, char **argv) if (ifi == NULL) break; } -#ifdef HAVE_POLL_H e = poll(set, 2, timeout ? (timeout->tv_sec * 1000 + timeout->tv_nsec / 1000 / 1000) : INFTIM); -#else - e = select(maxfd + 1, selectfdp, NULL, NULL, timeout); -#endif if (e < 1) { if (e < 0 && errno != EINTR) { warnmsg(LOG_ERR, __func__, "select: %s", @@ -378,17 +332,9 @@ main(int argc, char **argv) } /* packet reception */ -#ifdef HAVE_POLL_H if (set[1].revents & POLLIN) -#else - if (FD_ISSET(rtsock, selectfdp)) -#endif rtsock_input(rtsock); -#ifdef HAVE_POLL_H if (set[0].revents & POLLIN) -#else - if (FD_ISSET(s, selectfdp)) -#endif rtsol_input(s); } /* NOTREACHED */ diff --git a/usr.sbin/service/service.sh b/usr.sbin/service/service.sh index b5fd607..7aaecff 100755 --- a/usr.sbin/service/service.sh +++ b/usr.sbin/service/service.sh @@ -71,6 +71,9 @@ if [ -n "$RESTART" ]; then if grep -q ^rcvar $file; then eval `grep ^name= $file` eval `grep ^rcvar $file` + if [ -n "$rcvar" ]; then + load_rc_config_var ${name} ${rcvar} + fi checkyesno $rcvar 2>/dev/null && run_rc_script ${file} stop fi done @@ -100,6 +103,9 @@ if [ -n "$ENABLED" ]; then if grep -q ^rcvar $file; then eval `grep ^name= $file` eval `grep ^rcvar $file` + if [ -n "$rcvar" ]; then + load_rc_config_var ${name} ${rcvar} + fi checkyesno $rcvar 2>/dev/null && echo $file fi done diff --git a/usr.sbin/wpa/hostapd/Makefile b/usr.sbin/wpa/hostapd/Makefile index 04fbc4d..743f917 100644 --- a/usr.sbin/wpa/hostapd/Makefile +++ b/usr.sbin/wpa/hostapd/Makefile @@ -35,15 +35,15 @@ FILES= hostapd.conf hostapd.eap_user hostapd.wpa_psk .endif CFLAGS+=-DCONFIG_DRIVER_BSD \ - -DHOSTAPD \ -DCONFIG_DRIVER_RADIUS_ACL \ - -DCONFIG_RSN_PREAUTH \ + -DCONFIG_HS20 \ + -DCONFIG_INTERWORKING \ -DCONFIG_PEERKEY \ + -DCONFIG_RSN_PREAUTH \ -DCONFIG_WPS \ -DCONFIG_WPS2 \ -DCONFIG_WPS_UPNP \ - -DCONFIG_INTERWORKING \ - -DCONFIG_HS20 + -DHOSTAPD .if ${MK_INET6} != "no" CFLAGS+= -DCONFIG_IPV6 .endif @@ -65,8 +65,8 @@ CFLAGS+=-DDPKCS12_FUNCS \ -DEAP_SERVER_PEAP \ -DEAP_SERVER_TLS \ -DEAP_SERVER_TTLS \ - -DEAP_TLS_FUNCS \ - -DEAP_SERVER_WSC + -DEAP_SERVER_WSC \ + -DEAP_TLS_FUNCS SRCS+= eap_server_gtc.c \ eap_server_identity.c \ diff --git a/usr.sbin/wpa/wpa_supplicant/Makefile b/usr.sbin/wpa/wpa_supplicant/Makefile index ecbacb1..badae0d 100644 --- a/usr.sbin/wpa/wpa_supplicant/Makefile +++ b/usr.sbin/wpa/wpa_supplicant/Makefile @@ -38,18 +38,18 @@ CFLAGS+=-DCONFIG_BACKEND_FILE \ -DCONFIG_DRIVER_BSD \ -DCONFIG_DRIVER_NDIS \ -DCONFIG_DRIVER_WIRED \ + -DCONFIG_GAS \ + -DCONFIG_HS20 \ + -DCONFIG_IEEE80211R \ + -DCONFIG_INTERWORKING \ -DCONFIG_PEERKEY \ + -DCONFIG_PRIVSEP \ -DCONFIG_SMARTCARD \ -DCONFIG_TERMINATE_ONLASTIF \ + -DCONFIG_TLS=openssl \ -DCONFIG_WPS \ -DCONFIG_WPS2 \ -DCONFIG_WPS_UPNP \ - -DCONFIG_TLS=openssl \ - -DCONFIG_IEEE80211R \ - -DCONFIG_INTERWORKING \ - -DCONFIG_PRIVSEP \ - -DCONFIG_HS20 \ - -DCONFIG_GAS \ -DPKCS12_FUNCS #CFLAGS+= -g LIBADD= pcap util @@ -70,9 +70,6 @@ CFLAGS+=-DEAP_GTC \ -DEAP_PSK \ -DEAP_TLS \ -DEAP_TTLS \ - -DEAP_GTC \ - -DEAP_OTP \ - -DEAP_LEAP \ -DIEEE8021X_EAPOL SRCS+= chap.c \ eap.c \ |