diff options
author | Simon J. Gerraty <sjg@FreeBSD.org> | 2014-05-08 23:54:15 +0000 |
---|---|---|
committer | Simon J. Gerraty <sjg@FreeBSD.org> | 2014-05-08 23:54:15 +0000 |
commit | cc3f4b99653c34ae64f8a1fddea370abefef680e (patch) | |
tree | 8ce0ddd0e6f508bd20c77429c448969589170fae | |
parent | f974b33f6ed6f35170c520d2be111bfc2c3954cd (diff) | |
parent | 16aa1f0950a3b4407a36ecc96acc8ca0710ebd91 (diff) | |
download | src-test-cc3f4b99653c34ae64f8a1fddea370abefef680e.tar.gz src-test-cc3f4b99653c34ae64f8a1fddea370abefef680e.zip |
Notes
696 files changed, 44633 insertions, 5424 deletions
diff --git a/Makefile b/Makefile index 924ad9eb9389e..b6cad2f953df0 100644 --- a/Makefile +++ b/Makefile @@ -139,11 +139,7 @@ _MAKEOBJDIRPREFIX!= /usr/bin/env -i PATH=${PATH} ${MAKE} \ # Choices add to complexity though. # We cannot blindly use a make which may not be the one we want # so be exlicit - until all choice is removed. -.if !defined(WITHOUT_BMAKE) WANT_MAKE= bmake -.else -WANT_MAKE= fmake -.endif MYMAKE= ${MAKEOBJDIRPREFIX}${.CURDIR}/make.${MACHINE}/${WANT_MAKE} .if defined(.PARSEDIR) HAVE_MAKE= bmake @@ -152,7 +148,7 @@ HAVE_MAKE= fmake .endif .if exists(${MYMAKE}) SUB_MAKE:= ${MYMAKE} -m ${.CURDIR}/share/mk -.elif ${WANT_MAKE} != ${HAVE_MAKE} || ${WANT_MAKE} != "bmake" +.elif ${WANT_MAKE} != ${HAVE_MAKE} # It may not exist yet but we may cause it to. # In the case of fmake, upgrade_checks may cause a newer version to be built. SUB_MAKE= `test -x ${MYMAKE} && echo ${MYMAKE} || echo ${MAKE}` \ @@ -238,8 +234,17 @@ tinderbox toolchains kernel-toolchains: .MAKE ${TGTS}: ${_+_}@cd ${.CURDIR}; ${_MAKE} ${.TARGET} -# Set a reasonable default -.MAIN: all +# The historic default "all" target creates files which may cause stale +# or (in the cross build case) unlinkable results. Fail with an error +# when no target is given. The users can explicitly specify "all" +# if they want the historic behavior. +.MAIN: _guard + +_guard: + @echo + @echo "Explicit target required (use \"all\" for historic behavior)" + @echo + @false STARTTIME!= LC_ALL=C date CHECK_TIME!= find ${.CURDIR}/sys/sys/param.h -mtime -0s ; echo @@ -342,7 +347,7 @@ make bmake: .PHONY ${MMAKE} obj && \ ${MMAKE} depend && \ ${MMAKE} all && \ - ${MMAKE} install DESTDIR=${MYMAKE:H} BINDIR= + ${MMAKE} install DESTDIR=${MYMAKE:H} BINDIR= NO_MAN=t tinderbox toolchains kernel-toolchains: upgrade_checks @@ -449,9 +454,15 @@ universe_kernels: universe_kernconfs .if !defined(TARGET) TARGET!= uname -m .endif +.if defined(MAKE_ALL_KERNELS) +_THINNER=cat +.else +_THINNER=xargs grep -L "^.NO_UNIVERSE" +.endif KERNCONFS!= cd ${KERNSRCDIR}/${TARGET}/conf && \ find [A-Z0-9]*[A-Z0-9] -type f -maxdepth 0 \ - ! -name DEFAULTS ! -name NOTES + ! -name DEFAULTS ! -name NOTES | \ + ${_THINNER} universe_kernconfs: .for kernel in ${KERNCONFS} TARGET_ARCH_${kernel}!= cd ${KERNSRCDIR}/${TARGET}/conf && \ diff --git a/Makefile.inc1 b/Makefile.inc1 index c9ad941b0fe6d..549aa2fff001c 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -45,7 +45,7 @@ .error "Both TARGET and TARGET_ARCH must be defined." .endif -.include <bsd.own.mk> +.include "share/mk/src.opts.mk" .include <bsd.arch.inc.mk> .include <bsd.compiler.mk> @@ -1001,7 +1001,7 @@ buildkernel: cd ${KRNLCONFDIR}; \ PATH=${TMPPATH} \ config ${CONFIGARGS} -d ${KRNLOBJDIR}/${_kernel} \ - -I ${KERNCONFDIR} ${KERNCONFDIR}/${_kernel} + -I '${KERNCONFDIR}' '${KERNCONFDIR}/${_kernel}' .endif .if !defined(NO_CLEAN) && !defined(NO_KERNELCLEAN) @echo @@ -1480,6 +1480,7 @@ _prebuild_libs= ${_kerberos5_lib_libasn1} \ ${_secure_lib_libssh} ${_secure_lib_libssl} .if ${MK_GNUCXX} != "no" && ${MK_CXX} != "no" _prebuild_libs+= gnu/lib/libstdc++ gnu/lib/libsupc++ +gnu/lib/libstdc++__L: lib/msun__L .endif .if defined(WITH_ATF) || ${MK_TESTS} != "no" @@ -1807,7 +1808,7 @@ check-old: check-old-files check-old-libs check-old-dirs # showconfig - show build configuration. # showconfig: - @${MAKE} -n -f bsd.own.mk -V dummy -dg1 2>&1 | grep ^MK_ | sort + @${MAKE} -n -f src.opts.mk -V dummy -dg1 2>&1 | grep ^MK_ | sort .if !empty(KRNLOBJDIR) && !empty(KERNCONF) DTBOUTPUTPATH= ${KRNLOBJDIR}/${KERNCONF}/ @@ -1815,7 +1816,7 @@ DTBOUTPUTPATH= ${KRNLOBJDIR}/${KERNCONF}/ .if !defined(FDT_DTS_FILE) || empty(FDT_DTS_FILE) .if exists(${KERNCONFDIR}/${KERNCONF}) FDT_DTS_FILE!= awk 'BEGIN {FS="="} /^makeoptions[[:space:]]+FDT_DTS_FILE/ {print $$2}' \ - ${KERNCONFDIR}/${KERNCONF} ; echo + '${KERNCONFDIR}/${KERNCONF}' ; echo .endif .endif @@ -1829,24 +1830,9 @@ DTBOUTPUTPATH= ${.CURDIR} # Build 'standalone' Device Tree Blob # builddtb: - @if [ "${FDT_DTS_FILE}" = "" ]; then \ - echo "ERROR: FDT_DTS_FILE must be specified!"; \ - exit 1; \ - fi; \ - if [ ! -f ${.CURDIR}/sys/boot/fdt/dts/${TARGET}/${FDT_DTS_FILE} ]; then \ - echo "ERROR: Specified DTS file (${FDT_DTS_FILE}) does not \ - exist!"; \ - exit 1; \ - fi; \ - if [ "${DTBOUTPUTPATH}" = "${.CURDIR}" ]; then \ - echo "WARNING: DTB will be placed in the current working \ - directory"; \ - fi - @PATH=${TMPPATH} \ - MACHINE=${TARGET} \ + @PATH=${TMPPATH} MACHINE=${TARGET} \ ${.CURDIR}/sys/tools/fdt/make_dtb.sh ${.CURDIR}/sys \ - ${FDT_DTS_FILE} \ - ${DTBOUTPUTPATH}/`basename ${FDT_DTS_FILE} .dts` + "${FDT_DTS_FILE}" ${DTBOUTPUTPATH} ############### diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc index 4e49cdf3ef40f..2f6f9f3e2bef4 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -38,6 +38,14 @@ # xargs -n1 | sort | uniq -d; # done +# 20140505: Bogusly installing src.opts.mk +OLD_FILES+=usr/share/mk/src.opts.mk +# 20140505: Reject PR kern/187551 +OLD_DIRS+=usr/tests/sbin/ifconfig +OLD_FILES+=usr/tests/sbin/ifconfig/Kyuafile +OLD_FILES+=usr/tests/sbin/ifconfig/fibs_test +# 20140502: Removal of lindev(4) +OLD_FILES+=usr/share/man/man4/lindev.4.gz # 20140314: AppleTalk OLD_DIRS+=usr/include/netatalk OLD_FILES+=usr/include/netatalk/aarp.h @@ -49,7 +57,6 @@ OLD_FILES+=usr/include/netatalk/ddp_pcb.h OLD_FILES+=usr/include/netatalk/ddp_var.h OLD_FILES+=usr/include/netatalk/endian.h OLD_FILES+=usr/include/netatalk/phase2.h - # 20140314: Remove IPX/SPX OLD_LIBS+=lib/libipx.so.5 OLD_FILES+=usr/include/netipx/ipx.h diff --git a/UPDATING b/UPDATING index b1e55e3e87a2f..c0585c84b5e49 100644 --- a/UPDATING +++ b/UPDATING @@ -12,9 +12,9 @@ Items affecting the ports and packages system can be found in /usr/ports/UPDATING. Please read that file before running portupgrade. NOTE: FreeBSD has switched from gcc to clang. If you have trouble bootstrapping -from older versions of FreeBSD, try WITHOUT_CLANG to bootstrap to the tip of -head, and then rebuild without this option. The bootstrap process from -older version of current is a bit fragile. +from older versions of FreeBSD, try WITHOUT_CLANG and WITH_GCC to bootstrap to +the tip of head, and then rebuild without this option. The bootstrap process from +older version of current across the gcc/clang cutover is a bit fragile. NOTE TO PEOPLE WHO THINK THAT FreeBSD 11.x IS SLOW: FreeBSD 11.x has many debugging features turned on, in both the kernel @@ -31,6 +31,33 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 11.x IS SLOW: disable the most expensive debugging functionality run "ln -s 'abort:false,junk:false' /etc/malloc.conf".) +20140508: + We bogusly installed src.opts.mk in /usr/share/mk. This file should + be removed to avoid issues in the future (and has been added to + ObsoleteFiles.inc). + +20140505: + /etc/src.conf now affects only builds of the FreeBSD src tree. In the + past, it affected all builds that used the bsd.*.mk files. The old + behavior was a bug, but people may have relied upon it. To get this + behavior back, you can .include /etc/src.conf from /etc/make.conf + (which is still global and isn't changed). This also changes the + behavior of incremental builds inside the tree of individual + directories. Set MAKESYSPATH to ".../share/mk" to do that. + Although this has survived make universe and some upgrade scenarios, + other upgrade scenarios may have broken. At least one form of + temporary breakage was fixed with MAKESYSPATH settings for buildworld + as well... + + One side effect of all this cleaning up is that bsd.compiler.mk + is no longer implicitly included by bsd.own.mk. If you wish to + use COMPILER_TYPE, you must now explicitly include bsd.compiler.mk + as well. + +20140430: + The lindev device has been removed since /dev/full has been made a + standard device. __FreeBSD_version has been bumped. + 20140418: The YES_HESIOD knob has been removed. It has been obsolete for a decade. Please move to using WITH_HESIOD instead or your builds @@ -648,1264 +675,6 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 11.x IS SLOW: The stable/9 branch created in subversion. This corresponds to the RELENG_9 branch in CVS. -20110913: - This commit modifies vfs_register() so that it uses a hash - calculation to set vfc_typenum, which is enabled by default. - The first time a system is booted after this change, the - vfc_typenum values will change for all file systems. The - main effect of this is a change to the NFS server file handles - for file systems that use vfc_typenum in their fsid, such as ZFS. - It will, however, prevent vfc_typenum from changing when file - systems are loaded in a different order for subsequent reboots. - To disable this, you can set vfs.typenumhash=0 in /boot/loader.conf - until you are ready to remount all NFS clients after a reboot. - -20110828: - Bump the shared library version numbers for libraries that - do not use symbol versioning, have changed the ABI compared - to stable/8 and which shared library version was not bumped. - Done as part of 9.0-RELEASE cycle. - -20110815: - During the merge of Capsicum features, the fget(9) KPI was modified. - This may require the rebuilding of out-of-tree device drivers -- - issues have been reported specifically with the nVidia device driver. - __FreeBSD_version is bumped to 900041. - - Also, there is a period between 20110811 and 20110814 where the - special devices /dev/{stdin,stdout,stderr} did not work correctly. - Building world from a kernel during that window may not work. - -20110628: - The packet filter (pf) code has been updated to OpenBSD 4.5. - You need to update userland tools to be in sync with kernel. - This update breaks backward compatibility with earlier pfsync(4) - versions. Care must be taken when updating redundant firewall setups. - -20110608: - The following sysctls and tunables are retired on x86 platforms: - machdep.hlt_cpus - machdep.hlt_logical_cpus - The following sysctl is retired: - machdep.hyperthreading_allowed - The sysctls were supposed to provide a way to dynamically offline and - online selected CPUs on x86 platforms, but the implementation has not - been reliable especially with SCHED_ULE scheduler. - machdep.hyperthreading_allowed tunable is still available to ignore - hyperthreading CPUs at OS level. - Individual CPUs can be disabled using hint.lapic.X.disabled tunable, - where X is an APIC ID of a CPU. Be advised, though, that disabling - CPUs in non-uniform fashion will result in non-uniform topology and - may lead to sub-optimal system performance with SCHED_ULE, which is - a default scheduler. - -20110607: - cpumask_t type is retired and cpuset_t is used in order to describe - a mask of CPUs. - -20110531: - Changes to ifconfig(8) for dynamic address family detection mandate - that you are running a kernel of 20110525 or later. Make sure to - follow the update procedure to boot a new kernel before installing - world. - -20110513: - Support for sun4v architecture is officially dropped - -20110503: - Several KPI breaking changes have been committed to the mii(4) layer, - the PHY drivers and consequently some Ethernet drivers using mii(4). - This means that miibus.ko and the modules of the affected Ethernet - drivers need to be recompiled. - - Note to kernel developers: Given that the OUI bit reversion problem - was fixed as part of these changes all mii(4) commits related to OUIs, - i.e. to sys/dev/mii/miidevs, PHY driver probing and vendor specific - handling, no longer can be merged verbatim to stable/8 and previous - branches. - -20110430: - Users of the Atheros AR71xx SoC code now need to add 'device ar71xx_pci' - into their kernel configurations along with 'device pci'. - -20110427: - The default NFS client is now the new NFS client, so fstype "newnfs" - is now "nfs" and the regular/old NFS client is now fstype "oldnfs". - Although mounts via fstype "nfs" will usually work without userland - changes, it is recommended that the mount(8) and mount_nfs(8) - commands be rebuilt from sources and that a link to mount_nfs called - mount_oldnfs be created. The new client is compiled into the - kernel with "options NFSCL" and this is needed for diskless root - file systems. The GENERIC kernel configs have been changed to use - NFSCL and NFSD (the new server) instead of NFSCLIENT and NFSSERVER. - To use the regular/old client, you can "mount -t oldnfs ...". For - a diskless root file system, you must also include a line like: - - vfs.root.mountfrom="oldnfs:" - - in the boot/loader.conf on the root fs on the NFS server to make - a diskless root fs use the old client. - -20110424: - The GENERIC kernels for all architectures now default to the new - CAM-based ATA stack. It means that all legacy ATA drivers were - removed and replaced by respective CAM drivers. If you are using - ATA device names in /etc/fstab or other places, make sure to update - them respectively (adX -> adaY, acdX -> cdY, afdX -> daY, astX -> saY, - where 'Y's are the sequential numbers starting from zero for each type - in order of detection, unless configured otherwise with tunables, - see cam(4)). There will be symbolic links created in /dev/ to map - old adX devices to the respective adaY. They should provide basic - compatibility for file systems mounting in most cases, but they do - not support old user-level APIs and do not have respective providers - in GEOM. Consider using updated management tools with new device names. - - It is possible to load devices ahci, ata, siis and mvs as modules, - but option ATA_CAM should remain in kernel configuration to make ata - module work as CAM driver supporting legacy ATA controllers. Device ata - still can be used in modular fashion (atacore + ...). Modules atadisk - and atapi* are not used and won't affect operation in ATA_CAM mode. - Note that to use CAM-based ATA kernel should include CAM devices - scbus, pass, da (or explicitly ada), cd and optionally others. All of - them are parts of the cam module. - - ataraid(4) functionality is now supported by the RAID GEOM class. - To use it you can load geom_raid kernel module and use graid(8) tool - for management. Instead of /dev/arX device names, use /dev/raid/rX. - - No kernel config options or code have been removed, so if a problem - arises, please report it and optionally revert to the old ATA stack. - In order to do it you can remove from the kernel config: - options ATA_CAM - device ahci - device mvs - device siis - , and instead add back: - device atadisk # ATA disk drives - device ataraid # ATA RAID drives - device atapicd # ATAPI CDROM drives - device atapifd # ATAPI floppy drives - device atapist # ATAPI tape drives - -20110423: - The default NFS server has been changed to the new server, which - was referred to as the experimental server. If you need to switch - back to the old NFS server, you must now put the "-o" option on - both the mountd and nfsd commands. This can be done using the - mountd_flags and nfs_server_flags rc.conf variables until an - update to the rc scripts is committed, which is coming soon. - -20110418: - The GNU Objective-C runtime library (libobjc), and other Objective-C - related components have been removed from the base system. If you - require an Objective-C library, please use one of the available ports. - -20110331: - ath(4) has been split into bus- and device- modules. if_ath contains - the HAL, the TX rate control and the network device code. if_ath_pci - contains the PCI bus glue. For Atheros MIPS embedded systems, if_ath_ahb - contains the AHB glue. Users need to load both if_ath_pci and if_ath - in order to use ath on everything else. - - TO REPEAT: if_ath_ahb is not needed for normal users. Normal users only - need to load if_ath and if_ath_pci for ath(4) operation. - -20110314: - As part of the replacement of sysinstall, the process of building - release media has changed significantly. For details, please re-read - release(7), which has been updated to reflect the new build process. - -20110218: - GNU binutils 2.17.50 (as of 2007-07-03) has been merged to -HEAD. This - is the last available version under GPLv2. It brings a number of new - features, such as support for newer x86 CPU's (with SSE-3, SSSE-3, SSE - 4.1 and SSE 4.2), better support for powerpc64, a number of new - directives, and lots of other small improvements. See the ChangeLog - file in contrib/binutils for the full details. - -20110218: - IPsec's HMAC_SHA256-512 support has been fixed to be RFC4868 - compliant, and will now use half of hash for authentication. - This will break interoperability with all stacks (including all - actual FreeBSD versions) who implement - draft-ietf-ipsec-ciph-sha-256-00 (they use 96 bits of hash for - authentication). - The only workaround with such peers is to use another HMAC - algorithm for IPsec ("phase 2") authentication. - -20110207: - Remove the uio_yield prototype and symbol. This function has - been misnamed since it was introduced and should not be - globally exposed with this name. The equivalent functionality - is now available using kern_yield(curthread->td_user_pri). - The function remains undocumented. - -20110112: - A SYSCTL_[ADD_]UQUAD was added for unsigned uint64_t pointers, - symmetric with the existing SYSCTL_[ADD_]QUAD. Type checking - for scalar sysctls is defined but disabled. Code that needs - UQUAD to pass the type checking that must compile on older - systems where the define is not present can check against - __FreeBSD_version >= 900030. - - The system dialog(1) has been replaced with a new version previously - in ports as devel/cdialog. dialog(1) is mostly command-line compatible - with the previous version, but the libdialog associated with it has - a largely incompatible API. As such, the original version of libdialog - will be kept temporarily as libodialog, until its base system consumers - are replaced or updated. Bump __FreeBSD_version to 900030. - -20110103: - If you are trying to run make universe on a -stable system, and you get - the following warning: - "Makefile", line 356: "Target architecture for i386/conf/GENERIC - unknown. config(8) likely too old." - or something similar to it, then you must upgrade your -stable system - to 8.2-Release or newer (really, any time after r210146 7/15/2010 in - stable/8) or build the config from the latest stable/8 branch and - install it on your system. - - Prior to this date, building a current universe on 8-stable system from - between 7/15/2010 and 1/2/2011 would result in a weird shell parsing - error in the first kernel build phase. A new config on those old - systems will fix that problem for older versions of -current. - -20101228: - The TCP stack has been modified to allow Khelp modules to interact with - it via helper hook points and store per-connection data in the TCP - control block. Bump __FreeBSD_version to 900029. User space tools that - rely on the size of struct tcpcb in tcp_var.h (e.g. sockstat) need to - be recompiled. - -20101114: - Generic IEEE 802.3 annex 31B full duplex flow control support has been - added to mii(4) and bge(4), bce(4), msk(4), nfe(4) and stge(4) along - with brgphy(4), e1000phy(4) as well as ip1000phy() have been converted - to take advantage of it instead of using custom implementations. This - means that these drivers now no longer unconditionally advertise - support for flow control but only do so if flow control is a selected - media option. This was implemented in the generic support that way in - order to allow flow control to be switched on and off via ifconfig(8) - with the PHY specific default to typically off in order to protect - from unwanted effects. Consequently, if you used flow control with - one of the above mentioned drivers you now need to explicitly enable - it, for example via: - ifconfig bge0 media auto mediaopt flowcontrol - - Along with the above mentioned changes generic support for setting - 1000baseT master mode also has been added and brgphy(4), ciphy(4), - e1000phy(4) as well as ip1000phy(4) have been converted to take - advantage of it. This means that these drivers now no longer take the - link0 parameter for selecting master mode but the master media option - has to be used instead, for example like in the following: - ifconfig bge0 media 1000baseT mediaopt full-duplex,master - - Selection of master mode now is also available with all other PHY - drivers supporting 1000baseT. - -20101111: - The TCP stack has received a significant update to add support for - modularised congestion control and generally improve the clarity of - congestion control decisions. Bump __FreeBSD_version to 900025. User - space tools that rely on the size of struct tcpcb in tcp_var.h (e.g. - sockstat) need to be recompiled. - -20101002: - The man(1) utility has been replaced by a new version that no longer - uses /etc/manpath.config. Please consult man.conf(5) for how to - migrate local entries to the new format. - -20100928: - The copyright strings printed by login(1) and sshd(8) at the time of a - new connection have been removed to follow other operating systems and - upstream sshd. - -20100915: - A workaround for a fixed ld bug has been removed in kernel code, - so make sure that your system ld is built from sources after - revision 210245 from 2010-07-19 (r211583 if building head kernel - on stable/8, r211584 for stable/7; both from 2010-08-21). - A symptom of incorrect ld version is different addresses for - set_pcpu section and __start_set_pcpu symbol in kernel and/or modules. - -20100913: - The $ipv6_prefer variable in rc.conf(5) has been split into - $ip6addrctl_policy and $ipv6_activate_all_interfaces. - - The $ip6addrctl_policy is a variable to choose a pre-defined - address selection policy set by ip6addrctl(8). A value - "ipv4_prefer", "ipv6_prefer" or "AUTO" can be specified. The - default is "AUTO". - - The $ipv6_activate_all_interfaces specifies whether IFDISABLED - flag (see an entry of 20090926) is set on an interface with no - corresponding $ifconfig_IF_ipv6 line. The default is "NO" for - security reason. If you want IPv6 link-local address on all - interfaces by default, set this to "YES". - - The old ipv6_prefer="YES" is equivalent to - ipv6_activate_all_interfaces="YES" and - ip6addrctl_policy="ipv6_prefer". - -20100913: - DTrace has grown support for userland tracing. Due to this, DTrace is - now i386 and amd64 only. - dtruss(1) is now installed by default on those systems and a new - kernel module is needed for userland tracing: fasttrap. - No changes to your kernel config file are necessary to enable - userland tracing, but you might consider adding 'STRIP=' and - 'CFLAGS+=-fno-omit-frame-pointer' to your make.conf if you want - to have informative userland stack traces in DTrace (ustack). - -20100725: - The acpi_aiboost(4) driver has been removed in favor of the new - aibs(4) driver. You should update your kernel configuration file. - -20100722: - BSD grep has been imported to the base system and it is built by - default. It is completely BSD licensed, highly GNU-compatible, uses - less memory than its GNU counterpart and has a small codebase. - However, it is slower than its GNU counterpart, which is mostly - noticeable for larger searches, for smaller ones it is measurable - but not significant. The reason is complex, the most important factor - is that we lack a modern and efficient regex library and GNU - overcomes this by optimizing the searches internally. Future work - on improving the regex performance is planned, for the meantime, - users that need better performance, can build GNU grep instead by - setting the WITH_GNU_GREP knob. - -20100713: - Due to the import of powerpc64 support, all existing powerpc kernel - configuration files must be updated with a machine directive like this: - machine powerpc powerpc - - In addition, an updated config(8) is required to build powerpc kernels - after this change. - -20100713: - A new version of ZFS (version 15) has been merged to -HEAD. - This version uses a python library for the following subcommands: - zfs allow, zfs unallow, zfs groupspace, zfs userspace. - For full functionality of these commands the following port must - be installed: sysutils/py-zfs - -20100429: - 'vm_page's are now hashed by physical address to an array of mutexes. - Currently this is only used to serialize access to hold_count. Over - time the page queue mutex will be peeled away. This changes the size - of pmap on every architecture. And requires all callers of vm_page_hold - and vm_page_unhold to be updated. - -20100402: - WITH_CTF can now be specified in src.conf (not recommended, there - are some problems with static executables), make.conf (would also - affect ports which do not use GNU make and do not override the - compile targets) or in the kernel config (via "makeoptions - WITH_CTF=yes"). - When WITH_CTF was specified there before this was silently ignored, - so make sure that WITH_CTF is not used in places which could lead - to unwanted behavior. - -20100311: - The kernel option COMPAT_IA32 has been replaced with COMPAT_FREEBSD32 - to allow 32-bit compatibility on non-x86 platforms. All kernel - configurations on amd64 and ia64 platforms using these options must - be modified accordingly. - -20100113: - The utmp user accounting database has been replaced with utmpx, - the user accounting interface standardized by POSIX. - Unfortunately the semantics of utmp and utmpx don't match, - making it practically impossible to support both interfaces. - The user accounting database is used by tools like finger(1), - last(1), talk(1), w(1) and ac(8). - - All applications in the base system use utmpx. This means only - local binaries (e.g. from the ports tree) may still use these - utmp database files. These applications must be rebuilt to make - use of utmpx. - - After the system has been upgraded, it is safe to remove the old - log files (/var/run/utmp, /var/log/lastlog and /var/log/wtmp*), - assuming their contents is of no importance anymore. Old wtmp - databases can only be used by last(1) and ac(8) after they have - been converted to the new format using wtmpcvt(1). - -20100108: - Introduce the kernel thread "deadlock resolver" (which can be enabled - via the DEADLKRES option, see NOTES for more details) and the - sleepq_type() function for sleepqueues. - -20091202: - The rc.firewall and rc.firewall6 were unified, and - rc.firewall6 and rc.d/ip6fw were removed. - According to the removal of rc.d/ip6fw, ipv6_firewall_* rc - variables are obsoleted. Instead, the following new rc - variables are added to rc.d/ipfw: - - firewall_client_net_ipv6, firewall_simple_iif_ipv6, - firewall_simple_inet_ipv6, firewall_simple_oif_ipv6, - firewall_simple_onet_ipv6, firewall_trusted_ipv6 - - The meanings correspond to the relevant IPv4 variables. - -20091125: - 8.0-RELEASE. - -20091113: - The default terminal emulation for syscons(4) has been changed - from cons25 to xterm on all platforms except pc98. This means - that the /etc/ttys file needs to be updated to ensure correct - operation of applications on the console. - - The terminal emulation style can be toggled per window by using - vidcontrol(1)'s -T flag. The TEKEN_CONS25 kernel configuration - options can be used to change the compile-time default back to - cons25. - - To prevent graphical artifacts, make sure the TERM environment - variable is set to match the terminal emulation that is being - performed by syscons(4). - -20091109: - The layout of the structure ieee80211req_scan_result has changed. - Applications that require wireless scan results (e.g. ifconfig(8)) - from net80211 need to be recompiled. - - Applications such as wpa_supplicant(8) may require a full world - build without using NO_CLEAN in order to get synchronized with the - new structure. - -20091025: - The iwn(4) driver has been updated to support the 5000 and 5150 series. - There's one kernel module for each firmware. Adding "device iwnfw" - to the kernel configuration file means including all three firmware - images inside the kernel. If you want to include just the one for - your wireless card, use the devices iwn4965fw, iwn5000fw or - iwn5150fw. - -20090926: - The rc.d/network_ipv6, IPv6 configuration script has been integrated - into rc.d/netif. The changes are the following: - - 1. To use IPv6, simply define $ifconfig_IF_ipv6 like $ifconfig_IF - for IPv4. For aliases, $ifconfig_IF_aliasN should be used. - Note that both variables need the "inet6" keyword at the head. - - Do not set $ipv6_network_interfaces manually if you do not - understand what you are doing. It is not needed in most cases. - - $ipv6_ifconfig_IF and $ipv6_ifconfig_IF_aliasN still work, but - they are obsolete. - - 2. $ipv6_enable is obsolete. Use $ipv6_prefer and - "inet6 accept_rtadv" keyword in ifconfig(8) instead. - - If you define $ipv6_enable=YES, it means $ipv6_prefer=YES and - all configured interfaces have "inet6 accept_rtadv" in the - $ifconfig_IF_ipv6. These are for backward compatibility. - - 3. A new variable $ipv6_prefer has been added. If NO, IPv6 - functionality of interfaces with no corresponding - $ifconfig_IF_ipv6 is disabled by using "inet6 ifdisabled" flag, - and the default address selection policy of ip6addrctl(8) - is the IPv4-preferred one (see rc.d/ip6addrctl for more details). - Note that if you want to configure IPv6 functionality on the - disabled interfaces after boot, first you need to clear the flag by - using ifconfig(8) like: - - ifconfig em0 inet6 -ifdisabled - - If YES, the default address selection policy is set as - IPv6-preferred. - - The default value of $ipv6_prefer is NO. - - 4. If your system need to receive Router Advertisement messages, - define "inet6 accept_rtadv" in $ifconfig_IF_ipv6. The rc(8) - scripts automatically invoke rtsol(8) when the interface becomes - UP. The Router Advertisement messages are used for SLAAC - (State-Less Address AutoConfiguration). - -20090922: - 802.11s D3.03 support was committed. This is incompatible with the - previous code, which was based on D3.0. - -20090912: - A sysctl variable net.inet6.ip6.accept_rtadv now sets the default value - of a per-interface flag ND6_IFF_ACCEPT_RTADV, not a global knob to - control whether accepting Router Advertisement messages or not. - Also, a per-interface flag ND6_IFF_AUTO_LINKLOCAL has been added and - a sysctl variable net.inet6.ip6.auto_linklocal is its default value. - The ifconfig(8) utility now supports these flags. - -20090910: - ZFS snapshots are now mounted with MNT_IGNORE flag. Use -v option for - mount(8) and -a option for df(1) to see them. - -20090825: - The old tunable hw.bus.devctl_disable has been superseded by - hw.bus.devctl_queue. hw.bus.devctl_disable=1 in loader.conf should be - replaced by hw.bus.devctl_queue=0. The default for this new tunable - is 1000. - -20090813: - Remove the option STOP_NMI. The default action is now to use NMI only - for KDB via the newly introduced function stop_cpus_hard() and - maintain stop_cpus() to just use a normal IPI_STOP on ia32 and amd64. - -20090803: - The stable/8 branch created in subversion. This corresponds to the - RELENG_8 branch in CVS. - -20090719: - Bump the shared library version numbers for all libraries that do not - use symbol versioning as part of the 8.0-RELEASE cycle. Bump - __FreeBSD_version to 800105. - -20090714: - Due to changes in the implementation of virtual network stack support, - all network-related kernel modules must be recompiled. As this change - breaks the ABI, bump __FreeBSD_version to 800104. - -20090713: - The TOE interface to the TCP syncache has been modified to remove - struct tcpopt (<netinet/tcp_var.h>) from the ABI of the network stack. - The cxgb driver is the only TOE consumer affected by this change, and - needs to be recompiled along with the kernel. As this change breaks - the ABI, bump __FreeBSD_version to 800103. - -20090712: - Padding has been added to struct tcpcb, sackhint and tcpstat in - <netinet/tcp_var.h> to facilitate future MFCs and bug fixes whilst - maintaining the ABI. However, this change breaks the ABI, so bump - __FreeBSD_version to 800102. User space tools that rely on the size of - any of these structs (e.g. sockstat) need to be recompiled. - -20090630: - The NFS_LEGACYRPC option has been removed along with the old kernel - RPC implementation that this option selected. Kernel configurations - may need to be adjusted. - -20090629: - The network interface device nodes at /dev/net/<interface> have been - removed. All ioctl operations can be performed the normal way using - routing sockets. The kqueue functionality can generally be replaced - with routing sockets. - -20090628: - The documentation from the FreeBSD Documentation Project (Handbook, - FAQ, etc.) is now installed via packages by sysinstall(8) and under - the /usr/local/share/doc/freebsd directory instead of /usr/share/doc. - -20090624: - The ABI of various structures related to the SYSV IPC API have been - changed. As a result, the COMPAT_FREEBSD[456] and COMPAT_43 kernel - options now all require COMPAT_FREEBSD7. Bump __FreeBSD_version to - 800100. - -20090622: - Layout of struct vnet has changed as routing related variables were - moved to their own Vimage module. Modules need to be recompiled. Bump - __FreeBSD_version to 800099. - -20090619: - NGROUPS_MAX and NGROUPS have been increased from 16 to 1023 and 1024 - respectively. As long as no more than 16 groups per process are used, - no changes should be visible. When more than 16 groups are used, old - binaries may fail if they call getgroups() or getgrouplist() with - statically sized storage. Recompiling will work around this, but - applications should be modified to use dynamically allocated storage - for group arrays as POSIX.1-2008 does not cap an implementation's - number of supported groups at NGROUPS_MAX+1 as previous versions did. - - NFS and portalfs mounts may also be affected as the list of groups is - truncated to 16. Users of NFS who use more than 16 groups, should - take care that negative group permissions are not used on the exported - file systems as they will not be reliable unless a GSSAPI based - authentication method is used. - -20090616: - The compiling option ADAPTIVE_LOCKMGRS has been introduced. This - option compiles in the support for adaptive spinning for lockmgrs - which want to enable it. The lockinit() function now accepts the flag - LK_ADAPTIVE in order to make the lock object subject to adaptive - spinning when both held in write and read mode. - -20090613: - The layout of the structure returned by IEEE80211_IOC_STA_INFO has - changed. User applications that use this ioctl need to be rebuilt. - -20090611: - The layout of struct thread has changed. Kernel and modules need to - be rebuilt. - -20090608: - The layout of structs ifnet, domain, protosw and vnet_net has changed. - Kernel modules need to be rebuilt. Bump __FreeBSD_version to 800097. - -20090602: - window(1) has been removed from the base system. It can now be - installed from ports. The port is called misc/window. - -20090601: - The way we are storing and accessing `routing table' entries has - changed. Programs reading the FIB, like netstat, need to be - re-compiled. - -20090601: - A new netisr implementation has been added for FreeBSD 8. Network - file system modules, such as igmp, ipdivert, and others, should be - rebuilt. - Bump __FreeBSD_version to 800096. - -20090530: - Remove the tunable/sysctl debug.mpsafevfs as its initial purpose is no - more valid. - -20090530: - Add VOP_ACCESSX(9). File system modules need to be rebuilt. - Bump __FreeBSD_version to 800094. - -20090529: - Add mnt_xflag field to 'struct mount'. File system modules need to be - rebuilt. - Bump __FreeBSD_version to 800093. - -20090528: - The compiling option ADAPTIVE_SX has been retired while it has been - introduced the option NO_ADAPTIVE_SX which handles the reversed logic. - The KPI for sx_init_flags() changes as accepting flags: - SX_ADAPTIVESPIN flag has been retired while the SX_NOADAPTIVE flag has - been introduced in order to handle the reversed logic. - Bump __FreeBSD_version to 800092. - -20090527: - Add support for hierarchical jails. Remove global securelevel. - Bump __FreeBSD_version to 800091. - -20090523: - The layout of struct vnet_net has changed, therefore modules - need to be rebuilt. - Bump __FreeBSD_version to 800090. - -20090523: - The newly imported zic(8) produces a new format in the output. Please - run tzsetup(8) to install the newly created data to /etc/localtime. - -20090520: - The sysctl tree for the usb stack has renamed from hw.usb2.* to - hw.usb.* and is now consistent again with previous releases. - -20090520: - 802.11 monitor mode support was revised and driver api's were changed. - Drivers dependent on net80211 now support DLT_IEEE802_11_RADIO instead - of DLT_IEEE802_11. No user-visible data structures were changed but - applications that use DLT_IEEE802_11 may require changes. - Bump __FreeBSD_version to 800088. - -20090430: - The layout of the following structs has changed: sysctl_oid, - socket, ifnet, inpcbinfo, tcpcb, syncache_head, vnet_inet, - vnet_inet6 and vnet_ipfw. Most modules need to be rebuild or - panics may be experienced. World rebuild is required for - correctly checking networking state from userland. - Bump __FreeBSD_version to 800085. - -20090429: - MLDv2 and Source-Specific Multicast (SSM) have been merged - to the IPv6 stack. VIMAGE hooks are in but not yet used. - The implementation of SSM within FreeBSD's IPv6 stack closely - follows the IPv4 implementation. - - For kernel developers: - - * The most important changes are that the ip6_output() and - ip6_input() paths no longer take the IN6_MULTI_LOCK, - and this lock has been downgraded to a non-recursive mutex. - - * As with the changes to the IPv4 stack to support SSM, filtering - of inbound multicast traffic must now be performed by transport - protocols within the IPv6 stack. This does not apply to TCP and - SCTP, however, it does apply to UDP in IPv6 and raw IPv6. - - * The KPIs used by IPv6 multicast are similar to those used by - the IPv4 stack, with the following differences: - * im6o_mc_filter() is analogous to imo_multicast_filter(). - * The legacy KAME entry points in6_joingroup and in6_leavegroup() - are shimmed to in6_mc_join() and in6_mc_leave() respectively. - * IN6_LOOKUP_MULTI() has been deprecated and removed. - * IPv6 relies on MLD for the DAD mechanism. KAME's internal KPIs - for MLDv1 have an additional 'timer' argument which is used to - jitter the initial membership report for the solicited-node - multicast membership on-link. - * This is not strictly needed for MLDv2, which already jitters - its report transmissions. However, the 'timer' argument is - preserved in case MLDv1 is active on the interface. - - * The KAME linked-list based IPv6 membership implementation has - been refactored to use a vector similar to that used by the IPv4 - stack. - Code which maintains a list of its own multicast memberships - internally, e.g. carp, has been updated to reflect the new - semantics. - - * There is a known Lock Order Reversal (LOR) due to in6_setscope() - acquiring the IF_AFDATA_LOCK and being called within ip6_output(). - Whilst MLDv2 tries to avoid this otherwise benign LOR, it is an - implementation constraint which needs to be addressed in HEAD. - - For application developers: - - * The changes are broadly similar to those made for the IPv4 - stack. - - * The use of IPv4 and IPv6 multicast socket options on the same - socket, using mapped addresses, HAS NOT been tested or supported. - - * There are a number of issues with the implementation of various - IPv6 multicast APIs which need to be resolved in the API surface - before the implementation is fully compatible with KAME userland - use, and these are mostly to do with interface index treatment. - - * The literature available discusses the use of either the delta / ASM - API with setsockopt(2)/getsockopt(2), or the full-state / ASM API - using setsourcefilter(3)/getsourcefilter(3). For more information - please refer to RFC 3768, 'Socket Interface Extensions for - Multicast Source Filters'. - - * Applications which use the published RFC 3678 APIs should be fine. - - For systems administrators: - - * The mtest(8) utility has been refactored to support IPv6, in - addition to IPv4. Interface addresses are no longer accepted - as arguments, their names must be used instead. The utility - will map the interface name to its first IPv4 address as - returned by getifaddrs(3). - - * The ifmcstat(8) utility has also been updated to print the MLDv2 - endpoint state and source filter lists via sysctl(3). - - * The net.inet6.ip6.mcast.loop sysctl may be tuned to 0 to disable - loopback of IPv6 multicast datagrams by default; it defaults to 1 - to preserve the existing behaviour. Disabling multicast loopback is - recommended for optimal system performance. - - * The IPv6 MROUTING code has been changed to examine this sysctl - instead of attempting to perform a group lookup before looping - back forwarded datagrams. - - Bump __FreeBSD_version to 800084. - -20090422: - Implement low-level Bluetooth HCI API. - Bump __FreeBSD_version to 800083. - -20090419: - The layout of struct malloc_type, used by modules to register new - memory allocation types, has changed. Most modules will need to - be rebuilt or panics may be experienced. - Bump __FreeBSD_version to 800081. - -20090415: - Anticipate overflowing inp_flags - add inp_flags2. - This changes most offsets in inpcb, so checking v4 connection - state will require a world rebuild. - Bump __FreeBSD_version to 800080. - -20090415: - Add an llentry to struct route and struct route_in6. Modules - embedding a struct route will need to be recompiled. - Bump __FreeBSD_version to 800079. - -20090414: - The size of rt_metrics_lite and by extension rtentry has changed. - Networking administration apps will need to be recompiled. - The route command now supports show as an alias for get, weighting - of routes, sticky and nostick flags to alter the behavior of stateful - load balancing. - Bump __FreeBSD_version to 800078. - -20090408: - Do not use Giant for kbdmux(4) locking. This is wrong and - apparently causing more problems than it solves. This will - re-open the issue where interrupt handlers may race with - kbdmux(4) in polling mode. Typical symptoms include (but - not limited to) duplicated and/or missing characters when - low level console functions (such as gets) are used while - interrupts are enabled (for example geli password prompt, - mountroot prompt etc.). Disabling kbdmux(4) may help. - -20090407: - The size of structs vnet_net, vnet_inet and vnet_ipfw has changed; - kernel modules referencing any of the above need to be recompiled. - Bump __FreeBSD_version to 800075. - -20090320: - GEOM_PART has become the default partition slicer for storage devices, - replacing GEOM_MBR, GEOM_BSD, GEOM_PC98 and GEOM_GPT slicers. It - introduces some changes: - - MSDOS/EBR: the devices created from MSDOS extended partition entries - (EBR) can be named differently than with GEOM_MBR and are now symlinks - to devices with offset-based names. fstabs may need to be modified. - - BSD: the "geometry does not match label" warning is harmless in most - cases but it points to problems in file system misalignment with - disk geometry. The "c" partition is now implicit, covers the whole - top-level drive and cannot be (mis)used by users. - - General: Kernel dumps are now not allowed to be written to devices - whose partition types indicate they are meant to be used for file - systems (or, in case of MSDOS partitions, as something else than - the "386BSD" type). - - Most of these changes date approximately from 200812. - -20090319: - The uscanner(4) driver has been removed from the kernel. This follows - Linux removing theirs in 2.6 and making libusb the default interface - (supported by sane). - -20090319: - The multicast forwarding code has been cleaned up. netstat(1) - only relies on KVM now for printing bandwidth upcall meters. - The IPv4 and IPv6 modules are split into ip_mroute_mod and - ip6_mroute_mod respectively. The config(5) options for statically - compiling this code remain the same, i.e. 'options MROUTING'. - -20090315: - Support for the IFF_NEEDSGIANT network interface flag has been - removed, which means that non-MPSAFE network device drivers are no - longer supported. In particular, if_ar, if_sr, and network device - drivers from the old (legacy) USB stack can no longer be built or - used. - -20090313: - POSIX.1 Native Language Support (NLS) has been enabled in libc and - a bunch of new language catalog files have also been added. - This means that some common libc messages are now localized and - they depend on the LC_MESSAGES environmental variable. - -20090313: - The k8temp(4) driver has been renamed to amdtemp(4) since - support for Family 10 and Family 11 CPU families was added. - -20090309: - IGMPv3 and Source-Specific Multicast (SSM) have been merged - to the IPv4 stack. VIMAGE hooks are in but not yet used. - - For kernel developers, the most important changes are that the - ip_output() and ip_input() paths no longer take the IN_MULTI_LOCK(), - and this lock has been downgraded to a non-recursive mutex. - - Transport protocols (UDP, Raw IP) are now responsible for filtering - inbound multicast traffic according to group membership and source - filters. The imo_multicast_filter() KPI exists for this purpose. - Transports which do not use multicast (SCTP, TCP) already reject - multicast by default. Forwarding and receive performance may improve - as a mutex acquisition is no longer needed in the ip_input() - low-level input path. in_addmulti() and in_delmulti() are shimmed - to new KPIs which exist to support SSM in-kernel. - - For application developers, it is recommended that loopback of - multicast datagrams be disabled for best performance, as this - will still cause the lock to be taken for each looped-back - datagram transmission. The net.inet.ip.mcast.loop sysctl may - be tuned to 0 to disable loopback by default; it defaults to 1 - to preserve the existing behaviour. - - For systems administrators, to obtain best performance with - multicast reception and multiple groups, it is always recommended - that a card with a suitably precise hash filter is used. Hash - collisions will still result in the lock being taken within the - transport protocol input path to check group membership. - - If deploying FreeBSD in an environment with IGMP snooping switches, - it is recommended that the net.inet.igmp.sendlocal sysctl remain - enabled; this forces 224.0.0.0/24 group membership to be announced - via IGMP. - - The size of 'struct igmpstat' has changed; netstat needs to be - recompiled to reflect this. - Bump __FreeBSD_version to 800070. - -20090309: - libusb20.so.1 is now installed as libusb.so.1 and the ports system - updated to use it. This requires a buildworld/installworld in order to - update the library and dependencies (usbconfig, etc). Its advisable to - rebuild all ports which uses libusb. More specific directions are given - in the ports collection UPDATING file. Any /etc/libmap.conf entries for - libusb are no longer required and can be removed. - -20090302: - A workaround is committed to allow the creation of System V shared - memory segment of size > 2 GB on the 64-bit architectures. - Due to a limitation of the existing ABI, the shm_segsz member - of the struct shmid_ds, returned by shmctl(IPC_STAT) call is - wrong for large segments. Note that limits must be explicitly - raised to allow such segments to be created. - -20090301: - The layout of struct ifnet has changed, requiring a rebuild of all - network device driver modules. - -20090227: - The /dev handling for the new USB stack has changed, a - buildworld/installworld is required for libusb20. - -20090223: - The new USB2 stack has now been permanently moved in and all kernel and - module names reverted to their previous values (eg, usb, ehci, ohci, - ums, ...). The old usb stack can be compiled in by prefixing the name - with the letter 'o', the old usb modules have been removed. - Updating entry 20090216 for xorg and 20090215 for libmap may still - apply. - -20090217: - The rc.conf(5) option if_up_delay has been renamed to - defaultroute_delay to better reflect its purpose. If you have - customized this setting in /etc/rc.conf you need to update it to - use the new name. - -20090216: - xorg 7.4 wants to configure its input devices via hald which does not - yet work with USB2. If the keyboard/mouse does not work in xorg then - add - Option "AllowEmptyInput" "off" - to your ServerLayout section. This will cause X to use the configured - kbd and mouse sections from your xorg.conf. - -20090215: - The GENERIC kernels for all architectures now default to the new USB2 - stack. No kernel config options or code have been removed so if a - problem arises please report it and optionally revert to the old USB - stack. If you are loading USB kernel modules or have a custom kernel - that includes GENERIC then ensure that usb names are also changed over, - eg uftdi -> usb2_serial_ftdi. - - Older programs linked against the ports libusb 0.1 need to be - redirected to the new stack's libusb20. /etc/libmap.conf can - be used for this: - # Map old usb library to new one for usb2 stack - libusb-0.1.so.8 libusb20.so.1 - -20090209: - All USB ethernet devices now attach as interfaces under the name ueN - (eg. ue0). This is to provide a predictable name as vendors often - change usb chipsets in a product without notice. - -20090203: - The ichsmb(4) driver has been changed to require SMBus slave - addresses be left-justified (xxxxxxx0b) rather than right-justified. - All of the other SMBus controller drivers require left-justified - slave addresses, so this change makes all the drivers provide the - same interface. - -20090201: - INET6 statistics (struct ip6stat) was updated. - netstat(1) needs to be recompiled. - -20090119: - NTFS has been removed from GENERIC kernel on amd64 to match - GENERIC on i386. Should not cause any issues since mount_ntfs(8) - will load ntfs.ko module automatically when NTFS support is - actually needed, unless ntfs.ko is not installed or security - level prohibits loading kernel modules. If either is the case, - "options NTFS" has to be added into kernel config. - -20090115: - TCP Appropriate Byte Counting (RFC 3465) support added to kernel. - New field in struct tcpcb breaks ABI, so bump __FreeBSD_version to - 800061. User space tools that rely on the size of struct tcpcb in - tcp_var.h (e.g. sockstat) need to be recompiled. - -20081225: - ng_tty(4) module updated to match the new TTY subsystem. - Due to API change, user-level applications must be updated. - New API support added to mpd5 CVS and expected to be present - in next mpd5.3 release. - -20081219: - With __FreeBSD_version 800060 the makefs tool is part of - the base system (it was a port). - -20081216: - The afdata and ifnet locks have been changed from mutexes to - rwlocks, network modules will need to be re-compiled. - -20081214: - __FreeBSD_version 800059 incorporates the new arp-v2 rewrite. - RTF_CLONING, RTF_LLINFO and RTF_WASCLONED flags are eliminated. - The new code reduced struct rtentry{} by 16 bytes on 32-bit - architecture and 40 bytes on 64-bit architecture. The userland - applications "arp" and "ndp" have been updated accordingly. - The output from "netstat -r" shows only routing entries and - none of the L2 information. - -20081130: - __FreeBSD_version 800057 marks the switchover from the - binary ath hal to source code. Users must add the line: - - options AH_SUPPORT_AR5416 - - to their kernel config files when specifying: - - device ath_hal - - The ath_hal module no longer exists; the code is now compiled - together with the driver in the ath module. It is now - possible to tailor chip support (i.e. reduce the set of chips - and thereby the code size); consult ath_hal(4) for details. - -20081121: - __FreeBSD_version 800054 adds memory barriers to - <machine/atomic.h>, new interfaces to ifnet to facilitate - multiple hardware transmit queues for cards that support - them, and a lock-less ring-buffer implementation to - enable drivers to more efficiently manage queueing of - packets. - -20081117: - A new version of ZFS (version 13) has been merged to -HEAD. - This version has zpool attribute "listsnapshots" off by - default, which means "zfs list" does not show snapshots, - and is the same as Solaris behavior. - -20081028: - dummynet(4) ABI has changed. ipfw(8) needs to be recompiled. - -20081009: - The uhci, ohci, ehci and slhci USB Host controller drivers have - been put into separate modules. If you load the usb module - separately through loader.conf you will need to load the - appropriate *hci module as well. E.g. for a UHCI-based USB 2.0 - controller add the following to loader.conf: - - uhci_load="YES" - ehci_load="YES" - -20081009: - The ABI used by the PMC toolset has changed. Please keep - userland (libpmc(3)) and the kernel module (hwpmc(4)) in - sync. - -20081009: - atapci kernel module now includes only generic PCI ATA - driver. AHCI driver moved to ataahci kernel module. - All vendor-specific code moved into separate kernel modules: - ataacard, ataacerlabs, ataadaptec, ataamd, ataati, atacenatek, - atacypress, atacyrix, atahighpoint, ataintel, ataite, atajmicron, - atamarvell, atamicron, atanational, atanetcell, atanvidia, - atapromise, ataserverworks, atasiliconimage, atasis, atavia - -20080820: - The TTY subsystem of the kernel has been replaced by a new - implementation, which provides better scalability and an - improved driver model. Most common drivers have been migrated to - the new TTY subsystem, while others have not. The following - drivers have not yet been ported to the new TTY layer: - - PCI/ISA: - cy, digi, rc, rp, sio - - USB: - ubser, ucycom - - Line disciplines: - ng_h4, ng_tty, ppp, sl, snp - - Adding these drivers to your kernel configuration file shall - cause compilation to fail. - -20080818: - ntpd has been upgraded to 4.2.4p5. - -20080801: - OpenSSH has been upgraded to 5.1p1. - - For many years, FreeBSD's version of OpenSSH preferred DSA - over RSA for host and user authentication keys. With this - upgrade, we've switched to the vendor's default of RSA over - DSA. This may cause upgraded clients to warn about unknown - host keys even for previously known hosts. Users should - follow the usual procedure for verifying host keys before - accepting the RSA key. - - This can be circumvented by setting the "HostKeyAlgorithms" - option to "ssh-dss,ssh-rsa" in ~/.ssh/config or on the ssh - command line. - - Please note that the sequence of keys offered for - authentication has been changed as well. You may want to - specify IdentityFile in a different order to revert this - behavior. - -20080713: - The sio(4) driver has been removed from the i386 and amd64 - kernel configuration files. This means uart(4) is now the - default serial port driver on those platforms as well. - - To prevent collisions with the sio(4) driver, the uart(4) driver - uses different names for its device nodes. This means the - onboard serial port will now most likely be called "ttyu0" - instead of "ttyd0". You may need to reconfigure applications to - use the new device names. - - When using the serial port as a boot console, be sure to update - /boot/device.hints and /etc/ttys before booting the new kernel. - If you forget to do so, you can still manually specify the hints - at the loader prompt: - - set hint.uart.0.at="isa" - set hint.uart.0.port="0x3F8" - set hint.uart.0.flags="0x10" - set hint.uart.0.irq="4" - boot -s - -20080609: - The gpt(8) utility has been removed. Use gpart(8) to partition - disks instead. - -20080603: - The version that Linuxulator emulates was changed from 2.4.2 - to 2.6.16. If you experience any problems with Linux binaries - please try to set sysctl compat.linux.osrelease to 2.4.2 and - if it fixes the problem contact emulation mailing list. - -20080525: - ISDN4BSD (I4B) was removed from the src tree. You may need to - update a your kernel configuration and remove relevant entries. - -20080509: - I have checked in code to support multiple routing tables. - See the man pages setfib(1) and setfib(2). - This is a hopefully backwards compatible version, - but to make use of it you need to compile your kernel - with options ROUTETABLES=2 (or more up to 16). - -20080420: - The 802.11 wireless support was redone to enable multi-bss - operation on devices that are capable. The underlying device - is no longer used directly but instead wlanX devices are - cloned with ifconfig. This requires changes to rc.conf files. - For example, change: - ifconfig_ath0="WPA DHCP" - to - wlans_ath0=wlan0 - ifconfig_wlan0="WPA DHCP" - see rc.conf(5) for more details. In addition, mergemaster of - /etc/rc.d is highly recommended. Simultaneous update of userland - and kernel wouldn't hurt either. - - As part of the multi-bss changes the wlan_scan_ap and wlan_scan_sta - modules were merged into the base wlan module. All references - to these modules (e.g. in kernel config files) must be removed. - -20080408: - psm(4) has gained write(2) support in native operation level. - Arbitrary commands can be written to /dev/psm%d and status can - be read back from it. Therefore, an application is responsible - for status validation and error recovery. It is a no-op in - other operation levels. - -20080312: - Support for KSE threading has been removed from the kernel. To - run legacy applications linked against KSE libmap.conf may - be used. The following libmap.conf may be used to ensure - compatibility with any prior release: - - libpthread.so.1 libthr.so.1 - libpthread.so.2 libthr.so.2 - libkse.so.3 libthr.so.3 - -20080301: - The layout of struct vmspace has changed. This affects libkvm - and any executables that link against libkvm and use the - kvm_getprocs() function. In particular, but not exclusively, - it affects ps(1), fstat(1), pkill(1), systat(1), top(1) and w(1). - The effects are minimal, but it's advisable to upgrade world - nonetheless. - -20080229: - The latest em driver no longer has support in it for the - 82575 adapter, this is now moved to the igb driver. The - split was done to make new features that are incompatible - with older hardware easier to do. - -20080220: - The new geom_lvm(4) geom class has been renamed to geom_linux_lvm(4), - likewise the kernel option is now GEOM_LINUX_LVM. - -20080211: - The default NFS mount mode has changed from UDP to TCP for - increased reliability. If you rely on (insecurely) NFS - mounting across a firewall you may need to update your - firewall rules. - -20080208: - Belatedly note the addition of m_collapse for compacting - mbuf chains. - -20080126: - The fts(3) structures have been changed to use adequate - integer types for their members and so to be able to cope - with huge file trees. The old fts(3) ABI is preserved - through symbol versioning in libc, so third-party binaries - using fts(3) should still work, although they will not take - advantage of the extended types. At the same time, some - third-party software might fail to build after this change - due to unportable assumptions made in its source code about - fts(3) structure members. Such software should be fixed - by its vendor or, in the worst case, in the ports tree. - FreeBSD_version 800015 marks this change for the unlikely - case that a portable fix is impossible. - -20080123: - To upgrade to -current after this date, you must be running - FreeBSD not older than 6.0-RELEASE. Upgrading to -current - from 5.x now requires a stop over at RELENG_6 or RELENG_7 systems. - -20071128: - The ADAPTIVE_GIANT kernel option has been retired because its - functionality is the default now. - -20071118: - The AT keyboard emulation of sunkbd(4) has been turned on - by default. In order to make the special symbols of the Sun - keyboards driven by sunkbd(4) work under X these now have - to be configured the same way as Sun USB keyboards driven - by ukbd(4) (which also does AT keyboard emulation), f.e.: - - Option "XkbLayout" "us" - Option "XkbRules" "xorg" - Option "XkbSymbols" "pc(pc105)+sun_vndr/usb(sun_usb)+us" - -20071024: - It has been decided that it is desirable to provide ABI - backwards compatibility to the FreeBSD 4/5/6 versions of the - PCIOCGETCONF, PCIOCREAD and PCIOCWRITE IOCTLs, which was - broken with the introduction of PCI domain support (see the - 20070930 entry). Unfortunately, this required the ABI of - PCIOCGETCONF to be broken again in order to be able to - provide backwards compatibility to the old version of that - IOCTL. Thus consumers of PCIOCGETCONF have to be recompiled - again. As for prominent ports this affects neither pciutils - nor xorg-server this time, the hal port needs to be rebuilt - however. - -20071020: - The misnamed kthread_create() and friends have been renamed - to kproc_create() etc. Many of the callers already - used kproc_start().. - I will return kthread_create() and friends in a while - with implementations that actually create threads, not procs. - Renaming corresponds with version 800002. - -20071010: - RELENG_7 branched. - COMMON ITEMS: General Notes diff --git a/bin/Makefile b/bin/Makefile index 63d96fedbdfe2..ae509c41470ea 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -1,7 +1,7 @@ # From: @(#)Makefile 8.1 (Berkeley) 5/31/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= cat \ chflags \ diff --git a/bin/Makefile.inc b/bin/Makefile.inc index ec24a486b9de6..86141a1387f9a 100644 --- a/bin/Makefile.inc +++ b/bin/Makefile.inc @@ -1,7 +1,7 @@ # @(#)Makefile.inc 8.1 (Berkeley) 5/31/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> BINDIR?= /bin WARNS?= 6 diff --git a/bin/csh/Makefile b/bin/csh/Makefile index 1fa24a1f9d738..c8845f9523c9e 100644 --- a/bin/csh/Makefile +++ b/bin/csh/Makefile @@ -6,7 +6,7 @@ # # To profile, put -DPROF in DEFS and -pg in CFLAGS, and recompile. -.include <bsd.own.mk> +.include <src.opts.mk> TCSHDIR= ${.CURDIR}/../../contrib/tcsh .PATH: ${TCSHDIR} diff --git a/bin/date/Makefile b/bin/date/Makefile index 6da5848e16abb..56ce33afb4568 100644 --- a/bin/date/Makefile +++ b/bin/date/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 5/31/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= date SRCS= date.c netdate.c vary.c diff --git a/bin/dd/conv.c b/bin/dd/conv.c index cd66258c29452..2ffba1eaaa0b3 100644 --- a/bin/dd/conv.c +++ b/bin/dd/conv.c @@ -74,7 +74,7 @@ def(void) dd_out(0); /* - * Ddout copies the leftover output to the beginning of + * dd_out copies the leftover output to the beginning of * the buffer and resets the output buffer. Reset the * input buffer to match it. */ diff --git a/bin/dd/dd.c b/bin/dd/dd.c index 7e5bd913a2df3..8ae11a7d16368 100644 --- a/bin/dd/dd.c +++ b/bin/dd/dd.c @@ -50,8 +50,8 @@ __FBSDID("$FreeBSD$"); #include <sys/conf.h> #include <sys/disklabel.h> #include <sys/filio.h> -#include <sys/time.h> +#include <assert.h> #include <ctype.h> #include <err.h> #include <errno.h> @@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include <unistd.h> #include "dd.h" @@ -76,6 +77,7 @@ STAT st; /* statistics */ void (*cfunc)(void); /* conversion function */ uintmax_t cpy_cnt; /* # of blocks to copy */ static off_t pending = 0; /* pending seek if sparse */ +static off_t last_sp = 0; /* size of last added sparse block */ u_int ddflags = 0; /* conversion options */ size_t cbsz; /* conversion block size */ uintmax_t files_cnt = 1; /* # of files to copy */ @@ -123,7 +125,6 @@ static void setup(void) { u_int cnt; - struct timeval tv; if (in.name == NULL) { in.name = "stdin"; @@ -173,6 +174,8 @@ setup(void) } else if ((in.db = malloc(MAX(in.dbsz, cbsz) + cbsz)) == NULL || (out.db = malloc(out.dbsz + cbsz)) == NULL) err(1, "output buffer"); + + /* dbp is the first free position in each buffer. */ in.dbp = in.db; out.dbp = out.db; @@ -240,8 +243,8 @@ setup(void) ctab = casetab; } - (void)gettimeofday(&tv, NULL); - st.start = tv.tv_sec + tv.tv_usec * 1e-6; + if (clock_gettime(CLOCK_MONOTONIC, &st.start)) + err(1, "clock_gettime"); } static void @@ -434,8 +437,15 @@ dd_out(int force) * we play games with the buffer size, and it's usually a partial write. */ outp = out.db; + + /* + * If force, first try to write all pending data, else try to write + * just one block. Subsequently always write data one full block at + * a time at most. + */ for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { - for (cnt = n;; cnt -= nw) { + cnt = n; + do { sparse = 0; if (ddflags & C_SPARSE) { sparse = 1; /* Is buffer sparse? */ @@ -447,18 +457,24 @@ dd_out(int force) } if (sparse && !force) { pending += cnt; + last_sp = cnt; nw = cnt; } else { if (pending != 0) { - if (force) - pending--; + /* If forced to write, and we have no + * data left, we need to write the last + * sparse block explicitly. + */ + if (force && cnt == 0) { + pending -= last_sp; + assert(outp == out.db); + memset(outp, 0, cnt); + } if (lseek(out.fd, pending, SEEK_CUR) == -1) err(2, "%s: seek error creating sparse file", out.name); - if (force) - write(out.fd, outp, 1); - pending = 0; + pending = last_sp = 0; } if (cnt) nw = write(out.fd, outp, cnt); @@ -473,27 +489,29 @@ dd_out(int force) err(1, "%s", out.name); nw = 0; } + outp += nw; st.bytes += nw; - if ((size_t)nw == n) { - if (n != out.dbsz) - ++st.out_part; - else - ++st.out_full; - break; - } - ++st.out_part; - if ((size_t)nw == cnt) - break; - if (out.flags & ISTAPE) - errx(1, "%s: short write on tape device", - out.name); - if (out.flags & ISCHR && !warned) { - warned = 1; - warnx("%s: short write on character device", - out.name); + + if ((size_t)nw == n && n == out.dbsz) + ++st.out_full; + else + ++st.out_part; + + if ((size_t) nw != cnt) { + if (out.flags & ISTAPE) + errx(1, "%s: short write on tape device", + out.name); + if (out.flags & ISCHR && !warned) { + warned = 1; + warnx("%s: short write on character device", + out.name); + } } - } + + cnt -= nw; + } while (cnt != 0); + if ((out.dbcnt -= n) < out.dbsz) break; } diff --git a/bin/dd/dd.h b/bin/dd/dd.h index dace84526f52a..a8b45e594776a 100644 --- a/bin/dd/dd.h +++ b/bin/dd/dd.h @@ -41,7 +41,7 @@ typedef struct { /* XXX ssize_t? */ size_t dbcnt; /* current buffer byte count */ size_t dbrcnt; /* last read byte count */ - size_t dbsz; /* buffer size */ + size_t dbsz; /* block size */ #define ISCHR 0x01 /* character device (warn on short) */ #define ISPIPE 0x02 /* pipe-like (see position.c) */ @@ -64,7 +64,7 @@ typedef struct { uintmax_t trunc; /* # of truncated records */ uintmax_t swab; /* # of odd-length swab blocks */ uintmax_t bytes; /* # of bytes written */ - double start; /* start time of dd */ + struct timespec start; /* start time of dd */ } STAT; /* Flags (in ddflags). */ diff --git a/bin/dd/misc.c b/bin/dd/misc.c index 61f843bf13a43..eb1227bb5ac67 100644 --- a/bin/dd/misc.c +++ b/bin/dd/misc.c @@ -40,14 +40,15 @@ static char sccsid[] = "@(#)misc.c 8.3 (Berkeley) 4/2/94"; __FBSDID("$FreeBSD$"); #include <sys/types.h> -#include <sys/time.h> +#include <err.h> #include <errno.h> #include <inttypes.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include <unistd.h> #include "dd.h" @@ -56,16 +57,21 @@ __FBSDID("$FreeBSD$"); void summary(void) { - struct timeval tv; - double secs; + struct timespec end, ts_res; + double secs, res; if (ddflags & C_NOINFO) return; - (void)gettimeofday(&tv, NULL); - secs = tv.tv_sec + tv.tv_usec * 1e-6 - st.start; - if (secs < 1e-6) - secs = 1e-6; + if (clock_gettime(CLOCK_MONOTONIC, &end)) + err(1, "clock_gettime"); + if (clock_getres(CLOCK_MONOTONIC, &ts_res)) + err(1, "clock_getres"); + secs = (end.tv_sec - st.start.tv_sec) + \ + (end.tv_nsec - st.start.tv_nsec) * 1e-9; + res = ts_res.tv_sec + ts_res.tv_nsec * 1e-9; + if (secs < res) + secs = res; (void)fprintf(stderr, "%ju+%ju records in\n%ju+%ju records out\n", st.in_full, st.in_part, st.out_full, st.out_part); diff --git a/bin/ed/Makefile b/bin/ed/Makefile index 7c39e54bdf46b..fb1c37da3d01b 100644 --- a/bin/ed/Makefile +++ b/bin/ed/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ed SRCS= buf.c cbc.c glbl.c io.c main.c re.c sub.c undo.c diff --git a/bin/ls/Makefile b/bin/ls/Makefile index 4d02a7ec94acd..7149d9146b0cd 100644 --- a/bin/ls/Makefile +++ b/bin/ls/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/2/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ls SRCS= cmp.c ls.c print.c util.c diff --git a/bin/mv/Makefile b/bin/mv/Makefile index ad8cc4f02d443..02a5a48058002 100644 --- a/bin/mv/Makefile +++ b/bin/mv/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.2 (Berkeley) 4/2/94 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= mv diff --git a/bin/pax/Makefile b/bin/pax/Makefile index 95f18bba1c06d..c00d52c70811f 100644 --- a/bin/pax/Makefile +++ b/bin/pax/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 5/31/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> # To install on versions prior to BSD 4.4 the following may have to be # defined with CFLAGS += diff --git a/bin/pkill/Makefile b/bin/pkill/Makefile index bb4d865b7ae26..11bfbe3295969 100644 --- a/bin/pkill/Makefile +++ b/bin/pkill/Makefile @@ -1,7 +1,7 @@ # $NetBSD: Makefile,v 1.1 2002/03/01 11:21:58 ad Exp $ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= pkill diff --git a/bin/ps/Makefile b/bin/ps/Makefile index 9be197933ee84..5ba4f2fa705b1 100644 --- a/bin/ps/Makefile +++ b/bin/ps/Makefile @@ -11,7 +11,7 @@ SRCS= fmt.c keyword.c nlist.c print.c ps.c # on large systems. # CFLAGS+=-DLAZY_PS -DPADD= ${LIBM} ${LIBKVM} -LDADD= -lm -lkvm +DPADD= ${LIBM} ${LIBKVM} ${LIBJAIL} +LDADD= -lm -lkvm -ljail .include <bsd.prog.mk> diff --git a/bin/ps/ps.1 b/bin/ps/ps.1 index 118e9618566bd..c4239ea5bccd6 100644 --- a/bin/ps/ps.1 +++ b/bin/ps/ps.1 @@ -29,7 +29,7 @@ .\" @(#)ps.1 8.3 (Berkeley) 4/18/94 .\" $FreeBSD$ .\" -.Dd December 27, 2013 +.Dd May 2, 2014 .Dt PS 1 .Os .Sh NAME @@ -40,6 +40,7 @@ .Op Fl aCcdefHhjlmrSTuvwXxZ .Op Fl O Ar fmt | Fl o Ar fmt .Op Fl G Ar gid Ns Op , Ns Ar gid Ns Ar ... +.Op Fl J Ar jid Ns Op , Ns Ar jid Ns Ar ... .Op Fl M Ar core .Op Fl N Ar system .Op Fl p Ar pid Ns Op , Ns Ar pid Ns Ar ... @@ -62,7 +63,7 @@ will also display processes that do not have controlling terminals. .Pp A different set of processes can be selected for display by using any combination of the -.Fl a , G , p , T , t , +.Fl a , G , J , p , T , t , and .Fl U options. @@ -152,6 +153,20 @@ Print information associated with the following keywords: .Cm user , pid , ppid , pgid , sid , jobc , state , tt , time , and .Cm command . +.It Fl J +Display information about processes which match the specified jail IDs. +This may be either the +.Cm jid +or +.Cm name +of the jail. +Use +.Fl J +.Sy 0 +to display only host processes. +This flag implies +.Fl x +by default. .It Fl L List the set of keywords available for the .Fl O diff --git a/bin/ps/ps.c b/bin/ps/ps.c index 7099cc0bff6a8..9d14a72c9a60e 100644 --- a/bin/ps/ps.c +++ b/bin/ps/ps.c @@ -50,6 +50,7 @@ static char sccsid[] = "@(#)ps.c 8.4 (Berkeley) 4/2/94"; __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/jail.h> #include <sys/proc.h> #include <sys/user.h> #include <sys/stat.h> @@ -62,6 +63,7 @@ __FBSDID("$FreeBSD$"); #include <errno.h> #include <fcntl.h> #include <grp.h> +#include <jail.h> #include <kvm.h> #include <limits.h> #include <locale.h> @@ -124,6 +126,7 @@ struct listinfo { const char *lname; union { gid_t *gids; + int *jids; pid_t *pids; dev_t *ttys; uid_t *uids; @@ -132,6 +135,7 @@ struct listinfo { }; static int addelem_gid(struct listinfo *, const char *); +static int addelem_jid(struct listinfo *, const char *); static int addelem_pid(struct listinfo *, const char *); static int addelem_tty(struct listinfo *, const char *); static int addelem_uid(struct listinfo *, const char *); @@ -163,12 +167,12 @@ static char vfmt[] = "pid,state,time,sl,re,pagein,vsz,rss,lim,tsiz," "%cpu,%mem,command"; static char Zfmt[] = "label"; -#define PS_ARGS "AaCcde" OPT_LAZY_f "G:gHhjLlM:mN:O:o:p:rSTt:U:uvwXxZ" +#define PS_ARGS "AaCcde" OPT_LAZY_f "G:gHhjJ:LlM:mN:O:o:p:rSTt:U:uvwXxZ" int main(int argc, char *argv[]) { - struct listinfo gidlist, pgrplist, pidlist; + struct listinfo gidlist, jidlist, pgrplist, pidlist; struct listinfo ruidlist, sesslist, ttylist, uidlist; struct kinfo_proc *kp; KINFO *kinfo = NULL, *next_KINFO; @@ -208,6 +212,7 @@ main(int argc, char *argv[]) prtheader = showthreads = wflag = xkeep_implied = 0; xkeep = -1; /* Neither -x nor -X. */ init_list(&gidlist, addelem_gid, sizeof(gid_t), "group"); + init_list(&jidlist, addelem_jid, sizeof(int), "jail id"); init_list(&pgrplist, addelem_pid, sizeof(pid_t), "process group"); init_list(&pidlist, addelem_pid, sizeof(pid_t), "process id"); init_list(&ruidlist, addelem_uid, sizeof(uid_t), "ruser"); @@ -275,6 +280,11 @@ main(int argc, char *argv[]) case 'h': prtheader = ws.ws_row > 5 ? ws.ws_row : 22; break; + case 'J': + add_list(&jidlist, optarg); + xkeep_implied = 1; + nselectors++; + break; case 'j': parsefmt(jfmt, 0); _fmt = 1; @@ -538,6 +548,11 @@ main(int argc, char *argv[]) if (kp->ki_rgid == gidlist.l.gids[elem]) goto keepit; } + if (jidlist.count > 0) { + for (elem = 0; elem < jidlist.count; elem++) + if (kp->ki_jid == jidlist.l.jids[elem]) + goto keepit; + } if (pgrplist.count > 0) { for (elem = 0; elem < pgrplist.count; elem++) if (kp->ki_pgid == @@ -666,6 +681,7 @@ main(int argc, char *argv[]) } } free_list(&gidlist); + free_list(&jidlist); free_list(&pidlist); free_list(&pgrplist); free_list(&ruidlist); @@ -727,6 +743,30 @@ addelem_gid(struct listinfo *inf, const char *elem) } static int +addelem_jid(struct listinfo *inf, const char *elem) +{ + int tempid; + + if (*elem == '\0') { + warnx("Invalid (zero-length) jail id"); + optfatal = 1; + return (0); /* Do not add this value. */ + } + + tempid = jail_getid(elem); + if (tempid < 0) { + warnx("Invalid %s: %s", inf->lname, elem); + optfatal = 1; + return (0); + } + + if (inf->count >= inf->maxcount) + expand_list(inf); + inf->l.jids[(inf->count)++] = tempid; + return (1); +} + +static int addelem_pid(struct listinfo *inf, const char *elem) { char *endp; @@ -1373,7 +1413,7 @@ usage(void) (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", "usage: ps " SINGLE_OPTS " [-O fmt | -o fmt] [-G gid[,gid...]]", - " [-M core] [-N system]", + " [-J jid[,jid...]] [-M core] [-N system]", " [-p pid[,pid...]] [-t tty[,tty...]] [-U user[,user...]]", " ps [-L]"); exit(1); diff --git a/bin/sh/Makefile b/bin/sh/Makefile index e1ce5feb1851f..6a982bc2b8b7d 100644 --- a/bin/sh/Makefile +++ b/bin/sh/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.4 (Berkeley) 5/5/95 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= sh INSTALLFLAGS= -S diff --git a/bin/sh/tests/builtins/Makefile b/bin/sh/tests/builtins/Makefile index 945a14d6c5184..c0b21dc6072d3 100644 --- a/bin/sh/tests/builtins/Makefile +++ b/bin/sh/tests/builtins/Makefile @@ -80,6 +80,9 @@ FILES+= for2.0 FILES+= for3.0 FILES+= getopts1.0 getopts1.0.stdout FILES+= getopts2.0 getopts2.0.stdout +FILES+= getopts3.0 +FILES+= getopts4.0 +FILES+= getopts5.0 FILES+= hash1.0 hash1.0.stdout FILES+= hash2.0 hash2.0.stdout FILES+= hash3.0 hash3.0.stdout diff --git a/bin/sh/tests/builtins/getopts3.0 b/bin/sh/tests/builtins/getopts3.0 new file mode 100644 index 0000000000000..d02469b204696 --- /dev/null +++ b/bin/sh/tests/builtins/getopts3.0 @@ -0,0 +1,6 @@ +# $FreeBSD$ + +shift $# +getopts x opt +r=$? +[ "$r" != 0 ] && [ "$OPTIND" = 1 ] diff --git a/bin/sh/tests/builtins/getopts4.0 b/bin/sh/tests/builtins/getopts4.0 new file mode 100644 index 0000000000000..61d5c2b6b15c2 --- /dev/null +++ b/bin/sh/tests/builtins/getopts4.0 @@ -0,0 +1,10 @@ +# $FreeBSD$ + +set -- -x +opt=not +getopts x opt +r1=$? OPTIND1=$OPTIND opt1=$opt +getopts x opt +r2=$? OPTIND2=$OPTIND +[ "$r1" = 0 ] && [ "$OPTIND1" = 2 ] && [ "$opt1" = x ] && [ "$r2" != 0 ] && + [ "$OPTIND2" = 2 ] diff --git a/bin/sh/tests/builtins/getopts5.0 b/bin/sh/tests/builtins/getopts5.0 new file mode 100644 index 0000000000000..666ee7652de50 --- /dev/null +++ b/bin/sh/tests/builtins/getopts5.0 @@ -0,0 +1,10 @@ +# $FreeBSD$ + +set -- -x arg +opt=not +getopts x opt +r1=$? OPTIND1=$OPTIND opt1=$opt +getopts x opt +r2=$? OPTIND2=$OPTIND +[ "$r1" = 0 ] && [ "$OPTIND1" = 2 ] && [ "$opt1" = x ] && [ "$r2" != 0 ] && + [ "$OPTIND2" = 2 ] diff --git a/bin/test/Makefile b/bin/test/Makefile index e9a0507f0caca..8e3121b3167f4 100644 --- a/bin/test/Makefile +++ b/bin/test/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 5/31/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= test LINKS= ${BINDIR}/test ${BINDIR}/[ diff --git a/cddl/Makefile b/cddl/Makefile index 2a9b6f8089d50..44b778dbfc6ba 100644 --- a/cddl/Makefile +++ b/cddl/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= lib sbin usr.bin usr.sbin diff --git a/cddl/compat/opensolaris/include/thread_pool.h b/cddl/compat/opensolaris/include/thread_pool.h index 25ac55dedea7e..3bd23a6dd2aa3 100644 --- a/cddl/compat/opensolaris/include/thread_pool.h +++ b/cddl/compat/opensolaris/include/thread_pool.h @@ -1,39 +1,78 @@ -/*- - * Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org> - * All rights reserved. +/* + * CDDL HEADER START * - * 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. + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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. + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* * $FreeBSD$ */ -#ifndef _OPENSOLARIS_THREAD_POOL_H_ -#define _OPENSOLARIS_THREAD_POOL_H_ +#ifndef _THREAD_POOL_H_ +#define _THREAD_POOL_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <thread.h> +#include <pthread.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct tpool tpool_t; /* opaque thread pool descriptor */ + +#if defined(__STDC__) + +extern tpool_t *tpool_create(uint_t min_threads, uint_t max_threads, + uint_t linger, pthread_attr_t *attr); +extern int tpool_dispatch(tpool_t *tpool, + void (*func)(void *), void *arg); +extern void tpool_destroy(tpool_t *tpool); +extern void tpool_abandon(tpool_t *tpool); +extern void tpool_wait(tpool_t *tpool); +extern void tpool_suspend(tpool_t *tpool); +extern int tpool_suspended(tpool_t *tpool); +extern void tpool_resume(tpool_t *tpool); +extern int tpool_member(tpool_t *tpool); + +#else /* Non ANSI */ + +extern tpool_t *tpool_create(); +extern int tpool_dispatch(); +extern void tpool_destroy(); +extern void tpool_abandon(); +extern void tpool_wait(); +extern void tpool_suspend(); +extern int tpool_suspended(); +extern void tpool_resume(); +extern int tpool_member(); -typedef int tpool_t; +#endif /* __STDC__ */ -#define tpool_create(a, b, c, d) (0) -#define tpool_dispatch(pool, func, arg) func(arg) -#define tpool_wait(pool) do { } while (0) -#define tpool_destroy(pool) do { } while (0) +#ifdef __cplusplus +} +#endif -#endif /* !_OPENSOLARIS_THREAD_POOL_H_ */ +#endif /* _THREAD_POOL_H_ */ diff --git a/cddl/compat/opensolaris/misc/thread_pool.c b/cddl/compat/opensolaris/misc/thread_pool.c new file mode 100644 index 0000000000000..a6a834fb2bbd9 --- /dev/null +++ b/cddl/compat/opensolaris/misc/thread_pool.c @@ -0,0 +1,430 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <signal.h> +#include <errno.h> +#include "thread_pool_impl.h" + +typedef void (*_Voidfp)(void*); /* pointer to extern "C" function */ + +static void +delete_pool(tpool_t *tpool) +{ + tpool_job_t *job; + + /* + * There should be no pending jobs, but just in case... + */ + for (job = tpool->tp_head; job != NULL; job = tpool->tp_head) { + tpool->tp_head = job->tpj_next; + free(job); + } + (void) pthread_attr_destroy(&tpool->tp_attr); + free(tpool); +} + +/* + * Worker thread is terminating. + */ +static void +worker_cleanup(void *arg) +{ + tpool_t *tpool = arg; + + if (--tpool->tp_current == 0 && + (tpool->tp_flags & (TP_DESTROY | TP_ABANDON))) { + if (tpool->tp_flags & TP_ABANDON) { + pthread_mutex_unlock(&tpool->tp_mutex); + delete_pool(tpool); + return; + } + if (tpool->tp_flags & TP_DESTROY) + (void) pthread_cond_broadcast(&tpool->tp_busycv); + } + pthread_mutex_unlock(&tpool->tp_mutex); +} + +static void +notify_waiters(tpool_t *tpool) +{ + if (tpool->tp_head == NULL && tpool->tp_active == NULL) { + tpool->tp_flags &= ~TP_WAIT; + (void) pthread_cond_broadcast(&tpool->tp_waitcv); + } +} + +/* + * Called by a worker thread on return from a tpool_dispatch()d job. + */ +static void +job_cleanup(void *arg) +{ + tpool_t *tpool = arg; + pthread_t my_tid = pthread_self(); + tpool_active_t *activep; + tpool_active_t **activepp; + + pthread_mutex_lock(&tpool->tp_mutex); + /* CSTYLED */ + for (activepp = &tpool->tp_active;; activepp = &activep->tpa_next) { + activep = *activepp; + if (activep->tpa_tid == my_tid) { + *activepp = activep->tpa_next; + break; + } + } + if (tpool->tp_flags & TP_WAIT) + notify_waiters(tpool); +} + +static void * +tpool_worker(void *arg) +{ + tpool_t *tpool = (tpool_t *)arg; + int elapsed; + tpool_job_t *job; + void (*func)(void *); + tpool_active_t active; + sigset_t maskset; + + pthread_mutex_lock(&tpool->tp_mutex); + pthread_cleanup_push(worker_cleanup, tpool); + + /* + * This is the worker's main loop. + * It will only be left if a timeout or an error has occured. + */ + active.tpa_tid = pthread_self(); + for (;;) { + elapsed = 0; + tpool->tp_idle++; + if (tpool->tp_flags & TP_WAIT) + notify_waiters(tpool); + while ((tpool->tp_head == NULL || + (tpool->tp_flags & TP_SUSPEND)) && + !(tpool->tp_flags & (TP_DESTROY | TP_ABANDON))) { + if (tpool->tp_current <= tpool->tp_minimum || + tpool->tp_linger == 0) { + (void) pthread_cond_wait(&tpool->tp_workcv, + &tpool->tp_mutex); + } else { + struct timespec timeout; + + clock_gettime(CLOCK_MONOTONIC, &timeout); + timeout.tv_sec += tpool->tp_linger; + if (pthread_cond_timedwait(&tpool->tp_workcv, + &tpool->tp_mutex, &timeout) != 0) { + elapsed = 1; + break; + } + } + } + tpool->tp_idle--; + if (tpool->tp_flags & TP_DESTROY) + break; + if (tpool->tp_flags & TP_ABANDON) { + /* can't abandon a suspended pool */ + if (tpool->tp_flags & TP_SUSPEND) { + tpool->tp_flags &= ~TP_SUSPEND; + (void) pthread_cond_broadcast(&tpool->tp_workcv); + } + if (tpool->tp_head == NULL) + break; + } + if ((job = tpool->tp_head) != NULL && + !(tpool->tp_flags & TP_SUSPEND)) { + elapsed = 0; + func = job->tpj_func; + arg = job->tpj_arg; + tpool->tp_head = job->tpj_next; + if (job == tpool->tp_tail) + tpool->tp_tail = NULL; + tpool->tp_njobs--; + active.tpa_next = tpool->tp_active; + tpool->tp_active = &active; + pthread_mutex_unlock(&tpool->tp_mutex); + pthread_cleanup_push(job_cleanup, tpool); + free(job); + /* + * Call the specified function. + */ + func(arg); + /* + * We don't know what this thread has been doing, + * so we reset its signal mask and cancellation + * state back to the initial values. + */ + sigfillset(&maskset); + (void) pthread_sigmask(SIG_SETMASK, &maskset, NULL); + (void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, + NULL); + (void) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, + NULL); + pthread_cleanup_pop(1); + } + if (elapsed && tpool->tp_current > tpool->tp_minimum) { + /* + * We timed out and there is no work to be done + * and the number of workers exceeds the minimum. + * Exit now to reduce the size of the pool. + */ + break; + } + } + pthread_cleanup_pop(1); + return (arg); +} + +/* + * Create a worker thread, with all signals blocked. + */ +static int +create_worker(tpool_t *tpool) +{ + sigset_t maskset, oset; + pthread_t thread; + int error; + + sigfillset(&maskset); + (void) pthread_sigmask(SIG_SETMASK, &maskset, &oset); + error = pthread_create(&thread, &tpool->tp_attr, tpool_worker, tpool); + (void) pthread_sigmask(SIG_SETMASK, &oset, NULL); + return (error); +} + +tpool_t * +tpool_create(uint_t min_threads, uint_t max_threads, uint_t linger, + pthread_attr_t *attr) +{ + tpool_t *tpool; + int error; + + if (min_threads > max_threads || max_threads < 1) { + errno = EINVAL; + return (NULL); + } + + tpool = malloc(sizeof (*tpool)); + if (tpool == NULL) { + errno = ENOMEM; + return (NULL); + } + bzero(tpool, sizeof(*tpool)); + (void) pthread_mutex_init(&tpool->tp_mutex, NULL); + (void) pthread_cond_init(&tpool->tp_busycv, NULL); + (void) pthread_cond_init(&tpool->tp_workcv, NULL); + (void) pthread_cond_init(&tpool->tp_waitcv, NULL); + tpool->tp_minimum = min_threads; + tpool->tp_maximum = max_threads; + tpool->tp_linger = linger; + + /* make all pool threads be detached daemon threads */ + (void) pthread_attr_init(&tpool->tp_attr); + (void) pthread_attr_setdetachstate(&tpool->tp_attr, + PTHREAD_CREATE_DETACHED); + + return (tpool); +} + +/* + * Dispatch a work request to the thread pool. + * If there are idle workers, awaken one. + * Else, if the maximum number of workers has + * not been reached, spawn a new worker thread. + * Else just return with the job added to the queue. + */ +int +tpool_dispatch(tpool_t *tpool, void (*func)(void *), void *arg) +{ + tpool_job_t *job; + + if ((job = malloc(sizeof (*job))) == NULL) + return (-1); + bzero(job, sizeof(*job)); + job->tpj_next = NULL; + job->tpj_func = func; + job->tpj_arg = arg; + + pthread_mutex_lock(&tpool->tp_mutex); + + if (tpool->tp_head == NULL) + tpool->tp_head = job; + else + tpool->tp_tail->tpj_next = job; + tpool->tp_tail = job; + tpool->tp_njobs++; + + if (!(tpool->tp_flags & TP_SUSPEND)) { + if (tpool->tp_idle > 0) + (void) pthread_cond_signal(&tpool->tp_workcv); + else if (tpool->tp_current < tpool->tp_maximum && + create_worker(tpool) == 0) + tpool->tp_current++; + } + + pthread_mutex_unlock(&tpool->tp_mutex); + return (0); +} + +/* + * Assumes: by the time tpool_destroy() is called no one will use this + * thread pool in any way and no one will try to dispatch entries to it. + * Calling tpool_destroy() from a job in the pool will cause deadlock. + */ +void +tpool_destroy(tpool_t *tpool) +{ + tpool_active_t *activep; + + pthread_mutex_lock(&tpool->tp_mutex); + pthread_cleanup_push((_Voidfp)pthread_mutex_unlock, &tpool->tp_mutex); + + /* mark the pool as being destroyed; wakeup idle workers */ + tpool->tp_flags |= TP_DESTROY; + tpool->tp_flags &= ~TP_SUSPEND; + (void) pthread_cond_broadcast(&tpool->tp_workcv); + + /* cancel all active workers */ + for (activep = tpool->tp_active; activep; activep = activep->tpa_next) + (void) pthread_cancel(activep->tpa_tid); + + /* wait for all active workers to finish */ + while (tpool->tp_active != NULL) { + tpool->tp_flags |= TP_WAIT; + (void) pthread_cond_wait(&tpool->tp_waitcv, &tpool->tp_mutex); + } + + /* the last worker to terminate will wake us up */ + while (tpool->tp_current != 0) + (void) pthread_cond_wait(&tpool->tp_busycv, &tpool->tp_mutex); + + pthread_cleanup_pop(1); /* pthread_mutex_unlock(&tpool->tp_mutex); */ + delete_pool(tpool); +} + +/* + * Like tpool_destroy(), but don't cancel workers or wait for them to finish. + * The last worker to terminate will delete the pool. + */ +void +tpool_abandon(tpool_t *tpool) +{ + + pthread_mutex_lock(&tpool->tp_mutex); + if (tpool->tp_current == 0) { + /* no workers, just delete the pool */ + pthread_mutex_unlock(&tpool->tp_mutex); + delete_pool(tpool); + } else { + /* wake up all workers, last one will delete the pool */ + tpool->tp_flags |= TP_ABANDON; + tpool->tp_flags &= ~TP_SUSPEND; + (void) pthread_cond_broadcast(&tpool->tp_workcv); + pthread_mutex_unlock(&tpool->tp_mutex); + } +} + +/* + * Wait for all jobs to complete. + * Calling tpool_wait() from a job in the pool will cause deadlock. + */ +void +tpool_wait(tpool_t *tpool) +{ + + pthread_mutex_lock(&tpool->tp_mutex); + pthread_cleanup_push((_Voidfp)pthread_mutex_unlock, &tpool->tp_mutex); + while (tpool->tp_head != NULL || tpool->tp_active != NULL) { + tpool->tp_flags |= TP_WAIT; + (void) pthread_cond_wait(&tpool->tp_waitcv, &tpool->tp_mutex); + } + pthread_cleanup_pop(1); /* pthread_mutex_unlock(&tpool->tp_mutex); */ +} + +void +tpool_suspend(tpool_t *tpool) +{ + + pthread_mutex_lock(&tpool->tp_mutex); + tpool->tp_flags |= TP_SUSPEND; + pthread_mutex_unlock(&tpool->tp_mutex); +} + +int +tpool_suspended(tpool_t *tpool) +{ + int suspended; + + pthread_mutex_lock(&tpool->tp_mutex); + suspended = (tpool->tp_flags & TP_SUSPEND) != 0; + pthread_mutex_unlock(&tpool->tp_mutex); + + return (suspended); +} + +void +tpool_resume(tpool_t *tpool) +{ + int excess; + + pthread_mutex_lock(&tpool->tp_mutex); + if (!(tpool->tp_flags & TP_SUSPEND)) { + pthread_mutex_unlock(&tpool->tp_mutex); + return; + } + tpool->tp_flags &= ~TP_SUSPEND; + (void) pthread_cond_broadcast(&tpool->tp_workcv); + excess = tpool->tp_njobs - tpool->tp_idle; + while (excess-- > 0 && tpool->tp_current < tpool->tp_maximum) { + if (create_worker(tpool) != 0) + break; /* pthread_create() failed */ + tpool->tp_current++; + } + pthread_mutex_unlock(&tpool->tp_mutex); +} + +int +tpool_member(tpool_t *tpool) +{ + pthread_t my_tid = pthread_self(); + tpool_active_t *activep; + + pthread_mutex_lock(&tpool->tp_mutex); + for (activep = tpool->tp_active; activep; activep = activep->tpa_next) { + if (activep->tpa_tid == my_tid) { + pthread_mutex_unlock(&tpool->tp_mutex); + return (1); + } + } + pthread_mutex_unlock(&tpool->tp_mutex); + return (0); +} diff --git a/cddl/compat/opensolaris/misc/thread_pool_impl.h b/cddl/compat/opensolaris/misc/thread_pool_impl.h new file mode 100644 index 0000000000000..bc98ac8b1b370 --- /dev/null +++ b/cddl/compat/opensolaris/misc/thread_pool_impl.h @@ -0,0 +1,99 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * $FreeBSD$ + */ + +#ifndef _THREAD_POOL_IMPL_H +#define _THREAD_POOL_IMPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <thread_pool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Thread pool implementation definitions. + * See <thread_pool.h> for interface declarations. + */ + +/* + * FIFO queued job + */ +typedef struct tpool_job tpool_job_t; +struct tpool_job { + tpool_job_t *tpj_next; /* list of jobs */ + void (*tpj_func)(void *); /* function to call */ + void *tpj_arg; /* its argument */ +}; + +/* + * List of active threads, linked through their stacks. + */ +typedef struct tpool_active tpool_active_t; +struct tpool_active { + tpool_active_t *tpa_next; /* list of active threads */ + pthread_t tpa_tid; /* active thread id */ +}; + +/* + * The thread pool. + */ +struct tpool { + tpool_t *tp_forw; /* circular list of all thread pools */ + tpool_t *tp_back; + mutex_t tp_mutex; /* protects the pool data */ + cond_t tp_busycv; /* synchronization in tpool_dispatch */ + cond_t tp_workcv; /* synchronization with workers */ + cond_t tp_waitcv; /* synchronization in tpool_wait() */ + tpool_active_t *tp_active; /* threads performing work */ + tpool_job_t *tp_head; /* FIFO job queue */ + tpool_job_t *tp_tail; + pthread_attr_t tp_attr; /* attributes of the workers */ + int tp_flags; /* see below */ + uint_t tp_linger; /* seconds before idle workers exit */ + int tp_njobs; /* number of jobs in job queue */ + int tp_minimum; /* minimum number of worker threads */ + int tp_maximum; /* maximum number of worker threads */ + int tp_current; /* current number of worker threads */ + int tp_idle; /* number of idle workers */ +}; + +/* tp_flags */ +#define TP_WAIT 0x01 /* waiting in tpool_wait() */ +#define TP_SUSPEND 0x02 /* pool is being suspended */ +#define TP_DESTROY 0x04 /* pool is being destroyed */ +#define TP_ABANDON 0x08 /* pool is abandoned (auto-destroy) */ + +#ifdef __cplusplus +} +#endif + +#endif /* _THREAD_POOL_IMPL_H */ diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c index 767114ea571b7..92251d5f4f4be 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c @@ -1138,7 +1138,7 @@ alloc: #if defined(sun) dtp->dt_prcmode = DT_PROC_STOP_PREINIT; #else - dtp->dt_prcmode = DT_PROC_STOP_MAIN; + dtp->dt_prcmode = DT_PROC_STOP_POSTINIT; #endif dtp->dt_linkmode = DT_LINK_KERNEL; dtp->dt_linktype = DT_LTYP_ELF; diff --git a/cddl/lib/Makefile b/cddl/lib/Makefile index fef13839d9ae1..634d70eea5fad 100644 --- a/cddl/lib/Makefile +++ b/cddl/lib/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= ${_drti} \ libavl \ diff --git a/cddl/lib/libdtrace/libproc_compat.h b/cddl/lib/libdtrace/libproc_compat.h index a561157c0ba2b..d796f34f48aae 100644 --- a/cddl/lib/libdtrace/libproc_compat.h +++ b/cddl/lib/libdtrace/libproc_compat.h @@ -54,7 +54,6 @@ #define Psetbkpt proc_bkptset #define Psetflags proc_setflags #define Pstate proc_state -#define Pstate proc_state #define Psymbol_iter_by_addr proc_iter_symbyaddr #define Punsetflags proc_clearflags #define Pupdate_maps(p) do { } while (0) diff --git a/cddl/lib/libzfs/Makefile b/cddl/lib/libzfs/Makefile index 5b6b47dcc28c6..16660aca3ceb7 100644 --- a/cddl/lib/libzfs/Makefile +++ b/cddl/lib/libzfs/Makefile @@ -14,6 +14,7 @@ SRCS= deviceid.c \ fsshare.c \ mkdirp.c \ mnttab.c \ + thread_pool.c \ zmount.c \ zone.c diff --git a/cddl/sbin/Makefile b/cddl/sbin/Makefile index 4fd96f6ee0e5c..f40f2a45e759b 100644 --- a/cddl/sbin/Makefile +++ b/cddl/sbin/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= ${_tests} ${_zfs} ${_zpool} diff --git a/cddl/usr.bin/Makefile b/cddl/usr.bin/Makefile index 3547ff7b69948..533697d1ed003 100644 --- a/cddl/usr.bin/Makefile +++ b/cddl/usr.bin/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= \ ctfconvert \ diff --git a/cddl/usr.sbin/Makefile b/cddl/usr.sbin/Makefile index 8551c28a1a0b7..537b8e52792f9 100644 --- a/cddl/usr.sbin/Makefile +++ b/cddl/usr.sbin/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= ${_dtrace} \ ${_dtruss} \ diff --git a/contrib/gcc/config/i386/i386.c b/contrib/gcc/config/i386/i386.c index 88f28369297d2..26528bfa5a30a 100644 --- a/contrib/gcc/config/i386/i386.c +++ b/contrib/gcc/config/i386/i386.c @@ -14408,7 +14408,7 @@ ix86_local_alignment (tree type, int align) if (AGGREGATE_TYPE_P (type) && TYPE_SIZE (type) && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST - && (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 16 + && (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 128 || TREE_INT_CST_HIGH (TYPE_SIZE (type))) && align < 128) return 128; } diff --git a/contrib/libstdc++/include/bits/stl_multimap.h b/contrib/libstdc++/include/bits/stl_multimap.h index bb1c1544e716a..85feba78c5566 100644 --- a/contrib/libstdc++/include/bits/stl_multimap.h +++ b/contrib/libstdc++/include/bits/stl_multimap.h @@ -185,7 +185,7 @@ _GLIBCXX_BEGIN_NESTED_NAMESPACE(std, _GLIBCXX_STD) template <typename _InputIterator> multimap(_InputIterator __first, _InputIterator __last) : _M_t() - { _M_t._M_insert_unique(__first, __last); } + { _M_t._M_insert_equal(__first, __last); } /** * @brief Builds a %multimap from a range. diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Options.td b/contrib/llvm/tools/clang/include/clang/Driver/Options.td index ccfdf745c5a2f..5e7c76d981134 100644 --- a/contrib/llvm/tools/clang/include/clang/Driver/Options.td +++ b/contrib/llvm/tools/clang/include/clang/Driver/Options.td @@ -549,8 +549,6 @@ def finstrument_functions : Flag<["-"], "finstrument-functions">, Group<f_Group> def fkeep_inline_functions : Flag<["-"], "fkeep-inline-functions">, Group<clang_ignored_f_Group>; def flat__namespace : Flag<["-"], "flat_namespace">; def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>; -def flimit_debug_info : Flag<["-"], "flimit-debug-info">, Group<f_Group>, Flags<[CC1Option]>, - HelpText<"Limit debug information produced to reduce size of debug binary">; def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>; def flto : Flag<["-"], "flto">, Group<f_Group>; def fno_lto : Flag<["-"], "fno-lto">, Group<f_Group>; @@ -645,8 +643,6 @@ def fno_inline : Flag<["-"], "fno-inline">, Group<f_clang_Group>, Flags<[CC1Opti def fno_keep_inline_functions : Flag<["-"], "fno-keep-inline-functions">, Group<clang_ignored_f_Group>; def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group<f_Group>, HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">, Flags<[CC1Option]>; -def fno_limit_debug_info : Flag<["-"], "fno-limit-debug-info">, Group<f_Group>, Flags<[CC1Option]>, - HelpText<"Do not limit debug information produced to reduce size of debug binary">; def fno_merge_all_constants : Flag<["-"], "fno-merge-all-constants">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Disallow merging of constants">; def fno_modules : Flag <["-"], "fno-modules">, Group<f_Group>, @@ -774,6 +770,12 @@ def fno_signed_char : Flag<["-"], "fno-signed-char">, Flags<[CC1Option]>, def fsplit_stack : Flag<["-"], "fsplit-stack">, Group<f_Group>; def fstack_protector_all : Flag<["-"], "fstack-protector-all">, Group<f_Group>; def fstack_protector : Flag<["-"], "fstack-protector">, Group<f_Group>; +def fstandalone_debug : Flag<["-"], "fstandalone-debug">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Emit full debug info for all types used by the program">; +def fno_standalone_debug : Flag<["-"], "fno-standalone-debug">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Limit debug information produced to reduce size of debug binary">; +def flimit_debug_info : Flag<["-"], "flimit-debug-info">, Alias<fno_standalone_debug>; +def fno_limit_debug_info : Flag<["-"], "fno-limit-debug-info">, Alias<fstandalone_debug>; def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group<f_Group>; def fstrict_enums : Flag<["-"], "fstrict-enums">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Enable optimizations based on the strict definition of an enum's " diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h index 86aabf7b95ec1..0d2469791ce00 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h +++ b/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h @@ -50,12 +50,20 @@ public: }; enum DebugInfoKind { - NoDebugInfo, // Don't generate debug info. - DebugLineTablesOnly, // Emit only debug info necessary for generating - // line number tables (-gline-tables-only). - LimitedDebugInfo, // Limit generated debug info to reduce size - // (-flimit-debug-info). - FullDebugInfo // Generate complete debug info. + NoDebugInfo, /// Don't generate debug info. + + DebugLineTablesOnly, /// Emit only debug info necessary for generating + /// line number tables (-gline-tables-only). + + LimitedDebugInfo, /// Limit generated debug info to reduce size + /// (-fno-standalone-debug). This emits + /// forward decls for types that could be + /// replaced with forward decls in the source + /// code. For dynamic C++ classes type info + /// is only emitted int the module that + /// contains the classe's vtable. + + FullDebugInfo /// Generate complete debug info. }; enum TLSModel { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp index dc93d959fffc4..8be351ead4ac2 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1456,13 +1456,13 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) { // declaration. The completeType, completeRequiredType, and completeClassData // callbacks will handle promoting the declaration to a definition. if (T || + // Under -flimit-debug-info: (DebugKind <= CodeGenOptions::LimitedDebugInfo && - // Under -flimit-debug-info, emit only a declaration unless the type is - // required to be complete. - !RD->isCompleteDefinitionRequired() && CGM.getLangOpts().CPlusPlus) || - // If the class is dynamic, only emit a declaration. A definition will be - // emitted whenever the vtable is emitted. - (CXXDecl && CXXDecl->hasDefinition() && CXXDecl->isDynamicClass()) || T) { + // Emit only a forward declaration unless the type is required. + ((!RD->isCompleteDefinitionRequired() && CGM.getLangOpts().CPlusPlus) || + // If the class is dynamic, only emit a declaration. A definition will be + // emitted whenever the vtable is emitted. + (CXXDecl && CXXDecl->hasDefinition() && CXXDecl->isDynamicClass())))) { llvm::DIDescriptor FDContext = getContextDescriptor(cast<Decl>(RD->getDeclContext())); if (!T) diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp index ceea404e638fd..83ce2afd24712 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp @@ -3002,8 +3002,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_fformat_extensions); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); - Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info); - Args.AddLastArg(CmdArgs, options::OPT_fno_limit_debug_info); + Args.AddLastArg(CmdArgs, options::OPT_fstandalone_debug); + Args.AddLastArg(CmdArgs, options::OPT_fno_standalone_debug); Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names); // AltiVec language extensions aren't relevant for assembling. if (!isa<PreprocessJobAction>(JA) || diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp index ec1e53fe6aa62..81128fd1f58aa 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp @@ -295,7 +295,8 @@ static void ParseCommentArgs(CommentOptions &Opts, ArgList &Args) { } static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, - DiagnosticsEngine &Diags) { + DiagnosticsEngine &Diags, + const TargetOptions &TargetOpts) { using namespace options; bool Success = true; @@ -322,10 +323,16 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.setDebugInfo(CodeGenOptions::DebugLineTablesOnly); } else if (Args.hasArg(OPT_g_Flag) || Args.hasArg(OPT_gdwarf_2) || Args.hasArg(OPT_gdwarf_3) || Args.hasArg(OPT_gdwarf_4)) { - if (Args.hasFlag(OPT_flimit_debug_info, OPT_fno_limit_debug_info, true)) - Opts.setDebugInfo(CodeGenOptions::LimitedDebugInfo); - else + bool Default = false; + // Until dtrace (via CTF) can deal with distributed debug info, + // Darwin defaults to standalone/full debug info. + if (llvm::Triple(TargetOpts.Triple).isOSDarwin()) + Default = true; + + if (Args.hasFlag(OPT_fstandalone_debug, OPT_fno_standalone_debug, Default)) Opts.setDebugInfo(CodeGenOptions::FullDebugInfo); + else + Opts.setDebugInfo(CodeGenOptions::LimitedDebugInfo); } Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info); Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file); @@ -1657,8 +1664,9 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, ParseFileSystemArgs(Res.getFileSystemOpts(), *Args); // FIXME: We shouldn't have to pass the DashX option around here InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags); - Success = ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, DashX, Diags) - && Success; + ParseTargetArgs(Res.getTargetOpts(), *Args); + Success = ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, DashX, Diags, + Res.getTargetOpts()) && Success; ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args); if (DashX != IK_AST && DashX != IK_LLVM_IR) { ParseLangArgs(*Res.getLangOpts(), *Args, DashX, Diags); @@ -1673,8 +1681,6 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, FileMgr, Diags); ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args, Res.getFrontendOpts().ProgramAction); - ParseTargetArgs(Res.getTargetOpts(), *Args); - return Success; } diff --git a/contrib/ntp/ntpd/ntp_request.c b/contrib/ntp/ntpd/ntp_request.c index f5eed4449d9ad..6d479566d123c 100644 --- a/contrib/ntp/ntpd/ntp_request.c +++ b/contrib/ntp/ntpd/ntp_request.c @@ -1920,7 +1920,6 @@ mon_getlist_0( printf("wants monitor 0 list\n"); #endif if (!mon_enabled) { - req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); return; } im = (struct info_monitor *)prepare_pkt(srcadr, inter, inpkt, @@ -1965,7 +1964,6 @@ mon_getlist_1( extern int mon_enabled; if (!mon_enabled) { - req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); return; } im = (struct info_monitor_1 *)prepare_pkt(srcadr, inter, inpkt, diff --git a/contrib/top/commands.c b/contrib/top/commands.c index 4d987baac071e..707366d8aa48c 100644 --- a/contrib/top/commands.c +++ b/contrib/top/commands.c @@ -74,6 +74,7 @@ e - list errors generated by last \"kill\" or \"renice\" command\n\ H - toggle the displaying of threads\n\ i or I - toggle the displaying of idle processes\n\ j - toggle the displaying of jail ID\n\ +J - display processes for only one jail (+ selects all jails)\n\ k - kill processes; send a signal to a list of processes\n\ m - toggle the display between 'cpu' and 'io' modes\n\ n or # - change number of processes to display\n", stdout); diff --git a/contrib/top/machine.h b/contrib/top/machine.h index 699c7554df051..41da6008647bd 100644 --- a/contrib/top/machine.h +++ b/contrib/top/machine.h @@ -66,6 +66,7 @@ struct process_select int thread; /* show threads */ int uid; /* only this uid (unless uid == -1) */ int wcpu; /* show weighted cpu */ + int jid; /* only this jid (unless jid == -1) */ int jail; /* show jail ID */ int kidle; /* show per-CPU idle threads */ char *command; /* only this command (unless == NULL) */ diff --git a/contrib/top/top.X b/contrib/top/top.X index 9c54f85637e8b..15cf2dcb51190 100644 --- a/contrib/top/top.X +++ b/contrib/top/top.X @@ -20,6 +20,8 @@ top \- display and update information about the top cpu processes ] [ .BI \-s time ] [ +.BI \-J jail +] [ .BI \-U username ] [ .I number @@ -171,6 +173,21 @@ values are \*(lqcpu\*(rq, \*(lqsize\*(rq, \*(lqres\*(rq, and \*(lqtime\*(rq, but may vary on different operating systems. Note that not all operating systems support this option. .TP +.BI \-J jail +Show only those processes owned by +.IR jail . +This may be either the +.B jid +or +.B name +of the jail. +Use +.B 0 +to limit to host processes. +Using this option implies the +.B \-j +flag. +.PP .BI \-U username Show only those processes owned by .IR username . @@ -315,6 +332,12 @@ Toggle the display of .IR jail (8) ID. .TP +.B J +Display only processes owned by a specific jail (prompt for jail). +If the jail specified is simply \*(lq+\*(rq, then processes belonging +to all jails and the host will be displayed. +This will also enable the display of JID. +.TP .B P Toggle the display of per-CPU statistics. .TP diff --git a/contrib/top/top.c b/contrib/top/top.c index c2eb35da1a992..ebb06e5f8923c 100644 --- a/contrib/top/top.c +++ b/contrib/top/top.c @@ -38,7 +38,9 @@ char *copyright = #include <signal.h> #include <setjmp.h> #include <ctype.h> +#include <sys/jail.h> #include <sys/time.h> +#include <jail.h> /* includes specific to top */ #include "display.h" /* interface to display package */ @@ -198,9 +200,9 @@ char *argv[]; fd_set readfds; #ifdef ORDER - static char command_chars[] = "\f qh?en#sdkriIutHmSCajzPo"; + static char command_chars[] = "\f qh?en#sdkriIutHmSCajzPJo"; #else - static char command_chars[] = "\f qh?en#sdkriIutHmSCajzP"; + static char command_chars[] = "\f qh?en#sdkriIutHmSCajzPJ"; #endif /* these defines enumerate the "strchr"s of the commands in command_chars */ #define CMD_redraw 0 @@ -228,8 +230,9 @@ char *argv[]; #define CMD_jidtog 21 #define CMD_kidletog 22 #define CMD_pcputog 23 +#define CMD_jail 24 #ifdef ORDER -#define CMD_order 24 +#define CMD_order 25 #endif /* set the buffer for stdout */ @@ -261,6 +264,7 @@ char *argv[]; ps.uid = -1; ps.thread = No; ps.wcpu = 1; + ps.jid = -1; ps.jail = No; ps.kidle = Yes; ps.command = NULL; @@ -288,7 +292,7 @@ char *argv[]; optind = 1; } - while ((i = getopt(ac, av, "CSIHPabijnquvzs:d:U:m:o:t")) != EOF) + while ((i = getopt(ac, av, "CSIHPabijJ:nquvzs:d:U:m:o:t")) != EOF) { switch(i) { @@ -413,6 +417,15 @@ char *argv[]; ps.jail = !ps.jail; break; + case 'J': /* display only jail's processes */ + if ((ps.jid = jail_getid(optarg)) == -1) + { + fprintf(stderr, "%s: unknown jail\n", optarg); + exit(1); + } + ps.jail = 1; + break; + case 'P': pcpu_stats = !pcpu_stats; break; @@ -425,7 +438,7 @@ char *argv[]; fprintf(stderr, "Top version %s\n" "Usage: %s [-abCHIijnPqStuvz] [-d count] [-m io | cpu] [-o field] [-s time]\n" -" [-U username] [number]\n", +" [-J jail] [-U username] [number]\n", version_string(), myname); exit(1); } @@ -994,7 +1007,7 @@ restart: case CMD_user: new_message(MT_standout, - "Username to show: "); + "Username to show (+ for all): "); if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) { if (tempbuf2[0] == '+' && @@ -1085,6 +1098,44 @@ restart: reset_display(); putchar('\r'); break; + + case CMD_jail: + new_message(MT_standout, + "Jail to show (+ for all): "); + if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) + { + if (tempbuf2[0] == '+' && + tempbuf2[1] == '\0') + { + ps.jid = -1; + } + else if ((i = jail_getid(tempbuf2)) == -1) + { + new_message(MT_standout, + " %s: unknown jail", tempbuf2); + no_command = Yes; + } + else + { + ps.jid = i; + } + if (ps.jail == 0) { + ps.jail = 1; + new_message(MT_standout | + MT_delayed, " Displaying jail " + "ID."); + header_text = + format_header(uname_field); + reset_display(); + } + putchar('\r'); + } + else + { + clear_message(); + } + break; + case CMD_kidletog: ps.kidle = !ps.kidle; new_message(MT_standout | MT_delayed, diff --git a/crypto/openssl/ssl/s3_pkt.c b/crypto/openssl/ssl/s3_pkt.c index 96ba63262e44e..8deeab3c9fbfb 100644 --- a/crypto/openssl/ssl/s3_pkt.c +++ b/crypto/openssl/ssl/s3_pkt.c @@ -1055,7 +1055,7 @@ start: { s->rstate=SSL_ST_READ_HEADER; rr->off=0; - if (s->mode & SSL_MODE_RELEASE_BUFFERS) + if (s->mode & SSL_MODE_RELEASE_BUFFERS && s->s3->rbuf.left == 0) ssl3_release_read_buffer(s); } } diff --git a/etc/Makefile b/etc/Makefile index 340ade4dc2a04..03edb13d61645 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -1,7 +1,7 @@ # from: @(#)Makefile 5.11 (Berkeley) 5/21/91 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .if ${MK_SENDMAIL} != "no" SUBDIR= sendmail diff --git a/etc/defaults/rc.conf b/etc/defaults/rc.conf index 0d4b7428f7ea0..aa19b3031e56d 100644 --- a/etc/defaults/rc.conf +++ b/etc/defaults/rc.conf @@ -641,10 +641,10 @@ devfs_rulesets="/etc/defaults/devfs.rules /etc/devfs.rules" # Files containing devfs_system_ruleset="" # The name (NOT number) of a ruleset to apply to /dev devfs_set_rulesets="" # A list of /mount/dev=ruleset_name settings to # apply (must be mounted already, i.e. fstab(5)) -devfs_load_rulesets="NO" # Enable to always load the default rulesets -performance_cx_lowest="HIGH" # Online CPU idle state +devfs_load_rulesets="YES" # Enable to always load the default rulesets +performance_cx_lowest="Cmax" # Online CPU idle state performance_cpu_freq="NONE" # Online CPU frequency -economy_cx_lowest="HIGH" # Offline CPU idle state +economy_cx_lowest="Cmax" # Offline CPU idle state economy_cpu_freq="NONE" # Offline CPU frequency virecover_enable="YES" # Perform housekeeping for the vi(1) editor ugidfw_enable="NO" # Load mac_bsdextended(4) rules on boot diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index 4cc3f87b41eb3..2e6d30afa0cb9 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -97,8 +97,6 @@ .. growfs .. - ifconfig - .. mdconfig .. .. diff --git a/etc/mtree/Makefile b/etc/mtree/Makefile index f24867b8ecf87..afed37044fa23 100644 --- a/etc/mtree/Makefile +++ b/etc/mtree/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> FILES= ${_BSD.debug.dist} \ BSD.include.dist \ diff --git a/etc/periodic/daily/Makefile b/etc/periodic/daily/Makefile index aa28351ae2a15..61ede6ddacb37 100644 --- a/etc/periodic/daily/Makefile +++ b/etc/periodic/daily/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> FILES= 100.clean-disks \ 110.clean-tmps \ diff --git a/etc/periodic/monthly/Makefile b/etc/periodic/monthly/Makefile index d9e49691b6e9f..ea2bd9f0b057f 100644 --- a/etc/periodic/monthly/Makefile +++ b/etc/periodic/monthly/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> FILES= 450.status-security \ 999.local diff --git a/etc/periodic/security/Makefile b/etc/periodic/security/Makefile index c5af2f85b012f..026948b9d8540 100644 --- a/etc/periodic/security/Makefile +++ b/etc/periodic/security/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> FILES= 100.chksetuid \ 110.neggrpperm \ diff --git a/etc/periodic/weekly/Makefile b/etc/periodic/weekly/Makefile index b6f77c4f71d07..865ef5340def2 100644 --- a/etc/periodic/weekly/Makefile +++ b/etc/periodic/weekly/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> FILES= 340.noid \ 450.status-security \ diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile index 6c6801b52581c..7302d2934c177 100644 --- a/etc/rc.d/Makefile +++ b/etc/rc.d/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> FILES= DAEMON \ FILESYSTEMS \ diff --git a/games/Makefile b/games/Makefile index 716a7861db5d9..a3bb2965a25d5 100644 --- a/games/Makefile +++ b/games/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= \ bcd \ diff --git a/games/factor/Makefile b/games/factor/Makefile index da1737cdb28d8..afc9510405f25 100644 --- a/games/factor/Makefile +++ b/games/factor/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 5/31/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= factor SRCS= factor.c pr_tbl.c diff --git a/gnu/Makefile b/gnu/Makefile index b460590387ae2..25480c7b951a4 100644 --- a/gnu/Makefile +++ b/gnu/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 5.33.1.1 (Berkeley) 5/6/91 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= lib ${_tests} usr.bin diff --git a/gnu/lib/Makefile b/gnu/lib/Makefile index 0a607d7afa86f..2651eef5abdbb 100644 --- a/gnu/lib/Makefile +++ b/gnu/lib/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= csu libgcc libgcov libdialog libgomp libregex libreadline diff --git a/gnu/lib/csu/Makefile b/gnu/lib/csu/Makefile index 5aba49f447342..0a2c7d35ea6cf 100644 --- a/gnu/lib/csu/Makefile +++ b/gnu/lib/csu/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> MK_SSP= no GCCDIR= ${.CURDIR}/../../../contrib/gcc diff --git a/gnu/lib/libgcc/Makefile b/gnu/lib/libgcc/Makefile index d3befcbb89a89..11af4305edbbb 100644 --- a/gnu/lib/libgcc/Makefile +++ b/gnu/lib/libgcc/Makefile @@ -6,7 +6,7 @@ GCCLIB= ${.CURDIR}/../../../contrib/gcclibs SHLIB_NAME= libgcc_s.so.1 SHLIBDIR?= /lib -.include <bsd.own.mk> +.include <src.opts.mk> # # libgcc is linked in last and thus cannot depend on ssp symbols coming # from earlier libraries. Disable stack protection for this library. diff --git a/gnu/lib/libgcov/Makefile b/gnu/lib/libgcov/Makefile index aab6241052915..5292f9f8d53fb 100644 --- a/gnu/lib/libgcov/Makefile +++ b/gnu/lib/libgcov/Makefile @@ -3,7 +3,7 @@ MK_PROFILE= no MK_SSP= no -.include <bsd.own.mk> +.include <src.opts.mk> .include "${.CURDIR}/../../usr.bin/cc/Makefile.tgt" GCCDIR= ${.CURDIR}/../../../contrib/gcc diff --git a/gnu/lib/libstdc++/Makefile b/gnu/lib/libstdc++/Makefile index b0d45d63b651a..d19f9f3bb3ff6 100644 --- a/gnu/lib/libstdc++/Makefile +++ b/gnu/lib/libstdc++/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> GCCVER= 4.2 GCCDIR= ${.CURDIR}/../../../contrib/gcc diff --git a/gnu/lib/libsupc++/Makefile b/gnu/lib/libsupc++/Makefile index acf1b58ed3c1d..5cc5f04adf674 100644 --- a/gnu/lib/libsupc++/Makefile +++ b/gnu/lib/libsupc++/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> GCCVER= 4.2 GCCDIR= ${.CURDIR}/../../../contrib/gcc diff --git a/gnu/usr.bin/Makefile b/gnu/usr.bin/Makefile index 7e96a6f4829f3..76330699dffa3 100644 --- a/gnu/usr.bin/Makefile +++ b/gnu/usr.bin/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= ${_binutils} \ ${_cc} \ diff --git a/gnu/usr.bin/binutils/as/Makefile b/gnu/usr.bin/binutils/as/Makefile index 4436394f5de43..c058727069e7e 100644 --- a/gnu/usr.bin/binutils/as/Makefile +++ b/gnu/usr.bin/binutils/as/Makefile @@ -4,7 +4,7 @@ # BINDIR .include "${.CURDIR}/../../Makefile.inc" .include "${.CURDIR}/../Makefile.inc0" -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${SRCDIR}/gas ${SRCDIR}/gas/config diff --git a/gnu/usr.bin/binutils/ld/Makefile b/gnu/usr.bin/binutils/ld/Makefile index dff112169eba2..81a46d5d21b0b 100644 --- a/gnu/usr.bin/binutils/ld/Makefile +++ b/gnu/usr.bin/binutils/ld/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ .include "../Makefile.inc0" -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${SRCDIR}/ld diff --git a/gnu/usr.bin/cc/Makefile b/gnu/usr.bin/cc/Makefile index bf6d20c79ce4c..313aaf2da84f4 100644 --- a/gnu/usr.bin/cc/Makefile +++ b/gnu/usr.bin/cc/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> # The order of some of these are rather important. Some depend on previous # subdirs. diff --git a/gnu/usr.bin/cc/Makefile.inc b/gnu/usr.bin/cc/Makefile.inc index 39adc91308e7f..dc9779973210d 100644 --- a/gnu/usr.bin/cc/Makefile.inc +++ b/gnu/usr.bin/cc/Makefile.inc @@ -1,5 +1,6 @@ # $FreeBSD$ +.include <src.opts.mk> .include "../Makefile.inc" # Sometimes this is .include'd several times... diff --git a/gnu/usr.bin/cc/c++/Makefile b/gnu/usr.bin/cc/c++/Makefile index 1e7f33959f36a..39f372b2d8886 100644 --- a/gnu/usr.bin/cc/c++/Makefile +++ b/gnu/usr.bin/cc/c++/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ MAN= -.include <bsd.own.mk> +.include <src.opts.mk> .include "../Makefile.inc" .include "../Makefile.fe" diff --git a/gnu/usr.bin/cc/cc/Makefile b/gnu/usr.bin/cc/cc/Makefile index ba53565c35f71..0fd82e092db4a 100644 --- a/gnu/usr.bin/cc/cc/Makefile +++ b/gnu/usr.bin/cc/cc/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .include "../Makefile.inc" .include "../Makefile.fe" diff --git a/gnu/usr.bin/cc/cc1/Makefile b/gnu/usr.bin/cc/cc1/Makefile index e73b2c9911940..368517c1be009 100644 --- a/gnu/usr.bin/cc/cc1/Makefile +++ b/gnu/usr.bin/cc/cc1/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ MAN= -.include <bsd.own.mk> +.include <src.opts.mk> .include "../Makefile.inc" diff --git a/gnu/usr.bin/cc/cc1plus/Makefile b/gnu/usr.bin/cc/cc1plus/Makefile index 742d7c6d41f2b..64a07255e0110 100644 --- a/gnu/usr.bin/cc/cc1plus/Makefile +++ b/gnu/usr.bin/cc/cc1plus/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ MAN= -.include <bsd.own.mk> +.include <src.opts.mk> .include "../Makefile.inc" diff --git a/gnu/usr.bin/cc/cc_tools/Makefile b/gnu/usr.bin/cc/cc_tools/Makefile index 8f75f43aadda0..ae7f8b82d17d1 100644 --- a/gnu/usr.bin/cc/cc_tools/Makefile +++ b/gnu/usr.bin/cc/cc_tools/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> CFLAGS+= -I. diff --git a/gnu/usr.bin/cc/cpp/Makefile b/gnu/usr.bin/cc/cpp/Makefile index a8e48af2d02c1..a3ac04b909e33 100644 --- a/gnu/usr.bin/cc/cpp/Makefile +++ b/gnu/usr.bin/cc/cpp/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .include "../Makefile.inc" .include "../Makefile.fe" diff --git a/gnu/usr.bin/dialog/Makefile b/gnu/usr.bin/dialog/Makefile index 7c98cfc062c84..a7e0a57ad594f 100644 --- a/gnu/usr.bin/dialog/Makefile +++ b/gnu/usr.bin/dialog/Makefile @@ -10,7 +10,7 @@ CFLAGS+= -I${.CURDIR} -I${DIALOG} WARNS?= 6 -.include <bsd.own.mk> +.include <src.opts.mk> .if ${MK_NCURSESW} == "no" DPADD+= ${LIBNCURSES} diff --git a/gnu/usr.bin/grep/Makefile b/gnu/usr.bin/grep/Makefile index 7d3b60769b8d2..d412dfdfd0ed9 100644 --- a/gnu/usr.bin/grep/Makefile +++ b/gnu/usr.bin/grep/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> GREP_LIBZ=YES diff --git a/include/Makefile b/include/Makefile index 991c78366b88d..8b896bad89997 100644 --- a/include/Makefile +++ b/include/Makefile @@ -3,7 +3,7 @@ # # Doing a "make install" builds /usr/include. -.include <bsd.own.mk> +.include <src.opts.mk> CLEANFILES= osreldate.h version vers.c SUBDIR= arpa gssapi protocols rpcsvc rpc xlocale diff --git a/include/arpa/Makefile b/include/arpa/Makefile index 260b3b347ebe1..2f1c2495ebe5d 100644 --- a/include/arpa/Makefile +++ b/include/arpa/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> INCS= ftp.h inet.h nameser.h nameser_compat.h telnet.h tftp.h diff --git a/kerberos5/Makefile.inc b/kerberos5/Makefile.inc index 6dfd5187e0da8..c57b18a157b02 100644 --- a/kerberos5/Makefile.inc +++ b/kerberos5/Makefile.inc @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> NO_LINT= diff --git a/lib/Makefile b/lib/Makefile index fe99085104bf1..de87cbaa85601 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/4/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> # To satisfy shared library or ELF linkage when only the libraries being # built are visible: diff --git a/lib/atf/Makefile b/lib/atf/Makefile index a191f0da4d47c..0772065f08227 100644 --- a/lib/atf/Makefile +++ b/lib/atf/Makefile @@ -25,7 +25,7 @@ # # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= libatf-c \ libatf-c++ \ diff --git a/lib/atf/libatf-c++/Makefile b/lib/atf/libatf-c++/Makefile index d52e4965d0a15..84477f79927d3 100644 --- a/lib/atf/libatf-c++/Makefile +++ b/lib/atf/libatf-c++/Makefile @@ -25,6 +25,7 @@ # # $FreeBSD$ +.include <src.opts.mk> .include <bsd.init.mk> LIB= atf-c++ diff --git a/lib/atf/libatf-c/Makefile b/lib/atf/libatf-c/Makefile index 69c46114e8bb2..5c607f7b42da8 100644 --- a/lib/atf/libatf-c/Makefile +++ b/lib/atf/libatf-c/Makefile @@ -25,6 +25,7 @@ # # $FreeBSD$ +.include <src.opts.mk> .include <bsd.init.mk> LIB= atf-c diff --git a/lib/clang/Makefile b/lib/clang/Makefile index d335d80fbee28..ae7ae4a0a44dd 100644 --- a/lib/clang/Makefile +++ b/lib/clang/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .if !make(install) .if !defined(EARLY_BUILD) diff --git a/lib/clang/clang.build.mk b/lib/clang/clang.build.mk index 0ba18f060fcbb..27c0ca0687850 100644 --- a/lib/clang/clang.build.mk +++ b/lib/clang/clang.build.mk @@ -1,5 +1,7 @@ # $FreeBSD$ +.include <src.opts.mk> + CLANG_SRCS= ${LLVM_SRCS}/tools/clang CFLAGS+= -I${LLVM_SRCS}/include -I${CLANG_SRCS}/include \ diff --git a/lib/clang/libllvmanalysis/Makefile b/lib/clang/libllvmanalysis/Makefile index 34725fc39cb26..ea2a7189c40f4 100644 --- a/lib/clang/libllvmanalysis/Makefile +++ b/lib/clang/libllvmanalysis/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIB= llvmanalysis diff --git a/lib/clang/libllvmipa/Makefile b/lib/clang/libllvmipa/Makefile index 85b75afa1c370..c866ca0ddfe03 100644 --- a/lib/clang/libllvmipa/Makefile +++ b/lib/clang/libllvmipa/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIB= llvmipa diff --git a/lib/clang/libllvmipo/Makefile b/lib/clang/libllvmipo/Makefile index b1e90161786d6..85af0360244a0 100644 --- a/lib/clang/libllvmipo/Makefile +++ b/lib/clang/libllvmipo/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIB= llvmipo diff --git a/lib/clang/libllvmmc/Makefile b/lib/clang/libllvmmc/Makefile index 7fdc474eb7f11..84ba618902bbc 100644 --- a/lib/clang/libllvmmc/Makefile +++ b/lib/clang/libllvmmc/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIB= llvmmc diff --git a/lib/clang/libllvmscalaropts/Makefile b/lib/clang/libllvmscalaropts/Makefile index 1f4edffeede93..8da4bf06d0c98 100644 --- a/lib/clang/libllvmscalaropts/Makefile +++ b/lib/clang/libllvmscalaropts/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIB= llvmscalaropts diff --git a/lib/clang/libllvmsupport/Makefile b/lib/clang/libllvmsupport/Makefile index eb3f633286cb0..b7cfe6aa2d863 100644 --- a/lib/clang/libllvmsupport/Makefile +++ b/lib/clang/libllvmsupport/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIB= llvmsupport diff --git a/lib/clang/libllvmtransformutils/Makefile b/lib/clang/libllvmtransformutils/Makefile index f74209220254d..cfad040c638dc 100644 --- a/lib/clang/libllvmtransformutils/Makefile +++ b/lib/clang/libllvmtransformutils/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIB= llvmtransformutils diff --git a/lib/clang/libllvmx86disassembler/Makefile b/lib/clang/libllvmx86disassembler/Makefile index 797f2bf49a892..e5489a0e60892 100644 --- a/lib/clang/libllvmx86disassembler/Makefile +++ b/lib/clang/libllvmx86disassembler/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIB= llvmx86disassembler diff --git a/lib/libarchive/Makefile b/lib/libarchive/Makefile index eb3921949931a..bbe03a0bf1269 100644 --- a/lib/libarchive/Makefile +++ b/lib/libarchive/Makefile @@ -1,5 +1,5 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIBARCHIVEDIR= ${.CURDIR}/../../contrib/libarchive diff --git a/lib/libbsnmp/libbsnmp/Makefile b/lib/libbsnmp/libbsnmp/Makefile index 20015b98a9d03..0b9087d6540ca 100644 --- a/lib/libbsnmp/libbsnmp/Makefile +++ b/lib/libbsnmp/libbsnmp/Makefile @@ -2,7 +2,7 @@ # # Author: Harti Brandt <harti@freebsd.org> -.include <bsd.own.mk> +.include <src.opts.mk> CONTRIB= ${.CURDIR}/../../../contrib/bsnmp/lib .PATH: ${CONTRIB} diff --git a/lib/libc/Makefile b/lib/libc/Makefile index 6f88dac8254a5..e9bc33bd92772 100644 --- a/lib/libc/Makefile +++ b/lib/libc/Makefile @@ -3,7 +3,7 @@ SHLIBDIR?= /lib -.include <bsd.own.mk> +.include <src.opts.mk> LIBC_SRCTOP?= ${.CURDIR} diff --git a/lib/libc/arm/gen/fpsetmask_vfp.c b/lib/libc/arm/gen/fpsetmask_vfp.c index 061c03385b54d..170e06d74fa94 100644 --- a/lib/libc/arm/gen/fpsetmask_vfp.c +++ b/lib/libc/arm/gen/fpsetmask_vfp.c @@ -45,7 +45,7 @@ fpsetmask(fp_except_t mask) __asm __volatile("vmrs %0, fpscr" : "=&r"(old)); mask = (mask & FP_X_MASK) << 8; new = (old & ~(FP_X_MASK << 8)) | mask; - __asm __volatile("vmsr fpscr, %0" : : "r"(old)); + __asm __volatile("vmsr fpscr, %0" : : "r"(new)); return ((old >> 8) & FP_X_MASK); } diff --git a/lib/libc/locale/utf8.c b/lib/libc/locale/utf8.c index 40f0e1701bd54..cffa241133a5a 100644 --- a/lib/libc/locale/utf8.c +++ b/lib/libc/locale/utf8.c @@ -203,6 +203,13 @@ _UTF8_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n, errno = EILSEQ; return ((size_t)-1); } + if (wch >= 0xd800 && wch <= 0xdfff) { + /* + * Malformed input; invalid code points. + */ + errno = EILSEQ; + return ((size_t)-1); + } if (pwc != NULL) *pwc = wch; us->want = 0; diff --git a/lib/libc/regex/engine.c b/lib/libc/regex/engine.c index 2a1a75e0b1d6d..589bb9d72698e 100644 --- a/lib/libc/regex/engine.c +++ b/lib/libc/regex/engine.c @@ -686,19 +686,16 @@ backref(struct match *m, while (m->g->strip[ss] != SOP(O_BACK, i)) ss++; return(backref(m, sp+len, stop, ss+1, stopst, lev, rec)); - break; case OQUEST_: /* to null or not */ dp = backref(m, sp, stop, ss+1, stopst, lev, rec); if (dp != NULL) return(dp); /* not */ return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev, rec)); - break; case OPLUS_: assert(m->lastpos != NULL); assert(lev+1 <= m->g->nplus); m->lastpos[lev+1] = sp; return(backref(m, sp, stop, ss+1, stopst, lev+1, rec)); - break; case O_PLUS: if (sp == m->lastpos[lev]) /* last pass matched null */ return(backref(m, sp, stop, ss+1, stopst, lev-1, rec)); @@ -709,7 +706,6 @@ backref(struct match *m, return(backref(m, sp, stop, ss+1, stopst, lev-1, rec)); else return(dp); - break; case OCH_: /* find the right one, if any */ ssub = ss + 1; esub = ss + OPND(s) - 1; @@ -730,6 +726,7 @@ backref(struct match *m, else assert(OP(m->g->strip[esub]) == O_CH); } + /* NOTREACHED */ break; case OLPAREN: /* must undo assignment if rest fails */ i = OPND(s); @@ -741,7 +738,6 @@ backref(struct match *m, return(dp); m->pmatch[i].rm_so = offsave; return(NULL); - break; case ORPAREN: /* must undo assignment if rest fails */ i = OPND(s); assert(0 < i && i <= m->g->nsub); @@ -752,7 +748,6 @@ backref(struct match *m, return(dp); m->pmatch[i].rm_eo = offsave; return(NULL); - break; default: /* uh oh */ assert(nope); break; diff --git a/lib/libc/regex/regcomp.c b/lib/libc/regex/regcomp.c index f3a41e90fb71e..55f9c04c69108 100644 --- a/lib/libc/regex/regcomp.c +++ b/lib/libc/regex/regcomp.c @@ -746,7 +746,6 @@ p_b_term(struct parse *p, cset *cs) case '-': SETERROR(REG_ERANGE); return; /* NOTE RETURN */ - break; default: c = '\0'; break; diff --git a/lib/libc/rpc/clnt_vc.c b/lib/libc/rpc/clnt_vc.c index 7cd93b37e9dea..117cfba654862 100644 --- a/lib/libc/rpc/clnt_vc.c +++ b/lib/libc/rpc/clnt_vc.c @@ -301,15 +301,13 @@ clnt_vc_create(fd, raddr, prog, vers, sendsz, recvsz) return (cl); err: - if (cl) { - if (ct) { - if (ct->ct_addr.len) - mem_free(ct->ct_addr.buf, ct->ct_addr.len); - mem_free(ct, sizeof (struct ct_data)); - } - if (cl) - mem_free(cl, sizeof (CLIENT)); + if (ct) { + if (ct->ct_addr.len) + mem_free(ct->ct_addr.buf, ct->ct_addr.len); + mem_free(ct, sizeof (struct ct_data)); } + if (cl) + mem_free(cl, sizeof (CLIENT)); return ((CLIENT *)NULL); } diff --git a/lib/libc/sys/msync.2 b/lib/libc/sys/msync.2 index 42d8005418d15..a91faf2a66e0d 100644 --- a/lib/libc/sys/msync.2 +++ b/lib/libc/sys/msync.2 @@ -87,11 +87,13 @@ The .Fa addr argument is not a multiple of the hardware page size. -.It Bq Er EINVAL -The +.It Bq Er ENOMEM +The addresses in the range starting at +.Fa addr +and continuing for .Fa len -argument -is too large or negative. +bytes are outside the range allowed for the address space of a +process or specify one or more pages that are not mapped. .It Bq Er EINVAL The .Fa flags @@ -99,7 +101,7 @@ argument was both MS_ASYNC and MS_INVALIDATE. Only one of these flags is allowed. .It Bq Er EIO - An error occurred while writing at least one of the pages in +An error occurred while writing at least one of the pages in the specified region. .El .Sh SEE ALSO diff --git a/lib/libc_nonshared/Makefile b/lib/libc_nonshared/Makefile index e65fca06f8b62..db4fb32c79227 100644 --- a/lib/libc_nonshared/Makefile +++ b/lib/libc_nonshared/Makefile @@ -5,7 +5,7 @@ # compile modes. # bsd.lib.mk doesn't have an easy way to express that. MK_PROFILE?=no -.include <bsd.own.mk> +.include <src.opts.mk> NO_PIC= # -fpic on some platforms, -fPIC on others. CFLAGS+=${PICFLAG} -DPIC -fvisibility=hidden diff --git a/lib/libcapsicum/libcapsicum_dns.c b/lib/libcapsicum/libcapsicum_dns.c index 170e0d07d2d95..113f8dc5a315e 100644 --- a/lib/libcapsicum/libcapsicum_dns.c +++ b/lib/libcapsicum/libcapsicum_dns.c @@ -247,6 +247,7 @@ cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname, prevai->ai_next = curai; else if (firstai == NULL) firstai = curai; + prevai = curai; } nvlist_destroy(nvl); if (curai == NULL && nvlai != NULL) { diff --git a/lib/libcompiler_rt/Makefile b/lib/libcompiler_rt/Makefile index 5f8039bc166f0..91ce965739c9d 100644 --- a/lib/libcompiler_rt/Makefile +++ b/lib/libcompiler_rt/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIB= compiler_rt NO_PIC= diff --git a/lib/libcrypt/Makefile b/lib/libcrypt/Makefile index aca24d8f8af31..85bf94804fca6 100644 --- a/lib/libcrypt/Makefile +++ b/lib/libcrypt/Makefile @@ -4,7 +4,7 @@ SHLIBDIR?= /lib -.include <bsd.own.mk> +.include <src.opts.mk> SHLIB_MAJOR= 5 LIB= crypt diff --git a/lib/libfetch/Makefile b/lib/libfetch/Makefile index 085aba2c6cb4a..cef5f5a43c18a 100644 --- a/lib/libfetch/Makefile +++ b/lib/libfetch/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIB= fetch CFLAGS+= -I. diff --git a/lib/libipsec/Makefile b/lib/libipsec/Makefile index 840aefa54f270..7d3e94a7db5a0 100644 --- a/lib/libipsec/Makefile +++ b/lib/libipsec/Makefile @@ -29,7 +29,7 @@ SHLIBDIR?= /lib -.include <bsd.own.mk> +.include <src.opts.mk> LIB= ipsec SHLIB_MAJOR= 4 diff --git a/lib/libkiconv/Makefile b/lib/libkiconv/Makefile index bda505eeaff19..c7b2179c1943e 100644 --- a/lib/libkiconv/Makefile +++ b/lib/libkiconv/Makefile @@ -2,7 +2,7 @@ SHLIBDIR?= /lib -.include <bsd.own.mk> +.include <src.opts.mk> LIB= kiconv SRCS= kiconv_sysctl.c xlat16_iconv.c xlat16_sysctl.c diff --git a/lib/libmagic/Makefile b/lib/libmagic/Makefile index d341a3a5f5643..59d772df552fe 100644 --- a/lib/libmagic/Makefile +++ b/lib/libmagic/Makefile @@ -32,7 +32,7 @@ MAGFILES= ${CONTRDIR}/Header\ ${CONTRDIR}/Magdir/[a-z]* magic: ${MAGFILES} - cat ${.ALLSRC} > ${.TARGET} + cat ${.ALLSRC:O} > ${.TARGET} magic.mgc: mkmagic magic ./mkmagic magic diff --git a/lib/libmilter/Makefile b/lib/libmilter/Makefile index 0e625d0812a48..ca9838d9bff19 100644 --- a/lib/libmilter/Makefile +++ b/lib/libmilter/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SENDMAIL_DIR=${.CURDIR}/../../contrib/sendmail .PATH: ${SENDMAIL_DIR}/libmilter ${SENDMAIL_DIR}/libsm diff --git a/lib/libpam/modules/modules.inc b/lib/libpam/modules/modules.inc index c570cfd2f77c3..66fc63c89dc9c 100644 --- a/lib/libpam/modules/modules.inc +++ b/lib/libpam/modules/modules.inc @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> MODULES = MODULES += pam_chroot diff --git a/lib/libpam/modules/pam_unix/Makefile b/lib/libpam/modules/pam_unix/Makefile index 4d28cfd6a44b2..ea9e639c3b5f2 100644 --- a/lib/libpam/modules/pam_unix/Makefile +++ b/lib/libpam/modules/pam_unix/Makefile @@ -34,6 +34,7 @@ # # $FreeBSD$ +.include <src.opts.mk> .include <bsd.init.mk> LIB= pam_unix diff --git a/lib/libpcap/Makefile b/lib/libpcap/Makefile index 1a3e63409bb88..8cae1f1bdc491 100644 --- a/lib/libpcap/Makefile +++ b/lib/libpcap/Makefile @@ -3,7 +3,7 @@ SHLIBDIR?= /lib -.include <bsd.own.mk> +.include <src.opts.mk> LIB= pcap SRCS= grammar.y tokdefs.h version.h pcap-bpf.c \ diff --git a/lib/libproc/Makefile b/lib/libproc/Makefile index d2212961a0336..930249628edcf 100644 --- a/lib/libproc/Makefile +++ b/lib/libproc/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIB= proc diff --git a/lib/libproc/_libproc.h b/lib/libproc/_libproc.h index 8099ba1d91731..ffc89cfdad837 100644 --- a/lib/libproc/_libproc.h +++ b/lib/libproc/_libproc.h @@ -46,6 +46,8 @@ struct proc_handle { size_t rdobjsz; size_t nobjs; struct lwpstatus lwps; + rd_loadobj_t *rdexec; /* rdobj index of program executable. */ + char execname[MAXPATHLEN]; /* Path to program executable. */ }; #ifdef DEBUG diff --git a/lib/libproc/libproc.h b/lib/libproc/libproc.h index d80e88c466a07..be77e4b592142 100644 --- a/lib/libproc/libproc.h +++ b/lib/libproc/libproc.h @@ -102,6 +102,7 @@ typedef struct lwpstatus { #define PR_FAULTED 2 #define PR_SYSENTRY 3 #define PR_SYSEXIT 4 +#define PR_SIGNALLED 5 int pr_what; #define FLTBPT -1 } lwpstatus_t; diff --git a/lib/libproc/proc_bkpt.c b/lib/libproc/proc_bkpt.c index 2c2761acc9982..fe6ed4ab3c5df 100644 --- a/lib/libproc/proc_bkpt.c +++ b/lib/libproc/proc_bkpt.c @@ -55,13 +55,6 @@ __FBSDID("$FreeBSD$"); #error "Add support for your architecture" #endif -static void -proc_cont(struct proc_handle *phdl) -{ - - ptrace(PT_CONTINUE, proc_getpid(phdl), (caddr_t)1, 0); -} - static int proc_stop(struct proc_handle *phdl) { @@ -87,7 +80,7 @@ proc_bkptset(struct proc_handle *phdl, uintptr_t address, { struct ptrace_io_desc piod; unsigned long paddr, caddr; - int ret = 0; + int ret = 0, stopped; *saved = 0; if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD || @@ -98,9 +91,12 @@ proc_bkptset(struct proc_handle *phdl, uintptr_t address, DPRINTFX("adding breakpoint at 0x%lx", address); - if (phdl->status != PS_STOP) + stopped = 0; + if (phdl->status != PS_STOP) { if (proc_stop(phdl) != 0) return (-1); + stopped = 1; + } /* * Read the original instruction. @@ -135,9 +131,9 @@ proc_bkptset(struct proc_handle *phdl, uintptr_t address, } done: - if (phdl->status != PS_STOP) + if (stopped) /* Restart the process if we had to stop it. */ - proc_cont(phdl); + proc_continue(phdl); return (ret); } @@ -148,7 +144,7 @@ proc_bkptdel(struct proc_handle *phdl, uintptr_t address, { struct ptrace_io_desc piod; unsigned long paddr, caddr; - int ret = 0; + int ret = 0, stopped; if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD || phdl->status == PS_IDLE) { @@ -158,9 +154,12 @@ proc_bkptdel(struct proc_handle *phdl, uintptr_t address, DPRINTFX("removing breakpoint at 0x%lx", address); - if (phdl->status != PS_STOP) + stopped = 0; + if (phdl->status != PS_STOP) { if (proc_stop(phdl) != 0) return (-1); + stopped = 1; + } /* * Overwrite the breakpoint instruction that we setup previously. @@ -177,9 +176,9 @@ proc_bkptdel(struct proc_handle *phdl, uintptr_t address, ret = -1; } - if (phdl->status != PS_STOP) + if (stopped) /* Restart the process if we had to stop it. */ - proc_cont(phdl); + proc_continue(phdl); return (ret); } diff --git a/lib/libproc/proc_create.c b/lib/libproc/proc_create.c index d02eccf0d1477..4a925809badf5 100644 --- a/lib/libproc/proc_create.c +++ b/lib/libproc/proc_create.c @@ -26,8 +26,10 @@ * $FreeBSD$ */ -#include "_libproc.h" -#include <stdio.h> +#include <sys/types.h> +#include <sys/sysctl.h> +#include <sys/wait.h> + #include <err.h> #include <errno.h> #include <fcntl.h> @@ -35,7 +37,37 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> -#include <sys/wait.h> + +#include "_libproc.h" + +static int proc_init(pid_t, int, int, struct proc_handle *); + +static int +proc_init(pid_t pid, int flags, int status, struct proc_handle *phdl) +{ + int mib[4], error; + size_t len; + + memset(phdl, 0, sizeof(*phdl)); + phdl->pid = pid; + phdl->flags = flags; + phdl->status = status; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = pid; + len = sizeof(phdl->execname); + if (sysctl(mib, 4, phdl->execname, &len, NULL, 0) != 0) { + error = errno; + DPRINTF("ERROR: cannot get pathname for child process %d", pid); + return (error); + } + if (len == 0) + phdl->execname[0] = '\0'; + + return (0); +} int proc_attach(pid_t pid, int flags, struct proc_handle **pphdl) @@ -54,12 +86,12 @@ proc_attach(pid_t pid, int flags, struct proc_handle **pphdl) if ((phdl = malloc(sizeof(struct proc_handle))) == NULL) return (ENOMEM); - memset(phdl, 0, sizeof(struct proc_handle)); - phdl->pid = pid; - phdl->flags = flags; - phdl->status = PS_RUN; elf_version(EV_CURRENT); + error = proc_init(pid, flags, PS_RUN, phdl); + if (error != 0) + goto out; + if (ptrace(PT_ATTACH, phdl->pid, 0, 0) != 0) { error = errno; DPRINTF("ERROR: cannot ptrace child process %d", pid); @@ -123,9 +155,9 @@ proc_create(const char *file, char * const *argv, proc_child_func *pcf, _exit(2); } else { /* The parent owns the process handle. */ - memset(phdl, 0, sizeof(struct proc_handle)); - phdl->pid = pid; - phdl->status = PS_IDLE; + error = proc_init(pid, 0, PS_IDLE, phdl); + if (error != 0) + goto bad; /* Wait for the child process to stop. */ if (waitpid(pid, &status, WUNTRACED) == -1) { diff --git a/lib/libproc/proc_rtld.c b/lib/libproc/proc_rtld.c index 52590493c4c2b..8dff3b726615c 100644 --- a/lib/libproc/proc_rtld.c +++ b/lib/libproc/proc_rtld.c @@ -49,6 +49,9 @@ map_iter(const rd_loadobj_t *lop, void *arg) if (phdl->rdobjs == NULL) return (-1); } + if (strcmp(lop->rdl_path, phdl->execname) == 0 && + (lop->rdl_prot & RD_RDL_X) != 0) + phdl->rdexec = &phdl->rdobjs[phdl->nobjs]; memcpy(&phdl->rdobjs[phdl->nobjs++], lop, sizeof(*lop)); return (0); diff --git a/lib/libproc/proc_sym.c b/lib/libproc/proc_sym.c index 2338895ffa4ab..3777a46fd5e9c 100644 --- a/lib/libproc/proc_sym.c +++ b/lib/libproc/proc_sym.c @@ -112,17 +112,23 @@ proc_obj2map(struct proc_handle *p, const char *objname) rd_loadobj_t *rdl; char path[MAXPATHLEN]; + rdl = NULL; for (i = 0; i < p->nobjs; i++) { - rdl = &p->rdobjs[i]; - basename_r(rdl->rdl_path, path); + basename_r(p->rdobjs[i].rdl_path, path); if (strcmp(path, objname) == 0) { - if ((map = malloc(sizeof(*map))) == NULL) - return (NULL); - proc_rdl2prmap(rdl, map); - return (map); + rdl = &p->rdobjs[i]; + break; } } - return (NULL); + if (rdl == NULL && strcmp(objname, "a.out") == 0 && p->rdexec != NULL) + rdl = p->rdexec; + else + return (NULL); + + if ((map = malloc(sizeof(*map))) == NULL) + return (NULL); + proc_rdl2prmap(rdl, map); + return (map); } int @@ -386,8 +392,9 @@ proc_name2map(struct proc_handle *p, const char *name) free(kves); return (NULL); } - if (name == NULL || strcmp(name, "a.out") == 0) { - map = proc_addr2map(p, p->rdobjs[0].rdl_saddr); + if ((name == NULL || strcmp(name, "a.out") == 0) && + p->rdexec != NULL) { + map = proc_addr2map(p, p->rdexec->rdl_saddr); return (map); } for (i = 0; i < p->nobjs; i++) { diff --git a/lib/libproc/proc_util.c b/lib/libproc/proc_util.c index 1c3d5229c9f4f..4d9aa20b3de69 100644 --- a/lib/libproc/proc_util.c +++ b/lib/libproc/proc_util.c @@ -35,10 +35,9 @@ #include <sys/wait.h> #include <err.h> #include <errno.h> -#include <unistd.h> -#include <stdio.h> #include <signal.h> #include <string.h> +#include <unistd.h> #include "_libproc.h" int @@ -59,11 +58,14 @@ proc_clearflags(struct proc_handle *phdl, int mask) int proc_continue(struct proc_handle *phdl) { + int pending = 0; if (phdl == NULL) return (-1); - if (ptrace(PT_CONTINUE, phdl->pid, (caddr_t)(uintptr_t) 1, 0) != 0) + if (phdl->status == PS_STOP && WSTOPSIG(phdl->wstat) != SIGTRAP) + pending = WSTOPSIG(phdl->wstat); + if (ptrace(PT_CONTINUE, phdl->pid, (caddr_t)(uintptr_t)1, pending) != 0) return (-1); phdl->status = PS_RUN; @@ -208,12 +210,16 @@ proc_getlwpstatus(struct proc_handle *phdl) return (NULL); siginfo = &lwpinfo.pl_siginfo; if (lwpinfo.pl_event == PL_EVENT_SIGNAL && - (lwpinfo.pl_flags & PL_FLAG_SI) && - siginfo->si_signo == SIGTRAP && - (siginfo->si_code == TRAP_BRKPT || - siginfo->si_code == TRAP_TRACE)) { - psp->pr_why = PR_FAULTED; - psp->pr_what = FLTBPT; + (lwpinfo.pl_flags & PL_FLAG_SI) != 0) { + if (siginfo->si_signo == SIGTRAP && + (siginfo->si_code == TRAP_BRKPT || + siginfo->si_code == TRAP_TRACE)) { + psp->pr_why = PR_FAULTED; + psp->pr_what = FLTBPT; + } else { + psp->pr_why = PR_SIGNALLED; + psp->pr_what = siginfo->si_signo; + } } else if (lwpinfo.pl_flags & PL_FLAG_SCE) { psp->pr_why = PR_SYSENTRY; } else if (lwpinfo.pl_flags & PL_FLAG_SCX) { diff --git a/lib/libprocstat/Makefile b/lib/libprocstat/Makefile index af5a775d7d056..32c7daa0b19cb 100644 --- a/lib/libprocstat/Makefile +++ b/lib/libprocstat/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIB= procstat diff --git a/lib/libradius/Makefile b/lib/libradius/Makefile index cb68eaa32b1ae..2b769d9ee61d6 100644 --- a/lib/libradius/Makefile +++ b/lib/libradius/Makefile @@ -24,7 +24,7 @@ # # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIB= radius SRCS= radlib.c diff --git a/lib/librpcsvc/Makefile b/lib/librpcsvc/Makefile index 9c9e3ae04d530..ba972ac3e8ebb 100644 --- a/lib/librpcsvc/Makefile +++ b/lib/librpcsvc/Makefile @@ -1,7 +1,7 @@ # from: @(#)Makefile 5.10 (Berkeley) 6/24/90 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../include/rpcsvc diff --git a/lib/librtld_db/librtld_db.3 b/lib/librtld_db/librtld_db.3 index 0c9a762eb0108..4645142f7311a 100644 --- a/lib/librtld_db/librtld_db.3 +++ b/lib/librtld_db/librtld_db.3 @@ -48,7 +48,7 @@ .Fc .Ft rd_err_e .Fo rd_event_addr -.Fa "rd_agent_t *rdap, rd_notify_t *notify" +.Fa "rd_agent_t *rdap, rd_event_e event, rd_notify_t *notify" .Fc .Ft rd_err_e .Fo rd_event_enable @@ -142,10 +142,10 @@ enables reporting of events. This function always returns RD_OK. .Pp .Fn rd_event_addr -returns the event address in the +returns the event address corresponding to the .Ft event parameter. -At the moment we only report RD_NOTIFY_BPT events. +At the moment we only report events of type RD_NOTIFY_BPT. .Pp .Fn rd_event_getmsg returns the message associated with the latest event. diff --git a/lib/librtld_db/rtld_db.c b/lib/librtld_db/rtld_db.c index fef8d46c88fe5..2d1f6e697fac3 100644 --- a/lib/librtld_db/rtld_db.c +++ b/lib/librtld_db/rtld_db.c @@ -81,20 +81,40 @@ rd_errstr(rd_err_e rderr) } rd_err_e -rd_event_addr(rd_agent_t *rdap, rd_event_e event __unused, rd_notify_t *notify) +rd_event_addr(rd_agent_t *rdap, rd_event_e event, rd_notify_t *notify) { - DPRINTF("%s rdap %p notify %p\n", __func__, rdap, notify); - - notify->type = RD_NOTIFY_BPT; - notify->u.bptaddr = rdap->rda_addr; - - return (RD_OK); + rd_err_e ret; + + DPRINTF("%s rdap %p event %d notify %p\n", __func__, rdap, event, + notify); + + ret = RD_OK; + switch (event) { + case RD_NONE: + break; + case RD_PREINIT: + notify->type = RD_NOTIFY_BPT; + notify->u.bptaddr = rdap->rda_preinit_addr; + break; + case RD_POSTINIT: + notify->type = RD_NOTIFY_BPT; + notify->u.bptaddr = rdap->rda_postinit_addr; + break; + case RD_DLACTIVITY: + notify->type = RD_NOTIFY_BPT; + notify->u.bptaddr = rdap->rda_dlactivity_addr; + break; + default: + ret = RD_ERR; + break; + } + return (ret); } rd_err_e rd_event_enable(rd_agent_t *rdap __unused, int onoff) { - DPRINTF("%s onoff %d\n", __func__, onoff); + DPRINTF("%s onoff %d\n", __func__, onoff); return (RD_OK); } @@ -220,7 +240,15 @@ rd_reset(rd_agent_t *rdap) &sym) < 0) return (RD_ERR); DPRINTF("found r_debug_state at 0x%lx\n", (unsigned long)sym.st_value); - rdap->rda_addr = sym.st_value; + rdap->rda_preinit_addr = sym.st_value; + rdap->rda_dlactivity_addr = sym.st_value; + + if (proc_name2sym(rdap->rda_php, "ld-elf.so.1", "_r_debug_postinit", + &sym) < 0) + return (RD_ERR); + DPRINTF("found _r_debug_postinit at 0x%lx\n", + (unsigned long)sym.st_value); + rdap->rda_postinit_addr = sym.st_value; return (RD_OK); } diff --git a/lib/librtld_db/rtld_db.h b/lib/librtld_db/rtld_db.h index 33da4d3b9f389..9dd53f0095e5a 100644 --- a/lib/librtld_db/rtld_db.h +++ b/lib/librtld_db/rtld_db.h @@ -51,7 +51,9 @@ typedef enum { typedef struct rd_agent { struct proc_handle *rda_php; - uintptr_t rda_addr; /* address of r_debug_state */ + uintptr_t rda_dlactivity_addr; + uintptr_t rda_preinit_addr; + uintptr_t rda_postinit_addr; } rd_agent_t; typedef struct rd_loadobj { diff --git a/lib/libsm/Makefile b/lib/libsm/Makefile index 07172c75ea272..b30ba42e3af25 100644 --- a/lib/libsm/Makefile +++ b/lib/libsm/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SENDMAIL_DIR=${.CURDIR}/../../contrib/sendmail .PATH: ${SENDMAIL_DIR}/libsm diff --git a/lib/libsmb/Makefile b/lib/libsmb/Makefile index e464a8fd9875d..ea7327b3e94ca 100644 --- a/lib/libsmb/Makefile +++ b/lib/libsmb/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> CONTRIBDIR= ${.CURDIR}/../../contrib/smbfs .PATH: ${CONTRIBDIR}/lib/smb diff --git a/lib/libstand/Makefile b/lib/libstand/Makefile index 5f645203597a6..0e074d2a837e7 100644 --- a/lib/libstand/Makefile +++ b/lib/libstand/Makefile @@ -9,7 +9,7 @@ MK_PROFILE= no MK_SSP= no -.include <bsd.own.mk> +.include <src.opts.mk> LIB= stand NO_PIC= diff --git a/lib/libtelnet/Makefile b/lib/libtelnet/Makefile index e98fd53db3d09..a11138e48d900 100644 --- a/lib/libtelnet/Makefile +++ b/lib/libtelnet/Makefile @@ -1,7 +1,7 @@ # From: @(#)Makefile 8.2 (Berkeley) 12/15/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> TELNETDIR= ${.CURDIR}/../../contrib/telnet .PATH: ${TELNETDIR}/libtelnet diff --git a/lib/libthr/Makefile b/lib/libthr/Makefile index 1c70a5e71bd24..cfcc41efb9975 100644 --- a/lib/libthr/Makefile +++ b/lib/libthr/Makefile @@ -10,7 +10,7 @@ SHLIBDIR?= /lib -.include <bsd.own.mk> +.include <src.opts.mk> MK_SSP= no LIB=thr diff --git a/lib/libulog/Makefile b/lib/libulog/Makefile index 074d9db9f87a0..efbaece8fefbb 100644 --- a/lib/libulog/Makefile +++ b/lib/libulog/Makefile @@ -2,7 +2,7 @@ SHLIBDIR?=/lib -.include <bsd.own.mk> +.include <src.opts.mk> LIB= ulog SHLIB_MAJOR= 0 diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile index 582cceffba4ee..5e5139ff9fa02 100644 --- a/lib/libutil/Makefile +++ b/lib/libutil/Makefile @@ -3,7 +3,7 @@ SHLIBDIR?= /lib -.include <bsd.own.mk> +.include <src.opts.mk> LIB= util SHLIB_MAJOR= 9 diff --git a/lib/libutil/kinfo_getfile.3 b/lib/libutil/kinfo_getfile.3 index ca8c55c3242b9..1e0bab70150b5 100644 --- a/lib/libutil/kinfo_getfile.3 +++ b/lib/libutil/kinfo_getfile.3 @@ -48,7 +48,7 @@ field contains the process identifier. This should be the a process that you have privilege to access. The .Ar cntp -field is allows the caller to know how many records are returned. +field allows the caller to know how many records are returned. .Pp This function is a wrapper around .Xr sysctl 3 diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c index 60d3105db2063..4a7f852c6ffc0 100644 --- a/lib/libvmmapi/vmmapi.c +++ b/lib/libvmmapi/vmmapi.c @@ -343,10 +343,13 @@ vm_run(struct vmctx *ctx, int vcpu, uint64_t rip, struct vm_exit *vmexit) } int -vm_suspend(struct vmctx *ctx) +vm_suspend(struct vmctx *ctx, enum vm_suspend_how how) { + struct vm_suspend vmsuspend; - return (ioctl(ctx->fd, VM_SUSPEND, 0)); + bzero(&vmsuspend, sizeof(vmsuspend)); + vmsuspend.how = how; + return (ioctl(ctx->fd, VM_SUSPEND, &vmsuspend)); } static int diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h index ed63fb20259e3..2a2ca6b7f9dca 100644 --- a/lib/libvmmapi/vmmapi.h +++ b/lib/libvmmapi/vmmapi.h @@ -61,7 +61,7 @@ int vm_set_register(struct vmctx *ctx, int vcpu, int reg, uint64_t val); int vm_get_register(struct vmctx *ctx, int vcpu, int reg, uint64_t *retval); int vm_run(struct vmctx *ctx, int vcpu, uint64_t rip, struct vm_exit *ret_vmexit); -int vm_suspend(struct vmctx *ctx); +int vm_suspend(struct vmctx *ctx, enum vm_suspend_how how); int vm_apicid2vcpu(struct vmctx *ctx, int apicid); int vm_inject_exception(struct vmctx *ctx, int vcpu, int vec); int vm_inject_exception2(struct vmctx *ctx, int vcpu, int vec, int errcode); diff --git a/lib/libwrap/Makefile b/lib/libwrap/Makefile index 2ae6821d77570..7c2ca9a5535e3 100644 --- a/lib/libwrap/Makefile +++ b/lib/libwrap/Makefile @@ -2,7 +2,7 @@ # $FreeBSD$ # -.include <bsd.own.mk> +.include <src.opts.mk> LIB= wrap SHLIB_MAJOR= 6 diff --git a/lib/ncurses/Makefile b/lib/ncurses/Makefile index b363f6462204e..822905f44dcc7 100644 --- a/lib/ncurses/Makefile +++ b/lib/ncurses/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= ncurses form menu panel diff --git a/lib/ncurses/ncurses/Makefile b/lib/ncurses/ncurses/Makefile index 9cf3cc8975503..3821d4635b8a4 100644 --- a/lib/ncurses/ncurses/Makefile +++ b/lib/ncurses/ncurses/Makefile @@ -7,7 +7,7 @@ SHLIBDIR?= /lib MK_MAN=no .endif -.include <bsd.own.mk> +.include <src.opts.mk> .include "${.CURDIR}/../config.mk" diff --git a/libexec/Makefile b/libexec/Makefile index e087a8a8ffe78..8a32694d40506 100644 --- a/libexec/Makefile +++ b/libexec/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/4/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= ${_atf} \ ${_atrun} \ diff --git a/libexec/atf/atf-check/Makefile b/libexec/atf/atf-check/Makefile index 0cfa8636491b2..093de06ed5345 100644 --- a/libexec/atf/atf-check/Makefile +++ b/libexec/atf/atf-check/Makefile @@ -25,6 +25,7 @@ # # $FreeBSD$ +.include <src.opts.mk> .include <bsd.init.mk> ATF= ${.CURDIR:H:H:H}/contrib/atf diff --git a/libexec/ftpd/Makefile b/libexec/ftpd/Makefile index e415407fb9e67..0c7c9826a8431 100644 --- a/libexec/ftpd/Makefile +++ b/libexec/ftpd/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.2 (Berkeley) 4/4/94 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ftpd MAN= ftpd.8 ftpchroot.5 diff --git a/libexec/rlogind/Makefile b/libexec/rlogind/Makefile index 9807dc8e5ba30..de0fb20e2961b 100644 --- a/libexec/rlogind/Makefile +++ b/libexec/rlogind/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/4/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= rlogind MAN= rlogind.8 diff --git a/libexec/rtld-elf/Makefile b/libexec/rtld-elf/Makefile index 2a0953c96dfa1..21e2219d37275 100644 --- a/libexec/rtld-elf/Makefile +++ b/libexec/rtld-elf/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> MK_SSP= no PROG?= ld-elf.so.1 diff --git a/libexec/rtld-elf/Symbol.map b/libexec/rtld-elf/Symbol.map index 9ad6251848bc1..5ea7d7e171f65 100644 --- a/libexec/rtld-elf/Symbol.map +++ b/libexec/rtld-elf/Symbol.map @@ -30,4 +30,5 @@ FBSDprivate_1.0 { _rtld_atfork_post; _rtld_addr_phdr; _rtld_get_stack_prot; + _r_debug_postinit; }; diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index f96b8e7189f7b..443767d99ba46 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -162,6 +162,7 @@ static bool matched_symbol(SymLook *, const Obj_Entry *, Sym_Match_Result *, const unsigned long); void r_debug_state(struct r_debug *, struct link_map *) __noinline; +void _r_debug_postinit(struct link_map *) __noinline; /* * Data declarations. @@ -637,6 +638,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) if (obj_main->crt_no_init) preinit_main(); objlist_call_init(&initlist, &lockstate); + _r_debug_postinit(&obj_main->linkmap); objlist_clear(&initlist); dbg("loading filtees"); for (obj = obj_list->next; obj != NULL; obj = obj->next) { @@ -3549,7 +3551,20 @@ r_debug_state(struct r_debug* rd, struct link_map *m) * even when marked __noinline. However, gdb depends on those * calls being made. */ - __asm __volatile("" : : : "memory"); + __compiler_membar(); +} + +/* + * A function called after init routines have completed. This can be used to + * break before a program's entry routine is called, and can be used when + * main is not available in the symbol table. + */ +void +_r_debug_postinit(struct link_map *m) +{ + + /* See r_debug_state(). */ + __compiler_membar(); } /* diff --git a/libexec/tcpd/Makefile b/libexec/tcpd/Makefile index e707a4e334e89..f3fbf29b5d5f1 100644 --- a/libexec/tcpd/Makefile +++ b/libexec/tcpd/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../contrib/tcp_wrappers diff --git a/libexec/telnetd/Makefile b/libexec/telnetd/Makefile index dcc339878e146..99f023f263f2d 100644 --- a/libexec/telnetd/Makefile +++ b/libexec/telnetd/Makefile @@ -3,7 +3,7 @@ # Do not define -DKLUDGELINEMODE, as it does not interact well with many # telnet implementations. -.include <bsd.own.mk> +.include <src.opts.mk> TELNETDIR= ${.CURDIR}/../../contrib/telnet .PATH: ${TELNETDIR}/telnetd diff --git a/release/doc/en_US.ISO8859-1/hardware/article.xml b/release/doc/en_US.ISO8859-1/hardware/article.xml index 381416d1b850e..6255d97ad5e73 100644 --- a/release/doc/en_US.ISO8859-1/hardware/article.xml +++ b/release/doc/en_US.ISO8859-1/hardware/article.xml @@ -29,6 +29,7 @@ <year>2011</year> <year>2012</year> <year>2013</year> + <year>2014</year> <holder role="mailto:doc@FreeBSD.org">The &os; Documentation Project</holder> </copyright> @@ -732,10 +733,14 @@ &hwlist.mly; + &hwlist.mpr; + &hwlist.mps; &hwlist.mpt; + &hwlist.mrsas; + &hwlist.mvs; &hwlist.ncr; @@ -818,6 +823,9 @@ &hwlist.axe; + <para>ASIX Electronics AX88178A/AX88179 USB Gigabit Ethernet + adapters (&man.axge.4; driver)</para> + &hwlist.bce; <para>[&arch.amd64;, &arch.i386;] Broadcom BCM4401 based Fast @@ -1009,6 +1017,8 @@ &hwlist.ral; + &hwlist.rsu; + &hwlist.rum; &hwlist.run; @@ -1021,6 +1031,8 @@ &hwlist.urtw; + &hwlist.urtwn; + <para>[&arch.amd64;, &arch.i386;, &arch.pc98;] Lucent Technologies WaveLAN/IEEE 802.11b wireless network adapters and workalikes using the Lucent Hermes, Intersil PRISM-II, diff --git a/release/doc/en_US.ISO8859-1/relnotes/article.xml b/release/doc/en_US.ISO8859-1/relnotes/article.xml index be2466d5155e3..b987fed58afd3 100644 --- a/release/doc/en_US.ISO8859-1/relnotes/article.xml +++ b/release/doc/en_US.ISO8859-1/relnotes/article.xml @@ -3,6 +3,10 @@ "../../../share/xml/freebsd50.dtd" [ <!ENTITY % release PUBLIC "-//FreeBSD//ENTITIES Release Specification//EN" "release.ent"> %release; +<!ENTITY % sponsor PUBLIC "-//FreeBSD//ENTITIES Sponsor Specification//EN" "sponsor.ent"> + %sponsor; +<!ENTITY % vendor PUBLIC "-//FreeBSD//ENTITIES Vendor Specification//EN" "vendor.ent"> + %vendor; ]> <article xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"> <info><title>&os; &release.current; Release Notes</title> @@ -104,28 +108,63 @@ <sect2 xml:id="kernel"> <title>Kernel Changes</title> - <para revision="263754">The &man.sysctl.8; - <literal>hw.bus.devctl_disable</literal> has been - removed.</para> + <para revision="260888">The <filename>VT</filename> kernel + configuration file has been added, which enables the new + <literal>vt</literal> console driver.</para> <para revision="260903">Support for GPS ports has been added to &man.uhso.4;.</para> - <para revision="260888">The <filename>VT</filename> kernel - configuration file has been added, which enables the new - <literal>vt</literal> console driver.</para> + <para revision="264601" contrib="sponsor" + sponsor="&darpa_afrl;">The <literal>if_nf10bmac(4)</literal> + device has been added, providing support for NetFPGA-10G + Embedded CPU Ethernet Core.</para> + + <note> + <para>The <literal>if_nf10bmac(4)</literal> driver operates on + the FPGA, and is not suited for the PCI host interface.</para> + </note> + + <para revision="265132">The &man.full.4; device has been added, + and the <literal>lindev(4)</literal> device has been removed. + Prior to this change, <literal>lindev(4)</literal> provided only + the <filename>/dev/full</filename> character device, returning + <literal>ENOSPC</literal> on write attempts. As this device is + not specific to &linux;, a native &os; version has been + added.</para> + + <para revision="265236" contrib="sponsor" + sponsor="&lsi;, &spectralogic;" sponsorurl="">The &man.mpr.4; + device has been added, providing support for LSI Fusion-MPT + 3 12Gb SCSI/SATA controllers.</para> + + <para revision="265555" contrib="sponsor" + sponsor="&lsi;">The &man.mrsas.4; driver has been added, + providing support for LSI MegaRAID SAS controllers. The + &man.mfi.4; driver will attach to the controller, by default. + To enable &man.mrsas.4; add + <literal>hw.mfi.mrsas_enable=1</literal> to + <filename>/boot/loader.conf</filename>, which turns off + &man.mfi.4; device probing.</para> + + <note> + <para>At this time, the &man.mfiutil.8; utility and + the &os; version of + <application>MegaCLI</application> and + <application>StorCli</application> do not work with + &man.mrsas.4;.</para> + </note> <sect3 xml:id="kernel-virtualization"> <title>Virtualization support</title> - <para revision="260847">The &man.virtio_random.4; driver has - been added to harvest entropy from the host system.</para> - - <para revision="260583">Unmapped IO support has been added to - &man.virtio_scsi.4;.</para> - - <para revision="260582">Unmapped IO support has been added to - &man.virtio_blk.4;.</para> + <para revision="260410">Support for the <quote>Virtual Interrupt + Delivery</quote> feature of &intel; VT-x is enabled if + supported by the CPU. This feature can be disabled by running + <literal>sysctl hw.vmm.vmx.use_apic_vid=0</literal>. + Additionally, to persist this setting across reboots, add + <literal>hw.vmm.vmx.use_apic_vid=0</literal> to + <filename>/etc/sysctl.conf</filename>.</para> <para revision="260532">Support for <quote>Posted Interrupt Processing</quote> is enabled if supported by the CPU. This @@ -135,13 +174,14 @@ <literal>hw.vmm.vmx.use_apic_pir=0</literal> to <filename>/etc/sysctl.conf</filename>.</para> - <para revision="260410">Support for the <quote>Virtual Interrupt - Delivery</quote> feature of &intel; VT-x is enabled if - supported by the CPU. This feature can be disabled by running - <literal>sysctl hw.vmm.vmx.use_apic_vid=0</literal>. - Additionally, to persist this setting across reboots, add - <literal>hw.vmm.vmx.use_apic_vid=0</literal> to - <filename>/etc/sysctl.conf</filename>.</para> + <para revision="260582">Unmapped IO support has been added to + &man.virtio_blk.4;.</para> + + <para revision="260583">Unmapped IO support has been added to + &man.virtio_scsi.4;.</para> + + <para revision="260847">The &man.virtio_random.4; driver has + been added to harvest entropy from the host system.</para> </sect3> <sect3 xml:id="kernel-arm"> @@ -169,22 +209,26 @@ <sect4 xml:id="net-if"> <title>Network Interface Support</title> - <para revision="260552">Firmware for &intel; - Centrino™ Wireless-N 105 devices has been added - to the base system.</para> + <para revision="258830">Support for Broadcom chipsets + BCM57764, BCM57767, BCM57782, BCM57786 and BCM57787 has + been added to &man.bge.4;.</para> <para revision="260448">Support for the &intel; Centrino™ Wireless-N 135 chipset has been added.</para> - <para revision="258830">Support for Broadcom chipsets - BCM57764, BCM57767, BCM57782, BCM57786 and BCM57787 has - been added to &man.bge.4;.</para> + <para revision="260552">Firmware for &intel; + Centrino™ Wireless-N 105 devices has been added + to the base system.</para> <para revision="261975">The deprecated nve(4) driver has been removed. Users of NVIDIA nForce MCP network adapters are advised to use the &man.nfe.4; driver instead, which has been the default driver for this hardware since &os; 7.0.</para> + + <para revision="265348" contrib="sponsor" + sponsor="&netgate;">The &man.ath.hal.4; driver has been + updated to support the Atheros AR1111 chipset.</para> </sect4> </sect3> @@ -218,14 +262,15 @@ <sect2 xml:id="userland"> <title>Userland Changes</title> - <para revision="260926">Support for displaying VPD for PCI devices - via &man.pciconf.8; has been added.</para> + <para revision="258838" contrib="sponsor" sponsor="&ff;, &google;" + sponsorurl="">The &man.casperd.8; daemon has been added, + which provides access to functionality that is not available in + the <quote>capability mode</quote> sandbox.</para> - <para revision="260913">A new flag, <quote>onifconsole</quote> has - been added to <filename>/etc/ttys</filename>. This allows the - system to provide a login prompt via serial console if the - device is an active kernel console, otherwise it is equivalent - to <literal>off</literal>.</para> + <para revision="260594">When unable to load a kernel module with + &man.kldload.8;, a message informing to view output of + &man.dmesg.8; is now printed, opposed to the previous output + <quote>Exec format error.</quote>.</para> <para revision="260910">Allow &man.pciconf.8; to identify PCI devices that are attached to a driver to be identified by their @@ -234,14 +279,14 @@ to restrict the output to only listing details about a single device.</para> - <para revision="260594">When unable to load a kernel module with - &man.kldload.8;, a message informing to view output of - &man.dmesg.8; is now printed, opposed to the previous output - <quote>Exec format error.</quote>.</para> + <para revision="260913">A new flag, <quote>onifconsole</quote> has + been added to <filename>/etc/ttys</filename>. This allows the + system to provide a login prompt via serial console if the + device is an active kernel console, otherwise it is equivalent + to <literal>off</literal>.</para> - <para revision="258838">The &man.casperd.8; daemon has been added, - which provides access to functionality that is not available in - the <quote>capability mode</quote> sandbox.</para> + <para revision="260926">Support for displaying VPD for PCI devices + via &man.pciconf.8; has been added.</para> <para revision="261498">&man.ping.8; protects against malicious network packets using the Capsicum framework to drop @@ -250,6 +295,17 @@ <para revision="261504">&os;/&arch.i386; guests can be run under bhyve.</para> + <para revision="265229">The &man.ps.1; utility has been + updated to include the <literal>-J</literal> flag, used to + filter output by matching &man.jail.8; IDs and names. + Additionally, argument <literal>0</literal> can be used to + <literal>-J</literal> to only list processes running on the + host system.</para> + + <para revision="265249">The &man.top.1; utility has been updated + to filter by &man.jail.8; ID or name, in followup to the + &man.ps.1; change in <literal>r265229</literal>.</para> + <sect3 xml:id="rc-scripts"> <title><filename>/etc/rc.d</filename> Scripts</title> @@ -260,14 +316,15 @@ <sect2 xml:id="contrib"> <title>Contributed Software</title> - <para revision="260445">&man.byacc.1; has been updated to version - 20140101.</para> + <para revision="258884" contrib="sponsor" + sponsor="&darpa_afrl;">&man.lldb.1; has been updated to upstream + snapshot version r196259.</para> <para revision="259626">Timezone data files have been updated to version 2013i.</para> - <para revision="258884">&man.lldb.1; has been updated to upstream - snapshot version r196259.</para> + <para revision="260445">&man.byacc.1; has been updated to version + 20140101.</para> <para revision="261037"><application>OpenSSL</application> has been updated to version 1.0.1.f.</para> @@ -275,11 +332,8 @@ <para revision="261071">&man.jemalloc.3; has been updated to version 3.5.0.</para> - <para role="merged"><application>sendmail</application> has been - updated from 8.14.7 to 8.14.8.</para> - - <para revision="261320"><application>OpenSSH</application> has - been updated to 6.5p1.</para> + <para revision="261197" role="merged"><application>Sendmail</application> + has been updated from 8.14.7 to 8.14.8.</para> <para revision="261212"><application>bmake</application> has been updated to version 20140101.</para> @@ -287,6 +341,9 @@ <para revision="261283"><application>libc++</application> has been updated to version 3.4.</para> + <para revision="261320"><application>OpenSSH</application> has + been updated to 6.5p1.</para> + <para revision="261344"><application>mdocml</application> has been updated to version 1.12.3.</para> diff --git a/release/doc/share/misc/dev.archlist.txt b/release/doc/share/misc/dev.archlist.txt index 009fb95d1f389..ad7a6afa4ba0a 100644 --- a/release/doc/share/misc/dev.archlist.txt +++ b/release/doc/share/misc/dev.archlist.txt @@ -108,6 +108,7 @@ qlxgbe amd64 qlxge amd64 rc i386 ral i386,amd64 +rsu i386,amd64 rue i386,pc98,amd64 rum i386,amd64 run i386,amd64 diff --git a/release/doc/share/xml/catalog.xml b/release/doc/share/xml/catalog.xml index c4e04b6ae295c..74f8ccd068ff1 100644 --- a/release/doc/share/xml/catalog.xml +++ b/release/doc/share/xml/catalog.xml @@ -7,5 +7,7 @@ rewritePrefix="../../"/> <public publicId="-//FreeBSD//ENTITIES Release Specification//EN" uri="release.ent"/> + <public publicId="-//FreeBSD//ENTITIES Sponsor Specification//EN" uri="sponsor.ent"/> + <public publicId="-//FreeBSD//ENTITIES Vendor Specification//EN" uri="vendor.ent"/> <public publicId="-//FreeBSD//ENTITIES Auto Generated Device Lists//EN" uri="dev-auto.ent"/> </catalog> diff --git a/release/doc/share/xml/release.xsl b/release/doc/share/xml/release.xsl index 787cb28284f97..d3616a0c2beb8 100644 --- a/release/doc/share/xml/release.xsl +++ b/release/doc/share/xml/release.xsl @@ -43,6 +43,51 @@ <xsl:value-of select="concat('[r', @revision, ']')"/> </xsl:element> </xsl:if> + <xsl:if test="@contrib"> + <xsl:element name="span"> + <xsl:attribute name="class"> + <xsl:value-of select="'contrib'"/> + </xsl:attribute> + <xsl:choose> + <xsl:when test="@contrib = 'sponsor'"> + <xsl:if test="@sponsor != ''"> + (Sponsored by + <xsl:choose> + <xsl:when test="@sponsorurl != ''"> + <xsl:element name="a"> + <xsl:attribute name="href"> + <xsl:value-of select="@sponsorurl"/> + </xsl:attribute> + <xsl:value-of select="concat(@sponsor, ')')"/> + </xsl:element> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat(@sponsor, ')')"/> + </xsl:otherwise> + </xsl:choose> + </xsl:if> + </xsl:when> + <xsl:when test="@contrib = 'vendor'"> + <xsl:if test="@vendor != ''"> + (Contributed / provided by + <xsl:choose> + <xsl:when test="@vendorurl != ''"> + <xsl:element name="a"> + <xsl:attribute name="href"> + <xsl:value-of select="@vendorurl"/> + </xsl:attribute> + <xsl:value-of select="concat(@vendor, ')')"/> + </xsl:element> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat(@vendor, ')')"/> + </xsl:otherwise> + </xsl:choose> + </xsl:if> + </xsl:when> + </xsl:choose> + </xsl:element> + </xsl:if> </p> </xsl:variable> diff --git a/release/doc/share/xml/sponsor.ent b/release/doc/share/xml/sponsor.ent new file mode 100644 index 0000000000000..6e01090d3435a --- /dev/null +++ b/release/doc/share/xml/sponsor.ent @@ -0,0 +1,25 @@ +<!-- -*- sgml -*- + + $FreeBSD$ + + Sponsors of various works. + + Please keep the entity list sorted alphabetically. + +--> + +<!ENTITY afrl "AFRL"> + +<!ENTITY darpa "DARPA"> +<!ENTITY darpa_afrl "DARPA, AFRL"> + +<!ENTITY ff "The &os; Foundation"> +<!ENTITY ff.url "https://www.FreeBSDFoundation.org/"> + +<!ENTITY google "Google, Inc."> + +<!ENTITY lsi "LSI"> + +<!ENTITY netgate "Netgate"> + +<!ENTITY spectralogic "Spectra Logic"> diff --git a/release/doc/share/xml/vendor.ent b/release/doc/share/xml/vendor.ent new file mode 100644 index 0000000000000..75c879b71c825 --- /dev/null +++ b/release/doc/share/xml/vendor.ent @@ -0,0 +1,9 @@ +<!-- -*- sgml -*- + + $FreeBSD$ + + Vendors and contributors. + + Please keep the entity list sorted alphabetically. + +--> diff --git a/release/picobsd/tinyware/login/Makefile b/release/picobsd/tinyware/login/Makefile index a86fff46a933d..0a39c756ad18e 100644 --- a/release/picobsd/tinyware/login/Makefile +++ b/release/picobsd/tinyware/login/Makefile @@ -1,7 +1,7 @@ # From: @(#)Makefile 8.1 (Berkeley) 7/19/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../../../usr.bin/login diff --git a/release/powerpc/make-memstick.sh b/release/powerpc/make-memstick.sh index 2277af072fcee..4f6b69d473977 100755 --- a/release/powerpc/make-memstick.sh +++ b/release/powerpc/make-memstick.sh @@ -41,38 +41,7 @@ if [ $? -ne 0 ]; then fi rm ${1}/etc/fstab -# -# Use $BLOCKSIZE for transfers to improve efficiency. When calculating -# how many blocks to transfer "+ 2" is to account for truncation in the -# division and to provide space for the label. -# - -filesize=`stat -f "%z" ${tempfile}` -blocks=$(($filesize / ${BLOCKSIZE} + 1728)) -dd if=/dev/zero of=${2} bs=${BLOCKSIZE} count=${blocks} -if [ $? -ne 0 ]; then - echo "creation of image file failed" - exit 1 -fi - -unit=`mdconfig -a -t vnode -f ${2}` -if [ $? -ne 0 ]; then - echo "mdconfig failed" - exit 1 -fi - -gpart create -s APM ${unit} -gpart add -t freebsd-boot -s 800K ${unit} -gpart bootcode -p ${1}/boot/boot1.hfs -i 1 ${unit} -gpart add -t freebsd-ufs -l FreeBSD_Install ${unit} - -dd if=${tempfile} of=/dev/${unit}s3 bs=$BLOCKSIZE conv=sync -if [ $? -ne 0 ]; then - echo "copying filesystem into image file failed" - exit 1 -fi - -mdconfig -d -u ${unit} +mkimg -s apm -p freebsd-boot:=${1}/boot/boot1.hfs -p freebsd-ufs/FreeBSD_Install:=${tempfile} -o ${2} rm -f ${tempfile} diff --git a/release/scripts/relnotes-search.sh b/release/scripts/relnotes-search.sh new file mode 100755 index 0000000000000..a9a931a84c100 --- /dev/null +++ b/release/scripts/relnotes-search.sh @@ -0,0 +1,133 @@ +#!/bin/sh +#- +# Copyright (c) 2014 The FreeBSD Foundation +# All rights reserved. +# +# This software were developed by Glen Barber +# under sponsorship from the FreeBSD Foundation. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +set -C + +PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin" +export PATH + +usage() { + echo "Usage:" + echo -n "$(basename ${0}) [-rNNNNNN]" + echo " [-l /path/for/output] /path/to/branch" + echo " -r: The oldest commit to include in the search" + echo "" + exit 1 +} + +main() { + while getopts "l:r:" arg ; do + case ${arg} in + l) + # Disallow '-rNNNNNN' argument for oldest + # revision # from becoming the log file + # accidentally. + where="${OPTARG##-r*}" + [ -z "${where}" ] && usage + if [ -e "${where}" ]; then + echo "Log file already exists:" + echo " (${where})" + return 2 + fi + ;; + r) + rev="${OPTARG##-r}" + c=$(echo -n ${rev} | tr -d '0-9' | wc -c) + if [ ${c} -ne 0 ]; then + echo "Revision number must be numeric." + return 2 + fi + # Since the last specified revision is + # specified, mangle the variable to + # make svn syntax happy. + rev="-r${rev}:rHEAD" + ;; + *) + usage + ;; + esac + done + shift $(( ${OPTIND} - 1 )) + + # This assumes a local working copy, which svn search + # allows exactly one repository path (although the root + # can still be the path). + [ "$#" -ne 1 ] && usage + + # If no log file, write to stdout. + [ -z "${where}" ] && where=/dev/stdout + + svn= + # Where is svn? + for s in /usr/bin /usr/local/bin; do + if [ -x ${s}/svn ]; then + svn=${s}/svn + break + fi + if [ -x ${s}/svnlite ]; then + svn=${s}/svnlite + break + fi + done + # Did we find svn? + if [ -z "${svn}" ]; then + echo "svn(1) binary not found." + return 2 + fi + # Is more than one path specified? (This should never + # be triggered, because the argument count is checked + # above, but better safe than sorry.) + if [ $# -gt 1 ]; then + echo "Cannot specify more than one working path." + return 2 + fi + # Does the directory exist? + if [ ! -d "${1}" ]; then + echo "Specified path (${1}) is not a directory." + return 2 + fi + # Is it a subversion repository checkout? + ${svn} info ${1} >/dev/null 2>&1 + if [ "$?" -ne 0 ]; then + echo "Cannot determine svn repository information for ${1}" + return 2 + fi + + # All tests passed. Let's see what can possibly go wrong + # from here. The search string specified should match this + # in PCRE speak: ':[\t ]*' + ${svn} log ${rev} --search 'Relnotes:?[^ ]*' ${1} > ${where} + return $? +} + +main "${@}" +exit $? diff --git a/rescue/librescue/Makefile b/rescue/librescue/Makefile index 62f5da1ba2920..ad4931e52c665 100644 --- a/rescue/librescue/Makefile +++ b/rescue/librescue/Makefile @@ -2,7 +2,7 @@ # $FreeBSD$ # -.include <bsd.own.mk> +.include <src.opts.mk> MK_SSP= no # Certain library entries have hard-coded references to diff --git a/rescue/rescue/Makefile b/rescue/rescue/Makefile index ea0d1370d80c2..fc778f0aa2804 100644 --- a/rescue/rescue/Makefile +++ b/rescue/rescue/Makefile @@ -3,7 +3,7 @@ MAN= -.include <bsd.own.mk> +.include <src.opts.mk> MK_SSP= no PROG= rescue @@ -52,7 +52,7 @@ CRUNCH_SRCDIRS+= bin CRUNCH_PROGS_bin= cat chflags chio chmod cp date dd df echo \ ed expr getfacl hostname kenv kill ln ls mkdir mv \ pkill ps pwd realpath rm rmdir setfacl sh stty sync test -CRUNCH_LIBS+= -lcrypt -ledit -lkvm -ll -ltermcap -lutil +CRUNCH_LIBS+= -lcrypt -ledit -ljail -lkvm -ll -ltermcap -lutil CRUNCH_BUILDTOOLS+= bin/sh # Additional options for specific programs @@ -120,7 +120,7 @@ CRUNCH_PROGS_sbin+= zpool CRUNCH_LIBS+= -lalias -lcam -lcurses -ldevstat -lipsec .if ${MK_ZFS} != "no" -CRUNCH_LIBS+= -lavl -ljail -lzfs_core -lzfs -lnvpair -lpthread -luutil -lumem +CRUNCH_LIBS+= -lavl -lzfs_core -lzfs -lnvpair -lpthread -luutil -lumem .endif CRUNCH_LIBS+= -lgeom -lbsdxml -lkiconv -lmd -lsbuf -lufs -lz diff --git a/sbin/Makefile b/sbin/Makefile index 154815514349e..3725270c4c3fa 100644 --- a/sbin/Makefile +++ b/sbin/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.5 (Berkeley) 3/31/94 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> # XXX MISSING: icheck ncheck diff --git a/sbin/Makefile.inc b/sbin/Makefile.inc index e506f9c56cee5..896c64c82c130 100644 --- a/sbin/Makefile.inc +++ b/sbin/Makefile.inc @@ -1,7 +1,7 @@ # @(#)Makefile.inc 8.1 (Berkeley) 6/8/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> BINDIR?= /sbin WARNS?= 6 diff --git a/sbin/atm/atmconfig/Makefile b/sbin/atm/atmconfig/Makefile index b2857c972d604..3e42d3ff87b55 100644 --- a/sbin/atm/atmconfig/Makefile +++ b/sbin/atm/atmconfig/Makefile @@ -5,7 +5,7 @@ # # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= atmconfig .ifndef RESCUE diff --git a/sbin/dhclient/Makefile b/sbin/dhclient/Makefile index 57c92118d1310..09f19db0747e5 100644 --- a/sbin/dhclient/Makefile +++ b/sbin/dhclient/Makefile @@ -31,7 +31,7 @@ # OF THE POSSIBILITY OF SUCH DAMAGE. # -.include <bsd.own.mk> +.include <src.opts.mk> SRCS= dhclient.c clparse.c alloc.c dispatch.c hash.c bpf.c options.c \ tree.c conflex.c errwarn.c inet.c packet.c convert.c tables.c \ diff --git a/sbin/geom/class/Makefile b/sbin/geom/class/Makefile index 912561fbc52f4..a7ed1b9450e50 100644 --- a/sbin/geom/class/Makefile +++ b/sbin/geom/class/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= cache SUBDIR+=concat diff --git a/sbin/ggate/Makefile b/sbin/ggate/Makefile index 8f889f1837eb5..b463359916711 100644 --- a/sbin/ggate/Makefile +++ b/sbin/ggate/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= ${_ggatec} \ ${_ggated} \ diff --git a/sbin/growfs/Makefile b/sbin/growfs/Makefile index 58ce41df6310f..025771fa03703 100644 --- a/sbin/growfs/Makefile +++ b/sbin/growfs/Makefile @@ -6,7 +6,7 @@ #GFSDBG= -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../mount diff --git a/sbin/gvinum/gvinum.8 b/sbin/gvinum/gvinum.8 index d1d10d7214dd7..703a81056f70c 100644 --- a/sbin/gvinum/gvinum.8 +++ b/sbin/gvinum/gvinum.8 @@ -28,7 +28,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 1, 2013 +.Dd May 6, 2014 .Dt GVINUM 8 .Os .Sh NAME @@ -168,7 +168,7 @@ the beginning of the plex if the .Fl f flag is specified, or otherwise at the location of the parity check pointer. All subdisks in the plex must be up for a parity check. -.It Ic resetconfig +.It Ic resetconfig Oo Fl f Oc Reset the complete .Nm configuration. diff --git a/sbin/gvinum/gvinum.c b/sbin/gvinum/gvinum.c index 5760d2b8bb28d..4feaa811f2d8a 100644 --- a/sbin/gvinum/gvinum.c +++ b/sbin/gvinum/gvinum.c @@ -58,35 +58,36 @@ #include "gvinum.h" -void gvinum_attach(int, char **); -void gvinum_concat(int, char **); -void gvinum_create(int, char **); -void gvinum_detach(int, char **); -void gvinum_grow(int, char **); -void gvinum_help(void); -void gvinum_list(int, char **); -void gvinum_move(int, char **); -void gvinum_mirror(int, char **); -void gvinum_parityop(int, char **, int); -void gvinum_printconfig(int, char **); -void gvinum_raid5(int, char **); -void gvinum_rename(int, char **); -void gvinum_resetconfig(void); -void gvinum_rm(int, char **); -void gvinum_saveconfig(void); -void gvinum_setstate(int, char **); -void gvinum_start(int, char **); -void gvinum_stop(int, char **); -void gvinum_stripe(int, char **); -void parseline(int, char **); -void printconfig(FILE *, char *); - -char *create_drive(char *); -void create_volume(int, char **, char *); -char *find_name(const char *, int, int); -char *find_pattern(char *, char *); -void copy_device(struct gv_drive *, const char *); -#define find_drive() find_name("gvinumdrive", GV_TYPE_DRIVE, GV_MAXDRIVENAME) +static void gvinum_attach(int, char * const *); +static void gvinum_concat(int, char * const *); +static void gvinum_create(int, char * const *); +static void gvinum_detach(int, char * const *); +static void gvinum_grow(int, char * const *); +static void gvinum_help(void); +static void gvinum_list(int, char * const *); +static void gvinum_move(int, char * const *); +static void gvinum_mirror(int, char * const *); +static void gvinum_parityop(int, char * const * , int); +static void gvinum_printconfig(int, char * const *); +static void gvinum_raid5(int, char * const *); +static void gvinum_rename(int, char * const *); +static void gvinum_resetconfig(int, char * const *); +static void gvinum_rm(int, char * const *); +static void gvinum_saveconfig(void); +static void gvinum_setstate(int, char * const *); +static void gvinum_start(int, char * const *); +static void gvinum_stop(int, char * const *); +static void gvinum_stripe(int, char * const *); +static void parseline(int, char * const *); +static void printconfig(FILE *, const char *); + +static char *create_drive(const char *); +static void create_volume(int, char * const * , const char *); +static char *find_name(const char *, int, int); +static const char *find_pattern(char *, const char *); +static void copy_device(struct gv_drive *, const char *); +#define find_drive() \ + find_name("gvinumdrive", GV_TYPE_DRIVE, GV_MAXDRIVENAME) int main(int argc, char **argv) @@ -95,8 +96,10 @@ main(int argc, char **argv) char buffer[BUFSIZ], *inputline, *token[GV_MAXARGS]; /* Load the module if necessary. */ - if (kldfind(GVINUMMOD) < 0 && kldload(GVINUMMOD) < 0) - err(1, GVINUMMOD ": Kernel module not available"); + if (modfind(GVINUMMOD) < 0) { + if (kldload(GVINUMKLD) < 0 && modfind(GVINUMMOD) < 0) + err(1, GVINUMKLD ": Kernel module not available"); + } /* Arguments given on the command line. */ if (argc > 1) { @@ -130,8 +133,8 @@ main(int argc, char **argv) } /* Attach a plex to a volume or a subdisk to a plex. */ -void -gvinum_attach(int argc, char **argv) +static void +gvinum_attach(int argc, char * const *argv) { struct gctl_req *req; const char *errstr; @@ -167,8 +170,8 @@ gvinum_attach(int argc, char **argv) gctl_free(req); } -void -gvinum_create(int argc, char **argv) +static void +gvinum_create(int argc, char * const *argv) { struct gctl_req *req; struct gv_drive *d; @@ -191,8 +194,8 @@ gvinum_create(int argc, char **argv) flags |= GV_FLAG_F; /* Else it must be a file. */ } else { - if ((tmp = fopen(argv[1], "r")) == NULL) { - warn("can't open '%s' for reading", argv[1]); + if ((tmp = fopen(argv[i], "r")) == NULL) { + warn("can't open '%s' for reading", argv[i]); return; } } @@ -400,8 +403,8 @@ gvinum_create(int argc, char **argv) } /* Create a concatenated volume. */ -void -gvinum_concat(int argc, char **argv) +static void +gvinum_concat(int argc, char * const *argv) { if (argc < 2) { @@ -411,10 +414,9 @@ gvinum_concat(int argc, char **argv) create_volume(argc, argv, "concat"); } - /* Create a drive quick and dirty. */ -char * -create_drive(char *device) +static char * +create_drive(const char *device) { struct gv_drive *d; struct gctl_req *req; @@ -477,12 +479,12 @@ create_drive(char *device) return (drivename); } -/* +/* * General routine for creating a volume. Mainly for use by concat, mirror, * raid5 and stripe commands. */ -void -create_volume(int argc, char **argv, char *verb) +static void +create_volume(int argc, char * const *argv, const char *verb) { struct gctl_req *req; const char *errstr; @@ -516,7 +518,7 @@ create_volume(int argc, char **argv, char *verb) snprintf(buf, sizeof(buf), "drive%d", drives++); /* First we create the drive. */ - drivename = create_drive(argv[i]); + drivename = create_drive(argv[i]); if (drivename == NULL) goto bad; /* Then we add it to the request. */ @@ -532,7 +534,7 @@ create_volume(int argc, char **argv, char *verb) /* Then we send a request to actually create the volumes. */ gctl_ro_param(req, "verb", -1, verb); - gctl_ro_param(req, "flags", sizeof(int), &flags); + gctl_ro_param(req, "flags", sizeof(int), &flags); gctl_ro_param(req, "drives", sizeof(int), &drives); gctl_ro_param(req, "name", -1, volname); errstr = gctl_issue(req); @@ -543,8 +545,8 @@ bad: } /* Parse a line of the config, return the word after <pattern>. */ -char * -find_pattern(char *line, char *pattern) +static const char * +find_pattern(char *line, const char *pattern) { char *ptr; @@ -561,12 +563,12 @@ find_pattern(char *line, char *pattern) } /* Find a free name for an object given a prefix. */ -char * +static char * find_name(const char *prefix, int type, int namelen) { struct gctl_req *req; - char comment[1], buf[GV_CFG_LEN - 1], *name, *sname, *ptr; - const char *errstr; + char comment[1], buf[GV_CFG_LEN - 1], *sname, *ptr; + const char *errstr, *name; int i, n, begin, len, conflict; char line[1024]; @@ -631,9 +633,10 @@ find_name(const char *prefix, int type, int namelen) return (NULL); } -void +static void copy_device(struct gv_drive *d, const char *device) { + if (strncmp(device, "/dev/", 5) == 0) strlcpy(d->device, (device + 5), sizeof(d->device)); else @@ -641,8 +644,8 @@ copy_device(struct gv_drive *d, const char *device) } /* Detach a plex or subdisk from its parent. */ -void -gvinum_detach(int argc, char **argv) +static void +gvinum_detach(int argc, char * const *argv) { const char *errstr; struct gctl_req *req; @@ -652,7 +655,7 @@ gvinum_detach(int argc, char **argv) optreset = 1; optind = 1; while ((i = getopt(argc, argv, "f")) != -1) { - switch(i) { + switch (i) { case 'f': flags |= GV_FLAG_F; break; @@ -680,9 +683,10 @@ gvinum_detach(int argc, char **argv) gctl_free(req); } -void +static void gvinum_help(void) { + printf("COMMANDS\n" "checkparity [-f] plex\n" " Check the parity blocks of a RAID-5 plex.\n" @@ -721,7 +725,7 @@ gvinum_help(void) " Change the name of the specified object.\n" "rebuildparity plex [-f]\n" " Rebuild the parity blocks of a RAID-5 plex.\n" - "resetconfig\n" + "resetconfig [-f]\n" " Reset the complete gvinum configuration\n" "rm [-r] [-f] volume | plex | subdisk | drive\n" " Remove an object.\n" @@ -737,12 +741,10 @@ gvinum_help(void) "stripe [-fv] [-n name] drives\n" " Create a striped volume from the specified drives.\n" ); - - return; } -void -gvinum_setstate(int argc, char **argv) +static void +gvinum_setstate(int argc, char * const *argv) { struct gctl_req *req; int flags, i; @@ -796,8 +798,8 @@ gvinum_setstate(int argc, char **argv) gctl_free(req); } -void -gvinum_list(int argc, char **argv) +static void +gvinum_list(int argc, char * const *argv) { struct gctl_req *req; int flags, i, j; @@ -858,12 +860,11 @@ gvinum_list(int argc, char **argv) printf("%s", config); gctl_free(req); - return; } /* Create a mirrored volume. */ -void -gvinum_mirror(int argc, char **argv) +static void +gvinum_mirror(int argc, char * const *argv) { if (argc < 2) { @@ -874,8 +875,8 @@ gvinum_mirror(int argc, char **argv) } /* Note that move is currently of form '[-r] target object [...]' */ -void -gvinum_move(int argc, char **argv) +static void +gvinum_move(int argc, char * const *argv) { struct gctl_req *req; const char *errstr; @@ -925,17 +926,17 @@ gvinum_move(int argc, char **argv) if (errstr != NULL) warnx("can't move object(s): %s", errstr); gctl_free(req); - return; } -void -gvinum_printconfig(int argc, char **argv) +static void +gvinum_printconfig(int argc, char * const *argv) { + printconfig(stdout, ""); } -void -gvinum_parityop(int argc, char **argv, int rebuild) +static void +gvinum_parityop(int argc, char * const *argv, int rebuild) { struct gctl_req *req; int flags, i; @@ -959,7 +960,6 @@ gvinum_parityop(int argc, char **argv, int rebuild) case 'v': flags |= GV_FLAG_V; break; - case '?': default: warnx("invalid flag '%c'", i); return; @@ -987,8 +987,8 @@ gvinum_parityop(int argc, char **argv, int rebuild) } /* Create a RAID-5 volume. */ -void -gvinum_raid5(int argc, char **argv) +static void +gvinum_raid5(int argc, char * const *argv) { if (argc < 2) { @@ -998,9 +998,8 @@ gvinum_raid5(int argc, char **argv) create_volume(argc, argv, "raid5"); } - -void -gvinum_rename(int argc, char **argv) +static void +gvinum_rename(int argc, char * const *argv) { struct gctl_req *req; const char *errstr; @@ -1016,7 +1015,6 @@ gvinum_rename(int argc, char **argv) case 'r': flags |= GV_FLAG_R; break; - case '?': default: return; } @@ -1049,11 +1047,10 @@ gvinum_rename(int argc, char **argv) if (errstr != NULL) warnx("can't rename object: %s", errstr); gctl_free(req); - return; } -void -gvinum_rm(int argc, char **argv) +static void +gvinum_rm(int argc, char * const *argv) { struct gctl_req *req; int flags, i, j; @@ -1071,7 +1068,6 @@ gvinum_rm(int argc, char **argv) case 'r': flags |= GV_FLAG_R; break; - case '?': default: return; } @@ -1099,27 +1095,41 @@ gvinum_rm(int argc, char **argv) gctl_free(req); } -void -gvinum_resetconfig(void) +static void +gvinum_resetconfig(int argc, char * const *argv) { struct gctl_req *req; const char *errstr; char reply[32]; + int flags, i; - if (!isatty(STDIN_FILENO)) { - warn("Please enter this command from a tty device\n"); - return; + flags = 0; + while ((i = getopt(argc, argv, "f")) != -1) { + switch (i) { + case 'f': + flags |= GV_FLAG_F; + break; + default: + warn("invalid flag: %c", i); + return; + } } - printf(" WARNING! This command will completely wipe out your gvinum" - "configuration.\n" - " All data will be lost. If you really want to do this," - " enter the text\n\n" - " NO FUTURE\n" - " Enter text -> "); - fgets(reply, sizeof(reply), stdin); - if (strcmp(reply, "NO FUTURE\n")) { - printf("\n No change\n"); - return; + if ((flags & GV_FLAG_F) == 0) { + if (!isatty(STDIN_FILENO)) { + warn("Please enter this command from a tty device\n"); + return; + } + printf(" WARNING! This command will completely wipe out" + " your gvinum configuration.\n" + " All data will be lost. If you really want to do this," + " enter the text\n\n" + " NO FUTURE\n" + " Enter text -> "); + fgets(reply, sizeof(reply), stdin); + if (strcmp(reply, "NO FUTURE\n")) { + printf("\n No change\n"); + return; + } } req = gctl_get_handle(); gctl_ro_param(req, "class", -1, "VINUM"); @@ -1134,7 +1144,7 @@ gvinum_resetconfig(void) printf("gvinum configuration obliterated\n"); } -void +static void gvinum_saveconfig(void) { struct gctl_req *req; @@ -1149,8 +1159,8 @@ gvinum_saveconfig(void) gctl_free(req); } -void -gvinum_start(int argc, char **argv) +static void +gvinum_start(int argc, char * const *argv) { struct gctl_req *req; int i, initsize, j; @@ -1170,7 +1180,6 @@ gvinum_start(int argc, char **argv) case 'S': initsize = atoi(optarg); break; - case '?': default: return; } @@ -1202,14 +1211,15 @@ gvinum_start(int argc, char **argv) gctl_free(req); } -void -gvinum_stop(int argc, char **argv) +static void +gvinum_stop(int argc, char * const *argv) { int err, fileid; - fileid = kldfind(GVINUMMOD); + fileid = kldfind(GVINUMKLD); if (fileid == -1) { - warn("cannot find " GVINUMMOD); + if (modfind(GVINUMMOD) < 0) + warn("cannot find " GVINUMKLD); return; } @@ -1219,7 +1229,7 @@ gvinum_stop(int argc, char **argv) * event thread will be free for the g_wither_geom() call from * gv_unload(). It's silly, but it works. */ - printf("unloading " GVINUMMOD " kernel module... "); + printf("unloading " GVINUMKLD " kernel module... "); fflush(stdout); if ((err = kldunload(fileid)) != 0 && (errno == EAGAIN)) { sleep(1); @@ -1227,7 +1237,7 @@ gvinum_stop(int argc, char **argv) } if (err != 0) { printf(" failed!\n"); - warn("cannot unload " GVINUMMOD); + warn("cannot unload " GVINUMKLD); return; } @@ -1236,8 +1246,8 @@ gvinum_stop(int argc, char **argv) } /* Create a striped volume. */ -void -gvinum_stripe(int argc, char **argv) +static void +gvinum_stripe(int argc, char * const *argv) { if (argc < 2) { @@ -1248,8 +1258,8 @@ gvinum_stripe(int argc, char **argv) } /* Grow a subdisk by adding disk backed by provider. */ -void -gvinum_grow(int argc, char **argv) +static void +gvinum_grow(int argc, char * const *argv) { struct gctl_req *req; char *drive, *sdname; @@ -1259,6 +1269,7 @@ gvinum_grow(int argc, char **argv) const char *errstr; int drives, volumes, plexes, subdisks, flags; + flags = 0; drives = volumes = plexes = subdisks = 0; if (argc < 3) { warnx("usage:\tgrow plex drive\n"); @@ -1326,9 +1337,10 @@ gvinum_grow(int argc, char **argv) gctl_free(req); } -void -parseline(int argc, char **argv) +static void +parseline(int argc, char * const *argv) { + if (argc <= 0) return; @@ -1369,7 +1381,7 @@ parseline(int argc, char **argv) else if (!strcmp(argv[0], "rename")) gvinum_rename(argc, argv); else if (!strcmp(argv[0], "resetconfig")) - gvinum_resetconfig(); + gvinum_resetconfig(argc, argv); else if (!strcmp(argv[0], "rm")) gvinum_rm(argc, argv); else if (!strcmp(argv[0], "saveconfig")) @@ -1388,8 +1400,6 @@ parseline(int argc, char **argv) gvinum_parityop(argc, argv, 1); else printf("unknown command '%s'\n", argv[0]); - - return; } /* @@ -1397,8 +1407,8 @@ parseline(int argc, char **argv) * gvinum_create when called without an argument, in order to give the user * something to edit. */ -void -printconfig(FILE *of, char *comment) +static void +printconfig(FILE *of, const char *comment) { struct gctl_req *req; struct utsname uname_s; diff --git a/sbin/gvinum/gvinum.h b/sbin/gvinum/gvinum.h index d1b45a07749b0..8b72eea7834f9 100644 --- a/sbin/gvinum/gvinum.h +++ b/sbin/gvinum/gvinum.h @@ -36,4 +36,5 @@ /* $FreeBSD$ */ -#define GVINUMMOD "geom_vinum" +#define GVINUMMOD "g_vinum" +#define GVINUMKLD "geom_vinum" diff --git a/sbin/hastctl/Makefile b/sbin/hastctl/Makefile index 02531e6f5e8f0..89b972e567051 100644 --- a/sbin/hastctl/Makefile +++ b/sbin/hastctl/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../hastd diff --git a/sbin/hastd/Makefile b/sbin/hastd/Makefile index 7ff6ee830a065..306c83ac9e509 100644 --- a/sbin/hastd/Makefile +++ b/sbin/hastd/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= hastd SRCS= activemap.c diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile index 44c231942b64e..aae67249c2bf8 100644 --- a/sbin/ifconfig/Makefile +++ b/sbin/ifconfig/Makefile @@ -1,7 +1,7 @@ # From: @(#)Makefile 8.1 (Berkeley) 6/5/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ifconfig @@ -63,8 +63,4 @@ MAN= ifconfig.8 CFLAGS+= -Wall -Wmissing-prototypes -Wcast-qual -Wwrite-strings -Wnested-externs WARNS?= 2 -.if ${MK_TESTS} != "no" -SUBDIR+= tests -.endif - .include <bsd.prog.mk> diff --git a/sbin/ifconfig/tests/Makefile b/sbin/ifconfig/tests/Makefile deleted file mode 100644 index 9b7aa07e17901..0000000000000 --- a/sbin/ifconfig/tests/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# $FreeBSD$ - -.include <bsd.own.mk> - -TESTSDIR= ${TESTSBASE}/sbin/ifconfig - -ATF_TESTS_SH= fibs_test - -.include <bsd.test.mk> diff --git a/sbin/ifconfig/tests/fibs_test.sh b/sbin/ifconfig/tests/fibs_test.sh deleted file mode 100755 index 2a254580eb2b9..0000000000000 --- a/sbin/ifconfig/tests/fibs_test.sh +++ /dev/null @@ -1,126 +0,0 @@ -# -# Copyright (c) 2014 Spectra Logic Corporation -# 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. -# 2. Redistributions in binary form must reproduce at minimum a disclaimer -# substantially similar to the "NO WARRANTY" disclaimer below -# ("Disclaimer") and any redistribution must be conditioned upon -# including a substantially similar Disclaimer requirement for further -# binary redistribution. -# -# NO WARRANTY -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. -# -# Authors: Alan Somers (Spectra Logic Corporation) -# -# $FreeBSD$ - - -# Regression test for bin/187551 -atf_test_case process_fib cleanup -process_fib_head() -{ - atf_set "descr" "ifconfig will set its process fib whenever configuring an interface with nondefault fib" - atf_set "require.user" "root" - atf_set "require.config" "fibs" -} -process_fib_body() -{ - atf_expect_fail "bin/187551 ifconfig should change its process fib when configuring an interface with nondefault fib" - # Configure the TAP interface to use an RFC5737 nonrouteable address - # and a non-default fib - ADDR="192.0.2.2" - SUBNET="192.0.2.0" - MASK="24" - - # Check system configuration - if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then - atf_skip "This test requires net.add_addr_allfibs=0" - fi - get_fibs 1 - - # Configure a TAP interface - get_tap - ktrace ifconfig $TAP ${ADDR}/${MASK} fib $FIB0 - if kdump -s | egrep -q 'CALL[[:space:]]+setfib'; then - atf_pass - else - atf_fail "ifconfig never called setfib(2)" - fi -} - -process_fib_cleanup() -{ - cleanup_tap -} - -atf_init_test_cases() -{ - atf_add_test_case process_fib -} - - -# parameter numfibs The number of fibs to lookup -get_fibs() -{ - NUMFIBS=$1 - net_fibs=`sysctl -n net.fibs` - i=0 - while [ $i -lt "$NUMFIBS" ]; do - fib=`atf_config_get "fibs" | \ - awk -v i=$(( i + 1 )) '{print $i}'` - echo "fib is ${fib}" - eval FIB${i}=${fib} - if [ "$fib" -ge "$net_fibs" ]; then - atf_skip "The ${i}th configured fib is ${fib}, which is not less than net.fibs, which is ${net_fibs}" - fi - i=$(( $i + 1 )) - done -} - - - -# Creates a new tap(4) interface, registers it for cleanup, and returns the -# name via the environment variable TAP -get_tap() -{ - local TAPN=0 - while ! ifconfig tap${TAPN} create > /dev/null 2>&1; do - if [ "$TAPN" -ge 8 ]; then - atf_skip "Could not create a tap(4) interface" - else - TAPN=$(($TAPN + 1)) - fi - done - local TAPD=tap${TAPN} - # Record the TAP device so we can clean it up later - echo ${TAPD} >> "tap_devices_to_cleanup" - TAP=${TAPD} -} - - - - -cleanup_tap() -{ - for TAPD in `cat "tap_devices_to_cleanup"`; do - ifconfig ${TAPD} destroy - done -} - diff --git a/sbin/ipfw/Makefile b/sbin/ipfw/Makefile index 6aea26b7a3d49..de27e3ebdedc6 100644 --- a/sbin/ipfw/Makefile +++ b/sbin/ipfw/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ipfw SRCS= ipfw2.c dummynet.c ipv6.c main.c nat.c diff --git a/sbin/mdconfig/Makefile b/sbin/mdconfig/Makefile index 4b9b9405474da..69a688cdc3892 100644 --- a/sbin/mdconfig/Makefile +++ b/sbin/mdconfig/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= mdconfig MAN= mdconfig.8 diff --git a/sbin/newfs_msdos/newfs_msdos.c b/sbin/newfs_msdos/newfs_msdos.c index 1f5b4385f9bc3..4bfb219e35fce 100644 --- a/sbin/newfs_msdos/newfs_msdos.c +++ b/sbin/newfs_msdos/newfs_msdos.c @@ -51,50 +51,50 @@ static const char rcsid[] = #include <time.h> #include <unistd.h> -#define MAXU16 0xffff /* maximum unsigned 16-bit quantity */ -#define BPN 4 /* bits per nibble */ -#define NPB 2 /* nibbles per byte */ +#define MAXU16 0xffff /* maximum unsigned 16-bit quantity */ +#define BPN 4 /* bits per nibble */ +#define NPB 2 /* nibbles per byte */ -#define DOSMAGIC 0xaa55 /* DOS magic number */ -#define MINBPS 512 /* minimum bytes per sector */ -#define MAXSPC 128 /* maximum sectors per cluster */ -#define MAXNFT 16 /* maximum number of FATs */ -#define DEFBLK 4096 /* default block size */ -#define DEFBLK16 2048 /* default block size FAT16 */ -#define DEFRDE 512 /* default root directory entries */ -#define RESFTE 2 /* reserved FAT entries */ -#define MINCLS12 1U /* minimum FAT12 clusters */ -#define MINCLS16 0xff5U /* minimum FAT16 clusters */ -#define MINCLS32 0xfff5U /* minimum FAT32 clusters */ -#define MAXCLS12 0xff4U /* maximum FAT12 clusters */ -#define MAXCLS16 0xfff4U /* maximum FAT16 clusters */ -#define MAXCLS32 0xffffff4U /* maximum FAT32 clusters */ +#define DOSMAGIC 0xaa55 /* DOS magic number */ +#define MINBPS 512 /* minimum bytes per sector */ +#define MAXSPC 128 /* maximum sectors per cluster */ +#define MAXNFT 16 /* maximum number of FATs */ +#define DEFBLK 4096 /* default block size */ +#define DEFBLK16 2048 /* default block size FAT16 */ +#define DEFRDE 512 /* default root directory entries */ +#define RESFTE 2 /* reserved FAT entries */ +#define MINCLS12 1U /* minimum FAT12 clusters */ +#define MINCLS16 0xff5U /* minimum FAT16 clusters */ +#define MINCLS32 0xfff5U /* minimum FAT32 clusters */ +#define MAXCLS12 0xff4U /* maximum FAT12 clusters */ +#define MAXCLS16 0xfff4U /* maximum FAT16 clusters */ +#define MAXCLS32 0xffffff4U /* maximum FAT32 clusters */ -#define mincls(fat) ((fat) == 12 ? MINCLS12 : \ +#define mincls(fat) ((fat) == 12 ? MINCLS12 : \ (fat) == 16 ? MINCLS16 : \ MINCLS32) -#define maxcls(fat) ((fat) == 12 ? MAXCLS12 : \ +#define maxcls(fat) ((fat) == 12 ? MAXCLS12 : \ (fat) == 16 ? MAXCLS16 : \ MAXCLS32) -#define mk1(p, x) \ +#define mk1(p, x) \ (p) = (u_int8_t)(x) -#define mk2(p, x) \ +#define mk2(p, x) \ (p)[0] = (u_int8_t)(x), \ (p)[1] = (u_int8_t)((x) >> 010) -#define mk4(p, x) \ +#define mk4(p, x) \ (p)[0] = (u_int8_t)(x), \ (p)[1] = (u_int8_t)((x) >> 010), \ (p)[2] = (u_int8_t)((x) >> 020), \ (p)[3] = (u_int8_t)((x) >> 030) -#define argto1(arg, lo, msg) argtou(arg, lo, 0xff, msg) -#define argto2(arg, lo, msg) argtou(arg, lo, 0xffff, msg) -#define argto4(arg, lo, msg) argtou(arg, lo, 0xffffffff, msg) -#define argtox(arg, lo, msg) argtou(arg, lo, UINT_MAX, msg) +#define argto1(arg, lo, msg) argtou(arg, lo, 0xff, msg) +#define argto2(arg, lo, msg) argtou(arg, lo, 0xffff, msg) +#define argto4(arg, lo, msg) argtou(arg, lo, 0xffffffff, msg) +#define argtox(arg, lo, msg) argtou(arg, lo, UINT_MAX, msg) struct bs { u_int8_t bsJump[3]; /* bootstrap entry point */ @@ -131,7 +131,7 @@ struct bsx { u_int8_t exReserved1; /* reserved */ u_int8_t exBootSignature; /* extended boot signature */ u_int8_t exVolumeID[4]; /* volume ID number */ - u_int8_t exVolumeLabel[11]; /* volume label */ + u_int8_t exVolumeLabel[11]; /* volume label */ u_int8_t exFileSysType[8]; /* file system type */ } __packed; @@ -164,7 +164,7 @@ struct bpb { u_int bpbBackup; /* backup boot sector */ }; -#define BPBGAP 0, 0, 0, 0, 0, 0 +#define BPBGAP 0, 0, 0, 0, 0, 0 static struct { const char *name; @@ -174,10 +174,10 @@ static struct { {"180", {512, 1, 1, 2, 64, 360, 0xfc, 2, 9, 1, BPBGAP}}, {"320", {512, 2, 1, 2, 112, 640, 0xff, 1, 8, 2, BPBGAP}}, {"360", {512, 2, 1, 2, 112, 720, 0xfd, 2, 9, 2, BPBGAP}}, - {"640", {512, 2, 1, 2, 112, 1280, 0xfb, 2, 8, 2, BPBGAP}}, + {"640", {512, 2, 1, 2, 112, 1280, 0xfb, 2, 8, 2, BPBGAP}}, {"720", {512, 2, 1, 2, 112, 1440, 0xf9, 3, 9, 2, BPBGAP}}, {"1200", {512, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2, BPBGAP}}, - {"1232", {1024,1, 1, 2, 192, 1232, 0xfe, 2, 8, 2, BPBGAP}}, + {"1232", {1024,1, 1, 2, 192, 1232, 0xfe, 2, 8, 2, BPBGAP}}, {"1440", {512, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2, BPBGAP}}, {"2880", {512, 2, 1, 2, 240, 5760, 0xf0, 9, 36, 2, BPBGAP}} }; @@ -1029,7 +1029,7 @@ usage(void) fprintf(stderr, "usage: newfs_msdos [ -options ] special [disktype]\n" "where the options are:\n" - "\t-@ create file system at specified offset\n" + "\t-@ create file system at specified offset\n" "\t-B get bootstrap from file\n" "\t-C create image file with specified size\n" "\t-F FAT type (12, 16, or 32)\n" diff --git a/sbin/pfctl/Makefile b/sbin/pfctl/Makefile index 5b3735c6e771f..937f403569dd7 100644 --- a/sbin/pfctl/Makefile +++ b/sbin/pfctl/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> # pf_ruleset.c is shared between kernel and pfctl .PATH: ${.CURDIR}/../../sys/netpfil/pf diff --git a/sbin/ping/Makefile b/sbin/ping/Makefile index c3dda698b5196..a05efe371c570 100644 --- a/sbin/ping/Makefile +++ b/sbin/ping/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/5/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ping MAN= ping.8 diff --git a/sbin/route/Makefile b/sbin/route/Makefile index 569d21af07a0a..25134e473b662 100644 --- a/sbin/route/Makefile +++ b/sbin/route/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/5/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= route MAN= route.8 diff --git a/sbin/route/route.c b/sbin/route/route.c index 794f1430397b5..9b3bb9533f618 100644 --- a/sbin/route/route.c +++ b/sbin/route/route.c @@ -1727,8 +1727,6 @@ print_getmsg(struct rt_msghdr *rtm, int msglen, int fib) (sp[RTAX_IFP]->sa_family != AF_LINK || ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_nlen == 0)) sp[RTAX_IFP] = NULL; - if (sp[RTAX_DST] && sp[RTAX_NETMASK]) - sp[RTAX_NETMASK]->sa_family = sp[RTAX_DST]->sa_family; /* XXX */ if (sp[RTAX_DST]) (void)printf("destination: %s\n", routename(sp[RTAX_DST])); if (sp[RTAX_NETMASK]) diff --git a/sbin/setkey/Makefile b/sbin/setkey/Makefile index e2c93ccf489b1..bd04f07c1eb42 100644 --- a/sbin/setkey/Makefile +++ b/sbin/setkey/Makefile @@ -27,7 +27,7 @@ # # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= setkey MAN= setkey.8 diff --git a/secure/Makefile b/secure/Makefile index 4a111a25c5489..4e2cc4f72523a 100644 --- a/secure/Makefile +++ b/secure/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= lib libexec ${_tests} usr.bin usr.sbin diff --git a/secure/Makefile.inc b/secure/Makefile.inc index eb7c66ef14923..ca4cb857f2f72 100644 --- a/secure/Makefile.inc +++ b/secure/Makefile.inc @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .if exists(${.CURDIR}/../../lib/libcrypt/obj) CRYPTOBJDIR= ${.CURDIR}/../../lib/libcrypt/obj diff --git a/secure/lib/Makefile b/secure/lib/Makefile index 118204f67f8a5..4ca851766e623 100644 --- a/secure/lib/Makefile +++ b/secure/lib/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= .if ${MK_OPENSSL} != "no" diff --git a/secure/lib/libssh/Makefile b/secure/lib/libssh/Makefile index f4bfd06ea7fed..b63d6b9c6692b 100644 --- a/secure/lib/libssh/Makefile +++ b/secure/lib/libssh/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIB= ssh PRIVATELIB= true diff --git a/secure/libexec/Makefile b/secure/libexec/Makefile index 9edc8e66c1971..07aa3dd4bdc43 100644 --- a/secure/libexec/Makefile +++ b/secure/libexec/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= .if ${MK_OPENSSH} != "no" diff --git a/secure/libexec/sftp-server/Makefile b/secure/libexec/sftp-server/Makefile index ef56013ff3bce..eb788f6d0637d 100644 --- a/secure/libexec/sftp-server/Makefile +++ b/secure/libexec/sftp-server/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= sftp-server SRCS= sftp-server.c sftp-common.c sftp-server-main.c diff --git a/secure/libexec/ssh-keysign/Makefile b/secure/libexec/ssh-keysign/Makefile index 7deda1976ba3a..668ad9e1b4f88 100644 --- a/secure/libexec/ssh-keysign/Makefile +++ b/secure/libexec/ssh-keysign/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ssh-keysign SRCS= ssh-keysign.c roaming_dummy.c readconf.c diff --git a/secure/libexec/ssh-pkcs11-helper/Makefile b/secure/libexec/ssh-pkcs11-helper/Makefile index 4682929e2d931..f3cf9029f4cc1 100644 --- a/secure/libexec/ssh-pkcs11-helper/Makefile +++ b/secure/libexec/ssh-pkcs11-helper/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ssh-pkcs11-helper SRCS= ssh-pkcs11.c ssh-pkcs11-helper.c diff --git a/secure/usr.bin/Makefile b/secure/usr.bin/Makefile index e819ba74686ca..e14ebe3000e90 100644 --- a/secure/usr.bin/Makefile +++ b/secure/usr.bin/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= .if ${MK_OPENSSL} != "no" diff --git a/secure/usr.bin/scp/Makefile b/secure/usr.bin/scp/Makefile index c33470ca9ef3d..d58d855d80297 100644 --- a/secure/usr.bin/scp/Makefile +++ b/secure/usr.bin/scp/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= scp SRCS= scp.c diff --git a/secure/usr.bin/sftp/Makefile b/secure/usr.bin/sftp/Makefile index 924e1a702163f..15dcaa52061d9 100644 --- a/secure/usr.bin/sftp/Makefile +++ b/secure/usr.bin/sftp/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= sftp SRCS= sftp.c sftp-client.c sftp-common.c sftp-glob.c progressmeter.c diff --git a/secure/usr.bin/ssh-add/Makefile b/secure/usr.bin/ssh-add/Makefile index 316a6071280bb..97191ba51fbfb 100644 --- a/secure/usr.bin/ssh-add/Makefile +++ b/secure/usr.bin/ssh-add/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ssh-add SRCS+= ssh-add.c diff --git a/secure/usr.bin/ssh-agent/Makefile b/secure/usr.bin/ssh-agent/Makefile index 353abaced4105..b5db53236c8b3 100644 --- a/secure/usr.bin/ssh-agent/Makefile +++ b/secure/usr.bin/ssh-agent/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ssh-agent SRCS= ssh-agent.c diff --git a/secure/usr.bin/ssh-keygen/Makefile b/secure/usr.bin/ssh-keygen/Makefile index 75934d9bff91c..45e4d1691f982 100644 --- a/secure/usr.bin/ssh-keygen/Makefile +++ b/secure/usr.bin/ssh-keygen/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ssh-keygen SRCS= ssh-keygen.c diff --git a/secure/usr.bin/ssh-keyscan/Makefile b/secure/usr.bin/ssh-keyscan/Makefile index 7dcb4d10826e7..298f52a53c079 100644 --- a/secure/usr.bin/ssh-keyscan/Makefile +++ b/secure/usr.bin/ssh-keyscan/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ssh-keyscan SRCS= ssh-keyscan.c roaming_dummy.c diff --git a/secure/usr.bin/ssh/Makefile b/secure/usr.bin/ssh/Makefile index 4a46429701956..89f9927c0aaac 100644 --- a/secure/usr.bin/ssh/Makefile +++ b/secure/usr.bin/ssh/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ssh CFLAGS+=-I${SSHDIR} -include ssh_namespace.h diff --git a/secure/usr.sbin/Makefile b/secure/usr.sbin/Makefile index 33d945c0c683a..e42f456b12d06 100644 --- a/secure/usr.sbin/Makefile +++ b/secure/usr.sbin/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= .if ${MK_OPENSSH} != "no" diff --git a/secure/usr.sbin/sshd/Makefile b/secure/usr.sbin/sshd/Makefile index e1c71a3eab94b..d487fe3dd7cc5 100644 --- a/secure/usr.sbin/sshd/Makefile +++ b/secure/usr.sbin/sshd/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= sshd SRCS= sshd.c auth-rhosts.c auth-passwd.c auth-rsa.c auth-rh-rsa.c \ diff --git a/share/Makefile b/share/Makefile index 8ac475044833c..604e4169313ac 100644 --- a/share/Makefile +++ b/share/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/5/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> # Do not include `info' in the SUBDIR list, it is handled separately. diff --git a/share/doc/Makefile b/share/doc/Makefile index a4fe61d6c4799..fda977f118e08 100644 --- a/share/doc/Makefile +++ b/share/doc/Makefile @@ -1,7 +1,7 @@ # From: @(#)Makefile 8.1 (Berkeley) 6/5/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= ${_IPv6} \ ${_atf} \ diff --git a/share/doc/smm/Makefile b/share/doc/smm/Makefile index fd42bd4d53a6d..1d99b052a351c 100644 --- a/share/doc/smm/Makefile +++ b/share/doc/smm/Makefile @@ -1,7 +1,7 @@ # From: @(#)Makefile 8.1 (Berkeley) 6/10/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> # The following modules do not describe FreeBSD: # 14.uucpimpl, 15.uucpnet diff --git a/share/dtrace/Makefile b/share/dtrace/Makefile index adbdc84971c41..ba52997a59ba5 100644 --- a/share/dtrace/Makefile +++ b/share/dtrace/Makefile @@ -4,7 +4,7 @@ # the DTraceToolkit. # -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= ${_toolkit} diff --git a/share/examples/Makefile b/share/examples/Makefile index a4270bf38ae8e..dcc3256d2d298 100644 --- a/share/examples/Makefile +++ b/share/examples/Makefile @@ -2,7 +2,7 @@ # # Doing a make install builds /usr/share/examples -.include <bsd.own.mk> +.include <src.opts.mk> LDIRS= BSD_daemon \ FreeBSD_version \ diff --git a/share/man/Makefile b/share/man/Makefile index 524235c2e9f02..c3bd5f22aca42 100644 --- a/share/man/Makefile +++ b/share/man/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.2 (Berkeley) 4/16/94 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> # XXX MISSING: man3f SUBDIR= man1 man3 man4 man5 man6 man7 man8 man9 diff --git a/share/man/man1/Makefile b/share/man/man1/Makefile index 97885a6a8b836..1b37c4b34e339 100644 --- a/share/man/man1/Makefile +++ b/share/man/man1/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/5/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> MAN= builtin.1 intro.1 diff --git a/share/man/man3/Makefile b/share/man/man3/Makefile index ccdc549850268..f0cbf0ecd9f31 100644 --- a/share/man/man3/Makefile +++ b/share/man/man3/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.2 (Berkeley) 12/13/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> MAN= assert.3 \ ATOMIC_VAR_INIT.3 \ diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 59fd3e9bc3b76..b0f8e572ca268 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/18/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> MAN= aac.4 \ aacraid.4 \ @@ -142,6 +142,7 @@ MAN= aac.4 \ filemon.4 \ firewire.4 \ fpa.4 \ + full.4 \ fwe.4 \ fwip.4 \ fwohci.4 \ @@ -226,7 +227,6 @@ MAN= aac.4 \ le.4 \ led.4 \ lge.4 \ - ${_lindev.4} \ ${_linux.4} \ lmc.4 \ lo.4 \ @@ -262,8 +262,10 @@ MAN= aac.4 \ mod_cc.4 \ mos.4 \ mouse.4 \ + mpr.4 \ mps.4 \ mpt.4 \ + mrsas.4 \ msk.4 \ mtio.4 \ multicast.4 \ @@ -378,6 +380,7 @@ MAN= aac.4 \ ppc.4 \ ppi.4 \ procdesc.4 \ + proto.4 \ psm.4 \ pst.4 \ pt.4 \ @@ -789,7 +792,6 @@ _if_vxge.4= if_vxge.4 _if_wpi.4= if_wpi.4 _ipmi.4= ipmi.4 _io.4= io.4 -_lindev.4= lindev.4 _linux.4= linux.4 _ndis.4= ndis.4 _nfe.4= nfe.4 @@ -818,7 +820,6 @@ _wpi.4= wpi.4 _xen.4= xen.4 _xnb.4= xnb.4 -MLINKS+=lindev.4 full.4 .endif .if ${MACHINE_CPUARCH} == "amd64" diff --git a/share/man/man4/bce.4 b/share/man/man4/bce.4 index 00df65931eea2..004ffa30f2aa3 100644 --- a/share/man/man4/bce.4 +++ b/share/man/man4/bce.4 @@ -1,5 +1,4 @@ -.\" Copyright (c) 2006 Broadcom Corporation -.\" David Christensen <davidch@broadcom.com>. All rights reserved. +.\" Copyright (c) 2006-2014 QLogic Corporation .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -10,9 +9,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. Neither the name of Broadcom Corporation nor the name of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written consent. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' .\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -33,7 +29,7 @@ .Os .Sh NAME .Nm bce -.Nd "Broadcom NetXtreme II (BCM5706/5708/5709/5716) PCI/PCIe Gigabit Ethernet adapter driver" +.Nd "QLogic NetXtreme II (BCM5706/5708/5709/5716) PCI/PCIe Gigabit Ethernet adapter driver" .Sh SYNOPSIS To compile this driver into the kernel, place the following lines in your @@ -52,7 +48,7 @@ if_bce_load="YES" .Sh DESCRIPTION The .Nm -driver supports Broadcom's NetXtreme II product family, including the +driver supports QLogic's NetXtreme II product family, including the BCM5706, BCM5708, BCM5709 and BCM5716 Ethernet controllers. .Pp The NetXtreme II product family is composed of various Converged NIC (or CNIC) @@ -141,25 +137,25 @@ For more information on configuring this device, see .Sh HARDWARE The .Nm -driver provides support for various NICs based on the Broadcom NetXtreme II +driver provides support for various NICs based on the QLogic NetXtreme II family of Gigabit Ethernet controllers, including the following: .Pp .Bl -bullet -compact .It -Broadcom NetXtreme II BCM5706 1000Base-SX +QLogic NetXtreme II BCM5706 1000Base-SX .It -Broadcom NetXtreme II BCM5706 1000Base-T +QLogic NetXtreme II BCM5706 1000Base-T .It -Broadcom NetXtreme II BCM5708 1000Base-SX +QLogic NetXtreme II BCM5708 1000Base-SX .It -Broadcom NetXtreme II BCM5708 1000Base-T +QLogic NetXtreme II BCM5708 1000Base-T .It -Broadcom NetXtreme II BCM5709 1000Base-SX +QLogic NetXtreme II BCM5709 1000Base-SX .It -Broadcom NetXtreme II BCM5709 1000Base-T +QLogic NetXtreme II BCM5709 1000Base-T .It -Broadcom NetXtreme II BCM5716 1000Base-T +QLogic NetXtreme II BCM5716 1000Base-T .It Dell PowerEdge 1950 integrated BCM5708 NIC .It @@ -411,9 +407,11 @@ A controller hardware failure has occurred. If the problem continues replace the controller. .El .Sh SUPPORT -For general information and support, -go to the Broadcom NIC Open Source Developer Resource Site: -.Pa http://www.broadcom.com/support/ethernet_nic/open_source.php . +For support questions please contact your QLogic approved reseller or +QLogic Technical Support at +.Pa http://support.qlogic.com , +or by E-mail at +.Aq support@qlogic.com . .Sh SEE ALSO .Xr altq 4 , .Xr arp 4 , diff --git a/share/man/man4/bxe.4 b/share/man/man4/bxe.4 index be9ba2551f967..0067385b7cb4a 100644 --- a/share/man/man4/bxe.4 +++ b/share/man/man4/bxe.4 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2013 Broadcom Corporation. All rights reserved. +.\" Copyright (c) 2014 Qlogic Corporation. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -9,9 +9,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. Neither the name of Broadcom Corporation nor the name of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written consent. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' .\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -32,7 +29,7 @@ .Os .Sh NAME .Nm bxe -.Nd Broadcom NetXtreme II Ethernet 10Gb PCIe adapter driver +.Nd QLogic NetXtreme II Ethernet 10Gb PCIe adapter driver .Sh SYNOPSIS To compile this driver into the kernel, place the following lines in your @@ -50,7 +47,7 @@ if_bxe_load="YES" .Sh DESCRIPTION The .Nm -driver provides support for PCIe 10Gb Ethernet adapters based on the Broadcom +driver provides support for PCIe 10Gb Ethernet adapters based on the QLogic NetXtreme II family of 10Gb chips. The driver supports Jumbo Frames, VLAN tagging, checksum offload (IPv4, TCP, UDP, IPv6-TCP, IPv6-UDP), MSI-X @@ -59,32 +56,32 @@ Receive Side Scaling (RSS). .Sh HARDWARE The .Nm -driver provides support for various NICs based on the Broadcom NetXtreme II +driver provides support for various NICs based on the QLogic NetXtreme II family of 10Gb Ethernet controller chips, including the following: .Pp .Bl -bullet -compact .It -Broadcom NetXtreme II BCM57710 10Gb +QLogic NetXtreme II BCM57710 10Gb .It -Broadcom NetXtreme II BCM57711 10Gb +QLogic NetXtreme II BCM57711 10Gb .It -Broadcom NetXtreme II BCM57711E 10Gb +QLogic NetXtreme II BCM57711E 10Gb .It -Broadcom NetXtreme II BCM57712 10Gb +QLogic NetXtreme II BCM57712 10Gb .It -Broadcom NetXtreme II BCM57712-MF 10Gb +QLogic NetXtreme II BCM57712-MF 10Gb .It -Broadcom NetXtreme II BCM57800 10Gb +QLogic NetXtreme II BCM57800 10Gb .It -Broadcom NetXtreme II BCM57800-MF 10Gb +QLogic NetXtreme II BCM57800-MF 10Gb .It -Broadcom NetXtreme II BCM57810 10Gb +QLogic NetXtreme II BCM57810 10Gb .It -Broadcom NetXtreme II BCM57810-MF 10Gb +QLogic NetXtreme II BCM57810-MF 10Gb .It -Broadcom NetXtreme II BCM57840 10Gb / 20Gb +QLogic NetXtreme II BCM57840 10Gb / 20Gb .It -Broadcom NetXtreme II BCM57840-MF 10Gb +QLogic NetXtreme II BCM57840-MF 10Gb .El .Sh CONFIGURATION There a number of configuration parameters that can be set to tweak the @@ -318,6 +315,12 @@ When finished turn the logging back off: .Bd -literal -offset indent # sysctl dev.bxe.0.debug=0 .Ed +.Sh SUPPORT +For support questions please contact your QLogic approved reseller or +QLogic Technical Support at +.Pa http://support.qlogic.com , +or by E-mail at +.Aq support@qlogic.com . .Sh SEE ALSO .Xr netstat 1 , .Xr altq 4 , diff --git a/share/man/man4/lindev.4 b/share/man/man4/full.4 index ffc5e8310f976..a71eb926361dc 100644 --- a/share/man/man4/lindev.4 +++ b/share/man/man4/full.4 @@ -1,20 +1,19 @@ -.\"- -.\" Copyright (c) 2009 "Bjoern A. Zeeb" <bz@FreeBSD.org> -.\" All rights reserved. +.\" Copyright (c) 2014 +.\" Eitan Adler <eadler@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. +.\" 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. +.\" 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 +.\" 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) @@ -25,40 +24,17 @@ .\" .\" $FreeBSD$ .\" -.Dd September 26, 2009 -.Dt LINDEV 4 +.Dd March 29, 2014 +.Dt FULL 4 .Os .Sh NAME -.Nm lindev -.Nd Linux-specific pseudo devices support -.Sh SYNOPSIS -To compile this collection of linux-specific pseudo devices into the kernel, -place the following line in your kernel configuration file: -.Bd -ragged -offset indent -.Cd "device lindev" -.Ed -.Pp -Alternatively, to load the driver as a module at boot time, -place the following line in -.Xr loader.conf 5 : -.Bd -literal -offset indent -lindev_load="YES" -.Ed +.Nm full +.Nd the full device .Sh DESCRIPTION The .Nm -module provides a collection of linux-specific pseudo devices. -.Sh DEVICES -.Bl -tag -width /dev/full -.It Pa /dev/full -The -.Xr full -device always returns -.Er ENOSPC -on write attempts. -For reads it emulates -.Xr zero 4 . -.El +device supplies an endless stream of zeros when read. +However, it will always be full when writing to it. .Sh FILES .Bl -tag -width /dev/full .It Pa /dev/full @@ -66,8 +42,6 @@ For reads it emulates .Sh SEE ALSO .Xr null 4 , .Xr zero 4 -.Sh HISTORY -The -.Nm -module first appeared in -.Fx 8.1 . +.Sh Author +This device and man page was written by +.An Eitan Adler Aq eadler@FreeBSD.org . diff --git a/share/man/man4/mpr.4 b/share/man/man4/mpr.4 new file mode 100644 index 0000000000000..4a42fa136d17e --- /dev/null +++ b/share/man/man4/mpr.4 @@ -0,0 +1,229 @@ +.\" +.\" Copyright (c) 2010 Spectra Logic Corporation +.\" Copyright (c) 2014 LSI Corp +.\" 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. +.\" 2. Redistributions in binary form must reproduce at minimum a disclaimer +.\" substantially similar to the "NO WARRANTY" disclaimer below +.\" ("Disclaimer") and any redistribution must be conditioned upon +.\" including a substantially similar Disclaimer requirement for further +.\" binary redistribution. +.\" +.\" NO WARRANTY +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. +.\" +.\" mpr driver man page. +.\" +.\" Author: Ken Merry <ken@FreeBSD.org> +.\" Author: Stephen McConnell <stephen.mcconnell@lsi.com> +.\" +.\" $Id$ +.\" $FreeBSD$ +.\" +.Dd May 2, 2014 +.Dt MPR 4 +.Os +.Sh NAME +.Nm mpr +.Nd "LSI Fusion-MPT 3 IT/IR 12Gb/s Serial Attached SCSI/SATA driver" +.Sh SYNOPSIS +To compile this driver into the kernel, place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device pci" +.Cd "device scbus" +.Cd "device mpr" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +mpr_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for LSI Fusion-MPT 3 IT/IR +.Tn SAS +controllers. +.Sh HARDWARE +The following controllers are supported by the +.Nm +driver: +.Pp +.Bl -bullet -compact +.It +LSI SAS 3004 (4 Port SAS) +.It +LSI SAS 3008 (8 Port SAS) +.It +LSI SAS 3108 (8 Port SAS) +.El +.Sh CONFIGURATION +To disable MSI interrupts for all +.Nm +driver instances, set the following tunable value in +.Xr loader.conf 5 : +.Bd -literal -offset indent +hw.mpr.disable_msi=1 +.Ed +.Pp +To disable MSI interrupts for a specific +.Nm +driver instance, set the following tunable value in +.Xr loader.conf 5 : +.Bd -literal -offset indent +dev.mpr.X.disable_msi=1 +.Ed +.Pp +where X is the adapter number. +.Pp +To disable MSI-X interrupts for all +.Nm +driver instances, set the following tunable value in +.Xr loader.conf 5 : +.Bd -literal -offset indent +hw.mpr.disable_msix=1 +.Ed +.Pp +To disable MSI-X interrupts for a specific +.Nm +driver instance, set the following tunable value in +.Xr loader.conf 5 : +.Bd -literal -offset indent +dev.mpr.X.disable_msix=1 +.Ed +.Pp +To set the maximum number of DMA chains allocated for all adapters, set +the following variable in +.Xr loader.conf 5 : +.Bd -literal -offset indent +hw.mpr.max_chains=NNNN +.Ed +.Pp +To set the maximum number of DMA chains allocated for a specific adapter, +set the following variable in +.Xr loader.conf 5 : +.Bd -literal -offset indent +dev.mpr.X.max_chains=NNNN +.Ed +.Pp +This variable may also be viewed via +.Xr sysctl 8 +to see the maximum set for a given adapter. +.Pp +The current number of free chain frames may be seen via the +dev.mpr.X.chain_free +.Xr sysctl 8 +variable. +.Pp +The lowest number of free chain frames may be seen via the +dev.mpr.X.chain_free_lowwater +.Xr sysctl 8 +variable. +.Pp +The current number of active I/O commands is shown in the +dev.mpr.X.io_cmds_active +.Xr sysctl 8 +variable. +.Pp +The maximum number of active I/O commands seen since boot is shown in the +dev.mpr.X.io_cmds_highwater +.Xr sysctl 8 +variable. +.Pp +Devices can be excluded from +.Nm +control for all adapters by setting the following variable in +.Xr loader.conf 5 : +.Bd -literal -offset indent +hw.mpr.exclude_ids=Y +.Ed +.Pp +where Y is the target ID of the device. +If more than one device is to be +excluded, target ID's are separated by commas. +.Pp +Devices can be excluded from +.Nm +control for a specific adapter by setting the following variable in +.Xr loader.conf 5 : +.Bd -literal -offset indent +dev.mpr.X.exclude_ids=Y +.Ed +.Pp +where X is the adapter number and Y is the target ID of the device. +If more +than one device is to be excluded, target ID's are separated by commas. +.Sh DEBUGGING +To enable debugging prints from the +.Nm +driver, set the +.Bd -literal -offset indent +hw.mpr.X.debug_level +.Ed +.Pp +variable, where X is the adapter number, either in +.Xr loader.conf 5 +or via +.Xr sysctl 8 . +The following bits have the described effects: +.Bd -literal -offset indent +0x0001 Enable informational prints. +0x0002 Enable prints for driver faults. +0x0004 Enable prints for controller events. +0x0008 Enable prints for controller logging. +0x0010 Enable prints for tracing recovery operations. +0x0020 Enable prints for parameter errors and programming bugs. +0x0040 Enable prints for system initialization operations. +0x0080 Enable prints for more detailed information. +0x0100 Enable prints for user-generated commands. +0x0200 Enable prints for device mapping. +0x0400 Enable prints for tracing through driver functions. +.Ed +.Sh SEE ALSO +.Xr cam 4 , +.Xr cd 4 , +.Xr ch 4 , +.Xr da 4 , +.Xr mps 4 , +.Xr mpt 4 , +.Xr pci 4 , +.Xr sa 4 , +.Xr scsi 4 , +.Xr targ 4 , +.Xr loader.conf 5 , +.Xr sysctl 8 +.Sh HISTORY +The +.Nm +driver first appeared in FreeBSD 9.3. +.Sh AUTHORS +The +.Nm +driver was originally written by +.An -nosplit +.An Scott Long Aq scottl@FreeBSD.org . +It has been improved and tested by LSI Corporation. +.Pp +This man page was written by +.An Ken Merry Aq ken@FreeBSD.org +with additional input from +.An Stephen McConnell Aq stephen.mcconnell@lsi.com . diff --git a/share/man/man4/mrsas.4 b/share/man/man4/mrsas.4 new file mode 100644 index 0000000000000..60c144ecb4145 --- /dev/null +++ b/share/man/man4/mrsas.4 @@ -0,0 +1,403 @@ +.\" Copyright (c) 2014 LSI Corp +.\" All rights reserved. +.\" Author: Kashyap Desai +.\" Support: freebsdraid@lsi.com +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the <ORGANIZATION> nor the names of its +.\" contributors may be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 +.\" COPYRIGHT HOLDER 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. +.\" +.\" The views and conclusions contained in the software and documentation +.\" are those of the authors and should not be interpreted as representing +.\" official policies, either expressed or implied, of the FreeBSD Project. +.\" +.\" $FreeBSD$ +.\" +.Dd May 8, 2014 +.Dt MRSAS 4 +.Os +.Sh NAME +.Nm mrsas +.Nd "LSI MegaRAID 6Gb/s and 12Gb/s SAS+SATA RAID controller driver" +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device pci" +.Cd "device mrsas" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +mrsas_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver will detect LSI's next generation (6Gb/s and 12Gb/s) PCI Express +SAS/SATA RAID controllers. +See the +.Nm HARDWARE +section for the supported devices list. +A disk (virtual disk/physical disk) attached to the +.Nm +driver will be visible to the user through +.Xr camcontrol 8 +as +.Pa /dev/da? +device nodes. +A simple management interface is also provided on a per-controller basis via the +.Pa /dev/mrsas? +device node. +.Pp +The +.Nm +name is derived from the phrase "MegaRAID SAS HBA", which is +substantially different than the old "MegaRAID" Driver +.Xr mfi 4 +which does not connect targets +to the +.Xr cam 4 +layer and thus requires a new driver which attaches targets to the +.Xr cam 4 +layer. +Older MegaRAID controllers are supported by +.Xr mfi 4 +and will not work with +.Nm , +but both the +.Xr mfi 4 +and +.Nm +drivers can detect and manage the LSI MegaRAID SAS 2208/2308/3008/3108 series of +controllers. +.Pp +The +.Xr device.hints 5 +option is provided to tune the +.Nm +driver's behavior for LSI MegaRAID SAS 2208/2308/3008/3108 controllers. +By default, the +.Xr mfi 4 +driver will detect these controllers. +See the +.Nm PRIORITY +section to know more about driver priority for MR-Fusion devices. +.Pp +.Nm +will provide a priority of (-30) (between +.Dv BUS_PROBE_DEFAULT +and +.Dv BUS_PROBE_LOW_PRIORITY ) +at probe call for device id's 0x005B, 0x005D, and +0x005F so that +.Nm +does not take control of these devices without user intervention. +.Sh HARDWARE +The +.Nm +driver supports the following hardware: +.Pp +[ Thunderbolt 6Gb/s MR controller ] +.Bl -bullet -compact +.It +LSI MegaRAID SAS 9265 +.It +LSI MegaRAID SAS 9266 +.It +LSI MegaRAID SAS 9267 +.It +LSI MegaRAID SAS 9270 +.It +LSI MegaRAID SAS 9271 +.It +LSI MegaRAID SAS 9272 +.It +LSI MegaRAID SAS 9285 +.It +LSI MegaRAID SAS 9286 +.It +DELL PERC H810 +.It +DELL PERC H710/P +.El +.Pp +[ Invader/Fury 12Gb/s MR controller ] +.Bl -bullet -compact +.It +LSI MegaRAID SAS 9380 +.It +LSI MegaRAID SAS 9361 +.It +LSI MegaRAID SAS 9341 +.It +DELL PERC H830 +.It +DELL PERC H730/P +.It +DELL PERC H330 +.El +.Sh CONFIGURATION +To disable Online Controller Reset(OCR) for a specific +.Nm +driver instance, set the +following tunable value in +.Xr loader.conf 5 : +.Bd -literal -offset indent +dev.mrsas.X.disable_ocr=1 +.Ed +.Pp +where X is the adapter number. +.Pp +To change the I/O timeout value for a specific +.Nm +driver instance, set the following tunable value in +.Xr loader.conf 5 : +.Bd -literal -offset indent +dev.mrsas.X.mrsas_io_timeout=NNNNNN +.Ed +.Pp +where NNNNNN is the timeout value in milli-seconds. +.Pp +To change the firmware fault check timer value for a specific +.Nm +driver instance, set the following tunable value in +.Xr loader.conf 5 : +.Bd -literal -offset indent +dev.mrsas.X.mrsas_fw_fault_check_delay=NN +.Ed +.Pp +where NN is the fault check delay value in seconds. +.Pp +The current number of active I/O commands is shown in the +.Va dev.mrsas.X.fw_outstanding +.Xr sysctl 8 +variable. +.Sh DEBUGGING +To enable debugging prints from the +.Nm +driver, set the +.Va hw.mrsas.X.debug_level +variable, where X is the adapter number, either in +.Xr loader.conf 5 +or via +.Xr sysctl 8 . +The following bits have the described effects: +.Bl -tag -offset indent +.It 0x01 +Enable informational prints. +.It 0x02 +Enable tracing prints. +.It 0x04 +Enable prints for driver faults. +.It 0x08 +Enable prints for OCR and I/O timeout. +.It 0x10 +Enable prints for AEN events. +.El +.Sh PRIORITY +The +.Nm +driver will always set a default (-30) priority in the PCI subsystem for +selection of MR-Fusion cards. +(It is between +.Dv BUS_PROBE_DEFAULT +and +.Dv BUS_PROBE_LOW_PRIORITY ) . +MR-Fusion Controllers include all cards with the +Device IDs - +0x005B, +0x005D, +0x005F. +.Pp +The +.Xr mfi 4 +driver will set a priority of either +.Dv BUS_PROBE_DEFAULT +or +.Dv BUS_PROBE_LOW_PRIORITY +(depending on the device.hints setting) in the PCI +subsystem for selection of MR-Fusion cards. +With the above design in place, the +.Xr mfi 4 +driver will attach to a MR-Fusion card given that it has a higher priority than +.Nm . +.Pp +Using +.Pa /boot/device.hints +(as mentioned below), the user can provide a preference +for the +.Nm +driver to detect a MR-Fusion card instead of the +.Xr mfi 4 +driver. +.Bd -ragged -offset indent +.Cd hw.mfi.mrsas_enable="1" +.Ed +.Pp +At boot time, the +.Xr mfi 4 +driver will get priority to detect MR-Fusion controllers by default. +Before +changing this default driver selection policy, LSI advises users to understand +how the driver selection policy works. +LSI's policy is to provide priority to +the +.Xr mfi 4 +driver to detect MR-Fusion cards, but allow for the ability to choose the +.Nm +driver to detect MR-Fusion cards. +.Pp +LSI recommends setting hw.mfi.mrsas_enable="0" for customers who are using the +older +.Xr mfi 4 +driver and do not want to switch to +.Nm . +For those customers who are using a MR-Fusion controller for the first time, LSI +recommends using the +.Nm +driver and setting hw.mfi.mrsas_enable="1". +.Pp +Changing the default behavior is well tested under most conditions, but +unexpected behavior may pop up if more complex and unrealistic operations are +executed by switching between the +.Xr mfi 4 +and +.Nm +drivers for MR-Fusion. +Switching drivers is designed to happen only one time. +Although multiple +switching is possible, it is not recommended. +The user should decide from +.Nm Start of Day +which driver they want to use for the MR-Fusion card. +.Pp +The user may see different device names when switching from +.Xr mfi 4 +to +.Nm . +This behavior is +.Nm Functions As Designed +and the user needs to change the +.Xr fstab 5 +entry manually if they are doing any experiments with +.Xr mfi 4 +and +.Nm +interoperability. +.Sh FILES +.Bl -tag -width ".Pa /dev/mrsas?" -compact +.It Pa /dev/da? +array/logical disk interface +.It Pa /dev/mrsas? +management interface +.El +.Sh SEE ALSO +.Xr cam 4 , +.Xr mfi 4 , +.Xr pci 4 , +.Xr device.hints 5 , +.Xt camcontrol 8 +.Sh HISTORY +The +.Nm +driver first appeared in +.Fx 10.1 . +.Bd -ragged +.Cd "mfi Driver:" +.Xr mfi 4 +is the old +.Fx +driver which started with support for Gen-1 Controllers and +was extended to support up to MR-Fusion (Device ID = 0x005B, 0x005D, 0x005F). +.Ed +.Bd -ragged +.Cd "mrsas Driver:" +.Nm +is the new driver reworked by LSI which supports Thunderbolt and onward +products. +The SAS+SATA RAID controller with device id 0x005b is referred to as +the Thunderbolt controller throughout this man page. +.Ed +.Bd -ragged +.Nm cam aware HBA drivers: +.Fx +has a +.Xr cam 4 +layer which attaches storage devices and provides a common access mechanism to +storage controllers and attached devices. +The +.Nm +driver is +.Xr cam 4 +aware and devices associated with +.Nm +can be seen using +.Xr camcontrol 8 . +The +.Xr mfi 4 +driver does not understand the +.Xr cam 4 +layer and it directly associates storage disks to the block layer. +.Pp +.Nm Thunderbolt Controller: +This is the 6Gb/s MegaRAID HBA card which has device id 0x005B. +.Pp +.Nm Invader Controller: +This is 12Gb/s MegaRAID HBA card which has device id 0x005D. +.Pp +.Nm Fury Controller: +This is the 12Gb/s MegaRAID HBA card which has device id 0x005F. +.Ed +.Sh AUTHORS +The +.Nm +driver and this manual page were written by +.An Kashyap Desai Aq Kashyap.Desai@lsi.com . +.Sh TODO +The driver does not support big-endian architectures at this time. +.Pp +The driver does not support alias for device name (it is required when the user +switches between two drivers and does not want to edit +.Pa /etc/fstab +manually). +.Pp +The +.Nm +driver exposes devices as +.Pa /dev/da? , +whereas +.Xr mfi 4 +exposes devices as +.Pa /dev/mfid? . +.Pp +.Nm +does not support the Linux Emulator interface. +.Pp +.Nm +will not work with +.Xr mfiutil 8 . diff --git a/share/man/man4/null.4 b/share/man/man4/null.4 index 05ba12a70e589..067c2d8e7f39e 100644 --- a/share/man/man4/null.4 +++ b/share/man/man4/null.4 @@ -48,6 +48,7 @@ device is always zero. .It Pa /dev/null .El .Sh SEE ALSO +.Xr full 4 , .Xr zero 4 .Sh HISTORY A diff --git a/share/man/man4/proto.4 b/share/man/man4/proto.4 new file mode 100644 index 0000000000000..f0fd60a885829 --- /dev/null +++ b/share/man/man4/proto.4 @@ -0,0 +1,134 @@ +.\" +.\" Copyright (c) 2014 Marcel Moolenaar +.\" 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 ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd April 29, 2014 +.Dt PROTO 4 +.Os +.\" +.Sh NAME +.Nm proto +.Nd Driver for prototyping and H/W diagnostics +.\" +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following line in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device proto" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +proto_load="YES" +.Ed +.\" +.Sh DESCRIPTION +The +.Nm +device driver attaches to PCI devices when no other device drivers are +present and creates device special files for all resources associated +with the device. +The driver itself has no knowledge of the device it attaches to. +Programs can open these device special files and perform register-level +reads and writes. +As such, the +.Nm +device driver is nothing but a conduit or gateway between user space +programs and the hardware device. +.Pp +Examples for why this is useful include hardware diagnostics and prototyping. +In both these use cases, it is far more convenient to develop and run the +logic in user space. +Especially hardware diagnostics requires a somewhat user-friendly interface +and adequate reporting. +Neither is done easily as kernel code. +.\" +.Sh FILES +All device special files corresponding to a PCI device are located under +.Pa /dev/proto/pci<d>:<b>:<s>:<f> +with +.Pa pci<d>:<b>:<s>:<f> +representing the location of the PCI device in the PCI hierarchy. +A location includes: +.Bl -tag -width XXXXXX -compact +.It <d> +The PCI domain number +.It <b> +The PCI bus number +.It <s> +The PCI slot or device number +.It <f> +The PCI function number +.El +.Pp +Every PCI device has a device special file called +.Pa pcicfg . +This device special file gives access to the PCI configuration space. +For each valid base address register (BAR), a device special file is created +that contains the BAR offset and the resource type. +A resource type can be either +.Pa io +or +.Pa mem +representing I/O port or memory mapped I/O space (resp.) +.\" +.Sh EXAMPLES +A single function PCI device in domain 0, on bus 1, in slot 2 and having a +single memory mapped I/O region will have the following device special files: +.Bl -tag -compact +.It Pa /dev/proto/pci0:1:2:0/10.mem +.It Pa /dev/proto/pci0:1:2:0/pcicfg +.El +.\" +.Sh SECURITY CONSIDERATIONS +Because programs have direct access to the hardware, the +.Nm +driver is inherently insecure. +It is not advisable to use this driver on a production machine. +.\" +.Sh MISSING FUNCTIONALITY +The +.Nm +driver does not yet support interrupts. +Since interrupts cannot be handled by the driver itself, they must be converted +into signals and delivered to the program that has registered for interrupts. +.Pp +In order to test the transmission or reception of data, some means of doing +direct memory access (DMA) by the device must be possible. +This too must be under the control of the program. +The details of how a program can set up and +initiate DMA still need to be fleshed out. +.Pp +Support for non-PCI devices has not been implemented yet. +.\" +.Sh AUTHORS +The +.Nm +device driver and this manual page were written by +.An Marcel Moolenaar Aq marcel@xcllnt.net . diff --git a/share/man/man4/rsu.4 b/share/man/man4/rsu.4 index 5d5c56c30061e..e26e3588fe829 100644 --- a/share/man/man4/rsu.4 +++ b/share/man/man4/rsu.4 @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd July 29 2013 +.Dd May 3, 2014 .Dt RSU 4 .Os .Sh NAME @@ -40,7 +40,8 @@ place the following line in if_rsu_load="YES" .Ed .Pp -After you have read the license in /usr/share/doc/legal/realtek +After you have read the license in +.Pa /usr/share/doc/legal/realtek you will want to add the following lines to .Xr loader.conf 5 : .Bd -literal -offset indent @@ -93,18 +94,19 @@ due to serious weaknesses in it. The .Nm driver can be configured at runtime with -.Xr ifconfig 8 -or on boot with -.Xr hostname 1 . +.Xr ifconfig 8 . .Sh FILES The driver needs at least version 1.2 of the following firmware file, which is loaded when an interface is attached: .Pp .Bl -tag -width Ds -offset indent -compact -.It /boot/kernel/rsu-rtl8712fw.ko +.It Pa /boot/kernel/rsu-rtl8712fw.ko .El .Sh HARDWARE -The following adapters should work: +The +.Nm +driver provices support for Realtek RTL8188SU/RTL8192SU USB IEEE 802.11b/g/n +wireless network adapters, including: .Pp .Bl -tag -width Ds -offset indent -compact .It ASUS USB-N10 @@ -149,14 +151,15 @@ The driver will reset the hardware. This should not happen. .El .Sh SEE ALSO -.Xr hostname 1 , .Xr intro 1 , -.Xr usb 3 , +.Xr usb 4 , .Xr netintro 4 , .Xr rsufw 4 , .Xr wlan 4 , .Xr arp 8 , -.Xr ifconfig 8 +.Xr hostapd 8 , +.Xr ifconfig 8 , +.Xr wpa_supplicant 8 .Sh HISTORY The .Nm diff --git a/share/man/man4/tnt4882.4 b/share/man/man4/tnt4882.4 index d95ff8981cf22..e3eacbb3d49c2 100644 --- a/share/man/man4/tnt4882.4 +++ b/share/man/man4/tnt4882.4 @@ -44,7 +44,7 @@ This chip emulates a NEC \(mcPD7210 controller IC as the main interface between the host computer and the instrument bus. .Sh SEE ALSO .Xr gpib 3 , -.Xr gpib 4 , +.Xr gpib 4 .Sh HISTORY The .Nm diff --git a/share/man/man4/urtwn.4 b/share/man/man4/urtwn.4 index ec1b612c9771b..da1db76cb4156 100644 --- a/share/man/man4/urtwn.4 +++ b/share/man/man4/urtwn.4 @@ -14,7 +14,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 25, 2014 +.Dd May 3, 2014 .Dt URTWN 4 .Os .Sh NAME @@ -80,7 +80,10 @@ must be agreed by adding the following line to firmware license .El .Sh HARDWARE -The following adapters should work: +The +.Nm +driver supports Realtek RTL8188CU/RTL8188EU/RTL8192CU based USB +IEEE 802.11b/g/n wireless network adapters, including: .Pp .Bl -tag -width Ds -offset indent -compact .It ASUS USB-N10 NANO @@ -122,9 +125,9 @@ The driver will reset the hardware. This should not happen. .El .Sh SEE ALSO -.Xr urtwnfw 4 , .Xr intro 4 , .Xr netintro 4 , +.Xr urtwnfw 4 , .Xr usb 4 , .Xr wlan 4 , .Xr wlan_ccmp 4 , diff --git a/share/man/man4/vtnet.4 b/share/man/man4/vtnet.4 index c7b2189abbb01..d3d7bc81d5cd3 100644 --- a/share/man/man4/vtnet.4 +++ b/share/man/man4/vtnet.4 @@ -35,7 +35,7 @@ To compile this driver into the kernel, place the following lines in your kernel configuration file: .Bd -ragged -offset indent -.Cd "device if_vtnet" +.Cd "device vtnet" .Ed .Pp Alternatively, to load the driver as a diff --git a/share/man/man4/zero.4 b/share/man/man4/zero.4 index cb73a2c6549f7..c2ba4bd4b54b2 100644 --- a/share/man/man4/zero.4 +++ b/share/man/man4/zero.4 @@ -49,6 +49,7 @@ supply of null bytes when read. .It Pa /dev/zero .El .Sh SEE ALSO +.Xr full 4 , .Xr null 4 .Sh HISTORY A diff --git a/share/man/man5/Makefile b/share/man/man5/Makefile index e0bd22247d401..541f21176f07f 100644 --- a/share/man/man5/Makefile +++ b/share/man/man5/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/5/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> #MISSING: dump.5 plot.5 MAN= acct.5 \ diff --git a/share/man/man5/make.conf.5 b/share/man/man5/make.conf.5 index 2480b84d857ea..441de4b0a173d 100644 --- a/share/man/man5/make.conf.5 +++ b/share/man/man5/make.conf.5 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 28, 2013 +.Dd May 2, 2014 .Dt MAKE.CONF 5 .Os .Sh NAME @@ -692,6 +692,8 @@ and .Ev MAKEOBJDIR are environment variables and should not be set in .Nm +or as command line arguments to +.Xr make 1 , but in make's environment. .Sh BUGS This manual page may occasionally be out of date with respect to diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index 37ba7f2e85fcf..453f3c0850df3 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -192,6 +192,7 @@ MAN= accept_filter.9 \ pci.9 \ pfil.9 \ pfind.9 \ + pget.9 \ pgfind.9 \ physio.9 \ pmap.9 \ @@ -902,6 +903,7 @@ MLINKS+=\ mbuf.9 m_freem.9 \ mbuf.9 MGET.9 \ mbuf.9 m_get.9 \ + mbuf.9 m_get2.9 \ mbuf.9 m_getjcl.9 \ mbuf.9 m_getcl.9 \ mbuf.9 m_getclr.9 \ diff --git a/share/man/man9/mbuf.9 b/share/man/man9/mbuf.9 index 4df1d6ab704dd..9b75c6136b785 100644 --- a/share/man/man9/mbuf.9 +++ b/share/man/man9/mbuf.9 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 16, 2014 +.Dd April 30, 2014 .Dt MBUF 9 .Os .\" @@ -64,23 +64,25 @@ .Fn M_TRAILINGSPACE "struct mbuf *mbuf" .Fn M_MOVE_PKTHDR "struct mbuf *to" "struct mbuf *from" .Fn M_PREPEND "struct mbuf *mbuf" "int len" "int how" -.Fn MCHTYPE "struct mbuf *mbuf" "u_int type" +.Fn MCHTYPE "struct mbuf *mbuf" "short type" .Ft int .Fn M_WRITABLE "struct mbuf *mbuf" .\" .Ss Mbuf allocation functions .Ft struct mbuf * -.Fn m_get "int how" "int type" +.Fn m_get "int how" "short type" .Ft struct mbuf * -.Fn m_getm "struct mbuf *orig" "int len" "int how" "int type" +.Fn m_get2 "int size" "int how" "short type" "int flags" +.Ft struct mbuf * +.Fn m_getm "struct mbuf *orig" "int len" "int how" "short type" .Ft struct mbuf * .Fn m_getjcl "int how" "short type" "int flags" "int size" .Ft struct mbuf * .Fn m_getcl "int how" "short type" "int flags" .Ft struct mbuf * -.Fn m_getclr "int how" "int type" +.Fn m_getclr "int how" "short type" .Ft struct mbuf * -.Fn m_gethdr "int how" "int type" +.Fn m_gethdr "int how" "short type" .Ft struct mbuf * .Fn m_free "struct mbuf *mbuf" .Ft void @@ -528,6 +530,10 @@ The functions are: A function version of .Fn MGET for non-critical paths. +.It Fn m_get2 size how type flags +Allocate an +.Vt mbuf +with enough space to hold specified amount of data. .It Fn m_getm orig len how type Allocate .Fa len diff --git a/share/man/man9/pget.9 b/share/man/man9/pget.9 new file mode 100644 index 0000000000000..12eda29ca7c8d --- /dev/null +++ b/share/man/man9/pget.9 @@ -0,0 +1,107 @@ +.\" Copyright (c) 2011 Sergey Kandaurov +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd May 3, 2014 +.Dt PGET 9 +.Os +.Sh NAME +.Nm pget +.Nd locate a process by number +.Sh SYNOPSIS +.In sys/param.h +.In sys/proc.h +.Ft int +.Fn pget "pid_t pid" "int flags" "struct proc **pp" +.Sh DESCRIPTION +This function +takes a +.Fa pid +as its argument, +which can be either a process or thread id, +and fills a pointer to the +.Vt proc +structure in +.Fa *pp . +In the latter case, a process owning the specified thread is looked for. +The operation is performed by invoking the +.Xr pfind 9 +function. +The found process is returned locked. +For the +.Dv PGET_HOLD +case, it is returned unlocked (but held). +The +.Fn pget +function can +perform additional manipulations, depending on a +.Fa flags +argument. +.Pp +The +.Fa flags +argument is the logical OR of some subset of: +.Bl -tag -width ".Dv PGET_NOTINEXEC" +.It Dv PGET_HOLD +If set, the found process will be held and unlocked. +.It Dv PGET_CANSEE +If set, the found process will be checked for its visibility. +See +.Xr p_cansee 9 . +.It Dv PGET_CANDEBUG +If set, the found process will be checked for its debuggability. +See +.Xr p_candebug 9 . +.It Dv PGET_ISCURRENT +If set, the found process will be checked that it matches the current +process context. +.It Dv PGET_NOTWEXIT +If set, the found process will be checked that it does not have the process +flag +.Dv P_WEXIT +set. +.It Dv PGET_NOTINEXEC +If set, the found process will be checked that it does not have the process +flag +.Dv P_INEXEC +set. +.It Dv PGET_NOTID +If set, +.Fa pid +is not assumed as a thread id for values larger than +.Dv PID_MAX . +.It Dv PGET_WANTREAD +If set, the found process will be checked that the caller may get +a read access to its structure. +A shorthand for +.Pq Dv PGET_HOLD | PGET_CANDEBUG | PGET_NOTWEXIT . +.El +.Sh RETURN VALUES +If the process is found in the specified way, then zero is returned, +otherwise an appropriate error code is returned. +.Sh SEE ALSO +.Xr p_candebug 9 , +.Xr p_cansee 9 , +.Xr pfind 9 diff --git a/share/mk/Makefile b/share/mk/Makefile index 75cd9be82a0ba..ca3d8b3cff792 100644 --- a/share/mk/Makefile +++ b/share/mk/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ # @(#)Makefile 8.1 (Berkeley) 6/8/93 -.include <bsd.own.mk> +.include <src.opts.mk> FILES= \ bsd.README \ @@ -42,6 +42,9 @@ FILES= \ sys.mk \ version_gen.awk +# Installed for the moment, but not may not be in the future. +#FILES+= src.opts.mk + FILESDIR= ${BINDIR}/mk .if ${MK_TESTS} != "no" diff --git a/share/mk/bsd.compiler.mk b/share/mk/bsd.compiler.mk index 6554625bd4e9a..ca15d656596c8 100644 --- a/share/mk/bsd.compiler.mk +++ b/share/mk/bsd.compiler.mk @@ -1,5 +1,8 @@ # $FreeBSD$ +.if !target(__<bsd.compiler.mk>__) +__<bsd.compiler.mk>__: + .if ${MACHINE} == "common" COMPILER_TYPE= none .endif @@ -34,3 +37,5 @@ COMPILER_VERSION:= ${_COMPILER_VERSION:M[1-9].[0-9]*} .else COMPILER_FEATURES= .endif + +.endif # !target(__<bsd.compiler.mk>__) diff --git a/share/mk/bsd.mkopt.mk b/share/mk/bsd.mkopt.mk index b866583404218..3f22bc8aac9af 100644 --- a/share/mk/bsd.mkopt.mk +++ b/share/mk/bsd.mkopt.mk @@ -1,22 +1,34 @@ # # $FreeBSD$ # -# Generic mechanism to deal with WITH and WITHOUT options and turn them into MK_ options. +# Generic mechanism to deal with WITH and WITHOUT options and turn +# them into MK_ options. # +# For each option FOO in __DEFUALT_YES_OPTIONS, MK_FOO is set to +# "yes", unless WITHOUT_FOO is defined, in which case it is set to +# "no". # -# For each option FOO that defaults to YES, MK_FOO is set to yes, unless WITHOUT_FOO -# is defined, in which case it is set to no. If both WITH_FOO and WITHOUT_FOO are -# defined, WITHOUT_FOO wins. The list of default yes options is contained in the -# __DEFAULT_YES_OPTIONS variable, which is undefined after expansion. +# For each option FOO in __DEFUALT_NO_OPTIONS, MK_FOO is set to "no", +# unless WITH_FOO is defined, in which case it is set to "yes". # -# For each option FOO that defaults to NO, MK_FOO is set to no, unless WITH_FOO -# is defined, in which case it is set to yes. If both WITH_FOO and WITHOUT_FOO are -# defined, WITH_FOO wins. The list of default no options is contained in the -# __DEFAULT_NO_OPTIONS variable, which is undefined after expansion. +# If both WITH_FOO and WITHOUT_FOO are defined, WITHOUT_FOO wins and +# MK_FOO is set to "no" regardless of which list it was in. +# +# Both __DEFAULT_YES_OPTIONS and __DEFAULT_NO_OPTIONS are undef'd +# after all this processing, allowing this file to be included +# multiple times with different lists. +# +# Users should generally define WITH_FOO or WITHOUT_FOO, but the build +# system should use MK_FOO={yes,no} when it needs to override the +# user's desires or default behavior. +# + +# +# MK_* options which default to "yes". # .for var in ${__DEFAULT_YES_OPTIONS} .if !defined(MK_${var}) -.if defined(WITHOUT_${var}) # IF both WITH and WITHOUT defined, WITHOUT wins. +.if defined(WITHOUT_${var}) # WITHOUT always wins MK_${var}:= no .else MK_${var}:= yes @@ -30,7 +42,7 @@ MK_${var}:= yes # .for var in ${__DEFAULT_NO_OPTIONS} .if !defined(MK_${var}) -.if defined(WITH_${var}) && !defined(WITHOUT_${var}) # WITHOUT wins +.if defined(WITH_${var}) && !defined(WITHOUT_${var}) # WITHOUT aways wins MK_${var}:= yes .else MK_${var}:= no diff --git a/share/mk/bsd.opts.mk b/share/mk/bsd.opts.mk index f689dc91fbbc3..5f6a4db0edfc6 100644 --- a/share/mk/bsd.opts.mk +++ b/share/mk/bsd.opts.mk @@ -31,11 +31,6 @@ __<bsd.opts.mk>__: .if !defined(_WITHOUT_SRCCONF) -SRCCONF?= /etc/src.conf -.if exists(${SRCCONF}) || ${SRCCONF} != "/etc/src.conf" -.include "${SRCCONF}" -.endif - # # Define MK_* variables (which are either "yes" or "no") for users # to set via WITH_*/WITHOUT_* in /etc/src.conf and override in the @@ -56,6 +51,7 @@ __DEFAULT_YES_OPTIONS = \ MAN \ MANCOMPRESS \ NIS \ + NLS \ OPENSSH \ PROFILE \ SSP \ @@ -65,196 +61,16 @@ __DEFAULT_YES_OPTIONS = \ __DEFAULT_NO_OPTIONS = \ CTF \ DEBUG_FILES \ - INSTALL_AS_USER \ - -.include <bsd.mkopt.mk> + INSTALL_AS_USER -# Note: __DEFAULT_{YES,NO}_OPTIONS unset by bsd.mkopt.mk -# These options are used by src the builds - -__DEFAULT_YES_OPTIONS = \ - ACCT \ - ACPI \ - AMD \ - APM \ - ARM_EABI \ - AT \ - ATM \ - AUDIT \ - AUTHPF \ - BINUTILS \ - BINUTILS_BOOTSTRAP \ - BLUETOOTH \ - BMAKE \ - BOOT \ - BSD_CPIO \ - BSNMP \ - BZIP2 \ - CALENDAR \ - CAPSICUM \ - CASPER \ - CDDL \ - CPP \ - CROSS_COMPILER \ - CRYPT \ - CTM \ - CXX \ - DICT \ - DMAGENT \ - DYNAMICROOT \ - ED_CRYPTO \ - EXAMPLES \ - FDT \ - FLOPPY \ - FMTREE \ - FORMAT_EXTENSIONS \ - FORTH \ - FP_LIBC \ - FREEBSD_UPDATE \ - GAMES \ - GCOV \ - GDB \ - GNU \ - GNU_GREP_COMPAT \ - GPIB \ - GPIO \ - GPL_DTC \ - GROFF \ - HTML \ - ICONV \ - INET \ - INET6 \ - IPFILTER \ - IPFW \ - JAIL \ - KDUMP \ - KERNEL_SYMBOLS \ - KVM \ - LDNS \ - LDNS_UTILS \ - LEGACY_CONSOLE \ - LIB32 \ - LIBPTHREAD \ - LIBTHR \ - LOCALES \ - LOCATE \ - LPR \ - LS_COLORS \ - LZMA_SUPPORT \ - MAIL \ - MAILWRAPPER \ - MAKE \ - NCURSESW \ - NDIS \ - NETCAT \ - NETGRAPH \ - NLS \ - NLS_CATALOGS \ - NS_CACHING \ - NTP \ - OPENSSL \ - PAM \ - PC_SYSINSTALL \ - PF \ - PKGBOOTSTRAP \ - PMC \ - PORTSNAP \ - PPP \ - QUOTAS \ - RCMDS \ - RCS \ - RESCUE \ - ROUTED \ - SENDMAIL \ - SETUID_LOGIN \ - SHAREDOCS \ - SOURCELESS \ - SOURCELESS_HOST \ - SOURCELESS_UCODE \ - SVNLITE \ - SYSCALL_COMPAT \ - SYSCONS \ - SYSINSTALL \ - TCSH \ - TELNET \ - TEXTPROC \ - UNBOUND \ - USB \ - UTMPX \ - VI \ - WIRELESS \ - WPA_SUPPLICANT_EAPOL \ - ZFS \ - ZONEINFO - -__DEFAULT_NO_OPTIONS = \ +# meta mode related +__DEFAULT_NO_OPTIONS += \ AUTO_OBJ \ - BSD_GREP \ - CLANG_EXTRAS \ - EISA \ - HESIOD \ - LLDB \ META_MODE \ - NAND \ - OFED \ - OPENLDAP \ - OPENSSH_NONE_CIPHER \ - SHARED_TOOLCHAIN \ - SORT_THREADS \ STAGING \ - STAGING_PROG \ - SVN \ - TESTS \ - USB_GADGET_EXAMPLES - -# -# Default behaviour of some options depends on the architecture. Unfortunately -# this means that we have to test TARGET_ARCH (the buildworld case) as well -# as MACHINE_ARCH (the non-buildworld case). Normally TARGET_ARCH is not -# used at all in bsd.*.mk, but we have to make an exception here if we want -# to allow defaults for some things like clang to vary by target architecture. -# Additional, per-target behavior should be rarely added only after much -# gnashing of teeth and grinding of gears. -# -.if defined(TARGET_ARCH) -__T=${TARGET_ARCH} -.else -__T=${MACHINE_ARCH} -.endif -.if defined(TARGET) -__TT=${TARGET} -.else -__TT=${MACHINE} -.endif -# Clang is only for x86, powerpc and little-endian arm right now, by default. -.if ${__T} == "amd64" || ${__T} == "i386" || ${__T:Mpowerpc*} -__DEFAULT_YES_OPTIONS+=CLANG CLANG_FULL CLANG_BOOTSTRAP -.elif ${__T} == "arm" || ${__T} == "armv6" || ${__T} == "armv6hf" -__DEFAULT_YES_OPTIONS+=CLANG CLANG_BOOTSTRAP -# GCC is unable to build the full clang on arm, disable it by default. -__DEFAULT_NO_OPTIONS+=CLANG_FULL -.else -__DEFAULT_NO_OPTIONS+=CLANG CLANG_FULL CLANG_BOOTSTRAP -.endif -# Clang the default system compiler only on little-endian arm and x86. -.if ${__T} == "amd64" || ${__T} == "arm" || ${__T} == "armv6" || \ - ${__T} == "armv6hf" || ${__T} == "i386" -__DEFAULT_YES_OPTIONS+=CLANG_IS_CC -__DEFAULT_NO_OPTIONS+=GNUCXX -# The pc98 bootloader requires gcc to build and so we must leave gcc enabled -# for pc98 for now. -.if ${__TT} == "pc98" -__DEFAULT_YES_OPTIONS+=GCC GCC_BOOTSTRAP -.else -__DEFAULT_NO_OPTIONS+=GCC GCC_BOOTSTRAP -.endif -.else -# If clang is not cc, then build gcc by default -__DEFAULT_NO_OPTIONS+=CLANG_IS_CC CLANG CLANG_BOOTSTRAP -__DEFAULT_YES_OPTIONS+=GCC GNUCXX GCC_BOOTSTRAP -.endif - + STAGING_PROG + .include <bsd.mkopt.mk> # @@ -270,154 +86,12 @@ __DEFAULT_YES_OPTIONS+=GCC GNUCXX GCC_BOOTSTRAP MAN \ PROFILE .if defined(NO_${var}) -.warning "NO_${var} is defined, but deprecated. Please use MK_${var}=no instead." +# This warning may be premature... +#.warning "NO_${var} is defined, but deprecated. Please use MK_${var}=no instead." MK_${var}:=no .endif .endfor -# -# MK_* options that default to "yes" if the compiler is a C++11 compiler. -# -.include <bsd.compiler.mk> -.for var in \ - LIBCPLUSPLUS -.if !defined(MK_${var}) -.if ${COMPILER_FEATURES:Mc++11} -.if defined(WITHOUT_${var}) -MK_${var}:= no -.else -MK_${var}:= yes -.endif -.else -.if defined(WITH_${var}) -MK_${var}:= yes -.else -MK_${var}:= no -.endif -.endif -.endif -.endfor - -# -# Force some options off if their dependencies are off. -# Order is somewhat important. -# -.if ${MK_LIBPTHREAD} == "no" -MK_LIBTHR:= no -.endif - -.if ${MK_LDNS} == "no" -MK_LDNS_UTILS:= no -MK_UNBOUND:= no -.endif - -.if ${MK_SOURCELESS} == "no" -MK_SOURCELESS_HOST:= no -MK_SOURCELESS_UCODE:= no -.endif - -.if ${MK_CDDL} == "no" -MK_ZFS:= no -MK_CTF:= no -.endif - -.if ${MK_CRYPT} == "no" -MK_OPENSSL:= no -MK_OPENSSH:= no -MK_KERBEROS:= no -.endif - -.if ${MK_CXX} == "no" -MK_CLANG:= no -MK_GROFF:= no -.endif - -.if ${MK_MAIL} == "no" -MK_MAILWRAPPER:= no -MK_SENDMAIL:= no -MK_DMAGENT:= no -.endif - -.if ${MK_NETGRAPH} == "no" -MK_ATM:= no -MK_BLUETOOTH:= no -.endif - -.if ${MK_OPENSSL} == "no" -MK_OPENSSH:= no -MK_KERBEROS:= no -.endif - -.if ${MK_PF} == "no" -MK_AUTHPF:= no -.endif - -.if ${MK_TEXTPROC} == "no" -MK_GROFF:= no -.endif - -.if ${MK_CROSS_COMPILER} == "no" -MK_BINUTILS_BOOTSTRAP:= no -MK_CLANG_BOOTSTRAP:= no -MK_GCC_BOOTSTRAP:= no -.endif - -.if ${MK_TOOLCHAIN} == "no" -MK_BINUTILS:= no -MK_CLANG:= no -MK_GCC:= no -MK_GDB:= no -.endif - -.if ${MK_CLANG} == "no" -MK_CLANG_EXTRAS:= no -MK_CLANG_FULL:= no -.endif - -# -# Set defaults for the MK_*_SUPPORT variables. -# - -# -# MK_*_SUPPORT options which default to "yes" unless their corresponding -# MK_* variable is set to "no". -# -.for var in \ - BZIP2 \ - GNU \ - INET \ - INET6 \ - KERBEROS \ - KVM \ - NETGRAPH \ - PAM \ - WIRELESS -.if defined(WITHOUT_${var}_SUPPORT) || ${MK_${var}} == "no" -MK_${var}_SUPPORT:= no -.else -MK_${var}_SUPPORT:= yes -.endif -.endfor - -# -# MK_* options whose default value depends on another option. -# -.for vv in \ - GSSAPI/KERBEROS \ - MAN_UTILS/MAN -.if defined(WITH_${vv:H}) -MK_${vv:H}:= yes -.elif defined(WITHOUT_${vv:H}) -MK_${vv:H}:= no -.else -MK_${vv:H}:= ${MK_${vv:T}} -.endif -.endfor - -.if !${COMPILER_FEATURES:Mc++11} -MK_LLDB:= no -.endif - .endif # !_WITHOUT_SRCCONF .endif diff --git a/share/mk/bsd.own.mk b/share/mk/bsd.own.mk index 3105cd63d0a2d..952ca21a2852e 100644 --- a/share/mk/bsd.own.mk +++ b/share/mk/bsd.own.mk @@ -1,6 +1,6 @@ # $FreeBSD$ # -# The include file <bsd.own.mk> set common variables for owner, +# The include file <src.opts.mk> set common variables for owner, # group, mode, and directories. Defaults are in brackets. # # @@ -234,4 +234,7 @@ COMPRESS_EXT?= .gz # overriden by Makefiles, but the user may choose to set this in src.conf(5). TESTSBASE?= /usr/tests +# Compat for the moment +.include <bsd.compiler.mk> + .endif # !target(__<bsd.own.mk>__) diff --git a/share/mk/bsd.prog.mk b/share/mk/bsd.prog.mk index fc6ccbe0cac0f..976794d5cad6b 100644 --- a/share/mk/bsd.prog.mk +++ b/share/mk/bsd.prog.mk @@ -2,6 +2,7 @@ # $FreeBSD$ .include <bsd.init.mk> +.include <bsd.compiler.mk> .SUFFIXES: .out .o .c .cc .cpp .cxx .C .m .y .l .ln .s .S .asm diff --git a/share/mk/bsd.sys.mk b/share/mk/bsd.sys.mk index ca59d0b693806..a587b0d28b15d 100644 --- a/share/mk/bsd.sys.mk +++ b/share/mk/bsd.sys.mk @@ -24,7 +24,6 @@ CFLAGS+= -std=iso9899:1999 .else # CSTD CFLAGS+= -std=${CSTD} .endif # CSTD -.if !defined(NO_WARNS) # -pedantic is problematic because it also imposes namespace restrictions #CFLAGS+= -pedantic .if defined(WARNS) @@ -52,9 +51,8 @@ CWARNFLAGS+= -Wcast-align .if ${WARNS} >= 6 CWARNFLAGS+= -Wchar-subscripts -Winline -Wnested-externs -Wredundant-decls\ -Wold-style-definition -.if ${COMPILER_TYPE} == "clang" && !defined(EARLY_BUILD) && \ - !defined(NO_WMISSING_VARIABLE_DECLARATIONS) -CWARNFLAGS+= -Wmissing-variable-declarations +.if !defined(NO_WMISSING_VARIABLE_DECLARATIONS) +CWARNFLAGS.clang+= -Wmissing-variable-declarations .endif .endif # WARNS >= 6 .if ${WARNS} >= 2 && ${WARNS} <= 4 @@ -65,27 +63,25 @@ CWARNFLAGS+= -Wno-uninitialized CWARNFLAGS+= -Wno-pointer-sign # Clang has more warnings enabled by default, and when using -Wall, so if WARNS # is set to low values, these have to be disabled explicitly. -.if ${COMPILER_TYPE} == "clang" && !defined(EARLY_BUILD) .if ${WARNS} <= 6 -CWARNFLAGS+= -Wno-empty-body -Wno-string-plus-int +CWARNFLAGS.clang+= -Wno-empty-body -Wno-string-plus-int .if ${COMPILER_VERSION} > 3.3 -CWARNFLAGS+= -Wno-unused-const-variable +CWARNFLAGS.clang+= -Wno-unused-const-variable .endif .endif # WARNS <= 6 .if ${WARNS} <= 3 -CWARNFLAGS+= -Wno-tautological-compare -Wno-unused-value\ +CWARNFLAGS.clang+= -Wno-tautological-compare -Wno-unused-value\ -Wno-parentheses-equality -Wno-unused-function -Wno-enum-conversion .endif # WARNS <= 3 .if ${WARNS} <= 2 -CWARNFLAGS+= -Wno-switch -Wno-switch-enum -Wno-knr-promoted-parameter +CWARNFLAGS.clang+= -Wno-switch -Wno-switch-enum -Wno-knr-promoted-parameter .endif # WARNS <= 2 .if ${WARNS} <= 1 -CWARNFLAGS+= -Wno-parentheses +CWARNFLAGS.clang+= -Wno-parentheses .endif # WARNS <= 1 .if defined(NO_WARRAY_BOUNDS) -CWARNFLAGS+= -Wno-array-bounds +CWARNFLAGS.clang+= -Wno-array-bounds .endif # NO_WARRAY_BOUNDS -.endif # CLANG .endif # WARNS .if defined(FORMAT_AUDIT) @@ -95,11 +91,9 @@ WFORMAT= 1 .if ${WFORMAT} > 0 #CWARNFLAGS+= -Wformat-nonliteral -Wformat-security -Wno-format-extra-args CWARNFLAGS+= -Wformat=2 -Wno-format-extra-args -.if ${COMPILER_TYPE} == "clang" && !defined(EARLY_BUILD) .if ${WARNS} <= 3 -CWARNFLAGS+= -Wno-format-nonliteral +CWARNFLAGS.clang+= -Wno-format-nonliteral .endif # WARNS <= 3 -.endif # CLANG .if !defined(NO_WERROR) && !defined(NO_WERROR.${COMPILER_TYPE}) CWARNFLAGS+= -Werror .endif # !NO_WERROR && !NO_WERROR.${COMPILER_TYPE} @@ -108,32 +102,29 @@ CWARNFLAGS+= -Werror .if defined(NO_WFORMAT) || defined(NO_WFORMAT.${COMPILER_TYPE}) CWARNFLAGS+= -Wno-format .endif # NO_WFORMAT || NO_WFORMAT.${COMPILER_TYPE} -.endif # !NO_WARNS .if defined(IGNORE_PRAGMA) CWARNFLAGS+= -Wno-unknown-pragmas .endif # IGNORE_PRAGMA -.if !defined(EARLY_BUILD) .if ${COMPILER_TYPE} == "clang" +# Would love to do this unconditionally, but can't due to its use in +# kernel build coupled with CFLAGS.${TARGET} feature CLANG_NO_IAS= -no-integrated-as +.endif CLANG_OPT_SMALL= -mstack-alignment=8 -mllvm -inline-threshold=3\ -mllvm -enable-load-pre=false -mllvm -simplifycfg-dup-ret -CFLAGS+= -Qunused-arguments +CFLAGS.clang+= -Qunused-arguments .if ${MACHINE_CPUARCH} == "sparc64" # Don't emit .cfi directives, since we must use GNU as on sparc64, for now. -CFLAGS+= -fno-dwarf2-cfi-asm +CFLAGS.clang+= -fno-dwarf2-cfi-asm .endif # SPARC64 # The libc++ headers use c++11 extensions. These are normally silenced because # they are treated as system headers, but we explicitly disable that warning # suppression when building the base system to catch bugs in our headers. # Eventually we'll want to start building the base system C++ code as C++11, # but not yet. -CXXFLAGS+= -Wno-c++11-extensions -.endif # CLANG -CFLAGS+= ${CFLAGS.${COMPILER_TYPE}} -CXXFLAGS+= ${CXXFLAGS.${COMPILER_TYPE}} -.endif # !EARLY_BUILD +CXXFLAGS.clang+= -Wno-c++11-extensions .if ${MK_SSP} != "no" && ${MACHINE_CPUARCH} != "ia64" && \ ${MACHINE_CPUARCH} != "arm" && ${MACHINE_CPUARCH} != "mips" @@ -142,9 +133,19 @@ SSP_CFLAGS?= -fstack-protector CFLAGS+= ${SSP_CFLAGS} .endif # SSP && !IA64 && !ARM && !MIPS -# Allow user-specified additional warning flags -CFLAGS+= ${CWARNFLAGS} +# Allow user-specified additional warning flags, plus compiler specific flag overrides. +# Unless we're early in the build, in which case don't (which is lame, this should +# be handled by NO_WARNS which needs to migrate to something else. +.if !defined(NO_WARNS) && !defined(EARLY_BUILD) +CFLAGS+= ${CWARNFLAGS} ${CWARNFLAGS.${COMPILER_TYPE}} +.endif +# Not sure this is 100% kosher, but I think that EARLY_BUILD must be only +# defined when we're not building programs that use the CFLAGS.foo feature. +.if !defined(EARLY_BUILD) +CFLAGS+= ${CFLAGS.${COMPILER_TYPE}} +CXXFLAGS+= ${CXXFLAGS.${COMPILER_TYPE}} +.endif # Tell bmake not to mistake standard targets for things to be searched for # or expect to ever be up-to-date. diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk new file mode 100644 index 0000000000000..f82167b87bf6c --- /dev/null +++ b/share/mk/src.opts.mk @@ -0,0 +1,376 @@ +# $FreeBSD$ +# +# Option file for FreeBSD /usr/src builds. +# +# Users define WITH_FOO and WITHOUT_FOO on the command line or in /etc/src.conf +# and /etc/make.conf files. These translate in the build system to MK_FOO={yes,no} +# with sensible (usually) defaults. +# +# Makefiles must include bsd.opts.mk after defining specific MK_FOO options that +# are applicable for that Makefile (typically there are none, but sometimes there +# are exceptions). Recursive makes usually add MK_FOO=no for options that they wish +# to omit from that make. +# +# Makefiles must include bsd.srcpot.mk before they test the value of any MK_FOO +# variable. +# +# Makefiles may also assume that this file is included by src.opts.mk should it +# need variables defined there prior to the end of the Makefile where +# bsd.{subdir,lib.bin}.mk is traditionally included. +# +# The old-style YES_FOO and NO_FOO are being phased out. No new instances of them +# should be added. Old instances should be removed since they were just to +# bridge the gap between FreeBSD 4 and FreeBSD 5. +# +# Makefiles should never test WITH_FOO or WITHOUT_FOO directly (although an +# exception is made for _WITHOUT_SRCONF which turns off this mechanism +# completely). +# + +.if !target(__<src.opts.mk>__) +__<src.opts.mk>__: + +# Compat -- needed still? +.include <bsd.own.mk> + +# Allow user to configure things, but in the future this will move +# elsehwere... + +SRCCONF?= /etc/src.conf +.if exists(${SRCCONF}) || ${SRCCONF} != "/etc/src.conf" +.include "${SRCCONF}" +.endif + +# +# Define MK_* variables (which are either "yes" or "no") for users +# to set via WITH_*/WITHOUT_* in /etc/src.conf and override in the +# make(1) environment. +# These should be tested with `== "no"' or `!= "no"' in makefiles. +# The NO_* variables should only be set by makefiles for variables +# that haven't been converted over. +# + +# These options are used by src the builds + +__DEFAULT_YES_OPTIONS = \ + ACCT \ + ACPI \ + AMD \ + APM \ + ARM_EABI \ + AT \ + ATM \ + AUDIT \ + AUTHPF \ + BINUTILS \ + BINUTILS_BOOTSTRAP \ + BLUETOOTH \ + BOOT \ + BSD_CPIO \ + BSNMP \ + BZIP2 \ + CALENDAR \ + CAPSICUM \ + CASPER \ + CDDL \ + CPP \ + CROSS_COMPILER \ + CRYPT \ + CTM \ + CXX \ + DICT \ + DMAGENT \ + DYNAMICROOT \ + ED_CRYPTO \ + EXAMPLES \ + FDT \ + FLOPPY \ + FMTREE \ + FORMAT_EXTENSIONS \ + FORTH \ + FP_LIBC \ + FREEBSD_UPDATE \ + GAMES \ + GCOV \ + GDB \ + GNU \ + GNU_GREP_COMPAT \ + GPIB \ + GPIO \ + GPL_DTC \ + GROFF \ + HTML \ + ICONV \ + INET \ + INET6 \ + IPFILTER \ + IPFW \ + JAIL \ + KDUMP \ + KERNEL_SYMBOLS \ + KVM \ + LDNS \ + LDNS_UTILS \ + LEGACY_CONSOLE \ + LIB32 \ + LIBPTHREAD \ + LIBTHR \ + LOCALES \ + LOCATE \ + LPR \ + LS_COLORS \ + LZMA_SUPPORT \ + MAIL \ + MAILWRAPPER \ + MAKE \ + NCURSESW \ + NDIS \ + NETCAT \ + NETGRAPH \ + NLS_CATALOGS \ + NS_CACHING \ + NTP \ + OPENSSL \ + PAM \ + PC_SYSINSTALL \ + PF \ + PKGBOOTSTRAP \ + PMC \ + PORTSNAP \ + PPP \ + QUOTAS \ + RCMDS \ + RCS \ + RESCUE \ + ROUTED \ + SENDMAIL \ + SETUID_LOGIN \ + SHAREDOCS \ + SOURCELESS \ + SOURCELESS_HOST \ + SOURCELESS_UCODE \ + SVNLITE \ + SYSCALL_COMPAT \ + SYSCONS \ + SYSINSTALL \ + TCSH \ + TELNET \ + TEXTPROC \ + UNBOUND \ + USB \ + UTMPX \ + VI \ + WIRELESS \ + WPA_SUPPLICANT_EAPOL \ + ZFS \ + ZONEINFO + +__DEFAULT_NO_OPTIONS = \ + BSD_GREP \ + CLANG_EXTRAS \ + EISA \ + HESIOD \ + LLDB \ + NAND \ + OFED \ + OPENLDAP \ + OPENSSH_NONE_CIPHER \ + SHARED_TOOLCHAIN \ + SORT_THREADS \ + SVN \ + TESTS \ + USB_GADGET_EXAMPLES + +# +# Default behaviour of some options depends on the architecture. Unfortunately +# this means that we have to test TARGET_ARCH (the buildworld case) as well +# as MACHINE_ARCH (the non-buildworld case). Normally TARGET_ARCH is not +# used at all in bsd.*.mk, but we have to make an exception here if we want +# to allow defaults for some things like clang to vary by target architecture. +# Additional, per-target behavior should be rarely added only after much +# gnashing of teeth and grinding of gears. +# +.if defined(TARGET_ARCH) +__T=${TARGET_ARCH} +.else +__T=${MACHINE_ARCH} +.endif +.if defined(TARGET) +__TT=${TARGET} +.else +__TT=${MACHINE} +.endif +# Clang is only for x86, powerpc and little-endian arm right now, by default. +.if ${__T} == "amd64" || ${__T} == "i386" || ${__T:Mpowerpc*} +__DEFAULT_YES_OPTIONS+=CLANG CLANG_FULL CLANG_BOOTSTRAP +.elif ${__T} == "arm" || ${__T} == "armv6" || ${__T} == "armv6hf" +__DEFAULT_YES_OPTIONS+=CLANG CLANG_BOOTSTRAP +# GCC is unable to build the full clang on arm, disable it by default. +__DEFAULT_NO_OPTIONS+=CLANG_FULL +.else +__DEFAULT_NO_OPTIONS+=CLANG CLANG_FULL CLANG_BOOTSTRAP +.endif +# Clang the default system compiler only on little-endian arm and x86. +.if ${__T} == "amd64" || ${__T} == "arm" || ${__T} == "armv6" || \ + ${__T} == "armv6hf" || ${__T} == "i386" +__DEFAULT_YES_OPTIONS+=CLANG_IS_CC +__DEFAULT_NO_OPTIONS+=GNUCXX +# The pc98 bootloader requires gcc to build and so we must leave gcc enabled +# for pc98 for now. +.if ${__TT} == "pc98" +__DEFAULT_YES_OPTIONS+=GCC GCC_BOOTSTRAP +.else +__DEFAULT_NO_OPTIONS+=GCC GCC_BOOTSTRAP +.endif +.else +# If clang is not cc, then build gcc by default +__DEFAULT_NO_OPTIONS+=CLANG_IS_CC CLANG CLANG_BOOTSTRAP +__DEFAULT_YES_OPTIONS+=GCC GNUCXX GCC_BOOTSTRAP +.endif + +.include <bsd.mkopt.mk> + +# +# MK_* options that default to "yes" if the compiler is a C++11 compiler. +# +.include <bsd.compiler.mk> +.for var in \ + LIBCPLUSPLUS +.if !defined(MK_${var}) +.if ${COMPILER_FEATURES:Mc++11} +.if defined(WITHOUT_${var}) +MK_${var}:= no +.else +MK_${var}:= yes +.endif +.else +.if defined(WITH_${var}) +MK_${var}:= yes +.else +MK_${var}:= no +.endif +.endif +.endif +.endfor + +# +# Force some options off if their dependencies are off. +# Order is somewhat important. +# +.if ${MK_LIBPTHREAD} == "no" +MK_LIBTHR:= no +.endif + +.if ${MK_LDNS} == "no" +MK_LDNS_UTILS:= no +MK_UNBOUND:= no +.endif + +.if ${MK_SOURCELESS} == "no" +MK_SOURCELESS_HOST:= no +MK_SOURCELESS_UCODE:= no +.endif + +.if ${MK_CDDL} == "no" +MK_ZFS:= no +MK_CTF:= no +.endif + +.if ${MK_CRYPT} == "no" +MK_OPENSSL:= no +MK_OPENSSH:= no +MK_KERBEROS:= no +.endif + +.if ${MK_CXX} == "no" +MK_CLANG:= no +MK_GROFF:= no +.endif + +.if ${MK_MAIL} == "no" +MK_MAILWRAPPER:= no +MK_SENDMAIL:= no +MK_DMAGENT:= no +.endif + +.if ${MK_NETGRAPH} == "no" +MK_ATM:= no +MK_BLUETOOTH:= no +.endif + +.if ${MK_OPENSSL} == "no" +MK_OPENSSH:= no +MK_KERBEROS:= no +.endif + +.if ${MK_PF} == "no" +MK_AUTHPF:= no +.endif + +.if ${MK_TEXTPROC} == "no" +MK_GROFF:= no +.endif + +.if ${MK_CROSS_COMPILER} == "no" +MK_BINUTILS_BOOTSTRAP:= no +MK_CLANG_BOOTSTRAP:= no +MK_GCC_BOOTSTRAP:= no +.endif + +.if ${MK_TOOLCHAIN} == "no" +MK_BINUTILS:= no +MK_CLANG:= no +MK_GCC:= no +MK_GDB:= no +.endif + +.if ${MK_CLANG} == "no" +MK_CLANG_EXTRAS:= no +MK_CLANG_FULL:= no +.endif + +# +# Set defaults for the MK_*_SUPPORT variables. +# + +# +# MK_*_SUPPORT options which default to "yes" unless their corresponding +# MK_* variable is set to "no". +# +.for var in \ + BZIP2 \ + GNU \ + INET \ + INET6 \ + KERBEROS \ + KVM \ + NETGRAPH \ + PAM \ + WIRELESS +.if defined(WITHOUT_${var}_SUPPORT) || ${MK_${var}} == "no" +MK_${var}_SUPPORT:= no +.else +MK_${var}_SUPPORT:= yes +.endif +.endfor + +# +# MK_* options whose default value depends on another option. +# +.for vv in \ + GSSAPI/KERBEROS \ + MAN_UTILS/MAN +.if defined(WITH_${vv:H}) +MK_${vv:H}:= yes +.elif defined(WITHOUT_${vv:H}) +MK_${vv:H}:= no +.else +MK_${vv:H}:= ${MK_${vv:T}} +.endif +.endfor + +.if !${COMPILER_FEATURES:Mc++11} +MK_LLDB:= no +.endif + +.endif diff --git a/sys/Makefile b/sys/Makefile index 935f30d961472..47fd4629fb079 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> # The boot loader .if ${MK_BOOT} != "no" diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index 84031d985a925..1c21758ba9f4b 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -119,6 +119,7 @@ device isp # Qlogic family #device ispfw # Firmware for QLogic HBAs- normally a module device mpt # LSI-Logic MPT-Fusion device mps # LSI-Logic MPT-Fusion 2 +device mpr # LSI-Logic MPT-Fusion 3 #device ncr # NCR/Symbios Logic device sym # NCR/Symbios Logic (newer chipsets + those of `ncr') device trm # Tekram DC395U/UW/F DC315U adapters diff --git a/sys/amd64/conf/GENERIC.hints b/sys/amd64/conf/GENERIC.hints index eacbbe8512063..39beae1588935 100644 --- a/sys/amd64/conf/GENERIC.hints +++ b/sys/amd64/conf/GENERIC.hints @@ -31,3 +31,5 @@ hint.attimer.0.at="isa" hint.attimer.0.port="0x40" hint.attimer.0.irq="0" hint.wbwd.0.at="isa" +hint.acpi_throttle.0.disabled="1" +hint.p4tcc.0.disabled="1" diff --git a/sys/amd64/conf/NOTES b/sys/amd64/conf/NOTES index aa80598cac47a..61372f5342bb6 100644 --- a/sys/amd64/conf/NOTES +++ b/sys/amd64/conf/NOTES @@ -647,8 +647,5 @@ options VM_KMEM_SIZE_SCALE options NDISAPI device ndis -# Linux-specific pseudo devices support -device lindev - # Module to enable execution of application via emulators like QEMU options IMAGACT_BINMISC diff --git a/sys/amd64/include/vmm.h b/sys/amd64/include/vmm.h index 364bbb855e7f0..68240b9d13173 100644 --- a/sys/amd64/include/vmm.h +++ b/sys/amd64/include/vmm.h @@ -29,6 +29,14 @@ #ifndef _VMM_H_ #define _VMM_H_ +enum vm_suspend_how { + VM_SUSPEND_NONE, + VM_SUSPEND_RESET, + VM_SUSPEND_POWEROFF, + VM_SUSPEND_HALT, + VM_SUSPEND_LAST +}; + #ifdef _KERNEL #define VM_MAX_NAMELEN 32 @@ -115,7 +123,7 @@ int vm_get_seg_desc(struct vm *vm, int vcpu, int reg, int vm_set_seg_desc(struct vm *vm, int vcpu, int reg, struct seg_desc *desc); int vm_run(struct vm *vm, struct vm_run *vmrun); -int vm_suspend(struct vm *vm); +int vm_suspend(struct vm *vm, enum vm_suspend_how how); int vm_inject_nmi(struct vm *vm, int vcpu); int vm_nmi_pending(struct vm *vm, int vcpuid); void vm_nmi_clear(struct vm *vm, int vcpuid); @@ -134,6 +142,7 @@ int vm_apicid2vcpuid(struct vm *vm, int apicid); void vm_activate_cpu(struct vm *vm, int vcpu); cpuset_t vm_active_cpus(struct vm *vm); struct vm_exit *vm_exitinfo(struct vm *vm, int vcpuid); +void vm_exit_suspended(struct vm *vm, int vcpuid, uint64_t rip); /* * Rendezvous all vcpus specified in 'dest' and execute 'func(arg)'. @@ -317,7 +326,7 @@ enum vm_exitcode { VM_EXITCODE_PAGING, VM_EXITCODE_INST_EMUL, VM_EXITCODE_SPINUP_AP, - VM_EXITCODE_SPINDOWN_CPU, + VM_EXITCODE_DEPRECATED1, /* used to be SPINDOWN_CPU */ VM_EXITCODE_RENDEZVOUS, VM_EXITCODE_IOAPIC_EOI, VM_EXITCODE_SUSPENDED, @@ -382,6 +391,9 @@ struct vm_exit { struct { int vector; } ioapic_eoi; + struct { + enum vm_suspend_how how; + } suspended; } u; }; diff --git a/sys/amd64/include/vmm_dev.h b/sys/amd64/include/vmm_dev.h index 475a07fb7e8b6..fcd437f0198f2 100644 --- a/sys/amd64/include/vmm_dev.h +++ b/sys/amd64/include/vmm_dev.h @@ -159,6 +159,10 @@ struct vm_hpet_cap { uint32_t capabilities; /* lower 32 bits of HPET capabilities */ }; +struct vm_suspend { + enum vm_suspend_how how; +}; + enum { /* general routines */ IOCNUM_ABIVERS = 0, @@ -214,7 +218,7 @@ enum { #define VM_RUN \ _IOWR('v', IOCNUM_RUN, struct vm_run) #define VM_SUSPEND \ - _IO('v', IOCNUM_SUSPEND) + _IOW('v', IOCNUM_SUSPEND, struct vm_suspend) #define VM_MAP_MEMORY \ _IOWR('v', IOCNUM_MAP_MEMORY, struct vm_memory_segment) #define VM_GET_MEMORY_SEG \ diff --git a/sys/amd64/vmm/intel/vmx.c b/sys/amd64/vmm/intel/vmx.c index 286eba93616a1..767bcc5132dc3 100644 --- a/sys/amd64/vmm/intel/vmx.c +++ b/sys/amd64/vmm/intel/vmx.c @@ -1797,6 +1797,7 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) vmm_stat_incr(vmx->vm, vcpu, VMEXIT_RDMSR, 1); retu = false; ecx = vmxctx->guest_rcx; + VCPU_CTR1(vmx->vm, vcpu, "rdmsr 0x%08x", ecx); error = emulate_rdmsr(vmx->vm, vcpu, ecx, &retu); if (error) { vmexit->exitcode = VM_EXITCODE_RDMSR; @@ -1815,6 +1816,8 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) eax = vmxctx->guest_rax; ecx = vmxctx->guest_rcx; edx = vmxctx->guest_rdx; + VCPU_CTR2(vmx->vm, vcpu, "wrmsr 0x%08x value 0x%016lx", + ecx, (uint64_t)edx << 32 | eax); error = emulate_wrmsr(vmx->vm, vcpu, ecx, (uint64_t)edx << 32 | eax, &retu); if (error) { @@ -2045,16 +2048,6 @@ vmx_exit_rendezvous(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) } static __inline int -vmx_exit_suspended(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) -{ - - vmexit->rip = vmcs_guest_rip(); - vmexit->inst_length = 0; - vmexit->exitcode = VM_EXITCODE_SUSPENDED; - return (UNHANDLED); -} - -static __inline int vmx_exit_inst_error(struct vmxctx *vmxctx, int rc, struct vm_exit *vmexit) { @@ -2173,7 +2166,8 @@ vmx_run(void *arg, int vcpu, register_t startrip, pmap_t pmap, disable_intr(); if (vcpu_suspended(suspend_cookie)) { enable_intr(); - handled = vmx_exit_suspended(vmx, vcpu, vmexit); + vm_exit_suspended(vmx->vm, vcpu, vmcs_guest_rip()); + handled = UNHANDLED; break; } diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c index 27136f301286a..9aed5f5bb0bbf 100644 --- a/sys/amd64/vmm/vmm.c +++ b/sys/amd64/vmm/vmm.c @@ -142,6 +142,8 @@ struct vm { int suspend; volatile cpuset_t suspended_cpus; + + volatile cpuset_t halted_cpus; }; static int vmm_initialized; @@ -187,12 +189,20 @@ static VMM_STAT(VCPU_TOTAL_RUNTIME, "vcpu total runtime"); SYSCTL_NODE(_hw, OID_AUTO, vmm, CTLFLAG_RW, NULL, NULL); +/* + * Halt the guest if all vcpus are executing a HLT instruction with + * interrupts disabled. + */ +static int halt_detection_enabled = 1; +TUNABLE_INT("hw.vmm.halt_detection", &halt_detection_enabled); +SYSCTL_INT(_hw_vmm, OID_AUTO, halt_detection, CTLFLAG_RDTUN, + &halt_detection_enabled, 0, + "Halt VM if all vcpus execute HLT with interrupts disabled"); + static int vmm_ipinum; SYSCTL_INT(_hw_vmm, OID_AUTO, ipinum, CTLFLAG_RD, &vmm_ipinum, 0, "IPI vector used for vcpu notifications"); -static void vm_deactivate_cpu(struct vm *vm, int vcpuid); - static void vcpu_cleanup(struct vm *vm, int i) { @@ -1006,59 +1016,73 @@ vm_handle_rendezvous(struct vm *vm, int vcpuid) static int vm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled, bool *retu) { - struct vm_exit *vmexit; struct vcpu *vcpu; - int t, timo, spindown; + const char *wmesg; + int t, vcpu_halted, vm_halted; + + KASSERT(!CPU_ISSET(vcpuid, &vm->halted_cpus), ("vcpu already halted")); vcpu = &vm->vcpu[vcpuid]; - spindown = 0; + vcpu_halted = 0; + vm_halted = 0; vcpu_lock(vcpu); + while (1) { + /* + * Do a final check for pending NMI or interrupts before + * really putting this thread to sleep. Also check for + * software events that would cause this vcpu to wakeup. + * + * These interrupts/events could have happened after the + * vcpu returned from VMRUN() and before it acquired the + * vcpu lock above. + */ + if (vm->rendezvous_func != NULL || vm->suspend) + break; + if (vm_nmi_pending(vm, vcpuid)) + break; + if (!intr_disabled) { + if (vm_extint_pending(vm, vcpuid) || + vlapic_pending_intr(vcpu->vlapic, NULL)) { + break; + } + } - /* - * Do a final check for pending NMI or interrupts before - * really putting this thread to sleep. - * - * These interrupts could have happened any time after we - * returned from VMRUN() and before we grabbed the vcpu lock. - */ - if (vm->rendezvous_func == NULL && - !vm_nmi_pending(vm, vcpuid) && - (intr_disabled || !vlapic_pending_intr(vcpu->vlapic, NULL))) { - t = ticks; - vcpu_require_state_locked(vcpu, VCPU_SLEEPING); - if (vlapic_enabled(vcpu->vlapic)) { - /* - * XXX msleep_spin() is not interruptible so use the - * 'timo' to put an upper bound on the sleep time. - */ - timo = hz; - msleep_spin(vcpu, &vcpu->mtx, "vmidle", timo); + /* + * Some Linux guests implement "halt" by having all vcpus + * execute HLT with interrupts disabled. 'halted_cpus' keeps + * track of the vcpus that have entered this state. When all + * vcpus enter the halted state the virtual machine is halted. + */ + if (intr_disabled) { + wmesg = "vmhalt"; + VCPU_CTR0(vm, vcpuid, "Halted"); + if (!vcpu_halted && halt_detection_enabled) { + vcpu_halted = 1; + CPU_SET_ATOMIC(vcpuid, &vm->halted_cpus); + } + if (CPU_CMP(&vm->halted_cpus, &vm->active_cpus) == 0) { + vm_halted = 1; + break; + } } else { - /* - * Spindown the vcpu if the APIC is disabled and it - * had entered the halted state, but never spin - * down the BSP. - */ - if (vcpuid != 0) - spindown = 1; + wmesg = "vmidle"; } + + t = ticks; + vcpu_require_state_locked(vcpu, VCPU_SLEEPING); + msleep_spin(vcpu, &vcpu->mtx, wmesg, 0); vcpu_require_state_locked(vcpu, VCPU_FROZEN); vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t); } + + if (vcpu_halted) + CPU_CLR_ATOMIC(vcpuid, &vm->halted_cpus); + vcpu_unlock(vcpu); - /* - * Since 'vm_deactivate_cpu()' grabs a sleep mutex we must call it - * outside the confines of the vcpu spinlock. - */ - if (spindown) { - *retu = true; - vmexit = vm_exitinfo(vm, vcpuid); - vmexit->exitcode = VM_EXITCODE_SPINDOWN_CPU; - vm_deactivate_cpu(vm, vcpuid); - VCPU_CTR0(vm, vcpuid, "spinning down cpu"); - } + if (vm_halted) + vm_suspend(vm, VM_SUSPEND_HALT); return (0); } @@ -1211,16 +1235,45 @@ vm_handle_suspend(struct vm *vm, int vcpuid, bool *retu) } int -vm_suspend(struct vm *vm) +vm_suspend(struct vm *vm, enum vm_suspend_how how) { + int i; - if (atomic_cmpset_int(&vm->suspend, 0, 1)) { - VM_CTR0(vm, "virtual machine suspended"); - return (0); - } else { - VM_CTR0(vm, "virtual machine already suspended"); + if (how <= VM_SUSPEND_NONE || how >= VM_SUSPEND_LAST) + return (EINVAL); + + if (atomic_cmpset_int(&vm->suspend, 0, how) == 0) { + VM_CTR2(vm, "virtual machine already suspended %d/%d", + vm->suspend, how); return (EALREADY); } + + VM_CTR1(vm, "virtual machine successfully suspended %d", how); + + /* + * Notify all active vcpus that they are now suspended. + */ + for (i = 0; i < VM_MAXCPU; i++) { + if (CPU_ISSET(i, &vm->active_cpus)) + vcpu_notify_event(vm, i, false); + } + + return (0); +} + +void +vm_exit_suspended(struct vm *vm, int vcpuid, uint64_t rip) +{ + struct vm_exit *vmexit; + + KASSERT(vm->suspend > VM_SUSPEND_NONE && vm->suspend < VM_SUSPEND_LAST, + ("vm_exit_suspended: invalid suspend type %d", vm->suspend)); + + vmexit = vm_exitinfo(vm, vcpuid); + vmexit->rip = rip; + vmexit->inst_length = 0; + vmexit->exitcode = VM_EXITCODE_SUSPENDED; + vmexit->u.suspended.how = vm->suspend; } int @@ -1644,30 +1697,6 @@ vm_activate_cpu(struct vm *vm, int vcpuid) CPU_SET_ATOMIC(vcpuid, &vm->active_cpus); } -static void -vm_deactivate_cpu(struct vm *vm, int vcpuid) -{ - - KASSERT(vcpuid >= 0 && vcpuid < VM_MAXCPU, - ("vm_deactivate_cpu: invalid vcpuid %d", vcpuid)); - KASSERT(CPU_ISSET(vcpuid, &vm->active_cpus), - ("vm_deactivate_cpu: vcpuid %d is not active", vcpuid)); - - VCPU_CTR0(vm, vcpuid, "deactivated"); - CPU_CLR_ATOMIC(vcpuid, &vm->active_cpus); - - /* - * If a vcpu rendezvous is in progress then it could be blocked - * on 'vcpuid' - unblock it before disappearing forever. - */ - mtx_lock(&vm->rendezvous_mtx); - if (vm->rendezvous_func != NULL) { - VCPU_CTR0(vm, vcpuid, "unblock rendezvous after deactivation"); - wakeup(&vm->rendezvous_func); - } - mtx_unlock(&vm->rendezvous_mtx); -} - cpuset_t vm_active_cpus(struct vm *vm) { diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c index 37d841d205514..3112c52c97a8e 100644 --- a/sys/amd64/vmm/vmm_dev.c +++ b/sys/amd64/vmm/vmm_dev.c @@ -166,6 +166,7 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, struct vm_stat_desc *statdesc; struct vm_x2apic *x2apic; struct vm_gpa_pte *gpapte; + struct vm_suspend *vmsuspend; sc = vmmdev_lookup2(cdev); if (sc == NULL) @@ -241,7 +242,8 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, error = vm_run(sc->vm, vmrun); break; case VM_SUSPEND: - error = vm_suspend(sc->vm); + vmsuspend = (struct vm_suspend *)data; + error = vm_suspend(sc->vm, vmsuspend->how); break; case VM_STAT_DESC: { statdesc = (struct vm_stat_desc *)data; diff --git a/sys/arm/arm/locore.S b/sys/arm/arm/locore.S index 90eeeaf9aa054..ad4204b826284 100644 --- a/sys/arm/arm/locore.S +++ b/sys/arm/arm/locore.S @@ -308,11 +308,6 @@ Lreal_start: Lend: .word _edata -#ifdef SMP -Lstartup_pagetable_secondary: - .word temp_pagetable -#endif - .Lstart: .word _edata .word _ebss @@ -320,10 +315,6 @@ Lstartup_pagetable_secondary: .Lvirt_done: .word virt_done -#if defined(SMP) -.Lmpvirt_done: - .word mpvirt_done -#endif .Lmainreturned: .asciz "main() returned" @@ -349,52 +340,14 @@ pagetable: .word _C_LABEL(cpufuncs) #if defined(SMP) -Lsramaddr: - .word 0xffff0080 - -#if 0 -#define AP_DEBUG(tmp) \ - mrc p15, 0, r1, c0, c0, 5; \ - ldr r0, Lsramaddr; \ - add r0, r1, lsl #2; \ - mov r1, tmp; \ - str r1, [r0], #0x0000; -#else -#define AP_DEBUG(tmp) -#endif - - -ASENTRY_NP(mptramp) - mov r0, #0 - mcr p15, 0, r0, c7, c7, 0 - - AP_DEBUG(#1) - - mrs r3, cpsr - bic r3, r3, #(PSR_MODE) - orr r3, r3, #(PSR_SVC32_MODE) - msr cpsr_fsxc, r3 - - mrc p15, 0, r0, c0, c0, 5 - and r0, #0x0f /* Get CPU ID */ - - /* Read boot address for CPU */ - mov r1, #0x100 - mul r2, r0, r1 - ldr r1, Lpmureg - add r0, r2, r1 - ldr r1, [r0], #0x00 - mov pc, r1 - -Lpmureg: - .word 0xd0022124 -END(mptramp) +.Lmpvirt_done: + .word mpvirt_done +Lstartup_pagetable_secondary: + .word temp_pagetable ASENTRY_NP(mpentry) - AP_DEBUG(#2) - /* Make sure interrupts are disabled. */ mrs r7, cpsr orr r7, r7, #(I32_bit|F32_bit) @@ -417,35 +370,25 @@ ASENTRY_NP(mpentry) nop nop - AP_DEBUG(#3) - Ltag: ldr r0, Lstartup_pagetable_secondary bic r0, r0, #0xf0000000 orr r0, r0, #PHYSADDR ldr r0, [r0] -#if defined(SMP) orr r0, r0, #2 /* Set TTB shared memory flag */ -#endif mcr p15, 0, r0, c2, c0, 0 /* Set TTB */ mcr p15, 0, r0, c8, c7, 0 /* Flush TLB */ -#if defined(CPU_ARM1136) || defined(CPU_ARM1176) || defined(CPU_MV_PJ4B) || defined(CPU_CORTEXA) || defined(CPU_KRAIT) mov r0, #0 mcr p15, 0, r0, c13, c0, 1 /* Set ASID to 0 */ -#endif - - AP_DEBUG(#4) /* Set the Domain Access register. Very important! */ mov r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT) mcr p15, 0, r0, c3, c0, 0 /* Enable MMU */ mrc p15, 0, r0, c1, c0, 0 -#if defined(CPU_ARM1136) || defined(CPU_ARM1176) || defined(CPU_MV_PJ4B) || defined(CPU_CORTEXA) || defined(CPU_KRAIT) orr r0, r0, #CPU_CONTROL_V6_EXTPAGE orr r0, r0, #CPU_CONTROL_AF_ENABLE -#endif orr r0, r0, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE) mcr p15, 0, r0, c1, c0, 0 nop @@ -473,7 +416,7 @@ mpvirt_done: /* NOTREACHED */ .Lmpreturned: - .asciz "main() returned" + .asciz "init_secondary() returned" .align 0 END(mpentry) #endif diff --git a/sys/arm/arm/pl310.c b/sys/arm/arm/pl310.c index b087365b5835e..83e690711b410 100644 --- a/sys/arm/arm/pl310.c +++ b/sys/arm/arm/pl310.c @@ -71,7 +71,7 @@ __FBSDID("$FreeBSD$"); } while(0); static int pl310_enabled = 1; -TUNABLE_INT("pl310.enabled", &pl310_enabled); +TUNABLE_INT("hw.pl310.enabled", &pl310_enabled); static uint32_t g_l2cache_way_mask; @@ -125,6 +125,35 @@ pl310_print_config(struct pl310_softc *sc) (prefetch & PREFETCH_CTRL_OFFSET_MASK)); } +void +pl310_set_ram_latency(struct pl310_softc *sc, uint32_t which_reg, + uint32_t read, uint32_t write, uint32_t setup) +{ + uint32_t v; + + KASSERT(which_reg == PL310_TAG_RAM_CTRL || + which_reg == PL310_DATA_RAM_CTRL, + ("bad pl310 ram latency register address")); + + v = pl310_read4(sc, which_reg); + if (setup != 0) { + KASSERT(setup <= 8, ("bad pl310 setup latency: %d", setup)); + v &= ~RAM_CTRL_SETUP_MASK; + v |= (setup - 1) << RAM_CTRL_SETUP_SHIFT; + } + if (read != 0) { + KASSERT(read <= 8, ("bad pl310 read latency: %d", read)); + v &= ~RAM_CTRL_READ_MASK; + v |= (read - 1) << RAM_CTRL_READ_SHIFT; + } + if (write != 0) { + KASSERT(write <= 8, ("bad pl310 write latency: %d", write)); + v &= ~RAM_CTRL_WRITE_MASK; + v |= (write - 1) << RAM_CTRL_WRITE_SHIFT; + } + pl310_write4(sc, which_reg, v); +} + static int pl310_filter(void *arg) { @@ -149,7 +178,8 @@ static __inline void pl310_wait_background_op(uint32_t off, uint32_t mask) { - while (pl310_read4(pl310_softc, off) & mask); + while (pl310_read4(pl310_softc, off) & mask) + continue; } @@ -167,6 +197,7 @@ pl310_wait_background_op(uint32_t off, uint32_t mask) static __inline void pl310_cache_sync(void) { + if ((pl310_softc == NULL) || !pl310_softc->sc_enabled) return; @@ -318,6 +349,23 @@ pl310_inv_range(vm_paddr_t start, vm_size_t size) PL310_UNLOCK(pl310_softc); } +static void +pl310_set_way_sizes(struct pl310_softc *sc) +{ + uint32_t aux_value; + + aux_value = pl310_read4(sc, PL310_AUX_CTRL); + g_way_size = (aux_value & AUX_CTRL_WAY_SIZE_MASK) >> + AUX_CTRL_WAY_SIZE_SHIFT; + g_way_size = 1 << (g_way_size + 13); + if (aux_value & (1 << AUX_CTRL_ASSOCIATIVITY_SHIFT)) + g_ways_assoc = 16; + else + g_ways_assoc = 8; + g_l2cache_way_mask = (1 << g_ways_assoc) - 1; + g_l2cache_size = g_way_size * g_ways_assoc; +} + static int pl310_probe(device_t dev) { @@ -335,12 +383,11 @@ static int pl310_attach(device_t dev) { struct pl310_softc *sc = device_get_softc(dev); - int rid = 0; - uint32_t aux_value; - uint32_t ctrl_value; - uint32_t cache_id; + int rid; + uint32_t cache_id, debug_ctrl; sc->sc_dev = dev; + rid = 0; sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->sc_mem_res == NULL) @@ -356,7 +403,6 @@ pl310_attach(device_t dev) pl310_softc = sc; mtx_init(&sc->sc_mtx, "pl310lock", NULL, MTX_SPIN); - sc->sc_enabled = pl310_enabled; /* activate the interrupt */ bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, @@ -368,39 +414,49 @@ pl310_attach(device_t dev) device_printf(dev, "Part number: 0x%x, release: 0x%x\n", (cache_id >> CACHE_ID_PARTNUM_SHIFT) & CACHE_ID_PARTNUM_MASK, (cache_id >> CACHE_ID_RELEASE_SHIFT) & CACHE_ID_RELEASE_MASK); - aux_value = pl310_read4(sc, PL310_AUX_CTRL); - g_way_size = (aux_value & AUX_CTRL_WAY_SIZE_MASK) >> - AUX_CTRL_WAY_SIZE_SHIFT; - g_way_size = 1 << (g_way_size + 13); - if (aux_value & (1 << AUX_CTRL_ASSOCIATIVITY_SHIFT)) - g_ways_assoc = 16; - else - g_ways_assoc = 8; - g_l2cache_way_mask = (1 << g_ways_assoc) - 1; - g_l2cache_size = g_way_size * g_ways_assoc; - /* Print the information */ - device_printf(dev, "L2 Cache: %uKB/%dB %d ways\n", (g_l2cache_size / 1024), - g_l2cache_line_size, g_ways_assoc); - ctrl_value = pl310_read4(sc, PL310_CTRL); + /* + * If L2 cache is already enabled then something has violated the rules, + * because caches are supposed to be off at kernel entry. The cache + * must be disabled to write the configuration registers without + * triggering an access error (SLVERR), but there's no documented safe + * procedure for disabling the L2 cache in the manual. So we'll try to + * invent one: + * - Use the debug register to force write-through mode and prevent + * linefills (allocation of new lines on read); now anything we do + * will not cause new data to come into the L2 cache. + * - Writeback and invalidate the current contents. + * - Disable the controller. + * - Restore the original debug settings. + */ + if (pl310_read4(sc, PL310_CTRL) & CTRL_ENABLED) { + device_printf(dev, "Warning: L2 Cache should not already be " + "active; trying to de-activate and re-initialize...\n"); + sc->sc_enabled = 1; + debug_ctrl = pl310_read4(sc, PL310_DEBUG_CTRL); + platform_pl310_write_debug(sc, debug_ctrl | + DEBUG_CTRL_DISABLE_WRITEBACK | DEBUG_CTRL_DISABLE_LINEFILL); + pl310_set_way_sizes(sc); + pl310_wbinv_all(); + platform_pl310_write_ctrl(sc, CTRL_DISABLED); + platform_pl310_write_debug(sc, debug_ctrl); + } + sc->sc_enabled = pl310_enabled; - if (sc->sc_enabled && !(ctrl_value & CTRL_ENABLED)) { - /* invalidate current content */ + if (sc->sc_enabled) { + platform_pl310_init(sc); + pl310_set_way_sizes(sc); /* platform init might change these */ pl310_write4(pl310_softc, PL310_INV_WAY, 0xffff); pl310_wait_background_op(PL310_INV_WAY, 0xffff); - - /* Enable the L2 cache if disabled */ platform_pl310_write_ctrl(sc, CTRL_ENABLED); - device_printf(dev, "L2 Cache enabled\n"); + device_printf(dev, "L2 Cache enabled: %uKB/%dB %d ways\n", + (g_l2cache_size / 1024), g_l2cache_line_size, g_ways_assoc); if (bootverbose) pl310_print_config(sc); - } - - if (!sc->sc_enabled && (ctrl_value & CTRL_ENABLED)) { + } else { /* - * Set counters so when cache event happens - * we'll get interrupt and be warned that something - * is off + * Set counters so when cache event happens we'll get interrupt + * and be warned that something is off. */ /* Cache Line Eviction for Counter 0 */ @@ -410,12 +466,6 @@ pl310_attach(device_t dev) pl310_write4(sc, PL310_EVENT_COUNTER1_CONF, EVENT_COUNTER_CONF_INCR | EVENT_COUNTER_CONF_DRREQ); - /* Temporary switch on for final flush*/ - sc->sc_enabled = 1; - pl310_wbinv_all(); - sc->sc_enabled = 0; - platform_pl310_write_ctrl(sc, CTRL_DISABLED); - /* Enable and clear pending interrupts */ pl310_write4(sc, PL310_INTR_CLEAR, INTR_MASK_ECNTR); pl310_write4(sc, PL310_INTR_MASK, INTR_MASK_ALL); @@ -429,11 +479,6 @@ pl310_attach(device_t dev) device_printf(dev, "L2 Cache disabled\n"); } - if (sc->sc_enabled) - platform_pl310_init(sc); - - pl310_wbinv_all(); - /* Set the l2 functions in the set of cpufuncs */ cpufuncs.cf_l2cache_wbinv_all = pl310_wbinv_all; cpufuncs.cf_l2cache_wbinv_range = pl310_wbinv_range; @@ -446,7 +491,7 @@ pl310_attach(device_t dev) static device_method_t pl310_methods[] = { DEVMETHOD(device_probe, pl310_probe), DEVMETHOD(device_attach, pl310_attach), - {0, 0}, + DEVMETHOD_END }; static driver_t pl310_driver = { diff --git a/sys/arm/conf/ARNDALE b/sys/arm/conf/ARNDALE index e50d3f4ed65e7..da4c598e385e5 100644 --- a/sys/arm/conf/ARNDALE +++ b/sys/arm/conf/ARNDALE @@ -17,6 +17,8 @@ # # $FreeBSD$ +#NO_UNIVERSE + include "EXYNOS5250.common" ident ARNDALE diff --git a/sys/arm/conf/BWCT b/sys/arm/conf/BWCT index 4c0001952af7e..5ed552b702c67 100644 --- a/sys/arm/conf/BWCT +++ b/sys/arm/conf/BWCT @@ -17,6 +17,8 @@ # # $FreeBSD$ +#NO_UNIVERSE + ident BWCT options VERBOSE_INIT_ARM diff --git a/sys/arm/conf/COLIBRI-VF50 b/sys/arm/conf/COLIBRI-VF50 index 343fb89632381..9f73f6987f2f1 100644 --- a/sys/arm/conf/COLIBRI-VF50 +++ b/sys/arm/conf/COLIBRI-VF50 @@ -17,7 +17,9 @@ # # $FreeBSD$ -include "VYBRID.common" +#NO_UNIVERSE + +include "VYBRID" ident COLIBRI-VF50 #FDT diff --git a/sys/arm/conf/COSMIC b/sys/arm/conf/COSMIC index b3b407432f6f7..72ae5c20b07b5 100644 --- a/sys/arm/conf/COSMIC +++ b/sys/arm/conf/COSMIC @@ -17,7 +17,9 @@ # # $FreeBSD$ -include "VYBRID.common" +#NO_UNIVERSE + +include "VYBRID" ident COSMIC #FDT diff --git a/sys/arm/conf/EB9200 b/sys/arm/conf/EB9200 index 0afa9b4288eb0..3e3d124501fe8 100644 --- a/sys/arm/conf/EB9200 +++ b/sys/arm/conf/EB9200 @@ -12,6 +12,8 @@ # # $FreeBSD$ +#NO_UNIVERSE + ident EB9200 include "../at91/std.eb9200" diff --git a/sys/arm/conf/ETHERNUT5 b/sys/arm/conf/ETHERNUT5 index 9bc234df94943..9df7f9c55aaf7 100644 --- a/sys/arm/conf/ETHERNUT5 +++ b/sys/arm/conf/ETHERNUT5 @@ -17,6 +17,8 @@ # # $FreeBSD$ +#NO_UNIVERSE + ident ETHERNUT5 include "../at91/std.ethernut5" diff --git a/sys/arm/conf/HL200 b/sys/arm/conf/HL200 index c8d43c2616005..8e0d174512ef8 100644 --- a/sys/arm/conf/HL200 +++ b/sys/arm/conf/HL200 @@ -17,6 +17,8 @@ # # $FreeBSD$ +#NO_UNIVERSE + ident HL200 include "../at91/std.hl200" diff --git a/sys/arm/conf/HL201 b/sys/arm/conf/HL201 index 200f2f86ef7f6..fb80bbed8ca92 100644 --- a/sys/arm/conf/HL201 +++ b/sys/arm/conf/HL201 @@ -17,6 +17,8 @@ # # $FreeBSD$ +#NO_UNIVERSE + ident HL201 include "../at91/std.hl201" diff --git a/sys/arm/conf/KB920X b/sys/arm/conf/KB920X index 916425ac9e044..a758a66e4e6db 100644 --- a/sys/arm/conf/KB920X +++ b/sys/arm/conf/KB920X @@ -18,6 +18,8 @@ # # $FreeBSD$ +#NO_UNIVERSE + ident KB920X include "../at91/std.kb920x" diff --git a/sys/arm/conf/NSLU b/sys/arm/conf/NSLU index a8c04d3185d3b..e54e63b725686 100644 --- a/sys/arm/conf/NSLU +++ b/sys/arm/conf/NSLU @@ -17,6 +17,8 @@ # # $FreeBSD$ +#NO_UNIVERSE + ident NSLU # XXX What is defined in std.avila does not exactly match the following: diff --git a/sys/arm/conf/QILA9G20 b/sys/arm/conf/QILA9G20 index e0055573cf4db..257e37d34f5a0 100644 --- a/sys/arm/conf/QILA9G20 +++ b/sys/arm/conf/QILA9G20 @@ -18,6 +18,8 @@ # # $FreeBSD$ +#NO_UNIVERSE + ident QILA9G20 include "../at91/std.qila9g20" diff --git a/sys/arm/conf/QUARTZ b/sys/arm/conf/QUARTZ index b6c20bb66af61..04f1b5c94749a 100644 --- a/sys/arm/conf/QUARTZ +++ b/sys/arm/conf/QUARTZ @@ -17,7 +17,9 @@ # # $FreeBSD$ -include "VYBRID.common" +#NO_UNIVERSE + +include "VYBRID" ident QUARTZ #FDT diff --git a/sys/arm/conf/SAM9260EK b/sys/arm/conf/SAM9260EK index 930429d2f800b..34b64afd234b1 100644 --- a/sys/arm/conf/SAM9260EK +++ b/sys/arm/conf/SAM9260EK @@ -17,6 +17,8 @@ # # $FreeBSD$ +#NO_UNIVERSE + ident SAM9260EK include "../at91/std.sam9260ek" diff --git a/sys/arm/conf/SAM9X25EK b/sys/arm/conf/SAM9X25EK index 63fa8158bf948..d4b6343d97776 100644 --- a/sys/arm/conf/SAM9X25EK +++ b/sys/arm/conf/SAM9X25EK @@ -17,7 +17,8 @@ # # $FreeBSD$ -# NOUNIVERSE: disable building in make universe +#NO_UNIVERSE + ident SAM9X25EK include "../at91/std.sam9x25ek" diff --git a/sys/arm/conf/SN9G45 b/sys/arm/conf/SN9G45 index e44a0cf2c856a..3eb646bbeeb44 100644 --- a/sys/arm/conf/SN9G45 +++ b/sys/arm/conf/SN9G45 @@ -17,6 +17,8 @@ # # $FreeBSD$ +#NO_UNIVERSE + ident SN9G45 include "../at91/std.sn9g45" diff --git a/sys/arm/conf/VYBRID.common b/sys/arm/conf/VYBRID index 412f65cc1e64c..43cdac5940c0d 100644 --- a/sys/arm/conf/VYBRID.common +++ b/sys/arm/conf/VYBRID @@ -17,6 +17,7 @@ # # $FreeBSD$ +ident VYBRID include "../freescale/vybrid/std.vybrid" makeoptions MODULES_OVERRIDE="" @@ -146,3 +147,5 @@ device kbdmux options SC_DFLT_FONT # compile font in makeoptions SC_DFLT_FONT=cp437 device ukbd + +options FDT diff --git a/sys/arm/conf/WANDBOARD-DUAL b/sys/arm/conf/WANDBOARD-DUAL index 168b17d9e42bc..598c91d8a8004 100644 --- a/sys/arm/conf/WANDBOARD-DUAL +++ b/sys/arm/conf/WANDBOARD-DUAL @@ -17,6 +17,8 @@ # # $FreeBSD$ +#NO_UNIVERSE + include "IMX6" ident WANDBOARD-DUAL diff --git a/sys/arm/conf/WANDBOARD-QUAD b/sys/arm/conf/WANDBOARD-QUAD index 155b36adc7f59..571f54be1ca18 100644 --- a/sys/arm/conf/WANDBOARD-QUAD +++ b/sys/arm/conf/WANDBOARD-QUAD @@ -17,6 +17,8 @@ # # $FreeBSD$ +#NO_UNIVERSE + include "IMX6" ident WANDBOARD-QUAD diff --git a/sys/arm/conf/WANDBOARD-SOLO b/sys/arm/conf/WANDBOARD-SOLO index 7465e4f619967..f6df97c9574ed 100644 --- a/sys/arm/conf/WANDBOARD-SOLO +++ b/sys/arm/conf/WANDBOARD-SOLO @@ -17,6 +17,8 @@ # # $FreeBSD$ +#NO_UNIVERSE + include "IMX6" ident WANDBOARD-SOLO diff --git a/sys/arm/conf/WANDBOARD.common b/sys/arm/conf/WANDBOARD.common deleted file mode 100644 index a147353e9b71a..0000000000000 --- a/sys/arm/conf/WANDBOARD.common +++ /dev/null @@ -1,159 +0,0 @@ -# Kernel configuration for Wandboard -# -# For more information on this file, please read the config(5) manual page, -# and/or the handbook section on Kernel Configuration Files: -# -# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html -# -# The handbook is also available locally in /usr/share/doc/handbook -# if you've installed the doc distribution, otherwise always see the -# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the -# latest information. -# -# An exhaustive list of options and more detailed explanations of the -# device lines is also present in the ../../conf/NOTES and NOTES files. -# If you are in doubt as to the purpose or necessity of a line, check first -# in NOTES. -# -# $FreeBSD$ - -include "../freescale/imx/std.imx6" - -options HZ=250 # Scheduling quantum is 4 milliseconds. -options SCHED_4BSD # 4BSD scheduler -options PREEMPTION # Enable kernel thread preemption -options INET # InterNETworking -options INET6 # IPv6 communications protocols -#options SCTP # Stream Control Transmission Protocol -options FFS # Berkeley Fast Filesystem -options SOFTUPDATES # Enable FFS soft updates support -options UFS_ACL # Support for access control lists -options UFS_DIRHASH # Improve performance on big directories -options UFS_GJOURNAL # Enable gjournal-based UFS journaling -#options MD_ROOT # MD is a potential root device -options NFSCL # New Network Filesystem Client -#options NFSD # New Network Filesystem Server -options NFSLOCKD # Network Lock Manager -options NFS_ROOT # NFS usable as /, requires NFSCL -options TMPFS # Efficient memory filesystem -options MSDOSFS # MSDOS Filesystem -options CD9660 # ISO 9660 Filesystem -#options PROCFS # Process filesystem (requires PSEUDOFS) -options PSEUDOFS # Pseudo-filesystem framework -options GEOM_PART_BSD # BSD partition scheme -options GEOM_PART_MBR # MBR partition scheme -options GEOM_PART_GPT # GUID Partition Tables. -options GEOM_LABEL # Provides labelization -options KTRACE # ktrace(1) support -options SYSVSHM # SYSV-style shared memory -options SYSVMSG # SYSV-style message queues -options SYSVSEM # SYSV-style semaphores -options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions -options INCLUDE_CONFIG_FILE # Include this file in kernel - -# Debugging support. Always need this: -options KDB # Enable kernel debugger support. -# For minimum debugger support use KDB_TRACE, for interactive use DDB. -#options KDB_TRACE # Print a stack trace for a panic. -options DDB # Support DDB. -# For full debugger support use this instead: -#options GDB # Support remote GDB. -# Other debugging options... -makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols -options ALT_BREAK_TO_DEBUGGER # Use <CR><tilde><ctrl-b> to enter debugger. -#options DEBUG -#options DEADLKRES # Enable the deadlock resolver -#options INVARIANTS # Enable calls of extra sanity checking -#options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS -#options WITNESS # Enable checks to detect deadlocks and cycles - -# Note that 'bpf' is required for DHCP. -device bpf # Berkeley packet filter - -# Pseudo devices. -device loop # Network loopback -device random # Entropy device -device vlan # 802.1Q VLAN support -device tun # Packet tunnel. -device md # Memory "disks" -#device gif # IPv6 and IPv4 tunneling -#device faith # IPv6-to-IPv4 relaying (translation) -#device firmware # firmware assist module -device ether # Ethernet support -device miibus # Required for ethernet - -# Serial (COM) ports -device uart # Multi-uart driver - -#device iomux # IO Multiplexor - -# SCSI peripherals -device scbus # SCSI bus (required for SCSI) -device da # Direct Access (disks) -device cd # CD -device pass # Passthrough device (direct SCSI access) - -# USB support -#options USB_DEBUG # enable debug msgs -options USB_HOST_ALIGN=32 # Required for ARM, set to cache line size. -device ehci # OHCI USB interface -device usb # USB Bus (required) -device umass # Disks/Mass storage - Requires scbus and da -device uhid # "Human Interface Devices" -device u3g # USB modems - -# USB Ethernet, requires miibus -#device aue # ADMtek USB Ethernet -#device axe # ASIX Electronics USB Ethernet -#device cdce # Generic USB over Ethernet -#device cue # CATC USB Ethernet -#device kue # Kawasaki LSI USB Ethernet -#device rue # RealTek RTL8150 USB Ethernet -#device udav # Davicom DM9601E USB - -# USB Wireless -#device rum # Ralink Technology RT2501USB wireless NICs - -# Watchdog timer. -# WARNING: can't be disabled!!! -#device imxwdt # Watchdog - -# Wireless NIC cards -#device wlan # 802.11 support -#device wlan_wep # 802.11 WEP support -#device wlan_ccmp # 802.11 CCMP support -#device wlan_tkip # 802.11 TKIP support -#device wlan_amrr # AMRR transmit rate control algorithm - -# NOTE: serial console will be disabled if syscons enabled -# Uncomment following lines for framebuffer/syscons support -# Wandboard has no video console support yet. -#device sc -#device kbdmux -#options SC_DFLT_FONT # compile font in -#makeoptions SC_DFLT_FONT=cp437 -#device ukbd # Allow keyboard like HIDs to control console -#device ums - -# required for netbooting -#options BOOTP -#options BOOTP_COMPAT -#options BOOTP_NFSROOT -#options BOOTP_NFSV3 -#options BOOTP_WIRED_TO=ffec0 - -# U-Boot stuff lives on slice 1, FreeBSD on slice 2. -options ROOTDEVNAME=\"ufs:mmcsd0s2a\" - -#device fsliic # Freescale i2c/iic (not ready yet) -#device iic # iic protocol -#device iicbus # iic bus - -device sdhci # SD controller -device mmc # SD/MMC protocol -device mmcsd # SDCard disk device - -device ffec # Freescale Fast Ethernet Controller - -options FREEBSD_BOOT_LOADER # Process metadata passed from loader(8) - diff --git a/sys/arm/conf/ZEDBOARD b/sys/arm/conf/ZEDBOARD index 147c7f386d14b..99a2272b75ed2 100644 --- a/sys/arm/conf/ZEDBOARD +++ b/sys/arm/conf/ZEDBOARD @@ -56,6 +56,7 @@ options SYSVSEM # SYSV-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # Posix P1003_1B real-time extensions options FREEBSD_BOOT_LOADER options VFP # vfp/neon +options SMP # Symmetric MultiProcessor Kernel # Debugging makeoptions DEBUG=-g diff --git a/sys/arm/freescale/imx/imx6_pl310.c b/sys/arm/freescale/imx/imx6_pl310.c index a4e383ea1bd6e..9e0427faf4edc 100644 --- a/sys/arm/freescale/imx/imx6_pl310.c +++ b/sys/arm/freescale/imx/imx6_pl310.c @@ -44,6 +44,19 @@ __FBSDID("$FreeBSD$"); void platform_pl310_init(struct pl310_softc *sc) { + uint32_t reg; + + /* + * Enable power saving modes: + * - Dynamic Gating stops the clock when the controller is idle. + * - Standby stops the clock when the cores are in WFI mode. + */ + reg = pl310_read4(sc, PL310_POWER_CTRL); + reg |= POWER_CTRL_ENABLE_GATING | POWER_CTRL_ENABLE_STANDBY; + pl310_write4(sc, PL310_POWER_CTRL, reg); + + pl310_set_ram_latency(sc, PL310_TAG_RAM_CTRL, 4, 2, 3); + pl310_set_ram_latency(sc, PL310_DATA_RAM_CTRL, 4, 2, 3); } void diff --git a/sys/arm/include/cpufunc.h b/sys/arm/include/cpufunc.h index 6251e2c85a696..c2a96a81507ea 100644 --- a/sys/arm/include/cpufunc.h +++ b/sys/arm/include/cpufunc.h @@ -411,7 +411,7 @@ void armv6_idcache_wbinv_range (vm_offset_t, vm_size_t); void armv7_setttb (u_int); void armv7_tlb_flushID (void); void armv7_tlb_flushID_SE (u_int); -void armv7_icache_sync_all (); +void armv7_icache_sync_all (void); void armv7_icache_sync_range (vm_offset_t, vm_size_t); void armv7_idcache_wbinv_range (vm_offset_t, vm_size_t); void armv7_idcache_inv_all (void); diff --git a/sys/arm/include/pl310.h b/sys/arm/include/pl310.h index b4200a8dada22..873087700f0d2 100644 --- a/sys/arm/include/pl310.h +++ b/sys/arm/include/pl310.h @@ -62,6 +62,14 @@ #define AUX_CTRL_DATA_PREFETCH (1 << 28) #define AUX_CTRL_INSTR_PREFETCH (1 << 29) #define AUX_CTRL_EARLY_BRESP (1 << 30) +#define PL310_TAG_RAM_CTRL 0x108 +#define PL310_DATA_RAM_CTRL 0x10C +#define RAM_CTRL_WRITE_SHIFT 8 +#define RAM_CTRL_WRITE_MASK (0x7 << 8) +#define RAM_CTRL_READ_SHIFT 4 +#define RAM_CTRL_READ_MASK (0x7 << 4) +#define RAM_CTRL_SETUP_SHIFT 0 +#define RAM_CTRL_SETUP_MASK (0x7 << 0) #define PL310_EVENT_COUNTER_CTRL 0x200 #define EVENT_COUNTER_CTRL_ENABLED (1 << 0) #define EVENT_COUNTER_CTRL_C0_RESET (1 << 1) @@ -113,6 +121,9 @@ #define PL310_ADDR_FILTER_STAR 0xC00 #define PL310_ADDR_FILTER_END 0xC04 #define PL310_DEBUG_CTRL 0xF40 +#define DEBUG_CTRL_DISABLE_LINEFILL (1 << 0) +#define DEBUG_CTRL_DISABLE_WRITEBACK (1 << 1) +#define DEBUG_CTRL_SPNIDEN (1 << 2) #define PL310_PREFETCH_CTRL 0xF60 #define PREFETCH_CTRL_OFFSET_MASK (0x1f) #define PREFETCH_CTRL_NOTSAMEID (1 << 21) @@ -123,6 +134,8 @@ #define PREFETCH_CTRL_INSTR_PREFETCH (1 << 29) #define PREFETCH_CTRL_DL (1 << 30) #define PL310_POWER_CTRL 0xF60 +#define POWER_CTRL_ENABLE_GATING (1 << 0) +#define POWER_CTRL_ENABLE_STANDBY (1 << 1) struct pl310_softc { device_t sc_dev; @@ -162,6 +175,8 @@ pl310_write4(struct pl310_softc *sc, bus_size_t off, uint32_t val) } void pl310_print_config(struct pl310_softc *sc); +void pl310_set_ram_latency(struct pl310_softc *sc, uint32_t which_reg, + uint32_t read, uint32_t write, uint32_t setup); void platform_pl310_init(struct pl310_softc *); void platform_pl310_write_ctrl(struct pl310_softc *, uint32_t); diff --git a/sys/arm/mv/armadaxp/files.armadaxp b/sys/arm/mv/armadaxp/files.armadaxp index bd0316fa97c2f..2ca0836e3a151 100644 --- a/sys/arm/mv/armadaxp/files.armadaxp +++ b/sys/arm/mv/armadaxp/files.armadaxp @@ -4,3 +4,5 @@ arm/mv/armadaxp/armadaxp.c standard arm/mv/mpic.c standard arm/mv/rtc.c standard arm/mv/armadaxp/armadaxp_mp.c optional smp +arm/mv/armadaxp/mptramp.S optional smp + diff --git a/sys/dev/lindev/lindev.h b/sys/arm/mv/armadaxp/mptramp.S index 9b0be8250a02d..4d657e41b4707 100644 --- a/sys/dev/lindev/lindev.h +++ b/sys/arm/mv/armadaxp/mptramp.S @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2009 "Bjoern A. Zeeb" <bz@FreeBSD.org> + * Copyright 2011 Semihalf * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,13 +22,35 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ -#ifndef _DEV_LINDEV_LINDEV_H -#define _DEV_LINDEV_LINDEV_H +#include <machine/asm.h> +#include <machine/armreg.h> + +__FBSDID("$FreeBSD$"); + +ASENTRY_NP(mptramp) + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 + + mrs r3, cpsr + bic r3, r3, #(PSR_MODE) + orr r3, r3, #(PSR_SVC32_MODE) + msr cpsr_fsxc, r3 + + mrc p15, 0, r0, c0, c0, 5 + and r0, #0x0f /* Get CPU ID */ + + /* Read boot address for CPU */ + mov r1, #0x100 + mul r2, r0, r1 + ldr r1, Lpmureg + add r0, r2, r1 + ldr r1, [r0], #0x00 + + mov pc, r1 -int lindev_modevent_full(module_t, int, void *); +Lpmureg: + .word 0xd0022124 +END(mptramp) -#endif /* _DEV_LINDEV_LINDEV_H */ diff --git a/sys/arm/rockchip/rk30xx_machdep.c b/sys/arm/rockchip/rk30xx_machdep.c index d8e3f3c2253b1..0cb9bca6871f3 100644 --- a/sys/arm/rockchip/rk30xx_machdep.c +++ b/sys/arm/rockchip/rk30xx_machdep.c @@ -51,14 +51,11 @@ __FBSDID("$FreeBSD$"); #include <arm/rockchip/rk30xx_wdog.h> -/* Start of address space used for bootstrap map */ -#define DEVMAP_BOOTSTRAP_MAP_START 0xF0000000 - vm_offset_t initarm_lastaddr(void) { - return (DEVMAP_BOOTSTRAP_MAP_START); + return (arm_devmap_lastaddr()); } void @@ -81,27 +78,14 @@ initarm_late_init(void) CPU_CONTROL_DC_ENABLE|CPU_CONTROL_IC_ENABLE); } -#define FDT_DEVMAP_MAX (1 + 2 + 1 + 1) -static struct arm_devmap_entry fdt_devmap[FDT_DEVMAP_MAX] = { - { 0, 0, 0, 0, 0, } -}; - /* - * Construct pmap_devmap[] with DT-derived config data. + * Set up static device mappings. */ int initarm_devmap_init(void) { - int i = 0; - - fdt_devmap[i].pd_va = 0xF0000000; - fdt_devmap[i].pd_pa = 0x20000000; - fdt_devmap[i].pd_size = 0x100000; - fdt_devmap[i].pd_prot = VM_PROT_READ | VM_PROT_WRITE; - fdt_devmap[i].pd_cache = PTE_DEVICE; - i++; - arm_devmap_register_table(&fdt_devmap[0]); + arm_devmap_add_entry(0x20000000, 0x00100000); return (0); } diff --git a/sys/arm/xilinx/files.zynq7 b/sys/arm/xilinx/files.zynq7 index 5b25dc495d0cf..0407ecb4d5d1b 100644 --- a/sys/arm/xilinx/files.zynq7 +++ b/sys/arm/xilinx/files.zynq7 @@ -21,6 +21,7 @@ arm/xilinx/zy7_l2cache.c standard arm/xilinx/zy7_bus_space.c standard arm/xilinx/zy7_slcr.c standard arm/xilinx/zy7_devcfg.c standard +arm/xilinx/zy7_mp.c optional smp dev/cadence/if_cgem.c optional if_cgem dev/sdhci/sdhci_fdt.c optional sdhci diff --git a/sys/arm/xilinx/std.zynq7 b/sys/arm/xilinx/std.zynq7 index f387703fccfbe..1cee32da2e7a8 100644 --- a/sys/arm/xilinx/std.zynq7 +++ b/sys/arm/xilinx/std.zynq7 @@ -20,3 +20,5 @@ makeoptions KERNVIRTADDR=0xc0100000 options ARM_L2_PIPT +options IPI_IRQ_START=0 +options IPI_IRQ_END=15 diff --git a/sys/arm/xilinx/zy7_devcfg.c b/sys/arm/xilinx/zy7_devcfg.c index ae96dd36671e9..a8df6c7d75d98 100644 --- a/sys/arm/xilinx/zy7_devcfg.c +++ b/sys/arm/xilinx/zy7_devcfg.c @@ -267,24 +267,35 @@ zy7_devcfg_reset_pl(struct zy7_devcfg_softc *sc) devcfg_ctl = RD4(sc, ZY7_DEVCFG_CTRL); + /* Clear sticky bits and set up INIT signal positive edge interrupt. */ + WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL); + WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_PCFG_INIT_PE); + /* Deassert PROG_B (active low). */ devcfg_ctl |= ZY7_DEVCFG_CTRL_PCFG_PROG_B; WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl); - /* Wait for INIT_B deasserted (active low). */ - tries = 0; - while ((RD4(sc, ZY7_DEVCFG_STATUS) & - ZY7_DEVCFG_STATUS_PCFG_INIT) == 0) { - if (++tries >= 100) - return (EIO); - DELAY(5); + /* + * Wait for INIT to assert. If it is already asserted, we may not get + * an edge interrupt so cancel it and continue. + */ + if ((RD4(sc, ZY7_DEVCFG_STATUS) & + ZY7_DEVCFG_STATUS_PCFG_INIT) != 0) { + /* Already asserted. Cancel interrupt. */ + WR4(sc, ZY7_DEVCFG_INT_MASK, ~0); } - - /* Reassert PROG_B. */ + else { + /* Wait for positive edge interrupt. */ + err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7i1", hz); + if (err != 0) + return (err); + } + + /* Reassert PROG_B (active low). */ devcfg_ctl &= ~ZY7_DEVCFG_CTRL_PCFG_PROG_B; WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl); - /* Wait for INIT_B asserted. */ + /* Wait for INIT deasserted. This happens almost instantly. */ tries = 0; while ((RD4(sc, ZY7_DEVCFG_STATUS) & ZY7_DEVCFG_STATUS_PCFG_INIT) != 0) { @@ -293,7 +304,7 @@ zy7_devcfg_reset_pl(struct zy7_devcfg_softc *sc) DELAY(5); } - /* Clear sticky bits and set up INIT_B positive edge interrupt. */ + /* Clear sticky bits and set up INIT positive edge interrupt. */ WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL); WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_PCFG_INIT_PE); @@ -301,11 +312,11 @@ zy7_devcfg_reset_pl(struct zy7_devcfg_softc *sc) devcfg_ctl |= ZY7_DEVCFG_CTRL_PCFG_PROG_B; WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl); - /* Wait for INIT_B deasserted indicating FPGA internal initialization - * is complete. This takes much longer than the previous waits for - * INIT_B transition (on the order of 700us). + /* + * Wait for INIT asserted indicating FPGA internal initialization + * is complete. */ - err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7in", hz); + err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7i2", hz); if (err != 0) return (err); @@ -404,7 +415,9 @@ zy7_devcfg_write(struct cdev *dev, struct uio *uio, int ioflag) /* uiomove the data from user buffer to our dma map. */ segsz = MIN(PAGE_SIZE, uio->uio_resid); + DEVCFG_SC_UNLOCK(sc); err = uiomove(dma_mem, segsz, uio); + DEVCFG_SC_LOCK(sc); if (err != 0) break; diff --git a/sys/arm/xilinx/zy7_machdep.c b/sys/arm/xilinx/zy7_machdep.c index 8461fca906bb9..e7ffaa49ca757 100644 --- a/sys/arm/xilinx/zy7_machdep.c +++ b/sys/arm/xilinx/zy7_machdep.c @@ -60,7 +60,7 @@ vm_offset_t initarm_lastaddr(void) { - return (ZYNQ7_PSIO_VBASE); + return (arm_devmap_lastaddr()); } void @@ -79,39 +79,18 @@ initarm_late_init(void) { } -#define FDT_DEVMAP_SIZE 3 -static struct arm_devmap_entry fdt_devmap[FDT_DEVMAP_SIZE]; - /* - * Construct pmap_devmap[] with DT-derived config data. + * Set up static device mappings. Not strictly necessary -- simplebus will + * dynamically establish mappings as needed -- but doing it this way gets us + * nice efficient 1MB section mappings. */ int initarm_devmap_init(void) { - int i = 0; - - fdt_devmap[i].pd_va = ZYNQ7_PSIO_VBASE; - fdt_devmap[i].pd_pa = ZYNQ7_PSIO_HWBASE; - fdt_devmap[i].pd_size = ZYNQ7_PSIO_SIZE; - fdt_devmap[i].pd_prot = VM_PROT_READ | VM_PROT_WRITE; - fdt_devmap[i].pd_cache = PTE_DEVICE; - i++; - - fdt_devmap[i].pd_va = ZYNQ7_PSCTL_VBASE; - fdt_devmap[i].pd_pa = ZYNQ7_PSCTL_HWBASE; - fdt_devmap[i].pd_size = ZYNQ7_PSCTL_SIZE; - fdt_devmap[i].pd_prot = VM_PROT_READ | VM_PROT_WRITE; - fdt_devmap[i].pd_cache = PTE_DEVICE; - i++; - - /* end of table */ - fdt_devmap[i].pd_va = 0; - fdt_devmap[i].pd_pa = 0; - fdt_devmap[i].pd_size = 0; - fdt_devmap[i].pd_prot = 0; - fdt_devmap[i].pd_cache = 0; - - arm_devmap_register_table(&fdt_devmap[0]); + + arm_devmap_add_entry(ZYNQ7_PSIO_HWBASE, ZYNQ7_PSIO_SIZE); + arm_devmap_add_entry(ZYNQ7_PSCTL_HWBASE, ZYNQ7_PSCTL_SIZE); + return (0); } diff --git a/sys/arm/xilinx/zy7_mp.c b/sys/arm/xilinx/zy7_mp.c new file mode 100644 index 0000000000000..831c4df273c66 --- /dev/null +++ b/sys/arm/xilinx/zy7_mp.c @@ -0,0 +1,99 @@ +/*- + * Copyright (c) 2013 Thomas Skibo. 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 ``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/bus.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/smp.h> + +#include <machine/smp.h> +#include <machine/fdt.h> +#include <machine/intr.h> + +#include <arm/xilinx/zy7_reg.h> + +#define ZYNQ7_CPU1_ENTRY 0xfffffff0 + +void +platform_mp_init_secondary(void) +{ + + gic_init_secondary(); +} + +void +platform_mp_setmaxid(void) +{ + + mp_maxid = 1; +} + +int +platform_mp_probe(void) +{ + + mp_ncpus = 2; + return (1); +} + +void +platform_mp_start_ap(void) +{ + bus_space_handle_t ocm_handle; + + /* Map in magic location to give entry address to CPU1. */ + if (bus_space_map(fdtbus_bs_tag, ZYNQ7_CPU1_ENTRY, 4, + 0, &ocm_handle) != 0) + panic("platform_mp_start_ap: Couldn't map OCM\n"); + + /* Write start address for CPU1. */ + bus_space_write_4(fdtbus_bs_tag, ocm_handle, 0, + pmap_kextract((vm_offset_t)mpentry)); + + /* + * The SCU is enabled by the BOOTROM but I think the second CPU doesn't + * turn on filtering until after the wake-up below. I think that's why + * things don't work if I don't put these cache ops here. Also, the + * magic location, 0xfffffff0, isn't in the SCU's filtering range so it + * needs a write-back too. + */ + cpu_idcache_wbinv_all(); + cpu_l2cache_wbinv_all(); + + /* Wake up CPU1. */ + armv7_sev(); + + bus_space_unmap(fdtbus_bs_tag, ocm_handle, 4); +} + +void +platform_ipi_send(cpuset_t cpus, u_int ipi) +{ + + pic_ipi_send(cpus, ipi); +} diff --git a/sys/arm/xilinx/zy7_reg.h b/sys/arm/xilinx/zy7_reg.h index c1aac9445cb45..2f55ffedaacad 100644 --- a/sys/arm/xilinx/zy7_reg.h +++ b/sys/arm/xilinx/zy7_reg.h @@ -44,16 +44,13 @@ #define ZYNQ7_PLGP1_SIZE 0x40000000 /* I/O Peripheral registers. */ -#define ZYNQ7_PSIO_VBASE 0xE0000000 #define ZYNQ7_PSIO_HWBASE 0xE0000000 #define ZYNQ7_PSIO_SIZE 0x00300000 /* UART0 and UART1 */ -#define ZYNQ7_UART0_VBASE (ZYNQ7_PSIO_VBASE) #define ZYNQ7_UART0_HWBASE (ZYNQ7_PSIO_HWBASE) #define ZYNQ7_UART0_SIZE 0x1000 -#define ZYNQ7_UART1_VBASE (ZYNQ7_PSIO_VBASE+0x1000) #define ZYNQ7_UART1_HWBASE (ZYNQ7_PSIO_HWBASE+0x1000) #define ZYNQ7_UART1_SIZE 0x1000 @@ -63,15 +60,12 @@ #define ZYNQ7_SMC_SIZE 0x05000000 /* SLCR, PS system, and CPU private registers combined in this region. */ -#define ZYNQ7_PSCTL_VBASE 0xF8000000 #define ZYNQ7_PSCTL_HWBASE 0xF8000000 #define ZYNQ7_PSCTL_SIZE 0x01000000 -#define ZYNQ7_SLCR_VBASE (ZYNQ7_PSCTL_VBASE) #define ZYNQ7_SLCR_HWBASE (ZYNQ7_PSCTL_HWBASE) #define ZYNQ7_SLCR_SIZE 0x1000 -#define ZYNQ7_DEVCFG_VBASE (ZYNQ7_PSCTL_VBASE+0x7000) #define ZYNQ7_DEVCFG_HWBASE (ZYNQ7_PSCTL_HWBASE+0x7000) #define ZYNQ7_DEVCFG_SIZE 0x1000 diff --git a/sys/boot/Makefile b/sys/boot/Makefile index 0d6441d77bd87..2984bd5c89cfa 100644 --- a/sys/boot/Makefile +++ b/sys/boot/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .include <bsd.arch.inc.mk> .if ${MK_FORTH} != "no" diff --git a/sys/boot/amd64/Makefile.inc b/sys/boot/amd64/Makefile.inc index 1bc7ad8f1c3bd..ee96a42abd824 100644 --- a/sys/boot/amd64/Makefile.inc +++ b/sys/boot/amd64/Makefile.inc @@ -4,8 +4,9 @@ BINDIR?= /boot +# See conf/kern.mk for the correct set of these CFLAGS+= -ffreestanding -CFLAGS+= -mno-mmx -mno-3dnow -mno-sse -mno-sse2 -mno-sse3 -msoft-float +CFLAGS+= -mno-mmx -mno-sse -mno-aes -mno-avx -msoft-float LDFLAGS+= -nostdlib .include "../Makefile.inc" diff --git a/sys/boot/amd64/efi/Makefile b/sys/boot/amd64/efi/Makefile index f4138c9370524..a9a213227d0ef 100644 --- a/sys/boot/amd64/efi/Makefile +++ b/sys/boot/amd64/efi/Makefile @@ -2,7 +2,7 @@ MAN= -.include <bsd.own.mk> +.include <src.opts.mk> # In-tree GCC does not support __attribute__((ms_abi)). .if ${COMPILER_TYPE} != "gcc" diff --git a/sys/boot/arm/at91/bootspi/Makefile b/sys/boot/arm/at91/bootspi/Makefile index 04c4fbb515925..a02d447b48a36 100644 --- a/sys/boot/arm/at91/bootspi/Makefile +++ b/sys/boot/arm/at91/bootspi/Makefile @@ -1,5 +1,7 @@ # $FreeBSD$ +.include <src.opts.mk> + .PATH: ${.CURDIR}/../libat91 P=bootspi diff --git a/sys/boot/arm/at91/libat91/Makefile b/sys/boot/arm/at91/libat91/Makefile index 7ab9a1f3bb474..b02281dc640da 100644 --- a/sys/boot/arm/at91/libat91/Makefile +++ b/sys/boot/arm/at91/libat91/Makefile @@ -1,5 +1,6 @@ # $FreeBSD$ +.include <src.opts.mk> .include "${.CURDIR}/../Makefile.inc" SOC?=at91rm9200 diff --git a/sys/boot/arm/ixp425/boot2/Makefile b/sys/boot/arm/ixp425/boot2/Makefile index 14e87d1cea635..6fe515e0cfcbe 100644 --- a/sys/boot/arm/ixp425/boot2/Makefile +++ b/sys/boot/arm/ixp425/boot2/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> # We get a lot of the std lib functions from here. .PATH: ${.CURDIR}/../../at91/libat91 diff --git a/sys/boot/arm/uboot/Makefile b/sys/boot/arm/uboot/Makefile index 3402e02e2ed4f..a24eeac45a2f3 100644 --- a/sys/boot/arm/uboot/Makefile +++ b/sys/boot/arm/uboot/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ubldr NEWVERSWHAT= "U-Boot loader" ${MACHINE_ARCH} diff --git a/sys/boot/fdt/dts/arm/exynos5250.dtsi b/sys/boot/fdt/dts/arm/exynos5250.dtsi index 55246eabc2f74..3d2e6bcd2e7c5 100644 --- a/sys/boot/fdt/dts/arm/exynos5250.dtsi +++ b/sys/boot/fdt/dts/arm/exynos5250.dtsi @@ -126,7 +126,7 @@ reg = <0x12200000 0x1000>; interrupts = <107>; interrupt-parent = <&GIC>; - clock-frequency = <24000000>; /* TODO: verify freq */ + max-frequency = <24000000>; /* TODO: verify freq */ }; sdhci@12210000 { @@ -134,7 +134,7 @@ reg = <0x12210000 0x1000>; interrupts = <108>; interrupt-parent = <&GIC>; - clock-frequency = <24000000>; + max-frequency = <24000000>; }; sdhci@12220000 { @@ -142,7 +142,7 @@ reg = <0x12220000 0x1000>; interrupts = <109>; interrupt-parent = <&GIC>; - clock-frequency = <24000000>; + max-frequency = <24000000>; }; sdhci@12230000 { @@ -150,7 +150,7 @@ reg = <0x12230000 0x1000>; interrupts = <110>; interrupt-parent = <&GIC>; - clock-frequency = <24000000>; + max-frequency = <24000000>; }; serial0: serial@12C00000 { diff --git a/sys/boot/fdt/dts/arm/rk3188.dtsi b/sys/boot/fdt/dts/arm/rk3188.dtsi index 03e38c07cac1c..c6ac38561a1f5 100644 --- a/sys/boot/fdt/dts/arm/rk3188.dtsi +++ b/sys/boot/fdt/dts/arm/rk3188.dtsi @@ -31,6 +31,8 @@ #address-cells = <1>; #size-cells = <1>; + interrupt-parent = <&GIC>; + aliases { soc = &SOC; }; diff --git a/sys/boot/fdt/dts/arm/zedboard.dts b/sys/boot/fdt/dts/arm/zedboard.dts index a95a2f7769d1f..2d9fccdeac2a1 100644 --- a/sys/boot/fdt/dts/arm/zedboard.dts +++ b/sys/boot/fdt/dts/arm/zedboard.dts @@ -183,7 +183,7 @@ reg = <0x100000 0x1000>; interrupts = <56>; interrupt-parent = <&GIC>; - clock-frequency = <50000000>; + max-frequency = <50000000>; }; // QSPI diff --git a/sys/boot/forth/loader.conf b/sys/boot/forth/loader.conf index 641f95b2f9067..3f31b7a8ebec0 100644 --- a/sys/boot/forth/loader.conf +++ b/sys/boot/forth/loader.conf @@ -241,7 +241,6 @@ screensave_name="green_saver" # Set to the name of the screensaver module ibcs2_load="NO" # IBCS2 (SCO) emulation ibcs2_coff_load="NO" linux_load="NO" # Linux emulation -lindev_load="NO" # Linux-specific pseudo devices (see lindev(4)) svr4_load="NO" # SystemV R4 emulation streams_load="NO" # System V streams module diff --git a/sys/boot/i386/Makefile b/sys/boot/i386/Makefile index 3c05759fcf092..5ebd557647875 100644 --- a/sys/boot/i386/Makefile +++ b/sys/boot/i386/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= mbr pmbr boot0 boot0sio btx boot2 cdboot gptboot kgzldr \ libi386 libfirewire loader diff --git a/sys/boot/i386/boot2/Makefile b/sys/boot/i386/boot2/Makefile index 1391ac47a9752..fa8c29d33a883 100644 --- a/sys/boot/i386/boot2/Makefile +++ b/sys/boot/i386/boot2/Makefile @@ -38,13 +38,14 @@ CFLAGS= -Os \ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ -Winline \ - ${CLANG_OPT_SMALL} CFLAGS.gcc+= -fno-guess-branch-probability \ -fno-unit-at-a-time \ -mno-align-long-strings \ --param max-inline-insns-single=100 +CFLAGS.clang+=${CLANG_OPT_SMALL} + LD_FLAGS=-static -N --gc-sections # Pick up ../Makefile.inc early. diff --git a/sys/boot/i386/loader/Makefile b/sys/boot/i386/loader/Makefile index b98a725ab1e85..b33101283b494 100644 --- a/sys/boot/i386/loader/Makefile +++ b/sys/boot/i386/loader/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> MK_SSP= no LOADER?= loader diff --git a/sys/boot/ia64/common/Makefile b/sys/boot/ia64/common/Makefile index 5740070594e6b..ef2737f4cd2fe 100644 --- a/sys/boot/ia64/common/Makefile +++ b/sys/boot/ia64/common/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> MK_SSP= no LIB= ia64 diff --git a/sys/boot/ia64/efi/Makefile b/sys/boot/ia64/efi/Makefile index 6bb53b587123d..fc11d6e8d6570 100644 --- a/sys/boot/ia64/efi/Makefile +++ b/sys/boot/ia64/efi/Makefile @@ -2,7 +2,7 @@ MAN= -.include <bsd.own.mk> +.include <src.opts.mk> MK_SSP= no PROG= loader.sym diff --git a/sys/boot/ia64/ski/Makefile b/sys/boot/ia64/ski/Makefile index 31af84e3450fe..06201265f9017 100644 --- a/sys/boot/ia64/ski/Makefile +++ b/sys/boot/ia64/ski/Makefile @@ -2,7 +2,7 @@ MAN= -.include <bsd.own.mk> +.include <src.opts.mk> MK_SSP= no PROG= skiload diff --git a/sys/boot/libstand32/Makefile b/sys/boot/libstand32/Makefile index fd60d60f2f1b2..56f7d153678e5 100644 --- a/sys/boot/libstand32/Makefile +++ b/sys/boot/libstand32/Makefile @@ -8,7 +8,7 @@ MAN= -.include <bsd.own.mk> +.include <src.opts.mk> MK_SSP= no S= ${.CURDIR}/../../../lib/libstand diff --git a/sys/boot/mips/beri/loader/Makefile b/sys/boot/mips/beri/loader/Makefile index 93360018cedb5..fed224712ccdb 100644 --- a/sys/boot/mips/beri/loader/Makefile +++ b/sys/boot/mips/beri/loader/Makefile @@ -29,7 +29,7 @@ # # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> MK_SSP= no PROG?= loader diff --git a/sys/boot/pc98/loader/Makefile b/sys/boot/pc98/loader/Makefile index 489eeac1542e0..7ab13a189dd3c 100644 --- a/sys/boot/pc98/loader/Makefile +++ b/sys/boot/pc98/loader/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> MK_SSP= no LOADER?= loader diff --git a/sys/boot/powerpc/ofw/Makefile b/sys/boot/powerpc/ofw/Makefile index ae4a443986eab..bf4ea8ab16519 100644 --- a/sys/boot/powerpc/ofw/Makefile +++ b/sys/boot/powerpc/ofw/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> MK_SSP= no PROG= loader diff --git a/sys/boot/powerpc/ps3/Makefile b/sys/boot/powerpc/ps3/Makefile index 87aa6ed565e73..5742a86bd5006 100644 --- a/sys/boot/powerpc/ps3/Makefile +++ b/sys/boot/powerpc/ps3/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> MK_SSP= no PROG= loader.ps3 diff --git a/sys/boot/powerpc/uboot/Makefile b/sys/boot/powerpc/uboot/Makefile index c4180cbf25792..4239e47b4c3e7 100644 --- a/sys/boot/powerpc/uboot/Makefile +++ b/sys/boot/powerpc/uboot/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ubldr NEWVERSWHAT= "U-Boot loader" ${MACHINE_ARCH} diff --git a/sys/boot/sparc64/loader/Makefile b/sys/boot/sparc64/loader/Makefile index 4624b6f7b4485..d7266ad087814 100644 --- a/sys/boot/sparc64/loader/Makefile +++ b/sys/boot/sparc64/loader/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> MK_SSP= no PROG?= loader diff --git a/sys/boot/uboot/lib/Makefile b/sys/boot/uboot/lib/Makefile index e5ed3ceea56d5..4c9e5919a3e9f 100644 --- a/sys/boot/uboot/lib/Makefile +++ b/sys/boot/uboot/lib/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../common diff --git a/sys/boot/userboot/userboot/Makefile b/sys/boot/userboot/userboot/Makefile index cc528b35a738c..5623e72c2eda8 100644 --- a/sys/boot/userboot/userboot/Makefile +++ b/sys/boot/userboot/userboot/Makefile @@ -2,7 +2,7 @@ MAN= -.include <bsd.own.mk> +.include <src.opts.mk> MK_SSP= no SHLIB_NAME= userboot.so diff --git a/sys/boot/userboot/userboot/conf.c b/sys/boot/userboot/userboot/conf.c index 5eac87da98691..6727a223e327b 100644 --- a/sys/boot/userboot/userboot/conf.c +++ b/sys/boot/userboot/userboot/conf.c @@ -97,8 +97,10 @@ struct file_format *file_formats[] = { * data structures from bootstrap.h as well. */ extern struct console userboot_console; +extern struct console userboot_comconsole; struct console *consoles[] = { &userboot_console, + &userboot_comconsole, NULL }; diff --git a/sys/boot/userboot/userboot/userboot_cons.c b/sys/boot/userboot/userboot/userboot_cons.c index 5ecb7c8b2ec1e..6f73ad5633bb7 100644 --- a/sys/boot/userboot/userboot/userboot_cons.c +++ b/sys/boot/userboot/userboot/userboot_cons.c @@ -33,8 +33,12 @@ __FBSDID("$FreeBSD$"); int console; +static struct console *userboot_comconsp; + static void userboot_cons_probe(struct console *cp); static int userboot_cons_init(int); +static void userboot_comcons_probe(struct console *cp); +static int userboot_comcons_init(int); static void userboot_cons_putchar(int); static int userboot_cons_getchar(void); static int userboot_cons_poll(void); @@ -50,6 +54,21 @@ struct console userboot_console = { userboot_cons_poll, }; +/* + * Provide a simple alias to allow loader scripts to set the + * console to comconsole without resulting in an error + */ +struct console userboot_comconsole = { + "comconsole", + "comconsole", + 0, + userboot_comcons_probe, + userboot_comcons_init, + userboot_cons_putchar, + userboot_cons_getchar, + userboot_cons_poll, +}; + static void userboot_cons_probe(struct console *cp) { @@ -65,6 +84,31 @@ userboot_cons_init(int arg) } static void +userboot_comcons_probe(struct console *cp) +{ + + /* + * Save the console pointer so the comcons_init routine + * can set the C_PRESENT* flags. They are not set + * here to allow the existing userboot console to + * be elected the default. + */ + userboot_comconsp = cp; +} + +static int +userboot_comcons_init(int arg) +{ + + /* + * Set the C_PRESENT* flags to allow the comconsole + * to be selected as the active console + */ + userboot_comconsp->c_flags |= (C_PRESENTIN | C_PRESENTOUT); + return (0); +} + +static void userboot_cons_putchar(int c) { diff --git a/sys/cam/ctl/ctl_io.h b/sys/cam/ctl/ctl_io.h index e423bb065ba6d..e018b3f8a5f6d 100644 --- a/sys/cam/ctl/ctl_io.h +++ b/sys/cam/ctl/ctl_io.h @@ -293,21 +293,60 @@ union ctl_io; */ struct ctl_scsiio { struct ctl_io_hdr io_hdr; /* common to all I/O types */ + + /* + * The ext_* fields are generally intended for frontend use; CTL itself + * doesn't modify or use them. + */ uint32_t ext_sg_entries; /* 0 = no S/G list, > 0 = num entries */ uint8_t *ext_data_ptr; /* data buffer or S/G list */ uint32_t ext_data_len; /* Data transfer length */ uint32_t ext_data_filled; /* Amount of data filled so far */ - uint32_t kern_sg_entries; /* 0 = no S/G list, > 0 = num entries */ - uint32_t rem_sg_entries; /* 0 = no S/G list, > 0 = num entries */ - uint8_t *kern_data_ptr; /* data buffer or S/G list */ - uint32_t kern_data_len; /* Length of this S/G list/buffer */ - uint32_t kern_total_len; /* Total length of this transaction */ - uint32_t kern_data_resid; /* Length left to transfer after this*/ - uint32_t kern_rel_offset; /* Byte Offset of this transfer */ + + /* + * The number of scatter/gather entries in the list pointed to + * by kern_data_ptr. 0 means there is no list, just a data pointer. + */ + uint32_t kern_sg_entries; + + uint32_t rem_sg_entries; /* Unused. */ + + /* + * The data pointer or a pointer to the scatter/gather list. + */ + uint8_t *kern_data_ptr; + + /* + * Length of the data buffer or scatter/gather list. It's also + * the length of this particular piece of the data transfer, + * ie. number of bytes expected to be transferred by the current + * invocation of frontend's datamove() callback. It's always + * less than or equal to kern_total_len. + */ + uint32_t kern_data_len; + + /* + * Total length of data to be transferred during this particular + * SCSI command, as decoded from SCSI CDB. + */ + uint32_t kern_total_len; + + /* + * Amount of data left after the current data transfer. + */ + uint32_t kern_data_resid; + + /* + * Byte offset of this transfer, equal to the amount of data + * already transferred for this SCSI command during previous + * datamove() invocations. + */ + uint32_t kern_rel_offset; + struct scsi_sense_data sense_data; /* sense data */ uint8_t sense_len; /* Returned sense length */ uint8_t scsi_status; /* SCSI status byte */ - uint8_t sense_residual; /* sense residual length */ + uint8_t sense_residual; /* Unused. */ uint32_t residual; /* data residual length */ uint32_t tag_num; /* tag number */ ctl_tag_type tag_type; /* simple, ordered, head of queue,etc.*/ diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index 2faa8ddcb4e44..de2035323b349 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -90,7 +90,8 @@ typedef enum { DA_FLAG_SCTX_INIT = 0x200, DA_FLAG_CAN_RC16 = 0x400, DA_FLAG_PROBED = 0x800, - DA_FLAG_DIRTY = 0x1000 + DA_FLAG_DIRTY = 0x1000, + DA_FLAG_ANNOUNCED = 0x2000 } da_flags; typedef enum { @@ -211,6 +212,7 @@ struct da_softc { int trim_max_ranges; int delete_running; int delete_available; /* Delete methods possibly available */ + u_int maxio; uint32_t unmap_max_ranges; uint32_t unmap_max_lba; /* Max LBAs in UNMAP req */ uint64_t ws_max_blks; @@ -1658,10 +1660,18 @@ daasync(void *callback_arg, u_int32_t code, &error_code, &sense_key, &asc, &ascq)) { if (asc == 0x2A && ascq == 0x09) { xpt_print(ccb->ccb_h.path, - "capacity data has changed\n"); + "Capacity data has changed\n"); + softc->flags &= ~DA_FLAG_PROBED; dareprobe(periph); - } else if (asc == 0x28 && ascq == 0x00) + } else if (asc == 0x28 && ascq == 0x00) { + softc->flags &= ~DA_FLAG_PROBED; disk_media_changed(softc->disk, M_NOWAIT); + } else if (asc == 0x3F && ascq == 0x03) { + xpt_print(ccb->ccb_h.path, + "INQUIRY data has changed\n"); + softc->flags &= ~DA_FLAG_PROBED; + dareprobe(periph); + } } cam_periph_async(periph, code, path, arg); break; @@ -1891,7 +1901,7 @@ daprobedone(struct cam_periph *periph, union ccb *ccb) dadeletemethodchoose(softc, DA_DELETE_NONE); - if (bootverbose && (softc->flags & DA_FLAG_PROBED) == 0) { + if (bootverbose && (softc->flags & DA_FLAG_ANNOUNCED) == 0) { char buf[80]; int i, sep; @@ -1932,10 +1942,11 @@ daprobedone(struct cam_periph *periph, union ccb *ccb) */ xpt_release_ccb(ccb); softc->state = DA_STATE_NORMAL; + softc->flags |= DA_FLAG_PROBED; daschedule(periph); wakeup(&softc->disk->d_mediasize); - if ((softc->flags & DA_FLAG_PROBED) == 0) { - softc->flags |= DA_FLAG_PROBED; + if ((softc->flags & DA_FLAG_ANNOUNCED) == 0) { + softc->flags |= DA_FLAG_ANNOUNCED; cam_periph_unhold(periph); } else cam_periph_release_locked(periph); @@ -2125,11 +2136,12 @@ daregister(struct cam_periph *periph, void *arg) softc->disk->d_name = "da"; softc->disk->d_drv1 = periph; if (cpi.maxio == 0) - softc->disk->d_maxsize = DFLTPHYS; /* traditional default */ + softc->maxio = DFLTPHYS; /* traditional default */ else if (cpi.maxio > MAXPHYS) - softc->disk->d_maxsize = MAXPHYS; /* for safety */ + softc->maxio = MAXPHYS; /* for safety */ else - softc->disk->d_maxsize = cpi.maxio; + softc->maxio = cpi.maxio; + softc->disk->d_maxsize = softc->maxio; softc->disk->d_unit = periph->unit_number; softc->disk->d_flags = DISKFLAG_DIRECT_COMPLETION; if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0) @@ -3190,7 +3202,8 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) } } free(csio->data_ptr, M_SCSIDA); - if (announce_buf[0] != '\0' && ((softc->flags & DA_FLAG_PROBED) == 0)) { + if (announce_buf[0] != '\0' && + ((softc->flags & DA_FLAG_ANNOUNCED) == 0)) { /* * Create our sysctl variables, now that we know * we have successfully attached. @@ -3208,6 +3221,12 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) } } + /* We already probed the device. */ + if (softc->flags & DA_FLAG_PROBED) { + daprobedone(periph, done_ccb); + return; + } + /* Ensure re-probe doesn't see old delete. */ softc->delete_available = 0; if (lbp && (softc->quirks & DA_Q_NO_UNMAP) == 0) { @@ -3259,14 +3278,6 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) (lbp->flags & SVPD_LBP_WS10)); dadeleteflag(softc, DA_DELETE_UNMAP, (lbp->flags & SVPD_LBP_UNMAP)); - - if (lbp->flags & SVPD_LBP_UNMAP) { - free(lbp, M_SCSIDA); - xpt_release_ccb(done_ccb); - softc->state = DA_STATE_PROBE_BLK_LIMITS; - xpt_schedule(periph, priority); - return; - } } else { int error; error = daerror(done_ccb, CAM_RETRY_SELTO, @@ -3292,7 +3303,7 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) free(lbp, M_SCSIDA); xpt_release_ccb(done_ccb); - softc->state = DA_STATE_PROBE_BDC; + softc->state = DA_STATE_PROBE_BLK_LIMITS; xpt_schedule(periph, priority); return; } @@ -3303,12 +3314,20 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) block_limits = (struct scsi_vpd_block_limits *)csio->data_ptr; if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { + uint32_t max_txfer_len = scsi_4btoul( + block_limits->max_txfer_len); uint32_t max_unmap_lba_cnt = scsi_4btoul( block_limits->max_unmap_lba_cnt); uint32_t max_unmap_blk_cnt = scsi_4btoul( block_limits->max_unmap_blk_cnt); uint64_t ws_max_blks = scsi_8btou64( block_limits->max_write_same_length); + + if (max_txfer_len != 0) { + softc->disk->d_maxsize = MIN(softc->maxio, + (off_t)max_txfer_len * softc->params.secsize); + } + /* * We should already support UNMAP but we check lba * and block count to be sure @@ -3546,13 +3565,21 @@ daerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) */ else if (sense_key == SSD_KEY_UNIT_ATTENTION && asc == 0x2A && ascq == 0x09) { - xpt_print(periph->path, "capacity data has changed\n"); + xpt_print(periph->path, "Capacity data has changed\n"); + softc->flags &= ~DA_FLAG_PROBED; dareprobe(periph); sense_flags |= SF_NO_PRINT; } else if (sense_key == SSD_KEY_UNIT_ATTENTION && - asc == 0x28 && ascq == 0x00) + asc == 0x28 && ascq == 0x00) { + softc->flags &= ~DA_FLAG_PROBED; disk_media_changed(softc->disk, M_NOWAIT); - else if (sense_key == SSD_KEY_NOT_READY && + } else if (sense_key == SSD_KEY_UNIT_ATTENTION && + asc == 0x3F && ascq == 0x03) { + xpt_print(periph->path, "INQUIRY data has changed\n"); + softc->flags &= ~DA_FLAG_PROBED; + dareprobe(periph); + sense_flags |= SF_NO_PRINT; + } else if (sense_key == SSD_KEY_NOT_READY && asc == 0x3a && (softc->flags & DA_FLAG_PACK_INVALID) == 0) { softc->flags |= DA_FLAG_PACK_INVALID; disk_media_gone(softc->disk, M_NOWAIT); diff --git a/sys/cddl/compat/opensolaris/sys/dkio.h b/sys/cddl/compat/opensolaris/sys/dkio.h index 50cafabb1e115..a365c335c4216 100644 --- a/sys/cddl/compat/opensolaris/sys/dkio.h +++ b/sys/cddl/compat/opensolaris/sys/dkio.h @@ -75,8 +75,6 @@ extern "C" { */ #define DKIOCFLUSHWRITECACHE (DKIOC|34) /* flush cache to phys medium */ -#define DKIOCTRIM (DKIOC|35) /* TRIM a block */ - struct dk_callback { void (*dkc_callback)(void *dkc_cookie, int error); void *dkc_cookie; diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/metaslab.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/metaslab.c index 58aca2ca555fd..407c6eaf429f5 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/metaslab.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/metaslab.c @@ -411,7 +411,7 @@ metaslab_group_create(metaslab_class_t *mc, vdev_t *vd) mg->mg_class = mc; mg->mg_activation_count = 0; - mg->mg_taskq = taskq_create("metaslab_group_tasksq", metaslab_load_pct, + mg->mg_taskq = taskq_create("metaslab_group_taskq", metaslab_load_pct, minclsyspri, 10, INT_MAX, TASKQ_THREADS_CPU_PCT); return (mg); @@ -429,6 +429,7 @@ metaslab_group_destroy(metaslab_group_t *mg) */ ASSERT(mg->mg_activation_count <= 0); + taskq_destroy(mg->mg_taskq); avl_destroy(&mg->mg_metaslab_tree); mutex_destroy(&mg->mg_lock); kmem_free(mg, sizeof (metaslab_group_t)); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h index 41960b51e8baa..84187a843b17c 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h @@ -135,9 +135,10 @@ typedef enum zio_priority { ZIO_PRIORITY_ASYNC_READ, /* prefetch */ ZIO_PRIORITY_ASYNC_WRITE, /* spa_sync() */ ZIO_PRIORITY_SCRUB, /* asynchronous scrub/resilver reads */ + ZIO_PRIORITY_TRIM, /* free requests used for TRIM */ ZIO_PRIORITY_NUM_QUEUEABLE, - ZIO_PRIORITY_NOW /* non-queued i/os (e.g. free) */ + ZIO_PRIORITY_NOW /* non-queued I/Os (e.g. ioctl) */ } zio_priority_t; #define ZIO_PIPELINE_CONTINUE 0x100 @@ -195,6 +196,7 @@ enum zio_flag { ZIO_FLAG_NOPWRITE = 1 << 25, ZIO_FLAG_REEXECUTED = 1 << 26, ZIO_FLAG_DELEGATED = 1 << 27, + ZIO_FLAG_QUEUE_IO_DONE = 1 << 28, }; #define ZIO_FLAG_MUSTSUCCEED 0 @@ -349,7 +351,7 @@ typedef struct zio_transform { struct zio_transform *zt_next; } zio_transform_t; -typedef int zio_pipe_stage_t(zio_t *zio); +typedef int zio_pipe_stage_t(zio_t **ziop); /* * The io_reexecute flags are distinct from io_flags because the child must @@ -508,7 +510,7 @@ extern zio_t *zio_claim(zio_t *pio, spa_t *spa, uint64_t txg, extern zio_t *zio_ioctl(zio_t *pio, spa_t *spa, vdev_t *vd, int cmd, uint64_t offset, uint64_t size, zio_done_func_t *done, void *priv, - enum zio_flag flags); + zio_priority_t priority, enum zio_flag flags); extern zio_t *zio_read_phys(zio_t *pio, vdev_t *vd, uint64_t offset, uint64_t size, void *data, int checksum, diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio_impl.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio_impl.h index ad212b74e52a9..33b8edb51a81d 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio_impl.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio_impl.h @@ -215,6 +215,10 @@ enum zio_stage { ZIO_STAGE_FREE_BP_INIT | \ ZIO_STAGE_DVA_FREE) +#define ZIO_FREE_PHYS_PIPELINE \ + (ZIO_INTERLOCK_STAGES | \ + ZIO_VDEV_IO_STAGES) + #define ZIO_DDT_FREE_PIPELINE \ (ZIO_INTERLOCK_STAGES | \ ZIO_STAGE_FREE_BP_INIT | \ diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/trim_map.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/trim_map.c index fd7394a931a26..7e981993ca468 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/trim_map.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/trim_map.c @@ -449,7 +449,7 @@ trim_map_vdev_commit(spa_t *spa, zio_t *zio, vdev_t *vd) { trim_map_t *tm = vd->vdev_trimmap; trim_seg_t *ts; - uint64_t size, txgtarget, txgsafe; + uint64_t size, offset, txgtarget, txgsafe; hrtime_t timelimit; ASSERT(vd->vdev_ops->vdev_op_leaf); @@ -477,9 +477,19 @@ trim_map_vdev_commit(spa_t *spa, zio_t *zio, vdev_t *vd) avl_remove(&tm->tm_queued_frees, ts); avl_add(&tm->tm_inflight_frees, ts); size = ts->ts_end - ts->ts_start; - zio_nowait(zio_trim(zio, spa, vd, ts->ts_start, size)); + offset = ts->ts_start; TRIM_MAP_SDEC(tm, size); TRIM_MAP_QDEC(tm); + /* + * We drop the lock while we call zio_nowait as the IO + * scheduler can result in a different IO being run e.g. + * a write which would result in a recursive lock. + */ + mutex_exit(&tm->tm_lock); + + zio_nowait(zio_trim(zio, spa, vd, offset, size)); + + mutex_enter(&tm->tm_lock); } mutex_exit(&tm->tm_lock); } diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c index 1c30941fb2d13..b64ebddbcb1a7 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c @@ -800,10 +800,11 @@ vdev_geom_io_start(zio_t *zio) vd = zio->io_vd; - if (zio->io_type == ZIO_TYPE_IOCTL) { + switch (zio->io_type) { + case ZIO_TYPE_IOCTL: /* XXPOLICY */ if (!vdev_readable(vd)) { - zio->io_error = ENXIO; + zio->io_error = SET_ERROR(ENXIO); return (ZIO_PIPELINE_CONTINUE); } @@ -812,28 +813,28 @@ vdev_geom_io_start(zio_t *zio) if (zfs_nocacheflush || vdev_geom_bio_flush_disable) break; if (vd->vdev_nowritecache) { - zio->io_error = ENOTSUP; - break; - } - goto sendreq; - case DKIOCTRIM: - if (vdev_geom_bio_delete_disable) - break; - if (vd->vdev_notrim) { - zio->io_error = ENOTSUP; + zio->io_error = SET_ERROR(ENOTSUP); break; } goto sendreq; default: - zio->io_error = ENOTSUP; + zio->io_error = SET_ERROR(ENOTSUP); } return (ZIO_PIPELINE_CONTINUE); + case ZIO_TYPE_FREE: + if (vdev_geom_bio_delete_disable) + return (ZIO_PIPELINE_CONTINUE); + + if (vd->vdev_notrim) { + zio->io_error = SET_ERROR(ENOTSUP); + return (ZIO_PIPELINE_CONTINUE); + } } sendreq: cp = vd->vdev_tsd; if (cp == NULL) { - zio->io_error = ENXIO; + zio->io_error = SET_ERROR(ENXIO); return (ZIO_PIPELINE_CONTINUE); } bp = g_alloc_bio(); @@ -846,21 +847,20 @@ sendreq: bp->bio_offset = zio->io_offset; bp->bio_length = zio->io_size; break; + case ZIO_TYPE_FREE: + bp->bio_cmd = BIO_DELETE; + bp->bio_data = NULL; + bp->bio_offset = zio->io_offset; + bp->bio_length = zio->io_size; + break; case ZIO_TYPE_IOCTL: - switch (zio->io_cmd) { - case DKIOCFLUSHWRITECACHE: + if (zio->io_cmd == DKIOCFLUSHWRITECACHE) { bp->bio_cmd = BIO_FLUSH; bp->bio_flags |= BIO_ORDERED; bp->bio_data = NULL; bp->bio_offset = cp->provider->mediasize; bp->bio_length = 0; break; - case DKIOCTRIM: - bp->bio_cmd = BIO_DELETE; - bp->bio_data = NULL; - bp->bio_offset = zio->io_offset; - bp->bio_length = zio->io_size; - break; } break; } diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c index d7d0deeadd3dc..60fd4c3eedf2f 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c @@ -40,9 +40,9 @@ * * ZFS issues I/O operations to leaf vdevs to satisfy and complete zios. The * I/O scheduler determines when and in what order those operations are - * issued. The I/O scheduler divides operations into five I/O classes + * issued. The I/O scheduler divides operations into six I/O classes * prioritized in the following order: sync read, sync write, async read, - * async write, and scrub/resilver. Each queue defines the minimum and + * async write, scrub/resilver and trim. Each queue defines the minimum and * maximum number of concurrent operations that may be issued to the device. * In addition, the device has an aggregate maximum. Note that the sum of the * per-queue minimums must not exceed the aggregate maximum, and if the @@ -61,7 +61,7 @@ * done in the order specified above. No further operations are issued if the * aggregate maximum number of concurrent operations has been hit or if there * are no operations queued for an I/O class that has not hit its maximum. - * Every time an i/o is queued or an operation completes, the I/O scheduler + * Every time an I/O is queued or an operation completes, the I/O scheduler * looks for new operations to issue. * * All I/O classes have a fixed maximum number of outstanding operations @@ -70,7 +70,7 @@ * transaction groups (see txg.c). Transaction groups enter the syncing state * periodically so the number of queued async writes will quickly burst up and * then bleed down to zero. Rather than servicing them as quickly as possible, - * the I/O scheduler changes the maximum number of active async write i/os + * the I/O scheduler changes the maximum number of active async write I/Os * according to the amount of dirty data in the pool (see dsl_pool.c). Since * both throughput and latency typically increase with the number of * concurrent operations issued to physical devices, reducing the burstiness @@ -113,14 +113,14 @@ */ /* - * The maximum number of i/os active to each device. Ideally, this will be >= + * The maximum number of I/Os active to each device. Ideally, this will be >= * the sum of each queue's max_active. It must be at least the sum of each * queue's min_active. */ uint32_t zfs_vdev_max_active = 1000; /* - * Per-queue limits on the number of i/os active to each device. If the + * Per-queue limits on the number of I/Os active to each device. If the * sum of the queue's max_active is < zfs_vdev_max_active, then the * min_active comes into play. We will send min_active from each queue, * and then select from queues in the order defined by zio_priority_t. @@ -145,6 +145,14 @@ uint32_t zfs_vdev_async_write_min_active = 1; uint32_t zfs_vdev_async_write_max_active = 10; uint32_t zfs_vdev_scrub_min_active = 1; uint32_t zfs_vdev_scrub_max_active = 2; +uint32_t zfs_vdev_trim_min_active = 1; +/* + * TRIM max active is large in comparison to the other values due to the fact + * that TRIM IOs are coalesced at the device layer. This value is set such + * that a typical SSD can process the queued IOs in a single request. + */ +uint32_t zfs_vdev_trim_max_active = 64; + /* * When the pool has less than zfs_vdev_async_write_active_min_dirty_percent @@ -171,7 +179,7 @@ SYSCTL_DECL(_vfs_zfs_vdev); TUNABLE_INT("vfs.zfs.vdev.max_active", &zfs_vdev_max_active); SYSCTL_UINT(_vfs_zfs_vdev, OID_AUTO, max_active, CTLFLAG_RW, &zfs_vdev_max_active, 0, - "The maximum number of i/os of all types active for each device."); + "The maximum number of I/Os of all types active for each device."); #define ZFS_VDEV_QUEUE_KNOB_MIN(name) \ TUNABLE_INT("vfs.zfs.vdev." #name "_min_active", \ @@ -199,6 +207,8 @@ ZFS_VDEV_QUEUE_KNOB_MIN(async_write); ZFS_VDEV_QUEUE_KNOB_MAX(async_write); ZFS_VDEV_QUEUE_KNOB_MIN(scrub); ZFS_VDEV_QUEUE_KNOB_MAX(scrub); +ZFS_VDEV_QUEUE_KNOB_MIN(trim); +ZFS_VDEV_QUEUE_KNOB_MAX(trim); #undef ZFS_VDEV_QUEUE_KNOB @@ -299,6 +309,7 @@ static void vdev_queue_io_add(vdev_queue_t *vq, zio_t *zio) { spa_t *spa = zio->io_spa; + ASSERT(MUTEX_HELD(&vq->vq_lock)); ASSERT3U(zio->io_priority, <, ZIO_PRIORITY_NUM_QUEUEABLE); avl_add(&vq->vq_class[zio->io_priority].vqc_queued_tree, zio); @@ -315,6 +326,7 @@ static void vdev_queue_io_remove(vdev_queue_t *vq, zio_t *zio) { spa_t *spa = zio->io_spa; + ASSERT(MUTEX_HELD(&vq->vq_lock)); ASSERT3U(zio->io_priority, <, ZIO_PRIORITY_NUM_QUEUEABLE); avl_remove(&vq->vq_class[zio->io_priority].vqc_queued_tree, zio); @@ -403,6 +415,8 @@ vdev_queue_class_min_active(zio_priority_t p) return (zfs_vdev_async_write_min_active); case ZIO_PRIORITY_SCRUB: return (zfs_vdev_scrub_min_active); + case ZIO_PRIORITY_TRIM: + return (zfs_vdev_trim_min_active); default: panic("invalid priority %u", p); return (0); @@ -454,6 +468,8 @@ vdev_queue_class_max_active(spa_t *spa, zio_priority_t p) spa->spa_dsl_pool->dp_dirty_total)); case ZIO_PRIORITY_SCRUB: return (zfs_vdev_scrub_max_active); + case ZIO_PRIORITY_TRIM: + return (zfs_vdev_trim_max_active); default: panic("invalid priority %u", p); return (0); @@ -470,6 +486,8 @@ vdev_queue_class_to_issue(vdev_queue_t *vq) spa_t *spa = vq->vq_vdev->vdev_spa; zio_priority_t p; + ASSERT(MUTEX_HELD(&vq->vq_lock)); + if (avl_numnodes(&vq->vq_active_tree) >= zfs_vdev_max_active) return (ZIO_PRIORITY_NUM_QUEUEABLE); @@ -511,10 +529,11 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio) zio_t *first, *last, *aio, *dio, *mandatory, *nio; uint64_t maxgap = 0; uint64_t size; - boolean_t stretch = B_FALSE; - vdev_queue_class_t *vqc = &vq->vq_class[zio->io_priority]; - avl_tree_t *t = &vqc->vqc_queued_tree; - enum zio_flag flags = zio->io_flags & ZIO_FLAG_AGG_INHERIT; + boolean_t stretch; + avl_tree_t *t; + enum zio_flag flags; + + ASSERT(MUTEX_HELD(&vq->vq_lock)); if (zio->io_flags & ZIO_FLAG_DONT_AGGREGATE) return (NULL); @@ -552,6 +571,8 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio) * Walk backwards through sufficiently contiguous I/Os * recording the last non-option I/O. */ + flags = zio->io_flags & ZIO_FLAG_AGG_INHERIT; + t = &vq->vq_class[zio->io_priority].vqc_queued_tree; while ((dio = AVL_PREV(t, first)) != NULL && (dio->io_flags & ZIO_FLAG_AGG_INHERIT) == flags && IO_SPAN(dio, last) <= zfs_vdev_aggregation_limit && @@ -591,6 +612,7 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio) * non-optional I/O is close enough to make aggregation * worthwhile. */ + stretch = B_FALSE; if (zio->io_type == ZIO_TYPE_WRITE && mandatory != NULL) { zio_t *nio = last; while ((dio = AVL_NEXT(t, nio)) != NULL && @@ -731,11 +753,13 @@ vdev_queue_io(zio_t *zio) zio->io_priority != ZIO_PRIORITY_ASYNC_READ && zio->io_priority != ZIO_PRIORITY_SCRUB) zio->io_priority = ZIO_PRIORITY_ASYNC_READ; - } else { - ASSERT(zio->io_type == ZIO_TYPE_WRITE); + } else if (zio->io_type == ZIO_TYPE_WRITE) { if (zio->io_priority != ZIO_PRIORITY_SYNC_WRITE && zio->io_priority != ZIO_PRIORITY_ASYNC_WRITE) zio->io_priority = ZIO_PRIORITY_ASYNC_WRITE; + } else { + ASSERT(zio->io_type == ZIO_TYPE_FREE); + zio->io_priority = ZIO_PRIORITY_TRIM; } zio->io_flags |= ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_QUEUE; @@ -772,14 +796,25 @@ vdev_queue_io_done(zio_t *zio) vq->vq_io_complete_ts = gethrtime(); + if (zio->io_flags & ZIO_FLAG_QUEUE_IO_DONE) { + /* + * Executing from a previous vdev_queue_io_done so + * to avoid recursion we just unlock and return. + */ + mutex_exit(&vq->vq_lock); + return; + } + while ((nio = vdev_queue_io_to_issue(vq)) != NULL) { mutex_exit(&vq->vq_lock); + nio->io_flags |= ZIO_FLAG_QUEUE_IO_DONE; if (nio->io_done == vdev_queue_agg_io_done) { zio_nowait(nio); } else { zio_vdev_io_reissue(nio); zio_execute(nio); } + nio->io_flags &= ~ZIO_FLAG_QUEUE_IO_DONE; mutex_enter(&vq->vq_lock); } diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c index ea81b43b3232a..01946fb2b553d 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c @@ -788,6 +788,8 @@ zio_free_sync(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp, else if (BP_IS_GANG(bp) || BP_GET_DEDUP(bp)) stage |= ZIO_STAGE_ISSUE_ASYNC; + flags |= ZIO_FLAG_DONT_QUEUE; + zio = zio_create(pio, spa, txg, bp, NULL, size, NULL, NULL, ZIO_TYPE_FREE, ZIO_PRIORITY_NOW, flags, NULL, 0, NULL, ZIO_STAGE_OPEN, stage); @@ -827,14 +829,14 @@ zio_claim(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp, zio_t * zio_ioctl(zio_t *pio, spa_t *spa, vdev_t *vd, int cmd, uint64_t offset, uint64_t size, zio_done_func_t *done, void *private, - enum zio_flag flags) + zio_priority_t priority, enum zio_flag flags) { zio_t *zio; int c; if (vd->vdev_children == 0) { zio = zio_create(pio, spa, 0, NULL, NULL, size, done, private, - ZIO_TYPE_IOCTL, ZIO_PRIORITY_NOW, flags, vd, offset, NULL, + ZIO_TYPE_IOCTL, priority, flags, vd, offset, NULL, ZIO_STAGE_OPEN, ZIO_IOCTL_PIPELINE); zio->io_cmd = cmd; @@ -843,7 +845,7 @@ zio_ioctl(zio_t *pio, spa_t *spa, vdev_t *vd, int cmd, uint64_t offset, for (c = 0; c < vd->vdev_children; c++) zio_nowait(zio_ioctl(zio, spa, vd->vdev_child[c], cmd, - offset, size, done, private, flags)); + offset, size, done, private, priority, flags)); } return (zio); @@ -928,6 +930,10 @@ zio_vdev_child_io(zio_t *pio, blkptr_t *bp, vdev_t *vd, uint64_t offset, pio->io_pipeline &= ~ZIO_STAGE_CHECKSUM_VERIFY; } + /* Not all IO types require vdev io done stage e.g. free */ + if (!(pio->io_pipeline & ZIO_STAGE_VDEV_IO_DONE)) + pipeline &= ~ZIO_STAGE_VDEV_IO_DONE; + if (vd->vdev_children == 0) offset += VDEV_LABEL_START_SIZE; @@ -973,7 +979,7 @@ void zio_flush(zio_t *zio, vdev_t *vd) { zio_nowait(zio_ioctl(zio, zio->io_spa, vd, DKIOCFLUSHWRITECACHE, 0, 0, - NULL, NULL, + NULL, NULL, ZIO_PRIORITY_NOW, ZIO_FLAG_CANFAIL | ZIO_FLAG_DONT_PROPAGATE | ZIO_FLAG_DONT_RETRY)); } @@ -983,9 +989,10 @@ zio_trim(zio_t *zio, spa_t *spa, vdev_t *vd, uint64_t offset, uint64_t size) ASSERT(vd->vdev_ops->vdev_op_leaf); - return zio_ioctl(zio, spa, vd, DKIOCTRIM, offset, size, - NULL, NULL, - ZIO_FLAG_CANFAIL | ZIO_FLAG_DONT_PROPAGATE | ZIO_FLAG_DONT_RETRY); + return (zio_create(zio, spa, 0, NULL, NULL, size, NULL, NULL, + ZIO_TYPE_FREE, ZIO_PRIORITY_TRIM, ZIO_FLAG_DONT_AGGREGATE | + ZIO_FLAG_CANFAIL | ZIO_FLAG_DONT_PROPAGATE | ZIO_FLAG_DONT_RETRY, + vd, offset, NULL, ZIO_STAGE_OPEN, ZIO_FREE_PHYS_PIPELINE)); } void @@ -1012,8 +1019,9 @@ zio_shrink(zio_t *zio, uint64_t size) */ static int -zio_read_bp_init(zio_t *zio) +zio_read_bp_init(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; if (BP_GET_COMPRESS(bp) != ZIO_COMPRESS_OFF && @@ -1038,8 +1046,9 @@ zio_read_bp_init(zio_t *zio) } static int -zio_write_bp_init(zio_t *zio) +zio_write_bp_init(zio_t **ziop) { + zio_t *zio = *ziop; spa_t *spa = zio->io_spa; zio_prop_t *zp = &zio->io_prop; enum zio_compress compress = zp->zp_compress; @@ -1189,8 +1198,9 @@ zio_write_bp_init(zio_t *zio) } static int -zio_free_bp_init(zio_t *zio) +zio_free_bp_init(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; if (zio->io_child_type == ZIO_CHILD_LOGICAL) { @@ -1273,8 +1283,10 @@ zio_taskq_member(zio_t *zio, zio_taskq_type_t q) } static int -zio_issue_async(zio_t *zio) +zio_issue_async(zio_t **ziop) { + zio_t *zio = *ziop; + zio_taskq_dispatch(zio, ZIO_TASKQ_ISSUE, B_FALSE); return (ZIO_PIPELINE_STOP); @@ -1342,7 +1354,7 @@ zio_execute(zio_t *zio) } zio->io_stage = stage; - rv = zio_pipeline[highbit64(stage) - 1](zio); + rv = zio_pipeline[highbit64(stage) - 1](&zio); if (rv == ZIO_PIPELINE_STOP) return; @@ -1776,8 +1788,9 @@ zio_gang_tree_issue(zio_t *pio, zio_gang_node_t *gn, blkptr_t *bp, void *data) } static int -zio_gang_assemble(zio_t *zio) +zio_gang_assemble(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; ASSERT(BP_IS_GANG(bp) && zio->io_gang_leader == NULL); @@ -1791,8 +1804,9 @@ zio_gang_assemble(zio_t *zio) } static int -zio_gang_issue(zio_t *zio) +zio_gang_issue(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; if (zio_wait_for_children(zio, ZIO_CHILD_GANG, ZIO_WAIT_DONE)) @@ -1926,8 +1940,9 @@ zio_write_gang_block(zio_t *pio) * writes) and as a result is mutually exclusive with dedup. */ static int -zio_nop_write(zio_t *zio) +zio_nop_write(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; blkptr_t *bp_orig = &zio->io_bp_orig; zio_prop_t *zp = &zio->io_prop; @@ -1998,8 +2013,9 @@ zio_ddt_child_read_done(zio_t *zio) } static int -zio_ddt_read_start(zio_t *zio) +zio_ddt_read_start(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; ASSERT(BP_GET_DEDUP(bp)); @@ -2041,8 +2057,9 @@ zio_ddt_read_start(zio_t *zio) } static int -zio_ddt_read_done(zio_t *zio) +zio_ddt_read_done(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; if (zio_wait_for_children(zio, ZIO_CHILD_DDT, ZIO_WAIT_DONE)) @@ -2210,8 +2227,9 @@ zio_ddt_ditto_write_done(zio_t *zio) } static int -zio_ddt_write(zio_t *zio) +zio_ddt_write(zio_t **ziop) { + zio_t *zio = *ziop; spa_t *spa = zio->io_spa; blkptr_t *bp = zio->io_bp; uint64_t txg = zio->io_txg; @@ -2322,8 +2340,9 @@ zio_ddt_write(zio_t *zio) ddt_entry_t *freedde; /* for debugging */ static int -zio_ddt_free(zio_t *zio) +zio_ddt_free(zio_t **ziop) { + zio_t *zio = *ziop; spa_t *spa = zio->io_spa; blkptr_t *bp = zio->io_bp; ddt_t *ddt = ddt_select(spa, bp); @@ -2348,8 +2367,9 @@ zio_ddt_free(zio_t *zio) * ========================================================================== */ static int -zio_dva_allocate(zio_t *zio) +zio_dva_allocate(zio_t **ziop) { + zio_t *zio = *ziop; spa_t *spa = zio->io_spa; metaslab_class_t *mc = spa_normal_class(spa); blkptr_t *bp = zio->io_bp; @@ -2391,16 +2411,19 @@ zio_dva_allocate(zio_t *zio) } static int -zio_dva_free(zio_t *zio) +zio_dva_free(zio_t **ziop) { + zio_t *zio = *ziop; + metaslab_free(zio->io_spa, zio->io_bp, zio->io_txg, B_FALSE); return (ZIO_PIPELINE_CONTINUE); } static int -zio_dva_claim(zio_t *zio) +zio_dva_claim(zio_t **ziop) { + zio_t *zio = *ziop; int error; error = metaslab_claim(zio->io_spa, zio->io_bp, zio->io_txg); @@ -2494,8 +2517,9 @@ zio_free_zil(spa_t *spa, uint64_t txg, blkptr_t *bp) * ========================================================================== */ static int -zio_vdev_io_start(zio_t *zio) +zio_vdev_io_start(zio_t **ziop) { + zio_t *zio = *ziop; vdev_t *vd = zio->io_vd; uint64_t align; spa_t *spa = zio->io_spa; @@ -2513,7 +2537,8 @@ zio_vdev_io_start(zio_t *zio) return (vdev_mirror_ops.vdev_op_io_start(zio)); } - if (vd->vdev_ops->vdev_op_leaf && zio->io_type == ZIO_TYPE_FREE) { + if (vd->vdev_ops->vdev_op_leaf && zio->io_type == ZIO_TYPE_FREE && + zio->io_priority == ZIO_PRIORITY_NOW) { trim_map_free(vd, zio->io_offset, zio->io_size, zio->io_txg); return (ZIO_PIPELINE_CONTINUE); } @@ -2581,30 +2606,33 @@ zio_vdev_io_start(zio_t *zio) return (ZIO_PIPELINE_CONTINUE); } - if (vd->vdev_ops->vdev_op_leaf && - (zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE)) { - - if (zio->io_type == ZIO_TYPE_READ && vdev_cache_read(zio)) - return (ZIO_PIPELINE_CONTINUE); + if (vd->vdev_ops->vdev_op_leaf) { + switch (zio->io_type) { + case ZIO_TYPE_READ: + if (vdev_cache_read(zio)) + return (ZIO_PIPELINE_CONTINUE); + /* FALLTHROUGH */ + case ZIO_TYPE_WRITE: + case ZIO_TYPE_FREE: + if ((zio = vdev_queue_io(zio)) == NULL) + return (ZIO_PIPELINE_STOP); + *ziop = zio; - if ((zio = vdev_queue_io(zio)) == NULL) - return (ZIO_PIPELINE_STOP); - - if (!vdev_accessible(vd, zio)) { - zio->io_error = SET_ERROR(ENXIO); - zio_interrupt(zio); - return (ZIO_PIPELINE_STOP); + if (!vdev_accessible(vd, zio)) { + zio->io_error = SET_ERROR(ENXIO); + zio_interrupt(zio); + return (ZIO_PIPELINE_STOP); + } + break; } - } - - /* - * Note that we ignore repair writes for TRIM because they can conflict - * with normal writes. This isn't an issue because, by definition, we - * only repair blocks that aren't freed. - */ - if (vd->vdev_ops->vdev_op_leaf && zio->io_type == ZIO_TYPE_WRITE && - !(zio->io_flags & ZIO_FLAG_IO_REPAIR)) { - if (!trim_map_write_start(zio)) + /* + * Note that we ignore repair writes for TRIM because they can + * conflict with normal writes. This isn't an issue because, by + * definition, we only repair blocks that aren't freed. + */ + if (zio->io_type == ZIO_TYPE_WRITE && + !(zio->io_flags & ZIO_FLAG_IO_REPAIR) && + !trim_map_write_start(zio)) return (ZIO_PIPELINE_STOP); } @@ -2612,8 +2640,9 @@ zio_vdev_io_start(zio_t *zio) } static int -zio_vdev_io_done(zio_t *zio) +zio_vdev_io_done(zio_t **ziop) { + zio_t *zio = *ziop; vdev_t *vd = zio->io_vd; vdev_ops_t *ops = vd ? vd->vdev_ops : &vdev_mirror_ops; boolean_t unexpected_error = B_FALSE; @@ -2625,7 +2654,8 @@ zio_vdev_io_done(zio_t *zio) zio->io_type == ZIO_TYPE_WRITE || zio->io_type == ZIO_TYPE_FREE); if (vd != NULL && vd->vdev_ops->vdev_op_leaf && - (zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE)) { + (zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE || + zio->io_type == ZIO_TYPE_FREE)) { if (zio->io_type == ZIO_TYPE_WRITE && !(zio->io_flags & ZIO_FLAG_IO_REPAIR)) @@ -2644,7 +2674,10 @@ zio_vdev_io_done(zio_t *zio) zio->io_error = zio_handle_label_injection(zio, EIO); if (zio->io_error) { - if (!vdev_accessible(vd, zio)) { + if (zio->io_error == ENOTSUP && + zio->io_type == ZIO_TYPE_FREE) { + /* Not all devices support TRIM. */ + } else if (!vdev_accessible(vd, zio)) { zio->io_error = SET_ERROR(ENXIO); } else { unexpected_error = B_TRUE; @@ -2687,8 +2720,9 @@ zio_vsd_default_cksum_report(zio_t *zio, zio_cksum_report_t *zcr, void *ignored) } static int -zio_vdev_io_assess(zio_t *zio) +zio_vdev_io_assess(zio_t **ziop) { + zio_t *zio = *ziop; vdev_t *vd = zio->io_vd; if (zio_wait_for_children(zio, ZIO_CHILD_VDEV, ZIO_WAIT_DONE)) @@ -2705,7 +2739,8 @@ zio_vdev_io_assess(zio_t *zio) if (zio_injection_enabled && zio->io_error == 0) zio->io_error = zio_handle_fault_injection(zio, EIO); - if (zio->io_type == ZIO_TYPE_IOCTL && zio->io_cmd == DKIOCTRIM) + if (zio->io_type == ZIO_TYPE_FREE && + zio->io_priority != ZIO_PRIORITY_NOW) { switch (zio->io_error) { case 0: ZIO_TRIM_STAT_INCR(bytes, zio->io_size); @@ -2718,6 +2753,7 @@ zio_vdev_io_assess(zio_t *zio) ZIO_TRIM_STAT_BUMP(failed); break; } + } /* * If the I/O failed, determine whether we should attempt to retry it. @@ -2801,8 +2837,9 @@ zio_vdev_io_bypass(zio_t *zio) * ========================================================================== */ static int -zio_checksum_generate(zio_t *zio) +zio_checksum_generate(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; enum zio_checksum checksum; @@ -2832,8 +2869,9 @@ zio_checksum_generate(zio_t *zio) } static int -zio_checksum_verify(zio_t *zio) +zio_checksum_verify(zio_t **ziop) { + zio_t *zio = *ziop; zio_bad_cksum_t info; blkptr_t *bp = zio->io_bp; int error; @@ -2904,8 +2942,9 @@ zio_worst_error(int e1, int e2) * ========================================================================== */ static int -zio_ready(zio_t *zio) +zio_ready(zio_t **ziop) { + zio_t *zio = *ziop; blkptr_t *bp = zio->io_bp; zio_t *pio, *pio_next; @@ -2962,8 +3001,9 @@ zio_ready(zio_t *zio) } static int -zio_done(zio_t *zio) +zio_done(zio_t **ziop) { + zio_t *zio = *ziop; spa_t *spa = zio->io_spa; zio_t *lio = zio->io_logical; blkptr_t *bp = zio->io_bp; diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 22a2bb064b010..9d0e51952ad09 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -176,6 +176,7 @@ options GEOM_SHSEC # Shared secret. options GEOM_STRIPE # Disk striping. options GEOM_SUNLABEL # Sun/Solaris partitioning options GEOM_UZIP # Read-only compressed disks +options GEOM_VINUM # Vinum logical volume manager options GEOM_VIRSTOR # Virtual storage. options GEOM_VOL # Volume names from UFS superblock options GEOM_ZERO # Performance testing helper. diff --git a/sys/conf/files b/sys/conf/files index 8c0c2fc61059e..d11faa97473e9 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -14,7 +14,7 @@ acpi_quirks.h optional acpi \ # from the specified source (DTS) file: <platform>.dts -> <platform>.dtb # fdt_dtb_file optional fdt fdt_dtb_static \ - compile-with "sh $S/tools/fdt/make_dtb.sh $S ${FDT_DTS_FILE} ${.CURDIR}/${FDT_DTS_FILE:R}.dtb" \ + compile-with "sh $S/tools/fdt/make_dtb.sh $S ${FDT_DTS_FILE} ${.CURDIR}" \ no-obj no-implicit-rule before-depend \ clean "${FDT_DTS_FILE:R}.dtb" fdt_static_dtb.h optional fdt fdt_dtb_static \ @@ -1804,6 +1804,17 @@ dev/mmc/mmcbr_if.m standard dev/mmc/mmcbus_if.m standard dev/mmc/mmcsd.c optional mmcsd dev/mn/if_mn.c optional mn pci +dev/mpr/mpr.c optional mpr +dev/mpr/mpr_config.c optional mpr +# XXX Work around clang warning, until maintainer approves fix. +dev/mpr/mpr_mapping.c optional mpr \ + compile-with "${NORMAL_C} ${NO_WSOMETIMES_UNINITIALIZED}" +dev/mpr/mpr_pci.c optional mpr pci +dev/mpr/mpr_sas.c optional mpr \ + compile-with "${NORMAL_C} ${NO_WUNNEEDED_INTERNAL_DECL}" +dev/mpr/mpr_sas_lsi.c optional mpr +dev/mpr/mpr_table.c optional mpr +dev/mpr/mpr_user.c optional mpr dev/mps/mps.c optional mps dev/mps/mps_config.c optional mps # XXX Work around clang warning, until maintainer approves fix. @@ -1821,6 +1832,10 @@ dev/mpt/mpt_debug.c optional mpt dev/mpt/mpt_pci.c optional mpt pci dev/mpt/mpt_raid.c optional mpt dev/mpt/mpt_user.c optional mpt +dev/mrsas/mrsas.c optional mrsas +dev/mrsas/mrsas_cam.c optional mrsas +dev/mrsas/mrsas_ioctl.c optional mrsas +dev/mrsas/mrsas_fp.c optional mrsas dev/msk/if_msk.c optional msk dev/mvs/mvs.c optional mvs dev/mvs/mvs_if.m optional mvs @@ -2759,6 +2774,21 @@ contrib/xz-embedded/linux/lib/xz/xz_dec_stream.c \ optional xz_embedded | geom_uncompress \ compile-with "${NORMAL_C} -I$S/contrib/xz-embedded/freebsd/ -I$S/contrib/xz-embedded/linux/lib/xz/ -I$S/contrib/xz-embedded/linux/include/linux/" geom/uzip/g_uzip.c optional geom_uzip +geom/vinum/geom_vinum.c optional geom_vinum +geom/vinum/geom_vinum_create.c optional geom_vinum +geom/vinum/geom_vinum_drive.c optional geom_vinum +geom/vinum/geom_vinum_plex.c optional geom_vinum +geom/vinum/geom_vinum_volume.c optional geom_vinum +geom/vinum/geom_vinum_subr.c optional geom_vinum +geom/vinum/geom_vinum_raid5.c optional geom_vinum +geom/vinum/geom_vinum_share.c optional geom_vinum +geom/vinum/geom_vinum_list.c optional geom_vinum +geom/vinum/geom_vinum_rm.c optional geom_vinum +geom/vinum/geom_vinum_init.c optional geom_vinum +geom/vinum/geom_vinum_state.c optional geom_vinum +geom/vinum/geom_vinum_rename.c optional geom_vinum +geom/vinum/geom_vinum_move.c optional geom_vinum +geom/vinum/geom_vinum_events.c optional geom_vinum geom/virstor/binstream.c optional geom_virstor geom/virstor/g_virstor.c optional geom_virstor geom/virstor/g_virstor_md.c optional geom_virstor diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index f78f1c87bf31d..e7d33a800f1cf 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -232,8 +232,6 @@ dev/hyperv/vmbus/hv_hv.c optional hyperv dev/hyperv/vmbus/hv_ring_buffer.c optional hyperv dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c optional hyperv dev/kbd/kbd.c optional atkbd | sc | ukbd | vt -dev/lindev/full.c optional lindev -dev/lindev/lindev.c optional lindev dev/nfe/if_nfe.c optional nfe pci dev/ntb/if_ntb/if_ntb.c optional if_ntb dev/ntb/ntb_hw/ntb_hw.c optional if_ntb ntb_hw diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index 30c224a44e1f6..b07eebdfd2fa4 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -240,8 +240,6 @@ dev/ipmi/ipmi_pci.c optional ipmi pci dev/ipmi/ipmi_linux.c optional ipmi compat_linux dev/kbd/kbd.c optional atkbd | sc | ukbd | vt dev/le/if_le_isa.c optional le isa -dev/lindev/full.c optional lindev -dev/lindev/lindev.c optional lindev dev/mse/mse.c optional mse dev/mse/mse_isa.c optional mse isa dev/nfe/if_nfe.c optional nfe pci diff --git a/sys/conf/files.pc98 b/sys/conf/files.pc98 index 92696ee9c08b2..fff7b3ce8f495 100644 --- a/sys/conf/files.pc98 +++ b/sys/conf/files.pc98 @@ -110,8 +110,6 @@ dev/hwpmc/hwpmc_x86.c optional hwpmc dev/io/iodev.c optional io dev/kbd/kbd.c optional pckbd | sc | ukbd dev/le/if_le_cbus.c optional le isa -dev/lindev/full.c optional lindev -dev/lindev/lindev.c optional lindev dev/mse/mse.c optional mse dev/mse/mse_cbus.c optional mse isa dev/sbni/if_sbni.c optional sbni diff --git a/sys/conf/kern.pre.mk b/sys/conf/kern.pre.mk index 3ff23c2db92db..1b7c49dbd6dc0 100644 --- a/sys/conf/kern.pre.mk +++ b/sys/conf/kern.pre.mk @@ -3,7 +3,7 @@ # Part of a unified Makefile for building kernels. This part contains all # of the definitions that need to be before %BEFORE_DEPEND. -.include <bsd.own.mk> +.include <src.opts.mk> .include <bsd.compiler.mk> # backwards compat option for older systems. diff --git a/sys/conf/kmod.mk b/sys/conf/kmod.mk index 125ebc1b45c70..100c4705ab0da 100644 --- a/sys/conf/kmod.mk +++ b/sys/conf/kmod.mk @@ -72,6 +72,7 @@ OBJCOPY?= objcopy .error "Do not use KMODDEPS on 5.0+; use MODULE_VERSION/MODULE_DEPEND" .endif +.include <src.opts.mk> .include <bsd.init.mk> .include <bsd.compiler.mk> diff --git a/sys/conf/options b/sys/conf/options index 99596525cd889..fdc3530ab761e 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -125,6 +125,7 @@ GEOM_STRIPE opt_geom.h GEOM_SUNLABEL opt_geom.h GEOM_UNCOMPRESS opt_geom.h GEOM_UZIP opt_geom.h +GEOM_VINUM opt_geom.h GEOM_VIRSTOR opt_geom.h GEOM_VOL opt_geom.h GEOM_ZERO opt_geom.h diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_attach.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_attach.c index 46833ef749f4a..9cc99ec701f09 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_attach.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_attach.c @@ -4113,6 +4113,8 @@ ar9300_probe(uint16_t vendorid, uint16_t devid) return "Qualcomm Atheros QCA955x"; case AR9300_DEVID_QCA9565: /* Aphrodite */ return "Qualcomm Atheros AR9565"; + case AR9300_DEVID_AR1111_PCIE: + return "Atheros AR1111"; default: return AH_NULL; } diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c index 251957eaae3f8..a2cc25d741eae 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c @@ -60,6 +60,11 @@ ar9300_freebsd_set_tx_power_limit(struct ath_hal *ah, uint32_t limit) return (ar9300_set_tx_power_limit(ah, limit, 0, 0)); } +static uint64_t +ar9300_get_next_tbtt(struct ath_hal *ah) +{ + return (OS_REG_READ(ah, AR_NEXT_TBTT_TIMER)); +} void ar9300_attach_freebsd_ops(struct ath_hal *ah) @@ -195,6 +200,7 @@ ar9300_attach_freebsd_ops(struct ath_hal *ah) ah->ah_setStationBeaconTimers = ar9300_set_sta_beacon_timers; /* ah_resetStationBeaconTimers */ /* ah_getNextTBTT */ + ah->ah_getNextTBTT = ar9300_get_next_tbtt; /* Interrupt functions */ ah->ah_isInterruptPending = ar9300_is_interrupt_pending; diff --git a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_power.c b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_power.c index 629c40f9b8b1b..b842993c23f91 100644 --- a/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_power.c +++ b/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_power.c @@ -669,7 +669,8 @@ ar9300_set_power_mode(struct ath_hal *ah, HAL_POWER_MODE mode, int set_chip) switch (mode) { case HAL_PM_AWAKE: - ah->ah_powerMode = mode; + if (set_chip) + ah->ah_powerMode = mode; status = ar9300_set_power_mode_awake(ah, set_chip); #if ATH_SUPPORT_MCI if (AH_PRIVATE(ah)->ah_caps.halMciSupport) { @@ -699,8 +700,10 @@ ar9300_set_power_mode(struct ath_hal *ah, HAL_POWER_MODE mode, int set_chip) } #endif ar9300_set_power_mode_sleep(ah, set_chip); - ahp->ah_chip_full_sleep = AH_TRUE; - ah->ah_powerMode = mode; + if (set_chip) { + ahp->ah_chip_full_sleep = AH_TRUE; + ah->ah_powerMode = mode; + } break; case HAL_PM_NETWORK_SLEEP: #if ATH_SUPPORT_MCI @@ -709,7 +712,9 @@ ar9300_set_power_mode(struct ath_hal *ah, HAL_POWER_MODE mode, int set_chip) } #endif ar9300_set_power_mode_network_sleep(ah, set_chip); - ah->ah_powerMode = mode; + if (set_chip) { + ah->ah_powerMode = mode; + } break; default: HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, diff --git a/sys/dev/ath/ath_hal/ah_devid.h b/sys/dev/ath/ath_hal/ah_devid.h index 43d994dcd3ab7..1e4d473072583 100644 --- a/sys/dev/ath/ath_hal/ah_devid.h +++ b/sys/dev/ath/ath_hal/ah_devid.h @@ -92,6 +92,7 @@ #define AR9300_DEVID_AR946X_PCIE 0x0034 #define AR9300_DEVID_AR9330 0x0035 #define AR9300_DEVID_QCA9565 0x0036 +#define AR9300_DEVID_AR1111_PCIE 0x0037 #define AR9300_DEVID_QCA955X 0x0039 #define AR_SUBVENDOR_ID_NOG 0x0e11 /* No 11G subvendor ID */ diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_power.c b/sys/dev/ath/ath_hal/ar5210/ar5210_power.c index 7e7961fcc38a0..ec5e75d369349 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_power.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_power.c @@ -108,16 +108,19 @@ ar5210SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) setChip ? "set chip " : ""); switch (mode) { case HAL_PM_AWAKE: - ah->ah_powerMode = mode; + if (setChip) + ah->ah_powerMode = mode; status = ar5210SetPowerModeAwake(ah, setChip); break; case HAL_PM_FULL_SLEEP: ar5210SetPowerModeSleep(ah, setChip); - ah->ah_powerMode = mode; + if (setChip) + ah->ah_powerMode = mode; break; case HAL_PM_NETWORK_SLEEP: ar5210SetPowerModeAuto(ah, setChip); - ah->ah_powerMode = mode; + if (setChip) + ah->ah_powerMode = mode; break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n", diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_power.c b/sys/dev/ath/ath_hal/ar5211/ar5211_power.c index 0ed090215b52c..e646d90b66cab 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_power.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_power.c @@ -110,16 +110,19 @@ ar5211SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) setChip ? "set chip " : ""); switch (mode) { case HAL_PM_AWAKE: - ah->ah_powerMode = mode; + if (setChip) + ah->ah_powerMode = mode; status = ar5211SetPowerModeAwake(ah, setChip); break; case HAL_PM_FULL_SLEEP: ar5211SetPowerModeSleep(ah, setChip); - ah->ah_powerMode = mode; + if (setChip) + ah->ah_powerMode = mode; break; case HAL_PM_NETWORK_SLEEP: ar5211SetPowerModeNetworkSleep(ah, setChip); - ah->ah_powerMode = mode; + if (setChip) + ah->ah_powerMode = mode; break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n", diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_power.c b/sys/dev/ath/ath_hal/ar5212/ar5212_power.c index 555632895910a..3068510dd8cd9 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_power.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_power.c @@ -134,16 +134,19 @@ ar5212SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) setChip ? "set chip " : ""); switch (mode) { case HAL_PM_AWAKE: - ah->ah_powerMode = mode; + if (setChip) + ah->ah_powerMode = mode; status = ar5212SetPowerModeAwake(ah, setChip); break; case HAL_PM_FULL_SLEEP: ar5212SetPowerModeSleep(ah, setChip); - ah->ah_powerMode = mode; + if (setChip) + ah->ah_powerMode = mode; break; case HAL_PM_NETWORK_SLEEP: ar5212SetPowerModeNetworkSleep(ah, setChip); - ah->ah_powerMode = mode; + if (setChip) + ah->ah_powerMode = mode; break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode %u\n", diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_power.c b/sys/dev/ath/ath_hal/ar5416/ar5416_power.c index c70a8e7d5d57f..dff9a855917a4 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_power.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_power.c @@ -133,23 +133,29 @@ ar5416SetPowerMode(struct ath_hal *ah, HAL_POWER_MODE mode, int setChip) }; #endif int status = AH_TRUE; + +#if 0 if (!setChip) return AH_TRUE; +#endif HALDEBUG(ah, HAL_DEBUG_POWER, "%s: %s -> %s (%s)\n", __func__, modes[ah->ah_powerMode], modes[mode], setChip ? "set chip " : ""); switch (mode) { case HAL_PM_AWAKE: - ah->ah_powerMode = mode; + if (setChip) + ah->ah_powerMode = mode; status = ar5416SetPowerModeAwake(ah, setChip); break; case HAL_PM_FULL_SLEEP: ar5416SetPowerModeSleep(ah, setChip); - ah->ah_powerMode = mode; + if (setChip) + ah->ah_powerMode = mode; break; case HAL_PM_NETWORK_SLEEP: ar5416SetPowerModeNetworkSleep(ah, setChip); - ah->ah_powerMode = mode; + if (setChip) + ah->ah_powerMode = mode; break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown power mode 0x%x\n", diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index 6c98e603a835a..a3ab2f61dbfa3 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -165,6 +165,7 @@ static void ath_bmiss_vap(struct ieee80211vap *); static void ath_bmiss_proc(void *, int); static void ath_key_update_begin(struct ieee80211vap *); static void ath_key_update_end(struct ieee80211vap *); +static void ath_update_mcast_hw(struct ath_softc *); static void ath_update_mcast(struct ifnet *); static void ath_update_promisc(struct ifnet *); static void ath_updateslot(struct ifnet *); @@ -279,6 +280,164 @@ ath_legacy_attach_comp_func(struct ath_softc *sc) } } +/* + * Set the target power mode. + * + * If this is called during a point in time where + * the hardware is being programmed elsewhere, it will + * simply store it away and update it when all current + * uses of the hardware are completed. + */ +void +_ath_power_setpower(struct ath_softc *sc, int power_state, const char *file, int line) +{ + ATH_LOCK_ASSERT(sc); + + sc->sc_target_powerstate = power_state; + + DPRINTF(sc, ATH_DEBUG_PWRSAVE, "%s: (%s:%d) state=%d, refcnt=%d\n", + __func__, + file, + line, + power_state, + sc->sc_powersave_refcnt); + + if (sc->sc_powersave_refcnt == 0 && + power_state != sc->sc_cur_powerstate) { + sc->sc_cur_powerstate = power_state; + ath_hal_setpower(sc->sc_ah, power_state); + + /* + * If the NIC is force-awake, then set the + * self-gen frame state appropriately. + * + * If the nic is in network sleep or full-sleep, + * we let the above call leave the self-gen + * state as "sleep". + */ + if (sc->sc_cur_powerstate == HAL_PM_AWAKE && + sc->sc_target_selfgen_state != HAL_PM_AWAKE) { + ath_hal_setselfgenpower(sc->sc_ah, + sc->sc_target_selfgen_state); + } + } +} + +/* + * Set the current self-generated frames state. + * + * This is separate from the target power mode. The chip may be + * awake but the desired state is "sleep", so frames sent to the + * destination has PWRMGT=1 in the 802.11 header. The NIC also + * needs to know to set PWRMGT=1 in self-generated frames. + */ +void +_ath_power_set_selfgen(struct ath_softc *sc, int power_state, const char *file, int line) +{ + + ATH_LOCK_ASSERT(sc); + + DPRINTF(sc, ATH_DEBUG_PWRSAVE, "%s: (%s:%d) state=%d, refcnt=%d\n", + __func__, + file, + line, + power_state, + sc->sc_target_selfgen_state); + + sc->sc_target_selfgen_state = power_state; + + /* + * If the NIC is force-awake, then set the power state. + * Network-state and full-sleep will already transition it to + * mark self-gen frames as sleeping - and we can't + * guarantee the NIC is awake to program the self-gen frame + * setting anyway. + */ + if (sc->sc_cur_powerstate == HAL_PM_AWAKE) { + ath_hal_setselfgenpower(sc->sc_ah, power_state); + } +} + +/* + * Set the hardware power mode and take a reference. + * + * This doesn't update the target power mode in the driver; + * it just updates the hardware power state. + * + * XXX it should only ever force the hardware awake; it should + * never be called to set it asleep. + */ +void +_ath_power_set_power_state(struct ath_softc *sc, int power_state, const char *file, int line) +{ + ATH_LOCK_ASSERT(sc); + + DPRINTF(sc, ATH_DEBUG_PWRSAVE, "%s: (%s:%d) state=%d, refcnt=%d\n", + __func__, + file, + line, + power_state, + sc->sc_powersave_refcnt); + + sc->sc_powersave_refcnt++; + + if (power_state != sc->sc_cur_powerstate) { + ath_hal_setpower(sc->sc_ah, power_state); + sc->sc_cur_powerstate = power_state; + + /* + * Adjust the self-gen powerstate if appropriate. + */ + if (sc->sc_cur_powerstate == HAL_PM_AWAKE && + sc->sc_target_selfgen_state != HAL_PM_AWAKE) { + ath_hal_setselfgenpower(sc->sc_ah, + sc->sc_target_selfgen_state); + } + + } +} + +/* + * Restore the power save mode to what it once was. + * + * This will decrement the reference counter and once it hits + * zero, it'll restore the powersave state. + */ +void +_ath_power_restore_power_state(struct ath_softc *sc, const char *file, int line) +{ + + ATH_LOCK_ASSERT(sc); + + DPRINTF(sc, ATH_DEBUG_PWRSAVE, "%s: (%s:%d) refcnt=%d, target state=%d\n", + __func__, + file, + line, + sc->sc_powersave_refcnt, + sc->sc_target_powerstate); + + if (sc->sc_powersave_refcnt == 0) + device_printf(sc->sc_dev, "%s: refcnt=0?\n", __func__); + else + sc->sc_powersave_refcnt--; + + if (sc->sc_powersave_refcnt == 0 && + sc->sc_target_powerstate != sc->sc_cur_powerstate) { + sc->sc_cur_powerstate = sc->sc_target_powerstate; + ath_hal_setpower(sc->sc_ah, sc->sc_target_powerstate); + } + + /* + * Adjust the self-gen powerstate if appropriate. + */ + if (sc->sc_cur_powerstate == HAL_PM_AWAKE && + sc->sc_target_selfgen_state != HAL_PM_AWAKE) { + ath_hal_setselfgenpower(sc->sc_ah, + sc->sc_target_selfgen_state); + } + +} + #define HAL_MODE_HT20 (HAL_MODE_11NG_HT20 | HAL_MODE_11NA_HT20) #define HAL_MODE_HT40 \ (HAL_MODE_11NG_HT40PLUS | HAL_MODE_11NG_HT40MINUS | \ @@ -341,6 +500,10 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) ath_xmit_setup_legacy(sc); } + if (ath_hal_hasmybeacon(sc->sc_ah)) { + sc->sc_do_mybeacon = 1; + } + /* * Check if the MAC has multi-rate retry support. * We do this by trying to setup a fake extended @@ -605,6 +768,8 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) #ifdef ATH_ENABLE_DFS | IEEE80211_C_DFS /* Enable radar detection */ #endif + | IEEE80211_C_PMGT /* Station side power mgmt */ + | IEEE80211_C_SWSLEEP ; /* * Query the hal to figure out h/w crypto support. @@ -994,6 +1159,14 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) if (bootverbose) ieee80211_announce(ic); ath_announce(sc); + + /* + * Put it to sleep for now. + */ + ATH_LOCK(sc); + ath_power_setpower(sc, HAL_PM_FULL_SLEEP); + ATH_UNLOCK(sc); + return 0; bad2: ath_tx_cleanup(sc); @@ -1039,7 +1212,22 @@ ath_detach(struct ath_softc *sc) * it last * Other than that, it's straightforward... */ + + /* + * XXX Wake the hardware up first. ath_stop() will still + * wake it up first, but I'd rather do it here just to + * ensure it's awake. + */ + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ath_power_setpower(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + + /* + * Stop things cleanly. + */ ath_stop(ifp); + ieee80211_ifdetach(ifp->if_l2com); taskqueue_free(sc->sc_tq); #ifdef ATH_TX99_DIAG @@ -1402,6 +1590,10 @@ ath_vap_delete(struct ieee80211vap *vap) struct ath_hal *ah = sc->sc_ah; struct ath_vap *avp = ATH_VAP(vap); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + DPRINTF(sc, ATH_DEBUG_RESET, "%s: called\n", __func__); if (ifp->if_drv_flags & IFF_DRV_RUNNING) { /* @@ -1415,6 +1607,8 @@ ath_vap_delete(struct ieee80211vap *vap) ath_stoprecv(sc, 1); /* stop recv side */ } + /* .. leave the hardware awake for now. */ + ieee80211_vap_detach(vap); /* @@ -1502,6 +1696,9 @@ ath_vap_delete(struct ieee80211vap *vap) } ath_hal_intrset(ah, sc->sc_imask); } + + /* Ok, let the hardware asleep. */ + ath_power_restore_power_state(sc); ATH_UNLOCK(sc); } @@ -1547,8 +1744,12 @@ ath_reset_keycache(struct ath_softc *sc) struct ath_hal *ah = sc->sc_ah; int i; + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); for (i = 0; i < sc->sc_keymax; i++) ath_hal_keyreset(ah, i); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); ieee80211_crypto_reload_keys(ic); } @@ -1600,6 +1801,14 @@ ath_resume(struct ath_softc *sc) sc->sc_curchan != NULL ? sc->sc_curchan : ic->ic_curchan); ath_hal_setchainmasks(sc->sc_ah, sc->sc_cur_txchainmask, sc->sc_cur_rxchainmask); + + /* Ensure we set the current power state to on */ + ATH_LOCK(sc); + ath_power_setselfgen(sc, HAL_PM_AWAKE); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ath_power_setpower(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ath_hal_reset(ah, sc->sc_opmode, sc->sc_curchan != NULL ? sc->sc_curchan : ic->ic_curchan, AH_FALSE, &status); @@ -1632,6 +1841,10 @@ ath_resume(struct ath_softc *sc) if (sc->sc_resume_up) ieee80211_resume_all(ic); + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + /* XXX beacons ? */ } @@ -1689,6 +1902,10 @@ ath_intr(void *arg) return; } + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + if ((ifp->if_flags & IFF_UP) == 0 || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { HAL_INT status; @@ -1698,6 +1915,10 @@ ath_intr(void *arg) ath_hal_getisr(ah, &status); /* clear ISR */ ath_hal_intrset(ah, 0); /* disable further intr's */ ATH_PCU_UNLOCK(sc); + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); return; } @@ -1737,6 +1958,11 @@ ath_intr(void *arg) /* Short-circuit un-handled interrupts */ if (status == 0x0) { ATH_PCU_UNLOCK(sc); + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + return; } @@ -1903,10 +2129,18 @@ ath_intr(void *arg) ATH_KTR(sc, ATH_KTR_ERROR, 0, "ath_intr: RXORN"); sc->sc_stats.ast_rxorn++; } + if (status & HAL_INT_TSFOOR) { + device_printf(sc->sc_dev, "%s: TSFOOR\n", __func__); + sc->sc_syncbeacon = 1; + } } ATH_PCU_LOCK(sc); sc->sc_intr_cnt--; ATH_PCU_UNLOCK(sc); + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); } static void @@ -1937,6 +2171,8 @@ ath_fatal_proc(void *arg, int pending) static void ath_bmiss_vap(struct ieee80211vap *vap) { + struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; + /* * Workaround phantom bmiss interrupts by sanity-checking * the time of our last rx'd frame. If it is within the @@ -1945,6 +2181,16 @@ ath_bmiss_vap(struct ieee80211vap *vap) * be dispatched up for processing. Note this applies only * for h/w beacon miss events. */ + + /* + * XXX TODO: Just read the TSF during the interrupt path; + * that way we don't have to wake up again just to read it + * again. + */ + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + if ((vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS) == 0) { struct ifnet *ifp = vap->iv_ic->ic_ifp; struct ath_softc *sc = ifp->if_softc; @@ -1962,12 +2208,32 @@ ath_bmiss_vap(struct ieee80211vap *vap) if (tsf - lastrx <= bmisstimeout) { sc->sc_stats.ast_bmiss_phantom++; + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + return; } } + + /* + * There's no need to keep the hardware awake during the call + * to av_bmiss(). + */ + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + + /* + * Attempt to force a beacon resync. + */ + sc->sc_syncbeacon = 1; + ATH_VAP(vap)->av_bmiss(vap); } +/* XXX this needs a force wakeup! */ int ath_hal_gethangstate(struct ath_hal *ah, uint32_t mask, uint32_t *hangs) { @@ -1990,6 +2256,12 @@ ath_bmiss_proc(void *arg, int pending) DPRINTF(sc, ATH_DEBUG_ANY, "%s: pending %u\n", __func__, pending); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + + ath_beacon_miss(sc); + /* * Do a reset upon any becaon miss event. * @@ -2003,6 +2275,13 @@ ath_bmiss_proc(void *arg, int pending) ath_reset(ifp, ATH_RESET_NOLOSS); ieee80211_beacon_miss(ifp->if_l2com); } + + /* Force a beacon resync, in case they've drifted */ + sc->sc_syncbeacon = 1; + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); } /* @@ -2042,6 +2321,13 @@ ath_init(void *arg) ATH_LOCK(sc); /* + * Force the sleep state awake. + */ + ath_power_setselfgen(sc, HAL_PM_AWAKE); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ath_power_setpower(sc, HAL_PM_AWAKE); + + /* * Stop anything previously setup. This is safe * whether this is the first time through or not. */ @@ -2058,6 +2344,7 @@ ath_init(void *arg) ath_update_chainmasks(sc, ic->ic_curchan); ath_hal_setchainmasks(sc->sc_ah, sc->sc_cur_txchainmask, sc->sc_cur_rxchainmask); + if (!ath_hal_reset(ah, sc->sc_opmode, ic->ic_curchan, AH_FALSE, &status)) { if_printf(ifp, "unable to reset hardware; hal status %u\n", status); @@ -2113,6 +2400,7 @@ ath_init(void *arg) */ if (ath_startrecv(sc) != 0) { if_printf(ifp, "unable to start recv logic\n"); + ath_power_restore_power_state(sc); ATH_UNLOCK(sc); return; } @@ -2139,6 +2427,15 @@ ath_init(void *arg) if (sc->sc_needmib && ic->ic_opmode == IEEE80211_M_STA) sc->sc_imask |= HAL_INT_MIB; + /* + * XXX add capability for this. + * + * If we're in STA mode (and maybe IBSS?) then register for + * TSFOOR interrupts. + */ + if (ic->ic_opmode == IEEE80211_M_STA) + sc->sc_imask |= HAL_INT_TSFOOR; + /* Enable global TX timeout and carrier sense timeout if available */ if (ath_hal_gtxto_supported(ah)) sc->sc_imask |= HAL_INT_GTT; @@ -2150,6 +2447,7 @@ ath_init(void *arg) callout_reset(&sc->sc_wd_ch, hz, ath_watchdog, sc); ath_hal_intrset(ah, sc->sc_imask); + ath_power_restore_power_state(sc); ATH_UNLOCK(sc); #ifdef ATH_TX99_DIAG @@ -2170,6 +2468,12 @@ ath_stop_locked(struct ifnet *ifp) __func__, sc->sc_invalid, ifp->if_flags); ATH_LOCK_ASSERT(sc); + + /* + * Wake the hardware up before fiddling with it. + */ + ath_power_set_power_state(sc, HAL_PM_AWAKE); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { /* * Shutdown the hardware and driver: @@ -2210,9 +2514,20 @@ ath_stop_locked(struct ifnet *ifp) sc->sc_rxlink = NULL; ath_beacon_free(sc); /* XXX not needed */ } + + /* And now, restore the current power state */ + ath_power_restore_power_state(sc); } -#define MAX_TXRX_ITERATIONS 1000 +/* + * Wait until all pending TX/RX has completed. + * + * This waits until all existing transmit, receive and interrupts + * have completed. It's assumed that the caller has first + * grabbed the reset lock so it doesn't try to do overlapping + * chip resets. + */ +#define MAX_TXRX_ITERATIONS 100 static void ath_txrx_stop_locked(struct ath_softc *sc) { @@ -2231,7 +2546,8 @@ ath_txrx_stop_locked(struct ath_softc *sc) sc->sc_txstart_cnt || sc->sc_intr_cnt) { if (i <= 0) break; - msleep(sc, &sc->sc_pcu_mtx, 0, "ath_txrx_stop", 1); + msleep(sc, &sc->sc_pcu_mtx, 0, "ath_txrx_stop", + msecs_to_ticks(10)); i--; } @@ -2278,7 +2594,7 @@ ath_txrx_start(struct ath_softc *sc) * Another, cleaner way should be found to serialise all of * these operations. */ -#define MAX_RESET_ITERATIONS 10 +#define MAX_RESET_ITERATIONS 25 static int ath_reset_grablock(struct ath_softc *sc, int dowait) { @@ -2296,7 +2612,11 @@ ath_reset_grablock(struct ath_softc *sc, int dowait) break; } ATH_PCU_UNLOCK(sc); - pause("ath_reset_grablock", 1); + /* + * 1 tick is likely not enough time for long calibrations + * to complete. So we should wait quite a while. + */ + pause("ath_reset_grablock", msecs_to_ticks(100)); i--; ATH_PCU_LOCK(sc); } while (i > 0); @@ -2361,6 +2681,13 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) /* Try to (stop any further TX/RX from occuring */ taskqueue_block(sc->sc_tq); + /* + * Wake the hardware up. + */ + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ATH_PCU_LOCK(sc); /* @@ -2455,9 +2782,13 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) * reset counter - this way ath_intr() doesn't end up * disabling interrupts without a corresponding enable * in the rest or channel change path. + * + * Grab the TX reference in case we need to transmit. + * That way a parallel transmit doesn't. */ ATH_PCU_LOCK(sc); sc->sc_inreset_cnt--; + sc->sc_txstart_cnt++; /* XXX only do this if sc_inreset_cnt == 0? */ ath_hal_intrset(ah, sc->sc_imask); ATH_PCU_UNLOCK(sc); @@ -2474,6 +2805,8 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) /* Restart TX/RX as needed */ ath_txrx_start(sc); + /* XXX TODO: we need to hold the tx refcount here! */ + /* Restart TX completion and pending TX */ if (reset_type == ATH_RESET_NOLOSS) { for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { @@ -2498,6 +2831,14 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; IF_UNLOCK(&ifp->if_snd); + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + + ATH_PCU_LOCK(sc); + sc->sc_txstart_cnt--; + ATH_PCU_UNLOCK(sc); + /* Handle any frames in the TX queue */ /* * XXX should this be done by the caller, rather than @@ -2638,6 +2979,7 @@ ath_buf_clone(struct ath_softc *sc, struct ath_buf *bf) tbf->bf_status = bf->bf_status; tbf->bf_m = bf->bf_m; tbf->bf_node = bf->bf_node; + KASSERT((bf->bf_node != NULL), ("%s: bf_node=NULL!", __func__)); /* will be setup by the chain/setup function */ tbf->bf_lastds = NULL; /* for now, last == self */ @@ -2739,6 +3081,11 @@ ath_transmit(struct ifnet *ifp, struct mbuf *m) sc->sc_txstart_cnt++; ATH_PCU_UNLOCK(sc); + /* Wake the hardware up already */ + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ATH_KTR(sc, ATH_KTR_TX, 0, "ath_transmit: start"); /* * Grab the TX lock - it's ok to do this here; we haven't @@ -2972,6 +3319,11 @@ finish: sc->sc_txstart_cnt--; ATH_PCU_UNLOCK(sc); + /* Sleep the hardware if required */ + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + ATH_KTR(sc, ATH_KTR_TX, 0, "ath_transmit: finished"); return (retval); @@ -2999,7 +3351,6 @@ ath_key_update_begin(struct ieee80211vap *vap) DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__); taskqueue_block(sc->sc_tq); - IF_LOCK(&ifp->if_snd); /* NB: doesn't block mgmt frames */ } static void @@ -3009,7 +3360,6 @@ ath_key_update_end(struct ieee80211vap *vap) struct ath_softc *sc = ifp->if_softc; DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__); - IF_UNLOCK(&ifp->if_snd); taskqueue_unblock(sc->sc_tq); } @@ -3020,16 +3370,25 @@ ath_update_promisc(struct ifnet *ifp) u_int32_t rfilt; /* configure rx filter */ + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); rfilt = ath_calcrxfilter(sc); ath_hal_setrxfilter(sc->sc_ah, rfilt); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x\n", __func__, rfilt); } +/* + * Driver-internal mcast update call. + * + * Assumes the hardware is already awake. + */ static void -ath_update_mcast(struct ifnet *ifp) +ath_update_mcast_hw(struct ath_softc *sc) { - struct ath_softc *sc = ifp->if_softc; + struct ifnet *ifp = sc->sc_ifp; u_int32_t mfilt[2]; /* calculate and install multicast filter */ @@ -3057,11 +3416,33 @@ ath_update_mcast(struct ifnet *ifp) if_maddr_runlock(ifp); } else mfilt[0] = mfilt[1] = ~0; + ath_hal_setmcastfilter(sc->sc_ah, mfilt[0], mfilt[1]); + DPRINTF(sc, ATH_DEBUG_MODE, "%s: MC filter %08x:%08x\n", __func__, mfilt[0], mfilt[1]); } +/* + * Called from the net80211 layer - force the hardware + * awake before operating. + */ +static void +ath_update_mcast(struct ifnet *ifp) +{ + struct ath_softc *sc = ifp->if_softc; + + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + + ath_update_mcast_hw(sc); + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); +} + void ath_mode_init(struct ath_softc *sc) { @@ -3087,7 +3468,7 @@ ath_mode_init(struct ath_softc *sc) ath_hal_setmac(ah, IF_LLADDR(ifp)); /* calculate and install multicast filter */ - ath_update_mcast(ifp); + ath_update_mcast_hw(sc); } /* @@ -3119,8 +3500,13 @@ ath_setslottime(struct ath_softc *sc) __func__, ic->ic_curchan->ic_freq, ic->ic_curchan->ic_flags, ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", usec); + /* Wake up the hardware first before updating the slot time */ + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); ath_hal_setslottime(ah, usec); + ath_power_restore_power_state(sc); sc->sc_updateslot = OK; + ATH_UNLOCK(sc); } /* @@ -3137,6 +3523,8 @@ ath_updateslot(struct ifnet *ifp) * When not coordinating the BSS, change the hardware * immediately. For other operation we defer the change * until beacon updates have propagated to the stations. + * + * XXX sc_updateslot isn't changed behind a lock? */ if (ic->ic_opmode == IEEE80211_M_HOSTAP || ic->ic_opmode == IEEE80211_M_MBSS) @@ -4258,6 +4646,10 @@ ath_tx_proc_q0(void *arg, int npending) sc->sc_txq_active &= ~txqs; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ATH_KTR(sc, ATH_KTR_TXCOMP, 1, "ath_tx_proc_q0: txqs=0x%08x", txqs); @@ -4278,6 +4670,10 @@ ath_tx_proc_q0(void *arg, int npending) sc->sc_txproc_cnt--; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + ath_tx_kick(sc); } @@ -4299,6 +4695,10 @@ ath_tx_proc_q0123(void *arg, int npending) sc->sc_txq_active &= ~txqs; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ATH_KTR(sc, ATH_KTR_TXCOMP, 1, "ath_tx_proc_q0123: txqs=0x%08x", txqs); @@ -4331,6 +4731,10 @@ ath_tx_proc_q0123(void *arg, int npending) sc->sc_txproc_cnt--; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + ath_tx_kick(sc); } @@ -4351,6 +4755,10 @@ ath_tx_proc(void *arg, int npending) sc->sc_txq_active &= ~txqs; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ATH_KTR(sc, ATH_KTR_TXCOMP, 1, "ath_tx_proc: txqs=0x%08x", txqs); /* @@ -4376,6 +4784,10 @@ ath_tx_proc(void *arg, int npending) sc->sc_txproc_cnt--; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + ath_tx_kick(sc); } #undef TXQACTIVE @@ -4402,6 +4814,10 @@ ath_txq_sched_tasklet(void *arg, int npending) sc->sc_txproc_cnt++; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ATH_TX_LOCK(sc); for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { @@ -4410,6 +4826,10 @@ ath_txq_sched_tasklet(void *arg, int npending) } ATH_TX_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + ATH_PCU_LOCK(sc); sc->sc_txproc_cnt--; ATH_PCU_UNLOCK(sc); @@ -5057,6 +5477,15 @@ ath_calibrate(void *arg) HAL_BOOL aniCal, shortCal = AH_FALSE; int nextcal; + /* + * Force the hardware awake for ANI work. + */ + ath_power_set_power_state(sc, HAL_PM_AWAKE); + + /* Skip trying to do this if we're in reset */ + if (sc->sc_inreset_cnt) + goto restart; + if (ic->ic_flags & IEEE80211_F_SCAN) /* defer, off channel */ goto restart; longCal = (ticks - sc->sc_lastlongcal >= ath_longcalinterval*hz); @@ -5086,6 +5515,7 @@ ath_calibrate(void *arg) sc->sc_doresetcal = AH_TRUE; taskqueue_enqueue(sc->sc_tq, &sc->sc_resettask); callout_reset(&sc->sc_cal_ch, 1, ath_calibrate, sc); + ath_power_restore_power_state(sc); return; } /* @@ -5157,6 +5587,10 @@ restart: __func__); /* NB: don't rearm timer */ } + /* + * Restore power state now that we're done. + */ + ath_power_restore_power_state(sc); } static void @@ -5242,6 +5676,10 @@ ath_set_channel(struct ieee80211com *ic) struct ifnet *ifp = ic->ic_ifp; struct ath_softc *sc = ifp->if_softc; + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + (void) ath_chan_set(sc, ic->ic_curchan); /* * If we are returning to our bss channel then mark state @@ -5252,6 +5690,7 @@ ath_set_channel(struct ieee80211com *ic) ATH_LOCK(sc); if (!sc->sc_scanning && ic->ic_curchan == ic->ic_bsschan) sc->sc_syncbeacon = 1; + ath_power_restore_power_state(sc); ATH_UNLOCK(sc); } @@ -5284,6 +5723,7 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) int i, error, stamode; u_int32_t rfilt; int csa_run_transition = 0; + enum ieee80211_state ostate = vap->iv_state; static const HAL_LED_STATE leds[] = { HAL_LED_INIT, /* IEEE80211_S_INIT */ @@ -5297,7 +5737,7 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) }; DPRINTF(sc, ATH_DEBUG_STATE, "%s: %s -> %s\n", __func__, - ieee80211_state_name[vap->iv_state], + ieee80211_state_name[ostate], ieee80211_state_name[nstate]); /* @@ -5309,7 +5749,26 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) */ IEEE80211_LOCK_ASSERT(ic); - if (vap->iv_state == IEEE80211_S_CSA && nstate == IEEE80211_S_RUN) + /* Before we touch the hardware - wake it up */ + ATH_LOCK(sc); + /* + * If the NIC is in anything other than SLEEP state, + * we need to ensure that self-generated frames are + * set for PWRMGT=0. Otherwise we may end up with + * strange situations. + * + * XXX TODO: is this actually the case? :-) + */ + if (nstate != IEEE80211_S_SLEEP) + ath_power_setselfgen(sc, HAL_PM_AWAKE); + + /* + * Now, wake the thing up. + */ + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + + if (ostate == IEEE80211_S_CSA && nstate == IEEE80211_S_RUN) csa_run_transition = 1; callout_drain(&sc->sc_cal_ch); @@ -5322,6 +5781,13 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) * [re]setup beacons. Unblock the task q thread so * deferred interrupt processing is done. */ + + /* Ensure we stay awake during scan */ + ATH_LOCK(sc); + ath_power_setselfgen(sc, HAL_PM_AWAKE); + ath_power_setpower(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ath_hal_intrset(ah, sc->sc_imask &~ (HAL_INT_SWBA | HAL_INT_BMISS)); sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS); @@ -5334,6 +5800,11 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) stamode = (vap->iv_opmode == IEEE80211_M_STA || vap->iv_opmode == IEEE80211_M_AHDEMO || vap->iv_opmode == IEEE80211_M_IBSS); + + /* + * XXX Dont need to do this (and others) if we've transitioned + * from SLEEP->RUN. + */ if (stamode && nstate == IEEE80211_S_RUN) { sc->sc_curaid = ni->ni_associd; IEEE80211_ADDR_COPY(sc->sc_curbssid, ni->ni_bssid); @@ -5436,11 +5907,14 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) * beacon to update the beacon timer and thus we * won't get notified of the missing beacons. */ - sc->sc_syncbeacon = 1; -#if 0 - if (csa_run_transition) -#endif - ath_beacon_config(sc, vap); + if (ostate != IEEE80211_S_RUN && + ostate != IEEE80211_S_SLEEP) { + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: STA; syncbeacon=1\n", __func__); + sc->sc_syncbeacon = 1; + + if (csa_run_transition) + ath_beacon_config(sc, vap); /* * PR: kern/175227 @@ -5454,7 +5928,8 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) * timer fires (too often), leading to a STA * disassociation. */ - sc->sc_beacons = 1; + sc->sc_beacons = 1; + } break; case IEEE80211_M_MONITOR: /* @@ -5480,6 +5955,15 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; + + /* + * Force awake for RUN mode. + */ + ATH_LOCK(sc); + ath_power_setselfgen(sc, HAL_PM_AWAKE); + ath_power_setpower(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + /* * Finally, start any timers and the task q thread * (in case we didn't go through SCAN state). @@ -5491,6 +5975,7 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) DPRINTF(sc, ATH_DEBUG_CALIBRATE, "%s: calibration disabled\n", __func__); } + taskqueue_unblock(sc->sc_tq); } else if (nstate == IEEE80211_S_INIT) { /* @@ -5510,9 +5995,43 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) #ifdef IEEE80211_SUPPORT_TDMA ath_hal_setcca(ah, AH_TRUE); #endif + } else if (nstate == IEEE80211_S_SLEEP) { + /* We're going to sleep, so transition appropriately */ + /* For now, only do this if we're a single STA vap */ + if (sc->sc_nvaps == 1 && + vap->iv_opmode == IEEE80211_M_STA) { + DPRINTF(sc, ATH_DEBUG_BEACON, "%s: syncbeacon=%d\n", __func__, sc->sc_syncbeacon); + ATH_LOCK(sc); + /* + * Always at least set the self-generated + * frame config to set PWRMGT=1. + */ + ath_power_setselfgen(sc, HAL_PM_NETWORK_SLEEP); + + /* + * If we're not syncing beacons, transition + * to NETWORK_SLEEP. + * + * We stay awake if syncbeacon > 0 in case + * we need to listen for some beacons otherwise + * our beacon timer config may be wrong. + */ + if (sc->sc_syncbeacon == 0) { + ath_power_setpower(sc, HAL_PM_NETWORK_SLEEP); + } + ATH_UNLOCK(sc); + } } bad: ieee80211_free_node(ni); + + /* + * Restore the power state - either to what it was, or + * to network_sleep if it's alright. + */ + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); return error; } @@ -5567,6 +6086,13 @@ ath_newassoc(struct ieee80211_node *ni, int isnew) an->an_mcastrix = ath_tx_findrix(sc, tp->mcastrate); an->an_mgmtrix = ath_tx_findrix(sc, tp->mgmtrate); + DPRINTF(sc, ATH_DEBUG_NODE, "%s: %6D: reassoc; isnew=%d, is_powersave=%d\n", + __func__, + ni->ni_macaddr, + ":", + isnew, + an->an_is_powersave); + ATH_NODE_LOCK(an); ath_rate_newassoc(sc, an, isnew); ATH_NODE_UNLOCK(an); @@ -5813,6 +6339,10 @@ ath_watchdog(void *arg) struct ifnet *ifp = sc->sc_ifp; uint32_t hangs; + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + if (ath_hal_gethangstate(sc->sc_ah, 0xffff, &hangs) && hangs != 0) { if_printf(ifp, "%s hang detected (0x%x)\n", @@ -5822,6 +6352,10 @@ ath_watchdog(void *arg) do_reset = 1; ifp->if_oerrors++; sc->sc_stats.ast_watchdog++; + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); } /* @@ -5919,6 +6453,13 @@ ath_ioctl_diag(struct ath_softc *sc, struct ath_diag *ad) goto bad; } } + + + ATH_LOCK(sc); + if (id != HAL_DIAG_REGS) + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + if (ath_hal_getdiagstate(ah, id, indata, insize, &outdata, &outsize)) { if (outsize < ad->ad_out_size) ad->ad_out_size = outsize; @@ -5928,6 +6469,12 @@ ath_ioctl_diag(struct ath_softc *sc, struct ath_diag *ad) } else { error = EINVAL; } + + ATH_LOCK(sc); + if (id != HAL_DIAG_REGS) + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + bad: if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL) free(indata, M_TEMP); @@ -5957,7 +6504,9 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) * only reflect promisc mode settings. */ ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); ath_mode_init(sc); + ath_power_restore_power_state(sc); ATH_UNLOCK(sc); } else if (ifp->if_flags & IFF_UP) { /* @@ -5974,11 +6523,8 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } else { ATH_LOCK(sc); ath_stop_locked(ifp); -#ifdef notyet - /* XXX must wakeup in places like ath_vap_delete */ if (!sc->sc_invalid) - ath_hal_setpower(sc->sc_ah, HAL_PM_FULL_SLEEP); -#endif + ath_power_setpower(sc, HAL_PM_FULL_SLEEP); ATH_UNLOCK(sc); } break; diff --git a/sys/dev/ath/if_ath_beacon.c b/sys/dev/ath/if_ath_beacon.c index f721de64c93d2..317f83a358dda 100644 --- a/sys/dev/ath/if_ath_beacon.c +++ b/sys/dev/ath/if_ath_beacon.c @@ -382,7 +382,7 @@ ath_beacon_update(struct ieee80211vap *vap, int item) /* * Handle a beacon miss. */ -static void +void ath_beacon_miss(struct ath_softc *sc) { HAL_SURVEY_SAMPLE hs; @@ -916,7 +916,7 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap) struct ieee80211_node *ni; u_int32_t nexttbtt, intval, tsftu; u_int32_t nexttbtt_u8, intval_u8; - u_int64_t tsf; + u_int64_t tsf, tsf_beacon; if (vap == NULL) vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */ @@ -932,9 +932,17 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap) ni = ieee80211_ref_node(vap->iv_bss); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + /* extract tstamp from last beacon and convert to TU */ nexttbtt = TSF_TO_TU(LE_READ_4(ni->ni_tstamp.data + 4), LE_READ_4(ni->ni_tstamp.data)); + + tsf_beacon = ((uint64_t) LE_READ_4(ni->ni_tstamp.data + 4)) << 32; + tsf_beacon |= LE_READ_4(ni->ni_tstamp.data); + if (ic->ic_opmode == IEEE80211_M_HOSTAP || ic->ic_opmode == IEEE80211_M_MBSS) { /* @@ -980,14 +988,63 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap) */ tsf = ath_hal_gettsf64(ah); tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; - do { - nexttbtt += intval; - if (--dtimcount < 0) { - dtimcount = dtimperiod - 1; - if (--cfpcount < 0) - cfpcount = cfpperiod - 1; + + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: beacon tsf=%llu, hw tsf=%llu, nexttbtt=%u, tsftu=%u\n", + __func__, + (unsigned long long) tsf_beacon, + (unsigned long long) tsf, + nexttbtt, + tsftu); + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: beacon tsf=%llu, hw tsf=%llu, tsf delta=%lld\n", + __func__, + (unsigned long long) tsf_beacon, + (unsigned long long) tsf, + (long long) tsf - + (long long) tsf_beacon); + + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: nexttbtt=%llu, beacon tsf delta=%lld\n", + __func__, + (unsigned long long) nexttbtt, + (long long) ((long long) nexttbtt * 1024LL) - (long long) tsf_beacon); + + /* XXX cfpcount? */ + + if (nexttbtt > tsftu) { + uint32_t countdiff, oldtbtt, remainder; + + oldtbtt = nexttbtt; + remainder = (nexttbtt - tsftu) % intval; + nexttbtt = tsftu + remainder; + + countdiff = (oldtbtt - nexttbtt) / intval % dtimperiod; + if (dtimcount > countdiff) { + dtimcount -= countdiff; + } else { + dtimcount += dtimperiod - countdiff; + } + } else { //nexttbtt <= tsftu + uint32_t countdiff, oldtbtt, remainder; + + oldtbtt = nexttbtt; + remainder = (tsftu - nexttbtt) % intval; + nexttbtt = tsftu - remainder + intval; + countdiff = (nexttbtt - oldtbtt) / intval % dtimperiod; + if (dtimcount > countdiff) { + dtimcount -= countdiff; + } else { + dtimcount += dtimperiod - countdiff; } - } while (nexttbtt < tsftu); + } + + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: adj nexttbtt=%llu, rx tsf delta=%lld\n", + __func__, + (unsigned long long) nexttbtt, + (long long) ((long long)nexttbtt * 1024LL) - (long long)tsf); + memset(&bs, 0, sizeof(bs)); bs.bs_intval = intval; bs.bs_nexttbtt = nexttbtt; @@ -1034,9 +1091,12 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap) bs.bs_sleepduration = roundup(bs.bs_sleepduration, bs.bs_dtimperiod); DPRINTF(sc, ATH_DEBUG_BEACON, - "%s: tsf %ju tsf:tu %u intval %u nexttbtt %u dtim %u nextdtim %u bmiss %u sleep %u cfp:period %u maxdur %u next %u timoffset %u\n" + "%s: tsf %ju tsf:tu %u intval %u nexttbtt %u dtim %u " + "nextdtim %u bmiss %u sleep %u cfp:period %u " + "maxdur %u next %u timoffset %u\n" , __func__ - , tsf, tsftu + , tsf + , tsftu , bs.bs_intval , bs.bs_nexttbtt , bs.bs_dtimperiod @@ -1113,8 +1173,11 @@ ath_beacon_config(struct ath_softc *sc, struct ieee80211vap *vap) if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) ath_beacon_start_adhoc(sc, vap); } - sc->sc_syncbeacon = 0; ieee80211_free_node(ni); + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); #undef FUDGE #undef TSF_TO_TU } diff --git a/sys/dev/ath/if_ath_beacon.h b/sys/dev/ath/if_ath_beacon.h index f3f73d7166cf1..a9402680ee27e 100644 --- a/sys/dev/ath/if_ath_beacon.h +++ b/sys/dev/ath/if_ath_beacon.h @@ -48,5 +48,7 @@ extern int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni); extern void ath_beacon_return(struct ath_softc *sc, struct ath_buf *bf); extern void ath_beacon_free(struct ath_softc *sc); extern void ath_beacon_proc(void *arg, int pending); +extern void ath_beacon_miss(struct ath_softc *sc); #endif + diff --git a/sys/dev/ath/if_ath_debug.h b/sys/dev/ath/if_ath_debug.h index 83597afaa1a41..40c0b9a5ac74d 100644 --- a/sys/dev/ath/if_ath_debug.h +++ b/sys/dev/ath/if_ath_debug.h @@ -68,6 +68,7 @@ enum { ATH_DEBUG_SW_TX_FILT = 0x400000000ULL, /* SW TX FF */ ATH_DEBUG_NODE_PWRSAVE = 0x800000000ULL, /* node powersave */ ATH_DEBUG_DIVERSITY = 0x1000000000ULL, /* Diversity logic */ + ATH_DEBUG_PWRSAVE = 0x2000000000ULL, ATH_DEBUG_ANY = 0xffffffffffffffffULL }; diff --git a/sys/dev/ath/if_ath_keycache.c b/sys/dev/ath/if_ath_keycache.c index a9e6df0e46e81..fe99f106ac50c 100644 --- a/sys/dev/ath/if_ath_keycache.c +++ b/sys/dev/ath/if_ath_keycache.c @@ -78,6 +78,7 @@ __FBSDID("$FreeBSD$"); #include <dev/ath/if_ath_debug.h> #include <dev/ath/if_ath_keycache.h> +#include <dev/ath/if_ath_misc.h> #ifdef ATH_DEBUG static void @@ -198,6 +199,7 @@ ath_keyset(struct ath_softc *sc, struct ieee80211vap *vap, u_int8_t gmac[IEEE80211_ADDR_LEN]; const u_int8_t *mac; HAL_KEYVAL hk; + int ret; memset(&hk, 0, sizeof(hk)); /* @@ -251,13 +253,19 @@ ath_keyset(struct ath_softc *sc, struct ieee80211vap *vap, } else mac = k->wk_macaddr; + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); if (hk.kv_type == HAL_CIPHER_TKIP && (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) { - return ath_keyset_tkip(sc, k, &hk, mac); + ret = ath_keyset_tkip(sc, k, &hk, mac); } else { KEYPRINTF(sc, k->wk_keyix, &hk, mac); - return ath_hal_keyset(ah, k->wk_keyix, &hk, mac); + ret = ath_hal_keyset(ah, k->wk_keyix, &hk, mac); } + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + + return (ret); #undef N } @@ -492,6 +500,8 @@ ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s: delete key %u\n", __func__, keyix); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); ath_hal_keyreset(ah, keyix); /* * Handle split tx/rx keying required for TKIP with h/w MIC. @@ -515,6 +525,8 @@ ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) } } } + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); return 1; } diff --git a/sys/dev/ath/if_ath_led.c b/sys/dev/ath/if_ath_led.c index 33cc512ebf1ed..a55e0364689e3 100644 --- a/sys/dev/ath/if_ath_led.c +++ b/sys/dev/ath/if_ath_led.c @@ -122,6 +122,11 @@ __FBSDID("$FreeBSD$"); void ath_led_config(struct ath_softc *sc) { + + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + /* Software LED blinking - GPIO controlled LED */ if (sc->sc_softled) { ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin, @@ -144,6 +149,10 @@ ath_led_config(struct ath_softc *sc) ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_led_net_pin, HAL_GPIO_OUTPUT_MUX_MAC_NETWORK_LED); } + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); } static void diff --git a/sys/dev/ath/if_ath_misc.h b/sys/dev/ath/if_ath_misc.h index 0c99bc7cdaea1..711e69e87ba54 100644 --- a/sys/dev/ath/if_ath_misc.h +++ b/sys/dev/ath/if_ath_misc.h @@ -128,6 +128,19 @@ extern void ath_start_task(void *arg, int npending); extern void ath_tx_dump(struct ath_softc *sc, struct ath_txq *txq); /* + * Power state tracking. + */ +extern void _ath_power_setpower(struct ath_softc *sc, int power_state, const char *file, int line); +extern void _ath_power_set_selfgen(struct ath_softc *sc, int power_state, const char *file, int line); +extern void _ath_power_set_power_state(struct ath_softc *sc, int power_state, const char *file, int line); +extern void _ath_power_restore_power_state(struct ath_softc *sc, const char *file, int line); + +#define ath_power_setpower(sc, ps) _ath_power_setpower(sc, ps, __FILE__, __LINE__) +#define ath_power_setselfgen(sc, ps) _ath_power_set_selfgen(sc, ps, __FILE__, __LINE__) +#define ath_power_set_power_state(sc, ps) _ath_power_set_power_state(sc, ps, __FILE__, __LINE__) +#define ath_power_restore_power_state(sc) _ath_power_restore_power_state(sc, __FILE__, __LINE__) + +/* * Kick the frame TX task. */ static inline void diff --git a/sys/dev/ath/if_ath_rx.c b/sys/dev/ath/if_ath_rx.c index 5c30a46cbef2a..2f6cb58487d54 100644 --- a/sys/dev/ath/if_ath_rx.c +++ b/sys/dev/ath/if_ath_rx.c @@ -166,10 +166,22 @@ ath_calcrxfilter(struct ath_softc *sc) /* XXX ic->ic_monvaps != 0? */ if (ic->ic_opmode == IEEE80211_M_MONITOR || (ifp->if_flags & IFF_PROMISC)) rfilt |= HAL_RX_FILTER_PROM; + + /* + * Only listen to all beacons if we're scanning. + * + * Otherwise we only really need to hear beacons from + * our own BSSID. + */ if (ic->ic_opmode == IEEE80211_M_STA || - ic->ic_opmode == IEEE80211_M_IBSS || - sc->sc_swbmiss || sc->sc_scanning) - rfilt |= HAL_RX_FILTER_BEACON; + ic->ic_opmode == IEEE80211_M_IBSS || sc->sc_swbmiss) { + if (sc->sc_do_mybeacon && ! sc->sc_scanning) { + rfilt |= HAL_RX_FILTER_MYBEACON; + } else { /* scanning, non-mybeacon chips */ + rfilt |= HAL_RX_FILTER_BEACON; + } + } + /* * NB: We don't recalculate the rx filter when * ic_protmode changes; otherwise we could do @@ -233,6 +245,8 @@ ath_legacy_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) struct mbuf *m; struct ath_desc *ds; + /* XXX TODO: ATH_RX_LOCK_ASSERT(sc); */ + m = bf->bf_m; if (m == NULL) { /* @@ -317,6 +331,23 @@ ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, { struct ieee80211vap *vap = ni->ni_vap; struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; + uint64_t tsf_beacon_old, tsf_beacon; + uint64_t nexttbtt; + int64_t tsf_delta; + int32_t tsf_delta_bmiss; + int32_t tsf_remainder; + uint64_t tsf_beacon_target; + int tsf_intval; + + tsf_beacon_old = ((uint64_t) LE_READ_4(ni->ni_tstamp.data + 4)) << 32; + tsf_beacon_old |= LE_READ_4(ni->ni_tstamp.data); + +#define TU_TO_TSF(_tu) (((u_int64_t)(_tu)) << 10) + tsf_intval = 1; + if (ni->ni_intval > 0) { + tsf_intval = TU_TO_TSF(ni->ni_intval); + } +#undef TU_TO_TSF /* * Call up first so subsequent work can use information @@ -328,14 +359,79 @@ ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, /* update rssi statistics for use by the hal */ /* XXX unlocked check against vap->iv_bss? */ ATH_RSSI_LPF(sc->sc_halstats.ns_avgbrssi, rssi); + + tsf_beacon = ((uint64_t) LE_READ_4(ni->ni_tstamp.data + 4)) << 32; + tsf_beacon |= LE_READ_4(ni->ni_tstamp.data); + + nexttbtt = ath_hal_getnexttbtt(sc->sc_ah); + + /* + * Let's calculate the delta and remainder, so we can see + * if the beacon timer from the AP is varying by more than + * a few TU. (Which would be a huge, huge problem.) + */ + tsf_delta = (long long) tsf_beacon - (long long) tsf_beacon_old; + + tsf_delta_bmiss = tsf_delta / tsf_intval; + + /* + * If our delta is greater than half the beacon interval, + * let's round the bmiss value up to the next beacon + * interval. Ie, we're running really, really early + * on the next beacon. + */ + if (tsf_delta % tsf_intval > (tsf_intval / 2)) + tsf_delta_bmiss ++; + + tsf_beacon_target = tsf_beacon_old + + (((unsigned long long) tsf_delta_bmiss) * (long long) tsf_intval); + + /* + * The remainder using '%' is between 0 .. intval-1. + * If we're actually running too fast, then the remainder + * will be some large number just under intval-1. + * So we need to look at whether we're running + * before or after the target beacon interval + * and if we are, modify how we do the remainder + * calculation. + */ + if (tsf_beacon < tsf_beacon_target) { + tsf_remainder = + -(tsf_intval - ((tsf_beacon - tsf_beacon_old) % tsf_intval)); + } else { + tsf_remainder = (tsf_beacon - tsf_beacon_old) % tsf_intval; + } + + DPRINTF(sc, ATH_DEBUG_BEACON, "%s: old_tsf=%llu, new_tsf=%llu, target_tsf=%llu, delta=%lld, bmiss=%d, remainder=%d\n", + __func__, + (unsigned long long) tsf_beacon_old, + (unsigned long long) tsf_beacon, + (unsigned long long) tsf_beacon_target, + (long long) tsf_delta, + tsf_delta_bmiss, + tsf_remainder); + + DPRINTF(sc, ATH_DEBUG_BEACON, "%s: tsf=%llu, nexttbtt=%llu, delta=%d\n", + __func__, + (unsigned long long) tsf_beacon, + (unsigned long long) nexttbtt, + (int32_t) tsf_beacon - (int32_t) nexttbtt + tsf_intval); + if (sc->sc_syncbeacon && - ni == vap->iv_bss && vap->iv_state == IEEE80211_S_RUN) { + ni == vap->iv_bss && + (vap->iv_state == IEEE80211_S_RUN || vap->iv_state == IEEE80211_S_SLEEP)) { + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: syncbeacon=1; syncing\n", + __func__); /* * Resync beacon timers using the tsf of the beacon * frame we just received. */ ath_beacon_config(sc, vap); + sc->sc_syncbeacon = 0; } + + /* fall thru... */ case IEEE80211_FC0_SUBTYPE_PROBE_RESP: if (vap->iv_opmode == IEEE80211_M_IBSS && @@ -880,6 +976,14 @@ rx_next: #define ATH_RX_MAX 128 +/* + * XXX TODO: break out the "get buffers" from "call ath_rx_pkt()" like + * the EDMA code does. + * + * XXX TODO: then, do all of the RX list management stuff inside + * ATH_RX_LOCK() so we don't end up potentially racing. The EDMA + * code is doing it right. + */ static void ath_rx_proc(struct ath_softc *sc, int resched) { @@ -901,6 +1005,7 @@ ath_rx_proc(struct ath_softc *sc, int resched) u_int64_t tsf; int npkts = 0; int kickpcu = 0; + int ret; /* XXX we must not hold the ATH_LOCK here */ ATH_UNLOCK_ASSERT(sc); @@ -911,6 +1016,10 @@ ath_rx_proc(struct ath_softc *sc, int resched) kickpcu = sc->sc_kickpcu; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: called\n", __func__); ngood = 0; nf = ath_hal_getchannoise(ah, sc->sc_curchan); @@ -996,8 +1105,26 @@ ath_rx_proc(struct ath_softc *sc, int resched) if (ath_rx_pkt(sc, rs, status, tsf, nf, HAL_RX_QUEUE_HP, bf, m)) ngood++; rx_proc_next: - TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); - } while (ath_rxbuf_init(sc, bf) == 0); + /* + * If there's a holding buffer, insert that onto + * the RX list; the hardware is now definitely not pointing + * to it now. + */ + ret = 0; + if (sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf != NULL) { + TAILQ_INSERT_TAIL(&sc->sc_rxbuf, + sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf, + bf_list); + ret = ath_rxbuf_init(sc, + sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf); + } + /* + * Next, throw our buffer into the holding entry. The hardware + * may use the descriptor to read the link pointer before + * DMAing the next descriptor in to write out a packet. + */ + sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf = bf; + } while (ret == 0); /* rx signal state monitoring */ ath_hal_rxmonitor(ah, &sc->sc_halstats, sc->sc_curchan); @@ -1029,6 +1156,13 @@ rx_proc_next: * constantly write over the same frame, leading * the RX driver code here to get heavily confused. */ + /* + * XXX Has RX DMA stopped enough here to just call + * ath_startrecv()? + * XXX Do we need to use the holding buffer to restart + * RX DMA by appending entries to the final + * descriptor? Quite likely. + */ #if 1 ath_startrecv(sc); #else @@ -1066,6 +1200,13 @@ rx_proc_next: #undef PA2DESC /* + * Put the hardware to sleep again if we're done with it. + */ + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + + /* * If we hit the maximum number of frames in this round, * reschedule for another immediate pass. This gives * the TX and TX completion routines time to run, which @@ -1112,6 +1253,58 @@ ath_legacy_flushrecv(struct ath_softc *sc) ath_rx_proc(sc, 0); } +static void +ath_legacy_flush_rxpending(struct ath_softc *sc) +{ + + /* XXX ATH_RX_LOCK_ASSERT(sc); */ + + if (sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending != NULL) { + m_freem(sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending); + sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending = NULL; + } + if (sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending != NULL) { + m_freem(sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending); + sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending = NULL; + } +} + +static int +ath_legacy_flush_rxholdbf(struct ath_softc *sc) +{ + struct ath_buf *bf; + + /* XXX ATH_RX_LOCK_ASSERT(sc); */ + /* + * If there are RX holding buffers, free them here and return + * them to the list. + * + * XXX should just verify that bf->bf_m is NULL, as it must + * be at this point! + */ + bf = sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf; + if (bf != NULL) { + if (bf->bf_m != NULL) + m_freem(bf->bf_m); + bf->bf_m = NULL; + TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); + (void) ath_rxbuf_init(sc, bf); + } + sc->sc_rxedma[HAL_RX_QUEUE_HP].m_holdbf = NULL; + + bf = sc->sc_rxedma[HAL_RX_QUEUE_LP].m_holdbf; + if (bf != NULL) { + if (bf->bf_m != NULL) + m_freem(bf->bf_m); + bf->bf_m = NULL; + TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); + (void) ath_rxbuf_init(sc, bf); + } + sc->sc_rxedma[HAL_RX_QUEUE_LP].m_holdbf = NULL; + + return (0); +} + /* * Disable the receive h/w in preparation for a reset. */ @@ -1123,6 +1316,8 @@ ath_legacy_stoprecv(struct ath_softc *sc, int dodelay) ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr))) struct ath_hal *ah = sc->sc_ah; + ATH_RX_LOCK(sc); + ath_hal_stoppcurecv(ah); /* disable PCU */ ath_hal_setrxfilter(ah, 0); /* clear recv filter */ ath_hal_stopdmarecv(ah); /* disable DMA engine */ @@ -1156,22 +1351,23 @@ ath_legacy_stoprecv(struct ath_softc *sc, int dodelay) } } #endif - /* - * Free both high/low RX pending, just in case. - */ - if (sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending != NULL) { - m_freem(sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending); - sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending = NULL; - } - if (sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending != NULL) { - m_freem(sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending); - sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending = NULL; - } + + (void) ath_legacy_flush_rxpending(sc); + (void) ath_legacy_flush_rxholdbf(sc); + sc->sc_rxlink = NULL; /* just in case */ + + ATH_RX_UNLOCK(sc); #undef PA2DESC } /* + * XXX TODO: something was calling startrecv without calling + * stoprecv. Let's figure out what/why. It was showing up + * as a mbuf leak (rxpending) and ath_buf leak (holdbf.) + */ + +/* * Enable the receive h/w following a reset. */ static int @@ -1180,9 +1376,18 @@ ath_legacy_startrecv(struct ath_softc *sc) struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf; + ATH_RX_LOCK(sc); + + /* + * XXX should verify these are already all NULL! + */ sc->sc_rxlink = NULL; - sc->sc_rxedma[HAL_RX_QUEUE_LP].m_rxpending = NULL; - sc->sc_rxedma[HAL_RX_QUEUE_HP].m_rxpending = NULL; + (void) ath_legacy_flush_rxpending(sc); + (void) ath_legacy_flush_rxholdbf(sc); + + /* + * Re-chain all of the buffers in the RX buffer list. + */ TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) { int error = ath_rxbuf_init(sc, bf); if (error != 0) { @@ -1198,6 +1403,8 @@ ath_legacy_startrecv(struct ath_softc *sc) ath_hal_rxena(ah); /* enable recv descriptors */ ath_mode_init(sc); /* set filters, etc. */ ath_hal_startpcurecv(ah); /* re-enable PCU/DMA engine */ + + ATH_RX_UNLOCK(sc); return 0; } diff --git a/sys/dev/ath/if_ath_rx_edma.c b/sys/dev/ath/if_ath_rx_edma.c index 780367e7fb64f..a8758cfa268b7 100644 --- a/sys/dev/ath/if_ath_rx_edma.c +++ b/sys/dev/ath/if_ath_rx_edma.c @@ -286,7 +286,16 @@ ath_edma_recv_sched_queue(struct ath_softc *sc, HAL_RX_QUEUE qtype, int dosched) { + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ath_edma_recv_proc_queue(sc, qtype, dosched); + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask); } @@ -294,8 +303,17 @@ static void ath_edma_recv_sched(struct ath_softc *sc, int dosched) { + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, dosched); ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, dosched); + + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask); } @@ -309,6 +327,10 @@ ath_edma_recv_flush(struct ath_softc *sc) sc->sc_rxproc_cnt++; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + /* * Flush any active frames from FIFO -> deferred list */ @@ -318,9 +340,18 @@ ath_edma_recv_flush(struct ath_softc *sc) /* * Process what's in the deferred queue */ + /* + * XXX: If we read the tsf/channoise here and then pass it in, + * we could restore the power state before processing + * the deferred queue. + */ ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_HP, 0); ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_LP, 0); + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + ATH_PCU_LOCK(sc); sc->sc_rxproc_cnt--; ATH_PCU_UNLOCK(sc); @@ -560,12 +591,25 @@ ath_edma_recv_tasklet(void *arg, int npending) sc->sc_rxproc_cnt++; ATH_PCU_UNLOCK(sc); + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_HP, 1); ath_edma_recv_proc_queue(sc, HAL_RX_QUEUE_LP, 1); ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_HP, 1); ath_edma_recv_proc_deferred_queue(sc, HAL_RX_QUEUE_LP, 1); + /* + * XXX: If we read the tsf/channoise here and then pass it in, + * we could restore the power state before processing + * the deferred queue. + */ + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + /* XXX inside IF_LOCK ? */ if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { #ifdef IEEE80211_SUPPORT_SUPERG @@ -844,10 +888,13 @@ ath_edma_setup_rxfifo(struct ath_softc *sc, HAL_RX_QUEUE qtype) qtype); return (-EINVAL); } - device_printf(sc->sc_dev, "%s: type=%d, FIFO depth = %d entries\n", - __func__, - qtype, - re->m_fifolen); + + if (bootverbose) + device_printf(sc->sc_dev, + "%s: type=%d, FIFO depth = %d entries\n", + __func__, + qtype, + re->m_fifolen); /* Allocate ath_buf FIFO array, pre-zero'ed */ re->m_fifo = malloc(sizeof(struct ath_buf *) * re->m_fifolen, @@ -938,10 +985,12 @@ ath_recv_setup_edma(struct ath_softc *sc) (void) ath_hal_setrxbufsize(sc->sc_ah, sc->sc_edma_bufsize - sc->sc_rx_statuslen); - device_printf(sc->sc_dev, "RX status length: %d\n", - sc->sc_rx_statuslen); - device_printf(sc->sc_dev, "RX buffer size: %d\n", - sc->sc_edma_bufsize); + if (bootverbose) { + device_printf(sc->sc_dev, "RX status length: %d\n", + sc->sc_rx_statuslen); + device_printf(sc->sc_dev, "RX buffer size: %d\n", + sc->sc_edma_bufsize); + } sc->sc_rx.recv_stop = ath_edma_stoprecv; sc->sc_rx.recv_start = ath_edma_startrecv; diff --git a/sys/dev/ath/if_ath_sysctl.c b/sys/dev/ath/if_ath_sysctl.c index f1b6dd264c181..40a34d479db6e 100644 --- a/sys/dev/ath/if_ath_sysctl.c +++ b/sys/dev/ath/if_ath_sysctl.c @@ -108,13 +108,26 @@ static int ath_sysctl_slottime(SYSCTL_HANDLER_ARGS) { struct ath_softc *sc = arg1; - u_int slottime = ath_hal_getslottime(sc->sc_ah); + u_int slottime; int error; + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + slottime = ath_hal_getslottime(sc->sc_ah); + ATH_UNLOCK(sc); + error = sysctl_handle_int(oidp, &slottime, 0, req); if (error || !req->newptr) - return error; - return !ath_hal_setslottime(sc->sc_ah, slottime) ? EINVAL : 0; + goto finish; + + error = !ath_hal_setslottime(sc->sc_ah, slottime) ? EINVAL : 0; + +finish: + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + + return error; } static int @@ -400,12 +413,14 @@ ath_sysctl_txagg(SYSCTL_HANDLER_ARGS) ATH_RX_LOCK(sc); for (i = 0; i < 2; i++) { - printf("%d: fifolen: %d/%d; head=%d; tail=%d\n", + printf("%d: fifolen: %d/%d; head=%d; tail=%d; m_pending=%p, m_holdbf=%p\n", i, sc->sc_rxedma[i].m_fifo_depth, sc->sc_rxedma[i].m_fifolen, sc->sc_rxedma[i].m_fifo_head, - sc->sc_rxedma[i].m_fifo_tail); + sc->sc_rxedma[i].m_fifo_tail, + sc->sc_rxedma[i].m_rxpending, + sc->sc_rxedma[i].m_holdbf); } i = 0; TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) { diff --git a/sys/dev/ath/if_ath_tdma.c b/sys/dev/ath/if_ath_tdma.c index 3ea70e359a07f..de1a91ca02e90 100644 --- a/sys/dev/ath/if_ath_tdma.c +++ b/sys/dev/ath/if_ath_tdma.c @@ -477,16 +477,19 @@ ath_tdma_update(struct ieee80211_node *ni, DPRINTF(sc, ATH_DEBUG_TDMA_TIMER, "rs->rstamp %llu rstamp %llu tsf %llu txtime %d, nextslot %llu, " "nextslottu %d, nextslottume %d\n", - (unsigned long long) rs->rs_tstamp, rstamp, tsf, txtime, - nextslot, nextslottu, TSF_TO_TU(nextslot >> 32, nextslot)); + (unsigned long long) rs->rs_tstamp, + (unsigned long long) rstamp, + (unsigned long long) tsf, txtime, + (unsigned long long) nextslot, + nextslottu, TSF_TO_TU(nextslot >> 32, nextslot)); DPRINTF(sc, ATH_DEBUG_TDMA, " beacon tstamp: %llu (0x%016llx)\n", - le64toh(ni->ni_tstamp.tsf), - le64toh(ni->ni_tstamp.tsf)); + (unsigned long long) le64toh(ni->ni_tstamp.tsf), + (unsigned long long) le64toh(ni->ni_tstamp.tsf)); DPRINTF(sc, ATH_DEBUG_TDMA_TIMER, "nexttbtt %llu (0x%08llx) tsfdelta %d avg +%d/-%d\n", - nexttbtt, + (unsigned long long) nexttbtt, (long long) nexttbtt, tsfdelta, TDMA_AVG(sc->sc_avgtsfdeltap), TDMA_AVG(sc->sc_avgtsfdeltam)); @@ -580,7 +583,7 @@ ath_tdma_update(struct ieee80211_node *ni, DPRINTF(sc, ATH_DEBUG_TDMA_TIMER, "%s: calling ath_hal_adjusttsf: TSF=%llu, tsfdelta=%d\n", __func__, - tsf, + (unsigned long long) tsf, tsfdelta); #ifdef ATH_DEBUG_ALQ diff --git a/sys/dev/ath/if_ath_tx.c b/sys/dev/ath/if_ath_tx.c index d4e3ebd378725..1b140da6b0775 100644 --- a/sys/dev/ath/if_ath_tx.c +++ b/sys/dev/ath/if_ath_tx.c @@ -761,37 +761,21 @@ ath_tx_handoff_hw(struct ath_softc *sc, struct ath_txq *txq, ("ath_tx_handoff_hw called for mcast queue")); /* - * XXX racy, should hold the PCU lock when checking this, - * and also should ensure that the TX counter is >0! + * XXX We should instead just verify that sc_txstart_cnt + * or ath_txproc_cnt > 0. That would mean that + * the reset is going to be waiting for us to complete. */ - KASSERT((sc->sc_inreset_cnt == 0), - ("%s: TX during reset?\n", __func__)); + if (sc->sc_txproc_cnt == 0 && sc->sc_txstart_cnt == 0) { + device_printf(sc->sc_dev, + "%s: TX dispatch without holding txcount/txstart refcnt!\n", + __func__); + } -#if 0 /* - * This causes a LOR. Find out where the PCU lock is being - * held whilst the TXQ lock is grabbed - that shouldn't - * be occuring. + * XXX .. this is going to cause the hardware to get upset; + * so we really should find some way to drop or queue + * things. */ - ATH_PCU_LOCK(sc); - if (sc->sc_inreset_cnt) { - ATH_PCU_UNLOCK(sc); - DPRINTF(sc, ATH_DEBUG_RESET, - "%s: called with sc_in_reset != 0\n", - __func__); - DPRINTF(sc, ATH_DEBUG_XMIT, - "%s: queued: TXDP[%u] = %p (%p) depth %d\n", - __func__, txq->axq_qnum, - (caddr_t)bf->bf_daddr, bf->bf_desc, - txq->axq_depth); - /* XXX axq_link needs to be set and updated! */ - ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); - if (bf->bf_state.bfs_aggr) - txq->axq_aggr_depth++; - return; - } - ATH_PCU_UNLOCK(sc); -#endif ATH_TXQ_LOCK(txq); @@ -1615,6 +1599,7 @@ ath_tx_normal_setup(struct ath_softc *sc, struct ieee80211_node *ni, error = ath_tx_dmasetup(sc, bf, m0); if (error != 0) return error; + KASSERT((ni != NULL), ("%s: ni=NULL!", __func__)); bf->bf_node = ni; /* NB: held reference */ m0 = bf->bf_m; /* NB: may have changed */ wh = mtod(m0, struct ieee80211_frame *); @@ -2106,6 +2091,7 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni, int do_override; uint8_t type, subtype; int queue_to_head; + struct ath_node *an = ATH_NODE(ni); ATH_TX_LOCK_ASSERT(sc); @@ -2165,6 +2151,7 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni, return error; m0 = bf->bf_m; /* NB: may have changed */ wh = mtod(m0, struct ieee80211_frame *); + KASSERT((ni != NULL), ("%s: ni=NULL!", __func__)); bf->bf_node = ni; /* NB: held reference */ /* Always enable CLRDMASK for raw frames for now.. */ @@ -2183,12 +2170,24 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni, rt = sc->sc_currates; KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); + + /* Fetch first rate information */ rix = ath_tx_findrix(sc, params->ibp_rate0); + try0 = params->ibp_try0; + + /* + * Override EAPOL rate as appropriate. + */ + if (m0->m_flags & M_EAPOL) { + /* XXX? maybe always use long preamble? */ + rix = an->an_mgmtrix; + try0 = ATH_TXMAXTRY; /* XXX?too many? */ + } + txrate = rt->info[rix].rateCode; if (params->ibp_flags & IEEE80211_BPF_SHORTPRE) txrate |= rt->info[rix].shortPreamble; sc->sc_txrix = rix; - try0 = params->ibp_try0; ismrr = (params->ibp_try1 != 0); txantenna = params->ibp_pri >> 2; if (txantenna == 0) /* XXX? */ @@ -2261,8 +2260,7 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni, /* Blank the legacy rate array */ bzero(&bf->bf_state.bfs_rc, sizeof(bf->bf_state.bfs_rc)); - bf->bf_state.bfs_rc[0].rix = - ath_tx_findrix(sc, params->ibp_rate0); + bf->bf_state.bfs_rc[0].rix = rix; bf->bf_state.bfs_rc[0].tries = try0; bf->bf_state.bfs_rc[0].ratecode = txrate; @@ -2354,11 +2352,16 @@ ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, "%s: sc_inreset_cnt > 0; bailing\n", __func__); error = EIO; ATH_PCU_UNLOCK(sc); - goto bad0; + goto badbad; } sc->sc_txstart_cnt++; ATH_PCU_UNLOCK(sc); + /* Wake the hardware up already */ + ATH_LOCK(sc); + ath_power_set_power_state(sc, HAL_PM_AWAKE); + ATH_UNLOCK(sc); + ATH_TX_LOCK(sc); if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) { @@ -2437,7 +2440,14 @@ ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, sc->sc_txstart_cnt--; ATH_PCU_UNLOCK(sc); + + /* Put the hardware back to sleep if required */ + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + return 0; + bad2: ATH_KTR(sc, ATH_KTR_TX, 3, "ath_raw_xmit: bad2: m=%p, params=%p, " "bf=%p", @@ -2447,14 +2457,20 @@ bad2: ATH_TXBUF_LOCK(sc); ath_returnbuf_head(sc, bf); ATH_TXBUF_UNLOCK(sc); -bad: +bad: ATH_TX_UNLOCK(sc); ATH_PCU_LOCK(sc); sc->sc_txstart_cnt--; ATH_PCU_UNLOCK(sc); -bad0: + + /* Put the hardware back to sleep if required */ + ATH_LOCK(sc); + ath_power_restore_power_state(sc); + ATH_UNLOCK(sc); + +badbad: ATH_KTR(sc, ATH_KTR_TX, 2, "ath_raw_xmit: bad0: m=%p, params=%p", m, params); ifp->if_oerrors++; diff --git a/sys/dev/ath/if_ath_tx_edma.c b/sys/dev/ath/if_ath_tx_edma.c index 3405d4a34315e..7d149203d3ed0 100644 --- a/sys/dev/ath/if_ath_tx_edma.c +++ b/sys/dev/ath/if_ath_tx_edma.c @@ -866,12 +866,14 @@ ath_xmit_setup_edma(struct ath_softc *sc) (void) ath_hal_gettxstatuslen(sc->sc_ah, &sc->sc_tx_statuslen); (void) ath_hal_getntxmaps(sc->sc_ah, &sc->sc_tx_nmaps); - device_printf(sc->sc_dev, "TX descriptor length: %d\n", - sc->sc_tx_desclen); - device_printf(sc->sc_dev, "TX status length: %d\n", - sc->sc_tx_statuslen); - device_printf(sc->sc_dev, "TX buffers per descriptor: %d\n", - sc->sc_tx_nmaps); + if (bootverbose) { + device_printf(sc->sc_dev, "TX descriptor length: %d\n", + sc->sc_tx_desclen); + device_printf(sc->sc_dev, "TX status length: %d\n", + sc->sc_tx_statuslen); + device_printf(sc->sc_dev, "TX buffers per descriptor: %d\n", + sc->sc_tx_nmaps); + } sc->sc_tx.xmit_setup = ath_edma_dma_txsetup; sc->sc_tx.xmit_teardown = ath_edma_dma_txteardown; diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index 6b074d6c95c50..d1ae089f49b8f 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -510,6 +510,7 @@ struct ath_rx_edma { int m_fifo_tail; int m_fifo_depth; struct mbuf *m_rxpending; + struct ath_buf *m_holdbf; }; struct ath_tx_edma_fifo { @@ -621,7 +622,8 @@ struct ath_softc { sc_resetcal : 1,/* reset cal state next trip */ sc_rxslink : 1,/* do self-linked final descriptor */ sc_rxtsf32 : 1,/* RX dec TSF is 32 bits */ - sc_isedma : 1;/* supports EDMA */ + sc_isedma : 1,/* supports EDMA */ + sc_do_mybeacon : 1; /* supports mybeacon */ /* * Second set of flags. @@ -864,6 +866,22 @@ struct ath_softc { void (*sc_bar_response)(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, int status); + + /* + * Powersave state tracking. + * + * target/cur powerstate is the chip power state. + * target selfgen state is the self-generated frames + * state. The chip can be awake but transmitted frames + * can have the PWRMGT bit set to 1 so the destination + * thinks the node is asleep. + */ + HAL_POWER_MODE sc_target_powerstate; + HAL_POWER_MODE sc_target_selfgen_state; + + HAL_POWER_MODE sc_cur_powerstate; + + int sc_powersave_refcnt; }; #define ATH_LOCK_INIT(_sc) \ @@ -1038,6 +1056,8 @@ void ath_intr(void *); ((*(_ah)->ah_updateTxTrigLevel)((_ah), (_inc))) #define ath_hal_setpower(_ah, _mode) \ ((*(_ah)->ah_setPowerMode)((_ah), (_mode), AH_TRUE)) +#define ath_hal_setselfgenpower(_ah, _mode) \ + ((*(_ah)->ah_setPowerMode)((_ah), (_mode), AH_FALSE)) #define ath_hal_keycachesize(_ah) \ ((*(_ah)->ah_getKeyCacheSize)((_ah))) #define ath_hal_keyreset(_ah, _ix) \ @@ -1266,6 +1286,8 @@ void ath_intr(void *); #define ath_hal_setintmit(_ah, _v) \ ath_hal_setcapability(_ah, HAL_CAP_INTMIT, \ HAL_CAP_INTMIT_ENABLE, _v, NULL) +#define ath_hal_hasmybeacon(_ah) \ + (ath_hal_getcapability(_ah, HAL_CAP_DO_MYBEACON, 1, NULL) == HAL_OK) #define ath_hal_hasenforcetxop(_ah) \ (ath_hal_getcapability(_ah, HAL_CAP_ENFORCE_TXOP, 0, NULL) == HAL_OK) diff --git a/sys/dev/bce/if_bce.c b/sys/dev/bce/if_bce.c index a93b8afad5678..1605d24c50622 100644 --- a/sys/dev/bce/if_bce.c +++ b/sys/dev/bce/if_bce.c @@ -1,6 +1,5 @@ /*- - * Copyright (c) 2006-2010 Broadcom Corporation - * David Christensen <davidch@broadcom.com>. All rights reserved. + * Copyright (c) 2006-2014 QLogic Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -11,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -154,13 +150,13 @@ static const struct bce_type bce_devs[] = { { BRCM_VENDORID, BRCM_DEVICEID_BCM5706, HP_VENDORID, 0x1709, "HP NC371i Multifunction Gigabit Server Adapter" }, { BRCM_VENDORID, BRCM_DEVICEID_BCM5706, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM5706 1000Base-T" }, + "QLogic NetXtreme II BCM5706 1000Base-T" }, /* BCM5706S controllers and OEM boards. */ { BRCM_VENDORID, BRCM_DEVICEID_BCM5706S, HP_VENDORID, 0x3102, "HP NC370F Multifunction Gigabit Server Adapter" }, { BRCM_VENDORID, BRCM_DEVICEID_BCM5706S, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM5706 1000Base-SX" }, + "QLogic NetXtreme II BCM5706 1000Base-SX" }, /* BCM5708C controllers and OEM boards. */ { BRCM_VENDORID, BRCM_DEVICEID_BCM5708, HP_VENDORID, 0x7037, @@ -170,7 +166,7 @@ static const struct bce_type bce_devs[] = { { BRCM_VENDORID, BRCM_DEVICEID_BCM5708, HP_VENDORID, 0x7045, "HP NC374m PCIe Multifunction Adapter" }, { BRCM_VENDORID, BRCM_DEVICEID_BCM5708, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM5708 1000Base-T" }, + "QLogic NetXtreme II BCM5708 1000Base-T" }, /* BCM5708S controllers and OEM boards. */ { BRCM_VENDORID, BRCM_DEVICEID_BCM5708S, HP_VENDORID, 0x1706, @@ -180,7 +176,7 @@ static const struct bce_type bce_devs[] = { { BRCM_VENDORID, BRCM_DEVICEID_BCM5708S, HP_VENDORID, 0x703d, "HP NC373F PCIe Multifunc Giga Server Adapter" }, { BRCM_VENDORID, BRCM_DEVICEID_BCM5708S, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM5708 1000Base-SX" }, + "QLogic NetXtreme II BCM5708 1000Base-SX" }, /* BCM5709C controllers and OEM boards. */ { BRCM_VENDORID, BRCM_DEVICEID_BCM5709, HP_VENDORID, 0x7055, @@ -188,7 +184,7 @@ static const struct bce_type bce_devs[] = { { BRCM_VENDORID, BRCM_DEVICEID_BCM5709, HP_VENDORID, 0x7059, "HP NC382T PCIe DP Multifunction Gigabit Server Adapter" }, { BRCM_VENDORID, BRCM_DEVICEID_BCM5709, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM5709 1000Base-T" }, + "QLogic NetXtreme II BCM5709 1000Base-T" }, /* BCM5709S controllers and OEM boards. */ { BRCM_VENDORID, BRCM_DEVICEID_BCM5709S, HP_VENDORID, 0x171d, @@ -196,11 +192,11 @@ static const struct bce_type bce_devs[] = { { BRCM_VENDORID, BRCM_DEVICEID_BCM5709S, HP_VENDORID, 0x7056, "HP NC382i DP Multifunction Gigabit Server Adapter" }, { BRCM_VENDORID, BRCM_DEVICEID_BCM5709S, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM5709 1000Base-SX" }, + "QLogic NetXtreme II BCM5709 1000Base-SX" }, /* BCM5716 controllers and OEM boards. */ { BRCM_VENDORID, BRCM_DEVICEID_BCM5716, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM5716 1000Base-T" }, + "QLogic NetXtreme II BCM5716 1000Base-T" }, { 0, 0, 0, 0, NULL } }; diff --git a/sys/dev/bce/if_bcefw.h b/sys/dev/bce/if_bcefw.h index 8d97b31c0e6b9..fa0d528a126bc 100644 --- a/sys/dev/bce/if_bcefw.h +++ b/sys/dev/bce/if_bcefw.h @@ -1,6 +1,5 @@ /*- - * Copyright (c) 2006-2011 Broadcom Corporation - * David Christensen <davidch@broadcom.com>. All rights reserved. + * Copyright (c) 2006-2014 QLogic Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,9 +9,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -31,7 +27,7 @@ /* * This file contains firmware data derived from proprietary unpublished - * source code, Copyright (c) 2004-2011 Broadcom Corporation. + * source code, Copyright (c) 2004-2014 QLogic Corporation. * * Permission is hereby granted for the distribution of this firmware data * in hexadecimal or equivalent format, provided this copyright notice also diff --git a/sys/dev/bce/if_bcereg.h b/sys/dev/bce/if_bcereg.h index 88c40a5f82188..16f99ccdf55ea 100644 --- a/sys/dev/bce/if_bcereg.h +++ b/sys/dev/bce/if_bcereg.h @@ -1,6 +1,5 @@ /*- - * Copyright (c) 2006-2010 Broadcom Corporation - * David Christensen <davidch@broadcom.com>. All rights reserved. + * Copyright (c) 2006-2014 QLogic Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,9 +9,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/57710_init_values.c b/sys/dev/bxe/57710_init_values.c index 90cf332b520c5..3122c336a50fc 100644 --- a/sys/dev/bxe/57710_init_values.c +++ b/sys/dev/bxe/57710_init_values.c @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/57710_int_offsets.h b/sys/dev/bxe/57710_int_offsets.h index 543417953294e..c4c0faca7de05 100644 --- a/sys/dev/bxe/57710_int_offsets.h +++ b/sys/dev/bxe/57710_int_offsets.h @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/57711_init_values.c b/sys/dev/bxe/57711_init_values.c index 20747192e1d3a..8b15d00b65542 100644 --- a/sys/dev/bxe/57711_init_values.c +++ b/sys/dev/bxe/57711_init_values.c @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/57711_int_offsets.h b/sys/dev/bxe/57711_int_offsets.h index 449b960e0d268..a3ebbf36da0d5 100644 --- a/sys/dev/bxe/57711_int_offsets.h +++ b/sys/dev/bxe/57711_int_offsets.h @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/57712_init_values.c b/sys/dev/bxe/57712_init_values.c index 3f98bf4923cdd..112a1122e9cba 100644 --- a/sys/dev/bxe/57712_init_values.c +++ b/sys/dev/bxe/57712_init_values.c @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/57712_int_offsets.h b/sys/dev/bxe/57712_int_offsets.h index 3f6e83b3b202b..437de0b21e9c0 100644 --- a/sys/dev/bxe/57712_int_offsets.h +++ b/sys/dev/bxe/57712_int_offsets.h @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/bxe.c b/sys/dev/bxe/bxe.c index eb812d7ef157f..b6583d9cdfa25 100644 --- a/sys/dev/bxe/bxe.c +++ b/sys/dev/bxe/bxe.c @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -105,126 +98,126 @@ static struct bxe_device_type bxe_devs[] = { BRCM_VENDORID, CHIP_NUM_57710, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57710 10GbE" + "QLogic NetXtreme II BCM57710 10GbE" }, { BRCM_VENDORID, CHIP_NUM_57711, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57711 10GbE" + "QLogic NetXtreme II BCM57711 10GbE" }, { BRCM_VENDORID, CHIP_NUM_57711E, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57711E 10GbE" + "QLogic NetXtreme II BCM57711E 10GbE" }, { BRCM_VENDORID, CHIP_NUM_57712, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57712 10GbE" + "QLogic NetXtreme II BCM57712 10GbE" }, { BRCM_VENDORID, CHIP_NUM_57712_MF, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57712 MF 10GbE" + "QLogic NetXtreme II BCM57712 MF 10GbE" }, #if 0 { BRCM_VENDORID, CHIP_NUM_57712_VF, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57712 VF 10GbE" + "QLogic NetXtreme II BCM57712 VF 10GbE" }, #endif { BRCM_VENDORID, CHIP_NUM_57800, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57800 10GbE" + "QLogic NetXtreme II BCM57800 10GbE" }, { BRCM_VENDORID, CHIP_NUM_57800_MF, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57800 MF 10GbE" + "QLogic NetXtreme II BCM57800 MF 10GbE" }, #if 0 { BRCM_VENDORID, CHIP_NUM_57800_VF, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57800 VF 10GbE" + "QLogic NetXtreme II BCM57800 VF 10GbE" }, #endif { BRCM_VENDORID, CHIP_NUM_57810, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57810 10GbE" + "QLogic NetXtreme II BCM57810 10GbE" }, { BRCM_VENDORID, CHIP_NUM_57810_MF, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57810 MF 10GbE" + "QLogic NetXtreme II BCM57810 MF 10GbE" }, #if 0 { BRCM_VENDORID, CHIP_NUM_57810_VF, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57810 VF 10GbE" + "QLogic NetXtreme II BCM57810 VF 10GbE" }, #endif { BRCM_VENDORID, CHIP_NUM_57811, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57811 10GbE" + "QLogic NetXtreme II BCM57811 10GbE" }, { BRCM_VENDORID, CHIP_NUM_57811_MF, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57811 MF 10GbE" + "QLogic NetXtreme II BCM57811 MF 10GbE" }, #if 0 { BRCM_VENDORID, CHIP_NUM_57811_VF, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57811 VF 10GbE" + "QLogic NetXtreme II BCM57811 VF 10GbE" }, #endif { BRCM_VENDORID, CHIP_NUM_57840_4_10, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57840 4x10GbE" + "QLogic NetXtreme II BCM57840 4x10GbE" }, #if 0 { BRCM_VENDORID, CHIP_NUM_57840_2_20, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57840 2x20GbE" + "QLogic NetXtreme II BCM57840 2x20GbE" }, #endif { BRCM_VENDORID, CHIP_NUM_57840_MF, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57840 MF 10GbE" + "QLogic NetXtreme II BCM57840 MF 10GbE" }, #if 0 { BRCM_VENDORID, CHIP_NUM_57840_VF, PCI_ANY_ID, PCI_ANY_ID, - "Broadcom NetXtreme II BCM57840 VF 10GbE" + "QLogic NetXtreme II BCM57840 VF 10GbE" }, #endif { diff --git a/sys/dev/bxe/bxe.h b/sys/dev/bxe/bxe.h index 47a0b79e6ce66..a0709f630d355 100644 --- a/sys/dev/bxe/bxe.h +++ b/sys/dev/bxe/bxe.h @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/bxe_dcb.h b/sys/dev/bxe/bxe_dcb.h index 01beb8e02172a..79515e0010630 100644 --- a/sys/dev/bxe/bxe_dcb.h +++ b/sys/dev/bxe/bxe_dcb.h @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/bxe_debug.c b/sys/dev/bxe/bxe_debug.c index 328779f9c5a07..32db18aa3af24 100644 --- a/sys/dev/bxe/bxe_debug.c +++ b/sys/dev/bxe/bxe_debug.c @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/bxe_elink.c b/sys/dev/bxe/bxe_elink.c index f4e280151ab9e..64f6852574dad 100644 --- a/sys/dev/bxe/bxe_elink.c +++ b/sys/dev/bxe/bxe_elink.c @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/bxe_elink.h b/sys/dev/bxe/bxe_elink.h index dd5d406e18e06..a5be6a305dbf4 100644 --- a/sys/dev/bxe/bxe_elink.h +++ b/sys/dev/bxe/bxe_elink.h @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/bxe_stats.c b/sys/dev/bxe/bxe_stats.c index 977f6cfb25919..cfecc22ce8a29 100644 --- a/sys/dev/bxe/bxe_stats.c +++ b/sys/dev/bxe/bxe_stats.c @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/bxe_stats.h b/sys/dev/bxe/bxe_stats.h index 09a8a17592f80..cb98201abb131 100644 --- a/sys/dev/bxe/bxe_stats.h +++ b/sys/dev/bxe/bxe_stats.h @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/ecore_fw_defs.h b/sys/dev/bxe/ecore_fw_defs.h index c585cbffffb0f..30754f723eec3 100644 --- a/sys/dev/bxe/ecore_fw_defs.h +++ b/sys/dev/bxe/ecore_fw_defs.h @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/ecore_hsi.h b/sys/dev/bxe/ecore_hsi.h index bfffcec345845..005bb2e4dbce2 100644 --- a/sys/dev/bxe/ecore_hsi.h +++ b/sys/dev/bxe/ecore_hsi.h @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/ecore_init.h b/sys/dev/bxe/ecore_init.h index 21242acd6d6c8..7eab8112453bf 100644 --- a/sys/dev/bxe/ecore_init.h +++ b/sys/dev/bxe/ecore_init.h @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/ecore_init_ops.h b/sys/dev/bxe/ecore_init_ops.h index ff373a8948530..5d8dee41d36d3 100644 --- a/sys/dev/bxe/ecore_init_ops.h +++ b/sys/dev/bxe/ecore_init_ops.h @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/ecore_mfw_req.h b/sys/dev/bxe/ecore_mfw_req.h index 136d0f5ae715c..26884f8450b55 100644 --- a/sys/dev/bxe/ecore_mfw_req.h +++ b/sys/dev/bxe/ecore_mfw_req.h @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/ecore_reg.h b/sys/dev/bxe/ecore_reg.h index 3c8de57a1b9a3..916df8f339814 100644 --- a/sys/dev/bxe/ecore_reg.h +++ b/sys/dev/bxe/ecore_reg.h @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/ecore_sp.c b/sys/dev/bxe/ecore_sp.c index c33e42ed9294a..b716085222de3 100644 --- a/sys/dev/bxe/ecore_sp.c +++ b/sys/dev/bxe/ecore_sp.c @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/bxe/ecore_sp.h b/sys/dev/bxe/ecore_sp.h index ccb83eb1fead8..c3d9c3a85399a 100644 --- a/sys/dev/bxe/ecore_sp.h +++ b/sys/dev/bxe/ecore_sp.h @@ -1,9 +1,5 @@ /*- - * Copyright (c) 2007-2013 Broadcom Corporation. All rights reserved. - * - * Eric Davis <edavis@broadcom.com> - * David Christensen <davidch@broadcom.com> - * Gary Zambrano <zambrano@broadcom.com> + * Copyright (c) 2007-2014 QLogic Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,9 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Broadcom Corporation nor the name of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written consent. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE diff --git a/sys/dev/drm2/i915/i915_gem.c b/sys/dev/drm2/i915/i915_gem.c index 9af50d8f32dd5..99821e49ae1a3 100644 --- a/sys/dev/drm2/i915/i915_gem.c +++ b/sys/dev/drm2/i915/i915_gem.c @@ -1431,6 +1431,7 @@ retry: m = vm_phys_fictitious_to_vm_page(dev->agp->base + obj->gtt_offset + offset); if (m == NULL) { + VM_OBJECT_WUNLOCK(vm_obj); cause = 60; ret = -EFAULT; goto unlock; @@ -1450,7 +1451,6 @@ retry: DRM_UNLOCK(dev); VM_OBJECT_WUNLOCK(vm_obj); VM_WAIT; - VM_OBJECT_WLOCK(vm_obj); goto retry; } m->valid = VM_PAGE_BITS_ALL; diff --git a/sys/dev/drm2/radeon/radeon_drv.c b/sys/dev/drm2/radeon/radeon_drv.c index 0cf96d2aac5e7..37b4e265ffc32 100644 --- a/sys/dev/drm2/radeon/radeon_drv.c +++ b/sys/dev/drm2/radeon/radeon_drv.c @@ -85,6 +85,10 @@ extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos); extern struct drm_ioctl_desc radeon_ioctls_kms[]; extern int radeon_max_kms_ioctl; +#ifdef COMPAT_FREEBSD32 +extern struct drm_ioctl_desc radeon_compat_ioctls[]; +extern int radeon_num_compat_ioctls; +#endif #ifdef DUMBBELL_WIP int radeon_mmap(struct file *filp, struct vm_area_struct *vma); #endif /* DUMBBELL_WIP */ @@ -466,6 +470,10 @@ radeon_attach(device_t kdev) if (radeon_modeset == 1) { kms_driver.driver_features |= DRIVER_MODESET; kms_driver.max_ioctl = radeon_max_kms_ioctl; +#ifdef COMPAT_FREEBSD32 + kms_driver.compat_ioctls = radeon_compat_ioctls; + kms_driver.compat_ioctls_nr = &radeon_num_compat_ioctls; +#endif radeon_register_atpx_handler(); } dev->driver = &kms_driver; diff --git a/sys/dev/drm2/radeon/radeon_ioc32.c b/sys/dev/drm2/radeon/radeon_ioc32.c index 361d48cb3f48c..ee691be95e2a8 100644 --- a/sys/dev/drm2/radeon/radeon_ioc32.c +++ b/sys/dev/drm2/radeon/radeon_ioc32.c @@ -31,10 +31,13 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <linux/compat.h> +#include "opt_compat.h" -#include <drm/drmP.h> -#include <drm/radeon_drm.h> +#ifdef COMPAT_FREEBSD32 + +#include <dev/drm2/drmP.h> +#include <dev/drm2/drm.h> +#include <dev/drm2/radeon/radeon_drm.h> #include "radeon_drv.h" typedef struct drm_radeon_init32 { @@ -60,42 +63,37 @@ typedef struct drm_radeon_init32 { u32 gart_textures_offset; } drm_radeon_init32_t; -static int compat_radeon_cp_init(struct file *file, unsigned int cmd, - unsigned long arg) +static int compat_radeon_cp_init(struct drm_device *dev, void *arg, + struct drm_file *file_priv) { - drm_radeon_init32_t init32; - drm_radeon_init_t __user *init; - - if (copy_from_user(&init32, (void __user *)arg, sizeof(init32))) - return -EFAULT; - - init = compat_alloc_user_space(sizeof(*init)); - if (!access_ok(VERIFY_WRITE, init, sizeof(*init)) - || __put_user(init32.func, &init->func) - || __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset) - || __put_user(init32.is_pci, &init->is_pci) - || __put_user(init32.cp_mode, &init->cp_mode) - || __put_user(init32.gart_size, &init->gart_size) - || __put_user(init32.ring_size, &init->ring_size) - || __put_user(init32.usec_timeout, &init->usec_timeout) - || __put_user(init32.fb_bpp, &init->fb_bpp) - || __put_user(init32.front_offset, &init->front_offset) - || __put_user(init32.front_pitch, &init->front_pitch) - || __put_user(init32.back_offset, &init->back_offset) - || __put_user(init32.back_pitch, &init->back_pitch) - || __put_user(init32.depth_bpp, &init->depth_bpp) - || __put_user(init32.depth_offset, &init->depth_offset) - || __put_user(init32.depth_pitch, &init->depth_pitch) - || __put_user(init32.fb_offset, &init->fb_offset) - || __put_user(init32.mmio_offset, &init->mmio_offset) - || __put_user(init32.ring_offset, &init->ring_offset) - || __put_user(init32.ring_rptr_offset, &init->ring_rptr_offset) - || __put_user(init32.buffers_offset, &init->buffers_offset) - || __put_user(init32.gart_textures_offset, - &init->gart_textures_offset)) - return -EFAULT; - - return drm_ioctl(file, DRM_IOCTL_RADEON_CP_INIT, (unsigned long)init); + drm_radeon_init32_t *init32; + drm_radeon_init_t __user init; + + init32 = arg; + + init.func = init32->func; + init.sarea_priv_offset = (unsigned long)init32->sarea_priv_offset; + init.is_pci = init32->is_pci; + init.cp_mode = init32->cp_mode; + init.gart_size = init32->gart_size; + init.ring_size = init32->ring_size; + init.usec_timeout = init32->usec_timeout; + init.fb_bpp = init32->fb_bpp; + init.front_offset = init32->front_offset; + init.front_pitch = init32->front_pitch; + init.back_offset = init32->back_offset; + init.back_pitch = init32->back_pitch; + init.depth_bpp = init32->depth_bpp; + init.depth_offset = init32->depth_offset; + init.depth_pitch = init32->depth_pitch; + init.fb_offset = (unsigned long)init32->fb_offset; + init.mmio_offset = (unsigned long)init32->mmio_offset; + init.ring_offset = (unsigned long)init32->ring_offset; + init.ring_rptr_offset = (unsigned long)init32->ring_rptr_offset; + init.buffers_offset = (unsigned long)init32->buffers_offset; + init.gart_textures_offset = (unsigned long)init32->gart_textures_offset; + + return radeon_cp_init(dev, &init, file_priv); } typedef struct drm_radeon_clear32 { @@ -107,50 +105,37 @@ typedef struct drm_radeon_clear32 { u32 depth_boxes; } drm_radeon_clear32_t; -static int compat_radeon_cp_clear(struct file *file, unsigned int cmd, - unsigned long arg) +static int compat_radeon_cp_clear(struct drm_device *dev, void *arg, + struct drm_file *file_priv) { - drm_radeon_clear32_t clr32; - drm_radeon_clear_t __user *clr; - - if (copy_from_user(&clr32, (void __user *)arg, sizeof(clr32))) - return -EFAULT; - - clr = compat_alloc_user_space(sizeof(*clr)); - if (!access_ok(VERIFY_WRITE, clr, sizeof(*clr)) - || __put_user(clr32.flags, &clr->flags) - || __put_user(clr32.clear_color, &clr->clear_color) - || __put_user(clr32.clear_depth, &clr->clear_depth) - || __put_user(clr32.color_mask, &clr->color_mask) - || __put_user(clr32.depth_mask, &clr->depth_mask) - || __put_user((void __user *)(unsigned long)clr32.depth_boxes, - &clr->depth_boxes)) - return -EFAULT; - - return drm_ioctl(file, DRM_IOCTL_RADEON_CLEAR, (unsigned long)clr); + drm_radeon_clear32_t *clr32; + drm_radeon_clear_t __user clr; + + clr32 = arg; + + clr.flags = clr32->flags; + clr.clear_color = clr32->clear_color; + clr.clear_depth = clr32->clear_depth; + clr.color_mask = clr32->color_mask; + clr.depth_mask = clr32->depth_mask; + clr.depth_boxes = (drm_radeon_clear_rect_t *)(unsigned long)clr32->depth_boxes; + + return radeon_ioctls[DRM_IOCTL_RADEON_CLEAR].func(dev, &clr, file_priv); } typedef struct drm_radeon_stipple32 { u32 mask; } drm_radeon_stipple32_t; -static int compat_radeon_cp_stipple(struct file *file, unsigned int cmd, - unsigned long arg) +static int compat_radeon_cp_stipple(struct drm_device *dev, void *arg, + struct drm_file *file_priv) { drm_radeon_stipple32_t __user *argp = (void __user *)arg; - drm_radeon_stipple_t __user *request; - u32 mask; - - if (get_user(mask, &argp->mask)) - return -EFAULT; + drm_radeon_stipple_t __user request; - request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) - || __put_user((unsigned int __user *)(unsigned long)mask, - &request->mask)) - return -EFAULT; + request.mask = (unsigned int *)(unsigned long)argp->mask; - return drm_ioctl(file, DRM_IOCTL_RADEON_STIPPLE, (unsigned long)request); + return radeon_ioctls[DRM_IOCTL_RADEON_STIPPLE].func(dev, &request, file_priv); } typedef struct drm_radeon_tex_image32 { @@ -168,43 +153,32 @@ typedef struct drm_radeon_texture32 { u32 image; } drm_radeon_texture32_t; -static int compat_radeon_cp_texture(struct file *file, unsigned int cmd, - unsigned long arg) +static int compat_radeon_cp_texture(struct drm_device *dev, void *arg, + struct drm_file *file_priv) { - drm_radeon_texture32_t req32; - drm_radeon_texture_t __user *request; - drm_radeon_tex_image32_t img32; - drm_radeon_tex_image_t __user *image; - - if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) - return -EFAULT; - if (req32.image == 0) + drm_radeon_texture32_t *req32; + drm_radeon_texture_t __user request; + drm_radeon_tex_image32_t *img32; + drm_radeon_tex_image_t __user image; + + req32 = arg; + if (req32->image == 0) return -EINVAL; - if (copy_from_user(&img32, (void __user *)(unsigned long)req32.image, - sizeof(img32))) - return -EFAULT; - - request = compat_alloc_user_space(sizeof(*request) + sizeof(*image)); - if (!access_ok(VERIFY_WRITE, request, - sizeof(*request) + sizeof(*image))) - return -EFAULT; - image = (drm_radeon_tex_image_t __user *) (request + 1); - - if (__put_user(req32.offset, &request->offset) - || __put_user(req32.pitch, &request->pitch) - || __put_user(req32.format, &request->format) - || __put_user(req32.width, &request->width) - || __put_user(req32.height, &request->height) - || __put_user(image, &request->image) - || __put_user(img32.x, &image->x) - || __put_user(img32.y, &image->y) - || __put_user(img32.width, &image->width) - || __put_user(img32.height, &image->height) - || __put_user((const void __user *)(unsigned long)img32.data, - &image->data)) - return -EFAULT; - - return drm_ioctl(file, DRM_IOCTL_RADEON_TEXTURE, (unsigned long)request); + img32 = (drm_radeon_tex_image32_t *)(unsigned long)req32->image; + + request.offset = req32->offset; + request.pitch = req32->pitch; + request.format = req32->format; + request.width = req32->width; + request.height = req32->height; + request.image = ℑ + image.x = img32->x; + image.y = img32->y; + image.width = img32->width; + image.height = img32->height; + image.data = (void *)(unsigned long)img32->data; + + return radeon_ioctls[DRM_IOCTL_RADEON_TEXTURE].func(dev, &request, file_priv); } typedef struct drm_radeon_vertex2_32 { @@ -216,28 +190,22 @@ typedef struct drm_radeon_vertex2_32 { u32 prim; } drm_radeon_vertex2_32_t; -static int compat_radeon_cp_vertex2(struct file *file, unsigned int cmd, - unsigned long arg) +static int compat_radeon_cp_vertex2(struct drm_device *dev, void *arg, + struct drm_file *file_priv) { - drm_radeon_vertex2_32_t req32; - drm_radeon_vertex2_t __user *request; - - if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) - return -EFAULT; - - request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) - || __put_user(req32.idx, &request->idx) - || __put_user(req32.discard, &request->discard) - || __put_user(req32.nr_states, &request->nr_states) - || __put_user((void __user *)(unsigned long)req32.state, - &request->state) - || __put_user(req32.nr_prims, &request->nr_prims) - || __put_user((void __user *)(unsigned long)req32.prim, - &request->prim)) - return -EFAULT; - - return drm_ioctl(file, DRM_IOCTL_RADEON_VERTEX2, (unsigned long)request); + drm_radeon_vertex2_32_t *req32; + drm_radeon_vertex2_t __user request; + + req32 = arg; + + request.idx = req32->idx; + request.discard = req32->discard; + request.nr_states = req32->nr_states; + request.state = (drm_radeon_state_t *)(unsigned long)req32->state; + request.nr_prims = req32->nr_prims; + request.prim = (drm_radeon_prim_t *)(unsigned long)req32->prim; + + return radeon_ioctls[DRM_IOCTL_RADEON_VERTEX2].func(dev, &request, file_priv); } typedef struct drm_radeon_cmd_buffer32 { @@ -247,26 +215,20 @@ typedef struct drm_radeon_cmd_buffer32 { u32 boxes; } drm_radeon_cmd_buffer32_t; -static int compat_radeon_cp_cmdbuf(struct file *file, unsigned int cmd, - unsigned long arg) +static int compat_radeon_cp_cmdbuf(struct drm_device *dev, void *arg, + struct drm_file *file_priv) { - drm_radeon_cmd_buffer32_t req32; - drm_radeon_cmd_buffer_t __user *request; - - if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) - return -EFAULT; - - request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) - || __put_user(req32.bufsz, &request->bufsz) - || __put_user((void __user *)(unsigned long)req32.buf, - &request->buf) - || __put_user(req32.nbox, &request->nbox) - || __put_user((void __user *)(unsigned long)req32.boxes, - &request->boxes)) - return -EFAULT; - - return drm_ioctl(file, DRM_IOCTL_RADEON_CMDBUF, (unsigned long)request); + drm_radeon_cmd_buffer32_t *req32; + drm_radeon_cmd_buffer_t __user request; + + req32 = arg; + + request.bufsz = req32->bufsz; + request.buf = (char *)(unsigned long)req32->buf; + request.nbox = req32->nbox; + request.boxes = (struct drm_clip_rect *)(unsigned long)req32->boxes; + + return radeon_ioctls[DRM_IOCTL_RADEON_CMDBUF].func(dev, &request, file_priv); } typedef struct drm_radeon_getparam32 { @@ -274,23 +236,18 @@ typedef struct drm_radeon_getparam32 { u32 value; } drm_radeon_getparam32_t; -static int compat_radeon_cp_getparam(struct file *file, unsigned int cmd, - unsigned long arg) +static int compat_radeon_cp_getparam(struct drm_device *dev, void *arg, + struct drm_file *file_priv) { - drm_radeon_getparam32_t req32; - drm_radeon_getparam_t __user *request; + drm_radeon_getparam32_t *req32; + drm_radeon_getparam_t __user request; - if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) - return -EFAULT; + req32 = arg; - request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) - || __put_user(req32.param, &request->param) - || __put_user((void __user *)(unsigned long)req32.value, - &request->value)) - return -EFAULT; + request.param = req32->param; + request.value = (void *)(unsigned long)req32->value; - return drm_ioctl(file, DRM_IOCTL_RADEON_GETPARAM, (unsigned long)request); + return radeon_ioctls[DRM_IOCTL_RADEON_GETPARAM].func(dev, &request, file_priv); } typedef struct drm_radeon_mem_alloc32 { @@ -300,129 +257,71 @@ typedef struct drm_radeon_mem_alloc32 { u32 region_offset; /* offset from start of fb or GART */ } drm_radeon_mem_alloc32_t; -static int compat_radeon_mem_alloc(struct file *file, unsigned int cmd, - unsigned long arg) +static int compat_radeon_mem_alloc(struct drm_device *dev, void *arg, + struct drm_file *file_priv) { - drm_radeon_mem_alloc32_t req32; - drm_radeon_mem_alloc_t __user *request; - - if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) - return -EFAULT; - - request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) - || __put_user(req32.region, &request->region) - || __put_user(req32.alignment, &request->alignment) - || __put_user(req32.size, &request->size) - || __put_user((int __user *)(unsigned long)req32.region_offset, - &request->region_offset)) - return -EFAULT; - - return drm_ioctl(file, DRM_IOCTL_RADEON_ALLOC, (unsigned long)request); + drm_radeon_mem_alloc32_t *req32; + drm_radeon_mem_alloc_t __user request; + + req32 = arg; + + request.region = req32->region; + request.alignment = req32->alignment; + request.size = req32->size; + request.region_offset = (int *)(unsigned long)req32->region_offset; + + return radeon_mem_alloc(dev, &request, file_priv); } typedef struct drm_radeon_irq_emit32 { u32 irq_seq; } drm_radeon_irq_emit32_t; -static int compat_radeon_irq_emit(struct file *file, unsigned int cmd, - unsigned long arg) +static int compat_radeon_irq_emit(struct drm_device *dev, void *arg, + struct drm_file *file_priv) { - drm_radeon_irq_emit32_t req32; - drm_radeon_irq_emit_t __user *request; + drm_radeon_irq_emit32_t *req32; + drm_radeon_irq_emit_t __user request; - if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) - return -EFAULT; + req32 = arg; - request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) - || __put_user((int __user *)(unsigned long)req32.irq_seq, - &request->irq_seq)) - return -EFAULT; + request.irq_seq = (int *)(unsigned long)req32->irq_seq; - return drm_ioctl(file, DRM_IOCTL_RADEON_IRQ_EMIT, (unsigned long)request); + return radeon_irq_emit(dev, &request, file_priv); } /* The two 64-bit arches where alignof(u64)==4 in 32-bit code */ -#if defined (CONFIG_X86_64) || defined(CONFIG_IA64) typedef struct drm_radeon_setparam32 { int param; u64 value; } __attribute__((packed)) drm_radeon_setparam32_t; -static int compat_radeon_cp_setparam(struct file *file, unsigned int cmd, - unsigned long arg) +static int compat_radeon_cp_setparam(struct drm_device *dev, void *arg, + struct drm_file *file_priv) { - drm_radeon_setparam32_t req32; - drm_radeon_setparam_t __user *request; + drm_radeon_setparam32_t *req32; + drm_radeon_setparam_t __user request; - if (copy_from_user(&req32, (void __user *) arg, sizeof(req32))) - return -EFAULT; + req32 = arg; - request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) - || __put_user(req32.param, &request->param) - || __put_user((void __user *)(unsigned long)req32.value, - &request->value)) - return -EFAULT; + request.param = req32->param; + request.value = req32->value; - return drm_ioctl(file, DRM_IOCTL_RADEON_SETPARAM, (unsigned long) request); + return radeon_ioctls[DRM_IOCTL_RADEON_SETPARAM].func(dev, &request, file_priv); } -#else -#define compat_radeon_cp_setparam NULL -#endif /* X86_64 || IA64 */ - -static drm_ioctl_compat_t *radeon_compat_ioctls[] = { - [DRM_RADEON_CP_INIT] = compat_radeon_cp_init, - [DRM_RADEON_CLEAR] = compat_radeon_cp_clear, - [DRM_RADEON_STIPPLE] = compat_radeon_cp_stipple, - [DRM_RADEON_TEXTURE] = compat_radeon_cp_texture, - [DRM_RADEON_VERTEX2] = compat_radeon_cp_vertex2, - [DRM_RADEON_CMDBUF] = compat_radeon_cp_cmdbuf, - [DRM_RADEON_GETPARAM] = compat_radeon_cp_getparam, - [DRM_RADEON_SETPARAM] = compat_radeon_cp_setparam, - [DRM_RADEON_ALLOC] = compat_radeon_mem_alloc, - [DRM_RADEON_IRQ_EMIT] = compat_radeon_irq_emit, -}; - -/** - * Called whenever a 32-bit process running under a 64-bit kernel - * performs an ioctl on /dev/dri/card<n>. - * - * \param filp file pointer. - * \param cmd command. - * \param arg user argument. - * \return zero on success or negative number on failure. - */ -long radeon_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - unsigned int nr = DRM_IOCTL_NR(cmd); - drm_ioctl_compat_t *fn = NULL; - int ret; - - if (nr < DRM_COMMAND_BASE) - return drm_compat_ioctl(filp, cmd, arg); - - if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(radeon_compat_ioctls)) - fn = radeon_compat_ioctls[nr - DRM_COMMAND_BASE]; - if (fn != NULL) - ret = (*fn) (filp, cmd, arg); - else - ret = drm_ioctl(filp, cmd, arg); - - return ret; -} - -long radeon_kms_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - unsigned int nr = DRM_IOCTL_NR(cmd); - int ret; - - if (nr < DRM_COMMAND_BASE) - return drm_compat_ioctl(filp, cmd, arg); - - ret = drm_ioctl(filp, cmd, arg); +struct drm_ioctl_desc radeon_compat_ioctls[] = { + DRM_IOCTL_DEF(DRM_RADEON_CP_INIT, compat_radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_RADEON_CLEAR, compat_radeon_cp_clear, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_STIPPLE, compat_radeon_cp_stipple, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_TEXTURE, compat_radeon_cp_texture, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_VERTEX2, compat_radeon_cp_vertex2, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_CMDBUF, compat_radeon_cp_cmdbuf, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GETPARAM, compat_radeon_cp_getparam, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, compat_radeon_cp_setparam, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_ALLOC, compat_radeon_mem_alloc, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_IRQ_EMIT, compat_radeon_irq_emit, DRM_AUTH) +}; +int radeon_num_compat_ioctls = DRM_ARRAY_SIZE(radeon_compat_ioctls); - return ret; -} +#endif diff --git a/sys/dev/gpio/gpio_if.m b/sys/dev/gpio/gpio_if.m index 78383d3d46d85..4d6dfd17a5d75 100644 --- a/sys/dev/gpio/gpio_if.m +++ b/sys/dev/gpio/gpio_if.m @@ -31,6 +31,32 @@ INTERFACE gpio; +CODE { + static gpio_map_gpios_t gpio_default_map_gpios; + + int + gpio_default_map_gpios(device_t bus, phandle_t dev, + phandle_t gparent, int gcells, pcell_t *gpios, uint32_t *pin, + uint32_t *flags) + { + /* Propagate up the bus hierarchy until someone handles it. */ + if (device_get_parent(bus) != NULL) + return (GPIO_MAP_GPIOS(device_get_parent(bus), dev, + gparent, gcells, gpios, pin, flags)); + + /* If that fails, then assume the FreeBSD defaults. */ + *pin = gpios[0]; + if (gcells == 2 || gcells == 3) + *flags = gpios[gcells - 1]; + + return (0); + } +}; + +HEADER { + #include <dev/ofw/openfirm.h> +}; + # # Get total number of pins # @@ -100,3 +126,16 @@ METHOD int pin_setflags { uint32_t pin_num; uint32_t flags; }; + +# +# Allow the GPIO controller to map the gpio-specifier on its own. +# +METHOD int map_gpios { + device_t bus; + phandle_t dev; + phandle_t gparent; + int gcells; + pcell_t *gpios; + uint32_t *pin; + uint32_t *flags; +} DEFAULT gpio_default_map_gpios; diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c index d8eacc62e85e8..e09393c325377 100644 --- a/sys/dev/gpio/gpiobus.c +++ b/sys/dev/gpio/gpiobus.c @@ -29,21 +29,13 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> #include <sys/malloc.h> #include <sys/module.h> -#include <sys/kernel.h> -#include <sys/queue.h> -#include <sys/sysctl.h> -#include <sys/types.h> -#include <sys/bus.h> -#include <machine/bus.h> -#include <sys/rman.h> -#include <machine/resource.h> - -#include <sys/gpio.h> #include <dev/gpio/gpiobusvar.h> -#include "gpio_if.h" + #include "gpiobus_if.h" static int gpiobus_parse_pins(struct gpiobus_softc *, device_t, int); diff --git a/sys/dev/gpio/gpiobusvar.h b/sys/dev/gpio/gpiobusvar.h index 3d387107762ed..e2ee51bd6f0c1 100644 --- a/sys/dev/gpio/gpiobusvar.h +++ b/sys/dev/gpio/gpiobusvar.h @@ -32,7 +32,6 @@ #include "opt_platform.h" -#include <sys/param.h> #include <sys/lock.h> #include <sys/mutex.h> @@ -40,6 +39,8 @@ #include <dev/ofw/ofw_bus_subr.h> #endif +#include "gpio_if.h" + #define GPIOBUS_IVAR(d) (struct gpiobus_ivar *) device_get_ivars(d) #define GPIOBUS_SOFTC(d) (struct gpiobus_softc *) device_get_softc(d) #define GPIOBUS_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) @@ -73,6 +74,13 @@ struct ofw_gpiobus_devinfo { struct ofw_bus_devinfo opd_obdinfo; }; +static __inline int +gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells, + pcell_t *gpios, uint32_t *pin, uint32_t *flags) +{ + return (GPIO_MAP_GPIOS(bus, dev, gparent, gcells, gpios, pin, flags)); +} + device_t ofw_gpiobus_add_fdt_child(device_t, phandle_t); #endif void gpiobus_print_pins(struct gpiobus_ivar *); diff --git a/sys/dev/gpio/ofw_gpiobus.c b/sys/dev/gpio/ofw_gpiobus.c index f4eb37df96ae5..6e182926695ba 100644 --- a/sys/dev/gpio/ofw_gpiobus.c +++ b/sys/dev/gpio/ofw_gpiobus.c @@ -30,22 +30,14 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/systm.h> #include <sys/bus.h> -#include <sys/gpio.h> #include <sys/kernel.h> -#include <sys/libkern.h> -#include <sys/lock.h> +#include <sys/malloc.h> #include <sys/module.h> -#include <sys/mutex.h> #include <dev/gpio/gpiobusvar.h> #include <dev/ofw/ofw_bus.h> -#include <dev/ofw/openfirm.h> - -#include <machine/resource.h> - -#include "gpio_if.h" -#include "gpiobus_if.h" static int ofw_gpiobus_parse_gpios(struct gpiobus_softc *, struct gpiobus_ivar *, phandle_t); @@ -186,7 +178,7 @@ ofw_gpiobus_parse_gpios(struct gpiobus_softc *sc, struct gpiobus_ivar *dinfo, } /* Get the GPIO pin number and flags. */ - if (ofw_bus_map_gpios(sc->sc_dev, child, gpio, cells, + if (gpio_map_gpios(sc->sc_dev, child, gpio, cells, &gpios[i + 1], &dinfo->pins[j], &dinfo->flags[j]) != 0) { ofw_gpiobus_free_ivars(dinfo); free(gpios, M_DEVBUF); diff --git a/sys/dev/lindev/full.c b/sys/dev/lindev/full.c deleted file mode 100644 index 294094c075d3e..0000000000000 --- a/sys/dev/lindev/full.c +++ /dev/null @@ -1,103 +0,0 @@ -/*- - * Copyright (c) 2009 Ed Schouten <ed@FreeBSD.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/systm.h> -#include <sys/uio.h> - -#include <dev/lindev/lindev.h> - -static struct cdev *full_dev; - -static d_read_t full_read; -static d_write_t full_write; - -static struct cdevsw full_cdevsw = { - .d_version = D_VERSION, - .d_read = full_read, - .d_write = full_write, - .d_name = "full", -}; - -static void *zbuf; - -/* ARGSUSED */ -static int -full_read(struct cdev *dev __unused, struct uio *uio, int flags __unused) -{ - int error = 0; - - while (uio->uio_resid > 0 && error == 0) - error = uiomove(zbuf, MIN(uio->uio_resid, PAGE_SIZE), uio); - - return (error); -} - -/* ARGSUSED */ -static int -full_write(struct cdev *dev __unused, struct uio *uio __unused, - int flags __unused) -{ - - return (ENOSPC); -} - -/* ARGSUSED */ -int -lindev_modevent_full(module_t mod __unused, int type, void *data __unused) -{ - - switch(type) { - case MOD_LOAD: - zbuf = (void *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK | M_ZERO); - full_dev = make_dev(&full_cdevsw, 0, UID_ROOT, GID_WHEEL, - 0666, "full"); - if (bootverbose) - printf("full: <full device>\n"); - break; - - case MOD_UNLOAD: - destroy_dev(full_dev); - free(zbuf, M_TEMP); - break; - - case MOD_SHUTDOWN: - break; - - default: - return (EOPNOTSUPP); - } - - return (0); -} - diff --git a/sys/dev/mpr/mpi/mpi2.h b/sys/dev/mpr/mpi/mpi2.h new file mode 100644 index 0000000000000..10f17aba067ec --- /dev/null +++ b/sys/dev/mpr/mpi/mpi2.h @@ -0,0 +1,1257 @@ +/*- + * Copyright (c) 2013 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + +/* + * Copyright (c) 2000-2013 LSI Corporation. + * + * + * Name: mpi2.h + * Title: MPI Message independent structures and definitions + * including System Interface Register Set and + * scatter/gather formats. + * Creation Date: June 21, 2006 + * + * mpi2.h Version: 02.00.33 + * + * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 + * prefix are for use only on MPI v2.5 products, and must not be used + * with MPI v2.0 products. Unless otherwise noted, names beginning with + * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 Bumped MPI2_HEADER_VERSION_UNIT. + * 06-26-07 02.00.02 Bumped MPI2_HEADER_VERSION_UNIT. + * 08-31-07 02.00.03 Bumped MPI2_HEADER_VERSION_UNIT. + * Moved ReplyPostHostIndex register to offset 0x6C of the + * MPI2_SYSTEM_INTERFACE_REGS and modified the define for + * MPI2_REPLY_POST_HOST_INDEX_OFFSET. + * Added union of request descriptors. + * Added union of reply descriptors. + * 10-31-07 02.00.04 Bumped MPI2_HEADER_VERSION_UNIT. + * Added define for MPI2_VERSION_02_00. + * Fixed the size of the FunctionDependent5 field in the + * MPI2_DEFAULT_REPLY structure. + * 12-18-07 02.00.05 Bumped MPI2_HEADER_VERSION_UNIT. + * Removed the MPI-defined Fault Codes and extended the + * product specific codes up to 0xEFFF. + * Added a sixth key value for the WriteSequence register + * and changed the flush value to 0x0. + * Added message function codes for Diagnostic Buffer Post + * and Diagnsotic Release. + * New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED + * Moved MPI2_VERSION_UNION from mpi2_ioc.h. + * 02-29-08 02.00.06 Bumped MPI2_HEADER_VERSION_UNIT. + * 03-03-08 02.00.07 Bumped MPI2_HEADER_VERSION_UNIT. + * 05-21-08 02.00.08 Bumped MPI2_HEADER_VERSION_UNIT. + * Added #defines for marking a reply descriptor as unused. + * 06-27-08 02.00.09 Bumped MPI2_HEADER_VERSION_UNIT. + * 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT. + * Moved LUN field defines from mpi2_init.h. + * 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT. + * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT. + * In all request and reply descriptors, replaced VF_ID + * field with MSIxIndex field. + * Removed DevHandle field from + * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those + * bytes reserved. + * Added RAID Accelerator functionality. + * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT. + * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MSI-x index mask and shift for Reply Post Host + * Index register. + * Added function code for Host Based Discovery Action. + * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT. + * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL. + * Added defines for product-specific range of message + * function codes, 0xF0 to 0xFF. + * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT. + * Added alternative defines for the SGE Direction bit. + * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT. + * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define. + * 02-23-11 02.00.19 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MPI2_FUNCTION_SEND_HOST_MESSAGE. + * 03-09-11 02.00.20 Bumped MPI2_HEADER_VERSION_UNIT. + * 05-25-11 02.00.21 Bumped MPI2_HEADER_VERSION_UNIT. + * 08-24-11 02.00.22 Bumped MPI2_HEADER_VERSION_UNIT. + * 11-18-11 02.00.23 Bumped MPI2_HEADER_VERSION_UNIT. + * Incorporating additions for MPI v2.5. + * 02-06-12 02.00.24 Bumped MPI2_HEADER_VERSION_UNIT. + * 03-29-12 02.00.25 Bumped MPI2_HEADER_VERSION_UNIT. + * Added Hard Reset delay timings. + * 07-10-12 02.00.26 Bumped MPI2_HEADER_VERSION_UNIT. + * 07-26-12 02.00.27 Bumped MPI2_HEADER_VERSION_UNIT. + * 11-27-12 02.00.28 Bumped MPI2_HEADER_VERSION_UNIT. + * 12-20-12 02.00.29 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET. + * 04-09-13 02.00.30 Bumped MPI2_HEADER_VERSION_UNIT. + * 04-17-13 02.00.31 Bumped MPI2_HEADER_VERSION_UNIT. + * 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT. + * 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_H +#define MPI2_H + + +/***************************************************************************** +* +* MPI Version Definitions +* +*****************************************************************************/ + +#define MPI2_VERSION_MAJOR_MASK (0xFF00) +#define MPI2_VERSION_MAJOR_SHIFT (8) +#define MPI2_VERSION_MINOR_MASK (0x00FF) +#define MPI2_VERSION_MINOR_SHIFT (0) + +/* major version for all MPI v2.x */ +#define MPI2_VERSION_MAJOR (0x02) + +/* minor version for MPI v2.0 compatible products */ +#define MPI2_VERSION_MINOR (0x00) +#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \ + MPI2_VERSION_MINOR) +#define MPI2_VERSION_02_00 (0x0200) + + +/* minor version for MPI v2.5 compatible products */ +#define MPI25_VERSION_MINOR (0x05) +#define MPI25_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \ + MPI25_VERSION_MINOR) +#define MPI2_VERSION_02_05 (0x0205) + + +/* Unit and Dev versioning for this MPI header set */ +#define MPI2_HEADER_VERSION_UNIT (0x21) +#define MPI2_HEADER_VERSION_DEV (0x00) +#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) +#define MPI2_HEADER_VERSION_UNIT_SHIFT (8) +#define MPI2_HEADER_VERSION_DEV_MASK (0x00FF) +#define MPI2_HEADER_VERSION_DEV_SHIFT (0) +#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | MPI2_HEADER_VERSION_DEV) + + +/***************************************************************************** +* +* IOC State Definitions +* +*****************************************************************************/ + +#define MPI2_IOC_STATE_RESET (0x00000000) +#define MPI2_IOC_STATE_READY (0x10000000) +#define MPI2_IOC_STATE_OPERATIONAL (0x20000000) +#define MPI2_IOC_STATE_FAULT (0x40000000) + +#define MPI2_IOC_STATE_MASK (0xF0000000) +#define MPI2_IOC_STATE_SHIFT (28) + +/* Fault state range for prodcut specific codes */ +#define MPI2_FAULT_PRODUCT_SPECIFIC_MIN (0x0000) +#define MPI2_FAULT_PRODUCT_SPECIFIC_MAX (0xEFFF) + + +/***************************************************************************** +* +* System Interface Register Definitions +* +*****************************************************************************/ + +typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS +{ + U32 Doorbell; /* 0x00 */ + U32 WriteSequence; /* 0x04 */ + U32 HostDiagnostic; /* 0x08 */ + U32 Reserved1; /* 0x0C */ + U32 DiagRWData; /* 0x10 */ + U32 DiagRWAddressLow; /* 0x14 */ + U32 DiagRWAddressHigh; /* 0x18 */ + U32 Reserved2[5]; /* 0x1C */ + U32 HostInterruptStatus; /* 0x30 */ + U32 HostInterruptMask; /* 0x34 */ + U32 DCRData; /* 0x38 */ + U32 DCRAddress; /* 0x3C */ + U32 Reserved3[2]; /* 0x40 */ + U32 ReplyFreeHostIndex; /* 0x48 */ + U32 Reserved4[8]; /* 0x4C */ + U32 ReplyPostHostIndex; /* 0x6C */ + U32 Reserved5; /* 0x70 */ + U32 HCBSize; /* 0x74 */ + U32 HCBAddressLow; /* 0x78 */ + U32 HCBAddressHigh; /* 0x7C */ + U32 Reserved6[16]; /* 0x80 */ + U32 RequestDescriptorPostLow; /* 0xC0 */ + U32 RequestDescriptorPostHigh; /* 0xC4 */ + U32 Reserved7[14]; /* 0xC8 */ +} MPI2_SYSTEM_INTERFACE_REGS, MPI2_POINTER PTR_MPI2_SYSTEM_INTERFACE_REGS, + Mpi2SystemInterfaceRegs_t, MPI2_POINTER pMpi2SystemInterfaceRegs_t; + +/* + * Defines for working with the Doorbell register. + */ +#define MPI2_DOORBELL_OFFSET (0x00000000) + +/* IOC --> System values */ +#define MPI2_DOORBELL_USED (0x08000000) +#define MPI2_DOORBELL_WHO_INIT_MASK (0x07000000) +#define MPI2_DOORBELL_WHO_INIT_SHIFT (24) +#define MPI2_DOORBELL_FAULT_CODE_MASK (0x0000FFFF) +#define MPI2_DOORBELL_DATA_MASK (0x0000FFFF) + +/* System --> IOC values */ +#define MPI2_DOORBELL_FUNCTION_MASK (0xFF000000) +#define MPI2_DOORBELL_FUNCTION_SHIFT (24) +#define MPI2_DOORBELL_ADD_DWORDS_MASK (0x00FF0000) +#define MPI2_DOORBELL_ADD_DWORDS_SHIFT (16) + + +/* + * Defines for the WriteSequence register + */ +#define MPI2_WRITE_SEQUENCE_OFFSET (0x00000004) +#define MPI2_WRSEQ_KEY_VALUE_MASK (0x0000000F) +#define MPI2_WRSEQ_FLUSH_KEY_VALUE (0x0) +#define MPI2_WRSEQ_1ST_KEY_VALUE (0xF) +#define MPI2_WRSEQ_2ND_KEY_VALUE (0x4) +#define MPI2_WRSEQ_3RD_KEY_VALUE (0xB) +#define MPI2_WRSEQ_4TH_KEY_VALUE (0x2) +#define MPI2_WRSEQ_5TH_KEY_VALUE (0x7) +#define MPI2_WRSEQ_6TH_KEY_VALUE (0xD) + +/* + * Defines for the HostDiagnostic register + */ +#define MPI2_HOST_DIAGNOSTIC_OFFSET (0x00000008) + +#define MPI2_DIAG_BOOT_DEVICE_SELECT_MASK (0x00001800) +#define MPI2_DIAG_BOOT_DEVICE_SELECT_DEFAULT (0x00000000) +#define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW (0x00000800) + +#define MPI2_DIAG_CLEAR_FLASH_BAD_SIG (0x00000400) +#define MPI2_DIAG_FORCE_HCB_ON_RESET (0x00000200) +#define MPI2_DIAG_HCB_MODE (0x00000100) +#define MPI2_DIAG_DIAG_WRITE_ENABLE (0x00000080) +#define MPI2_DIAG_FLASH_BAD_SIG (0x00000040) +#define MPI2_DIAG_RESET_HISTORY (0x00000020) +#define MPI2_DIAG_DIAG_RW_ENABLE (0x00000010) +#define MPI2_DIAG_RESET_ADAPTER (0x00000004) +#define MPI2_DIAG_HOLD_IOC_RESET (0x00000002) + +/* + * Offsets for DiagRWData and address + */ +#define MPI2_DIAG_RW_DATA_OFFSET (0x00000010) +#define MPI2_DIAG_RW_ADDRESS_LOW_OFFSET (0x00000014) +#define MPI2_DIAG_RW_ADDRESS_HIGH_OFFSET (0x00000018) + +/* + * Defines for the HostInterruptStatus register + */ +#define MPI2_HOST_INTERRUPT_STATUS_OFFSET (0x00000030) +#define MPI2_HIS_SYS2IOC_DB_STATUS (0x80000000) +#define MPI2_HIS_IOP_DOORBELL_STATUS MPI2_HIS_SYS2IOC_DB_STATUS +#define MPI2_HIS_RESET_IRQ_STATUS (0x40000000) +#define MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT (0x00000008) +#define MPI2_HIS_IOC2SYS_DB_STATUS (0x00000001) +#define MPI2_HIS_DOORBELL_INTERRUPT MPI2_HIS_IOC2SYS_DB_STATUS + +/* + * Defines for the HostInterruptMask register + */ +#define MPI2_HOST_INTERRUPT_MASK_OFFSET (0x00000034) +#define MPI2_HIM_RESET_IRQ_MASK (0x40000000) +#define MPI2_HIM_REPLY_INT_MASK (0x00000008) +#define MPI2_HIM_RIM MPI2_HIM_REPLY_INT_MASK +#define MPI2_HIM_IOC2SYS_DB_MASK (0x00000001) +#define MPI2_HIM_DIM MPI2_HIM_IOC2SYS_DB_MASK + +/* + * Offsets for DCRData and address + */ +#define MPI2_DCR_DATA_OFFSET (0x00000038) +#define MPI2_DCR_ADDRESS_OFFSET (0x0000003C) + +/* + * Offset for the Reply Free Queue + */ +#define MPI2_REPLY_FREE_HOST_INDEX_OFFSET (0x00000048) + +/* + * Defines for the Reply Descriptor Post Queue + */ +#define MPI2_REPLY_POST_HOST_INDEX_OFFSET (0x0000006C) +#define MPI2_REPLY_POST_HOST_INDEX_MASK (0x00FFFFFF) +#define MPI2_RPHI_MSIX_INDEX_MASK (0xFF000000) +#define MPI2_RPHI_MSIX_INDEX_SHIFT (24) +#define MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET (0x0000030C) /* MPI v2.5 only */ + + +/* + * Defines for the HCBSize and address + */ +#define MPI2_HCB_SIZE_OFFSET (0x00000074) +#define MPI2_HCB_SIZE_SIZE_MASK (0xFFFFF000) +#define MPI2_HCB_SIZE_HCB_ENABLE (0x00000001) + +#define MPI2_HCB_ADDRESS_LOW_OFFSET (0x00000078) +#define MPI2_HCB_ADDRESS_HIGH_OFFSET (0x0000007C) + +/* + * Offsets for the Request Queue + */ +#define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET (0x000000C0) +#define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET (0x000000C4) + + +/* Hard Reset delay timings */ +#define MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC (50000) +#define MPI2_HARD_RESET_PCIE_RESET_READ_WINDOW_MICRO_SEC (255000) +#define MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC (256000) + +/***************************************************************************** +* +* Message Descriptors +* +*****************************************************************************/ + +/* Request Descriptors */ + +/* Default Request Descriptor */ +typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR +{ + U8 RequestFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 LMID; /* 0x04 */ + U16 DescriptorTypeDependent; /* 0x06 */ +} MPI2_DEFAULT_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_DEFAULT_REQUEST_DESCRIPTOR, + Mpi2DefaultRequestDescriptor_t, MPI2_POINTER pMpi2DefaultRequestDescriptor_t; + +/* defines for the RequestFlags field */ +#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E) +#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00) +#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET (0x02) +#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06) +#define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE (0x08) +#define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR (0x0A) +#define MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO (0x0C) + +#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01) + + +/* High Priority Request Descriptor */ +typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR +{ + U8 RequestFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 LMID; /* 0x04 */ + U16 Reserved1; /* 0x06 */ +} MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR, + Mpi2HighPriorityRequestDescriptor_t, + MPI2_POINTER pMpi2HighPriorityRequestDescriptor_t; + + +/* SCSI IO Request Descriptor */ +typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR +{ + U8 RequestFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 LMID; /* 0x04 */ + U16 DevHandle; /* 0x06 */ +} MPI2_SCSI_IO_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST_DESCRIPTOR, + Mpi2SCSIIORequestDescriptor_t, MPI2_POINTER pMpi2SCSIIORequestDescriptor_t; + + +/* SCSI Target Request Descriptor */ +typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR +{ + U8 RequestFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 LMID; /* 0x04 */ + U16 IoIndex; /* 0x06 */ +} MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR, + Mpi2SCSITargetRequestDescriptor_t, + MPI2_POINTER pMpi2SCSITargetRequestDescriptor_t; + + +/* RAID Accelerator Request Descriptor */ +typedef struct _MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR +{ + U8 RequestFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 LMID; /* 0x04 */ + U16 Reserved; /* 0x06 */ +} MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, + Mpi2RAIDAcceleratorRequestDescriptor_t, + MPI2_POINTER pMpi2RAIDAcceleratorRequestDescriptor_t; + + +/* Fast Path SCSI IO Request Descriptor */ +typedef MPI2_SCSI_IO_REQUEST_DESCRIPTOR + MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR, + Mpi25FastPathSCSIIORequestDescriptor_t, + MPI2_POINTER pMpi25FastPathSCSIIORequestDescriptor_t; + + +/* union of Request Descriptors */ +typedef union _MPI2_REQUEST_DESCRIPTOR_UNION +{ + MPI2_DEFAULT_REQUEST_DESCRIPTOR Default; + MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority; + MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO; + MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget; + MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator; + MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR FastPathSCSIIO; + U64 Words; +} MPI2_REQUEST_DESCRIPTOR_UNION, MPI2_POINTER PTR_MPI2_REQUEST_DESCRIPTOR_UNION, + Mpi2RequestDescriptorUnion_t, MPI2_POINTER pMpi2RequestDescriptorUnion_t; + + +/* Reply Descriptors */ + +/* Default Reply Descriptor */ +typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 DescriptorTypeDependent1; /* 0x02 */ + U32 DescriptorTypeDependent2; /* 0x04 */ +} MPI2_DEFAULT_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY_DESCRIPTOR, + Mpi2DefaultReplyDescriptor_t, MPI2_POINTER pMpi2DefaultReplyDescriptor_t; + +/* defines for the ReplyFlags field */ +#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F) +#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00) +#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY (0x01) +#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS (0x02) +#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER (0x03) +#define MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS (0x05) +#define MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS (0x06) +#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F) + +/* values for marking a reply descriptor as unused */ +#define MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK (0xFFFFFFFF) +#define MPI2_RPY_DESCRIPT_UNUSED_WORD1_MARK (0xFFFFFFFF) + +/* Address Reply Descriptor */ +typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U32 ReplyFrameAddress; /* 0x04 */ +} MPI2_ADDRESS_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR, + Mpi2AddressReplyDescriptor_t, MPI2_POINTER pMpi2AddressReplyDescriptor_t; + +#define MPI2_ADDRESS_REPLY_SMID_INVALID (0x00) + + +/* SCSI IO Success Reply Descriptor */ +typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 TaskTag; /* 0x04 */ + U16 Reserved1; /* 0x06 */ +} MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, + Mpi2SCSIIOSuccessReplyDescriptor_t, + MPI2_POINTER pMpi2SCSIIOSuccessReplyDescriptor_t; + + +/* TargetAssist Success Reply Descriptor */ +typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U8 SequenceNumber; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 IoIndex; /* 0x06 */ +} MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR, + Mpi2TargetAssistSuccessReplyDescriptor_t, + MPI2_POINTER pMpi2TargetAssistSuccessReplyDescriptor_t; + + +/* Target Command Buffer Reply Descriptor */ +typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U8 VP_ID; /* 0x02 */ + U8 Flags; /* 0x03 */ + U16 InitiatorDevHandle; /* 0x04 */ + U16 IoIndex; /* 0x06 */ +} MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, + Mpi2TargetCommandBufferReplyDescriptor_t, + MPI2_POINTER pMpi2TargetCommandBufferReplyDescriptor_t; + +/* defines for Flags field */ +#define MPI2_RPY_DESCRIPT_TCB_FLAGS_PHYNUM_MASK (0x3F) + + +/* RAID Accelerator Success Reply Descriptor */ +typedef struct _MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U32 Reserved; /* 0x04 */ +} MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, + Mpi2RAIDAcceleratorSuccessReplyDescriptor_t, + MPI2_POINTER pMpi2RAIDAcceleratorSuccessReplyDescriptor_t; + + +/* Fast Path SCSI IO Success Reply Descriptor */ +typedef MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR + MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, + Mpi25FastPathSCSIIOSuccessReplyDescriptor_t, + MPI2_POINTER pMpi25FastPathSCSIIOSuccessReplyDescriptor_t; + + +/* union of Reply Descriptors */ +typedef union _MPI2_REPLY_DESCRIPTORS_UNION +{ + MPI2_DEFAULT_REPLY_DESCRIPTOR Default; + MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply; + MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess; + MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess; + MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer; + MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess; + MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR FastPathSCSIIOSuccess; + U64 Words; +} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION, + Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t; + + + +/***************************************************************************** +* +* Message Functions +* +*****************************************************************************/ + +#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ +#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) /* SCSI Task Management */ +#define MPI2_FUNCTION_IOC_INIT (0x02) /* IOC Init */ +#define MPI2_FUNCTION_IOC_FACTS (0x03) /* IOC Facts */ +#define MPI2_FUNCTION_CONFIG (0x04) /* Configuration */ +#define MPI2_FUNCTION_PORT_FACTS (0x05) /* Port Facts */ +#define MPI2_FUNCTION_PORT_ENABLE (0x06) /* Port Enable */ +#define MPI2_FUNCTION_EVENT_NOTIFICATION (0x07) /* Event Notification */ +#define MPI2_FUNCTION_EVENT_ACK (0x08) /* Event Acknowledge */ +#define MPI2_FUNCTION_FW_DOWNLOAD (0x09) /* FW Download */ +#define MPI2_FUNCTION_TARGET_ASSIST (0x0B) /* Target Assist */ +#define MPI2_FUNCTION_TARGET_STATUS_SEND (0x0C) /* Target Status Send */ +#define MPI2_FUNCTION_TARGET_MODE_ABORT (0x0D) /* Target Mode Abort */ +#define MPI2_FUNCTION_FW_UPLOAD (0x12) /* FW Upload */ +#define MPI2_FUNCTION_RAID_ACTION (0x15) /* RAID Action */ +#define MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) /* SCSI IO RAID Passthrough */ +#define MPI2_FUNCTION_TOOLBOX (0x17) /* Toolbox */ +#define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18) /* SCSI Enclosure Processor */ +#define MPI2_FUNCTION_SMP_PASSTHROUGH (0x1A) /* SMP Passthrough */ +#define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) /* SAS IO Unit Control */ +#define MPI2_FUNCTION_SATA_PASSTHROUGH (0x1C) /* SATA Passthrough */ +#define MPI2_FUNCTION_DIAG_BUFFER_POST (0x1D) /* Diagnostic Buffer Post */ +#define MPI2_FUNCTION_DIAG_RELEASE (0x1E) /* Diagnostic Release */ +#define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) /* Target Command Buffer Post Base */ +#define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) /* Target Command Buffer Post List */ +#define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator */ +#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) /* Host Based Discovery Action */ +#define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) /* Power Management Control */ +#define MPI2_FUNCTION_SEND_HOST_MESSAGE (0x31) /* Send Host Message */ +#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) /* beginning of product-specific range */ +#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) /* end of product-specific range */ + + + +/* Doorbell functions */ +#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) +#define MPI2_FUNCTION_HANDSHAKE (0x42) + + +/***************************************************************************** +* +* IOC Status Values +* +*****************************************************************************/ + +/* mask for IOCStatus status value */ +#define MPI2_IOCSTATUS_MASK (0x7FFF) + +/**************************************************************************** +* Common IOCStatus values for all replies +****************************************************************************/ + +#define MPI2_IOCSTATUS_SUCCESS (0x0000) +#define MPI2_IOCSTATUS_INVALID_FUNCTION (0x0001) +#define MPI2_IOCSTATUS_BUSY (0x0002) +#define MPI2_IOCSTATUS_INVALID_SGL (0x0003) +#define MPI2_IOCSTATUS_INTERNAL_ERROR (0x0004) +#define MPI2_IOCSTATUS_INVALID_VPID (0x0005) +#define MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) +#define MPI2_IOCSTATUS_INVALID_FIELD (0x0007) +#define MPI2_IOCSTATUS_INVALID_STATE (0x0008) +#define MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009) + +/**************************************************************************** +* Config IOCStatus values +****************************************************************************/ + +#define MPI2_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) +#define MPI2_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) +#define MPI2_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) +#define MPI2_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) +#define MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) +#define MPI2_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) + +/**************************************************************************** +* SCSI IO Reply +****************************************************************************/ + +#define MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) +#define MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE (0x0042) +#define MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) +#define MPI2_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) +#define MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) +#define MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) +#define MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) +#define MPI2_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) +#define MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) +#define MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) +#define MPI2_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) +#define MPI2_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) + +/**************************************************************************** +* For use by SCSI Initiator and SCSI Target end-to-end data protection +****************************************************************************/ + +#define MPI2_IOCSTATUS_EEDP_GUARD_ERROR (0x004D) +#define MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004E) +#define MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F) + +/**************************************************************************** +* SCSI Target values +****************************************************************************/ + +#define MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062) +#define MPI2_IOCSTATUS_TARGET_ABORTED (0x0063) +#define MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064) +#define MPI2_IOCSTATUS_TARGET_NO_CONNECTION (0x0065) +#define MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A) +#define MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR (0x006D) +#define MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006E) +#define MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT (0x006F) +#define MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT (0x0070) +#define MPI2_IOCSTATUS_TARGET_NAK_RECEIVED (0x0071) + +/**************************************************************************** +* Serial Attached SCSI values +****************************************************************************/ + +#define MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090) +#define MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN (0x0091) + +/**************************************************************************** +* Diagnostic Buffer Post / Diagnostic Release values +****************************************************************************/ + +#define MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0) + +/**************************************************************************** +* RAID Accelerator values +****************************************************************************/ + +#define MPI2_IOCSTATUS_RAID_ACCEL_ERROR (0x00B0) + +/**************************************************************************** +* IOCStatus flag to indicate that log info is available +****************************************************************************/ + +#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000) + +/**************************************************************************** +* IOCLogInfo Types +****************************************************************************/ + +#define MPI2_IOCLOGINFO_TYPE_MASK (0xF0000000) +#define MPI2_IOCLOGINFO_TYPE_SHIFT (28) +#define MPI2_IOCLOGINFO_TYPE_NONE (0x0) +#define MPI2_IOCLOGINFO_TYPE_SCSI (0x1) +#define MPI2_IOCLOGINFO_TYPE_FC (0x2) +#define MPI2_IOCLOGINFO_TYPE_SAS (0x3) +#define MPI2_IOCLOGINFO_TYPE_ISCSI (0x4) +#define MPI2_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF) + + +/***************************************************************************** +* +* Standard Message Structures +* +*****************************************************************************/ + +/**************************************************************************** +* Request Message Header for all request messages +****************************************************************************/ + +typedef struct _MPI2_REQUEST_HEADER +{ + U16 FunctionDependent1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 FunctionDependent2; /* 0x04 */ + U8 FunctionDependent3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ +} MPI2_REQUEST_HEADER, MPI2_POINTER PTR_MPI2_REQUEST_HEADER, + MPI2RequestHeader_t, MPI2_POINTER pMPI2RequestHeader_t; + + +/**************************************************************************** +* Default Reply +****************************************************************************/ + +typedef struct _MPI2_DEFAULT_REPLY +{ + U16 FunctionDependent1; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 FunctionDependent2; /* 0x04 */ + U8 FunctionDependent3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U16 FunctionDependent5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_DEFAULT_REPLY, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY, + MPI2DefaultReply_t, MPI2_POINTER pMPI2DefaultReply_t; + + +/* common version structure/union used in messages and configuration pages */ + +typedef struct _MPI2_VERSION_STRUCT +{ + U8 Dev; /* 0x00 */ + U8 Unit; /* 0x01 */ + U8 Minor; /* 0x02 */ + U8 Major; /* 0x03 */ +} MPI2_VERSION_STRUCT; + +typedef union _MPI2_VERSION_UNION +{ + MPI2_VERSION_STRUCT Struct; + U32 Word; +} MPI2_VERSION_UNION; + + +/* LUN field defines, common to many structures */ +#define MPI2_LUN_FIRST_LEVEL_ADDRESSING (0x0000FFFF) +#define MPI2_LUN_SECOND_LEVEL_ADDRESSING (0xFFFF0000) +#define MPI2_LUN_THIRD_LEVEL_ADDRESSING (0x0000FFFF) +#define MPI2_LUN_FOURTH_LEVEL_ADDRESSING (0xFFFF0000) +#define MPI2_LUN_LEVEL_1_WORD (0xFF00) +#define MPI2_LUN_LEVEL_1_DWORD (0x0000FF00) + + +/***************************************************************************** +* +* Fusion-MPT MPI Scatter Gather Elements +* +*****************************************************************************/ + +/**************************************************************************** +* MPI Simple Element structures +****************************************************************************/ + +typedef struct _MPI2_SGE_SIMPLE32 +{ + U32 FlagsLength; + U32 Address; +} MPI2_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_SGE_SIMPLE32, + Mpi2SGESimple32_t, MPI2_POINTER pMpi2SGESimple32_t; + +typedef struct _MPI2_SGE_SIMPLE64 +{ + U32 FlagsLength; + U64 Address; +} MPI2_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_SGE_SIMPLE64, + Mpi2SGESimple64_t, MPI2_POINTER pMpi2SGESimple64_t; + +typedef struct _MPI2_SGE_SIMPLE_UNION +{ + U32 FlagsLength; + union + { + U32 Address32; + U64 Address64; + } u; +} MPI2_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_SIMPLE_UNION, + Mpi2SGESimpleUnion_t, MPI2_POINTER pMpi2SGESimpleUnion_t; + + +/**************************************************************************** +* MPI Chain Element structures - for MPI v2.0 products only +****************************************************************************/ + +typedef struct _MPI2_SGE_CHAIN32 +{ + U16 Length; + U8 NextChainOffset; + U8 Flags; + U32 Address; +} MPI2_SGE_CHAIN32, MPI2_POINTER PTR_MPI2_SGE_CHAIN32, + Mpi2SGEChain32_t, MPI2_POINTER pMpi2SGEChain32_t; + +typedef struct _MPI2_SGE_CHAIN64 +{ + U16 Length; + U8 NextChainOffset; + U8 Flags; + U64 Address; +} MPI2_SGE_CHAIN64, MPI2_POINTER PTR_MPI2_SGE_CHAIN64, + Mpi2SGEChain64_t, MPI2_POINTER pMpi2SGEChain64_t; + +typedef struct _MPI2_SGE_CHAIN_UNION +{ + U16 Length; + U8 NextChainOffset; + U8 Flags; + union + { + U32 Address32; + U64 Address64; + } u; +} MPI2_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_SGE_CHAIN_UNION, + Mpi2SGEChainUnion_t, MPI2_POINTER pMpi2SGEChainUnion_t; + + +/**************************************************************************** +* MPI Transaction Context Element structures - for MPI v2.0 products only +****************************************************************************/ + +typedef struct _MPI2_SGE_TRANSACTION32 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[1]; + U32 TransactionDetails[1]; +} MPI2_SGE_TRANSACTION32, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION32, + Mpi2SGETransaction32_t, MPI2_POINTER pMpi2SGETransaction32_t; + +typedef struct _MPI2_SGE_TRANSACTION64 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[2]; + U32 TransactionDetails[1]; +} MPI2_SGE_TRANSACTION64, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION64, + Mpi2SGETransaction64_t, MPI2_POINTER pMpi2SGETransaction64_t; + +typedef struct _MPI2_SGE_TRANSACTION96 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[3]; + U32 TransactionDetails[1]; +} MPI2_SGE_TRANSACTION96, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION96, + Mpi2SGETransaction96_t, MPI2_POINTER pMpi2SGETransaction96_t; + +typedef struct _MPI2_SGE_TRANSACTION128 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[4]; + U32 TransactionDetails[1]; +} MPI2_SGE_TRANSACTION128, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION128, + Mpi2SGETransaction_t128, MPI2_POINTER pMpi2SGETransaction_t128; + +typedef struct _MPI2_SGE_TRANSACTION_UNION +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + union + { + U32 TransactionContext32[1]; + U32 TransactionContext64[2]; + U32 TransactionContext96[3]; + U32 TransactionContext128[4]; + } u; + U32 TransactionDetails[1]; +} MPI2_SGE_TRANSACTION_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION_UNION, + Mpi2SGETransactionUnion_t, MPI2_POINTER pMpi2SGETransactionUnion_t; + + +/**************************************************************************** +* MPI SGE union for IO SGL's - for MPI v2.0 products only +****************************************************************************/ + +typedef struct _MPI2_MPI_SGE_IO_UNION +{ + union + { + MPI2_SGE_SIMPLE_UNION Simple; + MPI2_SGE_CHAIN_UNION Chain; + } u; +} MPI2_MPI_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_IO_UNION, + Mpi2MpiSGEIOUnion_t, MPI2_POINTER pMpi2MpiSGEIOUnion_t; + + +/**************************************************************************** +* MPI SGE union for SGL's with Simple and Transaction elements - for MPI v2.0 products only +****************************************************************************/ + +typedef struct _MPI2_SGE_TRANS_SIMPLE_UNION +{ + union + { + MPI2_SGE_SIMPLE_UNION Simple; + MPI2_SGE_TRANSACTION_UNION Transaction; + } u; +} MPI2_SGE_TRANS_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANS_SIMPLE_UNION, + Mpi2SGETransSimpleUnion_t, MPI2_POINTER pMpi2SGETransSimpleUnion_t; + + +/**************************************************************************** +* All MPI SGE types union +****************************************************************************/ + +typedef struct _MPI2_MPI_SGE_UNION +{ + union + { + MPI2_SGE_SIMPLE_UNION Simple; + MPI2_SGE_CHAIN_UNION Chain; + MPI2_SGE_TRANSACTION_UNION Transaction; + } u; +} MPI2_MPI_SGE_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_UNION, + Mpi2MpiSgeUnion_t, MPI2_POINTER pMpi2MpiSgeUnion_t; + + +/**************************************************************************** +* MPI SGE field definition and masks +****************************************************************************/ + +/* Flags field bit definitions */ + +#define MPI2_SGE_FLAGS_LAST_ELEMENT (0x80) +#define MPI2_SGE_FLAGS_END_OF_BUFFER (0x40) +#define MPI2_SGE_FLAGS_ELEMENT_TYPE_MASK (0x30) +#define MPI2_SGE_FLAGS_LOCAL_ADDRESS (0x08) +#define MPI2_SGE_FLAGS_DIRECTION (0x04) +#define MPI2_SGE_FLAGS_ADDRESS_SIZE (0x02) +#define MPI2_SGE_FLAGS_END_OF_LIST (0x01) + +#define MPI2_SGE_FLAGS_SHIFT (24) + +#define MPI2_SGE_LENGTH_MASK (0x00FFFFFF) +#define MPI2_SGE_CHAIN_LENGTH_MASK (0x0000FFFF) + +/* Element Type */ + +#define MPI2_SGE_FLAGS_TRANSACTION_ELEMENT (0x00) /* for MPI v2.0 products only */ +#define MPI2_SGE_FLAGS_SIMPLE_ELEMENT (0x10) +#define MPI2_SGE_FLAGS_CHAIN_ELEMENT (0x30) /* for MPI v2.0 products only */ +#define MPI2_SGE_FLAGS_ELEMENT_MASK (0x30) + +/* Address location */ + +#define MPI2_SGE_FLAGS_SYSTEM_ADDRESS (0x00) + +/* Direction */ + +#define MPI2_SGE_FLAGS_IOC_TO_HOST (0x00) +#define MPI2_SGE_FLAGS_HOST_TO_IOC (0x04) + +#define MPI2_SGE_FLAGS_DEST (MPI2_SGE_FLAGS_IOC_TO_HOST) +#define MPI2_SGE_FLAGS_SOURCE (MPI2_SGE_FLAGS_HOST_TO_IOC) + +/* Address Size */ + +#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00) +#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02) + +/* Context Size */ + +#define MPI2_SGE_FLAGS_32_BIT_CONTEXT (0x00) +#define MPI2_SGE_FLAGS_64_BIT_CONTEXT (0x02) +#define MPI2_SGE_FLAGS_96_BIT_CONTEXT (0x04) +#define MPI2_SGE_FLAGS_128_BIT_CONTEXT (0x06) + +#define MPI2_SGE_CHAIN_OFFSET_MASK (0x00FF0000) +#define MPI2_SGE_CHAIN_OFFSET_SHIFT (16) + +/**************************************************************************** +* MPI SGE operation Macros +****************************************************************************/ + +/* SIMPLE FlagsLength manipulations... */ +#define MPI2_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_SGE_FLAGS_SHIFT) +#define MPI2_SGE_GET_FLAGS(f) (((f) & ~MPI2_SGE_LENGTH_MASK) >> MPI2_SGE_FLAGS_SHIFT) +#define MPI2_SGE_LENGTH(f) ((f) & MPI2_SGE_LENGTH_MASK) +#define MPI2_SGE_CHAIN_LENGTH(f) ((f) & MPI2_SGE_CHAIN_LENGTH_MASK) + +#define MPI2_SGE_SET_FLAGS_LENGTH(f,l) (MPI2_SGE_SET_FLAGS(f) | MPI2_SGE_LENGTH(l)) + +#define MPI2_pSGE_GET_FLAGS(psg) MPI2_SGE_GET_FLAGS((psg)->FlagsLength) +#define MPI2_pSGE_GET_LENGTH(psg) MPI2_SGE_LENGTH((psg)->FlagsLength) +#define MPI2_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI2_SGE_SET_FLAGS_LENGTH(f,l) + +/* CAUTION - The following are READ-MODIFY-WRITE! */ +#define MPI2_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI2_SGE_SET_FLAGS(f) +#define MPI2_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI2_SGE_LENGTH(l) + +#define MPI2_GET_CHAIN_OFFSET(x) ((x & MPI2_SGE_CHAIN_OFFSET_MASK) >> MPI2_SGE_CHAIN_OFFSET_SHIFT) + + +/***************************************************************************** +* +* Fusion-MPT IEEE Scatter Gather Elements +* +*****************************************************************************/ + +/**************************************************************************** +* IEEE Simple Element structures +****************************************************************************/ + +/* MPI2_IEEE_SGE_SIMPLE32 is for MPI v2.0 products only */ +typedef struct _MPI2_IEEE_SGE_SIMPLE32 +{ + U32 Address; + U32 FlagsLength; +} MPI2_IEEE_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE32, + Mpi2IeeeSgeSimple32_t, MPI2_POINTER pMpi2IeeeSgeSimple32_t; + +typedef struct _MPI2_IEEE_SGE_SIMPLE64 +{ + U64 Address; + U32 Length; + U16 Reserved1; + U8 Reserved2; + U8 Flags; +} MPI2_IEEE_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE64, + Mpi2IeeeSgeSimple64_t, MPI2_POINTER pMpi2IeeeSgeSimple64_t; + +typedef union _MPI2_IEEE_SGE_SIMPLE_UNION +{ + MPI2_IEEE_SGE_SIMPLE32 Simple32; + MPI2_IEEE_SGE_SIMPLE64 Simple64; +} MPI2_IEEE_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE_UNION, + Mpi2IeeeSgeSimpleUnion_t, MPI2_POINTER pMpi2IeeeSgeSimpleUnion_t; + + +/**************************************************************************** +* IEEE Chain Element structures +****************************************************************************/ + +/* MPI2_IEEE_SGE_CHAIN32 is for MPI v2.0 products only */ +typedef MPI2_IEEE_SGE_SIMPLE32 MPI2_IEEE_SGE_CHAIN32; + +/* MPI2_IEEE_SGE_CHAIN64 is for MPI v2.0 products only */ +typedef MPI2_IEEE_SGE_SIMPLE64 MPI2_IEEE_SGE_CHAIN64; + +typedef union _MPI2_IEEE_SGE_CHAIN_UNION +{ + MPI2_IEEE_SGE_CHAIN32 Chain32; + MPI2_IEEE_SGE_CHAIN64 Chain64; +} MPI2_IEEE_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_CHAIN_UNION, + Mpi2IeeeSgeChainUnion_t, MPI2_POINTER pMpi2IeeeSgeChainUnion_t; + +/* MPI25_IEEE_SGE_CHAIN64 is for MPI v2.5 products only */ +typedef struct _MPI25_IEEE_SGE_CHAIN64 +{ + U64 Address; + U32 Length; + U16 Reserved1; + U8 NextChainOffset; + U8 Flags; +} MPI25_IEEE_SGE_CHAIN64, MPI2_POINTER PTR_MPI25_IEEE_SGE_CHAIN64, + Mpi25IeeeSgeChain64_t, MPI2_POINTER pMpi25IeeeSgeChain64_t; + + +/**************************************************************************** +* All IEEE SGE types union +****************************************************************************/ + +/* MPI2_IEEE_SGE_UNION is for MPI v2.0 products only */ +typedef struct _MPI2_IEEE_SGE_UNION +{ + union + { + MPI2_IEEE_SGE_SIMPLE_UNION Simple; + MPI2_IEEE_SGE_CHAIN_UNION Chain; + } u; +} MPI2_IEEE_SGE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_UNION, + Mpi2IeeeSgeUnion_t, MPI2_POINTER pMpi2IeeeSgeUnion_t; + + +/**************************************************************************** +* IEEE SGE union for IO SGL's +****************************************************************************/ + +typedef union _MPI25_SGE_IO_UNION +{ + MPI2_IEEE_SGE_SIMPLE64 IeeeSimple; + MPI25_IEEE_SGE_CHAIN64 IeeeChain; +} MPI25_SGE_IO_UNION, MPI2_POINTER PTR_MPI25_SGE_IO_UNION, + Mpi25SGEIOUnion_t, MPI2_POINTER pMpi25SGEIOUnion_t; + + +/**************************************************************************** +* IEEE SGE field definitions and masks +****************************************************************************/ + +/* Flags field bit definitions */ + +#define MPI2_IEEE_SGE_FLAGS_ELEMENT_TYPE_MASK (0x80) +#define MPI25_IEEE_SGE_FLAGS_END_OF_LIST (0x40) + +#define MPI2_IEEE32_SGE_FLAGS_SHIFT (24) + +#define MPI2_IEEE32_SGE_LENGTH_MASK (0x00FFFFFF) + +/* Element Type */ + +#define MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT (0x00) +#define MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80) + +/* Data Location Address Space */ + +#define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03) +#define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) /* for MPI v2.0, use in IEEE Simple Element only; for MPI v2.5, use in IEEE Simple or Chain element */ +#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) /* use in IEEE Simple Element only */ +#define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) +#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) /* for MPI v2.0, use in IEEE Simple Element only; for MPI v2.5, use in IEEE Simple or Chain element */ +#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR (0x03) /* use in MPI v2.0 IEEE Chain Element only */ +#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR (MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR) /* typo in name */ + +/**************************************************************************** +* IEEE SGE operation Macros +****************************************************************************/ + +/* SIMPLE FlagsLength manipulations... */ +#define MPI2_IEEE32_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_IEEE32_SGE_FLAGS_SHIFT) +#define MPI2_IEEE32_SGE_GET_FLAGS(f) (((f) & ~MPI2_IEEE32_SGE_LENGTH_MASK) >> MPI2_IEEE32_SGE_FLAGS_SHIFT) +#define MPI2_IEEE32_SGE_LENGTH(f) ((f) & MPI2_IEEE32_SGE_LENGTH_MASK) + +#define MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f, l) (MPI2_IEEE32_SGE_SET_FLAGS(f) | MPI2_IEEE32_SGE_LENGTH(l)) + +#define MPI2_IEEE32_pSGE_GET_FLAGS(psg) MPI2_IEEE32_SGE_GET_FLAGS((psg)->FlagsLength) +#define MPI2_IEEE32_pSGE_GET_LENGTH(psg) MPI2_IEEE32_SGE_LENGTH((psg)->FlagsLength) +#define MPI2_IEEE32_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f,l) + +/* CAUTION - The following are READ-MODIFY-WRITE! */ +#define MPI2_IEEE32_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI2_IEEE32_SGE_SET_FLAGS(f) +#define MPI2_IEEE32_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI2_IEEE32_SGE_LENGTH(l) + + + +/***************************************************************************** +* +* Fusion-MPT MPI/IEEE Scatter Gather Unions +* +*****************************************************************************/ + +typedef union _MPI2_SIMPLE_SGE_UNION +{ + MPI2_SGE_SIMPLE_UNION MpiSimple; + MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; +} MPI2_SIMPLE_SGE_UNION, MPI2_POINTER PTR_MPI2_SIMPLE_SGE_UNION, + Mpi2SimpleSgeUntion_t, MPI2_POINTER pMpi2SimpleSgeUntion_t; + + +typedef union _MPI2_SGE_IO_UNION +{ + MPI2_SGE_SIMPLE_UNION MpiSimple; + MPI2_SGE_CHAIN_UNION MpiChain; + MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; + MPI2_IEEE_SGE_CHAIN_UNION IeeeChain; +} MPI2_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_SGE_IO_UNION, + Mpi2SGEIOUnion_t, MPI2_POINTER pMpi2SGEIOUnion_t; + + +/**************************************************************************** +* +* Values for SGLFlags field, used in many request messages with an SGL +* +****************************************************************************/ + +/* values for MPI SGL Data Location Address Space subfield */ +#define MPI2_SGLFLAGS_ADDRESS_SPACE_MASK (0x0C) +#define MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE (0x00) +#define MPI2_SGLFLAGS_IOCDDR_ADDRESS_SPACE (0x04) +#define MPI2_SGLFLAGS_IOCPLB_ADDRESS_SPACE (0x08) +#define MPI2_SGLFLAGS_IOCPLBNTA_ADDRESS_SPACE (0x0C) +/* values for SGL Type subfield */ +#define MPI2_SGLFLAGS_SGL_TYPE_MASK (0x03) +#define MPI2_SGLFLAGS_SGL_TYPE_MPI (0x00) +#define MPI2_SGLFLAGS_SGL_TYPE_IEEE32 (0x01) /* MPI v2.0 products only */ +#define MPI2_SGLFLAGS_SGL_TYPE_IEEE64 (0x02) + + +#endif + diff --git a/sys/dev/mpr/mpi/mpi2_cnfg.h b/sys/dev/mpr/mpi/mpi2_cnfg.h new file mode 100644 index 0000000000000..d82750f80913f --- /dev/null +++ b/sys/dev/mpr/mpi/mpi2_cnfg.h @@ -0,0 +1,3169 @@ +/*- + * Copyright (c) 2013 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + +/* + * Copyright (c) 2000-2013 LSI Corporation. + * + * + * Name: mpi2_cnfg.h + * Title: MPI Configuration messages and pages + * Creation Date: November 10, 2006 + * + * mpi2_cnfg.h Version: 02.00.27 + * + * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 + * prefix are for use only on MPI v2.5 products, and must not be used + * with MPI v2.0 products. Unless otherwise noted, names beginning with + * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 Added defines for SAS IO Unit Page 2 PhyFlags. + * Added Manufacturing Page 11. + * Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE + * define. + * 06-26-07 02.00.02 Adding generic structure for product-specific + * Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS. + * Rework of BIOS Page 2 configuration page. + * Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the + * forms. + * Added configuration pages IOC Page 8 and Driver + * Persistent Mapping Page 0. + * 08-31-07 02.00.03 Modified configuration pages dealing with Integrated + * RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1, + * RAID Physical Disk Pages 0 and 1, RAID Configuration + * Page 0). + * Added new value for AccessStatus field of SAS Device + * Page 0 (_SATA_NEEDS_INITIALIZATION). + * 10-31-07 02.00.04 Added missing SEPDevHandle field to + * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + * 12-18-07 02.00.05 Modified IO Unit Page 0 to use 32-bit version fields for + * NVDATA. + * Modified IOC Page 7 to use masks and added field for + * SASBroadcastPrimitiveMasks. + * Added MPI2_CONFIG_PAGE_BIOS_4. + * Added MPI2_CONFIG_PAGE_LOG_0. + * 02-29-08 02.00.06 Modified various names to make them 32-character unique. + * Added SAS Device IDs. + * Updated Integrated RAID configuration pages including + * Manufacturing Page 4, IOC Page 6, and RAID Configuration + * Page 0. + * 05-21-08 02.00.07 Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA. + * Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION. + * Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING. + * Added missing MaxNumRoutedSasAddresses field to + * MPI2_CONFIG_PAGE_EXPANDER_0. + * Added SAS Port Page 0. + * Modified structure layout for + * MPI2_CONFIG_PAGE_DRIVER_MAPPING_0. + * 06-27-08 02.00.08 Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use + * MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array. + * 10-02-08 02.00.09 Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF + * to 0x000000FF. + * Added two new values for the Physical Disk Coercion Size + * bits in the Flags field of Manufacturing Page 4. + * Added product-specific Manufacturing pages 16 to 31. + * Modified Flags bits for controlling write cache on SATA + * drives in IO Unit Page 1. + * Added new bit to AdditionalControlFlags of SAS IO Unit + * Page 1 to control Invalid Topology Correction. + * Added additional defines for RAID Volume Page 0 + * VolumeStatusFlags field. + * Modified meaning of RAID Volume Page 0 VolumeSettings + * define for auto-configure of hot-swap drives. + * Added SupportedPhysDisks field to RAID Volume Page 1 and + * added related defines. + * Added PhysDiskAttributes field (and related defines) to + * RAID Physical Disk Page 0. + * Added MPI2_SAS_PHYINFO_PHY_VACANT define. + * Added three new DiscoveryStatus bits for SAS IO Unit + * Page 0 and SAS Expander Page 0. + * Removed multiplexing information from SAS IO Unit pages. + * Added BootDeviceWaitTime field to SAS IO Unit Page 4. + * Removed Zone Address Resolved bit from PhyInfo and from + * Expander Page 0 Flags field. + * Added two new AccessStatus values to SAS Device Page 0 + * for indicating routing problems. Added 3 reserved words + * to this page. + * 01-19-09 02.00.10 Fixed defines for GPIOVal field of IO Unit Page 3. + * Inserted missing reserved field into structure for IOC + * Page 6. + * Added more pending task bits to RAID Volume Page 0 + * VolumeStatusFlags defines. + * Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define. + * Added a new DiscoveryStatus bit for SAS IO Unit Page 0 + * and SAS Expander Page 0 to flag a downstream initiator + * when in simplified routing mode. + * Removed SATA Init Failure defines for DiscoveryStatus + * fields of SAS IO Unit Page 0 and SAS Expander Page 0. + * Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define. + * Added PortGroups, DmaGroup, and ControlGroup fields to + * SAS Device Page 0. + * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO + * Unit Page 6. + * Added expander reduced functionality data to SAS + * Expander Page 0. + * Added SAS PHY Page 2 and SAS PHY Page 3. + * 07-30-09 02.00.12 Added IO Unit Page 7. + * Added new device ids. + * Added SAS IO Unit Page 5. + * Added partial and slumber power management capable flags + * to SAS Device Page 0 Flags field. + * Added PhyInfo defines for power condition. + * Added Ethernet configuration pages. + * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. + * Added SAS PHY Page 4 structure and defines. + * 02-10-10 02.00.14 Modified the comments for the configuration page + * structures that contain an array of data. The host + * should use the "count" field in the page data (e.g. the + * NumPhys field) to determine the number of valid elements + * in the array. + * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines. + * Added PowerManagementCapabilities to IO Unit Page 7. + * Added PortWidthModGroup field to + * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines. + * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT + * define. + * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define. + * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define. + * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing) + * defines. + * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to + * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for + * the Pinout field. + * Added BoardTemperature and BoardTemperatureUnits fields + * to MPI2_CONFIG_PAGE_IO_UNIT_7. + * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define + * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure. + * 02-23-11 02.00.18 Added ProxyVF_ID field to MPI2_CONFIG_REQUEST. + * Added IO Unit Page 8, IO Unit Page 9, + * and IO Unit Page 10. + * Added SASNotifyPrimitiveMasks field to + * MPI2_CONFIG_PAGE_IOC_7. + * 03-09-11 02.00.19 Fixed IO Unit Page 10 (to match the spec). + * 05-25-11 02.00.20 Cleaned up a few comments. + * 08-24-11 02.00.21 Marked the IO Unit Page 7 PowerManagementCapabilities + * for PCIe link as obsolete. + * Added SpinupFlags field containing a Disable Spin-up bit + * to the MPI2_SAS_IOUNIT4_SPINUP_GROUP fields of SAS IO + * Unit Page 4. + * 11-18-11 02.00.22 Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT. + * Added UEFIVersion field to BIOS Page 1 and defined new + * BiosOptions bits. + * Incorporating additions for MPI v2.5. + * 11-27-12 02.00.23 Added MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER. + * Added MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID. + * 12-20-12 02.00.24 Marked MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION as + * obsolete for MPI v2.5 and later. + * Added some defines for 12G SAS speeds. + * 04-09-13 02.00.25 Added MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK. + * Fixed MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS to + * match the specification. + * 08-19-13 02.00.26 Added reserved words to MPI2_CONFIG_PAGE_IO_UNIT_7 for + * future use. + * 12-05-13 02.00.27 Added MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL for + * MPI2_CONFIG_PAGE_MAN_7. + * Added EnclosureLevel and ConnectorName fields to + * MPI2_CONFIG_PAGE_SAS_DEV_0. + * Added MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID for + * MPI2_CONFIG_PAGE_SAS_DEV_0. + * Added EnclosureLevel field to + * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + * Added MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID for + * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_CNFG_H +#define MPI2_CNFG_H + +/***************************************************************************** +* Configuration Page Header and defines +*****************************************************************************/ + +/* Config Page Header */ +typedef struct _MPI2_CONFIG_PAGE_HEADER +{ + U8 PageVersion; /* 0x00 */ + U8 PageLength; /* 0x01 */ + U8 PageNumber; /* 0x02 */ + U8 PageType; /* 0x03 */ +} MPI2_CONFIG_PAGE_HEADER, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER, + Mpi2ConfigPageHeader_t, MPI2_POINTER pMpi2ConfigPageHeader_t; + +typedef union _MPI2_CONFIG_PAGE_HEADER_UNION +{ + MPI2_CONFIG_PAGE_HEADER Struct; + U8 Bytes[4]; + U16 Word16[2]; + U32 Word32; +} MPI2_CONFIG_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER_UNION, + Mpi2ConfigPageHeaderUnion, MPI2_POINTER pMpi2ConfigPageHeaderUnion; + +/* Extended Config Page Header */ +typedef struct _MPI2_CONFIG_EXTENDED_PAGE_HEADER +{ + U8 PageVersion; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 PageNumber; /* 0x02 */ + U8 PageType; /* 0x03 */ + U16 ExtPageLength; /* 0x04 */ + U8 ExtPageType; /* 0x06 */ + U8 Reserved2; /* 0x07 */ +} MPI2_CONFIG_EXTENDED_PAGE_HEADER, + MPI2_POINTER PTR_MPI2_CONFIG_EXTENDED_PAGE_HEADER, + Mpi2ConfigExtendedPageHeader_t, MPI2_POINTER pMpi2ConfigExtendedPageHeader_t; + +typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION +{ + MPI2_CONFIG_PAGE_HEADER Struct; + MPI2_CONFIG_EXTENDED_PAGE_HEADER Ext; + U8 Bytes[8]; + U16 Word16[4]; + U32 Word32[2]; +} MPI2_CONFIG_EXT_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_EXT_PAGE_HEADER_UNION, + Mpi2ConfigPageExtendedHeaderUnion, MPI2_POINTER pMpi2ConfigPageExtendedHeaderUnion; + + +/* PageType field values */ +#define MPI2_CONFIG_PAGEATTR_READ_ONLY (0x00) +#define MPI2_CONFIG_PAGEATTR_CHANGEABLE (0x10) +#define MPI2_CONFIG_PAGEATTR_PERSISTENT (0x20) +#define MPI2_CONFIG_PAGEATTR_MASK (0xF0) + +#define MPI2_CONFIG_PAGETYPE_IO_UNIT (0x00) +#define MPI2_CONFIG_PAGETYPE_IOC (0x01) +#define MPI2_CONFIG_PAGETYPE_BIOS (0x02) +#define MPI2_CONFIG_PAGETYPE_RAID_VOLUME (0x08) +#define MPI2_CONFIG_PAGETYPE_MANUFACTURING (0x09) +#define MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK (0x0A) +#define MPI2_CONFIG_PAGETYPE_EXTENDED (0x0F) +#define MPI2_CONFIG_PAGETYPE_MASK (0x0F) + +#define MPI2_CONFIG_TYPENUM_MASK (0x0FFF) + + +/* ExtPageType field values */ +#define MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT (0x10) +#define MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER (0x11) +#define MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE (0x12) +#define MPI2_CONFIG_EXTPAGETYPE_SAS_PHY (0x13) +#define MPI2_CONFIG_EXTPAGETYPE_LOG (0x14) +#define MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE (0x15) +#define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG (0x16) +#define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17) +#define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18) +#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19) +#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING (0x1A) + + +/***************************************************************************** +* PageAddress defines +*****************************************************************************/ + +/* RAID Volume PageAddress format */ +#define MPI2_RAID_VOLUME_PGAD_FORM_MASK (0xF0000000) +#define MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI2_RAID_VOLUME_PGAD_FORM_HANDLE (0x10000000) + +#define MPI2_RAID_VOLUME_PGAD_HANDLE_MASK (0x0000FFFF) + + +/* RAID Physical Disk PageAddress format */ +#define MPI2_PHYSDISK_PGAD_FORM_MASK (0xF0000000) +#define MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM (0x00000000) +#define MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM (0x10000000) +#define MPI2_PHYSDISK_PGAD_FORM_DEVHANDLE (0x20000000) + +#define MPI2_PHYSDISK_PGAD_PHYSDISKNUM_MASK (0x000000FF) +#define MPI2_PHYSDISK_PGAD_DEVHANDLE_MASK (0x0000FFFF) + + +/* SAS Expander PageAddress format */ +#define MPI2_SAS_EXPAND_PGAD_FORM_MASK (0xF0000000) +#define MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL (0x00000000) +#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM (0x10000000) +#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL (0x20000000) + +#define MPI2_SAS_EXPAND_PGAD_HANDLE_MASK (0x0000FFFF) +#define MPI2_SAS_EXPAND_PGAD_PHYNUM_MASK (0x00FF0000) +#define MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT (16) + + +/* SAS Device PageAddress format */ +#define MPI2_SAS_DEVICE_PGAD_FORM_MASK (0xF0000000) +#define MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI2_SAS_DEVICE_PGAD_FORM_HANDLE (0x20000000) + +#define MPI2_SAS_DEVICE_PGAD_HANDLE_MASK (0x0000FFFF) + + +/* SAS PHY PageAddress format */ +#define MPI2_SAS_PHY_PGAD_FORM_MASK (0xF0000000) +#define MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER (0x00000000) +#define MPI2_SAS_PHY_PGAD_FORM_PHY_TBL_INDEX (0x10000000) + +#define MPI2_SAS_PHY_PGAD_PHY_NUMBER_MASK (0x000000FF) +#define MPI2_SAS_PHY_PGAD_PHY_TBL_INDEX_MASK (0x0000FFFF) + + +/* SAS Port PageAddress format */ +#define MPI2_SASPORT_PGAD_FORM_MASK (0xF0000000) +#define MPI2_SASPORT_PGAD_FORM_GET_NEXT_PORT (0x00000000) +#define MPI2_SASPORT_PGAD_FORM_PORT_NUM (0x10000000) + +#define MPI2_SASPORT_PGAD_PORTNUMBER_MASK (0x00000FFF) + + +/* SAS Enclosure PageAddress format */ +#define MPI2_SAS_ENCLOS_PGAD_FORM_MASK (0xF0000000) +#define MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE (0x10000000) + +#define MPI2_SAS_ENCLOS_PGAD_HANDLE_MASK (0x0000FFFF) + + +/* RAID Configuration PageAddress format */ +#define MPI2_RAID_PGAD_FORM_MASK (0xF0000000) +#define MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM (0x00000000) +#define MPI2_RAID_PGAD_FORM_CONFIGNUM (0x10000000) +#define MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG (0x20000000) + +#define MPI2_RAID_PGAD_CONFIGNUM_MASK (0x000000FF) + + +/* Driver Persistent Mapping PageAddress format */ +#define MPI2_DPM_PGAD_FORM_MASK (0xF0000000) +#define MPI2_DPM_PGAD_FORM_ENTRY_RANGE (0x00000000) + +#define MPI2_DPM_PGAD_ENTRY_COUNT_MASK (0x0FFF0000) +#define MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT (16) +#define MPI2_DPM_PGAD_START_ENTRY_MASK (0x0000FFFF) + + +/* Ethernet PageAddress format */ +#define MPI2_ETHERNET_PGAD_FORM_MASK (0xF0000000) +#define MPI2_ETHERNET_PGAD_FORM_IF_NUM (0x00000000) + +#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF) + + + +/**************************************************************************** +* Configuration messages +****************************************************************************/ + +/* Configuration Request Message */ +typedef struct _MPI2_CONFIG_REQUEST +{ + U8 Action; /* 0x00 */ + U8 SGLFlags; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 ExtPageLength; /* 0x04 */ + U8 ExtPageType; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U8 Reserved2; /* 0x0C */ + U8 ProxyVF_ID; /* 0x0D */ + U16 Reserved4; /* 0x0E */ + U32 Reserved3; /* 0x10 */ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x14 */ + U32 PageAddress; /* 0x18 */ + MPI2_SGE_IO_UNION PageBufferSGE; /* 0x1C */ +} MPI2_CONFIG_REQUEST, MPI2_POINTER PTR_MPI2_CONFIG_REQUEST, + Mpi2ConfigRequest_t, MPI2_POINTER pMpi2ConfigRequest_t; + +/* values for the Action field */ +#define MPI2_CONFIG_ACTION_PAGE_HEADER (0x00) +#define MPI2_CONFIG_ACTION_PAGE_READ_CURRENT (0x01) +#define MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT (0x02) +#define MPI2_CONFIG_ACTION_PAGE_DEFAULT (0x03) +#define MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM (0x04) +#define MPI2_CONFIG_ACTION_PAGE_READ_DEFAULT (0x05) +#define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM (0x06) +#define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE (0x07) + +/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ + + +/* Config Reply Message */ +typedef struct _MPI2_CONFIG_REPLY +{ + U8 Action; /* 0x00 */ + U8 SGLFlags; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 ExtPageLength; /* 0x04 */ + U8 ExtPageType; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U16 Reserved2; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x14 */ +} MPI2_CONFIG_REPLY, MPI2_POINTER PTR_MPI2_CONFIG_REPLY, + Mpi2ConfigReply_t, MPI2_POINTER pMpi2ConfigReply_t; + + + +/***************************************************************************** +* +* C o n f i g u r a t i o n P a g e s +* +*****************************************************************************/ + +/**************************************************************************** +* Manufacturing Config pages +****************************************************************************/ + +#define MPI2_MFGPAGE_VENDORID_LSI (0x1000) + +/* MPI v2.0 SAS products */ +#define MPI2_MFGPAGE_DEVID_SAS2004 (0x0070) +#define MPI2_MFGPAGE_DEVID_SAS2008 (0x0072) +#define MPI2_MFGPAGE_DEVID_SAS2108_1 (0x0074) +#define MPI2_MFGPAGE_DEVID_SAS2108_2 (0x0076) +#define MPI2_MFGPAGE_DEVID_SAS2108_3 (0x0077) +#define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064) +#define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065) + +#define MPI2_MFGPAGE_DEVID_SSS6200 (0x007E) + +#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080) +#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081) +#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082) +#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083) +#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084) +#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085) +#define MPI2_MFGPAGE_DEVID_SAS2308_1 (0x0086) +#define MPI2_MFGPAGE_DEVID_SAS2308_2 (0x0087) +#define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E) + +/* MPI v2.5 SAS products */ +#define MPI25_MFGPAGE_DEVID_SAS3004 (0x0096) +#define MPI25_MFGPAGE_DEVID_SAS3008 (0x0097) +#define MPI25_MFGPAGE_DEVID_SAS3108_1 (0x0090) +#define MPI25_MFGPAGE_DEVID_SAS3108_2 (0x0091) +#define MPI25_MFGPAGE_DEVID_SAS3108_5 (0x0094) +#define MPI25_MFGPAGE_DEVID_SAS3108_6 (0x0095) + + + + +/* Manufacturing Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_MAN_0 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 ChipName[16]; /* 0x04 */ + U8 ChipRevision[8]; /* 0x14 */ + U8 BoardName[16]; /* 0x1C */ + U8 BoardAssembly[16]; /* 0x2C */ + U8 BoardTracerNumber[16]; /* 0x3C */ +} MPI2_CONFIG_PAGE_MAN_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_0, + Mpi2ManufacturingPage0_t, MPI2_POINTER pMpi2ManufacturingPage0_t; + +#define MPI2_MANUFACTURING0_PAGEVERSION (0x00) + + +/* Manufacturing Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_MAN_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 VPD[256]; /* 0x04 */ +} MPI2_CONFIG_PAGE_MAN_1, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_1, + Mpi2ManufacturingPage1_t, MPI2_POINTER pMpi2ManufacturingPage1_t; + +#define MPI2_MANUFACTURING1_PAGEVERSION (0x00) + + +typedef struct _MPI2_CHIP_REVISION_ID +{ + U16 DeviceID; /* 0x00 */ + U8 PCIRevisionID; /* 0x02 */ + U8 Reserved; /* 0x03 */ +} MPI2_CHIP_REVISION_ID, MPI2_POINTER PTR_MPI2_CHIP_REVISION_ID, + Mpi2ChipRevisionId_t, MPI2_POINTER pMpi2ChipRevisionId_t; + + +/* Manufacturing Page 2 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS +#define MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_MAN_2 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + MPI2_CHIP_REVISION_ID ChipId; /* 0x04 */ + U32 HwSettings[MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS];/* 0x08 */ +} MPI2_CONFIG_PAGE_MAN_2, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_2, + Mpi2ManufacturingPage2_t, MPI2_POINTER pMpi2ManufacturingPage2_t; + +#define MPI2_MANUFACTURING2_PAGEVERSION (0x00) + + +/* Manufacturing Page 3 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI2_MAN_PAGE_3_INFO_WORDS +#define MPI2_MAN_PAGE_3_INFO_WORDS (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_MAN_3 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + MPI2_CHIP_REVISION_ID ChipId; /* 0x04 */ + U32 Info[MPI2_MAN_PAGE_3_INFO_WORDS];/* 0x08 */ +} MPI2_CONFIG_PAGE_MAN_3, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_3, + Mpi2ManufacturingPage3_t, MPI2_POINTER pMpi2ManufacturingPage3_t; + +#define MPI2_MANUFACTURING3_PAGEVERSION (0x00) + + +/* Manufacturing Page 4 */ + +typedef struct _MPI2_MANPAGE4_PWR_SAVE_SETTINGS +{ + U8 PowerSaveFlags; /* 0x00 */ + U8 InternalOperationsSleepTime; /* 0x01 */ + U8 InternalOperationsRunTime; /* 0x02 */ + U8 HostIdleTime; /* 0x03 */ +} MPI2_MANPAGE4_PWR_SAVE_SETTINGS, + MPI2_POINTER PTR_MPI2_MANPAGE4_PWR_SAVE_SETTINGS, + Mpi2ManPage4PwrSaveSettings_t, MPI2_POINTER pMpi2ManPage4PwrSaveSettings_t; + +/* defines for the PowerSaveFlags field */ +#define MPI2_MANPAGE4_MASK_POWERSAVE_MODE (0x03) +#define MPI2_MANPAGE4_POWERSAVE_MODE_DISABLED (0x00) +#define MPI2_MANPAGE4_CUSTOM_POWERSAVE_MODE (0x01) +#define MPI2_MANPAGE4_FULL_POWERSAVE_MODE (0x02) + +typedef struct _MPI2_CONFIG_PAGE_MAN_4 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Flags; /* 0x08 */ + U8 InquirySize; /* 0x0C */ + U8 Reserved2; /* 0x0D */ + U16 Reserved3; /* 0x0E */ + U8 InquiryData[56]; /* 0x10 */ + U32 RAID0VolumeSettings; /* 0x48 */ + U32 RAID1EVolumeSettings; /* 0x4C */ + U32 RAID1VolumeSettings; /* 0x50 */ + U32 RAID10VolumeSettings; /* 0x54 */ + U32 Reserved4; /* 0x58 */ + U32 Reserved5; /* 0x5C */ + MPI2_MANPAGE4_PWR_SAVE_SETTINGS PowerSaveSettings; /* 0x60 */ + U8 MaxOCEDisks; /* 0x64 */ + U8 ResyncRate; /* 0x65 */ + U16 DataScrubDuration; /* 0x66 */ + U8 MaxHotSpares; /* 0x68 */ + U8 MaxPhysDisksPerVol; /* 0x69 */ + U8 MaxPhysDisks; /* 0x6A */ + U8 MaxVolumes; /* 0x6B */ +} MPI2_CONFIG_PAGE_MAN_4, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_4, + Mpi2ManufacturingPage4_t, MPI2_POINTER pMpi2ManufacturingPage4_t; + +#define MPI2_MANUFACTURING4_PAGEVERSION (0x0A) + +/* Manufacturing Page 4 Flags field */ +#define MPI2_MANPAGE4_METADATA_SIZE_MASK (0x00030000) +#define MPI2_MANPAGE4_METADATA_512MB (0x00000000) + +#define MPI2_MANPAGE4_MIX_SSD_SAS_SATA (0x00008000) +#define MPI2_MANPAGE4_MIX_SSD_AND_NON_SSD (0x00004000) +#define MPI2_MANPAGE4_HIDE_PHYSDISK_NON_IR (0x00002000) + +#define MPI2_MANPAGE4_MASK_PHYSDISK_COERCION (0x00001C00) +#define MPI2_MANPAGE4_PHYSDISK_COERCION_1GB (0x00000000) +#define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION (0x00000400) +#define MPI2_MANPAGE4_PHYSDISK_ADAPTIVE_COERCION (0x00000800) +#define MPI2_MANPAGE4_PHYSDISK_ZERO_COERCION (0x00000C00) + +#define MPI2_MANPAGE4_MASK_BAD_BLOCK_MARKING (0x00000300) +#define MPI2_MANPAGE4_DEFAULT_BAD_BLOCK_MARKING (0x00000000) +#define MPI2_MANPAGE4_TABLE_BAD_BLOCK_MARKING (0x00000100) +#define MPI2_MANPAGE4_WRITE_LONG_BAD_BLOCK_MARKING (0x00000200) + +#define MPI2_MANPAGE4_FORCE_OFFLINE_FAILOVER (0x00000080) +#define MPI2_MANPAGE4_RAID10_DISABLE (0x00000040) +#define MPI2_MANPAGE4_RAID1E_DISABLE (0x00000020) +#define MPI2_MANPAGE4_RAID1_DISABLE (0x00000010) +#define MPI2_MANPAGE4_RAID0_DISABLE (0x00000008) +#define MPI2_MANPAGE4_IR_MODEPAGE8_DISABLE (0x00000004) +#define MPI2_MANPAGE4_IM_RESYNC_CACHE_ENABLE (0x00000002) +#define MPI2_MANPAGE4_IR_NO_MIX_SAS_SATA (0x00000001) + + +/* Manufacturing Page 5 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumPhys at runtime. + */ +#ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES +#define MPI2_MAN_PAGE_5_PHY_ENTRIES (1) +#endif + +typedef struct _MPI2_MANUFACTURING5_ENTRY +{ + U64 WWID; /* 0x00 */ + U64 DeviceName; /* 0x08 */ +} MPI2_MANUFACTURING5_ENTRY, MPI2_POINTER PTR_MPI2_MANUFACTURING5_ENTRY, + Mpi2Manufacturing5Entry_t, MPI2_POINTER pMpi2Manufacturing5Entry_t; + +typedef struct _MPI2_CONFIG_PAGE_MAN_5 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumPhys; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U32 Reserved3; /* 0x08 */ + U32 Reserved4; /* 0x0C */ + MPI2_MANUFACTURING5_ENTRY Phy[MPI2_MAN_PAGE_5_PHY_ENTRIES];/* 0x08 */ +} MPI2_CONFIG_PAGE_MAN_5, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_5, + Mpi2ManufacturingPage5_t, MPI2_POINTER pMpi2ManufacturingPage5_t; + +#define MPI2_MANUFACTURING5_PAGEVERSION (0x03) + + +/* Manufacturing Page 6 */ + +typedef struct _MPI2_CONFIG_PAGE_MAN_6 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 ProductSpecificInfo;/* 0x04 */ +} MPI2_CONFIG_PAGE_MAN_6, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_6, + Mpi2ManufacturingPage6_t, MPI2_POINTER pMpi2ManufacturingPage6_t; + +#define MPI2_MANUFACTURING6_PAGEVERSION (0x00) + + +/* Manufacturing Page 7 */ + +typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO +{ + U32 Pinout; /* 0x00 */ + U8 Connector[16]; /* 0x04 */ + U8 Location; /* 0x14 */ + U8 ReceptacleID; /* 0x15 */ + U16 Slot; /* 0x16 */ + U32 Reserved2; /* 0x18 */ +} MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO, + Mpi2ManPage7ConnectorInfo_t, MPI2_POINTER pMpi2ManPage7ConnectorInfo_t; + +/* defines for the Pinout field */ +#define MPI2_MANPAGE7_PINOUT_LANE_MASK (0x0000FF00) +#define MPI2_MANPAGE7_PINOUT_LANE_SHIFT (8) + +#define MPI2_MANPAGE7_PINOUT_TYPE_MASK (0x000000FF) +#define MPI2_MANPAGE7_PINOUT_TYPE_UNKNOWN (0x00) +#define MPI2_MANPAGE7_PINOUT_SATA_SINGLE (0x01) +#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x02) +#define MPI2_MANPAGE7_PINOUT_SFF_8486 (0x03) +#define MPI2_MANPAGE7_PINOUT_SFF_8484 (0x04) +#define MPI2_MANPAGE7_PINOUT_SFF_8087 (0x05) +#define MPI2_MANPAGE7_PINOUT_SFF_8643_4I (0x06) +#define MPI2_MANPAGE7_PINOUT_SFF_8643_8I (0x07) +#define MPI2_MANPAGE7_PINOUT_SFF_8470 (0x08) +#define MPI2_MANPAGE7_PINOUT_SFF_8088 (0x09) +#define MPI2_MANPAGE7_PINOUT_SFF_8644_4X (0x0A) +#define MPI2_MANPAGE7_PINOUT_SFF_8644_8X (0x0B) +#define MPI2_MANPAGE7_PINOUT_SFF_8644_16X (0x0C) +#define MPI2_MANPAGE7_PINOUT_SFF_8436 (0x0D) + +/* defines for the Location field */ +#define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01) +#define MPI2_MANPAGE7_LOCATION_INTERNAL (0x02) +#define MPI2_MANPAGE7_LOCATION_EXTERNAL (0x04) +#define MPI2_MANPAGE7_LOCATION_SWITCHABLE (0x08) +#define MPI2_MANPAGE7_LOCATION_AUTO (0x10) +#define MPI2_MANPAGE7_LOCATION_NOT_PRESENT (0x20) +#define MPI2_MANPAGE7_LOCATION_NOT_CONNECTED (0x80) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumPhys at runtime. + */ +#ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX +#define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_MAN_7 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Reserved2; /* 0x08 */ + U32 Flags; /* 0x0C */ + U8 EnclosureName[16]; /* 0x10 */ + U8 NumPhys; /* 0x20 */ + U8 Reserved3; /* 0x21 */ + U16 Reserved4; /* 0x22 */ + MPI2_MANPAGE7_CONNECTOR_INFO ConnectorInfo[MPI2_MANPAGE7_CONNECTOR_INFO_MAX]; /* 0x24 */ +} MPI2_CONFIG_PAGE_MAN_7, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7, + Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t; + +#define MPI2_MANUFACTURING7_PAGEVERSION (0x01) + +/* defines for the Flags field */ +#define MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL (0x00000008) +#define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER (0x00000002) +#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) + + +/* + * Generic structure to use for product-specific manufacturing pages + * (currently Manufacturing Page 8 through Manufacturing Page 31). + */ + +typedef struct _MPI2_CONFIG_PAGE_MAN_PS +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 ProductSpecificInfo;/* 0x04 */ +} MPI2_CONFIG_PAGE_MAN_PS, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_PS, + Mpi2ManufacturingPagePS_t, MPI2_POINTER pMpi2ManufacturingPagePS_t; + +#define MPI2_MANUFACTURING8_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING9_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING10_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING11_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING12_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING13_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING14_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING15_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING16_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING17_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING18_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING19_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING20_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING21_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING22_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING23_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING24_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING25_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING26_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING27_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING28_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING29_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING30_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING31_PAGEVERSION (0x00) + + +/**************************************************************************** +* IO Unit Config Pages +****************************************************************************/ + +/* IO Unit Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_0 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U64 UniqueValue; /* 0x04 */ + MPI2_VERSION_UNION NvdataVersionDefault; /* 0x08 */ + MPI2_VERSION_UNION NvdataVersionPersistent; /* 0x0A */ +} MPI2_CONFIG_PAGE_IO_UNIT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_0, + Mpi2IOUnitPage0_t, MPI2_POINTER pMpi2IOUnitPage0_t; + +#define MPI2_IOUNITPAGE0_PAGEVERSION (0x02) + + +/* IO Unit Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Flags; /* 0x04 */ +} MPI2_CONFIG_PAGE_IO_UNIT_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_1, + Mpi2IOUnitPage1_t, MPI2_POINTER pMpi2IOUnitPage1_t; + +#define MPI2_IOUNITPAGE1_PAGEVERSION (0x04) + +/* IO Unit Page 1 Flags defines */ +#define MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK (0x00004000) +#define MPI25_IOUNITPAGE1_NEW_DEVICE_FAST_PATH_DISABLE (0x00002000) +#define MPI25_IOUNITPAGE1_DISABLE_FAST_PATH (0x00001000) +#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800) +#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600) +#define MPI2_IOUNITPAGE1_SATA_WRITE_CACHE_SHIFT (9) +#define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000) +#define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200) +#define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE (0x00000400) +#define MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE (0x00000100) +#define MPI2_IOUNITPAGE1_DISABLE_IR (0x00000040) +#define MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING (0x00000020) +#define MPI2_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004) + + +/* IO Unit Page 3 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for GPIOCount at runtime. + */ +#ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX +#define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 GPIOCount; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U16 GPIOVal[MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX];/* 0x08 */ +} MPI2_CONFIG_PAGE_IO_UNIT_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_3, + Mpi2IOUnitPage3_t, MPI2_POINTER pMpi2IOUnitPage3_t; + +#define MPI2_IOUNITPAGE3_PAGEVERSION (0x01) + +/* defines for IO Unit Page 3 GPIOVal field */ +#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_MASK (0xFFFC) +#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_SHIFT (2) +#define MPI2_IOUNITPAGE3_GPIO_SETTING_OFF (0x0000) +#define MPI2_IOUNITPAGE3_GPIO_SETTING_ON (0x0001) + + +/* IO Unit Page 5 */ + +/* + * Upper layer code (drivers, utilities, etc.) should leave this define set to + * one and check the value returned for NumDmaEngines at runtime. + */ +#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES +#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U64 RaidAcceleratorBufferBaseAddress; /* 0x04 */ + U64 RaidAcceleratorBufferSize; /* 0x0C */ + U64 RaidAcceleratorControlBaseAddress; /* 0x14 */ + U8 RAControlSize; /* 0x1C */ + U8 NumDmaEngines; /* 0x1D */ + U8 RAMinControlSize; /* 0x1E */ + U8 RAMaxControlSize; /* 0x1F */ + U32 Reserved1; /* 0x20 */ + U32 Reserved2; /* 0x24 */ + U32 Reserved3; /* 0x28 */ + U32 DmaEngineCapabilities[MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES]; /* 0x2C */ +} MPI2_CONFIG_PAGE_IO_UNIT_5, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_5, + Mpi2IOUnitPage5_t, MPI2_POINTER pMpi2IOUnitPage5_t; + +#define MPI2_IOUNITPAGE5_PAGEVERSION (0x00) + +/* defines for IO Unit Page 5 DmaEngineCapabilities field */ +#define MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS (0xFFFF0000) +#define MPI2_IOUNITPAGE5_DMA_CAP_SHIFT_MAX_REQUESTS (16) + +#define MPI2_IOUNITPAGE5_DMA_CAP_EEDP (0x0008) +#define MPI2_IOUNITPAGE5_DMA_CAP_PARITY_GENERATION (0x0004) +#define MPI2_IOUNITPAGE5_DMA_CAP_HASHING (0x0002) +#define MPI2_IOUNITPAGE5_DMA_CAP_ENCRYPTION (0x0001) + + +/* IO Unit Page 6 */ + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_6 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 Flags; /* 0x04 */ + U8 RAHostControlSize; /* 0x06 */ + U8 Reserved0; /* 0x07 */ + U64 RaidAcceleratorHostControlBaseAddress; /* 0x08 */ + U32 Reserved1; /* 0x10 */ + U32 Reserved2; /* 0x14 */ + U32 Reserved3; /* 0x18 */ +} MPI2_CONFIG_PAGE_IO_UNIT_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_6, + Mpi2IOUnitPage6_t, MPI2_POINTER pMpi2IOUnitPage6_t; + +#define MPI2_IOUNITPAGE6_PAGEVERSION (0x00) + +/* defines for IO Unit Page 6 Flags field */ +#define MPI2_IOUNITPAGE6_FLAGS_ENABLE_RAID_ACCELERATOR (0x0001) + + +/* IO Unit Page 7 */ + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 CurrentPowerMode; /* 0x04 */ /* reserved in MPI 2.0 */ + U8 PreviousPowerMode; /* 0x05 */ /* reserved in MPI 2.0 */ + U8 PCIeWidth; /* 0x06 */ + U8 PCIeSpeed; /* 0x07 */ + U32 ProcessorState; /* 0x08 */ + U32 PowerManagementCapabilities; /* 0x0C */ + U16 IOCTemperature; /* 0x10 */ + U8 IOCTemperatureUnits; /* 0x12 */ + U8 IOCSpeed; /* 0x13 */ + U16 BoardTemperature; /* 0x14 */ + U8 BoardTemperatureUnits; /* 0x16 */ + U8 Reserved3; /* 0x17 */ + U32 Reserved4; /* 0x18 */ + U32 Reserved5; /* 0x1C */ + U32 Reserved6; /* 0x20 */ + U32 Reserved7; /* 0x24 */ +} MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7, + Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t; + +#define MPI2_IOUNITPAGE7_PAGEVERSION (0x04) + +/* defines for IO Unit Page 7 CurrentPowerMode and PreviousPowerMode fields */ +#define MPI25_IOUNITPAGE7_PM_INIT_MASK (0xC0) +#define MPI25_IOUNITPAGE7_PM_INIT_UNAVAILABLE (0x00) +#define MPI25_IOUNITPAGE7_PM_INIT_HOST (0x40) +#define MPI25_IOUNITPAGE7_PM_INIT_IO_UNIT (0x80) +#define MPI25_IOUNITPAGE7_PM_INIT_PCIE_DPA (0xC0) + +#define MPI25_IOUNITPAGE7_PM_MODE_MASK (0x07) +#define MPI25_IOUNITPAGE7_PM_MODE_UNAVAILABLE (0x00) +#define MPI25_IOUNITPAGE7_PM_MODE_UNKNOWN (0x01) +#define MPI25_IOUNITPAGE7_PM_MODE_FULL_POWER (0x04) +#define MPI25_IOUNITPAGE7_PM_MODE_REDUCED_POWER (0x05) +#define MPI25_IOUNITPAGE7_PM_MODE_STANDBY (0x06) + + +/* defines for IO Unit Page 7 PCIeWidth field */ +#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01) +#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X2 (0x02) +#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X4 (0x04) +#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X8 (0x08) + +/* defines for IO Unit Page 7 PCIeSpeed field */ +#define MPI2_IOUNITPAGE7_PCIE_SPEED_2_5_GBPS (0x00) +#define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01) +#define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02) + +/* defines for IO Unit Page 7 ProcessorState field */ +#define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F) +#define MPI2_IOUNITPAGE7_PSTATE_SHIFT_SECOND (0) + +#define MPI2_IOUNITPAGE7_PSTATE_NOT_PRESENT (0x00) +#define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01) +#define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02) + +/* defines for IO Unit Page 7 PowerManagementCapabilities field */ +#define MPI25_IOUNITPAGE7_PMCAP_DPA_FULL_PWR_MODE (0x00400000) +#define MPI25_IOUNITPAGE7_PMCAP_DPA_REDUCED_PWR_MODE (0x00200000) +#define MPI25_IOUNITPAGE7_PMCAP_DPA_STANDBY_MODE (0x00100000) +#define MPI25_IOUNITPAGE7_PMCAP_HOST_FULL_PWR_MODE (0x00040000) +#define MPI25_IOUNITPAGE7_PMCAP_HOST_REDUCED_PWR_MODE (0x00020000) +#define MPI25_IOUNITPAGE7_PMCAP_HOST_STANDBY_MODE (0x00010000) +#define MPI25_IOUNITPAGE7_PMCAP_IO_FULL_PWR_MODE (0x00004000) +#define MPI25_IOUNITPAGE7_PMCAP_IO_REDUCED_PWR_MODE (0x00002000) +#define MPI25_IOUNITPAGE7_PMCAP_IO_STANDBY_MODE (0x00001000) +#define MPI2_IOUNITPAGE7_PMCAP_HOST_12_5_PCT_IOCSPEED (0x00000400) +#define MPI2_IOUNITPAGE7_PMCAP_HOST_25_0_PCT_IOCSPEED (0x00000200) +#define MPI2_IOUNITPAGE7_PMCAP_HOST_50_0_PCT_IOCSPEED (0x00000100) +#define MPI25_IOUNITPAGE7_PMCAP_IO_12_5_PCT_IOCSPEED (0x00000040) +#define MPI25_IOUNITPAGE7_PMCAP_IO_25_0_PCT_IOCSPEED (0x00000020) +#define MPI25_IOUNITPAGE7_PMCAP_IO_50_0_PCT_IOCSPEED (0x00000010) +#define MPI2_IOUNITPAGE7_PMCAP_HOST_WIDTH_CHANGE_PCIE (0x00000008) /* obsolete */ +#define MPI2_IOUNITPAGE7_PMCAP_HOST_SPEED_CHANGE_PCIE (0x00000004) /* obsolete */ +#define MPI25_IOUNITPAGE7_PMCAP_IO_WIDTH_CHANGE_PCIE (0x00000002) /* obsolete */ +#define MPI25_IOUNITPAGE7_PMCAP_IO_SPEED_CHANGE_PCIE (0x00000001) /* obsolete */ + +/* obsolete names for the PowerManagementCapabilities bits (above) */ +#define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED (0x00000400) +#define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED (0x00000200) +#define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED (0x00000100) +#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008) /* obsolete */ +#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004) /* obsolete */ + + +/* defines for IO Unit Page 7 IOCTemperatureUnits field */ +#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00) +#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01) +#define MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS (0x02) + +/* defines for IO Unit Page 7 IOCSpeed field */ +#define MPI2_IOUNITPAGE7_IOC_SPEED_FULL (0x01) +#define MPI2_IOUNITPAGE7_IOC_SPEED_HALF (0x02) +#define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04) +#define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08) + +/* defines for IO Unit Page 7 BoardTemperatureUnits field */ +#define MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT (0x00) +#define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT (0x01) +#define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS (0x02) + + +/* IO Unit Page 8 */ + +#define MPI2_IOUNIT8_NUM_THRESHOLDS (4) + +typedef struct _MPI2_IOUNIT8_SENSOR +{ + U16 Flags; /* 0x00 */ + U16 Reserved1; /* 0x02 */ + U16 Threshold[MPI2_IOUNIT8_NUM_THRESHOLDS]; /* 0x04 */ + U32 Reserved2; /* 0x0C */ + U32 Reserved3; /* 0x10 */ + U32 Reserved4; /* 0x14 */ +} MPI2_IOUNIT8_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT8_SENSOR, + Mpi2IOUnit8Sensor_t, MPI2_POINTER pMpi2IOUnit8Sensor_t; + +/* defines for IO Unit Page 8 Sensor Flags field */ +#define MPI2_IOUNIT8_SENSOR_FLAGS_T3_ENABLE (0x0008) +#define MPI2_IOUNIT8_SENSOR_FLAGS_T2_ENABLE (0x0004) +#define MPI2_IOUNIT8_SENSOR_FLAGS_T1_ENABLE (0x0002) +#define MPI2_IOUNIT8_SENSOR_FLAGS_T0_ENABLE (0x0001) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumSensors at runtime. + */ +#ifndef MPI2_IOUNITPAGE8_SENSOR_ENTRIES +#define MPI2_IOUNITPAGE8_SENSOR_ENTRIES (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_8 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Reserved2; /* 0x08 */ + U8 NumSensors; /* 0x0C */ + U8 PollingInterval; /* 0x0D */ + U16 Reserved3; /* 0x0E */ + MPI2_IOUNIT8_SENSOR Sensor[MPI2_IOUNITPAGE8_SENSOR_ENTRIES];/* 0x10 */ +} MPI2_CONFIG_PAGE_IO_UNIT_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_8, + Mpi2IOUnitPage8_t, MPI2_POINTER pMpi2IOUnitPage8_t; + +#define MPI2_IOUNITPAGE8_PAGEVERSION (0x00) + + +/* IO Unit Page 9 */ + +typedef struct _MPI2_IOUNIT9_SENSOR +{ + U16 CurrentTemperature; /* 0x00 */ + U16 Reserved1; /* 0x02 */ + U8 Flags; /* 0x04 */ + U8 Reserved2; /* 0x05 */ + U16 Reserved3; /* 0x06 */ + U32 Reserved4; /* 0x08 */ + U32 Reserved5; /* 0x0C */ +} MPI2_IOUNIT9_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT9_SENSOR, + Mpi2IOUnit9Sensor_t, MPI2_POINTER pMpi2IOUnit9Sensor_t; + +/* defines for IO Unit Page 9 Sensor Flags field */ +#define MPI2_IOUNIT9_SENSOR_FLAGS_TEMP_VALID (0x01) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumSensors at runtime. + */ +#ifndef MPI2_IOUNITPAGE9_SENSOR_ENTRIES +#define MPI2_IOUNITPAGE9_SENSOR_ENTRIES (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_9 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Reserved2; /* 0x08 */ + U8 NumSensors; /* 0x0C */ + U8 Reserved4; /* 0x0D */ + U16 Reserved3; /* 0x0E */ + MPI2_IOUNIT9_SENSOR Sensor[MPI2_IOUNITPAGE9_SENSOR_ENTRIES];/* 0x10 */ +} MPI2_CONFIG_PAGE_IO_UNIT_9, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_9, + Mpi2IOUnitPage9_t, MPI2_POINTER pMpi2IOUnitPage9_t; + +#define MPI2_IOUNITPAGE9_PAGEVERSION (0x00) + + +/* IO Unit Page 10 */ + +typedef struct _MPI2_IOUNIT10_FUNCTION +{ + U8 CreditPercent; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ +} MPI2_IOUNIT10_FUNCTION, MPI2_POINTER PTR_MPI2_IOUNIT10_FUNCTION, + Mpi2IOUnit10Function_t, MPI2_POINTER pMpi2IOUnit10Function_t; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumFunctions at runtime. + */ +#ifndef MPI2_IOUNITPAGE10_FUNCTION_ENTRIES +#define MPI2_IOUNITPAGE10_FUNCTION_ENTRIES (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumFunctions; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U32 Reserved3; /* 0x08 */ + U32 Reserved4; /* 0x0C */ + MPI2_IOUNIT10_FUNCTION Function[MPI2_IOUNITPAGE10_FUNCTION_ENTRIES]; /* 0x10 */ +} MPI2_CONFIG_PAGE_IO_UNIT_10, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_10, + Mpi2IOUnitPage10_t, MPI2_POINTER pMpi2IOUnitPage10_t; + +#define MPI2_IOUNITPAGE10_PAGEVERSION (0x01) + + + +/**************************************************************************** +* IOC Config Pages +****************************************************************************/ + +/* IOC Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_IOC_0 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Reserved2; /* 0x08 */ + U16 VendorID; /* 0x0C */ + U16 DeviceID; /* 0x0E */ + U8 RevisionID; /* 0x10 */ + U8 Reserved3; /* 0x11 */ + U16 Reserved4; /* 0x12 */ + U32 ClassCode; /* 0x14 */ + U16 SubsystemVendorID; /* 0x18 */ + U16 SubsystemID; /* 0x1A */ +} MPI2_CONFIG_PAGE_IOC_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_0, + Mpi2IOCPage0_t, MPI2_POINTER pMpi2IOCPage0_t; + +#define MPI2_IOCPAGE0_PAGEVERSION (0x02) + + +/* IOC Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_IOC_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Flags; /* 0x04 */ + U32 CoalescingTimeout; /* 0x08 */ + U8 CoalescingDepth; /* 0x0C */ + U8 PCISlotNum; /* 0x0D */ + U8 PCIBusNum; /* 0x0E */ + U8 PCIDomainSegment; /* 0x0F */ + U32 Reserved1; /* 0x10 */ + U32 Reserved2; /* 0x14 */ +} MPI2_CONFIG_PAGE_IOC_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_1, + Mpi2IOCPage1_t, MPI2_POINTER pMpi2IOCPage1_t; + +#define MPI2_IOCPAGE1_PAGEVERSION (0x05) + +/* defines for IOC Page 1 Flags field */ +#define MPI2_IOCPAGE1_REPLY_COALESCING (0x00000001) + +#define MPI2_IOCPAGE1_PCISLOTNUM_UNKNOWN (0xFF) +#define MPI2_IOCPAGE1_PCIBUSNUM_UNKNOWN (0xFF) +#define MPI2_IOCPAGE1_PCIDOMAIN_UNKNOWN (0xFF) + +/* IOC Page 6 */ + +typedef struct _MPI2_CONFIG_PAGE_IOC_6 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 CapabilitiesFlags; /* 0x04 */ + U8 MaxDrivesRAID0; /* 0x08 */ + U8 MaxDrivesRAID1; /* 0x09 */ + U8 MaxDrivesRAID1E; /* 0x0A */ + U8 MaxDrivesRAID10; /* 0x0B */ + U8 MinDrivesRAID0; /* 0x0C */ + U8 MinDrivesRAID1; /* 0x0D */ + U8 MinDrivesRAID1E; /* 0x0E */ + U8 MinDrivesRAID10; /* 0x0F */ + U32 Reserved1; /* 0x10 */ + U8 MaxGlobalHotSpares; /* 0x14 */ + U8 MaxPhysDisks; /* 0x15 */ + U8 MaxVolumes; /* 0x16 */ + U8 MaxConfigs; /* 0x17 */ + U8 MaxOCEDisks; /* 0x18 */ + U8 Reserved2; /* 0x19 */ + U16 Reserved3; /* 0x1A */ + U32 SupportedStripeSizeMapRAID0; /* 0x1C */ + U32 SupportedStripeSizeMapRAID1E; /* 0x20 */ + U32 SupportedStripeSizeMapRAID10; /* 0x24 */ + U32 Reserved4; /* 0x28 */ + U32 Reserved5; /* 0x2C */ + U16 DefaultMetadataSize; /* 0x30 */ + U16 Reserved6; /* 0x32 */ + U16 MaxBadBlockTableEntries; /* 0x34 */ + U16 Reserved7; /* 0x36 */ + U32 IRNvsramVersion; /* 0x38 */ +} MPI2_CONFIG_PAGE_IOC_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_6, + Mpi2IOCPage6_t, MPI2_POINTER pMpi2IOCPage6_t; + +#define MPI2_IOCPAGE6_PAGEVERSION (0x05) + +/* defines for IOC Page 6 CapabilitiesFlags */ +#define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT (0x00000020) +#define MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT (0x00000010) +#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT (0x00000008) +#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT (0x00000004) +#define MPI2_IOCPAGE6_CAP_FLAGS_RAID0_SUPPORT (0x00000002) +#define MPI2_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE (0x00000001) + + +/* IOC Page 7 */ + +#define MPI2_IOCPAGE7_EVENTMASK_WORDS (4) + +typedef struct _MPI2_CONFIG_PAGE_IOC_7 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 EventMasks[MPI2_IOCPAGE7_EVENTMASK_WORDS];/* 0x08 */ + U16 SASBroadcastPrimitiveMasks; /* 0x18 */ + U16 SASNotifyPrimitiveMasks; /* 0x1A */ + U32 Reserved3; /* 0x1C */ +} MPI2_CONFIG_PAGE_IOC_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_7, + Mpi2IOCPage7_t, MPI2_POINTER pMpi2IOCPage7_t; + +#define MPI2_IOCPAGE7_PAGEVERSION (0x02) + + +/* IOC Page 8 */ + +typedef struct _MPI2_CONFIG_PAGE_IOC_8 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumDevsPerEnclosure; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U16 MaxPersistentEntries; /* 0x08 */ + U16 MaxNumPhysicalMappedIDs; /* 0x0A */ + U16 Flags; /* 0x0C */ + U16 Reserved3; /* 0x0E */ + U16 IRVolumeMappingFlags; /* 0x10 */ + U16 Reserved4; /* 0x12 */ + U32 Reserved5; /* 0x14 */ +} MPI2_CONFIG_PAGE_IOC_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_8, + Mpi2IOCPage8_t, MPI2_POINTER pMpi2IOCPage8_t; + +#define MPI2_IOCPAGE8_PAGEVERSION (0x00) + +/* defines for IOC Page 8 Flags field */ +#define MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1 (0x00000020) +#define MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0 (0x00000010) + +#define MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE (0x0000000E) +#define MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING (0x00000000) +#define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING (0x00000002) + +#define MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING (0x00000001) +#define MPI2_IOCPAGE8_FLAGS_ENABLE_PERSISTENT_MAPPING (0x00000000) + +/* defines for IOC Page 8 IRVolumeMappingFlags */ +#define MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE (0x00000003) +#define MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING (0x00000000) +#define MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING (0x00000001) + + +/**************************************************************************** +* BIOS Config Pages +****************************************************************************/ + +/* BIOS Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_BIOS_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 BiosOptions; /* 0x04 */ + U32 IOCSettings; /* 0x08 */ + U32 Reserved1; /* 0x0C */ + U32 DeviceSettings; /* 0x10 */ + U16 NumberOfDevices; /* 0x14 */ + U16 UEFIVersion; /* 0x16 */ + U16 IOTimeoutBlockDevicesNonRM; /* 0x18 */ + U16 IOTimeoutSequential; /* 0x1A */ + U16 IOTimeoutOther; /* 0x1C */ + U16 IOTimeoutBlockDevicesRM; /* 0x1E */ +} MPI2_CONFIG_PAGE_BIOS_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_1, + Mpi2BiosPage1_t, MPI2_POINTER pMpi2BiosPage1_t; + +#define MPI2_BIOSPAGE1_PAGEVERSION (0x05) + +/* values for BIOS Page 1 BiosOptions field */ +#define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID (0x000000F0) +#define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID (0x00000000) + +#define MPI2_BIOSPAGE1_OPTIONS_MASK_UEFI_HII_REGISTRATION (0x00000006) +#define MPI2_BIOSPAGE1_OPTIONS_ENABLE_UEFI_HII (0x00000000) +#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_UEFI_HII (0x00000002) +#define MPI2_BIOSPAGE1_OPTIONS_VERSION_CHECK_UEFI_HII (0x00000004) + +#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001) + +/* values for BIOS Page 1 IOCSettings field */ +#define MPI2_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE (0x00030000) +#define MPI2_BIOSPAGE1_IOCSET_ENCLOSURE_SLOT_BOOT (0x00000000) +#define MPI2_BIOSPAGE1_IOCSET_SAS_ADDRESS_BOOT (0x00010000) + +#define MPI2_BIOSPAGE1_IOCSET_MASK_RM_SETTING (0x000000C0) +#define MPI2_BIOSPAGE1_IOCSET_NONE_RM_SETTING (0x00000000) +#define MPI2_BIOSPAGE1_IOCSET_BOOT_RM_SETTING (0x00000040) +#define MPI2_BIOSPAGE1_IOCSET_MEDIA_RM_SETTING (0x00000080) + +#define MPI2_BIOSPAGE1_IOCSET_MASK_ADAPTER_SUPPORT (0x00000030) +#define MPI2_BIOSPAGE1_IOCSET_NO_SUPPORT (0x00000000) +#define MPI2_BIOSPAGE1_IOCSET_BIOS_SUPPORT (0x00000010) +#define MPI2_BIOSPAGE1_IOCSET_OS_SUPPORT (0x00000020) +#define MPI2_BIOSPAGE1_IOCSET_ALL_SUPPORT (0x00000030) + +#define MPI2_BIOSPAGE1_IOCSET_ALTERNATE_CHS (0x00000008) + +/* values for BIOS Page 1 DeviceSettings field */ +#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SMART_POLLING (0x00000010) +#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN (0x00000008) +#define MPI2_BIOSPAGE1_DEVSET_DISABLE_RM_LUN (0x00000004) +#define MPI2_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002) +#define MPI2_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN (0x00000001) + +/* defines for BIOS Page 1 UEFIVersion field */ +#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_MASK (0xFF00) +#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_SHIFT (8) +#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_MASK (0x00FF) +#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_SHIFT (0) + + + +/* BIOS Page 2 */ + +typedef struct _MPI2_BOOT_DEVICE_ADAPTER_ORDER +{ + U32 Reserved1; /* 0x00 */ + U32 Reserved2; /* 0x04 */ + U32 Reserved3; /* 0x08 */ + U32 Reserved4; /* 0x0C */ + U32 Reserved5; /* 0x10 */ + U32 Reserved6; /* 0x14 */ +} MPI2_BOOT_DEVICE_ADAPTER_ORDER, + MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ADAPTER_ORDER, + Mpi2BootDeviceAdapterOrder_t, MPI2_POINTER pMpi2BootDeviceAdapterOrder_t; + +typedef struct _MPI2_BOOT_DEVICE_SAS_WWID +{ + U64 SASAddress; /* 0x00 */ + U8 LUN[8]; /* 0x08 */ + U32 Reserved1; /* 0x10 */ + U32 Reserved2; /* 0x14 */ +} MPI2_BOOT_DEVICE_SAS_WWID, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_SAS_WWID, + Mpi2BootDeviceSasWwid_t, MPI2_POINTER pMpi2BootDeviceSasWwid_t; + +typedef struct _MPI2_BOOT_DEVICE_ENCLOSURE_SLOT +{ + U64 EnclosureLogicalID; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U32 Reserved2; /* 0x0C */ + U16 SlotNumber; /* 0x10 */ + U16 Reserved3; /* 0x12 */ + U32 Reserved4; /* 0x14 */ +} MPI2_BOOT_DEVICE_ENCLOSURE_SLOT, + MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ENCLOSURE_SLOT, + Mpi2BootDeviceEnclosureSlot_t, MPI2_POINTER pMpi2BootDeviceEnclosureSlot_t; + +typedef struct _MPI2_BOOT_DEVICE_DEVICE_NAME +{ + U64 DeviceName; /* 0x00 */ + U8 LUN[8]; /* 0x08 */ + U32 Reserved1; /* 0x10 */ + U32 Reserved2; /* 0x14 */ +} MPI2_BOOT_DEVICE_DEVICE_NAME, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_DEVICE_NAME, + Mpi2BootDeviceDeviceName_t, MPI2_POINTER pMpi2BootDeviceDeviceName_t; + +typedef union _MPI2_MPI2_BIOSPAGE2_BOOT_DEVICE +{ + MPI2_BOOT_DEVICE_ADAPTER_ORDER AdapterOrder; + MPI2_BOOT_DEVICE_SAS_WWID SasWwid; + MPI2_BOOT_DEVICE_ENCLOSURE_SLOT EnclosureSlot; + MPI2_BOOT_DEVICE_DEVICE_NAME DeviceName; +} MPI2_BIOSPAGE2_BOOT_DEVICE, MPI2_POINTER PTR_MPI2_BIOSPAGE2_BOOT_DEVICE, + Mpi2BiosPage2BootDevice_t, MPI2_POINTER pMpi2BiosPage2BootDevice_t; + +typedef struct _MPI2_CONFIG_PAGE_BIOS_2 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Reserved2; /* 0x08 */ + U32 Reserved3; /* 0x0C */ + U32 Reserved4; /* 0x10 */ + U32 Reserved5; /* 0x14 */ + U32 Reserved6; /* 0x18 */ + U8 ReqBootDeviceForm; /* 0x1C */ + U8 Reserved7; /* 0x1D */ + U16 Reserved8; /* 0x1E */ + MPI2_BIOSPAGE2_BOOT_DEVICE RequestedBootDevice; /* 0x20 */ + U8 ReqAltBootDeviceForm; /* 0x38 */ + U8 Reserved9; /* 0x39 */ + U16 Reserved10; /* 0x3A */ + MPI2_BIOSPAGE2_BOOT_DEVICE RequestedAltBootDevice; /* 0x3C */ + U8 CurrentBootDeviceForm; /* 0x58 */ + U8 Reserved11; /* 0x59 */ + U16 Reserved12; /* 0x5A */ + MPI2_BIOSPAGE2_BOOT_DEVICE CurrentBootDevice; /* 0x58 */ +} MPI2_CONFIG_PAGE_BIOS_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_2, + Mpi2BiosPage2_t, MPI2_POINTER pMpi2BiosPage2_t; + +#define MPI2_BIOSPAGE2_PAGEVERSION (0x04) + +/* values for BIOS Page 2 BootDeviceForm fields */ +#define MPI2_BIOSPAGE2_FORM_MASK (0x0F) +#define MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED (0x00) +#define MPI2_BIOSPAGE2_FORM_SAS_WWID (0x05) +#define MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06) +#define MPI2_BIOSPAGE2_FORM_DEVICE_NAME (0x07) + + +/* BIOS Page 3 */ + +typedef struct _MPI2_ADAPTER_INFO +{ + U8 PciBusNumber; /* 0x00 */ + U8 PciDeviceAndFunctionNumber; /* 0x01 */ + U16 AdapterFlags; /* 0x02 */ +} MPI2_ADAPTER_INFO, MPI2_POINTER PTR_MPI2_ADAPTER_INFO, + Mpi2AdapterInfo_t, MPI2_POINTER pMpi2AdapterInfo_t; + +#define MPI2_ADAPTER_INFO_FLAGS_EMBEDDED (0x0001) +#define MPI2_ADAPTER_INFO_FLAGS_INIT_STATUS (0x0002) + +typedef struct _MPI2_CONFIG_PAGE_BIOS_3 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 GlobalFlags; /* 0x04 */ + U32 BiosVersion; /* 0x08 */ + MPI2_ADAPTER_INFO AdapterOrder[4]; /* 0x0C */ + U32 Reserved1; /* 0x1C */ +} MPI2_CONFIG_PAGE_BIOS_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_3, + Mpi2BiosPage3_t, MPI2_POINTER pMpi2BiosPage3_t; + +#define MPI2_BIOSPAGE3_PAGEVERSION (0x00) + +/* values for BIOS Page 3 GlobalFlags */ +#define MPI2_BIOSPAGE3_FLAGS_PAUSE_ON_ERROR (0x00000002) +#define MPI2_BIOSPAGE3_FLAGS_VERBOSE_ENABLE (0x00000004) +#define MPI2_BIOSPAGE3_FLAGS_HOOK_INT_40_DISABLE (0x00000010) + +#define MPI2_BIOSPAGE3_FLAGS_DEV_LIST_DISPLAY_MASK (0x000000E0) +#define MPI2_BIOSPAGE3_FLAGS_INSTALLED_DEV_DISPLAY (0x00000000) +#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DISPLAY (0x00000020) +#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DEV_DISPLAY (0x00000040) + + +/* BIOS Page 4 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumPhys at runtime. + */ +#ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES +#define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1) +#endif + +typedef struct _MPI2_BIOS4_ENTRY +{ + U64 ReassignmentWWID; /* 0x00 */ + U64 ReassignmentDeviceName; /* 0x08 */ +} MPI2_BIOS4_ENTRY, MPI2_POINTER PTR_MPI2_BIOS4_ENTRY, + Mpi2MBios4Entry_t, MPI2_POINTER pMpi2Bios4Entry_t; + +typedef struct _MPI2_CONFIG_PAGE_BIOS_4 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumPhys; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + MPI2_BIOS4_ENTRY Phy[MPI2_BIOS_PAGE_4_PHY_ENTRIES]; /* 0x08 */ +} MPI2_CONFIG_PAGE_BIOS_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_4, + Mpi2BiosPage4_t, MPI2_POINTER pMpi2BiosPage4_t; + +#define MPI2_BIOSPAGE4_PAGEVERSION (0x01) + + +/**************************************************************************** +* RAID Volume Config Pages +****************************************************************************/ + +/* RAID Volume Page 0 */ + +typedef struct _MPI2_RAIDVOL0_PHYS_DISK +{ + U8 RAIDSetNum; /* 0x00 */ + U8 PhysDiskMap; /* 0x01 */ + U8 PhysDiskNum; /* 0x02 */ + U8 Reserved; /* 0x03 */ +} MPI2_RAIDVOL0_PHYS_DISK, MPI2_POINTER PTR_MPI2_RAIDVOL0_PHYS_DISK, + Mpi2RaidVol0PhysDisk_t, MPI2_POINTER pMpi2RaidVol0PhysDisk_t; + +/* defines for the PhysDiskMap field */ +#define MPI2_RAIDVOL0_PHYSDISK_PRIMARY (0x01) +#define MPI2_RAIDVOL0_PHYSDISK_SECONDARY (0x02) + +typedef struct _MPI2_RAIDVOL0_SETTINGS +{ + U16 Settings; /* 0x00 */ + U8 HotSparePool; /* 0x01 */ + U8 Reserved; /* 0x02 */ +} MPI2_RAIDVOL0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDVOL0_SETTINGS, + Mpi2RaidVol0Settings_t, MPI2_POINTER pMpi2RaidVol0Settings_t; + +/* RAID Volume Page 0 HotSparePool defines, also used in RAID Physical Disk */ +#define MPI2_RAID_HOT_SPARE_POOL_0 (0x01) +#define MPI2_RAID_HOT_SPARE_POOL_1 (0x02) +#define MPI2_RAID_HOT_SPARE_POOL_2 (0x04) +#define MPI2_RAID_HOT_SPARE_POOL_3 (0x08) +#define MPI2_RAID_HOT_SPARE_POOL_4 (0x10) +#define MPI2_RAID_HOT_SPARE_POOL_5 (0x20) +#define MPI2_RAID_HOT_SPARE_POOL_6 (0x40) +#define MPI2_RAID_HOT_SPARE_POOL_7 (0x80) + +/* RAID Volume Page 0 VolumeSettings defines */ +#define MPI2_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX (0x0008) +#define MPI2_RAIDVOL0_SETTING_AUTO_CONFIG_HSWAP_DISABLE (0x0004) + +#define MPI2_RAIDVOL0_SETTING_MASK_WRITE_CACHING (0x0003) +#define MPI2_RAIDVOL0_SETTING_UNCHANGED (0x0000) +#define MPI2_RAIDVOL0_SETTING_DISABLE_WRITE_CACHING (0x0001) +#define MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING (0x0002) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumPhysDisks at runtime. + */ +#ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX +#define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 DevHandle; /* 0x04 */ + U8 VolumeState; /* 0x06 */ + U8 VolumeType; /* 0x07 */ + U32 VolumeStatusFlags; /* 0x08 */ + MPI2_RAIDVOL0_SETTINGS VolumeSettings; /* 0x0C */ + U64 MaxLBA; /* 0x10 */ + U32 StripeSize; /* 0x18 */ + U16 BlockSize; /* 0x1C */ + U16 Reserved1; /* 0x1E */ + U8 SupportedPhysDisks; /* 0x20 */ + U8 ResyncRate; /* 0x21 */ + U16 DataScrubDuration; /* 0x22 */ + U8 NumPhysDisks; /* 0x24 */ + U8 Reserved2; /* 0x25 */ + U8 Reserved3; /* 0x26 */ + U8 InactiveStatus; /* 0x27 */ + MPI2_RAIDVOL0_PHYS_DISK PhysDisk[MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX]; /* 0x28 */ +} MPI2_CONFIG_PAGE_RAID_VOL_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_0, + Mpi2RaidVolPage0_t, MPI2_POINTER pMpi2RaidVolPage0_t; + +#define MPI2_RAIDVOLPAGE0_PAGEVERSION (0x0A) + +/* values for RAID VolumeState */ +#define MPI2_RAID_VOL_STATE_MISSING (0x00) +#define MPI2_RAID_VOL_STATE_FAILED (0x01) +#define MPI2_RAID_VOL_STATE_INITIALIZING (0x02) +#define MPI2_RAID_VOL_STATE_ONLINE (0x03) +#define MPI2_RAID_VOL_STATE_DEGRADED (0x04) +#define MPI2_RAID_VOL_STATE_OPTIMAL (0x05) + +/* values for RAID VolumeType */ +#define MPI2_RAID_VOL_TYPE_RAID0 (0x00) +#define MPI2_RAID_VOL_TYPE_RAID1E (0x01) +#define MPI2_RAID_VOL_TYPE_RAID1 (0x02) +#define MPI2_RAID_VOL_TYPE_RAID10 (0x05) +#define MPI2_RAID_VOL_TYPE_UNKNOWN (0xFF) + +/* values for RAID Volume Page 0 VolumeStatusFlags field */ +#define MPI2_RAIDVOL0_STATUS_FLAG_PENDING_RESYNC (0x02000000) +#define MPI2_RAIDVOL0_STATUS_FLAG_BACKG_INIT_PENDING (0x01000000) +#define MPI2_RAIDVOL0_STATUS_FLAG_MDC_PENDING (0x00800000) +#define MPI2_RAIDVOL0_STATUS_FLAG_USER_CONSIST_PENDING (0x00400000) +#define MPI2_RAIDVOL0_STATUS_FLAG_MAKE_DATA_CONSISTENT (0x00200000) +#define MPI2_RAIDVOL0_STATUS_FLAG_DATA_SCRUB (0x00100000) +#define MPI2_RAIDVOL0_STATUS_FLAG_CONSISTENCY_CHECK (0x00080000) +#define MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION (0x00040000) +#define MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT (0x00020000) +#define MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x00010000) +#define MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT (0x00000080) +#define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED (0x00000040) +#define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE (0x00000020) +#define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR (0x00000000) +#define MPI2_RAIDVOL0_STATUS_FLAG_1E_ADJACENT_MIRROR (0x00000010) +#define MPI2_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL (0x00000008) +#define MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE (0x00000004) +#define MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED (0x00000002) +#define MPI2_RAIDVOL0_STATUS_FLAG_ENABLED (0x00000001) + +/* values for RAID Volume Page 0 SupportedPhysDisks field */ +#define MPI2_RAIDVOL0_SUPPORT_SOLID_STATE_DISKS (0x08) +#define MPI2_RAIDVOL0_SUPPORT_HARD_DISKS (0x04) +#define MPI2_RAIDVOL0_SUPPORT_SAS_PROTOCOL (0x02) +#define MPI2_RAIDVOL0_SUPPORT_SATA_PROTOCOL (0x01) + +/* values for RAID Volume Page 0 InactiveStatus field */ +#define MPI2_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00) +#define MPI2_RAIDVOLPAGE0_STALE_METADATA_INACTIVE (0x01) +#define MPI2_RAIDVOLPAGE0_FOREIGN_VOLUME_INACTIVE (0x02) +#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_RESOURCE_INACTIVE (0x03) +#define MPI2_RAIDVOLPAGE0_CLONE_VOLUME_INACTIVE (0x04) +#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_METADATA_INACTIVE (0x05) +#define MPI2_RAIDVOLPAGE0_PREVIOUSLY_DELETED (0x06) + + +/* RAID Volume Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 DevHandle; /* 0x04 */ + U16 Reserved0; /* 0x06 */ + U8 GUID[24]; /* 0x08 */ + U8 Name[16]; /* 0x20 */ + U64 WWID; /* 0x30 */ + U32 Reserved1; /* 0x38 */ + U32 Reserved2; /* 0x3C */ +} MPI2_CONFIG_PAGE_RAID_VOL_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_1, + Mpi2RaidVolPage1_t, MPI2_POINTER pMpi2RaidVolPage1_t; + +#define MPI2_RAIDVOLPAGE1_PAGEVERSION (0x03) + + +/**************************************************************************** +* RAID Physical Disk Config Pages +****************************************************************************/ + +/* RAID Physical Disk Page 0 */ + +typedef struct _MPI2_RAIDPHYSDISK0_SETTINGS +{ + U16 Reserved1; /* 0x00 */ + U8 HotSparePool; /* 0x02 */ + U8 Reserved2; /* 0x03 */ +} MPI2_RAIDPHYSDISK0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_SETTINGS, + Mpi2RaidPhysDisk0Settings_t, MPI2_POINTER pMpi2RaidPhysDisk0Settings_t; + +/* use MPI2_RAID_HOT_SPARE_POOL_ defines for the HotSparePool field */ + +typedef struct _MPI2_RAIDPHYSDISK0_INQUIRY_DATA +{ + U8 VendorID[8]; /* 0x00 */ + U8 ProductID[16]; /* 0x08 */ + U8 ProductRevLevel[4]; /* 0x18 */ + U8 SerialNum[32]; /* 0x1C */ +} MPI2_RAIDPHYSDISK0_INQUIRY_DATA, + MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_INQUIRY_DATA, + Mpi2RaidPhysDisk0InquiryData_t, MPI2_POINTER pMpi2RaidPhysDisk0InquiryData_t; + +typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 DevHandle; /* 0x04 */ + U8 Reserved1; /* 0x06 */ + U8 PhysDiskNum; /* 0x07 */ + MPI2_RAIDPHYSDISK0_SETTINGS PhysDiskSettings; /* 0x08 */ + U32 Reserved2; /* 0x0C */ + MPI2_RAIDPHYSDISK0_INQUIRY_DATA InquiryData; /* 0x10 */ + U32 Reserved3; /* 0x4C */ + U8 PhysDiskState; /* 0x50 */ + U8 OfflineReason; /* 0x51 */ + U8 IncompatibleReason; /* 0x52 */ + U8 PhysDiskAttributes; /* 0x53 */ + U32 PhysDiskStatusFlags; /* 0x54 */ + U64 DeviceMaxLBA; /* 0x58 */ + U64 HostMaxLBA; /* 0x60 */ + U64 CoercedMaxLBA; /* 0x68 */ + U16 BlockSize; /* 0x70 */ + U16 Reserved5; /* 0x72 */ + U32 Reserved6; /* 0x74 */ +} MPI2_CONFIG_PAGE_RD_PDISK_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_0, + Mpi2RaidPhysDiskPage0_t, MPI2_POINTER pMpi2RaidPhysDiskPage0_t; + +#define MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION (0x05) + +/* PhysDiskState defines */ +#define MPI2_RAID_PD_STATE_NOT_CONFIGURED (0x00) +#define MPI2_RAID_PD_STATE_NOT_COMPATIBLE (0x01) +#define MPI2_RAID_PD_STATE_OFFLINE (0x02) +#define MPI2_RAID_PD_STATE_ONLINE (0x03) +#define MPI2_RAID_PD_STATE_HOT_SPARE (0x04) +#define MPI2_RAID_PD_STATE_DEGRADED (0x05) +#define MPI2_RAID_PD_STATE_REBUILDING (0x06) +#define MPI2_RAID_PD_STATE_OPTIMAL (0x07) + +/* OfflineReason defines */ +#define MPI2_PHYSDISK0_ONLINE (0x00) +#define MPI2_PHYSDISK0_OFFLINE_MISSING (0x01) +#define MPI2_PHYSDISK0_OFFLINE_FAILED (0x03) +#define MPI2_PHYSDISK0_OFFLINE_INITIALIZING (0x04) +#define MPI2_PHYSDISK0_OFFLINE_REQUESTED (0x05) +#define MPI2_PHYSDISK0_OFFLINE_FAILED_REQUESTED (0x06) +#define MPI2_PHYSDISK0_OFFLINE_OTHER (0xFF) + +/* IncompatibleReason defines */ +#define MPI2_PHYSDISK0_COMPATIBLE (0x00) +#define MPI2_PHYSDISK0_INCOMPATIBLE_PROTOCOL (0x01) +#define MPI2_PHYSDISK0_INCOMPATIBLE_BLOCKSIZE (0x02) +#define MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA (0x03) +#define MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD (0x04) +#define MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA (0x05) +#define MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE (0x06) +#define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN (0xFF) + +/* PhysDiskAttributes defines */ +#define MPI2_PHYSDISK0_ATTRIB_MEDIA_MASK (0x0C) +#define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE (0x08) +#define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE (0x04) + +#define MPI2_PHYSDISK0_ATTRIB_PROTOCOL_MASK (0x03) +#define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL (0x02) +#define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL (0x01) + +/* PhysDiskStatusFlags defines */ +#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED (0x00000040) +#define MPI2_PHYSDISK0_STATUS_FLAG_OCE_TARGET (0x00000020) +#define MPI2_PHYSDISK0_STATUS_FLAG_WRITE_CACHE_ENABLED (0x00000010) +#define MPI2_PHYSDISK0_STATUS_FLAG_OPTIMAL_PREVIOUS (0x00000000) +#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_OPTIMAL_PREVIOUS (0x00000008) +#define MPI2_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME (0x00000004) +#define MPI2_PHYSDISK0_STATUS_FLAG_QUIESCED (0x00000002) +#define MPI2_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC (0x00000001) + + +/* RAID Physical Disk Page 1 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumPhysDiskPaths at runtime. + */ +#ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX +#define MPI2_RAID_PHYS_DISK1_PATH_MAX (1) +#endif + +typedef struct _MPI2_RAIDPHYSDISK1_PATH +{ + U16 DevHandle; /* 0x00 */ + U16 Reserved1; /* 0x02 */ + U64 WWID; /* 0x04 */ + U64 OwnerWWID; /* 0x0C */ + U8 OwnerIdentifier; /* 0x14 */ + U8 Reserved2; /* 0x15 */ + U16 Flags; /* 0x16 */ +} MPI2_RAIDPHYSDISK1_PATH, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK1_PATH, + Mpi2RaidPhysDisk1Path_t, MPI2_POINTER pMpi2RaidPhysDisk1Path_t; + +/* RAID Physical Disk Page 1 Physical Disk Path Flags field defines */ +#define MPI2_RAID_PHYSDISK1_FLAG_PRIMARY (0x0004) +#define MPI2_RAID_PHYSDISK1_FLAG_BROKEN (0x0002) +#define MPI2_RAID_PHYSDISK1_FLAG_INVALID (0x0001) + +typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumPhysDiskPaths; /* 0x04 */ + U8 PhysDiskNum; /* 0x05 */ + U16 Reserved1; /* 0x06 */ + U32 Reserved2; /* 0x08 */ + MPI2_RAIDPHYSDISK1_PATH PhysicalDiskPath[MPI2_RAID_PHYS_DISK1_PATH_MAX];/* 0x0C */ +} MPI2_CONFIG_PAGE_RD_PDISK_1, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_1, + Mpi2RaidPhysDiskPage1_t, MPI2_POINTER pMpi2RaidPhysDiskPage1_t; + +#define MPI2_RAIDPHYSDISKPAGE1_PAGEVERSION (0x02) + + +/**************************************************************************** +* values for fields used by several types of SAS Config Pages +****************************************************************************/ + +/* values for NegotiatedLinkRates fields */ +#define MPI2_SAS_NEG_LINK_RATE_MASK_LOGICAL (0xF0) +#define MPI2_SAS_NEG_LINK_RATE_SHIFT_LOGICAL (4) +#define MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL (0x0F) +/* link rates used for Negotiated Physical and Logical Link Rate */ +#define MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE (0x00) +#define MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED (0x01) +#define MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED (0x02) +#define MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE (0x03) +#define MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR (0x04) +#define MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS (0x05) +#define MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY (0x06) +#define MPI2_SAS_NEG_LINK_RATE_1_5 (0x08) +#define MPI2_SAS_NEG_LINK_RATE_3_0 (0x09) +#define MPI2_SAS_NEG_LINK_RATE_6_0 (0x0A) +#define MPI25_SAS_NEG_LINK_RATE_12_0 (0x0B) + + +/* values for AttachedPhyInfo fields */ +#define MPI2_SAS_APHYINFO_INSIDE_ZPSDS_PERSISTENT (0x00000040) +#define MPI2_SAS_APHYINFO_REQUESTED_INSIDE_ZPSDS (0x00000020) +#define MPI2_SAS_APHYINFO_BREAK_REPLY_CAPABLE (0x00000010) + +#define MPI2_SAS_APHYINFO_REASON_MASK (0x0000000F) +#define MPI2_SAS_APHYINFO_REASON_UNKNOWN (0x00000000) +#define MPI2_SAS_APHYINFO_REASON_POWER_ON (0x00000001) +#define MPI2_SAS_APHYINFO_REASON_HARD_RESET (0x00000002) +#define MPI2_SAS_APHYINFO_REASON_SMP_PHY_CONTROL (0x00000003) +#define MPI2_SAS_APHYINFO_REASON_LOSS_OF_SYNC (0x00000004) +#define MPI2_SAS_APHYINFO_REASON_MULTIPLEXING_SEQ (0x00000005) +#define MPI2_SAS_APHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00000006) +#define MPI2_SAS_APHYINFO_REASON_BREAK_TIMEOUT (0x00000007) +#define MPI2_SAS_APHYINFO_REASON_PHY_TEST_STOPPED (0x00000008) + + +/* values for PhyInfo fields */ +#define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000) + +#define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000) +#define MPI2_SAS_PHYINFO_SHIFT_PHY_POWER_CONDITION (27) +#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000) +#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000) +#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000) + +#define MPI2_SAS_PHYINFO_CHANGED_REQ_INSIDE_ZPSDS (0x04000000) +#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT (0x02000000) +#define MPI2_SAS_PHYINFO_REQ_INSIDE_ZPSDS (0x01000000) +#define MPI2_SAS_PHYINFO_ZONE_GROUP_PERSISTENT (0x00400000) +#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS (0x00200000) +#define MPI2_SAS_PHYINFO_ZONING_ENABLED (0x00100000) + +#define MPI2_SAS_PHYINFO_REASON_MASK (0x000F0000) +#define MPI2_SAS_PHYINFO_REASON_UNKNOWN (0x00000000) +#define MPI2_SAS_PHYINFO_REASON_POWER_ON (0x00010000) +#define MPI2_SAS_PHYINFO_REASON_HARD_RESET (0x00020000) +#define MPI2_SAS_PHYINFO_REASON_SMP_PHY_CONTROL (0x00030000) +#define MPI2_SAS_PHYINFO_REASON_LOSS_OF_SYNC (0x00040000) +#define MPI2_SAS_PHYINFO_REASON_MULTIPLEXING_SEQ (0x00050000) +#define MPI2_SAS_PHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00060000) +#define MPI2_SAS_PHYINFO_REASON_BREAK_TIMEOUT (0x00070000) +#define MPI2_SAS_PHYINFO_REASON_PHY_TEST_STOPPED (0x00080000) + +#define MPI2_SAS_PHYINFO_MULTIPLEXING_SUPPORTED (0x00008000) +#define MPI2_SAS_PHYINFO_SATA_PORT_ACTIVE (0x00004000) +#define MPI2_SAS_PHYINFO_SATA_PORT_SELECTOR_PRESENT (0x00002000) +#define MPI2_SAS_PHYINFO_VIRTUAL_PHY (0x00001000) + +#define MPI2_SAS_PHYINFO_MASK_PARTIAL_PATHWAY_TIME (0x00000F00) +#define MPI2_SAS_PHYINFO_SHIFT_PARTIAL_PATHWAY_TIME (8) + +#define MPI2_SAS_PHYINFO_MASK_ROUTING_ATTRIBUTE (0x000000F0) +#define MPI2_SAS_PHYINFO_DIRECT_ROUTING (0x00000000) +#define MPI2_SAS_PHYINFO_SUBTRACTIVE_ROUTING (0x00000010) +#define MPI2_SAS_PHYINFO_TABLE_ROUTING (0x00000020) + + +/* values for SAS ProgrammedLinkRate fields */ +#define MPI2_SAS_PRATE_MAX_RATE_MASK (0xF0) +#define MPI2_SAS_PRATE_MAX_RATE_NOT_PROGRAMMABLE (0x00) +#define MPI2_SAS_PRATE_MAX_RATE_1_5 (0x80) +#define MPI2_SAS_PRATE_MAX_RATE_3_0 (0x90) +#define MPI2_SAS_PRATE_MAX_RATE_6_0 (0xA0) +#define MPI25_SAS_PRATE_MAX_RATE_12_0 (0xB0) +#define MPI2_SAS_PRATE_MIN_RATE_MASK (0x0F) +#define MPI2_SAS_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00) +#define MPI2_SAS_PRATE_MIN_RATE_1_5 (0x08) +#define MPI2_SAS_PRATE_MIN_RATE_3_0 (0x09) +#define MPI2_SAS_PRATE_MIN_RATE_6_0 (0x0A) +#define MPI25_SAS_PRATE_MIN_RATE_12_0 (0x0B) + + +/* values for SAS HwLinkRate fields */ +#define MPI2_SAS_HWRATE_MAX_RATE_MASK (0xF0) +#define MPI2_SAS_HWRATE_MAX_RATE_1_5 (0x80) +#define MPI2_SAS_HWRATE_MAX_RATE_3_0 (0x90) +#define MPI2_SAS_HWRATE_MAX_RATE_6_0 (0xA0) +#define MPI25_SAS_HWRATE_MAX_RATE_12_0 (0xB0) +#define MPI2_SAS_HWRATE_MIN_RATE_MASK (0x0F) +#define MPI2_SAS_HWRATE_MIN_RATE_1_5 (0x08) +#define MPI2_SAS_HWRATE_MIN_RATE_3_0 (0x09) +#define MPI2_SAS_HWRATE_MIN_RATE_6_0 (0x0A) +#define MPI25_SAS_HWRATE_MIN_RATE_12_0 (0x0B) + + + +/**************************************************************************** +* SAS IO Unit Config Pages +****************************************************************************/ + +/* SAS IO Unit Page 0 */ + +typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA +{ + U8 Port; /* 0x00 */ + U8 PortFlags; /* 0x01 */ + U8 PhyFlags; /* 0x02 */ + U8 NegotiatedLinkRate; /* 0x03 */ + U32 ControllerPhyDeviceInfo;/* 0x04 */ + U16 AttachedDevHandle; /* 0x08 */ + U16 ControllerDevHandle; /* 0x0A */ + U32 DiscoveryStatus; /* 0x0C */ + U32 Reserved; /* 0x10 */ +} MPI2_SAS_IO_UNIT0_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT0_PHY_DATA, + Mpi2SasIOUnit0PhyData_t, MPI2_POINTER pMpi2SasIOUnit0PhyData_t; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumPhys at runtime. + */ +#ifndef MPI2_SAS_IOUNIT0_PHY_MAX +#define MPI2_SAS_IOUNIT0_PHY_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U8 NumPhys; /* 0x0C */ + U8 Reserved2; /* 0x0D */ + U16 Reserved3; /* 0x0E */ + MPI2_SAS_IO_UNIT0_PHY_DATA PhyData[MPI2_SAS_IOUNIT0_PHY_MAX]; /* 0x10 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_0, + Mpi2SasIOUnitPage0_t, MPI2_POINTER pMpi2SasIOUnitPage0_t; + +#define MPI2_SASIOUNITPAGE0_PAGEVERSION (0x05) + +/* values for SAS IO Unit Page 0 PortFlags */ +#define MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS (0x08) +#define MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG (0x01) + +/* values for SAS IO Unit Page 0 PhyFlags */ +#define MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED (0x10) +#define MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08) + +/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ + +/* see mpi2_sas.h for values for SAS IO Unit Page 0 ControllerPhyDeviceInfo values */ + +/* values for SAS IO Unit Page 0 DiscoveryStatus */ +#define MPI2_SASIOUNIT0_DS_MAX_ENCLOSURES_EXCEED (0x80000000) +#define MPI2_SASIOUNIT0_DS_MAX_EXPANDERS_EXCEED (0x40000000) +#define MPI2_SASIOUNIT0_DS_MAX_DEVICES_EXCEED (0x20000000) +#define MPI2_SASIOUNIT0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) +#define MPI2_SASIOUNIT0_DS_DOWNSTREAM_INITIATOR (0x08000000) +#define MPI2_SASIOUNIT0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) +#define MPI2_SASIOUNIT0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) +#define MPI2_SASIOUNIT0_DS_MULTI_PORT_DOMAIN (0x00002000) +#define MPI2_SASIOUNIT0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) +#define MPI2_SASIOUNIT0_DS_UNSUPPORTED_DEVICE (0x00000800) +#define MPI2_SASIOUNIT0_DS_TABLE_LINK (0x00000400) +#define MPI2_SASIOUNIT0_DS_SUBTRACTIVE_LINK (0x00000200) +#define MPI2_SASIOUNIT0_DS_SMP_CRC_ERROR (0x00000100) +#define MPI2_SASIOUNIT0_DS_SMP_FUNCTION_FAILED (0x00000080) +#define MPI2_SASIOUNIT0_DS_INDEX_NOT_EXIST (0x00000040) +#define MPI2_SASIOUNIT0_DS_OUT_ROUTE_ENTRIES (0x00000020) +#define MPI2_SASIOUNIT0_DS_SMP_TIMEOUT (0x00000010) +#define MPI2_SASIOUNIT0_DS_MULTIPLE_PORTS (0x00000004) +#define MPI2_SASIOUNIT0_DS_UNADDRESSABLE_DEVICE (0x00000002) +#define MPI2_SASIOUNIT0_DS_LOOP_DETECTED (0x00000001) + + +/* SAS IO Unit Page 1 */ + +typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA +{ + U8 Port; /* 0x00 */ + U8 PortFlags; /* 0x01 */ + U8 PhyFlags; /* 0x02 */ + U8 MaxMinLinkRate; /* 0x03 */ + U32 ControllerPhyDeviceInfo; /* 0x04 */ + U16 MaxTargetPortConnectTime; /* 0x08 */ + U16 Reserved1; /* 0x0A */ +} MPI2_SAS_IO_UNIT1_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT1_PHY_DATA, + Mpi2SasIOUnit1PhyData_t, MPI2_POINTER pMpi2SasIOUnit1PhyData_t; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumPhys at runtime. + */ +#ifndef MPI2_SAS_IOUNIT1_PHY_MAX +#define MPI2_SAS_IOUNIT1_PHY_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 ControlFlags; /* 0x08 */ + U16 SASNarrowMaxQueueDepth; /* 0x0A */ + U16 AdditionalControlFlags; /* 0x0C */ + U16 SASWideMaxQueueDepth; /* 0x0E */ + U8 NumPhys; /* 0x10 */ + U8 SATAMaxQDepth; /* 0x11 */ + U8 ReportDeviceMissingDelay; /* 0x12 */ + U8 IODeviceMissingDelay; /* 0x13 */ + MPI2_SAS_IO_UNIT1_PHY_DATA PhyData[MPI2_SAS_IOUNIT1_PHY_MAX]; /* 0x14 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_1, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_1, + Mpi2SasIOUnitPage1_t, MPI2_POINTER pMpi2SasIOUnitPage1_t; + +#define MPI2_SASIOUNITPAGE1_PAGEVERSION (0x09) + +/* values for SAS IO Unit Page 1 ControlFlags */ +#define MPI2_SASIOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000) +#define MPI2_SASIOUNIT1_CONTROL_SATA_3_0_MAX (0x4000) +#define MPI2_SASIOUNIT1_CONTROL_SATA_1_5_MAX (0x2000) /* MPI v2.0 only. Obsolete in MPI v2.5 and later. */ +#define MPI2_SASIOUNIT1_CONTROL_SATA_SW_PRESERVE (0x1000) + +#define MPI2_SASIOUNIT1_CONTROL_MASK_DEV_SUPPORT (0x0600) +#define MPI2_SASIOUNIT1_CONTROL_SHIFT_DEV_SUPPORT (9) +#define MPI2_SASIOUNIT1_CONTROL_DEV_SUPPORT_BOTH (0x0) +#define MPI2_SASIOUNIT1_CONTROL_DEV_SAS_SUPPORT (0x1) +#define MPI2_SASIOUNIT1_CONTROL_DEV_SATA_SUPPORT (0x2) + +#define MPI2_SASIOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED (0x0080) +#define MPI2_SASIOUNIT1_CONTROL_SATA_SMART_REQUIRED (0x0040) +#define MPI2_SASIOUNIT1_CONTROL_SATA_NCQ_REQUIRED (0x0020) +#define MPI2_SASIOUNIT1_CONTROL_SATA_FUA_REQUIRED (0x0010) +#define MPI2_SASIOUNIT1_CONTROL_TABLE_SUBTRACTIVE_ILLEGAL (0x0008) +#define MPI2_SASIOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL (0x0004) +#define MPI2_SASIOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY (0x0002) +#define MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001) /* MPI v2.0 only. Obsolete in MPI v2.5 and later. */ + +/* values for SAS IO Unit Page 1 AdditionalControlFlags */ +#define MPI2_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080) +#define MPI2_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040) +#define MPI2_SASIOUNIT1_ACONTROL_INVALID_TOPOLOGY_CORRECTION (0x0020) +#define MPI2_SASIOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET (0x0010) +#define MPI2_SASIOUNIT1_ACONTROL_OTHER_AFFILIATION_SATA_LINK_RESET (0x0008) +#define MPI2_SASIOUNIT1_ACONTROL_SELF_AFFILIATION_SATA_LINK_RESET (0x0004) +#define MPI2_SASIOUNIT1_ACONTROL_NO_AFFILIATION_SATA_LINK_RESET (0x0002) +#define MPI2_SASIOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001) + +/* defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */ +#define MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK (0x7F) +#define MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16 (0x80) + +/* values for SAS IO Unit Page 1 PortFlags */ +#define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) + +/* values for SAS IO Unit Page 1 PhyFlags */ +#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10) +#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08) + +/* values for SAS IO Unit Page 1 MaxMinLinkRate */ +#define MPI2_SASIOUNIT1_MAX_RATE_MASK (0xF0) +#define MPI2_SASIOUNIT1_MAX_RATE_1_5 (0x80) +#define MPI2_SASIOUNIT1_MAX_RATE_3_0 (0x90) +#define MPI2_SASIOUNIT1_MAX_RATE_6_0 (0xA0) +#define MPI25_SASIOUNIT1_MAX_RATE_12_0 (0xB0) +#define MPI2_SASIOUNIT1_MIN_RATE_MASK (0x0F) +#define MPI2_SASIOUNIT1_MIN_RATE_1_5 (0x08) +#define MPI2_SASIOUNIT1_MIN_RATE_3_0 (0x09) +#define MPI2_SASIOUNIT1_MIN_RATE_6_0 (0x0A) +#define MPI25_SASIOUNIT1_MIN_RATE_12_0 (0x0B) + +/* see mpi2_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */ + + +/* SAS IO Unit Page 4 */ + +typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP +{ + U8 MaxTargetSpinup; /* 0x00 */ + U8 SpinupDelay; /* 0x01 */ + U8 SpinupFlags; /* 0x02 */ + U8 Reserved1; /* 0x03 */ +} MPI2_SAS_IOUNIT4_SPINUP_GROUP, MPI2_POINTER PTR_MPI2_SAS_IOUNIT4_SPINUP_GROUP, + Mpi2SasIOUnit4SpinupGroup_t, MPI2_POINTER pMpi2SasIOUnit4SpinupGroup_t; + +/* defines for SAS IO Unit Page 4 SpinupFlags */ +#define MPI2_SASIOUNIT4_SPINUP_DISABLE_FLAG (0x01) + + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumPhys at runtime. + */ +#ifndef MPI2_SAS_IOUNIT4_PHY_MAX +#define MPI2_SAS_IOUNIT4_PHY_MAX (4) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + MPI2_SAS_IOUNIT4_SPINUP_GROUP SpinupGroupParameters[4]; /* 0x08 */ + U32 Reserved1; /* 0x18 */ + U32 Reserved2; /* 0x1C */ + U32 Reserved3; /* 0x20 */ + U8 BootDeviceWaitTime; /* 0x24 */ + U8 Reserved4; /* 0x25 */ + U16 Reserved5; /* 0x26 */ + U8 NumPhys; /* 0x28 */ + U8 PEInitialSpinupDelay; /* 0x29 */ + U8 PEReplyDelay; /* 0x2A */ + U8 Flags; /* 0x2B */ + U8 PHY[MPI2_SAS_IOUNIT4_PHY_MAX]; /* 0x2C */ +} MPI2_CONFIG_PAGE_SASIOUNIT_4, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_4, + Mpi2SasIOUnitPage4_t, MPI2_POINTER pMpi2SasIOUnitPage4_t; + +#define MPI2_SASIOUNITPAGE4_PAGEVERSION (0x02) + +/* defines for Flags field */ +#define MPI2_SASIOUNIT4_FLAGS_AUTO_PORTENABLE (0x01) + +/* defines for PHY field */ +#define MPI2_SASIOUNIT4_PHY_SPINUP_GROUP_MASK (0x03) + + +/* SAS IO Unit Page 5 */ + +typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS +{ + U8 ControlFlags; /* 0x00 */ + U8 PortWidthModGroup; /* 0x01 */ + U16 InactivityTimerExponent; /* 0x02 */ + U8 SATAPartialTimeout; /* 0x04 */ + U8 Reserved2; /* 0x05 */ + U8 SATASlumberTimeout; /* 0x06 */ + U8 Reserved3; /* 0x07 */ + U8 SASPartialTimeout; /* 0x08 */ + U8 Reserved4; /* 0x09 */ + U8 SASSlumberTimeout; /* 0x0A */ + U8 Reserved5; /* 0x0B */ +} MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, + MPI2_POINTER PTR_MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, + Mpi2SasIOUnit5PhyPmSettings_t, MPI2_POINTER pMpi2SasIOUnit5PhyPmSettings_t; + +/* defines for ControlFlags field */ +#define MPI2_SASIOUNIT5_CONTROL_SAS_SLUMBER_ENABLE (0x08) +#define MPI2_SASIOUNIT5_CONTROL_SAS_PARTIAL_ENABLE (0x04) +#define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02) +#define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01) + +/* defines for PortWidthModeGroup field */ +#define MPI2_SASIOUNIT5_PWMG_DISABLE (0xFF) + +/* defines for InactivityTimerExponent field */ +#define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000) +#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12) +#define MPI2_SASIOUNIT5_ITE_MASK_SAS_PARTIAL (0x0700) +#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_PARTIAL (8) +#define MPI2_SASIOUNIT5_ITE_MASK_SATA_SLUMBER (0x0070) +#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_SLUMBER (4) +#define MPI2_SASIOUNIT5_ITE_MASK_SATA_PARTIAL (0x0007) +#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_PARTIAL (0) + +#define MPI2_SASIOUNIT5_ITE_TEN_SECONDS (7) +#define MPI2_SASIOUNIT5_ITE_ONE_SECOND (6) +#define MPI2_SASIOUNIT5_ITE_HUNDRED_MILLISECONDS (5) +#define MPI2_SASIOUNIT5_ITE_TEN_MILLISECONDS (4) +#define MPI2_SASIOUNIT5_ITE_ONE_MILLISECOND (3) +#define MPI2_SASIOUNIT5_ITE_HUNDRED_MICROSECONDS (2) +#define MPI2_SASIOUNIT5_ITE_TEN_MICROSECONDS (1) +#define MPI2_SASIOUNIT5_ITE_ONE_MICROSECOND (0) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumPhys at runtime. + */ +#ifndef MPI2_SAS_IOUNIT5_PHY_MAX +#define MPI2_SAS_IOUNIT5_PHY_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 NumPhys; /* 0x08 */ + U8 Reserved1; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 Reserved3; /* 0x0C */ + MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS SASPhyPowerManagementSettings[MPI2_SAS_IOUNIT5_PHY_MAX]; /* 0x10 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_5, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5, + Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t; + +#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x01) + + +/* SAS IO Unit Page 6 */ + +typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS +{ + U8 CurrentStatus; /* 0x00 */ + U8 CurrentModulation; /* 0x01 */ + U8 CurrentUtilization; /* 0x02 */ + U8 Reserved1; /* 0x03 */ + U32 Reserved2; /* 0x04 */ +} MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, + MPI2_POINTER PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, + Mpi2SasIOUnit6PortWidthModGroupStatus_t, + MPI2_POINTER pMpi2SasIOUnit6PortWidthModGroupStatus_t; + +/* defines for CurrentStatus field */ +#define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE (0x00) +#define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED (0x01) +#define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG (0x02) +#define MPI2_SASIOUNIT6_STATUS_LINK_DOWN (0x03) +#define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY (0x04) +#define MPI2_SASIOUNIT6_STATUS_INACTIVE (0x05) +#define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT (0x06) +#define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST (0x07) + +/* defines for CurrentModulation field */ +#define MPI2_SASIOUNIT6_MODULATION_25_PERCENT (0x00) +#define MPI2_SASIOUNIT6_MODULATION_50_PERCENT (0x01) +#define MPI2_SASIOUNIT6_MODULATION_75_PERCENT (0x02) +#define MPI2_SASIOUNIT6_MODULATION_100_PERCENT (0x03) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumGroups at runtime. + */ +#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX +#define MPI2_SAS_IOUNIT6_GROUP_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U32 Reserved2; /* 0x0C */ + U8 NumGroups; /* 0x10 */ + U8 Reserved3; /* 0x11 */ + U16 Reserved4; /* 0x12 */ + MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS + PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /* 0x14 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_6, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6, + Mpi2SasIOUnitPage6_t, MPI2_POINTER pMpi2SasIOUnitPage6_t; + +#define MPI2_SASIOUNITPAGE6_PAGEVERSION (0x00) + + +/* SAS IO Unit Page 7 */ + +typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS +{ + U8 Flags; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U8 Threshold75Pct; /* 0x04 */ + U8 Threshold50Pct; /* 0x05 */ + U8 Threshold25Pct; /* 0x06 */ + U8 Reserved3; /* 0x07 */ +} MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, + MPI2_POINTER PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, + Mpi2SasIOUnit7PortWidthModGroupSettings_t, + MPI2_POINTER pMpi2SasIOUnit7PortWidthModGroupSettings_t; + +/* defines for Flags field */ +#define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION (0x01) + + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumGroups at runtime. + */ +#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX +#define MPI2_SAS_IOUNIT7_GROUP_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 SamplingInterval; /* 0x08 */ + U8 WindowLength; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U32 Reserved2; /* 0x0C */ + U32 Reserved3; /* 0x10 */ + U8 NumGroups; /* 0x14 */ + U8 Reserved4; /* 0x15 */ + U16 Reserved5; /* 0x16 */ + MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS + PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX]; /* 0x18 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_7, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7, + Mpi2SasIOUnitPage7_t, MPI2_POINTER pMpi2SasIOUnitPage7_t; + +#define MPI2_SASIOUNITPAGE7_PAGEVERSION (0x00) + + +/* SAS IO Unit Page 8 */ + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U32 PowerManagementCapabilities; /* 0x0C */ + U8 TxRxSleepStatus; /* 0x10 */ /* reserved in MPI 2.0 */ + U8 Reserved2; /* 0x11 */ + U16 Reserved3; /* 0x12 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_8, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8, + Mpi2SasIOUnitPage8_t, MPI2_POINTER pMpi2SasIOUnitPage8_t; + +#define MPI2_SASIOUNITPAGE8_PAGEVERSION (0x00) + +/* defines for PowerManagementCapabilities field */ +#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD (0x00001000) +#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x00000800) +#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x00000400) +#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x00000200) +#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x00000100) +#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x00000010) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x00000008) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x00000004) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x00000002) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x00000001) + +/* defines for TxRxSleepStatus field */ +#define MPI25_SASIOUNIT8_TXRXSLEEP_UNSUPPORTED (0x00) +#define MPI25_SASIOUNIT8_TXRXSLEEP_DISENGAGED (0x01) +#define MPI25_SASIOUNIT8_TXRXSLEEP_ACTIVE (0x02) +#define MPI25_SASIOUNIT8_TXRXSLEEP_SHUTDOWN (0x03) + + + +/* SAS IO Unit Page 16 */ + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT16 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U64 TimeStamp; /* 0x08 */ + U32 Reserved1; /* 0x10 */ + U32 Reserved2; /* 0x14 */ + U32 FastPathPendedRequests; /* 0x18 */ + U32 FastPathUnPendedRequests; /* 0x1C */ + U32 FastPathHostRequestStarts; /* 0x20 */ + U32 FastPathFirmwareRequestStarts; /* 0x24 */ + U32 FastPathHostCompletions; /* 0x28 */ + U32 FastPathFirmwareCompletions; /* 0x2C */ + U32 NonFastPathRequestStarts; /* 0x30 */ + U32 NonFastPathHostCompletions; /* 0x30 */ +} MPI2_CONFIG_PAGE_SASIOUNIT16, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT16, + Mpi2SasIOUnitPage16_t, MPI2_POINTER pMpi2SasIOUnitPage16_t; + +#define MPI2_SASIOUNITPAGE16_PAGEVERSION (0x00) + + +/**************************************************************************** +* SAS Expander Config Pages +****************************************************************************/ + +/* SAS Expander Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 PhysicalPort; /* 0x08 */ + U8 ReportGenLength; /* 0x09 */ + U16 EnclosureHandle; /* 0x0A */ + U64 SASAddress; /* 0x0C */ + U32 DiscoveryStatus; /* 0x14 */ + U16 DevHandle; /* 0x18 */ + U16 ParentDevHandle; /* 0x1A */ + U16 ExpanderChangeCount; /* 0x1C */ + U16 ExpanderRouteIndexes; /* 0x1E */ + U8 NumPhys; /* 0x20 */ + U8 SASLevel; /* 0x21 */ + U16 Flags; /* 0x22 */ + U16 STPBusInactivityTimeLimit; /* 0x24 */ + U16 STPMaxConnectTimeLimit; /* 0x26 */ + U16 STP_SMP_NexusLossTime; /* 0x28 */ + U16 MaxNumRoutedSasAddresses; /* 0x2A */ + U64 ActiveZoneManagerSASAddress;/* 0x2C */ + U16 ZoneLockInactivityLimit; /* 0x34 */ + U16 Reserved1; /* 0x36 */ + U8 TimeToReducedFunc; /* 0x38 */ + U8 InitialTimeToReducedFunc; /* 0x39 */ + U8 MaxReducedFuncTime; /* 0x3A */ + U8 Reserved2; /* 0x3B */ +} MPI2_CONFIG_PAGE_EXPANDER_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_0, + Mpi2ExpanderPage0_t, MPI2_POINTER pMpi2ExpanderPage0_t; + +#define MPI2_SASEXPANDER0_PAGEVERSION (0x06) + +/* values for SAS Expander Page 0 DiscoveryStatus field */ +#define MPI2_SAS_EXPANDER0_DS_MAX_ENCLOSURES_EXCEED (0x80000000) +#define MPI2_SAS_EXPANDER0_DS_MAX_EXPANDERS_EXCEED (0x40000000) +#define MPI2_SAS_EXPANDER0_DS_MAX_DEVICES_EXCEED (0x20000000) +#define MPI2_SAS_EXPANDER0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) +#define MPI2_SAS_EXPANDER0_DS_DOWNSTREAM_INITIATOR (0x08000000) +#define MPI2_SAS_EXPANDER0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) +#define MPI2_SAS_EXPANDER0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) +#define MPI2_SAS_EXPANDER0_DS_MULTI_PORT_DOMAIN (0x00002000) +#define MPI2_SAS_EXPANDER0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) +#define MPI2_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE (0x00000800) +#define MPI2_SAS_EXPANDER0_DS_TABLE_LINK (0x00000400) +#define MPI2_SAS_EXPANDER0_DS_SUBTRACTIVE_LINK (0x00000200) +#define MPI2_SAS_EXPANDER0_DS_SMP_CRC_ERROR (0x00000100) +#define MPI2_SAS_EXPANDER0_DS_SMP_FUNCTION_FAILED (0x00000080) +#define MPI2_SAS_EXPANDER0_DS_INDEX_NOT_EXIST (0x00000040) +#define MPI2_SAS_EXPANDER0_DS_OUT_ROUTE_ENTRIES (0x00000020) +#define MPI2_SAS_EXPANDER0_DS_SMP_TIMEOUT (0x00000010) +#define MPI2_SAS_EXPANDER0_DS_MULTIPLE_PORTS (0x00000004) +#define MPI2_SAS_EXPANDER0_DS_UNADDRESSABLE_DEVICE (0x00000002) +#define MPI2_SAS_EXPANDER0_DS_LOOP_DETECTED (0x00000001) + +/* values for SAS Expander Page 0 Flags field */ +#define MPI2_SAS_EXPANDER0_FLAGS_REDUCED_FUNCTIONALITY (0x2000) +#define MPI2_SAS_EXPANDER0_FLAGS_ZONE_LOCKED (0x1000) +#define MPI2_SAS_EXPANDER0_FLAGS_SUPPORTED_PHYSICAL_PRES (0x0800) +#define MPI2_SAS_EXPANDER0_FLAGS_ASSERTED_PHYSICAL_PRES (0x0400) +#define MPI2_SAS_EXPANDER0_FLAGS_ZONING_SUPPORT (0x0200) +#define MPI2_SAS_EXPANDER0_FLAGS_ENABLED_ZONING (0x0100) +#define MPI2_SAS_EXPANDER0_FLAGS_TABLE_TO_TABLE_SUPPORT (0x0080) +#define MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE (0x0010) +#define MPI2_SAS_EXPANDER0_FLAGS_OTHERS_CONFIG (0x0004) +#define MPI2_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x0002) +#define MPI2_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x0001) + + +/* SAS Expander Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_EXPANDER_1 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 PhysicalPort; /* 0x08 */ + U8 Reserved1; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U8 NumPhys; /* 0x0C */ + U8 Phy; /* 0x0D */ + U16 NumTableEntriesProgrammed; /* 0x0E */ + U8 ProgrammedLinkRate; /* 0x10 */ + U8 HwLinkRate; /* 0x11 */ + U16 AttachedDevHandle; /* 0x12 */ + U32 PhyInfo; /* 0x14 */ + U32 AttachedDeviceInfo; /* 0x18 */ + U16 ExpanderDevHandle; /* 0x1C */ + U8 ChangeCount; /* 0x1E */ + U8 NegotiatedLinkRate; /* 0x1F */ + U8 PhyIdentifier; /* 0x20 */ + U8 AttachedPhyIdentifier; /* 0x21 */ + U8 Reserved3; /* 0x22 */ + U8 DiscoveryInfo; /* 0x23 */ + U32 AttachedPhyInfo; /* 0x24 */ + U8 ZoneGroup; /* 0x28 */ + U8 SelfConfigStatus; /* 0x29 */ + U16 Reserved4; /* 0x2A */ +} MPI2_CONFIG_PAGE_EXPANDER_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_1, + Mpi2ExpanderPage1_t, MPI2_POINTER pMpi2ExpanderPage1_t; + +#define MPI2_SASEXPANDER1_PAGEVERSION (0x02) + +/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */ + +/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */ + +/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */ + +/* see mpi2_sas.h for the MPI2_SAS_DEVICE_INFO_ defines used for the AttachedDeviceInfo field */ + +/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ + +/* values for SAS Expander Page 1 DiscoveryInfo field */ +#define MPI2_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED (0x04) +#define MPI2_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02) +#define MPI2_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01) + +/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ + + +/**************************************************************************** +* SAS Device Config Pages +****************************************************************************/ + +/* SAS Device Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 Slot; /* 0x08 */ + U16 EnclosureHandle; /* 0x0A */ + U64 SASAddress; /* 0x0C */ + U16 ParentDevHandle; /* 0x14 */ + U8 PhyNum; /* 0x16 */ + U8 AccessStatus; /* 0x17 */ + U16 DevHandle; /* 0x18 */ + U8 AttachedPhyIdentifier; /* 0x1A */ + U8 ZoneGroup; /* 0x1B */ + U32 DeviceInfo; /* 0x1C */ + U16 Flags; /* 0x20 */ + U8 PhysicalPort; /* 0x22 */ + U8 MaxPortConnections; /* 0x23 */ + U64 DeviceName; /* 0x24 */ + U8 PortGroups; /* 0x2C */ + U8 DmaGroup; /* 0x2D */ + U8 ControlGroup; /* 0x2E */ + U8 EnclosureLevel; /* 0x2F */ + U8 ConnectorName[4]; /* 0x30 */ + U32 Reserved3; /* 0x34 */ +} MPI2_CONFIG_PAGE_SAS_DEV_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_0, + Mpi2SasDevicePage0_t, MPI2_POINTER pMpi2SasDevicePage0_t; + +#define MPI2_SASDEVICE0_PAGEVERSION (0x09) + +/* values for SAS Device Page 0 AccessStatus field */ +#define MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00) +#define MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01) +#define MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02) +#define MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT (0x03) +#define MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION (0x04) +#define MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE (0x05) +#define MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE (0x06) +#define MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED (0x07) +/* specific values for SATA Init failures */ +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN (0x10) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x11) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG (0x12) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION (0x13) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER (0x14) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN (0x15) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN (0x16) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN (0x17) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION (0x18) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE (0x19) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX (0x1F) + +/* see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */ + +/* values for SAS Device Page 0 Flags field */ +#define MPI2_SAS_DEVICE0_FLAGS_UNAUTHORIZED_DEVICE (0x8000) +#define MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH (0x4000) +#define MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE (0x2000) +#define MPI2_SAS_DEVICE0_FLAGS_SLUMBER_PM_CAPABLE (0x1000) +#define MPI2_SAS_DEVICE0_FLAGS_PARTIAL_PM_CAPABLE (0x0800) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200) +#define MPI2_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED (0x0080) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED (0x0040) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010) +#define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008) +#define MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID (0x0002) +#define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001) + + +/* SAS Device Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_1 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U64 SASAddress; /* 0x0C */ + U32 Reserved2; /* 0x14 */ + U16 DevHandle; /* 0x18 */ + U16 Reserved3; /* 0x1A */ + U8 InitialRegDeviceFIS[20];/* 0x1C */ +} MPI2_CONFIG_PAGE_SAS_DEV_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_1, + Mpi2SasDevicePage1_t, MPI2_POINTER pMpi2SasDevicePage1_t; + +#define MPI2_SASDEVICE1_PAGEVERSION (0x01) + + +/**************************************************************************** +* SAS PHY Config Pages +****************************************************************************/ + +/* SAS PHY Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 OwnerDevHandle; /* 0x08 */ + U16 Reserved1; /* 0x0A */ + U16 AttachedDevHandle; /* 0x0C */ + U8 AttachedPhyIdentifier; /* 0x0E */ + U8 Reserved2; /* 0x0F */ + U32 AttachedPhyInfo; /* 0x10 */ + U8 ProgrammedLinkRate; /* 0x14 */ + U8 HwLinkRate; /* 0x15 */ + U8 ChangeCount; /* 0x16 */ + U8 Flags; /* 0x17 */ + U32 PhyInfo; /* 0x18 */ + U8 NegotiatedLinkRate; /* 0x1C */ + U8 Reserved3; /* 0x1D */ + U16 Reserved4; /* 0x1E */ +} MPI2_CONFIG_PAGE_SAS_PHY_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_0, + Mpi2SasPhyPage0_t, MPI2_POINTER pMpi2SasPhyPage0_t; + +#define MPI2_SASPHY0_PAGEVERSION (0x03) + +/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ + +/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */ + +/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */ + +/* values for SAS PHY Page 0 Flags field */ +#define MPI2_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC (0x01) + +/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */ + +/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ + + +/* SAS PHY Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_1 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U32 InvalidDwordCount; /* 0x0C */ + U32 RunningDisparityErrorCount; /* 0x10 */ + U32 LossDwordSynchCount; /* 0x14 */ + U32 PhyResetProblemCount; /* 0x18 */ +} MPI2_CONFIG_PAGE_SAS_PHY_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_1, + Mpi2SasPhyPage1_t, MPI2_POINTER pMpi2SasPhyPage1_t; + +#define MPI2_SASPHY1_PAGEVERSION (0x01) + + +/* SAS PHY Page 2 */ + +typedef struct _MPI2_SASPHY2_PHY_EVENT +{ + U8 PhyEventCode; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 PhyEventInfo; /* 0x04 */ +} MPI2_SASPHY2_PHY_EVENT, MPI2_POINTER PTR_MPI2_SASPHY2_PHY_EVENT, + Mpi2SasPhy2PhyEvent_t, MPI2_POINTER pMpi2SasPhy2PhyEvent_t; + +/* use MPI2_SASPHY3_EVENT_CODE_ for the PhyEventCode field */ + + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumPhyEvents at runtime. + */ +#ifndef MPI2_SASPHY2_PHY_EVENT_MAX +#define MPI2_SASPHY2_PHY_EVENT_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U8 NumPhyEvents; /* 0x0C */ + U8 Reserved2; /* 0x0D */ + U16 Reserved3; /* 0x0E */ + MPI2_SASPHY2_PHY_EVENT PhyEvent[MPI2_SASPHY2_PHY_EVENT_MAX]; /* 0x10 */ +} MPI2_CONFIG_PAGE_SAS_PHY_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_2, + Mpi2SasPhyPage2_t, MPI2_POINTER pMpi2SasPhyPage2_t; + +#define MPI2_SASPHY2_PAGEVERSION (0x00) + + +/* SAS PHY Page 3 */ + +typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG +{ + U8 PhyEventCode; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U8 CounterType; /* 0x04 */ + U8 ThresholdWindow; /* 0x05 */ + U8 TimeUnits; /* 0x06 */ + U8 Reserved3; /* 0x07 */ + U32 EventThreshold; /* 0x08 */ + U16 ThresholdFlags; /* 0x0C */ + U16 Reserved4; /* 0x0E */ +} MPI2_SASPHY3_PHY_EVENT_CONFIG, MPI2_POINTER PTR_MPI2_SASPHY3_PHY_EVENT_CONFIG, + Mpi2SasPhy3PhyEventConfig_t, MPI2_POINTER pMpi2SasPhy3PhyEventConfig_t; + +/* values for PhyEventCode field */ +#define MPI2_SASPHY3_EVENT_CODE_NO_EVENT (0x00) +#define MPI2_SASPHY3_EVENT_CODE_INVALID_DWORD (0x01) +#define MPI2_SASPHY3_EVENT_CODE_RUNNING_DISPARITY_ERROR (0x02) +#define MPI2_SASPHY3_EVENT_CODE_LOSS_DWORD_SYNC (0x03) +#define MPI2_SASPHY3_EVENT_CODE_PHY_RESET_PROBLEM (0x04) +#define MPI2_SASPHY3_EVENT_CODE_ELASTICITY_BUF_OVERFLOW (0x05) +#define MPI2_SASPHY3_EVENT_CODE_RX_ERROR (0x06) +#define MPI2_SASPHY3_EVENT_CODE_RX_ADDR_FRAME_ERROR (0x20) +#define MPI2_SASPHY3_EVENT_CODE_TX_AC_OPEN_REJECT (0x21) +#define MPI2_SASPHY3_EVENT_CODE_RX_AC_OPEN_REJECT (0x22) +#define MPI2_SASPHY3_EVENT_CODE_TX_RC_OPEN_REJECT (0x23) +#define MPI2_SASPHY3_EVENT_CODE_RX_RC_OPEN_REJECT (0x24) +#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_PARTIAL_WAITING_ON (0x25) +#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_CONNECT_WAITING_ON (0x26) +#define MPI2_SASPHY3_EVENT_CODE_TX_BREAK (0x27) +#define MPI2_SASPHY3_EVENT_CODE_RX_BREAK (0x28) +#define MPI2_SASPHY3_EVENT_CODE_BREAK_TIMEOUT (0x29) +#define MPI2_SASPHY3_EVENT_CODE_CONNECTION (0x2A) +#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_PATHWAY_BLOCKED (0x2B) +#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_ARB_WAIT_TIME (0x2C) +#define MPI2_SASPHY3_EVENT_CODE_PEAK_ARB_WAIT_TIME (0x2D) +#define MPI2_SASPHY3_EVENT_CODE_PEAK_CONNECT_TIME (0x2E) +#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_FRAMES (0x40) +#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_FRAMES (0x41) +#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_ERROR_FRAMES (0x42) +#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_ERROR_FRAMES (0x43) +#define MPI2_SASPHY3_EVENT_CODE_TX_CREDIT_BLOCKED (0x44) +#define MPI2_SASPHY3_EVENT_CODE_RX_CREDIT_BLOCKED (0x45) +#define MPI2_SASPHY3_EVENT_CODE_TX_SATA_FRAMES (0x50) +#define MPI2_SASPHY3_EVENT_CODE_RX_SATA_FRAMES (0x51) +#define MPI2_SASPHY3_EVENT_CODE_SATA_OVERFLOW (0x52) +#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_FRAMES (0x60) +#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_FRAMES (0x61) +#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_ERROR_FRAMES (0x63) +#define MPI2_SASPHY3_EVENT_CODE_HOTPLUG_TIMEOUT (0xD0) +#define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xD1) +#define MPI2_SASPHY3_EVENT_CODE_RX_AIP (0xD2) + +/* values for the CounterType field */ +#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING (0x00) +#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING (0x01) +#define MPI2_SASPHY3_COUNTER_TYPE_PEAK_VALUE (0x02) + +/* values for the TimeUnits field */ +#define MPI2_SASPHY3_TIME_UNITS_10_MICROSECONDS (0x00) +#define MPI2_SASPHY3_TIME_UNITS_100_MICROSECONDS (0x01) +#define MPI2_SASPHY3_TIME_UNITS_1_MILLISECOND (0x02) +#define MPI2_SASPHY3_TIME_UNITS_10_MILLISECONDS (0x03) + +/* values for the ThresholdFlags field */ +#define MPI2_SASPHY3_TFLAGS_PHY_RESET (0x0002) +#define MPI2_SASPHY3_TFLAGS_EVENT_NOTIFY (0x0001) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumPhyEvents at runtime. + */ +#ifndef MPI2_SASPHY3_PHY_EVENT_MAX +#define MPI2_SASPHY3_PHY_EVENT_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U8 NumPhyEvents; /* 0x0C */ + U8 Reserved2; /* 0x0D */ + U16 Reserved3; /* 0x0E */ + MPI2_SASPHY3_PHY_EVENT_CONFIG PhyEventConfig[MPI2_SASPHY3_PHY_EVENT_MAX]; /* 0x10 */ +} MPI2_CONFIG_PAGE_SAS_PHY_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_3, + Mpi2SasPhyPage3_t, MPI2_POINTER pMpi2SasPhyPage3_t; + +#define MPI2_SASPHY3_PAGEVERSION (0x00) + + +/* SAS PHY Page 4 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_4 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 Reserved1; /* 0x08 */ + U8 Reserved2; /* 0x0A */ + U8 Flags; /* 0x0B */ + U8 InitialFrame[28]; /* 0x0C */ +} MPI2_CONFIG_PAGE_SAS_PHY_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_4, + Mpi2SasPhyPage4_t, MPI2_POINTER pMpi2SasPhyPage4_t; + +#define MPI2_SASPHY4_PAGEVERSION (0x00) + +/* values for the Flags field */ +#define MPI2_SASPHY4_FLAGS_FRAME_VALID (0x02) +#define MPI2_SASPHY4_FLAGS_SATA_FRAME (0x01) + + + + +/**************************************************************************** +* SAS Port Config Pages +****************************************************************************/ + +/* SAS Port Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_PORT_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 PortNumber; /* 0x08 */ + U8 PhysicalPort; /* 0x09 */ + U8 PortWidth; /* 0x0A */ + U8 PhysicalPortWidth; /* 0x0B */ + U8 ZoneGroup; /* 0x0C */ + U8 Reserved1; /* 0x0D */ + U16 Reserved2; /* 0x0E */ + U64 SASAddress; /* 0x10 */ + U32 DeviceInfo; /* 0x18 */ + U32 Reserved3; /* 0x1C */ + U32 Reserved4; /* 0x20 */ +} MPI2_CONFIG_PAGE_SAS_PORT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PORT_0, + Mpi2SasPortPage0_t, MPI2_POINTER pMpi2SasPortPage0_t; + +#define MPI2_SASPORT0_PAGEVERSION (0x00) + +/* see mpi2_sas.h for values for SAS Port Page 0 DeviceInfo values */ + + +/**************************************************************************** +* SAS Enclosure Config Pages +****************************************************************************/ + +/* SAS Enclosure Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U64 EnclosureLogicalID; /* 0x0C */ + U16 Flags; /* 0x14 */ + U16 EnclosureHandle; /* 0x16 */ + U16 NumSlots; /* 0x18 */ + U16 StartSlot; /* 0x1A */ + U8 Reserved2; /* 0x1C */ + U8 EnclosureLevel; /* 0x1D */ + U16 SEPDevHandle; /* 0x1E */ + U32 Reserved3; /* 0x20 */ + U32 Reserved4; /* 0x24 */ +} MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, + Mpi2SasEnclosurePage0_t, MPI2_POINTER pMpi2SasEnclosurePage0_t; + +#define MPI2_SASENCLOSURE0_PAGEVERSION (0x04) + +/* values for SAS Enclosure Page 0 Flags field */ +#define MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID (0x0010) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK (0x000F) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SES (0x0001) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SGPIO (0x0002) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_EXP_SGPIO (0x0003) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0004) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_GPIO (0x0005) + + +/**************************************************************************** +* Log Config Page +****************************************************************************/ + +/* Log Page 0 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumLogEntries at runtime. + */ +#ifndef MPI2_LOG_0_NUM_LOG_ENTRIES +#define MPI2_LOG_0_NUM_LOG_ENTRIES (1) +#endif + +#define MPI2_LOG_0_LOG_DATA_LENGTH (0x1C) + +typedef struct _MPI2_LOG_0_ENTRY +{ + U64 TimeStamp; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U16 LogSequence; /* 0x0C */ + U16 LogEntryQualifier; /* 0x0E */ + U8 VP_ID; /* 0x10 */ + U8 VF_ID; /* 0x11 */ + U16 Reserved2; /* 0x12 */ + U8 LogData[MPI2_LOG_0_LOG_DATA_LENGTH];/* 0x14 */ +} MPI2_LOG_0_ENTRY, MPI2_POINTER PTR_MPI2_LOG_0_ENTRY, + Mpi2Log0Entry_t, MPI2_POINTER pMpi2Log0Entry_t; + +/* values for Log Page 0 LogEntry LogEntryQualifier field */ +#define MPI2_LOG_0_ENTRY_QUAL_ENTRY_UNUSED (0x0000) +#define MPI2_LOG_0_ENTRY_QUAL_POWER_ON_RESET (0x0001) +#define MPI2_LOG_0_ENTRY_QUAL_TIMESTAMP_UPDATE (0x0002) +#define MPI2_LOG_0_ENTRY_QUAL_MIN_IMPLEMENT_SPEC (0x8000) +#define MPI2_LOG_0_ENTRY_QUAL_MAX_IMPLEMENT_SPEC (0xFFFF) + +typedef struct _MPI2_CONFIG_PAGE_LOG_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U32 Reserved2; /* 0x0C */ + U16 NumLogEntries; /* 0x10 */ + U16 Reserved3; /* 0x12 */ + MPI2_LOG_0_ENTRY LogEntry[MPI2_LOG_0_NUM_LOG_ENTRIES]; /* 0x14 */ +} MPI2_CONFIG_PAGE_LOG_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_LOG_0, + Mpi2LogPage0_t, MPI2_POINTER pMpi2LogPage0_t; + +#define MPI2_LOG_0_PAGEVERSION (0x02) + + +/**************************************************************************** +* RAID Config Page +****************************************************************************/ + +/* RAID Page 0 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumElements at runtime. + */ +#ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS +#define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1) +#endif + +typedef struct _MPI2_RAIDCONFIG0_CONFIG_ELEMENT +{ + U16 ElementFlags; /* 0x00 */ + U16 VolDevHandle; /* 0x02 */ + U8 HotSparePool; /* 0x04 */ + U8 PhysDiskNum; /* 0x05 */ + U16 PhysDiskDevHandle; /* 0x06 */ +} MPI2_RAIDCONFIG0_CONFIG_ELEMENT, + MPI2_POINTER PTR_MPI2_RAIDCONFIG0_CONFIG_ELEMENT, + Mpi2RaidConfig0ConfigElement_t, MPI2_POINTER pMpi2RaidConfig0ConfigElement_t; + +/* values for the ElementFlags field */ +#define MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE (0x000F) +#define MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT (0x0000) +#define MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT (0x0001) +#define MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT (0x0002) +#define MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT (0x0003) + + +typedef struct _MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 NumHotSpares; /* 0x08 */ + U8 NumPhysDisks; /* 0x09 */ + U8 NumVolumes; /* 0x0A */ + U8 ConfigNum; /* 0x0B */ + U32 Flags; /* 0x0C */ + U8 ConfigGUID[24]; /* 0x10 */ + U32 Reserved1; /* 0x28 */ + U8 NumElements; /* 0x2C */ + U8 Reserved2; /* 0x2D */ + U16 Reserved3; /* 0x2E */ + MPI2_RAIDCONFIG0_CONFIG_ELEMENT ConfigElement[MPI2_RAIDCONFIG0_MAX_ELEMENTS]; /* 0x30 */ +} MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, + Mpi2RaidConfigurationPage0_t, MPI2_POINTER pMpi2RaidConfigurationPage0_t; + +#define MPI2_RAIDCONFIG0_PAGEVERSION (0x00) + +/* values for RAID Configuration Page 0 Flags field */ +#define MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG (0x00000001) + + +/**************************************************************************** +* Driver Persistent Mapping Config Pages +****************************************************************************/ + +/* Driver Persistent Mapping Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY +{ + U64 PhysicalIdentifier; /* 0x00 */ + U16 MappingInformation; /* 0x08 */ + U16 DeviceIndex; /* 0x0A */ + U32 PhysicalBitsMapping; /* 0x0C */ + U32 Reserved1; /* 0x10 */ +} MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY, + Mpi2DriverMap0Entry_t, MPI2_POINTER pMpi2DriverMap0Entry_t; + +typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY Entry; /* 0x08 */ +} MPI2_CONFIG_PAGE_DRIVER_MAPPING_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAPPING_0, + Mpi2DriverMappingPage0_t, MPI2_POINTER pMpi2DriverMappingPage0_t; + +#define MPI2_DRIVERMAPPING0_PAGEVERSION (0x00) + +/* values for Driver Persistent Mapping Page 0 MappingInformation field */ +#define MPI2_DRVMAP0_MAPINFO_SLOT_MASK (0x07F0) +#define MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT (4) +#define MPI2_DRVMAP0_MAPINFO_MISSING_MASK (0x000F) + + +/**************************************************************************** +* Ethernet Config Pages +****************************************************************************/ + +/* Ethernet Page 0 */ + +/* IP address (union of IPv4 and IPv6) */ +typedef union _MPI2_ETHERNET_IP_ADDR +{ + U32 IPv4Addr; + U32 IPv6Addr[4]; +} MPI2_ETHERNET_IP_ADDR, MPI2_POINTER PTR_MPI2_ETHERNET_IP_ADDR, + Mpi2EthernetIpAddr_t, MPI2_POINTER pMpi2EthernetIpAddr_t; + +#define MPI2_ETHERNET_HOST_NAME_LENGTH (32) + +typedef struct _MPI2_CONFIG_PAGE_ETHERNET_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 NumInterfaces; /* 0x08 */ + U8 Reserved0; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U32 Status; /* 0x0C */ + U8 MediaState; /* 0x10 */ + U8 Reserved2; /* 0x11 */ + U16 Reserved3; /* 0x12 */ + U8 MacAddress[6]; /* 0x14 */ + U8 Reserved4; /* 0x1A */ + U8 Reserved5; /* 0x1B */ + MPI2_ETHERNET_IP_ADDR IpAddress; /* 0x1C */ + MPI2_ETHERNET_IP_ADDR SubnetMask; /* 0x2C */ + MPI2_ETHERNET_IP_ADDR GatewayIpAddress; /* 0x3C */ + MPI2_ETHERNET_IP_ADDR DNS1IpAddress; /* 0x4C */ + MPI2_ETHERNET_IP_ADDR DNS2IpAddress; /* 0x5C */ + MPI2_ETHERNET_IP_ADDR DhcpIpAddress; /* 0x6C */ + U8 HostName[MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */ +} MPI2_CONFIG_PAGE_ETHERNET_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_0, + Mpi2EthernetPage0_t, MPI2_POINTER pMpi2EthernetPage0_t; + +#define MPI2_ETHERNETPAGE0_PAGEVERSION (0x00) + +/* values for Ethernet Page 0 Status field */ +#define MPI2_ETHPG0_STATUS_IPV6_CAPABLE (0x80000000) +#define MPI2_ETHPG0_STATUS_IPV4_CAPABLE (0x40000000) +#define MPI2_ETHPG0_STATUS_CONSOLE_CONNECTED (0x20000000) +#define MPI2_ETHPG0_STATUS_DEFAULT_IF (0x00000100) +#define MPI2_ETHPG0_STATUS_FW_DWNLD_ENABLED (0x00000080) +#define MPI2_ETHPG0_STATUS_TELNET_ENABLED (0x00000040) +#define MPI2_ETHPG0_STATUS_SSH2_ENABLED (0x00000020) +#define MPI2_ETHPG0_STATUS_DHCP_CLIENT_ENABLED (0x00000010) +#define MPI2_ETHPG0_STATUS_IPV6_ENABLED (0x00000008) +#define MPI2_ETHPG0_STATUS_IPV4_ENABLED (0x00000004) +#define MPI2_ETHPG0_STATUS_IPV6_ADDRESSES (0x00000002) +#define MPI2_ETHPG0_STATUS_ETH_IF_ENABLED (0x00000001) + +/* values for Ethernet Page 0 MediaState field */ +#define MPI2_ETHPG0_MS_DUPLEX_MASK (0x80) +#define MPI2_ETHPG0_MS_HALF_DUPLEX (0x00) +#define MPI2_ETHPG0_MS_FULL_DUPLEX (0x80) + +#define MPI2_ETHPG0_MS_CONNECT_SPEED_MASK (0x07) +#define MPI2_ETHPG0_MS_NOT_CONNECTED (0x00) +#define MPI2_ETHPG0_MS_10MBIT (0x01) +#define MPI2_ETHPG0_MS_100MBIT (0x02) +#define MPI2_ETHPG0_MS_1GBIT (0x03) + + +/* Ethernet Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved0; /* 0x08 */ + U32 Flags; /* 0x0C */ + U8 MediaState; /* 0x10 */ + U8 Reserved1; /* 0x11 */ + U16 Reserved2; /* 0x12 */ + U8 MacAddress[6]; /* 0x14 */ + U8 Reserved3; /* 0x1A */ + U8 Reserved4; /* 0x1B */ + MPI2_ETHERNET_IP_ADDR StaticIpAddress; /* 0x1C */ + MPI2_ETHERNET_IP_ADDR StaticSubnetMask; /* 0x2C */ + MPI2_ETHERNET_IP_ADDR StaticGatewayIpAddress; /* 0x3C */ + MPI2_ETHERNET_IP_ADDR StaticDNS1IpAddress; /* 0x4C */ + MPI2_ETHERNET_IP_ADDR StaticDNS2IpAddress; /* 0x5C */ + U32 Reserved5; /* 0x6C */ + U32 Reserved6; /* 0x70 */ + U32 Reserved7; /* 0x74 */ + U32 Reserved8; /* 0x78 */ + U8 HostName[MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */ +} MPI2_CONFIG_PAGE_ETHERNET_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_1, + Mpi2EthernetPage1_t, MPI2_POINTER pMpi2EthernetPage1_t; + +#define MPI2_ETHERNETPAGE1_PAGEVERSION (0x00) + +/* values for Ethernet Page 1 Flags field */ +#define MPI2_ETHPG1_FLAG_SET_DEFAULT_IF (0x00000100) +#define MPI2_ETHPG1_FLAG_ENABLE_FW_DOWNLOAD (0x00000080) +#define MPI2_ETHPG1_FLAG_ENABLE_TELNET (0x00000040) +#define MPI2_ETHPG1_FLAG_ENABLE_SSH2 (0x00000020) +#define MPI2_ETHPG1_FLAG_ENABLE_DHCP_CLIENT (0x00000010) +#define MPI2_ETHPG1_FLAG_ENABLE_IPV6 (0x00000008) +#define MPI2_ETHPG1_FLAG_ENABLE_IPV4 (0x00000004) +#define MPI2_ETHPG1_FLAG_USE_IPV6_ADDRESSES (0x00000002) +#define MPI2_ETHPG1_FLAG_ENABLE_ETH_IF (0x00000001) + +/* values for Ethernet Page 1 MediaState field */ +#define MPI2_ETHPG1_MS_DUPLEX_MASK (0x80) +#define MPI2_ETHPG1_MS_HALF_DUPLEX (0x00) +#define MPI2_ETHPG1_MS_FULL_DUPLEX (0x80) + +#define MPI2_ETHPG1_MS_DATA_RATE_MASK (0x07) +#define MPI2_ETHPG1_MS_DATA_RATE_AUTO (0x00) +#define MPI2_ETHPG1_MS_DATA_RATE_10MBIT (0x01) +#define MPI2_ETHPG1_MS_DATA_RATE_100MBIT (0x02) +#define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03) + + +/**************************************************************************** +* Extended Manufacturing Config Pages +****************************************************************************/ + +/* + * Generic structure to use for product-specific extended manufacturing pages + * (currently Extended Manufacturing Page 40 through Extended Manufacturing + * Page 60). + */ + +typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 ProductSpecificInfo; /* 0x08 */ +} MPI2_CONFIG_PAGE_EXT_MAN_PS, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXT_MAN_PS, + Mpi2ExtManufacturingPagePS_t, MPI2_POINTER pMpi2ExtManufacturingPagePS_t; + +/* PageVersion should be provided by product-specific code */ + +#endif + diff --git a/sys/dev/mpr/mpi/mpi2_hbd.h b/sys/dev/mpr/mpi/mpi2_hbd.h new file mode 100644 index 0000000000000..d0cc09f905a0f --- /dev/null +++ b/sys/dev/mpr/mpi/mpi2_hbd.h @@ -0,0 +1,152 @@ +/*- + * Copyright (c) 2013 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + +/* + * Copyright (c) 2009-2011 LSI Corporation. + * + * + * Name: mpi2_hbd.h + * Title: MPI Host Based Discovery messages and structures + * Creation Date: October 21, 2009 + * + * mpi2_hbd.h Version: 02.00.02 + * + * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 + * prefix are for use only on MPI v2.5 products, and must not be used + * with MPI v2.0 products. Unless otherwise noted, names beginning with + * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 10-28-09 02.00.00 Initial version. + * 08-11-10 02.00.01 Removed PortGroups, DmaGroup, and ControlGroup from + * HBD Action request, replaced by AdditionalInfo field. + * 11-18-11 02.00.02 Incorporating additions for MPI v2.5. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_HBD_H +#define MPI2_HBD_H + +/**************************************************************************** +* Host Based Discovery Action messages +****************************************************************************/ + +/* Host Based Discovery Action Request Message */ +typedef struct _MPI2_HBD_ACTION_REQUEST +{ + U8 Operation; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 DevHandle; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U32 Reserved4; /* 0x0C */ + U64 SASAddress; /* 0x10 */ + U32 Reserved5; /* 0x18 */ + U32 HbdDeviceInfo; /* 0x1C */ + U16 ParentDevHandle; /* 0x20 */ + U16 MaxQDepth; /* 0x22 */ + U8 FirstPhyIdentifier; /* 0x24 */ + U8 Port; /* 0x25 */ + U8 MaxConnections; /* 0x26 */ + U8 MaxRate; /* 0x27 */ + U32 AdditionalInfo; /* 0x28 */ + U16 InitialAWT; /* 0x2C */ + U16 Reserved7; /* 0x2E */ + U32 Reserved8; /* 0x30 */ +} MPI2_HBD_ACTION_REQUEST, MPI2_POINTER PTR_MPI2_HBD_ACTION_REQUEST, + Mpi2HbdActionRequest_t, MPI2_POINTER pMpi2HbdActionRequest_t; + +/* values for the Operation field */ +#define MPI2_HBD_OP_ADD_DEVICE (0x01) +#define MPI2_HBD_OP_REMOVE_DEVICE (0x02) +#define MPI2_HBD_OP_UPDATE_DEVICE (0x03) + +/* values for the HbdDeviceInfo field */ +#define MPI2_HBD_DEVICE_INFO_VIRTUAL_DEVICE (0x00004000) +#define MPI2_HBD_DEVICE_INFO_ATAPI_DEVICE (0x00002000) +#define MPI2_HBD_DEVICE_INFO_DIRECT_ATTACH (0x00000800) +#define MPI2_HBD_DEVICE_INFO_SSP_TARGET (0x00000400) +#define MPI2_HBD_DEVICE_INFO_STP_TARGET (0x00000200) +#define MPI2_HBD_DEVICE_INFO_SMP_TARGET (0x00000100) +#define MPI2_HBD_DEVICE_INFO_SATA_DEVICE (0x00000080) +#define MPI2_HBD_DEVICE_INFO_SSP_INITIATOR (0x00000040) +#define MPI2_HBD_DEVICE_INFO_STP_INITIATOR (0x00000020) +#define MPI2_HBD_DEVICE_INFO_SMP_INITIATOR (0x00000010) +#define MPI2_HBD_DEVICE_INFO_SATA_HOST (0x00000008) + +#define MPI2_HBD_DEVICE_INFO_MASK_DEVICE_TYPE (0x00000007) +#define MPI2_HBD_DEVICE_INFO_NO_DEVICE (0x00000000) +#define MPI2_HBD_DEVICE_INFO_END_DEVICE (0x00000001) +#define MPI2_HBD_DEVICE_INFO_EDGE_EXPANDER (0x00000002) +#define MPI2_HBD_DEVICE_INFO_FANOUT_EXPANDER (0x00000003) + +/* values for the MaxRate field */ +#define MPI2_HBD_MAX_RATE_MASK (0x0F) +#define MPI2_HBD_MAX_RATE_1_5 (0x08) +#define MPI2_HBD_MAX_RATE_3_0 (0x09) +#define MPI2_HBD_MAX_RATE_6_0 (0x0A) +#define MPI25_HBD_MAX_RATE_12_0 (0x0B) + + +/* Host Based Discovery Action Reply Message */ +typedef struct _MPI2_HBD_ACTION_REPLY +{ + U8 Operation; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 DevHandle; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_HBD_ACTION_REPLY, MPI2_POINTER PTR_MPI2_HBD_ACTION_REPLY, + Mpi2HbdActionReply_t, MPI2_POINTER pMpi2HbdActionReply_t; + + +#endif + + diff --git a/sys/dev/mpr/mpi/mpi2_history.txt b/sys/dev/mpr/mpi/mpi2_history.txt new file mode 100644 index 0000000000000..296b75b878591 --- /dev/null +++ b/sys/dev/mpr/mpi/mpi2_history.txt @@ -0,0 +1,619 @@ +/*- + * Copyright (c) 2013 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + + ============================== + Fusion-MPT MPI 2.0 / 2.5 Header File Change History + ============================== + + Copyright (c) 2000-2013 LSI Corporation. + + --------------------------------------- + Header Set Release Version: 02.00.33 + Header Set Release Date: 12-05-13 + --------------------------------------- + + Filename Current version Prior version + ---------- --------------- ------------- + mpi2.h 02.00.33 02.00.32 + mpi2_cnfg.h 02.00.27 02.00.26 + mpi2_init.h 02.00.15 02.00.15 + mpi2_ioc.h 02.00.24 02.00.23 + mpi2_raid.h 02.00.10 02.00.10 + mpi2_sas.h 02.00.08 02.00.08 + mpi2_targ.h 02.00.06 02.00.06 + mpi2_tool.h 02.00.11 02.00.11 + mpi2_type.h 02.00.00 02.00.00 + mpi2_ra.h 02.00.00 02.00.00 + mpi2_hbd.h 02.00.02 02.00.02 + mpi2_history.txt 02.00.33 02.00.32 + + + * Date Version Description + * -------- -------- ------------------------------------------------------ + +mpi2.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 Bumped MPI2_HEADER_VERSION_UNIT. + * 06-26-07 02.00.02 Bumped MPI2_HEADER_VERSION_UNIT. + * 08-31-07 02.00.03 Bumped MPI2_HEADER_VERSION_UNIT. + * Moved ReplyPostHostIndex register to offset 0x6C of the + * MPI2_SYSTEM_INTERFACE_REGS and modified the define for + * MPI2_REPLY_POST_HOST_INDEX_OFFSET. + * Added union of request descriptors. + * Added union of reply descriptors. + * 10-31-07 02.00.04 Bumped MPI2_HEADER_VERSION_UNIT. + * Added define for MPI2_VERSION_02_00. + * Fixed the size of the FunctionDependent5 field in the + * MPI2_DEFAULT_REPLY structure. + * 12-18-07 02.00.05 Bumped MPI2_HEADER_VERSION_UNIT. + * Removed the MPI-defined Fault Codes and extended the + * product specific codes up to 0xEFFF. + * Added a sixth key value for the WriteSequence register + * and changed the flush value to 0x0. + * Added message function codes for Diagnostic Buffer Post + * and Diagnsotic Release. + * New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED + * Moved MPI2_VERSION_UNION from mpi2_ioc.h. + * 02-29-08 02.00.06 Bumped MPI2_HEADER_VERSION_UNIT. + * 03-03-08 02.00.07 Bumped MPI2_HEADER_VERSION_UNIT. + * 05-21-08 02.00.08 Bumped MPI2_HEADER_VERSION_UNIT. + * Added #defines for marking a reply descriptor as unused. + * 06-27-08 02.00.09 Bumped MPI2_HEADER_VERSION_UNIT. + * 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT. + * Moved LUN field defines from mpi2_init.h. + * 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT. + * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT. + * In all request and reply descriptors, replaced VF_ID + * field with MSIxIndex field. + * Removed DevHandle field from + * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those + * bytes reserved. + * Added RAID Accelerator functionality. + * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT. + * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MSI-x index mask and shift for Reply Post Host + * Index register. + * Added function code for Host Based Discovery Action. + * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT. + * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL. + * Added defines for product-specific range of message + * function codes, 0xF0 to 0xFF. + * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT. + * Added alternative defines for the SGE Direction bit. + * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT. + * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define. + * 02-23-11 02.00.19 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MPI2_FUNCTION_SEND_HOST_MESSAGE. + * 03-09-11 02.00.20 Bumped MPI2_HEADER_VERSION_UNIT. + * 05-25-11 02.00.21 Bumped MPI2_HEADER_VERSION_UNIT. + * 08-24-11 02.00.22 Bumped MPI2_HEADER_VERSION_UNIT. + * 11-18-11 02.00.23 Bumped MPI2_HEADER_VERSION_UNIT. + * Incorporating additions for MPI v2.5. + * 02-06-12 02.00.24 Bumped MPI2_HEADER_VERSION_UNIT. + * 03-29-12 02.00.25 Bumped MPI2_HEADER_VERSION_UNIT. + * Added Hard Reset delay timings. + * 07-10-12 02.00.26 Bumped MPI2_HEADER_VERSION_UNIT. + * 07-26-12 02.00.27 Bumped MPI2_HEADER_VERSION_UNIT. + * 11-27-12 02.00.28 Bumped MPI2_HEADER_VERSION_UNIT. + * 12-20-12 02.00.29 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET. + * 04-09-13 02.00.30 Bumped MPI2_HEADER_VERSION_UNIT. + * 04-17-13 02.00.31 Bumped MPI2_HEADER_VERSION_UNIT. + * 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT. + * 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT. + * -------------------------------------------------------------------------- + +mpi2_cnfg.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 Added defines for SAS IO Unit Page 2 PhyFlags. + * Added Manufacturing Page 11. + * Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE + * define. + * 06-26-07 02.00.02 Adding generic structure for product-specific + * Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS. + * Rework of BIOS Page 2 configuration page. + * Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the + * forms. + * Added configuration pages IOC Page 8 and Driver + * Persistent Mapping Page 0. + * 08-31-07 02.00.03 Modified configuration pages dealing with Integrated + * RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1, + * RAID Physical Disk Pages 0 and 1, RAID Configuration + * Page 0). + * Added new value for AccessStatus field of SAS Device + * Page 0 (_SATA_NEEDS_INITIALIZATION). + * 10-31-07 02.00.04 Added missing SEPDevHandle field to + * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + * 12-18-07 02.00.05 Modified IO Unit Page 0 to use 32-bit version fields for + * NVDATA. + * Modified IOC Page 7 to use masks and added field for + * SASBroadcastPrimitiveMasks. + * Added MPI2_CONFIG_PAGE_BIOS_4. + * Added MPI2_CONFIG_PAGE_LOG_0. + * 02-29-08 02.00.06 Modified various names to make them 32-character unique. + * Added SAS Device IDs. + * Updated Integrated RAID configuration pages including + * Manufacturing Page 4, IOC Page 6, and RAID Configuration + * Page 0. + * 05-21-08 02.00.07 Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA. + * Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION. + * Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING. + * Added missing MaxNumRoutedSasAddresses field to + * MPI2_CONFIG_PAGE_EXPANDER_0. + * Added SAS Port Page 0. + * Modified structure layout for + * MPI2_CONFIG_PAGE_DRIVER_MAPPING_0. + * 06-27-08 02.00.08 Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use + * MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array. + * 10-02-08 02.00.09 Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF + * to 0x000000FF. + * Added two new values for the Physical Disk Coercion Size + * bits in the Flags field of Manufacturing Page 4. + * Added product-specific Manufacturing pages 16 to 31. + * Modified Flags bits for controlling write cache on SATA + * drives in IO Unit Page 1. + * Added new bit to AdditionalControlFlags of SAS IO Unit + * Page 1 to control Invalid Topology Correction. + * Added SupportedPhysDisks field to RAID Volume Page 1 and + * added related defines. + * Added additional defines for RAID Volume Page 0 + * VolumeStatusFlags field. + * Modified meaning of RAID Volume Page 0 VolumeSettings + * define for auto-configure of hot-swap drives. + * Added PhysDiskAttributes field (and related defines) to + * RAID Physical Disk Page 0. + * Added MPI2_SAS_PHYINFO_PHY_VACANT define. + * Added three new DiscoveryStatus bits for SAS IO Unit + * Page 0 and SAS Expander Page 0. + * Removed multiplexing information from SAS IO Unit pages. + * Added BootDeviceWaitTime field to SAS IO Unit Page 4. + * Removed Zone Address Resolved bit from PhyInfo and from + * Expander Page 0 Flags field. + * Added two new AccessStatus values to SAS Device Page 0 + * for indicating routing problems. Added 3 reserved words + * to this page. + * 01-19-09 02.00.10 Fixed defines for GPIOVal field of IO Unit Page 3. + * Inserted missing reserved field into structure for IOC + * Page 6. + * Added more pending task bits to RAID Volume Page 0 + * VolumeStatusFlags defines. + * Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define. + * Added a new DiscoveryStatus bit for SAS IO Unit Page 0 + * and SAS Expander Page 0 to flag a downstream initiator + * when in simplified routing mode. + * Removed SATA Init Failure defines for DiscoveryStatus + * fields of SAS IO Unit Page 0 and SAS Expander Page 0. + * Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define. + * Added PortGroups, DmaGroup, and ControlGroup fields to + * SAS Device Page 0. + * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO + * Unit Page 6. + * Added expander reduced functionality data to SAS + * Expander Page 0. + * Added SAS PHY Page 2 and SAS PHY Page 3. + * 07-30-09 02.00.12 Added IO Unit Page 7. + * Added new device ids. + * Added SAS IO Unit Page 5. + * Added partial and slumber power management capable flags + * to SAS Device Page 0 Flags field. + * Added PhyInfo defines for power condition. + * Added Ethernet configuration pages. + * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. + * Added SAS PHY Page 4 structure and defines. + * 02-10-10 02.00.14 Modified the comments for the configuration page + * structures that contain an array of data. The host + * should use the "count" field in the page data (e.g. the + * NumPhys field) to determine the number of valid elements + * in the array. + * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines. + * Added PowerManagementCapabilities to IO Unit Page 7. + * Added PortWidthModGroup field to + * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines. + * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT + * define. + * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define. + * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define. + * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing) + * defines. + * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to + * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for + * the Pinout field. + * Added BoardTemperature and BoardTemperatureUnits fields + * to MPI2_CONFIG_PAGE_IO_UNIT_7. + * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define + * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure. + * 02-23-11 02.00.18 Added ProxyVF_ID field to MPI2_CONFIG_REQUEST. + * Added IO Unit Page 8, IO Unit Page 9, + * and IO Unit Page 10. + * Added SASNotifyPrimitiveMasks field to + * MPI2_CONFIG_PAGE_IOC_7. + * 03-09-11 02.00.19 Fixed IO Unit Page 10 (to match the spec). + * 05-25-11 02.00.20 Cleaned up a few comments. + * 08-24-11 02.00.21 Marked the IO Unit Page 7 PowerManagementCapabilities + * for PCIe link as obsolete. + * Added SpinupFlags field containing a Disable Spin-up bit + * to the MPI2_SAS_IOUNIT4_SPINUP_GROUP fields of SAS IO + * Unit Page 4. + * 11-18-11 02.00.22 Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT. + * Added UEFIVersion field to BIOS Page 1 and defined new + * BiosOptions bits. + * Incorporating additions for MPI v2.5. + * 11-27-12 02.00.23 Added MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER. + * Added MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID. + * 12-20-12 02.00.24 Marked MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION as + * obsolete for MPI v2.5 and later. + * Added some defines for 12G SAS speeds. + * 04-09-13 02.00.25 Added MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK. + * Fixed MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS to + * match the specification. + * 08-19-13 02.00.26 Added reserved words to MPI2_CONFIG_PAGE_IO_UNIT_7 for + * future use. + * 12-05-13 02.00.27 Added MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL for + * MPI2_CONFIG_PAGE_MAN_7. + * Added EnclosureLevel and ConnectorName fields to + * MPI2_CONFIG_PAGE_SAS_DEV_0. + * Added MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID for + * MPI2_CONFIG_PAGE_SAS_DEV_0. + * Added EnclosureLevel field to + * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + * Added MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID for + * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + * -------------------------------------------------------------------------- + +mpi2_init.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 10-31-07 02.00.01 Fixed name for pMpi2SCSITaskManagementRequest_t. + * 12-18-07 02.00.02 Modified Task Management Target Reset Method defines. + * 02-29-08 02.00.03 Added Query Task Set and Query Unit Attention. + * 03-03-08 02.00.04 Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY. + * 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t. + * 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO + * Control field Task Attribute flags. + * Moved LUN field defines to mpi2.h becasue they are + * common to many structures. + * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to + * Query Asynchronous Event. + * Defined two new bits in the SlotStatus field of the SCSI + * Enclosure Processor Request and Reply. + * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for + * both SCSI IO Error Reply and SCSI Task Management Reply. + * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. + * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. + * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it. + * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request. + * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define. + * 11-18-11 02.00.12 Incorporating additions for MPI v2.5. + * 02-06-12 02.00.13 Added alternate defines for Task Priority / Command + * Priority to match SAM-4. + * Added EEDPErrorOffset to MPI2_SCSI_IO_REPLY. + * 07-10-12 02.00.14 Added MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION. + * -------------------------------------------------------------------------- + +mpi2_ioc.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 In IOCFacts Reply structure, renamed MaxDevices to + * MaxTargets. + * Added TotalImageSize field to FWDownload Request. + * Added reserved words to FWUpload Request. + * 06-26-07 02.00.02 Added IR Configuration Change List Event. + * 08-31-07 02.00.03 Removed SystemReplyQueueDepth field from the IOCInit + * request and replaced it with + * ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth. + * Replaced the MinReplyQueueDepth field of the IOCFacts + * reply with MaxReplyDescriptorPostQueueDepth. + * Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum + * depth for the Reply Descriptor Post Queue. + * Added SASAddress field to Initiator Device Table + * Overflow Event data. + * 10-31-07 02.00.04 Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING + * for SAS Initiator Device Status Change Event data. + * Modified Reason Code defines for SAS Topology Change + * List Event data, including adding a bit for PHY Vacant + * status, and adding a mask for the Reason Code. + * Added define for + * MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING. + * Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID. + * 12-18-07 02.00.05 Added Boot Status defines for the IOCExceptions field of + * the IOCFacts Reply. + * Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. + * Moved MPI2_VERSION_UNION to mpi2.h. + * Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks + * instead of enables, and added SASBroadcastPrimitiveMasks + * field. + * Added Log Entry Added Event and related structure. + * 02-29-08 02.00.06 Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID. + * Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET. + * Added MaxVolumes and MaxPersistentEntries fields to + * IOCFacts reply. + * Added ProtocalFlags and IOCCapabilities fields to + * MPI2_FW_IMAGE_HEADER. + * Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT. + * 03-03-08 02.00.07 Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to + * a U16 (from a U32). + * Removed extra 's' from EventMasks name. + * 06-27-08 02.00.08 Fixed an offset in a comment. + * 10-02-08 02.00.09 Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST. + * Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and + * renamed MinReplyFrameSize to ReplyFrameSize. + * Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX. + * Added two new RAIDOperation values for Integrated RAID + * Operations Status Event data. + * Added four new IR Configuration Change List Event data + * ReasonCode values. + * Added two new ReasonCode defines for SAS Device Status + * Change Event data. + * Added three new DiscoveryStatus bits for the SAS + * Discovery event data. + * Added Multiplexing Status Change bit to the PhyStatus + * field of the SAS Topology Change List event data. + * Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY. + * BootFlags are now product-specific. + * Added defines for the indivdual signature bytes + * for MPI2_INIT_IMAGE_FOOTER. + * 01-19-09 02.00.10 Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define. + * Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR + * define. + * Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE + * define. + * Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define. + * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define. + * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define. + * Added two new reason codes for SAS Device Status Change + * Event. + * Added new event: SAS PHY Counter. + * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure. + * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. + * Added new product id family for 2208. + * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST. + * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY. + * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY. + * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY. + * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define. + * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define. + * Added Host Based Discovery Phy Event data. + * Added defines for ProductID Product field + * (MPI2_FW_HEADER_PID_). + * Modified values for SAS ProductID Family + * (MPI2_FW_HEADER_PID_FAMILY_). + * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines. + * Added PowerManagementControl Request structures and + * defines. + * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete. + * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define. + * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC. + * 02-23-11 02.00.17 Added SAS NOTIFY Primitive event, and added + * SASNotifyPrimitiveMasks field to + * MPI2_EVENT_NOTIFICATION_REQUEST. + * Added Temperature Threshold Event. + * Added Host Message Event. + * Added Send Host Message request and reply. + * 05-25-11 02.00.18 For Extended Image Header, added + * MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC and + * MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC defines. + * Deprecated MPI2_EXT_IMAGE_TYPE_MAX define. + * 08-24-11 02.00.19 Added PhysicalPort field to + * MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE structure. + * Marked MPI2_PM_CONTROL_FEATURE_PCIE_LINK as obsolete. + * 11-18-11 02.00.20 Incorporating additions for MPI v2.5. + * 03-29-12 02.00.21 Added a product specific range to event values. + * 07-26-12 02.00.22 Added MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE. + * Added ElapsedSeconds field to + * MPI2_EVENT_DATA_IR_OPERATION_STATUS. + * 08-19-13 02.00.23 For IOCInit, added MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE + * and MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY. + * Added MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE. + * Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY. + * Added Encrypted Hash Extended Image. + * 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS. + * -------------------------------------------------------------------------- + +mpi2_raid.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 08-31-07 02.00.01 Modifications to RAID Action request and reply, + * including the Actions and ActionData. + * 02-29-08 02.00.02 Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD. + * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that + * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT + * can be sized by the build environment. + * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of + * VolumeCreationFlags and marked the old one as obsolete. + * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define. + * 08-24-10 02.00.06 Added MPI2_RAID_ACTION_COMPATIBILITY_CHECK along with + * related structures and defines. + * Added product-specific range to RAID Action values. + * 11-18-11 02.00.07 Incorporating additions for MPI v2.5. + * 02-06-12 02.00.08 Added MPI2_RAID_ACTION_PHYSDISK_HIDDEN. + * 07-26-12 02.00.09 Added ElapsedSeconds field to MPI2_RAID_VOL_INDICATOR. + * Added MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID define. + * 04-17-13 02.00.10 Added MPI25_RAID_ACTION_ADATA_ALLOW_PI. + * -------------------------------------------------------------------------- + +mpi2_sas.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-26-07 02.00.01 Added Clear All Persistent Operation to SAS IO Unit + * Control Request. + * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control + * Request. + * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST + * to MPI2_SGE_IO_UNION since it supports chained SGLs. + * 05-12-10 02.00.04 Modified some comments. + * 08-11-10 02.00.05 Added NCQ operations to SAS IO Unit Control. + * 11-18-11 02.00.06 Incorporating additions for MPI v2.5. + * 07-10-12 02.00.07 Added MPI2_SATA_PT_SGE_UNION for use in the SATA + * Passthrough Request message. + * 08-19-13 02.00.08 Made MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL obsolete + * for anything newer than MPI v2.0. + * -------------------------------------------------------------------------- + +mpi2_targ.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 08-31-07 02.00.01 Added Command Buffer Data Location Address Space bits to + * BufferPostFlags field of CommandBufferPostBase Request. + * 02-29-08 02.00.02 Modified various names to make them 32-character unique. + * 10-02-08 02.00.03 Removed NextCmdBufferOffset from + * MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST. + * Target Status Send Request only takes a single SGE for + * response data. + * 02-10-10 02.00.04 Added comment to MPI2_TARGET_SSP_RSP_IU structure. + * 11-18-11 02.00.05 Incorporating additions for MPI v2.5. + * 11-27-12 02.00.06 Added InitiatorDevHandle field to MPI2_TARGET_MODE_ABORT + * request message structure. + * Added AbortType MPI2_TARGET_MODE_ABORT_DEVHANDLE and + * MPI2_TARGET_MODE_ABORT_ALL_COMMANDS. + * -------------------------------------------------------------------------- + +mpi2_tool.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release + * structures and defines. + * 02-29-08 02.00.02 Modified various names to make them 32-character unique. + * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool. + * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request + * and reply messages. + * Added MPI2_DIAG_BUF_TYPE_EXTENDED. + * Incremented MPI2_DIAG_BUF_TYPE_COUNT. + * 05-12-10 02.00.05 Added Diagnostic Data Upload tool. + * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer + * Post Request. + * 05-25-11 02.00.07 Added Flags field and related defines to + * MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST. + * 11-18-11 02.00.08 Incorporating additions for MPI v2.5. + * 07-10-12 02.00.09 Add MPI v2.5 Toolbox Diagnostic CLI Tool Request + * message. + * 07-26-12 02.00.10 Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that + * it uses MPI Chain SGE as well as MPI Simple SGE. + * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info. + * -------------------------------------------------------------------------- + +mpi2_type.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * -------------------------------------------------------------------------- + +mpi2_ra.h + * 05-06-09 02.00.00 Initial version. + * -------------------------------------------------------------------------- + +mpi2_hbd.h + * 10-28-09 02.00.00 Initial version. + * 08-11-10 02.00.01 Removed PortGroups, DmaGroup, and ControlGroup from + * HBD Action request, replaced by AdditionalInfo field. + * 11-18-11 02.00.02 Incorporating additions for MPI v2.5. + * -------------------------------------------------------------------------- + + +mpi2_history.txt Parts list history + +Filename 02.00.33 02.00.32 02.00.31 02.00.30 +---------- -------- -------- -------- -------- +mpi2.h 02.00.33 02.00.32 02.00.31 02.00.30 +mpi2_cnfg.h 02.00.27 02.00.26 02.00.25 02.00.25 +mpi2_init.h 02.00.15 02.00.15 02.00.15 02.00.15 +mpi2_ioc.h 02.00.24 02.00.23 02.00.22 02.00.22 +mpi2_raid.h 02.00.10 02.00.10 02.00.10 02.00.09 +mpi2_sas.h 02.00.08 02.00.08 02.00.07 02.00.07 +mpi2_targ.h 02.00.06 02.00.06 02.00.06 02.00.06 +mpi2_tool.h 02.00.11 02.00.11 02.00.10 02.00.10 +mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 +mpi2_ra.h 02.00.00 02.00.00 02.00.00 02.00.00 +mpi2_hbd.h 02.00.02 02.00.02 02.00.02 02.00.02 + +Filename 02.00.29 02.00.28 02.00.27 02.00.26 02.00.25 02.00.24 +---------- -------- -------- -------- -------- -------- -------- +mpi2.h 02.00.29 02.00.28 02.00.27 02.00.26 02.00.25 02.00.24 +mpi2_cnfg.h 02.00.24 02.00.23 02.00.22 02.00.22 02.00.22 02.00.22 +mpi2_init.h 02.00.14 02.00.14 02.00.14 02.00.14 02.00.13 02.00.13 +mpi2_ioc.h 02.00.22 02.00.22 02.00.22 02.00.21 02.00.21 02.00.20 +mpi2_raid.h 02.00.09 02.00.09 02.00.09 02.00.08 02.00.08 02.00.08 +mpi2_sas.h 02.00.07 02.00.07 02.00.07 02.00.07 02.00.06 02.00.06 +mpi2_targ.h 02.00.06 02.00.06 02.00.05 02.00.05 02.00.05 02.00.05 +mpi2_tool.h 02.00.10 02.00.10 02.00.10 02.00.09 02.00.08 02.00.08 +mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 +mpi2_ra.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 +mpi2_hbd.h 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02 + +Filename 02.00.23 02.00.22 02.00.21 02.00.20 02.00.19 02.00.18 +---------- -------- -------- -------- -------- -------- -------- +mpi2.h 02.00.23 02.00.22 02.00.21 02.00.20 02.00.19 02.00.18 +mpi2_cnfg.h 02.00.22 02.00.21 02.00.20 02.00.19 02.00.18 02.00.17 +mpi2_init.h 02.00.12 02.00.11 02.00.11 02.00.11 02.00.11 02.00.11 +mpi2_ioc.h 02.00.20 02.00.19 02.00.18 02.00.17 02.00.17 02.00.16 +mpi2_raid.h 02.00.07 02.00.06 02.00.05 02.00.05 02.00.05 02.00.05 +mpi2_sas.h 02.00.06 02.00.05 02.00.05 02.00.05 02.00.05 02.00.05 +mpi2_targ.h 02.00.05 02.00.04 02.00.04 02.00.04 02.00.04 02.00.04 +mpi2_tool.h 02.00.08 02.00.07 02.00.07 02.00.06 02.00.06 02.00.06 +mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 +mpi2_ra.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 +mpi2_hbd.h 02.00.02 02.00.01 02.00.01 02.00.01 02.00.01 02.00.01 + +Filename 02.00.17 02.00.16 02.00.15 02.00.14 02.00.13 02.00.12 +---------- -------- -------- -------- -------- -------- -------- +mpi2.h 02.00.17 02.00.16 02.00.15 02.00.14 02.00.13 02.00.12 +mpi2_cnfg.h 02.00.16 02.00.15 02.00.14 02.00.13 02.00.12 02.00.11 +mpi2_init.h 02.00.10 02.00.10 02.00.09 02.00.08 02.00.07 02.00.07 +mpi2_ioc.h 02.00.15 02.00.15 02.00.14 02.00.13 02.00.12 02.00.11 +mpi2_raid.h 02.00.05 02.00.05 02.00.04 02.00.04 02.00.04 02.00.03 +mpi2_sas.h 02.00.05 02.00.04 02.00.03 02.00.03 02.00.02 02.00.02 +mpi2_targ.h 02.00.04 02.00.04 02.00.04 02.00.03 02.00.03 02.00.03 +mpi2_tool.h 02.00.06 02.00.05 02.00.04 02.00.04 02.00.04 02.00.03 +mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 +mpi2_ra.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 +mpi2_hbd.h 02.00.01 02.00.00 02.00.00 02.00.00 + +Filename 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 +---------- -------- -------- -------- -------- -------- -------- +mpi2.h 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 +mpi2_cnfg.h 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 02.00.06 +mpi2_init.h 02.00.06 02.00.06 02.00.05 02.00.05 02.00.04 02.00.03 +mpi2_ioc.h 02.00.10 02.00.09 02.00.08 02.00.07 02.00.07 02.00.06 +mpi2_raid.h 02.00.03 02.00.03 02.00.03 02.00.03 02.00.02 02.00.02 +mpi2_sas.h 02.00.02 02.00.02 02.00.01 02.00.01 02.00.01 02.00.01 +mpi2_targ.h 02.00.03 02.00.03 02.00.02 02.00.02 02.00.02 02.00.02 +mpi2_tool.h 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02 +mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 + +Filename 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00 +---------- -------- -------- -------- -------- -------- -------- +mpi2.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00 +mpi2_cnfg.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00 +mpi2_init.h 02.00.02 02.00.01 02.00.00 02.00.00 02.00.00 02.00.00 +mpi2_ioc.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00 +mpi2_raid.h 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 02.00.00 +mpi2_sas.h 02.00.01 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 +mpi2_targ.h 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 02.00.00 +mpi2_tool.h 02.00.01 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 +mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 + diff --git a/sys/dev/mpr/mpi/mpi2_init.h b/sys/dev/mpr/mpi/mpi2_init.h new file mode 100644 index 0000000000000..62b0cfed120a8 --- /dev/null +++ b/sys/dev/mpr/mpi/mpi2_init.h @@ -0,0 +1,614 @@ +/*- + * Copyright (c) 2013 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + +/* + * Copyright (c) 2000-2013 LSI Corporation. + * + * + * Name: mpi2_init.h + * Title: MPI SCSI initiator mode messages and structures + * Creation Date: June 23, 2006 + * + * mpi2_init.h Version: 02.00.15 + * + * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 + * prefix are for use only on MPI v2.5 products, and must not be used + * with MPI v2.0 products. Unless otherwise noted, names beginning with + * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 10-31-07 02.00.01 Fixed name for pMpi2SCSITaskManagementRequest_t. + * 12-18-07 02.00.02 Modified Task Management Target Reset Method defines. + * 02-29-08 02.00.03 Added Query Task Set and Query Unit Attention. + * 03-03-08 02.00.04 Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY. + * 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t. + * 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO + * Control field Task Attribute flags. + * Moved LUN field defines to mpi2.h becasue they are + * common to many structures. + * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to + * Query Asynchronous Event. + * Defined two new bits in the SlotStatus field of the SCSI + * Enclosure Processor Request and Reply. + * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for + * both SCSI IO Error Reply and SCSI Task Management Reply. + * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. + * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. + * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it. + * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request. + * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define. + * 11-18-11 02.00.12 Incorporating additions for MPI v2.5. + * 02-06-12 02.00.13 Added alternate defines for Task Priority / Command + * Priority to match SAM-4. + * Added EEDPErrorOffset to MPI2_SCSI_IO_REPLY. + * 07-10-12 02.00.14 Added MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION. + * 04-09-13 02.00.15 Added SCSIStatusQualifier field to MPI2_SCSI_IO_REPLY, + * replacing the Reserved4 field. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_INIT_H +#define MPI2_INIT_H + +/***************************************************************************** +* +* SCSI Initiator Messages +* +*****************************************************************************/ + +/**************************************************************************** +* SCSI IO messages and associated structures +****************************************************************************/ + +typedef struct _MPI2_SCSI_IO_CDB_EEDP32 +{ + U8 CDB[20]; /* 0x00 */ + U32 PrimaryReferenceTag; /* 0x14 */ + U16 PrimaryApplicationTag; /* 0x18 */ + U16 PrimaryApplicationTagMask; /* 0x1A */ + U32 TransferLength; /* 0x1C */ +} MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32, + Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t; + +/* MPI v2.0 CDB field */ +typedef union _MPI2_SCSI_IO_CDB_UNION +{ + U8 CDB32[32]; + MPI2_SCSI_IO_CDB_EEDP32 EEDP32; + MPI2_SGE_SIMPLE_UNION SGE; +} MPI2_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_UNION, + Mpi2ScsiIoCdb_t, MPI2_POINTER pMpi2ScsiIoCdb_t; + +/* MPI v2.0 SCSI IO Request Message */ +typedef struct _MPI2_SCSI_IO_REQUEST +{ + U16 DevHandle; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U32 SenseBufferLowAddress; /* 0x0C */ + U16 SGLFlags; /* 0x10 */ + U8 SenseBufferLength; /* 0x12 */ + U8 Reserved4; /* 0x13 */ + U8 SGLOffset0; /* 0x14 */ + U8 SGLOffset1; /* 0x15 */ + U8 SGLOffset2; /* 0x16 */ + U8 SGLOffset3; /* 0x17 */ + U32 SkipCount; /* 0x18 */ + U32 DataLength; /* 0x1C */ + U32 BidirectionalDataLength; /* 0x20 */ + U16 IoFlags; /* 0x24 */ + U16 EEDPFlags; /* 0x26 */ + U32 EEDPBlockSize; /* 0x28 */ + U32 SecondaryReferenceTag; /* 0x2C */ + U16 SecondaryApplicationTag; /* 0x30 */ + U16 ApplicationTagTranslationMask; /* 0x32 */ + U8 LUN[8]; /* 0x34 */ + U32 Control; /* 0x3C */ + MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */ + +#ifdef MPI2_SCSI_IO_VENDOR_UNIQUE_REGION /* typically this is left undefined */ + MPI2_SCSI_IO_VENDOR_UNIQUE VendorRegion; +#endif + + MPI2_SGE_IO_UNION SGL; /* 0x60 */ + +} MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST, + Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t; + +/* SCSI IO MsgFlags bits */ + +/* MsgFlags for SenseBufferAddressSpace */ +#define MPI2_SCSIIO_MSGFLAGS_MASK_SENSE_ADDR (0x0C) +#define MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR (0x00) +#define MPI2_SCSIIO_MSGFLAGS_IOCDDR_SENSE_ADDR (0x04) +#define MPI2_SCSIIO_MSGFLAGS_IOCPLB_SENSE_ADDR (0x08) +#define MPI2_SCSIIO_MSGFLAGS_IOCPLBNTA_SENSE_ADDR (0x0C) + +/* SCSI IO SGLFlags bits */ + +/* base values for Data Location Address Space */ +#define MPI2_SCSIIO_SGLFLAGS_ADDR_MASK (0x0C) +#define MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR (0x00) +#define MPI2_SCSIIO_SGLFLAGS_IOCDDR_ADDR (0x04) +#define MPI2_SCSIIO_SGLFLAGS_IOCPLB_ADDR (0x08) +#define MPI2_SCSIIO_SGLFLAGS_IOCPLBNTA_ADDR (0x0C) + +/* base values for Type */ +#define MPI2_SCSIIO_SGLFLAGS_TYPE_MASK (0x03) +#define MPI2_SCSIIO_SGLFLAGS_TYPE_MPI (0x00) +#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE32 (0x01) +#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE64 (0x02) + +/* shift values for each sub-field */ +#define MPI2_SCSIIO_SGLFLAGS_SGL3_SHIFT (12) +#define MPI2_SCSIIO_SGLFLAGS_SGL2_SHIFT (8) +#define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT (4) +#define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT (0) + +/* number of SGLOffset fields */ +#define MPI2_SCSIIO_NUM_SGLOFFSETS (4) + +/* SCSI IO IoFlags bits */ + +/* Large CDB Address Space */ +#define MPI2_SCSIIO_CDB_ADDR_MASK (0x6000) +#define MPI2_SCSIIO_CDB_ADDR_SYSTEM (0x0000) +#define MPI2_SCSIIO_CDB_ADDR_IOCDDR (0x2000) +#define MPI2_SCSIIO_CDB_ADDR_IOCPLB (0x4000) +#define MPI2_SCSIIO_CDB_ADDR_IOCPLBNTA (0x6000) + +#define MPI2_SCSIIO_IOFLAGS_LARGE_CDB (0x1000) +#define MPI2_SCSIIO_IOFLAGS_BIDIRECTIONAL (0x0800) +#define MPI2_SCSIIO_IOFLAGS_MULTICAST (0x0400) +#define MPI2_SCSIIO_IOFLAGS_CMD_DETERMINES_DATA_DIR (0x0200) +#define MPI2_SCSIIO_IOFLAGS_CDBLENGTH_MASK (0x01FF) + +/* SCSI IO EEDPFlags bits */ + +#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG (0x8000) +#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_REFTAG (0x4000) +#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG (0x2000) +#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_APPTAG (0x1000) + +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG (0x0400) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) + +#define MPI2_SCSIIO_EEDPFLAGS_PASSTHRU_REFTAG (0x0008) + +#define MPI2_SCSIIO_EEDPFLAGS_MASK_OP (0x0007) +#define MPI2_SCSIIO_EEDPFLAGS_NOOP_OP (0x0000) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_OP (0x0001) +#define MPI2_SCSIIO_EEDPFLAGS_STRIP_OP (0x0002) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP (0x0003) +#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) +#define MPI2_SCSIIO_EEDPFLAGS_REPLACE_OP (0x0006) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REGEN_OP (0x0007) + +/* SCSI IO LUN fields: use MPI2_LUN_ from mpi2.h */ + +/* SCSI IO Control bits */ +#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_MASK (0xFC000000) +#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT (26) + +#define MPI2_SCSIIO_CONTROL_DATADIRECTION_MASK (0x03000000) +#define MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION (24) +#define MPI2_SCSIIO_CONTROL_NODATATRANSFER (0x00000000) +#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000) +#define MPI2_SCSIIO_CONTROL_READ (0x02000000) +#define MPI2_SCSIIO_CONTROL_BIDIRECTIONAL (0x03000000) + +#define MPI2_SCSIIO_CONTROL_TASKPRI_MASK (0x00007800) +#define MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT (11) +/* alternate name for the previous field; called Command Priority in SAM-4 */ +#define MPI2_SCSIIO_CONTROL_CMDPRI_MASK (0x00007800) +#define MPI2_SCSIIO_CONTROL_CMDPRI_SHIFT (11) + +#define MPI2_SCSIIO_CONTROL_TASKATTRIBUTE_MASK (0x00000700) +#define MPI2_SCSIIO_CONTROL_SIMPLEQ (0x00000000) +#define MPI2_SCSIIO_CONTROL_HEADOFQ (0x00000100) +#define MPI2_SCSIIO_CONTROL_ORDEREDQ (0x00000200) +#define MPI2_SCSIIO_CONTROL_ACAQ (0x00000400) + +#define MPI2_SCSIIO_CONTROL_TLR_MASK (0x000000C0) +#define MPI2_SCSIIO_CONTROL_NO_TLR (0x00000000) +#define MPI2_SCSIIO_CONTROL_TLR_ON (0x00000040) +#define MPI2_SCSIIO_CONTROL_TLR_OFF (0x00000080) + + +/* MPI v2.5 CDB field */ +typedef union _MPI25_SCSI_IO_CDB_UNION +{ + U8 CDB32[32]; + MPI2_SCSI_IO_CDB_EEDP32 EEDP32; + MPI2_IEEE_SGE_SIMPLE64 SGE; +} MPI25_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI25_SCSI_IO_CDB_UNION, + Mpi25ScsiIoCdb_t, MPI2_POINTER pMpi25ScsiIoCdb_t; + +/* MPI v2.5 SCSI IO Request Message */ +typedef struct _MPI25_SCSI_IO_REQUEST +{ + U16 DevHandle; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U32 SenseBufferLowAddress; /* 0x0C */ + U8 DMAFlags; /* 0x10 */ + U8 Reserved5; /* 0x11 */ + U8 SenseBufferLength; /* 0x12 */ + U8 Reserved4; /* 0x13 */ + U8 SGLOffset0; /* 0x14 */ + U8 SGLOffset1; /* 0x15 */ + U8 SGLOffset2; /* 0x16 */ + U8 SGLOffset3; /* 0x17 */ + U32 SkipCount; /* 0x18 */ + U32 DataLength; /* 0x1C */ + U32 BidirectionalDataLength; /* 0x20 */ + U16 IoFlags; /* 0x24 */ + U16 EEDPFlags; /* 0x26 */ + U16 EEDPBlockSize; /* 0x28 */ + U16 Reserved6; /* 0x2A */ + U32 SecondaryReferenceTag; /* 0x2C */ + U16 SecondaryApplicationTag; /* 0x30 */ + U16 ApplicationTagTranslationMask; /* 0x32 */ + U8 LUN[8]; /* 0x34 */ + U32 Control; /* 0x3C */ + MPI25_SCSI_IO_CDB_UNION CDB; /* 0x40 */ + +#ifdef MPI25_SCSI_IO_VENDOR_UNIQUE_REGION /* typically this is left undefined */ + MPI25_SCSI_IO_VENDOR_UNIQUE VendorRegion; +#endif + + MPI25_SGE_IO_UNION SGL; /* 0x60 */ + +} MPI25_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI25_SCSI_IO_REQUEST, + Mpi25SCSIIORequest_t, MPI2_POINTER pMpi25SCSIIORequest_t; + +/* use MPI2_SCSIIO_MSGFLAGS_ defines for the MsgFlags field */ + +/* Defines for the DMAFlags field + * Each setting affects 4 SGLS, from SGL0 to SGL3. + * D = Data + * C = Cache DIF + * I = Interleaved + * H = Host DIF + */ +#define MPI25_SCSIIO_DMAFLAGS_OP_MASK (0x0F) +#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_D_D (0x00) +#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_D_C (0x01) +#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_D_I (0x02) +#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_C_C (0x03) +#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_C_I (0x04) +#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_I_I (0x05) +#define MPI25_SCSIIO_DMAFLAGS_OP_D_C_C_C (0x06) +#define MPI25_SCSIIO_DMAFLAGS_OP_D_C_C_I (0x07) +#define MPI25_SCSIIO_DMAFLAGS_OP_D_C_I_I (0x08) +#define MPI25_SCSIIO_DMAFLAGS_OP_D_I_I_I (0x09) +#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_D_D (0x0A) +#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_D_C (0x0B) +#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_D_I (0x0C) +#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_C_C (0x0D) +#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_C_I (0x0E) +#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_I_I (0x0F) + +/* number of SGLOffset fields */ +#define MPI25_SCSIIO_NUM_SGLOFFSETS (4) + +/* defines for the IoFlags field */ +#define MPI25_SCSIIO_IOFLAGS_IO_PATH_MASK (0xC000) +#define MPI25_SCSIIO_IOFLAGS_NORMAL_PATH (0x0000) +#define MPI25_SCSIIO_IOFLAGS_FAST_PATH (0x4000) + +#define MPI25_SCSIIO_IOFLAGS_LARGE_CDB (0x1000) +#define MPI25_SCSIIO_IOFLAGS_BIDIRECTIONAL (0x0800) +#define MPI25_SCSIIO_IOFLAGS_CDBLENGTH_MASK (0x01FF) + +/* MPI v2.5 defines for the EEDPFlags bits */ +/* use MPI2_SCSIIO_EEDPFLAGS_ defines for the other EEDPFlags bits */ +#define MPI25_SCSIIO_EEDPFLAGS_ESCAPE_MODE_MASK (0x00C0) +#define MPI25_SCSIIO_EEDPFLAGS_COMPATIBLE_MODE (0x0000) +#define MPI25_SCSIIO_EEDPFLAGS_DO_NOT_DISABLE_MODE (0x0040) +#define MPI25_SCSIIO_EEDPFLAGS_APPTAG_DISABLE_MODE (0x0080) +#define MPI25_SCSIIO_EEDPFLAGS_APPTAG_REFTAG_DISABLE_MODE (0x00C0) + +#define MPI25_SCSIIO_EEDPFLAGS_HOST_GUARD_METHOD_MASK (0x0030) +#define MPI25_SCSIIO_EEDPFLAGS_T10_CRC_HOST_GUARD (0x0000) +#define MPI25_SCSIIO_EEDPFLAGS_IP_CHKSUM_HOST_GUARD (0x0010) + +/* use MPI2_LUN_ defines from mpi2.h for the LUN field */ + +/* use MPI2_SCSIIO_CONTROL_ defines for the Control field */ + + +/* NOTE: The SCSI IO Reply is nearly the same for MPI 2.0 and MPI 2.5, so + * MPI2_SCSI_IO_REPLY is used for both. + */ + +/* SCSI IO Error Reply Message */ +typedef struct _MPI2_SCSI_IO_REPLY +{ + U16 DevHandle; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U8 SCSIStatus; /* 0x0C */ + U8 SCSIState; /* 0x0D */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 TransferCount; /* 0x14 */ + U32 SenseCount; /* 0x18 */ + U32 ResponseInfo; /* 0x1C */ + U16 TaskTag; /* 0x20 */ + U16 SCSIStatusQualifier; /* 0x22 */ + U32 BidirectionalTransferCount; /* 0x24 */ + U32 EEDPErrorOffset; /* 0x28 */ /* MPI 2.5 only; Reserved in MPI 2.0 */ + U32 Reserved6; /* 0x2C */ +} MPI2_SCSI_IO_REPLY, MPI2_POINTER PTR_MPI2_SCSI_IO_REPLY, + Mpi2SCSIIOReply_t, MPI2_POINTER pMpi2SCSIIOReply_t; + +/* SCSI IO Reply SCSIStatus values (SAM-4 status codes) */ + +#define MPI2_SCSI_STATUS_GOOD (0x00) +#define MPI2_SCSI_STATUS_CHECK_CONDITION (0x02) +#define MPI2_SCSI_STATUS_CONDITION_MET (0x04) +#define MPI2_SCSI_STATUS_BUSY (0x08) +#define MPI2_SCSI_STATUS_INTERMEDIATE (0x10) +#define MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET (0x14) +#define MPI2_SCSI_STATUS_RESERVATION_CONFLICT (0x18) +#define MPI2_SCSI_STATUS_COMMAND_TERMINATED (0x22) /* obsolete */ +#define MPI2_SCSI_STATUS_TASK_SET_FULL (0x28) +#define MPI2_SCSI_STATUS_ACA_ACTIVE (0x30) +#define MPI2_SCSI_STATUS_TASK_ABORTED (0x40) + +/* SCSI IO Reply SCSIState flags */ + +#define MPI2_SCSI_STATE_RESPONSE_INFO_VALID (0x10) +#define MPI2_SCSI_STATE_TERMINATED (0x08) +#define MPI2_SCSI_STATE_NO_SCSI_STATUS (0x04) +#define MPI2_SCSI_STATE_AUTOSENSE_FAILED (0x02) +#define MPI2_SCSI_STATE_AUTOSENSE_VALID (0x01) + +/* masks and shifts for the ResponseInfo field */ + +#define MPI2_SCSI_RI_MASK_REASONCODE (0x000000FF) +#define MPI2_SCSI_RI_SHIFT_REASONCODE (0) + +#define MPI2_SCSI_TASKTAG_UNKNOWN (0xFFFF) + + +/**************************************************************************** +* SCSI Task Management messages +****************************************************************************/ + +/* SCSI Task Management Request Message */ +typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST +{ + U16 DevHandle; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 Reserved1; /* 0x04 */ + U8 TaskType; /* 0x05 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U8 LUN[8]; /* 0x0C */ + U32 Reserved4[7]; /* 0x14 */ + U16 TaskMID; /* 0x30 */ + U16 Reserved5; /* 0x32 */ +} MPI2_SCSI_TASK_MANAGE_REQUEST, + MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REQUEST, + Mpi2SCSITaskManagementRequest_t, + MPI2_POINTER pMpi2SCSITaskManagementRequest_t; + +/* TaskType values */ + +#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01) +#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02) +#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) +#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) +#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) +#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) +#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08) +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09) +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT (0x0A) + +/* obsolete TaskType name */ +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION (MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT) + +/* MsgFlags bits */ + +#define MPI2_SCSITASKMGMT_MSGFLAGS_MASK_TARGET_RESET (0x18) +#define MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET (0x00) +#define MPI2_SCSITASKMGMT_MSGFLAGS_NEXUS_RESET_SRST (0x08) +#define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET (0x10) + +#define MPI2_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x01) + + + +/* SCSI Task Management Reply Message */ +typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY +{ + U16 DevHandle; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 ResponseCode; /* 0x04 */ + U8 TaskType; /* 0x05 */ + U8 Reserved1; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U16 Reserved3; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 TerminationCount; /* 0x14 */ + U32 ResponseInfo; /* 0x18 */ +} MPI2_SCSI_TASK_MANAGE_REPLY, + MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REPLY, + Mpi2SCSITaskManagementReply_t, MPI2_POINTER pMpi2SCSIManagementReply_t; + +/* ResponseCode values */ + +#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00) +#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02) +#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04) +#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05) +#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08) +#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09) +#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A) +#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80) + +/* masks and shifts for the ResponseInfo field */ + +#define MPI2_SCSITASKMGMT_RI_MASK_REASONCODE (0x000000FF) +#define MPI2_SCSITASKMGMT_RI_SHIFT_REASONCODE (0) +#define MPI2_SCSITASKMGMT_RI_MASK_ARI2 (0x0000FF00) +#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI2 (8) +#define MPI2_SCSITASKMGMT_RI_MASK_ARI1 (0x00FF0000) +#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI1 (16) +#define MPI2_SCSITASKMGMT_RI_MASK_ARI0 (0xFF000000) +#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI0 (24) + + +/**************************************************************************** +* SCSI Enclosure Processor messages +****************************************************************************/ + +/* SCSI Enclosure Processor Request Message */ +typedef struct _MPI2_SEP_REQUEST +{ + U16 DevHandle; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 Action; /* 0x04 */ + U8 Flags; /* 0x05 */ + U8 Reserved1; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 SlotStatus; /* 0x0C */ + U32 Reserved3; /* 0x10 */ + U32 Reserved4; /* 0x14 */ + U32 Reserved5; /* 0x18 */ + U16 Slot; /* 0x1C */ + U16 EnclosureHandle; /* 0x1E */ +} MPI2_SEP_REQUEST, MPI2_POINTER PTR_MPI2_SEP_REQUEST, + Mpi2SepRequest_t, MPI2_POINTER pMpi2SepRequest_t; + +/* Action defines */ +#define MPI2_SEP_REQ_ACTION_WRITE_STATUS (0x00) +#define MPI2_SEP_REQ_ACTION_READ_STATUS (0x01) + +/* Flags defines */ +#define MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS (0x00) +#define MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS (0x01) + +/* SlotStatus defines */ +#define MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE (0x00040000) +#define MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) +#define MPI2_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED (0x00000200) +#define MPI2_SEP_REQ_SLOTSTATUS_HOT_SPARE (0x00000100) +#define MPI2_SEP_REQ_SLOTSTATUS_UNCONFIGURED (0x00000080) +#define MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT (0x00000040) +#define MPI2_SEP_REQ_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010) +#define MPI2_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) +#define MPI2_SEP_REQ_SLOTSTATUS_DEV_REBUILDING (0x00000004) +#define MPI2_SEP_REQ_SLOTSTATUS_DEV_FAULTY (0x00000002) +#define MPI2_SEP_REQ_SLOTSTATUS_NO_ERROR (0x00000001) + + +/* SCSI Enclosure Processor Reply Message */ +typedef struct _MPI2_SEP_REPLY +{ + U16 DevHandle; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 Action; /* 0x04 */ + U8 Flags; /* 0x05 */ + U8 Reserved1; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U16 Reserved3; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 SlotStatus; /* 0x14 */ + U32 Reserved4; /* 0x18 */ + U16 Slot; /* 0x1C */ + U16 EnclosureHandle; /* 0x1E */ +} MPI2_SEP_REPLY, MPI2_POINTER PTR_MPI2_SEP_REPLY, + Mpi2SepReply_t, MPI2_POINTER pMpi2SepReply_t; + +/* SlotStatus defines */ +#define MPI2_SEP_REPLY_SLOTSTATUS_REMOVE_READY (0x00040000) +#define MPI2_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) +#define MPI2_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED (0x00000200) +#define MPI2_SEP_REPLY_SLOTSTATUS_HOT_SPARE (0x00000100) +#define MPI2_SEP_REPLY_SLOTSTATUS_UNCONFIGURED (0x00000080) +#define MPI2_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT (0x00000040) +#define MPI2_SEP_REPLY_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010) +#define MPI2_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) +#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING (0x00000004) +#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_FAULTY (0x00000002) +#define MPI2_SEP_REPLY_SLOTSTATUS_NO_ERROR (0x00000001) + + +#endif + + diff --git a/sys/dev/mpr/mpi/mpi2_ioc.h b/sys/dev/mpr/mpi/mpi2_ioc.h new file mode 100644 index 0000000000000..38a46f5280bc5 --- /dev/null +++ b/sys/dev/mpr/mpi/mpi2_ioc.h @@ -0,0 +1,1856 @@ +/*- + * Copyright (c) 2013 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + +/* + * Copyright (c) 2000-2013 LSI Corporation. + * + * + * Name: mpi2_ioc.h + * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages + * Creation Date: October 11, 2006 + * + * mpi2_ioc.h Version: 02.00.24 + * + * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 + * prefix are for use only on MPI v2.5 products, and must not be used + * with MPI v2.0 products. Unless otherwise noted, names beginning with + * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 In IOCFacts Reply structure, renamed MaxDevices to + * MaxTargets. + * Added TotalImageSize field to FWDownload Request. + * Added reserved words to FWUpload Request. + * 06-26-07 02.00.02 Added IR Configuration Change List Event. + * 08-31-07 02.00.03 Removed SystemReplyQueueDepth field from the IOCInit + * request and replaced it with + * ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth. + * Replaced the MinReplyQueueDepth field of the IOCFacts + * reply with MaxReplyDescriptorPostQueueDepth. + * Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum + * depth for the Reply Descriptor Post Queue. + * Added SASAddress field to Initiator Device Table + * Overflow Event data. + * 10-31-07 02.00.04 Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING + * for SAS Initiator Device Status Change Event data. + * Modified Reason Code defines for SAS Topology Change + * List Event data, including adding a bit for PHY Vacant + * status, and adding a mask for the Reason Code. + * Added define for + * MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING. + * Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID. + * 12-18-07 02.00.05 Added Boot Status defines for the IOCExceptions field of + * the IOCFacts Reply. + * Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. + * Moved MPI2_VERSION_UNION to mpi2.h. + * Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks + * instead of enables, and added SASBroadcastPrimitiveMasks + * field. + * Added Log Entry Added Event and related structure. + * 02-29-08 02.00.06 Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID. + * Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET. + * Added MaxVolumes and MaxPersistentEntries fields to + * IOCFacts reply. + * Added ProtocalFlags and IOCCapabilities fields to + * MPI2_FW_IMAGE_HEADER. + * Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT. + * 03-03-08 02.00.07 Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to + * a U16 (from a U32). + * Removed extra 's' from EventMasks name. + * 06-27-08 02.00.08 Fixed an offset in a comment. + * 10-02-08 02.00.09 Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST. + * Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and + * renamed MinReplyFrameSize to ReplyFrameSize. + * Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX. + * Added two new RAIDOperation values for Integrated RAID + * Operations Status Event data. + * Added four new IR Configuration Change List Event data + * ReasonCode values. + * Added two new ReasonCode defines for SAS Device Status + * Change Event data. + * Added three new DiscoveryStatus bits for the SAS + * Discovery event data. + * Added Multiplexing Status Change bit to the PhyStatus + * field of the SAS Topology Change List event data. + * Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY. + * BootFlags are now product-specific. + * Added defines for the indivdual signature bytes + * for MPI2_INIT_IMAGE_FOOTER. + * 01-19-09 02.00.10 Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define. + * Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR + * define. + * Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE + * define. + * Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define. + * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define. + * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define. + * Added two new reason codes for SAS Device Status Change + * Event. + * Added new event: SAS PHY Counter. + * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure. + * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. + * Added new product id family for 2208. + * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST. + * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY. + * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY. + * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY. + * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define. + * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define. + * Added Host Based Discovery Phy Event data. + * Added defines for ProductID Product field + * (MPI2_FW_HEADER_PID_). + * Modified values for SAS ProductID Family + * (MPI2_FW_HEADER_PID_FAMILY_). + * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines. + * Added PowerManagementControl Request structures and + * defines. + * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete. + * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define. + * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC. + * 02-23-11 02.00.17 Added SAS NOTIFY Primitive event, and added + * SASNotifyPrimitiveMasks field to + * MPI2_EVENT_NOTIFICATION_REQUEST. + * Added Temperature Threshold Event. + * Added Host Message Event. + * Added Send Host Message request and reply. + * 05-25-11 02.00.18 For Extended Image Header, added + * MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC and + * MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC defines. + * Deprecated MPI2_EXT_IMAGE_TYPE_MAX define. + * 08-24-11 02.00.19 Added PhysicalPort field to + * MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE structure. + * Marked MPI2_PM_CONTROL_FEATURE_PCIE_LINK as obsolete. + * 11-18-11 02.00.20 Incorporating additions for MPI v2.5. + * 03-29-12 02.00.21 Added a product specific range to event values. + * 07-26-12 02.00.22 Added MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE. + * Added ElapsedSeconds field to + * MPI2_EVENT_DATA_IR_OPERATION_STATUS. + * 08-19-13 02.00.23 For IOCInit, added MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE + * and MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY. + * Added MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE. + * Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY. + * Added Encrypted Hash Extended Image. + * 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_IOC_H +#define MPI2_IOC_H + +/***************************************************************************** +* +* IOC Messages +* +*****************************************************************************/ + +/**************************************************************************** +* IOCInit message +****************************************************************************/ + +/* IOCInit Request message */ +typedef struct _MPI2_IOC_INIT_REQUEST +{ + U8 WhoInit; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 MsgVersion; /* 0x0C */ + U16 HeaderVersion; /* 0x0E */ + U32 Reserved5; /* 0x10 */ + U16 Reserved6; /* 0x14 */ + U8 Reserved7; /* 0x16 */ + U8 HostMSIxVectors; /* 0x17 */ + U16 Reserved8; /* 0x18 */ + U16 SystemRequestFrameSize; /* 0x1A */ + U16 ReplyDescriptorPostQueueDepth; /* 0x1C */ + U16 ReplyFreeQueueDepth; /* 0x1E */ + U32 SenseBufferAddressHigh; /* 0x20 */ + U32 SystemReplyAddressHigh; /* 0x24 */ + U64 SystemRequestFrameBaseAddress; /* 0x28 */ + U64 ReplyDescriptorPostQueueAddress;/* 0x30 */ + U64 ReplyFreeQueueAddress; /* 0x38 */ + U64 TimeStamp; /* 0x40 */ +} MPI2_IOC_INIT_REQUEST, MPI2_POINTER PTR_MPI2_IOC_INIT_REQUEST, + Mpi2IOCInitRequest_t, MPI2_POINTER pMpi2IOCInitRequest_t; + +/* WhoInit values */ +#define MPI2_WHOINIT_NOT_INITIALIZED (0x00) +#define MPI2_WHOINIT_SYSTEM_BIOS (0x01) +#define MPI2_WHOINIT_ROM_BIOS (0x02) +#define MPI2_WHOINIT_PCI_PEER (0x03) +#define MPI2_WHOINIT_HOST_DRIVER (0x04) +#define MPI2_WHOINIT_MANUFACTURER (0x05) + +/* MsgFlags */ +#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE (0x01) + +/* MsgVersion */ +#define MPI2_IOCINIT_MSGVERSION_MAJOR_MASK (0xFF00) +#define MPI2_IOCINIT_MSGVERSION_MAJOR_SHIFT (8) +#define MPI2_IOCINIT_MSGVERSION_MINOR_MASK (0x00FF) +#define MPI2_IOCINIT_MSGVERSION_MINOR_SHIFT (0) + +/* HeaderVersion */ +#define MPI2_IOCINIT_HDRVERSION_UNIT_MASK (0xFF00) +#define MPI2_IOCINIT_HDRVERSION_UNIT_SHIFT (8) +#define MPI2_IOCINIT_HDRVERSION_DEV_MASK (0x00FF) +#define MPI2_IOCINIT_HDRVERSION_DEV_SHIFT (0) + +/* minimum depth for a Reply Descriptor Post Queue */ +#define MPI2_RDPQ_DEPTH_MIN (16) + +/* Reply Descriptor Post Queue Array Entry */ +typedef struct _MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY +{ + U64 RDPQBaseAddress; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U32 Reserved2; /* 0x0C */ +} MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY, + MPI2_POINTER PTR_MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY, + Mpi2IOCInitRDPQArrayEntry, MPI2_POINTER pMpi2IOCInitRDPQArrayEntry; + +/* IOCInit Reply message */ +typedef struct _MPI2_IOC_INIT_REPLY +{ + U8 WhoInit; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_IOC_INIT_REPLY, MPI2_POINTER PTR_MPI2_IOC_INIT_REPLY, + Mpi2IOCInitReply_t, MPI2_POINTER pMpi2IOCInitReply_t; + + +/**************************************************************************** +* IOCFacts message +****************************************************************************/ + +/* IOCFacts Request message */ +typedef struct _MPI2_IOC_FACTS_REQUEST +{ + U16 Reserved1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ +} MPI2_IOC_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_IOC_FACTS_REQUEST, + Mpi2IOCFactsRequest_t, MPI2_POINTER pMpi2IOCFactsRequest_t; + + +/* IOCFacts Reply message */ +typedef struct _MPI2_IOC_FACTS_REPLY +{ + U16 MsgVersion; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 HeaderVersion; /* 0x04 */ + U8 IOCNumber; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U16 IOCExceptions; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U8 MaxChainDepth; /* 0x14 */ + U8 WhoInit; /* 0x15 */ + U8 NumberOfPorts; /* 0x16 */ + U8 MaxMSIxVectors; /* 0x17 */ + U16 RequestCredit; /* 0x18 */ + U16 ProductID; /* 0x1A */ + U32 IOCCapabilities; /* 0x1C */ + MPI2_VERSION_UNION FWVersion; /* 0x20 */ + U16 IOCRequestFrameSize; /* 0x24 */ + U16 IOCMaxChainSegmentSize; /* 0x26 */ /* MPI 2.5 only; Reserved in MPI 2.0 */ + U16 MaxInitiators; /* 0x28 */ + U16 MaxTargets; /* 0x2A */ + U16 MaxSasExpanders; /* 0x2C */ + U16 MaxEnclosures; /* 0x2E */ + U16 ProtocolFlags; /* 0x30 */ + U16 HighPriorityCredit; /* 0x32 */ + U16 MaxReplyDescriptorPostQueueDepth; /* 0x34 */ + U8 ReplyFrameSize; /* 0x36 */ + U8 MaxVolumes; /* 0x37 */ + U16 MaxDevHandle; /* 0x38 */ + U16 MaxPersistentEntries; /* 0x3A */ + U16 MinDevHandle; /* 0x3C */ + U16 Reserved4; /* 0x3E */ +} MPI2_IOC_FACTS_REPLY, MPI2_POINTER PTR_MPI2_IOC_FACTS_REPLY, + Mpi2IOCFactsReply_t, MPI2_POINTER pMpi2IOCFactsReply_t; + +/* MsgVersion */ +#define MPI2_IOCFACTS_MSGVERSION_MAJOR_MASK (0xFF00) +#define MPI2_IOCFACTS_MSGVERSION_MAJOR_SHIFT (8) +#define MPI2_IOCFACTS_MSGVERSION_MINOR_MASK (0x00FF) +#define MPI2_IOCFACTS_MSGVERSION_MINOR_SHIFT (0) + +/* HeaderVersion */ +#define MPI2_IOCFACTS_HDRVERSION_UNIT_MASK (0xFF00) +#define MPI2_IOCFACTS_HDRVERSION_UNIT_SHIFT (8) +#define MPI2_IOCFACTS_HDRVERSION_DEV_MASK (0x00FF) +#define MPI2_IOCFACTS_HDRVERSION_DEV_SHIFT (0) + +/* IOCExceptions */ +#define MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE (0x0200) +#define MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX (0x0100) + +#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_MASK (0x00E0) +#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_GOOD (0x0000) +#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_BACKUP (0x0020) +#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_RESTORED (0x0040) +#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_CORRUPT_BACKUP (0x0060) + +#define MPI2_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED (0x0010) +#define MPI2_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL (0x0008) +#define MPI2_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0004) +#define MPI2_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (0x0002) +#define MPI2_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0001) + +/* defines for WhoInit field are after the IOCInit Request */ + +/* ProductID field uses MPI2_FW_HEADER_PID_ */ + +/* IOCCapabilities */ +#define MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE (0x00040000) +#define MPI25_IOCFACTS_CAPABILITY_FAST_PATH_CAPABLE (0x00020000) +#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000) +#define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX (0x00008000) +#define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR (0x00004000) +#define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY (0x00002000) +#define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID (0x00001000) +#define MPI2_IOCFACTS_CAPABILITY_TLR (0x00000800) +#define MPI2_IOCFACTS_CAPABILITY_MULTICAST (0x00000100) +#define MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET (0x00000080) +#define MPI2_IOCFACTS_CAPABILITY_EEDP (0x00000040) +#define MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020) +#define MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010) +#define MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008) +#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004) + +/* ProtocolFlags */ +#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001) +#define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR (0x0002) + + +/**************************************************************************** +* PortFacts message +****************************************************************************/ + +/* PortFacts Request message */ +typedef struct _MPI2_PORT_FACTS_REQUEST +{ + U16 Reserved1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 PortNumber; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ +} MPI2_PORT_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_PORT_FACTS_REQUEST, + Mpi2PortFactsRequest_t, MPI2_POINTER pMpi2PortFactsRequest_t; + +/* PortFacts Reply message */ +typedef struct _MPI2_PORT_FACTS_REPLY +{ + U16 Reserved1; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 PortNumber; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U8 Reserved5; /* 0x14 */ + U8 PortType; /* 0x15 */ + U16 Reserved6; /* 0x16 */ + U16 MaxPostedCmdBuffers; /* 0x18 */ + U16 Reserved7; /* 0x1A */ +} MPI2_PORT_FACTS_REPLY, MPI2_POINTER PTR_MPI2_PORT_FACTS_REPLY, + Mpi2PortFactsReply_t, MPI2_POINTER pMpi2PortFactsReply_t; + +/* PortType values */ +#define MPI2_PORTFACTS_PORTTYPE_INACTIVE (0x00) +#define MPI2_PORTFACTS_PORTTYPE_FC (0x10) +#define MPI2_PORTFACTS_PORTTYPE_ISCSI (0x20) +#define MPI2_PORTFACTS_PORTTYPE_SAS_PHYSICAL (0x30) +#define MPI2_PORTFACTS_PORTTYPE_SAS_VIRTUAL (0x31) + + +/**************************************************************************** +* PortEnable message +****************************************************************************/ + +/* PortEnable Request message */ +typedef struct _MPI2_PORT_ENABLE_REQUEST +{ + U16 Reserved1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 Reserved2; /* 0x04 */ + U8 PortFlags; /* 0x05 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ +} MPI2_PORT_ENABLE_REQUEST, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REQUEST, + Mpi2PortEnableRequest_t, MPI2_POINTER pMpi2PortEnableRequest_t; + + +/* PortEnable Reply message */ +typedef struct _MPI2_PORT_ENABLE_REPLY +{ + U16 Reserved1; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 Reserved2; /* 0x04 */ + U8 PortFlags; /* 0x05 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_PORT_ENABLE_REPLY, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REPLY, + Mpi2PortEnableReply_t, MPI2_POINTER pMpi2PortEnableReply_t; + + +/**************************************************************************** +* EventNotification message +****************************************************************************/ + +/* EventNotification Request message */ +#define MPI2_EVENT_NOTIFY_EVENTMASK_WORDS (4) + +typedef struct _MPI2_EVENT_NOTIFICATION_REQUEST +{ + U16 Reserved1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 Reserved5; /* 0x0C */ + U32 Reserved6; /* 0x10 */ + U32 EventMasks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];/* 0x14 */ + U16 SASBroadcastPrimitiveMasks; /* 0x24 */ + U16 SASNotifyPrimitiveMasks; /* 0x26 */ + U32 Reserved8; /* 0x28 */ +} MPI2_EVENT_NOTIFICATION_REQUEST, + MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REQUEST, + Mpi2EventNotificationRequest_t, MPI2_POINTER pMpi2EventNotificationRequest_t; + + +/* EventNotification Reply message */ +typedef struct _MPI2_EVENT_NOTIFICATION_REPLY +{ + U16 EventDataLength; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 AckRequired; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U16 Reserved3; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U16 Event; /* 0x14 */ + U16 Reserved4; /* 0x16 */ + U32 EventContext; /* 0x18 */ + U32 EventData[1]; /* 0x1C */ +} MPI2_EVENT_NOTIFICATION_REPLY, MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REPLY, + Mpi2EventNotificationReply_t, MPI2_POINTER pMpi2EventNotificationReply_t; + +/* AckRequired */ +#define MPI2_EVENT_NOTIFICATION_ACK_NOT_REQUIRED (0x00) +#define MPI2_EVENT_NOTIFICATION_ACK_REQUIRED (0x01) + +/* Event */ +#define MPI2_EVENT_LOG_DATA (0x0001) +#define MPI2_EVENT_STATE_CHANGE (0x0002) +#define MPI2_EVENT_HARD_RESET_RECEIVED (0x0005) +#define MPI2_EVENT_EVENT_CHANGE (0x000A) +#define MPI2_EVENT_TASK_SET_FULL (0x000E) /* obsolete */ +#define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE (0x000F) +#define MPI2_EVENT_IR_OPERATION_STATUS (0x0014) +#define MPI2_EVENT_SAS_DISCOVERY (0x0016) +#define MPI2_EVENT_SAS_BROADCAST_PRIMITIVE (0x0017) +#define MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x0018) +#define MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW (0x0019) +#define MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST (0x001C) +#define MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE (0x001D) +#define MPI2_EVENT_IR_VOLUME (0x001E) +#define MPI2_EVENT_IR_PHYSICAL_DISK (0x001F) +#define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x0020) +#define MPI2_EVENT_LOG_ENTRY_ADDED (0x0021) +#define MPI2_EVENT_SAS_PHY_COUNTER (0x0022) +#define MPI2_EVENT_GPIO_INTERRUPT (0x0023) +#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024) +#define MPI2_EVENT_SAS_QUIESCE (0x0025) +#define MPI2_EVENT_SAS_NOTIFY_PRIMITIVE (0x0026) +#define MPI2_EVENT_TEMP_THRESHOLD (0x0027) +#define MPI2_EVENT_HOST_MESSAGE (0x0028) +#define MPI2_EVENT_POWER_PERFORMANCE_CHANGE (0x0029) +#define MPI2_EVENT_MIN_PRODUCT_SPECIFIC (0x006E) +#define MPI2_EVENT_MAX_PRODUCT_SPECIFIC (0x007F) + + +/* Log Entry Added Event data */ + +/* the following structure matches MPI2_LOG_0_ENTRY in mpi2_cnfg.h */ +#define MPI2_EVENT_DATA_LOG_DATA_LENGTH (0x1C) + +typedef struct _MPI2_EVENT_DATA_LOG_ENTRY_ADDED +{ + U64 TimeStamp; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U16 LogSequence; /* 0x0C */ + U16 LogEntryQualifier; /* 0x0E */ + U8 VP_ID; /* 0x10 */ + U8 VF_ID; /* 0x11 */ + U16 Reserved2; /* 0x12 */ + U8 LogData[MPI2_EVENT_DATA_LOG_DATA_LENGTH];/* 0x14 */ +} MPI2_EVENT_DATA_LOG_ENTRY_ADDED, + MPI2_POINTER PTR_MPI2_EVENT_DATA_LOG_ENTRY_ADDED, + Mpi2EventDataLogEntryAdded_t, MPI2_POINTER pMpi2EventDataLogEntryAdded_t; + + +/* GPIO Interrupt Event data */ + +typedef struct _MPI2_EVENT_DATA_GPIO_INTERRUPT +{ + U8 GPIONum; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ +} MPI2_EVENT_DATA_GPIO_INTERRUPT, + MPI2_POINTER PTR_MPI2_EVENT_DATA_GPIO_INTERRUPT, + Mpi2EventDataGpioInterrupt_t, MPI2_POINTER pMpi2EventDataGpioInterrupt_t; + + +/* Temperature Threshold Event data */ + +typedef struct _MPI2_EVENT_DATA_TEMPERATURE +{ + U16 Status; /* 0x00 */ + U8 SensorNum; /* 0x02 */ + U8 Reserved1; /* 0x03 */ + U16 CurrentTemperature; /* 0x04 */ + U16 Reserved2; /* 0x06 */ + U32 Reserved3; /* 0x08 */ + U32 Reserved4; /* 0x0C */ +} MPI2_EVENT_DATA_TEMPERATURE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_TEMPERATURE, + Mpi2EventDataTemperature_t, MPI2_POINTER pMpi2EventDataTemperature_t; + +/* Temperature Threshold Event data Status bits */ +#define MPI2_EVENT_TEMPERATURE3_EXCEEDED (0x0008) +#define MPI2_EVENT_TEMPERATURE2_EXCEEDED (0x0004) +#define MPI2_EVENT_TEMPERATURE1_EXCEEDED (0x0002) +#define MPI2_EVENT_TEMPERATURE0_EXCEEDED (0x0001) + + +/* Host Message Event data */ + +typedef struct _MPI2_EVENT_DATA_HOST_MESSAGE +{ + U8 SourceVF_ID; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 Reserved3; /* 0x04 */ + U32 HostData[1]; /* 0x08 */ +} MPI2_EVENT_DATA_HOST_MESSAGE, MPI2_POINTER PTR_MPI2_EVENT_DATA_HOST_MESSAGE, + Mpi2EventDataHostMessage_t, MPI2_POINTER pMpi2EventDataHostMessage_t; + + +/* Power Performance Change Event */ + +typedef struct _MPI2_EVENT_DATA_POWER_PERF_CHANGE +{ + U8 CurrentPowerMode; /* 0x00 */ + U8 PreviousPowerMode; /* 0x01 */ + U16 Reserved1; /* 0x02 */ +} MPI2_EVENT_DATA_POWER_PERF_CHANGE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_POWER_PERF_CHANGE, + Mpi2EventDataPowerPerfChange_t, MPI2_POINTER pMpi2EventDataPowerPerfChange_t; + +/* defines for CurrentPowerMode and PreviousPowerMode fields */ +#define MPI2_EVENT_PM_INIT_MASK (0xC0) +#define MPI2_EVENT_PM_INIT_UNAVAILABLE (0x00) +#define MPI2_EVENT_PM_INIT_HOST (0x40) +#define MPI2_EVENT_PM_INIT_IO_UNIT (0x80) +#define MPI2_EVENT_PM_INIT_PCIE_DPA (0xC0) + +#define MPI2_EVENT_PM_MODE_MASK (0x07) +#define MPI2_EVENT_PM_MODE_UNAVAILABLE (0x00) +#define MPI2_EVENT_PM_MODE_UNKNOWN (0x01) +#define MPI2_EVENT_PM_MODE_FULL_POWER (0x04) +#define MPI2_EVENT_PM_MODE_REDUCED_POWER (0x05) +#define MPI2_EVENT_PM_MODE_STANDBY (0x06) + + +/* Hard Reset Received Event data */ + +typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED +{ + U8 Reserved1; /* 0x00 */ + U8 Port; /* 0x01 */ + U16 Reserved2; /* 0x02 */ +} MPI2_EVENT_DATA_HARD_RESET_RECEIVED, + MPI2_POINTER PTR_MPI2_EVENT_DATA_HARD_RESET_RECEIVED, + Mpi2EventDataHardResetReceived_t, + MPI2_POINTER pMpi2EventDataHardResetReceived_t; + + +/* Task Set Full Event data */ +/* this event is obsolete */ + +typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL +{ + U16 DevHandle; /* 0x00 */ + U16 CurrentDepth; /* 0x02 */ +} MPI2_EVENT_DATA_TASK_SET_FULL, MPI2_POINTER PTR_MPI2_EVENT_DATA_TASK_SET_FULL, + Mpi2EventDataTaskSetFull_t, MPI2_POINTER pMpi2EventDataTaskSetFull_t; + + +/* SAS Device Status Change Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE +{ + U16 TaskTag; /* 0x00 */ + U8 ReasonCode; /* 0x02 */ + U8 PhysicalPort; /* 0x03 */ + U8 ASC; /* 0x04 */ + U8 ASCQ; /* 0x05 */ + U16 DevHandle; /* 0x06 */ + U32 Reserved2; /* 0x08 */ + U64 SASAddress; /* 0x0C */ + U8 LUN[8]; /* 0x14 */ +} MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, + Mpi2EventDataSasDeviceStatusChange_t, + MPI2_POINTER pMpi2EventDataSasDeviceStatusChange_t; + +/* SAS Device Status Change Event data ReasonCode values */ +#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05) +#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07) +#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08) +#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL (0x09) +#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B) +#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C) +#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET (0x0E) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL (0x0F) +#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE (0x10) +#define MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY (0x11) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY (0x12) + + +/* Integrated RAID Operation Status Event data */ + +typedef struct _MPI2_EVENT_DATA_IR_OPERATION_STATUS +{ + U16 VolDevHandle; /* 0x00 */ + U16 Reserved1; /* 0x02 */ + U8 RAIDOperation; /* 0x04 */ + U8 PercentComplete; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U32 ElapsedSeconds; /* 0x08 */ +} MPI2_EVENT_DATA_IR_OPERATION_STATUS, + MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_OPERATION_STATUS, + Mpi2EventDataIrOperationStatus_t, + MPI2_POINTER pMpi2EventDataIrOperationStatus_t; + +/* Integrated RAID Operation Status Event data RAIDOperation values */ +#define MPI2_EVENT_IR_RAIDOP_RESYNC (0x00) +#define MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION (0x01) +#define MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK (0x02) +#define MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT (0x03) +#define MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT (0x04) + + +/* Integrated RAID Volume Event data */ + +typedef struct _MPI2_EVENT_DATA_IR_VOLUME +{ + U16 VolDevHandle; /* 0x00 */ + U8 ReasonCode; /* 0x02 */ + U8 Reserved1; /* 0x03 */ + U32 NewValue; /* 0x04 */ + U32 PreviousValue; /* 0x08 */ +} MPI2_EVENT_DATA_IR_VOLUME, MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_VOLUME, + Mpi2EventDataIrVolume_t, MPI2_POINTER pMpi2EventDataIrVolume_t; + +/* Integrated RAID Volume Event data ReasonCode values */ +#define MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED (0x01) +#define MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED (0x02) +#define MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED (0x03) + + +/* Integrated RAID Physical Disk Event data */ + +typedef struct _MPI2_EVENT_DATA_IR_PHYSICAL_DISK +{ + U16 Reserved1; /* 0x00 */ + U8 ReasonCode; /* 0x02 */ + U8 PhysDiskNum; /* 0x03 */ + U16 PhysDiskDevHandle; /* 0x04 */ + U16 Reserved2; /* 0x06 */ + U16 Slot; /* 0x08 */ + U16 EnclosureHandle; /* 0x0A */ + U32 NewValue; /* 0x0C */ + U32 PreviousValue; /* 0x10 */ +} MPI2_EVENT_DATA_IR_PHYSICAL_DISK, + MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_PHYSICAL_DISK, + Mpi2EventDataIrPhysicalDisk_t, MPI2_POINTER pMpi2EventDataIrPhysicalDisk_t; + +/* Integrated RAID Physical Disk Event data ReasonCode values */ +#define MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED (0x01) +#define MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED (0x02) +#define MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED (0x03) + + +/* Integrated RAID Configuration Change List Event data */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumElements at runtime. + */ +#ifndef MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT +#define MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT (1) +#endif + +typedef struct _MPI2_EVENT_IR_CONFIG_ELEMENT +{ + U16 ElementFlags; /* 0x00 */ + U16 VolDevHandle; /* 0x02 */ + U8 ReasonCode; /* 0x04 */ + U8 PhysDiskNum; /* 0x05 */ + U16 PhysDiskDevHandle; /* 0x06 */ +} MPI2_EVENT_IR_CONFIG_ELEMENT, MPI2_POINTER PTR_MPI2_EVENT_IR_CONFIG_ELEMENT, + Mpi2EventIrConfigElement_t, MPI2_POINTER pMpi2EventIrConfigElement_t; + +/* IR Configuration Change List Event data ElementFlags values */ +#define MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK (0x000F) +#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT (0x0000) +#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT (0x0001) +#define MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT (0x0002) + +/* IR Configuration Change List Event data ReasonCode values */ +#define MPI2_EVENT_IR_CHANGE_RC_ADDED (0x01) +#define MPI2_EVENT_IR_CHANGE_RC_REMOVED (0x02) +#define MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE (0x03) +#define MPI2_EVENT_IR_CHANGE_RC_HIDE (0x04) +#define MPI2_EVENT_IR_CHANGE_RC_UNHIDE (0x05) +#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED (0x06) +#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED (0x07) +#define MPI2_EVENT_IR_CHANGE_RC_PD_CREATED (0x08) +#define MPI2_EVENT_IR_CHANGE_RC_PD_DELETED (0x09) + +typedef struct _MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST +{ + U8 NumElements; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 Reserved2; /* 0x02 */ + U8 ConfigNum; /* 0x03 */ + U32 Flags; /* 0x04 */ + MPI2_EVENT_IR_CONFIG_ELEMENT ConfigElement[MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT]; /* 0x08 */ +} MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, + MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, + Mpi2EventDataIrConfigChangeList_t, + MPI2_POINTER pMpi2EventDataIrConfigChangeList_t; + +/* IR Configuration Change List Event data Flags values */ +#define MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG (0x00000001) + + +/* SAS Discovery Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_DISCOVERY +{ + U8 Flags; /* 0x00 */ + U8 ReasonCode; /* 0x01 */ + U8 PhysicalPort; /* 0x02 */ + U8 Reserved1; /* 0x03 */ + U32 DiscoveryStatus; /* 0x04 */ +} MPI2_EVENT_DATA_SAS_DISCOVERY, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DISCOVERY, + Mpi2EventDataSasDiscovery_t, MPI2_POINTER pMpi2EventDataSasDiscovery_t; + +/* SAS Discovery Event data Flags values */ +#define MPI2_EVENT_SAS_DISC_DEVICE_CHANGE (0x02) +#define MPI2_EVENT_SAS_DISC_IN_PROGRESS (0x01) + +/* SAS Discovery Event data ReasonCode values */ +#define MPI2_EVENT_SAS_DISC_RC_STARTED (0x01) +#define MPI2_EVENT_SAS_DISC_RC_COMPLETED (0x02) + +/* SAS Discovery Event data DiscoveryStatus values */ +#define MPI2_EVENT_SAS_DISC_DS_MAX_ENCLOSURES_EXCEED (0x80000000) +#define MPI2_EVENT_SAS_DISC_DS_MAX_EXPANDERS_EXCEED (0x40000000) +#define MPI2_EVENT_SAS_DISC_DS_MAX_DEVICES_EXCEED (0x20000000) +#define MPI2_EVENT_SAS_DISC_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) +#define MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR (0x08000000) +#define MPI2_EVENT_SAS_DISC_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) +#define MPI2_EVENT_SAS_DISC_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) +#define MPI2_EVENT_SAS_DISC_DS_MULTI_PORT_DOMAIN (0x00002000) +#define MPI2_EVENT_SAS_DISC_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) +#define MPI2_EVENT_SAS_DISC_DS_UNSUPPORTED_DEVICE (0x00000800) +#define MPI2_EVENT_SAS_DISC_DS_TABLE_LINK (0x00000400) +#define MPI2_EVENT_SAS_DISC_DS_SUBTRACTIVE_LINK (0x00000200) +#define MPI2_EVENT_SAS_DISC_DS_SMP_CRC_ERROR (0x00000100) +#define MPI2_EVENT_SAS_DISC_DS_SMP_FUNCTION_FAILED (0x00000080) +#define MPI2_EVENT_SAS_DISC_DS_INDEX_NOT_EXIST (0x00000040) +#define MPI2_EVENT_SAS_DISC_DS_OUT_ROUTE_ENTRIES (0x00000020) +#define MPI2_EVENT_SAS_DISC_DS_SMP_TIMEOUT (0x00000010) +#define MPI2_EVENT_SAS_DISC_DS_MULTIPLE_PORTS (0x00000004) +#define MPI2_EVENT_SAS_DISC_DS_UNADDRESSABLE_DEVICE (0x00000002) +#define MPI2_EVENT_SAS_DISC_DS_LOOP_DETECTED (0x00000001) + + +/* SAS Broadcast Primitive Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE +{ + U8 PhyNum; /* 0x00 */ + U8 Port; /* 0x01 */ + U8 PortWidth; /* 0x02 */ + U8 Primitive; /* 0x03 */ +} MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, + Mpi2EventDataSasBroadcastPrimitive_t, + MPI2_POINTER pMpi2EventDataSasBroadcastPrimitive_t; + +/* defines for the Primitive field */ +#define MPI2_EVENT_PRIMITIVE_CHANGE (0x01) +#define MPI2_EVENT_PRIMITIVE_SES (0x02) +#define MPI2_EVENT_PRIMITIVE_EXPANDER (0x03) +#define MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT (0x04) +#define MPI2_EVENT_PRIMITIVE_RESERVED3 (0x05) +#define MPI2_EVENT_PRIMITIVE_RESERVED4 (0x06) +#define MPI2_EVENT_PRIMITIVE_CHANGE0_RESERVED (0x07) +#define MPI2_EVENT_PRIMITIVE_CHANGE1_RESERVED (0x08) + + +/* SAS Notify Primitive Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE +{ + U8 PhyNum; /* 0x00 */ + U8 Port; /* 0x01 */ + U8 Reserved1; /* 0x02 */ + U8 Primitive; /* 0x03 */ +} MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, + Mpi2EventDataSasNotifyPrimitive_t, + MPI2_POINTER pMpi2EventDataSasNotifyPrimitive_t; + +/* defines for the Primitive field */ +#define MPI2_EVENT_NOTIFY_ENABLE_SPINUP (0x01) +#define MPI2_EVENT_NOTIFY_POWER_LOSS_EXPECTED (0x02) +#define MPI2_EVENT_NOTIFY_RESERVED1 (0x03) +#define MPI2_EVENT_NOTIFY_RESERVED2 (0x04) + + +/* SAS Initiator Device Status Change Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE +{ + U8 ReasonCode; /* 0x00 */ + U8 PhysicalPort; /* 0x01 */ + U16 DevHandle; /* 0x02 */ + U64 SASAddress; /* 0x04 */ +} MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, + Mpi2EventDataSasInitDevStatusChange_t, + MPI2_POINTER pMpi2EventDataSasInitDevStatusChange_t; + +/* SAS Initiator Device Status Change event ReasonCode values */ +#define MPI2_EVENT_SAS_INIT_RC_ADDED (0x01) +#define MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING (0x02) + + +/* SAS Initiator Device Table Overflow Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW +{ + U16 MaxInit; /* 0x00 */ + U16 CurrentInit; /* 0x02 */ + U64 SASAddress; /* 0x04 */ +} MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, + Mpi2EventDataSasInitTableOverflow_t, + MPI2_POINTER pMpi2EventDataSasInitTableOverflow_t; + + +/* SAS Topology Change List Event data */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumEntries at runtime. + */ +#ifndef MPI2_EVENT_SAS_TOPO_PHY_COUNT +#define MPI2_EVENT_SAS_TOPO_PHY_COUNT (1) +#endif + +typedef struct _MPI2_EVENT_SAS_TOPO_PHY_ENTRY +{ + U16 AttachedDevHandle; /* 0x00 */ + U8 LinkRate; /* 0x02 */ + U8 PhyStatus; /* 0x03 */ +} MPI2_EVENT_SAS_TOPO_PHY_ENTRY, MPI2_POINTER PTR_MPI2_EVENT_SAS_TOPO_PHY_ENTRY, + Mpi2EventSasTopoPhyEntry_t, MPI2_POINTER pMpi2EventSasTopoPhyEntry_t; + +typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST +{ + U16 EnclosureHandle; /* 0x00 */ + U16 ExpanderDevHandle; /* 0x02 */ + U8 NumPhys; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U8 NumEntries; /* 0x08 */ + U8 StartPhyNum; /* 0x09 */ + U8 ExpStatus; /* 0x0A */ + U8 PhysicalPort; /* 0x0B */ + MPI2_EVENT_SAS_TOPO_PHY_ENTRY PHY[MPI2_EVENT_SAS_TOPO_PHY_COUNT]; /* 0x0C*/ +} MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, + Mpi2EventDataSasTopologyChangeList_t, + MPI2_POINTER pMpi2EventDataSasTopologyChangeList_t; + +/* values for the ExpStatus field */ +#define MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER (0x00) +#define MPI2_EVENT_SAS_TOPO_ES_ADDED (0x01) +#define MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING (0x02) +#define MPI2_EVENT_SAS_TOPO_ES_RESPONDING (0x03) +#define MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING (0x04) + +/* defines for the LinkRate field */ +#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_MASK (0xF0) +#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_SHIFT (4) +#define MPI2_EVENT_SAS_TOPO_LR_PREV_MASK (0x0F) +#define MPI2_EVENT_SAS_TOPO_LR_PREV_SHIFT (0) + +#define MPI2_EVENT_SAS_TOPO_LR_UNKNOWN_LINK_RATE (0x00) +#define MPI2_EVENT_SAS_TOPO_LR_PHY_DISABLED (0x01) +#define MPI2_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED (0x02) +#define MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE (0x03) +#define MPI2_EVENT_SAS_TOPO_LR_PORT_SELECTOR (0x04) +#define MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS (0x05) +#define MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY (0x06) +#define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5 (0x08) +#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09) +#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A) +#define MPI25_EVENT_SAS_TOPO_LR_RATE_12_0 (0x0B) + +/* values for the PhyStatus field */ +#define MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT (0x80) +#define MPI2_EVENT_SAS_TOPO_PS_MULTIPLEX_CHANGE (0x10) +/* values for the PhyStatus ReasonCode sub-field */ +#define MPI2_EVENT_SAS_TOPO_RC_MASK (0x0F) +#define MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED (0x01) +#define MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING (0x02) +#define MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED (0x03) +#define MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE (0x04) +#define MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING (0x05) + + +/* SAS Enclosure Device Status Change Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE +{ + U16 EnclosureHandle; /* 0x00 */ + U8 ReasonCode; /* 0x02 */ + U8 PhysicalPort; /* 0x03 */ + U64 EnclosureLogicalID; /* 0x04 */ + U16 NumSlots; /* 0x0C */ + U16 StartSlot; /* 0x0E */ + U32 PhyBits; /* 0x10 */ +} MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE, + Mpi2EventDataSasEnclDevStatusChange_t, + MPI2_POINTER pMpi2EventDataSasEnclDevStatusChange_t; + +/* SAS Enclosure Device Status Change event ReasonCode values */ +#define MPI2_EVENT_SAS_ENCL_RC_ADDED (0x01) +#define MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING (0x02) + + +/* SAS PHY Counter Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER +{ + U64 TimeStamp; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U8 PhyEventCode; /* 0x0C */ + U8 PhyNum; /* 0x0D */ + U16 Reserved2; /* 0x0E */ + U32 PhyEventInfo; /* 0x10 */ + U8 CounterType; /* 0x14 */ + U8 ThresholdWindow; /* 0x15 */ + U8 TimeUnits; /* 0x16 */ + U8 Reserved3; /* 0x17 */ + U32 EventThreshold; /* 0x18 */ + U16 ThresholdFlags; /* 0x1C */ + U16 Reserved4; /* 0x1E */ +} MPI2_EVENT_DATA_SAS_PHY_COUNTER, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_PHY_COUNTER, + Mpi2EventDataSasPhyCounter_t, MPI2_POINTER pMpi2EventDataSasPhyCounter_t; + +/* use MPI2_SASPHY3_EVENT_CODE_ values from mpi2_cnfg.h for the PhyEventCode field */ + +/* use MPI2_SASPHY3_COUNTER_TYPE_ values from mpi2_cnfg.h for the CounterType field */ + +/* use MPI2_SASPHY3_TIME_UNITS_ values from mpi2_cnfg.h for the TimeUnits field */ + +/* use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h for the ThresholdFlags field */ + + +/* SAS Quiesce Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE +{ + U8 ReasonCode; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 Reserved3; /* 0x04 */ +} MPI2_EVENT_DATA_SAS_QUIESCE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_QUIESCE, + Mpi2EventDataSasQuiesce_t, MPI2_POINTER pMpi2EventDataSasQuiesce_t; + +/* SAS Quiesce Event data ReasonCode values */ +#define MPI2_EVENT_SAS_QUIESCE_RC_STARTED (0x01) +#define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED (0x02) + + +/* Host Based Discovery Phy Event data */ + +typedef struct _MPI2_EVENT_HBD_PHY_SAS +{ + U8 Flags; /* 0x00 */ + U8 NegotiatedLinkRate; /* 0x01 */ + U8 PhyNum; /* 0x02 */ + U8 PhysicalPort; /* 0x03 */ + U32 Reserved1; /* 0x04 */ + U8 InitialFrame[28]; /* 0x08 */ +} MPI2_EVENT_HBD_PHY_SAS, MPI2_POINTER PTR_MPI2_EVENT_HBD_PHY_SAS, + Mpi2EventHbdPhySas_t, MPI2_POINTER pMpi2EventHbdPhySas_t; + +/* values for the Flags field */ +#define MPI2_EVENT_HBD_SAS_FLAGS_FRAME_VALID (0x02) +#define MPI2_EVENT_HBD_SAS_FLAGS_SATA_FRAME (0x01) + +/* use MPI2_SAS_NEG_LINK_RATE_ defines from mpi2_cnfg.h for the NegotiatedLinkRate field */ + +typedef union _MPI2_EVENT_HBD_DESCRIPTOR +{ + MPI2_EVENT_HBD_PHY_SAS Sas; +} MPI2_EVENT_HBD_DESCRIPTOR, MPI2_POINTER PTR_MPI2_EVENT_HBD_DESCRIPTOR, + Mpi2EventHbdDescriptor_t, MPI2_POINTER pMpi2EventHbdDescriptor_t; + +typedef struct _MPI2_EVENT_DATA_HBD_PHY +{ + U8 DescriptorType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 Reserved3; /* 0x04 */ + MPI2_EVENT_HBD_DESCRIPTOR Descriptor; /* 0x08 */ +} MPI2_EVENT_DATA_HBD_PHY, MPI2_POINTER PTR_MPI2_EVENT_DATA_HBD_PHY, + Mpi2EventDataHbdPhy_t, MPI2_POINTER pMpi2EventDataMpi2EventDataHbdPhy_t; + +/* values for the DescriptorType field */ +#define MPI2_EVENT_HBD_DT_SAS (0x01) + + + +/**************************************************************************** +* EventAck message +****************************************************************************/ + +/* EventAck Request message */ +typedef struct _MPI2_EVENT_ACK_REQUEST +{ + U16 Reserved1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Event; /* 0x0C */ + U16 Reserved5; /* 0x0E */ + U32 EventContext; /* 0x10 */ +} MPI2_EVENT_ACK_REQUEST, MPI2_POINTER PTR_MPI2_EVENT_ACK_REQUEST, + Mpi2EventAckRequest_t, MPI2_POINTER pMpi2EventAckRequest_t; + + +/* EventAck Reply message */ +typedef struct _MPI2_EVENT_ACK_REPLY +{ + U16 Reserved1; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_EVENT_ACK_REPLY, MPI2_POINTER PTR_MPI2_EVENT_ACK_REPLY, + Mpi2EventAckReply_t, MPI2_POINTER pMpi2EventAckReply_t; + + +/**************************************************************************** +* SendHostMessage message +****************************************************************************/ + +/* SendHostMessage Request message */ +typedef struct _MPI2_SEND_HOST_MESSAGE_REQUEST +{ + U16 HostDataLength; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U8 Reserved4; /* 0x0C */ + U8 DestVF_ID; /* 0x0D */ + U16 Reserved5; /* 0x0E */ + U32 Reserved6; /* 0x10 */ + U32 Reserved7; /* 0x14 */ + U32 Reserved8; /* 0x18 */ + U32 Reserved9; /* 0x1C */ + U32 Reserved10; /* 0x20 */ + U32 HostData[1]; /* 0x24 */ +} MPI2_SEND_HOST_MESSAGE_REQUEST, + MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REQUEST, + Mpi2SendHostMessageRequest_t, MPI2_POINTER pMpi2SendHostMessageRequest_t; + + +/* SendHostMessage Reply message */ +typedef struct _MPI2_SEND_HOST_MESSAGE_REPLY +{ + U16 HostDataLength; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_SEND_HOST_MESSAGE_REPLY, MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REPLY, + Mpi2SendHostMessageReply_t, MPI2_POINTER pMpi2SendHostMessageReply_t; + + +/**************************************************************************** +* FWDownload message +****************************************************************************/ + +/* MPI v2.0 FWDownload Request message */ +typedef struct _MPI2_FW_DOWNLOAD_REQUEST +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 TotalImageSize; /* 0x0C */ + U32 Reserved5; /* 0x10 */ + MPI2_MPI_SGE_UNION SGL; /* 0x14 */ +} MPI2_FW_DOWNLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REQUEST, + Mpi2FWDownloadRequest, MPI2_POINTER pMpi2FWDownloadRequest; + +#define MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT (0x01) + +#define MPI2_FW_DOWNLOAD_ITYPE_FW (0x01) +#define MPI2_FW_DOWNLOAD_ITYPE_BIOS (0x02) +#define MPI2_FW_DOWNLOAD_ITYPE_MANUFACTURING (0x06) +#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07) +#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08) +#define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID (0x09) +#define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE (0x0A) +#define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) +#define MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY (0x0C) /* MPI v2.5 and newer */ +#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0) + +/* MPI v2.0 FWDownload TransactionContext Element */ +typedef struct _MPI2_FW_DOWNLOAD_TCSGE +{ + U8 Reserved1; /* 0x00 */ + U8 ContextSize; /* 0x01 */ + U8 DetailsLength; /* 0x02 */ + U8 Flags; /* 0x03 */ + U32 Reserved2; /* 0x04 */ + U32 ImageOffset; /* 0x08 */ + U32 ImageSize; /* 0x0C */ +} MPI2_FW_DOWNLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_TCSGE, + Mpi2FWDownloadTCSGE_t, MPI2_POINTER pMpi2FWDownloadTCSGE_t; + + +/* MPI v2.5 FWDownload Request message */ +typedef struct _MPI25_FW_DOWNLOAD_REQUEST +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 TotalImageSize; /* 0x0C */ + U32 Reserved5; /* 0x10 */ + U32 Reserved6; /* 0x14 */ + U32 ImageOffset; /* 0x18 */ + U32 ImageSize; /* 0x1C */ + MPI25_SGE_IO_UNION SGL; /* 0x20 */ +} MPI25_FW_DOWNLOAD_REQUEST, MPI2_POINTER PTR_MPI25_FW_DOWNLOAD_REQUEST, + Mpi25FWDownloadRequest, MPI2_POINTER pMpi25FWDownloadRequest; + + +/* FWDownload Reply message */ +typedef struct _MPI2_FW_DOWNLOAD_REPLY +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_FW_DOWNLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REPLY, + Mpi2FWDownloadReply_t, MPI2_POINTER pMpi2FWDownloadReply_t; + + +/**************************************************************************** +* FWUpload message +****************************************************************************/ + +/* MPI v2.0 FWUpload Request message */ +typedef struct _MPI2_FW_UPLOAD_REQUEST +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 Reserved5; /* 0x0C */ + U32 Reserved6; /* 0x10 */ + MPI2_MPI_SGE_UNION SGL; /* 0x14 */ +} MPI2_FW_UPLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REQUEST, + Mpi2FWUploadRequest_t, MPI2_POINTER pMpi2FWUploadRequest_t; + +#define MPI2_FW_UPLOAD_ITYPE_FW_CURRENT (0x00) +#define MPI2_FW_UPLOAD_ITYPE_FW_FLASH (0x01) +#define MPI2_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02) +#define MPI2_FW_UPLOAD_ITYPE_FW_BACKUP (0x05) +#define MPI2_FW_UPLOAD_ITYPE_MANUFACTURING (0x06) +#define MPI2_FW_UPLOAD_ITYPE_CONFIG_1 (0x07) +#define MPI2_FW_UPLOAD_ITYPE_CONFIG_2 (0x08) +#define MPI2_FW_UPLOAD_ITYPE_MEGARAID (0x09) +#define MPI2_FW_UPLOAD_ITYPE_COMPLETE (0x0A) +#define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) + +/* MPI v2.0 FWUpload TransactionContext Element */ +typedef struct _MPI2_FW_UPLOAD_TCSGE +{ + U8 Reserved1; /* 0x00 */ + U8 ContextSize; /* 0x01 */ + U8 DetailsLength; /* 0x02 */ + U8 Flags; /* 0x03 */ + U32 Reserved2; /* 0x04 */ + U32 ImageOffset; /* 0x08 */ + U32 ImageSize; /* 0x0C */ +} MPI2_FW_UPLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_UPLOAD_TCSGE, + Mpi2FWUploadTCSGE_t, MPI2_POINTER pMpi2FWUploadTCSGE_t; + + +/* MPI v2.5 FWUpload Request message */ +typedef struct _MPI25_FW_UPLOAD_REQUEST +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 Reserved5; /* 0x0C */ + U32 Reserved6; /* 0x10 */ + U32 Reserved7; /* 0x14 */ + U32 ImageOffset; /* 0x18 */ + U32 ImageSize; /* 0x1C */ + MPI25_SGE_IO_UNION SGL; /* 0x20 */ +} MPI25_FW_UPLOAD_REQUEST, MPI2_POINTER PTR_MPI25_FW_UPLOAD_REQUEST, + Mpi25FWUploadRequest_t, MPI2_POINTER pMpi25FWUploadRequest_t; + + +/* FWUpload Reply message */ +typedef struct _MPI2_FW_UPLOAD_REPLY +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 ActualImageSize; /* 0x14 */ +} MPI2_FW_UPLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REPLY, + Mpi2FWUploadReply_t, MPI2_POINTER pMPi2FWUploadReply_t; + + +/* FW Image Header */ +typedef struct _MPI2_FW_IMAGE_HEADER +{ + U32 Signature; /* 0x00 */ + U32 Signature0; /* 0x04 */ + U32 Signature1; /* 0x08 */ + U32 Signature2; /* 0x0C */ + MPI2_VERSION_UNION MPIVersion; /* 0x10 */ + MPI2_VERSION_UNION FWVersion; /* 0x14 */ + MPI2_VERSION_UNION NVDATAVersion; /* 0x18 */ + MPI2_VERSION_UNION PackageVersion; /* 0x1C */ + U16 VendorID; /* 0x20 */ + U16 ProductID; /* 0x22 */ + U16 ProtocolFlags; /* 0x24 */ + U16 Reserved26; /* 0x26 */ + U32 IOCCapabilities; /* 0x28 */ + U32 ImageSize; /* 0x2C */ + U32 NextImageHeaderOffset; /* 0x30 */ + U32 Checksum; /* 0x34 */ + U32 Reserved38; /* 0x38 */ + U32 Reserved3C; /* 0x3C */ + U32 Reserved40; /* 0x40 */ + U32 Reserved44; /* 0x44 */ + U32 Reserved48; /* 0x48 */ + U32 Reserved4C; /* 0x4C */ + U32 Reserved50; /* 0x50 */ + U32 Reserved54; /* 0x54 */ + U32 Reserved58; /* 0x58 */ + U32 Reserved5C; /* 0x5C */ + U32 Reserved60; /* 0x60 */ + U32 FirmwareVersionNameWhat; /* 0x64 */ + U8 FirmwareVersionName[32]; /* 0x68 */ + U32 VendorNameWhat; /* 0x88 */ + U8 VendorName[32]; /* 0x8C */ + U32 PackageNameWhat; /* 0x88 */ + U8 PackageName[32]; /* 0x8C */ + U32 ReservedD0; /* 0xD0 */ + U32 ReservedD4; /* 0xD4 */ + U32 ReservedD8; /* 0xD8 */ + U32 ReservedDC; /* 0xDC */ + U32 ReservedE0; /* 0xE0 */ + U32 ReservedE4; /* 0xE4 */ + U32 ReservedE8; /* 0xE8 */ + U32 ReservedEC; /* 0xEC */ + U32 ReservedF0; /* 0xF0 */ + U32 ReservedF4; /* 0xF4 */ + U32 ReservedF8; /* 0xF8 */ + U32 ReservedFC; /* 0xFC */ +} MPI2_FW_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_FW_IMAGE_HEADER, + Mpi2FWImageHeader_t, MPI2_POINTER pMpi2FWImageHeader_t; + +/* Signature field */ +#define MPI2_FW_HEADER_SIGNATURE_OFFSET (0x00) +#define MPI2_FW_HEADER_SIGNATURE_MASK (0xFF000000) +#define MPI2_FW_HEADER_SIGNATURE (0xEA000000) + +/* Signature0 field */ +#define MPI2_FW_HEADER_SIGNATURE0_OFFSET (0x04) +#define MPI2_FW_HEADER_SIGNATURE0 (0x5AFAA55A) + +/* Signature1 field */ +#define MPI2_FW_HEADER_SIGNATURE1_OFFSET (0x08) +#define MPI2_FW_HEADER_SIGNATURE1 (0xA55AFAA5) + +/* Signature2 field */ +#define MPI2_FW_HEADER_SIGNATURE2_OFFSET (0x0C) +#define MPI2_FW_HEADER_SIGNATURE2 (0x5AA55AFA) + + +/* defines for using the ProductID field */ +#define MPI2_FW_HEADER_PID_TYPE_MASK (0xF000) +#define MPI2_FW_HEADER_PID_TYPE_SAS (0x2000) + +#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) +#define MPI2_FW_HEADER_PID_PROD_A (0x0000) +#define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200) +#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700) + + +#define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF) +/* SAS ProductID Family bits */ +#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0013) +#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0014) +#define MPI25_FW_HEADER_PID_FAMILY_3108_SAS (0x0021) + +/* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */ + +/* use MPI2_IOCFACTS_CAPABILITY_ defines for IOCCapabilities field */ + + +#define MPI2_FW_HEADER_IMAGESIZE_OFFSET (0x2C) +#define MPI2_FW_HEADER_NEXTIMAGE_OFFSET (0x30) +#define MPI2_FW_HEADER_VERNMHWAT_OFFSET (0x64) + +#define MPI2_FW_HEADER_WHAT_SIGNATURE (0x29232840) + +#define MPI2_FW_HEADER_SIZE (0x100) + + +/* Extended Image Header */ +typedef struct _MPI2_EXT_IMAGE_HEADER + +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 Checksum; /* 0x04 */ + U32 ImageSize; /* 0x08 */ + U32 NextImageHeaderOffset; /* 0x0C */ + U32 PackageVersion; /* 0x10 */ + U32 Reserved3; /* 0x14 */ + U32 Reserved4; /* 0x18 */ + U32 Reserved5; /* 0x1C */ + U8 IdentifyString[32]; /* 0x20 */ +} MPI2_EXT_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_EXT_IMAGE_HEADER, + Mpi2ExtImageHeader_t, MPI2_POINTER pMpi2ExtImageHeader_t; + +/* useful offsets */ +#define MPI2_EXT_IMAGE_IMAGETYPE_OFFSET (0x00) +#define MPI2_EXT_IMAGE_IMAGESIZE_OFFSET (0x08) +#define MPI2_EXT_IMAGE_NEXTIMAGE_OFFSET (0x0C) + +#define MPI2_EXT_IMAGE_HEADER_SIZE (0x40) + +/* defines for the ImageType field */ +#define MPI2_EXT_IMAGE_TYPE_UNSPECIFIED (0x00) +#define MPI2_EXT_IMAGE_TYPE_FW (0x01) +#define MPI2_EXT_IMAGE_TYPE_NVDATA (0x03) +#define MPI2_EXT_IMAGE_TYPE_BOOTLOADER (0x04) +#define MPI2_EXT_IMAGE_TYPE_INITIALIZATION (0x05) +#define MPI2_EXT_IMAGE_TYPE_FLASH_LAYOUT (0x06) +#define MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES (0x07) +#define MPI2_EXT_IMAGE_TYPE_MEGARAID (0x08) +#define MPI2_EXT_IMAGE_TYPE_ENCRYPTED_HASH (0x09) /* MPI v2.5 and newer */ +#define MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC (0x80) +#define MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC (0xFF) + +#define MPI2_EXT_IMAGE_TYPE_MAX (MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC) /* deprecated */ + + + +/* FLASH Layout Extended Image Data */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check RegionsPerLayout at runtime. + */ +#ifndef MPI2_FLASH_NUMBER_OF_REGIONS +#define MPI2_FLASH_NUMBER_OF_REGIONS (1) +#endif + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumberOfLayouts at runtime. + */ +#ifndef MPI2_FLASH_NUMBER_OF_LAYOUTS +#define MPI2_FLASH_NUMBER_OF_LAYOUTS (1) +#endif + +typedef struct _MPI2_FLASH_REGION +{ + U8 RegionType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 RegionOffset; /* 0x04 */ + U32 RegionSize; /* 0x08 */ + U32 Reserved3; /* 0x0C */ +} MPI2_FLASH_REGION, MPI2_POINTER PTR_MPI2_FLASH_REGION, + Mpi2FlashRegion_t, MPI2_POINTER pMpi2FlashRegion_t; + +typedef struct _MPI2_FLASH_LAYOUT +{ + U32 FlashSize; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Reserved2; /* 0x08 */ + U32 Reserved3; /* 0x0C */ + MPI2_FLASH_REGION Region[MPI2_FLASH_NUMBER_OF_REGIONS];/* 0x10 */ +} MPI2_FLASH_LAYOUT, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT, + Mpi2FlashLayout_t, MPI2_POINTER pMpi2FlashLayout_t; + +typedef struct _MPI2_FLASH_LAYOUT_DATA +{ + U8 ImageRevision; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 SizeOfRegion; /* 0x02 */ + U8 Reserved2; /* 0x03 */ + U16 NumberOfLayouts; /* 0x04 */ + U16 RegionsPerLayout; /* 0x06 */ + U16 MinimumSectorAlignment; /* 0x08 */ + U16 Reserved3; /* 0x0A */ + U32 Reserved4; /* 0x0C */ + MPI2_FLASH_LAYOUT Layout[MPI2_FLASH_NUMBER_OF_LAYOUTS];/* 0x10 */ +} MPI2_FLASH_LAYOUT_DATA, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT_DATA, + Mpi2FlashLayoutData_t, MPI2_POINTER pMpi2FlashLayoutData_t; + +/* defines for the RegionType field */ +#define MPI2_FLASH_REGION_UNUSED (0x00) +#define MPI2_FLASH_REGION_FIRMWARE (0x01) +#define MPI2_FLASH_REGION_BIOS (0x02) +#define MPI2_FLASH_REGION_NVDATA (0x03) +#define MPI2_FLASH_REGION_FIRMWARE_BACKUP (0x05) +#define MPI2_FLASH_REGION_MFG_INFORMATION (0x06) +#define MPI2_FLASH_REGION_CONFIG_1 (0x07) +#define MPI2_FLASH_REGION_CONFIG_2 (0x08) +#define MPI2_FLASH_REGION_MEGARAID (0x09) +#define MPI2_FLASH_REGION_INIT (0x0A) + +/* ImageRevision */ +#define MPI2_FLASH_LAYOUT_IMAGE_REVISION (0x00) + + + +/* Supported Devices Extended Image Data */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumberOfDevices at runtime. + */ +#ifndef MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES +#define MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES (1) +#endif + +typedef struct _MPI2_SUPPORTED_DEVICE +{ + U16 DeviceID; /* 0x00 */ + U16 VendorID; /* 0x02 */ + U16 DeviceIDMask; /* 0x04 */ + U16 Reserved1; /* 0x06 */ + U8 LowPCIRev; /* 0x08 */ + U8 HighPCIRev; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 Reserved3; /* 0x0C */ +} MPI2_SUPPORTED_DEVICE, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICE, + Mpi2SupportedDevice_t, MPI2_POINTER pMpi2SupportedDevice_t; + +typedef struct _MPI2_SUPPORTED_DEVICES_DATA +{ + U8 ImageRevision; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 NumberOfDevices; /* 0x02 */ + U8 Reserved2; /* 0x03 */ + U32 Reserved3; /* 0x04 */ + MPI2_SUPPORTED_DEVICE SupportedDevice[MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES]; /* 0x08 */ +} MPI2_SUPPORTED_DEVICES_DATA, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICES_DATA, + Mpi2SupportedDevicesData_t, MPI2_POINTER pMpi2SupportedDevicesData_t; + +/* ImageRevision */ +#define MPI2_SUPPORTED_DEVICES_IMAGE_REVISION (0x00) + + +/* Init Extended Image Data */ + +typedef struct _MPI2_INIT_IMAGE_FOOTER + +{ + U32 BootFlags; /* 0x00 */ + U32 ImageSize; /* 0x04 */ + U32 Signature0; /* 0x08 */ + U32 Signature1; /* 0x0C */ + U32 Signature2; /* 0x10 */ + U32 ResetVector; /* 0x14 */ +} MPI2_INIT_IMAGE_FOOTER, MPI2_POINTER PTR_MPI2_INIT_IMAGE_FOOTER, + Mpi2InitImageFooter_t, MPI2_POINTER pMpi2InitImageFooter_t; + +/* defines for the BootFlags field */ +#define MPI2_INIT_IMAGE_BOOTFLAGS_OFFSET (0x00) + +/* defines for the ImageSize field */ +#define MPI2_INIT_IMAGE_IMAGESIZE_OFFSET (0x04) + +/* defines for the Signature0 field */ +#define MPI2_INIT_IMAGE_SIGNATURE0_OFFSET (0x08) +#define MPI2_INIT_IMAGE_SIGNATURE0 (0x5AA55AEA) + +/* defines for the Signature1 field */ +#define MPI2_INIT_IMAGE_SIGNATURE1_OFFSET (0x0C) +#define MPI2_INIT_IMAGE_SIGNATURE1 (0xA55AEAA5) + +/* defines for the Signature2 field */ +#define MPI2_INIT_IMAGE_SIGNATURE2_OFFSET (0x10) +#define MPI2_INIT_IMAGE_SIGNATURE2 (0x5AEAA55A) + +/* Signature fields as individual bytes */ +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_0 (0xEA) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_1 (0x5A) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_2 (0xA5) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_3 (0x5A) + +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_4 (0xA5) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_5 (0xEA) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_6 (0x5A) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_7 (0xA5) + +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_8 (0x5A) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_9 (0xA5) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_A (0xEA) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_B (0x5A) + +/* defines for the ResetVector field */ +#define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET (0x14) + + +/* Encrypted Hash Extended Image Data */ + +typedef struct _MPI25_ENCRYPTED_HASH_ENTRY +{ + U8 HashImageType; /* 0x00 */ + U8 HashAlgorithm; /* 0x01 */ + U8 EncryptionAlgorithm; /* 0x02 */ + U8 Reserved1; /* 0x03 */ + U32 Reserved2; /* 0x04 */ + U32 EncryptedHash[1]; /* 0x08 */ /* variable length */ +} MPI25_ENCRYPTED_HASH_ENTRY, MPI2_POINTER PTR_MPI25_ENCRYPTED_HASH_ENTRY, + Mpi25EncryptedHashEntry_t, MPI2_POINTER pMpi25EncryptedHashEntry_t; + +/* values for HashImageType */ +#define MPI25_HASH_IMAGE_TYPE_UNUSED (0x00) +#define MPI25_HASH_IMAGE_TYPE_FIRMWARE (0x01) +#define MPI25_HASH_IMAGE_TYPE_BIOS (0x02) + +/* values for HashAlgorithm */ +#define MPI25_HASH_ALGORITHM_UNUSED (0x00) +#define MPI25_HASH_ALGORITHM_SHA256 (0x01) + +/* values for EncryptionAlgorithm */ +#define MPI25_ENCRYPTION_ALG_UNUSED (0x00) +#define MPI25_ENCRYPTION_ALG_RSA256 (0x01) + +typedef struct _MPI25_ENCRYPTED_HASH_DATA +{ + U8 ImageVersion; /* 0x00 */ + U8 NumHash; /* 0x01 */ + U16 Reserved1; /* 0x02 */ + U32 Reserved2; /* 0x04 */ + MPI25_ENCRYPTED_HASH_ENTRY EncryptedHashEntry[1]; /* 0x08 */ /* variable number of entries */ +} MPI25_ENCRYPTED_HASH_DATA, MPI2_POINTER PTR_MPI25_ENCRYPTED_HASH_DATA, + Mpi25EncryptedHashData_t, MPI2_POINTER pMpi25EncryptedHashData_t; + +/**************************************************************************** +* PowerManagementControl message +****************************************************************************/ + +/* PowerManagementControl Request message */ +typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST +{ + U8 Feature; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U8 Parameter1; /* 0x0C */ + U8 Parameter2; /* 0x0D */ + U8 Parameter3; /* 0x0E */ + U8 Parameter4; /* 0x0F */ + U32 Reserved5; /* 0x10 */ + U32 Reserved6; /* 0x14 */ +} MPI2_PWR_MGMT_CONTROL_REQUEST, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REQUEST, + Mpi2PwrMgmtControlRequest_t, MPI2_POINTER pMpi2PwrMgmtControlRequest_t; + +/* defines for the Feature field */ +#define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND (0x01) +#define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION (0x02) +#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK (0x03) /* obsolete */ +#define MPI2_PM_CONTROL_FEATURE_IOC_SPEED (0x04) +#define MPI2_PM_CONTROL_FEATURE_GLOBAL_PWR_MGMT_MODE (0x05) /* reserved in MPI 2.0 */ +#define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC (0x80) +#define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC (0xFF) + +/* parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */ +/* Parameter1 contains a PHY number */ +/* Parameter2 indicates power condition action using these defines */ +#define MPI2_PM_CONTROL_PARAM2_PARTIAL (0x01) +#define MPI2_PM_CONTROL_PARAM2_SLUMBER (0x02) +#define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT (0x03) +/* Parameter3 and Parameter4 are reserved */ + +/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION Feature */ +/* Parameter1 contains SAS port width modulation group number */ +/* Parameter2 indicates IOC action using these defines */ +#define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP (0x01) +#define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION (0x02) +#define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP (0x03) +/* Parameter3 indicates desired modulation level using these defines */ +#define MPI2_PM_CONTROL_PARAM3_25_PERCENT (0x00) +#define MPI2_PM_CONTROL_PARAM3_50_PERCENT (0x01) +#define MPI2_PM_CONTROL_PARAM3_75_PERCENT (0x02) +#define MPI2_PM_CONTROL_PARAM3_100_PERCENT (0x03) +/* Parameter4 is reserved */ + +/* this next set (_PCIE_LINK) is obsolete */ +/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */ +/* Parameter1 indicates desired PCIe link speed using these defines */ +#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS (0x00) /* obsolete */ +#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01) /* obsolete */ +#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02) /* obsolete */ +/* Parameter2 indicates desired PCIe link width using these defines */ +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01) /* obsolete */ +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02) /* obsolete */ +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04) /* obsolete */ +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08) /* obsolete */ +/* Parameter3 and Parameter4 are reserved */ + +/* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */ +/* Parameter1 indicates desired IOC hardware clock speed using these defines */ +#define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED (0x01) +#define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED (0x02) +#define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED (0x04) +#define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED (0x08) +/* Parameter2, Parameter3, and Parameter4 are reserved */ + +/* parameter usage for the MPI2_PM_CONTROL_FEATURE_GLOBAL_PWR_MGMT_MODE Feature */ +/* Parameter1 indicates host action regarding global power management mode */ +#define MPI2_PM_CONTROL_PARAM1_TAKE_CONTROL (0x01) +#define MPI2_PM_CONTROL_PARAM1_CHANGE_GLOBAL_MODE (0x02) +#define MPI2_PM_CONTROL_PARAM1_RELEASE_CONTROL (0x03) +/* Parameter2 indicates the requested global power management mode */ +#define MPI2_PM_CONTROL_PARAM2_FULL_PWR_PERF (0x01) +#define MPI2_PM_CONTROL_PARAM2_REDUCED_PWR_PERF (0x08) +#define MPI2_PM_CONTROL_PARAM2_STANDBY (0x40) +/* Parameter3 and Parameter4 are reserved */ + + +/* PowerManagementControl Reply message */ +typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY +{ + U8 Feature; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_PWR_MGMT_CONTROL_REPLY, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REPLY, + Mpi2PwrMgmtControlReply_t, MPI2_POINTER pMpi2PwrMgmtControlReply_t; + + +#endif + diff --git a/sys/dev/mpr/mpi/mpi2_ra.h b/sys/dev/mpr/mpi/mpi2_ra.h new file mode 100644 index 0000000000000..76db06b71b98f --- /dev/null +++ b/sys/dev/mpr/mpi/mpi2_ra.h @@ -0,0 +1,118 @@ +/*- + * Copyright (c) 2013 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + +/* + * Copyright (c) 2009 LSI Corporation. + * + * + * Name: mpi2_ra.h + * Title: MPI RAID Accelerator messages and structures + * Creation Date: April 13, 2009 + * + * mpi2_ra.h Version: 02.00.00 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-06-09 02.00.00 Initial version. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_RA_H +#define MPI2_RA_H + +/* generic structure for RAID Accelerator Control Block */ +typedef struct _MPI2_RAID_ACCELERATOR_CONTROL_BLOCK +{ + U32 Reserved[8]; /* 0x00 */ + U32 RaidAcceleratorCDB[1]; /* 0x20 */ +} MPI2_RAID_ACCELERATOR_CONTROL_BLOCK, + MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_CONTROL_BLOCK, + Mpi2RAIDAcceleratorControlBlock_t, + MPI2_POINTER pMpi2RAIDAcceleratorControlBlock_t; + + +/****************************************************************************** +* +* RAID Accelerator Messages +* +*******************************************************************************/ + +/* RAID Accelerator Request Message */ +typedef struct _MPI2_RAID_ACCELERATOR_REQUEST +{ + U16 Reserved0; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U64 RaidAcceleratorControlBlockAddress; /* 0x0C */ + U8 DmaEngineNumber; /* 0x14 */ + U8 Reserved4; /* 0x15 */ + U16 Reserved5; /* 0x16 */ + U32 Reserved6; /* 0x18 */ + U32 Reserved7; /* 0x1C */ + U32 Reserved8; /* 0x20 */ +} MPI2_RAID_ACCELERATOR_REQUEST, MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_REQUEST, + Mpi2RAIDAcceleratorRequest_t, MPI2_POINTER pMpi2RAIDAcceleratorRequest_t; + + +/* RAID Accelerator Error Reply Message */ +typedef struct _MPI2_RAID_ACCELERATOR_REPLY +{ + U16 Reserved0; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 ProductSpecificData[3]; /* 0x14 */ +} MPI2_RAID_ACCELERATOR_REPLY, MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_REPLY, + Mpi2RAIDAcceleratorReply_t, MPI2_POINTER pMpi2RAIDAcceleratorReply_t; + + +#endif + + diff --git a/sys/dev/mpr/mpi/mpi2_raid.h b/sys/dev/mpr/mpi/mpi2_raid.h new file mode 100644 index 0000000000000..c6bb59864a3c9 --- /dev/null +++ b/sys/dev/mpr/mpi/mpi2_raid.h @@ -0,0 +1,406 @@ +/*- + * Copyright (c) 2013 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + +/* + * Copyright (c) 2000-2013 LSI Corporation. + * + * + * Name: mpi2_raid.h + * Title: MPI Integrated RAID messages and structures + * Creation Date: April 26, 2007 + * + * mpi2_raid.h Version: 02.00.10 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 08-31-07 02.00.01 Modifications to RAID Action request and reply, + * including the Actions and ActionData. + * 02-29-08 02.00.02 Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD. + * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that + * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT + * can be sized by the build environment. + * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of + * VolumeCreationFlags and marked the old one as obsolete. + * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define. + * 08-24-10 02.00.06 Added MPI2_RAID_ACTION_COMPATIBILITY_CHECK along with + * related structures and defines. + * Added product-specific range to RAID Action values. + * 11-18-11 02.00.07 Incorporating additions for MPI v2.5. + * 02-06-12 02.00.08 Added MPI2_RAID_ACTION_PHYSDISK_HIDDEN. + * 07-26-12 02.00.09 Added ElapsedSeconds field to MPI2_RAID_VOL_INDICATOR. + * Added MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID define. + * 04-17-13 02.00.10 Added MPI25_RAID_ACTION_ADATA_ALLOW_PI. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_RAID_H +#define MPI2_RAID_H + +/***************************************************************************** +* +* Integrated RAID Messages +* +*****************************************************************************/ + +/**************************************************************************** +* RAID Action messages +****************************************************************************/ + +/* ActionDataWord defines for use with MPI2_RAID_ACTION_CREATE_VOLUME action */ +#define MPI25_RAID_ACTION_ADATA_ALLOW_PI (0x80000000) + +/* ActionDataWord defines for use with MPI2_RAID_ACTION_DELETE_VOLUME action */ +#define MPI2_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000) +#define MPI2_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000001) + +/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */ + +/* ActionDataWord defines for use with MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES action */ +#define MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD (0x00000001) + +/* ActionDataWord for MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE Action */ +typedef struct _MPI2_RAID_ACTION_RATE_DATA +{ + U8 RateToChange; /* 0x00 */ + U8 RateOrMode; /* 0x01 */ + U16 DataScrubDuration; /* 0x02 */ +} MPI2_RAID_ACTION_RATE_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_RATE_DATA, + Mpi2RaidActionRateData_t, MPI2_POINTER pMpi2RaidActionRateData_t; + +#define MPI2_RAID_ACTION_SET_RATE_RESYNC (0x00) +#define MPI2_RAID_ACTION_SET_RATE_DATA_SCRUB (0x01) +#define MPI2_RAID_ACTION_SET_RATE_POWERSAVE_MODE (0x02) + +/* ActionDataWord for MPI2_RAID_ACTION_START_RAID_FUNCTION Action */ +typedef struct _MPI2_RAID_ACTION_START_RAID_FUNCTION +{ + U8 RAIDFunction; /* 0x00 */ + U8 Flags; /* 0x01 */ + U16 Reserved1; /* 0x02 */ +} MPI2_RAID_ACTION_START_RAID_FUNCTION, + MPI2_POINTER PTR_MPI2_RAID_ACTION_START_RAID_FUNCTION, + Mpi2RaidActionStartRaidFunction_t, + MPI2_POINTER pMpi2RaidActionStartRaidFunction_t; + +/* defines for the RAIDFunction field */ +#define MPI2_RAID_ACTION_START_BACKGROUND_INIT (0x00) +#define MPI2_RAID_ACTION_START_ONLINE_CAP_EXPANSION (0x01) +#define MPI2_RAID_ACTION_START_CONSISTENCY_CHECK (0x02) + +/* defines for the Flags field */ +#define MPI2_RAID_ACTION_START_NEW (0x00) +#define MPI2_RAID_ACTION_START_RESUME (0x01) + +/* ActionDataWord for MPI2_RAID_ACTION_STOP_RAID_FUNCTION Action */ +typedef struct _MPI2_RAID_ACTION_STOP_RAID_FUNCTION +{ + U8 RAIDFunction; /* 0x00 */ + U8 Flags; /* 0x01 */ + U16 Reserved1; /* 0x02 */ +} MPI2_RAID_ACTION_STOP_RAID_FUNCTION, + MPI2_POINTER PTR_MPI2_RAID_ACTION_STOP_RAID_FUNCTION, + Mpi2RaidActionStopRaidFunction_t, + MPI2_POINTER pMpi2RaidActionStopRaidFunction_t; + +/* defines for the RAIDFunction field */ +#define MPI2_RAID_ACTION_STOP_BACKGROUND_INIT (0x00) +#define MPI2_RAID_ACTION_STOP_ONLINE_CAP_EXPANSION (0x01) +#define MPI2_RAID_ACTION_STOP_CONSISTENCY_CHECK (0x02) + +/* defines for the Flags field */ +#define MPI2_RAID_ACTION_STOP_ABORT (0x00) +#define MPI2_RAID_ACTION_STOP_PAUSE (0x01) + +/* ActionDataWord for MPI2_RAID_ACTION_CREATE_HOT_SPARE Action */ +typedef struct _MPI2_RAID_ACTION_HOT_SPARE +{ + U8 HotSparePool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 DevHandle; /* 0x02 */ +} MPI2_RAID_ACTION_HOT_SPARE, MPI2_POINTER PTR_MPI2_RAID_ACTION_HOT_SPARE, + Mpi2RaidActionHotSpare_t, MPI2_POINTER pMpi2RaidActionHotSpare_t; + +/* ActionDataWord for MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE Action */ +typedef struct _MPI2_RAID_ACTION_FW_UPDATE_MODE +{ + U8 Flags; /* 0x00 */ + U8 DeviceFirmwareUpdateModeTimeout; /* 0x01 */ + U16 Reserved1; /* 0x02 */ +} MPI2_RAID_ACTION_FW_UPDATE_MODE, + MPI2_POINTER PTR_MPI2_RAID_ACTION_FW_UPDATE_MODE, + Mpi2RaidActionFwUpdateMode_t, MPI2_POINTER pMpi2RaidActionFwUpdateMode_t; + +/* ActionDataWord defines for use with MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE action */ +#define MPI2_RAID_ACTION_ADATA_DISABLE_FW_UPDATE (0x00) +#define MPI2_RAID_ACTION_ADATA_ENABLE_FW_UPDATE (0x01) + +typedef union _MPI2_RAID_ACTION_DATA +{ + U32 Word; + MPI2_RAID_ACTION_RATE_DATA Rates; + MPI2_RAID_ACTION_START_RAID_FUNCTION StartRaidFunction; + MPI2_RAID_ACTION_STOP_RAID_FUNCTION StopRaidFunction; + MPI2_RAID_ACTION_HOT_SPARE HotSpare; + MPI2_RAID_ACTION_FW_UPDATE_MODE FwUpdateMode; +} MPI2_RAID_ACTION_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_DATA, + Mpi2RaidActionData_t, MPI2_POINTER pMpi2RaidActionData_t; + + +/* RAID Action Request Message */ +typedef struct _MPI2_RAID_ACTION_REQUEST +{ + U8 Action; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 VolDevHandle; /* 0x04 */ + U8 PhysDiskNum; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 Reserved3; /* 0x0C */ + MPI2_RAID_ACTION_DATA ActionDataWord; /* 0x10 */ + MPI2_SGE_SIMPLE_UNION ActionDataSGE; /* 0x14 */ +} MPI2_RAID_ACTION_REQUEST, MPI2_POINTER PTR_MPI2_RAID_ACTION_REQUEST, + Mpi2RaidActionRequest_t, MPI2_POINTER pMpi2RaidActionRequest_t; + +/* RAID Action request Action values */ + +#define MPI2_RAID_ACTION_INDICATOR_STRUCT (0x01) +#define MPI2_RAID_ACTION_CREATE_VOLUME (0x02) +#define MPI2_RAID_ACTION_DELETE_VOLUME (0x03) +#define MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES (0x04) +#define MPI2_RAID_ACTION_ENABLE_ALL_VOLUMES (0x05) +#define MPI2_RAID_ACTION_PHYSDISK_OFFLINE (0x0A) +#define MPI2_RAID_ACTION_PHYSDISK_ONLINE (0x0B) +#define MPI2_RAID_ACTION_FAIL_PHYSDISK (0x0F) +#define MPI2_RAID_ACTION_ACTIVATE_VOLUME (0x11) +#define MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15) +#define MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE (0x17) +#define MPI2_RAID_ACTION_SET_VOLUME_NAME (0x18) +#define MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE (0x19) +#define MPI2_RAID_ACTION_ENABLE_FAILED_VOLUME (0x1C) +#define MPI2_RAID_ACTION_CREATE_HOT_SPARE (0x1D) +#define MPI2_RAID_ACTION_DELETE_HOT_SPARE (0x1E) +#define MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED (0x20) +#define MPI2_RAID_ACTION_START_RAID_FUNCTION (0x21) +#define MPI2_RAID_ACTION_STOP_RAID_FUNCTION (0x22) +#define MPI2_RAID_ACTION_COMPATIBILITY_CHECK (0x23) +#define MPI2_RAID_ACTION_PHYSDISK_HIDDEN (0x24) +#define MPI2_RAID_ACTION_MIN_PRODUCT_SPECIFIC (0x80) +#define MPI2_RAID_ACTION_MAX_PRODUCT_SPECIFIC (0xFF) + + +/* RAID Volume Creation Structure */ + +/* + * The following define can be customized for the targeted product. + */ +#ifndef MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS +#define MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS (1) +#endif + +typedef struct _MPI2_RAID_VOLUME_PHYSDISK +{ + U8 RAIDSetNum; /* 0x00 */ + U8 PhysDiskMap; /* 0x01 */ + U16 PhysDiskDevHandle; /* 0x02 */ +} MPI2_RAID_VOLUME_PHYSDISK, MPI2_POINTER PTR_MPI2_RAID_VOLUME_PHYSDISK, + Mpi2RaidVolumePhysDisk_t, MPI2_POINTER pMpi2RaidVolumePhysDisk_t; + +/* defines for the PhysDiskMap field */ +#define MPI2_RAIDACTION_PHYSDISK_PRIMARY (0x01) +#define MPI2_RAIDACTION_PHYSDISK_SECONDARY (0x02) + +typedef struct _MPI2_RAID_VOLUME_CREATION_STRUCT +{ + U8 NumPhysDisks; /* 0x00 */ + U8 VolumeType; /* 0x01 */ + U16 Reserved1; /* 0x02 */ + U32 VolumeCreationFlags; /* 0x04 */ + U32 VolumeSettings; /* 0x08 */ + U8 Reserved2; /* 0x0C */ + U8 ResyncRate; /* 0x0D */ + U16 DataScrubDuration; /* 0x0E */ + U64 VolumeMaxLBA; /* 0x10 */ + U32 StripeSize; /* 0x18 */ + U8 Name[16]; /* 0x1C */ + MPI2_RAID_VOLUME_PHYSDISK PhysDisk[MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS];/* 0x2C */ +} MPI2_RAID_VOLUME_CREATION_STRUCT, + MPI2_POINTER PTR_MPI2_RAID_VOLUME_CREATION_STRUCT, + Mpi2RaidVolumeCreationStruct_t, MPI2_POINTER pMpi2RaidVolumeCreationStruct_t; + +/* use MPI2_RAID_VOL_TYPE_ defines from mpi2_cnfg.h for VolumeType */ + +/* defines for the VolumeCreationFlags field */ +#define MPI2_RAID_VOL_CREATION_DEFAULT_SETTINGS (0x80000000) +#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x00000004) /* MPI 2.0 only */ +#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x00000002) +#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x00000001) +/* The following is an obsolete define. + * It must be shifted left 24 bits in order to set the proper bit. + */ +#define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80) + + +/* RAID Online Capacity Expansion Structure */ + +typedef struct _MPI2_RAID_ONLINE_CAPACITY_EXPANSION +{ + U32 Flags; /* 0x00 */ + U16 DevHandle0; /* 0x04 */ + U16 Reserved1; /* 0x06 */ + U16 DevHandle1; /* 0x08 */ + U16 Reserved2; /* 0x0A */ +} MPI2_RAID_ONLINE_CAPACITY_EXPANSION, + MPI2_POINTER PTR_MPI2_RAID_ONLINE_CAPACITY_EXPANSION, + Mpi2RaidOnlineCapacityExpansion_t, + MPI2_POINTER pMpi2RaidOnlineCapacityExpansion_t; + + +/* RAID Compatibility Input Structure */ + +typedef struct _MPI2_RAID_COMPATIBILITY_INPUT_STRUCT +{ + U16 SourceDevHandle; /* 0x00 */ + U16 CandidateDevHandle; /* 0x02 */ + U32 Flags; /* 0x04 */ + U32 Reserved1; /* 0x08 */ + U32 Reserved2; /* 0x0C */ +} MPI2_RAID_COMPATIBILITY_INPUT_STRUCT, + MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_INPUT_STRUCT, + Mpi2RaidCompatibilityInputStruct_t, + MPI2_POINTER pMpi2RaidCompatibilityInputStruct_t; + +/* defines for RAID Compatibility Structure Flags field */ +#define MPI2_RAID_COMPAT_SOURCE_IS_VOLUME_FLAG (0x00000002) +#define MPI2_RAID_COMPAT_REPORT_SOURCE_INFO_FLAG (0x00000001) + + +/* RAID Volume Indicator Structure */ + +typedef struct _MPI2_RAID_VOL_INDICATOR +{ + U64 TotalBlocks; /* 0x00 */ + U64 BlocksRemaining; /* 0x08 */ + U32 Flags; /* 0x10 */ + U32 ElapsedSeconds; /* 0x14 */ +} MPI2_RAID_VOL_INDICATOR, MPI2_POINTER PTR_MPI2_RAID_VOL_INDICATOR, + Mpi2RaidVolIndicator_t, MPI2_POINTER pMpi2RaidVolIndicator_t; + +/* defines for RAID Volume Indicator Flags field */ +#define MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID (0x80000000) + +#define MPI2_RAID_VOL_FLAGS_OP_MASK (0x0000000F) +#define MPI2_RAID_VOL_FLAGS_OP_BACKGROUND_INIT (0x00000000) +#define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001) +#define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK (0x00000002) +#define MPI2_RAID_VOL_FLAGS_OP_RESYNC (0x00000003) +#define MPI2_RAID_VOL_FLAGS_OP_MDC (0x00000004) + + +/* RAID Compatibility Result Structure */ + +typedef struct _MPI2_RAID_COMPATIBILITY_RESULT_STRUCT +{ + U8 State; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 GenericAttributes; /* 0x04 */ + U32 OEMSpecificAttributes; /* 0x08 */ + U32 Reserved3; /* 0x0C */ + U32 Reserved4; /* 0x10 */ +} MPI2_RAID_COMPATIBILITY_RESULT_STRUCT, + MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_RESULT_STRUCT, + Mpi2RaidCompatibilityResultStruct_t, + MPI2_POINTER pMpi2RaidCompatibilityResultStruct_t; + +/* defines for RAID Compatibility Result Structure State field */ +#define MPI2_RAID_COMPAT_STATE_COMPATIBLE (0x00) +#define MPI2_RAID_COMPAT_STATE_NOT_COMPATIBLE (0x01) + +/* defines for RAID Compatibility Result Structure GenericAttributes field */ +#define MPI2_RAID_COMPAT_GENATTRIB_4K_SECTOR (0x00000010) + +#define MPI2_RAID_COMPAT_GENATTRIB_MEDIA_MASK (0x0000000C) +#define MPI2_RAID_COMPAT_GENATTRIB_SOLID_STATE_DRIVE (0x00000008) +#define MPI2_RAID_COMPAT_GENATTRIB_HARD_DISK_DRIVE (0x00000004) + +#define MPI2_RAID_COMPAT_GENATTRIB_PROTOCOL_MASK (0x00000003) +#define MPI2_RAID_COMPAT_GENATTRIB_SAS_PROTOCOL (0x00000002) +#define MPI2_RAID_COMPAT_GENATTRIB_SATA_PROTOCOL (0x00000001) + + +/* RAID Action Reply ActionData union */ +typedef union _MPI2_RAID_ACTION_REPLY_DATA +{ + U32 Word[6]; + MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator; + U16 VolDevHandle; + U8 VolumeState; + U8 PhysDiskNum; + MPI2_RAID_COMPATIBILITY_RESULT_STRUCT RaidCompatibilityResult; +} MPI2_RAID_ACTION_REPLY_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY_DATA, + Mpi2RaidActionReplyData_t, MPI2_POINTER pMpi2RaidActionReplyData_t; + +/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */ + + +/* RAID Action Reply Message */ +typedef struct _MPI2_RAID_ACTION_REPLY +{ + U8 Action; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 VolDevHandle; /* 0x04 */ + U8 PhysDiskNum; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U16 Reserved3; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + MPI2_RAID_ACTION_REPLY_DATA ActionData; /* 0x14 */ +} MPI2_RAID_ACTION_REPLY, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY, + Mpi2RaidActionReply_t, MPI2_POINTER pMpi2RaidActionReply_t; + + +#endif + diff --git a/sys/dev/mpr/mpi/mpi2_sas.h b/sys/dev/mpr/mpi/mpi2_sas.h new file mode 100644 index 0000000000000..2a107f1e16170 --- /dev/null +++ b/sys/dev/mpr/mpi/mpi2_sas.h @@ -0,0 +1,346 @@ +/*- + * Copyright (c) 2013 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + +/* + * Copyright (c) 2000-2013 LSI Corporation. + * + * + * Name: mpi2_sas.h + * Title: MPI Serial Attached SCSI structures and definitions + * Creation Date: February 9, 2007 + * + * mpi2_sas.h Version: 02.00.08 + * + * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 + * prefix are for use only on MPI v2.5 products, and must not be used + * with MPI v2.0 products. Unless otherwise noted, names beginning with + * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-26-07 02.00.01 Added Clear All Persistent Operation to SAS IO Unit + * Control Request. + * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control + * Request. + * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST + * to MPI2_SGE_IO_UNION since it supports chained SGLs. + * 05-12-10 02.00.04 Modified some comments. + * 08-11-10 02.00.05 Added NCQ operations to SAS IO Unit Control. + * 11-18-11 02.00.06 Incorporating additions for MPI v2.5. + * 07-10-12 02.00.07 Added MPI2_SATA_PT_SGE_UNION for use in the SATA + * Passthrough Request message. + * 08-19-13 02.00.08 Made MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL obsolete + * for anything newer than MPI v2.0. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_SAS_H +#define MPI2_SAS_H + +/* + * Values for SASStatus. + */ +#define MPI2_SASSTATUS_SUCCESS (0x00) +#define MPI2_SASSTATUS_UNKNOWN_ERROR (0x01) +#define MPI2_SASSTATUS_INVALID_FRAME (0x02) +#define MPI2_SASSTATUS_UTC_BAD_DEST (0x03) +#define MPI2_SASSTATUS_UTC_BREAK_RECEIVED (0x04) +#define MPI2_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED (0x05) +#define MPI2_SASSTATUS_UTC_PORT_LAYER_REQUEST (0x06) +#define MPI2_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED (0x07) +#define MPI2_SASSTATUS_UTC_STP_RESOURCES_BUSY (0x08) +#define MPI2_SASSTATUS_UTC_WRONG_DESTINATION (0x09) +#define MPI2_SASSTATUS_SHORT_INFORMATION_UNIT (0x0A) +#define MPI2_SASSTATUS_LONG_INFORMATION_UNIT (0x0B) +#define MPI2_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA (0x0C) +#define MPI2_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR (0x0D) +#define MPI2_SASSTATUS_XFER_RDY_NOT_EXPECTED (0x0E) +#define MPI2_SASSTATUS_DATA_INCORRECT_DATA_LENGTH (0x0F) +#define MPI2_SASSTATUS_DATA_TOO_MUCH_READ_DATA (0x10) +#define MPI2_SASSTATUS_DATA_OFFSET_ERROR (0x11) +#define MPI2_SASSTATUS_SDSF_NAK_RECEIVED (0x12) +#define MPI2_SASSTATUS_SDSF_CONNECTION_FAILED (0x13) +#define MPI2_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT (0x14) + + +/* + * Values for the SAS DeviceInfo field used in SAS Device Status Change Event + * data and SAS Configuration pages. + */ +#define MPI2_SAS_DEVICE_INFO_SEP (0x00004000) +#define MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000) +#define MPI2_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000) +#define MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH (0x00000800) +#define MPI2_SAS_DEVICE_INFO_SSP_TARGET (0x00000400) +#define MPI2_SAS_DEVICE_INFO_STP_TARGET (0x00000200) +#define MPI2_SAS_DEVICE_INFO_SMP_TARGET (0x00000100) +#define MPI2_SAS_DEVICE_INFO_SATA_DEVICE (0x00000080) +#define MPI2_SAS_DEVICE_INFO_SSP_INITIATOR (0x00000040) +#define MPI2_SAS_DEVICE_INFO_STP_INITIATOR (0x00000020) +#define MPI2_SAS_DEVICE_INFO_SMP_INITIATOR (0x00000010) +#define MPI2_SAS_DEVICE_INFO_SATA_HOST (0x00000008) + +#define MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE (0x00000007) +#define MPI2_SAS_DEVICE_INFO_NO_DEVICE (0x00000000) +#define MPI2_SAS_DEVICE_INFO_END_DEVICE (0x00000001) +#define MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER (0x00000002) +#define MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER (0x00000003) + + +/***************************************************************************** +* +* SAS Messages +* +*****************************************************************************/ + +/**************************************************************************** +* SMP Passthrough messages +****************************************************************************/ + +/* SMP Passthrough Request Message */ +typedef struct _MPI2_SMP_PASSTHROUGH_REQUEST +{ + U8 PassthroughFlags; /* 0x00 */ + U8 PhysicalPort; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 RequestDataLength; /* 0x04 */ + U8 SGLFlags; /* 0x06 */ /* MPI v2.0 only. Reserved on MPI v2.5. */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U32 Reserved2; /* 0x0C */ + U64 SASAddress; /* 0x10 */ + U32 Reserved3; /* 0x18 */ + U32 Reserved4; /* 0x1C */ + MPI2_SIMPLE_SGE_UNION SGL; /* 0x20 */ /* MPI v2.5: IEEE Simple 64 elements only */ +} MPI2_SMP_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REQUEST, + Mpi2SmpPassthroughRequest_t, MPI2_POINTER pMpi2SmpPassthroughRequest_t; + +/* values for PassthroughFlags field */ +#define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80) + +/* MPI v2.0: use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ + + +/* SMP Passthrough Reply Message */ +typedef struct _MPI2_SMP_PASSTHROUGH_REPLY +{ + U8 PassthroughFlags; /* 0x00 */ + U8 PhysicalPort; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 ResponseDataLength; /* 0x04 */ + U8 SGLFlags; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U8 Reserved2; /* 0x0C */ + U8 SASStatus; /* 0x0D */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 Reserved3; /* 0x14 */ + U8 ResponseData[4]; /* 0x18 */ +} MPI2_SMP_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REPLY, + Mpi2SmpPassthroughReply_t, MPI2_POINTER pMpi2SmpPassthroughReply_t; + +/* values for PassthroughFlags field */ +#define MPI2_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE (0x80) + +/* values for SASStatus field are at the top of this file */ + + +/**************************************************************************** +* SATA Passthrough messages +****************************************************************************/ + +typedef union _MPI2_SATA_PT_SGE_UNION +{ + MPI2_SGE_SIMPLE_UNION MpiSimple; /* MPI v2.0 only */ + MPI2_SGE_CHAIN_UNION MpiChain; /* MPI v2.0 only */ + MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; + MPI2_IEEE_SGE_CHAIN_UNION IeeeChain; /* MPI v2.0 only */ + MPI25_IEEE_SGE_CHAIN64 IeeeChain64; /* MPI v2.5 only */ +} MPI2_SATA_PT_SGE_UNION, MPI2_POINTER PTR_MPI2_SATA_PT_SGE_UNION, + Mpi2SataPTSGEUnion_t, MPI2_POINTER pMpi2SataPTSGEUnion_t; + + +/* SATA Passthrough Request Message */ +typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST +{ + U16 DevHandle; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 PassthroughFlags; /* 0x04 */ + U8 SGLFlags; /* 0x06 */ /* MPI v2.0 only. Reserved on MPI v2.5. */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U32 Reserved2; /* 0x0C */ + U32 Reserved3; /* 0x10 */ + U32 Reserved4; /* 0x14 */ + U32 DataLength; /* 0x18 */ + U8 CommandFIS[20]; /* 0x1C */ + MPI2_SATA_PT_SGE_UNION SGL; /* 0x30 */ /* MPI v2.5: IEEE 64 elements only */ +} MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST, + Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t; + +/* values for PassthroughFlags field */ +#define MPI2_SATA_PT_REQ_PT_FLAGS_EXECUTE_DIAG (0x0100) +#define MPI2_SATA_PT_REQ_PT_FLAGS_DMA (0x0020) +#define MPI2_SATA_PT_REQ_PT_FLAGS_PIO (0x0010) +#define MPI2_SATA_PT_REQ_PT_FLAGS_UNSPECIFIED_VU (0x0004) +#define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE (0x0002) +#define MPI2_SATA_PT_REQ_PT_FLAGS_READ (0x0001) + +/* MPI v2.0: use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ + + +/* SATA Passthrough Reply Message */ +typedef struct _MPI2_SATA_PASSTHROUGH_REPLY +{ + U16 DevHandle; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 PassthroughFlags; /* 0x04 */ + U8 SGLFlags; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U8 Reserved2; /* 0x0C */ + U8 SASStatus; /* 0x0D */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U8 StatusFIS[20]; /* 0x14 */ + U32 StatusControlRegisters; /* 0x28 */ + U32 TransferCount; /* 0x2C */ +} MPI2_SATA_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REPLY, + Mpi2SataPassthroughReply_t, MPI2_POINTER pMpi2SataPassthroughReply_t; + +/* values for SASStatus field are at the top of this file */ + + +/**************************************************************************** +* SAS IO Unit Control messages +****************************************************************************/ + +/* SAS IO Unit Control Request Message */ +typedef struct _MPI2_SAS_IOUNIT_CONTROL_REQUEST +{ + U8 Operation; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 DevHandle; /* 0x04 */ + U8 IOCParameter; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U8 PhyNum; /* 0x0E */ + U8 PrimFlags; /* 0x0F */ + U32 Primitive; /* 0x10 */ + U8 LookupMethod; /* 0x14 */ + U8 Reserved5; /* 0x15 */ + U16 SlotNumber; /* 0x16 */ + U64 LookupAddress; /* 0x18 */ + U32 IOCParameterValue; /* 0x20 */ + U32 Reserved7; /* 0x24 */ + U32 Reserved8; /* 0x28 */ +} MPI2_SAS_IOUNIT_CONTROL_REQUEST, + MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REQUEST, + Mpi2SasIoUnitControlRequest_t, MPI2_POINTER pMpi2SasIoUnitControlRequest_t; + +/* values for the Operation field */ +#define MPI2_SAS_OP_CLEAR_ALL_PERSISTENT (0x02) +#define MPI2_SAS_OP_PHY_LINK_RESET (0x06) +#define MPI2_SAS_OP_PHY_HARD_RESET (0x07) +#define MPI2_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08) +#define MPI2_SAS_OP_SEND_PRIMITIVE (0x0A) +#define MPI2_SAS_OP_FORCE_FULL_DISCOVERY (0x0B) +#define MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C) /* MPI v2.0 only */ +#define MPI2_SAS_OP_REMOVE_DEVICE (0x0D) +#define MPI2_SAS_OP_LOOKUP_MAPPING (0x0E) +#define MPI2_SAS_OP_SET_IOC_PARAMETER (0x0F) +#define MPI25_SAS_OP_ENABLE_FP_DEVICE (0x10) +#define MPI25_SAS_OP_DISABLE_FP_DEVICE (0x11) +#define MPI25_SAS_OP_ENABLE_FP_ALL (0x12) +#define MPI25_SAS_OP_DISABLE_FP_ALL (0x13) +#define MPI2_SAS_OP_DEV_ENABLE_NCQ (0x14) +#define MPI2_SAS_OP_DEV_DISABLE_NCQ (0x15) +#define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80) + +/* values for the PrimFlags field */ +#define MPI2_SAS_PRIMFLAGS_SINGLE (0x08) +#define MPI2_SAS_PRIMFLAGS_TRIPLE (0x02) +#define MPI2_SAS_PRIMFLAGS_REDUNDANT (0x01) + +/* values for the LookupMethod field */ +#define MPI2_SAS_LOOKUP_METHOD_SAS_ADDRESS (0x01) +#define MPI2_SAS_LOOKUP_METHOD_SAS_ENCLOSURE_SLOT (0x02) +#define MPI2_SAS_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03) + + +/* SAS IO Unit Control Reply Message */ +typedef struct _MPI2_SAS_IOUNIT_CONTROL_REPLY +{ + U8 Operation; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 DevHandle; /* 0x04 */ + U8 IOCParameter; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_SAS_IOUNIT_CONTROL_REPLY, + MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REPLY, + Mpi2SasIoUnitControlReply_t, MPI2_POINTER pMpi2SasIoUnitControlReply_t; + + +#endif + + diff --git a/sys/dev/mpr/mpi/mpi2_targ.h b/sys/dev/mpr/mpi/mpi2_targ.h new file mode 100644 index 0000000000000..506e64f6370c6 --- /dev/null +++ b/sys/dev/mpr/mpi/mpi2_targ.h @@ -0,0 +1,600 @@ +/*- + * Copyright (c) 2013 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + +/* + * Copyright (c) 2000-2012 LSI Corporation. + * + * + * Name: mpi2_targ.h + * Title: MPI Target mode messages and structures + * Creation Date: September 8, 2006 + * + * mpi2_targ.h Version: 02.00.06 + * + * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 + * prefix are for use only on MPI v2.5 products, and must not be used + * with MPI v2.0 products. Unless otherwise noted, names beginning with + * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 08-31-07 02.00.01 Added Command Buffer Data Location Address Space bits to + * BufferPostFlags field of CommandBufferPostBase Request. + * 02-29-08 02.00.02 Modified various names to make them 32-character unique. + * 10-02-08 02.00.03 Removed NextCmdBufferOffset from + * MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST. + * Target Status Send Request only takes a single SGE for + * response data. + * 02-10-10 02.00.04 Added comment to MPI2_TARGET_SSP_RSP_IU structure. + * 11-18-11 02.00.05 Incorporating additions for MPI v2.5. + * 11-27-12 02.00.06 Added InitiatorDevHandle field to MPI2_TARGET_MODE_ABORT + * request message structure. + * Added AbortType MPI2_TARGET_MODE_ABORT_DEVHANDLE and + * MPI2_TARGET_MODE_ABORT_ALL_COMMANDS. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_TARG_H +#define MPI2_TARG_H + + +/****************************************************************************** +* +* SCSI Target Messages +* +*******************************************************************************/ + +/**************************************************************************** +* Target Command Buffer Post Base Request +****************************************************************************/ + +typedef struct _MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST +{ + U8 BufferPostFlags; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 TotalCmdBuffers; /* 0x04 */ + U8 Reserved; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 Reserved3; /* 0x0C */ + U16 CmdBufferLength; /* 0x10 */ + U16 Reserved4; /* 0x12 */ + U32 BaseAddressLow; /* 0x14 */ + U32 BaseAddressHigh; /* 0x18 */ +} MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST, + MPI2_POINTER PTR_MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST, + Mpi2TargetCmdBufferPostBaseRequest_t, + MPI2_POINTER pMpi2TargetCmdBufferPostBaseRequest_t; + +/* values for the BufferPostflags field */ +#define MPI2_CMD_BUF_POST_BASE_ADDRESS_SPACE_MASK (0x0C) +#define MPI2_CMD_BUF_POST_BASE_SYSTEM_ADDRESS_SPACE (0x00) +#define MPI2_CMD_BUF_POST_BASE_IOCDDR_ADDRESS_SPACE (0x04) +#define MPI2_CMD_BUF_POST_BASE_IOCPLB_ADDRESS_SPACE (0x08) +#define MPI2_CMD_BUF_POST_BASE_IOCPLBNTA_ADDRESS_SPACE (0x0C) + +#define MPI2_CMD_BUF_POST_BASE_FLAGS_AUTO_POST_ALL (0x01) + + +/**************************************************************************** +* Target Command Buffer Post List Request +****************************************************************************/ + +typedef struct _MPI2_TARGET_CMD_BUF_POST_LIST_REQUEST +{ + U16 Reserved; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 CmdBufferCount; /* 0x04 */ + U8 Reserved1; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 Reserved3; /* 0x0C */ + U16 IoIndex[2]; /* 0x10 */ +} MPI2_TARGET_CMD_BUF_POST_LIST_REQUEST, + MPI2_POINTER PTR_MPI2_TARGET_CMD_BUF_POST_LIST_REQUEST, + Mpi2TargetCmdBufferPostListRequest_t, + MPI2_POINTER pMpi2TargetCmdBufferPostListRequest_t; + +/**************************************************************************** +* Target Command Buffer Post Base List Reply +****************************************************************************/ + +typedef struct _MPI2_TARGET_BUF_POST_BASE_LIST_REPLY +{ + U8 Flags; /* 0x00 */ + U8 Reserved; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U16 IoIndex; /* 0x14 */ + U16 Reserved5; /* 0x16 */ + U32 Reserved6; /* 0x18 */ +} MPI2_TARGET_BUF_POST_BASE_LIST_REPLY, + MPI2_POINTER PTR_MPI2_TARGET_BUF_POST_BASE_LIST_REPLY, + Mpi2TargetCmdBufferPostBaseListReply_t, + MPI2_POINTER pMpi2TargetCmdBufferPostBaseListReply_t; + +/* Flags defines */ +#define MPI2_CMD_BUF_POST_REPLY_IOINDEX_VALID (0x01) + + +/**************************************************************************** +* Command Buffer Formats (with 16 byte CDB) +****************************************************************************/ + +typedef struct _MPI2_TARGET_SSP_CMD_BUFFER +{ + U8 FrameType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 InitiatorConnectionTag; /* 0x02 */ + U32 HashedSourceSASAddress; /* 0x04 */ + U16 Reserved2; /* 0x08 */ + U16 Flags; /* 0x0A */ + U32 Reserved3; /* 0x0C */ + U16 Tag; /* 0x10 */ + U16 TargetPortTransferTag; /* 0x12 */ + U32 DataOffset; /* 0x14 */ + /* COMMAND information unit starts here */ + U8 LogicalUnitNumber[8]; /* 0x18 */ + U8 Reserved4; /* 0x20 */ + U8 TaskAttribute; /* lower 3 bits */ /* 0x21 */ + U8 Reserved5; /* 0x22 */ + U8 AdditionalCDBLength; /* upper 5 bits */ /* 0x23 */ + U8 CDB[16]; /* 0x24 */ + /* Additional CDB bytes extend past the CDB field */ +} MPI2_TARGET_SSP_CMD_BUFFER, MPI2_POINTER PTR_MPI2_TARGET_SSP_CMD_BUFFER, + Mpi2TargetSspCmdBuffer, MPI2_POINTER pMp2iTargetSspCmdBuffer; + +typedef struct _MPI2_TARGET_SSP_TASK_BUFFER +{ + U8 FrameType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 InitiatorConnectionTag; /* 0x02 */ + U32 HashedSourceSASAddress; /* 0x04 */ + U16 Reserved2; /* 0x08 */ + U16 Flags; /* 0x0A */ + U32 Reserved3; /* 0x0C */ + U16 Tag; /* 0x10 */ + U16 TargetPortTransferTag; /* 0x12 */ + U32 DataOffset; /* 0x14 */ + /* TASK information unit starts here */ + U8 LogicalUnitNumber[8]; /* 0x18 */ + U16 Reserved4; /* 0x20 */ + U8 TaskManagementFunction; /* 0x22 */ + U8 Reserved5; /* 0x23 */ + U16 ManagedTaskTag; /* 0x24 */ + U16 Reserved6; /* 0x26 */ + U32 Reserved7; /* 0x28 */ + U32 Reserved8; /* 0x2C */ + U32 Reserved9; /* 0x30 */ +} MPI2_TARGET_SSP_TASK_BUFFER, MPI2_POINTER PTR_MPI2_TARGET_SSP_TASK_BUFFER, + Mpi2TargetSspTaskBuffer, MPI2_POINTER pMpi2TargetSspTaskBuffer; + +/* mask and shift for HashedSourceSASAddress field */ +#define MPI2_TARGET_HASHED_SAS_ADDRESS_MASK (0xFFFFFF00) +#define MPI2_TARGET_HASHED_SAS_ADDRESS_SHIFT (8) + + +/**************************************************************************** +* MPI v2.0 Target Assist Request +****************************************************************************/ + +typedef struct _MPI2_TARGET_ASSIST_REQUEST +{ + U8 Reserved1; /* 0x00 */ + U8 TargetAssistFlags; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 QueueTag; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 IoIndex; /* 0x0C */ + U16 InitiatorConnectionTag; /* 0x0E */ + U16 SGLFlags; /* 0x10 */ + U8 SequenceNumber; /* 0x12 */ + U8 Reserved4; /* 0x13 */ + U8 SGLOffset0; /* 0x14 */ + U8 SGLOffset1; /* 0x15 */ + U8 SGLOffset2; /* 0x16 */ + U8 SGLOffset3; /* 0x17 */ + U32 SkipCount; /* 0x18 */ + U32 DataLength; /* 0x1C */ + U32 BidirectionalDataLength; /* 0x20 */ + U16 IoFlags; /* 0x24 */ + U16 EEDPFlags; /* 0x26 */ + U32 EEDPBlockSize; /* 0x28 */ + U32 SecondaryReferenceTag; /* 0x2C */ + U16 SecondaryApplicationTag; /* 0x30 */ + U16 ApplicationTagTranslationMask; /* 0x32 */ + U32 PrimaryReferenceTag; /* 0x34 */ + U16 PrimaryApplicationTag; /* 0x38 */ + U16 PrimaryApplicationTagMask; /* 0x3A */ + U32 RelativeOffset; /* 0x3C */ + U32 Reserved5; /* 0x40 */ + U32 Reserved6; /* 0x44 */ + U32 Reserved7; /* 0x48 */ + U32 Reserved8; /* 0x4C */ + MPI2_SGE_IO_UNION SGL[1]; /* 0x50 */ +} MPI2_TARGET_ASSIST_REQUEST, MPI2_POINTER PTR_MPI2_TARGET_ASSIST_REQUEST, + Mpi2TargetAssistRequest_t, MPI2_POINTER pMpi2TargetAssistRequest_t; + +/* Target Assist TargetAssistFlags bits */ + +#define MPI2_TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER (0x80) +#define MPI2_TARGET_ASSIST_FLAGS_TLR (0x10) +#define MPI2_TARGET_ASSIST_FLAGS_RETRANSMIT (0x04) +#define MPI2_TARGET_ASSIST_FLAGS_AUTO_STATUS (0x02) +#define MPI2_TARGET_ASSIST_FLAGS_DATA_DIRECTION (0x01) + +/* Target Assist SGLFlags bits */ + +/* base values for Data Location Address Space */ +#define MPI2_TARGET_ASSIST_SGLFLAGS_ADDR_MASK (0x0C) +#define MPI2_TARGET_ASSIST_SGLFLAGS_SYSTEM_ADDR (0x00) +#define MPI2_TARGET_ASSIST_SGLFLAGS_IOCDDR_ADDR (0x04) +#define MPI2_TARGET_ASSIST_SGLFLAGS_IOCPLB_ADDR (0x08) +#define MPI2_TARGET_ASSIST_SGLFLAGS_PLBNTA_ADDR (0x0C) + +/* base values for Type */ +#define MPI2_TARGET_ASSIST_SGLFLAGS_TYPE_MASK (0x03) +#define MPI2_TARGET_ASSIST_SGLFLAGS_MPI_TYPE (0x00) +#define MPI2_TARGET_ASSIST_SGLFLAGS_32IEEE_TYPE (0x01) +#define MPI2_TARGET_ASSIST_SGLFLAGS_64IEEE_TYPE (0x02) + +/* shift values for each sub-field */ +#define MPI2_TARGET_ASSIST_SGLFLAGS_SGL3_SHIFT (12) +#define MPI2_TARGET_ASSIST_SGLFLAGS_SGL2_SHIFT (8) +#define MPI2_TARGET_ASSIST_SGLFLAGS_SGL1_SHIFT (4) +#define MPI2_TARGET_ASSIST_SGLFLAGS_SGL0_SHIFT (0) + +/* Target Assist IoFlags bits */ + +#define MPI2_TARGET_ASSIST_IOFLAGS_BIDIRECTIONAL (0x0800) +#define MPI2_TARGET_ASSIST_IOFLAGS_MULTICAST (0x0400) +#define MPI2_TARGET_ASSIST_IOFLAGS_RECEIVE_FIRST (0x0200) + +/* Target Assist EEDPFlags bits */ + +#define MPI2_TA_EEDPFLAGS_INC_PRI_REFTAG (0x8000) +#define MPI2_TA_EEDPFLAGS_INC_SEC_REFTAG (0x4000) +#define MPI2_TA_EEDPFLAGS_INC_PRI_APPTAG (0x2000) +#define MPI2_TA_EEDPFLAGS_INC_SEC_APPTAG (0x1000) + +#define MPI2_TA_EEDPFLAGS_CHECK_REFTAG (0x0400) +#define MPI2_TA_EEDPFLAGS_CHECK_APPTAG (0x0200) +#define MPI2_TA_EEDPFLAGS_CHECK_GUARD (0x0100) + +#define MPI2_TA_EEDPFLAGS_PASSTHRU_REFTAG (0x0008) + +#define MPI2_TA_EEDPFLAGS_MASK_OP (0x0007) +#define MPI2_TA_EEDPFLAGS_NOOP_OP (0x0000) +#define MPI2_TA_EEDPFLAGS_CHECK_OP (0x0001) +#define MPI2_TA_EEDPFLAGS_STRIP_OP (0x0002) +#define MPI2_TA_EEDPFLAGS_CHECK_REMOVE_OP (0x0003) +#define MPI2_TA_EEDPFLAGS_INSERT_OP (0x0004) +#define MPI2_TA_EEDPFLAGS_REPLACE_OP (0x0006) +#define MPI2_TA_EEDPFLAGS_CHECK_REGEN_OP (0x0007) + + +/**************************************************************************** +* MPI v2.5 Target Assist Request +****************************************************************************/ + +typedef struct _MPI25_TARGET_ASSIST_REQUEST +{ + U8 Reserved1; /* 0x00 */ + U8 TargetAssistFlags; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 QueueTag; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 IoIndex; /* 0x0C */ + U16 InitiatorConnectionTag; /* 0x0E */ + U8 DMAFlags; /* 0x10 */ + U8 Reserved9; /* 0x11 */ + U8 SequenceNumber; /* 0x12 */ + U8 Reserved4; /* 0x13 */ + U8 SGLOffset0; /* 0x14 */ + U8 SGLOffset1; /* 0x15 */ + U8 SGLOffset2; /* 0x16 */ + U8 SGLOffset3; /* 0x17 */ + U32 SkipCount; /* 0x18 */ + U32 DataLength; /* 0x1C */ + U32 BidirectionalDataLength; /* 0x20 */ + U16 IoFlags; /* 0x24 */ + U16 EEDPFlags; /* 0x26 */ + U16 EEDPBlockSize; /* 0x28 */ + U16 Reserved10; /* 0x2A */ + U32 SecondaryReferenceTag; /* 0x2C */ + U16 SecondaryApplicationTag; /* 0x30 */ + U16 ApplicationTagTranslationMask; /* 0x32 */ + U32 PrimaryReferenceTag; /* 0x34 */ + U16 PrimaryApplicationTag; /* 0x38 */ + U16 PrimaryApplicationTagMask; /* 0x3A */ + U32 RelativeOffset; /* 0x3C */ + U32 Reserved5; /* 0x40 */ + U32 Reserved6; /* 0x44 */ + U32 Reserved7; /* 0x48 */ + U32 Reserved8; /* 0x4C */ + MPI25_SGE_IO_UNION SGL; /* 0x50 */ +} MPI25_TARGET_ASSIST_REQUEST, MPI2_POINTER PTR_MPI25_TARGET_ASSIST_REQUEST, + Mpi25TargetAssistRequest_t, MPI2_POINTER pMpi25TargetAssistRequest_t; + +/* use MPI2_TARGET_ASSIST_FLAGS_ defines for the Flags field */ + +/* Defines for the DMAFlags field + * Each setting affects 4 SGLS, from SGL0 to SGL3. + * D = Data + * C = Cache DIF + * I = Interleaved + * H = Host DIF + */ +#define MPI25_TA_DMAFLAGS_OP_MASK (0x0F) +#define MPI25_TA_DMAFLAGS_OP_D_D_D_D (0x00) +#define MPI25_TA_DMAFLAGS_OP_D_D_D_C (0x01) +#define MPI25_TA_DMAFLAGS_OP_D_D_D_I (0x02) +#define MPI25_TA_DMAFLAGS_OP_D_D_C_C (0x03) +#define MPI25_TA_DMAFLAGS_OP_D_D_C_I (0x04) +#define MPI25_TA_DMAFLAGS_OP_D_D_I_I (0x05) +#define MPI25_TA_DMAFLAGS_OP_D_C_C_C (0x06) +#define MPI25_TA_DMAFLAGS_OP_D_C_C_I (0x07) +#define MPI25_TA_DMAFLAGS_OP_D_C_I_I (0x08) +#define MPI25_TA_DMAFLAGS_OP_D_I_I_I (0x09) +#define MPI25_TA_DMAFLAGS_OP_D_H_D_D (0x0A) +#define MPI25_TA_DMAFLAGS_OP_D_H_D_C (0x0B) +#define MPI25_TA_DMAFLAGS_OP_D_H_D_I (0x0C) +#define MPI25_TA_DMAFLAGS_OP_D_H_C_C (0x0D) +#define MPI25_TA_DMAFLAGS_OP_D_H_C_I (0x0E) +#define MPI25_TA_DMAFLAGS_OP_D_H_I_I (0x0F) + +/* defines for the IoFlags field */ +#define MPI25_TARGET_ASSIST_IOFLAGS_BIDIRECTIONAL (0x0800) +#define MPI25_TARGET_ASSIST_IOFLAGS_RECEIVE_FIRST (0x0200) + +/* defines for the EEDPFlags field */ +#define MPI25_TA_EEDPFLAGS_INC_PRI_REFTAG (0x8000) +#define MPI25_TA_EEDPFLAGS_INC_SEC_REFTAG (0x4000) +#define MPI25_TA_EEDPFLAGS_INC_PRI_APPTAG (0x2000) +#define MPI25_TA_EEDPFLAGS_INC_SEC_APPTAG (0x1000) + +#define MPI25_TA_EEDPFLAGS_CHECK_REFTAG (0x0400) +#define MPI25_TA_EEDPFLAGS_CHECK_APPTAG (0x0200) +#define MPI25_TA_EEDPFLAGS_CHECK_GUARD (0x0100) + +#define MPI25_TA_EEDPFLAGS_ESCAPE_MODE_MASK (0x00C0) +#define MPI25_TA_EEDPFLAGS_COMPATIBLE_MODE (0x0000) +#define MPI25_TA_EEDPFLAGS_DO_NOT_DISABLE_MODE (0x0040) +#define MPI25_TA_EEDPFLAGS_APPTAG_DISABLE_MODE (0x0080) +#define MPI25_TA_EEDPFLAGS_APPTAG_REFTAG_DISABLE_MODE (0x00C0) + +#define MPI25_TA_EEDPFLAGS_HOST_GUARD_METHOD_MASK (0x0030) +#define MPI25_TA_EEDPFLAGS_T10_CRC_HOST_GUARD (0x0000) +#define MPI25_TA_EEDPFLAGS_IP_CHKSUM_HOST_GUARD (0x0010) + +#define MPI25_TA_EEDPFLAGS_PASSTHRU_REFTAG (0x0008) + +#define MPI25_TA_EEDPFLAGS_MASK_OP (0x0007) +#define MPI25_TA_EEDPFLAGS_NOOP_OP (0x0000) +#define MPI25_TA_EEDPFLAGS_CHECK_OP (0x0001) +#define MPI25_TA_EEDPFLAGS_STRIP_OP (0x0002) +#define MPI25_TA_EEDPFLAGS_CHECK_REMOVE_OP (0x0003) +#define MPI25_TA_EEDPFLAGS_INSERT_OP (0x0004) +#define MPI25_TA_EEDPFLAGS_REPLACE_OP (0x0006) +#define MPI25_TA_EEDPFLAGS_CHECK_REGEN_OP (0x0007) + + +/**************************************************************************** +* Target Status Send Request +****************************************************************************/ + +typedef struct _MPI2_TARGET_STATUS_SEND_REQUEST +{ + U8 Reserved1; /* 0x00 */ + U8 StatusFlags; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 QueueTag; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 IoIndex; /* 0x0C */ + U16 InitiatorConnectionTag; /* 0x0E */ + U16 SGLFlags; /* 0x10 */ /* MPI v2.0 only. Reserved on MPI v2.5. */ + U16 Reserved4; /* 0x12 */ + U8 SGLOffset0; /* 0x14 */ + U8 Reserved5; /* 0x15 */ + U16 Reserved6; /* 0x16 */ + U32 Reserved7; /* 0x18 */ + U32 Reserved8; /* 0x1C */ + MPI2_SIMPLE_SGE_UNION StatusDataSGE; /* 0x20 */ /* MPI v2.5: This must be an IEEE Simple Element 64. */ +} MPI2_TARGET_STATUS_SEND_REQUEST, + MPI2_POINTER PTR_MPI2_TARGET_STATUS_SEND_REQUEST, + Mpi2TargetStatusSendRequest_t, MPI2_POINTER pMpi2TargetStatusSendRequest_t; + +/* Target Status Send StatusFlags bits */ + +#define MPI2_TSS_FLAGS_REPOST_CMD_BUFFER (0x80) +#define MPI2_TSS_FLAGS_RETRANSMIT (0x04) +#define MPI2_TSS_FLAGS_AUTO_GOOD_STATUS (0x01) + +/* Target Status Send SGLFlags bits - MPI v2.0 only */ +/* Data Location Address Space */ +#define MPI2_TSS_SGLFLAGS_ADDR_MASK (0x0C) +#define MPI2_TSS_SGLFLAGS_SYSTEM_ADDR (0x00) +#define MPI2_TSS_SGLFLAGS_IOCDDR_ADDR (0x04) +#define MPI2_TSS_SGLFLAGS_IOCPLB_ADDR (0x08) +#define MPI2_TSS_SGLFLAGS_IOCPLBNTA_ADDR (0x0C) +/* Type */ +#define MPI2_TSS_SGLFLAGS_TYPE_MASK (0x03) +#define MPI2_TSS_SGLFLAGS_MPI_TYPE (0x00) +#define MPI2_TSS_SGLFLAGS_IEEE32_TYPE (0x01) +#define MPI2_TSS_SGLFLAGS_IEEE64_TYPE (0x02) + + + +/* + * NOTE: The SSP status IU is big-endian. When used on a little-endian system, + * this structure properly orders the bytes. + */ +typedef struct _MPI2_TARGET_SSP_RSP_IU +{ + U32 Reserved0[6]; /* reserved for SSP header */ /* 0x00 */ + + /* start of RESPONSE information unit */ + U32 Reserved1; /* 0x18 */ + U32 Reserved2; /* 0x1C */ + U16 Reserved3; /* 0x20 */ + U8 DataPres; /* lower 2 bits */ /* 0x22 */ + U8 Status; /* 0x23 */ + U32 Reserved4; /* 0x24 */ + U32 SenseDataLength; /* 0x28 */ + U32 ResponseDataLength; /* 0x2C */ + + /* start of Response or Sense Data (size may vary dynamically) */ + U8 ResponseSenseData[4]; /* 0x30 */ +} MPI2_TARGET_SSP_RSP_IU, MPI2_POINTER PTR_MPI2_TARGET_SSP_RSP_IU, + Mpi2TargetSspRspIu_t, MPI2_POINTER pMpi2TargetSspRspIu_t; + + +/**************************************************************************** +* Target Standard Reply - used with Target Assist or Target Status Send +****************************************************************************/ + +typedef struct _MPI2_TARGET_STANDARD_REPLY +{ + U16 Reserved; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U16 IoIndex; /* 0x14 */ + U16 Reserved5; /* 0x16 */ + U32 TransferCount; /* 0x18 */ + U32 BidirectionalTransferCount; /* 0x1C */ +} MPI2_TARGET_STANDARD_REPLY, MPI2_POINTER PTR_MPI2_TARGET_STANDARD_REPLY, + Mpi2TargetErrorReply_t, MPI2_POINTER pMpi2TargetErrorReply_t; + + +/**************************************************************************** +* Target Mode Abort Request +****************************************************************************/ + +typedef struct _MPI2_TARGET_MODE_ABORT_REQUEST +{ + U8 AbortType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 IoIndexToAbort; /* 0x0C */ + U16 InitiatorDevHandle; /* 0x0E */ + U32 MidToAbort; /* 0x10 */ +} MPI2_TARGET_MODE_ABORT, MPI2_POINTER PTR_MPI2_TARGET_MODE_ABORT, + Mpi2TargetModeAbort_t, MPI2_POINTER pMpi2TargetModeAbort_t; + +/* Target Mode Abort AbortType values */ + +#define MPI2_TARGET_MODE_ABORT_ALL_CMD_BUFFERS (0x00) +#define MPI2_TARGET_MODE_ABORT_ALL_IO (0x01) +#define MPI2_TARGET_MODE_ABORT_EXACT_IO (0x02) +#define MPI2_TARGET_MODE_ABORT_EXACT_IO_REQUEST (0x03) +#define MPI2_TARGET_MODE_ABORT_IO_REQUEST_AND_IO (0x04) +#define MPI2_TARGET_MODE_ABORT_DEVHANDLE (0x05) +#define MPI2_TARGET_MODE_ABORT_ALL_COMMANDS (0x06) + + +/**************************************************************************** +* Target Mode Abort Reply +****************************************************************************/ + +typedef struct _MPI2_TARGET_MODE_ABORT_REPLY +{ + U16 Reserved; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 AbortCount; /* 0x14 */ +} MPI2_TARGET_MODE_ABORT_REPLY, MPI2_POINTER PTR_MPI2_TARGET_MODE_ABORT_REPLY, + Mpi2TargetModeAbortReply_t, MPI2_POINTER pMpi2TargetModeAbortReply_t; + + +#endif + diff --git a/sys/dev/mpr/mpi/mpi2_tool.h b/sys/dev/mpr/mpi/mpi2_tool.h new file mode 100644 index 0000000000000..94542cc7959b8 --- /dev/null +++ b/sys/dev/mpr/mpi/mpi2_tool.h @@ -0,0 +1,546 @@ +/*- + * Copyright (c) 2013 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + +/* + * Copyright (c) 2000-2013 LSI Corporation. + * + * + * Name: mpi2_tool.h + * Title: MPI diagnostic tool structures and definitions + * Creation Date: March 26, 2007 + * + * mpi2_tool.h Version: 02.00.11 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release + * structures and defines. + * 02-29-08 02.00.02 Modified various names to make them 32-character unique. + * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool. + * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request + * and reply messages. + * Added MPI2_DIAG_BUF_TYPE_EXTENDED. + * Incremented MPI2_DIAG_BUF_TYPE_COUNT. + * 05-12-10 02.00.05 Added Diagnostic Data Upload tool. + * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer + * Post Request. + * 05-25-11 02.00.07 Added Flags field and related defines to + * MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST. + * 11-18-11 02.00.08 Incorporating additions for MPI v2.5. + * 07-10-12 02.00.09 Add MPI v2.5 Toolbox Diagnostic CLI Tool Request + * message. + * 07-26-12 02.00.10 Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that + * it uses MPI Chain SGE as well as MPI Simple SGE. + * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_TOOL_H +#define MPI2_TOOL_H + +/***************************************************************************** +* +* Toolbox Messages +* +*****************************************************************************/ + +/* defines for the Tools */ +#define MPI2_TOOLBOX_CLEAN_TOOL (0x00) +#define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01) +#define MPI2_TOOLBOX_DIAG_DATA_UPLOAD_TOOL (0x02) +#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03) +#define MPI2_TOOLBOX_BEACON_TOOL (0x05) +#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06) +#define MPI2_TOOLBOX_TEXT_DISPLAY_TOOL (0x07) + + +/**************************************************************************** +* Toolbox reply +****************************************************************************/ + +typedef struct _MPI2_TOOLBOX_REPLY +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_TOOLBOX_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_REPLY, + Mpi2ToolboxReply_t, MPI2_POINTER pMpi2ToolboxReply_t; + + +/**************************************************************************** +* Toolbox Clean Tool request +****************************************************************************/ + +typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 Flags; /* 0x0C */ + } MPI2_TOOLBOX_CLEAN_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_CLEAN_REQUEST, + Mpi2ToolboxCleanRequest_t, MPI2_POINTER pMpi2ToolboxCleanRequest_t; + +/* values for the Flags field */ +#define MPI2_TOOLBOX_CLEAN_BOOT_SERVICES (0x80000000) +#define MPI2_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES (0x40000000) +#define MPI2_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000) +#define MPI2_TOOLBOX_CLEAN_FW_CURRENT (0x10000000) +#define MPI2_TOOLBOX_CLEAN_FW_BACKUP (0x08000000) +#define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000) +#define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000) +#define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004) +#define MPI2_TOOLBOX_CLEAN_SEEPROM (0x00000002) +#define MPI2_TOOLBOX_CLEAN_NVSRAM (0x00000001) + + +/**************************************************************************** +* Toolbox Memory Move request +****************************************************************************/ + +typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + MPI2_SGE_SIMPLE_UNION SGL; /* 0x0C */ +} MPI2_TOOLBOX_MEM_MOVE_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_MEM_MOVE_REQUEST, + Mpi2ToolboxMemMoveRequest_t, MPI2_POINTER pMpi2ToolboxMemMoveRequest_t; + + +/**************************************************************************** +* Toolbox Diagnostic Data Upload request +****************************************************************************/ + +typedef struct _MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U8 SGLFlags; /* 0x0C */ + U8 Reserved5; /* 0x0D */ + U16 Reserved6; /* 0x0E */ + U32 Flags; /* 0x10 */ + U32 DataLength; /* 0x14 */ + MPI2_SGE_SIMPLE_UNION SGL; /* 0x18 */ +} MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, + MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, + Mpi2ToolboxDiagDataUploadRequest_t, + MPI2_POINTER pMpi2ToolboxDiagDataUploadRequest_t; + +/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ + + +typedef struct _MPI2_DIAG_DATA_UPLOAD_HEADER +{ + U32 DiagDataLength; /* 00h */ + U8 FormatCode; /* 04h */ + U8 Reserved1; /* 05h */ + U16 Reserved2; /* 06h */ +} MPI2_DIAG_DATA_UPLOAD_HEADER, MPI2_POINTER PTR_MPI2_DIAG_DATA_UPLOAD_HEADER, + Mpi2DiagDataUploadHeader_t, MPI2_POINTER pMpi2DiagDataUploadHeader_t; + + +/**************************************************************************** +* Toolbox ISTWI Read Write Tool +****************************************************************************/ + +/* Toolbox ISTWI Read Write Tool request message */ +typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 Reserved5; /* 0x0C */ + U32 Reserved6; /* 0x10 */ + U8 DevIndex; /* 0x14 */ + U8 Action; /* 0x15 */ + U8 SGLFlags; /* 0x16 */ + U8 Flags; /* 0x17 */ + U16 TxDataLength; /* 0x18 */ + U16 RxDataLength; /* 0x1A */ + U32 Reserved8; /* 0x1C */ + U32 Reserved9; /* 0x20 */ + U32 Reserved10; /* 0x24 */ + U32 Reserved11; /* 0x28 */ + U32 Reserved12; /* 0x2C */ + MPI2_SGE_SIMPLE_UNION SGL; /* 0x30 */ +} MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, + MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, + Mpi2ToolboxIstwiReadWriteRequest_t, + MPI2_POINTER pMpi2ToolboxIstwiReadWriteRequest_t; + +/* values for the Action field */ +#define MPI2_TOOL_ISTWI_ACTION_READ_DATA (0x01) +#define MPI2_TOOL_ISTWI_ACTION_WRITE_DATA (0x02) +#define MPI2_TOOL_ISTWI_ACTION_SEQUENCE (0x03) +#define MPI2_TOOL_ISTWI_ACTION_RESERVE_BUS (0x10) +#define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11) +#define MPI2_TOOL_ISTWI_ACTION_RESET (0x12) + +/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ + +/* values for the Flags field */ +#define MPI2_TOOL_ISTWI_FLAG_AUTO_RESERVE_RELEASE (0x80) +#define MPI2_TOOL_ISTWI_FLAG_PAGE_ADDR_MASK (0x07) + + +/* Toolbox ISTWI Read Write Tool reply message */ +typedef struct _MPI2_TOOLBOX_ISTWI_REPLY +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U8 DevIndex; /* 0x14 */ + U8 Action; /* 0x15 */ + U8 IstwiStatus; /* 0x16 */ + U8 Reserved6; /* 0x17 */ + U16 TxDataCount; /* 0x18 */ + U16 RxDataCount; /* 0x1A */ +} MPI2_TOOLBOX_ISTWI_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_REPLY, + Mpi2ToolboxIstwiReply_t, MPI2_POINTER pMpi2ToolboxIstwiReply_t; + + +/**************************************************************************** +* Toolbox Beacon Tool request +****************************************************************************/ + +typedef struct _MPI2_TOOLBOX_BEACON_REQUEST +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U8 Reserved5; /* 0x0C */ + U8 PhysicalPort; /* 0x0D */ + U8 Reserved6; /* 0x0E */ + U8 Flags; /* 0x0F */ +} MPI2_TOOLBOX_BEACON_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_BEACON_REQUEST, + Mpi2ToolboxBeaconRequest_t, MPI2_POINTER pMpi2ToolboxBeaconRequest_t; + +/* values for the Flags field */ +#define MPI2_TOOLBOX_FLAGS_BEACONMODE_OFF (0x00) +#define MPI2_TOOLBOX_FLAGS_BEACONMODE_ON (0x01) + + +/**************************************************************************** +* Toolbox Diagnostic CLI Tool +****************************************************************************/ + +#define MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH (0x5C) + +/* MPI v2.0 Toolbox Diagnostic CLI Tool request message */ +typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U8 SGLFlags; /* 0x0C */ + U8 Reserved5; /* 0x0D */ + U16 Reserved6; /* 0x0E */ + U32 DataLength; /* 0x10 */ + U8 DiagnosticCliCommand[MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH]; /* 0x14 */ + MPI2_MPI_SGE_IO_UNION SGL; /* 0x70 */ +} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, + MPI2_POINTER PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, + Mpi2ToolboxDiagnosticCliRequest_t, + MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t; + +/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ + + +/* MPI v2.5 Toolbox Diagnostic CLI Tool request message */ +typedef struct _MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 Reserved5; /* 0x0C */ + U32 DataLength; /* 0x10 */ + U8 DiagnosticCliCommand[MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH]; /* 0x14 */ + MPI25_SGE_IO_UNION SGL; /* 0x70 */ +} MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, + MPI2_POINTER PTR_MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, + Mpi25ToolboxDiagnosticCliRequest_t, + MPI2_POINTER pMpi25ToolboxDiagnosticCliRequest_t; + + +/* Toolbox Diagnostic CLI Tool reply message */ +typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 ReturnedDataLength; /* 0x14 */ +} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY, + MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_CLI_REPLY, + Mpi2ToolboxDiagnosticCliReply_t, + MPI2_POINTER pMpi2ToolboxDiagnosticCliReply_t; + + +/**************************************************************************** +* Toolbox Console Text Display Tool +****************************************************************************/ + +/* Toolbox Console Text Display Tool request message */ +typedef struct _MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U8 Console; /* 0x0C */ + U8 Flags; /* 0x0D */ + U16 Reserved6; /* 0x0E */ + U8 TextToDisplay[4]; /* 0x10 */ /* actual length determined at runtime based on frame size */ +} MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST, + MPI2_POINTER PTR_MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST, + Mpi2ToolboxTextDisplayRequest_t, + MPI2_POINTER pMpi2ToolboxTextDisplayRequest_t; + +/* defines for the Console field */ +#define MPI2_TOOLBOX_CONSOLE_TYPE_MASK (0xF0) +#define MPI2_TOOLBOX_CONSOLE_TYPE_DEFAULT (0x00) +#define MPI2_TOOLBOX_CONSOLE_TYPE_UART (0x10) +#define MPI2_TOOLBOX_CONSOLE_TYPE_ETHERNET (0x20) + +#define MPI2_TOOLBOX_CONSOLE_NUMBER_MASK (0x0F) + +/* defines for the Flags field */ +#define MPI2_TOOLBOX_CONSOLE_FLAG_TIMESTAMP (0x01) + + + +/***************************************************************************** +* +* Diagnostic Buffer Messages +* +*****************************************************************************/ + + +/**************************************************************************** +* Diagnostic Buffer Post request +****************************************************************************/ + +typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST +{ + U8 ExtendedType; /* 0x00 */ + U8 BufferType; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U64 BufferAddress; /* 0x0C */ + U32 BufferLength; /* 0x14 */ + U32 Reserved5; /* 0x18 */ + U32 Reserved6; /* 0x1C */ + U32 Flags; /* 0x20 */ + U32 ProductSpecific[23]; /* 0x24 */ +} MPI2_DIAG_BUFFER_POST_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REQUEST, + Mpi2DiagBufferPostRequest_t, MPI2_POINTER pMpi2DiagBufferPostRequest_t; + +/* values for the ExtendedType field */ +#define MPI2_DIAG_EXTENDED_TYPE_UTILIZATION (0x02) + +/* values for the BufferType field */ +#define MPI2_DIAG_BUF_TYPE_TRACE (0x00) +#define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01) +#define MPI2_DIAG_BUF_TYPE_EXTENDED (0x02) +/* count of the number of buffer types */ +#define MPI2_DIAG_BUF_TYPE_COUNT (0x03) + +/* values for the Flags field */ +#define MPI2_DIAG_BUF_FLAG_RELEASE_ON_FULL (0x00000002) /* for MPI v2.0 products only */ +#define MPI2_DIAG_BUF_FLAG_IMMEDIATE_RELEASE (0x00000001) + + +/**************************************************************************** +* Diagnostic Buffer Post reply +****************************************************************************/ + +typedef struct _MPI2_DIAG_BUFFER_POST_REPLY +{ + U8 ExtendedType; /* 0x00 */ + U8 BufferType; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 TransferLength; /* 0x14 */ +} MPI2_DIAG_BUFFER_POST_REPLY, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REPLY, + Mpi2DiagBufferPostReply_t, MPI2_POINTER pMpi2DiagBufferPostReply_t; + + +/**************************************************************************** +* Diagnostic Release request +****************************************************************************/ + +typedef struct _MPI2_DIAG_RELEASE_REQUEST +{ + U8 Reserved1; /* 0x00 */ + U8 BufferType; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ +} MPI2_DIAG_RELEASE_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REQUEST, + Mpi2DiagReleaseRequest_t, MPI2_POINTER pMpi2DiagReleaseRequest_t; + + +/**************************************************************************** +* Diagnostic Buffer Post reply +****************************************************************************/ + +typedef struct _MPI2_DIAG_RELEASE_REPLY +{ + U8 Reserved1; /* 0x00 */ + U8 BufferType; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_DIAG_RELEASE_REPLY, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REPLY, + Mpi2DiagReleaseReply_t, MPI2_POINTER pMpi2DiagReleaseReply_t; + + +#endif + diff --git a/sys/dev/mpr/mpi/mpi2_type.h b/sys/dev/mpr/mpi/mpi2_type.h new file mode 100644 index 0000000000000..da3aefb968f44 --- /dev/null +++ b/sys/dev/mpr/mpi/mpi2_type.h @@ -0,0 +1,131 @@ +/*- + * Copyright (c) 2013 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + +/* + * Copyright (c) 2000-2007 LSI Corporation. + * + * + * Name: mpi2_type.h + * Title: MPI basic type definitions + * Creation Date: August 16, 2006 + * + * mpi2_type.h Version: 02.00.00 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_TYPE_H +#define MPI2_TYPE_H + + +/******************************************************************************* + * Define MPI2_POINTER if it hasn't already been defined. By default + * MPI2_POINTER is defined to be a near pointer. MPI2_POINTER can be defined as + * a far pointer by defining MPI2_POINTER as "far *" before this header file is + * included. + */ +#ifndef MPI2_POINTER +#define MPI2_POINTER * +#endif + +/* the basic types may have already been included by mpi_type.h */ +#ifndef MPI_TYPE_H +/***************************************************************************** +* +* Basic Types +* +*****************************************************************************/ + +typedef signed char S8; +typedef unsigned char U8; +typedef signed short S16; +typedef unsigned short U16; + +#ifdef __FreeBSD__ + +typedef int32_t S32; +typedef uint32_t U32; + +#else + +#if defined(unix) || defined(__arm) || defined(ALPHA) || defined(__PPC__) || defined(__ppc) + + typedef signed int S32; + typedef unsigned int U32; + +#else + + typedef signed long S32; + typedef unsigned long U32; + +#endif +#endif + +typedef struct _S64 +{ + U32 Low; + S32 High; +} S64; + +typedef struct _U64 +{ + U32 Low; + U32 High; +} U64; + + +/***************************************************************************** +* +* Pointer Types +* +*****************************************************************************/ + +typedef S8 *PS8; +typedef U8 *PU8; +typedef S16 *PS16; +typedef U16 *PU16; +typedef S32 *PS32; +typedef U32 *PU32; +typedef S64 *PS64; +typedef U64 *PU64; + +#endif + +#endif + diff --git a/sys/dev/mpr/mpr.c b/sys/dev/mpr/mpr.c new file mode 100644 index 0000000000000..3656eec368646 --- /dev/null +++ b/sys/dev/mpr/mpr.c @@ -0,0 +1,2795 @@ +/*- + * Copyright (c) 2009 Yahoo! Inc. + * Copyright (c) 2012-2014 LSI Corp. + * 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$"); + +/* Communications core for LSI MPT2 */ + +/* TODO Move headers to mprvar */ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/selinfo.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/bio.h> +#include <sys/malloc.h> +#include <sys/uio.h> +#include <sys/sysctl.h> +#include <sys/queue.h> +#include <sys/kthread.h> +#include <sys/taskqueue.h> +#include <sys/endian.h> +#include <sys/eventhandler.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> +#include <sys/proc.h> + +#include <dev/pci/pcivar.h> + +#include <cam/cam.h> +#include <cam/scsi/scsi_all.h> + +#include <dev/mpr/mpi/mpi2_type.h> +#include <dev/mpr/mpi/mpi2.h> +#include <dev/mpr/mpi/mpi2_ioc.h> +#include <dev/mpr/mpi/mpi2_sas.h> +#include <dev/mpr/mpi/mpi2_cnfg.h> +#include <dev/mpr/mpi/mpi2_init.h> +#include <dev/mpr/mpi/mpi2_tool.h> +#include <dev/mpr/mpr_ioctl.h> +#include <dev/mpr/mprvar.h> +#include <dev/mpr/mpr_table.h> +#include <dev/mpr/mpr_sas.h> + +static int mpr_diag_reset(struct mpr_softc *sc, int sleep_flag); +static int mpr_init_queues(struct mpr_softc *sc); +static int mpr_message_unit_reset(struct mpr_softc *sc, int sleep_flag); +static int mpr_transition_operational(struct mpr_softc *sc); +static int mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t attaching); +static void mpr_iocfacts_free(struct mpr_softc *sc); +static void mpr_startup(void *arg); +static int mpr_send_iocinit(struct mpr_softc *sc); +static int mpr_alloc_queues(struct mpr_softc *sc); +static int mpr_alloc_replies(struct mpr_softc *sc); +static int mpr_alloc_requests(struct mpr_softc *sc); +static int mpr_attach_log(struct mpr_softc *sc); +static __inline void mpr_complete_command(struct mpr_softc *sc, + struct mpr_command *cm); +static void mpr_dispatch_event(struct mpr_softc *sc, uintptr_t data, + MPI2_EVENT_NOTIFICATION_REPLY *reply); +static void mpr_config_complete(struct mpr_softc *sc, + struct mpr_command *cm); +static void mpr_periodic(void *); +static int mpr_reregister_events(struct mpr_softc *sc); +static void mpr_enqueue_request(struct mpr_softc *sc, + struct mpr_command *cm); +static int mpr_get_iocfacts(struct mpr_softc *sc, + MPI2_IOC_FACTS_REPLY *facts); +static int mpr_wait_db_ack(struct mpr_softc *sc, int timeout, int sleep_flag); +SYSCTL_NODE(_hw, OID_AUTO, mpr, CTLFLAG_RD, 0, "MPR Driver Parameters"); + +MALLOC_DEFINE(M_MPR, "mpr", "mpr driver memory"); + +/* + * Do a "Diagnostic Reset" aka a hard reset. This should get the chip out of + * any state and back to its initialization state machine. + */ +static char mpt2_reset_magic[] = { 0x00, 0x0f, 0x04, 0x0b, 0x02, 0x07, 0x0d }; + +/* + * Added this union to smoothly convert le64toh cm->cm_desc.Words. + * Compiler only supports unint64_t to be passed as an argument. + * Otherwise it will through this error: + * "aggregate value used where an integer was expected" + */ +typedef union _reply_descriptor { + u64 word; + struct { + u32 low; + u32 high; + } u; +}reply_descriptor,address_descriptor; + +/* Rate limit chain-fail messages to 1 per minute */ +static struct timeval mpr_chainfail_interval = { 60, 0 }; + +/* + * sleep_flag can be either CAN_SLEEP or NO_SLEEP. + * If this function is called from process context, it can sleep + * and there is no harm to sleep, in case if this fuction is called + * from Interrupt handler, we can not sleep and need NO_SLEEP flag set. + * based on sleep flags driver will call either msleep, pause or DELAY. + * msleep and pause are of same variant, but pause is used when mpr_mtx + * is not hold by driver. + */ +static int +mpr_diag_reset(struct mpr_softc *sc,int sleep_flag) +{ + uint32_t reg; + int i, error, tries = 0; + uint8_t first_wait_done = FALSE; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + /* Clear any pending interrupts */ + mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); + + /* + * Force NO_SLEEP for threads prohibited to sleep + * e.a Thread from interrupt handler are prohibited to sleep. + */ +#if __FreeBSD_version >= 1000029 + if (curthread->td_no_sleeping) +#else //__FreeBSD_version < 1000029 + if (curthread->td_pflags & TDP_NOSLEEPING) +#endif //__FreeBSD_version >= 1000029 + sleep_flag = NO_SLEEP; + + /* Push the magic sequence */ + error = ETIMEDOUT; + while (tries++ < 20) { + for (i = 0; i < sizeof(mpt2_reset_magic); i++) + mpr_regwrite(sc, MPI2_WRITE_SEQUENCE_OFFSET, + mpt2_reset_magic[i]); + + /* wait 100 msec */ + if (mtx_owned(&sc->mpr_mtx) && sleep_flag == CAN_SLEEP) + msleep(&sc->msleep_fake_chan, &sc->mpr_mtx, 0, + "mprdiag", hz/10); + else if (sleep_flag == CAN_SLEEP) + pause("mprdiag", hz/10); + else + DELAY(100 * 1000); + + reg = mpr_regread(sc, MPI2_HOST_DIAGNOSTIC_OFFSET); + if (reg & MPI2_DIAG_DIAG_WRITE_ENABLE) { + error = 0; + break; + } + } + if (error) + return (error); + + /* Send the actual reset. XXX need to refresh the reg? */ + mpr_regwrite(sc, MPI2_HOST_DIAGNOSTIC_OFFSET, + reg | MPI2_DIAG_RESET_ADAPTER); + + /* Wait up to 300 seconds in 50ms intervals */ + error = ETIMEDOUT; + for (i = 0; i < 6000; i++) { + /* + * Wait 50 msec. If this is the first time through, wait 256 + * msec to satisfy Diag Reset timing requirements. + */ + if (first_wait_done) { + if (mtx_owned(&sc->mpr_mtx) && sleep_flag == CAN_SLEEP) + msleep(&sc->msleep_fake_chan, &sc->mpr_mtx, 0, + "mprdiag", hz/20); + else if (sleep_flag == CAN_SLEEP) + pause("mprdiag", hz/20); + else + DELAY(50 * 1000); + } else { + DELAY(256 * 1000); + first_wait_done = TRUE; + } + /* + * Check for the RESET_ADAPTER bit to be cleared first, then + * wait for the RESET state to be cleared, which takes a little + * longer. + */ + reg = mpr_regread(sc, MPI2_HOST_DIAGNOSTIC_OFFSET); + if (reg & MPI2_DIAG_RESET_ADAPTER) { + continue; + } + reg = mpr_regread(sc, MPI2_DOORBELL_OFFSET); + if ((reg & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_RESET) { + error = 0; + break; + } + } + if (error) + return (error); + + mpr_regwrite(sc, MPI2_WRITE_SEQUENCE_OFFSET, 0x0); + + return (0); +} + +static int +mpr_message_unit_reset(struct mpr_softc *sc, int sleep_flag) +{ + + MPR_FUNCTRACE(sc); + + mpr_regwrite(sc, MPI2_DOORBELL_OFFSET, + MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET << + MPI2_DOORBELL_FUNCTION_SHIFT); + + if (mpr_wait_db_ack(sc, 5, sleep_flag) != 0) { + mpr_dprint(sc, MPR_FAULT, "Doorbell handshake failed : <%s>\n", + __func__); + return (ETIMEDOUT); + } + + return (0); +} + +static int +mpr_transition_ready(struct mpr_softc *sc) +{ + uint32_t reg, state; + int error, tries = 0; + int sleep_flags; + + MPR_FUNCTRACE(sc); + /* If we are in attach call, do not sleep */ + sleep_flags = (sc->mpr_flags & MPR_FLAGS_ATTACH_DONE) + ? CAN_SLEEP : NO_SLEEP; + + error = 0; + while (tries++ < 1200) { + reg = mpr_regread(sc, MPI2_DOORBELL_OFFSET); + mpr_dprint(sc, MPR_INIT, "Doorbell= 0x%x\n", reg); + + /* + * Ensure the IOC is ready to talk. If it's not, try + * resetting it. + */ + if (reg & MPI2_DOORBELL_USED) { + mpr_diag_reset(sc, sleep_flags); + DELAY(50000); + continue; + } + + /* Is the adapter owned by another peer? */ + if ((reg & MPI2_DOORBELL_WHO_INIT_MASK) == + (MPI2_WHOINIT_PCI_PEER << MPI2_DOORBELL_WHO_INIT_SHIFT)) { + device_printf(sc->mpr_dev, "IOC is under the control " + "of another peer host, aborting initialization.\n"); + return (ENXIO); + } + + state = reg & MPI2_IOC_STATE_MASK; + if (state == MPI2_IOC_STATE_READY) { + /* Ready to go! */ + error = 0; + break; + } else if (state == MPI2_IOC_STATE_FAULT) { + mpr_dprint(sc, MPR_FAULT, "IOC in fault state 0x%x\n", + state & MPI2_DOORBELL_FAULT_CODE_MASK); + mpr_diag_reset(sc, sleep_flags); + } else if (state == MPI2_IOC_STATE_OPERATIONAL) { + /* Need to take ownership */ + mpr_message_unit_reset(sc, sleep_flags); + } else if (state == MPI2_IOC_STATE_RESET) { + /* Wait a bit, IOC might be in transition */ + mpr_dprint(sc, MPR_FAULT, + "IOC in unexpected reset state\n"); + } else { + mpr_dprint(sc, MPR_FAULT, + "IOC in unknown state 0x%x\n", state); + error = EINVAL; + break; + } + + /* Wait 50ms for things to settle down. */ + DELAY(50000); + } + + if (error) + device_printf(sc->mpr_dev, "Cannot transition IOC to ready\n"); + + return (error); +} + +static int +mpr_transition_operational(struct mpr_softc *sc) +{ + uint32_t reg, state; + int error; + + MPR_FUNCTRACE(sc); + + error = 0; + reg = mpr_regread(sc, MPI2_DOORBELL_OFFSET); + mpr_dprint(sc, MPR_INIT, "Doorbell= 0x%x\n", reg); + + state = reg & MPI2_IOC_STATE_MASK; + if (state != MPI2_IOC_STATE_READY) { + if ((error = mpr_transition_ready(sc)) != 0) { + mpr_dprint(sc, MPR_FAULT, + "%s failed to transition ready\n", __func__); + return (error); + } + } + + error = mpr_send_iocinit(sc); + return (error); +} + +/* + * This is called during attach and when re-initializing due to a Diag Reset. + * IOC Facts is used to allocate many of the structures needed by the driver. + * If called from attach, de-allocation is not required because the driver has + * not allocated any structures yet, but if called from a Diag Reset, previously + * allocated structures based on IOC Facts will need to be freed and re- + * allocated bases on the latest IOC Facts. + */ +static int +mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t attaching) +{ + int error, i; + Mpi2IOCFactsReply_t saved_facts; + uint8_t saved_mode, reallocating; + struct mprsas_lun *lun, *lun_tmp; + struct mprsas_target *targ; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + /* Save old IOC Facts and then only reallocate if Facts have changed */ + if (!attaching) { + bcopy(sc->facts, &saved_facts, sizeof(MPI2_IOC_FACTS_REPLY)); + } + + /* + * Get IOC Facts. In all cases throughout this function, panic if doing + * a re-initialization and only return the error if attaching so the OS + * can handle it. + */ + if ((error = mpr_get_iocfacts(sc, sc->facts)) != 0) { + if (attaching) { + mpr_dprint(sc, MPR_FAULT, "%s failed to get IOC Facts " + "with error %d\n", __func__, error); + return (error); + } else { + panic("%s failed to get IOC Facts with error %d\n", + __func__, error); + } + } + + mpr_print_iocfacts(sc, sc->facts); + + snprintf(sc->fw_version, sizeof(sc->fw_version), + "%02d.%02d.%02d.%02d", + sc->facts->FWVersion.Struct.Major, + sc->facts->FWVersion.Struct.Minor, + sc->facts->FWVersion.Struct.Unit, + sc->facts->FWVersion.Struct.Dev); + + mpr_printf(sc, "Firmware: %s, Driver: %s\n", sc->fw_version, + MPR_DRIVER_VERSION); + mpr_printf(sc, "IOCCapabilities: %b\n", sc->facts->IOCCapabilities, + "\20" "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf" + "\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR" + "\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc"); + + /* + * If the chip doesn't support event replay then a hard reset will be + * required to trigger a full discovery. Do the reset here then + * retransition to Ready. A hard reset might have already been done, + * but it doesn't hurt to do it again. Only do this if attaching, not + * for a Diag Reset. + */ + if (attaching) { + if ((sc->facts->IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY) == 0) { + mpr_diag_reset(sc, NO_SLEEP); + if ((error = mpr_transition_ready(sc)) != 0) { + mpr_dprint(sc, MPR_FAULT, "%s failed to " + "transition to ready with error %d\n", + __func__, error); + return (error); + } + } + } + + /* + * Set flag if IR Firmware is loaded. If the RAID Capability has + * changed from the previous IOC Facts, log a warning, but only if + * checking this after a Diag Reset and not during attach. + */ + saved_mode = sc->ir_firmware; + if (sc->facts->IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) + sc->ir_firmware = 1; + if (!attaching) { + if (sc->ir_firmware != saved_mode) { + mpr_dprint(sc, MPR_FAULT, "%s new IR/IT mode in IOC " + "Facts does not match previous mode\n", __func__); + } + } + + /* Only deallocate and reallocate if relevant IOC Facts have changed */ + reallocating = FALSE; + if ((!attaching) && + ((saved_facts.MsgVersion != sc->facts->MsgVersion) || + (saved_facts.HeaderVersion != sc->facts->HeaderVersion) || + (saved_facts.MaxChainDepth != sc->facts->MaxChainDepth) || + (saved_facts.RequestCredit != sc->facts->RequestCredit) || + (saved_facts.ProductID != sc->facts->ProductID) || + (saved_facts.IOCCapabilities != sc->facts->IOCCapabilities) || + (saved_facts.IOCRequestFrameSize != + sc->facts->IOCRequestFrameSize) || + (saved_facts.MaxTargets != sc->facts->MaxTargets) || + (saved_facts.MaxSasExpanders != sc->facts->MaxSasExpanders) || + (saved_facts.MaxEnclosures != sc->facts->MaxEnclosures) || + (saved_facts.HighPriorityCredit != sc->facts->HighPriorityCredit) || + (saved_facts.MaxReplyDescriptorPostQueueDepth != + sc->facts->MaxReplyDescriptorPostQueueDepth) || + (saved_facts.ReplyFrameSize != sc->facts->ReplyFrameSize) || + (saved_facts.MaxVolumes != sc->facts->MaxVolumes) || + (saved_facts.MaxPersistentEntries != + sc->facts->MaxPersistentEntries))) { + reallocating = TRUE; + } + + /* + * Some things should be done if attaching or re-allocating after a Diag + * Reset, but are not needed after a Diag Reset if the FW has not + * changed. + */ + if (attaching || reallocating) { + /* + * Check if controller supports FW diag buffers and set flag to + * enable each type. + */ + if (sc->facts->IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) + sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_TRACE]. + enabled = TRUE; + if (sc->facts->IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) + sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_SNAPSHOT]. + enabled = TRUE; + if (sc->facts->IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) + sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_EXTENDED]. + enabled = TRUE; + + /* + * Set flag if EEDP is supported and if TLR is supported. + */ + if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) + sc->eedp_enabled = TRUE; + if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) + sc->control_TLR = TRUE; + + /* + * Size the queues. Since the reply queues always need one free + * entry, we'll just deduct one reply message here. + */ + sc->num_reqs = MIN(MPR_REQ_FRAMES, sc->facts->RequestCredit); + sc->num_replies = MIN(MPR_REPLY_FRAMES + MPR_EVT_REPLY_FRAMES, + sc->facts->MaxReplyDescriptorPostQueueDepth) - 1; + + /* + * Initialize all Tail Queues + */ + TAILQ_INIT(&sc->req_list); + TAILQ_INIT(&sc->high_priority_req_list); + TAILQ_INIT(&sc->chain_list); + TAILQ_INIT(&sc->tm_list); + } + + /* + * If doing a Diag Reset and the FW is significantly different + * (reallocating will be set above in IOC Facts comparison), then all + * buffers based on the IOC Facts will need to be freed before they are + * reallocated. + */ + if (reallocating) { + mpr_iocfacts_free(sc); + + /* + * The number of targets is based on IOC Facts, so free all of + * the allocated LUNs for each target and then the target buffer + * itself. + */ + for (i=0; i< saved_facts.MaxTargets; i++) { + targ = &sc->sassc->targets[i]; + SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, + lun_tmp) { + free(lun, M_MPR); + } + } + free(sc->sassc->targets, M_MPR); + + sc->sassc->targets = malloc(sizeof(struct mprsas_target) * + sc->facts->MaxTargets, M_MPR, M_WAITOK|M_ZERO); + if (!sc->sassc->targets) { + panic("%s failed to alloc targets with error %d\n", + __func__, ENOMEM); + } + } + + /* + * Any deallocation has been completed. Now start reallocating + * if needed. Will only need to reallocate if attaching or if the new + * IOC Facts are different from the previous IOC Facts after a Diag + * Reset. Targets have already been allocated above if needed. + */ + if (attaching || reallocating) { + if (((error = mpr_alloc_queues(sc)) != 0) || + ((error = mpr_alloc_replies(sc)) != 0) || + ((error = mpr_alloc_requests(sc)) != 0)) { + if (attaching ) { + mpr_dprint(sc, MPR_FAULT, "%s failed to alloc " + "queues with error %d\n", __func__, error); + mpr_free(sc); + return (error); + } else { + panic("%s failed to alloc queues with error " + "%d\n", __func__, error); + } + } + } + + /* Always initialize the queues */ + bzero(sc->free_queue, sc->fqdepth * 4); + mpr_init_queues(sc); + + /* + * Always get the chip out of the reset state, but only panic if not + * attaching. If attaching and there is an error, that is handled by + * the OS. + */ + error = mpr_transition_operational(sc); + if (error != 0) { + if (attaching) { + mpr_printf(sc, "%s failed to transition to " + "operational with error %d\n", __func__, error); + mpr_free(sc); + return (error); + } else { + panic("%s failed to transition to operational with " + "error %d\n", __func__, error); + } + } + + /* + * Finish the queue initialization. + * These are set here instead of in mpr_init_queues() because the + * IOC resets these values during the state transition in + * mpr_transition_operational(). The free index is set to 1 + * because the corresponding index in the IOC is set to 0, and the + * IOC treats the queues as full if both are set to the same value. + * Hence the reason that the queue can't hold all of the possible + * replies. + */ + sc->replypostindex = 0; + mpr_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex); + mpr_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, 0); + + /* + * Attach the subsystems so they can prepare their event masks. + */ + /* XXX Should be dynamic so that IM/IR and user modules can attach */ + if (attaching) { + if (((error = mpr_attach_log(sc)) != 0) || + ((error = mpr_attach_sas(sc)) != 0) || + ((error = mpr_attach_user(sc)) != 0)) { + mpr_printf(sc, "%s failed to attach all subsystems: " + "error %d\n", __func__, error); + mpr_free(sc); + return (error); + } + + if ((error = mpr_pci_setup_interrupts(sc)) != 0) { + mpr_printf(sc, "%s failed to setup interrupts\n", + __func__); + mpr_free(sc); + return (error); + } + } + + return (error); +} + +/* + * This is called if memory is being free (during detach for example) and when + * buffers need to be reallocated due to a Diag Reset. + */ +static void +mpr_iocfacts_free(struct mpr_softc *sc) +{ + struct mpr_command *cm; + int i; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + if (sc->free_busaddr != 0) + bus_dmamap_unload(sc->queues_dmat, sc->queues_map); + if (sc->free_queue != NULL) + bus_dmamem_free(sc->queues_dmat, sc->free_queue, + sc->queues_map); + if (sc->queues_dmat != NULL) + bus_dma_tag_destroy(sc->queues_dmat); + + if (sc->chain_busaddr != 0) + bus_dmamap_unload(sc->chain_dmat, sc->chain_map); + if (sc->chain_frames != NULL) + bus_dmamem_free(sc->chain_dmat, sc->chain_frames, + sc->chain_map); + if (sc->chain_dmat != NULL) + bus_dma_tag_destroy(sc->chain_dmat); + + if (sc->sense_busaddr != 0) + bus_dmamap_unload(sc->sense_dmat, sc->sense_map); + if (sc->sense_frames != NULL) + bus_dmamem_free(sc->sense_dmat, sc->sense_frames, + sc->sense_map); + if (sc->sense_dmat != NULL) + bus_dma_tag_destroy(sc->sense_dmat); + + if (sc->reply_busaddr != 0) + bus_dmamap_unload(sc->reply_dmat, sc->reply_map); + if (sc->reply_frames != NULL) + bus_dmamem_free(sc->reply_dmat, sc->reply_frames, + sc->reply_map); + if (sc->reply_dmat != NULL) + bus_dma_tag_destroy(sc->reply_dmat); + + if (sc->req_busaddr != 0) + bus_dmamap_unload(sc->req_dmat, sc->req_map); + if (sc->req_frames != NULL) + bus_dmamem_free(sc->req_dmat, sc->req_frames, sc->req_map); + if (sc->req_dmat != NULL) + bus_dma_tag_destroy(sc->req_dmat); + + if (sc->chains != NULL) + free(sc->chains, M_MPR); + if (sc->commands != NULL) { + for (i = 1; i < sc->num_reqs; i++) { + cm = &sc->commands[i]; + bus_dmamap_destroy(sc->buffer_dmat, cm->cm_dmamap); + } + free(sc->commands, M_MPR); + } + if (sc->buffer_dmat != NULL) + bus_dma_tag_destroy(sc->buffer_dmat); +} + +/* + * The terms diag reset and hard reset are used interchangeably in the MPI + * docs to mean resetting the controller chip. In this code diag reset + * cleans everything up, and the hard reset function just sends the reset + * sequence to the chip. This should probably be refactored so that every + * subsystem gets a reset notification of some sort, and can clean up + * appropriately. + */ +int +mpr_reinit(struct mpr_softc *sc) +{ + int error; + struct mprsas_softc *sassc; + + sassc = sc->sassc; + + MPR_FUNCTRACE(sc); + + mtx_assert(&sc->mpr_mtx, MA_OWNED); + + if (sc->mpr_flags & MPR_FLAGS_DIAGRESET) { + mpr_dprint(sc, MPR_INIT, "%s reset already in progress\n", + __func__); + return 0; + } + + mpr_dprint(sc, MPR_INFO, "Reinitializing controller,\n"); + /* make sure the completion callbacks can recognize they're getting + * a NULL cm_reply due to a reset. + */ + sc->mpr_flags |= MPR_FLAGS_DIAGRESET; + + /* + * Mask interrupts here. + */ + mpr_dprint(sc, MPR_INIT, "%s mask interrupts\n", __func__); + mpr_mask_intr(sc); + + error = mpr_diag_reset(sc, CAN_SLEEP); + if (error != 0) { + panic("%s hard reset failed with error %d\n", __func__, error); + } + + /* Restore the PCI state, including the MSI-X registers */ + mpr_pci_restore(sc); + + /* Give the I/O subsystem special priority to get itself prepared */ + mprsas_handle_reinit(sc); + + /* + * Get IOC Facts and allocate all structures based on this information. + * The attach function will also call mpr_iocfacts_allocate at startup. + * If relevant values have changed in IOC Facts, this function will free + * all of the memory based on IOC Facts and reallocate that memory. + */ + if ((error = mpr_iocfacts_allocate(sc, FALSE)) != 0) { + panic("%s IOC Facts based allocation failed with error %d\n", + __func__, error); + } + + /* + * Mapping structures will be re-allocated after getting IOC Page8, so + * free these structures here. + */ + mpr_mapping_exit(sc); + + /* + * The static page function currently read is IOC Page8. Others can be + * added in future. It's possible that the values in IOC Page8 have + * changed after a Diag Reset due to user modification, so always read + * these. Interrupts are masked, so unmask them before getting config + * pages. + */ + mpr_unmask_intr(sc); + sc->mpr_flags &= ~MPR_FLAGS_DIAGRESET; + mpr_base_static_config_pages(sc); + + /* + * Some mapping info is based in IOC Page8 data, so re-initialize the + * mapping tables. + */ + mpr_mapping_initialize(sc); + + /* + * Restart will reload the event masks clobbered by the reset, and + * then enable the port. + */ + mpr_reregister_events(sc); + + /* the end of discovery will release the simq, so we're done. */ + mpr_dprint(sc, MPR_INFO, "%s finished sc %p post %u free %u\n", + __func__, sc, sc->replypostindex, sc->replyfreeindex); + mprsas_release_simq_reinit(sassc); + + return 0; +} + +/* Wait for the chip to ACK a word that we've put into its FIFO + * Wait for <timeout> seconds. In single loop wait for busy loop + * for 500 microseconds. + * Total is [ 0.5 * (2000 * <timeout>) ] in miliseconds. + * */ +static int +mpr_wait_db_ack(struct mpr_softc *sc, int timeout, int sleep_flag) +{ + u32 cntdn, count; + u32 int_status; + u32 doorbell; + + count = 0; + cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; + do { + int_status = mpr_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET); + if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) { + mpr_dprint(sc, MPR_INIT, "%s: successful count(%d), " + "timeout(%d)\n", __func__, count, timeout); + return 0; + } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { + doorbell = mpr_regread(sc, MPI2_DOORBELL_OFFSET); + if ((doorbell & MPI2_IOC_STATE_MASK) == + MPI2_IOC_STATE_FAULT) { + mpr_dprint(sc, MPR_FAULT, + "fault_state(0x%04x)!\n", doorbell); + return (EFAULT); + } + } else if (int_status == 0xFFFFFFFF) + goto out; + + /* + * If it can sleep, sleep for 1 milisecond, else busy loop for + * 0.5 milisecond + */ + if (mtx_owned(&sc->mpr_mtx) && sleep_flag == CAN_SLEEP) + msleep(&sc->msleep_fake_chan, &sc->mpr_mtx, 0, "mprdba", hz/1000); + else if (sleep_flag == CAN_SLEEP) + pause("mprdba", hz/1000); + else + DELAY(500); + count++; + } while (--cntdn); + + out: + mpr_dprint(sc, MPR_FAULT, "%s: failed due to timeout count(%d), " + "int_status(%x)!\n", __func__, count, int_status); + return (ETIMEDOUT); +} + +/* Wait for the chip to signal that the next word in its FIFO can be fetched */ +static int +mpr_wait_db_int(struct mpr_softc *sc) +{ + int retry; + + for (retry = 0; retry < MPR_DB_MAX_WAIT; retry++) { + if ((mpr_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET) & + MPI2_HIS_IOC2SYS_DB_STATUS) != 0) + return (0); + DELAY(2000); + } + return (ETIMEDOUT); +} + +/* Step through the synchronous command state machine, i.e. "Doorbell mode" */ +static int +mpr_request_sync(struct mpr_softc *sc, void *req, MPI2_DEFAULT_REPLY *reply, + int req_sz, int reply_sz, int timeout) +{ + uint32_t *data32; + uint16_t *data16; + int i, count, ioc_sz, residual; + int sleep_flags = CAN_SLEEP; + +#if __FreeBSD_version >= 1000029 + if (curthread->td_no_sleeping) +#else //__FreeBSD_version < 1000029 + if (curthread->td_pflags & TDP_NOSLEEPING) +#endif //__FreeBSD_version >= 1000029 + sleep_flags = NO_SLEEP; + + /* Step 1 */ + mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); + + /* Step 2 */ + if (mpr_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED) + return (EBUSY); + + /* Step 3 + * Announce that a message is coming through the doorbell. Messages + * are pushed at 32bit words, so round up if needed. + */ + count = (req_sz + 3) / 4; + mpr_regwrite(sc, MPI2_DOORBELL_OFFSET, + (MPI2_FUNCTION_HANDSHAKE << MPI2_DOORBELL_FUNCTION_SHIFT) | + (count << MPI2_DOORBELL_ADD_DWORDS_SHIFT)); + + /* Step 4 */ + if (mpr_wait_db_int(sc) || + (mpr_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED) == 0) { + mpr_dprint(sc, MPR_FAULT, "Doorbell failed to activate\n"); + return (ENXIO); + } + mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); + if (mpr_wait_db_ack(sc, 5, sleep_flags) != 0) { + mpr_dprint(sc, MPR_FAULT, "Doorbell handshake failed\n"); + return (ENXIO); + } + + /* Step 5 */ + /* Clock out the message data synchronously in 32-bit dwords*/ + data32 = (uint32_t *)req; + for (i = 0; i < count; i++) { + mpr_regwrite(sc, MPI2_DOORBELL_OFFSET, htole32(data32[i])); + if (mpr_wait_db_ack(sc, 5, sleep_flags) != 0) { + mpr_dprint(sc, MPR_FAULT, + "Timeout while writing doorbell\n"); + return (ENXIO); + } + } + + /* Step 6 */ + /* Clock in the reply in 16-bit words. The total length of the + * message is always in the 4th byte, so clock out the first 2 words + * manually, then loop the rest. + */ + data16 = (uint16_t *)reply; + if (mpr_wait_db_int(sc) != 0) { + mpr_dprint(sc, MPR_FAULT, "Timeout reading doorbell 0\n"); + return (ENXIO); + } + data16[0] = + mpr_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_DATA_MASK; + mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); + if (mpr_wait_db_int(sc) != 0) { + mpr_dprint(sc, MPR_FAULT, "Timeout reading doorbell 1\n"); + return (ENXIO); + } + data16[1] = + mpr_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_DATA_MASK; + mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); + + /* Number of 32bit words in the message */ + ioc_sz = reply->MsgLength; + + /* + * Figure out how many 16bit words to clock in without overrunning. + * The precision loss with dividing reply_sz can safely be + * ignored because the messages can only be multiples of 32bits. + */ + residual = 0; + count = MIN((reply_sz / 4), ioc_sz) * 2; + if (count < ioc_sz * 2) { + residual = ioc_sz * 2 - count; + mpr_dprint(sc, MPR_ERROR, "Driver error, throwing away %d " + "residual message words\n", residual); + } + + for (i = 2; i < count; i++) { + if (mpr_wait_db_int(sc) != 0) { + mpr_dprint(sc, MPR_FAULT, + "Timeout reading doorbell %d\n", i); + return (ENXIO); + } + data16[i] = mpr_regread(sc, MPI2_DOORBELL_OFFSET) & + MPI2_DOORBELL_DATA_MASK; + mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); + } + + /* + * Pull out residual words that won't fit into the provided buffer. + * This keeps the chip from hanging due to a driver programming + * error. + */ + while (residual--) { + if (mpr_wait_db_int(sc) != 0) { + mpr_dprint(sc, MPR_FAULT, "Timeout reading doorbell\n"); + return (ENXIO); + } + (void)mpr_regread(sc, MPI2_DOORBELL_OFFSET); + mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); + } + + /* Step 7 */ + if (mpr_wait_db_int(sc) != 0) { + mpr_dprint(sc, MPR_FAULT, "Timeout waiting to exit doorbell\n"); + return (ENXIO); + } + if (mpr_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED) + mpr_dprint(sc, MPR_FAULT, "Warning, doorbell still active\n"); + mpr_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); + + return (0); +} + +static void +mpr_enqueue_request(struct mpr_softc *sc, struct mpr_command *cm) +{ + reply_descriptor rd; + + MPR_FUNCTRACE(sc); + mpr_dprint(sc, MPR_TRACE, "%s SMID %u cm %p ccb %p\n", __func__, + cm->cm_desc.Default.SMID, cm, cm->cm_ccb); + + if (sc->mpr_flags & MPR_FLAGS_ATTACH_DONE && !(sc->mpr_flags & + MPR_FLAGS_SHUTDOWN)) + mtx_assert(&sc->mpr_mtx, MA_OWNED); + + if (++sc->io_cmds_active > sc->io_cmds_highwater) + sc->io_cmds_highwater++; + + rd.u.low = cm->cm_desc.Words.Low; + rd.u.high = cm->cm_desc.Words.High; + rd.word = htole64(rd.word); + /* TODO-We may need to make below regwrite atomic */ + mpr_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET, + rd.u.low); + mpr_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET, + rd.u.high); +} + +/* + * Just the FACTS, ma'am. + */ +static int +mpr_get_iocfacts(struct mpr_softc *sc, MPI2_IOC_FACTS_REPLY *facts) +{ + MPI2_DEFAULT_REPLY *reply; + MPI2_IOC_FACTS_REQUEST request; + int error, req_sz, reply_sz; + + MPR_FUNCTRACE(sc); + + req_sz = sizeof(MPI2_IOC_FACTS_REQUEST); + reply_sz = sizeof(MPI2_IOC_FACTS_REPLY); + reply = (MPI2_DEFAULT_REPLY *)facts; + + bzero(&request, req_sz); + request.Function = MPI2_FUNCTION_IOC_FACTS; + error = mpr_request_sync(sc, &request, reply, req_sz, reply_sz, 5); + + return (error); +} + +static int +mpr_send_iocinit(struct mpr_softc *sc) +{ + MPI2_IOC_INIT_REQUEST init; + MPI2_DEFAULT_REPLY reply; + int req_sz, reply_sz, error; + struct timeval now; + uint64_t time_in_msec; + + MPR_FUNCTRACE(sc); + + req_sz = sizeof(MPI2_IOC_INIT_REQUEST); + reply_sz = sizeof(MPI2_IOC_INIT_REPLY); + bzero(&init, req_sz); + bzero(&reply, reply_sz); + + /* + * Fill in the init block. Note that most addresses are + * deliberately in the lower 32bits of memory. This is a micro- + * optimzation for PCI/PCIX, though it's not clear if it helps PCIe. + */ + init.Function = MPI2_FUNCTION_IOC_INIT; + init.WhoInit = MPI2_WHOINIT_HOST_DRIVER; + init.MsgVersion = htole16(MPI2_VERSION); + init.HeaderVersion = htole16(MPI2_HEADER_VERSION); + init.SystemRequestFrameSize = htole16(sc->facts->IOCRequestFrameSize); + init.ReplyDescriptorPostQueueDepth = htole16(sc->pqdepth); + init.ReplyFreeQueueDepth = htole16(sc->fqdepth); + init.SenseBufferAddressHigh = 0; + init.SystemReplyAddressHigh = 0; + init.SystemRequestFrameBaseAddress.High = 0; + init.SystemRequestFrameBaseAddress.Low = + htole32((uint32_t)sc->req_busaddr); + init.ReplyDescriptorPostQueueAddress.High = 0; + init.ReplyDescriptorPostQueueAddress.Low = + htole32((uint32_t)sc->post_busaddr); + init.ReplyFreeQueueAddress.High = 0; + init.ReplyFreeQueueAddress.Low = htole32((uint32_t)sc->free_busaddr); + getmicrotime(&now); + time_in_msec = (now.tv_sec * 1000 + now.tv_usec/1000); + init.TimeStamp.High = htole32((time_in_msec >> 32) & 0xFFFFFFFF); + init.TimeStamp.Low = htole32(time_in_msec & 0xFFFFFFFF); + + error = mpr_request_sync(sc, &init, &reply, req_sz, reply_sz, 5); + if ((reply.IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) + error = ENXIO; + + mpr_dprint(sc, MPR_INIT, "IOCInit status= 0x%x\n", reply.IOCStatus); + return (error); +} + +void +mpr_memaddr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + bus_addr_t *addr; + + addr = arg; + *addr = segs[0].ds_addr; +} + +static int +mpr_alloc_queues(struct mpr_softc *sc) +{ + bus_addr_t queues_busaddr; + uint8_t *queues; + int qsize, fqsize, pqsize; + + /* + * The reply free queue contains 4 byte entries in multiples of 16 and + * aligned on a 16 byte boundary. There must always be an unused entry. + * This queue supplies fresh reply frames for the firmware to use. + * + * The reply descriptor post queue contains 8 byte entries in + * multiples of 16 and aligned on a 16 byte boundary. This queue + * contains filled-in reply frames sent from the firmware to the host. + * + * These two queues are allocated together for simplicity. + */ + sc->fqdepth = roundup2((sc->num_replies + 1), 16); + sc->pqdepth = roundup2((sc->num_replies + 1), 16); + fqsize= sc->fqdepth * 4; + pqsize = sc->pqdepth * 8; + qsize = fqsize + pqsize; + + if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ + 16, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + qsize, /* maxsize */ + 1, /* nsegments */ + qsize, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->queues_dmat)) { + device_printf(sc->mpr_dev, "Cannot allocate queues DMA tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->queues_dmat, (void **)&queues, BUS_DMA_NOWAIT, + &sc->queues_map)) { + device_printf(sc->mpr_dev, "Cannot allocate queues memory\n"); + return (ENOMEM); + } + bzero(queues, qsize); + bus_dmamap_load(sc->queues_dmat, sc->queues_map, queues, qsize, + mpr_memaddr_cb, &queues_busaddr, 0); + + sc->free_queue = (uint32_t *)queues; + sc->free_busaddr = queues_busaddr; + sc->post_queue = (MPI2_REPLY_DESCRIPTORS_UNION *)(queues + fqsize); + sc->post_busaddr = queues_busaddr + fqsize; + + return (0); +} + +static int +mpr_alloc_replies(struct mpr_softc *sc) +{ + int rsize, num_replies; + + /* + * sc->num_replies should be one less than sc->fqdepth. We need to + * allocate space for sc->fqdepth replies, but only sc->num_replies + * replies can be used at once. + */ + num_replies = max(sc->fqdepth, sc->num_replies); + + rsize = sc->facts->ReplyFrameSize * num_replies * 4; + if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ + 4, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + rsize, /* maxsize */ + 1, /* nsegments */ + rsize, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->reply_dmat)) { + device_printf(sc->mpr_dev, "Cannot allocate replies DMA tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->reply_dmat, (void **)&sc->reply_frames, + BUS_DMA_NOWAIT, &sc->reply_map)) { + device_printf(sc->mpr_dev, "Cannot allocate replies memory\n"); + return (ENOMEM); + } + bzero(sc->reply_frames, rsize); + bus_dmamap_load(sc->reply_dmat, sc->reply_map, sc->reply_frames, rsize, + mpr_memaddr_cb, &sc->reply_busaddr, 0); + + return (0); +} + +static int +mpr_alloc_requests(struct mpr_softc *sc) +{ + struct mpr_command *cm; + struct mpr_chain *chain; + int i, rsize, nsegs; + + rsize = sc->facts->IOCRequestFrameSize * sc->num_reqs * 4; + if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ + 16, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + rsize, /* maxsize */ + 1, /* nsegments */ + rsize, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->req_dmat)) { + device_printf(sc->mpr_dev, "Cannot allocate request DMA tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->req_dmat, (void **)&sc->req_frames, + BUS_DMA_NOWAIT, &sc->req_map)) { + device_printf(sc->mpr_dev, "Cannot allocate request memory\n"); + return (ENOMEM); + } + bzero(sc->req_frames, rsize); + bus_dmamap_load(sc->req_dmat, sc->req_map, sc->req_frames, rsize, + mpr_memaddr_cb, &sc->req_busaddr, 0); + + rsize = sc->facts->IOCRequestFrameSize * sc->max_chains * 4; + if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ + 16, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + rsize, /* maxsize */ + 1, /* nsegments */ + rsize, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->chain_dmat)) { + device_printf(sc->mpr_dev, "Cannot allocate chain DMA tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->chain_dmat, (void **)&sc->chain_frames, + BUS_DMA_NOWAIT, &sc->chain_map)) { + device_printf(sc->mpr_dev, "Cannot allocate chain memory\n"); + return (ENOMEM); + } + bzero(sc->chain_frames, rsize); + bus_dmamap_load(sc->chain_dmat, sc->chain_map, sc->chain_frames, rsize, + mpr_memaddr_cb, &sc->chain_busaddr, 0); + + rsize = MPR_SENSE_LEN * sc->num_reqs; + if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ + 1, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + rsize, /* maxsize */ + 1, /* nsegments */ + rsize, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->sense_dmat)) { + device_printf(sc->mpr_dev, "Cannot allocate sense DMA tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->sense_dmat, (void **)&sc->sense_frames, + BUS_DMA_NOWAIT, &sc->sense_map)) { + device_printf(sc->mpr_dev, "Cannot allocate sense memory\n"); + return (ENOMEM); + } + bzero(sc->sense_frames, rsize); + bus_dmamap_load(sc->sense_dmat, sc->sense_map, sc->sense_frames, rsize, + mpr_memaddr_cb, &sc->sense_busaddr, 0); + + sc->chains = malloc(sizeof(struct mpr_chain) * sc->max_chains, M_MPR, + M_WAITOK | M_ZERO); + if (!sc->chains) { + device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n", + __func__, __LINE__); + return (ENOMEM); + } + for (i = 0; i < sc->max_chains; i++) { + chain = &sc->chains[i]; + chain->chain = (MPI2_SGE_IO_UNION *)(sc->chain_frames + + i * sc->facts->IOCRequestFrameSize * 4); + chain->chain_busaddr = sc->chain_busaddr + + i * sc->facts->IOCRequestFrameSize * 4; + mpr_free_chain(sc, chain); + sc->chain_free_lowwater++; + } + + /* XXX Need to pick a more precise value */ + nsegs = (MAXPHYS / PAGE_SIZE) + 1; + if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ + 1, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ + nsegs, /* nsegments */ + BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + busdma_lock_mutex, /* lockfunc */ + &sc->mpr_mtx, /* lockarg */ + &sc->buffer_dmat)) { + device_printf(sc->mpr_dev, "Cannot allocate buffer DMA tag\n"); + return (ENOMEM); + } + + /* + * SMID 0 cannot be used as a free command per the firmware spec. + * Just drop that command instead of risking accounting bugs. + */ + sc->commands = malloc(sizeof(struct mpr_command) * sc->num_reqs, + M_MPR, M_WAITOK | M_ZERO); + if (!sc->commands) { + device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n", + __func__, __LINE__); + return (ENOMEM); + } + for (i = 1; i < sc->num_reqs; i++) { + cm = &sc->commands[i]; + cm->cm_req = sc->req_frames + + i * sc->facts->IOCRequestFrameSize * 4; + cm->cm_req_busaddr = sc->req_busaddr + + i * sc->facts->IOCRequestFrameSize * 4; + cm->cm_sense = &sc->sense_frames[i]; + cm->cm_sense_busaddr = sc->sense_busaddr + i * MPR_SENSE_LEN; + cm->cm_desc.Default.SMID = i; + cm->cm_sc = sc; + TAILQ_INIT(&cm->cm_chain_list); + callout_init_mtx(&cm->cm_callout, &sc->mpr_mtx, 0); + + /* XXX Is a failure here a critical problem? */ + if (bus_dmamap_create(sc->buffer_dmat, 0, &cm->cm_dmamap) == 0) + if (i <= sc->facts->HighPriorityCredit) + mpr_free_high_priority_command(sc, cm); + else + mpr_free_command(sc, cm); + else { + panic("failed to allocate command %d\n", i); + sc->num_reqs = i; + break; + } + } + + return (0); +} + +static int +mpr_init_queues(struct mpr_softc *sc) +{ + int i; + + memset((uint8_t *)sc->post_queue, 0xff, sc->pqdepth * 8); + + /* + * According to the spec, we need to use one less reply than we + * have space for on the queue. So sc->num_replies (the number we + * use) should be less than sc->fqdepth (allocated size). + */ + if (sc->num_replies >= sc->fqdepth) + return (EINVAL); + + /* + * Initialize all of the free queue entries. + */ + for (i = 0; i < sc->fqdepth; i++) + sc->free_queue[i] = sc->reply_busaddr + (i * sc->facts->ReplyFrameSize * 4); + sc->replyfreeindex = sc->num_replies; + + return (0); +} + +/* Get the driver parameter tunables. Lowest priority are the driver defaults. + * Next are the global settings, if they exist. Highest are the per-unit + * settings, if they exist. + */ +static void +mpr_get_tunables(struct mpr_softc *sc) +{ + char tmpstr[80]; + + /* XXX default to some debugging for now */ + sc->mpr_debug = MPR_INFO | MPR_FAULT; + sc->disable_msix = 0; + sc->disable_msi = 0; + sc->max_chains = MPR_CHAIN_FRAMES; + + /* + * Grab the global variables. + */ + TUNABLE_INT_FETCH("hw.mpr.debug_level", &sc->mpr_debug); + TUNABLE_INT_FETCH("hw.mpr.disable_msix", &sc->disable_msix); + TUNABLE_INT_FETCH("hw.mpr.disable_msi", &sc->disable_msi); + TUNABLE_INT_FETCH("hw.mpr.max_chains", &sc->max_chains); + + /* Grab the unit-instance variables */ + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.debug_level", + device_get_unit(sc->mpr_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->mpr_debug); + + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.disable_msix", + device_get_unit(sc->mpr_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->disable_msix); + + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.disable_msi", + device_get_unit(sc->mpr_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->disable_msi); + + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_chains", + device_get_unit(sc->mpr_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->max_chains); + + bzero(sc->exclude_ids, sizeof(sc->exclude_ids)); + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.exclude_ids", + device_get_unit(sc->mpr_dev)); + TUNABLE_STR_FETCH(tmpstr, sc->exclude_ids, sizeof(sc->exclude_ids)); +} + +static void +mpr_setup_sysctl(struct mpr_softc *sc) +{ + struct sysctl_ctx_list *sysctl_ctx = NULL; + struct sysctl_oid *sysctl_tree = NULL; + char tmpstr[80], tmpstr2[80]; + + /* + * Setup the sysctl variable so the user can change the debug level + * on the fly. + */ + snprintf(tmpstr, sizeof(tmpstr), "MPR controller %d", + device_get_unit(sc->mpr_dev)); + snprintf(tmpstr2, sizeof(tmpstr2), "%d", device_get_unit(sc->mpr_dev)); + + sysctl_ctx = device_get_sysctl_ctx(sc->mpr_dev); + if (sysctl_ctx != NULL) + sysctl_tree = device_get_sysctl_tree(sc->mpr_dev); + + if (sysctl_tree == NULL) { + sysctl_ctx_init(&sc->sysctl_ctx); + sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_hw_mpr), OID_AUTO, tmpstr2, + CTLFLAG_RD, 0, tmpstr); + if (sc->sysctl_tree == NULL) + return; + sysctl_ctx = &sc->sysctl_ctx; + sysctl_tree = sc->sysctl_tree; + } + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "debug_level", CTLFLAG_RW, &sc->mpr_debug, 0, + "mpr debug level"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "disable_msix", CTLFLAG_RD, &sc->disable_msix, 0, + "Disable the use of MSI-X interrupts"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "disable_msi", CTLFLAG_RD, &sc->disable_msi, 0, + "Disable the use of MSI interrupts"); + + SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "firmware_version", CTLFLAG_RW, &sc->fw_version, + strlen(sc->fw_version), "firmware version"); + + SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "driver_version", CTLFLAG_RW, MPR_DRIVER_VERSION, + strlen(MPR_DRIVER_VERSION), "driver version"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "io_cmds_active", CTLFLAG_RD, + &sc->io_cmds_active, 0, "number of currently active commands"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "io_cmds_highwater", CTLFLAG_RD, + &sc->io_cmds_highwater, 0, "maximum active commands seen"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "chain_free", CTLFLAG_RD, + &sc->chain_free, 0, "number of free chain elements"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "chain_free_lowwater", CTLFLAG_RD, + &sc->chain_free_lowwater, 0,"lowest number of free chain elements"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "max_chains", CTLFLAG_RD, + &sc->max_chains, 0,"maximum chain frames that will be allocated"); + +#if __FreeBSD_version >= 900030 + SYSCTL_ADD_UQUAD(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "chain_alloc_fail", CTLFLAG_RD, + &sc->chain_alloc_fail, "chain allocation failures"); +#endif //FreeBSD_version >= 900030 +} + +int +mpr_attach(struct mpr_softc *sc) +{ + int error; + + mpr_get_tunables(sc); + + MPR_FUNCTRACE(sc); + + mtx_init(&sc->mpr_mtx, "MPR lock", NULL, MTX_DEF); + callout_init_mtx(&sc->periodic, &sc->mpr_mtx, 0); + TAILQ_INIT(&sc->event_list); + timevalclear(&sc->lastfail); + + if ((error = mpr_transition_ready(sc)) != 0) { + mpr_printf(sc, "%s failed to transition ready\n", __func__); + return (error); + } + + sc->facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY), M_MPR, + M_ZERO|M_NOWAIT); + if (!sc->facts) { + device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n", + __func__, __LINE__); + return (ENOMEM); + } + + /* + * Get IOC Facts and allocate all structures based on this information. + * A Diag Reset will also call mpr_iocfacts_allocate and re-read the IOC + * Facts. If relevant values have changed in IOC Facts, this function + * will free all of the memory based on IOC Facts and reallocate that + * memory. If this fails, any allocated memory should already be freed. + */ + if ((error = mpr_iocfacts_allocate(sc, TRUE)) != 0) { + mpr_dprint(sc, MPR_FAULT, "%s IOC Facts based allocation " + "failed with error %d\n", __func__, error); + return (error); + } + + /* Start the periodic watchdog check on the IOC Doorbell */ + mpr_periodic(sc); + + /* + * The portenable will kick off discovery events that will drive the + * rest of the initialization process. The CAM/SAS module will + * hold up the boot sequence until discovery is complete. + */ + sc->mpr_ich.ich_func = mpr_startup; + sc->mpr_ich.ich_arg = sc; + if (config_intrhook_establish(&sc->mpr_ich) != 0) { + mpr_dprint(sc, MPR_ERROR, "Cannot establish MPR config hook\n"); + error = EINVAL; + } + + /* + * Allow IR to shutdown gracefully when shutdown occurs. + */ + sc->shutdown_eh = EVENTHANDLER_REGISTER(shutdown_final, + mprsas_ir_shutdown, sc, SHUTDOWN_PRI_DEFAULT); + + if (sc->shutdown_eh == NULL) + mpr_dprint(sc, MPR_ERROR, "shutdown event registration " + "failed\n"); + + mpr_setup_sysctl(sc); + + sc->mpr_flags |= MPR_FLAGS_ATTACH_DONE; + + return (error); +} + +/* Run through any late-start handlers. */ +static void +mpr_startup(void *arg) +{ + struct mpr_softc *sc; + + sc = (struct mpr_softc *)arg; + + mpr_lock(sc); + mpr_unmask_intr(sc); + + /* initialize device mapping tables */ + mpr_base_static_config_pages(sc); + mpr_mapping_initialize(sc); + mprsas_startup(sc); + mpr_unlock(sc); +} + +/* Periodic watchdog. Is called with the driver lock already held. */ +static void +mpr_periodic(void *arg) +{ + struct mpr_softc *sc; + uint32_t db; + + sc = (struct mpr_softc *)arg; + if (sc->mpr_flags & MPR_FLAGS_SHUTDOWN) + return; + + db = mpr_regread(sc, MPI2_DOORBELL_OFFSET); + if ((db & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { + if ((db & MPI2_DOORBELL_FAULT_CODE_MASK) == + IFAULT_IOP_OVER_TEMP_THRESHOLD_EXCEEDED) { + panic("TEMPERATURE FAULT: STOPPING."); + } + mpr_dprint(sc, MPR_FAULT, "IOC Fault 0x%08x, Resetting\n", db); + mpr_reinit(sc); + } + + callout_reset(&sc->periodic, MPR_PERIODIC_DELAY * hz, mpr_periodic, sc); +} + +static void +mpr_log_evt_handler(struct mpr_softc *sc, uintptr_t data, + MPI2_EVENT_NOTIFICATION_REPLY *event) +{ + MPI2_EVENT_DATA_LOG_ENTRY_ADDED *entry; + + mpr_print_event(sc, event); + + switch (event->Event) { + case MPI2_EVENT_LOG_DATA: + mpr_dprint(sc, MPR_EVENT, "MPI2_EVENT_LOG_DATA:\n"); + if (sc->mpr_debug & MPR_EVENT) + hexdump(event->EventData, event->EventDataLength, NULL, + 0); + break; + case MPI2_EVENT_LOG_ENTRY_ADDED: + entry = (MPI2_EVENT_DATA_LOG_ENTRY_ADDED *)event->EventData; + mpr_dprint(sc, MPR_EVENT, "MPI2_EVENT_LOG_ENTRY_ADDED event " + "0x%x Sequence %d:\n", entry->LogEntryQualifier, + entry->LogSequence); + break; + default: + break; + } + return; +} + +static int +mpr_attach_log(struct mpr_softc *sc) +{ + uint8_t events[16]; + + bzero(events, 16); + setbit(events, MPI2_EVENT_LOG_DATA); + setbit(events, MPI2_EVENT_LOG_ENTRY_ADDED); + + mpr_register_events(sc, events, mpr_log_evt_handler, NULL, + &sc->mpr_log_eh); + + return (0); +} + +static int +mpr_detach_log(struct mpr_softc *sc) +{ + + if (sc->mpr_log_eh != NULL) + mpr_deregister_events(sc, sc->mpr_log_eh); + return (0); +} + +/* + * Free all of the driver resources and detach submodules. Should be called + * without the lock held. + */ +int +mpr_free(struct mpr_softc *sc) +{ + int error; + + /* Turn off the watchdog */ + mpr_lock(sc); + sc->mpr_flags |= MPR_FLAGS_SHUTDOWN; + mpr_unlock(sc); + /* Lock must not be held for this */ + callout_drain(&sc->periodic); + + if (((error = mpr_detach_log(sc)) != 0) || + ((error = mpr_detach_sas(sc)) != 0)) + return (error); + + mpr_detach_user(sc); + + /* Put the IOC back in the READY state. */ + mpr_lock(sc); + if ((error = mpr_transition_ready(sc)) != 0) { + mpr_unlock(sc); + return (error); + } + mpr_unlock(sc); + + if (sc->facts != NULL) + free(sc->facts, M_MPR); + + /* + * Free all buffers that are based on IOC Facts. A Diag Reset may need + * to free these buffers too. + */ + mpr_iocfacts_free(sc); + + if (sc->sysctl_tree != NULL) + sysctl_ctx_free(&sc->sysctl_ctx); + + /* Deregister the shutdown function */ + if (sc->shutdown_eh != NULL) + EVENTHANDLER_DEREGISTER(shutdown_final, sc->shutdown_eh); + + mtx_destroy(&sc->mpr_mtx); + + return (0); +} + +static __inline void +mpr_complete_command(struct mpr_softc *sc, struct mpr_command *cm) +{ + MPR_FUNCTRACE(sc); + + if (cm == NULL) { + mpr_dprint(sc, MPR_ERROR, "Completing NULL command\n"); + return; + } + + if (cm->cm_flags & MPR_CM_FLAGS_POLLED) + cm->cm_flags |= MPR_CM_FLAGS_COMPLETE; + + if (cm->cm_complete != NULL) { + mpr_dprint(sc, MPR_TRACE, + "%s cm %p calling cm_complete %p data %p reply %p\n", + __func__, cm, cm->cm_complete, cm->cm_complete_data, + cm->cm_reply); + cm->cm_complete(sc, cm); + } + + if (cm->cm_flags & MPR_CM_FLAGS_WAKEUP) { + mpr_dprint(sc, MPR_TRACE, "waking up %p\n", cm); + wakeup(cm); + } + + if (sc->io_cmds_active != 0) { + sc->io_cmds_active--; + } else { + mpr_dprint(sc, MPR_ERROR, "Warning: io_cmds_active is " + "out of sync - resynching to 0\n"); + } +} + +static void +mpr_sas_log_info(struct mpr_softc *sc , u32 log_info) +{ + union loginfo_type { + u32 loginfo; + struct { + u32 subcode:16; + u32 code:8; + u32 originator:4; + u32 bus_type:4; + } dw; + }; + union loginfo_type sas_loginfo; + char *originator_str = NULL; + + sas_loginfo.loginfo = log_info; + if (sas_loginfo.dw.bus_type != 3 /*SAS*/) + return; + + /* each nexus loss loginfo */ + if (log_info == 0x31170000) + return; + + /* eat the loginfos associated with task aborts */ + if ((log_info == 30050000) || (log_info == 0x31140000) || + (log_info == 0x31130000)) + return; + + switch (sas_loginfo.dw.originator) { + case 0: + originator_str = "IOP"; + break; + case 1: + originator_str = "PL"; + break; + case 2: + originator_str = "IR"; + break; + } + + mpr_dprint(sc, MPR_INFO, "log_info(0x%08x): originator(%s), " + "code(0x%02x), sub_code(0x%04x)\n", log_info, + originator_str, sas_loginfo.dw.code, + sas_loginfo.dw.subcode); +} + +static void +mpr_display_reply_info(struct mpr_softc *sc, uint8_t *reply) +{ + MPI2DefaultReply_t *mpi_reply; + u16 sc_status; + + mpi_reply = (MPI2DefaultReply_t*)reply; + sc_status = le16toh(mpi_reply->IOCStatus); + if (sc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) + mpr_sas_log_info(sc, le32toh(mpi_reply->IOCLogInfo)); +} + +void +mpr_intr(void *data) +{ + struct mpr_softc *sc; + uint32_t status; + + sc = (struct mpr_softc *)data; + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + /* + * Check interrupt status register to flush the bus. This is + * needed for both INTx interrupts and driver-driven polling + */ + status = mpr_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET); + if ((status & MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT) == 0) + return; + + mpr_lock(sc); + mpr_intr_locked(data); + mpr_unlock(sc); + return; +} + +/* + * In theory, MSI/MSIX interrupts shouldn't need to read any registers on the + * chip. Hopefully this theory is correct. + */ +void +mpr_intr_msi(void *data) +{ + struct mpr_softc *sc; + + sc = (struct mpr_softc *)data; + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + mpr_lock(sc); + mpr_intr_locked(data); + mpr_unlock(sc); + return; +} + +/* + * The locking is overly broad and simplistic, but easy to deal with for now. + */ +void +mpr_intr_locked(void *data) +{ + MPI2_REPLY_DESCRIPTORS_UNION *desc; + struct mpr_softc *sc; + struct mpr_command *cm = NULL; + uint8_t flags; + u_int pq; + MPI2_DIAG_RELEASE_REPLY *rel_rep; + mpr_fw_diagnostic_buffer_t *pBuffer; + + sc = (struct mpr_softc *)data; + + pq = sc->replypostindex; + mpr_dprint(sc, MPR_TRACE, + "%s sc %p starting with replypostindex %u\n", + __func__, sc, sc->replypostindex); + + for ( ;; ) { + cm = NULL; + desc = &sc->post_queue[sc->replypostindex]; + flags = desc->Default.ReplyFlags & + MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; + if ((flags == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) || + (le32toh(desc->Words.High) == 0xffffffff)) + break; + + /* increment the replypostindex now, so that event handlers + * and cm completion handlers which decide to do a diag + * reset can zero it without it getting incremented again + * afterwards, and we break out of this loop on the next + * iteration since the reply post queue has been cleared to + * 0xFF and all descriptors look unused (which they are). + */ + if (++sc->replypostindex >= sc->pqdepth) + sc->replypostindex = 0; + + switch (flags) { + case MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS: + case MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS: + cm = &sc->commands[le16toh(desc->SCSIIOSuccess.SMID)]; + cm->cm_reply = NULL; + break; + case MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY: + { + uint32_t baddr; + uint8_t *reply; + + /* + * Re-compose the reply address from the address + * sent back from the chip. The ReplyFrameAddress + * is the lower 32 bits of the physical address of + * particular reply frame. Convert that address to + * host format, and then use that to provide the + * offset against the virtual address base + * (sc->reply_frames). + */ + baddr = le32toh(desc->AddressReply.ReplyFrameAddress); + reply = sc->reply_frames + + (baddr - ((uint32_t)sc->reply_busaddr)); + /* + * Make sure the reply we got back is in a valid + * range. If not, go ahead and panic here, since + * we'll probably panic as soon as we deference the + * reply pointer anyway. + */ + if ((reply < sc->reply_frames) + || (reply > (sc->reply_frames + + (sc->fqdepth * sc->facts->ReplyFrameSize * 4)))) { + printf("%s: WARNING: reply %p out of range!\n", + __func__, reply); + printf("%s: reply_frames %p, fqdepth %d, " + "frame size %d\n", __func__, + sc->reply_frames, sc->fqdepth, + sc->facts->ReplyFrameSize * 4); + printf("%s: baddr %#x,\n", __func__, baddr); + /* LSI-TODO. See Linux Code for Graceful exit */ + panic("Reply address out of range"); + } + if (le16toh(desc->AddressReply.SMID) == 0) { + if (((MPI2_DEFAULT_REPLY *)reply)->Function == + MPI2_FUNCTION_DIAG_BUFFER_POST) { + /* + * If SMID is 0 for Diag Buffer Post, + * this implies that the reply is due to + * a release function with a status that + * the buffer has been released. Set + * the buffer flags accordingly. + */ + rel_rep = + (MPI2_DIAG_RELEASE_REPLY *)reply; + if (le16toh(rel_rep->IOCStatus) == + MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED) + { + pBuffer = + &sc->fw_diag_buffer_list[ + rel_rep->BufferType]; + pBuffer->valid_data = TRUE; + pBuffer->owned_by_firmware = + FALSE; + pBuffer->immediate = FALSE; + } + } else + mpr_dispatch_event(sc, baddr, + (MPI2_EVENT_NOTIFICATION_REPLY *) + reply); + } else { + cm = &sc->commands[ + le16toh(desc->AddressReply.SMID)]; + cm->cm_reply = reply; + cm->cm_reply_data = + le32toh(desc->AddressReply. + ReplyFrameAddress); + } + break; + } + case MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS: + case MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER: + case MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS: + default: + /* Unhandled */ + mpr_dprint(sc, MPR_ERROR, "Unhandled reply 0x%x\n", + desc->Default.ReplyFlags); + cm = NULL; + break; + } + + if (cm != NULL) { + // Print Error reply frame + if (cm->cm_reply) + mpr_display_reply_info(sc,cm->cm_reply); + mpr_complete_command(sc, cm); + } + + desc->Words.Low = 0xffffffff; + desc->Words.High = 0xffffffff; + } + + if (pq != sc->replypostindex) { + mpr_dprint(sc, MPR_TRACE, + "%s sc %p writing postindex %d\n", + __func__, sc, sc->replypostindex); + mpr_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, + sc->replypostindex); + } + + return; +} + +static void +mpr_dispatch_event(struct mpr_softc *sc, uintptr_t data, + MPI2_EVENT_NOTIFICATION_REPLY *reply) +{ + struct mpr_event_handle *eh; + int event, handled = 0; + + event = le16toh(reply->Event); + TAILQ_FOREACH(eh, &sc->event_list, eh_list) { + if (isset(eh->mask, event)) { + eh->callback(sc, data, reply); + handled++; + } + } + + if (handled == 0) + mpr_dprint(sc, MPR_EVENT, "Unhandled event 0x%x\n", + le16toh(event)); + + /* + * This is the only place that the event/reply should be freed. + * Anything wanting to hold onto the event data should have + * already copied it into their own storage. + */ + mpr_free_reply(sc, data); +} + +static void +mpr_reregister_events_complete(struct mpr_softc *sc, struct mpr_command *cm) +{ + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + if (cm->cm_reply) + mpr_print_event(sc, + (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply); + + mpr_free_command(sc, cm); + + /* next, send a port enable */ + mprsas_startup(sc); +} + +/* + * For both register_events and update_events, the caller supplies a bitmap + * of events that it _wants_. These functions then turn that into a bitmask + * suitable for the controller. + */ +int +mpr_register_events(struct mpr_softc *sc, uint8_t *mask, + mpr_evt_callback_t *cb, void *data, struct mpr_event_handle **handle) +{ + struct mpr_event_handle *eh; + int error = 0; + + eh = malloc(sizeof(struct mpr_event_handle), M_MPR, M_WAITOK|M_ZERO); + if (!eh) { + device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n", + __func__, __LINE__); + return (ENOMEM); + } + eh->callback = cb; + eh->data = data; + TAILQ_INSERT_TAIL(&sc->event_list, eh, eh_list); + if (mask != NULL) + error = mpr_update_events(sc, eh, mask); + *handle = eh; + + return (error); +} + +int +mpr_update_events(struct mpr_softc *sc, struct mpr_event_handle *handle, + uint8_t *mask) +{ + MPI2_EVENT_NOTIFICATION_REQUEST *evtreq; + MPI2_EVENT_NOTIFICATION_REPLY *reply; + struct mpr_command *cm; + struct mpr_event_handle *eh; + int error, i; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + if ((mask != NULL) && (handle != NULL)) + bcopy(mask, &handle->mask[0], 16); + memset(sc->event_mask, 0xff, 16); + + TAILQ_FOREACH(eh, &sc->event_list, eh_list) { + for (i = 0; i < 16; i++) + sc->event_mask[i] &= ~eh->mask[i]; + } + + if ((cm = mpr_alloc_command(sc)) == NULL) + return (EBUSY); + evtreq = (MPI2_EVENT_NOTIFICATION_REQUEST *)cm->cm_req; + evtreq->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; + evtreq->MsgFlags = 0; + evtreq->SASBroadcastPrimitiveMasks = 0; +#ifdef MPR_DEBUG_ALL_EVENTS + { + u_char fullmask[16]; + memset(fullmask, 0x00, 16); + bcopy(fullmask, (uint8_t *)&evtreq->EventMasks, 16); + } +#else + bcopy(sc->event_mask, (uint8_t *)&evtreq->EventMasks, 16); +#endif + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + + error = mpr_request_polled(sc, cm); + reply = (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply; + if ((reply == NULL) || + (reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) + error = ENXIO; + + if(reply) + mpr_print_event(sc, reply); + + mpr_dprint(sc, MPR_TRACE, "%s finished error %d\n", __func__, error); + + mpr_free_command(sc, cm); + return (error); +} + +static int +mpr_reregister_events(struct mpr_softc *sc) +{ + MPI2_EVENT_NOTIFICATION_REQUEST *evtreq; + struct mpr_command *cm; + struct mpr_event_handle *eh; + int error, i; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + /* first, reregister events */ + + memset(sc->event_mask, 0xff, 16); + + TAILQ_FOREACH(eh, &sc->event_list, eh_list) { + for (i = 0; i < 16; i++) + sc->event_mask[i] &= ~eh->mask[i]; + } + + if ((cm = mpr_alloc_command(sc)) == NULL) + return (EBUSY); + evtreq = (MPI2_EVENT_NOTIFICATION_REQUEST *)cm->cm_req; + evtreq->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; + evtreq->MsgFlags = 0; + evtreq->SASBroadcastPrimitiveMasks = 0; +#ifdef MPR_DEBUG_ALL_EVENTS + { + u_char fullmask[16]; + memset(fullmask, 0x00, 16); + bcopy(fullmask, (uint8_t *)&evtreq->EventMasks, 16); + } +#else + bcopy(sc->event_mask, (uint8_t *)&evtreq->EventMasks, 16); +#endif + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + cm->cm_complete = mpr_reregister_events_complete; + + error = mpr_map_command(sc, cm); + + mpr_dprint(sc, MPR_TRACE, "%s finished with error %d\n", __func__, + error); + return (error); +} + +int +mpr_deregister_events(struct mpr_softc *sc, struct mpr_event_handle *handle) +{ + + TAILQ_REMOVE(&sc->event_list, handle, eh_list); + free(handle, M_MPR); + return (mpr_update_events(sc, NULL, NULL)); +} + +/* + * Add a chain element as the next SGE for the specified command. + * Reset cm_sge and cm_sgesize to indicate all the available space. Chains are + * only required for IEEE commands. Therefore there is no code for commands + * that have the MPR_CM_FLAGS_SGE_SIMPLE flag set (and those commands shouldn't + * be requesting chains). + */ +static int +mpr_add_chain(struct mpr_command *cm, int segsleft) +{ + struct mpr_softc *sc = cm->cm_sc; + MPI2_REQUEST_HEADER *req; + MPI25_IEEE_SGE_CHAIN64 *ieee_sgc; + struct mpr_chain *chain; + int space, sgc_size, current_segs, rem_segs, segs_per_frame; + uint8_t next_chain_offset = 0; + + /* + * Fail if a command is requesting a chain for SIMPLE SGE's. For SAS3 + * only IEEE commands should be requesting chains. Return some error + * code other than 0. + */ + if (cm->cm_flags & MPR_CM_FLAGS_SGE_SIMPLE) { + mpr_dprint(sc, MPR_ERROR, "A chain element cannot be added to " + "an MPI SGL.\n"); + return(ENOBUFS); + } + + sgc_size = sizeof(MPI25_IEEE_SGE_CHAIN64); + if (cm->cm_sglsize < sgc_size) + panic("MPR: Need SGE Error Code\n"); + + chain = mpr_alloc_chain(cm->cm_sc); + if (chain == NULL) + return (ENOBUFS); + + space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4; + + /* + * Note: a double-linked list is used to make it easier to walk for + * debugging. + */ + TAILQ_INSERT_TAIL(&cm->cm_chain_list, chain, chain_link); + + /* + * Need to know if the number of frames left is more than 1 or not. If + * more than 1 frame is required, NextChainOffset will need to be set, + * which will just be the last segment of the frame. + */ + rem_segs = 0; + if (cm->cm_sglsize < (sgc_size * segsleft)) { + /* + * rem_segs is the number of segements remaining after the + * segments that will go into the current frame. Since it is + * known that at least one more frame is required, account for + * the chain element. To know if more than one more frame is + * required, just check if there will be a remainder after using + * the current frame (with this chain) and the next frame. If + * so the NextChainOffset must be the last element of the next + * frame. + */ + current_segs = (cm->cm_sglsize / sgc_size) - 1; + rem_segs = segsleft - current_segs; + segs_per_frame = space / sgc_size; + if (rem_segs > segs_per_frame) { + next_chain_offset = segs_per_frame - 1; + } + } + ieee_sgc = &((MPI25_SGE_IO_UNION *)cm->cm_sge)->IeeeChain; + ieee_sgc->Length = next_chain_offset ? htole32((uint32_t)space) : + htole32((uint32_t)rem_segs * (uint32_t)sgc_size); + ieee_sgc->NextChainOffset = next_chain_offset; + ieee_sgc->Flags = (MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT | + MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); + ieee_sgc->Address.Low = htole32(chain->chain_busaddr); + ieee_sgc->Address.High = htole32(chain->chain_busaddr >> 32); + cm->cm_sge = &((MPI25_SGE_IO_UNION *)chain->chain)->IeeeSimple; + req = (MPI2_REQUEST_HEADER *)cm->cm_req; + req->ChainOffset = ((sc->facts->IOCRequestFrameSize * 4) - + sgc_size) >> 4; + + cm->cm_sglsize = space; + return (0); +} + +/* + * Add one scatter-gather element to the scatter-gather list for a command. + * Maintain cm_sglsize and cm_sge as the remaining size and pointer to the next + * SGE to fill in, respectively. In Gen3, the MPI SGL does not have a chain, + * so don't consider any chain additions. + */ +int +mpr_push_sge(struct mpr_command *cm, MPI2_SGE_SIMPLE64 *sge, size_t len, + int segsleft) +{ + uint32_t saved_buf_len, saved_address_low, saved_address_high; + u32 sge_flags; + + /* + * case 1: >=1 more segment, no room for anything (error) + * case 2: 1 more segment and enough room for it + */ + + if (cm->cm_sglsize < (segsleft * sizeof(MPI2_SGE_SIMPLE64))) { + mpr_dprint(cm->cm_sc, MPR_ERROR, + "%s: warning: Not enough room for MPI SGL in frame.\n", + __func__); + return(ENOBUFS); + } + + KASSERT(segsleft == 1, + ("segsleft cannot be more than 1 for an MPI SGL; segsleft = %d\n", + segsleft)); + + /* + * There is one more segment left to add for the MPI SGL and there is + * enough room in the frame to add it. This is the normal case because + * MPI SGL's don't have chains, otherwise something is wrong. + * + * If this is a bi-directional request, need to account for that + * here. Save the pre-filled sge values. These will be used + * either for the 2nd SGL or for a single direction SGL. If + * cm_out_len is non-zero, this is a bi-directional request, so + * fill in the OUT SGL first, then the IN SGL, otherwise just + * fill in the IN SGL. Note that at this time, when filling in + * 2 SGL's for a bi-directional request, they both use the same + * DMA buffer (same cm command). + */ + saved_buf_len = sge->FlagsLength & 0x00FFFFFF; + saved_address_low = sge->Address.Low; + saved_address_high = sge->Address.High; + if (cm->cm_out_len) { + sge->FlagsLength = cm->cm_out_len | + ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_END_OF_BUFFER | + MPI2_SGE_FLAGS_HOST_TO_IOC | + MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << + MPI2_SGE_FLAGS_SHIFT); + cm->cm_sglsize -= len; + /* Endian Safe code */ + sge_flags = sge->FlagsLength; + sge->FlagsLength = htole32(sge_flags); + sge->Address.High = htole32(sge->Address.High); + sge->Address.Low = htole32(sge->Address.Low); + bcopy(sge, cm->cm_sge, len); + cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len); + } + sge->FlagsLength = saved_buf_len | + ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_END_OF_BUFFER | + MPI2_SGE_FLAGS_LAST_ELEMENT | + MPI2_SGE_FLAGS_END_OF_LIST | + MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << + MPI2_SGE_FLAGS_SHIFT); + if (cm->cm_flags & MPR_CM_FLAGS_DATAIN) { + sge->FlagsLength |= + ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) << + MPI2_SGE_FLAGS_SHIFT); + } else { + sge->FlagsLength |= + ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) << + MPI2_SGE_FLAGS_SHIFT); + } + sge->Address.Low = saved_address_low; + sge->Address.High = saved_address_high; + + cm->cm_sglsize -= len; + /* Endian Safe code */ + sge_flags = sge->FlagsLength; + sge->FlagsLength = htole32(sge_flags); + sge->Address.High = htole32(sge->Address.High); + sge->Address.Low = htole32(sge->Address.Low); + bcopy(sge, cm->cm_sge, len); + cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len); + return (0); +} + +/* + * Add one IEEE scatter-gather element (chain or simple) to the IEEE scatter- + * gather list for a command. Maintain cm_sglsize and cm_sge as the + * remaining size and pointer to the next SGE to fill in, respectively. + */ +int +mpr_push_ieee_sge(struct mpr_command *cm, void *sgep, int segsleft) +{ + MPI2_IEEE_SGE_SIMPLE64 *sge = sgep; + int error, ieee_sge_size = sizeof(MPI25_SGE_IO_UNION); + uint32_t saved_buf_len, saved_address_low, saved_address_high; + uint32_t sge_length; + + /* + * case 1: No room for chain or segment (error). + * case 2: Two or more segments left but only room for chain. + * case 3: Last segment and room for it, so set flags. + */ + + /* + * There should be room for at least one element, or there is a big + * problem. + */ + if (cm->cm_sglsize < ieee_sge_size) + panic("MPR: Need SGE Error Code\n"); + + if ((segsleft >= 2) && (cm->cm_sglsize < (ieee_sge_size * 2))) { + if ((error = mpr_add_chain(cm, segsleft)) != 0) + return (error); + } + + if (segsleft == 1) { + /* + * If this is a bi-directional request, need to account for that + * here. Save the pre-filled sge values. These will be used + * either for the 2nd SGL or for a single direction SGL. If + * cm_out_len is non-zero, this is a bi-directional request, so + * fill in the OUT SGL first, then the IN SGL, otherwise just + * fill in the IN SGL. Note that at this time, when filling in + * 2 SGL's for a bi-directional request, they both use the same + * DMA buffer (same cm command). + */ + saved_buf_len = sge->Length; + saved_address_low = sge->Address.Low; + saved_address_high = sge->Address.High; + if (cm->cm_out_len) { + sge->Length = cm->cm_out_len; + sge->Flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); + cm->cm_sglsize -= ieee_sge_size; + /* Endian Safe code */ + sge_length = sge->Length; + sge->Length = htole32(sge_length); + sge->Address.High = htole32(sge->Address.High); + sge->Address.Low = htole32(sge->Address.Low); + bcopy(sgep, cm->cm_sge, ieee_sge_size); + cm->cm_sge = + (MPI25_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + + ieee_sge_size); + } + sge->Length = saved_buf_len; + sge->Flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR | + MPI25_IEEE_SGE_FLAGS_END_OF_LIST); + sge->Address.Low = saved_address_low; + sge->Address.High = saved_address_high; + } + + cm->cm_sglsize -= ieee_sge_size; + /* Endian Safe code */ + sge_length = sge->Length; + sge->Length = htole32(sge_length); + sge->Address.High = htole32(sge->Address.High); + sge->Address.Low = htole32(sge->Address.Low); + bcopy(sgep, cm->cm_sge, ieee_sge_size); + cm->cm_sge = (MPI25_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + + ieee_sge_size); + return (0); +} + +/* + * Add one dma segment to the scatter-gather list for a command. + */ +int +mpr_add_dmaseg(struct mpr_command *cm, vm_paddr_t pa, size_t len, u_int flags, + int segsleft) +{ + MPI2_SGE_SIMPLE64 sge; + MPI2_IEEE_SGE_SIMPLE64 ieee_sge; + + if (!(cm->cm_flags & MPR_CM_FLAGS_SGE_SIMPLE)) { + ieee_sge.Flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); + ieee_sge.Length = len; + mpr_from_u64(pa, &ieee_sge.Address); + + return (mpr_push_ieee_sge(cm, &ieee_sge, segsleft)); + } else { + /* + * This driver always uses 64-bit address elements for + * simplicity. + */ + flags |= MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_64_BIT_ADDRESSING; + /* Set Endian safe macro in mpr_push_sge */ + sge.FlagsLength = len | (flags << MPI2_SGE_FLAGS_SHIFT); + mpr_from_u64(pa, &sge.Address); + + return (mpr_push_sge(cm, &sge, sizeof sge, segsleft)); + } +} + +static void +mpr_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + struct mpr_softc *sc; + struct mpr_command *cm; + u_int i, dir, sflags; + + cm = (struct mpr_command *)arg; + sc = cm->cm_sc; + + /* + * In this case, just print out a warning and let the chip tell the + * user they did the wrong thing. + */ + if ((cm->cm_max_segs != 0) && (nsegs > cm->cm_max_segs)) { + mpr_dprint(sc, MPR_ERROR, + "%s: warning: busdma returned %d segments, " + "more than the %d allowed\n", __func__, nsegs, + cm->cm_max_segs); + } + + /* + * Set up DMA direction flags. Bi-directional requests are also handled + * here. In that case, both direction flags will be set. + */ + sflags = 0; + if (cm->cm_flags & MPR_CM_FLAGS_SMP_PASS) { + /* + * We have to add a special case for SMP passthrough, there + * is no easy way to generically handle it. The first + * S/G element is used for the command (therefore the + * direction bit needs to be set). The second one is used + * for the reply. We'll leave it to the caller to make + * sure we only have two buffers. + */ + /* + * Even though the busdma man page says it doesn't make + * sense to have both direction flags, it does in this case. + * We have one s/g element being accessed in each direction. + */ + dir = BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD; + + /* + * Set the direction flag on the first buffer in the SMP + * passthrough request. We'll clear it for the second one. + */ + sflags |= MPI2_SGE_FLAGS_DIRECTION | + MPI2_SGE_FLAGS_END_OF_BUFFER; + } else if (cm->cm_flags & MPR_CM_FLAGS_DATAOUT) { + sflags |= MPI2_SGE_FLAGS_HOST_TO_IOC; + dir = BUS_DMASYNC_PREWRITE; + } else + dir = BUS_DMASYNC_PREREAD; + + for (i = 0; i < nsegs; i++) { + if ((cm->cm_flags & MPR_CM_FLAGS_SMP_PASS) && (i != 0)) { + sflags &= ~MPI2_SGE_FLAGS_DIRECTION; + } + error = mpr_add_dmaseg(cm, segs[i].ds_addr, segs[i].ds_len, + sflags, nsegs - i); + if (error != 0) { + /* Resource shortage, roll back! */ + if (ratecheck(&sc->lastfail, &mpr_chainfail_interval)) + mpr_dprint(sc, MPR_INFO, "Out of chain frames, " + "consider increasing hw.mpr.max_chains.\n"); + cm->cm_flags |= MPR_CM_FLAGS_CHAIN_FAILED; + mpr_complete_command(sc, cm); + return; + } + } + + bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); + mpr_enqueue_request(sc, cm); + + return; +} + +static void +mpr_data_cb2(void *arg, bus_dma_segment_t *segs, int nsegs, bus_size_t mapsize, + int error) +{ + mpr_data_cb(arg, segs, nsegs, error); +} + +/* + * This is the routine to enqueue commands ansynchronously. + * Note that the only error path here is from bus_dmamap_load(), which can + * return EINPROGRESS if it is waiting for resources. Other than this, it's + * assumed that if you have a command in-hand, then you have enough credits + * to use it. + */ +int +mpr_map_command(struct mpr_softc *sc, struct mpr_command *cm) +{ + int error = 0; + + if (cm->cm_flags & MPR_CM_FLAGS_USE_UIO) { + error = bus_dmamap_load_uio(sc->buffer_dmat, cm->cm_dmamap, + &cm->cm_uio, mpr_data_cb2, cm, 0); + } else if (cm->cm_flags & MPR_CM_FLAGS_USE_CCB) { + error = bus_dmamap_load_ccb(sc->buffer_dmat, cm->cm_dmamap, + cm->cm_data, mpr_data_cb, cm, 0); + } else if ((cm->cm_data != NULL) && (cm->cm_length != 0)) { + error = bus_dmamap_load(sc->buffer_dmat, cm->cm_dmamap, + cm->cm_data, cm->cm_length, mpr_data_cb, cm, 0); + } else { + /* Add a zero-length element as needed */ + if (cm->cm_sge != NULL) + mpr_add_dmaseg(cm, 0, 0, 0, 1); + mpr_enqueue_request(sc, cm); + } + + return (error); +} + +/* + * This is the routine to enqueue commands synchronously. An error of + * EINPROGRESS from mpr_map_command() is ignored since the command will + * be executed and enqueued automatically. Other errors come from msleep(). + */ +int +mpr_wait_command(struct mpr_softc *sc, struct mpr_command *cm, int timeout, + int sleep_flag) +{ + int error, rc; + struct timeval cur_time, start_time; + + if (sc->mpr_flags & MPR_FLAGS_DIAGRESET) + return EBUSY; + + cm->cm_complete = NULL; + cm->cm_flags |= (MPR_CM_FLAGS_WAKEUP + MPR_CM_FLAGS_POLLED); + error = mpr_map_command(sc, cm); + if ((error != 0) && (error != EINPROGRESS)) + return (error); + + // Check for context and wait for 50 mSec at a time until time has + // expired or the command has finished. If msleep can't be used, need + // to poll. +#if __FreeBSD_version >= 1000029 + if (curthread->td_no_sleeping) +#else //__FreeBSD_version < 1000029 + if (curthread->td_pflags & TDP_NOSLEEPING) +#endif //__FreeBSD_version >= 1000029 + sleep_flag = NO_SLEEP; + getmicrotime(&start_time); + if (mtx_owned(&sc->mpr_mtx) && sleep_flag == CAN_SLEEP) { + error = msleep(cm, &sc->mpr_mtx, 0, "mprwait", timeout*hz); + } else { + while ((cm->cm_flags & MPR_CM_FLAGS_COMPLETE) == 0) { + mpr_intr_locked(sc); + if (sleep_flag == CAN_SLEEP) + pause("mprwait", hz/20); + else + DELAY(50000); + + getmicrotime(&cur_time); + if ((cur_time.tv_sec - start_time.tv_sec) > timeout) { + error = EWOULDBLOCK; + break; + } + } + } + + if (error == EWOULDBLOCK) { + mpr_dprint(sc, MPR_FAULT, "Calling Reinit from %s\n", __func__); + rc = mpr_reinit(sc); + mpr_dprint(sc, MPR_FAULT, "Reinit %s\n", (rc == 0) ? "success" : + "failed"); + error = ETIMEDOUT; + } + return (error); +} + +/* + * This is the routine to enqueue a command synchonously and poll for + * completion. Its use should be rare. + */ +int +mpr_request_polled(struct mpr_softc *sc, struct mpr_command *cm) +{ + int error, timeout = 0, rc; + struct timeval cur_time, start_time; + + error = 0; + + cm->cm_flags |= MPR_CM_FLAGS_POLLED; + cm->cm_complete = NULL; + mpr_map_command(sc, cm); + + getmicrotime(&start_time); + while ((cm->cm_flags & MPR_CM_FLAGS_COMPLETE) == 0) { + mpr_intr_locked(sc); + + if (mtx_owned(&sc->mpr_mtx)) + msleep(&sc->msleep_fake_chan, &sc->mpr_mtx, 0, + "mprpoll", hz/20); + else + pause("mprpoll", hz/20); + + /* + * Check for real-time timeout and fail if more than 60 seconds. + */ + getmicrotime(&cur_time); + timeout = cur_time.tv_sec - start_time.tv_sec; + if (timeout > 60) { + mpr_dprint(sc, MPR_FAULT, "polling failed\n"); + error = ETIMEDOUT; + break; + } + } + + if(error) { + mpr_dprint(sc, MPR_FAULT, "Calling Reinit from %s\n", __func__); + rc = mpr_reinit(sc); + mpr_dprint(sc, MPR_FAULT, "Reinit %s\n", (rc == 0) ? + "success" : "failed"); + } + return (error); +} + +/* + * The MPT driver had a verbose interface for config pages. In this driver, + * reduce it to much simplier terms, similar to the Linux driver. + */ +int +mpr_read_config_page(struct mpr_softc *sc, struct mpr_config_params *params) +{ + MPI2_CONFIG_REQUEST *req; + struct mpr_command *cm; + int error; + + if (sc->mpr_flags & MPR_FLAGS_BUSY) { + return (EBUSY); + } + + cm = mpr_alloc_command(sc); + if (cm == NULL) { + return (EBUSY); + } + + req = (MPI2_CONFIG_REQUEST *)cm->cm_req; + req->Function = MPI2_FUNCTION_CONFIG; + req->Action = params->action; + req->SGLFlags = 0; + req->ChainOffset = 0; + req->PageAddress = params->page_address; + if (params->hdr.Struct.PageType == MPI2_CONFIG_PAGETYPE_EXTENDED) { + MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr; + + hdr = ¶ms->hdr.Ext; + req->ExtPageType = hdr->ExtPageType; + req->ExtPageLength = hdr->ExtPageLength; + req->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + req->Header.PageLength = 0; /* Must be set to zero */ + req->Header.PageNumber = hdr->PageNumber; + req->Header.PageVersion = hdr->PageVersion; + } else { + MPI2_CONFIG_PAGE_HEADER *hdr; + + hdr = ¶ms->hdr.Struct; + req->Header.PageType = hdr->PageType; + req->Header.PageNumber = hdr->PageNumber; + req->Header.PageLength = hdr->PageLength; + req->Header.PageVersion = hdr->PageVersion; + } + + cm->cm_data = params->buffer; + cm->cm_length = params->length; + cm->cm_sge = &req->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + + cm->cm_complete_data = params; + if (params->callback != NULL) { + cm->cm_complete = mpr_config_complete; + return (mpr_map_command(sc, cm)); + } else { + error = mpr_wait_command(sc, cm, 0, CAN_SLEEP); + if (error) { + mpr_dprint(sc, MPR_FAULT, + "Error %d reading config page\n", error); + mpr_free_command(sc, cm); + return (error); + } + mpr_config_complete(sc, cm); + } + + return (0); +} + +int +mpr_write_config_page(struct mpr_softc *sc, struct mpr_config_params *params) +{ + return (EINVAL); +} + +static void +mpr_config_complete(struct mpr_softc *sc, struct mpr_command *cm) +{ + MPI2_CONFIG_REPLY *reply; + struct mpr_config_params *params; + + MPR_FUNCTRACE(sc); + params = cm->cm_complete_data; + + if (cm->cm_data != NULL) { + bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); + } + + /* + * XXX KDM need to do more error recovery? This results in the + * device in question not getting probed. + */ + if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { + params->status = MPI2_IOCSTATUS_BUSY; + goto done; + } + + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (reply == NULL) { + params->status = MPI2_IOCSTATUS_BUSY; + goto done; + } + params->status = reply->IOCStatus; + if (params->hdr.Ext.ExtPageType != 0) { + params->hdr.Ext.ExtPageType = reply->ExtPageType; + params->hdr.Ext.ExtPageLength = reply->ExtPageLength; + } else { + params->hdr.Struct.PageType = reply->Header.PageType; + params->hdr.Struct.PageNumber = reply->Header.PageNumber; + params->hdr.Struct.PageLength = reply->Header.PageLength; + params->hdr.Struct.PageVersion = reply->Header.PageVersion; + } + +done: + mpr_free_command(sc, cm); + if (params->callback != NULL) + params->callback(sc, params); + + return; +} diff --git a/sys/dev/mpr/mpr_config.c b/sys/dev/mpr/mpr_config.c new file mode 100644 index 0000000000000..125451608dee7 --- /dev/null +++ b/sys/dev/mpr/mpr_config.c @@ -0,0 +1,1302 @@ +/*- + * Copyright (c) 2011-2014 LSI Corp. + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* TODO Move headers to mprvar */ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/kthread.h> +#include <sys/taskqueue.h> +#include <sys/bus.h> +#include <sys/endian.h> +#include <sys/sysctl.h> +#include <sys/eventhandler.h> +#include <sys/uio.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <dev/mpr/mpi/mpi2_type.h> +#include <dev/mpr/mpi/mpi2.h> +#include <dev/mpr/mpi/mpi2_ioc.h> +#include <dev/mpr/mpi/mpi2_sas.h> +#include <dev/mpr/mpi/mpi2_cnfg.h> +#include <dev/mpr/mpi/mpi2_init.h> +#include <dev/mpr/mpi/mpi2_tool.h> +#include <dev/mpr/mpr_ioctl.h> +#include <dev/mpr/mprvar.h> + +/** + * mpr_config_get_ioc_pg8 - obtain ioc page 8 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpr_config_get_ioc_pg8(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply, + Mpi2IOCPage8_t *config_page) +{ + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mpr_command *cm; + MPI2_CONFIG_PAGE_IOC_8 *page = NULL; + int error = 0; + u16 ioc_status; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC; + request->Header.PageNumber = 8; + request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mpr_wait_command(sc, cm, 60, CAN_SLEEP); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: request for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mpr_free_command(sc, cm); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC; + request->Header.PageNumber = 8; + request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION; + request->Header.PageLength = mpi_reply->Header.PageLength; + cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc((cm->cm_length), M_MPR, M_ZERO | M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + cm->cm_data = page; + + error = mpr_wait_command(sc, cm, 60, CAN_SLEEP); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: request for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: page read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + bcopy(page, config_page, MIN(cm->cm_length, (sizeof(Mpi2IOCPage8_t)))); + +out: + free(page, M_MPR); + if (cm) + mpr_free_command(sc, cm); + return (error); +} + +/** + * mpr_config_get_iounit_pg8 - obtain iounit page 8 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpr_config_get_iounit_pg8(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply, + Mpi2IOUnitPage8_t *config_page) +{ + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mpr_command *cm; + MPI2_CONFIG_PAGE_IO_UNIT_8 *page = NULL; + int error = 0; + u16 ioc_status; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; + request->Header.PageNumber = 8; + request->Header.PageVersion = MPI2_IOUNITPAGE8_PAGEVERSION; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mpr_wait_command(sc, cm, 60, CAN_SLEEP); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: request for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mpr_free_command(sc, cm); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; + request->Header.PageNumber = 8; + request->Header.PageVersion = MPI2_IOUNITPAGE8_PAGEVERSION; + request->Header.PageLength = mpi_reply->Header.PageLength; + cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc((cm->cm_length), M_MPR, M_ZERO | M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + cm->cm_data = page; + + error = mpr_wait_command(sc, cm, 60, CAN_SLEEP); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: request for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: page read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + bcopy(page, config_page, MIN(cm->cm_length, + (sizeof(Mpi2IOUnitPage8_t)))); + +out: + free(page, M_MPR); + if (cm) + mpr_free_command(sc, cm); + return (error); +} + +/** + * mpr_base_static_config_pages - static start of day config pages. + * @sc: per adapter object + * + * Return nothing. + */ +void +mpr_base_static_config_pages(struct mpr_softc *sc) +{ + Mpi2ConfigReply_t mpi_reply; + int retry; + + retry = 0; + while (mpr_config_get_ioc_pg8(sc, &mpi_reply, &sc->ioc_pg8)) { + retry++; + if (retry > 5) { + /* We need to Handle this situation */ + /*FIXME*/ + break; + } + } + retry = 0; + while (mpr_config_get_iounit_pg8(sc, &mpi_reply, &sc->iounit_pg8)) { + retry++; + if (retry > 5) { + /* We need to Handle this situation */ + /*FIXME*/ + break; + } + } +} + +/** + * mpr_config_get_dpm_pg0 - obtain driver persistent mapping page0 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @sz: size of buffer passed in config_page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpr_config_get_dpm_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply, + Mpi2DriverMappingPage0_t *config_page, u16 sz) +{ + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mpr_command *cm; + Mpi2DriverMappingPage0_t *page = NULL; + int error = 0; + u16 ioc_status; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + memset(config_page, 0, sz); + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING; + request->Header.PageNumber = 0; + request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION; + request->PageAddress = sc->max_dpm_entries << + MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mpr_wait_command(sc, cm, 60, CAN_SLEEP); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: request for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mpr_free_command(sc, cm); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_READ_NVRAM; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING; + request->Header.PageNumber = 0; + request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION; + request->PageAddress = sc->max_dpm_entries << + MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT; + request->ExtPageLength = mpi_reply->ExtPageLength; + cm->cm_length = le16toh(request->ExtPageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc(cm->cm_length, M_MPR, M_ZERO|M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + cm->cm_data = page; + error = mpr_wait_command(sc, cm, 60, CAN_SLEEP); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: request for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: page read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + bcopy(page, config_page, MIN(cm->cm_length, sz)); +out: + free(page, M_MPR); + if (cm) + mpr_free_command(sc, cm); + return (error); +} + +/** + * mpr_config_set_dpm_pg0 - write an entry in driver persistent mapping page0 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @entry_idx: entry index in DPM Page0 to be modified + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ + +int mpr_config_set_dpm_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply, + Mpi2DriverMappingPage0_t *config_page, u16 entry_idx) +{ + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mpr_command *cm; + MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 *page = NULL; + int error = 0; + u16 ioc_status; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING; + request->Header.PageNumber = 0; + request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION; + /* We can remove below two lines ????*/ + request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT; + request->PageAddress |= htole16(entry_idx); + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mpr_wait_command(sc, cm, 60, CAN_SLEEP); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: request for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mpr_free_command(sc, cm); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING; + request->Header.PageNumber = 0; + request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION; + request->ExtPageLength = mpi_reply->ExtPageLength; + request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT; + request->PageAddress |= htole16(entry_idx); + cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAOUT; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc(cm->cm_length, M_MPR, M_ZERO | M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + bcopy(config_page, page, MIN(cm->cm_length, + (sizeof(Mpi2DriverMappingPage0_t)))); + cm->cm_data = page; + error = mpr_wait_command(sc, cm, 60, CAN_SLEEP); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: request to write page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: page written with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } +out: + free(page, M_MPR); + if (cm) + mpr_free_command(sc, cm); + return (error); +} + +/** + * mpr_config_get_sas_device_pg0 - obtain sas device page 0 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @form: GET_NEXT_HANDLE or HANDLE + * @handle: device handle + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpr_config_get_sas_device_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u16 handle) +{ + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mpr_command *cm; + Mpi2SasDevicePage0_t *page = NULL; + int error = 0; + u16 ioc_status; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; + request->Header.PageNumber = 0; + request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mpr_wait_command(sc, cm, 60, CAN_SLEEP); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: request for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mpr_free_command(sc, cm); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; + request->Header.PageNumber = 0; + request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION; + request->ExtPageLength = mpi_reply->ExtPageLength; + request->PageAddress = htole32(form | handle); + cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc(cm->cm_length, M_MPR, M_ZERO | M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + cm->cm_data = page; + + error = mpr_wait_command(sc, cm, 60, CAN_SLEEP); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: request for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: page read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + bcopy(page, config_page, MIN(cm->cm_length, + sizeof(Mpi2SasDevicePage0_t))); +out: + free(page, M_MPR); + if (cm) + mpr_free_command(sc, cm); + return (error); +} + +/** + * mpr_config_get_bios_pg3 - obtain BIOS page 3 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpr_config_get_bios_pg3(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply, + Mpi2BiosPage3_t *config_page) +{ + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mpr_command *cm; + Mpi2BiosPage3_t *page = NULL; + int error = 0; + u16 ioc_status; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS; + request->Header.PageNumber = 3; + request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mpr_wait_command(sc, cm, 60, CAN_SLEEP); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: request for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mpr_free_command(sc, cm); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS; + request->Header.PageNumber = 3; + request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION; + request->Header.PageLength = mpi_reply->Header.PageLength; + cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc(cm->cm_length, M_MPR, M_ZERO | M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + cm->cm_data = page; + + error = mpr_wait_command(sc, cm, 60, CAN_SLEEP); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: request for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: page read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + bcopy(page, config_page, MIN(cm->cm_length, sizeof(Mpi2BiosPage3_t))); +out: + free(page, M_MPR); + if (cm) + mpr_free_command(sc, cm); + return (error); +} + +/** + * mpr_config_get_raid_volume_pg0 - obtain raid volume page 0 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @page_address: form and handle value used to get page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpr_config_get_raid_volume_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t + *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 page_address) +{ + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mpr_command *cm; + Mpi2RaidVolPage0_t *page = NULL; + int error = 0; + u16 ioc_status; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; + request->Header.PageNumber = 0; + request->Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + + /* + * This page must be polled because the IOC isn't ready yet when this + * page is needed. + */ + error = mpr_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mpr_free_command(sc, cm); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; + request->Header.PageNumber = 0; + request->Header.PageLength = mpi_reply->Header.PageLength; + request->Header.PageVersion = mpi_reply->Header.PageVersion; + request->PageAddress = page_address; + cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc(cm->cm_length, M_MPR, M_ZERO | M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + cm->cm_data = page; + + /* + * This page must be polled because the IOC isn't ready yet when this + * page is needed. + */ + error = mpr_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: page read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + bcopy(page, config_page, cm->cm_length); +out: + free(page, M_MPR); + if (cm) + mpr_free_command(sc, cm); + return (error); +} + +/** + * mpr_config_get_raid_volume_pg1 - obtain raid volume page 1 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @form: GET_NEXT_HANDLE or HANDLE + * @handle: volume handle + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpr_config_get_raid_volume_pg1(struct mpr_softc *sc, Mpi2ConfigReply_t + *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u16 handle) +{ + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mpr_command *cm; + Mpi2RaidVolPage1_t *page = NULL; + int error = 0; + u16 ioc_status; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; + request->Header.PageNumber = 1; + request->Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mpr_wait_command(sc, cm, 60, CAN_SLEEP); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: request for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mpr_free_command(sc, cm); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; + request->Header.PageNumber = 1; + request->Header.PageLength = mpi_reply->Header.PageLength; + request->Header.PageVersion = mpi_reply->Header.PageVersion; + request->PageAddress = htole32(form | handle); + cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc(cm->cm_length, M_MPR, M_ZERO | M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + cm->cm_data = page; + + error = mpr_wait_command(sc, cm, 60, CAN_SLEEP); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: request for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: page read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + bcopy(page, config_page, MIN(cm->cm_length, + sizeof(Mpi2RaidVolPage1_t))); +out: + free(page, M_MPR); + if (cm) + mpr_free_command(sc, cm); + return (error); +} + +/** + * mpr_config_get_volume_wwid - returns wwid given the volume handle + * @sc: per adapter object + * @volume_handle: volume handle + * @wwid: volume wwid + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpr_config_get_volume_wwid(struct mpr_softc *sc, u16 volume_handle, u64 *wwid) +{ + Mpi2ConfigReply_t mpi_reply; + Mpi2RaidVolPage1_t raid_vol_pg1; + + *wwid = 0; + if (!(mpr_config_get_raid_volume_pg1(sc, &mpi_reply, &raid_vol_pg1, + MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, volume_handle))) { + *wwid = le64toh((u64)raid_vol_pg1.WWID.High << 32 | + raid_vol_pg1.WWID.Low); + return 0; + } else + return -1; +} + +/** + * mpr_config_get_pd_pg0 - obtain raid phys disk page 0 + * @sc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @page_address: form and handle value used to get page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpr_config_get_raid_pd_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply, + Mpi2RaidPhysDiskPage0_t *config_page, u32 page_address) +{ + MPI2_CONFIG_REQUEST *request; + MPI2_CONFIG_REPLY *reply; + struct mpr_command *cm; + Mpi2RaidPhysDiskPage0_t *page = NULL; + int error = 0; + u16 ioc_status; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK; + request->Header.PageNumber = 0; + request->Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + + /* + * This page must be polled because the IOC isn't ready yet when this + * page is needed. + */ + error = mpr_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for header completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: header read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + /* We have to do free and alloc for the reply-free and reply-post + * counters to match - Need to review the reply FIFO handling. + */ + mpr_free_command(sc, cm); + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed @ line %d\n", __func__, + __LINE__); + error = EBUSY; + goto out; + } + request = (MPI2_CONFIG_REQUEST *)cm->cm_req; + bzero(request, sizeof(MPI2_CONFIG_REQUEST)); + request->Function = MPI2_FUNCTION_CONFIG; + request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK; + request->Header.PageNumber = 0; + request->Header.PageLength = mpi_reply->Header.PageLength; + request->Header.PageVersion = mpi_reply->Header.PageVersion; + request->PageAddress = page_address; + cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4; + cm->cm_sge = &request->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + page = malloc(cm->cm_length, M_MPR, M_ZERO | M_NOWAIT); + if (!page) { + printf("%s: page alloc failed\n", __func__); + error = ENOMEM; + goto out; + } + cm->cm_data = page; + + /* + * This page must be polled because the IOC isn't ready yet when this + * page is needed. + */ + error = mpr_request_polled(sc, cm); + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: poll for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY)); + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + /* FIXME */ + /* If the poll returns error then we need to do diag reset */ + printf("%s: page read with error; iocstatus = 0x%x\n", + __func__, ioc_status); + error = ENXIO; + goto out; + } + bcopy(page, config_page, MIN(cm->cm_length, + sizeof(Mpi2RaidPhysDiskPage0_t))); +out: + free(page, M_MPR); + if (cm) + mpr_free_command(sc, cm); + return (error); +} diff --git a/sys/dev/mpr/mpr_ioctl.h b/sys/dev/mpr/mpr_ioctl.h new file mode 100644 index 0000000000000..5ec482f311b01 --- /dev/null +++ b/sys/dev/mpr/mpr_ioctl.h @@ -0,0 +1,386 @@ +/*- + * Copyright (c) 2008 Yahoo!, Inc. + * All rights reserved. + * Written by: John Baldwin <jhb@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD userland interface + * + * $FreeBSD$ + */ +/*- + * Copyright (c) 2011-2014 LSI Corp. + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + +#ifndef _MPR_IOCTL_H_ +#define _MPR_IOCTL_H_ + +#include <dev/mpr/mpi/mpi2_type.h> +#include <dev/mpr/mpi/mpi2.h> +#include <dev/mpr/mpi/mpi2_cnfg.h> +#include <dev/mpr/mpi/mpi2_sas.h> + +/* + * For the read header requests, the header should include the page + * type or extended page type, page number, and page version. The + * buffer and length are unused. The completed header is returned in + * the 'header' member. + * + * For the read page and write page requests, 'buf' should point to a + * buffer of 'len' bytes which holds the entire page (including the + * header). + * + * All requests specify the page address in 'page_address'. + */ +struct mpr_cfg_page_req { + MPI2_CONFIG_PAGE_HEADER header; + uint32_t page_address; + void *buf; + int len; + uint16_t ioc_status; +}; + +struct mpr_ext_cfg_page_req { + MPI2_CONFIG_EXTENDED_PAGE_HEADER header; + uint32_t page_address; + void *buf; + int len; + uint16_t ioc_status; +}; + +struct mpr_raid_action { + uint8_t action; + uint8_t volume_bus; + uint8_t volume_id; + uint8_t phys_disk_num; + uint32_t action_data_word; + void *buf; + int len; + uint32_t volume_status; + uint32_t action_data[4]; + uint16_t action_status; + uint16_t ioc_status; + uint8_t write; +}; + +struct mpr_usr_command { + void *req; + uint32_t req_len; + void *rpl; + uint32_t rpl_len; + void *buf; + int len; + uint32_t flags; +}; + +typedef struct mpr_pci_bits +{ + union { + struct { + uint32_t DeviceNumber :5; + uint32_t FunctionNumber :3; + uint32_t BusNumber :24; + } bits; + uint32_t AsDWORD; + } u; + uint32_t PciSegmentId; +} mpr_pci_bits_t; + +/* + * The following is the MPRIOCTL_GET_ADAPTER_DATA data structure. This data + * structure is setup so that we hopefully are properly aligned for both + * 32-bit and 64-bit mode applications. + * + * Adapter Type - Value = 6 = SCSI Protocol through SAS-3 adapter + * + * MPI Port Number - The PCI Function number for this device + * + * PCI Device HW Id - The PCI device number for this device + * + */ +#define MPRIOCTL_ADAPTER_TYPE_SAS3 6 +typedef struct mpr_adapter_data +{ + uint32_t StructureLength; + uint32_t AdapterType; + uint32_t MpiPortNumber; + uint32_t PCIDeviceHwId; + uint32_t PCIDeviceHwRev; + uint32_t SubSystemId; + uint32_t SubsystemVendorId; + uint32_t Reserved1; + uint32_t MpiFirmwareVersion; + uint32_t BiosVersion; + uint8_t DriverVersion[32]; + uint8_t Reserved2; + uint8_t ScsiId; + uint16_t Reserved3; + mpr_pci_bits_t PciInformation; +} mpr_adapter_data_t; + + +typedef struct mpr_update_flash +{ + uint64_t PtrBuffer; + uint32_t ImageChecksum; + uint32_t ImageOffset; + uint32_t ImageSize; + uint32_t ImageType; +} mpr_update_flash_t; + + +#define MPR_PASS_THRU_DIRECTION_NONE 0 +#define MPR_PASS_THRU_DIRECTION_READ 1 +#define MPR_PASS_THRU_DIRECTION_WRITE 2 +#define MPR_PASS_THRU_DIRECTION_BOTH 3 + +typedef struct mpr_pass_thru +{ + uint64_t PtrRequest; + uint64_t PtrReply; + uint64_t PtrData; + uint32_t RequestSize; + uint32_t ReplySize; + uint32_t DataSize; + uint32_t DataDirection; + uint64_t PtrDataOut; + uint32_t DataOutSize; + uint32_t Timeout; +} mpr_pass_thru_t; + + +/* + * Event queue defines + */ +#define MPR_EVENT_QUEUE_SIZE (50) /* Max Events stored in driver */ +#define MPR_MAX_EVENT_DATA_LENGTH (48) /* Size of each event in Dwords */ + +typedef struct mpr_event_query +{ + uint16_t Entries; + uint16_t Reserved; + uint32_t Types[4]; +} mpr_event_query_t; + +typedef struct mpr_event_enable +{ + uint32_t Types[4]; +} mpr_event_enable_t; + +/* + * Event record entry for ioctl. + */ +typedef struct mpr_event_entry +{ + uint32_t Type; + uint32_t Number; + uint32_t Data[MPR_MAX_EVENT_DATA_LENGTH]; +} mpr_event_entry_t; + +typedef struct mpr_event_report +{ + uint32_t Size; + uint64_t PtrEvents; +} mpr_event_report_t; + + +typedef struct mpr_pci_info +{ + uint32_t BusNumber; + uint8_t DeviceNumber; + uint8_t FunctionNumber; + uint16_t InterruptVector; + uint8_t PciHeader[256]; +} mpr_pci_info_t; + + +typedef struct mpr_diag_action +{ + uint32_t Action; + uint32_t Length; + uint64_t PtrDiagAction; + uint32_t ReturnCode; +} mpr_diag_action_t; + +#define MPR_FW_DIAGNOSTIC_UID_NOT_FOUND (0xFF) + +#define MPR_FW_DIAG_NEW (0x806E6577) + +#define MPR_FW_DIAG_TYPE_REGISTER (0x00000001) +#define MPR_FW_DIAG_TYPE_UNREGISTER (0x00000002) +#define MPR_FW_DIAG_TYPE_QUERY (0x00000003) +#define MPR_FW_DIAG_TYPE_READ_BUFFER (0x00000004) +#define MPR_FW_DIAG_TYPE_RELEASE (0x00000005) + +#define MPR_FW_DIAG_INVALID_UID (0x00000000) + +#define MPR_DIAG_SUCCESS 0 +#define MPR_DIAG_FAILURE 1 + +#define MPR_FW_DIAG_ERROR_SUCCESS (0x00000000) +#define MPR_FW_DIAG_ERROR_FAILURE (0x00000001) +#define MPR_FW_DIAG_ERROR_INVALID_PARAMETER (0x00000002) +#define MPR_FW_DIAG_ERROR_POST_FAILED (0x00000010) +#define MPR_FW_DIAG_ERROR_INVALID_UID (0x00000011) +#define MPR_FW_DIAG_ERROR_RELEASE_FAILED (0x00000012) +#define MPR_FW_DIAG_ERROR_NO_BUFFER (0x00000013) +#define MPR_FW_DIAG_ERROR_ALREADY_RELEASED (0x00000014) + + +typedef struct mpr_fw_diag_register +{ + uint8_t ExtendedType; + uint8_t BufferType; + uint16_t ApplicationFlags; + uint32_t DiagnosticFlags; + uint32_t ProductSpecific[23]; + uint32_t RequestedBufferSize; + uint32_t UniqueId; +} mpr_fw_diag_register_t; + +typedef struct mpr_fw_diag_unregister +{ + uint32_t UniqueId; +} mpr_fw_diag_unregister_t; + +#define MPR_FW_DIAG_FLAG_APP_OWNED (0x0001) +#define MPR_FW_DIAG_FLAG_BUFFER_VALID (0x0002) +#define MPR_FW_DIAG_FLAG_FW_BUFFER_ACCESS (0x0004) + +typedef struct mpr_fw_diag_query +{ + uint8_t ExtendedType; + uint8_t BufferType; + uint16_t ApplicationFlags; + uint32_t DiagnosticFlags; + uint32_t ProductSpecific[23]; + uint32_t TotalBufferSize; + uint32_t DriverAddedBufferSize; + uint32_t UniqueId; +} mpr_fw_diag_query_t; + +typedef struct mpr_fw_diag_release +{ + uint32_t UniqueId; +} mpr_fw_diag_release_t; + +#define MPR_FW_DIAG_FLAG_REREGISTER (0x0001) +#define MPR_FW_DIAG_FLAG_FORCE_RELEASE (0x0002) + +typedef struct mpr_diag_read_buffer +{ + uint8_t Status; + uint8_t Reserved; + uint16_t Flags; + uint32_t StartingOffset; + uint32_t BytesToRead; + uint32_t UniqueId; + uint64_t PtrDataBuffer; +} mpr_diag_read_buffer_t; + +/* + * Register Access + */ +#define REG_IO_READ 1 +#define REG_IO_WRITE 2 +#define REG_MEM_READ 3 +#define REG_MEM_WRITE 4 + +typedef struct mpr_reg_access +{ + uint32_t Command; + uint32_t RegOffset; + uint32_t RegData; +} mpr_reg_access_t; + +typedef struct mpr_btdh_mapping +{ + uint16_t TargetID; + uint16_t Bus; + uint16_t DevHandle; + uint16_t Reserved; +} mpr_btdh_mapping_t; + +#define MPRIO_MPR_COMMAND_FLAG_VERBOSE 0x01 +#define MPRIO_MPR_COMMAND_FLAG_DEBUG 0x02 +#define MPRIO_READ_CFG_HEADER _IOWR('M', 200, struct mpr_cfg_page_req) +#define MPRIO_READ_CFG_PAGE _IOWR('M', 201, struct mpr_cfg_page_req) +#define MPRIO_READ_EXT_CFG_HEADER _IOWR('M', 202, struct mpr_ext_cfg_page_req) +#define MPRIO_READ_EXT_CFG_PAGE _IOWR('M', 203, struct mpr_ext_cfg_page_req) +#define MPRIO_WRITE_CFG_PAGE _IOWR('M', 204, struct mpr_cfg_page_req) +#define MPRIO_RAID_ACTION _IOWR('M', 205, struct mpr_raid_action) +#define MPRIO_MPR_COMMAND _IOWR('M', 210, struct mpr_usr_command) + +#define MPTIOCTL ('I') +#define MPTIOCTL_GET_ADAPTER_DATA _IOWR(MPTIOCTL, 1,\ + struct mpr_adapter_data) +#define MPTIOCTL_UPDATE_FLASH _IOWR(MPTIOCTL, 2,\ + struct mpr_update_flash) +#define MPTIOCTL_RESET_ADAPTER _IO(MPTIOCTL, 3) +#define MPTIOCTL_PASS_THRU _IOWR(MPTIOCTL, 4,\ + struct mpr_pass_thru) +#define MPTIOCTL_EVENT_QUERY _IOWR(MPTIOCTL, 5,\ + struct mpr_event_query) +#define MPTIOCTL_EVENT_ENABLE _IOWR(MPTIOCTL, 6,\ + struct mpr_event_enable) +#define MPTIOCTL_EVENT_REPORT _IOWR(MPTIOCTL, 7,\ + struct mpr_event_report) +#define MPTIOCTL_GET_PCI_INFO _IOWR(MPTIOCTL, 8,\ + struct mpr_pci_info) +#define MPTIOCTL_DIAG_ACTION _IOWR(MPTIOCTL, 9,\ + struct mpr_diag_action) +#define MPTIOCTL_REG_ACCESS _IOWR(MPTIOCTL, 10,\ + struct mpr_reg_access) +#define MPTIOCTL_BTDH_MAPPING _IOWR(MPTIOCTL, 11,\ + struct mpr_btdh_mapping) + +#endif /* !_MPR_IOCTL_H_ */ diff --git a/sys/dev/mpr/mpr_mapping.c b/sys/dev/mpr/mpr_mapping.c new file mode 100644 index 0000000000000..7f0fc00a9c52a --- /dev/null +++ b/sys/dev/mpr/mpr_mapping.c @@ -0,0 +1,2269 @@ +/*- + * Copyright (c) 2011-2014 LSI Corp. + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* TODO Move headers to mprvar */ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/kthread.h> +#include <sys/taskqueue.h> +#include <sys/bus.h> +#include <sys/endian.h> +#include <sys/sysctl.h> +#include <sys/eventhandler.h> +#include <sys/uio.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <dev/mpr/mpi/mpi2_type.h> +#include <dev/mpr/mpi/mpi2.h> +#include <dev/mpr/mpi/mpi2_ioc.h> +#include <dev/mpr/mpi/mpi2_sas.h> +#include <dev/mpr/mpi/mpi2_cnfg.h> +#include <dev/mpr/mpi/mpi2_init.h> +#include <dev/mpr/mpi/mpi2_tool.h> +#include <dev/mpr/mpr_ioctl.h> +#include <dev/mpr/mprvar.h> +#include <dev/mpr/mpr_mapping.h> + +/** + * _mapping_clear_entry - Clear a particular mapping entry. + * @map_entry: map table entry + * + * Returns nothing. + */ +static inline void +_mapping_clear_map_entry(struct dev_mapping_table *map_entry) +{ + map_entry->physical_id = 0; + map_entry->device_info = 0; + map_entry->phy_bits = 0; + map_entry->dpm_entry_num = MPR_DPM_BAD_IDX; + map_entry->dev_handle = 0; + map_entry->channel = -1; + map_entry->id = -1; + map_entry->missing_count = 0; + map_entry->init_complete = 0; + map_entry->TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR; +} + +/** + * _mapping_clear_enc_entry - Clear a particular enclosure table entry. + * @enc_entry: enclosure table entry + * + * Returns nothing. + */ +static inline void +_mapping_clear_enc_entry(struct enc_mapping_table *enc_entry) +{ + enc_entry->enclosure_id = 0; + enc_entry->start_index = MPR_MAPTABLE_BAD_IDX; + enc_entry->phy_bits = 0; + enc_entry->dpm_entry_num = MPR_DPM_BAD_IDX; + enc_entry->enc_handle = 0; + enc_entry->num_slots = 0; + enc_entry->start_slot = 0; + enc_entry->missing_count = 0; + enc_entry->removal_flag = 0; + enc_entry->skip_search = 0; + enc_entry->init_complete = 0; +} + +/** + * _mapping_commit_enc_entry - write a particular enc entry in DPM page0. + * @sc: per adapter object + * @enc_entry: enclosure table entry + * + * Returns 0 for success, non-zero for failure. + */ +static int +_mapping_commit_enc_entry(struct mpr_softc *sc, + struct enc_mapping_table *et_entry) +{ + Mpi2DriverMap0Entry_t *dpm_entry; + struct dev_mapping_table *mt_entry; + Mpi2ConfigReply_t mpi_reply; + Mpi2DriverMappingPage0_t config_page; + + if (!sc->is_dpm_enable) + return 0; + + memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t)); + memcpy(&config_page.Header, (u8 *) sc->dpm_pg0, + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry += et_entry->dpm_entry_num; + dpm_entry->PhysicalIdentifier.Low = + ( 0xFFFFFFFF & et_entry->enclosure_id); + dpm_entry->PhysicalIdentifier.High = + ( et_entry->enclosure_id >> 32); + mt_entry = &sc->mapping_table[et_entry->start_index]; + dpm_entry->DeviceIndex = htole16(mt_entry->id); + dpm_entry->MappingInformation = et_entry->num_slots; + dpm_entry->MappingInformation <<= MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT; + dpm_entry->MappingInformation |= et_entry->missing_count; + dpm_entry->MappingInformation = htole16(dpm_entry->MappingInformation); + dpm_entry->PhysicalBitsMapping = htole32(et_entry->phy_bits); + dpm_entry->Reserved1 = 0; + + memcpy(&config_page.Entry, (u8 *)dpm_entry, + sizeof(Mpi2DriverMap0Entry_t)); + if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page, + et_entry->dpm_entry_num)) { + printf("%s: write of dpm entry %d for enclosure failed\n", + __func__, et_entry->dpm_entry_num); + dpm_entry->MappingInformation = le16toh(dpm_entry-> + MappingInformation); + dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); + dpm_entry->PhysicalBitsMapping = + le32toh(dpm_entry->PhysicalBitsMapping); + return -1; + } + dpm_entry->MappingInformation = le16toh(dpm_entry-> + MappingInformation); + dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); + dpm_entry->PhysicalBitsMapping = + le32toh(dpm_entry->PhysicalBitsMapping); + return 0; +} + +/** + * _mapping_commit_map_entry - write a particular map table entry in DPM page0. + * @sc: per adapter object + * @enc_entry: enclosure table entry + * + * Returns 0 for success, non-zero for failure. + */ + +static int +_mapping_commit_map_entry(struct mpr_softc *sc, + struct dev_mapping_table *mt_entry) +{ + Mpi2DriverMap0Entry_t *dpm_entry; + Mpi2ConfigReply_t mpi_reply; + Mpi2DriverMappingPage0_t config_page; + + if (!sc->is_dpm_enable) + return 0; + + memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t)); + memcpy(&config_page.Header, (u8 *)sc->dpm_pg0, + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *) sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry = dpm_entry + mt_entry->dpm_entry_num; + dpm_entry->PhysicalIdentifier.Low = (0xFFFFFFFF & + mt_entry->physical_id); + dpm_entry->PhysicalIdentifier.High = (mt_entry->physical_id >> 32); + dpm_entry->DeviceIndex = htole16(mt_entry->id); + dpm_entry->MappingInformation = htole16(mt_entry->missing_count); + dpm_entry->PhysicalBitsMapping = 0; + dpm_entry->Reserved1 = 0; + dpm_entry->MappingInformation = htole16(dpm_entry->MappingInformation); + memcpy(&config_page.Entry, (u8 *)dpm_entry, + sizeof(Mpi2DriverMap0Entry_t)); + if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page, + mt_entry->dpm_entry_num)) { + printf("%s: write of dpm entry %d for device failed\n", + __func__, mt_entry->dpm_entry_num); + dpm_entry->MappingInformation = le16toh(dpm_entry-> + MappingInformation); + dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); + return -1; + } + + dpm_entry->MappingInformation = le16toh(dpm_entry->MappingInformation); + dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); + return 0; +} + +/** + * _mapping_get_ir_maprange - get start and end index for IR map range. + * @sc: per adapter object + * @start_idx: place holder for start index + * @end_idx: place holder for end index + * + * The IR volumes can be mapped either at start or end of the mapping table + * this function gets the detail of where IR volume mapping starts and ends + * in the device mapping table + * + * Returns nothing. + */ +static void +_mapping_get_ir_maprange(struct mpr_softc *sc, u32 *start_idx, u32 *end_idx) +{ + u16 volume_mapping_flags; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + + volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) & + MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; + if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) { + *start_idx = 0; + if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0) + *start_idx = 1; + } else + *start_idx = sc->max_devices - sc->max_volumes; + *end_idx = *start_idx + sc->max_volumes - 1; +} + +/** + * _mapping_get_enc_idx_from_id - get enclosure index from enclosure ID + * @sc: per adapter object + * @enc_id: enclosure logical identifier + * + * Returns the index of enclosure entry on success or bad index. + */ +static u8 +_mapping_get_enc_idx_from_id(struct mpr_softc *sc, u64 enc_id, + u64 phy_bits) +{ + struct enc_mapping_table *et_entry; + u8 enc_idx = 0; + + for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) { + et_entry = &sc->enclosure_table[enc_idx]; + if ((et_entry->enclosure_id == le64toh(enc_id)) && + (!et_entry->phy_bits || (et_entry->phy_bits & + le32toh(phy_bits)))) + return enc_idx; + } + return MPR_ENCTABLE_BAD_IDX; +} + +/** + * _mapping_get_enc_idx_from_handle - get enclosure index from handle + * @sc: per adapter object + * @enc_id: enclosure handle + * + * Returns the index of enclosure entry on success or bad index. + */ +static u8 +_mapping_get_enc_idx_from_handle(struct mpr_softc *sc, u16 handle) +{ + struct enc_mapping_table *et_entry; + u8 enc_idx = 0; + + for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) { + et_entry = &sc->enclosure_table[enc_idx]; + if (et_entry->missing_count) + continue; + if (et_entry->enc_handle == handle) + return enc_idx; + } + return MPR_ENCTABLE_BAD_IDX; +} + +/** + * _mapping_get_high_missing_et_idx - get missing enclosure index + * @sc: per adapter object + * + * Search through the enclosure table and identifies the enclosure entry + * with high missing count and returns it's index + * + * Returns the index of enclosure entry on success or bad index. + */ +static u8 +_mapping_get_high_missing_et_idx(struct mpr_softc *sc) +{ + struct enc_mapping_table *et_entry; + u8 high_missing_count = 0; + u8 enc_idx, high_idx = MPR_ENCTABLE_BAD_IDX; + + for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) { + et_entry = &sc->enclosure_table[enc_idx]; + if ((et_entry->missing_count > high_missing_count) && + !et_entry->skip_search) { + high_missing_count = et_entry->missing_count; + high_idx = enc_idx; + } + } + return high_idx; +} + +/** + * _mapping_get_high_missing_mt_idx - get missing map table index + * @sc: per adapter object + * + * Search through the map table and identifies the device entry + * with high missing count and returns it's index + * + * Returns the index of map table entry on success or bad index. + */ +static u32 +_mapping_get_high_missing_mt_idx(struct mpr_softc *sc) +{ + u32 map_idx, high_idx = MPR_ENCTABLE_BAD_IDX; + u8 high_missing_count = 0; + u32 start_idx, end_idx, start_idx_ir = 0, end_idx_ir; + struct dev_mapping_table *mt_entry; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + + start_idx = 0; + end_idx = sc->max_devices; + if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0) + start_idx = 1; + if (sc->ir_firmware) { + _mapping_get_ir_maprange(sc, &start_idx_ir, &end_idx_ir); + if (start_idx == start_idx_ir) + start_idx = end_idx_ir + 1; + else + end_idx = start_idx_ir; + } + mt_entry = &sc->mapping_table[start_idx]; + for (map_idx = start_idx; map_idx < end_idx; map_idx++, mt_entry++) { + if (mt_entry->missing_count > high_missing_count) { + high_missing_count = mt_entry->missing_count; + high_idx = map_idx; + } + } + return high_idx; +} + +/** + * _mapping_get_ir_mt_idx_from_wwid - get map table index from volume WWID + * @sc: per adapter object + * @wwid: world wide unique ID of the volume + * + * Returns the index of map table entry on success or bad index. + */ +static u32 +_mapping_get_ir_mt_idx_from_wwid(struct mpr_softc *sc, u64 wwid) +{ + u32 start_idx, end_idx, map_idx; + struct dev_mapping_table *mt_entry; + + _mapping_get_ir_maprange(sc, &start_idx, &end_idx); + mt_entry = &sc->mapping_table[start_idx]; + for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) + if (mt_entry->physical_id == wwid) + return map_idx; + + return MPR_MAPTABLE_BAD_IDX; +} + +/** + * _mapping_get_mt_idx_from_id - get map table index from a device ID + * @sc: per adapter object + * @dev_id: device identifer (SAS Address) + * + * Returns the index of map table entry on success or bad index. + */ +static u32 +_mapping_get_mt_idx_from_id(struct mpr_softc *sc, u64 dev_id) +{ + u32 map_idx; + struct dev_mapping_table *mt_entry; + + for (map_idx = 0; map_idx < sc->max_devices; map_idx++) { + mt_entry = &sc->mapping_table[map_idx]; + if (mt_entry->physical_id == dev_id) + return map_idx; + } + return MPR_MAPTABLE_BAD_IDX; +} + +/** + * _mapping_get_ir_mt_idx_from_handle - get map table index from volume handle + * @sc: per adapter object + * @wwid: volume device handle + * + * Returns the index of map table entry on success or bad index. + */ +static u32 +_mapping_get_ir_mt_idx_from_handle(struct mpr_softc *sc, u16 volHandle) +{ + u32 start_idx, end_idx, map_idx; + struct dev_mapping_table *mt_entry; + + _mapping_get_ir_maprange(sc, &start_idx, &end_idx); + mt_entry = &sc->mapping_table[start_idx]; + for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) + if (mt_entry->dev_handle == volHandle) + return map_idx; + + return MPR_MAPTABLE_BAD_IDX; +} + +/** + * _mapping_get_mt_idx_from_handle - get map table index from handle + * @sc: per adapter object + * @dev_id: device handle + * + * Returns the index of map table entry on success or bad index. + */ +static u32 +_mapping_get_mt_idx_from_handle(struct mpr_softc *sc, u16 handle) +{ + u32 map_idx; + struct dev_mapping_table *mt_entry; + + for (map_idx = 0; map_idx < sc->max_devices; map_idx++) { + mt_entry = &sc->mapping_table[map_idx]; + if (mt_entry->dev_handle == handle) + return map_idx; + } + return MPR_MAPTABLE_BAD_IDX; +} + +/** + * _mapping_get_free_ir_mt_idx - get first free index for a volume + * @sc: per adapter object + * + * Search through mapping table for free index for a volume and if no free + * index then looks for a volume with high mapping index + * + * Returns the index of map table entry on success or bad index. + */ +static u32 +_mapping_get_free_ir_mt_idx(struct mpr_softc *sc) +{ + u8 high_missing_count = 0; + u32 start_idx, end_idx, map_idx; + u32 high_idx = MPR_MAPTABLE_BAD_IDX; + struct dev_mapping_table *mt_entry; + + _mapping_get_ir_maprange(sc, &start_idx, &end_idx); + + mt_entry = &sc->mapping_table[start_idx]; + for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) + if (!(mt_entry->device_info & MPR_MAP_IN_USE)) + return map_idx; + + mt_entry = &sc->mapping_table[start_idx]; + for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) { + if (mt_entry->missing_count > high_missing_count) { + high_missing_count = mt_entry->missing_count; + high_idx = map_idx; + } + } + return high_idx; +} + +/** + * _mapping_get_free_mt_idx - get first free index for a device + * @sc: per adapter object + * @start_idx: offset in the table to start search + * + * Returns the index of map table entry on success or bad index. + */ +static u32 +_mapping_get_free_mt_idx(struct mpr_softc *sc, u32 start_idx) +{ + u32 map_idx, max_idx = sc->max_devices; + struct dev_mapping_table *mt_entry = &sc->mapping_table[start_idx]; + u16 volume_mapping_flags; + + volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) & + MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; + if (sc->ir_firmware && (volume_mapping_flags == + MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) + max_idx -= sc->max_volumes; + for (map_idx = start_idx; map_idx < max_idx; map_idx++, mt_entry++) + if (!(mt_entry->device_info & (MPR_MAP_IN_USE | + MPR_DEV_RESERVED))) + return map_idx; + + return MPR_MAPTABLE_BAD_IDX; +} + +/** + * _mapping_get_dpm_idx_from_id - get DPM index from ID + * @sc: per adapter object + * @id: volume WWID or enclosure ID or device ID + * + * Returns the index of DPM entry on success or bad index. + */ +static u16 +_mapping_get_dpm_idx_from_id(struct mpr_softc *sc, u64 id, u32 phy_bits) +{ + u16 entry_num; + uint64_t PhysicalIdentifier; + Mpi2DriverMap0Entry_t *dpm_entry; + + dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + PhysicalIdentifier = dpm_entry->PhysicalIdentifier.High; + PhysicalIdentifier = (PhysicalIdentifier << 32) | + dpm_entry->PhysicalIdentifier.Low; + for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++, + dpm_entry++) + if ((id == PhysicalIdentifier) && + (!phy_bits || !dpm_entry->PhysicalBitsMapping || + (phy_bits & dpm_entry->PhysicalBitsMapping))) + return entry_num; + + return MPR_DPM_BAD_IDX; +} + + +/** + * _mapping_get_free_dpm_idx - get first available DPM index + * @sc: per adapter object + * + * Returns the index of DPM entry on success or bad index. + */ +static u32 +_mapping_get_free_dpm_idx(struct mpr_softc *sc) +{ + u16 entry_num; + + for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) { + if (!sc->dpm_entry_used[entry_num]) + return entry_num; + } + return MPR_DPM_BAD_IDX; +} + +/** + * _mapping_update_ir_missing_cnt - Updates missing count for a volume + * @sc: per adapter object + * @map_idx: map table index of the volume + * @element: IR configuration change element + * @wwid: IR volume ID. + * + * Updates the missing count in the map table and in the DPM entry for a volume + * + * Returns nothing. + */ +static void +_mapping_update_ir_missing_cnt(struct mpr_softc *sc, u32 map_idx, + Mpi2EventIrConfigElement_t *element, u64 wwid) +{ + struct dev_mapping_table *mt_entry; + u8 missing_cnt, reason = element->ReasonCode; + u16 dpm_idx; + Mpi2DriverMap0Entry_t *dpm_entry; + + if (!sc->is_dpm_enable) + return; + mt_entry = &sc->mapping_table[map_idx]; + if (reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) { + mt_entry->missing_count = 0; + } else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) { + mt_entry->missing_count = 0; + mt_entry->init_complete = 0; + } else if ((reason == MPI2_EVENT_IR_CHANGE_RC_REMOVED) || + (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED)) { + if (!mt_entry->init_complete) { + if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT) + mt_entry->missing_count++; + else + mt_entry->init_complete = 1; + } + if (!mt_entry->missing_count) + mt_entry->missing_count++; + mt_entry->dev_handle = 0; + } + + dpm_idx = mt_entry->dpm_entry_num; + if (dpm_idx == MPR_DPM_BAD_IDX) { + if ((reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) || + (reason == MPI2_EVENT_IR_CHANGE_RC_REMOVED)) + dpm_idx = _mapping_get_dpm_idx_from_id(sc, + mt_entry->physical_id, 0); + else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) + return; + } + if (dpm_idx != MPR_DPM_BAD_IDX) { + dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry += dpm_idx; + missing_cnt = dpm_entry->MappingInformation & + MPI2_DRVMAP0_MAPINFO_MISSING_MASK; + if ((mt_entry->physical_id == + le64toh((u64)dpm_entry->PhysicalIdentifier.High | + dpm_entry->PhysicalIdentifier.Low)) && (missing_cnt == + mt_entry->missing_count)) + mt_entry->init_complete = 1; + } else { + dpm_idx = _mapping_get_free_dpm_idx(sc); + mt_entry->init_complete = 0; + } + + if ((dpm_idx != MPR_DPM_BAD_IDX) && !mt_entry->init_complete) { + mt_entry->init_complete = 1; + mt_entry->dpm_entry_num = dpm_idx; + dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry += dpm_idx; + dpm_entry->PhysicalIdentifier.Low = + (0xFFFFFFFF & mt_entry->physical_id); + dpm_entry->PhysicalIdentifier.High = + (mt_entry->physical_id >> 32); + dpm_entry->DeviceIndex = map_idx; + dpm_entry->MappingInformation = mt_entry->missing_count; + dpm_entry->PhysicalBitsMapping = 0; + dpm_entry->Reserved1 = 0; + sc->dpm_flush_entry[dpm_idx] = 1; + sc->dpm_entry_used[dpm_idx] = 1; + } else if (dpm_idx == MPR_DPM_BAD_IDX) { + printf("%s: no space to add entry in DPM table\n", __func__); + mt_entry->init_complete = 1; + } +} + +/** + * _mapping_add_to_removal_table - mark an entry for removal + * @sc: per adapter object + * @handle: Handle of enclosures/device/volume + * + * Adds the handle or DPM entry number in removal table. + * + * Returns nothing. + */ +static void +_mapping_add_to_removal_table(struct mpr_softc *sc, u16 handle, + u16 dpm_idx) +{ + struct map_removal_table *remove_entry; + u32 i; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + + remove_entry = sc->removal_table; + + for (i = 0; i < sc->max_devices; i++, remove_entry++) { + if (remove_entry->dev_handle || remove_entry->dpm_entry_num != + MPR_DPM_BAD_IDX) + continue; + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { + if (dpm_idx) + remove_entry->dpm_entry_num = dpm_idx; + if (remove_entry->dpm_entry_num == MPR_DPM_BAD_IDX) + remove_entry->dev_handle = handle; + } else if ((ioc_pg8_flags & + MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) + remove_entry->dev_handle = handle; + break; + } + +} + +/** + * _mapping_update_missing_count - Update missing count for a device + * @sc: per adapter object + * @topo_change: Topology change event entry + * + * Search through the topology change list and if any device is found not + * responding it's associated map table entry and DPM entry is updated + * + * Returns nothing. + */ +static void +_mapping_update_missing_count(struct mpr_softc *sc, + struct _map_topology_change *topo_change) +{ + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + u8 entry; + struct _map_phy_change *phy_change; + u32 map_idx; + struct dev_mapping_table *mt_entry; + Mpi2DriverMap0Entry_t *dpm_entry; + + for (entry = 0; entry < topo_change->num_entries; entry++) { + phy_change = &topo_change->phy_details[entry]; + if (!phy_change->dev_handle || (phy_change->reason != + MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) + continue; + map_idx = _mapping_get_mt_idx_from_handle(sc, phy_change-> + dev_handle); + phy_change->is_processed = 1; + if (map_idx == MPR_MAPTABLE_BAD_IDX) { + printf("%s: device is already removed from mapping " + "table\n", __func__); + continue; + } + mt_entry = &sc->mapping_table[map_idx]; + if (!mt_entry->init_complete) { + if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT) + mt_entry->missing_count++; + else + mt_entry->init_complete = 1; + } + if (!mt_entry->missing_count) + mt_entry->missing_count++; + _mapping_add_to_removal_table(sc, mt_entry->dev_handle, 0); + mt_entry->dev_handle = 0; + + if (((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) && + sc->is_dpm_enable && !mt_entry->init_complete && + mt_entry->dpm_entry_num != MPR_DPM_BAD_IDX) { + dpm_entry = + (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry += mt_entry->dpm_entry_num; + dpm_entry->MappingInformation = mt_entry->missing_count; + sc->dpm_flush_entry[mt_entry->dpm_entry_num] = 1; + } + mt_entry->init_complete = 1; + } +} + +/** + * _mapping_find_enc_map_space -find map table entries for enclosure + * @sc: per adapter object + * @et_entry: enclosure entry + * + * Search through the mapping table defragment it and provide contiguous + * space in map table for a particular enclosure entry + * + * Returns start index in map table or bad index. + */ +static u32 +_mapping_find_enc_map_space(struct mpr_softc *sc, + struct enc_mapping_table *et_entry) +{ + u16 vol_mapping_flags; + u32 skip_count, end_of_table, map_idx, enc_idx; + u16 num_found; + u32 start_idx = MPR_MAPTABLE_BAD_IDX; + struct dev_mapping_table *mt_entry; + struct enc_mapping_table *enc_entry; + unsigned char done_flag = 0, found_space; + u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs); + + skip_count = sc->num_rsvd_entries; + num_found = 0; + + vol_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) & + MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; + + if (!sc->ir_firmware) + end_of_table = sc->max_devices; + else if (vol_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) + end_of_table = sc->max_devices; + else + end_of_table = sc->max_devices - sc->max_volumes; + + for (map_idx = (max_num_phy_ids + skip_count); + map_idx < end_of_table; map_idx++) { + mt_entry = &sc->mapping_table[map_idx]; + if ((et_entry->enclosure_id == mt_entry->physical_id) && + (!mt_entry->phy_bits || (mt_entry->phy_bits & + et_entry->phy_bits))) { + num_found += 1; + if (num_found == et_entry->num_slots) { + start_idx = (map_idx - num_found) + 1; + return start_idx; + } + } else + num_found = 0; + } + for (map_idx = (max_num_phy_ids + skip_count); + map_idx < end_of_table; map_idx++) { + mt_entry = &sc->mapping_table[map_idx]; + if (!(mt_entry->device_info & MPR_DEV_RESERVED)) { + num_found += 1; + if (num_found == et_entry->num_slots) { + start_idx = (map_idx - num_found) + 1; + return start_idx; + } + } else + num_found = 0; + } + + while (!done_flag) { + enc_idx = _mapping_get_high_missing_et_idx(sc); + if (enc_idx == MPR_ENCTABLE_BAD_IDX) + return MPR_MAPTABLE_BAD_IDX; + enc_entry = &sc->enclosure_table[enc_idx]; + /*VSP FIXME*/ + enc_entry->skip_search = 1; + mt_entry = &sc->mapping_table[enc_entry->start_index]; + for (map_idx = enc_entry->start_index; map_idx < + (enc_entry->start_index + enc_entry->num_slots); map_idx++, + mt_entry++) + mt_entry->device_info &= ~MPR_DEV_RESERVED; + found_space = 0; + for (map_idx = (max_num_phy_ids + + skip_count); map_idx < end_of_table; map_idx++) { + mt_entry = &sc->mapping_table[map_idx]; + if (!(mt_entry->device_info & MPR_DEV_RESERVED)) { + num_found += 1; + if (num_found == et_entry->num_slots) { + start_idx = (map_idx - num_found) + 1; + found_space = 1; + } + } else + num_found = 0; + } + + if (!found_space) + continue; + for (map_idx = start_idx; map_idx < (start_idx + num_found); + map_idx++) { + enc_entry = sc->enclosure_table; + for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; + enc_idx++, enc_entry++) { + if (map_idx < enc_entry->start_index || + map_idx > (enc_entry->start_index + + enc_entry->num_slots)) + continue; + if (!enc_entry->removal_flag) { + enc_entry->removal_flag = 1; + _mapping_add_to_removal_table(sc, 0, + enc_entry->dpm_entry_num); + } + mt_entry = &sc->mapping_table[map_idx]; + if (mt_entry->device_info & + MPR_MAP_IN_USE) { + _mapping_add_to_removal_table(sc, + mt_entry->dev_handle, 0); + _mapping_clear_map_entry(mt_entry); + } + if (map_idx == (enc_entry->start_index + + enc_entry->num_slots - 1)) + _mapping_clear_enc_entry(et_entry); + } + } + enc_entry = sc->enclosure_table; + for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; + enc_idx++, enc_entry++) { + if (!enc_entry->removal_flag) { + mt_entry = &sc->mapping_table[enc_entry-> + start_index]; + for (map_idx = enc_entry->start_index; map_idx < + (enc_entry->start_index + + enc_entry->num_slots); map_idx++, + mt_entry++) + mt_entry->device_info |= + MPR_DEV_RESERVED; + et_entry->skip_search = 0; + } + } + done_flag = 1; + } + return start_idx; +} + +/** + * _mapping_get_dev_info -get information about newly added devices + * @sc: per adapter object + * @topo_change: Topology change event entry + * + * Search through the topology change event list and issues sas device pg0 + * requests for the newly added device and reserved entries in tables + * + * Returns nothing + */ +static void +_mapping_get_dev_info(struct mpr_softc *sc, + struct _map_topology_change *topo_change) +{ + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + Mpi2ConfigReply_t mpi_reply; + Mpi2SasDevicePage0_t sas_device_pg0; + u8 entry, enc_idx, phy_idx; + u32 map_idx, index, device_info; + struct _map_phy_change *phy_change, *tmp_phy_change; + uint64_t sas_address; + struct enc_mapping_table *et_entry; + struct dev_mapping_table *mt_entry; + u8 add_code = MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED; + int rc; + + for (entry = 0; entry < topo_change->num_entries; entry++) { + phy_change = &topo_change->phy_details[entry]; + if (phy_change->is_processed || !phy_change->dev_handle || + phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) + continue; + if (mpr_config_get_sas_device_pg0(sc, &mpi_reply, + &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, + phy_change->dev_handle)) { + phy_change->is_processed = 1; + continue; + } + + device_info = le32toh(sas_device_pg0.DeviceInfo); + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { + if ((device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE) && + (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)) { + rc = mprsas_get_sas_address_for_sata_disk(sc, + &sas_address, phy_change->dev_handle, + device_info); + if (rc) { + printf("%s: failed to compute the " + "hashed SAS Address for SATA " + "device with handle 0x%04x\n", + __func__, phy_change->dev_handle); + sas_address = + sas_device_pg0.SASAddress.High; + sas_address = (sas_address << 32) | + sas_device_pg0.SASAddress.Low; + } + mpr_dprint(sc, MPR_INFO, "SAS Address for SATA " + "device = %jx\n", sas_address); + } else { + sas_address = + sas_device_pg0.SASAddress.High; + sas_address = (sas_address << 32) | + sas_device_pg0.SASAddress.Low; + } + } else { + sas_address = sas_device_pg0.SASAddress.High; + sas_address = (sas_address << 32) | + sas_device_pg0.SASAddress.Low; + } + phy_change->physical_id = sas_address; + phy_change->slot = le16toh(sas_device_pg0.Slot); + phy_change->device_info = + le32toh(sas_device_pg0.DeviceInfo); + + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { + enc_idx = _mapping_get_enc_idx_from_handle(sc, + topo_change->enc_handle); + if (enc_idx == MPR_ENCTABLE_BAD_IDX) { + phy_change->is_processed = 1; + printf("%s: failed to add the device with " + "handle 0x%04x because the enclosure is " + "not in the mapping table\n", __func__, + phy_change->dev_handle); + continue; + } + if (!((phy_change->device_info & + MPI2_SAS_DEVICE_INFO_END_DEVICE) && + (phy_change->device_info & + (MPI2_SAS_DEVICE_INFO_SSP_TARGET | + MPI2_SAS_DEVICE_INFO_STP_TARGET | + MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))) { + phy_change->is_processed = 1; + continue; + } + et_entry = &sc->enclosure_table[enc_idx]; + if (et_entry->start_index != MPR_MAPTABLE_BAD_IDX) + continue; + if (!topo_change->exp_handle) { + map_idx = sc->num_rsvd_entries; + et_entry->start_index = map_idx; + } else { + map_idx = _mapping_find_enc_map_space(sc, + et_entry); + et_entry->start_index = map_idx; + if (et_entry->start_index == + MPR_MAPTABLE_BAD_IDX) { + phy_change->is_processed = 1; + for (phy_idx = 0; phy_idx < + topo_change->num_entries; + phy_idx++) { + tmp_phy_change = + &topo_change->phy_details + [phy_idx]; + if (tmp_phy_change->reason == + add_code) + tmp_phy_change-> + is_processed = 1; + } + break; + } + } + mt_entry = &sc->mapping_table[map_idx]; + for (index = map_idx; index < (et_entry->num_slots + + map_idx); index++, mt_entry++) { + mt_entry->device_info = MPR_DEV_RESERVED; + mt_entry->physical_id = et_entry->enclosure_id; + mt_entry->phy_bits = et_entry->phy_bits; + } + } + } +} + +/** + * _mapping_set_mid_to_eid -set map table data from enclosure table + * @sc: per adapter object + * @et_entry: enclosure entry + * + * Returns nothing + */ +static inline void +_mapping_set_mid_to_eid(struct mpr_softc *sc, + struct enc_mapping_table *et_entry) +{ + struct dev_mapping_table *mt_entry; + u16 slots = et_entry->num_slots, map_idx; + u32 start_idx = et_entry->start_index; + if (start_idx != MPR_MAPTABLE_BAD_IDX) { + mt_entry = &sc->mapping_table[start_idx]; + for (map_idx = 0; map_idx < slots; map_idx++, mt_entry++) + mt_entry->physical_id = et_entry->enclosure_id; + } +} + +/** + * _mapping_clear_removed_entries - mark the entries to be cleared + * @sc: per adapter object + * + * Search through the removal table and mark the entries which needs to be + * flushed to DPM and also updates the map table and enclosure table by + * clearing the corresponding entries. + * + * Returns nothing + */ +static void +_mapping_clear_removed_entries(struct mpr_softc *sc) +{ + u32 remove_idx; + struct map_removal_table *remove_entry; + Mpi2DriverMap0Entry_t *dpm_entry; + u8 done_flag = 0, num_entries, m, i; + struct enc_mapping_table *et_entry, *from, *to; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + + if (sc->is_dpm_enable) { + remove_entry = sc->removal_table; + for (remove_idx = 0; remove_idx < sc->max_devices; + remove_idx++, remove_entry++) { + if (remove_entry->dpm_entry_num != MPR_DPM_BAD_IDX) { + dpm_entry = (Mpi2DriverMap0Entry_t *) + ((u8 *) sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry += remove_entry->dpm_entry_num; + dpm_entry->PhysicalIdentifier.Low = 0; + dpm_entry->PhysicalIdentifier.High = 0; + dpm_entry->DeviceIndex = 0; + dpm_entry->MappingInformation = 0; + dpm_entry->PhysicalBitsMapping = 0; + sc->dpm_flush_entry[remove_entry-> + dpm_entry_num] = 1; + sc->dpm_entry_used[remove_entry->dpm_entry_num] + = 0; + remove_entry->dpm_entry_num = MPR_DPM_BAD_IDX; + } + } + } + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { + num_entries = sc->num_enc_table_entries; + while (!done_flag) { + done_flag = 1; + et_entry = sc->enclosure_table; + for (i = 0; i < num_entries; i++, et_entry++) { + if (!et_entry->enc_handle && et_entry-> + init_complete) { + done_flag = 0; + if (i != (num_entries - 1)) { + from = &sc->enclosure_table + [i+1]; + to = &sc->enclosure_table[i]; + for (m = i; m < (num_entries - + 1); m++, from++, to++) { + _mapping_set_mid_to_eid + (sc, to); + *to = *from; + } + _mapping_clear_enc_entry(to); + sc->num_enc_table_entries--; + num_entries = + sc->num_enc_table_entries; + } else { + _mapping_clear_enc_entry + (et_entry); + sc->num_enc_table_entries--; + num_entries = + sc->num_enc_table_entries; + } + } + } + } + } +} + +/** + * _mapping_add_new_device -Add the new device into mapping table + * @sc: per adapter object + * @topo_change: Topology change event entry + * + * Search through the topology change event list and updates map table, + * enclosure table and DPM pages for for the newly added devices. + * + * Returns nothing + */ +static void +_mapping_add_new_device(struct mpr_softc *sc, + struct _map_topology_change *topo_change) +{ + u8 enc_idx, missing_cnt, is_removed = 0; + u16 dpm_idx; + u32 search_idx, map_idx; + u32 entry; + struct dev_mapping_table *mt_entry; + struct enc_mapping_table *et_entry; + struct _map_phy_change *phy_change; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + Mpi2DriverMap0Entry_t *dpm_entry; + uint64_t temp64_var; + u8 map_shift = MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT; + u8 hdr_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER); + u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs); + + for (entry = 0; entry < topo_change->num_entries; entry++) { + phy_change = &topo_change->phy_details[entry]; + if (phy_change->is_processed) + continue; + if (phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED || + !phy_change->dev_handle) { + phy_change->is_processed = 1; + continue; + } + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { + enc_idx = _mapping_get_enc_idx_from_handle + (sc, topo_change->enc_handle); + if (enc_idx == MPR_ENCTABLE_BAD_IDX) { + phy_change->is_processed = 1; + printf("%s: failed to add the device with " + "handle 0x%04x because the enclosure is " + "not in the mapping table\n", __func__, + phy_change->dev_handle); + continue; + } + et_entry = &sc->enclosure_table[enc_idx]; + if (et_entry->start_index == MPR_MAPTABLE_BAD_IDX) { + phy_change->is_processed = 1; + if (!sc->mt_full_retry) { + sc->mt_add_device_failed = 1; + continue; + } + printf("%s: failed to add the device with " + "handle 0x%04x because there is no free " + "space available in the mapping table\n", + __func__, phy_change->dev_handle); + continue; + } + map_idx = et_entry->start_index + phy_change->slot - + et_entry->start_slot; + mt_entry = &sc->mapping_table[map_idx]; + mt_entry->physical_id = phy_change->physical_id; + mt_entry->channel = 0; + mt_entry->id = map_idx; + mt_entry->dev_handle = phy_change->dev_handle; + mt_entry->missing_count = 0; + mt_entry->dpm_entry_num = et_entry->dpm_entry_num; + mt_entry->device_info = phy_change->device_info | + (MPR_DEV_RESERVED | MPR_MAP_IN_USE); + if (sc->is_dpm_enable) { + dpm_idx = et_entry->dpm_entry_num; + if (dpm_idx == MPR_DPM_BAD_IDX) + dpm_idx = _mapping_get_dpm_idx_from_id + (sc, et_entry->enclosure_id, + et_entry->phy_bits); + if (dpm_idx == MPR_DPM_BAD_IDX) { + dpm_idx = _mapping_get_free_dpm_idx(sc); + if (dpm_idx != MPR_DPM_BAD_IDX) { + dpm_entry = + (Mpi2DriverMap0Entry_t *) + ((u8 *) sc->dpm_pg0 + + hdr_sz); + dpm_entry += dpm_idx; + dpm_entry-> + PhysicalIdentifier.Low = + (0xFFFFFFFF & + et_entry->enclosure_id); + dpm_entry-> + PhysicalIdentifier.High = + ( et_entry->enclosure_id + >> 32); + dpm_entry->DeviceIndex = + (U16)et_entry->start_index; + dpm_entry->MappingInformation = + et_entry->num_slots; + dpm_entry->MappingInformation + <<= map_shift; + dpm_entry->PhysicalBitsMapping + = et_entry->phy_bits; + et_entry->dpm_entry_num = + dpm_idx; + /* FIXME Do I need to set the dpm_idxin mt_entry too */ + sc->dpm_entry_used[dpm_idx] = 1; + sc->dpm_flush_entry[dpm_idx] = + 1; + phy_change->is_processed = 1; + } else { + phy_change->is_processed = 1; + mpr_dprint(sc, MPR_INFO, "%s: " + "failed to add the device " + "with handle 0x%04x to " + "persistent table because " + "there is no free space " + "available\n", __func__, + phy_change->dev_handle); + } + } else { + et_entry->dpm_entry_num = dpm_idx; + mt_entry->dpm_entry_num = dpm_idx; + } + } + /* FIXME Why not mt_entry too? */ + et_entry->init_complete = 1; + } else if ((ioc_pg8_flags & + MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { + map_idx = _mapping_get_mt_idx_from_id + (sc, phy_change->physical_id); + if (map_idx == MPR_MAPTABLE_BAD_IDX) { + search_idx = sc->num_rsvd_entries; + if (topo_change->exp_handle) + search_idx += max_num_phy_ids; + map_idx = _mapping_get_free_mt_idx(sc, + search_idx); + } + if (map_idx == MPR_MAPTABLE_BAD_IDX) { + map_idx = _mapping_get_high_missing_mt_idx(sc); + if (map_idx != MPR_MAPTABLE_BAD_IDX) { + mt_entry = &sc->mapping_table[map_idx]; + if (mt_entry->dev_handle) { + _mapping_add_to_removal_table + (sc, mt_entry->dev_handle, + 0); + is_removed = 1; + } + mt_entry->init_complete = 0; + } + } + if (map_idx != MPR_MAPTABLE_BAD_IDX) { + mt_entry = &sc->mapping_table[map_idx]; + mt_entry->physical_id = phy_change->physical_id; + mt_entry->channel = 0; + mt_entry->id = map_idx; + mt_entry->dev_handle = phy_change->dev_handle; + mt_entry->missing_count = 0; + mt_entry->device_info = phy_change->device_info + | (MPR_DEV_RESERVED | MPR_MAP_IN_USE); + } else { + phy_change->is_processed = 1; + if (!sc->mt_full_retry) { + sc->mt_add_device_failed = 1; + continue; + } + printf("%s: failed to add the device with " + "handle 0x%04x because there is no free " + "space available in the mapping table\n", + __func__, phy_change->dev_handle); + continue; + } + if (sc->is_dpm_enable) { + if (mt_entry->dpm_entry_num != + MPR_DPM_BAD_IDX) { + dpm_idx = mt_entry->dpm_entry_num; + dpm_entry = (Mpi2DriverMap0Entry_t *) + ((u8 *)sc->dpm_pg0 + hdr_sz); + dpm_entry += dpm_idx; + missing_cnt = dpm_entry-> + MappingInformation & + MPI2_DRVMAP0_MAPINFO_MISSING_MASK; + temp64_var = dpm_entry-> + PhysicalIdentifier.High; + temp64_var = (temp64_var << 32) | + dpm_entry->PhysicalIdentifier.Low; + if ((mt_entry->physical_id == + temp64_var) && !missing_cnt) + mt_entry->init_complete = 1; + } else { + dpm_idx = _mapping_get_free_dpm_idx(sc); + mt_entry->init_complete = 0; + } + if (dpm_idx != MPR_DPM_BAD_IDX && + !mt_entry->init_complete) { + mt_entry->init_complete = 1; + mt_entry->dpm_entry_num = dpm_idx; + dpm_entry = (Mpi2DriverMap0Entry_t *) + ((u8 *)sc->dpm_pg0 + hdr_sz); + dpm_entry += dpm_idx; + dpm_entry->PhysicalIdentifier.Low = + (0xFFFFFFFF & + mt_entry->physical_id); + dpm_entry->PhysicalIdentifier.High = + (mt_entry->physical_id >> 32); + dpm_entry->DeviceIndex = (U16) map_idx; + dpm_entry->MappingInformation = 0; + dpm_entry->PhysicalBitsMapping = 0; + sc->dpm_entry_used[dpm_idx] = 1; + sc->dpm_flush_entry[dpm_idx] = 1; + phy_change->is_processed = 1; + } else if (dpm_idx == MPR_DPM_BAD_IDX) { + phy_change->is_processed = 1; + mpr_dprint(sc, MPR_INFO, "%s: " + "failed to add the device " + "with handle 0x%04x to " + "persistent table because " + "there is no free space " + "available\n", __func__, + phy_change->dev_handle); + } + } + mt_entry->init_complete = 1; + } + + phy_change->is_processed = 1; + } + if (is_removed) + _mapping_clear_removed_entries(sc); +} + +/** + * _mapping_flush_dpm_pages -Flush the DPM pages to NVRAM + * @sc: per adapter object + * + * Returns nothing + */ +static void +_mapping_flush_dpm_pages(struct mpr_softc *sc) +{ + Mpi2DriverMap0Entry_t *dpm_entry; + Mpi2ConfigReply_t mpi_reply; + Mpi2DriverMappingPage0_t config_page; + u16 entry_num; + + for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) { + if (!sc->dpm_flush_entry[entry_num]) + continue; + memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t)); + memcpy(&config_page.Header, (u8 *)sc->dpm_pg0, + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + dpm_entry += entry_num; + dpm_entry->MappingInformation = htole16(dpm_entry-> + MappingInformation); + dpm_entry->DeviceIndex = htole16(dpm_entry->DeviceIndex); + dpm_entry->PhysicalBitsMapping = htole32(dpm_entry-> + PhysicalBitsMapping); + memcpy(&config_page.Entry, (u8 *)dpm_entry, + sizeof(Mpi2DriverMap0Entry_t)); + /* TODO-How to handle failed writes? */ + if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page, + entry_num)) { + printf("%s: write of dpm entry %d for device failed\n", + __func__, entry_num); + } else + sc->dpm_flush_entry[entry_num] = 0; + dpm_entry->MappingInformation = le16toh(dpm_entry-> + MappingInformation); + dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); + dpm_entry->PhysicalBitsMapping = le32toh(dpm_entry-> + PhysicalBitsMapping); + } +} + +/** + * _mapping_allocate_memory- allocates the memory required for mapping tables + * @sc: per adapter object + * + * Allocates the memory for all the tables required for host mapping + * + * Return 0 on success or non-zero on failure. + */ +int +mpr_mapping_allocate_memory(struct mpr_softc *sc) +{ + uint32_t dpm_pg0_sz; + + sc->mapping_table = malloc((sizeof(struct dev_mapping_table) * + sc->max_devices), M_MPR, M_ZERO|M_NOWAIT); + if (!sc->mapping_table) + goto free_resources; + + sc->removal_table = malloc((sizeof(struct map_removal_table) * + sc->max_devices), M_MPR, M_ZERO|M_NOWAIT); + if (!sc->removal_table) + goto free_resources; + + sc->enclosure_table = malloc((sizeof(struct enc_mapping_table) * + sc->max_enclosures), M_MPR, M_ZERO|M_NOWAIT); + if (!sc->enclosure_table) + goto free_resources; + + sc->dpm_entry_used = malloc((sizeof(u8) * sc->max_dpm_entries), + M_MPR, M_ZERO|M_NOWAIT); + if (!sc->dpm_entry_used) + goto free_resources; + + sc->dpm_flush_entry = malloc((sizeof(u8) * sc->max_dpm_entries), + M_MPR, M_ZERO|M_NOWAIT); + if (!sc->dpm_flush_entry) + goto free_resources; + + dpm_pg0_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER) + + (sc->max_dpm_entries * sizeof(MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY)); + + sc->dpm_pg0 = malloc(dpm_pg0_sz, M_MPR, M_ZERO|M_NOWAIT); + if (!sc->dpm_pg0) { + printf("%s: memory alloc failed for dpm page; disabling dpm\n", + __func__); + sc->is_dpm_enable = 0; + } + + return 0; + +free_resources: + free(sc->mapping_table, M_MPR); + free(sc->removal_table, M_MPR); + free(sc->enclosure_table, M_MPR); + free(sc->dpm_entry_used, M_MPR); + free(sc->dpm_flush_entry, M_MPR); + free(sc->dpm_pg0, M_MPR); + printf("%s: device initialization failed due to failure in mapping " + "table memory allocation\n", __func__); + return -1; +} + +/** + * mpr_mapping_free_memory- frees the memory allocated for mapping tables + * @sc: per adapter object + * + * Returns nothing. + */ +void +mpr_mapping_free_memory(struct mpr_softc *sc) +{ + free(sc->mapping_table, M_MPR); + free(sc->removal_table, M_MPR); + free(sc->enclosure_table, M_MPR); + free(sc->dpm_entry_used, M_MPR); + free(sc->dpm_flush_entry, M_MPR); + free(sc->dpm_pg0, M_MPR); +} + + +static void +_mapping_process_dpm_pg0(struct mpr_softc *sc) +{ + u8 missing_cnt, enc_idx; + u16 slot_id, entry_num, num_slots; + u32 map_idx, dev_idx, start_idx, end_idx; + struct dev_mapping_table *mt_entry; + Mpi2DriverMap0Entry_t *dpm_entry; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs); + struct enc_mapping_table *et_entry; + u64 physical_id; + u32 phy_bits = 0; + + if (sc->ir_firmware) + _mapping_get_ir_maprange(sc, &start_idx, &end_idx); + + dpm_entry = (Mpi2DriverMap0Entry_t *) ((uint8_t *) sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++, + dpm_entry++) { + physical_id = dpm_entry->PhysicalIdentifier.High; + physical_id = (physical_id << 32) | + dpm_entry->PhysicalIdentifier.Low; + if (!physical_id) { + sc->dpm_entry_used[entry_num] = 0; + continue; + } + sc->dpm_entry_used[entry_num] = 1; + dpm_entry->MappingInformation = le16toh(dpm_entry-> + MappingInformation); + missing_cnt = dpm_entry->MappingInformation & + MPI2_DRVMAP0_MAPINFO_MISSING_MASK; + dev_idx = le16toh(dpm_entry->DeviceIndex); + phy_bits = le32toh(dpm_entry->PhysicalBitsMapping); + if (sc->ir_firmware && (dev_idx >= start_idx) && + (dev_idx <= end_idx)) { + mt_entry = &sc->mapping_table[dev_idx]; + mt_entry->physical_id = dpm_entry->PhysicalIdentifier.High; + mt_entry->physical_id = (mt_entry->physical_id << 32) | + dpm_entry->PhysicalIdentifier.Low; + mt_entry->channel = MPR_RAID_CHANNEL; + mt_entry->id = dev_idx; + mt_entry->missing_count = missing_cnt; + mt_entry->dpm_entry_num = entry_num; + mt_entry->device_info = MPR_DEV_RESERVED; + continue; + } + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { + if (dev_idx < (sc->num_rsvd_entries + + max_num_phy_ids)) { + slot_id = 0; + if (ioc_pg8_flags & + MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1) + slot_id = 1; + num_slots = max_num_phy_ids; + } else { + slot_id = 0; + num_slots = dpm_entry->MappingInformation & + MPI2_DRVMAP0_MAPINFO_SLOT_MASK; + num_slots >>= MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT; + } + enc_idx = sc->num_enc_table_entries; + if (enc_idx >= sc->max_enclosures) { + printf("%s: enclosure entries exceed max " + "enclosures of %d\n", __func__, + sc->max_enclosures); + break; + } + sc->num_enc_table_entries++; + et_entry = &sc->enclosure_table[enc_idx]; + physical_id = dpm_entry->PhysicalIdentifier.High; + et_entry->enclosure_id = (physical_id << 32) | + dpm_entry->PhysicalIdentifier.Low; + et_entry->start_index = dev_idx; + et_entry->dpm_entry_num = entry_num; + et_entry->num_slots = num_slots; + et_entry->start_slot = slot_id; + et_entry->missing_count = missing_cnt; + et_entry->phy_bits = phy_bits; + + mt_entry = &sc->mapping_table[dev_idx]; + for (map_idx = dev_idx; map_idx < (dev_idx + num_slots); + map_idx++, mt_entry++) { + if (mt_entry->dpm_entry_num != + MPR_DPM_BAD_IDX) { + printf("%s: conflict in mapping table " + "for enclosure %d\n", __func__, + enc_idx); + break; + } + physical_id = dpm_entry->PhysicalIdentifier.High; + mt_entry->physical_id = (physical_id << 32) | + dpm_entry->PhysicalIdentifier.Low; + mt_entry->phy_bits = phy_bits; + mt_entry->channel = 0; + mt_entry->id = dev_idx; + mt_entry->dpm_entry_num = entry_num; + mt_entry->missing_count = missing_cnt; + mt_entry->device_info = MPR_DEV_RESERVED; + } + } else if ((ioc_pg8_flags & + MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { + map_idx = dev_idx; + mt_entry = &sc->mapping_table[map_idx]; + if (mt_entry->dpm_entry_num != MPR_DPM_BAD_IDX) { + printf("%s: conflict in mapping table for " + "device %d\n", __func__, map_idx); + break; + } + physical_id = dpm_entry->PhysicalIdentifier.High; + mt_entry->physical_id = (physical_id << 32) | + dpm_entry->PhysicalIdentifier.Low; + mt_entry->phy_bits = phy_bits; + mt_entry->channel = 0; + mt_entry->id = dev_idx; + mt_entry->missing_count = missing_cnt; + mt_entry->dpm_entry_num = entry_num; + mt_entry->device_info = MPR_DEV_RESERVED; + } + } /*close the loop for DPM table */ +} + +/* + * mpr_mapping_check_devices - start of the day check for device availabilty + * @sc: per adapter object + * @sleep_flag: Flag indicating whether this function can sleep or not + * + * Returns nothing. + */ +void +mpr_mapping_check_devices(struct mpr_softc *sc, int sleep_flag) +{ + u32 i; +/* u32 cntdn, i; + u32 timeout = 60;*/ + struct dev_mapping_table *mt_entry; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + struct enc_mapping_table *et_entry; + u32 start_idx, end_idx; + + /* We need to ucomment this when this function is called + * from the port enable complete */ +#if 0 + sc->track_mapping_events = 0; + cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; + do { + if (!sc->pending_map_events) + break; + if (sleep_flag == CAN_SLEEP) + pause("mpr_pause", (hz/1000));/* 1msec sleep */ + else + DELAY(500); /* 500 useconds delay */ + } while (--cntdn); + + + if (!cntdn) + printf("%s: there are %d" + " pending events after %d seconds of delay\n", + __func__, sc->pending_map_events, timeout); +#endif + sc->pending_map_events = 0; + + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { + et_entry = sc->enclosure_table; + for (i = 0; i < sc->num_enc_table_entries; i++, et_entry++) { + if (!et_entry->init_complete) { + if (et_entry->missing_count < + MPR_MAX_MISSING_COUNT) { + et_entry->missing_count++; + if (et_entry->dpm_entry_num != + MPR_DPM_BAD_IDX) + _mapping_commit_enc_entry(sc, + et_entry); + } + et_entry->init_complete = 1; + } + } + if (!sc->ir_firmware) + return; + _mapping_get_ir_maprange(sc, &start_idx, &end_idx); + mt_entry = &sc->mapping_table[start_idx]; + for (i = start_idx; i < (end_idx + 1); i++, mt_entry++) { + if (mt_entry->device_info & MPR_DEV_RESERVED + && !mt_entry->physical_id) + mt_entry->init_complete = 1; + else if (mt_entry->device_info & MPR_DEV_RESERVED) { + if (!mt_entry->init_complete) { + if (mt_entry->missing_count < + MPR_MAX_MISSING_COUNT) { + mt_entry->missing_count++; + if (mt_entry->dpm_entry_num != + MPR_DPM_BAD_IDX) + _mapping_commit_map_entry(sc, + mt_entry); + } + mt_entry->init_complete = 1; + } + } + } + } else if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == + MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { + mt_entry = sc->mapping_table; + for (i = 0; i < sc->max_devices; i++, mt_entry++) { + if (mt_entry->device_info & MPR_DEV_RESERVED + && !mt_entry->physical_id) + mt_entry->init_complete = 1; + else if (mt_entry->device_info & MPR_DEV_RESERVED) { + if (!mt_entry->init_complete) { + if (mt_entry->missing_count < + MPR_MAX_MISSING_COUNT) { + mt_entry->missing_count++; + if (mt_entry->dpm_entry_num != + MPR_DPM_BAD_IDX) + _mapping_commit_map_entry(sc, + mt_entry); + } + mt_entry->init_complete = 1; + } + } + } + } +} + + +/** + * mpr_mapping_is_reinit_required - check whether event replay required + * @sc: per adapter object + * + * Checks the per ioc flags and decide whether reinit of events required + * + * Returns 1 for reinit of ioc 0 for not. + */ +int mpr_mapping_is_reinit_required(struct mpr_softc *sc) +{ + if (!sc->mt_full_retry && sc->mt_add_device_failed) { + sc->mt_full_retry = 1; + sc->mt_add_device_failed = 0; + _mapping_flush_dpm_pages(sc); + return 1; + } + sc->mt_full_retry = 1; + return 0; +} + +/** + * mpr_mapping_initialize - initialize mapping tables + * @sc: per adapter object + * + * Read controller persitant mapping tables into internal data area. + * + * Return 0 for success or non-zero for failure. + */ +int +mpr_mapping_initialize(struct mpr_softc *sc) +{ + uint16_t volume_mapping_flags, dpm_pg0_sz; + uint32_t i; + Mpi2ConfigReply_t mpi_reply; + int error; + uint8_t retry_count; + uint16_t ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + + /* The additional 1 accounts for the virtual enclosure + * created for the controller + */ + sc->max_enclosures = sc->facts->MaxEnclosures + 1; + sc->max_expanders = sc->facts->MaxSasExpanders; + sc->max_volumes = sc->facts->MaxVolumes; + sc->max_devices = sc->facts->MaxTargets + sc->max_volumes; + sc->pending_map_events = 0; + sc->num_enc_table_entries = 0; + sc->num_rsvd_entries = 0; + sc->num_channels = 1; + sc->max_dpm_entries = sc->ioc_pg8.MaxPersistentEntries; + sc->is_dpm_enable = (sc->max_dpm_entries) ? 1 : 0; + sc->track_mapping_events = 0; + + if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING) + sc->is_dpm_enable = 0; + + if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0) + sc->num_rsvd_entries = 1; + + volume_mapping_flags = sc->ioc_pg8.IRVolumeMappingFlags & + MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; + if (sc->ir_firmware && (volume_mapping_flags == + MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING)) + sc->num_rsvd_entries += sc->max_volumes; + + error = mpr_mapping_allocate_memory(sc); + if (error) + return (error); + + for (i = 0; i < sc->max_devices; i++) + _mapping_clear_map_entry(sc->mapping_table + i); + + for (i = 0; i < sc->max_enclosures; i++) + _mapping_clear_enc_entry(sc->enclosure_table + i); + + for (i = 0; i < sc->max_devices; i++) { + sc->removal_table[i].dev_handle = 0; + sc->removal_table[i].dpm_entry_num = MPR_DPM_BAD_IDX; + } + + memset(sc->dpm_entry_used, 0, sc->max_dpm_entries); + memset(sc->dpm_flush_entry, 0, sc->max_dpm_entries); + + if (sc->is_dpm_enable) { + dpm_pg0_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER) + + (sc->max_dpm_entries * + sizeof(MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY)); + retry_count = 0; + +retry_read_dpm: + if (mpr_config_get_dpm_pg0(sc, &mpi_reply, sc->dpm_pg0, + dpm_pg0_sz)) { + printf("%s: dpm page read failed; disabling dpm\n", + __func__); + if (retry_count < 3) { + retry_count++; + goto retry_read_dpm; + } + sc->is_dpm_enable = 0; + } + } + + if (sc->is_dpm_enable) + _mapping_process_dpm_pg0(sc); + + sc->track_mapping_events = 1; + return 0; +} + +/** + * mpr_mapping_exit - clear mapping table and associated memory + * @sc: per adapter object + * + * Returns nothing. + */ +void +mpr_mapping_exit(struct mpr_softc *sc) +{ + _mapping_flush_dpm_pages(sc); + mpr_mapping_free_memory(sc); +} + +/** + * mpr_mapping_get_sas_id - assign a target id for sas device + * @sc: per adapter object + * @sas_address: sas address of the device + * @handle: device handle + * + * Returns valid ID on success or BAD_ID. + */ +unsigned int +mpr_mapping_get_sas_id(struct mpr_softc *sc, uint64_t sas_address, u16 handle) +{ + u32 map_idx; + struct dev_mapping_table *mt_entry; + + for (map_idx = 0; map_idx < sc->max_devices; map_idx++) { + mt_entry = &sc->mapping_table[map_idx]; + if (mt_entry->dev_handle == handle && mt_entry->physical_id == + sas_address) + return mt_entry->id; + } + + return MPR_MAP_BAD_ID; +} + +/** + * mpr_mapping_get_sas_id_from_handle - find a target id in mapping table using + * only the dev handle. This is just a wrapper function for the local function + * _mapping_get_mt_idx_from_handle. + * @sc: per adapter object + * @handle: device handle + * + * Returns valid ID on success or BAD_ID. + */ +unsigned int +mpr_mapping_get_sas_id_from_handle(struct mpr_softc *sc, u16 handle) +{ + return (_mapping_get_mt_idx_from_handle(sc, handle)); +} + +/** + * mpr_mapping_get_raid_id - assign a target id for raid device + * @sc: per adapter object + * @wwid: world wide identifier for raid volume + * @handle: device handle + * + * Returns valid ID on success or BAD_ID. + */ +unsigned int +mpr_mapping_get_raid_id(struct mpr_softc *sc, u64 wwid, u16 handle) +{ + u32 map_idx; + struct dev_mapping_table *mt_entry; + + for (map_idx = 0; map_idx < sc->max_devices; map_idx++) { + mt_entry = &sc->mapping_table[map_idx]; + if (mt_entry->dev_handle == handle && mt_entry->physical_id == + wwid) + return mt_entry->id; + } + + return MPR_MAP_BAD_ID; +} + +/** + * mpr_mapping_get_raid_id_from_handle - find raid device in mapping table + * using only the volume dev handle. This is just a wrapper function for the + * local function _mapping_get_ir_mt_idx_from_handle. + * @sc: per adapter object + * @volHandle: volume device handle + * + * Returns valid ID on success or BAD_ID. + */ +unsigned int +mpr_mapping_get_raid_id_from_handle(struct mpr_softc *sc, u16 volHandle) +{ + return (_mapping_get_ir_mt_idx_from_handle(sc, volHandle)); +} + +/** + * mpr_mapping_enclosure_dev_status_change_event - handle enclosure events + * @sc: per adapter object + * @event_data: event data payload + * + * Return nothing. + */ +void +mpr_mapping_enclosure_dev_status_change_event(struct mpr_softc *sc, + Mpi2EventDataSasEnclDevStatusChange_t *event_data) +{ + u8 enc_idx, missing_count; + struct enc_mapping_table *et_entry; + Mpi2DriverMap0Entry_t *dpm_entry; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + u8 map_shift = MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT; + u8 update_phy_bits = 0; + u32 saved_phy_bits; + uint64_t temp64_var; + + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) != + MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) + goto out; + + dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + + if (event_data->ReasonCode == MPI2_EVENT_SAS_ENCL_RC_ADDED) { + if (!event_data->NumSlots) { + printf("%s: enclosure with handle = 0x%x reported 0 " + "slots\n", __func__, + le16toh(event_data->EnclosureHandle)); + goto out; + } + temp64_var = event_data->EnclosureLogicalID.High; + temp64_var = (temp64_var << 32) | + event_data->EnclosureLogicalID.Low; + enc_idx = _mapping_get_enc_idx_from_id(sc, temp64_var, + event_data->PhyBits); + if (enc_idx != MPR_ENCTABLE_BAD_IDX) { + et_entry = &sc->enclosure_table[enc_idx]; + if (et_entry->init_complete && + !et_entry->missing_count) { + printf("%s: enclosure %d is already present " + "with handle = 0x%x\n",__func__, enc_idx, + et_entry->enc_handle); + goto out; + } + et_entry->enc_handle = le16toh(event_data-> + EnclosureHandle); + et_entry->start_slot = le16toh(event_data->StartSlot); + saved_phy_bits = et_entry->phy_bits; + et_entry->phy_bits |= le32toh(event_data->PhyBits); + if (saved_phy_bits != et_entry->phy_bits) + update_phy_bits = 1; + if (et_entry->missing_count || update_phy_bits) { + et_entry->missing_count = 0; + if (sc->is_dpm_enable && + et_entry->dpm_entry_num != + MPR_DPM_BAD_IDX) { + dpm_entry += et_entry->dpm_entry_num; + missing_count = + (u8)(dpm_entry->MappingInformation & + MPI2_DRVMAP0_MAPINFO_MISSING_MASK); + if (!et_entry->init_complete && ( + missing_count || update_phy_bits)) { + dpm_entry->MappingInformation + = et_entry->num_slots; + dpm_entry->MappingInformation + <<= map_shift; + dpm_entry->PhysicalBitsMapping + = et_entry->phy_bits; + sc->dpm_flush_entry[et_entry-> + dpm_entry_num] = 1; + } + } + } + } else { + enc_idx = sc->num_enc_table_entries; + if (enc_idx >= sc->max_enclosures) { + printf("%s: enclosure can not be added; " + "mapping table is full\n", __func__); + goto out; + } + sc->num_enc_table_entries++; + et_entry = &sc->enclosure_table[enc_idx]; + et_entry->enc_handle = le16toh(event_data-> + EnclosureHandle); + et_entry->enclosure_id = event_data-> + EnclosureLogicalID.High; + et_entry->enclosure_id = ( et_entry->enclosure_id << + 32) | event_data->EnclosureLogicalID.Low; + et_entry->start_index = MPR_MAPTABLE_BAD_IDX; + et_entry->dpm_entry_num = MPR_DPM_BAD_IDX; + et_entry->num_slots = le16toh(event_data->NumSlots); + et_entry->start_slot = le16toh(event_data->StartSlot); + et_entry->phy_bits = le32toh(event_data->PhyBits); + } + et_entry->init_complete = 1; + } else if (event_data->ReasonCode == + MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING) { + enc_idx = _mapping_get_enc_idx_from_handle(sc, + le16toh(event_data->EnclosureHandle)); + if (enc_idx == MPR_ENCTABLE_BAD_IDX) { + printf("%s: cannot unmap enclosure %d because it has " + "already been deleted", __func__, enc_idx); + goto out; + } + et_entry = &sc->enclosure_table[enc_idx]; + if (!et_entry->init_complete) { + if (et_entry->missing_count < MPR_MAX_MISSING_COUNT) + et_entry->missing_count++; + else + et_entry->init_complete = 1; + } + if (!et_entry->missing_count) + et_entry->missing_count++; + if (sc->is_dpm_enable && !et_entry->init_complete && + et_entry->dpm_entry_num != MPR_DPM_BAD_IDX) { + dpm_entry += et_entry->dpm_entry_num; + dpm_entry->MappingInformation = et_entry->num_slots; + dpm_entry->MappingInformation <<= map_shift; + dpm_entry->MappingInformation |= + et_entry->missing_count; + sc->dpm_flush_entry[et_entry->dpm_entry_num] = 1; + } + et_entry->init_complete = 1; + } + +out: + _mapping_flush_dpm_pages(sc); + if (sc->pending_map_events) + sc->pending_map_events--; +} + +/** + * mpr_mapping_topology_change_event - handle topology change events + * @sc: per adapter object + * @event_data: event data payload + * + * Returns nothing. + */ +void +mpr_mapping_topology_change_event(struct mpr_softc *sc, + Mpi2EventDataSasTopologyChangeList_t *event_data) +{ + struct _map_topology_change topo_change; + struct _map_phy_change *phy_change; + Mpi2EventSasTopoPhyEntry_t *event_phy_change; + u8 i, num_entries; + + topo_change.enc_handle = le16toh(event_data->EnclosureHandle); + topo_change.exp_handle = le16toh(event_data->ExpanderDevHandle); + num_entries = event_data->NumEntries; + topo_change.num_entries = num_entries; + topo_change.start_phy_num = event_data->StartPhyNum; + topo_change.num_phys = event_data->NumPhys; + topo_change.exp_status = event_data->ExpStatus; + event_phy_change = event_data->PHY; + topo_change.phy_details = NULL; + + if (!num_entries) + goto out; + phy_change = malloc(sizeof(struct _map_phy_change) * num_entries, + M_MPR, M_NOWAIT|M_ZERO); + topo_change.phy_details = phy_change; + if (!phy_change) + goto out; + for (i = 0; i < num_entries; i++, event_phy_change++, phy_change++) { + phy_change->dev_handle = le16toh(event_phy_change-> + AttachedDevHandle); + phy_change->reason = event_phy_change->PhyStatus & + MPI2_EVENT_SAS_TOPO_RC_MASK; + } + _mapping_update_missing_count(sc, &topo_change); + _mapping_get_dev_info(sc, &topo_change); + _mapping_clear_removed_entries(sc); + _mapping_add_new_device(sc, &topo_change); + +out: + free(topo_change.phy_details, M_MPR); + _mapping_flush_dpm_pages(sc); + if (sc->pending_map_events) + sc->pending_map_events--; +} + +/** + * _mapping_check_update_ir_mt_idx - Check and update IR map table index + * @sc: per adapter object + * @event_data: event data payload + * @evt_idx: current event index + * @map_idx: current index and the place holder for new map table index + * @wwid_table: world wide name for volumes in the element table + * + * pass through IR events and find whether any events matches and if so + * tries to find new index if not returns failure + * + * Returns 0 on success and 1 on failure + */ +static int +_mapping_check_update_ir_mt_idx(struct mpr_softc *sc, + Mpi2EventDataIrConfigChangeList_t *event_data, int evt_idx, u32 *map_idx, + u64 *wwid_table) +{ + struct dev_mapping_table *mt_entry; + u32 st_idx, end_idx, mt_idx = *map_idx; + u8 match = 0; + Mpi2EventIrConfigElement_t *element; + u16 element_flags; + int i; + + mt_entry = &sc->mapping_table[mt_idx]; + _mapping_get_ir_maprange(sc, &st_idx, &end_idx); +search_again: + match = 0; + for (i = evt_idx + 1; i < event_data->NumElements; i++) { + element = (Mpi2EventIrConfigElement_t *) + &event_data->ConfigElement[i]; + element_flags = le16toh(element->ElementFlags); + if ((element_flags & + MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK) != + MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT) + continue; + if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_ADDED || + element->ReasonCode == + MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) { + if (mt_entry->physical_id == wwid_table[i]) { + match = 1; + break; + } + } + } + + if (match) { + do { + mt_idx++; + if (mt_idx > end_idx) + return 1; + mt_entry = &sc->mapping_table[mt_idx]; + } while (mt_entry->device_info & MPR_MAP_IN_USE); + goto search_again; + } + *map_idx = mt_idx; + return 0; +} + +/** + * mpr_mapping_ir_config_change_event - handle IR config change list events + * @sc: per adapter object + * @event_data: event data payload + * + * Returns nothing. + */ +void +mpr_mapping_ir_config_change_event(struct mpr_softc *sc, + Mpi2EventDataIrConfigChangeList_t *event_data) +{ + Mpi2EventIrConfigElement_t *element; + int i; + u64 *wwid_table; + u32 map_idx, flags; + struct dev_mapping_table *mt_entry; + u16 element_flags; + u8 log_full_error = 0; + + wwid_table = malloc(sizeof(u64) * event_data->NumElements, M_MPR, + M_NOWAIT | M_ZERO); + if (!wwid_table) + goto out; + element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; + flags = le32toh(event_data->Flags); + for (i = 0; i < event_data->NumElements; i++, element++) { + element_flags = le16toh(element->ElementFlags); + if ((element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_ADDED) && + (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_REMOVED) && + (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE) + && (element->ReasonCode != + MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED)) + continue; + if ((element_flags & + MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK) == + MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT) { + mpr_config_get_volume_wwid(sc, + le16toh(element->VolDevHandle), &wwid_table[i]); + map_idx = _mapping_get_ir_mt_idx_from_wwid(sc, + wwid_table[i]); + if (map_idx != MPR_MAPTABLE_BAD_IDX) { + mt_entry = &sc->mapping_table[map_idx]; + mt_entry->device_info |= MPR_MAP_IN_USE; + } + } + } + if (flags == MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) + goto out; + else { + element = (Mpi2EventIrConfigElement_t *)&event_data-> + ConfigElement[0]; + for (i = 0; i < event_data->NumElements; i++, element++) { + if (element->ReasonCode == + MPI2_EVENT_IR_CHANGE_RC_ADDED || + element->ReasonCode == + MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) { + map_idx = _mapping_get_ir_mt_idx_from_wwid + (sc, wwid_table[i]); + if (map_idx != MPR_MAPTABLE_BAD_IDX) { + mt_entry = &sc->mapping_table[map_idx]; + mt_entry->channel = MPR_RAID_CHANNEL; + mt_entry->id = map_idx; + mt_entry->dev_handle = le16toh + (element->VolDevHandle); + mt_entry->device_info = + MPR_DEV_RESERVED | MPR_MAP_IN_USE; + _mapping_update_ir_missing_cnt(sc, + map_idx, element, wwid_table[i]); + continue; + } + map_idx = _mapping_get_free_ir_mt_idx(sc); + if (map_idx == MPR_MAPTABLE_BAD_IDX) + log_full_error = 1; + else if (i < (event_data->NumElements - 1)) { + log_full_error = + _mapping_check_update_ir_mt_idx + (sc, event_data, i, &map_idx, + wwid_table); + } + if (log_full_error) { + printf("%s: no space to add the RAID " + "volume with handle 0x%04x in " + "mapping table\n", __func__, le16toh + (element->VolDevHandle)); + continue; + } + mt_entry = &sc->mapping_table[map_idx]; + mt_entry->physical_id = wwid_table[i]; + mt_entry->channel = MPR_RAID_CHANNEL; + mt_entry->id = map_idx; + mt_entry->dev_handle = le16toh(element-> + VolDevHandle); + mt_entry->device_info = MPR_DEV_RESERVED | + MPR_MAP_IN_USE; + mt_entry->init_complete = 0; + _mapping_update_ir_missing_cnt(sc, map_idx, + element, wwid_table[i]); + } else if (element->ReasonCode == + MPI2_EVENT_IR_CHANGE_RC_REMOVED) { + map_idx = _mapping_get_ir_mt_idx_from_wwid(sc, + wwid_table[i]); + if (map_idx == MPR_MAPTABLE_BAD_IDX) { + printf("%s: failed to remove a volume " + "because it has already been " + "removed\n", __func__); + continue; + } + _mapping_update_ir_missing_cnt(sc, map_idx, + element, wwid_table[i]); + } else if (element->ReasonCode == + MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) { + map_idx = _mapping_get_mt_idx_from_handle(sc, + le16toh(element->VolDevHandle)); + if (map_idx == MPR_MAPTABLE_BAD_IDX) { + printf("%s: failed to remove volume " + "with handle 0x%04x because it has " + "already been removed\n", __func__, + le16toh(element->VolDevHandle)); + continue; + } + mt_entry = &sc->mapping_table[map_idx]; + _mapping_update_ir_missing_cnt(sc, map_idx, + element, mt_entry->physical_id); + } + } + } + +out: + _mapping_flush_dpm_pages(sc); + free(wwid_table, M_MPR); + if (sc->pending_map_events) + sc->pending_map_events--; +} diff --git a/sys/dev/mpr/mpr_mapping.h b/sys/dev/mpr/mpr_mapping.h new file mode 100644 index 0000000000000..3250c424e2a4f --- /dev/null +++ b/sys/dev/mpr/mpr_mapping.h @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 2011-2014 LSI Corp. + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + +#ifndef _MPR_MAPPING_H +#define _MPR_MAPPING_H + +/** + * struct _map_phy_change - PHY entries recieved in Topology change list + * @physical_id: SAS address of the device attached with the associate PHY + * @device_info: bitfield provides detailed info about the device + * @dev_handle: device handle for the device pointed by this entry + * @slot: slot ID + * @is_processed: Flag to indicate whether this entry is processed or not + */ +struct _map_phy_change { + uint64_t physical_id; + uint32_t device_info; + uint16_t dev_handle; + uint16_t slot; + uint8_t reason; + uint8_t is_processed; +}; + +/** + * struct _map_topology_change - entries to be removed from mapping table + * @dpm_entry_num: index of this device in device persistent map table + * @dev_handle: device handle for the device pointed by this entry + */ +struct _map_topology_change { + uint16_t enc_handle; + uint16_t exp_handle; + uint8_t num_entries; + uint8_t start_phy_num; + uint8_t num_phys; + uint8_t exp_status; + struct _map_phy_change *phy_details; +}; + + +extern int +mprsas_get_sas_address_for_sata_disk(struct mpr_softc *ioc, + u64 *sas_address, u16 handle, u32 device_info); + +#endif diff --git a/sys/dev/mpr/mpr_pci.c b/sys/dev/mpr/mpr_pci.c new file mode 100644 index 0000000000000..e19f33adceb4c --- /dev/null +++ b/sys/dev/mpr/mpr_pci.c @@ -0,0 +1,350 @@ +/*- + * Copyright (c) 2009 Yahoo! Inc. + * 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$"); + +/* PCI/PCI-X/PCIe bus interface for the LSI MPT2 controllers */ + +/* TODO Move headers to mprvar */ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/malloc.h> +#include <sys/sysctl.h> +#include <sys/uio.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pci_private.h> + +#include <dev/mpr/mpi/mpi2_type.h> +#include <dev/mpr/mpi/mpi2.h> +#include <dev/mpr/mpi/mpi2_ioc.h> +#include <dev/mpr/mpi/mpi2_cnfg.h> +#include <dev/mpr/mpi/mpi2_tool.h> + +#include <sys/queue.h> +#include <sys/kthread.h> +#include <dev/mpr/mpr_ioctl.h> +#include <dev/mpr/mprvar.h> + +static int mpr_pci_probe(device_t); +static int mpr_pci_attach(device_t); +static int mpr_pci_detach(device_t); +static int mpr_pci_suspend(device_t); +static int mpr_pci_resume(device_t); +static void mpr_pci_free(struct mpr_softc *); +static int mpr_alloc_msix(struct mpr_softc *sc, int msgs); +static int mpr_alloc_msi(struct mpr_softc *sc, int msgs); + +static device_method_t mpr_methods[] = { + DEVMETHOD(device_probe, mpr_pci_probe), + DEVMETHOD(device_attach, mpr_pci_attach), + DEVMETHOD(device_detach, mpr_pci_detach), + DEVMETHOD(device_suspend, mpr_pci_suspend), + DEVMETHOD(device_resume, mpr_pci_resume), + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), + { 0, 0 } +}; + +static driver_t mpr_pci_driver = { + "mpr", + mpr_methods, + sizeof(struct mpr_softc) +}; + +static devclass_t mpr_devclass; +DRIVER_MODULE(mpr, pci, mpr_pci_driver, mpr_devclass, 0, 0); +MODULE_DEPEND(mpr, cam, 1, 1, 1); + +struct mpr_ident { + uint16_t vendor; + uint16_t device; + uint16_t subvendor; + uint16_t subdevice; + u_int flags; + const char *desc; +} mpr_identifiers[] = { + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3004, + 0xffff, 0xffff, 0, "LSI SAS3004" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3008, + 0xffff, 0xffff, 0, "LSI SAS3008" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_1, + 0xffff, 0xffff, 0, "LSI SAS3108_1" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_2, + 0xffff, 0xffff, 0, "LSI SAS3108_2" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_5, + 0xffff, 0xffff, 0, "LSI SAS3108_5" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6, + 0xffff, 0xffff, 0, "LSI SAS3108_6" }, + { 0, 0, 0, 0, 0, NULL } +}; + +static struct mpr_ident * +mpr_find_ident(device_t dev) +{ + struct mpr_ident *m; + + for (m = mpr_identifiers; m->vendor != 0; m++) { + if (m->vendor != pci_get_vendor(dev)) + continue; + if (m->device != pci_get_device(dev)) + continue; + if ((m->subvendor != 0xffff) && + (m->subvendor != pci_get_subvendor(dev))) + continue; + if ((m->subdevice != 0xffff) && + (m->subdevice != pci_get_subdevice(dev))) + continue; + return (m); + } + + return (NULL); +} + +static int +mpr_pci_probe(device_t dev) +{ + struct mpr_ident *id; + + if ((id = mpr_find_ident(dev)) != NULL) { + device_set_desc(dev, id->desc); + return (BUS_PROBE_DEFAULT); + } + return (ENXIO); +} + +static int +mpr_pci_attach(device_t dev) +{ + struct mpr_softc *sc; + struct mpr_ident *m; + int error; + + sc = device_get_softc(dev); + bzero(sc, sizeof(*sc)); + sc->mpr_dev = dev; + m = mpr_find_ident(dev); + sc->mpr_flags = m->flags; + + /* Twiddle basic PCI config bits for a sanity check */ + pci_enable_busmaster(dev); + + /* Allocate the System Interface Register Set */ + sc->mpr_regs_rid = PCIR_BAR(1); + if ((sc->mpr_regs_resource = bus_alloc_resource_any(dev, + SYS_RES_MEMORY, &sc->mpr_regs_rid, RF_ACTIVE)) == NULL) { + mpr_printf(sc, "Cannot allocate PCI registers\n"); + return (ENXIO); + } + sc->mpr_btag = rman_get_bustag(sc->mpr_regs_resource); + sc->mpr_bhandle = rman_get_bushandle(sc->mpr_regs_resource); + + /* Allocate the parent DMA tag */ + if (bus_dma_tag_create( bus_get_dma_tag(dev), /* parent */ + 1, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ + BUS_SPACE_UNRESTRICTED, /* nsegments */ + BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->mpr_parent_dmat)) { + mpr_printf(sc, "Cannot allocate parent DMA tag\n"); + mpr_pci_free(sc); + return (ENOMEM); + } + + if ((error = mpr_attach(sc)) != 0) + mpr_pci_free(sc); + + return (error); +} + +int +mpr_pci_setup_interrupts(struct mpr_softc *sc) +{ + device_t dev; + int i, error, msgs; + + dev = sc->mpr_dev; + error = ENXIO; + if ((sc->disable_msix == 0) && + ((msgs = pci_msix_count(dev)) >= MPR_MSI_COUNT)) + error = mpr_alloc_msix(sc, MPR_MSI_COUNT); + if ((error != 0) && (sc->disable_msi == 0) && + ((msgs = pci_msi_count(dev)) >= MPR_MSI_COUNT)) + error = mpr_alloc_msi(sc, MPR_MSI_COUNT); + + if (error != 0) { + sc->mpr_flags |= MPR_FLAGS_INTX; + sc->mpr_irq_rid[0] = 0; + sc->mpr_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &sc->mpr_irq_rid[0], RF_SHAREABLE | RF_ACTIVE); + if (sc->mpr_irq[0] == NULL) { + mpr_printf(sc, "Cannot allocate INTx interrupt\n"); + return (ENXIO); + } + error = bus_setup_intr(dev, sc->mpr_irq[0], + INTR_TYPE_BIO | INTR_MPSAFE, NULL, mpr_intr, sc, + &sc->mpr_intrhand[0]); + if (error) + mpr_printf(sc, "Cannot setup INTx interrupt\n"); + } else { + sc->mpr_flags |= MPR_FLAGS_MSI; + for (i = 0; i < MPR_MSI_COUNT; i++) { + sc->mpr_irq_rid[i] = i + 1; + sc->mpr_irq[i] = bus_alloc_resource_any(dev, + SYS_RES_IRQ, &sc->mpr_irq_rid[i], RF_ACTIVE); + if (sc->mpr_irq[i] == NULL) { + mpr_printf(sc, + "Cannot allocate MSI interrupt\n"); + return (ENXIO); + } + error = bus_setup_intr(dev, sc->mpr_irq[i], + INTR_TYPE_BIO | INTR_MPSAFE, NULL, mpr_intr_msi, + sc, &sc->mpr_intrhand[i]); + if (error) { + mpr_printf(sc, + "Cannot setup MSI interrupt %d\n", i); + break; + } + } + } + + return (error); +} + +static int +mpr_pci_detach(device_t dev) +{ + struct mpr_softc *sc; + int error; + + sc = device_get_softc(dev); + + if ((error = mpr_free(sc)) != 0) + return (error); + + mpr_pci_free(sc); + return (0); +} + +static void +mpr_pci_free(struct mpr_softc *sc) +{ + int i; + + if (sc->mpr_parent_dmat != NULL) { + bus_dma_tag_destroy(sc->mpr_parent_dmat); + } + + if (sc->mpr_flags & MPR_FLAGS_MSI) { + for (i = 0; i < MPR_MSI_COUNT; i++) { + if (sc->mpr_irq[i] != NULL) { + bus_teardown_intr(sc->mpr_dev, sc->mpr_irq[i], + sc->mpr_intrhand[i]); + bus_release_resource(sc->mpr_dev, SYS_RES_IRQ, + sc->mpr_irq_rid[i], sc->mpr_irq[i]); + } + } + pci_release_msi(sc->mpr_dev); + } + + if (sc->mpr_flags & MPR_FLAGS_INTX) { + bus_teardown_intr(sc->mpr_dev, sc->mpr_irq[0], + sc->mpr_intrhand[0]); + bus_release_resource(sc->mpr_dev, SYS_RES_IRQ, + sc->mpr_irq_rid[0], sc->mpr_irq[0]); + } + + if (sc->mpr_regs_resource != NULL) { + bus_release_resource(sc->mpr_dev, SYS_RES_MEMORY, + sc->mpr_regs_rid, sc->mpr_regs_resource); + } + + return; +} + +static int +mpr_pci_suspend(device_t dev) +{ + return (EINVAL); +} + +static int +mpr_pci_resume(device_t dev) +{ + return (EINVAL); +} + +static int +mpr_alloc_msix(struct mpr_softc *sc, int msgs) +{ + int error; + + error = pci_alloc_msix(sc->mpr_dev, &msgs); + return (error); +} + +static int +mpr_alloc_msi(struct mpr_softc *sc, int msgs) +{ + int error; + + error = pci_alloc_msi(sc->mpr_dev, &msgs); + return (error); +} + +int +mpr_pci_restore(struct mpr_softc *sc) +{ + struct pci_devinfo *dinfo; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + dinfo = device_get_ivars(sc->mpr_dev); + if (dinfo == NULL) { + mpr_dprint(sc, MPR_FAULT, "%s: NULL dinfo\n", __func__); + return (EINVAL); + } + + pci_cfg_restore(sc->mpr_dev, dinfo); + return (0); +} + diff --git a/sys/dev/mpr/mpr_sas.c b/sys/dev/mpr/mpr_sas.c new file mode 100644 index 0000000000000..1f95358c877e7 --- /dev/null +++ b/sys/dev/mpr/mpr_sas.c @@ -0,0 +1,3485 @@ +/*- + * Copyright (c) 2009 Yahoo! Inc. + * Copyright (c) 2011-2014 LSI Corp. + * 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$"); + +/* Communications core for LSI MPT2 */ + +/* TODO Move headers to mprvar */ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/selinfo.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/bio.h> +#include <sys/malloc.h> +#include <sys/uio.h> +#include <sys/sysctl.h> +#include <sys/endian.h> +#include <sys/queue.h> +#include <sys/kthread.h> +#include <sys/taskqueue.h> +#include <sys/sbuf.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <machine/stdarg.h> + +#include <cam/cam.h> +#include <cam/cam_ccb.h> +#include <cam/cam_debug.h> +#include <cam/cam_sim.h> +#include <cam/cam_xpt_sim.h> +#include <cam/cam_xpt_periph.h> +#include <cam/cam_periph.h> +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_message.h> +#if __FreeBSD_version >= 900026 +#include <cam/scsi/smp_all.h> +#endif + +#include <dev/mpr/mpi/mpi2_type.h> +#include <dev/mpr/mpi/mpi2.h> +#include <dev/mpr/mpi/mpi2_ioc.h> +#include <dev/mpr/mpi/mpi2_sas.h> +#include <dev/mpr/mpi/mpi2_cnfg.h> +#include <dev/mpr/mpi/mpi2_init.h> +#include <dev/mpr/mpi/mpi2_tool.h> +#include <dev/mpr/mpr_ioctl.h> +#include <dev/mpr/mprvar.h> +#include <dev/mpr/mpr_table.h> +#include <dev/mpr/mpr_sas.h> + +#define MPRSAS_DISCOVERY_TIMEOUT 20 +#define MPRSAS_MAX_DISCOVERY_TIMEOUTS 10 /* 200 seconds */ + +/* + * static array to check SCSI OpCode for EEDP protection bits + */ +#define PRO_R MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP +#define PRO_W MPI2_SCSIIO_EEDPFLAGS_INSERT_OP +#define PRO_V MPI2_SCSIIO_EEDPFLAGS_INSERT_OP +static uint8_t op_code_prot[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, + 0, 0, 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +MALLOC_DEFINE(M_MPRSAS, "MPRSAS", "MPR SAS memory"); + +static void mprsas_remove_device(struct mpr_softc *, struct mpr_command *); +static void mprsas_remove_complete(struct mpr_softc *, struct mpr_command *); +static void mprsas_action(struct cam_sim *sim, union ccb *ccb); +static void mprsas_poll(struct cam_sim *sim); +static void mprsas_scsiio_timeout(void *data); +static void mprsas_abort_complete(struct mpr_softc *sc, + struct mpr_command *cm); +static void mprsas_action_scsiio(struct mprsas_softc *, union ccb *); +static void mprsas_scsiio_complete(struct mpr_softc *, struct mpr_command *); +static void mprsas_action_resetdev(struct mprsas_softc *, union ccb *); +static void mprsas_resetdev_complete(struct mpr_softc *, + struct mpr_command *); +static int mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm, + struct mpr_command *cm); +static int mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, + uint8_t type); +static void mprsas_async(void *callback_arg, uint32_t code, + struct cam_path *path, void *arg); +static void mprsas_prepare_ssu(struct mpr_softc *sc, struct cam_path *path, + struct ccb_getdev *cgd); +#if (__FreeBSD_version < 901503) || \ + ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) +static void mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path, + struct ccb_getdev *cgd); +static void mprsas_read_cap_done(struct cam_periph *periph, + union ccb *done_ccb); +#endif +static int mprsas_send_portenable(struct mpr_softc *sc); +static void mprsas_portenable_complete(struct mpr_softc *sc, + struct mpr_command *cm); + +#if __FreeBSD_version >= 900026 +static void +mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm); +static void mprsas_send_smpcmd(struct mprsas_softc *sassc, + union ccb *ccb, uint64_t sasaddr); +static void +mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb); +#endif + +struct mprsas_target * +mprsas_find_target_by_handle(struct mprsas_softc *sassc, int start, + uint16_t handle) +{ + struct mprsas_target *target; + int i; + + for (i = start; i < sassc->maxtargets; i++) { + target = &sassc->targets[i]; + if (target->handle == handle) + return (target); + } + + return (NULL); +} + +/* we need to freeze the simq during attach and diag reset, to avoid failing + * commands before device handles have been found by discovery. Since + * discovery involves reading config pages and possibly sending commands, + * discovery actions may continue even after we receive the end of discovery + * event, so refcount discovery actions instead of assuming we can unfreeze + * the simq when we get the event. + */ +void +mprsas_startup_increment(struct mprsas_softc *sassc) +{ + MPR_FUNCTRACE(sassc->sc); + + if ((sassc->flags & MPRSAS_IN_STARTUP) != 0) { + if (sassc->startup_refcount++ == 0) { + /* just starting, freeze the simq */ + mpr_dprint(sassc->sc, MPR_INIT, + "%s freezing simq\n", __func__); +#if (__FreeBSD_version >= 1000039) || \ + ((__FreeBSD_version < 1000000) && (__FreeBSD_version >= 902502)) + xpt_hold_boot(); +#endif + xpt_freeze_simq(sassc->sim, 1); + } + mpr_dprint(sassc->sc, MPR_INIT, "%s refcount %u\n", __func__, + sassc->startup_refcount); + } +} + +void +mprsas_release_simq_reinit(struct mprsas_softc *sassc) +{ + if (sassc->flags & MPRSAS_QUEUE_FROZEN) { + sassc->flags &= ~MPRSAS_QUEUE_FROZEN; + xpt_release_simq(sassc->sim, 1); + mpr_dprint(sassc->sc, MPR_INFO, "Unfreezing SIM queue\n"); + } +} + +void +mprsas_startup_decrement(struct mprsas_softc *sassc) +{ + MPR_FUNCTRACE(sassc->sc); + + if ((sassc->flags & MPRSAS_IN_STARTUP) != 0) { + if (--sassc->startup_refcount == 0) { + /* finished all discovery-related actions, release + * the simq and rescan for the latest topology. + */ + mpr_dprint(sassc->sc, MPR_INIT, + "%s releasing simq\n", __func__); + sassc->flags &= ~MPRSAS_IN_STARTUP; + xpt_release_simq(sassc->sim, 1); +#if (__FreeBSD_version >= 1000039) || \ + ((__FreeBSD_version < 1000000) && (__FreeBSD_version >= 902502)) + xpt_release_boot(); +#else + mprsas_rescan_target(sassc->sc, NULL); +#endif + } + mpr_dprint(sassc->sc, MPR_INIT, "%s refcount %u\n", __func__, + sassc->startup_refcount); + } +} + +/* LSI's firmware requires us to stop sending commands when we're doing task + * management, so refcount the TMs and keep the simq frozen when any are in + * use. + */ +struct mpr_command * +mprsas_alloc_tm(struct mpr_softc *sc) +{ + struct mpr_command *tm; + + MPR_FUNCTRACE(sc); + tm = mpr_alloc_high_priority_command(sc); + if (tm != NULL) { + if (sc->sassc->tm_count++ == 0) { + mpr_dprint(sc, MPR_RECOVERY, + "%s freezing simq\n", __func__); + xpt_freeze_simq(sc->sassc->sim, 1); + } + mpr_dprint(sc, MPR_RECOVERY, "%s tm_count %u\n", __func__, + sc->sassc->tm_count); + } + return tm; +} + +void +mprsas_free_tm(struct mpr_softc *sc, struct mpr_command *tm) +{ + mpr_dprint(sc, MPR_TRACE, "%s", __func__); + if (tm == NULL) + return; + + /* if there are no TMs in use, we can release the simq. We use our + * own refcount so that it's easier for a diag reset to cleanup and + * release the simq. + */ + if (--sc->sassc->tm_count == 0) { + mpr_dprint(sc, MPR_RECOVERY, "%s releasing simq\n", __func__); + xpt_release_simq(sc->sassc->sim, 1); + } + mpr_dprint(sc, MPR_RECOVERY, "%s tm_count %u\n", __func__, + sc->sassc->tm_count); + + mpr_free_high_priority_command(sc, tm); +} + +void +mprsas_rescan_target(struct mpr_softc *sc, struct mprsas_target *targ) +{ + struct mprsas_softc *sassc = sc->sassc; + path_id_t pathid; + target_id_t targetid; + union ccb *ccb; + + MPR_FUNCTRACE(sc); + pathid = cam_sim_path(sassc->sim); + if (targ == NULL) + targetid = CAM_TARGET_WILDCARD; + else + targetid = targ - sassc->targets; + + /* + * Allocate a CCB and schedule a rescan. + */ + ccb = xpt_alloc_ccb_nowait(); + if (ccb == NULL) { + mpr_dprint(sc, MPR_ERROR, "unable to alloc CCB for rescan\n"); + return; + } + + if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, + targetid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + mpr_dprint(sc, MPR_ERROR, "unable to create path for rescan\n"); + xpt_free_ccb(ccb); + return; + } + + if (targetid == CAM_TARGET_WILDCARD) + ccb->ccb_h.func_code = XPT_SCAN_BUS; + else + ccb->ccb_h.func_code = XPT_SCAN_TGT; + + mpr_dprint(sc, MPR_TRACE, "%s targetid %u\n", __func__, targetid); + xpt_rescan(ccb); +} + +static void +mprsas_log_command(struct mpr_command *cm, u_int level, const char *fmt, ...) +{ + struct sbuf sb; + va_list ap; + char str[192]; + char path_str[64]; + + if (cm == NULL) + return; + + /* No need to be in here if debugging isn't enabled */ + if ((cm->cm_sc->mpr_debug & level) == 0) + return; + + sbuf_new(&sb, str, sizeof(str), 0); + + va_start(ap, fmt); + + if (cm->cm_ccb != NULL) { + xpt_path_string(cm->cm_ccb->csio.ccb_h.path, path_str, + sizeof(path_str)); + sbuf_cat(&sb, path_str); + if (cm->cm_ccb->ccb_h.func_code == XPT_SCSI_IO) { + scsi_command_string(&cm->cm_ccb->csio, &sb); + sbuf_printf(&sb, "length %d ", + cm->cm_ccb->csio.dxfer_len); + } + } else { + sbuf_printf(&sb, "(noperiph:%s%d:%u:%u:%u): ", + cam_sim_name(cm->cm_sc->sassc->sim), + cam_sim_unit(cm->cm_sc->sassc->sim), + cam_sim_bus(cm->cm_sc->sassc->sim), + cm->cm_targ ? cm->cm_targ->tid : 0xFFFFFFFF, + cm->cm_lun); + } + + sbuf_printf(&sb, "SMID %u ", cm->cm_desc.Default.SMID); + sbuf_vprintf(&sb, fmt, ap); + sbuf_finish(&sb); + mpr_dprint_field(cm->cm_sc, level, "%s", sbuf_data(&sb)); + + va_end(ap); +} + +static void +mprsas_remove_volume(struct mpr_softc *sc, struct mpr_command *tm) +{ + MPI2_SCSI_TASK_MANAGE_REPLY *reply; + struct mprsas_target *targ; + uint16_t handle; + + MPR_FUNCTRACE(sc); + + reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; + handle = (uint16_t)(uintptr_t)tm->cm_complete_data; + targ = tm->cm_targ; + + if (reply == NULL) { + /* XXX retry the remove after the diag reset completes? */ + mpr_dprint(sc, MPR_FAULT, "%s NULL reply resetting device " + "0x%04x\n", __func__, handle); + mprsas_free_tm(sc, tm); + return; + } + + if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) { + mpr_dprint(sc, MPR_FAULT, "IOCStatus = 0x%x while resetting " + "device 0x%x\n", reply->IOCStatus, handle); + mprsas_free_tm(sc, tm); + return; + } + + mpr_dprint(sc, MPR_XINFO, "Reset aborted %u commands\n", + reply->TerminationCount); + mpr_free_reply(sc, tm->cm_reply_data); + tm->cm_reply = NULL; /* Ensures the reply won't get re-freed */ + + mpr_dprint(sc, MPR_XINFO, "clearing target %u handle 0x%04x\n", + targ->tid, handle); + + /* + * Don't clear target if remove fails because things will get confusing. + * Leave the devname and sasaddr intact so that we know to avoid reusing + * this target id if possible, and so we can assign the same target id + * to this device if it comes back in the future. + */ + if (reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) { + targ = tm->cm_targ; + targ->handle = 0x0; + targ->encl_handle = 0x0; + targ->encl_level_valid = 0x0; + targ->encl_level = 0x0; + targ->connector_name[0] = ' '; + targ->connector_name[1] = ' '; + targ->connector_name[2] = ' '; + targ->connector_name[3] = ' '; + targ->encl_slot = 0x0; + targ->exp_dev_handle = 0x0; + targ->phy_num = 0x0; + targ->linkrate = 0x0; + targ->devinfo = 0x0; + targ->flags = 0x0; + targ->scsi_req_desc_type = 0; + } + + mprsas_free_tm(sc, tm); +} + + +/* + * No Need to call "MPI2_SAS_OP_REMOVE_DEVICE" For Volume removal. + * Otherwise Volume Delete is same as Bare Drive Removal. + */ +void +mprsas_prepare_volume_remove(struct mprsas_softc *sassc, uint16_t handle) +{ + MPI2_SCSI_TASK_MANAGE_REQUEST *req; + struct mpr_softc *sc; + struct mpr_command *cm; + struct mprsas_target *targ = NULL; + + MPR_FUNCTRACE(sassc->sc); + sc = sassc->sc; + + targ = mprsas_find_target_by_handle(sassc, 0, handle); + if (targ == NULL) { + /* FIXME: what is the action? */ + /* We don't know about this device? */ + mpr_dprint(sc, MPR_ERROR, + "%s %d : invalid handle 0x%x \n", __func__,__LINE__, handle); + return; + } + + targ->flags |= MPRSAS_TARGET_INREMOVAL; + + cm = mprsas_alloc_tm(sc); + if (cm == NULL) { + mpr_dprint(sc, MPR_ERROR, + "%s: command alloc failure\n", __func__); + return; + } + + mprsas_rescan_target(sc, targ); + + req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; + req->DevHandle = targ->handle; + req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; + req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; + + /* SAS Hard Link Reset / SATA Link Reset */ + req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; + + cm->cm_targ = targ; + cm->cm_data = NULL; + cm->cm_desc.HighPriority.RequestFlags = + MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; + cm->cm_complete = mprsas_remove_volume; + cm->cm_complete_data = (void *)(uintptr_t)handle; + mpr_map_command(sc, cm); +} + +/* + * The MPT2 firmware performs debounce on the link to avoid transient link + * errors and false removals. When it does decide that link has been lost + * and a device needs to go away, it expects that the host will perform a + * target reset and then an op remove. The reset has the side-effect of + * aborting any outstanding requests for the device, which is required for + * the op-remove to succeed. It's not clear if the host should check for + * the device coming back alive after the reset. + */ +void +mprsas_prepare_remove(struct mprsas_softc *sassc, uint16_t handle) +{ + MPI2_SCSI_TASK_MANAGE_REQUEST *req; + struct mpr_softc *sc; + struct mpr_command *cm; + struct mprsas_target *targ = NULL; + + MPR_FUNCTRACE(sassc->sc); + + sc = sassc->sc; + + targ = mprsas_find_target_by_handle(sassc, 0, handle); + if (targ == NULL) { + /* FIXME: what is the action? */ + /* We don't know about this device? */ + mpr_dprint(sc, MPR_ERROR, "%s : invalid handle 0x%x \n", + __func__, handle); + return; + } + + targ->flags |= MPRSAS_TARGET_INREMOVAL; + + cm = mprsas_alloc_tm(sc); + if (cm == NULL) { + mpr_dprint(sc, MPR_ERROR, "%s: command alloc failure\n", + __func__); + return; + } + + mprsas_rescan_target(sc, targ); + + req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; + memset(req, 0, sizeof(*req)); + req->DevHandle = htole16(targ->handle); + req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; + req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; + + /* SAS Hard Link Reset / SATA Link Reset */ + req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; + + cm->cm_targ = targ; + cm->cm_data = NULL; + cm->cm_desc.HighPriority.RequestFlags = + MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; + cm->cm_complete = mprsas_remove_device; + cm->cm_complete_data = (void *)(uintptr_t)handle; + mpr_map_command(sc, cm); +} + +static void +mprsas_remove_device(struct mpr_softc *sc, struct mpr_command *tm) +{ + MPI2_SCSI_TASK_MANAGE_REPLY *reply; + MPI2_SAS_IOUNIT_CONTROL_REQUEST *req; + struct mprsas_target *targ; + struct mpr_command *next_cm; + uint16_t handle; + + MPR_FUNCTRACE(sc); + + reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; + handle = (uint16_t)(uintptr_t)tm->cm_complete_data; + targ = tm->cm_targ; + + /* + * Currently there should be no way we can hit this case. It only + * happens when we have a failure to allocate chain frames, and + * task management commands don't have S/G lists. + */ + if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { + mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for remove of " + "handle %#04x! This should not happen!\n", __func__, + tm->cm_flags, handle); + mprsas_free_tm(sc, tm); + return; + } + + if (reply == NULL) { + /* XXX retry the remove after the diag reset completes? */ + mpr_dprint(sc, MPR_FAULT, "%s NULL reply resetting device " + "0x%04x\n", __func__, handle); + mprsas_free_tm(sc, tm); + return; + } + + if (le16toh(reply->IOCStatus) != MPI2_IOCSTATUS_SUCCESS) { + mpr_dprint(sc, MPR_FAULT, "IOCStatus = 0x%x while resetting " + "device 0x%x\n", le16toh(reply->IOCStatus), handle); + mprsas_free_tm(sc, tm); + return; + } + + mpr_dprint(sc, MPR_XINFO, "Reset aborted %u commands\n", + le32toh(reply->TerminationCount)); + mpr_free_reply(sc, tm->cm_reply_data); + tm->cm_reply = NULL; /* Ensures the reply won't get re-freed */ + + /* Reuse the existing command */ + req = (MPI2_SAS_IOUNIT_CONTROL_REQUEST *)tm->cm_req; + memset(req, 0, sizeof(*req)); + req->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; + req->Operation = MPI2_SAS_OP_REMOVE_DEVICE; + req->DevHandle = htole16(handle); + tm->cm_data = NULL; + tm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + tm->cm_complete = mprsas_remove_complete; + tm->cm_complete_data = (void *)(uintptr_t)handle; + + mpr_map_command(sc, tm); + + mpr_dprint(sc, MPR_XINFO, "clearing target %u handle 0x%04x\n", + targ->tid, handle); + if (targ->encl_level_valid) { + mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, " + "connector name (%4s)\n", targ->encl_level, targ->encl_slot, + targ->connector_name); + } + TAILQ_FOREACH_SAFE(tm, &targ->commands, cm_link, next_cm) { + union ccb *ccb; + + mpr_dprint(sc, MPR_XINFO, "Completing missed command %p\n", tm); + ccb = tm->cm_complete_data; + ccb->ccb_h.status = CAM_DEV_NOT_THERE; + mprsas_scsiio_complete(sc, tm); + } +} + +static void +mprsas_remove_complete(struct mpr_softc *sc, struct mpr_command *tm) +{ + MPI2_SAS_IOUNIT_CONTROL_REPLY *reply; + uint16_t handle; + struct mprsas_target *targ; + struct mprsas_lun *lun; + + MPR_FUNCTRACE(sc); + + reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)tm->cm_reply; + handle = (uint16_t)(uintptr_t)tm->cm_complete_data; + + /* + * Currently there should be no way we can hit this case. It only + * happens when we have a failure to allocate chain frames, and + * task management commands don't have S/G lists. + */ + if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { + mpr_dprint(sc, MPR_XINFO, "%s: cm_flags = %#x for remove of " + "handle %#04x! This should not happen!\n", __func__, + tm->cm_flags, handle); + mprsas_free_tm(sc, tm); + return; + } + + if (reply == NULL) { + /* most likely a chip reset */ + mpr_dprint(sc, MPR_FAULT, "%s NULL reply removing device " + "0x%04x\n", __func__, handle); + mprsas_free_tm(sc, tm); + return; + } + + mpr_dprint(sc, MPR_XINFO, "%s on handle 0x%04x, IOCStatus= 0x%x\n", + __func__, handle, le16toh(reply->IOCStatus)); + + /* + * Don't clear target if remove fails because things will get confusing. + * Leave the devname and sasaddr intact so that we know to avoid reusing + * this target id if possible, and so we can assign the same target id + * to this device if it comes back in the future. + */ + if (le16toh(reply->IOCStatus) == MPI2_IOCSTATUS_SUCCESS) { + targ = tm->cm_targ; + targ->handle = 0x0; + targ->encl_handle = 0x0; + targ->encl_level_valid = 0x0; + targ->encl_level = 0x0; + targ->connector_name[0] = ' '; + targ->connector_name[1] = ' '; + targ->connector_name[2] = ' '; + targ->connector_name[3] = ' '; + targ->encl_slot = 0x0; + targ->exp_dev_handle = 0x0; + targ->phy_num = 0x0; + targ->linkrate = 0x0; + targ->devinfo = 0x0; + targ->flags = 0x0; + targ->scsi_req_desc_type = 0; + + while (!SLIST_EMPTY(&targ->luns)) { + lun = SLIST_FIRST(&targ->luns); + SLIST_REMOVE_HEAD(&targ->luns, lun_link); + free(lun, M_MPR); + } + } + + mprsas_free_tm(sc, tm); +} + +static int +mprsas_register_events(struct mpr_softc *sc) +{ + uint8_t events[16]; + + bzero(events, 16); + setbit(events, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); + setbit(events, MPI2_EVENT_SAS_DISCOVERY); + setbit(events, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE); + setbit(events, MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE); + setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW); + setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST); + setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE); + setbit(events, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST); + setbit(events, MPI2_EVENT_IR_VOLUME); + setbit(events, MPI2_EVENT_IR_PHYSICAL_DISK); + setbit(events, MPI2_EVENT_IR_OPERATION_STATUS); + setbit(events, MPI2_EVENT_TEMP_THRESHOLD); + + mpr_register_events(sc, events, mprsas_evt_handler, NULL, + &sc->sassc->mprsas_eh); + + return (0); +} + +int +mpr_attach_sas(struct mpr_softc *sc) +{ + struct mprsas_softc *sassc; + cam_status status; + int unit, error = 0; + + MPR_FUNCTRACE(sc); + + sassc = malloc(sizeof(struct mprsas_softc), M_MPR, M_WAITOK|M_ZERO); + if (!sassc) { + device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n", + __func__, __LINE__); + return (ENOMEM); + } + + /* + * XXX MaxTargets could change during a reinit. since we don't + * resize the targets[] array during such an event, cache the value + * of MaxTargets here so that we don't get into trouble later. This + * should move into the reinit logic. + */ + sassc->maxtargets = sc->facts->MaxTargets; + sassc->targets = malloc(sizeof(struct mprsas_target) * + sassc->maxtargets, M_MPR, M_WAITOK|M_ZERO); + if (!sassc->targets) { + device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n", + __func__, __LINE__); + free(sassc, M_MPR); + return (ENOMEM); + } + sc->sassc = sassc; + sassc->sc = sc; + + if ((sassc->devq = cam_simq_alloc(sc->num_reqs)) == NULL) { + mpr_dprint(sc, MPR_ERROR, "Cannot allocate SIMQ\n"); + error = ENOMEM; + goto out; + } + + unit = device_get_unit(sc->mpr_dev); + sassc->sim = cam_sim_alloc(mprsas_action, mprsas_poll, "mpr", sassc, + unit, &sc->mpr_mtx, sc->num_reqs, sc->num_reqs, sassc->devq); + if (sassc->sim == NULL) { + mpr_dprint(sc, MPR_ERROR, "Cannot allocate SIM\n"); + error = EINVAL; + goto out; + } + + TAILQ_INIT(&sassc->ev_queue); + + /* Initialize taskqueue for Event Handling */ + TASK_INIT(&sassc->ev_task, 0, mprsas_firmware_event_work, sc); + sassc->ev_tq = taskqueue_create("mpr_taskq", M_NOWAIT | M_ZERO, + taskqueue_thread_enqueue, &sassc->ev_tq); + + /* Run the task queue with lowest priority */ + taskqueue_start_threads(&sassc->ev_tq, 1, 255, "%s taskq", + device_get_nameunit(sc->mpr_dev)); + + mpr_lock(sc); + + /* + * XXX There should be a bus for every port on the adapter, but since + * we're just going to fake the topology for now, we'll pretend that + * everything is just a target on a single bus. + */ + if ((error = xpt_bus_register(sassc->sim, sc->mpr_dev, 0)) != 0) { + mpr_dprint(sc, MPR_ERROR, "Error %d registering SCSI bus\n", + error); + mpr_unlock(sc); + goto out; + } + + /* + * Assume that discovery events will start right away. Freezing + * + * Hold off boot until discovery is complete. + */ + sassc->flags |= MPRSAS_IN_STARTUP | MPRSAS_IN_DISCOVERY; + sc->sassc->startup_refcount = 0; + mprsas_startup_increment(sassc); + + callout_init(&sassc->discovery_callout, 1 /*mprafe*/); + + sassc->tm_count = 0; + + /* + * Register for async events so we can determine the EEDP + * capabilities of devices. + */ + status = xpt_create_path(&sassc->path, /*periph*/NULL, + cam_sim_path(sc->sassc->sim), CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD); + if (status != CAM_REQ_CMP) { + mpr_printf(sc, "Error %#x creating sim path\n", status); + sassc->path = NULL; + } else { + int event; + +#if (__FreeBSD_version >= 1000006) || \ + ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000)) + event = AC_ADVINFO_CHANGED | AC_FOUND_DEVICE; +#else + event = AC_FOUND_DEVICE; +#endif + + /* + * Prior to the CAM locking improvements, we can't call + * xpt_register_async() with a particular path specified. + * + * If a path isn't specified, xpt_register_async() will + * generate a wildcard path and acquire the XPT lock while + * it calls xpt_action() to execute the XPT_SASYNC_CB CCB. + * It will then drop the XPT lock once that is done. + * + * If a path is specified for xpt_register_async(), it will + * not acquire and drop the XPT lock around the call to + * xpt_action(). xpt_action() asserts that the caller + * holds the SIM lock, so the SIM lock has to be held when + * calling xpt_register_async() when the path is specified. + * + * But xpt_register_async calls xpt_for_all_devices(), + * which calls xptbustraverse(), which will acquire each + * SIM lock. When it traverses our particular bus, it will + * necessarily acquire the SIM lock, which will lead to a + * recursive lock acquisition. + * + * The CAM locking changes fix this problem by acquiring + * the XPT topology lock around bus traversal in + * xptbustraverse(), so the caller can hold the SIM lock + * and it does not cause a recursive lock acquisition. + * + * These __FreeBSD_version values are approximate, especially + * for stable/10, which is two months later than the actual + * change. + */ + +#if (__FreeBSD_version < 1000703) || \ + ((__FreeBSD_version >= 1100000) && (__FreeBSD_version < 1100002)) + mpr_unlock(sc); + status = xpt_register_async(event, mprsas_async, sc, + NULL); + mpr_lock(sc); +#else + status = xpt_register_async(event, mprsas_async, sc, + sassc->path); +#endif + + if (status != CAM_REQ_CMP) { + mpr_dprint(sc, MPR_ERROR, + "Error %#x registering async handler for " + "AC_ADVINFO_CHANGED events\n", status); + xpt_free_path(sassc->path); + sassc->path = NULL; + } + } + if (status != CAM_REQ_CMP) { + /* + * EEDP use is the exception, not the rule. + * Warn the user, but do not fail to attach. + */ + mpr_printf(sc, "EEDP capabilities disabled.\n"); + } + + mpr_unlock(sc); + + mprsas_register_events(sc); +out: + if (error) + mpr_detach_sas(sc); + return (error); +} + +int +mpr_detach_sas(struct mpr_softc *sc) +{ + struct mprsas_softc *sassc; + struct mprsas_lun *lun, *lun_tmp; + struct mprsas_target *targ; + int i; + + MPR_FUNCTRACE(sc); + + if (sc->sassc == NULL) + return (0); + + sassc = sc->sassc; + mpr_deregister_events(sc, sassc->mprsas_eh); + + /* + * Drain and free the event handling taskqueue with the lock + * unheld so that any parallel processing tasks drain properly + * without deadlocking. + */ + if (sassc->ev_tq != NULL) + taskqueue_free(sassc->ev_tq); + + /* Make sure CAM doesn't wedge if we had to bail out early. */ + mpr_lock(sc); + + /* Deregister our async handler */ + if (sassc->path != NULL) { + xpt_register_async(0, mprsas_async, sc, sassc->path); + xpt_free_path(sassc->path); + sassc->path = NULL; + } + + if (sassc->flags & MPRSAS_IN_STARTUP) + xpt_release_simq(sassc->sim, 1); + + if (sassc->sim != NULL) { + xpt_bus_deregister(cam_sim_path(sassc->sim)); + cam_sim_free(sassc->sim, FALSE); + } + + sassc->flags |= MPRSAS_SHUTDOWN; + mpr_unlock(sc); + + if (sassc->devq != NULL) + cam_simq_free(sassc->devq); + + for (i = 0; i < sassc->maxtargets; i++) { + targ = &sassc->targets[i]; + SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, lun_tmp) { + free(lun, M_MPR); + } + } + free(sassc->targets, M_MPR); + free(sassc, M_MPR); + sc->sassc = NULL; + + return (0); +} + +void +mprsas_discovery_end(struct mprsas_softc *sassc) +{ + struct mpr_softc *sc = sassc->sc; + + MPR_FUNCTRACE(sc); + + if (sassc->flags & MPRSAS_DISCOVERY_TIMEOUT_PENDING) + callout_stop(&sassc->discovery_callout); + +} + +static void +mprsas_action(struct cam_sim *sim, union ccb *ccb) +{ + struct mprsas_softc *sassc; + + sassc = cam_sim_softc(sim); + + MPR_FUNCTRACE(sassc->sc); + mpr_dprint(sassc->sc, MPR_TRACE, "%s func 0x%x\n", __func__, + ccb->ccb_h.func_code); + mtx_assert(&sassc->sc->mpr_mtx, MA_OWNED); + + switch (ccb->ccb_h.func_code) { + case XPT_PATH_INQ: + { + struct ccb_pathinq *cpi = &ccb->cpi; + + cpi->version_num = 1; + cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; + cpi->target_sprt = 0; +#if (__FreeBSD_version >= 1000039) || \ + ((__FreeBSD_version < 1000000) && (__FreeBSD_version >= 902502)) + cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED | PIM_NOSCAN; +#else + cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED; +#endif + cpi->hba_eng_cnt = 0; + cpi->max_target = sassc->maxtargets - 1; + cpi->max_lun = 255; + cpi->initiator_id = sassc->maxtargets - 1; + strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); + strncpy(cpi->hba_vid, "LSILogic", HBA_IDLEN); + strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); + cpi->unit_number = cam_sim_unit(sim); + cpi->bus_id = cam_sim_bus(sim); + /* + * XXXSLM-I think this needs to change based on config page or + * something instead of hardcoded to 150000. + */ + cpi->base_transfer_speed = 150000; + cpi->transport = XPORT_SAS; + cpi->transport_version = 0; + cpi->protocol = PROTO_SCSI; + cpi->protocol_version = SCSI_REV_SPC; +#if __FreeBSD_version >= 800001 + /* + * XXXSLM-probably need to base this number on max SGL's and + * page size. + */ + cpi->maxio = 256 * 1024; +#endif + cpi->ccb_h.status = CAM_REQ_CMP; + break; + } + case XPT_GET_TRAN_SETTINGS: + { + struct ccb_trans_settings *cts; + struct ccb_trans_settings_sas *sas; + struct ccb_trans_settings_scsi *scsi; + struct mprsas_target *targ; + + cts = &ccb->cts; + sas = &cts->xport_specific.sas; + scsi = &cts->proto_specific.scsi; + + KASSERT(cts->ccb_h.target_id < sassc->maxtargets, + ("Target %d out of bounds in XPT_GET_TRAN_SETTINGS\n", + cts->ccb_h.target_id)); + targ = &sassc->targets[cts->ccb_h.target_id]; + if (targ->handle == 0x0) { + cts->ccb_h.status = CAM_DEV_NOT_THERE; + break; + } + + cts->protocol_version = SCSI_REV_SPC2; + cts->transport = XPORT_SAS; + cts->transport_version = 0; + + sas->valid = CTS_SAS_VALID_SPEED; + switch (targ->linkrate) { + case 0x08: + sas->bitrate = 150000; + break; + case 0x09: + sas->bitrate = 300000; + break; + case 0x0a: + sas->bitrate = 600000; + break; + default: + sas->valid = 0; + } + + cts->protocol = PROTO_SCSI; + scsi->valid = CTS_SCSI_VALID_TQ; + scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; + + cts->ccb_h.status = CAM_REQ_CMP; + break; + } + case XPT_CALC_GEOMETRY: + cam_calc_geometry(&ccb->ccg, /*extended*/1); + ccb->ccb_h.status = CAM_REQ_CMP; + break; + case XPT_RESET_DEV: + mpr_dprint(sassc->sc, MPR_XINFO, + "mprsas_action XPT_RESET_DEV\n"); + mprsas_action_resetdev(sassc, ccb); + return; + case XPT_RESET_BUS: + case XPT_ABORT: + case XPT_TERM_IO: + mpr_dprint(sassc->sc, MPR_XINFO, + "mprsas_action faking success for abort or reset\n"); + ccb->ccb_h.status = CAM_REQ_CMP; + break; + case XPT_SCSI_IO: + mprsas_action_scsiio(sassc, ccb); + return; +#if __FreeBSD_version >= 900026 + case XPT_SMP_IO: + mprsas_action_smpio(sassc, ccb); + return; +#endif + default: + ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; + break; + } + xpt_done(ccb); + +} + +static void +mprsas_announce_reset(struct mpr_softc *sc, uint32_t ac_code, + target_id_t target_id, lun_id_t lun_id) +{ + path_id_t path_id = cam_sim_path(sc->sassc->sim); + struct cam_path *path; + + mpr_dprint(sc, MPR_XINFO, "%s code %x target %d lun %jx\n", __func__, + ac_code, target_id, (uintmax_t)lun_id); + + if (xpt_create_path(&path, NULL, + path_id, target_id, lun_id) != CAM_REQ_CMP) { + mpr_dprint(sc, MPR_ERROR, "unable to create path for reset " + "notification\n"); + return; + } + + xpt_async(ac_code, path, NULL); + xpt_free_path(path); +} + +static void +mprsas_complete_all_commands(struct mpr_softc *sc) +{ + struct mpr_command *cm; + int i; + int completed; + + MPR_FUNCTRACE(sc); + mtx_assert(&sc->mpr_mtx, MA_OWNED); + + /* complete all commands with a NULL reply */ + for (i = 1; i < sc->num_reqs; i++) { + cm = &sc->commands[i]; + cm->cm_reply = NULL; + completed = 0; + + if (cm->cm_flags & MPR_CM_FLAGS_POLLED) + cm->cm_flags |= MPR_CM_FLAGS_COMPLETE; + + if (cm->cm_complete != NULL) { + mprsas_log_command(cm, MPR_RECOVERY, + "completing cm %p state %x ccb %p for diag reset\n", + cm, cm->cm_state, cm->cm_ccb); + cm->cm_complete(sc, cm); + completed = 1; + } + + if (cm->cm_flags & MPR_CM_FLAGS_WAKEUP) { + mprsas_log_command(cm, MPR_RECOVERY, + "waking up cm %p state %x ccb %p for diag reset\n", + cm, cm->cm_state, cm->cm_ccb); + wakeup(cm); + completed = 1; + } + + if ((completed == 0) && (cm->cm_state != MPR_CM_STATE_FREE)) { + /* this should never happen, but if it does, log */ + mprsas_log_command(cm, MPR_RECOVERY, + "cm %p state %x flags 0x%x ccb %p during diag " + "reset\n", cm, cm->cm_state, cm->cm_flags, + cm->cm_ccb); + } + } +} + +void +mprsas_handle_reinit(struct mpr_softc *sc) +{ + int i; + + /* Go back into startup mode and freeze the simq, so that CAM + * doesn't send any commands until after we've rediscovered all + * targets and found the proper device handles for them. + * + * After the reset, portenable will trigger discovery, and after all + * discovery-related activities have finished, the simq will be + * released. + */ + mpr_dprint(sc, MPR_INIT, "%s startup\n", __func__); + sc->sassc->flags |= MPRSAS_IN_STARTUP; + sc->sassc->flags |= MPRSAS_IN_DISCOVERY; + mprsas_startup_increment(sc->sassc); + + /* notify CAM of a bus reset */ + mprsas_announce_reset(sc, AC_BUS_RESET, CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD); + + /* complete and cleanup after all outstanding commands */ + mprsas_complete_all_commands(sc); + + mpr_dprint(sc, MPR_INIT, "%s startup %u tm %u after command " + "completion\n", __func__, sc->sassc->startup_refcount, + sc->sassc->tm_count); + + /* zero all the target handles, since they may change after the + * reset, and we have to rediscover all the targets and use the new + * handles. + */ + for (i = 0; i < sc->sassc->maxtargets; i++) { + if (sc->sassc->targets[i].outstanding != 0) + mpr_dprint(sc, MPR_INIT, "target %u outstanding %u\n", + i, sc->sassc->targets[i].outstanding); + sc->sassc->targets[i].handle = 0x0; + sc->sassc->targets[i].exp_dev_handle = 0x0; + sc->sassc->targets[i].outstanding = 0; + sc->sassc->targets[i].flags = MPRSAS_TARGET_INDIAGRESET; + } +} +static void +mprsas_tm_timeout(void *data) +{ + struct mpr_command *tm = data; + struct mpr_softc *sc = tm->cm_sc; + + mtx_assert(&sc->mpr_mtx, MA_OWNED); + + mprsas_log_command(tm, MPR_INFO|MPR_RECOVERY, + "task mgmt %p timed out\n", tm); + mpr_reinit(sc); +} + +static void +mprsas_logical_unit_reset_complete(struct mpr_softc *sc, + struct mpr_command *tm) +{ + MPI2_SCSI_TASK_MANAGE_REPLY *reply; + MPI2_SCSI_TASK_MANAGE_REQUEST *req; + unsigned int cm_count = 0; + struct mpr_command *cm; + struct mprsas_target *targ; + + callout_stop(&tm->cm_callout); + + req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; + reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; + targ = tm->cm_targ; + + /* + * Currently there should be no way we can hit this case. It only + * happens when we have a failure to allocate chain frames, and + * task management commands don't have S/G lists. + */ + if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { + mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for LUN reset! " + "This should not happen!\n", __func__, tm->cm_flags); + mprsas_free_tm(sc, tm); + return; + } + + if (reply == NULL) { + mprsas_log_command(tm, MPR_RECOVERY, + "NULL reset reply for tm %p\n", tm); + if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { + /* this completion was due to a reset, just cleanup */ + targ->flags &= ~MPRSAS_TARGET_INRESET; + targ->tm = NULL; + mprsas_free_tm(sc, tm); + } + else { + /* we should have gotten a reply. */ + mpr_reinit(sc); + } + return; + } + + mprsas_log_command(tm, MPR_RECOVERY, + "logical unit reset status 0x%x code 0x%x count %u\n", + le16toh(reply->IOCStatus), le32toh(reply->ResponseCode), + le32toh(reply->TerminationCount)); + + /* See if there are any outstanding commands for this LUN. + * This could be made more efficient by using a per-LU data + * structure of some sort. + */ + TAILQ_FOREACH(cm, &targ->commands, cm_link) { + if (cm->cm_lun == tm->cm_lun) + cm_count++; + } + + if (cm_count == 0) { + mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, + "logical unit %u finished recovery after reset\n", + tm->cm_lun, tm); + + mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, + tm->cm_lun); + + /* we've finished recovery for this logical unit. check and + * see if some other logical unit has a timedout command + * that needs to be processed. + */ + cm = TAILQ_FIRST(&targ->timedout_commands); + if (cm) { + mprsas_send_abort(sc, tm, cm); + } + else { + targ->tm = NULL; + mprsas_free_tm(sc, tm); + } + } + else { + /* if we still have commands for this LUN, the reset + * effectively failed, regardless of the status reported. + * Escalate to a target reset. + */ + mprsas_log_command(tm, MPR_RECOVERY, + "logical unit reset complete for tm %p, but still have %u " + "command(s)\n", tm, cm_count); + mprsas_send_reset(sc, tm, + MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET); + } +} + +static void +mprsas_target_reset_complete(struct mpr_softc *sc, struct mpr_command *tm) +{ + MPI2_SCSI_TASK_MANAGE_REPLY *reply; + MPI2_SCSI_TASK_MANAGE_REQUEST *req; + struct mprsas_target *targ; + + callout_stop(&tm->cm_callout); + + req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; + reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; + targ = tm->cm_targ; + + /* + * Currently there should be no way we can hit this case. It only + * happens when we have a failure to allocate chain frames, and + * task management commands don't have S/G lists. + */ + if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { + mpr_dprint(sc, MPR_ERROR,"%s: cm_flags = %#x for target reset! " + "This should not happen!\n", __func__, tm->cm_flags); + mprsas_free_tm(sc, tm); + return; + } + + if (reply == NULL) { + mprsas_log_command(tm, MPR_RECOVERY, + "NULL reset reply for tm %p\n", tm); + if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { + /* this completion was due to a reset, just cleanup */ + targ->flags &= ~MPRSAS_TARGET_INRESET; + targ->tm = NULL; + mprsas_free_tm(sc, tm); + } + else { + /* we should have gotten a reply. */ + mpr_reinit(sc); + } + return; + } + + mprsas_log_command(tm, MPR_RECOVERY, + "target reset status 0x%x code 0x%x count %u\n", + le16toh(reply->IOCStatus), le32toh(reply->ResponseCode), + le32toh(reply->TerminationCount)); + + targ->flags &= ~MPRSAS_TARGET_INRESET; + + if (targ->outstanding == 0) { + /* we've finished recovery for this target and all + * of its logical units. + */ + mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, + "recovery finished after target reset\n"); + + mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, + CAM_LUN_WILDCARD); + + targ->tm = NULL; + mprsas_free_tm(sc, tm); + } + else { + /* after a target reset, if this target still has + * outstanding commands, the reset effectively failed, + * regardless of the status reported. escalate. + */ + mprsas_log_command(tm, MPR_RECOVERY, + "target reset complete for tm %p, but still have %u " + "command(s)\n", tm, targ->outstanding); + mpr_reinit(sc); + } +} + +#define MPR_RESET_TIMEOUT 30 + +static int +mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, uint8_t type) +{ + MPI2_SCSI_TASK_MANAGE_REQUEST *req; + struct mprsas_target *target; + int err; + + target = tm->cm_targ; + if (target->handle == 0) { + mpr_dprint(sc, MPR_ERROR,"%s null devhandle for target_id %d\n", + __func__, target->tid); + return -1; + } + + req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; + req->DevHandle = htole16(target->handle); + req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; + req->TaskType = type; + + if (type == MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET) { + /* XXX Need to handle invalid LUNs */ + MPR_SET_LUN(req->LUN, tm->cm_lun); + tm->cm_targ->logical_unit_resets++; + mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, + "sending logical unit reset\n"); + tm->cm_complete = mprsas_logical_unit_reset_complete; + } + else if (type == MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { + /* + * Target reset method = + * SAS Hard Link Reset / SATA Link Reset + */ + req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; + tm->cm_targ->target_resets++; + tm->cm_targ->flags |= MPRSAS_TARGET_INRESET; + mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, + "sending target reset\n"); + tm->cm_complete = mprsas_target_reset_complete; + } + else { + mpr_dprint(sc, MPR_ERROR, "unexpected reset type 0x%x\n", type); + return -1; + } + + mpr_dprint(sc, MPR_XINFO, "to target %u handle 0x%04x\n", target->tid, + target->handle); + if (target->encl_level_valid) { + mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, " + "connector name (%4s)\n", target->encl_level, + target->encl_slot, target->connector_name); + } + + tm->cm_data = NULL; + tm->cm_desc.HighPriority.RequestFlags = + MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; + tm->cm_complete_data = (void *)tm; + + callout_reset(&tm->cm_callout, MPR_RESET_TIMEOUT * hz, + mprsas_tm_timeout, tm); + + err = mpr_map_command(sc, tm); + if (err) + mprsas_log_command(tm, MPR_RECOVERY, + "error %d sending reset type %u\n", + err, type); + + return err; +} + + +static void +mprsas_abort_complete(struct mpr_softc *sc, struct mpr_command *tm) +{ + struct mpr_command *cm; + MPI2_SCSI_TASK_MANAGE_REPLY *reply; + MPI2_SCSI_TASK_MANAGE_REQUEST *req; + struct mprsas_target *targ; + + callout_stop(&tm->cm_callout); + + req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; + reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; + targ = tm->cm_targ; + + /* + * Currently there should be no way we can hit this case. It only + * happens when we have a failure to allocate chain frames, and + * task management commands don't have S/G lists. + */ + if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { + mprsas_log_command(tm, MPR_RECOVERY, + "cm_flags = %#x for abort %p TaskMID %u!\n", + tm->cm_flags, tm, le16toh(req->TaskMID)); + mprsas_free_tm(sc, tm); + return; + } + + if (reply == NULL) { + mprsas_log_command(tm, MPR_RECOVERY, + "NULL abort reply for tm %p TaskMID %u\n", + tm, le16toh(req->TaskMID)); + if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { + /* this completion was due to a reset, just cleanup */ + targ->tm = NULL; + mprsas_free_tm(sc, tm); + } + else { + /* we should have gotten a reply. */ + mpr_reinit(sc); + } + return; + } + + mprsas_log_command(tm, MPR_RECOVERY, + "abort TaskMID %u status 0x%x code 0x%x count %u\n", + le16toh(req->TaskMID), + le16toh(reply->IOCStatus), le32toh(reply->ResponseCode), + le32toh(reply->TerminationCount)); + + cm = TAILQ_FIRST(&tm->cm_targ->timedout_commands); + if (cm == NULL) { + /* if there are no more timedout commands, we're done with + * error recovery for this target. + */ + mprsas_log_command(tm, MPR_RECOVERY, + "finished recovery after aborting TaskMID %u\n", + le16toh(req->TaskMID)); + + targ->tm = NULL; + mprsas_free_tm(sc, tm); + } + else if (le16toh(req->TaskMID) != cm->cm_desc.Default.SMID) { + /* abort success, but we have more timedout commands to abort */ + mprsas_log_command(tm, MPR_RECOVERY, + "continuing recovery after aborting TaskMID %u\n", + le16toh(req->TaskMID)); + + mprsas_send_abort(sc, tm, cm); + } + else { + /* we didn't get a command completion, so the abort + * failed as far as we're concerned. escalate. + */ + mprsas_log_command(tm, MPR_RECOVERY, + "abort failed for TaskMID %u tm %p\n", + le16toh(req->TaskMID), tm); + + mprsas_send_reset(sc, tm, + MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET); + } +} + +#define MPR_ABORT_TIMEOUT 5 + +static int +mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm, + struct mpr_command *cm) +{ + MPI2_SCSI_TASK_MANAGE_REQUEST *req; + struct mprsas_target *targ; + int err; + + targ = cm->cm_targ; + if (targ->handle == 0) { + mpr_dprint(sc, MPR_ERROR,"%s null devhandle for target_id %d\n", + __func__, cm->cm_ccb->ccb_h.target_id); + return -1; + } + + mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, + "Aborting command %p\n", cm); + + req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; + req->DevHandle = htole16(targ->handle); + req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; + req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK; + + /* XXX Need to handle invalid LUNs */ + MPR_SET_LUN(req->LUN, cm->cm_ccb->ccb_h.target_lun); + + req->TaskMID = htole16(cm->cm_desc.Default.SMID); + + tm->cm_data = NULL; + tm->cm_desc.HighPriority.RequestFlags = + MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; + tm->cm_complete = mprsas_abort_complete; + tm->cm_complete_data = (void *)tm; + tm->cm_targ = cm->cm_targ; + tm->cm_lun = cm->cm_lun; + + callout_reset(&tm->cm_callout, MPR_ABORT_TIMEOUT * hz, + mprsas_tm_timeout, tm); + + targ->aborts++; + + err = mpr_map_command(sc, tm); + if (err) + mprsas_log_command(tm, MPR_RECOVERY, + "error %d sending abort for cm %p SMID %u\n", + err, cm, req->TaskMID); + return err; +} + + +static void +mprsas_scsiio_timeout(void *data) +{ + struct mpr_softc *sc; + struct mpr_command *cm; + struct mprsas_target *targ; + + cm = (struct mpr_command *)data; + sc = cm->cm_sc; + + MPR_FUNCTRACE(sc); + mtx_assert(&sc->mpr_mtx, MA_OWNED); + + mpr_dprint(sc, MPR_XINFO, "Timeout checking cm %p\n", cm); + + /* + * Run the interrupt handler to make sure it's not pending. This + * isn't perfect because the command could have already completed + * and been re-used, though this is unlikely. + */ + mpr_intr_locked(sc); + if (cm->cm_state == MPR_CM_STATE_FREE) { + mprsas_log_command(cm, MPR_XINFO, + "SCSI command %p almost timed out\n", cm); + return; + } + + if (cm->cm_ccb == NULL) { + mpr_dprint(sc, MPR_ERROR, "command timeout with NULL ccb\n"); + return; + } + + targ = cm->cm_targ; + targ->timeouts++; + + mprsas_log_command(cm, MPR_XINFO, "command timeout cm %p ccb %p " + "target %u, handle(0x%04x)\n", cm, cm->cm_ccb, targ->tid, + targ->handle); + if (targ->encl_level_valid) { + mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, " + "connector name (%4s)\n", targ->encl_level, targ->encl_slot, + targ->connector_name); + } + + /* XXX first, check the firmware state, to see if it's still + * operational. if not, do a diag reset. + */ + + cm->cm_ccb->ccb_h.status = CAM_CMD_TIMEOUT; + cm->cm_state = MPR_CM_STATE_TIMEDOUT; + TAILQ_INSERT_TAIL(&targ->timedout_commands, cm, cm_recovery); + + if (targ->tm != NULL) { + /* target already in recovery, just queue up another + * timedout command to be processed later. + */ + mpr_dprint(sc, MPR_RECOVERY, "queued timedout cm %p for " + "processing by tm %p\n", cm, targ->tm); + } + else if ((targ->tm = mprsas_alloc_tm(sc)) != NULL) { + mpr_dprint(sc, MPR_RECOVERY, "timedout cm %p allocated tm %p\n", + cm, targ->tm); + + /* start recovery by aborting the first timedout command */ + mprsas_send_abort(sc, targ->tm, cm); + } + else { + /* XXX queue this target up for recovery once a TM becomes + * available. The firmware only has a limited number of + * HighPriority credits for the high priority requests used + * for task management, and we ran out. + * + * Isilon: don't worry about this for now, since we have + * more credits than disks in an enclosure, and limit + * ourselves to one TM per target for recovery. + */ + mpr_dprint(sc, MPR_RECOVERY, + "timedout cm %p failed to allocate a tm\n", cm); + } +} + +static void +mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb) +{ + MPI2_SCSI_IO_REQUEST *req; + struct ccb_scsiio *csio; + struct mpr_softc *sc; + struct mprsas_target *targ; + struct mprsas_lun *lun; + struct mpr_command *cm; + uint8_t i, lba_byte, *ref_tag_addr; + uint16_t eedp_flags; + uint32_t mpi_control; + + sc = sassc->sc; + MPR_FUNCTRACE(sc); + mtx_assert(&sc->mpr_mtx, MA_OWNED); + + csio = &ccb->csio; + targ = &sassc->targets[csio->ccb_h.target_id]; + mpr_dprint(sc, MPR_TRACE, "ccb %p target flag %x\n", ccb, targ->flags); + if (targ->handle == 0x0) { + mpr_dprint(sc, MPR_ERROR, "%s NULL handle for target %u\n", + __func__, csio->ccb_h.target_id); + csio->ccb_h.status = CAM_DEV_NOT_THERE; + xpt_done(ccb); + return; + } + if (targ->flags & MPR_TARGET_FLAGS_RAID_COMPONENT) { + mpr_dprint(sc, MPR_TRACE, "%s Raid component no SCSI IO " + "supported %u\n", __func__, csio->ccb_h.target_id); + csio->ccb_h.status = CAM_DEV_NOT_THERE; + xpt_done(ccb); + return; + } + /* + * Sometimes, it is possible to get a command that is not "In + * Progress" and was actually aborted by the upper layer. Check for + * this here and complete the command without error. + */ + if (ccb->ccb_h.status != CAM_REQ_INPROG) { + mpr_dprint(sc, MPR_TRACE, "%s Command is not in progress for " + "target %u\n", __func__, csio->ccb_h.target_id); + xpt_done(ccb); + return; + } + /* + * If devinfo is 0 this will be a volume. In that case don't tell CAM + * that the volume has timed out. We want volumes to be enumerated + * until they are deleted/removed, not just failed. + */ + if (targ->flags & MPRSAS_TARGET_INREMOVAL) { + if (targ->devinfo == 0) + csio->ccb_h.status = CAM_REQ_CMP; + else + csio->ccb_h.status = CAM_SEL_TIMEOUT; + xpt_done(ccb); + return; + } + + if ((sc->mpr_flags & MPR_FLAGS_SHUTDOWN) != 0) { + mpr_dprint(sc, MPR_TRACE, "%s shutting down\n", __func__); + csio->ccb_h.status = CAM_DEV_NOT_THERE; + xpt_done(ccb); + return; + } + + cm = mpr_alloc_command(sc); + if (cm == NULL || (sc->mpr_flags & MPR_FLAGS_DIAGRESET)) { + if (cm != NULL) { + mpr_free_command(sc, cm); + } + if ((sassc->flags & MPRSAS_QUEUE_FROZEN) == 0) { + xpt_freeze_simq(sassc->sim, 1); + sassc->flags |= MPRSAS_QUEUE_FROZEN; + } + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + ccb->ccb_h.status |= CAM_REQUEUE_REQ; + xpt_done(ccb); + return; + } + + req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req; + bzero(req, sizeof(*req)); + req->DevHandle = htole16(targ->handle); + req->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; + req->MsgFlags = 0; + req->SenseBufferLowAddress = htole32(cm->cm_sense_busaddr); + req->SenseBufferLength = MPR_SENSE_LEN; + req->SGLFlags = 0; + req->ChainOffset = 0; + req->SGLOffset0 = 24; /* 32bit word offset to the SGL */ + req->SGLOffset1= 0; + req->SGLOffset2= 0; + req->SGLOffset3= 0; + req->SkipCount = 0; + req->DataLength = htole32(csio->dxfer_len); + req->BidirectionalDataLength = 0; + req->IoFlags = htole16(csio->cdb_len); + req->EEDPFlags = 0; + + /* Note: BiDirectional transfers are not supported */ + switch (csio->ccb_h.flags & CAM_DIR_MASK) { + case CAM_DIR_IN: + mpi_control = MPI2_SCSIIO_CONTROL_READ; + cm->cm_flags |= MPR_CM_FLAGS_DATAIN; + break; + case CAM_DIR_OUT: + mpi_control = MPI2_SCSIIO_CONTROL_WRITE; + cm->cm_flags |= MPR_CM_FLAGS_DATAOUT; + break; + case CAM_DIR_NONE: + default: + mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER; + break; + } + + if (csio->cdb_len == 32) + mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT; + /* + * It looks like the hardware doesn't require an explicit tag + * number for each transaction. SAM Task Management not supported + * at the moment. + */ + switch (csio->tag_action) { + case MSG_HEAD_OF_Q_TAG: + mpi_control |= MPI2_SCSIIO_CONTROL_HEADOFQ; + break; + case MSG_ORDERED_Q_TAG: + mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ; + break; + case MSG_ACA_TASK: + mpi_control |= MPI2_SCSIIO_CONTROL_ACAQ; + break; + case CAM_TAG_ACTION_NONE: + case MSG_SIMPLE_Q_TAG: + default: + mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; + break; + } + mpi_control |= sc->mapping_table[csio->ccb_h.target_id].TLR_bits; + req->Control = htole32(mpi_control); + + if (MPR_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) { + mpr_free_command(sc, cm); + ccb->ccb_h.status = CAM_LUN_INVALID; + xpt_done(ccb); + return; + } + + if (csio->ccb_h.flags & CAM_CDB_POINTER) + bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len); + else + bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len); + req->IoFlags = htole16(csio->cdb_len); + + /* + * Check if EEDP is supported and enabled. If it is then check if the + * SCSI opcode could be using EEDP. If so, make sure the LUN exists and + * is formatted for EEDP support. If all of this is true, set CDB up + * for EEDP transfer. + */ + eedp_flags = op_code_prot[req->CDB.CDB32[0]]; + if (sc->eedp_enabled && eedp_flags) { + SLIST_FOREACH(lun, &targ->luns, lun_link) { + if (lun->lun_id == csio->ccb_h.target_lun) { + break; + } + } + + if ((lun != NULL) && (lun->eedp_formatted)) { + req->EEDPBlockSize = htole16(lun->eedp_block_size); + eedp_flags |= (MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | + MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | + MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD); + req->EEDPFlags = htole16(eedp_flags); + + /* + * If CDB less than 32, fill in Primary Ref Tag with + * low 4 bytes of LBA. If CDB is 32, tag stuff is + * already there. Also, set protection bit. FreeBSD + * currently does not support CDBs bigger than 16, but + * the code doesn't hurt, and will be here for the + * future. + */ + if (csio->cdb_len != 32) { + lba_byte = (csio->cdb_len == 16) ? 6 : 2; + ref_tag_addr = (uint8_t *)&req->CDB.EEDP32. + PrimaryReferenceTag; + for (i = 0; i < 4; i++) { + *ref_tag_addr = + req->CDB.CDB32[lba_byte + i]; + ref_tag_addr++; + } + req->CDB.EEDP32.PrimaryReferenceTag = + htole32(req-> + CDB.EEDP32.PrimaryReferenceTag); + req->CDB.EEDP32.PrimaryApplicationTagMask = + 0xFFFF; + req->CDB.CDB32[1] = (req->CDB.CDB32[1] & 0x1F) | + 0x20; + } else { + eedp_flags |= + MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG; + req->EEDPFlags = htole16(eedp_flags); + req->CDB.CDB32[10] = (req->CDB.CDB32[10] & + 0x1F) | 0x20; + } + } + } + + cm->cm_length = csio->dxfer_len; + if (cm->cm_length != 0) { + cm->cm_data = ccb; + cm->cm_flags |= MPR_CM_FLAGS_USE_CCB; + } else { + cm->cm_data = NULL; + } + cm->cm_sge = &req->SGL; + cm->cm_sglsize = (32 - 24) * 4; + cm->cm_complete = mprsas_scsiio_complete; + cm->cm_complete_data = ccb; + cm->cm_targ = targ; + cm->cm_lun = csio->ccb_h.target_lun; + cm->cm_ccb = ccb; + /* + * If using FP desc type, need to set a bit in IoFlags (SCSI IO is 0) + * and set descriptor type. + */ + if (targ->scsi_req_desc_type == + MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO) { + req->IoFlags |= MPI25_SCSIIO_IOFLAGS_FAST_PATH; + cm->cm_desc.FastPathSCSIIO.RequestFlags = + MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; + cm->cm_desc.FastPathSCSIIO.DevHandle = htole16(targ->handle); + } else { + cm->cm_desc.SCSIIO.RequestFlags = + MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; + cm->cm_desc.SCSIIO.DevHandle = htole16(targ->handle); + } + + callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000, + mprsas_scsiio_timeout, cm); + + targ->issued++; + targ->outstanding++; + TAILQ_INSERT_TAIL(&targ->commands, cm, cm_link); + ccb->ccb_h.status |= CAM_SIM_QUEUED; + + mprsas_log_command(cm, MPR_XINFO, "%s cm %p ccb %p outstanding %u\n", + __func__, cm, ccb, targ->outstanding); + + mpr_map_command(sc, cm); + return; +} + +static void +mpr_response_code(struct mpr_softc *sc, u8 response_code) +{ + char *desc; + + switch (response_code) { + case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE: + desc = "task management request completed"; + break; + case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME: + desc = "invalid frame"; + break; + case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: + desc = "task management request not supported"; + break; + case MPI2_SCSITASKMGMT_RSP_TM_FAILED: + desc = "task management request failed"; + break; + case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED: + desc = "task management request succeeded"; + break; + case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN: + desc = "invalid lun"; + break; + case 0xA: + desc = "overlapped tag attempted"; + break; + case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: + desc = "task queued, however not sent to target"; + break; + default: + desc = "unknown"; + break; + } + mpr_dprint(sc, MPR_XINFO, "response_code(0x%01x): %s\n", response_code, + desc); +} + +/** + * mpr_sc_failed_io_info - translated non-succesfull SCSI_IO request + */ +static void +mpr_sc_failed_io_info(struct mpr_softc *sc, struct ccb_scsiio *csio, + Mpi2SCSIIOReply_t *mpi_reply, struct mprsas_target *targ) +{ + u32 response_info; + u8 *response_bytes; + u16 ioc_status = le16toh(mpi_reply->IOCStatus) & + MPI2_IOCSTATUS_MASK; + u8 scsi_state = mpi_reply->SCSIState; + u8 scsi_status = mpi_reply->SCSIStatus; + char *desc_ioc_state = NULL; + char *desc_scsi_status = NULL; + char *desc_scsi_state = sc->tmp_string; + u32 log_info = le32toh(mpi_reply->IOCLogInfo); + + if (log_info == 0x31170000) + return; + + switch (ioc_status) { + case MPI2_IOCSTATUS_SUCCESS: + desc_ioc_state = "success"; + break; + case MPI2_IOCSTATUS_INVALID_FUNCTION: + desc_ioc_state = "invalid function"; + break; + case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: + desc_ioc_state = "scsi recovered error"; + break; + case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: + desc_ioc_state = "scsi invalid dev handle"; + break; + case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: + desc_ioc_state = "scsi device not there"; + break; + case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: + desc_ioc_state = "scsi data overrun"; + break; + case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: + desc_ioc_state = "scsi data underrun"; + break; + case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: + desc_ioc_state = "scsi io data error"; + break; + case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: + desc_ioc_state = "scsi protocol error"; + break; + case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: + desc_ioc_state = "scsi task terminated"; + break; + case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: + desc_ioc_state = "scsi residual mismatch"; + break; + case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: + desc_ioc_state = "scsi task mgmt failed"; + break; + case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: + desc_ioc_state = "scsi ioc terminated"; + break; + case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: + desc_ioc_state = "scsi ext terminated"; + break; + case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: + desc_ioc_state = "eedp guard error"; + break; + case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: + desc_ioc_state = "eedp ref tag error"; + break; + case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: + desc_ioc_state = "eedp app tag error"; + break; + default: + desc_ioc_state = "unknown"; + break; + } + + switch (scsi_status) { + case MPI2_SCSI_STATUS_GOOD: + desc_scsi_status = "good"; + break; + case MPI2_SCSI_STATUS_CHECK_CONDITION: + desc_scsi_status = "check condition"; + break; + case MPI2_SCSI_STATUS_CONDITION_MET: + desc_scsi_status = "condition met"; + break; + case MPI2_SCSI_STATUS_BUSY: + desc_scsi_status = "busy"; + break; + case MPI2_SCSI_STATUS_INTERMEDIATE: + desc_scsi_status = "intermediate"; + break; + case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET: + desc_scsi_status = "intermediate condmet"; + break; + case MPI2_SCSI_STATUS_RESERVATION_CONFLICT: + desc_scsi_status = "reservation conflict"; + break; + case MPI2_SCSI_STATUS_COMMAND_TERMINATED: + desc_scsi_status = "command terminated"; + break; + case MPI2_SCSI_STATUS_TASK_SET_FULL: + desc_scsi_status = "task set full"; + break; + case MPI2_SCSI_STATUS_ACA_ACTIVE: + desc_scsi_status = "aca active"; + break; + case MPI2_SCSI_STATUS_TASK_ABORTED: + desc_scsi_status = "task aborted"; + break; + default: + desc_scsi_status = "unknown"; + break; + } + + desc_scsi_state[0] = '\0'; + if (!scsi_state) + desc_scsi_state = " "; + if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) + strcat(desc_scsi_state, "response info "); + if (scsi_state & MPI2_SCSI_STATE_TERMINATED) + strcat(desc_scsi_state, "state terminated "); + if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS) + strcat(desc_scsi_state, "no status "); + if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED) + strcat(desc_scsi_state, "autosense failed "); + if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) + strcat(desc_scsi_state, "autosense valid "); + + mpr_dprint(sc, MPR_XINFO, "\thandle(0x%04x), ioc_status(%s)(0x%04x)\n", + le16toh(mpi_reply->DevHandle), desc_ioc_state, ioc_status); + if (targ->encl_level_valid) { + mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, " + "connector name (%4s)\n", targ->encl_level, targ->encl_slot, + targ->connector_name); + } + /* We can add more detail about underflow data here + * TO-DO + * */ + mpr_dprint(sc, MPR_XINFO, "\tscsi_status(%s)(0x%02x), " + "scsi_state(%s)(0x%02x)\n", desc_scsi_status, scsi_status, + desc_scsi_state, scsi_state); + + if (sc->mpr_debug & MPR_XINFO && + scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { + mpr_dprint(sc, MPR_XINFO, "-> Sense Buffer Data : Start :\n"); + scsi_sense_print(csio); + mpr_dprint(sc, MPR_XINFO, "-> Sense Buffer Data : End :\n"); + } + + if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { + response_info = le32toh(mpi_reply->ResponseInfo); + response_bytes = (u8 *)&response_info; + mpr_response_code(sc,response_bytes[0]); + } +} + +static void +mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) +{ + MPI2_SCSI_IO_REPLY *rep; + union ccb *ccb; + struct ccb_scsiio *csio; + struct mprsas_softc *sassc; + struct scsi_vpd_supported_page_list *vpd_list = NULL; + u8 *TLR_bits, TLR_on; + int dir = 0, i; + u16 alloc_len; + + MPR_FUNCTRACE(sc); + mpr_dprint(sc, MPR_TRACE, + "cm %p SMID %u ccb %p reply %p outstanding %u\n", cm, + cm->cm_desc.Default.SMID, cm->cm_ccb, cm->cm_reply, + cm->cm_targ->outstanding); + + callout_stop(&cm->cm_callout); + mtx_assert(&sc->mpr_mtx, MA_OWNED); + + sassc = sc->sassc; + ccb = cm->cm_complete_data; + csio = &ccb->csio; + rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply; + /* + * XXX KDM if the chain allocation fails, does it matter if we do + * the sync and unload here? It is simpler to do it in every case, + * assuming it doesn't cause problems. + */ + if (cm->cm_data != NULL) { + if (cm->cm_flags & MPR_CM_FLAGS_DATAIN) + dir = BUS_DMASYNC_POSTREAD; + else if (cm->cm_flags & MPR_CM_FLAGS_DATAOUT) + dir = BUS_DMASYNC_POSTWRITE; + bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); + bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); + } + + cm->cm_targ->completed++; + cm->cm_targ->outstanding--; + TAILQ_REMOVE(&cm->cm_targ->commands, cm, cm_link); + ccb->ccb_h.status &= ~(CAM_STATUS_MASK | CAM_SIM_QUEUED); + + if (cm->cm_state == MPR_CM_STATE_TIMEDOUT) { + TAILQ_REMOVE(&cm->cm_targ->timedout_commands, cm, cm_recovery); + if (cm->cm_reply != NULL) + mprsas_log_command(cm, MPR_RECOVERY, + "completed timedout cm %p ccb %p during recovery " + "ioc %x scsi %x state %x xfer %u\n", cm, cm->cm_ccb, + le16toh(rep->IOCStatus), rep->SCSIStatus, + rep->SCSIState, le32toh(rep->TransferCount)); + else + mprsas_log_command(cm, MPR_RECOVERY, + "completed timedout cm %p ccb %p during recovery\n", + cm, cm->cm_ccb); + } else if (cm->cm_targ->tm != NULL) { + if (cm->cm_reply != NULL) + mprsas_log_command(cm, MPR_RECOVERY, + "completed cm %p ccb %p during recovery " + "ioc %x scsi %x state %x xfer %u\n", + cm, cm->cm_ccb, le16toh(rep->IOCStatus), + rep->SCSIStatus, rep->SCSIState, + le32toh(rep->TransferCount)); + else + mprsas_log_command(cm, MPR_RECOVERY, + "completed cm %p ccb %p during recovery\n", + cm, cm->cm_ccb); + } else if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { + mprsas_log_command(cm, MPR_RECOVERY, + "reset completed cm %p ccb %p\n", cm, cm->cm_ccb); + } + + if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { + /* + * We ran into an error after we tried to map the command, + * so we're getting a callback without queueing the command + * to the hardware. So we set the status here, and it will + * be retained below. We'll go through the "fast path", + * because there can be no reply when we haven't actually + * gone out to the hardware. + */ + ccb->ccb_h.status = CAM_REQUEUE_REQ; + + /* + * Currently the only error included in the mask is + * MPR_CM_FLAGS_CHAIN_FAILED, which means we're out of + * chain frames. We need to freeze the queue until we get + * a command that completed without this error, which will + * hopefully have some chain frames attached that we can + * use. If we wanted to get smarter about it, we would + * only unfreeze the queue in this condition when we're + * sure that we're getting some chain frames back. That's + * probably unnecessary. + */ + if ((sassc->flags & MPRSAS_QUEUE_FROZEN) == 0) { + xpt_freeze_simq(sassc->sim, 1); + sassc->flags |= MPRSAS_QUEUE_FROZEN; + mpr_dprint(sc, MPR_INFO, "Error sending command, " + "freezing SIM queue\n"); + } + } + + /* + * If this is a Start Stop Unit command and it was issued by the driver + * during shutdown, decrement the refcount to account for all of the + * commands that were sent. All SSU commands should be completed before + * shutdown completes, meaning SSU_refcount will be 0 after SSU_started + * is TRUE. + */ + if (sc->SSU_started && (csio->cdb_io.cdb_bytes[0] == START_STOP_UNIT)) { + mpr_dprint(sc, MPR_INFO, "Decrementing SSU count.\n"); + sc->SSU_refcount--; + } + + /* Take the fast path to completion */ + if (cm->cm_reply == NULL) { + if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { + if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) + ccb->ccb_h.status = CAM_SCSI_BUS_RESET; + else { + ccb->ccb_h.status = CAM_REQ_CMP; + ccb->csio.scsi_status = SCSI_STATUS_OK; + } + if (sassc->flags & MPRSAS_QUEUE_FROZEN) { + ccb->ccb_h.status |= CAM_RELEASE_SIMQ; + sassc->flags &= ~MPRSAS_QUEUE_FROZEN; + mpr_dprint(sc, MPR_XINFO, + "Unfreezing SIM queue\n"); + } + } + + /* + * There are two scenarios where the status won't be + * CAM_REQ_CMP. The first is if MPR_CM_FLAGS_ERROR_MASK is + * set, the second is in the MPR_FLAGS_DIAGRESET above. + */ + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + /* + * Freeze the dev queue so that commands are + * executed in the correct order with after error + * recovery. + */ + ccb->ccb_h.status |= CAM_DEV_QFRZN; + xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); + } + mpr_free_command(sc, cm); + xpt_done(ccb); + return; + } + + mprsas_log_command(cm, MPR_XINFO, + "ioc %x scsi %x state %x xfer %u\n", + le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState, + le32toh(rep->TransferCount)); + + switch (le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) { + case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: + csio->resid = cm->cm_length - le32toh(rep->TransferCount); + /* FALLTHROUGH */ + case MPI2_IOCSTATUS_SUCCESS: + case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: + + if ((le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) == + MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR) + mprsas_log_command(cm, MPR_XINFO, "recovered error\n"); + + /* Completion failed at the transport level. */ + if (rep->SCSIState & (MPI2_SCSI_STATE_NO_SCSI_STATUS | + MPI2_SCSI_STATE_TERMINATED)) { + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + break; + } + + /* In a modern packetized environment, an autosense failure + * implies that there's not much else that can be done to + * recover the command. + */ + if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED) { + ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; + break; + } + + /* + * CAM doesn't care about SAS Response Info data, but if this is + * the state check if TLR should be done. If not, clear the + * TLR_bits for the target. + */ + if ((rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) && + ((le32toh(rep->ResponseInfo) & MPI2_SCSI_RI_MASK_REASONCODE) + == MPR_SCSI_RI_INVALID_FRAME)) { + sc->mapping_table[csio->ccb_h.target_id].TLR_bits = + (u8)MPI2_SCSIIO_CONTROL_NO_TLR; + } + + /* + * Intentionally override the normal SCSI status reporting + * for these two cases. These are likely to happen in a + * multi-initiator environment, and we want to make sure that + * CAM retries these commands rather than fail them. + */ + if ((rep->SCSIStatus == MPI2_SCSI_STATUS_COMMAND_TERMINATED) || + (rep->SCSIStatus == MPI2_SCSI_STATUS_TASK_ABORTED)) { + ccb->ccb_h.status = CAM_REQ_ABORTED; + break; + } + + /* Handle normal status and sense */ + csio->scsi_status = rep->SCSIStatus; + if (rep->SCSIStatus == MPI2_SCSI_STATUS_GOOD) + ccb->ccb_h.status = CAM_REQ_CMP; + else + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + + if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) { + int sense_len, returned_sense_len; + + returned_sense_len = min(le32toh(rep->SenseCount), + sizeof(struct scsi_sense_data)); + if (returned_sense_len < csio->sense_len) + csio->sense_resid = csio->sense_len - + returned_sense_len; + else + csio->sense_resid = 0; + + sense_len = min(returned_sense_len, + csio->sense_len - csio->sense_resid); + bzero(&csio->sense_data, sizeof(csio->sense_data)); + bcopy(cm->cm_sense, &csio->sense_data, sense_len); + ccb->ccb_h.status |= CAM_AUTOSNS_VALID; + } + + /* + * Check if this is an INQUIRY command. If it's a VPD inquiry, + * and it's page code 0 (Supported Page List), and there is + * inquiry data, and this is for a sequential access device, and + * the device is an SSP target, and TLR is supported by the + * controller, turn the TLR_bits value ON if page 0x90 is + * supported. + */ + if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) && + (csio->cdb_io.cdb_bytes[1] & SI_EVPD) && + (csio->cdb_io.cdb_bytes[2] == SVPD_SUPPORTED_PAGE_LIST) && + ((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) && + (csio->data_ptr != NULL) && + ((csio->data_ptr[0] & 0x1f) == T_SEQUENTIAL) && + (sc->control_TLR) && + (sc->mapping_table[csio->ccb_h.target_id].device_info & + MPI2_SAS_DEVICE_INFO_SSP_TARGET)) { + vpd_list = (struct scsi_vpd_supported_page_list *) + csio->data_ptr; + TLR_bits = &sc->mapping_table[csio->ccb_h.target_id]. + TLR_bits; + *TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR; + TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON; + alloc_len = ((u16)csio->cdb_io.cdb_bytes[3] << 8) + + csio->cdb_io.cdb_bytes[4]; + alloc_len -= csio->resid; + for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) { + if (vpd_list->list[i] == 0x90) { + *TLR_bits = TLR_on; + break; + } + } + } + break; + case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: + case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: + /* + * If devinfo is 0 this will be a volume. In that case don't + * tell CAM that the volume is not there. We want volumes to + * be enumerated until they are deleted/removed, not just + * failed. + */ + if (cm->cm_targ->devinfo == 0) + ccb->ccb_h.status = CAM_REQ_CMP; + else + ccb->ccb_h.status = CAM_DEV_NOT_THERE; + break; + case MPI2_IOCSTATUS_INVALID_SGL: + mpr_print_scsiio_cmd(sc, cm); + ccb->ccb_h.status = CAM_UNREC_HBA_ERROR; + break; + case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: + /* + * This is one of the responses that comes back when an I/O + * has been aborted. If it is because of a timeout that we + * initiated, just set the status to CAM_CMD_TIMEOUT. + * Otherwise set it to CAM_REQ_ABORTED. The effect on the + * command is the same (it gets retried, subject to the + * retry counter), the only difference is what gets printed + * on the console. + */ + if (cm->cm_state == MPR_CM_STATE_TIMEDOUT) + ccb->ccb_h.status = CAM_CMD_TIMEOUT; + else + ccb->ccb_h.status = CAM_REQ_ABORTED; + break; + case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: + /* resid is ignored for this condition */ + csio->resid = 0; + ccb->ccb_h.status = CAM_DATA_RUN_ERR; + break; + case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: + case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: + /* + * Since these are generally external (i.e. hopefully + * transient transport-related) errors, retry these without + * decrementing the retry count. + */ + ccb->ccb_h.status = CAM_REQUEUE_REQ; + mprsas_log_command(cm, MPR_INFO, + "terminated ioc %x scsi %x state %x xfer %u\n", + le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState, + le32toh(rep->TransferCount)); + break; + case MPI2_IOCSTATUS_INVALID_FUNCTION: + case MPI2_IOCSTATUS_INTERNAL_ERROR: + case MPI2_IOCSTATUS_INVALID_VPID: + case MPI2_IOCSTATUS_INVALID_FIELD: + case MPI2_IOCSTATUS_INVALID_STATE: + case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED: + case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: + case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: + case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: + case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: + default: + mprsas_log_command(cm, MPR_XINFO, + "completed ioc %x scsi %x state %x xfer %u\n", + le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState, + le32toh(rep->TransferCount)); + csio->resid = cm->cm_length; + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + break; + } + + mpr_sc_failed_io_info(sc, csio, rep, cm->cm_targ); + + if (sassc->flags & MPRSAS_QUEUE_FROZEN) { + ccb->ccb_h.status |= CAM_RELEASE_SIMQ; + sassc->flags &= ~MPRSAS_QUEUE_FROZEN; + mpr_dprint(sc, MPR_XINFO, "Command completed, unfreezing SIM " + "queue\n"); + } + + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + ccb->ccb_h.status |= CAM_DEV_QFRZN; + xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); + } + + mpr_free_command(sc, cm); + xpt_done(ccb); +} + +#if __FreeBSD_version >= 900026 +static void +mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm) +{ + MPI2_SMP_PASSTHROUGH_REPLY *rpl; + MPI2_SMP_PASSTHROUGH_REQUEST *req; + uint64_t sasaddr; + union ccb *ccb; + + ccb = cm->cm_complete_data; + + /* + * Currently there should be no way we can hit this case. It only + * happens when we have a failure to allocate chain frames, and SMP + * commands require two S/G elements only. That should be handled + * in the standard request size. + */ + if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { + mpr_dprint(sc, MPR_ERROR,"%s: cm_flags = %#x on SMP request!\n", + __func__, cm->cm_flags); + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + goto bailout; + } + + rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply; + if (rpl == NULL) { + mpr_dprint(sc, MPR_ERROR, "%s: NULL cm_reply!\n", __func__); + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + goto bailout; + } + + req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req; + sasaddr = le32toh(req->SASAddress.Low); + sasaddr |= ((uint64_t)(le32toh(req->SASAddress.High))) << 32; + + if ((le16toh(rpl->IOCStatus) & MPI2_IOCSTATUS_MASK) != + MPI2_IOCSTATUS_SUCCESS || + rpl->SASStatus != MPI2_SASSTATUS_SUCCESS) { + mpr_dprint(sc, MPR_XINFO, "%s: IOCStatus %04x SASStatus %02x\n", + __func__, le16toh(rpl->IOCStatus), rpl->SASStatus); + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + goto bailout; + } + + mpr_dprint(sc, MPR_XINFO, "%s: SMP request to SAS address " + "%#jx completed successfully\n", __func__, (uintmax_t)sasaddr); + + if (ccb->smpio.smp_response[2] == SMP_FR_ACCEPTED) + ccb->ccb_h.status = CAM_REQ_CMP; + else + ccb->ccb_h.status = CAM_SMP_STATUS_ERROR; + +bailout: + /* + * We sync in both directions because we had DMAs in the S/G list + * in both directions. + */ + bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); + mpr_free_command(sc, cm); + xpt_done(ccb); +} + +static void +mprsas_send_smpcmd(struct mprsas_softc *sassc, union ccb *ccb, + uint64_t sasaddr) +{ + struct mpr_command *cm; + uint8_t *request, *response; + MPI2_SMP_PASSTHROUGH_REQUEST *req; + struct mpr_softc *sc; + struct sglist *sg; + int error; + + sc = sassc->sc; + sg = NULL; + error = 0; + +#if (__FreeBSD_version >= 1000028) || \ + ((__FreeBSD_version >= 902001) && (__FreeBSD_version < 1000000)) + switch (ccb->ccb_h.flags & CAM_DATA_MASK) { + case CAM_DATA_PADDR: + case CAM_DATA_SG_PADDR: + /* + * XXX We don't yet support physical addresses here. + */ + mpr_dprint(sc, MPR_ERROR, "%s: physical addresses not " + "supported\n", __func__); + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + return; + case CAM_DATA_SG: + /* + * The chip does not support more than one buffer for the + * request or response. + */ + if ((ccb->smpio.smp_request_sglist_cnt > 1) + || (ccb->smpio.smp_response_sglist_cnt > 1)) { + mpr_dprint(sc, MPR_ERROR, + "%s: multiple request or response buffer segments " + "not supported for SMP\n", __func__); + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + return; + } + + /* + * The CAM_SCATTER_VALID flag was originally implemented + * for the XPT_SCSI_IO CCB, which only has one data pointer. + * We have two. So, just take that flag to mean that we + * might have S/G lists, and look at the S/G segment count + * to figure out whether that is the case for each individual + * buffer. + */ + if (ccb->smpio.smp_request_sglist_cnt != 0) { + bus_dma_segment_t *req_sg; + + req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request; + request = (uint8_t *)(uintptr_t)req_sg[0].ds_addr; + } else + request = ccb->smpio.smp_request; + + if (ccb->smpio.smp_response_sglist_cnt != 0) { + bus_dma_segment_t *rsp_sg; + + rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response; + response = (uint8_t *)(uintptr_t)rsp_sg[0].ds_addr; + } else + response = ccb->smpio.smp_response; + break; + case CAM_DATA_VADDR: + request = ccb->smpio.smp_request; + response = ccb->smpio.smp_response; + break; + default: + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + return; + } +#else /* __FreeBSD_version < 1000028 */ + /* + * XXX We don't yet support physical addresses here. + */ + if (ccb->ccb_h.flags & (CAM_DATA_PHYS|CAM_SG_LIST_PHYS)) { + mpr_printf(sc, "%s: physical addresses not supported\n", + __func__); + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + return; + } + + /* + * If the user wants to send an S/G list, check to make sure they + * have single buffers. + */ + if (ccb->ccb_h.flags & CAM_SCATTER_VALID) { + /* + * The chip does not support more than one buffer for the + * request or response. + */ + if ((ccb->smpio.smp_request_sglist_cnt > 1) + || (ccb->smpio.smp_response_sglist_cnt > 1)) { + mpr_dprint(sc, MPR_ERROR, "%s: multiple request or " + "response buffer segments not supported for SMP\n", + __func__); + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + return; + } + + /* + * The CAM_SCATTER_VALID flag was originally implemented + * for the XPT_SCSI_IO CCB, which only has one data pointer. + * We have two. So, just take that flag to mean that we + * might have S/G lists, and look at the S/G segment count + * to figure out whether that is the case for each individual + * buffer. + */ + if (ccb->smpio.smp_request_sglist_cnt != 0) { + bus_dma_segment_t *req_sg; + + req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request; + request = (uint8_t *)(uintptr_t)req_sg[0].ds_addr; + } else + request = ccb->smpio.smp_request; + + if (ccb->smpio.smp_response_sglist_cnt != 0) { + bus_dma_segment_t *rsp_sg; + + rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response; + response = (uint8_t *)(uintptr_t)rsp_sg[0].ds_addr; + } else + response = ccb->smpio.smp_response; + } else { + request = ccb->smpio.smp_request; + response = ccb->smpio.smp_response; + } +#endif /* __FreeBSD_version < 1000028 */ + + cm = mpr_alloc_command(sc); + if (cm == NULL) { + mpr_dprint(sc, MPR_ERROR, + "%s: cannot allocate command\n", __func__); + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + xpt_done(ccb); + return; + } + + req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req; + bzero(req, sizeof(*req)); + req->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; + + /* Allow the chip to use any route to this SAS address. */ + req->PhysicalPort = 0xff; + + req->RequestDataLength = htole16(ccb->smpio.smp_request_len); + req->SGLFlags = + MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE | MPI2_SGLFLAGS_SGL_TYPE_MPI; + + mpr_dprint(sc, MPR_XINFO, "%s: sending SMP request to SAS address " + "%#jx\n", __func__, (uintmax_t)sasaddr); + + mpr_init_sge(cm, req, &req->SGL); + + /* + * Set up a uio to pass into mpr_map_command(). This allows us to + * do one map command, and one busdma call in there. + */ + cm->cm_uio.uio_iov = cm->cm_iovec; + cm->cm_uio.uio_iovcnt = 2; + cm->cm_uio.uio_segflg = UIO_SYSSPACE; + + /* + * The read/write flag isn't used by busdma, but set it just in + * case. This isn't exactly accurate, either, since we're going in + * both directions. + */ + cm->cm_uio.uio_rw = UIO_WRITE; + + cm->cm_iovec[0].iov_base = request; + cm->cm_iovec[0].iov_len = le16toh(req->RequestDataLength); + cm->cm_iovec[1].iov_base = response; + cm->cm_iovec[1].iov_len = ccb->smpio.smp_response_len; + + cm->cm_uio.uio_resid = cm->cm_iovec[0].iov_len + + cm->cm_iovec[1].iov_len; + + /* + * Trigger a warning message in mpr_data_cb() for the user if we + * wind up exceeding two S/G segments. The chip expects one + * segment for the request and another for the response. + */ + cm->cm_max_segs = 2; + + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_complete = mprsas_smpio_complete; + cm->cm_complete_data = ccb; + + /* + * Tell the mapping code that we're using a uio, and that this is + * an SMP passthrough request. There is a little special-case + * logic there (in mpr_data_cb()) to handle the bidirectional + * transfer. + */ + cm->cm_flags |= MPR_CM_FLAGS_USE_UIO | MPR_CM_FLAGS_SMP_PASS | + MPR_CM_FLAGS_DATAIN | MPR_CM_FLAGS_DATAOUT; + + /* The chip data format is little endian. */ + req->SASAddress.High = htole32(sasaddr >> 32); + req->SASAddress.Low = htole32(sasaddr); + + /* + * XXX Note that we don't have a timeout/abort mechanism here. + * From the manual, it looks like task management requests only + * work for SCSI IO and SATA passthrough requests. We may need to + * have a mechanism to retry requests in the event of a chip reset + * at least. Hopefully the chip will insure that any errors short + * of that are relayed back to the driver. + */ + error = mpr_map_command(sc, cm); + if ((error != 0) && (error != EINPROGRESS)) { + mpr_dprint(sc, MPR_ERROR, "%s: error %d returned from " + "mpr_map_command()\n", __func__, error); + goto bailout_error; + } + + return; + +bailout_error: + mpr_free_command(sc, cm); + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + xpt_done(ccb); + return; +} + +static void +mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb) +{ + struct mpr_softc *sc; + struct mprsas_target *targ; + uint64_t sasaddr = 0; + + sc = sassc->sc; + + /* + * Make sure the target exists. + */ + KASSERT(ccb->ccb_h.target_id < sassc->maxtargets, + ("Target %d out of bounds in XPT_SMP_IO\n", ccb->ccb_h.target_id)); + targ = &sassc->targets[ccb->ccb_h.target_id]; + if (targ->handle == 0x0) { + mpr_dprint(sc, MPR_ERROR, "%s: target %d does not exist!\n", + __func__, ccb->ccb_h.target_id); + ccb->ccb_h.status = CAM_SEL_TIMEOUT; + xpt_done(ccb); + return; + } + + /* + * If this device has an embedded SMP target, we'll talk to it + * directly. + * figure out what the expander's address is. + */ + if ((targ->devinfo & MPI2_SAS_DEVICE_INFO_SMP_TARGET) != 0) + sasaddr = targ->sasaddr; + + /* + * If we don't have a SAS address for the expander yet, try + * grabbing it from the page 0x83 information cached in the + * transport layer for this target. LSI expanders report the + * expander SAS address as the port-associated SAS address in + * Inquiry VPD page 0x83. Maxim expanders don't report it in page + * 0x83. + * + * XXX KDM disable this for now, but leave it commented out so that + * it is obvious that this is another possible way to get the SAS + * address. + * + * The parent handle method below is a little more reliable, and + * the other benefit is that it works for devices other than SES + * devices. So you can send a SMP request to a da(4) device and it + * will get routed to the expander that device is attached to. + * (Assuming the da(4) device doesn't contain an SMP target...) + */ +#if 0 + if (sasaddr == 0) + sasaddr = xpt_path_sas_addr(ccb->ccb_h.path); +#endif + + /* + * If we still don't have a SAS address for the expander, look for + * the parent device of this device, which is probably the expander. + */ + if (sasaddr == 0) { +#ifdef OLD_MPR_PROBE + struct mprsas_target *parent_target; +#endif + + if (targ->parent_handle == 0x0) { + mpr_dprint(sc, MPR_ERROR, "%s: handle %d does not have " + "a valid parent handle!\n", __func__, targ->handle); + ccb->ccb_h.status = CAM_DEV_NOT_THERE; + goto bailout; + } +#ifdef OLD_MPR_PROBE + parent_target = mprsas_find_target_by_handle(sassc, 0, + targ->parent_handle); + + if (parent_target == NULL) { + mpr_dprint(sc, MPR_ERROR, "%s: handle %d does not have " + "a valid parent target!\n", __func__, targ->handle); + ccb->ccb_h.status = CAM_DEV_NOT_THERE; + goto bailout; + } + + if ((parent_target->devinfo & + MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) { + mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent %d " + "does not have an SMP target!\n", __func__, + targ->handle, parent_target->handle); + ccb->ccb_h.status = CAM_DEV_NOT_THERE; + goto bailout; + + } + + sasaddr = parent_target->sasaddr; +#else /* OLD_MPR_PROBE */ + if ((targ->parent_devinfo & + MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) { + mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent %d " + "does not have an SMP target!\n", __func__, + targ->handle, targ->parent_handle); + ccb->ccb_h.status = CAM_DEV_NOT_THERE; + goto bailout; + + } + if (targ->parent_sasaddr == 0x0) { + mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent handle " + "%d does not have a valid SAS address!\n", __func__, + targ->handle, targ->parent_handle); + ccb->ccb_h.status = CAM_DEV_NOT_THERE; + goto bailout; + } + + sasaddr = targ->parent_sasaddr; +#endif /* OLD_MPR_PROBE */ + + } + + if (sasaddr == 0) { + mpr_dprint(sc, MPR_INFO, "%s: unable to find SAS address for " + "handle %d\n", __func__, targ->handle); + ccb->ccb_h.status = CAM_DEV_NOT_THERE; + goto bailout; + } + mprsas_send_smpcmd(sassc, ccb, sasaddr); + + return; + +bailout: + xpt_done(ccb); + +} +#endif //__FreeBSD_version >= 900026 + +static void +mprsas_action_resetdev(struct mprsas_softc *sassc, union ccb *ccb) +{ + MPI2_SCSI_TASK_MANAGE_REQUEST *req; + struct mpr_softc *sc; + struct mpr_command *tm; + struct mprsas_target *targ; + + MPR_FUNCTRACE(sassc->sc); + mtx_assert(&sassc->sc->mpr_mtx, MA_OWNED); + + KASSERT(ccb->ccb_h.target_id < sassc->maxtargets, + ("Target %d out of bounds in XPT_RESET_DEV\n", + ccb->ccb_h.target_id)); + sc = sassc->sc; + tm = mpr_alloc_command(sc); + if (tm == NULL) { + mpr_dprint(sc, MPR_ERROR, + "command alloc failure in mprsas_action_resetdev\n"); + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + xpt_done(ccb); + return; + } + + targ = &sassc->targets[ccb->ccb_h.target_id]; + req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; + req->DevHandle = htole16(targ->handle); + req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; + req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; + + /* SAS Hard Link Reset / SATA Link Reset */ + req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; + + tm->cm_data = NULL; + tm->cm_desc.HighPriority.RequestFlags = + MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; + tm->cm_complete = mprsas_resetdev_complete; + tm->cm_complete_data = ccb; + tm->cm_targ = targ; + mpr_map_command(sc, tm); +} + +static void +mprsas_resetdev_complete(struct mpr_softc *sc, struct mpr_command *tm) +{ + MPI2_SCSI_TASK_MANAGE_REPLY *resp; + union ccb *ccb; + + MPR_FUNCTRACE(sc); + mtx_assert(&sc->mpr_mtx, MA_OWNED); + + resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; + ccb = tm->cm_complete_data; + + /* + * Currently there should be no way we can hit this case. It only + * happens when we have a failure to allocate chain frames, and + * task management commands don't have S/G lists. + */ + if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { + MPI2_SCSI_TASK_MANAGE_REQUEST *req; + + req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; + + mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for reset of " + "handle %#04x! This should not happen!\n", __func__, + tm->cm_flags, req->DevHandle); + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + goto bailout; + } + + mpr_dprint(sc, MPR_XINFO, + "%s: IOCStatus = 0x%x ResponseCode = 0x%x\n", __func__, + le16toh(resp->IOCStatus), le32toh(resp->ResponseCode)); + + if (le32toh(resp->ResponseCode) == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) { + ccb->ccb_h.status = CAM_REQ_CMP; + mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, + CAM_LUN_WILDCARD); + } + else + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + +bailout: + + mprsas_free_tm(sc, tm); + xpt_done(ccb); +} + +static void +mprsas_poll(struct cam_sim *sim) +{ + struct mprsas_softc *sassc; + + sassc = cam_sim_softc(sim); + + if (sassc->sc->mpr_debug & MPR_TRACE) { + /* frequent debug messages during a panic just slow + * everything down too much. + */ + mpr_printf(sassc->sc, "%s clearing MPR_TRACE\n", __func__); + sassc->sc->mpr_debug &= ~MPR_TRACE; + } + + mpr_intr_locked(sassc->sc); +} + +static void +mprsas_async(void *callback_arg, uint32_t code, struct cam_path *path, + void *arg) +{ + struct mpr_softc *sc; + + sc = (struct mpr_softc *)callback_arg; + + switch (code) { +#if (__FreeBSD_version >= 1000006) || \ + ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000)) + case AC_ADVINFO_CHANGED: { + struct mprsas_target *target; + struct mprsas_softc *sassc; + struct scsi_read_capacity_data_long rcap_buf; + struct ccb_dev_advinfo cdai; + struct mprsas_lun *lun; + lun_id_t lunid; + int found_lun; + uintptr_t buftype; + + buftype = (uintptr_t)arg; + + found_lun = 0; + sassc = sc->sassc; + + /* + * We're only interested in read capacity data changes. + */ + if (buftype != CDAI_TYPE_RCAPLONG) + break; + + /* + * See the comment in mpr_attach_sas() for a detailed + * explanation. In these versions of FreeBSD we register + * for all events and filter out the events that don't + * apply to us. + */ +#if (__FreeBSD_version < 1000703) || \ + ((__FreeBSD_version >= 1100000) && (__FreeBSD_version < 1100002)) + if (xpt_path_path_id(path) != sassc->sim->path_id) + break; +#endif + + /* + * We should have a handle for this, but check to make sure. + */ + KASSERT(xpt_path_target_id(path) < sassc->maxtargets, + ("Target %d out of bounds in mprsas_async\n", + xpt_path_target_id(path))); + target = &sassc->targets[xpt_path_target_id(path)]; + if (target->handle == 0) + break; + + lunid = xpt_path_lun_id(path); + + SLIST_FOREACH(lun, &target->luns, lun_link) { + if (lun->lun_id == lunid) { + found_lun = 1; + break; + } + } + + if (found_lun == 0) { + lun = malloc(sizeof(struct mprsas_lun), M_MPR, + M_NOWAIT | M_ZERO); + if (lun == NULL) { + mpr_dprint(sc, MPR_ERROR, "Unable to alloc " + "LUN for EEDP support.\n"); + break; + } + lun->lun_id = lunid; + SLIST_INSERT_HEAD(&target->luns, lun, lun_link); + } + + bzero(&rcap_buf, sizeof(rcap_buf)); + xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL); + cdai.ccb_h.func_code = XPT_DEV_ADVINFO; + cdai.ccb_h.flags = CAM_DIR_IN; + cdai.buftype = CDAI_TYPE_RCAPLONG; + cdai.flags = 0; + cdai.bufsiz = sizeof(rcap_buf); + cdai.buf = (uint8_t *)&rcap_buf; + xpt_action((union ccb *)&cdai); + if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) + cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); + + if (((cdai.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) + && (rcap_buf.prot & SRC16_PROT_EN)) { + lun->eedp_formatted = TRUE; + lun->eedp_block_size = scsi_4btoul(rcap_buf.length); + } else { + lun->eedp_formatted = FALSE; + lun->eedp_block_size = 0; + } + break; + } +#endif + case AC_FOUND_DEVICE: { + struct ccb_getdev *cgd; + + /* + * See the comment in mpr_attach_sas() for a detailed + * explanation. In these versions of FreeBSD we register + * for all events and filter out the events that don't + * apply to us. + */ +#if (__FreeBSD_version < 1000703) || \ + ((__FreeBSD_version >= 1100000) && (__FreeBSD_version < 1100002)) + if (xpt_path_path_id(path) != sc->sassc->sim->path_id) + break; +#endif + + cgd = arg; + mprsas_prepare_ssu(sc, path, cgd); + +#if (__FreeBSD_version < 901503) || \ + ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) + mprsas_check_eedp(sc, path, cgd); +#endif + break; + } + default: + break; + } +} + +static void +mprsas_prepare_ssu(struct mpr_softc *sc, struct cam_path *path, + struct ccb_getdev *cgd) +{ + struct mprsas_softc *sassc = sc->sassc; + path_id_t pathid; + target_id_t targetid; + lun_id_t lunid; + struct mprsas_target *target; + struct mprsas_lun *lun; + uint8_t found_lun; + + sassc = sc->sassc; + pathid = cam_sim_path(sassc->sim); + targetid = xpt_path_target_id(path); + lunid = xpt_path_lun_id(path); + + KASSERT(targetid < sassc->maxtargets, + ("Target %d out of bounds in mprsas_prepare_ssu\n", targetid)); + target = &sassc->targets[targetid]; + if (target->handle == 0x0) + return; + + /* + * If LUN is already in list, don't create a new one. + */ + found_lun = FALSE; + SLIST_FOREACH(lun, &target->luns, lun_link) { + if (lun->lun_id == lunid) { + found_lun = TRUE; + break; + } + } + if (!found_lun) { + lun = malloc(sizeof(struct mprsas_lun), M_MPR, + M_NOWAIT | M_ZERO); + if (lun == NULL) { + mpr_dprint(sc, MPR_ERROR, "Unable to alloc LUN for " + "preparing SSU.\n"); + return; + } + lun->lun_id = lunid; + SLIST_INSERT_HEAD(&target->luns, lun, lun_link); + } + + /* + * If this is a SATA direct-access end device, mark it so that a SCSI + * StartStopUnit command will be sent to it when the driver is being + * shutdown. + */ + if (((cgd->inq_data.device & 0x1F) == T_DIRECT) && + (target->devinfo & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) && + ((target->devinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) == + MPI2_SAS_DEVICE_INFO_END_DEVICE)) { + lun->stop_at_shutdown = TRUE; + } +} + +#if (__FreeBSD_version < 901503) || \ + ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) +static void +mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path, + struct ccb_getdev *cgd) +{ + struct mprsas_softc *sassc = sc->sassc; + struct ccb_scsiio *csio; + struct scsi_read_capacity_16 *scsi_cmd; + struct scsi_read_capacity_eedp *rcap_buf; + path_id_t pathid; + target_id_t targetid; + lun_id_t lunid; + union ccb *ccb; + struct cam_path *local_path; + struct mprsas_target *target; + struct mprsas_lun *lun; + uint8_t found_lun; + char path_str[64]; + + sassc = sc->sassc; + pathid = cam_sim_path(sassc->sim); + targetid = xpt_path_target_id(path); + lunid = xpt_path_lun_id(path); + + KASSERT(targetid < sassc->maxtargets, + ("Target %d out of bounds in mprsas_check_eedp\n", targetid)); + target = &sassc->targets[targetid]; + if (target->handle == 0x0) + return; + + /* + * Determine if the device is EEDP capable. + * + * If this flag is set in the inquiry data, the device supports + * protection information, and must support the 16 byte read capacity + * command, otherwise continue without sending read cap 16 + */ + if ((cgd->inq_data.spc3_flags & SPC3_SID_PROTECT) == 0) + return; + + /* + * Issue a READ CAPACITY 16 command. This info is used to determine if + * the LUN is formatted for EEDP support. + */ + ccb = xpt_alloc_ccb_nowait(); + if (ccb == NULL) { + mpr_dprint(sc, MPR_ERROR, "Unable to alloc CCB for EEDP " + "support.\n"); + return; + } + + if (xpt_create_path(&local_path, xpt_periph, pathid, targetid, lunid) + != CAM_REQ_CMP) { + mpr_dprint(sc, MPR_ERROR, "Unable to create path for EEDP " + "support\n"); + xpt_free_ccb(ccb); + return; + } + + /* + * If LUN is already in list, don't create a new one. + */ + found_lun = FALSE; + SLIST_FOREACH(lun, &target->luns, lun_link) { + if (lun->lun_id == lunid) { + found_lun = TRUE; + break; + } + } + if (!found_lun) { + lun = malloc(sizeof(struct mprsas_lun), M_MPR, + M_NOWAIT | M_ZERO); + if (lun == NULL) { + mpr_dprint(sc, MPR_ERROR, "Unable to alloc LUN for " + "EEDP support.\n"); + xpt_free_path(local_path); + xpt_free_ccb(ccb); + return; + } + lun->lun_id = lunid; + SLIST_INSERT_HEAD(&target->luns, lun, lun_link); + } + + xpt_path_string(local_path, path_str, sizeof(path_str)); + mpr_dprint(sc, MPR_INFO, "Sending read cap: path %s handle %d\n", + path_str, target->handle); + + /* + * Issue a READ CAPACITY 16 command for the LUN. The + * mprsas_read_cap_done function will load the read cap info into the + * LUN struct. + */ + rcap_buf = malloc(sizeof(struct scsi_read_capacity_eedp), M_MPR, + M_NOWAIT | M_ZERO); + if (rcap_buf == NULL) { + mpr_dprint(sc, MPR_FAULT, "Unable to alloc read capacity " + "buffer for EEDP support.\n"); + xpt_free_path(ccb->ccb_h.path); + xpt_free_ccb(ccb); + return; + } + xpt_setup_ccb(&ccb->ccb_h, local_path, CAM_PRIORITY_XPT); + csio = &ccb->csio; + csio->ccb_h.func_code = XPT_SCSI_IO; + csio->ccb_h.flags = CAM_DIR_IN; + csio->ccb_h.retry_count = 4; + csio->ccb_h.cbfcnp = mprsas_read_cap_done; + csio->ccb_h.timeout = 60000; + csio->data_ptr = (uint8_t *)rcap_buf; + csio->dxfer_len = sizeof(struct scsi_read_capacity_eedp); + csio->sense_len = MPR_SENSE_LEN; + csio->cdb_len = sizeof(*scsi_cmd); + csio->tag_action = MSG_SIMPLE_Q_TAG; + + scsi_cmd = (struct scsi_read_capacity_16 *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = 0x9E; + scsi_cmd->service_action = SRC16_SERVICE_ACTION; + ((uint8_t *)scsi_cmd)[13] = sizeof(struct scsi_read_capacity_eedp); + + ccb->ccb_h.ppriv_ptr1 = sassc; + xpt_action(ccb); +} + +static void +mprsas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb) +{ + struct mprsas_softc *sassc; + struct mprsas_target *target; + struct mprsas_lun *lun; + struct scsi_read_capacity_eedp *rcap_buf; + + if (done_ccb == NULL) + return; + + /* Driver need to release devq, it Scsi command is + * generated by driver internally. + * Currently there is a single place where driver + * calls scsi command internally. In future if driver + * calls more scsi command internally, it needs to release + * devq internally, since those command will not go back to + * cam_periph. + */ + if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) ) { + done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN; + xpt_release_devq(done_ccb->ccb_h.path, + /*count*/ 1, /*run_queue*/TRUE); + } + + rcap_buf = (struct scsi_read_capacity_eedp *)done_ccb->csio.data_ptr; + + /* + * Get the LUN ID for the path and look it up in the LUN list for the + * target. + */ + sassc = (struct mprsas_softc *)done_ccb->ccb_h.ppriv_ptr1; + KASSERT(done_ccb->ccb_h.target_id < sassc->maxtargets, + ("Target %d out of bounds in mprsas_read_cap_done\n", + done_ccb->ccb_h.target_id)); + target = &sassc->targets[done_ccb->ccb_h.target_id]; + SLIST_FOREACH(lun, &target->luns, lun_link) { + if (lun->lun_id != done_ccb->ccb_h.target_lun) + continue; + + /* + * Got the LUN in the target's LUN list. Fill it in with EEDP + * info. If the READ CAP 16 command had some SCSI error (common + * if command is not supported), mark the lun as not supporting + * EEDP and set the block size to 0. + */ + if (((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) + || (done_ccb->csio.scsi_status != SCSI_STATUS_OK)) { + lun->eedp_formatted = FALSE; + lun->eedp_block_size = 0; + break; + } + + if (rcap_buf->protect & 0x01) { + mpr_dprint(sassc->sc, MPR_INFO, "LUN %d for " + "target ID %d is formatted for EEDP " + "support.\n", done_ccb->ccb_h.target_lun, + done_ccb->ccb_h.target_id); + lun->eedp_formatted = TRUE; + lun->eedp_block_size = scsi_4btoul(rcap_buf->length); + } + break; + } + + // Finished with this CCB and path. + free(rcap_buf, M_MPR); + xpt_free_path(done_ccb->ccb_h.path); + xpt_free_ccb(done_ccb); +} +#endif /* (__FreeBSD_version < 901503) || \ + ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) */ + +int +mprsas_startup(struct mpr_softc *sc) +{ + /* + * Send the port enable message and set the wait_for_port_enable flag. + * This flag helps to keep the simq frozen until all discovery events + * are processed. + */ + sc->wait_for_port_enable = 1; + mprsas_send_portenable(sc); + return (0); +} + +static int +mprsas_send_portenable(struct mpr_softc *sc) +{ + MPI2_PORT_ENABLE_REQUEST *request; + struct mpr_command *cm; + + MPR_FUNCTRACE(sc); + + if ((cm = mpr_alloc_command(sc)) == NULL) + return (EBUSY); + request = (MPI2_PORT_ENABLE_REQUEST *)cm->cm_req; + request->Function = MPI2_FUNCTION_PORT_ENABLE; + request->MsgFlags = 0; + request->VP_ID = 0; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_complete = mprsas_portenable_complete; + cm->cm_data = NULL; + cm->cm_sge = NULL; + + mpr_map_command(sc, cm); + mpr_dprint(sc, MPR_XINFO, + "mpr_send_portenable finished cm %p req %p complete %p\n", + cm, cm->cm_req, cm->cm_complete); + return (0); +} + +static void +mprsas_portenable_complete(struct mpr_softc *sc, struct mpr_command *cm) +{ + MPI2_PORT_ENABLE_REPLY *reply; + struct mprsas_softc *sassc; + + MPR_FUNCTRACE(sc); + sassc = sc->sassc; + + /* + * Currently there should be no way we can hit this case. It only + * happens when we have a failure to allocate chain frames, and + * port enable commands don't have S/G lists. + */ + if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { + mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for port enable! " + "This should not happen!\n", __func__, cm->cm_flags); + } + + reply = (MPI2_PORT_ENABLE_REPLY *)cm->cm_reply; + if (reply == NULL) + mpr_dprint(sc, MPR_FAULT, "Portenable NULL reply\n"); + else if (le16toh(reply->IOCStatus & MPI2_IOCSTATUS_MASK) != + MPI2_IOCSTATUS_SUCCESS) + mpr_dprint(sc, MPR_FAULT, "Portenable failed\n"); + + mpr_free_command(sc, cm); + if (sc->mpr_ich.ich_arg != NULL) { + mpr_dprint(sc, MPR_XINFO, "disestablish config intrhook\n"); + config_intrhook_disestablish(&sc->mpr_ich); + sc->mpr_ich.ich_arg = NULL; + } + + /* + * Done waiting for port enable to complete. Decrement the refcount. + * If refcount is 0, discovery is complete and a rescan of the bus can + * take place. + */ + sc->wait_for_port_enable = 0; + sc->port_enable_complete = 1; + wakeup(&sc->port_enable_complete); + mprsas_startup_decrement(sassc); +} + +int +mprsas_check_id(struct mprsas_softc *sassc, int id) +{ + struct mpr_softc *sc = sassc->sc; + char *ids; + char *name; + + ids = &sc->exclude_ids[0]; + while((name = strsep(&ids, ",")) != NULL) { + if (name[0] == '\0') + continue; + if (strtol(name, NULL, 0) == (long)id) + return (1); + } + + return (0); +} diff --git a/sys/dev/mpr/mpr_sas.h b/sys/dev/mpr/mpr_sas.h new file mode 100644 index 0000000000000..9d3116af29d0c --- /dev/null +++ b/sys/dev/mpr/mpr_sas.h @@ -0,0 +1,168 @@ +/*- + * Copyright (c) 2011-2014 LSI Corp. + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + +struct mpr_fw_event_work; + +struct mprsas_lun { + SLIST_ENTRY(mprsas_lun) lun_link; + lun_id_t lun_id; + uint8_t eedp_formatted; + uint32_t eedp_block_size; + uint8_t stop_at_shutdown; +}; + +struct mprsas_target { + uint16_t handle; + uint8_t linkrate; + uint8_t encl_level_valid; + uint8_t encl_level; + char connector_name[4]; + uint64_t devname; + uint32_t devinfo; + uint16_t encl_handle; + uint16_t encl_slot; + uint8_t flags; +#define MPRSAS_TARGET_INABORT (1 << 0) +#define MPRSAS_TARGET_INRESET (1 << 1) +#define MPRSAS_TARGET_INDIAGRESET (1 << 2) +#define MPRSAS_TARGET_INREMOVAL (1 << 3) +#define MPR_TARGET_FLAGS_RAID_COMPONENT (1 << 4) +#define MPR_TARGET_FLAGS_VOLUME (1 << 5) +#define MPRSAS_TARGET_INRECOVERY (MPRSAS_TARGET_INABORT | \ + MPRSAS_TARGET_INRESET | MPRSAS_TARGET_INCHIPRESET) + +#define MPRSAS_TARGET_ADD (1 << 29) +#define MPRSAS_TARGET_REMOVE (1 << 30) + uint16_t tid; + SLIST_HEAD(, mprsas_lun) luns; + TAILQ_HEAD(, mpr_command) commands; + struct mpr_command *tm; + TAILQ_HEAD(, mpr_command) timedout_commands; + uint16_t exp_dev_handle; + uint16_t phy_num; + uint64_t sasaddr; + uint16_t parent_handle; + uint64_t parent_sasaddr; + uint32_t parent_devinfo; + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_tree; + TAILQ_ENTRY(mprsas_target) sysctl_link; + uint64_t issued; + uint64_t completed; + unsigned int outstanding; + unsigned int timeouts; + unsigned int aborts; + unsigned int logical_unit_resets; + unsigned int target_resets; + uint8_t scsi_req_desc_type; +}; + +struct mprsas_softc { + struct mpr_softc *sc; + u_int flags; +#define MPRSAS_IN_DISCOVERY (1 << 0) +#define MPRSAS_IN_STARTUP (1 << 1) +#define MPRSAS_DISCOVERY_TIMEOUT_PENDING (1 << 2) +#define MPRSAS_QUEUE_FROZEN (1 << 3) +#define MPRSAS_SHUTDOWN (1 << 4) +#define MPRSAS_SCANTHREAD (1 << 5) + u_int maxtargets; + struct mprsas_target *targets; + struct cam_devq *devq; + struct cam_sim *sim; + struct cam_path *path; + struct intr_config_hook sas_ich; + struct callout discovery_callout; + struct mpr_event_handle *mprsas_eh; + + u_int startup_refcount; + u_int tm_count; + struct proc *sysctl_proc; + + struct taskqueue *ev_tq; + struct task ev_task; + TAILQ_HEAD(, mpr_fw_event_work) ev_queue; +}; + +MALLOC_DECLARE(M_MPRSAS); + +/* + * Abstracted so that the driver can be backwards and forwards compatible + * with future versions of CAM that will provide this functionality. + */ +#define MPR_SET_LUN(lun, ccblun) \ + mprsas_set_lun(lun, ccblun) + +static __inline int +mprsas_set_lun(uint8_t *lun, u_int ccblun) +{ + uint64_t *newlun; + + newlun = (uint64_t *)lun; + *newlun = 0; + if (ccblun <= 0xff) { + /* Peripheral device address method, LUN is 0 to 255 */ + lun[1] = ccblun; + } else if (ccblun <= 0x3fff) { + /* Flat space address method, LUN is <= 16383 */ + scsi_ulto2b(ccblun, lun); + lun[0] |= 0x40; + } else if (ccblun <= 0xffffff) { + /* Extended flat space address method, LUN is <= 16777215 */ + scsi_ulto3b(ccblun, &lun[1]); + /* Extended Flat space address method */ + lun[0] = 0xc0; + /* Length = 1, i.e. LUN is 3 bytes long */ + lun[0] |= 0x10; + /* Extended Address Method */ + lun[0] |= 0x02; + } else { + return (EINVAL); + } + + return (0); +} + +#define MPR_SET_SINGLE_LUN(req, lun) \ +do { \ + bzero((req)->LUN, 8); \ + (req)->LUN[1] = lun; \ +} while(0) + +void mprsas_rescan_target(struct mpr_softc *sc, struct mprsas_target *targ); +void mprsas_discovery_end(struct mprsas_softc *sassc); +void mprsas_startup_increment(struct mprsas_softc *sassc); +void mprsas_startup_decrement(struct mprsas_softc *sassc); +void mprsas_release_simq_reinit(struct mprsas_softc *sassc); + +struct mpr_command * mprsas_alloc_tm(struct mpr_softc *sc); +void mprsas_free_tm(struct mpr_softc *sc, struct mpr_command *tm); +void mprsas_firmware_event_work(void *arg, int pending); +int mprsas_check_id(struct mprsas_softc *sassc, int id); diff --git a/sys/dev/mpr/mpr_sas_lsi.c b/sys/dev/mpr/mpr_sas_lsi.c new file mode 100644 index 0000000000000..32e9b3a078047 --- /dev/null +++ b/sys/dev/mpr/mpr_sas_lsi.c @@ -0,0 +1,1218 @@ +/*- + * Copyright (c) 2011-2014 LSI Corp. + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* Communications core for LSI MPT2 */ + +/* TODO Move headers to mprvar */ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/selinfo.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/bio.h> +#include <sys/malloc.h> +#include <sys/uio.h> +#include <sys/sysctl.h> +#include <sys/endian.h> +#include <sys/queue.h> +#include <sys/kthread.h> +#include <sys/taskqueue.h> +#include <sys/sbuf.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <machine/stdarg.h> + +#include <cam/cam.h> +#include <cam/cam_ccb.h> +#include <cam/cam_debug.h> +#include <cam/cam_sim.h> +#include <cam/cam_xpt_sim.h> +#include <cam/cam_xpt_periph.h> +#include <cam/cam_periph.h> +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_message.h> + +#include <dev/mpr/mpi/mpi2_type.h> +#include <dev/mpr/mpi/mpi2.h> +#include <dev/mpr/mpi/mpi2_ioc.h> +#include <dev/mpr/mpi/mpi2_sas.h> +#include <dev/mpr/mpi/mpi2_cnfg.h> +#include <dev/mpr/mpi/mpi2_init.h> +#include <dev/mpr/mpi/mpi2_raid.h> +#include <dev/mpr/mpi/mpi2_tool.h> +#include <dev/mpr/mpr_ioctl.h> +#include <dev/mpr/mprvar.h> +#include <dev/mpr/mpr_table.h> +#include <dev/mpr/mpr_sas.h> + +/* For Hashed SAS Address creation for SATA Drives */ +#define MPT2SAS_SN_LEN 20 +#define MPT2SAS_MN_LEN 40 + +struct mpr_fw_event_work { + u16 event; + void *event_data; + TAILQ_ENTRY(mpr_fw_event_work) ev_link; +}; + +union _sata_sas_address { + u8 wwid[8]; + struct { + u32 high; + u32 low; + } word; +}; + +/* + * define the IDENTIFY DEVICE structure + */ +struct _ata_identify_device_data { + u16 reserved1[10]; /* 0-9 */ + u16 serial_number[10]; /* 10-19 */ + u16 reserved2[7]; /* 20-26 */ + u16 model_number[20]; /* 27-46*/ + u16 reserved3[209]; /* 47-255*/ +}; +static u32 event_count; +static void mprsas_fw_work(struct mpr_softc *sc, + struct mpr_fw_event_work *fw_event); +static void mprsas_fw_event_free(struct mpr_softc *, + struct mpr_fw_event_work *); +static int mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate); +static int mprsas_get_sata_identify(struct mpr_softc *sc, u16 handle, + Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, + u32 devinfo); +int mprsas_get_sas_address_for_sata_disk(struct mpr_softc *sc, + u64 *sas_address, u16 handle, u32 device_info); +static int mprsas_volume_add(struct mpr_softc *sc, + u16 handle); +static void mprsas_SSU_to_SATA_devices(struct mpr_softc *sc); +static void mprsas_stop_unit_done(struct cam_periph *periph, + union ccb *done_ccb); + +void +mprsas_evt_handler(struct mpr_softc *sc, uintptr_t data, + MPI2_EVENT_NOTIFICATION_REPLY *event) +{ + struct mpr_fw_event_work *fw_event; + u16 sz; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + mpr_print_evt_sas(sc, event); + mprsas_record_event(sc, event); + + fw_event = malloc(sizeof(struct mpr_fw_event_work), M_MPR, + M_ZERO|M_NOWAIT); + if (!fw_event) { + printf("%s: allocate failed for fw_event\n", __func__); + return; + } + sz = le16toh(event->EventDataLength) * 4; + fw_event->event_data = malloc(sz, M_MPR, M_ZERO|M_NOWAIT); + if (!fw_event->event_data) { + printf("%s: allocate failed for event_data\n", __func__); + free(fw_event, M_MPR); + return; + } + + bcopy(event->EventData, fw_event->event_data, sz); + fw_event->event = event->Event; + if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST || + event->Event == MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE || + event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) && + sc->track_mapping_events) + sc->pending_map_events++; + + /* + * When wait_for_port_enable flag is set, make sure that all the events + * are processed. Increment the startup_refcount and decrement it after + * events are processed. + */ + if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST || + event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) && + sc->wait_for_port_enable) + mprsas_startup_increment(sc->sassc); + + TAILQ_INSERT_TAIL(&sc->sassc->ev_queue, fw_event, ev_link); + taskqueue_enqueue(sc->sassc->ev_tq, &sc->sassc->ev_task); + +} + +static void +mprsas_fw_event_free(struct mpr_softc *sc, struct mpr_fw_event_work *fw_event) +{ + + free(fw_event->event_data, M_MPR); + free(fw_event, M_MPR); +} + +/** + * _mpr_fw_work - delayed task for processing firmware events + * @sc: per adapter object + * @fw_event: The fw_event_work object + * Context: user. + * + * Return nothing. + */ +static void +mprsas_fw_work(struct mpr_softc *sc, struct mpr_fw_event_work *fw_event) +{ + struct mprsas_softc *sassc; + sassc = sc->sassc; + + mpr_dprint(sc, MPR_EVENT, "(%d)->(%s) Working on Event: [%x]\n", + event_count++, __func__, fw_event->event); + switch (fw_event->event) { + case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: + { + MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data; + MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy; + int i; + + data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *) + fw_event->event_data; + + mpr_mapping_topology_change_event(sc, fw_event->event_data); + + for (i = 0; i < data->NumEntries; i++) { + phy = &data->PHY[i]; + switch (phy->PhyStatus & MPI2_EVENT_SAS_TOPO_RC_MASK) { + case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: + if (mprsas_add_device(sc, + le16toh(phy->AttachedDevHandle), + phy->LinkRate)) { + printf("%s: failed to add device with " + "handle 0x%x\n", __func__, + le16toh(phy->AttachedDevHandle)); + mprsas_prepare_remove(sassc, le16toh( + phy->AttachedDevHandle)); + } + break; + case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: + mprsas_prepare_remove(sassc, le16toh( + phy->AttachedDevHandle)); + break; + case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: + case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE: + case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING: + default: + break; + } + } + /* + * refcount was incremented for this event in + * mprsas_evt_handler. Decrement it here because the event has + * been processed. + */ + mprsas_startup_decrement(sassc); + break; + } + case MPI2_EVENT_SAS_DISCOVERY: + { + MPI2_EVENT_DATA_SAS_DISCOVERY *data; + + data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)fw_event->event_data; + + if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_STARTED) + mpr_dprint(sc, MPR_TRACE,"SAS discovery start " + "event\n"); + if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_COMPLETED) { + mpr_dprint(sc, MPR_TRACE,"SAS discovery stop event\n"); + sassc->flags &= ~MPRSAS_IN_DISCOVERY; + mprsas_discovery_end(sassc); + } + break; + } + case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: + { + Mpi2EventDataSasEnclDevStatusChange_t *data; + data = (Mpi2EventDataSasEnclDevStatusChange_t *) + fw_event->event_data; + mpr_mapping_enclosure_dev_status_change_event(sc, + fw_event->event_data); + break; + } + case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: + { + Mpi2EventIrConfigElement_t *element; + int i; + u8 foreign_config, reason; + u16 elementType; + Mpi2EventDataIrConfigChangeList_t *event_data; + struct mprsas_target *targ; + unsigned int id; + + event_data = fw_event->event_data; + foreign_config = (le32toh(event_data->Flags) & + MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0; + + element = + (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; + id = mpr_mapping_get_raid_id_from_handle(sc, + element->VolDevHandle); + + mpr_mapping_ir_config_change_event(sc, event_data); + for (i = 0; i < event_data->NumElements; i++, element++) { + reason = element->ReasonCode; + elementType = le16toh(element->ElementFlags) & + MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK; + /* + * check for element type of Phys Disk or Hot Spare + */ + if ((elementType != + MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT) + && (elementType != + MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT)) + // do next element + goto skip_fp_send; + + /* + * check for reason of Hide, Unhide, PD Created, or PD + * Deleted + */ + if ((reason != MPI2_EVENT_IR_CHANGE_RC_HIDE) && + (reason != MPI2_EVENT_IR_CHANGE_RC_UNHIDE) && + (reason != MPI2_EVENT_IR_CHANGE_RC_PD_CREATED) && + (reason != MPI2_EVENT_IR_CHANGE_RC_PD_DELETED)) + goto skip_fp_send; + + // check for a reason of Hide or PD Created + if ((reason == MPI2_EVENT_IR_CHANGE_RC_HIDE) || + (reason == MPI2_EVENT_IR_CHANGE_RC_PD_CREATED)) + { + // build RAID Action message + Mpi2RaidActionRequest_t *action; + Mpi2RaidActionReply_t *reply; + struct mpr_command *cm; + int error = 0; + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed\n", + __func__); + return; + } + + mpr_dprint(sc, MPR_INFO, "Sending FP action " + "from " + "MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST " + ":\n"); + action = (MPI2_RAID_ACTION_REQUEST *)cm->cm_req; + action->Function = MPI2_FUNCTION_RAID_ACTION; + action->Action = + MPI2_RAID_ACTION_PHYSDISK_HIDDEN; + action->PhysDiskNum = element->PhysDiskNum; + cm->cm_desc.Default.RequestFlags = + MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + error = mpr_request_polled(sc, cm); + reply = (Mpi2RaidActionReply_t *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* + * If the poll returns error then we + * need to do diag reset + */ + printf("%s: poll for page completed " + "with error %d", __func__, error); + } + if (reply && (le16toh(reply->IOCStatus) & + MPI2_IOCSTATUS_MASK) != + MPI2_IOCSTATUS_SUCCESS) { + mpr_dprint(sc, MPR_INFO, "%s: error " + "sending RaidActionPage; iocstatus " + "= 0x%x\n", __func__, + le16toh(reply->IOCStatus)); + } + + if (cm) + mpr_free_command(sc, cm); + } +skip_fp_send: + mpr_dprint(sc, MPR_INFO, "Received " + "MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST Reason " + "code %x:\n", element->ReasonCode); + switch (element->ReasonCode) { + case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED: + case MPI2_EVENT_IR_CHANGE_RC_ADDED: + if (!foreign_config) { + if (mprsas_volume_add(sc, + le16toh(element->VolDevHandle))) { + printf("%s: failed to add RAID " + "volume with handle 0x%x\n", + __func__, le16toh(element-> + VolDevHandle)); + } + } + break; + case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: + case MPI2_EVENT_IR_CHANGE_RC_REMOVED: + /* + * Rescan after volume is deleted or removed. + */ + if (!foreign_config) { + if (id == MPR_MAP_BAD_ID) { + printf("%s: could not get ID " + "for volume with handle " + "0x%04x\n", __func__, + le16toh(element-> + VolDevHandle)); + break; + } + + targ = &sassc->targets[id]; + targ->handle = 0x0; + targ->encl_slot = 0x0; + targ->encl_handle = 0x0; + targ->encl_level_valid = 0x0; + targ->encl_level = 0x0; + targ->connector_name[0] = ' '; + targ->connector_name[1] = ' '; + targ->connector_name[2] = ' '; + targ->connector_name[3] = ' '; + targ->exp_dev_handle = 0x0; + targ->phy_num = 0x0; + targ->linkrate = 0x0; + mprsas_rescan_target(sc, targ); + printf("RAID target id 0x%x removed\n", + targ->tid); + } + break; + case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: + case MPI2_EVENT_IR_CHANGE_RC_HIDE: + /* + * Phys Disk of a volume has been created. Hide + * it from the OS. + */ + targ = mprsas_find_target_by_handle(sassc, 0, + element->PhysDiskDevHandle); + if (targ == NULL) + break; + targ->flags |= MPR_TARGET_FLAGS_RAID_COMPONENT; + mprsas_rescan_target(sc, targ); + + break; + case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: + /* + * Phys Disk of a volume has been deleted. + * Expose it to the OS. + */ + if (mprsas_add_device(sc, + le16toh(element->PhysDiskDevHandle), 0)) { + printf("%s: failed to add device with " + "handle 0x%x\n", __func__, + le16toh(element-> + PhysDiskDevHandle)); + mprsas_prepare_remove(sassc, + le16toh(element-> + PhysDiskDevHandle)); + } + break; + } + } + /* + * refcount was incremented for this event in + * mprsas_evt_handler. Decrement it here because the event has + * been processed. + */ + mprsas_startup_decrement(sassc); + break; + } + case MPI2_EVENT_IR_VOLUME: + { + Mpi2EventDataIrVolume_t *event_data = fw_event->event_data; + + /* + * Informational only. + */ + mpr_dprint(sc, MPR_EVENT, "Received IR Volume event:\n"); + switch (event_data->ReasonCode) { + case MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED: + mpr_dprint(sc, MPR_EVENT, " Volume Settings " + "changed from 0x%x to 0x%x for Volome with " + "handle 0x%x", le32toh(event_data->PreviousValue), + le32toh(event_data->NewValue), + le16toh(event_data->VolDevHandle)); + break; + case MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED: + mpr_dprint(sc, MPR_EVENT, " Volume Status " + "changed from 0x%x to 0x%x for Volome with " + "handle 0x%x", le32toh(event_data->PreviousValue), + le32toh(event_data->NewValue), + le16toh(event_data->VolDevHandle)); + break; + case MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED: + mpr_dprint(sc, MPR_EVENT, " Volume State " + "changed from 0x%x to 0x%x for Volome with " + "handle 0x%x", le32toh(event_data->PreviousValue), + le32toh(event_data->NewValue), + le16toh(event_data->VolDevHandle)); + u32 state; + struct mprsas_target *targ; + state = le32toh(event_data->NewValue); + switch (state) { + case MPI2_RAID_VOL_STATE_MISSING: + case MPI2_RAID_VOL_STATE_FAILED: + mprsas_prepare_volume_remove(sassc, + event_data->VolDevHandle); + break; + + case MPI2_RAID_VOL_STATE_ONLINE: + case MPI2_RAID_VOL_STATE_DEGRADED: + case MPI2_RAID_VOL_STATE_OPTIMAL: + targ = + mprsas_find_target_by_handle(sassc, + 0, event_data->VolDevHandle); + if (targ) { + printf("%s %d: Volume handle " + "0x%x is already added \n", + __func__, __LINE__, + event_data->VolDevHandle); + break; + } + if (mprsas_volume_add(sc, + le16toh(event_data-> + VolDevHandle))) { + printf("%s: failed to add RAID " + "volume with handle 0x%x\n", + __func__, le16toh( + event_data->VolDevHandle)); + } + break; + default: + break; + } + break; + default: + break; + } + break; + } + case MPI2_EVENT_IR_PHYSICAL_DISK: + { + Mpi2EventDataIrPhysicalDisk_t *event_data = + fw_event->event_data; + struct mprsas_target *targ; + + /* + * Informational only. + */ + mpr_dprint(sc, MPR_EVENT, "Received IR Phys Disk event:\n"); + switch (event_data->ReasonCode) { + case MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED: + mpr_dprint(sc, MPR_EVENT, " Phys Disk Settings " + "changed from 0x%x to 0x%x for Phys Disk Number " + "%d and handle 0x%x at Enclosure handle 0x%x, Slot " + "%d", le32toh(event_data->PreviousValue), + le32toh(event_data->NewValue), + event_data->PhysDiskNum, + le16toh(event_data->PhysDiskDevHandle), + le16toh(event_data->EnclosureHandle), + le16toh(event_data->Slot)); + break; + case MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED: + mpr_dprint(sc, MPR_EVENT, " Phys Disk Status changed " + "from 0x%x to 0x%x for Phys Disk Number %d and " + "handle 0x%x at Enclosure handle 0x%x, Slot %d", + le32toh(event_data->PreviousValue), + le32toh(event_data->NewValue), + event_data->PhysDiskNum, + le16toh(event_data->PhysDiskDevHandle), + le16toh(event_data->EnclosureHandle), + le16toh(event_data->Slot)); + break; + case MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED: + mpr_dprint(sc, MPR_EVENT, " Phys Disk State changed " + "from 0x%x to 0x%x for Phys Disk Number %d and " + "handle 0x%x at Enclosure handle 0x%x, Slot %d", + le32toh(event_data->PreviousValue), + le32toh(event_data->NewValue), + event_data->PhysDiskNum, + le16toh(event_data->PhysDiskDevHandle), + le16toh(event_data->EnclosureHandle), + le16toh(event_data->Slot)); + switch (event_data->NewValue) { + case MPI2_RAID_PD_STATE_ONLINE: + case MPI2_RAID_PD_STATE_DEGRADED: + case MPI2_RAID_PD_STATE_REBUILDING: + case MPI2_RAID_PD_STATE_OPTIMAL: + case MPI2_RAID_PD_STATE_HOT_SPARE: + targ = mprsas_find_target_by_handle( + sassc, 0, + event_data->PhysDiskDevHandle); + if (targ) { + targ->flags |= + MPR_TARGET_FLAGS_RAID_COMPONENT; + printf("%s %d: Found Target " + "for handle 0x%x.\n", + __func__, __LINE__ , + event_data-> + PhysDiskDevHandle); + } + break; + case MPI2_RAID_PD_STATE_OFFLINE: + case MPI2_RAID_PD_STATE_NOT_CONFIGURED: + case MPI2_RAID_PD_STATE_NOT_COMPATIBLE: + default: + targ = mprsas_find_target_by_handle( + sassc, 0, + event_data->PhysDiskDevHandle); + if (targ) { + targ->flags |= + ~MPR_TARGET_FLAGS_RAID_COMPONENT; + printf("%s %d: Found Target " + "for handle 0x%x. \n", + __func__, __LINE__ , + event_data-> + PhysDiskDevHandle); + } + break; + } + default: + break; + } + break; + } + case MPI2_EVENT_IR_OPERATION_STATUS: + { + Mpi2EventDataIrOperationStatus_t *event_data = + fw_event->event_data; + + /* + * Informational only. + */ + mpr_dprint(sc, MPR_EVENT, "Received IR Op Status event:\n"); + mpr_dprint(sc, MPR_EVENT, " RAID Operation of %d is %d " + "percent complete for Volume with handle 0x%x", + event_data->RAIDOperation, event_data->PercentComplete, + le16toh(event_data->VolDevHandle)); + break; + } + case MPI2_EVENT_TEMP_THRESHOLD: + { + pMpi2EventDataTemperature_t temp_event; + + temp_event = (pMpi2EventDataTemperature_t)fw_event->event_data; + + /* + * The Temp Sensor Count must be greater than the event's Sensor + * Num to be valid. If valid, print the temp thresholds that + * have been exceeded. + */ + if (sc->iounit_pg8.NumSensors > temp_event->SensorNum) { + mpr_dprint(sc, MPR_FAULT, "Temperature Threshold flags " + "%s %s %s %s exceeded for Sensor: %d !!!\n", + ((temp_event->Status & 0x01) == 1) ? "0 " : " ", + ((temp_event->Status & 0x02) == 2) ? "1 " : " ", + ((temp_event->Status & 0x04) == 4) ? "2 " : " ", + ((temp_event->Status & 0x08) == 8) ? "3 " : " ", + temp_event->SensorNum); + mpr_dprint(sc, MPR_FAULT, "Current Temp in Celsius: " + "%d\n", temp_event->CurrentTemperature); + } + break; + } + case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: + case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: + default: + mpr_dprint(sc, MPR_TRACE,"Unhandled event 0x%0X\n", + fw_event->event); + break; + + } + mpr_dprint(sc, MPR_EVENT, "(%d)->(%s) Event Free: [%x]\n", event_count, + __func__, fw_event->event); + mprsas_fw_event_free(sc, fw_event); +} + +void +mprsas_firmware_event_work(void *arg, int pending) +{ + struct mpr_fw_event_work *fw_event; + struct mpr_softc *sc; + + sc = (struct mpr_softc *)arg; + mpr_lock(sc); + while ((fw_event = TAILQ_FIRST(&sc->sassc->ev_queue)) != NULL) { + TAILQ_REMOVE(&sc->sassc->ev_queue, fw_event, ev_link); + mprsas_fw_work(sc, fw_event); + } + mpr_unlock(sc); +} + +static int +mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){ + char devstring[80]; + struct mprsas_softc *sassc; + struct mprsas_target *targ; + Mpi2ConfigReply_t mpi_reply; + Mpi2SasDevicePage0_t config_page; + uint64_t sas_address, sata_sas_address; + uint64_t parent_sas_address = 0; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + u32 device_info, parent_devinfo = 0; + unsigned int id; + int ret; + int error = 0; + struct mprsas_lun *lun; + + sassc = sc->sassc; + mprsas_startup_increment(sassc); + if ((mpr_config_get_sas_device_pg0(sc, &mpi_reply, &config_page, + MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { + printf("%s: error reading SAS device page0\n", __func__); + error = ENXIO; + goto out; + } + + device_info = le32toh(config_page.DeviceInfo); + + if (((device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) + && (le16toh(config_page.ParentDevHandle) != 0)) { + Mpi2ConfigReply_t tmp_mpi_reply; + Mpi2SasDevicePage0_t parent_config_page; + + if ((mpr_config_get_sas_device_pg0(sc, &tmp_mpi_reply, + &parent_config_page, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, + le16toh(config_page.ParentDevHandle)))) { + printf("%s: error reading SAS device %#x page0\n", + __func__, le16toh(config_page.ParentDevHandle)); + } else { + parent_sas_address = parent_config_page.SASAddress.High; + parent_sas_address = (parent_sas_address << 32) | + parent_config_page.SASAddress.Low; + parent_devinfo = le32toh(parent_config_page.DeviceInfo); + } + } + /* TODO Check proper endianess */ + sas_address = config_page.SASAddress.High; + sas_address = (sas_address << 32) | + config_page.SASAddress.Low; + + if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) + == MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { + if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) { + ret = mprsas_get_sas_address_for_sata_disk(sc, + &sata_sas_address, handle, device_info); + if (!ret) + id = mpr_mapping_get_sas_id(sc, + sata_sas_address, handle); + else + id = mpr_mapping_get_sas_id(sc, + sas_address, handle); + } else + id = mpr_mapping_get_sas_id(sc, sas_address, + handle); + } else + id = mpr_mapping_get_sas_id(sc, sas_address, handle); + + if (id == MPR_MAP_BAD_ID) { + printf("failure at %s:%d/%s()! Could not get ID for device " + "with handle 0x%04x\n", __FILE__, __LINE__, __func__, + handle); + error = ENXIO; + goto out; + } + + if (mprsas_check_id(sassc, id) != 0) { + device_printf(sc->mpr_dev, "Excluding target id %d\n", id); + error = ENXIO; + goto out; + } + + mpr_dprint(sc, MPR_MAPPING, "SAS Address from SAS device page0 = %jx\n", + sas_address); + targ = &sassc->targets[id]; + targ->devinfo = device_info; + targ->devname = le32toh(config_page.DeviceName.High); + targ->devname = (targ->devname << 32) | + le32toh(config_page.DeviceName.Low); + targ->encl_handle = le16toh(config_page.EnclosureHandle); + targ->encl_slot = le16toh(config_page.Slot); + targ->encl_level = config_page.EnclosureLevel; + targ->connector_name[0] = config_page.ConnectorName[0]; + targ->connector_name[1] = config_page.ConnectorName[1]; + targ->connector_name[2] = config_page.ConnectorName[2]; + targ->connector_name[3] = config_page.ConnectorName[3]; + targ->handle = handle; + targ->parent_handle = le16toh(config_page.ParentDevHandle); + targ->sasaddr = mpr_to_u64(&config_page.SASAddress); + targ->parent_sasaddr = le64toh(parent_sas_address); + targ->parent_devinfo = parent_devinfo; + targ->tid = id; + targ->linkrate = (linkrate>>4); + targ->flags = 0; + if (le16toh(config_page.Flags) & + MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) { + targ->scsi_req_desc_type = + MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; + } + if (le16toh(config_page.Flags) & + MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { + targ->encl_level_valid = TRUE; + } + TAILQ_INIT(&targ->commands); + TAILQ_INIT(&targ->timedout_commands); + while (!SLIST_EMPTY(&targ->luns)) { + lun = SLIST_FIRST(&targ->luns); + SLIST_REMOVE_HEAD(&targ->luns, lun_link); + free(lun, M_MPR); + } + SLIST_INIT(&targ->luns); + + mpr_describe_devinfo(targ->devinfo, devstring, 80); + mpr_dprint(sc, (MPR_XINFO|MPR_MAPPING), "Found device <%s> <%s> " + "handle<0x%04x> enclosureHandle<0x%04x> slot %d\n", devstring, + mpr_describe_table(mpr_linkrate_names, targ->linkrate), + targ->handle, targ->encl_handle, targ->encl_slot); + if (targ->encl_level_valid) { + mpr_dprint(sc, (MPR_XINFO|MPR_MAPPING), "At enclosure level %d " + "and connector name (%4s)\n", targ->encl_level, + targ->connector_name); + } +#if ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000039)) || \ + (__FreeBSD_version < 902502) + if ((sassc->flags & MPRSAS_IN_STARTUP) == 0) +#endif + mprsas_rescan_target(sc, targ); + mpr_dprint(sc, MPR_MAPPING, "Target id 0x%x added\n", targ->tid); +out: + mprsas_startup_decrement(sassc); + return (error); + +} + +int +mprsas_get_sas_address_for_sata_disk(struct mpr_softc *sc, + u64 *sas_address, u16 handle, u32 device_info) +{ + Mpi2SataPassthroughReply_t mpi_reply; + int i, rc, try_count; + u32 *bufferptr; + union _sata_sas_address hash_address; + struct _ata_identify_device_data ata_identify; + u8 buffer[MPT2SAS_MN_LEN + MPT2SAS_SN_LEN]; + u32 ioc_status; + u8 sas_status; + + memset(&ata_identify, 0, sizeof(ata_identify)); + try_count = 0; + do { + rc = mprsas_get_sata_identify(sc, handle, &mpi_reply, + (char *)&ata_identify, sizeof(ata_identify), device_info); + try_count++; + ioc_status = le16toh(mpi_reply.IOCStatus) + & MPI2_IOCSTATUS_MASK; + sas_status = mpi_reply.SASStatus; + } while ((rc == -EAGAIN || ioc_status || sas_status) && + (try_count < 5)); + + if (rc == 0 && !ioc_status && !sas_status) { + mpr_dprint(sc, MPR_MAPPING, "%s: got SATA identify " + "successfully for handle = 0x%x with try_count = %d\n", + __func__, handle, try_count); + } else { + mpr_dprint(sc, MPR_MAPPING, "%s: handle = 0x%x failed\n", + __func__, handle); + return -1; + } + /* Copy & byteswap the 40 byte model number to a buffer */ + for (i = 0; i < MPT2SAS_MN_LEN; i += 2) { + buffer[i] = ((u8 *)ata_identify.model_number)[i + 1]; + buffer[i + 1] = ((u8 *)ata_identify.model_number)[i]; + } + /* Copy & byteswap the 20 byte serial number to a buffer */ + for (i = 0; i < MPT2SAS_SN_LEN; i += 2) { + buffer[MPT2SAS_MN_LEN + i] = + ((u8 *)ata_identify.serial_number)[i + 1]; + buffer[MPT2SAS_MN_LEN + i + 1] = + ((u8 *)ata_identify.serial_number)[i]; + } + bufferptr = (u32 *)buffer; + /* There are 60 bytes to hash down to 8. 60 isn't divisible by 8, + * so loop through the first 56 bytes (7*8), + * and then add in the last dword. + */ + hash_address.word.low = 0; + hash_address.word.high = 0; + for (i = 0; (i < ((MPT2SAS_MN_LEN+MPT2SAS_SN_LEN)/8)); i++) { + hash_address.word.low += *bufferptr; + bufferptr++; + hash_address.word.high += *bufferptr; + bufferptr++; + } + /* Add the last dword */ + hash_address.word.low += *bufferptr; + /* Make sure the hash doesn't start with 5, because it could clash + * with a SAS address. Change 5 to a D. + */ + if ((hash_address.word.high & 0x000000F0) == (0x00000050)) + hash_address.word.high |= 0x00000080; + *sas_address = (u64)hash_address.wwid[0] << 56 | + (u64)hash_address.wwid[1] << 48 | (u64)hash_address.wwid[2] << 40 | + (u64)hash_address.wwid[3] << 32 | (u64)hash_address.wwid[4] << 24 | + (u64)hash_address.wwid[5] << 16 | (u64)hash_address.wwid[6] << 8 | + (u64)hash_address.wwid[7]; + return 0; +} + +static int +mprsas_get_sata_identify(struct mpr_softc *sc, u16 handle, + Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, u32 devinfo) +{ + Mpi2SataPassthroughRequest_t *mpi_request; + Mpi2SataPassthroughReply_t *reply; + struct mpr_command *cm; + char *buffer; + int error = 0; + + buffer = malloc( sz, M_MPR, M_NOWAIT | M_ZERO); + if (!buffer) + return ENOMEM; + + if ((cm = mpr_alloc_command(sc)) == NULL) { + free(buffer, M_MPR); + return (EBUSY); + } + mpi_request = (MPI2_SATA_PASSTHROUGH_REQUEST *)cm->cm_req; + bzero(mpi_request,sizeof(MPI2_SATA_PASSTHROUGH_REQUEST)); + mpi_request->Function = MPI2_FUNCTION_SATA_PASSTHROUGH; + mpi_request->VF_ID = 0; + mpi_request->DevHandle = htole16(handle); + mpi_request->PassthroughFlags = (MPI2_SATA_PT_REQ_PT_FLAGS_PIO | + MPI2_SATA_PT_REQ_PT_FLAGS_READ); + mpi_request->DataLength = htole32(sz); + mpi_request->CommandFIS[0] = 0x27; + mpi_request->CommandFIS[1] = 0x80; + mpi_request->CommandFIS[2] = (devinfo & + MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? 0xA1 : 0xEC; + cm->cm_sge = &mpi_request->SGL; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPR_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = buffer; + cm->cm_length = htole32(sz); + error = mpr_wait_command(sc, cm, 60, CAN_SLEEP); + reply = (Mpi2SataPassthroughReply_t *)cm->cm_reply; + if (error || (reply == NULL)) { + /* FIXME */ + /* + * If the request returns an error then we need to do a diag + * reset + */ + printf("%s: request for page completed with error %d", + __func__, error); + error = ENXIO; + goto out; + } + bcopy(buffer, id_buffer, sz); + bcopy(reply, mpi_reply, sizeof(Mpi2SataPassthroughReply_t)); + if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) != + MPI2_IOCSTATUS_SUCCESS) { + printf("%s: error reading SATA PASSTHRU; iocstatus = 0x%x\n", + __func__, reply->IOCStatus); + error = ENXIO; + goto out; + } +out: + mpr_free_command(sc, cm); + free(buffer, M_MPR); + return (error); +} + +static int +mprsas_volume_add(struct mpr_softc *sc, u16 handle) +{ + struct mprsas_softc *sassc; + struct mprsas_target *targ; + u64 wwid; + unsigned int id; + int error = 0; + struct mprsas_lun *lun; + + sassc = sc->sassc; + mprsas_startup_increment(sassc); + /* wwid is endian safe */ + mpr_config_get_volume_wwid(sc, handle, &wwid); + if (!wwid) { + printf("%s: invalid WWID; cannot add volume to mapping table\n", + __func__); + error = ENXIO; + goto out; + } + + id = mpr_mapping_get_raid_id(sc, wwid, handle); + if (id == MPR_MAP_BAD_ID) { + printf("%s: could not get ID for volume with handle 0x%04x and " + "WWID 0x%016llx\n", __func__, handle, + (unsigned long long)wwid); + error = ENXIO; + goto out; + } + + targ = &sassc->targets[id]; + targ->tid = id; + targ->handle = handle; + targ->devname = wwid; + TAILQ_INIT(&targ->commands); + TAILQ_INIT(&targ->timedout_commands); + while (!SLIST_EMPTY(&targ->luns)) { + lun = SLIST_FIRST(&targ->luns); + SLIST_REMOVE_HEAD(&targ->luns, lun_link); + free(lun, M_MPR); + } + SLIST_INIT(&targ->luns); +#if ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000039)) || \ + (__FreeBSD_version < 902502) + if ((sassc->flags & MPRSAS_IN_STARTUP) == 0) +#endif + mprsas_rescan_target(sc, targ); + mpr_dprint(sc, MPR_MAPPING, "RAID target id %d added (WWID = 0x%jx)\n", + targ->tid, wwid); +out: + mprsas_startup_decrement(sassc); + return (error); +} + +/** + * mprsas_SSU_to_SATA_devices + * @sc: per adapter object + * + * Looks through the target list and issues a StartStopUnit SCSI command to each + * SATA direct-access device. This helps to ensure that data corruption is + * avoided when the system is being shut down. This must be called after the IR + * System Shutdown RAID Action is sent if in IR mode. + * + * Return nothing. + */ +static void +mprsas_SSU_to_SATA_devices(struct mpr_softc *sc) +{ + struct mprsas_softc *sassc = sc->sassc; + union ccb *ccb; + path_id_t pathid = cam_sim_path(sassc->sim); + target_id_t targetid; + struct mprsas_target *target; + struct mprsas_lun *lun; + char path_str[64]; + struct timeval cur_time, start_time; + + mpr_lock(sc); + + /* + * For each LUN of each target, issue a StartStopUnit command to stop + * the device. + */ + sc->SSU_started = TRUE; + sc->SSU_refcount = 0; + for (targetid = 0; targetid < sc->facts->MaxTargets; targetid++) { + target = &sassc->targets[targetid]; + if (target->handle == 0x0) { + continue; + } + + SLIST_FOREACH(lun, &target->luns, lun_link) { + ccb = xpt_alloc_ccb_nowait(); + if (ccb == NULL) { + mpr_unlock(sc); + mpr_dprint(sc, MPR_FAULT, "Unable to alloc " + "CCB to stop unit.\n"); + return; + } + + /* + * The stop_at_shutdown flag will be set if this LUN is + * a SATA direct-access end device. + */ + if (lun->stop_at_shutdown) { + if (xpt_create_path(&ccb->ccb_h.path, + xpt_periph, pathid, targetid, + lun->lun_id) != CAM_REQ_CMP) { + mpr_dprint(sc, MPR_FAULT, "Unable to " + "create LUN path to stop unit.\n"); + xpt_free_ccb(ccb); + mpr_unlock(sc); + return; + } + xpt_path_string(ccb->ccb_h.path, path_str, + sizeof(path_str)); + + mpr_dprint(sc, MPR_INFO, "Sending StopUnit: " + "path %s handle %d\n", path_str, + target->handle); + + /* + * Issue a START STOP UNIT command for the LUN. + * Increment the SSU counter to be used to + * count the number of required replies. + */ + mpr_dprint(sc, MPR_INFO, "Incrementing SSU " + "count\n"); + sc->SSU_refcount++; + ccb->ccb_h.target_id = + xpt_path_target_id(ccb->ccb_h.path); + ccb->ccb_h.target_lun = lun->lun_id; + ccb->ccb_h.ppriv_ptr1 = sassc; + scsi_start_stop(&ccb->csio, + /*retries*/0, + mprsas_stop_unit_done, + MSG_SIMPLE_Q_TAG, + /*start*/FALSE, + /*load/eject*/0, + /*immediate*/FALSE, + MPR_SENSE_LEN, + /*timeout*/10000); + xpt_action(ccb); + } + } + } + + mpr_unlock(sc); + + /* + * Wait until all of the SSU commands have completed or time has + * expired (60 seconds). pause for 100ms each time through. If any + * command times out, the target will be reset in the SCSI command + * timeout routine. + */ + getmicrotime(&start_time); + while (sc->SSU_refcount) { + pause("mprwait", hz/10); + + getmicrotime(&cur_time); + if ((cur_time.tv_sec - start_time.tv_sec) > 60) { + mpr_dprint(sc, MPR_FAULT, "Time has expired waiting " + "for SSU commands to complete.\n"); + break; + } + } +} + +static void +mprsas_stop_unit_done(struct cam_periph *periph, union ccb *done_ccb) +{ + struct mprsas_softc *sassc; + char path_str[64]; + + sassc = (struct mprsas_softc *)done_ccb->ccb_h.ppriv_ptr1; + + xpt_path_string(done_ccb->ccb_h.path, path_str, sizeof(path_str)); + mpr_dprint(sassc->sc, MPR_INFO, "Completing stop unit for %s\n", + path_str); + + if (done_ccb == NULL) + return; + + /* + * Nothing more to do except free the CCB and path. If the command + * timed out, an abort reset, then target reset will be issued during + * the SCSI Command process. + */ + xpt_free_path(done_ccb->ccb_h.path); + xpt_free_ccb(done_ccb); +} + +/** + * mprsas_ir_shutdown - IR shutdown notification + * @sc: per adapter object + * + * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that + * the host system is shutting down. + * + * Return nothing. + */ +void +mprsas_ir_shutdown(struct mpr_softc *sc) +{ + u16 volume_mapping_flags; + u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + struct dev_mapping_table *mt_entry; + u32 start_idx, end_idx; + unsigned int id, found_volume = 0; + struct mpr_command *cm; + Mpi2RaidActionRequest_t *action; + + mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); + + /* is IR firmware build loaded? */ + if (!sc->ir_firmware) + goto out; + + /* are there any volumes? Look at IR target IDs. */ + // TODO-later, this should be looked up in the RAID config structure + // when it is implemented. + volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) & + MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; + if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) { + start_idx = 0; + if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0) + start_idx = 1; + } else + start_idx = sc->max_devices - sc->max_volumes; + end_idx = start_idx + sc->max_volumes - 1; + + for (id = start_idx; id < end_idx; id++) { + mt_entry = &sc->mapping_table[id]; + if ((mt_entry->physical_id != 0) && + (mt_entry->missing_count == 0)) { + found_volume = 1; + break; + } + } + + if (!found_volume) + goto out; + + if ((cm = mpr_alloc_command(sc)) == NULL) { + printf("%s: command alloc failed\n", __func__); + goto out; + } + + action = (MPI2_RAID_ACTION_REQUEST *)cm->cm_req; + action->Function = MPI2_FUNCTION_RAID_ACTION; + action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + mpr_lock(sc); + mpr_wait_command(sc, cm, 5, CAN_SLEEP); + mpr_unlock(sc); + + /* + * Don't check for reply, just leave. + */ + if (cm) + mpr_free_command(sc, cm); + +out: + mprsas_SSU_to_SATA_devices(sc); +} diff --git a/sys/dev/mpr/mpr_table.c b/sys/dev/mpr/mpr_table.c new file mode 100644 index 0000000000000..b1e12b38415e2 --- /dev/null +++ b/sys/dev/mpr/mpr_table.c @@ -0,0 +1,516 @@ +/*- + * Copyright (c) 2009 Yahoo! Inc. + * 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$"); + +/* Debugging tables for MPT2 */ + +/* TODO Move headers to mprvar */ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/selinfo.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/bio.h> +#include <sys/malloc.h> +#include <sys/uio.h> +#include <sys/sysctl.h> +#include <sys/queue.h> +#include <sys/kthread.h> +#include <sys/taskqueue.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <cam/scsi/scsi_all.h> + +#include <dev/mpr/mpi/mpi2_type.h> +#include <dev/mpr/mpi/mpi2.h> +#include <dev/mpr/mpi/mpi2_ioc.h> +#include <dev/mpr/mpi/mpi2_cnfg.h> +#include <dev/mpr/mpi/mpi2_init.h> +#include <dev/mpr/mpi/mpi2_tool.h> +#include <dev/mpr/mpr_ioctl.h> +#include <dev/mpr/mprvar.h> +#include <dev/mpr/mpr_table.h> + +char * +mpr_describe_table(struct mpr_table_lookup *table, u_int code) +{ + int i; + + for (i = 0; table[i].string != NULL; i++) { + if (table[i].code == code) + return(table[i].string); + } + return(table[i+1].string); +} + +struct mpr_table_lookup mpr_event_names[] = { + {"LogData", 0x01}, + {"StateChange", 0x02}, + {"HardResetReceived", 0x05}, + {"EventChange", 0x0a}, + {"TaskSetFull", 0x0e}, + {"SasDeviceStatusChange", 0x0f}, + {"IrOperationStatus", 0x14}, + {"SasDiscovery", 0x16}, + {"SasBroadcastPrimitive", 0x17}, + {"SasInitDeviceStatusChange", 0x18}, + {"SasInitTableOverflow", 0x19}, + {"SasTopologyChangeList", 0x1c}, + {"SasEnclDeviceStatusChange", 0x1d}, + {"IrVolume", 0x1e}, + {"IrPhysicalDisk", 0x1f}, + {"IrConfigurationChangeList", 0x20}, + {"LogEntryAdded", 0x21}, + {"SasPhyCounter", 0x22}, + {"GpioInterrupt", 0x23}, + {"HbdPhyEvent", 0x24}, + {NULL, 0}, + {"Unknown Event", 0} +}; + +struct mpr_table_lookup mpr_phystatus_names[] = { + {"NewTargetAdded", 0x01}, + {"TargetGone", 0x02}, + {"PHYLinkStatusChange", 0x03}, + {"PHYLinkStatusUnchanged", 0x04}, + {"TargetMissing", 0x05}, + {NULL, 0}, + {"Unknown Status", 0} +}; + +struct mpr_table_lookup mpr_linkrate_names[] = { + {"PHY disabled", 0x01}, + {"Speed Negotiation Failed", 0x02}, + {"SATA OOB Complete", 0x03}, + {"SATA Port Selector", 0x04}, + {"SMP Reset in Progress", 0x05}, + {"1.5Gbps", 0x08}, + {"3.0Gbps", 0x09}, + {"6.0Gbps", 0x0a}, + {NULL, 0}, + {"LinkRate Unknown", 0x00} +}; + +struct mpr_table_lookup mpr_sasdev0_devtype[] = { + {"End Device", 0x01}, + {"Edge Expander", 0x02}, + {"Fanout Expander", 0x03}, + {NULL, 0}, + {"No Device", 0x00} +}; + +struct mpr_table_lookup mpr_phyinfo_reason_names[] = { + {"Power On", 0x01}, + {"Hard Reset", 0x02}, + {"SMP Phy Control Link Reset", 0x03}, + {"Loss DWORD Sync", 0x04}, + {"Multiplex Sequence", 0x05}, + {"I-T Nexus Loss Timer", 0x06}, + {"Break Timeout Timer", 0x07}, + {"PHY Test Function", 0x08}, + {NULL, 0}, + {"Unknown Reason", 0x00} +}; + +struct mpr_table_lookup mpr_whoinit_names[] = { + {"System BIOS", 0x01}, + {"ROM BIOS", 0x02}, + {"PCI Peer", 0x03}, + {"Host Driver", 0x04}, + {"Manufacturing", 0x05}, + {NULL, 0}, + {"Not Initialized", 0x00} +}; + +struct mpr_table_lookup mpr_sasdisc_reason[] = { + {"Discovery Started", 0x01}, + {"Discovery Complete", 0x02}, + {NULL, 0}, + {"Unknown", 0x00} +}; + +struct mpr_table_lookup mpr_sastopo_exp[] = { + {"Added", 0x01}, + {"Not Responding", 0x02}, + {"Responding", 0x03}, + {"Delay Not Responding", 0x04}, + {NULL, 0}, + {"Unknown", 0x00} +}; + +struct mpr_table_lookup mpr_sasdev_reason[] = { + {"SMART Data", 0x05}, + {"Unsupported", 0x07}, + {"Internal Device Reset", 0x08}, + {"Task Abort Internal", 0x09}, + {"Abort Task Set Internal", 0x0a}, + {"Clear Task Set Internal", 0x0b}, + {"Query Task Internal", 0x0c}, + {"Async Notification", 0x0d}, + {"Cmp Internal Device Reset", 0x0e}, + {"Cmp Task Abort Internal", 0x0f}, + {"Sata Init Failure", 0x10}, + {NULL, 0}, + {"Unknown", 0x00} +}; + +void +mpr_describe_devinfo(uint32_t devinfo, char *string, int len) +{ + snprintf(string, len, "%b,%s", devinfo, + "\20" "\4SataHost" "\5SmpInit" "\6StpInit" "\7SspInit" + "\10SataDev" "\11SmpTarg" "\12StpTarg" "\13SspTarg" "\14Direct" + "\15LsiDev" "\16AtapiDev" "\17SepDev", + mpr_describe_table(mpr_sasdev0_devtype, devinfo & 0x03)); +} + +void +mpr_print_iocfacts(struct mpr_softc *sc, MPI2_IOC_FACTS_REPLY *facts) +{ + + MPR_PRINTFIELD_START(sc, "IOCFacts"); + MPR_PRINTFIELD(sc, facts, MsgVersion, 0x%x); + MPR_PRINTFIELD(sc, facts, HeaderVersion, 0x%x); + MPR_PRINTFIELD(sc, facts, IOCNumber, %d); + MPR_PRINTFIELD(sc, facts, IOCExceptions, 0x%x); + MPR_PRINTFIELD(sc, facts, MaxChainDepth, %d); + mpr_dprint_field(sc, MPR_XINFO, "WhoInit: %s\n", + mpr_describe_table(mpr_whoinit_names, facts->WhoInit)); + MPR_PRINTFIELD(sc, facts, NumberOfPorts, %d); + MPR_PRINTFIELD(sc, facts, RequestCredit, %d); + MPR_PRINTFIELD(sc, facts, ProductID, 0x%x); + mpr_dprint_field(sc, MPR_XINFO, "IOCCapabilities: %b\n", + facts->IOCCapabilities, "\20" "\3ScsiTaskFull" "\4DiagTrace" + "\5SnapBuf" "\6ExtBuf" "\7EEDP" "\10BiDirTarg" "\11Multicast" + "\14TransRetry" "\15IR" "\16EventReplay" "\17RaidAccel" + "\20MSIXIndex" "\21HostDisc"); + mpr_dprint_field(sc, MPR_XINFO, "FWVersion= %d-%d-%d-%d\n", + facts->FWVersion.Struct.Major, + facts->FWVersion.Struct.Minor, + facts->FWVersion.Struct.Unit, + facts->FWVersion.Struct.Dev); + MPR_PRINTFIELD(sc, facts, IOCRequestFrameSize, %d); + MPR_PRINTFIELD(sc, facts, MaxInitiators, %d); + MPR_PRINTFIELD(sc, facts, MaxTargets, %d); + MPR_PRINTFIELD(sc, facts, MaxSasExpanders, %d); + MPR_PRINTFIELD(sc, facts, MaxEnclosures, %d); + mpr_dprint_field(sc, MPR_XINFO, "ProtocolFlags: %b\n", + facts->ProtocolFlags, "\20" "\1ScsiTarg" "\2ScsiInit"); + MPR_PRINTFIELD(sc, facts, HighPriorityCredit, %d); + MPR_PRINTFIELD(sc, facts, MaxReplyDescriptorPostQueueDepth, %d); + MPR_PRINTFIELD(sc, facts, ReplyFrameSize, %d); + MPR_PRINTFIELD(sc, facts, MaxVolumes, %d); + MPR_PRINTFIELD(sc, facts, MaxDevHandle, %d); + MPR_PRINTFIELD(sc, facts, MaxPersistentEntries, %d); +} + +void +mpr_print_portfacts(struct mpr_softc *sc, MPI2_PORT_FACTS_REPLY *facts) +{ + + MPR_PRINTFIELD_START(sc, "PortFacts"); + MPR_PRINTFIELD(sc, facts, PortNumber, %d); + MPR_PRINTFIELD(sc, facts, PortType, 0x%x); + MPR_PRINTFIELD(sc, facts, MaxPostedCmdBuffers, %d); +} + +void +mpr_print_event(struct mpr_softc *sc, MPI2_EVENT_NOTIFICATION_REPLY *event) +{ + + MPR_EVENTFIELD_START(sc, "EventReply"); + MPR_EVENTFIELD(sc, event, EventDataLength, %d); + MPR_EVENTFIELD(sc, event, AckRequired, %d); + mpr_dprint_field(sc, MPR_EVENT, "Event: %s (0x%x)\n", + mpr_describe_table(mpr_event_names, event->Event), event->Event); + MPR_EVENTFIELD(sc, event, EventContext, 0x%x); +} + +void +mpr_print_sasdev0(struct mpr_softc *sc, MPI2_CONFIG_PAGE_SAS_DEV_0 *buf) +{ + MPR_PRINTFIELD_START(sc, "SAS Device Page 0"); + MPR_PRINTFIELD(sc, buf, Slot, %d); + MPR_PRINTFIELD(sc, buf, EnclosureHandle, 0x%x); + mpr_dprint_field(sc, MPR_XINFO, "SASAddress: 0x%jx\n", + mpr_to_u64(&buf->SASAddress)); + MPR_PRINTFIELD(sc, buf, ParentDevHandle, 0x%x); + MPR_PRINTFIELD(sc, buf, PhyNum, %d); + MPR_PRINTFIELD(sc, buf, AccessStatus, 0x%x); + MPR_PRINTFIELD(sc, buf, DevHandle, 0x%x); + MPR_PRINTFIELD(sc, buf, AttachedPhyIdentifier, 0x%x); + MPR_PRINTFIELD(sc, buf, ZoneGroup, %d); + mpr_dprint_field(sc, MPR_XINFO, "DeviceInfo: %b,%s\n", buf->DeviceInfo, + "\20" "\4SataHost" "\5SmpInit" "\6StpInit" "\7SspInit" + "\10SataDev" "\11SmpTarg" "\12StpTarg" "\13SspTarg" "\14Direct" + "\15LsiDev" "\16AtapiDev" "\17SepDev", + mpr_describe_table(mpr_sasdev0_devtype, buf->DeviceInfo & 0x03)); + MPR_PRINTFIELD(sc, buf, Flags, 0x%x); + MPR_PRINTFIELD(sc, buf, PhysicalPort, %d); + MPR_PRINTFIELD(sc, buf, MaxPortConnections, %d); + mpr_dprint_field(sc, MPR_XINFO, "DeviceName: 0x%jx\n", + mpr_to_u64(&buf->DeviceName)); + MPR_PRINTFIELD(sc, buf, PortGroups, %d); + MPR_PRINTFIELD(sc, buf, DmaGroup, %d); + MPR_PRINTFIELD(sc, buf, ControlGroup, %d); +} + +void +mpr_print_evt_sas(struct mpr_softc *sc, MPI2_EVENT_NOTIFICATION_REPLY *event) +{ + + mpr_print_event(sc, event); + + switch(event->Event) { + case MPI2_EVENT_SAS_DISCOVERY: + { + MPI2_EVENT_DATA_SAS_DISCOVERY *data; + + data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)&event->EventData; + mpr_dprint_field(sc, MPR_EVENT, "Flags: %b\n", data->Flags, + "\20" "\1InProgress" "\2DeviceChange"); + mpr_dprint_field(sc, MPR_EVENT, "ReasonCode: %s\n", + mpr_describe_table(mpr_sasdisc_reason, data->ReasonCode)); + MPR_EVENTFIELD(sc, data, PhysicalPort, %d); + mpr_dprint_field(sc, MPR_EVENT, "DiscoveryStatus: %b\n", + data->DiscoveryStatus, "\20" + "\1Loop" "\2UnaddressableDev" "\3DupSasAddr" "\5SmpTimeout" + "\6ExpRouteFull" "\7RouteIndexError" "\10SmpFailed" + "\11SmpCrcError" "\12SubSubLink" "\13TableTableLink" + "\14UnsupDevice" "\15TableSubLink" "\16MultiDomain" + "\17MultiSub" "\20MultiSubSub" "\34DownstreamInit" + "\35MaxPhys" "\36MaxTargs" "\37MaxExpanders" + "\40MaxEnclosures"); + break; + } + case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: + { + MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data; + MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy; + int i, phynum; + + data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *) + &event->EventData; + MPR_EVENTFIELD(sc, data, EnclosureHandle, 0x%x); + MPR_EVENTFIELD(sc, data, ExpanderDevHandle, 0x%x); + MPR_EVENTFIELD(sc, data, NumPhys, %d); + MPR_EVENTFIELD(sc, data, NumEntries, %d); + MPR_EVENTFIELD(sc, data, StartPhyNum, %d); + mpr_dprint_field(sc, MPR_EVENT, "ExpStatus: %s (0x%x)\n", + mpr_describe_table(mpr_sastopo_exp, data->ExpStatus), + data->ExpStatus); + MPR_EVENTFIELD(sc, data, PhysicalPort, %d); + for (i = 0; i < data->NumEntries; i++) { + phy = &data->PHY[i]; + phynum = data->StartPhyNum + i; + mpr_dprint_field(sc, MPR_EVENT, + "PHY[%d].AttachedDevHandle: 0x%04x\n", phynum, + phy->AttachedDevHandle); + mpr_dprint_field(sc, MPR_EVENT, + "PHY[%d].LinkRate: %s (0x%x)\n", phynum, + mpr_describe_table(mpr_linkrate_names, + (phy->LinkRate >> 4) & 0xf), phy->LinkRate); + mpr_dprint_field(sc,MPR_EVENT,"PHY[%d].PhyStatus: " + "%s\n", phynum, + mpr_describe_table(mpr_phystatus_names, + phy->PhyStatus)); + } + break; + } + case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: + { + MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE *data; + + data = (MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE *) + &event->EventData; + MPR_EVENTFIELD(sc, data, EnclosureHandle, 0x%x); + mpr_dprint_field(sc, MPR_EVENT, "ReasonCode: %s\n", + mpr_describe_table(mpr_sastopo_exp, data->ReasonCode)); + MPR_EVENTFIELD(sc, data, PhysicalPort, %d); + MPR_EVENTFIELD(sc, data, NumSlots, %d); + MPR_EVENTFIELD(sc, data, StartSlot, %d); + MPR_EVENTFIELD(sc, data, PhyBits, 0x%x); + break; + } + case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: + { + MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *data; + + data = (MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *) + &event->EventData; + MPR_EVENTFIELD(sc, data, TaskTag, 0x%x); + mpr_dprint_field(sc, MPR_EVENT, "ReasonCode: %s\n", + mpr_describe_table(mpr_sasdev_reason, data->ReasonCode)); + MPR_EVENTFIELD(sc, data, ASC, 0x%x); + MPR_EVENTFIELD(sc, data, ASCQ, 0x%x); + MPR_EVENTFIELD(sc, data, DevHandle, 0x%x); + mpr_dprint_field(sc, MPR_EVENT, "SASAddress: 0x%jx\n", + mpr_to_u64(&data->SASAddress)); + } + default: + break; + } +} + +void +mpr_print_expander1(struct mpr_softc *sc, MPI2_CONFIG_PAGE_EXPANDER_1 *buf) +{ + MPR_PRINTFIELD_START(sc, "SAS Expander Page 1 #%d", buf->Phy); + MPR_PRINTFIELD(sc, buf, PhysicalPort, %d); + MPR_PRINTFIELD(sc, buf, NumPhys, %d); + MPR_PRINTFIELD(sc, buf, Phy, %d); + MPR_PRINTFIELD(sc, buf, NumTableEntriesProgrammed, %d); + mpr_dprint_field(sc, MPR_XINFO, "ProgrammedLinkRate: %s (0x%x)\n", + mpr_describe_table(mpr_linkrate_names, + (buf->ProgrammedLinkRate >> 4) & 0xf), buf->ProgrammedLinkRate); + mpr_dprint_field(sc, MPR_XINFO, "HwLinkRate: %s (0x%x)\n", + mpr_describe_table(mpr_linkrate_names, + (buf->HwLinkRate >> 4) & 0xf), buf->HwLinkRate); + MPR_PRINTFIELD(sc, buf, AttachedDevHandle, 0x%04x); + mpr_dprint_field(sc, MPR_XINFO, "PhyInfo Reason: %s (0x%x)\n", + mpr_describe_table(mpr_phyinfo_reason_names, + (buf->PhyInfo >> 16) & 0xf), buf->PhyInfo); + mpr_dprint_field(sc, MPR_XINFO, "AttachedDeviceInfo: %b,%s\n", + buf->AttachedDeviceInfo, "\20" "\4SATAhost" "\5SMPinit" "\6STPinit" + "\7SSPinit" "\10SATAdev" "\11SMPtarg" "\12STPtarg" "\13SSPtarg" + "\14Direct" "\15LSIdev" "\16ATAPIdev" "\17SEPdev", + mpr_describe_table(mpr_sasdev0_devtype, + buf->AttachedDeviceInfo & 0x03)); + MPR_PRINTFIELD(sc, buf, ExpanderDevHandle, 0x%04x); + MPR_PRINTFIELD(sc, buf, ChangeCount, %d); + mpr_dprint_field(sc, MPR_XINFO, "NegotiatedLinkRate: %s (0x%x)\n", + mpr_describe_table(mpr_linkrate_names, + buf->NegotiatedLinkRate & 0xf), buf->NegotiatedLinkRate); + MPR_PRINTFIELD(sc, buf, PhyIdentifier, %d); + MPR_PRINTFIELD(sc, buf, AttachedPhyIdentifier, %d); + MPR_PRINTFIELD(sc, buf, DiscoveryInfo, 0x%x); + MPR_PRINTFIELD(sc, buf, AttachedPhyInfo, 0x%x); + mpr_dprint_field(sc, MPR_XINFO, "AttachedPhyInfo Reason: %s (0x%x)\n", + mpr_describe_table(mpr_phyinfo_reason_names, + buf->AttachedPhyInfo & 0xf), buf->AttachedPhyInfo); + MPR_PRINTFIELD(sc, buf, ZoneGroup, %d); + MPR_PRINTFIELD(sc, buf, SelfConfigStatus, 0x%x); +} + +void +mpr_print_sasphy0(struct mpr_softc *sc, MPI2_CONFIG_PAGE_SAS_PHY_0 *buf) +{ + MPR_PRINTFIELD_START(sc, "SAS PHY Page 0"); + MPR_PRINTFIELD(sc, buf, OwnerDevHandle, 0x%04x); + MPR_PRINTFIELD(sc, buf, AttachedDevHandle, 0x%04x); + MPR_PRINTFIELD(sc, buf, AttachedPhyIdentifier, %d); + mpr_dprint_field(sc, MPR_XINFO, "AttachedPhyInfo Reason: %s (0x%x)\n", + mpr_describe_table(mpr_phyinfo_reason_names, + buf->AttachedPhyInfo & 0xf), buf->AttachedPhyInfo); + mpr_dprint_field(sc, MPR_XINFO, "ProgrammedLinkRate: %s (0x%x)\n", + mpr_describe_table(mpr_linkrate_names, + (buf->ProgrammedLinkRate >> 4) & 0xf), buf->ProgrammedLinkRate); + mpr_dprint_field(sc, MPR_XINFO, "HwLinkRate: %s (0x%x)\n", + mpr_describe_table(mpr_linkrate_names, + (buf->HwLinkRate >> 4) & 0xf), buf->HwLinkRate); + MPR_PRINTFIELD(sc, buf, ChangeCount, %d); + MPR_PRINTFIELD(sc, buf, Flags, 0x%x); + mpr_dprint_field(sc, MPR_XINFO, "PhyInfo Reason: %s (0x%x)\n", + mpr_describe_table(mpr_phyinfo_reason_names, + (buf->PhyInfo >> 16) & 0xf), buf->PhyInfo); + mpr_dprint_field(sc, MPR_XINFO, "NegotiatedLinkRate: %s (0x%x)\n", + mpr_describe_table(mpr_linkrate_names, + buf->NegotiatedLinkRate & 0xf), buf->NegotiatedLinkRate); +} + +void +mpr_print_sgl(struct mpr_softc *sc, struct mpr_command *cm, int offset) +{ + MPI2_IEEE_SGE_SIMPLE64 *ieee_sge; + MPI25_IEEE_SGE_CHAIN64 *ieee_sgc; + MPI2_SGE_SIMPLE64 *sge; + MPI2_REQUEST_HEADER *req; + struct mpr_chain *chain = NULL; + char *frame; + u_int i = 0, flags, length; + + req = (MPI2_REQUEST_HEADER *)cm->cm_req; + frame = (char *)cm->cm_req; + ieee_sge = (MPI2_IEEE_SGE_SIMPLE64 *)&frame[offset * 4]; + sge = (MPI2_SGE_SIMPLE64 *)&frame[offset * 4]; + printf("SGL for command %p\n", cm); + + hexdump(frame, 128, NULL, 0); + while ((frame != NULL) && (!(cm->cm_flags & MPR_CM_FLAGS_SGE_SIMPLE))) { + flags = ieee_sge->Flags; + length = le32toh(ieee_sge->Length); + printf("IEEE seg%d flags=0x%02x len=0x%08x addr=0x%016jx\n", i, + flags, length, mpr_to_u64(&ieee_sge->Address)); + if (flags & MPI25_IEEE_SGE_FLAGS_END_OF_LIST) + break; + ieee_sge++; + i++; + if (flags & MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT) { + ieee_sgc = (MPI25_IEEE_SGE_CHAIN64 *)ieee_sge; + printf("IEEE chain flags=0x%x len=0x%x Offset=0x%x " + "Address=0x%016jx\n", ieee_sgc->Flags, + le32toh(ieee_sgc->Length), + ieee_sgc->NextChainOffset, + mpr_to_u64(&ieee_sgc->Address)); + if (chain == NULL) + chain = TAILQ_FIRST(&cm->cm_chain_list); + else + chain = TAILQ_NEXT(chain, chain_link); + frame = (char *)chain->chain; + ieee_sge = (MPI2_IEEE_SGE_SIMPLE64 *)frame; + hexdump(frame, 128, NULL, 0); + } + } + while ((frame != NULL) && (cm->cm_flags & MPR_CM_FLAGS_SGE_SIMPLE)) { + flags = le32toh(sge->FlagsLength) >> MPI2_SGE_FLAGS_SHIFT; + printf("seg%d flags=0x%02x len=0x%06x addr=0x%016jx\n", i, + flags, le32toh(sge->FlagsLength) & 0xffffff, + mpr_to_u64(&sge->Address)); + if (flags & (MPI2_SGE_FLAGS_END_OF_LIST | + MPI2_SGE_FLAGS_END_OF_BUFFER)) + break; + sge++; + i++; + } +} + +void +mpr_print_scsiio_cmd(struct mpr_softc *sc, struct mpr_command *cm) +{ + MPI2_SCSI_IO_REQUEST *req; + + req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req; + mpr_print_sgl(sc, cm, req->SGLOffset0); +} + diff --git a/sys/dev/lindev/lindev.c b/sys/dev/mpr/mpr_table.h index cf876042ae954..6539232138e31 100644 --- a/sys/dev/lindev/lindev.c +++ b/sys/dev/mpr/mpr_table.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2009 "Bjoern A. Zeeb" <bz@FreeBSD.org> + * Copyright (c) 2009 Yahoo! Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,52 +22,32 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD$ */ -/* - * "lindev" is supposed to be a collection of linux-specific devices - * that we also support, just not by default. - * While currently there is only "/dev/full", we are planning to see - * more in the future. - * This file is only the container to load/unload all supported devices; - * the implementation of each should go into its own file. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/module.h> - -#include <dev/lindev/lindev.h> - -/* ARGSUSED */ -static int -lindev_modevent(module_t mod, int type, void *data) -{ - int error; - - switch(type) { - case MOD_LOAD: - error = lindev_modevent_full(mod, type, data); - break; - - case MOD_UNLOAD: - error = lindev_modevent_full(mod, type, data); - break; - - case MOD_SHUTDOWN: - error = lindev_modevent_full(mod, type, data); - break; - - default: - return (EOPNOTSUPP); - } - - return (error); -} - -DEV_MODULE(lindev, lindev_modevent, NULL); -MODULE_VERSION(lindev, 1); +#ifndef _MPR_TABLE_H +#define _MPR_TABLE_H + +struct mpr_table_lookup { + char *string; + u_int code; +}; + +char * mpr_describe_table(struct mpr_table_lookup *table, u_int code); +void mpr_describe_devinfo(uint32_t devinfo, char *string, int len); + +extern struct mpr_table_lookup mpr_event_names[]; +extern struct mpr_table_lookup mpr_phystatus_names[]; +extern struct mpr_table_lookup mpr_linkrate_names[]; + +void mpr_print_iocfacts(struct mpr_softc *, MPI2_IOC_FACTS_REPLY *); +void mpr_print_portfacts(struct mpr_softc *, MPI2_PORT_FACTS_REPLY *); +void mpr_print_event(struct mpr_softc *, MPI2_EVENT_NOTIFICATION_REPLY *); +void mpr_print_sasdev0(struct mpr_softc *, MPI2_CONFIG_PAGE_SAS_DEV_0 *); +void mpr_print_evt_sas(struct mpr_softc *, MPI2_EVENT_NOTIFICATION_REPLY *); +void mpr_print_expander1(struct mpr_softc *, MPI2_CONFIG_PAGE_EXPANDER_1 *); +void mpr_print_sasphy0(struct mpr_softc *, MPI2_CONFIG_PAGE_SAS_PHY_0 *); +void mpr_print_sgl(struct mpr_softc *, struct mpr_command *, int); +void mpr_print_scsiio_cmd(struct mpr_softc *, struct mpr_command *); +#endif diff --git a/sys/dev/mpr/mpr_user.c b/sys/dev/mpr/mpr_user.c new file mode 100644 index 0000000000000..60680f5288a31 --- /dev/null +++ b/sys/dev/mpr/mpr_user.c @@ -0,0 +1,2453 @@ +/*- + * Copyright (c) 2008 Yahoo!, Inc. + * All rights reserved. + * Written by: John Baldwin <jhb@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD userland interface + */ +/*- + * Copyright (c) 2011-2014 LSI Corp. + * 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. + * + * LSI MPT-Fusion Host Adapter FreeBSD + * + * $FreeBSD$ + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_compat.h" + +/* TODO Move headers to mprvar */ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/selinfo.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/bio.h> +#include <sys/malloc.h> +#include <sys/uio.h> +#include <sys/sysctl.h> +#include <sys/ioccom.h> +#include <sys/endian.h> +#include <sys/queue.h> +#include <sys/kthread.h> +#include <sys/taskqueue.h> +#include <sys/proc.h> +#include <sys/sysent.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <cam/cam.h> +#include <cam/scsi/scsi_all.h> + +#include <dev/mpr/mpi/mpi2_type.h> +#include <dev/mpr/mpi/mpi2.h> +#include <dev/mpr/mpi/mpi2_ioc.h> +#include <dev/mpr/mpi/mpi2_cnfg.h> +#include <dev/mpr/mpi/mpi2_init.h> +#include <dev/mpr/mpi/mpi2_tool.h> +#include <dev/mpr/mpr_ioctl.h> +#include <dev/mpr/mprvar.h> +#include <dev/mpr/mpr_table.h> +#include <dev/mpr/mpr_sas.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> + +static d_open_t mpr_open; +static d_close_t mpr_close; +static d_ioctl_t mpr_ioctl_devsw; + +static struct cdevsw mpr_cdevsw = { + .d_version = D_VERSION, + .d_flags = 0, + .d_open = mpr_open, + .d_close = mpr_close, + .d_ioctl = mpr_ioctl_devsw, + .d_name = "mpr", +}; + +typedef int (mpr_user_f)(struct mpr_command *, struct mpr_usr_command *); +static mpr_user_f mpi_pre_ioc_facts; +static mpr_user_f mpi_pre_port_facts; +static mpr_user_f mpi_pre_fw_download; +static mpr_user_f mpi_pre_fw_upload; +static mpr_user_f mpi_pre_sata_passthrough; +static mpr_user_f mpi_pre_smp_passthrough; +static mpr_user_f mpi_pre_config; +static mpr_user_f mpi_pre_sas_io_unit_control; + +static int mpr_user_read_cfg_header(struct mpr_softc *, + struct mpr_cfg_page_req *); +static int mpr_user_read_cfg_page(struct mpr_softc *, + struct mpr_cfg_page_req *, void *); +static int mpr_user_read_extcfg_header(struct mpr_softc *, + struct mpr_ext_cfg_page_req *); +static int mpr_user_read_extcfg_page(struct mpr_softc *, + struct mpr_ext_cfg_page_req *, void *); +static int mpr_user_write_cfg_page(struct mpr_softc *, + struct mpr_cfg_page_req *, void *); +static int mpr_user_setup_request(struct mpr_command *, + struct mpr_usr_command *); +static int mpr_user_command(struct mpr_softc *, struct mpr_usr_command *); + +static int mpr_user_pass_thru(struct mpr_softc *sc, mpr_pass_thru_t *data); +static void mpr_user_get_adapter_data(struct mpr_softc *sc, + mpr_adapter_data_t *data); +static void mpr_user_read_pci_info(struct mpr_softc *sc, + mpr_pci_info_t *data); +static uint8_t mpr_get_fw_diag_buffer_number(struct mpr_softc *sc, + uint32_t unique_id); +static int mpr_post_fw_diag_buffer(struct mpr_softc *sc, + mpr_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code); +static int mpr_release_fw_diag_buffer(struct mpr_softc *sc, + mpr_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code, + uint32_t diag_type); +static int mpr_diag_register(struct mpr_softc *sc, + mpr_fw_diag_register_t *diag_register, uint32_t *return_code); +static int mpr_diag_unregister(struct mpr_softc *sc, + mpr_fw_diag_unregister_t *diag_unregister, uint32_t *return_code); +static int mpr_diag_query(struct mpr_softc *sc, + mpr_fw_diag_query_t *diag_query, uint32_t *return_code); +static int mpr_diag_read_buffer(struct mpr_softc *sc, + mpr_diag_read_buffer_t *diag_read_buffer, uint8_t *ioctl_buf, + uint32_t *return_code); +static int mpr_diag_release(struct mpr_softc *sc, + mpr_fw_diag_release_t *diag_release, uint32_t *return_code); +static int mpr_do_diag_action(struct mpr_softc *sc, uint32_t action, + uint8_t *diag_action, uint32_t length, uint32_t *return_code); +static int mpr_user_diag_action(struct mpr_softc *sc, + mpr_diag_action_t *data); +static void mpr_user_event_query(struct mpr_softc *sc, + mpr_event_query_t *data); +static void mpr_user_event_enable(struct mpr_softc *sc, + mpr_event_enable_t *data); +static int mpr_user_event_report(struct mpr_softc *sc, + mpr_event_report_t *data); +static int mpr_user_reg_access(struct mpr_softc *sc, mpr_reg_access_t *data); +static int mpr_user_btdh(struct mpr_softc *sc, mpr_btdh_mapping_t *data); + +static MALLOC_DEFINE(M_MPRUSER, "mpr_user", "Buffers for mpr(4) ioctls"); + +/* Macros from compat/freebsd32/freebsd32.h */ +#define PTRIN(v) (void *)(uintptr_t)(v) +#define PTROUT(v) (uint32_t)(uintptr_t)(v) + +#define CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0) +#define PTRIN_CP(src,dst,fld) \ + do { (dst).fld = PTRIN((src).fld); } while (0) +#define PTROUT_CP(src,dst,fld) \ + do { (dst).fld = PTROUT((src).fld); } while (0) + +/* + * MPI functions that support IEEE SGLs for SAS3. + */ +static uint8_t ieee_sgl_func_list[] = { + MPI2_FUNCTION_SCSI_IO_REQUEST, + MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH, + MPI2_FUNCTION_SMP_PASSTHROUGH, + MPI2_FUNCTION_SATA_PASSTHROUGH, + MPI2_FUNCTION_FW_UPLOAD, + MPI2_FUNCTION_FW_DOWNLOAD, + MPI2_FUNCTION_TARGET_ASSIST, + MPI2_FUNCTION_TARGET_STATUS_SEND, + MPI2_FUNCTION_TOOLBOX +}; + +int +mpr_attach_user(struct mpr_softc *sc) +{ + int unit; + + unit = device_get_unit(sc->mpr_dev); + sc->mpr_cdev = make_dev(&mpr_cdevsw, unit, UID_ROOT, GID_OPERATOR, + 0640, "mpr%d", unit); + if (sc->mpr_cdev == NULL) { + return (ENOMEM); + } + sc->mpr_cdev->si_drv1 = sc; + return (0); +} + +void +mpr_detach_user(struct mpr_softc *sc) +{ + + /* XXX: do a purge of pending requests? */ + if (sc->mpr_cdev != NULL) + destroy_dev(sc->mpr_cdev); +} + +static int +mpr_open(struct cdev *dev, int flags, int fmt, struct thread *td) +{ + + return (0); +} + +static int +mpr_close(struct cdev *dev, int flags, int fmt, struct thread *td) +{ + + return (0); +} + +static int +mpr_user_read_cfg_header(struct mpr_softc *sc, + struct mpr_cfg_page_req *page_req) +{ + MPI2_CONFIG_PAGE_HEADER *hdr; + struct mpr_config_params params; + int error; + + hdr = ¶ms.hdr.Struct; + params.action = MPI2_CONFIG_ACTION_PAGE_HEADER; + params.page_address = le32toh(page_req->page_address); + hdr->PageVersion = 0; + hdr->PageLength = 0; + hdr->PageNumber = page_req->header.PageNumber; + hdr->PageType = page_req->header.PageType; + params.buffer = NULL; + params.length = 0; + params.callback = NULL; + + if ((error = mpr_read_config_page(sc, ¶ms)) != 0) { + /* + * Leave the request. Without resetting the chip, it's + * still owned by it and we'll just get into trouble + * freeing it now. Mark it as abandoned so that if it + * shows up later it can be freed. + */ + mpr_printf(sc, "read_cfg_header timed out\n"); + return (ETIMEDOUT); + } + + page_req->ioc_status = htole16(params.status); + if ((page_req->ioc_status & MPI2_IOCSTATUS_MASK) == + MPI2_IOCSTATUS_SUCCESS) { + bcopy(hdr, &page_req->header, sizeof(page_req->header)); + } + + return (0); +} + +static int +mpr_user_read_cfg_page(struct mpr_softc *sc, + struct mpr_cfg_page_req *page_req, + void *buf) +{ + MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr; + struct mpr_config_params params; + int error; + + reqhdr = buf; + hdr = ¶ms.hdr.Struct; + hdr->PageVersion = reqhdr->PageVersion; + hdr->PageLength = reqhdr->PageLength; + hdr->PageNumber = reqhdr->PageNumber; + hdr->PageType = reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK; + params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + params.page_address = le32toh(page_req->page_address); + params.buffer = buf; + params.length = le32toh(page_req->len); + params.callback = NULL; + + if ((error = mpr_read_config_page(sc, ¶ms)) != 0) { + mpr_printf(sc, "mpr_user_read_cfg_page timed out\n"); + return (ETIMEDOUT); + } + + page_req->ioc_status = htole16(params.status); + return (0); +} + +static int +mpr_user_read_extcfg_header(struct mpr_softc *sc, + struct mpr_ext_cfg_page_req *ext_page_req) +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr; + struct mpr_config_params params; + int error; + + hdr = ¶ms.hdr.Ext; + params.action = MPI2_CONFIG_ACTION_PAGE_HEADER; + hdr->PageVersion = ext_page_req->header.PageVersion; + hdr->PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + hdr->ExtPageLength = 0; + hdr->PageNumber = ext_page_req->header.PageNumber; + hdr->ExtPageType = ext_page_req->header.ExtPageType; + params.page_address = le32toh(ext_page_req->page_address); + if ((error = mpr_read_config_page(sc, ¶ms)) != 0) { + /* + * Leave the request. Without resetting the chip, it's + * still owned by it and we'll just get into trouble + * freeing it now. Mark it as abandoned so that if it + * shows up later it can be freed. + */ + mpr_printf(sc, "mpr_user_read_extcfg_header timed out\n"); + return (ETIMEDOUT); + } + + ext_page_req->ioc_status = htole16(params.status); + if ((ext_page_req->ioc_status & MPI2_IOCSTATUS_MASK) == + MPI2_IOCSTATUS_SUCCESS) { + ext_page_req->header.PageVersion = hdr->PageVersion; + ext_page_req->header.PageNumber = hdr->PageNumber; + ext_page_req->header.PageType = hdr->PageType; + ext_page_req->header.ExtPageLength = hdr->ExtPageLength; + ext_page_req->header.ExtPageType = hdr->ExtPageType; + } + + return (0); +} + +static int +mpr_user_read_extcfg_page(struct mpr_softc *sc, + struct mpr_ext_cfg_page_req *ext_page_req, void *buf) +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER *reqhdr, *hdr; + struct mpr_config_params params; + int error; + + reqhdr = buf; + hdr = ¶ms.hdr.Ext; + params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + params.page_address = le32toh(ext_page_req->page_address); + hdr->PageVersion = reqhdr->PageVersion; + hdr->PageNumber = reqhdr->PageNumber; + hdr->PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + hdr->ExtPageType = reqhdr->ExtPageType; + hdr->ExtPageLength = reqhdr->ExtPageLength; + params.buffer = buf; + params.length = le32toh(ext_page_req->len); + params.callback = NULL; + + if ((error = mpr_read_config_page(sc, ¶ms)) != 0) { + mpr_printf(sc, "mpr_user_read_extcfg_page timed out\n"); + return (ETIMEDOUT); + } + + ext_page_req->ioc_status = htole16(params.status); + return (0); +} + +static int +mpr_user_write_cfg_page(struct mpr_softc *sc, + struct mpr_cfg_page_req *page_req, void *buf) +{ + MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr; + struct mpr_config_params params; + u_int hdr_attr; + int error; + + reqhdr = buf; + hdr = ¶ms.hdr.Struct; + hdr_attr = reqhdr->PageType & MPI2_CONFIG_PAGEATTR_MASK; + if (hdr_attr != MPI2_CONFIG_PAGEATTR_CHANGEABLE && + hdr_attr != MPI2_CONFIG_PAGEATTR_PERSISTENT) { + mpr_printf(sc, "page type 0x%x not changeable\n", + reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK); + return (EINVAL); + } + + /* + * There isn't any point in restoring stripped out attributes + * if you then mask them going down to issue the request. + */ + + hdr->PageVersion = reqhdr->PageVersion; + hdr->PageLength = reqhdr->PageLength; + hdr->PageNumber = reqhdr->PageNumber; + hdr->PageType = reqhdr->PageType; + params.action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; + params.page_address = le32toh(page_req->page_address); + params.buffer = buf; + params.length = le32toh(page_req->len); + params.callback = NULL; + + if ((error = mpr_write_config_page(sc, ¶ms)) != 0) { + mpr_printf(sc, "mpr_write_cfg_page timed out\n"); + return (ETIMEDOUT); + } + + page_req->ioc_status = htole16(params.status); + return (0); +} + +void +mpr_init_sge(struct mpr_command *cm, void *req, void *sge) +{ + int off, space; + + space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4; + off = (uintptr_t)sge - (uintptr_t)req; + + KASSERT(off < space, ("bad pointers %p %p, off %d, space %d", + req, sge, off, space)); + + cm->cm_sge = sge; + cm->cm_sglsize = space - off; +} + +/* + * Prepare the mpr_command for an IOC_FACTS request. + */ +static int +mpi_pre_ioc_facts(struct mpr_command *cm, struct mpr_usr_command *cmd) +{ + MPI2_IOC_FACTS_REQUEST *req = (void *)cm->cm_req; + MPI2_IOC_FACTS_REPLY *rpl; + + if (cmd->req_len != sizeof *req) + return (EINVAL); + if (cmd->rpl_len != sizeof *rpl) + return (EINVAL); + + cm->cm_sge = NULL; + cm->cm_sglsize = 0; + return (0); +} + +/* + * Prepare the mpr_command for a PORT_FACTS request. + */ +static int +mpi_pre_port_facts(struct mpr_command *cm, struct mpr_usr_command *cmd) +{ + MPI2_PORT_FACTS_REQUEST *req = (void *)cm->cm_req; + MPI2_PORT_FACTS_REPLY *rpl; + + if (cmd->req_len != sizeof *req) + return (EINVAL); + if (cmd->rpl_len != sizeof *rpl) + return (EINVAL); + + cm->cm_sge = NULL; + cm->cm_sglsize = 0; + return (0); +} + +/* + * Prepare the mpr_command for a FW_DOWNLOAD request. + */ +static int +mpi_pre_fw_download(struct mpr_command *cm, struct mpr_usr_command *cmd) +{ + MPI25_FW_DOWNLOAD_REQUEST *req = (void *)cm->cm_req; + MPI2_FW_DOWNLOAD_REPLY *rpl; + int error; + + if (cmd->req_len != sizeof *req) + return (EINVAL); + if (cmd->rpl_len != sizeof *rpl) + return (EINVAL); + + if (cmd->len == 0) + return (EINVAL); + + error = copyin(cmd->buf, cm->cm_data, cmd->len); + if (error != 0) + return (error); + + mpr_init_sge(cm, req, &req->SGL); + + /* + * For now, the F/W image must be provided in a single request. + */ + if ((req->MsgFlags & MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT) == 0) + return (EINVAL); + if (req->TotalImageSize != cmd->len) + return (EINVAL); + + req->ImageOffset = 0; + req->ImageSize = cmd->len; + + cm->cm_flags |= MPR_CM_FLAGS_DATAOUT; + + return (mpr_push_ieee_sge(cm, &req->SGL, 0)); +} + +/* + * Prepare the mpr_command for a FW_UPLOAD request. + */ +static int +mpi_pre_fw_upload(struct mpr_command *cm, struct mpr_usr_command *cmd) +{ + MPI25_FW_UPLOAD_REQUEST *req = (void *)cm->cm_req; + MPI2_FW_UPLOAD_REPLY *rpl; + + if (cmd->req_len != sizeof *req) + return (EINVAL); + if (cmd->rpl_len != sizeof *rpl) + return (EINVAL); + + mpr_init_sge(cm, req, &req->SGL); + if (cmd->len == 0) { + /* Perhaps just asking what the size of the fw is? */ + return (0); + } + + req->ImageOffset = 0; + req->ImageSize = cmd->len; + + return (mpr_push_ieee_sge(cm, &req->SGL, 0)); +} + +/* + * Prepare the mpr_command for a SATA_PASSTHROUGH request. + */ +static int +mpi_pre_sata_passthrough(struct mpr_command *cm, struct mpr_usr_command *cmd) +{ + MPI2_SATA_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req; + MPI2_SATA_PASSTHROUGH_REPLY *rpl; + + if (cmd->req_len != sizeof *req) + return (EINVAL); + if (cmd->rpl_len != sizeof *rpl) + return (EINVAL); + + mpr_init_sge(cm, req, &req->SGL); + return (0); +} + +/* + * Prepare the mpr_command for a SMP_PASSTHROUGH request. + */ +static int +mpi_pre_smp_passthrough(struct mpr_command *cm, struct mpr_usr_command *cmd) +{ + MPI2_SMP_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req; + MPI2_SMP_PASSTHROUGH_REPLY *rpl; + + if (cmd->req_len != sizeof *req) + return (EINVAL); + if (cmd->rpl_len != sizeof *rpl) + return (EINVAL); + + mpr_init_sge(cm, req, &req->SGL); + return (0); +} + +/* + * Prepare the mpr_command for a CONFIG request. + */ +static int +mpi_pre_config(struct mpr_command *cm, struct mpr_usr_command *cmd) +{ + MPI2_CONFIG_REQUEST *req = (void *)cm->cm_req; + MPI2_CONFIG_REPLY *rpl; + + if (cmd->req_len != sizeof *req) + return (EINVAL); + if (cmd->rpl_len != sizeof *rpl) + return (EINVAL); + + mpr_init_sge(cm, req, &req->PageBufferSGE); + return (0); +} + +/* + * Prepare the mpr_command for a SAS_IO_UNIT_CONTROL request. + */ +static int +mpi_pre_sas_io_unit_control(struct mpr_command *cm, + struct mpr_usr_command *cmd) +{ + + cm->cm_sge = NULL; + cm->cm_sglsize = 0; + return (0); +} + +/* + * A set of functions to prepare an mpr_command for the various + * supported requests. + */ +struct mpr_user_func { + U8 Function; + mpr_user_f *f_pre; +} mpr_user_func_list[] = { + { MPI2_FUNCTION_IOC_FACTS, mpi_pre_ioc_facts }, + { MPI2_FUNCTION_PORT_FACTS, mpi_pre_port_facts }, + { MPI2_FUNCTION_FW_DOWNLOAD, mpi_pre_fw_download }, + { MPI2_FUNCTION_FW_UPLOAD, mpi_pre_fw_upload }, + { MPI2_FUNCTION_SATA_PASSTHROUGH, mpi_pre_sata_passthrough }, + { MPI2_FUNCTION_SMP_PASSTHROUGH, mpi_pre_smp_passthrough}, + { MPI2_FUNCTION_CONFIG, mpi_pre_config}, + { MPI2_FUNCTION_SAS_IO_UNIT_CONTROL, mpi_pre_sas_io_unit_control }, + { 0xFF, NULL } /* list end */ +}; + +static int +mpr_user_setup_request(struct mpr_command *cm, struct mpr_usr_command *cmd) +{ + MPI2_REQUEST_HEADER *hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; + struct mpr_user_func *f; + + for (f = mpr_user_func_list; f->f_pre != NULL; f++) { + if (hdr->Function == f->Function) + return (f->f_pre(cm, cmd)); + } + return (EINVAL); +} + +static int +mpr_user_command(struct mpr_softc *sc, struct mpr_usr_command *cmd) +{ + MPI2_REQUEST_HEADER *hdr; + MPI2_DEFAULT_REPLY *rpl; + void *buf = NULL; + struct mpr_command *cm = NULL; + int err = 0; + int sz; + + mpr_lock(sc); + cm = mpr_alloc_command(sc); + + if (cm == NULL) { + mpr_printf(sc, "%s: no mpr requests\n", __func__); + err = ENOMEM; + goto Ret; + } + mpr_unlock(sc); + + hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; + + mpr_dprint(sc, MPR_USER, "%s: req %p %d rpl %p %d\n", __func__, + cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len); + + if (cmd->req_len > (int)sc->facts->IOCRequestFrameSize * 4) { + err = EINVAL; + goto RetFreeUnlocked; + } + err = copyin(cmd->req, hdr, cmd->req_len); + if (err != 0) + goto RetFreeUnlocked; + + mpr_dprint(sc, MPR_USER, "%s: Function %02X MsgFlags %02X\n", __func__, + hdr->Function, hdr->MsgFlags); + + if (cmd->len > 0) { + buf = malloc(cmd->len, M_MPRUSER, M_WAITOK|M_ZERO); + if (!buf) { + mpr_printf(sc, "Cannot allocate memory %s %d\n", + __func__, __LINE__); + return (ENOMEM); + } + cm->cm_data = buf; + cm->cm_length = cmd->len; + } else { + cm->cm_data = NULL; + cm->cm_length = 0; + } + + cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + + err = mpr_user_setup_request(cm, cmd); + if (err == EINVAL) { + mpr_printf(sc, "%s: unsupported parameter or unsupported " + "function in request (function = 0x%X)\n", __func__, + hdr->Function); + } + if (err != 0) + goto RetFreeUnlocked; + + mpr_lock(sc); + err = mpr_wait_command(sc, cm, 30, CAN_SLEEP); + + if (err) { + mpr_printf(sc, "%s: invalid request: error %d\n", + __func__, err); + goto Ret; + } + + rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; + if (rpl != NULL) + sz = rpl->MsgLength * 4; + else + sz = 0; + + if (sz > cmd->rpl_len) { + mpr_printf(sc, "%s: user reply buffer (%d) smaller than " + "returned buffer (%d)\n", __func__, cmd->rpl_len, sz); + sz = cmd->rpl_len; + } + + mpr_unlock(sc); + copyout(rpl, cmd->rpl, sz); + if (buf != NULL) + copyout(buf, cmd->buf, cmd->len); + mpr_dprint(sc, MPR_USER, "%s: reply size %d\n", __func__, sz); + +RetFreeUnlocked: + mpr_lock(sc); + if (cm != NULL) + mpr_free_command(sc, cm); +Ret: + mpr_unlock(sc); + if (buf != NULL) + free(buf, M_MPRUSER); + return (err); +} + +static int +mpr_user_pass_thru(struct mpr_softc *sc, mpr_pass_thru_t *data) +{ + MPI2_REQUEST_HEADER *hdr, tmphdr; + MPI2_DEFAULT_REPLY *rpl; + struct mpr_command *cm = NULL; + int i, err = 0, dir = 0, sz; + uint8_t tool, function = 0; + u_int sense_len; + struct mprsas_target *targ = NULL; + + /* + * Only allow one passthru command at a time. Use the MPR_FLAGS_BUSY + * bit to denote that a passthru is being processed. + */ + mpr_lock(sc); + if (sc->mpr_flags & MPR_FLAGS_BUSY) { + mpr_dprint(sc, MPR_USER, "%s: Only one passthru command " + "allowed at a single time.", __func__); + mpr_unlock(sc); + return (EBUSY); + } + sc->mpr_flags |= MPR_FLAGS_BUSY; + mpr_unlock(sc); + + /* + * Do some validation on data direction. Valid cases are: + * 1) DataSize is 0 and direction is NONE + * 2) DataSize is non-zero and one of: + * a) direction is READ or + * b) direction is WRITE or + * c) direction is BOTH and DataOutSize is non-zero + * If valid and the direction is BOTH, change the direction to READ. + * if valid and the direction is not BOTH, make sure DataOutSize is 0. + */ + if (((data->DataSize == 0) && + (data->DataDirection == MPR_PASS_THRU_DIRECTION_NONE)) || + ((data->DataSize != 0) && + ((data->DataDirection == MPR_PASS_THRU_DIRECTION_READ) || + (data->DataDirection == MPR_PASS_THRU_DIRECTION_WRITE) || + ((data->DataDirection == MPR_PASS_THRU_DIRECTION_BOTH) && + (data->DataOutSize != 0))))) { + if (data->DataDirection == MPR_PASS_THRU_DIRECTION_BOTH) + data->DataDirection = MPR_PASS_THRU_DIRECTION_READ; + else + data->DataOutSize = 0; + } else + return (EINVAL); + + mpr_dprint(sc, MPR_USER, "%s: req 0x%jx %d rpl 0x%jx %d " + "data in 0x%jx %d data out 0x%jx %d data dir %d\n", __func__, + data->PtrRequest, data->RequestSize, data->PtrReply, + data->ReplySize, data->PtrData, data->DataSize, + data->PtrDataOut, data->DataOutSize, data->DataDirection); + + /* + * copy in the header so we know what we're dealing with before we + * commit to allocating a command for it. + */ + err = copyin(PTRIN(data->PtrRequest), &tmphdr, data->RequestSize); + if (err != 0) + goto RetFreeUnlocked; + + if (data->RequestSize > (int)sc->facts->IOCRequestFrameSize * 4) { + err = EINVAL; + goto RetFreeUnlocked; + } + + function = tmphdr.Function; + mpr_dprint(sc, MPR_USER, "%s: Function %02X MsgFlags %02X\n", __func__, + function, tmphdr.MsgFlags); + + /* + * Handle a passthru TM request. + */ + if (function == MPI2_FUNCTION_SCSI_TASK_MGMT) { + MPI2_SCSI_TASK_MANAGE_REQUEST *task; + + mpr_lock(sc); + cm = mprsas_alloc_tm(sc); + if (cm == NULL) { + err = EINVAL; + goto Ret; + } + + /* Copy the header in. Only a small fixup is needed. */ + task = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; + bcopy(&tmphdr, task, data->RequestSize); + task->TaskMID = cm->cm_desc.Default.SMID; + + cm->cm_data = NULL; + cm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; + cm->cm_complete = NULL; + cm->cm_complete_data = NULL; + + err = mpr_wait_command(sc, cm, 30, CAN_SLEEP); + + if (err != 0) { + err = EIO; + mpr_dprint(sc, MPR_FAULT, "%s: task management failed", + __func__); + } + /* + * Copy the reply data and sense data to user space. + */ + if (cm->cm_reply != NULL) { + rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; + sz = rpl->MsgLength * 4; + + if (sz > data->ReplySize) { + mpr_printf(sc, "%s: user reply buffer (%d) " + "smaller than returned buffer (%d)\n", + __func__, data->ReplySize, sz); + } + mpr_unlock(sc); + copyout(cm->cm_reply, PTRIN(data->PtrReply), + data->ReplySize); + mpr_lock(sc); + } + mprsas_free_tm(sc, cm); + goto Ret; + } + + mpr_lock(sc); + cm = mpr_alloc_command(sc); + + if (cm == NULL) { + mpr_printf(sc, "%s: no mpr requests\n", __func__); + err = ENOMEM; + goto Ret; + } + mpr_unlock(sc); + + hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; + bcopy(&tmphdr, hdr, data->RequestSize); + + /* + * Do some checking to make sure the IOCTL request contains a valid + * request. Then set the SGL info. + */ + mpr_init_sge(cm, hdr, (void *)((uint8_t *)hdr + data->RequestSize)); + + /* + * Set up for read, write or both. From check above, DataOutSize will + * be 0 if direction is READ or WRITE, but it will have some non-zero + * value if the direction is BOTH. So, just use the biggest size to get + * the cm_data buffer size. If direction is BOTH, 2 SGLs need to be set + * up; the first is for the request and the second will contain the + * response data. cm_out_len needs to be set here and this will be used + * when the SGLs are set up. + */ + cm->cm_data = NULL; + cm->cm_length = MAX(data->DataSize, data->DataOutSize); + cm->cm_out_len = data->DataOutSize; + cm->cm_flags = 0; + if (cm->cm_length != 0) { + cm->cm_data = malloc(cm->cm_length, M_MPRUSER, M_WAITOK | + M_ZERO); + if (cm->cm_data == NULL) { + mpr_dprint(sc, MPR_FAULT, "%s: alloc failed for IOCTL " + "passthru length %d\n", __func__, cm->cm_length); + } else { + cm->cm_flags = MPR_CM_FLAGS_DATAIN; + if (data->DataOutSize) { + cm->cm_flags |= MPR_CM_FLAGS_DATAOUT; + err = copyin(PTRIN(data->PtrDataOut), + cm->cm_data, data->DataOutSize); + } else if (data->DataDirection == + MPR_PASS_THRU_DIRECTION_WRITE) { + cm->cm_flags = MPR_CM_FLAGS_DATAOUT; + err = copyin(PTRIN(data->PtrData), + cm->cm_data, data->DataSize); + } + if (err != 0) + mpr_dprint(sc, MPR_FAULT, "%s: failed to copy " + "IOCTL data from user space\n", __func__); + } + } + /* + * Set this flag only if processing a command that does not need an + * IEEE SGL. The CLI Tool within the Toolbox uses IEEE SGLs, so clear + * the flag only for that tool if processing a Toolbox function. + */ + cm->cm_flags |= MPR_CM_FLAGS_SGE_SIMPLE; + for (i = 0; i < sizeof (ieee_sgl_func_list); i++) { + if (function == ieee_sgl_func_list[i]) { + if (function == MPI2_FUNCTION_TOOLBOX) + { + tool = (uint8_t)hdr->FunctionDependent1; + if (tool != MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL) + break; + } + cm->cm_flags &= ~MPR_CM_FLAGS_SGE_SIMPLE; + break; + } + } + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + + /* + * Set up Sense buffer and SGL offset for IO passthru. SCSI IO request + * uses SCSI IO or Fast Path SCSI IO descriptor. + */ + if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) || + (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { + MPI2_SCSI_IO_REQUEST *scsi_io_req; + + scsi_io_req = (MPI2_SCSI_IO_REQUEST *)hdr; + /* + * Put SGE for data and data_out buffer at the end of + * scsi_io_request message header (64 bytes in total). + * Following above SGEs, the residual space will be used by + * sense data. + */ + scsi_io_req->SenseBufferLength = (uint8_t)(data->RequestSize - + 64); + scsi_io_req->SenseBufferLowAddress = + htole32(cm->cm_sense_busaddr); + + /* + * Set SGLOffset0 value. This is the number of dwords that SGL + * is offset from the beginning of MPI2_SCSI_IO_REQUEST struct. + */ + scsi_io_req->SGLOffset0 = 24; + + /* + * Setup descriptor info. RAID passthrough must use the + * default request descriptor which is already set, so if this + * is a SCSI IO request, change the descriptor to SCSI IO or + * Fast Path SCSI IO. Also, if this is a SCSI IO request, + * handle the reply in the mprsas_scsio_complete function. + */ + if (function == MPI2_FUNCTION_SCSI_IO_REQUEST) { + targ = mprsas_find_target_by_handle(sc->sassc, 0, + scsi_io_req->DevHandle); + + if (!targ) { + printf("No Target found for handle %d\n", + scsi_io_req->DevHandle); + err = EINVAL; + goto RetFreeUnlocked; + } + + if (targ->scsi_req_desc_type == + MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO) { + cm->cm_desc.FastPathSCSIIO.RequestFlags = + MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; + cm->cm_desc.FastPathSCSIIO.DevHandle = + scsi_io_req->DevHandle; + scsi_io_req->IoFlags |= + MPI25_SCSIIO_IOFLAGS_FAST_PATH; + } else { + cm->cm_desc.SCSIIO.RequestFlags = + MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; + cm->cm_desc.SCSIIO.DevHandle = + scsi_io_req->DevHandle; + } + + /* + * Make sure the DevHandle is not 0 because this is a + * likely error. + */ + if (scsi_io_req->DevHandle == 0) { + err = EINVAL; + goto RetFreeUnlocked; + } + } + } + + mpr_lock(sc); + + err = mpr_wait_command(sc, cm, 30, CAN_SLEEP); + + if (err) { + mpr_printf(sc, "%s: invalid request: error %d\n", __func__, + err); + mpr_unlock(sc); + goto RetFreeUnlocked; + } + + /* + * Sync the DMA data, if any. Then copy the data to user space. + */ + if (cm->cm_data != NULL) { + if (cm->cm_flags & MPR_CM_FLAGS_DATAIN) + dir = BUS_DMASYNC_POSTREAD; + else if (cm->cm_flags & MPR_CM_FLAGS_DATAOUT) + dir = BUS_DMASYNC_POSTWRITE;; + bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); + bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); + + if (cm->cm_flags & MPR_CM_FLAGS_DATAIN) { + mpr_unlock(sc); + err = copyout(cm->cm_data, + PTRIN(data->PtrData), data->DataSize); + mpr_lock(sc); + if (err != 0) + mpr_dprint(sc, MPR_FAULT, "%s: failed to copy " + "IOCTL data to user space\n", __func__); + } + } + + /* + * Copy the reply data and sense data to user space. + */ + if (cm->cm_reply != NULL) { + rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; + sz = rpl->MsgLength * 4; + + if (sz > data->ReplySize) { + mpr_printf(sc, "%s: user reply buffer (%d) smaller " + "than returned buffer (%d)\n", __func__, + data->ReplySize, sz); + } + mpr_unlock(sc); + copyout(cm->cm_reply, PTRIN(data->PtrReply), data->ReplySize); + mpr_lock(sc); + + if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) || + (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { + if (((MPI2_SCSI_IO_REPLY *)rpl)->SCSIState & + MPI2_SCSI_STATE_AUTOSENSE_VALID) { + sense_len = + MIN((le32toh(((MPI2_SCSI_IO_REPLY *)rpl)-> + SenseCount)), sizeof(struct + scsi_sense_data)); + mpr_unlock(sc); + copyout(cm->cm_sense, cm->cm_req + 64, + sense_len); + mpr_lock(sc); + } + } + } + mpr_unlock(sc); + +RetFreeUnlocked: + mpr_lock(sc); + + if (cm != NULL) { + if (cm->cm_data) + free(cm->cm_data, M_MPRUSER); + mpr_free_command(sc, cm); + } +Ret: + sc->mpr_flags &= ~MPR_FLAGS_BUSY; + mpr_unlock(sc); + + return (err); +} + +static void +mpr_user_get_adapter_data(struct mpr_softc *sc, mpr_adapter_data_t *data) +{ + Mpi2ConfigReply_t mpi_reply; + Mpi2BiosPage3_t config_page; + + /* + * Use the PCI interface functions to get the Bus, Device, and Function + * information. + */ + data->PciInformation.u.bits.BusNumber = pci_get_bus(sc->mpr_dev); + data->PciInformation.u.bits.DeviceNumber = pci_get_slot(sc->mpr_dev); + data->PciInformation.u.bits.FunctionNumber = + pci_get_function(sc->mpr_dev); + + /* + * Get the FW version that should already be saved in IOC Facts. + */ + data->MpiFirmwareVersion = sc->facts->FWVersion.Word; + + /* + * General device info. + */ + data->AdapterType = MPRIOCTL_ADAPTER_TYPE_SAS3; + data->PCIDeviceHwId = pci_get_device(sc->mpr_dev); + data->PCIDeviceHwRev = pci_read_config(sc->mpr_dev, PCIR_REVID, 1); + data->SubSystemId = pci_get_subdevice(sc->mpr_dev); + data->SubsystemVendorId = pci_get_subvendor(sc->mpr_dev); + + /* + * Get the driver version. + */ + strcpy((char *)&data->DriverVersion[0], MPR_DRIVER_VERSION); + + /* + * Need to get BIOS Config Page 3 for the BIOS Version. + */ + data->BiosVersion = 0; + mpr_lock(sc); + if (mpr_config_get_bios_pg3(sc, &mpi_reply, &config_page)) + printf("%s: Error while retrieving BIOS Version\n", __func__); + else + data->BiosVersion = config_page.BiosVersion; + mpr_unlock(sc); +} + +static void +mpr_user_read_pci_info(struct mpr_softc *sc, mpr_pci_info_t *data) +{ + int i; + + /* + * Use the PCI interface functions to get the Bus, Device, and Function + * information. + */ + data->BusNumber = pci_get_bus(sc->mpr_dev); + data->DeviceNumber = pci_get_slot(sc->mpr_dev); + data->FunctionNumber = pci_get_function(sc->mpr_dev); + + /* + * Now get the interrupt vector and the pci header. The vector can + * only be 0 right now. The header is the first 256 bytes of config + * space. + */ + data->InterruptVector = 0; + for (i = 0; i < sizeof (data->PciHeader); i++) { + data->PciHeader[i] = pci_read_config(sc->mpr_dev, i, 1); + } +} + +static uint8_t +mpr_get_fw_diag_buffer_number(struct mpr_softc *sc, uint32_t unique_id) +{ + uint8_t index; + + for (index = 0; index < MPI2_DIAG_BUF_TYPE_COUNT; index++) { + if (sc->fw_diag_buffer_list[index].unique_id == unique_id) { + return (index); + } + } + + return (MPR_FW_DIAGNOSTIC_UID_NOT_FOUND); +} + +static int +mpr_post_fw_diag_buffer(struct mpr_softc *sc, + mpr_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code) +{ + MPI2_DIAG_BUFFER_POST_REQUEST *req; + MPI2_DIAG_BUFFER_POST_REPLY *reply; + struct mpr_command *cm = NULL; + int i, status; + + /* + * If buffer is not enabled, just leave. + */ + *return_code = MPR_FW_DIAG_ERROR_POST_FAILED; + if (!pBuffer->enabled) { + return (MPR_DIAG_FAILURE); + } + + /* + * Clear some flags initially. + */ + pBuffer->force_release = FALSE; + pBuffer->valid_data = FALSE; + pBuffer->owned_by_firmware = FALSE; + + /* + * Get a command. + */ + cm = mpr_alloc_command(sc); + if (cm == NULL) { + mpr_printf(sc, "%s: no mpr requests\n", __func__); + return (MPR_DIAG_FAILURE); + } + + /* + * Build the request for releasing the FW Diag Buffer and send it. + */ + req = (MPI2_DIAG_BUFFER_POST_REQUEST *)cm->cm_req; + req->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; + req->BufferType = pBuffer->buffer_type; + req->ExtendedType = pBuffer->extended_type; + req->BufferLength = pBuffer->size; + for (i = 0; i < (sizeof(req->ProductSpecific) / 4); i++) + req->ProductSpecific[i] = pBuffer->product_specific[i]; + mpr_from_u64(sc->fw_diag_busaddr, &req->BufferAddress); + cm->cm_data = NULL; + cm->cm_length = 0; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_complete_data = NULL; + + /* + * Send command synchronously. + */ + status = mpr_wait_command(sc, cm, 30, CAN_SLEEP); + if (status) { + mpr_printf(sc, "%s: invalid request: error %d\n", __func__, + status); + status = MPR_DIAG_FAILURE; + goto done; + } + + /* + * Process POST reply. + */ + reply = (MPI2_DIAG_BUFFER_POST_REPLY *)cm->cm_reply; + if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) { + status = MPR_DIAG_FAILURE; + mpr_dprint(sc, MPR_FAULT, "%s: post of FW Diag Buffer failed " + "with IOCStatus = 0x%x, IOCLogInfo = 0x%x and " + "TransferLength = 0x%x\n", __func__, reply->IOCStatus, + reply->IOCLogInfo, reply->TransferLength); + goto done; + } + + /* + * Post was successful. + */ + pBuffer->valid_data = TRUE; + pBuffer->owned_by_firmware = TRUE; + *return_code = MPR_FW_DIAG_ERROR_SUCCESS; + status = MPR_DIAG_SUCCESS; + +done: + mpr_free_command(sc, cm); + return (status); +} + +static int +mpr_release_fw_diag_buffer(struct mpr_softc *sc, + mpr_fw_diagnostic_buffer_t *pBuffer, uint32_t *return_code, + uint32_t diag_type) +{ + MPI2_DIAG_RELEASE_REQUEST *req; + MPI2_DIAG_RELEASE_REPLY *reply; + struct mpr_command *cm = NULL; + int status; + + /* + * If buffer is not enabled, just leave. + */ + *return_code = MPR_FW_DIAG_ERROR_RELEASE_FAILED; + if (!pBuffer->enabled) { + mpr_dprint(sc, MPR_USER, "%s: This buffer type is not " + "supported by the IOC", __func__); + return (MPR_DIAG_FAILURE); + } + + /* + * Clear some flags initially. + */ + pBuffer->force_release = FALSE; + pBuffer->valid_data = FALSE; + pBuffer->owned_by_firmware = FALSE; + + /* + * Get a command. + */ + cm = mpr_alloc_command(sc); + if (cm == NULL) { + mpr_printf(sc, "%s: no mpr requests\n", __func__); + return (MPR_DIAG_FAILURE); + } + + /* + * Build the request for releasing the FW Diag Buffer and send it. + */ + req = (MPI2_DIAG_RELEASE_REQUEST *)cm->cm_req; + req->Function = MPI2_FUNCTION_DIAG_RELEASE; + req->BufferType = pBuffer->buffer_type; + cm->cm_data = NULL; + cm->cm_length = 0; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_complete_data = NULL; + + /* + * Send command synchronously. + */ + status = mpr_wait_command(sc, cm, 30, CAN_SLEEP); + if (status) { + mpr_printf(sc, "%s: invalid request: error %d\n", __func__, + status); + status = MPR_DIAG_FAILURE; + goto done; + } + + /* + * Process RELEASE reply. + */ + reply = (MPI2_DIAG_RELEASE_REPLY *)cm->cm_reply; + if ((reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) || + pBuffer->owned_by_firmware) { + status = MPR_DIAG_FAILURE; + mpr_dprint(sc, MPR_FAULT, "%s: release of FW Diag Buffer " + "failed with IOCStatus = 0x%x and IOCLogInfo = 0x%x\n", + __func__, reply->IOCStatus, reply->IOCLogInfo); + goto done; + } + + /* + * Release was successful. + */ + *return_code = MPR_FW_DIAG_ERROR_SUCCESS; + status = MPR_DIAG_SUCCESS; + + /* + * If this was for an UNREGISTER diag type command, clear the unique ID. + */ + if (diag_type == MPR_FW_DIAG_TYPE_UNREGISTER) { + pBuffer->unique_id = MPR_FW_DIAG_INVALID_UID; + } + +done: + return (status); +} + +static int +mpr_diag_register(struct mpr_softc *sc, + mpr_fw_diag_register_t *diag_register, uint32_t *return_code) +{ + mpr_fw_diagnostic_buffer_t *pBuffer; + uint8_t extended_type, buffer_type, i; + uint32_t buffer_size; + uint32_t unique_id; + int status; + + extended_type = diag_register->ExtendedType; + buffer_type = diag_register->BufferType; + buffer_size = diag_register->RequestedBufferSize; + unique_id = diag_register->UniqueId; + + /* + * Check for valid buffer type + */ + if (buffer_type >= MPI2_DIAG_BUF_TYPE_COUNT) { + *return_code = MPR_FW_DIAG_ERROR_INVALID_PARAMETER; + return (MPR_DIAG_FAILURE); + } + + /* + * Get the current buffer and look up the unique ID. The unique ID + * should not be found. If it is, the ID is already in use. + */ + i = mpr_get_fw_diag_buffer_number(sc, unique_id); + pBuffer = &sc->fw_diag_buffer_list[buffer_type]; + if (i != MPR_FW_DIAGNOSTIC_UID_NOT_FOUND) { + *return_code = MPR_FW_DIAG_ERROR_INVALID_UID; + return (MPR_DIAG_FAILURE); + } + + /* + * The buffer's unique ID should not be registered yet, and the given + * unique ID cannot be 0. + */ + if ((pBuffer->unique_id != MPR_FW_DIAG_INVALID_UID) || + (unique_id == MPR_FW_DIAG_INVALID_UID)) { + *return_code = MPR_FW_DIAG_ERROR_INVALID_UID; + return (MPR_DIAG_FAILURE); + } + + /* + * If this buffer is already posted as immediate, just change owner. + */ + if (pBuffer->immediate && pBuffer->owned_by_firmware && + (pBuffer->unique_id == MPR_FW_DIAG_INVALID_UID)) { + pBuffer->immediate = FALSE; + pBuffer->unique_id = unique_id; + return (MPR_DIAG_SUCCESS); + } + + /* + * Post a new buffer after checking if it's enabled. The DMA buffer + * that is allocated will be contiguous (nsegments = 1). + */ + if (!pBuffer->enabled) { + *return_code = MPR_FW_DIAG_ERROR_NO_BUFFER; + return (MPR_DIAG_FAILURE); + } + if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ + 1, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + buffer_size, /* maxsize */ + 1, /* nsegments */ + buffer_size, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->fw_diag_dmat)) { + device_printf(sc->mpr_dev, "Cannot allocate FW diag buffer DMA " + "tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->fw_diag_dmat, (void **)&sc->fw_diag_buffer, + BUS_DMA_NOWAIT, &sc->fw_diag_map)) { + device_printf(sc->mpr_dev, "Cannot allocate FW diag buffer " + "memory\n"); + return (ENOMEM); + } + bzero(sc->fw_diag_buffer, buffer_size); + bus_dmamap_load(sc->fw_diag_dmat, sc->fw_diag_map, sc->fw_diag_buffer, + buffer_size, mpr_memaddr_cb, &sc->fw_diag_busaddr, 0); + pBuffer->size = buffer_size; + + /* + * Copy the given info to the diag buffer and post the buffer. + */ + pBuffer->buffer_type = buffer_type; + pBuffer->immediate = FALSE; + if (buffer_type == MPI2_DIAG_BUF_TYPE_TRACE) { + for (i = 0; i < (sizeof (pBuffer->product_specific) / 4); + i++) { + pBuffer->product_specific[i] = + diag_register->ProductSpecific[i]; + } + } + pBuffer->extended_type = extended_type; + pBuffer->unique_id = unique_id; + status = mpr_post_fw_diag_buffer(sc, pBuffer, return_code); + + /* + * In case there was a failure, free the DMA buffer. + */ + if (status == MPR_DIAG_FAILURE) { + if (sc->fw_diag_busaddr != 0) + bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map); + if (sc->fw_diag_buffer != NULL) + bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer, + sc->fw_diag_map); + if (sc->fw_diag_dmat != NULL) + bus_dma_tag_destroy(sc->fw_diag_dmat); + } + + return (status); +} + +static int +mpr_diag_unregister(struct mpr_softc *sc, + mpr_fw_diag_unregister_t *diag_unregister, uint32_t *return_code) +{ + mpr_fw_diagnostic_buffer_t *pBuffer; + uint8_t i; + uint32_t unique_id; + int status; + + unique_id = diag_unregister->UniqueId; + + /* + * Get the current buffer and look up the unique ID. The unique ID + * should be there. + */ + i = mpr_get_fw_diag_buffer_number(sc, unique_id); + if (i == MPR_FW_DIAGNOSTIC_UID_NOT_FOUND) { + *return_code = MPR_FW_DIAG_ERROR_INVALID_UID; + return (MPR_DIAG_FAILURE); + } + + pBuffer = &sc->fw_diag_buffer_list[i]; + + /* + * Try to release the buffer from FW before freeing it. If release + * fails, don't free the DMA buffer in case FW tries to access it + * later. If buffer is not owned by firmware, can't release it. + */ + if (!pBuffer->owned_by_firmware) { + status = MPR_DIAG_SUCCESS; + } else { + status = mpr_release_fw_diag_buffer(sc, pBuffer, return_code, + MPR_FW_DIAG_TYPE_UNREGISTER); + } + + /* + * At this point, return the current status no matter what happens with + * the DMA buffer. + */ + pBuffer->unique_id = MPR_FW_DIAG_INVALID_UID; + if (status == MPR_DIAG_SUCCESS) { + if (sc->fw_diag_busaddr != 0) + bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map); + if (sc->fw_diag_buffer != NULL) + bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer, + sc->fw_diag_map); + if (sc->fw_diag_dmat != NULL) + bus_dma_tag_destroy(sc->fw_diag_dmat); + } + + return (status); +} + +static int +mpr_diag_query(struct mpr_softc *sc, mpr_fw_diag_query_t *diag_query, + uint32_t *return_code) +{ + mpr_fw_diagnostic_buffer_t *pBuffer; + uint8_t i; + uint32_t unique_id; + + unique_id = diag_query->UniqueId; + + /* + * If ID is valid, query on ID. + * If ID is invalid, query on buffer type. + */ + if (unique_id == MPR_FW_DIAG_INVALID_UID) { + i = diag_query->BufferType; + if (i >= MPI2_DIAG_BUF_TYPE_COUNT) { + *return_code = MPR_FW_DIAG_ERROR_INVALID_UID; + return (MPR_DIAG_FAILURE); + } + } else { + i = mpr_get_fw_diag_buffer_number(sc, unique_id); + if (i == MPR_FW_DIAGNOSTIC_UID_NOT_FOUND) { + *return_code = MPR_FW_DIAG_ERROR_INVALID_UID; + return (MPR_DIAG_FAILURE); + } + } + + /* + * Fill query structure with the diag buffer info. + */ + pBuffer = &sc->fw_diag_buffer_list[i]; + diag_query->BufferType = pBuffer->buffer_type; + diag_query->ExtendedType = pBuffer->extended_type; + if (diag_query->BufferType == MPI2_DIAG_BUF_TYPE_TRACE) { + for (i = 0; i < (sizeof(diag_query->ProductSpecific) / 4); + i++) { + diag_query->ProductSpecific[i] = + pBuffer->product_specific[i]; + } + } + diag_query->TotalBufferSize = pBuffer->size; + diag_query->DriverAddedBufferSize = 0; + diag_query->UniqueId = pBuffer->unique_id; + diag_query->ApplicationFlags = 0; + diag_query->DiagnosticFlags = 0; + + /* + * Set/Clear application flags + */ + if (pBuffer->immediate) { + diag_query->ApplicationFlags &= ~MPR_FW_DIAG_FLAG_APP_OWNED; + } else { + diag_query->ApplicationFlags |= MPR_FW_DIAG_FLAG_APP_OWNED; + } + if (pBuffer->valid_data || pBuffer->owned_by_firmware) { + diag_query->ApplicationFlags |= MPR_FW_DIAG_FLAG_BUFFER_VALID; + } else { + diag_query->ApplicationFlags &= ~MPR_FW_DIAG_FLAG_BUFFER_VALID; + } + if (pBuffer->owned_by_firmware) { + diag_query->ApplicationFlags |= + MPR_FW_DIAG_FLAG_FW_BUFFER_ACCESS; + } else { + diag_query->ApplicationFlags &= + ~MPR_FW_DIAG_FLAG_FW_BUFFER_ACCESS; + } + + return (MPR_DIAG_SUCCESS); +} + +static int +mpr_diag_read_buffer(struct mpr_softc *sc, + mpr_diag_read_buffer_t *diag_read_buffer, uint8_t *ioctl_buf, + uint32_t *return_code) +{ + mpr_fw_diagnostic_buffer_t *pBuffer; + uint8_t i, *pData; + uint32_t unique_id; + int status; + + unique_id = diag_read_buffer->UniqueId; + + /* + * Get the current buffer and look up the unique ID. The unique ID + * should be there. + */ + i = mpr_get_fw_diag_buffer_number(sc, unique_id); + if (i == MPR_FW_DIAGNOSTIC_UID_NOT_FOUND) { + *return_code = MPR_FW_DIAG_ERROR_INVALID_UID; + return (MPR_DIAG_FAILURE); + } + + pBuffer = &sc->fw_diag_buffer_list[i]; + + /* + * Make sure requested read is within limits + */ + if (diag_read_buffer->StartingOffset + diag_read_buffer->BytesToRead > + pBuffer->size) { + *return_code = MPR_FW_DIAG_ERROR_INVALID_PARAMETER; + return (MPR_DIAG_FAILURE); + } + + /* + * Copy the requested data from DMA to the diag_read_buffer. The DMA + * buffer that was allocated is one contiguous buffer. + */ + pData = (uint8_t *)(sc->fw_diag_buffer + + diag_read_buffer->StartingOffset); + if (copyout(pData, ioctl_buf, diag_read_buffer->BytesToRead) != 0) + return (MPR_DIAG_FAILURE); + diag_read_buffer->Status = 0; + + /* + * Set or clear the Force Release flag. + */ + if (pBuffer->force_release) { + diag_read_buffer->Flags |= MPR_FW_DIAG_FLAG_FORCE_RELEASE; + } else { + diag_read_buffer->Flags &= ~MPR_FW_DIAG_FLAG_FORCE_RELEASE; + } + + /* + * If buffer is to be reregistered, make sure it's not already owned by + * firmware first. + */ + status = MPR_DIAG_SUCCESS; + if (!pBuffer->owned_by_firmware) { + if (diag_read_buffer->Flags & MPR_FW_DIAG_FLAG_REREGISTER) { + status = mpr_post_fw_diag_buffer(sc, pBuffer, + return_code); + } + } + + return (status); +} + +static int +mpr_diag_release(struct mpr_softc *sc, mpr_fw_diag_release_t *diag_release, + uint32_t *return_code) +{ + mpr_fw_diagnostic_buffer_t *pBuffer; + uint8_t i; + uint32_t unique_id; + int status; + + unique_id = diag_release->UniqueId; + + /* + * Get the current buffer and look up the unique ID. The unique ID + * should be there. + */ + i = mpr_get_fw_diag_buffer_number(sc, unique_id); + if (i == MPR_FW_DIAGNOSTIC_UID_NOT_FOUND) { + *return_code = MPR_FW_DIAG_ERROR_INVALID_UID; + return (MPR_DIAG_FAILURE); + } + + pBuffer = &sc->fw_diag_buffer_list[i]; + + /* + * If buffer is not owned by firmware, it's already been released. + */ + if (!pBuffer->owned_by_firmware) { + *return_code = MPR_FW_DIAG_ERROR_ALREADY_RELEASED; + return (MPR_DIAG_FAILURE); + } + + /* + * Release the buffer. + */ + status = mpr_release_fw_diag_buffer(sc, pBuffer, return_code, + MPR_FW_DIAG_TYPE_RELEASE); + return (status); +} + +static int +mpr_do_diag_action(struct mpr_softc *sc, uint32_t action, + uint8_t *diag_action, uint32_t length, uint32_t *return_code) +{ + mpr_fw_diag_register_t diag_register; + mpr_fw_diag_unregister_t diag_unregister; + mpr_fw_diag_query_t diag_query; + mpr_diag_read_buffer_t diag_read_buffer; + mpr_fw_diag_release_t diag_release; + int status = MPR_DIAG_SUCCESS; + uint32_t original_return_code; + + original_return_code = *return_code; + *return_code = MPR_FW_DIAG_ERROR_SUCCESS; + + switch (action) { + case MPR_FW_DIAG_TYPE_REGISTER: + if (!length) { + *return_code = + MPR_FW_DIAG_ERROR_INVALID_PARAMETER; + status = MPR_DIAG_FAILURE; + break; + } + if (copyin(diag_action, &diag_register, + sizeof(diag_register)) != 0) + return (MPR_DIAG_FAILURE); + status = mpr_diag_register(sc, &diag_register, + return_code); + break; + + case MPR_FW_DIAG_TYPE_UNREGISTER: + if (length < sizeof(diag_unregister)) { + *return_code = + MPR_FW_DIAG_ERROR_INVALID_PARAMETER; + status = MPR_DIAG_FAILURE; + break; + } + if (copyin(diag_action, &diag_unregister, + sizeof(diag_unregister)) != 0) + return (MPR_DIAG_FAILURE); + status = mpr_diag_unregister(sc, &diag_unregister, + return_code); + break; + + case MPR_FW_DIAG_TYPE_QUERY: + if (length < sizeof (diag_query)) { + *return_code = + MPR_FW_DIAG_ERROR_INVALID_PARAMETER; + status = MPR_DIAG_FAILURE; + break; + } + if (copyin(diag_action, &diag_query, sizeof(diag_query)) + != 0) + return (MPR_DIAG_FAILURE); + status = mpr_diag_query(sc, &diag_query, return_code); + if (status == MPR_DIAG_SUCCESS) + if (copyout(&diag_query, diag_action, + sizeof (diag_query)) != 0) + return (MPR_DIAG_FAILURE); + break; + + case MPR_FW_DIAG_TYPE_READ_BUFFER: + if (copyin(diag_action, &diag_read_buffer, + sizeof(diag_read_buffer)) != 0) + return (MPR_DIAG_FAILURE); + if (length < diag_read_buffer.BytesToRead) { + *return_code = + MPR_FW_DIAG_ERROR_INVALID_PARAMETER; + status = MPR_DIAG_FAILURE; + break; + } + status = mpr_diag_read_buffer(sc, &diag_read_buffer, + PTRIN(diag_read_buffer.PtrDataBuffer), + return_code); + if (status == MPR_DIAG_SUCCESS) { + if (copyout(&diag_read_buffer, diag_action, + sizeof(diag_read_buffer) - + sizeof(diag_read_buffer.PtrDataBuffer)) != + 0) + return (MPR_DIAG_FAILURE); + } + break; + + case MPR_FW_DIAG_TYPE_RELEASE: + if (length < sizeof(diag_release)) { + *return_code = + MPR_FW_DIAG_ERROR_INVALID_PARAMETER; + status = MPR_DIAG_FAILURE; + break; + } + if (copyin(diag_action, &diag_release, + sizeof(diag_release)) != 0) + return (MPR_DIAG_FAILURE); + status = mpr_diag_release(sc, &diag_release, + return_code); + break; + + default: + *return_code = MPR_FW_DIAG_ERROR_INVALID_PARAMETER; + status = MPR_DIAG_FAILURE; + break; + } + + if ((status == MPR_DIAG_FAILURE) && + (original_return_code == MPR_FW_DIAG_NEW) && + (*return_code != MPR_FW_DIAG_ERROR_SUCCESS)) + status = MPR_DIAG_SUCCESS; + + return (status); +} + +static int +mpr_user_diag_action(struct mpr_softc *sc, mpr_diag_action_t *data) +{ + int status; + + /* + * Only allow one diag action at one time. + */ + if (sc->mpr_flags & MPR_FLAGS_BUSY) { + mpr_dprint(sc, MPR_USER, "%s: Only one FW diag command " + "allowed at a single time.", __func__); + return (EBUSY); + } + sc->mpr_flags |= MPR_FLAGS_BUSY; + + /* + * Send diag action request + */ + if (data->Action == MPR_FW_DIAG_TYPE_REGISTER || + data->Action == MPR_FW_DIAG_TYPE_UNREGISTER || + data->Action == MPR_FW_DIAG_TYPE_QUERY || + data->Action == MPR_FW_DIAG_TYPE_READ_BUFFER || + data->Action == MPR_FW_DIAG_TYPE_RELEASE) { + status = mpr_do_diag_action(sc, data->Action, + PTRIN(data->PtrDiagAction), data->Length, + &data->ReturnCode); + } else + status = EINVAL; + + sc->mpr_flags &= ~MPR_FLAGS_BUSY; + return (status); +} + +/* + * Copy the event recording mask and the event queue size out. For + * clarification, the event recording mask (events_to_record) is not the same + * thing as the event mask (event_mask). events_to_record has a bit set for + * every event type that is to be recorded by the driver, and event_mask has a + * bit cleared for every event that is allowed into the driver from the IOC. + * They really have nothing to do with each other. + */ +static void +mpr_user_event_query(struct mpr_softc *sc, mpr_event_query_t *data) +{ + uint8_t i; + + mpr_lock(sc); + data->Entries = MPR_EVENT_QUEUE_SIZE; + + for (i = 0; i < 4; i++) { + data->Types[i] = sc->events_to_record[i]; + } + mpr_unlock(sc); +} + +/* + * Set the driver's event mask according to what's been given. See + * mpr_user_event_query for explanation of the event recording mask and the IOC + * event mask. It's the app's responsibility to enable event logging by setting + * the bits in events_to_record. Initially, no events will be logged. + */ +static void +mpr_user_event_enable(struct mpr_softc *sc, mpr_event_enable_t *data) +{ + uint8_t i; + + mpr_lock(sc); + for (i = 0; i < 4; i++) { + sc->events_to_record[i] = data->Types[i]; + } + mpr_unlock(sc); +} + +/* + * Copy out the events that have been recorded, up to the max events allowed. + */ +static int +mpr_user_event_report(struct mpr_softc *sc, mpr_event_report_t *data) +{ + int status = 0; + uint32_t size; + + mpr_lock(sc); + size = data->Size; + if ((size >= sizeof(sc->recorded_events)) && (status == 0)) { + mpr_unlock(sc); + if (copyout((void *)sc->recorded_events, + PTRIN(data->PtrEvents), size) != 0) + status = EFAULT; + mpr_lock(sc); + } else { + /* + * data->Size value is not large enough to copy event data. + */ + status = EFAULT; + } + + /* + * Change size value to match the number of bytes that were copied. + */ + if (status == 0) + data->Size = sizeof(sc->recorded_events); + mpr_unlock(sc); + + return (status); +} + +/* + * Record events into the driver from the IOC if they are not masked. + */ +void +mprsas_record_event(struct mpr_softc *sc, + MPI2_EVENT_NOTIFICATION_REPLY *event_reply) +{ + uint32_t event; + int i, j; + uint16_t event_data_len; + boolean_t sendAEN = FALSE; + + event = event_reply->Event; + + /* + * Generate a system event to let anyone who cares know that a + * LOG_ENTRY_ADDED event has occurred. This is sent no matter what the + * event mask is set to. + */ + if (event == MPI2_EVENT_LOG_ENTRY_ADDED) { + sendAEN = TRUE; + } + + /* + * Record the event only if its corresponding bit is set in + * events_to_record. event_index is the index into recorded_events and + * event_number is the overall number of an event being recorded since + * start-of-day. event_index will roll over; event_number will never + * roll over. + */ + i = (uint8_t)(event / 32); + j = (uint8_t)(event % 32); + if ((i < 4) && ((1 << j) & sc->events_to_record[i])) { + i = sc->event_index; + sc->recorded_events[i].Type = event; + sc->recorded_events[i].Number = ++sc->event_number; + bzero(sc->recorded_events[i].Data, MPR_MAX_EVENT_DATA_LENGTH * + 4); + event_data_len = event_reply->EventDataLength; + + if (event_data_len > 0) { + /* + * Limit data to size in m_event entry + */ + if (event_data_len > MPR_MAX_EVENT_DATA_LENGTH) { + event_data_len = MPR_MAX_EVENT_DATA_LENGTH; + } + for (j = 0; j < event_data_len; j++) { + sc->recorded_events[i].Data[j] = + event_reply->EventData[j]; + } + + /* + * check for index wrap-around + */ + if (++i == MPR_EVENT_QUEUE_SIZE) { + i = 0; + } + sc->event_index = (uint8_t)i; + + /* + * Set flag to send the event. + */ + sendAEN = TRUE; + } + } + + /* + * Generate a system event if flag is set to let anyone who cares know + * that an event has occurred. + */ + if (sendAEN) { +//SLM-how to send a system event (see kqueue, kevent) +// (void) ddi_log_sysevent(mpt->m_dip, DDI_VENDOR_LSI, "MPT_SAS", +// "SAS", NULL, NULL, DDI_NOSLEEP); + } +} + +static int +mpr_user_reg_access(struct mpr_softc *sc, mpr_reg_access_t *data) +{ + int status = 0; + + switch (data->Command) { + /* + * IO access is not supported. + */ + case REG_IO_READ: + case REG_IO_WRITE: + mpr_dprint(sc, MPR_USER, "IO access is not supported. " + "Use memory access."); + status = EINVAL; + break; + + case REG_MEM_READ: + data->RegData = mpr_regread(sc, data->RegOffset); + break; + + case REG_MEM_WRITE: + mpr_regwrite(sc, data->RegOffset, data->RegData); + break; + + default: + status = EINVAL; + break; + } + + return (status); +} + +static int +mpr_user_btdh(struct mpr_softc *sc, mpr_btdh_mapping_t *data) +{ + uint8_t bt2dh = FALSE; + uint8_t dh2bt = FALSE; + uint16_t dev_handle, bus, target; + + bus = data->Bus; + target = data->TargetID; + dev_handle = data->DevHandle; + + /* + * When DevHandle is 0xFFFF and Bus/Target are not 0xFFFF, use Bus/ + * Target to get DevHandle. When Bus/Target are 0xFFFF and DevHandle is + * not 0xFFFF, use DevHandle to get Bus/Target. Anything else is + * invalid. + */ + if ((bus == 0xFFFF) && (target == 0xFFFF) && (dev_handle != 0xFFFF)) + dh2bt = TRUE; + if ((dev_handle == 0xFFFF) && (bus != 0xFFFF) && (target != 0xFFFF)) + bt2dh = TRUE; + if (!dh2bt && !bt2dh) + return (EINVAL); + + /* + * Only handle bus of 0. Make sure target is within range. + */ + if (bt2dh) { + if (bus != 0) + return (EINVAL); + + if (target > sc->max_devices) { + mpr_dprint(sc, MPR_FAULT, "Target ID is out of range " + "for Bus/Target to DevHandle mapping."); + return (EINVAL); + } + dev_handle = sc->mapping_table[target].dev_handle; + if (dev_handle) + data->DevHandle = dev_handle; + } else { + bus = 0; + target = mpr_mapping_get_sas_id_from_handle(sc, dev_handle); + data->Bus = bus; + data->TargetID = target; + } + + return (0); +} + +static int +mpr_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag, + struct thread *td) +{ + struct mpr_softc *sc; + struct mpr_cfg_page_req *page_req; + struct mpr_ext_cfg_page_req *ext_page_req; + void *mpr_page; + int error, msleep_ret; + + mpr_page = NULL; + sc = dev->si_drv1; + page_req = (void *)arg; + ext_page_req = (void *)arg; + + switch (cmd) { + case MPRIO_READ_CFG_HEADER: + mpr_lock(sc); + error = mpr_user_read_cfg_header(sc, page_req); + mpr_unlock(sc); + break; + case MPRIO_READ_CFG_PAGE: + mpr_page = malloc(page_req->len, M_MPRUSER, M_WAITOK | M_ZERO); + if (!mpr_page) { + mpr_printf(sc, "Cannot allocate memory %s %d\n", + __func__, __LINE__); + return (ENOMEM); + } + error = copyin(page_req->buf, mpr_page, + sizeof(MPI2_CONFIG_PAGE_HEADER)); + if (error) + break; + mpr_lock(sc); + error = mpr_user_read_cfg_page(sc, page_req, mpr_page); + mpr_unlock(sc); + if (error) + break; + error = copyout(mpr_page, page_req->buf, page_req->len); + break; + case MPRIO_READ_EXT_CFG_HEADER: + mpr_lock(sc); + error = mpr_user_read_extcfg_header(sc, ext_page_req); + mpr_unlock(sc); + break; + case MPRIO_READ_EXT_CFG_PAGE: + mpr_page = malloc(ext_page_req->len, M_MPRUSER, + M_WAITOK | M_ZERO); + if (!mpr_page) { + mpr_printf(sc, "Cannot allocate memory %s %d\n", + __func__, __LINE__); + return (ENOMEM); + } + error = copyin(ext_page_req->buf, mpr_page, + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + if (error) + break; + mpr_lock(sc); + error = mpr_user_read_extcfg_page(sc, ext_page_req, mpr_page); + mpr_unlock(sc); + if (error) + break; + error = copyout(mpr_page, ext_page_req->buf, ext_page_req->len); + break; + case MPRIO_WRITE_CFG_PAGE: + mpr_page = malloc(page_req->len, M_MPRUSER, M_WAITOK|M_ZERO); + if (!mpr_page) { + mpr_printf(sc, "Cannot allocate memory %s %d\n", + __func__, __LINE__); + return (ENOMEM); + } + error = copyin(page_req->buf, mpr_page, page_req->len); + if (error) + break; + mpr_lock(sc); + error = mpr_user_write_cfg_page(sc, page_req, mpr_page); + mpr_unlock(sc); + break; + case MPRIO_MPR_COMMAND: + error = mpr_user_command(sc, (struct mpr_usr_command *)arg); + break; + case MPTIOCTL_PASS_THRU: + /* + * The user has requested to pass through a command to be + * executed by the MPT firmware. Call our routine which does + * this. Only allow one passthru IOCTL at one time. + */ + error = mpr_user_pass_thru(sc, (mpr_pass_thru_t *)arg); + break; + case MPTIOCTL_GET_ADAPTER_DATA: + /* + * The user has requested to read adapter data. Call our + * routine which does this. + */ + error = 0; + mpr_user_get_adapter_data(sc, (mpr_adapter_data_t *)arg); + break; + case MPTIOCTL_GET_PCI_INFO: + /* + * The user has requested to read pci info. Call + * our routine which does this. + */ + mpr_lock(sc); + error = 0; + mpr_user_read_pci_info(sc, (mpr_pci_info_t *)arg); + mpr_unlock(sc); + break; + case MPTIOCTL_RESET_ADAPTER: + mpr_lock(sc); + sc->port_enable_complete = 0; + uint32_t reinit_start = time_uptime; + error = mpr_reinit(sc); + /* Sleep for 300 second. */ + msleep_ret = msleep(&sc->port_enable_complete, &sc->mpr_mtx, + PRIBIO, "mpr_porten", 300 * hz); + mpr_unlock(sc); + if (msleep_ret) + printf("Port Enable did not complete after Diag " + "Reset msleep error %d.\n", msleep_ret); + else + mpr_dprint(sc, MPR_USER, "Hard Reset with Port Enable " + "completed in %d seconds.\n", + (uint32_t)(time_uptime - reinit_start)); + break; + case MPTIOCTL_DIAG_ACTION: + /* + * The user has done a diag buffer action. Call our routine + * which does this. Only allow one diag action at one time. + */ + mpr_lock(sc); + error = mpr_user_diag_action(sc, (mpr_diag_action_t *)arg); + mpr_unlock(sc); + break; + case MPTIOCTL_EVENT_QUERY: + /* + * The user has done an event query. Call our routine which does + * this. + */ + error = 0; + mpr_user_event_query(sc, (mpr_event_query_t *)arg); + break; + case MPTIOCTL_EVENT_ENABLE: + /* + * The user has done an event enable. Call our routine which + * does this. + */ + error = 0; + mpr_user_event_enable(sc, (mpr_event_enable_t *)arg); + break; + case MPTIOCTL_EVENT_REPORT: + /* + * The user has done an event report. Call our routine which + * does this. + */ + error = mpr_user_event_report(sc, (mpr_event_report_t *)arg); + break; + case MPTIOCTL_REG_ACCESS: + /* + * The user has requested register access. Call our routine + * which does this. + */ + mpr_lock(sc); + error = mpr_user_reg_access(sc, (mpr_reg_access_t *)arg); + mpr_unlock(sc); + break; + case MPTIOCTL_BTDH_MAPPING: + /* + * The user has requested to translate a bus/target to a + * DevHandle or a DevHandle to a bus/target. Call our routine + * which does this. + */ + error = mpr_user_btdh(sc, (mpr_btdh_mapping_t *)arg); + break; + default: + error = ENOIOCTL; + break; + } + + if (mpr_page != NULL) + free(mpr_page, M_MPRUSER); + + return (error); +} + +#ifdef COMPAT_FREEBSD32 + +struct mpr_cfg_page_req32 { + MPI2_CONFIG_PAGE_HEADER header; + uint32_t page_address; + uint32_t buf; + int len; + uint16_t ioc_status; +}; + +struct mpr_ext_cfg_page_req32 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER header; + uint32_t page_address; + uint32_t buf; + int len; + uint16_t ioc_status; +}; + +struct mpr_raid_action32 { + uint8_t action; + uint8_t volume_bus; + uint8_t volume_id; + uint8_t phys_disk_num; + uint32_t action_data_word; + uint32_t buf; + int len; + uint32_t volume_status; + uint32_t action_data[4]; + uint16_t action_status; + uint16_t ioc_status; + uint8_t write; +}; + +struct mpr_usr_command32 { + uint32_t req; + uint32_t req_len; + uint32_t rpl; + uint32_t rpl_len; + uint32_t buf; + int len; + uint32_t flags; +}; + +#define MPRIO_READ_CFG_HEADER32 _IOWR('M', 200, struct mpr_cfg_page_req32) +#define MPRIO_READ_CFG_PAGE32 _IOWR('M', 201, struct mpr_cfg_page_req32) +#define MPRIO_READ_EXT_CFG_HEADER32 _IOWR('M', 202, struct mpr_ext_cfg_page_req32) +#define MPRIO_READ_EXT_CFG_PAGE32 _IOWR('M', 203, struct mpr_ext_cfg_page_req32) +#define MPRIO_WRITE_CFG_PAGE32 _IOWR('M', 204, struct mpr_cfg_page_req32) +#define MPRIO_RAID_ACTION32 _IOWR('M', 205, struct mpr_raid_action32) +#define MPRIO_MPR_COMMAND32 _IOWR('M', 210, struct mpr_usr_command32) + +static int +mpr_ioctl32(struct cdev *dev, u_long cmd32, void *_arg, int flag, + struct thread *td) +{ + struct mpr_cfg_page_req32 *page32 = _arg; + struct mpr_ext_cfg_page_req32 *ext32 = _arg; + struct mpr_raid_action32 *raid32 = _arg; + struct mpr_usr_command32 *user32 = _arg; + union { + struct mpr_cfg_page_req page; + struct mpr_ext_cfg_page_req ext; + struct mpr_raid_action raid; + struct mpr_usr_command user; + } arg; + u_long cmd; + int error; + + switch (cmd32) { + case MPRIO_READ_CFG_HEADER32: + case MPRIO_READ_CFG_PAGE32: + case MPRIO_WRITE_CFG_PAGE32: + if (cmd32 == MPRIO_READ_CFG_HEADER32) + cmd = MPRIO_READ_CFG_HEADER; + else if (cmd32 == MPRIO_READ_CFG_PAGE32) + cmd = MPRIO_READ_CFG_PAGE; + else + cmd = MPRIO_WRITE_CFG_PAGE; + CP(*page32, arg.page, header); + CP(*page32, arg.page, page_address); + PTRIN_CP(*page32, arg.page, buf); + CP(*page32, arg.page, len); + CP(*page32, arg.page, ioc_status); + break; + + case MPRIO_READ_EXT_CFG_HEADER32: + case MPRIO_READ_EXT_CFG_PAGE32: + if (cmd32 == MPRIO_READ_EXT_CFG_HEADER32) + cmd = MPRIO_READ_EXT_CFG_HEADER; + else + cmd = MPRIO_READ_EXT_CFG_PAGE; + CP(*ext32, arg.ext, header); + CP(*ext32, arg.ext, page_address); + PTRIN_CP(*ext32, arg.ext, buf); + CP(*ext32, arg.ext, len); + CP(*ext32, arg.ext, ioc_status); + break; + + case MPRIO_RAID_ACTION32: + cmd = MPRIO_RAID_ACTION; + CP(*raid32, arg.raid, action); + CP(*raid32, arg.raid, volume_bus); + CP(*raid32, arg.raid, volume_id); + CP(*raid32, arg.raid, phys_disk_num); + CP(*raid32, arg.raid, action_data_word); + PTRIN_CP(*raid32, arg.raid, buf); + CP(*raid32, arg.raid, len); + CP(*raid32, arg.raid, volume_status); + bcopy(raid32->action_data, arg.raid.action_data, + sizeof arg.raid.action_data); + CP(*raid32, arg.raid, ioc_status); + CP(*raid32, arg.raid, write); + break; + + case MPRIO_MPR_COMMAND32: + cmd = MPRIO_MPR_COMMAND; + PTRIN_CP(*user32, arg.user, req); + CP(*user32, arg.user, req_len); + PTRIN_CP(*user32, arg.user, rpl); + CP(*user32, arg.user, rpl_len); + PTRIN_CP(*user32, arg.user, buf); + CP(*user32, arg.user, len); + CP(*user32, arg.user, flags); + break; + default: + return (ENOIOCTL); + } + + error = mpr_ioctl(dev, cmd, &arg, flag, td); + if (error == 0 && (cmd32 & IOC_OUT) != 0) { + switch (cmd32) { + case MPRIO_READ_CFG_HEADER32: + case MPRIO_READ_CFG_PAGE32: + case MPRIO_WRITE_CFG_PAGE32: + CP(arg.page, *page32, header); + CP(arg.page, *page32, page_address); + PTROUT_CP(arg.page, *page32, buf); + CP(arg.page, *page32, len); + CP(arg.page, *page32, ioc_status); + break; + + case MPRIO_READ_EXT_CFG_HEADER32: + case MPRIO_READ_EXT_CFG_PAGE32: + CP(arg.ext, *ext32, header); + CP(arg.ext, *ext32, page_address); + PTROUT_CP(arg.ext, *ext32, buf); + CP(arg.ext, *ext32, len); + CP(arg.ext, *ext32, ioc_status); + break; + + case MPRIO_RAID_ACTION32: + CP(arg.raid, *raid32, action); + CP(arg.raid, *raid32, volume_bus); + CP(arg.raid, *raid32, volume_id); + CP(arg.raid, *raid32, phys_disk_num); + CP(arg.raid, *raid32, action_data_word); + PTROUT_CP(arg.raid, *raid32, buf); + CP(arg.raid, *raid32, len); + CP(arg.raid, *raid32, volume_status); + bcopy(arg.raid.action_data, raid32->action_data, + sizeof arg.raid.action_data); + CP(arg.raid, *raid32, ioc_status); + CP(arg.raid, *raid32, write); + break; + + case MPRIO_MPR_COMMAND32: + PTROUT_CP(arg.user, *user32, req); + CP(arg.user, *user32, req_len); + PTROUT_CP(arg.user, *user32, rpl); + CP(arg.user, *user32, rpl_len); + PTROUT_CP(arg.user, *user32, buf); + CP(arg.user, *user32, len); + CP(arg.user, *user32, flags); + break; + } + } + + return (error); +} +#endif /* COMPAT_FREEBSD32 */ + +static int +mpr_ioctl_devsw(struct cdev *dev, u_long com, caddr_t arg, int flag, + struct thread *td) +{ +#ifdef COMPAT_FREEBSD32 + if (SV_CURPROC_FLAG(SV_ILP32)) + return (mpr_ioctl32(dev, com, arg, flag, td)); +#endif + return (mpr_ioctl(dev, com, arg, flag, td)); +} diff --git a/sys/dev/mpr/mprvar.h b/sys/dev/mpr/mprvar.h new file mode 100644 index 0000000000000..9752dcd35f6f4 --- /dev/null +++ b/sys/dev/mpr/mprvar.h @@ -0,0 +1,766 @@ +/*- + * Copyright (c) 2009 Yahoo! Inc. + * Copyright (c) 2011-2014 LSI Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MPRVAR_H +#define _MPRVAR_H + +#define MPR_DRIVER_VERSION "05.255.05.00-fbsd" + +#define MPR_DB_MAX_WAIT 2500 + +#define MPR_REQ_FRAMES 1024 +#define MPR_EVT_REPLY_FRAMES 32 +#define MPR_REPLY_FRAMES MPR_REQ_FRAMES +#define MPR_CHAIN_FRAMES 2048 +#define MPR_SENSE_LEN SSD_FULL_SIZE +#define MPR_MSI_COUNT 1 +#define MPR_SGE64_SIZE 12 +#define MPR_SGE32_SIZE 8 +#define MPR_SGC_SIZE 8 + +#define MPR_FUNCTRACE(sc) \ + mpr_dprint((sc), MPR_TRACE, "%s\n", __func__) + +#define CAN_SLEEP 1 +#define NO_SLEEP 0 + +#define MPR_PERIODIC_DELAY 1 /* 1 second heartbeat/watchdog check */ + +#define IFAULT_IOP_OVER_TEMP_THRESHOLD_EXCEEDED 0x2810 + +#define MPR_SCSI_RI_INVALID_FRAME (0x00000002) +#define MPR_STRING_LENGTH 64 + +#include <sys/endian.h> + +/* + * host mapping related macro definitions + */ +#define MPR_MAPTABLE_BAD_IDX 0xFFFFFFFF +#define MPR_DPM_BAD_IDX 0xFFFF +#define MPR_ENCTABLE_BAD_IDX 0xFF +#define MPR_MAX_MISSING_COUNT 0x0F +#define MPR_DEV_RESERVED 0x20000000 +#define MPR_MAP_IN_USE 0x10000000 +#define MPR_RAID_CHANNEL 1 +#define MPR_MAP_BAD_ID 0xFFFFFFFF + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +/** + * struct dev_mapping_table - device mapping information + * @physical_id: SAS address for drives or WWID for RAID volumes + * @device_info: bitfield provides detailed info about the device + * @phy_bits: bitfields indicating controller phys + * @dpm_entry_num: index of this device in device persistent map table + * @dev_handle: device handle for the device pointed by this entry + * @channel: target channel + * @id: target id + * @missing_count: number of times the device not detected by driver + * @hide_flag: Hide this physical disk/not (foreign configuration) + * @init_complete: Whether the start of the day checks completed or not + * @TLR_bits: Turn TLR support on or off + */ +struct dev_mapping_table { + u64 physical_id; + u32 device_info; + u32 phy_bits; + u16 dpm_entry_num; + u16 dev_handle; + u8 reserved1; + u8 channel; + u16 id; + u8 missing_count; + u8 init_complete; + u8 TLR_bits; + u8 reserved2; +}; + +/** + * struct enc_mapping_table - mapping information about an enclosure + * @enclosure_id: Logical ID of this enclosure + * @start_index: index to the entry in dev_mapping_table + * @phy_bits: bitfields indicating controller phys + * @dpm_entry_num: index of this enclosure in device persistent map table + * @enc_handle: device handle for the enclosure pointed by this entry + * @num_slots: number of slots in the enclosure + * @start_slot: Starting slot id + * @missing_count: number of times the device not detected by driver + * @removal_flag: used to mark the device for removal + * @skip_search: used as a flag to include/exclude enclosure for search + * @init_complete: Whether the start of the day checks completed or not + */ +struct enc_mapping_table { + u64 enclosure_id; + u32 start_index; + u32 phy_bits; + u16 dpm_entry_num; + u16 enc_handle; + u16 num_slots; + u16 start_slot; + u8 missing_count; + u8 removal_flag; + u8 skip_search; + u8 init_complete; +}; + +/** + * struct map_removal_table - entries to be removed from mapping table + * @dpm_entry_num: index of this device in device persistent map table + * @dev_handle: device handle for the device pointed by this entry + */ +struct map_removal_table{ + u16 dpm_entry_num; + u16 dev_handle; +}; + +typedef struct mpr_fw_diagnostic_buffer { + size_t size; + uint8_t extended_type; + uint8_t buffer_type; + uint8_t force_release; + uint32_t product_specific[23]; + uint8_t immediate; + uint8_t enabled; + uint8_t valid_data; + uint8_t owned_by_firmware; + uint32_t unique_id; +} mpr_fw_diagnostic_buffer_t; + +struct mpr_softc; +struct mpr_command; +struct mprsas_softc; +union ccb; +struct mprsas_target; +struct mpr_column_map; + +MALLOC_DECLARE(M_MPR); + +typedef void mpr_evt_callback_t(struct mpr_softc *, uintptr_t, + MPI2_EVENT_NOTIFICATION_REPLY *reply); +typedef void mpr_command_callback_t(struct mpr_softc *, struct mpr_command *cm); + +struct mpr_chain { + TAILQ_ENTRY(mpr_chain) chain_link; + void *chain; + uint64_t chain_busaddr; +}; + +/* + * This needs to be at least 2 to support SMP passthrough. + */ +#define MPR_IOVEC_COUNT 2 + +struct mpr_command { + TAILQ_ENTRY(mpr_command) cm_link; + TAILQ_ENTRY(mpr_command) cm_recovery; + struct mpr_softc *cm_sc; + union ccb *cm_ccb; + void *cm_data; + u_int cm_length; + u_int cm_out_len; + struct uio cm_uio; + struct iovec cm_iovec[MPR_IOVEC_COUNT]; + u_int cm_max_segs; + u_int cm_sglsize; + void *cm_sge; + uint8_t *cm_req; + uint8_t *cm_reply; + uint32_t cm_reply_data; + mpr_command_callback_t *cm_complete; + void *cm_complete_data; + struct mprsas_target *cm_targ; + MPI2_REQUEST_DESCRIPTOR_UNION cm_desc; + u_int cm_lun; + u_int cm_flags; +#define MPR_CM_FLAGS_POLLED (1 << 0) +#define MPR_CM_FLAGS_COMPLETE (1 << 1) +#define MPR_CM_FLAGS_SGE_SIMPLE (1 << 2) +#define MPR_CM_FLAGS_DATAOUT (1 << 3) +#define MPR_CM_FLAGS_DATAIN (1 << 4) +#define MPR_CM_FLAGS_WAKEUP (1 << 5) +#define MPR_CM_FLAGS_USE_UIO (1 << 6) +#define MPR_CM_FLAGS_SMP_PASS (1 << 7) +#define MPR_CM_FLAGS_CHAIN_FAILED (1 << 8) +#define MPR_CM_FLAGS_ERROR_MASK MPR_CM_FLAGS_CHAIN_FAILED +#define MPR_CM_FLAGS_USE_CCB (1 << 9) + u_int cm_state; +#define MPR_CM_STATE_FREE 0 +#define MPR_CM_STATE_BUSY 1 +#define MPR_CM_STATE_TIMEDOUT 2 + bus_dmamap_t cm_dmamap; + struct scsi_sense_data *cm_sense; + TAILQ_HEAD(, mpr_chain) cm_chain_list; + uint32_t cm_req_busaddr; + uint32_t cm_sense_busaddr; + struct callout cm_callout; +}; + +struct mpr_column_map { + uint16_t dev_handle; + uint8_t phys_disk_num; +}; + +struct mpr_event_handle { + TAILQ_ENTRY(mpr_event_handle) eh_list; + mpr_evt_callback_t *callback; + void *data; + uint8_t mask[16]; +}; + +struct mpr_softc { + device_t mpr_dev; + struct cdev *mpr_cdev; + u_int mpr_flags; +#define MPR_FLAGS_INTX (1 << 0) +#define MPR_FLAGS_MSI (1 << 1) +#define MPR_FLAGS_BUSY (1 << 2) +#define MPR_FLAGS_SHUTDOWN (1 << 3) +#define MPR_FLAGS_DIAGRESET (1 << 4) +#define MPR_FLAGS_ATTACH_DONE (1 << 5) + u_int mpr_debug; + u_int disable_msix; + u_int disable_msi; + int tm_cmds_active; + int io_cmds_active; + int io_cmds_highwater; + int chain_free; + int max_chains; + int chain_free_lowwater; +#if __FreeBSD_version >= 900030 + uint64_t chain_alloc_fail; +#endif + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_tree; + char fw_version[16]; + struct mpr_command *commands; + struct mpr_chain *chains; + struct callout periodic; + + struct mprsas_softc *sassc; + char tmp_string[MPR_STRING_LENGTH]; + TAILQ_HEAD(, mpr_command) req_list; + TAILQ_HEAD(, mpr_command) high_priority_req_list; + TAILQ_HEAD(, mpr_chain) chain_list; + TAILQ_HEAD(, mpr_command) tm_list; + int replypostindex; + int replyfreeindex; + + struct resource *mpr_regs_resource; + bus_space_handle_t mpr_bhandle; + bus_space_tag_t mpr_btag; + int mpr_regs_rid; + + bus_dma_tag_t mpr_parent_dmat; + bus_dma_tag_t buffer_dmat; + + MPI2_IOC_FACTS_REPLY *facts; + int num_reqs; + int num_replies; + int fqdepth; /* Free queue */ + int pqdepth; /* Post queue */ + + uint8_t event_mask[16]; + TAILQ_HEAD(, mpr_event_handle) event_list; + struct mpr_event_handle *mpr_log_eh; + + struct mtx mpr_mtx; + struct intr_config_hook mpr_ich; + struct resource *mpr_irq[MPR_MSI_COUNT]; + void *mpr_intrhand[MPR_MSI_COUNT]; + int mpr_irq_rid[MPR_MSI_COUNT]; + + uint8_t *req_frames; + bus_addr_t req_busaddr; + bus_dma_tag_t req_dmat; + bus_dmamap_t req_map; + + uint8_t *reply_frames; + bus_addr_t reply_busaddr; + bus_dma_tag_t reply_dmat; + bus_dmamap_t reply_map; + + struct scsi_sense_data *sense_frames; + bus_addr_t sense_busaddr; + bus_dma_tag_t sense_dmat; + bus_dmamap_t sense_map; + + uint8_t *chain_frames; + bus_addr_t chain_busaddr; + bus_dma_tag_t chain_dmat; + bus_dmamap_t chain_map; + + MPI2_REPLY_DESCRIPTORS_UNION *post_queue; + bus_addr_t post_busaddr; + uint32_t *free_queue; + bus_addr_t free_busaddr; + bus_dma_tag_t queues_dmat; + bus_dmamap_t queues_map; + + uint8_t *fw_diag_buffer; + bus_addr_t fw_diag_busaddr; + bus_dma_tag_t fw_diag_dmat; + bus_dmamap_t fw_diag_map; + + uint8_t ir_firmware; + + /* static config pages */ + Mpi2IOCPage8_t ioc_pg8; + Mpi2IOUnitPage8_t iounit_pg8; + + /* host mapping support */ + struct dev_mapping_table *mapping_table; + struct enc_mapping_table *enclosure_table; + struct map_removal_table *removal_table; + uint8_t *dpm_entry_used; + uint8_t *dpm_flush_entry; + Mpi2DriverMappingPage0_t *dpm_pg0; + uint16_t max_devices; + uint16_t max_enclosures; + uint16_t max_expanders; + uint8_t max_volumes; + uint8_t num_enc_table_entries; + uint8_t num_rsvd_entries; + uint8_t num_channels; + uint16_t max_dpm_entries; + uint8_t is_dpm_enable; + uint8_t track_mapping_events; + uint32_t pending_map_events; + uint8_t mt_full_retry; + uint8_t mt_add_device_failed; + + /* FW diag Buffer List */ + mpr_fw_diagnostic_buffer_t + fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_COUNT]; + + /* Event Recording IOCTL support */ + uint32_t events_to_record[4]; + mpr_event_entry_t recorded_events[MPR_EVENT_QUEUE_SIZE]; + uint8_t event_index; + uint32_t event_number; + + /* EEDP and TLR support */ + uint8_t eedp_enabled; + uint8_t control_TLR; + + /* Shutdown Event Handler */ + eventhandler_tag shutdown_eh; + + /* To track topo events during reset */ +#define MPR_DIAG_RESET_TIMEOUT 300000 + uint8_t wait_for_port_enable; + uint8_t port_enable_complete; + uint8_t msleep_fake_chan; + + /* StartStopUnit command handling at shutdown */ + uint32_t SSU_refcount; + uint8_t SSU_started; + + char exclude_ids[80]; + struct timeval lastfail; +}; + +struct mpr_config_params { + MPI2_CONFIG_EXT_PAGE_HEADER_UNION hdr; + u_int action; + u_int page_address; /* Attributes, not a phys address */ + u_int status; + void *buffer; + u_int length; + int timeout; + void (*callback)(struct mpr_softc *, struct mpr_config_params *); + void *cbdata; +}; + +struct scsi_read_capacity_eedp +{ + uint8_t addr[8]; + uint8_t length[4]; + uint8_t protect; +}; + +static __inline uint32_t +mpr_regread(struct mpr_softc *sc, uint32_t offset) +{ + return (bus_space_read_4(sc->mpr_btag, sc->mpr_bhandle, offset)); +} + +static __inline void +mpr_regwrite(struct mpr_softc *sc, uint32_t offset, uint32_t val) +{ + bus_space_write_4(sc->mpr_btag, sc->mpr_bhandle, offset, val); +} + +/* free_queue must have Little Endian address + * TODO- cm_reply_data is unwanted. We can remove it. + * */ +static __inline void +mpr_free_reply(struct mpr_softc *sc, uint32_t busaddr) +{ + if (++sc->replyfreeindex >= sc->fqdepth) + sc->replyfreeindex = 0; + sc->free_queue[sc->replyfreeindex] = htole32(busaddr); + mpr_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex); +} + +static __inline struct mpr_chain * +mpr_alloc_chain(struct mpr_softc *sc) +{ + struct mpr_chain *chain; + + if ((chain = TAILQ_FIRST(&sc->chain_list)) != NULL) { + TAILQ_REMOVE(&sc->chain_list, chain, chain_link); + sc->chain_free--; + if (sc->chain_free < sc->chain_free_lowwater) + sc->chain_free_lowwater = sc->chain_free; + } +#if __FreeBSD_version >= 900030 + else + sc->chain_alloc_fail++; +#endif + return (chain); +} + +static __inline void +mpr_free_chain(struct mpr_softc *sc, struct mpr_chain *chain) +{ +#if 0 + bzero(chain->chain, 128); +#endif + sc->chain_free++; + TAILQ_INSERT_TAIL(&sc->chain_list, chain, chain_link); +} + +static __inline void +mpr_free_command(struct mpr_softc *sc, struct mpr_command *cm) +{ + struct mpr_chain *chain, *chain_temp; + + if (cm->cm_reply != NULL) + mpr_free_reply(sc, cm->cm_reply_data); + cm->cm_reply = NULL; + cm->cm_flags = 0; + cm->cm_complete = NULL; + cm->cm_complete_data = NULL; + cm->cm_ccb = NULL; + cm->cm_targ = NULL; + cm->cm_max_segs = 0; + cm->cm_lun = 0; + cm->cm_state = MPR_CM_STATE_FREE; + cm->cm_data = NULL; + cm->cm_length = 0; + cm->cm_out_len = 0; + cm->cm_sglsize = 0; + cm->cm_sge = NULL; + + TAILQ_FOREACH_SAFE(chain, &cm->cm_chain_list, chain_link, chain_temp) { + TAILQ_REMOVE(&cm->cm_chain_list, chain, chain_link); + mpr_free_chain(sc, chain); + } + TAILQ_INSERT_TAIL(&sc->req_list, cm, cm_link); +} + +static __inline struct mpr_command * +mpr_alloc_command(struct mpr_softc *sc) +{ + struct mpr_command *cm; + + cm = TAILQ_FIRST(&sc->req_list); + if (cm == NULL) + return (NULL); + + TAILQ_REMOVE(&sc->req_list, cm, cm_link); + KASSERT(cm->cm_state == MPR_CM_STATE_FREE, ("mpr: Allocating busy command\n")); + cm->cm_state = MPR_CM_STATE_BUSY; + return (cm); +} + +static __inline void +mpr_free_high_priority_command(struct mpr_softc *sc, struct mpr_command *cm) +{ + struct mpr_chain *chain, *chain_temp; + + if (cm->cm_reply != NULL) + mpr_free_reply(sc, cm->cm_reply_data); + cm->cm_reply = NULL; + cm->cm_flags = 0; + cm->cm_complete = NULL; + cm->cm_complete_data = NULL; + cm->cm_ccb = NULL; + cm->cm_targ = NULL; + cm->cm_lun = 0; + cm->cm_state = MPR_CM_STATE_FREE; + TAILQ_FOREACH_SAFE(chain, &cm->cm_chain_list, chain_link, chain_temp) { + TAILQ_REMOVE(&cm->cm_chain_list, chain, chain_link); + mpr_free_chain(sc, chain); + } + TAILQ_INSERT_TAIL(&sc->high_priority_req_list, cm, cm_link); +} + +static __inline struct mpr_command * +mpr_alloc_high_priority_command(struct mpr_softc *sc) +{ + struct mpr_command *cm; + + cm = TAILQ_FIRST(&sc->high_priority_req_list); + if (cm == NULL) + return (NULL); + + TAILQ_REMOVE(&sc->high_priority_req_list, cm, cm_link); + KASSERT(cm->cm_state == MPR_CM_STATE_FREE, ("mpr: Allocating busy command\n")); + cm->cm_state = MPR_CM_STATE_BUSY; + return (cm); +} + +static __inline void +mpr_lock(struct mpr_softc *sc) +{ + mtx_lock(&sc->mpr_mtx); +} + +static __inline void +mpr_unlock(struct mpr_softc *sc) +{ + mtx_unlock(&sc->mpr_mtx); +} + +#define MPR_INFO (1 << 0) /* Basic info */ +#define MPR_FAULT (1 << 1) /* Hardware faults */ +#define MPR_EVENT (1 << 2) /* Event data from the controller */ +#define MPR_LOG (1 << 3) /* Log data from the controller */ +#define MPR_RECOVERY (1 << 4) /* Command error recovery tracing */ +#define MPR_ERROR (1 << 5) /* Parameter errors, programming bugs */ +#define MPR_INIT (1 << 6) /* Things related to system init */ +#define MPR_XINFO (1 << 7) /* More detailed/noisy info */ +#define MPR_USER (1 << 8) /* Trace user-generated commands */ +#define MPR_MAPPING (1 << 9) /* Trace device mappings */ +#define MPR_TRACE (1 << 10) /* Function-by-function trace */ + +#define mpr_printf(sc, args...) \ + device_printf((sc)->mpr_dev, ##args) + +#define mpr_vprintf(sc, args...) \ +do { \ + if (bootverbose) \ + mpr_printf(sc, ##args); \ +} while (0) + +#define mpr_dprint(sc, level, msg, args...) \ +do { \ + if ((sc)->mpr_debug & level) \ + device_printf((sc)->mpr_dev, msg, ##args); \ +} while (0) + +#define mpr_dprint_field(sc, level, msg, args...) \ +do { \ + if ((sc)->mpr_debug & level) \ + printf("\t" msg, ##args); \ +} while (0) + +#define MPR_PRINTFIELD_START(sc, tag...) \ + mpr_dprint((sc), MPR_INFO, ##tag); \ + mpr_dprint_field((sc), MPR_INFO, ":\n") +#define MPR_PRINTFIELD_END(sc, tag) \ + mpr_dprint((sc), MPR_INFO, tag "\n") +#define MPR_PRINTFIELD(sc, facts, attr, fmt) \ + mpr_dprint_field((sc), MPR_INFO, #attr ": " #fmt "\n", (facts)->attr) + +#define MPR_EVENTFIELD_START(sc, tag...) \ + mpr_dprint((sc), MPR_EVENT, ##tag); \ + mpr_dprint_field((sc), MPR_EVENT, ":\n") +#define MPR_EVENTFIELD(sc, facts, attr, fmt) \ + mpr_dprint_field((sc), MPR_EVENT, #attr ": " #fmt "\n", (facts)->attr) + +#define CAN_SLEEP 1 +#define NO_SLEEP 0 + +static __inline void +mpr_from_u64(uint64_t data, U64 *mpr) +{ + (mpr)->High = htole32((uint32_t)((data) >> 32)); + (mpr)->Low = htole32((uint32_t)((data) & 0xffffffff)); +} + +static __inline uint64_t +mpr_to_u64(U64 *data) +{ + + return (((uint64_t)le32toh(data->High) << 32) | le32toh(data->Low)); +} + +static __inline void +mpr_mask_intr(struct mpr_softc *sc) +{ + uint32_t mask; + + mask = mpr_regread(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET); + mask |= MPI2_HIM_REPLY_INT_MASK; + mpr_regwrite(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask); +} + +static __inline void +mpr_unmask_intr(struct mpr_softc *sc) +{ + uint32_t mask; + + mask = mpr_regread(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET); + mask &= ~MPI2_HIM_REPLY_INT_MASK; + mpr_regwrite(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask); +} + +int mpr_pci_setup_interrupts(struct mpr_softc *sc); +int mpr_pci_restore(struct mpr_softc *sc); + +int mpr_attach(struct mpr_softc *sc); +int mpr_free(struct mpr_softc *sc); +void mpr_intr(void *); +void mpr_intr_msi(void *); +void mpr_intr_locked(void *); +int mpr_register_events(struct mpr_softc *, uint8_t *, mpr_evt_callback_t *, + void *, struct mpr_event_handle **); +int mpr_restart(struct mpr_softc *); +int mpr_update_events(struct mpr_softc *, struct mpr_event_handle *, + uint8_t *); +int mpr_deregister_events(struct mpr_softc *, struct mpr_event_handle *); +int mpr_push_sge(struct mpr_command *, MPI2_SGE_SIMPLE64 *, size_t, int); +int mpr_push_ieee_sge(struct mpr_command *, void *, int); +int mpr_add_dmaseg(struct mpr_command *, vm_paddr_t, size_t, u_int, int); +int mpr_attach_sas(struct mpr_softc *sc); +int mpr_detach_sas(struct mpr_softc *sc); +int mpr_read_config_page(struct mpr_softc *, struct mpr_config_params *); +int mpr_write_config_page(struct mpr_softc *, struct mpr_config_params *); +void mpr_memaddr_cb(void *, bus_dma_segment_t *, int , int ); +void mpr_init_sge(struct mpr_command *cm, void *req, void *sge); +int mpr_attach_user(struct mpr_softc *); +void mpr_detach_user(struct mpr_softc *); +void mprsas_record_event(struct mpr_softc *sc, + MPI2_EVENT_NOTIFICATION_REPLY *event_reply); + +int mpr_map_command(struct mpr_softc *sc, struct mpr_command *cm); +int mpr_wait_command(struct mpr_softc *sc, struct mpr_command *cm, + int timeout, int sleep_flag); +int mpr_request_polled(struct mpr_softc *sc, struct mpr_command *cm); + +int mpr_config_get_bios_pg3(struct mpr_softc *sc, Mpi2ConfigReply_t + *mpi_reply, Mpi2BiosPage3_t *config_page); +int mpr_config_get_raid_volume_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t + *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 page_address); +int mpr_config_get_ioc_pg8(struct mpr_softc *sc, Mpi2ConfigReply_t *, + Mpi2IOCPage8_t *); +int mpr_config_get_iounit_pg8(struct mpr_softc *sc, + Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page); +int mpr_config_get_sas_device_pg0(struct mpr_softc *, Mpi2ConfigReply_t *, + Mpi2SasDevicePage0_t *, u32 , u16 ); +int mpr_config_get_dpm_pg0(struct mpr_softc *, Mpi2ConfigReply_t *, + Mpi2DriverMappingPage0_t *, u16 ); +int mpr_config_get_raid_volume_pg1(struct mpr_softc *sc, + Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, + u16 handle); +int mpr_config_get_volume_wwid(struct mpr_softc *sc, u16 volume_handle, + u64 *wwid); +int mpr_config_get_raid_pd_pg0(struct mpr_softc *sc, + Mpi2ConfigReply_t *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, + u32 page_address); +void mprsas_ir_shutdown(struct mpr_softc *sc); + +int mpr_reinit(struct mpr_softc *sc); +void mprsas_handle_reinit(struct mpr_softc *sc); + +void mpr_base_static_config_pages(struct mpr_softc *sc); + +int mpr_mapping_initialize(struct mpr_softc *); +void mpr_mapping_topology_change_event(struct mpr_softc *, + Mpi2EventDataSasTopologyChangeList_t *); +int mpr_mapping_is_reinit_required(struct mpr_softc *); +void mpr_mapping_free_memory(struct mpr_softc *sc); +int mpr_config_set_dpm_pg0(struct mpr_softc *, Mpi2ConfigReply_t *, + Mpi2DriverMappingPage0_t *, u16 ); +void mpr_mapping_exit(struct mpr_softc *); +void mpr_mapping_check_devices(struct mpr_softc *, int); +int mpr_mapping_allocate_memory(struct mpr_softc *sc); +unsigned int mpr_mapping_get_sas_id(struct mpr_softc *, uint64_t , u16); +unsigned int mpr_mapping_get_sas_id_from_handle(struct mpr_softc *sc, + u16 handle); +unsigned int mpr_mapping_get_raid_id(struct mpr_softc *sc, u64 wwid, + u16 handle); +unsigned int mpr_mapping_get_raid_id_from_handle(struct mpr_softc *sc, + u16 volHandle); +void mpr_mapping_enclosure_dev_status_change_event(struct mpr_softc *, + Mpi2EventDataSasEnclDevStatusChange_t *event_data); +void mpr_mapping_ir_config_change_event(struct mpr_softc *sc, + Mpi2EventDataIrConfigChangeList_t *event_data); + +void mprsas_evt_handler(struct mpr_softc *sc, uintptr_t data, + MPI2_EVENT_NOTIFICATION_REPLY *event); +void mprsas_prepare_remove(struct mprsas_softc *sassc, uint16_t handle); +void mprsas_prepare_volume_remove(struct mprsas_softc *sassc, + uint16_t handle); +int mprsas_startup(struct mpr_softc *sc); +struct mprsas_target * mprsas_find_target_by_handle(struct mprsas_softc *, + int, uint16_t); + +SYSCTL_DECL(_hw_mpr); + +/* Compatibility shims for different OS versions */ +#if __FreeBSD_version >= 800001 +#define mpr_kproc_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg) \ + kproc_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg) +#define mpr_kproc_exit(arg) kproc_exit(arg) +#else +#define mpr_kproc_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg) \ + kthread_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg) +#define mpr_kproc_exit(arg) kthread_exit(arg) +#endif + +#if defined(CAM_PRIORITY_XPT) +#define MPR_PRIORITY_XPT CAM_PRIORITY_XPT +#else +#define MPR_PRIORITY_XPT 5 +#endif + +#if __FreeBSD_version < 800107 +// Prior to FreeBSD-8.0 scp3_flags was not defined. +#define spc3_flags reserved + +#define SPC3_SID_PROTECT 0x01 +#define SPC3_SID_3PC 0x08 +#define SPC3_SID_TPGS_MASK 0x30 +#define SPC3_SID_TPGS_IMPLICIT 0x10 +#define SPC3_SID_TPGS_EXPLICIT 0x20 +#define SPC3_SID_ACC 0x40 +#define SPC3_SID_SCCS 0x80 + +#define CAM_PRIORITY_NORMAL CAM_PRIORITY_NONE +#endif + +#endif + diff --git a/sys/dev/mps/mps_sas.c b/sys/dev/mps/mps_sas.c index 3e140ca6da5c6..de34de0e68ab6 100644 --- a/sys/dev/mps/mps_sas.c +++ b/sys/dev/mps/mps_sas.c @@ -2316,8 +2316,9 @@ mpssas_scsiio_complete(struct mps_softc *sc, struct mps_command *cm) (csio->cdb_io.cdb_bytes[1] & SI_EVPD) && (csio->cdb_io.cdb_bytes[2] == SVPD_SUPPORTED_PAGE_LIST) && ((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) && - (csio->data_ptr != NULL) && (((uint8_t *)cm->cm_data)[0] == - T_SEQUENTIAL) && (sc->control_TLR) && + (csio->data_ptr != NULL) && + ((csio->data_ptr[0] & 0x1f) == T_SEQUENTIAL) && + (sc->control_TLR) && (sc->mapping_table[csio->ccb_h.target_id].device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET)) { vpd_list = (struct scsi_vpd_supported_page_list *) @@ -2328,6 +2329,7 @@ mpssas_scsiio_complete(struct mps_softc *sc, struct mps_command *cm) TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON; alloc_len = ((u16)csio->cdb_io.cdb_bytes[3] << 8) + csio->cdb_io.cdb_bytes[4]; + alloc_len -= csio->resid; for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) { if (vpd_list->list[i] == 0x90) { *TLR_bits = TLR_on; diff --git a/sys/dev/mrsas/mrsas.c b/sys/dev/mrsas/mrsas.c new file mode 100644 index 0000000000000..b74012870d06f --- /dev/null +++ b/sys/dev/mrsas/mrsas.c @@ -0,0 +1,3672 @@ +/* + * Copyright (c) 2014, LSI Corp. + * All rights reserved. + * Author: Marian Choy + * Support: freebsdraid@lsi.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of the <ORGANIZATION> nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Send feedback to: <megaraidfbsd@lsi.com> + * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035 + * ATTN: MegaRaid FreeBSD + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <dev/mrsas/mrsas.h> +#include <dev/mrsas/mrsas_ioctl.h> + +#include <cam/cam.h> +#include <cam/cam_ccb.h> + +#include <sys/sysctl.h> +#include <sys/types.h> +#include <sys/kthread.h> +#include <sys/taskqueue.h> + + +/* + * Function prototypes + */ +static d_open_t mrsas_open; +static d_close_t mrsas_close; +static d_read_t mrsas_read; +static d_write_t mrsas_write; +static d_ioctl_t mrsas_ioctl; + +static struct mrsas_ident *mrsas_find_ident(device_t); +static void mrsas_shutdown_ctlr(struct mrsas_softc *sc, u_int32_t opcode); +static void mrsas_flush_cache(struct mrsas_softc *sc); +static void mrsas_reset_reply_desc(struct mrsas_softc *sc); +static void mrsas_ocr_thread(void *arg); +static int mrsas_get_map_info(struct mrsas_softc *sc); +static int mrsas_get_ld_map_info(struct mrsas_softc *sc); +static int mrsas_sync_map_info(struct mrsas_softc *sc); +static int mrsas_get_pd_list(struct mrsas_softc *sc); +static int mrsas_get_ld_list(struct mrsas_softc *sc); +static int mrsas_setup_irq(struct mrsas_softc *sc); +static int mrsas_alloc_mem(struct mrsas_softc *sc); +static int mrsas_init_fw(struct mrsas_softc *sc); +static int mrsas_setup_raidmap(struct mrsas_softc *sc); +static int mrsas_complete_cmd(struct mrsas_softc *sc); +static int mrsas_clear_intr(struct mrsas_softc *sc); +static int mrsas_get_ctrl_info(struct mrsas_softc *sc, + struct mrsas_ctrl_info *ctrl_info); +static int mrsas_issue_blocked_abort_cmd(struct mrsas_softc *sc, + struct mrsas_mfi_cmd *cmd_to_abort); +u_int32_t mrsas_read_reg(struct mrsas_softc *sc, int offset); +u_int8_t mrsas_build_mptmfi_passthru(struct mrsas_softc *sc, + struct mrsas_mfi_cmd *mfi_cmd); +int mrsas_transition_to_ready(struct mrsas_softc *sc, int ocr); +int mrsas_init_adapter(struct mrsas_softc *sc); +int mrsas_alloc_mpt_cmds(struct mrsas_softc *sc); +int mrsas_alloc_ioc_cmd(struct mrsas_softc *sc); +int mrsas_alloc_ctlr_info_cmd(struct mrsas_softc *sc); +int mrsas_ioc_init(struct mrsas_softc *sc); +int mrsas_bus_scan(struct mrsas_softc *sc); +int mrsas_issue_dcmd(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd); +int mrsas_issue_polled(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd); +int mrsas_reset_ctrl(struct mrsas_softc *sc); +int mrsas_wait_for_outstanding(struct mrsas_softc *sc); +int mrsas_issue_blocked_cmd(struct mrsas_softc *sc, + struct mrsas_mfi_cmd *cmd); +int mrsas_alloc_tmp_dcmd(struct mrsas_softc *sc, struct mrsas_tmp_dcmd *tcmd, + int size); +void mrsas_release_mfi_cmd(struct mrsas_mfi_cmd *cmd); +void mrsas_wakeup(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd); +void mrsas_complete_aen(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd); +void mrsas_complete_abort(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd); +void mrsas_disable_intr(struct mrsas_softc *sc); +void mrsas_enable_intr(struct mrsas_softc *sc); +void mrsas_free_ioc_cmd(struct mrsas_softc *sc); +void mrsas_free_mem(struct mrsas_softc *sc); +void mrsas_free_tmp_dcmd(struct mrsas_tmp_dcmd *tmp); +void mrsas_isr(void *arg); +void mrsas_teardown_intr(struct mrsas_softc *sc); +void mrsas_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error); +void mrsas_kill_hba (struct mrsas_softc *sc); +void mrsas_aen_handler(struct mrsas_softc *sc); +void mrsas_write_reg(struct mrsas_softc *sc, int offset, + u_int32_t value); +void mrsas_fire_cmd(struct mrsas_softc *sc, u_int32_t req_desc_lo, + u_int32_t req_desc_hi); +void mrsas_free_ctlr_info_cmd(struct mrsas_softc *sc); +void mrsas_complete_mptmfi_passthru(struct mrsas_softc *sc, + struct mrsas_mfi_cmd *cmd, u_int8_t status); +void mrsas_map_mpt_cmd_status(struct mrsas_mpt_cmd *cmd, u_int8_t status, + u_int8_t extStatus); +struct mrsas_mfi_cmd* mrsas_get_mfi_cmd(struct mrsas_softc *sc); +MRSAS_REQUEST_DESCRIPTOR_UNION * mrsas_build_mpt_cmd(struct mrsas_softc *sc, + struct mrsas_mfi_cmd *cmd); + +extern int mrsas_cam_attach(struct mrsas_softc *sc); +extern void mrsas_cam_detach(struct mrsas_softc *sc); +extern void mrsas_cmd_done(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd); +extern void mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd); +extern int mrsas_alloc_mfi_cmds(struct mrsas_softc *sc); +extern void mrsas_release_mpt_cmd(struct mrsas_mpt_cmd *cmd); +extern struct mrsas_mpt_cmd *mrsas_get_mpt_cmd(struct mrsas_softc *sc); +extern int mrsas_passthru(struct mrsas_softc *sc, void *arg); +extern uint8_t MR_ValidateMapInfo(struct mrsas_softc *sc); +extern u_int16_t MR_GetLDTgtId(u_int32_t ld, MR_FW_RAID_MAP_ALL *map); +extern MR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map); +extern void mrsas_xpt_freeze(struct mrsas_softc *sc); +extern void mrsas_xpt_release(struct mrsas_softc *sc); +extern MRSAS_REQUEST_DESCRIPTOR_UNION *mrsas_get_request_desc(struct mrsas_softc *sc, + u_int16_t index); +extern int mrsas_bus_scan_sim(struct mrsas_softc *sc, struct cam_sim *sim); +static int mrsas_alloc_evt_log_info_cmd(struct mrsas_softc *sc); +static void mrsas_free_evt_log_info_cmd(struct mrsas_softc *sc); +SYSCTL_NODE(_hw, OID_AUTO, mrsas, CTLFLAG_RD, 0, "MRSAS Driver Parameters"); + + +/** + * PCI device struct and table + * + */ +typedef struct mrsas_ident { + uint16_t vendor; + uint16_t device; + uint16_t subvendor; + uint16_t subdevice; + const char *desc; +} MRSAS_CTLR_ID; + +MRSAS_CTLR_ID device_table[] = { + {0x1000, MRSAS_TBOLT, 0xffff, 0xffff, "LSI Thunderbolt SAS Controller"}, + {0x1000, MRSAS_INVADER, 0xffff, 0xffff, "LSI Invader SAS Controller"}, + {0x1000, MRSAS_FURY, 0xffff, 0xffff, "LSI Fury SAS Controller"}, + {0, 0, 0, 0, NULL} +}; + +/** + * Character device entry points + * + */ +static struct cdevsw mrsas_cdevsw = { + .d_version = D_VERSION, + .d_open = mrsas_open, + .d_close = mrsas_close, + .d_read = mrsas_read, + .d_write = mrsas_write, + .d_ioctl = mrsas_ioctl, + .d_name = "mrsas", +}; + +MALLOC_DEFINE(M_MRSAS, "mrsasbuf", "Buffers for the MRSAS driver"); + +/** + * In the cdevsw routines, we find our softc by using the si_drv1 member + * of struct cdev. We set this variable to point to our softc in our + * attach routine when we create the /dev entry. + */ +int +mrsas_open(struct cdev *dev, int oflags, int devtype, d_thread_t *td) +{ + struct mrsas_softc *sc; + + sc = dev->si_drv1; + return (0); +} + +int +mrsas_close(struct cdev *dev, int fflag, int devtype, d_thread_t *td) +{ + struct mrsas_softc *sc; + + sc = dev->si_drv1; + return (0); +} + +int +mrsas_read(struct cdev *dev, struct uio *uio, int ioflag) +{ + struct mrsas_softc *sc; + + sc = dev->si_drv1; + return (0); +} +int +mrsas_write(struct cdev *dev, struct uio *uio, int ioflag) +{ + struct mrsas_softc *sc; + + sc = dev->si_drv1; + return (0); +} + +/** + * Register Read/Write Functions + * + */ +void +mrsas_write_reg(struct mrsas_softc *sc, int offset, + u_int32_t value) +{ + bus_space_tag_t bus_tag = sc->bus_tag; + bus_space_handle_t bus_handle = sc->bus_handle; + + bus_space_write_4(bus_tag, bus_handle, offset, value); +} + +u_int32_t +mrsas_read_reg(struct mrsas_softc *sc, int offset) +{ + bus_space_tag_t bus_tag = sc->bus_tag; + bus_space_handle_t bus_handle = sc->bus_handle; + + return((u_int32_t)bus_space_read_4(bus_tag, bus_handle, offset)); +} + + +/** + * Interrupt Disable/Enable/Clear Functions + * + */ +void mrsas_disable_intr(struct mrsas_softc *sc) +{ + u_int32_t mask = 0xFFFFFFFF; + u_int32_t status; + + mrsas_write_reg(sc, offsetof(mrsas_reg_set, outbound_intr_mask), mask); + /* Dummy read to force pci flush */ + status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_mask)); +} + +void mrsas_enable_intr(struct mrsas_softc *sc) +{ + u_int32_t mask = MFI_FUSION_ENABLE_INTERRUPT_MASK; + u_int32_t status; + + mrsas_write_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status), ~0); + status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status)); + + mrsas_write_reg(sc, offsetof(mrsas_reg_set, outbound_intr_mask), ~mask); + status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_mask)); +} + +static int mrsas_clear_intr(struct mrsas_softc *sc) +{ + u_int32_t status, fw_status, fw_state; + + /* Read received interrupt */ + status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status)); + + /* If FW state change interrupt is received, write to it again to clear */ + if (status & MRSAS_FW_STATE_CHNG_INTERRUPT) { + fw_status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, + outbound_scratch_pad)); + fw_state = fw_status & MFI_STATE_MASK; + if (fw_state == MFI_STATE_FAULT) { + device_printf(sc->mrsas_dev, "FW is in FAULT state!\n"); + if(sc->ocr_thread_active) + wakeup(&sc->ocr_chan); + } + mrsas_write_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status), status); + mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status)); + return(1); + } + + /* Not our interrupt, so just return */ + if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK)) + return(0); + + /* We got a reply interrupt */ + return(1); +} + +/** + * PCI Support Functions + * + */ +static struct mrsas_ident * mrsas_find_ident(device_t dev) +{ + struct mrsas_ident *pci_device; + + for (pci_device=device_table; pci_device->vendor != 0; pci_device++) + { + if ((pci_device->vendor == pci_get_vendor(dev)) && + (pci_device->device == pci_get_device(dev)) && + ((pci_device->subvendor == pci_get_subvendor(dev)) || + (pci_device->subvendor == 0xffff)) && + ((pci_device->subdevice == pci_get_subdevice(dev)) || + (pci_device->subdevice == 0xffff))) + return (pci_device); + } + return (NULL); +} + +static int mrsas_probe(device_t dev) +{ + static u_int8_t first_ctrl = 1; + struct mrsas_ident *id; + + if ((id = mrsas_find_ident(dev)) != NULL) { + if (first_ctrl) { + printf("LSI MegaRAID SAS FreeBSD mrsas driver version: %s\n", MRSAS_VERSION); + first_ctrl = 0; + } + device_set_desc(dev, id->desc); + /* between BUS_PROBE_DEFAULT and BUS_PROBE_LOW_PRIORITY */ + return (-30); + } + return (ENXIO); +} + +/** + * mrsas_setup_sysctl: setup sysctl values for mrsas + * input: Adapter instance soft state + * + * Setup sysctl entries for mrsas driver. + */ +static void +mrsas_setup_sysctl(struct mrsas_softc *sc) +{ + struct sysctl_ctx_list *sysctl_ctx = NULL; + struct sysctl_oid *sysctl_tree = NULL; + char tmpstr[80], tmpstr2[80]; + + /* + * Setup the sysctl variable so the user can change the debug level + * on the fly. + */ + snprintf(tmpstr, sizeof(tmpstr), "MRSAS controller %d", + device_get_unit(sc->mrsas_dev)); + snprintf(tmpstr2, sizeof(tmpstr2), "%d", device_get_unit(sc->mrsas_dev)); + + sysctl_ctx = device_get_sysctl_ctx(sc->mrsas_dev); + if (sysctl_ctx != NULL) + sysctl_tree = device_get_sysctl_tree(sc->mrsas_dev); + + if (sysctl_tree == NULL) { + sysctl_ctx_init(&sc->sysctl_ctx); + sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_hw_mrsas), OID_AUTO, tmpstr2, + CTLFLAG_RD, 0, tmpstr); + if (sc->sysctl_tree == NULL) + return; + sysctl_ctx = &sc->sysctl_ctx; + sysctl_tree = sc->sysctl_tree; + } + SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "disable_ocr", CTLFLAG_RW, &sc->disableOnlineCtrlReset, 0, + "Disable the use of OCR"); + + SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "driver_version", CTLFLAG_RD, MRSAS_VERSION, + strlen(MRSAS_VERSION), "driver version"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "reset_count", CTLFLAG_RD, + &sc->reset_count, 0, "number of ocr from start of the day"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "fw_outstanding", CTLFLAG_RD, + &sc->fw_outstanding, 0, "FW outstanding commands"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "io_cmds_highwater", CTLFLAG_RD, + &sc->io_cmds_highwater, 0, "Max FW outstanding commands"); + + SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "mrsas_debug", CTLFLAG_RW, &sc->mrsas_debug, 0, + "Driver debug level"); + + SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "mrsas_io_timeout", CTLFLAG_RW, &sc->mrsas_io_timeout, + 0, "Driver IO timeout value in mili-second."); + + SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "mrsas_fw_fault_check_delay", CTLFLAG_RW, + &sc->mrsas_fw_fault_check_delay, + 0, "FW fault check thread delay in seconds. <default is 1 sec>"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "reset_in_progress", CTLFLAG_RD, + &sc->reset_in_progress, 0, "ocr in progress status"); + +} + +/** + * mrsas_get_tunables: get tunable parameters. + * input: Adapter instance soft state + * + * Get tunable parameters. This will help to debug driver at boot time. + */ +static void +mrsas_get_tunables(struct mrsas_softc *sc) +{ + char tmpstr[80]; + + /* XXX default to some debugging for now */ + sc->mrsas_debug = MRSAS_FAULT; + sc->mrsas_io_timeout = MRSAS_IO_TIMEOUT; + sc->mrsas_fw_fault_check_delay = 1; + sc->reset_count = 0; + sc->reset_in_progress = 0; + + /* + * Grab the global variables. + */ + TUNABLE_INT_FETCH("hw.mrsas.debug_level", &sc->mrsas_debug); + + /* Grab the unit-instance variables */ + snprintf(tmpstr, sizeof(tmpstr), "dev.mrsas.%d.debug_level", + device_get_unit(sc->mrsas_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->mrsas_debug); +} + +/** + * mrsas_alloc_evt_log_info cmd: Allocates memory to get event log information. + * Used to get sequence number at driver load time. + * input: Adapter soft state + * + * Allocates DMAable memory for the event log info internal command. + */ +int mrsas_alloc_evt_log_info_cmd(struct mrsas_softc *sc) +{ + int el_info_size; + + /* Allocate get event log info command */ + el_info_size = sizeof(struct mrsas_evt_log_info); + if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent + 1, 0, // algnmnt, boundary + BUS_SPACE_MAXADDR_32BIT,// lowaddr + BUS_SPACE_MAXADDR, // highaddr + NULL, NULL, // filter, filterarg + el_info_size, // maxsize + 1, // msegments + el_info_size, // maxsegsize + BUS_DMA_ALLOCNOW, // flags + NULL, NULL, // lockfunc, lockarg + &sc->el_info_tag)) { + device_printf(sc->mrsas_dev, "Cannot allocate event log info tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->el_info_tag, (void **)&sc->el_info_mem, + BUS_DMA_NOWAIT, &sc->el_info_dmamap)) { + device_printf(sc->mrsas_dev, "Cannot allocate event log info cmd mem\n"); + return (ENOMEM); + } + if (bus_dmamap_load(sc->el_info_tag, sc->el_info_dmamap, + sc->el_info_mem, el_info_size, mrsas_addr_cb, + &sc->el_info_phys_addr, BUS_DMA_NOWAIT)) { + device_printf(sc->mrsas_dev, "Cannot load event log info cmd mem\n"); + return (ENOMEM); + } + + memset(sc->el_info_mem, 0, el_info_size); + return (0); +} + +/** + * mrsas_free_evt_info_cmd: Free memory for Event log info command + * input: Adapter soft state + * + * Deallocates memory for the event log info internal command. + */ +void mrsas_free_evt_log_info_cmd(struct mrsas_softc *sc) +{ + if (sc->el_info_phys_addr) + bus_dmamap_unload(sc->el_info_tag, sc->el_info_dmamap); + if (sc->el_info_mem != NULL) + bus_dmamem_free(sc->el_info_tag, sc->el_info_mem, sc->el_info_dmamap); + if (sc->el_info_tag != NULL) + bus_dma_tag_destroy(sc->el_info_tag); +} + +/** + * mrsas_get_seq_num: Get latest event sequence number + * @sc: Adapter soft state + * @eli: Firmware event log sequence number information. + * Firmware maintains a log of all events in a non-volatile area. + * Driver get the sequence number using DCMD + * "MR_DCMD_CTRL_EVENT_GET_INFO" at driver load time. + */ + +static int +mrsas_get_seq_num(struct mrsas_softc *sc, + struct mrsas_evt_log_info *eli) +{ + struct mrsas_mfi_cmd *cmd; + struct mrsas_dcmd_frame *dcmd; + + cmd = mrsas_get_mfi_cmd(sc); + + if (!cmd) { + device_printf(sc->mrsas_dev, "Failed to get a free cmd\n"); + return -ENOMEM; + } + + dcmd = &cmd->frame->dcmd; + + if (mrsas_alloc_evt_log_info_cmd(sc) != SUCCESS) { + device_printf(sc->mrsas_dev, "Cannot allocate evt log info cmd\n"); + mrsas_release_mfi_cmd(cmd); + return -ENOMEM; + } + + memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); + + dcmd->cmd = MFI_CMD_DCMD; + dcmd->cmd_status = 0x0; + dcmd->sge_count = 1; + dcmd->flags = MFI_FRAME_DIR_READ; + dcmd->timeout = 0; + dcmd->pad_0 = 0; + dcmd->data_xfer_len = sizeof(struct mrsas_evt_log_info); + dcmd->opcode = MR_DCMD_CTRL_EVENT_GET_INFO; + dcmd->sgl.sge32[0].phys_addr = sc->el_info_phys_addr; + dcmd->sgl.sge32[0].length = sizeof(struct mrsas_evt_log_info); + + mrsas_issue_blocked_cmd(sc, cmd); + + /* + * Copy the data back into callers buffer + */ + memcpy(eli, sc->el_info_mem, sizeof(struct mrsas_evt_log_info)); + mrsas_free_evt_log_info_cmd(sc); + mrsas_release_mfi_cmd(cmd); + + return 0; +} + + +/** + * mrsas_register_aen: Register for asynchronous event notification + * @sc: Adapter soft state + * @seq_num: Starting sequence number + * @class_locale: Class of the event + * This function subscribes for events beyond the @seq_num + * and type @class_locale. + * + * */ +static int +mrsas_register_aen(struct mrsas_softc *sc, u_int32_t seq_num, + u_int32_t class_locale_word) +{ + int ret_val; + struct mrsas_mfi_cmd *cmd; + struct mrsas_dcmd_frame *dcmd; + union mrsas_evt_class_locale curr_aen; + union mrsas_evt_class_locale prev_aen; + +/* + * If there an AEN pending already (aen_cmd), check if the + * class_locale of that pending AEN is inclusive of the new + * AEN request we currently have. If it is, then we don't have + * to do anything. In other words, whichever events the current + * AEN request is subscribing to, have already been subscribed + * to. + * If the old_cmd is _not_ inclusive, then we have to abort + * that command, form a class_locale that is superset of both + * old and current and re-issue to the FW + * */ + + curr_aen.word = class_locale_word; + + if (sc->aen_cmd) { + + prev_aen.word = sc->aen_cmd->frame->dcmd.mbox.w[1]; + +/* + * A class whose enum value is smaller is inclusive of all + * higher values. If a PROGRESS (= -1) was previously + * registered, then a new registration requests for higher + * classes need not be sent to FW. They are automatically + * included. + * Locale numbers don't have such hierarchy. They are bitmap values + */ + if ((prev_aen.members.class <= curr_aen.members.class) && + !((prev_aen.members.locale & curr_aen.members.locale) ^ + curr_aen.members.locale)) { + /* + * Previously issued event registration includes + * current request. Nothing to do. + */ + return 0; + } else { + curr_aen.members.locale |= prev_aen.members.locale; + + if (prev_aen.members.class < curr_aen.members.class) + curr_aen.members.class = prev_aen.members.class; + + sc->aen_cmd->abort_aen = 1; + ret_val = mrsas_issue_blocked_abort_cmd(sc, + sc->aen_cmd); + + if (ret_val) { + printf("mrsas: Failed to abort " + "previous AEN command\n"); + return ret_val; + } + } + } + + cmd = mrsas_get_mfi_cmd(sc); + + if (!cmd) + return -ENOMEM; + + dcmd = &cmd->frame->dcmd; + + memset(sc->evt_detail_mem, 0, sizeof(struct mrsas_evt_detail)); + +/* + * Prepare DCMD for aen registration + */ + memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); + + dcmd->cmd = MFI_CMD_DCMD; + dcmd->cmd_status = 0x0; + dcmd->sge_count = 1; + dcmd->flags = MFI_FRAME_DIR_READ; + dcmd->timeout = 0; + dcmd->pad_0 = 0; + dcmd->data_xfer_len = sizeof(struct mrsas_evt_detail); + dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT; + dcmd->mbox.w[0] = seq_num; + sc->last_seq_num = seq_num; + dcmd->mbox.w[1] = curr_aen.word; + dcmd->sgl.sge32[0].phys_addr = (u_int32_t) sc->evt_detail_phys_addr; + dcmd->sgl.sge32[0].length = sizeof(struct mrsas_evt_detail); + + if (sc->aen_cmd != NULL) { + mrsas_release_mfi_cmd(cmd); + return 0; + } + + /* + * Store reference to the cmd used to register for AEN. When an + * application wants us to register for AEN, we have to abort this + * cmd and re-register with a new EVENT LOCALE supplied by that app + */ + sc->aen_cmd = cmd; + + /* + Issue the aen registration frame + */ + if (mrsas_issue_dcmd(sc, cmd)){ + device_printf(sc->mrsas_dev, "Cannot issue AEN DCMD command.\n"); + return(1); + } + + return 0; +} +/** + * mrsas_start_aen - Subscribes to AEN during driver load time + * @instance: Adapter soft state + */ +static int mrsas_start_aen(struct mrsas_softc *sc) +{ + struct mrsas_evt_log_info eli; + union mrsas_evt_class_locale class_locale; + + + /* Get the latest sequence number from FW*/ + + memset(&eli, 0, sizeof(eli)); + + if (mrsas_get_seq_num(sc, &eli)) + return -1; + + /* Register AEN with FW for latest sequence number plus 1*/ + class_locale.members.reserved = 0; + class_locale.members.locale = MR_EVT_LOCALE_ALL; + class_locale.members.class = MR_EVT_CLASS_DEBUG; + + return mrsas_register_aen(sc, eli.newest_seq_num + 1, + class_locale.word); +} + +/** + * mrsas_attach: PCI entry point + * input: device struct pointer + * + * Performs setup of PCI and registers, initializes mutexes and + * linked lists, registers interrupts and CAM, and initializes + * the adapter/controller to its proper state. + */ +static int mrsas_attach(device_t dev) +{ + struct mrsas_softc *sc = device_get_softc(dev); + uint32_t cmd, bar, error; + + /* Look up our softc and initialize its fields. */ + sc->mrsas_dev = dev; + sc->device_id = pci_get_device(dev); + + mrsas_get_tunables(sc); + + /* + * Set up PCI and registers + */ + cmd = pci_read_config(dev, PCIR_COMMAND, 2); + if ( (cmd & PCIM_CMD_PORTEN) == 0) { + return (ENXIO); + } + /* Force the busmaster enable bit on. */ + cmd |= PCIM_CMD_BUSMASTEREN; + pci_write_config(dev, PCIR_COMMAND, cmd, 2); + + //bar = pci_read_config(dev, MRSAS_PCI_BAR0, 4); + bar = pci_read_config(dev, MRSAS_PCI_BAR1, 4); + + sc->reg_res_id = MRSAS_PCI_BAR1; /* BAR1 offset */ + if ((sc->reg_res = bus_alloc_resource(dev, SYS_RES_MEMORY, + &(sc->reg_res_id), 0, ~0, 1, RF_ACTIVE)) + == NULL) { + device_printf(dev, "Cannot allocate PCI registers\n"); + goto attach_fail; + } + sc->bus_tag = rman_get_bustag(sc->reg_res); + sc->bus_handle = rman_get_bushandle(sc->reg_res); + + /* Intialize mutexes */ + mtx_init(&sc->sim_lock, "mrsas_sim_lock", NULL, MTX_DEF); + mtx_init(&sc->pci_lock, "mrsas_pci_lock", NULL, MTX_DEF); + mtx_init(&sc->io_lock, "mrsas_io_lock", NULL, MTX_DEF); + mtx_init(&sc->aen_lock, "mrsas_aen_lock", NULL, MTX_DEF); + mtx_init(&sc->ioctl_lock, "mrsas_ioctl_lock", NULL, MTX_SPIN); + mtx_init(&sc->mpt_cmd_pool_lock, "mrsas_mpt_cmd_pool_lock", NULL, MTX_DEF); + mtx_init(&sc->mfi_cmd_pool_lock, "mrsas_mfi_cmd_pool_lock", NULL, MTX_DEF); + mtx_init(&sc->raidmap_lock, "mrsas_raidmap_lock", NULL, MTX_DEF); + + /* Intialize linked list */ + TAILQ_INIT(&sc->mrsas_mpt_cmd_list_head); + TAILQ_INIT(&sc->mrsas_mfi_cmd_list_head); + + atomic_set(&sc->fw_outstanding,0); + + sc->io_cmds_highwater = 0; + + /* Create a /dev entry for this device. */ + sc->mrsas_cdev = make_dev(&mrsas_cdevsw, device_get_unit(dev), UID_ROOT, + GID_OPERATOR, (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP), "mrsas%u", + device_get_unit(dev)); + if (sc->mrsas_cdev) + sc->mrsas_cdev->si_drv1 = sc; + + sc->adprecovery = MRSAS_HBA_OPERATIONAL; + sc->UnevenSpanSupport = 0; + + /* Initialize Firmware */ + if (mrsas_init_fw(sc) != SUCCESS) { + goto attach_fail_fw; + } + + /* Register SCSI mid-layer */ + if ((mrsas_cam_attach(sc) != SUCCESS)) { + goto attach_fail_cam; + } + + /* Register IRQs */ + if (mrsas_setup_irq(sc) != SUCCESS) { + goto attach_fail_irq; + } + + /* Enable Interrupts */ + mrsas_enable_intr(sc); + + error = mrsas_kproc_create(mrsas_ocr_thread, sc, + &sc->ocr_thread, 0, 0, "mrsas_ocr%d", + device_get_unit(sc->mrsas_dev)); + if (error) { + printf("Error %d starting rescan thread\n", error); + goto attach_fail_irq; + } + + mrsas_setup_sysctl(sc); + + /* Initiate AEN (Asynchronous Event Notification)*/ + + if (mrsas_start_aen(sc)) { + printf("Error: start aen failed\n"); + goto fail_start_aen; + } + + return (0); + +fail_start_aen: +attach_fail_irq: + mrsas_teardown_intr(sc); +attach_fail_cam: + mrsas_cam_detach(sc); +attach_fail_fw: +//attach_fail_raidmap: + mrsas_free_mem(sc); + mtx_destroy(&sc->sim_lock); + mtx_destroy(&sc->aen_lock); + mtx_destroy(&sc->pci_lock); + mtx_destroy(&sc->io_lock); + mtx_destroy(&sc->ioctl_lock); + mtx_destroy(&sc->mpt_cmd_pool_lock); + mtx_destroy(&sc->mfi_cmd_pool_lock); + mtx_destroy(&sc->raidmap_lock); +attach_fail: + destroy_dev(sc->mrsas_cdev); + if (sc->reg_res){ + bus_release_resource(sc->mrsas_dev, SYS_RES_MEMORY, + sc->reg_res_id, sc->reg_res); + } + return (ENXIO); +} + +/** + * mrsas_detach: De-allocates and teardown resources + * input: device struct pointer + * + * This function is the entry point for device disconnect and detach. It + * performs memory de-allocations, shutdown of the controller and various + * teardown and destroy resource functions. + */ +static int mrsas_detach(device_t dev) +{ + struct mrsas_softc *sc; + int i = 0; + + sc = device_get_softc(dev); + sc->remove_in_progress = 1; + if(sc->ocr_thread_active) + wakeup(&sc->ocr_chan); + while(sc->reset_in_progress){ + i++; + if (!(i % MRSAS_RESET_NOTICE_INTERVAL)) { + mrsas_dprint(sc, MRSAS_INFO, + "[%2d]waiting for ocr to be finished\n",i); + } + pause("mr_shutdown", hz); + } + i = 0; + while(sc->ocr_thread_active){ + i++; + if (!(i % MRSAS_RESET_NOTICE_INTERVAL)) { + mrsas_dprint(sc, MRSAS_INFO, + "[%2d]waiting for " + "mrsas_ocr thread to quit ocr %d\n",i, + sc->ocr_thread_active); + } + pause("mr_shutdown", hz); + } + mrsas_flush_cache(sc); + mrsas_shutdown_ctlr(sc, MR_DCMD_CTRL_SHUTDOWN); + mrsas_disable_intr(sc); + mrsas_cam_detach(sc); + mrsas_teardown_intr(sc); + mrsas_free_mem(sc); + mtx_destroy(&sc->sim_lock); + mtx_destroy(&sc->aen_lock); + mtx_destroy(&sc->pci_lock); + mtx_destroy(&sc->io_lock); + mtx_destroy(&sc->ioctl_lock); + mtx_destroy(&sc->mpt_cmd_pool_lock); + mtx_destroy(&sc->mfi_cmd_pool_lock); + mtx_destroy(&sc->raidmap_lock); + if (sc->reg_res){ + bus_release_resource(sc->mrsas_dev, + SYS_RES_MEMORY, sc->reg_res_id, sc->reg_res); + } + destroy_dev(sc->mrsas_cdev); + if (sc->sysctl_tree != NULL) + sysctl_ctx_free(&sc->sysctl_ctx); + return (0); +} + +/** + * mrsas_free_mem: Frees allocated memory + * input: Adapter instance soft state + * + * This function is called from mrsas_detach() to free previously allocated + * memory. + */ +void mrsas_free_mem(struct mrsas_softc *sc) +{ + int i; + u_int32_t max_cmd; + struct mrsas_mfi_cmd *mfi_cmd; + struct mrsas_mpt_cmd *mpt_cmd; + + /* + * Free RAID map memory + */ + for (i=0; i < 2; i++) + { + if (sc->raidmap_phys_addr[i]) + bus_dmamap_unload(sc->raidmap_tag[i], sc->raidmap_dmamap[i]); + if (sc->raidmap_mem[i] != NULL) + bus_dmamem_free(sc->raidmap_tag[i], sc->raidmap_mem[i], sc->raidmap_dmamap[i]); + if (sc->raidmap_tag[i] != NULL) + bus_dma_tag_destroy(sc->raidmap_tag[i]); + } + + /* + * Free version buffer memroy + */ + if (sc->verbuf_phys_addr) + bus_dmamap_unload(sc->verbuf_tag, sc->verbuf_dmamap); + if (sc->verbuf_mem != NULL) + bus_dmamem_free(sc->verbuf_tag, sc->verbuf_mem, sc->verbuf_dmamap); + if (sc->verbuf_tag != NULL) + bus_dma_tag_destroy(sc->verbuf_tag); + + + /* + * Free sense buffer memory + */ + if (sc->sense_phys_addr) + bus_dmamap_unload(sc->sense_tag, sc->sense_dmamap); + if (sc->sense_mem != NULL) + bus_dmamem_free(sc->sense_tag, sc->sense_mem, sc->sense_dmamap); + if (sc->sense_tag != NULL) + bus_dma_tag_destroy(sc->sense_tag); + + /* + * Free chain frame memory + */ + if (sc->chain_frame_phys_addr) + bus_dmamap_unload(sc->chain_frame_tag, sc->chain_frame_dmamap); + if (sc->chain_frame_mem != NULL) + bus_dmamem_free(sc->chain_frame_tag, sc->chain_frame_mem, sc->chain_frame_dmamap); + if (sc->chain_frame_tag != NULL) + bus_dma_tag_destroy(sc->chain_frame_tag); + + /* + * Free IO Request memory + */ + if (sc->io_request_phys_addr) + bus_dmamap_unload(sc->io_request_tag, sc->io_request_dmamap); + if (sc->io_request_mem != NULL) + bus_dmamem_free(sc->io_request_tag, sc->io_request_mem, sc->io_request_dmamap); + if (sc->io_request_tag != NULL) + bus_dma_tag_destroy(sc->io_request_tag); + + /* + * Free Reply Descriptor memory + */ + if (sc->reply_desc_phys_addr) + bus_dmamap_unload(sc->reply_desc_tag, sc->reply_desc_dmamap); + if (sc->reply_desc_mem != NULL) + bus_dmamem_free(sc->reply_desc_tag, sc->reply_desc_mem, sc->reply_desc_dmamap); + if (sc->reply_desc_tag != NULL) + bus_dma_tag_destroy(sc->reply_desc_tag); + + /* + * Free event detail memory + */ + if (sc->evt_detail_phys_addr) + bus_dmamap_unload(sc->evt_detail_tag, sc->evt_detail_dmamap); + if (sc->evt_detail_mem != NULL) + bus_dmamem_free(sc->evt_detail_tag, sc->evt_detail_mem, sc->evt_detail_dmamap); + if (sc->evt_detail_tag != NULL) + bus_dma_tag_destroy(sc->evt_detail_tag); + + /* + * Free MFI frames + */ + if (sc->mfi_cmd_list) { + for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) { + mfi_cmd = sc->mfi_cmd_list[i]; + mrsas_free_frame(sc, mfi_cmd); + } + } + if (sc->mficmd_frame_tag != NULL) + bus_dma_tag_destroy(sc->mficmd_frame_tag); + + /* + * Free MPT internal command list + */ + max_cmd = sc->max_fw_cmds; + if (sc->mpt_cmd_list) { + for (i = 0; i < max_cmd; i++) { + mpt_cmd = sc->mpt_cmd_list[i]; + bus_dmamap_destroy(sc->data_tag, mpt_cmd->data_dmamap); + free(sc->mpt_cmd_list[i], M_MRSAS); + } + free(sc->mpt_cmd_list, M_MRSAS); + sc->mpt_cmd_list = NULL; + } + + /* + * Free MFI internal command list + */ + + if (sc->mfi_cmd_list) { + for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) { + free(sc->mfi_cmd_list[i], M_MRSAS); + } + free(sc->mfi_cmd_list, M_MRSAS); + sc->mfi_cmd_list = NULL; + } + + /* + * Free request descriptor memory + */ + free(sc->req_desc, M_MRSAS); + sc->req_desc = NULL; + + /* + * Destroy parent tag + */ + if (sc->mrsas_parent_tag != NULL) + bus_dma_tag_destroy(sc->mrsas_parent_tag); +} + +/** + * mrsas_teardown_intr: Teardown interrupt + * input: Adapter instance soft state + * + * This function is called from mrsas_detach() to teardown and release + * bus interrupt resourse. + */ +void mrsas_teardown_intr(struct mrsas_softc *sc) +{ + if (sc->intr_handle) + bus_teardown_intr(sc->mrsas_dev, sc->mrsas_irq, sc->intr_handle); + if (sc->mrsas_irq != NULL) + bus_release_resource(sc->mrsas_dev, SYS_RES_IRQ, sc->irq_id, sc->mrsas_irq); + sc->intr_handle = NULL; +} + +/** + * mrsas_suspend: Suspend entry point + * input: Device struct pointer + * + * This function is the entry point for system suspend from the OS. + */ +static int mrsas_suspend(device_t dev) +{ + struct mrsas_softc *sc; + + sc = device_get_softc(dev); + return (0); +} + +/** + * mrsas_resume: Resume entry point + * input: Device struct pointer + * + * This function is the entry point for system resume from the OS. + */ +static int mrsas_resume(device_t dev) +{ + struct mrsas_softc *sc; + + sc = device_get_softc(dev); + return (0); +} + +/** + * mrsas_ioctl: IOCtl commands entry point. + * + * This function is the entry point for IOCtls from the OS. It calls the + * appropriate function for processing depending on the command received. + */ +static int +mrsas_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) +{ + struct mrsas_softc *sc; + int ret = 0, i = 0; + + sc = (struct mrsas_softc *)(dev->si_drv1); + + if (sc->remove_in_progress) { + mrsas_dprint(sc, MRSAS_INFO, + "Driver remove or shutdown called.\n"); + return ENOENT; + } + + mtx_lock_spin(&sc->ioctl_lock); + if (!sc->reset_in_progress) { + mtx_unlock_spin(&sc->ioctl_lock); + goto do_ioctl; + } + + /* Release ioclt_lock, and wait for OCR + * to be finished */ + mtx_unlock_spin(&sc->ioctl_lock); + while(sc->reset_in_progress){ + i++; + if (!(i % MRSAS_RESET_NOTICE_INTERVAL)) { + mrsas_dprint(sc, MRSAS_INFO, + "[%2d]waiting for " + "OCR to be finished %d\n",i, + sc->ocr_thread_active); + } + pause("mr_ioctl", hz); + } + +do_ioctl: + switch (cmd) { + case MRSAS_IOC_FIRMWARE_PASS_THROUGH: + ret = mrsas_passthru(sc, (void *)arg); + break; + case MRSAS_IOC_SCAN_BUS: + ret = mrsas_bus_scan(sc); + break; + } + + return (ret); +} + +/** + * mrsas_setup_irq: Set up interrupt. + * input: Adapter instance soft state + * + * This function sets up interrupts as a bus resource, with flags indicating + * resource permitting contemporaneous sharing and for resource to activate + * atomically. + */ +static int mrsas_setup_irq(struct mrsas_softc *sc) +{ + sc->irq_id = 0; + sc->mrsas_irq = bus_alloc_resource_any(sc->mrsas_dev, SYS_RES_IRQ, + &sc->irq_id, RF_SHAREABLE | RF_ACTIVE); + if (sc->mrsas_irq == NULL){ + device_printf(sc->mrsas_dev, "Cannot allocate interrupt\n"); + return (FAIL); + } + if (bus_setup_intr(sc->mrsas_dev, sc->mrsas_irq, INTR_MPSAFE|INTR_TYPE_CAM, + NULL, mrsas_isr, sc, &sc->intr_handle)) { + device_printf(sc->mrsas_dev, "Cannot set up interrupt\n"); + return (FAIL); + } + + return (0); +} + +/* + * mrsas_isr: ISR entry point + * input: argument pointer + * + * This function is the interrupt service routine entry point. There + * are two types of interrupts, state change interrupt and response + * interrupt. If an interrupt is not ours, we just return. + */ +void mrsas_isr(void *arg) +{ + struct mrsas_softc *sc = (struct mrsas_softc *)arg; + int status; + + /* Clear FW state change interrupt */ + status = mrsas_clear_intr(sc); + + /* Not our interrupt */ + if (!status) + return; + + /* If we are resetting, bail */ + if (test_bit(MRSAS_FUSION_IN_RESET, &sc->reset_flags)) { + printf(" Entered into ISR when OCR is going active. \n"); + mrsas_clear_intr(sc); + return; + } + /* Process for reply request and clear response interrupt */ + if (mrsas_complete_cmd(sc) != SUCCESS) + mrsas_clear_intr(sc); + + return; +} + +/* + * mrsas_complete_cmd: Process reply request + * input: Adapter instance soft state + * + * This function is called from mrsas_isr() to process reply request and + * clear response interrupt. Processing of the reply request entails + * walking through the reply descriptor array for the command request + * pended from Firmware. We look at the Function field to determine + * the command type and perform the appropriate action. Before we + * return, we clear the response interrupt. + */ +static int mrsas_complete_cmd(struct mrsas_softc *sc) +{ + Mpi2ReplyDescriptorsUnion_t *desc; + MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc; + MRSAS_RAID_SCSI_IO_REQUEST *scsi_io_req; + struct mrsas_mpt_cmd *cmd_mpt; + struct mrsas_mfi_cmd *cmd_mfi; + u_int8_t arm, reply_descript_type; + u_int16_t smid, num_completed; + u_int8_t status, extStatus; + union desc_value desc_val; + PLD_LOAD_BALANCE_INFO lbinfo; + u_int32_t device_id; + int threshold_reply_count = 0; + + + /* If we have a hardware error, not need to continue */ + if (sc->adprecovery == MRSAS_HW_CRITICAL_ERROR) + return (DONE); + + desc = sc->reply_desc_mem; + desc += sc->last_reply_idx; + + reply_desc = (MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc; + + desc_val.word = desc->Words; + num_completed = 0; + + reply_descript_type = reply_desc->ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; + + /* Find our reply descriptor for the command and process */ + while((desc_val.u.low != 0xFFFFFFFF) && (desc_val.u.high != 0xFFFFFFFF)) + { + smid = reply_desc->SMID; + cmd_mpt = sc->mpt_cmd_list[smid -1]; + scsi_io_req = (MRSAS_RAID_SCSI_IO_REQUEST *)cmd_mpt->io_request; + + status = scsi_io_req->RaidContext.status; + extStatus = scsi_io_req->RaidContext.exStatus; + + switch (scsi_io_req->Function) + { + case MPI2_FUNCTION_SCSI_IO_REQUEST : /*Fast Path IO.*/ + device_id = cmd_mpt->ccb_ptr->ccb_h.target_id; + lbinfo = &sc->load_balance_info[device_id]; + if (cmd_mpt->load_balance == MRSAS_LOAD_BALANCE_FLAG) { + arm = lbinfo->raid1DevHandle[0] == scsi_io_req->DevHandle ? 0 : 1; + atomic_dec(&lbinfo->scsi_pending_cmds[arm]); + cmd_mpt->load_balance &= ~MRSAS_LOAD_BALANCE_FLAG; + } + //Fall thru and complete IO + case MRSAS_MPI2_FUNCTION_LD_IO_REQUEST: + mrsas_map_mpt_cmd_status(cmd_mpt, status, extStatus); + mrsas_cmd_done(sc, cmd_mpt); + scsi_io_req->RaidContext.status = 0; + scsi_io_req->RaidContext.exStatus = 0; + atomic_dec(&sc->fw_outstanding); + break; + case MRSAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST: /*MFI command */ + cmd_mfi = sc->mfi_cmd_list[cmd_mpt->sync_cmd_idx]; + mrsas_complete_mptmfi_passthru(sc, cmd_mfi, status); + cmd_mpt->flags = 0; + mrsas_release_mpt_cmd(cmd_mpt); + break; + } + + sc->last_reply_idx++; + if (sc->last_reply_idx >= sc->reply_q_depth) + sc->last_reply_idx = 0; + + desc->Words = ~((uint64_t)0x00); /* set it back to all 0xFFFFFFFFs */ + num_completed++; + threshold_reply_count++; + + /* Get the next reply descriptor */ + if (!sc->last_reply_idx) + desc = sc->reply_desc_mem; + else + desc++; + + reply_desc = (MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc; + desc_val.word = desc->Words; + + reply_descript_type = reply_desc->ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; + + if(reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) + break; + + /* + * Write to reply post index after completing threshold reply count + * and still there are more replies in reply queue pending to be + * completed. + */ + if (threshold_reply_count >= THRESHOLD_REPLY_COUNT) { + mrsas_write_reg(sc, offsetof(mrsas_reg_set, reply_post_host_index), + sc->last_reply_idx); + threshold_reply_count = 0; + } + } + + /* No match, just return */ + if (num_completed == 0) + return (DONE); + + /* Clear response interrupt */ + mrsas_write_reg(sc, offsetof(mrsas_reg_set, reply_post_host_index),sc->last_reply_idx); + + return(0); +} + +/* + * mrsas_map_mpt_cmd_status: Allocate DMAable memory. + * input: Adapter instance soft state + * + * This function is called from mrsas_complete_cmd(), for LD IO and FastPath IO. + * It checks the command status and maps the appropriate CAM status for the CCB. + */ +void mrsas_map_mpt_cmd_status(struct mrsas_mpt_cmd *cmd, u_int8_t status, u_int8_t extStatus) +{ + struct mrsas_softc *sc = cmd->sc; + u_int8_t *sense_data; + + switch (status) { + case MFI_STAT_OK: + cmd->ccb_ptr->ccb_h.status = CAM_REQ_CMP; + break; + case MFI_STAT_SCSI_IO_FAILED: + case MFI_STAT_SCSI_DONE_WITH_ERROR: + cmd->ccb_ptr->ccb_h.status = CAM_SCSI_STATUS_ERROR; + sense_data = (u_int8_t *)&cmd->ccb_ptr->csio.sense_data; + if (sense_data) { + /* For now just copy 18 bytes back */ + memcpy(sense_data, cmd->sense, 18); + cmd->ccb_ptr->csio.sense_len = 18; + cmd->ccb_ptr->ccb_h.status |= CAM_AUTOSNS_VALID; + } + break; + case MFI_STAT_LD_OFFLINE: + case MFI_STAT_DEVICE_NOT_FOUND: + if (cmd->ccb_ptr->ccb_h.target_lun) + cmd->ccb_ptr->ccb_h.status |= CAM_LUN_INVALID; + else + cmd->ccb_ptr->ccb_h.status |= CAM_DEV_NOT_THERE; + break; + case MFI_STAT_CONFIG_SEQ_MISMATCH: + /*send status to CAM layer to retry sending command without + * decrementing retry counter*/ + cmd->ccb_ptr->ccb_h.status |= CAM_REQUEUE_REQ; + break; + default: + device_printf(sc->mrsas_dev, "FW cmd complete status %x\n", status); + cmd->ccb_ptr->ccb_h.status = CAM_REQ_CMP_ERR; + cmd->ccb_ptr->csio.scsi_status = status; + } + return; +} + +/* + * mrsas_alloc_mem: Allocate DMAable memory. + * input: Adapter instance soft state + * + * This function creates the parent DMA tag and allocates DMAable memory. + * DMA tag describes constraints of DMA mapping. Memory allocated is mapped + * into Kernel virtual address. Callback argument is physical memory address. + */ +static int mrsas_alloc_mem(struct mrsas_softc *sc) +{ + u_int32_t verbuf_size, io_req_size, reply_desc_size, sense_size, + chain_frame_size, evt_detail_size; + + /* + * Allocate parent DMA tag + */ + if (bus_dma_tag_create(NULL, /* parent */ + 1, /* alignment */ + 0, /* boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MRSAS_MAX_IO_SIZE,/* maxsize */ + MRSAS_MAX_SGL, /* nsegments */ + MRSAS_MAX_IO_SIZE,/* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->mrsas_parent_tag /* tag */ + )) { + device_printf(sc->mrsas_dev, "Cannot allocate parent DMA tag\n"); + return(ENOMEM); + } + + /* + * Allocate for version buffer + */ + verbuf_size = MRSAS_MAX_NAME_LENGTH*(sizeof(bus_addr_t)); + if (bus_dma_tag_create(sc->mrsas_parent_tag, // parent + 1, 0, // algnmnt, boundary + BUS_SPACE_MAXADDR_32BIT,// lowaddr + BUS_SPACE_MAXADDR, // highaddr + NULL, NULL, // filter, filterarg + verbuf_size, // maxsize + 1, // msegments + verbuf_size, // maxsegsize + BUS_DMA_ALLOCNOW, // flags + NULL, NULL, // lockfunc, lockarg + &sc->verbuf_tag)) { + device_printf(sc->mrsas_dev, "Cannot allocate verbuf DMA tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->verbuf_tag, (void **)&sc->verbuf_mem, + BUS_DMA_NOWAIT, &sc->verbuf_dmamap)) { + device_printf(sc->mrsas_dev, "Cannot allocate verbuf memory\n"); + return (ENOMEM); + } + bzero(sc->verbuf_mem, verbuf_size); + if (bus_dmamap_load(sc->verbuf_tag, sc->verbuf_dmamap, sc->verbuf_mem, + verbuf_size, mrsas_addr_cb, &sc->verbuf_phys_addr, BUS_DMA_NOWAIT)){ + device_printf(sc->mrsas_dev, "Cannot load verbuf DMA map\n"); + return(ENOMEM); + } + + /* + * Allocate IO Request Frames + */ + io_req_size = sc->io_frames_alloc_sz; + if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent + 16, 0, // algnmnt, boundary + BUS_SPACE_MAXADDR_32BIT,// lowaddr + BUS_SPACE_MAXADDR, // highaddr + NULL, NULL, // filter, filterarg + io_req_size, // maxsize + 1, // msegments + io_req_size, // maxsegsize + BUS_DMA_ALLOCNOW, // flags + NULL, NULL, // lockfunc, lockarg + &sc->io_request_tag)) { + device_printf(sc->mrsas_dev, "Cannot create IO request tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->io_request_tag, (void **)&sc->io_request_mem, + BUS_DMA_NOWAIT, &sc->io_request_dmamap)) { + device_printf(sc->mrsas_dev, "Cannot alloc IO request memory\n"); + return (ENOMEM); + } + bzero(sc->io_request_mem, io_req_size); + if (bus_dmamap_load(sc->io_request_tag, sc->io_request_dmamap, + sc->io_request_mem, io_req_size, mrsas_addr_cb, + &sc->io_request_phys_addr, BUS_DMA_NOWAIT)) { + device_printf(sc->mrsas_dev, "Cannot load IO request memory\n"); + return (ENOMEM); + } + + /* + * Allocate Chain Frames + */ + chain_frame_size = sc->chain_frames_alloc_sz; + if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent + 4, 0, // algnmnt, boundary + BUS_SPACE_MAXADDR_32BIT,// lowaddr + BUS_SPACE_MAXADDR, // highaddr + NULL, NULL, // filter, filterarg + chain_frame_size, // maxsize + 1, // msegments + chain_frame_size, // maxsegsize + BUS_DMA_ALLOCNOW, // flags + NULL, NULL, // lockfunc, lockarg + &sc->chain_frame_tag)) { + device_printf(sc->mrsas_dev, "Cannot create chain frame tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->chain_frame_tag, (void **)&sc->chain_frame_mem, + BUS_DMA_NOWAIT, &sc->chain_frame_dmamap)) { + device_printf(sc->mrsas_dev, "Cannot alloc chain frame memory\n"); + return (ENOMEM); + } + bzero(sc->chain_frame_mem, chain_frame_size); + if (bus_dmamap_load(sc->chain_frame_tag, sc->chain_frame_dmamap, + sc->chain_frame_mem, chain_frame_size, mrsas_addr_cb, + &sc->chain_frame_phys_addr, BUS_DMA_NOWAIT)) { + device_printf(sc->mrsas_dev, "Cannot load chain frame memory\n"); + return (ENOMEM); + } + + /* + * Allocate Reply Descriptor Array + */ + reply_desc_size = sc->reply_alloc_sz; + if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent + 16, 0, // algnmnt, boundary + BUS_SPACE_MAXADDR_32BIT,// lowaddr + BUS_SPACE_MAXADDR, // highaddr + NULL, NULL, // filter, filterarg + reply_desc_size, // maxsize + 1, // msegments + reply_desc_size, // maxsegsize + BUS_DMA_ALLOCNOW, // flags + NULL, NULL, // lockfunc, lockarg + &sc->reply_desc_tag)) { + device_printf(sc->mrsas_dev, "Cannot create reply descriptor tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->reply_desc_tag, (void **)&sc->reply_desc_mem, + BUS_DMA_NOWAIT, &sc->reply_desc_dmamap)) { + device_printf(sc->mrsas_dev, "Cannot alloc reply descriptor memory\n"); + return (ENOMEM); + } + if (bus_dmamap_load(sc->reply_desc_tag, sc->reply_desc_dmamap, + sc->reply_desc_mem, reply_desc_size, mrsas_addr_cb, + &sc->reply_desc_phys_addr, BUS_DMA_NOWAIT)) { + device_printf(sc->mrsas_dev, "Cannot load reply descriptor memory\n"); + return (ENOMEM); + } + + /* + * Allocate Sense Buffer Array. Keep in lower 4GB + */ + sense_size = sc->max_fw_cmds * MRSAS_SENSE_LEN; + if (bus_dma_tag_create(sc->mrsas_parent_tag, // parent + 64, 0, // algnmnt, boundary + BUS_SPACE_MAXADDR_32BIT,// lowaddr + BUS_SPACE_MAXADDR, // highaddr + NULL, NULL, // filter, filterarg + sense_size, // maxsize + 1, // nsegments + sense_size, // maxsegsize + BUS_DMA_ALLOCNOW, // flags + NULL, NULL, // lockfunc, lockarg + &sc->sense_tag)) { + device_printf(sc->mrsas_dev, "Cannot allocate sense buf tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->sense_tag, (void **)&sc->sense_mem, + BUS_DMA_NOWAIT, &sc->sense_dmamap)) { + device_printf(sc->mrsas_dev, "Cannot allocate sense buf memory\n"); + return (ENOMEM); + } + if (bus_dmamap_load(sc->sense_tag, sc->sense_dmamap, + sc->sense_mem, sense_size, mrsas_addr_cb, &sc->sense_phys_addr, + BUS_DMA_NOWAIT)){ + device_printf(sc->mrsas_dev, "Cannot load sense buf memory\n"); + return (ENOMEM); + } + + /* + * Allocate for Event detail structure + */ + evt_detail_size = sizeof(struct mrsas_evt_detail); + if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent + 1, 0, // algnmnt, boundary + BUS_SPACE_MAXADDR_32BIT,// lowaddr + BUS_SPACE_MAXADDR, // highaddr + NULL, NULL, // filter, filterarg + evt_detail_size, // maxsize + 1, // msegments + evt_detail_size, // maxsegsize + BUS_DMA_ALLOCNOW, // flags + NULL, NULL, // lockfunc, lockarg + &sc->evt_detail_tag)) { + device_printf(sc->mrsas_dev, "Cannot create Event detail tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->evt_detail_tag, (void **)&sc->evt_detail_mem, + BUS_DMA_NOWAIT, &sc->evt_detail_dmamap)) { + device_printf(sc->mrsas_dev, "Cannot alloc Event detail buffer memory\n"); + return (ENOMEM); + } + bzero(sc->evt_detail_mem, evt_detail_size); + if (bus_dmamap_load(sc->evt_detail_tag, sc->evt_detail_dmamap, + sc->evt_detail_mem, evt_detail_size, mrsas_addr_cb, + &sc->evt_detail_phys_addr, BUS_DMA_NOWAIT)) { + device_printf(sc->mrsas_dev, "Cannot load Event detail buffer memory\n"); + return (ENOMEM); + } + + + /* + * Create a dma tag for data buffers; size will be the maximum + * possible I/O size (280kB). + */ + if (bus_dma_tag_create(sc->mrsas_parent_tag, // parent + 1, // alignment + 0, // boundary + BUS_SPACE_MAXADDR, // lowaddr + BUS_SPACE_MAXADDR, // highaddr + NULL, NULL, // filter, filterarg + MRSAS_MAX_IO_SIZE, // maxsize + MRSAS_MAX_SGL, // nsegments + MRSAS_MAX_IO_SIZE, // maxsegsize + BUS_DMA_ALLOCNOW, // flags + busdma_lock_mutex, // lockfunc + &sc->io_lock, // lockfuncarg + &sc->data_tag)) { + device_printf(sc->mrsas_dev, "Cannot create data dma tag\n"); + return(ENOMEM); + } + + return(0); +} + +/* + * mrsas_addr_cb: Callback function of bus_dmamap_load() + * input: callback argument, + * machine dependent type that describes DMA segments, + * number of segments, + * error code. + * + * This function is for the driver to receive mapping information resultant + * of the bus_dmamap_load(). The information is actually not being used, + * but the address is saved anyway. + */ +void +mrsas_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + bus_addr_t *addr; + + addr = arg; + *addr = segs[0].ds_addr; +} + +/* + * mrsas_setup_raidmap: Set up RAID map. + * input: Adapter instance soft state + * + * Allocate DMA memory for the RAID maps and perform setup. + */ +static int mrsas_setup_raidmap(struct mrsas_softc *sc) +{ + sc->map_sz = sizeof(MR_FW_RAID_MAP) + + (sizeof(MR_LD_SPAN_MAP) * (MAX_LOGICAL_DRIVES - 1)); + + for (int i=0; i < 2; i++) + { + if (bus_dma_tag_create(sc->mrsas_parent_tag, // parent + 4, 0, // algnmnt, boundary + BUS_SPACE_MAXADDR_32BIT,// lowaddr + BUS_SPACE_MAXADDR, // highaddr + NULL, NULL, // filter, filterarg + sc->map_sz, // maxsize + 1, // nsegments + sc->map_sz, // maxsegsize + BUS_DMA_ALLOCNOW, // flags + NULL, NULL, // lockfunc, lockarg + &sc->raidmap_tag[i])) { + device_printf(sc->mrsas_dev, "Cannot allocate raid map tag.\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->raidmap_tag[i], (void **)&sc->raidmap_mem[i], + BUS_DMA_NOWAIT, &sc->raidmap_dmamap[i])) { + device_printf(sc->mrsas_dev, "Cannot allocate raidmap memory.\n"); + return (ENOMEM); + } + if (bus_dmamap_load(sc->raidmap_tag[i], sc->raidmap_dmamap[i], + sc->raidmap_mem[i], sc->map_sz, mrsas_addr_cb, &sc->raidmap_phys_addr[i], + BUS_DMA_NOWAIT)){ + device_printf(sc->mrsas_dev, "Cannot load raidmap memory.\n"); + return (ENOMEM); + } + if (!sc->raidmap_mem[i]) { + device_printf(sc->mrsas_dev, "Cannot allocate memory for raid map.\n"); + return (ENOMEM); + } + } + + if (!mrsas_get_map_info(sc)) + mrsas_sync_map_info(sc); + + return (0); +} + +/** + * mrsas_init_fw: Initialize Firmware + * input: Adapter soft state + * + * Calls transition_to_ready() to make sure Firmware is in operational + * state and calls mrsas_init_adapter() to send IOC_INIT command to + * Firmware. It issues internal commands to get the controller info + * after the IOC_INIT command response is received by Firmware. + * Note: code relating to get_pdlist, get_ld_list and max_sectors + * are currently not being used, it is left here as placeholder. + */ +static int mrsas_init_fw(struct mrsas_softc *sc) +{ + u_int32_t max_sectors_1; + u_int32_t max_sectors_2; + u_int32_t tmp_sectors; + struct mrsas_ctrl_info *ctrl_info; + + int ret, ocr = 0; + + + /* Make sure Firmware is ready */ + ret = mrsas_transition_to_ready(sc, ocr); + if (ret != SUCCESS) { + return(ret); + } + + /* Get operational params, sge flags, send init cmd to ctlr */ + if (mrsas_init_adapter(sc) != SUCCESS){ + device_printf(sc->mrsas_dev, "Adapter initialize Fail.\n"); + return(1); + } + + /* Allocate internal commands for pass-thru */ + if (mrsas_alloc_mfi_cmds(sc) != SUCCESS){ + device_printf(sc->mrsas_dev, "Allocate MFI cmd failed.\n"); + return(1); + } + + if (mrsas_setup_raidmap(sc) != SUCCESS) { + device_printf(sc->mrsas_dev, "Set up RAID map failed.\n"); + return(1); + } + + /* For pass-thru, get PD/LD list and controller info */ + memset(sc->pd_list, 0, MRSAS_MAX_PD * sizeof(struct mrsas_pd_list)); + mrsas_get_pd_list(sc); + + memset(sc->ld_ids, 0xff, MRSAS_MAX_LD); + mrsas_get_ld_list(sc); + + //memset(sc->log_to_span, 0, MRSAS_MAX_LD * sizeof(LD_SPAN_INFO)); + + ctrl_info = malloc(sizeof(struct mrsas_ctrl_info), M_MRSAS, M_NOWAIT); + + /* + * Compute the max allowed sectors per IO: The controller info has two + * limits on max sectors. Driver should use the minimum of these two. + * + * 1 << stripe_sz_ops.min = max sectors per strip + * + * Note that older firmwares ( < FW ver 30) didn't report information + * to calculate max_sectors_1. So the number ended up as zero always. + */ + tmp_sectors = 0; + if (ctrl_info && !mrsas_get_ctrl_info(sc, ctrl_info)) { + max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) * + ctrl_info->max_strips_per_io; + max_sectors_2 = ctrl_info->max_request_size; + tmp_sectors = min(max_sectors_1 , max_sectors_2); + sc->disableOnlineCtrlReset = + ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset; + sc->UnevenSpanSupport = + ctrl_info->adapterOperations2.supportUnevenSpans; + if(sc->UnevenSpanSupport) { + device_printf(sc->mrsas_dev, "FW supports: UnevenSpanSupport=%x\n", + sc->UnevenSpanSupport); + if (MR_ValidateMapInfo(sc)) + sc->fast_path_io = 1; + else + sc->fast_path_io = 0; + + } + } + sc->max_sectors_per_req = sc->max_num_sge * MRSAS_PAGE_SIZE / 512; + + if (tmp_sectors && (sc->max_sectors_per_req > tmp_sectors)) + sc->max_sectors_per_req = tmp_sectors; + + if (ctrl_info) + free(ctrl_info, M_MRSAS); + + return(0); +} + +/** + * mrsas_init_adapter: Initializes the adapter/controller + * input: Adapter soft state + * + * Prepares for the issuing of the IOC Init cmd to FW for initializing the + * ROC/controller. The FW register is read to determined the number of + * commands that is supported. All memory allocations for IO is based on + * max_cmd. Appropriate calculations are performed in this function. + */ +int mrsas_init_adapter(struct mrsas_softc *sc) +{ + uint32_t status; + u_int32_t max_cmd; + int ret; + + /* Read FW status register */ + status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_scratch_pad)); + + /* Get operational params from status register */ + sc->max_fw_cmds = status & MRSAS_FWSTATE_MAXCMD_MASK; + + /* Decrement the max supported by 1, to correlate with FW */ + sc->max_fw_cmds = sc->max_fw_cmds-1; + max_cmd = sc->max_fw_cmds; + + /* Determine allocation size of command frames */ + sc->reply_q_depth = ((max_cmd *2 +1 +15)/16*16); + sc->request_alloc_sz = sizeof(MRSAS_REQUEST_DESCRIPTOR_UNION) * max_cmd; + sc->reply_alloc_sz = sizeof(MPI2_REPLY_DESCRIPTORS_UNION) * (sc->reply_q_depth); + sc->io_frames_alloc_sz = MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE + (MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * (max_cmd + 1)); + sc->chain_frames_alloc_sz = 1024 * max_cmd; + sc->max_sge_in_main_msg = (MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE - + offsetof(MRSAS_RAID_SCSI_IO_REQUEST, SGL))/16; + + sc->max_sge_in_chain = MRSAS_MAX_SZ_CHAIN_FRAME / sizeof(MPI2_SGE_IO_UNION); + sc->max_num_sge = sc->max_sge_in_main_msg + sc->max_sge_in_chain - 2; + + /* Used for pass thru MFI frame (DCMD) */ + sc->chain_offset_mfi_pthru = offsetof(MRSAS_RAID_SCSI_IO_REQUEST, SGL)/16; + + sc->chain_offset_io_request = (MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE - + sizeof(MPI2_SGE_IO_UNION))/16; + + sc->last_reply_idx = 0; + + ret = mrsas_alloc_mem(sc); + if (ret != SUCCESS) + return(ret); + + ret = mrsas_alloc_mpt_cmds(sc); + if (ret != SUCCESS) + return(ret); + + ret = mrsas_ioc_init(sc); + if (ret != SUCCESS) + return(ret); + + + return(0); +} + +/** + * mrsas_alloc_ioc_cmd: Allocates memory for IOC Init command + * input: Adapter soft state + * + * Allocates for the IOC Init cmd to FW to initialize the ROC/controller. + */ +int mrsas_alloc_ioc_cmd(struct mrsas_softc *sc) +{ + int ioc_init_size; + + /* Allocate IOC INIT command */ + ioc_init_size = 1024 + sizeof(MPI2_IOC_INIT_REQUEST); + if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent + 1, 0, // algnmnt, boundary + BUS_SPACE_MAXADDR_32BIT,// lowaddr + BUS_SPACE_MAXADDR, // highaddr + NULL, NULL, // filter, filterarg + ioc_init_size, // maxsize + 1, // msegments + ioc_init_size, // maxsegsize + BUS_DMA_ALLOCNOW, // flags + NULL, NULL, // lockfunc, lockarg + &sc->ioc_init_tag)) { + device_printf(sc->mrsas_dev, "Cannot allocate ioc init tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->ioc_init_tag, (void **)&sc->ioc_init_mem, + BUS_DMA_NOWAIT, &sc->ioc_init_dmamap)) { + device_printf(sc->mrsas_dev, "Cannot allocate ioc init cmd mem\n"); + return (ENOMEM); + } + bzero(sc->ioc_init_mem, ioc_init_size); + if (bus_dmamap_load(sc->ioc_init_tag, sc->ioc_init_dmamap, + sc->ioc_init_mem, ioc_init_size, mrsas_addr_cb, + &sc->ioc_init_phys_mem, BUS_DMA_NOWAIT)) { + device_printf(sc->mrsas_dev, "Cannot load ioc init cmd mem\n"); + return (ENOMEM); + } + + return (0); +} + +/** + * mrsas_free_ioc_cmd: Allocates memory for IOC Init command + * input: Adapter soft state + * + * Deallocates memory of the IOC Init cmd. + */ +void mrsas_free_ioc_cmd(struct mrsas_softc *sc) +{ + if (sc->ioc_init_phys_mem) + bus_dmamap_unload(sc->ioc_init_tag, sc->ioc_init_dmamap); + if (sc->ioc_init_mem != NULL) + bus_dmamem_free(sc->ioc_init_tag, sc->ioc_init_mem, sc->ioc_init_dmamap); + if (sc->ioc_init_tag != NULL) + bus_dma_tag_destroy(sc->ioc_init_tag); +} + +/** + * mrsas_ioc_init: Sends IOC Init command to FW + * input: Adapter soft state + * + * Issues the IOC Init cmd to FW to initialize the ROC/controller. + */ +int mrsas_ioc_init(struct mrsas_softc *sc) +{ + struct mrsas_init_frame *init_frame; + pMpi2IOCInitRequest_t IOCInitMsg; + MRSAS_REQUEST_DESCRIPTOR_UNION req_desc; + u_int8_t max_wait = MRSAS_IOC_INIT_WAIT_TIME; + bus_addr_t phys_addr; + int i, retcode = 0; + + /* Allocate memory for the IOC INIT command */ + if (mrsas_alloc_ioc_cmd(sc)) { + device_printf(sc->mrsas_dev, "Cannot allocate IOC command.\n"); + return(1); + } + + IOCInitMsg = (pMpi2IOCInitRequest_t)(((char *)sc->ioc_init_mem) +1024); + IOCInitMsg->Function = MPI2_FUNCTION_IOC_INIT; + IOCInitMsg->WhoInit = MPI2_WHOINIT_HOST_DRIVER; + IOCInitMsg->MsgVersion = MPI2_VERSION; + IOCInitMsg->HeaderVersion = MPI2_HEADER_VERSION; + IOCInitMsg->SystemRequestFrameSize = MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4; + IOCInitMsg->ReplyDescriptorPostQueueDepth = sc->reply_q_depth; + IOCInitMsg->ReplyDescriptorPostQueueAddress = sc->reply_desc_phys_addr; + IOCInitMsg->SystemRequestFrameBaseAddress = sc->io_request_phys_addr; + + init_frame = (struct mrsas_init_frame *)sc->ioc_init_mem; + init_frame->cmd = MFI_CMD_INIT; + init_frame->cmd_status = 0xFF; + init_frame->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; + + if (sc->verbuf_mem) { + snprintf((char *)sc->verbuf_mem, strlen(MRSAS_VERSION)+2,"%s\n", + MRSAS_VERSION); + init_frame->driver_ver_lo = (bus_addr_t)sc->verbuf_phys_addr; + init_frame->driver_ver_hi = 0; + } + + phys_addr = (bus_addr_t)sc->ioc_init_phys_mem + 1024; + init_frame->queue_info_new_phys_addr_lo = phys_addr; + init_frame->data_xfer_len = sizeof(Mpi2IOCInitRequest_t); + + req_desc.addr.Words = (bus_addr_t)sc->ioc_init_phys_mem; + req_desc.MFAIo.RequestFlags = + (MRSAS_REQ_DESCRIPT_FLAGS_MFA << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + + mrsas_disable_intr(sc); + mrsas_dprint(sc, MRSAS_OCR, "Issuing IOC INIT command to FW.\n"); + //device_printf(sc->mrsas_dev, "Issuing IOC INIT command to FW.\n");del? + mrsas_fire_cmd(sc, req_desc.addr.u.low, req_desc.addr.u.high); + + /* + * Poll response timer to wait for Firmware response. While this + * timer with the DELAY call could block CPU, the time interval for + * this is only 1 millisecond. + */ + if (init_frame->cmd_status == 0xFF) { + for (i=0; i < (max_wait * 1000); i++){ + if (init_frame->cmd_status == 0xFF) + DELAY(1000); + else + break; + } + } + + if (init_frame->cmd_status == 0) + mrsas_dprint(sc, MRSAS_OCR, + "IOC INIT response received from FW.\n"); + //device_printf(sc->mrsas_dev, "IOC INIT response received from FW.\n");del? + else + { + if (init_frame->cmd_status == 0xFF) + device_printf(sc->mrsas_dev, "IOC Init timed out after %d seconds.\n", max_wait); + else + device_printf(sc->mrsas_dev, "IOC Init failed, status = 0x%x\n", init_frame->cmd_status); + retcode = 1; + } + + mrsas_free_ioc_cmd(sc); + return (retcode); +} + +/** + * mrsas_alloc_mpt_cmds: Allocates the command packets + * input: Adapter instance soft state + * + * This function allocates the internal commands for IOs. Each command that is + * issued to FW is wrapped in a local data structure called mrsas_mpt_cmd. + * An array is allocated with mrsas_mpt_cmd context. The free commands are + * maintained in a linked list (cmd pool). SMID value range is from 1 to + * max_fw_cmds. + */ +int mrsas_alloc_mpt_cmds(struct mrsas_softc *sc) +{ + int i, j; + u_int32_t max_cmd; + struct mrsas_mpt_cmd *cmd; + pMpi2ReplyDescriptorsUnion_t reply_desc; + u_int32_t offset, chain_offset, sense_offset; + bus_addr_t io_req_base_phys, chain_frame_base_phys, sense_base_phys; + u_int8_t *io_req_base, *chain_frame_base, *sense_base; + + max_cmd = sc->max_fw_cmds; + + sc->req_desc = malloc(sc->request_alloc_sz, M_MRSAS, M_NOWAIT); + if (!sc->req_desc) { + device_printf(sc->mrsas_dev, "Out of memory, cannot alloc req desc\n"); + return(ENOMEM); + } + memset(sc->req_desc, 0, sc->request_alloc_sz); + + /* + * sc->mpt_cmd_list is an array of struct mrsas_mpt_cmd pointers. Allocate the + * dynamic array first and then allocate individual commands. + */ + sc->mpt_cmd_list = malloc(sizeof(struct mrsas_mpt_cmd*)*max_cmd, M_MRSAS, M_NOWAIT); + if (!sc->mpt_cmd_list) { + device_printf(sc->mrsas_dev, "Cannot alloc memory for mpt_cmd_list.\n"); + return(ENOMEM); + } + memset(sc->mpt_cmd_list, 0, sizeof(struct mrsas_mpt_cmd *)*max_cmd); + for (i = 0; i < max_cmd; i++) { + sc->mpt_cmd_list[i] = malloc(sizeof(struct mrsas_mpt_cmd), + M_MRSAS, M_NOWAIT); + if (!sc->mpt_cmd_list[i]) { + for (j = 0; j < i; j++) + free(sc->mpt_cmd_list[j],M_MRSAS); + free(sc->mpt_cmd_list, M_MRSAS); + sc->mpt_cmd_list = NULL; + return(ENOMEM); + } + } + + io_req_base = (u_int8_t*)sc->io_request_mem + MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; + io_req_base_phys = (bus_addr_t)sc->io_request_phys_addr + MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; + chain_frame_base = (u_int8_t*)sc->chain_frame_mem; + chain_frame_base_phys = (bus_addr_t)sc->chain_frame_phys_addr; + sense_base = (u_int8_t*)sc->sense_mem; + sense_base_phys = (bus_addr_t)sc->sense_phys_addr; + for (i = 0; i < max_cmd; i++) { + cmd = sc->mpt_cmd_list[i]; + offset = MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i; + chain_offset = 1024 * i; + sense_offset = MRSAS_SENSE_LEN * i; + memset(cmd, 0, sizeof(struct mrsas_mpt_cmd)); + cmd->index = i + 1; + cmd->ccb_ptr = NULL; + callout_init(&cmd->cm_callout, 0); + cmd->sync_cmd_idx = (u_int32_t)MRSAS_ULONG_MAX; + cmd->sc = sc; + cmd->io_request = (MRSAS_RAID_SCSI_IO_REQUEST *) (io_req_base + offset); + memset(cmd->io_request, 0, sizeof(MRSAS_RAID_SCSI_IO_REQUEST)); + cmd->io_request_phys_addr = io_req_base_phys + offset; + cmd->chain_frame = (MPI2_SGE_IO_UNION *) (chain_frame_base + chain_offset); + cmd->chain_frame_phys_addr = chain_frame_base_phys + chain_offset; + cmd->sense = sense_base + sense_offset; + cmd->sense_phys_addr = sense_base_phys + sense_offset; + if (bus_dmamap_create(sc->data_tag, 0, &cmd->data_dmamap)) { + return(FAIL); + } + TAILQ_INSERT_TAIL(&(sc->mrsas_mpt_cmd_list_head), cmd, next); + } + + /* Initialize reply descriptor array to 0xFFFFFFFF */ + reply_desc = sc->reply_desc_mem; + for (i = 0; i < sc->reply_q_depth; i++, reply_desc++) { + reply_desc->Words = MRSAS_ULONG_MAX; + } + return(0); +} + +/** + * mrsas_fire_cmd: Sends command to FW + * input: Adapter soft state + * request descriptor address low + * request descriptor address high + * + * This functions fires the command to Firmware by writing to the + * inbound_low_queue_port and inbound_high_queue_port. + */ +void mrsas_fire_cmd(struct mrsas_softc *sc, u_int32_t req_desc_lo, + u_int32_t req_desc_hi) +{ + mtx_lock(&sc->pci_lock); + mrsas_write_reg(sc, offsetof(mrsas_reg_set, inbound_low_queue_port), + req_desc_lo); + mrsas_write_reg(sc, offsetof(mrsas_reg_set, inbound_high_queue_port), + req_desc_hi); + mtx_unlock(&sc->pci_lock); +} + +/** + * mrsas_transition_to_ready: Move FW to Ready state + * input: Adapter instance soft state + * + * During the initialization, FW passes can potentially be in any one of + * several possible states. If the FW in operational, waiting-for-handshake + * states, driver must take steps to bring it to ready state. Otherwise, it + * has to wait for the ready state. + */ +int mrsas_transition_to_ready(struct mrsas_softc *sc, int ocr) +{ + int i; + u_int8_t max_wait; + u_int32_t val, fw_state; + u_int32_t cur_state; + u_int32_t abs_state, curr_abs_state; + + val = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_scratch_pad)); + fw_state = val & MFI_STATE_MASK; + max_wait = MRSAS_RESET_WAIT_TIME; + + if (fw_state != MFI_STATE_READY) + device_printf(sc->mrsas_dev, "Waiting for FW to come to ready state\n"); + + while (fw_state != MFI_STATE_READY) { + abs_state = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_scratch_pad)); + switch (fw_state) { + case MFI_STATE_FAULT: + device_printf(sc->mrsas_dev, "FW is in FAULT state!!\n"); + if (ocr) { + cur_state = MFI_STATE_FAULT; + break; + } + else + return -ENODEV; + case MFI_STATE_WAIT_HANDSHAKE: + /* Set the CLR bit in inbound doorbell */ + mrsas_write_reg(sc, offsetof(mrsas_reg_set, doorbell), + MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG); + cur_state = MFI_STATE_WAIT_HANDSHAKE; + break; + case MFI_STATE_BOOT_MESSAGE_PENDING: + mrsas_write_reg(sc, offsetof(mrsas_reg_set, doorbell), + MFI_INIT_HOTPLUG); + cur_state = MFI_STATE_BOOT_MESSAGE_PENDING; + break; + case MFI_STATE_OPERATIONAL: + /* Bring it to READY state; assuming max wait 10 secs */ + mrsas_disable_intr(sc); + mrsas_write_reg(sc, offsetof(mrsas_reg_set, doorbell), MFI_RESET_FLAGS); + for (i=0; i < max_wait * 1000; i++) { + if (mrsas_read_reg(sc, offsetof(mrsas_reg_set, doorbell)) & 1) + DELAY(1000); + else + break; + } + cur_state = MFI_STATE_OPERATIONAL; + break; + case MFI_STATE_UNDEFINED: + /* This state should not last for more than 2 seconds */ + cur_state = MFI_STATE_UNDEFINED; + break; + case MFI_STATE_BB_INIT: + cur_state = MFI_STATE_BB_INIT; + break; + case MFI_STATE_FW_INIT: + cur_state = MFI_STATE_FW_INIT; + break; + case MFI_STATE_FW_INIT_2: + cur_state = MFI_STATE_FW_INIT_2; + break; + case MFI_STATE_DEVICE_SCAN: + cur_state = MFI_STATE_DEVICE_SCAN; + break; + case MFI_STATE_FLUSH_CACHE: + cur_state = MFI_STATE_FLUSH_CACHE; + break; + default: + device_printf(sc->mrsas_dev, "Unknown state 0x%x\n", fw_state); + return -ENODEV; + } + + /* + * The cur_state should not last for more than max_wait secs + */ + for (i = 0; i < (max_wait * 1000); i++) { + fw_state = (mrsas_read_reg(sc, offsetof(mrsas_reg_set, + outbound_scratch_pad))& MFI_STATE_MASK); + curr_abs_state = mrsas_read_reg(sc, offsetof(mrsas_reg_set, + outbound_scratch_pad)); + if (abs_state == curr_abs_state) + DELAY(1000); + else + break; + } + + /* + * Return error if fw_state hasn't changed after max_wait + */ + if (curr_abs_state == abs_state) { + device_printf(sc->mrsas_dev, "FW state [%d] hasn't changed " + "in %d secs\n", fw_state, max_wait); + return -ENODEV; + } + } + mrsas_dprint(sc, MRSAS_OCR, "FW now in Ready state\n"); + //device_printf(sc->mrsas_dev, "FW now in Ready state\n");del? + return 0; +} + +/** + * mrsas_get_mfi_cmd: Get a cmd from free command pool + * input: Adapter soft state + * + * This function removes an MFI command from the command list. + */ +struct mrsas_mfi_cmd* mrsas_get_mfi_cmd(struct mrsas_softc *sc) +{ + struct mrsas_mfi_cmd *cmd = NULL; + + mtx_lock(&sc->mfi_cmd_pool_lock); + if (!TAILQ_EMPTY(&sc->mrsas_mfi_cmd_list_head)){ + cmd = TAILQ_FIRST(&sc->mrsas_mfi_cmd_list_head); + TAILQ_REMOVE(&sc->mrsas_mfi_cmd_list_head, cmd, next); + } + mtx_unlock(&sc->mfi_cmd_pool_lock); + + return cmd; +} + +/** + * mrsas_ocr_thread Thread to handle OCR/Kill Adapter. + * input: Adapter Context. + * + * This function will check FW status register and flag + * do_timeout_reset flag. It will do OCR/Kill adapter if + * FW is in fault state or IO timed out has trigger reset. + */ +static void +mrsas_ocr_thread(void *arg) +{ + struct mrsas_softc *sc; + u_int32_t fw_status, fw_state; + + sc = (struct mrsas_softc *)arg; + + mrsas_dprint(sc, MRSAS_TRACE, "%s\n", __func__); + + sc->ocr_thread_active = 1; + mtx_lock(&sc->sim_lock); + for (;;) { + /* Sleep for 1 second and check the queue status*/ + msleep(&sc->ocr_chan, &sc->sim_lock, PRIBIO, + "mrsas_ocr", sc->mrsas_fw_fault_check_delay * hz); + if (sc->remove_in_progress) { + mrsas_dprint(sc, MRSAS_OCR, + "Exit due to shutdown from %s\n", __func__); + break; + } + fw_status = mrsas_read_reg(sc, + offsetof(mrsas_reg_set, outbound_scratch_pad)); + fw_state = fw_status & MFI_STATE_MASK; + if (fw_state == MFI_STATE_FAULT || sc->do_timedout_reset) { + device_printf(sc->mrsas_dev, "OCR started due to %s!\n", + sc->do_timedout_reset?"IO Timeout": + "FW fault detected"); + mtx_lock_spin(&sc->ioctl_lock); + sc->reset_in_progress = 1; + sc->reset_count++; + mtx_unlock_spin(&sc->ioctl_lock); + mrsas_xpt_freeze(sc); + mrsas_reset_ctrl(sc); + mrsas_xpt_release(sc); + sc->reset_in_progress = 0; + sc->do_timedout_reset = 0; + } + } + mtx_unlock(&sc->sim_lock); + sc->ocr_thread_active = 0; + mrsas_kproc_exit(0); +} + +/** + * mrsas_reset_reply_desc Reset Reply descriptor as part of OCR. + * input: Adapter Context. + * + * This function will clear reply descriptor so that post OCR + * driver and FW will lost old history. + */ +void mrsas_reset_reply_desc(struct mrsas_softc *sc) +{ + int i; + pMpi2ReplyDescriptorsUnion_t reply_desc; + + sc->last_reply_idx = 0; + reply_desc = sc->reply_desc_mem; + for (i = 0; i < sc->reply_q_depth; i++, reply_desc++) { + reply_desc->Words = MRSAS_ULONG_MAX; + } +} + +/** + * mrsas_reset_ctrl Core function to OCR/Kill adapter. + * input: Adapter Context. + * + * This function will run from thread context so that it can sleep. + * 1. Do not handle OCR if FW is in HW critical error. + * 2. Wait for outstanding command to complete for 180 seconds. + * 3. If #2 does not find any outstanding command Controller is in working + * state, so skip OCR. + * Otherwise, do OCR/kill Adapter based on flag disableOnlineCtrlReset. + * 4. Start of the OCR, return all SCSI command back to CAM layer which has + * ccb_ptr. + * 5. Post OCR, Re-fire Managment command and move Controller to Operation + * state. + */ +int mrsas_reset_ctrl(struct mrsas_softc *sc) +{ + int retval = SUCCESS, i, j, retry = 0; + u_int32_t host_diag, abs_state, status_reg, reset_adapter; + union ccb *ccb; + struct mrsas_mfi_cmd *mfi_cmd; + struct mrsas_mpt_cmd *mpt_cmd; + MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc; + + if (sc->adprecovery == MRSAS_HW_CRITICAL_ERROR) { + device_printf(sc->mrsas_dev, + "mrsas: Hardware critical error, returning FAIL.\n"); + return FAIL; + } + + set_bit(MRSAS_FUSION_IN_RESET, &sc->reset_flags); + sc->adprecovery = MRSAS_ADPRESET_SM_INFAULT; + mrsas_disable_intr(sc); + DELAY(1000 * 1000); + + /* First try waiting for commands to complete */ + if (mrsas_wait_for_outstanding(sc)) { + mrsas_dprint(sc, MRSAS_OCR, + "resetting adapter from %s.\n", + __func__); + /* Now return commands back to the CAM layer */ + for (i = 0 ; i < sc->max_fw_cmds; i++) { + mpt_cmd = sc->mpt_cmd_list[i]; + if (mpt_cmd->ccb_ptr) { + ccb = (union ccb *)(mpt_cmd->ccb_ptr); + ccb->ccb_h.status = CAM_SCSI_BUS_RESET; + mrsas_cmd_done(sc, mpt_cmd); + atomic_dec(&sc->fw_outstanding); + } + } + + status_reg = mrsas_read_reg(sc, offsetof(mrsas_reg_set, + outbound_scratch_pad)); + abs_state = status_reg & MFI_STATE_MASK; + reset_adapter = status_reg & MFI_RESET_ADAPTER; + if (sc->disableOnlineCtrlReset || + (abs_state == MFI_STATE_FAULT && !reset_adapter)) { + /* Reset not supported, kill adapter */ + mrsas_dprint(sc, MRSAS_OCR,"Reset not supported, killing adapter.\n"); + mrsas_kill_hba(sc); + sc->adprecovery = MRSAS_HW_CRITICAL_ERROR; + retval = FAIL; + goto out; + } + + /* Now try to reset the chip */ + for (i = 0; i < MRSAS_FUSION_MAX_RESET_TRIES; i++) { + mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset), + MPI2_WRSEQ_FLUSH_KEY_VALUE); + mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset), + MPI2_WRSEQ_1ST_KEY_VALUE); + mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset), + MPI2_WRSEQ_2ND_KEY_VALUE); + mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset), + MPI2_WRSEQ_3RD_KEY_VALUE); + mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset), + MPI2_WRSEQ_4TH_KEY_VALUE); + mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset), + MPI2_WRSEQ_5TH_KEY_VALUE); + mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset), + MPI2_WRSEQ_6TH_KEY_VALUE); + + /* Check that the diag write enable (DRWE) bit is on */ + host_diag = mrsas_read_reg(sc, offsetof(mrsas_reg_set, + fusion_host_diag)); + retry = 0; + while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) { + DELAY(100 * 1000); + host_diag = mrsas_read_reg(sc, offsetof(mrsas_reg_set, + fusion_host_diag)); + if (retry++ == 100) { + mrsas_dprint(sc, MRSAS_OCR, + "Host diag unlock failed!\n"); + break; + } + } + if (!(host_diag & HOST_DIAG_WRITE_ENABLE)) + continue; + + /* Send chip reset command */ + mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_host_diag), + host_diag | HOST_DIAG_RESET_ADAPTER); + DELAY(3000 * 1000); + + /* Make sure reset adapter bit is cleared */ + host_diag = mrsas_read_reg(sc, offsetof(mrsas_reg_set, + fusion_host_diag)); + retry = 0; + while (host_diag & HOST_DIAG_RESET_ADAPTER) { + DELAY(100 * 1000); + host_diag = mrsas_read_reg(sc, offsetof(mrsas_reg_set, + fusion_host_diag)); + if (retry++ == 1000) { + mrsas_dprint(sc, MRSAS_OCR, + "Diag reset adapter never cleared!\n"); + break; + } + } + if (host_diag & HOST_DIAG_RESET_ADAPTER) + continue; + + abs_state = mrsas_read_reg(sc, offsetof(mrsas_reg_set, + outbound_scratch_pad)) & MFI_STATE_MASK; + retry = 0; + + while ((abs_state <= MFI_STATE_FW_INIT) && (retry++ < 1000)) { + DELAY(100 * 1000); + abs_state = mrsas_read_reg(sc, offsetof(mrsas_reg_set, + outbound_scratch_pad)) & MFI_STATE_MASK; + } + if (abs_state <= MFI_STATE_FW_INIT) { + mrsas_dprint(sc, MRSAS_OCR, "firmware state < MFI_STATE_FW_INIT," + " state = 0x%x\n", abs_state); + continue; + } + + /* Wait for FW to become ready */ + if (mrsas_transition_to_ready(sc, 1)) { + mrsas_dprint(sc, MRSAS_OCR, + "mrsas: Failed to transition controller to ready.\n"); + continue; + } + + mrsas_reset_reply_desc(sc); + if (mrsas_ioc_init(sc)) { + mrsas_dprint(sc, MRSAS_OCR, "mrsas_ioc_init() failed!\n"); + continue; + } + + clear_bit(MRSAS_FUSION_IN_RESET, &sc->reset_flags); + mrsas_enable_intr(sc); + sc->adprecovery = MRSAS_HBA_OPERATIONAL; + + /* Re-fire management commands */ + for (j = 0 ; j < sc->max_fw_cmds; j++) { + mpt_cmd = sc->mpt_cmd_list[j]; + if (mpt_cmd->sync_cmd_idx != (u_int32_t)MRSAS_ULONG_MAX) { + mfi_cmd = sc->mfi_cmd_list[mpt_cmd->sync_cmd_idx]; + if (mfi_cmd->frame->dcmd.opcode == + MR_DCMD_LD_MAP_GET_INFO) { + mrsas_release_mfi_cmd(mfi_cmd); + mrsas_release_mpt_cmd(mpt_cmd); + } else { + req_desc = mrsas_get_request_desc(sc, + mfi_cmd->cmd_id.context.smid - 1); + mrsas_dprint(sc, MRSAS_OCR, + "Re-fire command DCMD opcode 0x%x index %d\n ", + mfi_cmd->frame->dcmd.opcode, j); + if (!req_desc) + device_printf(sc->mrsas_dev, + "Cannot build MPT cmd.\n"); + else + mrsas_fire_cmd(sc, req_desc->addr.u.low, + req_desc->addr.u.high); + } + } + } + + /* Reset load balance info */ + memset(sc->load_balance_info, 0, + sizeof(LD_LOAD_BALANCE_INFO) * MAX_LOGICAL_DRIVES); + + if (!mrsas_get_map_info(sc)) + mrsas_sync_map_info(sc); + + /* Adapter reset completed successfully */ + device_printf(sc->mrsas_dev, "Reset successful\n"); + retval = SUCCESS; + goto out; + } + /* Reset failed, kill the adapter */ + device_printf(sc->mrsas_dev, "Reset failed, killing adapter.\n"); + mrsas_kill_hba(sc); + retval = FAIL; + } else { + clear_bit(MRSAS_FUSION_IN_RESET, &sc->reset_flags); + mrsas_enable_intr(sc); + sc->adprecovery = MRSAS_HBA_OPERATIONAL; + } +out: + clear_bit(MRSAS_FUSION_IN_RESET, &sc->reset_flags); + mrsas_dprint(sc, MRSAS_OCR, + "Reset Exit with %d.\n", retval); + return retval; +} + +/** + * mrsas_kill_hba Kill HBA when OCR is not supported. + * input: Adapter Context. + * + * This function will kill HBA when OCR is not supported. + */ +void mrsas_kill_hba (struct mrsas_softc *sc) +{ + mrsas_dprint(sc, MRSAS_OCR, "%s\n", __func__); + mrsas_write_reg(sc, offsetof(mrsas_reg_set, doorbell), + MFI_STOP_ADP); + /* Flush */ + mrsas_read_reg(sc, offsetof(mrsas_reg_set, doorbell)); +} + +/** + * mrsas_wait_for_outstanding Wait for outstanding commands + * input: Adapter Context. + * + * This function will wait for 180 seconds for outstanding + * commands to be completed. + */ +int mrsas_wait_for_outstanding(struct mrsas_softc *sc) +{ + int i, outstanding, retval = 0; + u_int32_t fw_state; + + for (i = 0; i < MRSAS_RESET_WAIT_TIME; i++) { + if (sc->remove_in_progress) { + mrsas_dprint(sc, MRSAS_OCR, + "Driver remove or shutdown called.\n"); + retval = 1; + goto out; + } + /* Check if firmware is in fault state */ + fw_state = mrsas_read_reg(sc, offsetof(mrsas_reg_set, + outbound_scratch_pad)) & MFI_STATE_MASK; + if (fw_state == MFI_STATE_FAULT) { + mrsas_dprint(sc, MRSAS_OCR, + "Found FW in FAULT state, will reset adapter.\n"); + retval = 1; + goto out; + } + outstanding = atomic_read(&sc->fw_outstanding); + if (!outstanding) + goto out; + + if (!(i % MRSAS_RESET_NOTICE_INTERVAL)) { + mrsas_dprint(sc, MRSAS_OCR, "[%2d]waiting for %d " + "commands to complete\n",i,outstanding); + mrsas_complete_cmd(sc); + } + DELAY(1000 * 1000); + } + + if (atomic_read(&sc->fw_outstanding)) { + mrsas_dprint(sc, MRSAS_OCR, + " pending commands remain after waiting," + " will reset adapter.\n"); + retval = 1; + } +out: + return retval; +} + +/** + * mrsas_release_mfi_cmd: Return a cmd to free command pool + * input: Command packet for return to free cmd pool + * + * This function returns the MFI command to the command list. + */ +void mrsas_release_mfi_cmd(struct mrsas_mfi_cmd *cmd) +{ + struct mrsas_softc *sc = cmd->sc; + + mtx_lock(&sc->mfi_cmd_pool_lock); + cmd->ccb_ptr = NULL; + cmd->cmd_id.frame_count = 0; + TAILQ_INSERT_TAIL(&(sc->mrsas_mfi_cmd_list_head), cmd, next); + mtx_unlock(&sc->mfi_cmd_pool_lock); + + return; +} + +/** + * mrsas_get_controller_info - Returns FW's controller structure + * input: Adapter soft state + * Controller information structure + * + * Issues an internal command (DCMD) to get the FW's controller structure. + * This information is mainly used to find out the maximum IO transfer per + * command supported by the FW. + */ +static int mrsas_get_ctrl_info(struct mrsas_softc *sc, + struct mrsas_ctrl_info *ctrl_info) +{ + int retcode = 0; + struct mrsas_mfi_cmd *cmd; + struct mrsas_dcmd_frame *dcmd; + + cmd = mrsas_get_mfi_cmd(sc); + + if (!cmd) { + device_printf(sc->mrsas_dev, "Failed to get a free cmd\n"); + return -ENOMEM; + } + dcmd = &cmd->frame->dcmd; + + if (mrsas_alloc_ctlr_info_cmd(sc) != SUCCESS) { + device_printf(sc->mrsas_dev, "Cannot allocate get ctlr info cmd\n"); + mrsas_release_mfi_cmd(cmd); + return -ENOMEM; + } + memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); + + dcmd->cmd = MFI_CMD_DCMD; + dcmd->cmd_status = 0xFF; + dcmd->sge_count = 1; + dcmd->flags = MFI_FRAME_DIR_READ; + dcmd->timeout = 0; + dcmd->pad_0 = 0; + dcmd->data_xfer_len = sizeof(struct mrsas_ctrl_info); + dcmd->opcode = MR_DCMD_CTRL_GET_INFO; + dcmd->sgl.sge32[0].phys_addr = sc->ctlr_info_phys_addr; + dcmd->sgl.sge32[0].length = sizeof(struct mrsas_ctrl_info); + + if (!mrsas_issue_polled(sc, cmd)) + memcpy(ctrl_info, sc->ctlr_info_mem, sizeof(struct mrsas_ctrl_info)); + else + retcode = 1; + + mrsas_free_ctlr_info_cmd(sc); + mrsas_release_mfi_cmd(cmd); + return(retcode); +} + +/** + * mrsas_alloc_ctlr_info_cmd: Allocates memory for controller info command + * input: Adapter soft state + * + * Allocates DMAable memory for the controller info internal command. + */ +int mrsas_alloc_ctlr_info_cmd(struct mrsas_softc *sc) +{ + int ctlr_info_size; + + /* Allocate get controller info command */ + ctlr_info_size = sizeof(struct mrsas_ctrl_info); + if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent + 1, 0, // algnmnt, boundary + BUS_SPACE_MAXADDR_32BIT,// lowaddr + BUS_SPACE_MAXADDR, // highaddr + NULL, NULL, // filter, filterarg + ctlr_info_size, // maxsize + 1, // msegments + ctlr_info_size, // maxsegsize + BUS_DMA_ALLOCNOW, // flags + NULL, NULL, // lockfunc, lockarg + &sc->ctlr_info_tag)) { + device_printf(sc->mrsas_dev, "Cannot allocate ctlr info tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->ctlr_info_tag, (void **)&sc->ctlr_info_mem, + BUS_DMA_NOWAIT, &sc->ctlr_info_dmamap)) { + device_printf(sc->mrsas_dev, "Cannot allocate ctlr info cmd mem\n"); + return (ENOMEM); + } + if (bus_dmamap_load(sc->ctlr_info_tag, sc->ctlr_info_dmamap, + sc->ctlr_info_mem, ctlr_info_size, mrsas_addr_cb, + &sc->ctlr_info_phys_addr, BUS_DMA_NOWAIT)) { + device_printf(sc->mrsas_dev, "Cannot load ctlr info cmd mem\n"); + return (ENOMEM); + } + + memset(sc->ctlr_info_mem, 0, ctlr_info_size); + return (0); +} + +/** + * mrsas_free_ctlr_info_cmd: Free memory for controller info command + * input: Adapter soft state + * + * Deallocates memory of the get controller info cmd. + */ +void mrsas_free_ctlr_info_cmd(struct mrsas_softc *sc) +{ + if (sc->ctlr_info_phys_addr) + bus_dmamap_unload(sc->ctlr_info_tag, sc->ctlr_info_dmamap); + if (sc->ctlr_info_mem != NULL) + bus_dmamem_free(sc->ctlr_info_tag, sc->ctlr_info_mem, sc->ctlr_info_dmamap); + if (sc->ctlr_info_tag != NULL) + bus_dma_tag_destroy(sc->ctlr_info_tag); +} + +/** + * mrsas_issue_polled: Issues a polling command + * inputs: Adapter soft state + * Command packet to be issued + * + * This function is for posting of internal commands to Firmware. MFI + * requires the cmd_status to be set to 0xFF before posting. The maximun + * wait time of the poll response timer is 180 seconds. + */ +int mrsas_issue_polled(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd) +{ + struct mrsas_header *frame_hdr = &cmd->frame->hdr; + u_int8_t max_wait = MRSAS_INTERNAL_CMD_WAIT_TIME; + int i, retcode = 0; + + frame_hdr->cmd_status = 0xFF; + frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; + + /* Issue the frame using inbound queue port */ + if (mrsas_issue_dcmd(sc, cmd)) { + device_printf(sc->mrsas_dev, "Cannot issue DCMD internal command.\n"); + return(1); + } + + /* + * Poll response timer to wait for Firmware response. While this + * timer with the DELAY call could block CPU, the time interval for + * this is only 1 millisecond. + */ + if (frame_hdr->cmd_status == 0xFF) { + for (i=0; i < (max_wait * 1000); i++){ + if (frame_hdr->cmd_status == 0xFF) + DELAY(1000); + else + break; + } + } + if (frame_hdr->cmd_status != 0) + { + if (frame_hdr->cmd_status == 0xFF) + device_printf(sc->mrsas_dev, "DCMD timed out after %d seconds.\n", max_wait); + else + device_printf(sc->mrsas_dev, "DCMD failed, status = 0x%x\n", frame_hdr->cmd_status); + retcode = 1; + } + return(retcode); +} + +/** + * mrsas_issue_dcmd - Issues a MFI Pass thru cmd + * input: Adapter soft state + * mfi cmd pointer + * + * This function is called by mrsas_issued_blocked_cmd() and + * mrsas_issued_polled(), to build the MPT command and then fire the + * command to Firmware. + */ +int +mrsas_issue_dcmd(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd) +{ + MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc; + + req_desc = mrsas_build_mpt_cmd(sc, cmd); + if (!req_desc) { + device_printf(sc->mrsas_dev, "Cannot build MPT cmd.\n"); + return(1); + } + + mrsas_fire_cmd(sc, req_desc->addr.u.low, req_desc->addr.u.high); + + return(0); +} + +/** + * mrsas_build_mpt_cmd - Calls helper function to build Passthru cmd + * input: Adapter soft state + * mfi cmd to build + * + * This function is called by mrsas_issue_cmd() to build the MPT-MFI + * passthru command and prepares the MPT command to send to Firmware. + */ +MRSAS_REQUEST_DESCRIPTOR_UNION * +mrsas_build_mpt_cmd(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd) +{ + MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc; + u_int16_t index; + + if (mrsas_build_mptmfi_passthru(sc, cmd)) { + device_printf(sc->mrsas_dev, "Cannot build MPT-MFI passthru cmd.\n"); + return NULL; + } + + index = cmd->cmd_id.context.smid; + + req_desc = mrsas_get_request_desc(sc, index-1); + if(!req_desc) + return NULL; + + req_desc->addr.Words = 0; + req_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + + req_desc->SCSIIO.SMID = index; + + return(req_desc); +} + +/** + * mrsas_build_mptmfi_passthru - Builds a MPT MFI Passthru command + * input: Adapter soft state + * mfi cmd pointer + * + * The MPT command and the io_request are setup as a passthru command. + * The SGE chain address is set to frame_phys_addr of the MFI command. + */ +u_int8_t +mrsas_build_mptmfi_passthru(struct mrsas_softc *sc, struct mrsas_mfi_cmd *mfi_cmd) +{ + MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain; + PTR_MRSAS_RAID_SCSI_IO_REQUEST io_req; + struct mrsas_mpt_cmd *mpt_cmd; + struct mrsas_header *frame_hdr = &mfi_cmd->frame->hdr; + + mpt_cmd = mrsas_get_mpt_cmd(sc); + if (!mpt_cmd) + return(1); + + /* Save the smid. To be used for returning the cmd */ + mfi_cmd->cmd_id.context.smid = mpt_cmd->index; + + mpt_cmd->sync_cmd_idx = mfi_cmd->index; + + /* + * For cmds where the flag is set, store the flag and check + * on completion. For cmds with this flag, don't call + * mrsas_complete_cmd. + */ + + if (frame_hdr->flags & MFI_FRAME_DONT_POST_IN_REPLY_QUEUE) + mpt_cmd->flags = MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; + + io_req = mpt_cmd->io_request; + + if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) { + pMpi25IeeeSgeChain64_t sgl_ptr_end = (pMpi25IeeeSgeChain64_t) &io_req->SGL; + sgl_ptr_end += sc->max_sge_in_main_msg - 1; + sgl_ptr_end->Flags = 0; + } + + mpi25_ieee_chain = (MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain; + + io_req->Function = MRSAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST; + io_req->SGLOffset0 = offsetof(MRSAS_RAID_SCSI_IO_REQUEST, SGL) / 4; + io_req->ChainOffset = sc->chain_offset_mfi_pthru; + + mpi25_ieee_chain->Address = mfi_cmd->frame_phys_addr; + + mpi25_ieee_chain->Flags= IEEE_SGE_FLAGS_CHAIN_ELEMENT | + MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR; + + mpi25_ieee_chain->Length = MRSAS_MAX_SZ_CHAIN_FRAME; + + return(0); +} + +/** + * mrsas_issue_blocked_cmd - Synchronous wrapper around regular FW cmds + * input: Adapter soft state + * Command to be issued + * + * This function waits on an event for the command to be returned + * from the ISR. Max wait time is MRSAS_INTERNAL_CMD_WAIT_TIME secs. + * Used for issuing internal and ioctl commands. + */ +int mrsas_issue_blocked_cmd(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd) +{ + u_int8_t max_wait = MRSAS_INTERNAL_CMD_WAIT_TIME; + unsigned long total_time = 0; + int retcode = 0; + + /* Initialize cmd_status */ + cmd->cmd_status = ECONNREFUSED; + + /* Build MPT-MFI command for issue to FW */ + if (mrsas_issue_dcmd(sc, cmd)){ + device_printf(sc->mrsas_dev, "Cannot issue DCMD internal command.\n"); + return(1); + } + + sc->chan = (void*)&cmd; + + /* The following is for debug only... */ + //device_printf(sc->mrsas_dev,"DCMD issued to FW, about to sleep-wait...\n"); + //device_printf(sc->mrsas_dev,"sc->chan = %p\n", sc->chan); + + while (1) { + if (cmd->cmd_status == ECONNREFUSED){ + tsleep((void *)&sc->chan, 0, "mrsas_sleep", hz); + } + else + break; + total_time++; + if (total_time >= max_wait) { + device_printf(sc->mrsas_dev, "Internal command timed out after %d seconds.\n", max_wait); + retcode = 1; + break; + } + } + return(retcode); +} + +/** + * mrsas_complete_mptmfi_passthru - Completes a command + * input: sc: Adapter soft state + * cmd: Command to be completed + * status: cmd completion status + * + * This function is called from mrsas_complete_cmd() after an interrupt + * is received from Firmware, and io_request->Function is + * MRSAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST. + */ +void +mrsas_complete_mptmfi_passthru(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd, + u_int8_t status) +{ + struct mrsas_header *hdr = &cmd->frame->hdr; + u_int8_t cmd_status = cmd->frame->hdr.cmd_status; + + /* Reset the retry counter for future re-tries */ + cmd->retry_for_fw_reset = 0; + + if (cmd->ccb_ptr) + cmd->ccb_ptr = NULL; + + switch (hdr->cmd) { + case MFI_CMD_INVALID: + device_printf(sc->mrsas_dev, "MFI_CMD_INVALID command.\n"); + break; + case MFI_CMD_PD_SCSI_IO: + case MFI_CMD_LD_SCSI_IO: + /* + * MFI_CMD_PD_SCSI_IO and MFI_CMD_LD_SCSI_IO could have been + * issued either through an IO path or an IOCTL path. If it + * was via IOCTL, we will send it to internal completion. + */ + if (cmd->sync_cmd) { + cmd->sync_cmd = 0; + mrsas_wakeup(sc, cmd); + break; + } + case MFI_CMD_SMP: + case MFI_CMD_STP: + case MFI_CMD_DCMD: + /* Check for LD map update */ + if ((cmd->frame->dcmd.opcode == MR_DCMD_LD_MAP_GET_INFO) && + (cmd->frame->dcmd.mbox.b[1] == 1)) { + sc->fast_path_io = 0; + mtx_lock(&sc->raidmap_lock); + if (cmd_status != 0) { + if (cmd_status != MFI_STAT_NOT_FOUND) + device_printf(sc->mrsas_dev, "map sync failed, status=%x\n",cmd_status); + else { + mrsas_release_mfi_cmd(cmd); + mtx_unlock(&sc->raidmap_lock); + break; + } + } + else + sc->map_id++; + mrsas_release_mfi_cmd(cmd); + if (MR_ValidateMapInfo(sc)) + sc->fast_path_io = 0; + else + sc->fast_path_io = 1; + mrsas_sync_map_info(sc); + mtx_unlock(&sc->raidmap_lock); + break; + } +#if 0 //currently not supporting event handling, so commenting out + if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO || + cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) { + mrsas_poll_wait_aen = 0; + } +#endif + /* See if got an event notification */ + if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_WAIT) + mrsas_complete_aen(sc, cmd); + else + mrsas_wakeup(sc, cmd); + break; + case MFI_CMD_ABORT: + /* Command issued to abort another cmd return */ + mrsas_complete_abort(sc, cmd); + break; + default: + device_printf(sc->mrsas_dev,"Unknown command completed! [0x%X]\n", hdr->cmd); + break; + } +} + +/** + * mrsas_wakeup - Completes an internal command + * input: Adapter soft state + * Command to be completed + * + * In mrsas_issue_blocked_cmd(), after a command is issued to Firmware, + * a wait timer is started. This function is called from + * mrsas_complete_mptmfi_passthru() as it completes the command, + * to wake up from the command wait. + */ +void mrsas_wakeup(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd) +{ + cmd->cmd_status = cmd->frame->io.cmd_status; + + if (cmd->cmd_status == ECONNREFUSED) + cmd->cmd_status = 0; + + /* For debug only ... */ + //device_printf(sc->mrsas_dev,"DCMD rec'd for wakeup, sc->chan=%p\n", sc->chan); + + sc->chan = (void*)&cmd; + wakeup_one((void *)&sc->chan); + return; +} + +/** + * mrsas_shutdown_ctlr: Instructs FW to shutdown the controller + * input: Adapter soft state + * Shutdown/Hibernate + * + * This function issues a DCMD internal command to Firmware to initiate + * shutdown of the controller. + */ +static void mrsas_shutdown_ctlr(struct mrsas_softc *sc, u_int32_t opcode) +{ + struct mrsas_mfi_cmd *cmd; + struct mrsas_dcmd_frame *dcmd; + + if (sc->adprecovery == MRSAS_HW_CRITICAL_ERROR) + return; + + cmd = mrsas_get_mfi_cmd(sc); + if (!cmd) { + device_printf(sc->mrsas_dev,"Cannot allocate for shutdown cmd.\n"); + return; + } + + if (sc->aen_cmd) + mrsas_issue_blocked_abort_cmd(sc, sc->aen_cmd); + + if (sc->map_update_cmd) + mrsas_issue_blocked_abort_cmd(sc, sc->map_update_cmd); + + dcmd = &cmd->frame->dcmd; + memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); + + dcmd->cmd = MFI_CMD_DCMD; + dcmd->cmd_status = 0x0; + dcmd->sge_count = 0; + dcmd->flags = MFI_FRAME_DIR_NONE; + dcmd->timeout = 0; + dcmd->pad_0 = 0; + dcmd->data_xfer_len = 0; + dcmd->opcode = opcode; + + device_printf(sc->mrsas_dev,"Preparing to shut down controller.\n"); + + mrsas_issue_blocked_cmd(sc, cmd); + mrsas_release_mfi_cmd(cmd); + + return; +} + +/** + * mrsas_flush_cache: Requests FW to flush all its caches + * input: Adapter soft state + * + * This function is issues a DCMD internal command to Firmware to initiate + * flushing of all caches. + */ +static void mrsas_flush_cache(struct mrsas_softc *sc) +{ + struct mrsas_mfi_cmd *cmd; + struct mrsas_dcmd_frame *dcmd; + + if (sc->adprecovery == MRSAS_HW_CRITICAL_ERROR) + return; + + cmd = mrsas_get_mfi_cmd(sc); + if (!cmd) { + device_printf(sc->mrsas_dev,"Cannot allocate for flush cache cmd.\n"); + return; + } + + dcmd = &cmd->frame->dcmd; + memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); + + dcmd->cmd = MFI_CMD_DCMD; + dcmd->cmd_status = 0x0; + dcmd->sge_count = 0; + dcmd->flags = MFI_FRAME_DIR_NONE; + dcmd->timeout = 0; + dcmd->pad_0 = 0; + dcmd->data_xfer_len = 0; + dcmd->opcode = MR_DCMD_CTRL_CACHE_FLUSH; + dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE; + + mrsas_issue_blocked_cmd(sc, cmd); + mrsas_release_mfi_cmd(cmd); + + return; +} + +/** + * mrsas_get_map_info: Load and validate RAID map + * input: Adapter instance soft state + * + * This function calls mrsas_get_ld_map_info() and MR_ValidateMapInfo() + * to load and validate RAID map. It returns 0 if successful, 1 other- + * wise. + */ +static int mrsas_get_map_info(struct mrsas_softc *sc) +{ + uint8_t retcode = 0; + + sc->fast_path_io = 0; + if (!mrsas_get_ld_map_info(sc)) { + retcode = MR_ValidateMapInfo(sc); + if (retcode == 0) { + sc->fast_path_io = 1; + return 0; + } + } + return 1; +} + +/** + * mrsas_get_ld_map_info: Get FW's ld_map structure + * input: Adapter instance soft state + * + * Issues an internal command (DCMD) to get the FW's controller PD + * list structure. + */ +static int mrsas_get_ld_map_info(struct mrsas_softc *sc) +{ + int retcode = 0; + struct mrsas_mfi_cmd *cmd; + struct mrsas_dcmd_frame *dcmd; + MR_FW_RAID_MAP_ALL *map; + bus_addr_t map_phys_addr = 0; + + cmd = mrsas_get_mfi_cmd(sc); + if (!cmd) { + device_printf(sc->mrsas_dev, "Cannot alloc for ld map info cmd.\n"); + return 1; + } + + dcmd = &cmd->frame->dcmd; + + map = sc->raidmap_mem[(sc->map_id & 1)]; + map_phys_addr = sc->raidmap_phys_addr[(sc->map_id & 1)]; + if (!map) { + device_printf(sc->mrsas_dev, "Failed to alloc mem for ld map info.\n"); + mrsas_release_mfi_cmd(cmd); + return (ENOMEM); + } + memset(map, 0, sizeof(*map)); + memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); + + dcmd->cmd = MFI_CMD_DCMD; + dcmd->cmd_status = 0xFF; + dcmd->sge_count = 1; + dcmd->flags = MFI_FRAME_DIR_READ; + dcmd->timeout = 0; + dcmd->pad_0 = 0; + dcmd->data_xfer_len = sc->map_sz; + dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO; + dcmd->sgl.sge32[0].phys_addr = map_phys_addr; + dcmd->sgl.sge32[0].length = sc->map_sz; + if (!mrsas_issue_polled(sc, cmd)) + retcode = 0; + else + { + device_printf(sc->mrsas_dev, "Fail to send get LD map info cmd.\n"); + retcode = 1; + } + mrsas_release_mfi_cmd(cmd); + return(retcode); +} + +/** + * mrsas_sync_map_info: Get FW's ld_map structure + * input: Adapter instance soft state + * + * Issues an internal command (DCMD) to get the FW's controller PD + * list structure. + */ +static int mrsas_sync_map_info(struct mrsas_softc *sc) +{ + int retcode = 0, i; + struct mrsas_mfi_cmd *cmd; + struct mrsas_dcmd_frame *dcmd; + uint32_t size_sync_info, num_lds; + MR_LD_TARGET_SYNC *target_map = NULL; + MR_FW_RAID_MAP_ALL *map; + MR_LD_RAID *raid; + MR_LD_TARGET_SYNC *ld_sync; + bus_addr_t map_phys_addr = 0; + + cmd = mrsas_get_mfi_cmd(sc); + if (!cmd) { + device_printf(sc->mrsas_dev, "Cannot alloc for sync map info cmd\n"); + return 1; + } + + map = sc->raidmap_mem[sc->map_id & 1]; + num_lds = map->raidMap.ldCount; + + dcmd = &cmd->frame->dcmd; + size_sync_info = sizeof(MR_LD_TARGET_SYNC) * num_lds; + memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); + + target_map = (MR_LD_TARGET_SYNC *)sc->raidmap_mem[(sc->map_id - 1) & 1]; + memset(target_map, 0, sizeof(MR_FW_RAID_MAP_ALL)); + + map_phys_addr = sc->raidmap_phys_addr[(sc->map_id - 1) & 1]; + + ld_sync = (MR_LD_TARGET_SYNC *)target_map; + + for (i = 0; i < num_lds; i++, ld_sync++) { + raid = MR_LdRaidGet(i, map); + ld_sync->targetId = MR_GetLDTgtId(i, map); + ld_sync->seqNum = raid->seqNum; + } + + dcmd->cmd = MFI_CMD_DCMD; + dcmd->cmd_status = 0xFF; + dcmd->sge_count = 1; + dcmd->flags = MFI_FRAME_DIR_WRITE; + dcmd->timeout = 0; + dcmd->pad_0 = 0; + dcmd->data_xfer_len = sc->map_sz; + dcmd->mbox.b[0] = num_lds; + dcmd->mbox.b[1] = MRSAS_DCMD_MBOX_PEND_FLAG; + dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO; + dcmd->sgl.sge32[0].phys_addr = map_phys_addr; + dcmd->sgl.sge32[0].length = sc->map_sz; + + sc->map_update_cmd = cmd; + if (mrsas_issue_dcmd(sc, cmd)) { + device_printf(sc->mrsas_dev, "Fail to send sync map info command.\n"); + return(1); + } + return(retcode); +} + +/** + * mrsas_get_pd_list: Returns FW's PD list structure + * input: Adapter soft state + * + * Issues an internal command (DCMD) to get the FW's controller PD + * list structure. This information is mainly used to find out about + * system supported by Firmware. + */ +static int mrsas_get_pd_list(struct mrsas_softc *sc) +{ + int retcode = 0, pd_index = 0, pd_count=0, pd_list_size; + struct mrsas_mfi_cmd *cmd; + struct mrsas_dcmd_frame *dcmd; + struct MR_PD_LIST *pd_list_mem; + struct MR_PD_ADDRESS *pd_addr; + bus_addr_t pd_list_phys_addr = 0; + struct mrsas_tmp_dcmd *tcmd; + + cmd = mrsas_get_mfi_cmd(sc); + if (!cmd) { + device_printf(sc->mrsas_dev, "Cannot alloc for get PD list cmd\n"); + return 1; + } + + dcmd = &cmd->frame->dcmd; + + tcmd = malloc(sizeof(struct mrsas_tmp_dcmd), M_MRSAS, M_NOWAIT); + pd_list_size = MRSAS_MAX_PD * sizeof(struct MR_PD_LIST); + if (mrsas_alloc_tmp_dcmd(sc, tcmd, pd_list_size) != SUCCESS) { + device_printf(sc->mrsas_dev, "Cannot alloc dmamap for get PD list cmd\n"); + mrsas_release_mfi_cmd(cmd); + return(ENOMEM); + } + else { + pd_list_mem = tcmd->tmp_dcmd_mem; + pd_list_phys_addr = tcmd->tmp_dcmd_phys_addr; + } + memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); + + dcmd->mbox.b[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST; + dcmd->mbox.b[1] = 0; + dcmd->cmd = MFI_CMD_DCMD; + dcmd->cmd_status = 0xFF; + dcmd->sge_count = 1; + dcmd->flags = MFI_FRAME_DIR_READ; + dcmd->timeout = 0; + dcmd->pad_0 = 0; + dcmd->data_xfer_len = MRSAS_MAX_PD * sizeof(struct MR_PD_LIST); + dcmd->opcode = MR_DCMD_PD_LIST_QUERY; + dcmd->sgl.sge32[0].phys_addr = pd_list_phys_addr; + dcmd->sgl.sge32[0].length = MRSAS_MAX_PD * sizeof(struct MR_PD_LIST); + + if (!mrsas_issue_polled(sc, cmd)) + retcode = 0; + else + retcode = 1; + + /* Get the instance PD list */ + pd_count = MRSAS_MAX_PD; + pd_addr = pd_list_mem->addr; + if (retcode == 0 && pd_list_mem->count < pd_count) { + memset(sc->local_pd_list, 0, MRSAS_MAX_PD * sizeof(struct mrsas_pd_list)); + for (pd_index = 0; pd_index < pd_list_mem->count; pd_index++) { + sc->local_pd_list[pd_addr->deviceId].tid = pd_addr->deviceId; + sc->local_pd_list[pd_addr->deviceId].driveType = pd_addr->scsiDevType; + sc->local_pd_list[pd_addr->deviceId].driveState = MR_PD_STATE_SYSTEM; + pd_addr++; + } + } + + /* Use mutext/spinlock if pd_list component size increase more than 32 bit. */ + memcpy(sc->pd_list, sc->local_pd_list, sizeof(sc->local_pd_list)); + mrsas_free_tmp_dcmd(tcmd); + mrsas_release_mfi_cmd(cmd); + free(tcmd, M_MRSAS); + return(retcode); +} + +/** + * mrsas_get_ld_list: Returns FW's LD list structure + * input: Adapter soft state + * + * Issues an internal command (DCMD) to get the FW's controller PD + * list structure. This information is mainly used to find out about + * supported by the FW. + */ +static int mrsas_get_ld_list(struct mrsas_softc *sc) +{ + int ld_list_size, retcode = 0, ld_index = 0, ids = 0; + struct mrsas_mfi_cmd *cmd; + struct mrsas_dcmd_frame *dcmd; + struct MR_LD_LIST *ld_list_mem; + bus_addr_t ld_list_phys_addr = 0; + struct mrsas_tmp_dcmd *tcmd; + + cmd = mrsas_get_mfi_cmd(sc); + if (!cmd) { + device_printf(sc->mrsas_dev, "Cannot alloc for get LD list cmd\n"); + return 1; + } + + dcmd = &cmd->frame->dcmd; + + tcmd = malloc(sizeof(struct mrsas_tmp_dcmd), M_MRSAS, M_NOWAIT); + ld_list_size = sizeof(struct MR_LD_LIST); + if (mrsas_alloc_tmp_dcmd(sc, tcmd, ld_list_size) != SUCCESS) { + device_printf(sc->mrsas_dev, "Cannot alloc dmamap for get LD list cmd\n"); + mrsas_release_mfi_cmd(cmd); + return(ENOMEM); + } + else { + ld_list_mem = tcmd->tmp_dcmd_mem; + ld_list_phys_addr = tcmd->tmp_dcmd_phys_addr; + } + memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); + + dcmd->cmd = MFI_CMD_DCMD; + dcmd->cmd_status = 0xFF; + dcmd->sge_count = 1; + dcmd->flags = MFI_FRAME_DIR_READ; + dcmd->timeout = 0; + dcmd->data_xfer_len = sizeof(struct MR_LD_LIST); + dcmd->opcode = MR_DCMD_LD_GET_LIST; + dcmd->sgl.sge32[0].phys_addr = ld_list_phys_addr; + dcmd->sgl.sge32[0].length = sizeof(struct MR_LD_LIST); + dcmd->pad_0 = 0; + + if (!mrsas_issue_polled(sc, cmd)) + retcode = 0; + else + retcode = 1; + + /* Get the instance LD list */ + if ((retcode == 0) && (ld_list_mem->ldCount <= (MAX_LOGICAL_DRIVES))){ + sc->CurLdCount = ld_list_mem->ldCount; + memset(sc->ld_ids, 0xff, MRSAS_MAX_LD); + for (ld_index = 0; ld_index < ld_list_mem->ldCount; ld_index++) { + if (ld_list_mem->ldList[ld_index].state != 0) { + ids = ld_list_mem->ldList[ld_index].ref.ld_context.targetId; + sc->ld_ids[ids] = ld_list_mem->ldList[ld_index].ref.ld_context.targetId; + } + } + } + + mrsas_free_tmp_dcmd(tcmd); + mrsas_release_mfi_cmd(cmd); + free(tcmd, M_MRSAS); + return(retcode); +} + +/** + * mrsas_alloc_tmp_dcmd: Allocates memory for temporary command + * input: Adapter soft state + * Temp command + * Size of alloction + * + * Allocates DMAable memory for a temporary internal command. The allocated + * memory is initialized to all zeros upon successful loading of the dma + * mapped memory. + */ +int mrsas_alloc_tmp_dcmd(struct mrsas_softc *sc, struct mrsas_tmp_dcmd *tcmd, + int size) +{ + if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent + 1, 0, // algnmnt, boundary + BUS_SPACE_MAXADDR_32BIT,// lowaddr + BUS_SPACE_MAXADDR, // highaddr + NULL, NULL, // filter, filterarg + size, // maxsize + 1, // msegments + size, // maxsegsize + BUS_DMA_ALLOCNOW, // flags + NULL, NULL, // lockfunc, lockarg + &tcmd->tmp_dcmd_tag)) { + device_printf(sc->mrsas_dev, "Cannot allocate tmp dcmd tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(tcmd->tmp_dcmd_tag, (void **)&tcmd->tmp_dcmd_mem, + BUS_DMA_NOWAIT, &tcmd->tmp_dcmd_dmamap)) { + device_printf(sc->mrsas_dev, "Cannot allocate tmp dcmd mem\n"); + return (ENOMEM); + } + if (bus_dmamap_load(tcmd->tmp_dcmd_tag, tcmd->tmp_dcmd_dmamap, + tcmd->tmp_dcmd_mem, size, mrsas_addr_cb, + &tcmd->tmp_dcmd_phys_addr, BUS_DMA_NOWAIT)) { + device_printf(sc->mrsas_dev, "Cannot load tmp dcmd mem\n"); + return (ENOMEM); + } + + memset(tcmd->tmp_dcmd_mem, 0, size); + return (0); +} + +/** + * mrsas_free_tmp_dcmd: Free memory for temporary command + * input: temporary dcmd pointer + * + * Deallocates memory of the temporary command for use in the construction + * of the internal DCMD. + */ +void mrsas_free_tmp_dcmd(struct mrsas_tmp_dcmd *tmp) +{ + if (tmp->tmp_dcmd_phys_addr) + bus_dmamap_unload(tmp->tmp_dcmd_tag, tmp->tmp_dcmd_dmamap); + if (tmp->tmp_dcmd_mem != NULL) + bus_dmamem_free(tmp->tmp_dcmd_tag, tmp->tmp_dcmd_mem, tmp->tmp_dcmd_dmamap); + if (tmp->tmp_dcmd_tag != NULL) + bus_dma_tag_destroy(tmp->tmp_dcmd_tag); +} + +/** + * mrsas_issue_blocked_abort_cmd: Aborts previously issued cmd + * input: Adapter soft state + * Previously issued cmd to be aborted + * + * This function is used to abort previously issued commands, such as AEN and + * RAID map sync map commands. The abort command is sent as a DCMD internal + * command and subsequently the driver will wait for a return status. The + * max wait time is MRSAS_INTERNAL_CMD_WAIT_TIME seconds. + */ +static int mrsas_issue_blocked_abort_cmd(struct mrsas_softc *sc, + struct mrsas_mfi_cmd *cmd_to_abort) +{ + struct mrsas_mfi_cmd *cmd; + struct mrsas_abort_frame *abort_fr; + u_int8_t retcode = 0; + unsigned long total_time = 0; + u_int8_t max_wait = MRSAS_INTERNAL_CMD_WAIT_TIME; + + cmd = mrsas_get_mfi_cmd(sc); + if (!cmd) { + device_printf(sc->mrsas_dev, "Cannot alloc for abort cmd\n"); + return(1); + } + + abort_fr = &cmd->frame->abort; + + /* Prepare and issue the abort frame */ + abort_fr->cmd = MFI_CMD_ABORT; + abort_fr->cmd_status = 0xFF; + abort_fr->flags = 0; + abort_fr->abort_context = cmd_to_abort->index; + abort_fr->abort_mfi_phys_addr_lo = cmd_to_abort->frame_phys_addr; + abort_fr->abort_mfi_phys_addr_hi = 0; + + cmd->sync_cmd = 1; + cmd->cmd_status = 0xFF; + + if (mrsas_issue_dcmd(sc, cmd)) { + device_printf(sc->mrsas_dev, "Fail to send abort command.\n"); + return(1); + } + + /* Wait for this cmd to complete */ + sc->chan = (void*)&cmd; + while (1) { + if (cmd->cmd_status == 0xFF){ + tsleep((void *)&sc->chan, 0, "mrsas_sleep", hz); + } + else + break; + total_time++; + if (total_time >= max_wait) { + device_printf(sc->mrsas_dev, "Abort cmd timed out after %d sec.\n", max_wait); + retcode = 1; + break; + } + } + + cmd->sync_cmd = 0; + mrsas_release_mfi_cmd(cmd); + return(retcode); +} + +/** + * mrsas_complete_abort: Completes aborting a command + * input: Adapter soft state + * Cmd that was issued to abort another cmd + * + * The mrsas_issue_blocked_abort_cmd() function waits for the command status + * to change after sending the command. This function is called from + * mrsas_complete_mptmfi_passthru() to wake up the sleep thread associated. + */ +void mrsas_complete_abort(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd) +{ + if (cmd->sync_cmd) { + cmd->sync_cmd = 0; + cmd->cmd_status = 0; + sc->chan = (void*)&cmd; + wakeup_one((void *)&sc->chan); + } + return; +} + +/** + * mrsas_aen_handler: Callback function for AEN processing from thread context. + * input: Adapter soft state + * + */ +void mrsas_aen_handler(struct mrsas_softc *sc) +{ + union mrsas_evt_class_locale class_locale; + int doscan = 0; + u_int32_t seq_num; + int error; + + if (!sc) { + device_printf(sc->mrsas_dev, "invalid instance!\n"); + return; + } + + if (sc->evt_detail_mem) { + switch (sc->evt_detail_mem->code) { + case MR_EVT_PD_INSERTED: + mrsas_get_pd_list(sc); + mrsas_bus_scan_sim(sc, sc->sim_1); + doscan = 0; + break; + case MR_EVT_PD_REMOVED: + mrsas_get_pd_list(sc); + mrsas_bus_scan_sim(sc, sc->sim_1); + doscan = 0; + break; + case MR_EVT_LD_OFFLINE: + case MR_EVT_CFG_CLEARED: + case MR_EVT_LD_DELETED: + mrsas_bus_scan_sim(sc, sc->sim_0); + doscan = 0; + break; + case MR_EVT_LD_CREATED: + mrsas_get_ld_list(sc); + mrsas_bus_scan_sim(sc, sc->sim_0); + doscan = 0; + break; + case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED: + case MR_EVT_FOREIGN_CFG_IMPORTED: + case MR_EVT_LD_STATE_CHANGE: + doscan = 1; + break; + default: + doscan = 0; + break; + } + } else { + device_printf(sc->mrsas_dev, "invalid evt_detail\n"); + return; + } + if (doscan) { + mrsas_get_pd_list(sc); + mrsas_dprint(sc, MRSAS_AEN, "scanning ...sim 1\n"); + mrsas_bus_scan_sim(sc, sc->sim_1); + mrsas_get_ld_list(sc); + mrsas_dprint(sc, MRSAS_AEN, "scanning ...sim 0\n"); + mrsas_bus_scan_sim(sc, sc->sim_0); + } + + seq_num = sc->evt_detail_mem->seq_num + 1; + + // Register AEN with FW for latest sequence number plus 1 + class_locale.members.reserved = 0; + class_locale.members.locale = MR_EVT_LOCALE_ALL; + class_locale.members.class = MR_EVT_CLASS_DEBUG; + + if (sc->aen_cmd != NULL ) + return ; + + mtx_lock(&sc->aen_lock); + error = mrsas_register_aen(sc, seq_num, + class_locale.word); + mtx_unlock(&sc->aen_lock); + + if (error) + device_printf(sc->mrsas_dev, "register aen failed error %x\n", error); + +} + + +/** + * mrsas_complete_aen: Completes AEN command + * input: Adapter soft state + * Cmd that was issued to abort another cmd + * + * This function will be called from ISR and will continue + * event processing from thread context by enqueuing task + * in ev_tq (callback function "mrsas_aen_handler"). + */ +void mrsas_complete_aen(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd) +{ + /* + * Don't signal app if it is just an aborted previously registered aen + */ + if ((!cmd->abort_aen) && (sc->remove_in_progress == 0)) { + /* TO DO (?) */ + } + else + cmd->abort_aen = 0; + + sc->aen_cmd = NULL; + mrsas_release_mfi_cmd(cmd); + + if (!sc->remove_in_progress) + taskqueue_enqueue(sc->ev_tq, &sc->ev_task); + + return; +} + +static device_method_t mrsas_methods[] = { + DEVMETHOD(device_probe, mrsas_probe), + DEVMETHOD(device_attach, mrsas_attach), + DEVMETHOD(device_detach, mrsas_detach), + DEVMETHOD(device_suspend, mrsas_suspend), + DEVMETHOD(device_resume, mrsas_resume), + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), + { 0, 0 } +}; + +static driver_t mrsas_driver = { + "mrsas", + mrsas_methods, + sizeof(struct mrsas_softc) +}; + +static devclass_t mrsas_devclass; +DRIVER_MODULE(mrsas, pci, mrsas_driver, mrsas_devclass, 0, 0); +MODULE_DEPEND(mrsas, cam, 1,1,1); + diff --git a/sys/dev/mrsas/mrsas.h b/sys/dev/mrsas/mrsas.h new file mode 100644 index 0000000000000..6ec78915ff748 --- /dev/null +++ b/sys/dev/mrsas/mrsas.h @@ -0,0 +1,2464 @@ +/* + * Copyright (c) 2014, LSI Corp. + * All rights reserved. + * Authors: Marian Choy + * Support: freebsdraid@lsi.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of the <ORGANIZATION> nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Send feedback to: <megaraidfbsd@lsi.com> + * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035 + * ATTN: MegaRaid FreeBSD + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifndef MRSAS_H +#define MRSAS_H + +#include <sys/param.h> /* defines used in kernel.h */ +#include <sys/module.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/errno.h> +#include <sys/kernel.h> /* types used in module initialization */ +#include <sys/conf.h> /* cdevsw struct */ +#include <sys/uio.h> /* uio struct */ +#include <sys/malloc.h> +#include <sys/bus.h> /* structs, prototypes for pci bus stuff */ + +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> +#include <machine/atomic.h> + +#include <dev/pci/pcivar.h> /* For pci_get macros! */ +#include <dev/pci/pcireg.h> + +#include <sys/types.h> +#include <sys/sysctl.h> +#include <sys/stat.h> +#include <sys/taskqueue.h> +#include <sys/poll.h> +#include <sys/selinfo.h> + +/* + * Device IDs and PCI + */ +#define MRSAS_TBOLT 0x005b +#define MRSAS_INVADER 0x005d +#define MRSAS_FURY 0x005f +#define MRSAS_PCI_BAR0 0x10 +#define MRSAS_PCI_BAR1 0x14 +#define MRSAS_PCI_BAR2 0x1C + +/* + * Firmware State Defines + */ +#define MRSAS_FWSTATE_MAXCMD_MASK 0x0000FFFF +#define MRSAS_FWSTATE_SGE_MASK 0x00FF0000 +#define MRSAS_FW_STATE_CHNG_INTERRUPT 1 + +/* + * Message Frame Defines + */ +#define MRSAS_SENSE_LEN 96 +#define MRSAS_FUSION_MAX_RESET_TRIES 3 + +/* + * Miscellaneous Defines + */ +#define BYTE_ALIGNMENT 1 +#define MRSAS_MAX_NAME_LENGTH 32 +#define MRSAS_VERSION "06.704.01.00-fbsd" +#define MRSAS_ULONG_MAX 0xFFFFFFFFFFFFFFFF +#define MRSAS_DEFAULT_TIMEOUT 0x14 //temp +#define DONE 0 +#define MRSAS_PAGE_SIZE 4096 +#define MRSAS_RESET_NOTICE_INTERVAL 5 +#define MRSAS_IO_TIMEOUT 180000 /* 180 second timeout */ +#define MRSAS_LDIO_QUEUE_DEPTH 70 /* 70 percent as default */ +#define THRESHOLD_REPLY_COUNT 50 + +/* + Boolean types +*/ +#if (__FreeBSD_version < 901000) + typedef enum _boolean { false, true } boolean; +#endif +enum err { SUCCESS, FAIL }; + +MALLOC_DECLARE(M_MRSAS); +SYSCTL_DECL(_hw_mrsas); + +#define MRSAS_INFO (1 << 0) +#define MRSAS_TRACE (1 << 1) +#define MRSAS_FAULT (1 << 2) +#define MRSAS_OCR (1 << 3) +#define MRSAS_TOUT MRSAS_OCR +#define MRSAS_AEN (1 << 4) +#define MRSAS_PRL11 (1 << 5) + +#define mrsas_dprint(sc, level, msg, args...) \ +do { \ + if (sc->mrsas_debug & level) \ + device_printf(sc->mrsas_dev, msg, ##args); \ +} while (0) + + +/**************************************************************************** + * Raid Context structure which describes MegaRAID specific IO Paramenters + * This resides at offset 0x60 where the SGL normally starts in MPT IO Frames + ****************************************************************************/ + +typedef struct _RAID_CONTEXT { + u_int8_t Type:4; // 0x00 + u_int8_t nseg:4; // 0x00 + u_int8_t resvd0; // 0x01 + u_int16_t timeoutValue; // 0x02 -0x03 + u_int8_t regLockFlags; // 0x04 + u_int8_t resvd1; // 0x05 + u_int16_t VirtualDiskTgtId; // 0x06 -0x07 + u_int64_t regLockRowLBA; // 0x08 - 0x0F + u_int32_t regLockLength; // 0x10 - 0x13 + u_int16_t nextLMId; // 0x14 - 0x15 + u_int8_t exStatus; // 0x16 + u_int8_t status; // 0x17 status + u_int8_t RAIDFlags; // 0x18 resvd[7:6],ioSubType[5:4],resvd[3:1],preferredCpu[0] + u_int8_t numSGE; // 0x19 numSge; not including chain entries + u_int16_t configSeqNum; // 0x1A -0x1B + u_int8_t spanArm; // 0x1C span[7:5], arm[4:0] + u_int8_t resvd2[3]; // 0x1D-0x1f +} RAID_CONTEXT; + + +/************************************************************************* + * MPI2 Defines + ************************************************************************/ + +#define MPI2_FUNCTION_IOC_INIT (0x02) /* IOC Init */ +#define MPI2_WHOINIT_HOST_DRIVER (0x04) +#define MPI2_VERSION_MAJOR (0x02) +#define MPI2_VERSION_MINOR (0x00) +#define MPI2_VERSION_MAJOR_MASK (0xFF00) +#define MPI2_VERSION_MAJOR_SHIFT (8) +#define MPI2_VERSION_MINOR_MASK (0x00FF) +#define MPI2_VERSION_MINOR_SHIFT (0) +#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \ + MPI2_VERSION_MINOR) +#define MPI2_HEADER_VERSION_UNIT (0x10) +#define MPI2_HEADER_VERSION_DEV (0x00) +#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) +#define MPI2_HEADER_VERSION_UNIT_SHIFT (8) +#define MPI2_HEADER_VERSION_DEV_MASK (0x00FF) +#define MPI2_HEADER_VERSION_DEV_SHIFT (0) +#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | MPI2_HEADER_VERSION_DEV) +#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) +#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG (0x8000) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG (0x0400) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP (0x0003) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) +#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) +#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ +#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06) +#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00) +#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02) +#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000) +#define MPI2_SCSIIO_CONTROL_READ (0x02000000) +#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E) +#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F) +#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00) +#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F) +#define MPI2_WRSEQ_FLUSH_KEY_VALUE (0x0) +#define MPI2_WRITE_SEQUENCE_OFFSET (0x00000004) +#define MPI2_WRSEQ_1ST_KEY_VALUE (0xF) +#define MPI2_WRSEQ_2ND_KEY_VALUE (0x4) +#define MPI2_WRSEQ_3RD_KEY_VALUE (0xB) +#define MPI2_WRSEQ_4TH_KEY_VALUE (0x2) +#define MPI2_WRSEQ_5TH_KEY_VALUE (0x7) +#define MPI2_WRSEQ_6TH_KEY_VALUE (0xD) + +#ifndef MPI2_POINTER +#define MPI2_POINTER * +#endif + + +/*************************************** + * MPI2 Structures + ***************************************/ + +typedef struct _MPI25_IEEE_SGE_CHAIN64 +{ + u_int64_t Address; + u_int32_t Length; + u_int16_t Reserved1; + u_int8_t NextChainOffset; + u_int8_t Flags; +} MPI25_IEEE_SGE_CHAIN64, MPI2_POINTER PTR_MPI25_IEEE_SGE_CHAIN64, + Mpi25IeeeSgeChain64_t, MPI2_POINTER pMpi25IeeeSgeChain64_t; + +typedef struct _MPI2_SGE_SIMPLE_UNION +{ + u_int32_t FlagsLength; + union + { + u_int32_t Address32; + u_int64_t Address64; + } u; +} MPI2_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_SIMPLE_UNION, + Mpi2SGESimpleUnion_t, MPI2_POINTER pMpi2SGESimpleUnion_t; + +typedef struct +{ + u_int8_t CDB[20]; /* 0x00 */ + u_int32_t PrimaryReferenceTag; /* 0x14 */ + u_int16_t PrimaryApplicationTag; /* 0x18 */ + u_int16_t PrimaryApplicationTagMask; /* 0x1A */ + u_int32_t TransferLength; /* 0x1C */ +} MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32, + Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t; + +typedef struct _MPI2_SGE_CHAIN_UNION +{ + u_int16_t Length; + u_int8_t NextChainOffset; + u_int8_t Flags; + union + { + u_int32_t Address32; + u_int64_t Address64; + } u; +} MPI2_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_SGE_CHAIN_UNION, + Mpi2SGEChainUnion_t, MPI2_POINTER pMpi2SGEChainUnion_t; + +typedef struct _MPI2_IEEE_SGE_SIMPLE32 +{ + u_int32_t Address; + u_int32_t FlagsLength; +} MPI2_IEEE_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE32, + Mpi2IeeeSgeSimple32_t, MPI2_POINTER pMpi2IeeeSgeSimple32_t; +typedef struct _MPI2_IEEE_SGE_SIMPLE64 +{ + u_int64_t Address; + u_int32_t Length; + u_int16_t Reserved1; + u_int8_t Reserved2; + u_int8_t Flags; +} MPI2_IEEE_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE64, + Mpi2IeeeSgeSimple64_t, MPI2_POINTER pMpi2IeeeSgeSimple64_t; + +typedef union _MPI2_IEEE_SGE_SIMPLE_UNION +{ + MPI2_IEEE_SGE_SIMPLE32 Simple32; + MPI2_IEEE_SGE_SIMPLE64 Simple64; +} MPI2_IEEE_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE_UNION, + Mpi2IeeeSgeSimpleUnion_t, MPI2_POINTER pMpi2IeeeSgeSimpleUnion_t; + +typedef MPI2_IEEE_SGE_SIMPLE32 MPI2_IEEE_SGE_CHAIN32; +typedef MPI2_IEEE_SGE_SIMPLE64 MPI2_IEEE_SGE_CHAIN64; + +typedef union _MPI2_IEEE_SGE_CHAIN_UNION +{ + MPI2_IEEE_SGE_CHAIN32 Chain32; + MPI2_IEEE_SGE_CHAIN64 Chain64; +} MPI2_IEEE_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_CHAIN_UNION, + Mpi2IeeeSgeChainUnion_t, MPI2_POINTER pMpi2IeeeSgeChainUnion_t; + +typedef union _MPI2_SGE_IO_UNION +{ + MPI2_SGE_SIMPLE_UNION MpiSimple; + MPI2_SGE_CHAIN_UNION MpiChain; + MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; + MPI2_IEEE_SGE_CHAIN_UNION IeeeChain; +} MPI2_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_SGE_IO_UNION, + Mpi2SGEIOUnion_t, MPI2_POINTER pMpi2SGEIOUnion_t; + +typedef union +{ + u_int8_t CDB32[32]; + MPI2_SCSI_IO_CDB_EEDP32 EEDP32; + MPI2_SGE_SIMPLE_UNION SGE; +} MPI2_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_UNION, + Mpi2ScsiIoCdb_t, MPI2_POINTER pMpi2ScsiIoCdb_t; + +/* + * RAID SCSI IO Request Message + * Total SGE count will be one less than _MPI2_SCSI_IO_REQUEST + */ +typedef struct _MPI2_RAID_SCSI_IO_REQUEST +{ + u_int16_t DevHandle; /* 0x00 */ + u_int8_t ChainOffset; /* 0x02 */ + u_int8_t Function; /* 0x03 */ + u_int16_t Reserved1; /* 0x04 */ + u_int8_t Reserved2; /* 0x06 */ + u_int8_t MsgFlags; /* 0x07 */ + u_int8_t VP_ID; /* 0x08 */ + u_int8_t VF_ID; /* 0x09 */ + u_int16_t Reserved3; /* 0x0A */ + u_int32_t SenseBufferLowAddress; /* 0x0C */ + u_int16_t SGLFlags; /* 0x10 */ + u_int8_t SenseBufferLength; /* 0x12 */ + u_int8_t Reserved4; /* 0x13 */ + u_int8_t SGLOffset0; /* 0x14 */ + u_int8_t SGLOffset1; /* 0x15 */ + u_int8_t SGLOffset2; /* 0x16 */ + u_int8_t SGLOffset3; /* 0x17 */ + u_int32_t SkipCount; /* 0x18 */ + u_int32_t DataLength; /* 0x1C */ + u_int32_t BidirectionalDataLength; /* 0x20 */ + u_int16_t IoFlags; /* 0x24 */ + u_int16_t EEDPFlags; /* 0x26 */ + u_int32_t EEDPBlockSize; /* 0x28 */ + u_int32_t SecondaryReferenceTag; /* 0x2C */ + u_int16_t SecondaryApplicationTag; /* 0x30 */ + u_int16_t ApplicationTagTranslationMask; /* 0x32 */ + u_int8_t LUN[8]; /* 0x34 */ + u_int32_t Control; /* 0x3C */ + MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */ + RAID_CONTEXT RaidContext; /* 0x60 */ + MPI2_SGE_IO_UNION SGL; /* 0x80 */ +} MRSAS_RAID_SCSI_IO_REQUEST, MPI2_POINTER PTR_MRSAS_RAID_SCSI_IO_REQUEST, + MRSASRaidSCSIIORequest_t, MPI2_POINTER pMRSASRaidSCSIIORequest_t; + +/* + * MPT RAID MFA IO Descriptor. + */ +typedef struct _MRSAS_RAID_MFA_IO_DESCRIPTOR { + u_int32_t RequestFlags : 8; + u_int32_t MessageAddress1 : 24; /* bits 31:8*/ + u_int32_t MessageAddress2; /* bits 61:32 */ +} MRSAS_RAID_MFA_IO_REQUEST_DESCRIPTOR,*PMRSAS_RAID_MFA_IO_REQUEST_DESCRIPTOR; + +/* Default Request Descriptor */ +typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR +{ + u_int8_t RequestFlags; /* 0x00 */ + u_int8_t MSIxIndex; /* 0x01 */ + u_int16_t SMID; /* 0x02 */ + u_int16_t LMID; /* 0x04 */ + u_int16_t DescriptorTypeDependent; /* 0x06 */ +} MPI2_DEFAULT_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_DEFAULT_REQUEST_DESCRIPTOR, + Mpi2DefaultRequestDescriptor_t, MPI2_POINTER pMpi2DefaultRequestDescriptor_t; + +/* High Priority Request Descriptor */ +typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR +{ + u_int8_t RequestFlags; /* 0x00 */ + u_int8_t MSIxIndex; /* 0x01 */ + u_int16_t SMID; /* 0x02 */ + u_int16_t LMID; /* 0x04 */ + u_int16_t Reserved1; /* 0x06 */ +} MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR, + Mpi2HighPriorityRequestDescriptor_t, + MPI2_POINTER pMpi2HighPriorityRequestDescriptor_t; + +/* SCSI IO Request Descriptor */ +typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR +{ + u_int8_t RequestFlags; /* 0x00 */ + u_int8_t MSIxIndex; /* 0x01 */ + u_int16_t SMID; /* 0x02 */ + u_int16_t LMID; /* 0x04 */ + u_int16_t DevHandle; /* 0x06 */ +} MPI2_SCSI_IO_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST_DESCRIPTOR, + Mpi2SCSIIORequestDescriptor_t, MPI2_POINTER pMpi2SCSIIORequestDescriptor_t; + +/* SCSI Target Request Descriptor */ +typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR +{ + u_int8_t RequestFlags; /* 0x00 */ + u_int8_t MSIxIndex; /* 0x01 */ + u_int16_t SMID; /* 0x02 */ + u_int16_t LMID; /* 0x04 */ + u_int16_t IoIndex; /* 0x06 */ +} MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR, + Mpi2SCSITargetRequestDescriptor_t, + MPI2_POINTER pMpi2SCSITargetRequestDescriptor_t; + +/* RAID Accelerator Request Descriptor */ +typedef struct _MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR +{ + u_int8_t RequestFlags; /* 0x00 */ + u_int8_t MSIxIndex; /* 0x01 */ + u_int16_t SMID; /* 0x02 */ + u_int16_t LMID; /* 0x04 */ + u_int16_t Reserved; /* 0x06 */ +} MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, + Mpi2RAIDAcceleratorRequestDescriptor_t, + MPI2_POINTER pMpi2RAIDAcceleratorRequestDescriptor_t; + +/* union of Request Descriptors */ +typedef union _MRSAS_REQUEST_DESCRIPTOR_UNION +{ + MPI2_DEFAULT_REQUEST_DESCRIPTOR Default; + MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority; + MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO; + MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget; + MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator; + MRSAS_RAID_MFA_IO_REQUEST_DESCRIPTOR MFAIo; + union { + struct { + u_int32_t low; + u_int32_t high; + } u; + u_int64_t Words; + } addr; +} MRSAS_REQUEST_DESCRIPTOR_UNION; + +/* Default Reply Descriptor */ +typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR +{ + u_int8_t ReplyFlags; /* 0x00 */ + u_int8_t MSIxIndex; /* 0x01 */ + u_int16_t DescriptorTypeDependent1; /* 0x02 */ + u_int32_t DescriptorTypeDependent2; /* 0x04 */ +} MPI2_DEFAULT_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY_DESCRIPTOR, + Mpi2DefaultReplyDescriptor_t, MPI2_POINTER pMpi2DefaultReplyDescriptor_t; + +/* Address Reply Descriptor */ +typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR +{ + u_int8_t ReplyFlags; /* 0x00 */ + u_int8_t MSIxIndex; /* 0x01 */ + u_int16_t SMID; /* 0x02 */ + u_int32_t ReplyFrameAddress; /* 0x04 */ +} MPI2_ADDRESS_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR, + Mpi2AddressReplyDescriptor_t, MPI2_POINTER pMpi2AddressReplyDescriptor_t; + +/* SCSI IO Success Reply Descriptor */ +typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR +{ + u_int8_t ReplyFlags; /* 0x00 */ + u_int8_t MSIxIndex; /* 0x01 */ + u_int16_t SMID; /* 0x02 */ + u_int16_t TaskTag; /* 0x04 */ + u_int16_t Reserved1; /* 0x06 */ +} MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, + Mpi2SCSIIOSuccessReplyDescriptor_t, + MPI2_POINTER pMpi2SCSIIOSuccessReplyDescriptor_t; + +/* TargetAssist Success Reply Descriptor */ +typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR +{ + u_int8_t ReplyFlags; /* 0x00 */ + u_int8_t MSIxIndex; /* 0x01 */ + u_int16_t SMID; /* 0x02 */ + u_int8_t SequenceNumber; /* 0x04 */ + u_int8_t Reserved1; /* 0x05 */ + u_int16_t IoIndex; /* 0x06 */ +} MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR, + Mpi2TargetAssistSuccessReplyDescriptor_t, + MPI2_POINTER pMpi2TargetAssistSuccessReplyDescriptor_t; + +/* Target Command Buffer Reply Descriptor */ +typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR +{ + u_int8_t ReplyFlags; /* 0x00 */ + u_int8_t MSIxIndex; /* 0x01 */ + u_int8_t VP_ID; /* 0x02 */ + u_int8_t Flags; /* 0x03 */ + u_int16_t InitiatorDevHandle; /* 0x04 */ + u_int16_t IoIndex; /* 0x06 */ +} MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, + Mpi2TargetCommandBufferReplyDescriptor_t, + MPI2_POINTER pMpi2TargetCommandBufferReplyDescriptor_t; + +/* RAID Accelerator Success Reply Descriptor */ +typedef struct _MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR +{ + u_int8_t ReplyFlags; /* 0x00 */ + u_int8_t MSIxIndex; /* 0x01 */ + u_int16_t SMID; /* 0x02 */ + u_int32_t Reserved; /* 0x04 */ +} MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, + Mpi2RAIDAcceleratorSuccessReplyDescriptor_t, + MPI2_POINTER pMpi2RAIDAcceleratorSuccessReplyDescriptor_t; + +/* union of Reply Descriptors */ +typedef union _MPI2_REPLY_DESCRIPTORS_UNION +{ + MPI2_DEFAULT_REPLY_DESCRIPTOR Default; + MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply; + MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess; + MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess; + MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer; + MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess; + u_int64_t Words; +} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION, + Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t; + +typedef struct { + volatile unsigned int val; +} atomic_t; + +#define atomic_read(v) atomic_load_acq_int(&(v)->val) +#define atomic_set(v,i) atomic_store_rel_int(&(v)->val, i) +#define atomic_dec(v) atomic_fetchadd_int(&(v)->val, -1) +#define atomic_inc(v) atomic_fetchadd_int(&(v)->val, 1) + +/* IOCInit Request message */ +typedef struct _MPI2_IOC_INIT_REQUEST +{ + u_int8_t WhoInit; /* 0x00 */ + u_int8_t Reserved1; /* 0x01 */ + u_int8_t ChainOffset; /* 0x02 */ + u_int8_t Function; /* 0x03 */ + u_int16_t Reserved2; /* 0x04 */ + u_int8_t Reserved3; /* 0x06 */ + u_int8_t MsgFlags; /* 0x07 */ + u_int8_t VP_ID; /* 0x08 */ + u_int8_t VF_ID; /* 0x09 */ + u_int16_t Reserved4; /* 0x0A */ + u_int16_t MsgVersion; /* 0x0C */ + u_int16_t HeaderVersion; /* 0x0E */ + u_int32_t Reserved5; /* 0x10 */ + u_int16_t Reserved6; /* 0x14 */ + u_int8_t Reserved7; /* 0x16 */ + u_int8_t HostMSIxVectors; /* 0x17 */ + u_int16_t Reserved8; /* 0x18 */ + u_int16_t SystemRequestFrameSize; /* 0x1A */ + u_int16_t ReplyDescriptorPostQueueDepth; /* 0x1C */ + u_int16_t ReplyFreeQueueDepth; /* 0x1E */ + u_int32_t SenseBufferAddressHigh; /* 0x20 */ + u_int32_t SystemReplyAddressHigh; /* 0x24 */ + u_int64_t SystemRequestFrameBaseAddress; /* 0x28 */ + u_int64_t ReplyDescriptorPostQueueAddress;/* 0x30 */ + u_int64_t ReplyFreeQueueAddress; /* 0x38 */ + u_int64_t TimeStamp; /* 0x40 */ +} MPI2_IOC_INIT_REQUEST, MPI2_POINTER PTR_MPI2_IOC_INIT_REQUEST, + Mpi2IOCInitRequest_t, MPI2_POINTER pMpi2IOCInitRequest_t; + +/* + * MR private defines + */ +#define MR_PD_INVALID 0xFFFF +#define MAX_SPAN_DEPTH 8 +#define MAX_QUAD_DEPTH MAX_SPAN_DEPTH +#define MAX_RAIDMAP_SPAN_DEPTH (MAX_SPAN_DEPTH) +#define MAX_ROW_SIZE 32 +#define MAX_RAIDMAP_ROW_SIZE (MAX_ROW_SIZE) +#define MAX_LOGICAL_DRIVES 64 +#define MAX_RAIDMAP_LOGICAL_DRIVES (MAX_LOGICAL_DRIVES) +#define MAX_RAIDMAP_VIEWS (MAX_LOGICAL_DRIVES) +#define MAX_ARRAYS 128 +#define MAX_RAIDMAP_ARRAYS (MAX_ARRAYS) +#define MAX_PHYSICAL_DEVICES 256 +#define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES) +#define MR_DCMD_LD_MAP_GET_INFO 0x0300e101 // get the mapping information of this LD + + +/******************************************************************* + * RAID map related structures + ********************************************************************/ + +typedef struct _MR_DEV_HANDLE_INFO { + u_int16_t curDevHdl; // the device handle currently used by fw to issue the command. + u_int8_t validHandles; // bitmap of valid device handles. + u_int8_t reserved; + u_int16_t devHandle[2]; // 0x04 dev handles for all the paths. +} MR_DEV_HANDLE_INFO; + +typedef struct _MR_ARRAY_INFO { + u_int16_t pd[MAX_RAIDMAP_ROW_SIZE]; +} MR_ARRAY_INFO; // 0x40, Total Size + +typedef struct _MR_QUAD_ELEMENT { + u_int64_t logStart; // 0x00 + u_int64_t logEnd; // 0x08 + u_int64_t offsetInSpan; // 0x10 + u_int32_t diff; // 0x18 + u_int32_t reserved1; // 0x1C +} MR_QUAD_ELEMENT; // 0x20, Total size + +typedef struct _MR_SPAN_INFO { + u_int32_t noElements; // 0x00 + u_int32_t reserved1; // 0x04 + MR_QUAD_ELEMENT quad[MAX_RAIDMAP_SPAN_DEPTH]; // 0x08 +} MR_SPAN_INFO; // 0x108, Total size + +typedef struct _MR_LD_SPAN_ { // SPAN structure + u_int64_t startBlk; // 0x00, starting block number in array + u_int64_t numBlks; // 0x08, number of blocks + u_int16_t arrayRef; // 0x10, array reference + u_int8_t spanRowSize; // 0x11, span row size + u_int8_t spanRowDataSize; // 0x12, span row data size + u_int8_t reserved[4]; // 0x13, reserved +} MR_LD_SPAN; // 0x18, Total Size + +typedef struct _MR_SPAN_BLOCK_INFO { + u_int64_t num_rows; // number of rows/span + MR_LD_SPAN span; // 0x08 + MR_SPAN_INFO block_span_info; // 0x20 +} MR_SPAN_BLOCK_INFO; + +typedef struct _MR_LD_RAID { + struct { + u_int32_t fpCapable :1; + u_int32_t reserved5 :3; + u_int32_t ldPiMode :4; + u_int32_t pdPiMode :4; // Every Pd has to be same. + u_int32_t encryptionType :8; // FDE or ctlr encryption (MR_LD_ENCRYPTION_TYPE) + u_int32_t fpWriteCapable :1; + u_int32_t fpReadCapable :1; + u_int32_t fpWriteAcrossStripe :1; + u_int32_t fpReadAcrossStripe :1; + u_int32_t fpNonRWCapable :1; // TRUE if supporting Non RW IO + u_int32_t reserved4 :7; + } capability; // 0x00 + u_int32_t reserved6; + u_int64_t size; // 0x08, LD size in blocks + + u_int8_t spanDepth; // 0x10, Total Number of Spans + u_int8_t level; // 0x11, RAID level + u_int8_t stripeShift; // 0x12, shift-count to get stripe size (0=512, 1=1K, 7=64K, etc.) + u_int8_t rowSize; // 0x13, number of disks in a row + + u_int8_t rowDataSize; // 0x14, number of data disks in a row + u_int8_t writeMode; // 0x15, WRITE_THROUGH or WRITE_BACK + u_int8_t PRL; // 0x16, To differentiate between RAID1 and RAID1E + u_int8_t SRL; // 0x17 + + u_int16_t targetId; // 0x18, ld Target Id. + u_int8_t ldState; // 0x1a, state of ld, state corresponds to MR_LD_STATE + u_int8_t regTypeReqOnWrite;// 0x1b, Pre calculate region type requests based on MFC etc.. + u_int8_t modFactor; // 0x1c, same as rowSize, + u_int8_t regTypeReqOnRead; // 0x1d, region lock type used for read, valid only if regTypeOnReadIsValid=1 + u_int16_t seqNum; // 0x1e, LD sequence number + + struct { + u_int32_t ldSyncRequired:1; // This LD requires sync command before completing + u_int32_t regTypeReqOnReadLsValid:1; // Qualifier for regTypeOnRead + u_int32_t reserved:30; + } flags; // 0x20 + + u_int8_t LUN[8]; // 0x24, 8 byte LUN field used for SCSI + u_int8_t fpIoTimeoutForLd; // 0x2C, timeout value for FP IOs + u_int8_t reserved2[3]; // 0x2D + u_int32_t logicalBlockLength; // 0x30 Logical block size for the LD + struct { + u_int32_t LdPiExp:4; // 0x34, P_I_EXPONENT for ReadCap 16 + u_int32_t LdLogicalBlockExp:4; // 0x34, LOGICAL BLOCKS PER PHYS BLOCK + u_int32_t reserved1:24; // 0x34 + } exponent; + u_int8_t reserved3[0x80-0x38]; // 0x38 +} MR_LD_RAID; // 0x80, Total Size + +typedef struct _MR_LD_SPAN_MAP { + MR_LD_RAID ldRaid; // 0x00 + u_int8_t dataArmMap[MAX_RAIDMAP_ROW_SIZE]; // 0x80, needed for GET_ARM() - R0/1/5 only. + MR_SPAN_BLOCK_INFO spanBlock[MAX_RAIDMAP_SPAN_DEPTH]; // 0xA0 +} MR_LD_SPAN_MAP; // 0x9E0 + +typedef struct _MR_FW_RAID_MAP { + u_int32_t totalSize; // total size of this structure, including this field. + union { + struct { // Simple method of version checking variables + u_int32_t maxLd; + u_int32_t maxSpanDepth; + u_int32_t maxRowSize; + u_int32_t maxPdCount; + u_int32_t maxArrays; + } validationInfo; + u_int32_t version[5]; + u_int32_t reserved1[5]; + } raid_desc; + u_int32_t ldCount; // count of lds. + u_int32_t Reserved1; + u_int8_t ldTgtIdToLd[MAX_RAIDMAP_LOGICAL_DRIVES+MAX_RAIDMAP_VIEWS]; // 0x20 + // This doesn't correspond to + // FW Ld Tgt Id to LD, but will purge. For example: if tgt Id is 4 + // and FW LD is 2, and there is only one LD, FW will populate the + // array like this. [0xFF, 0xFF, 0xFF, 0xFF, 0x0,.....]. This is to + // help reduce the entire strcture size if there are few LDs or + // driver is looking info for 1 LD only. + u_int8_t fpPdIoTimeoutSec; // timeout value used by driver in FP IOs + u_int8_t reserved2[7]; + MR_ARRAY_INFO arMapInfo[MAX_RAIDMAP_ARRAYS]; // 0x00a8 + MR_DEV_HANDLE_INFO devHndlInfo[MAX_RAIDMAP_PHYSICAL_DEVICES]; // 0x20a8 + MR_LD_SPAN_MAP ldSpanMap[1]; // 0x28a8-[0-MAX_RAIDMAP_LOGICAL_DRIVES+MAX_RAIDMAP_VIEWS+1]; +} MR_FW_RAID_MAP; // 0x3288, Total Size + +typedef struct _LD_LOAD_BALANCE_INFO +{ + u_int8_t loadBalanceFlag; + u_int8_t reserved1; + u_int16_t raid1DevHandle[2]; + atomic_t scsi_pending_cmds[2]; + u_int64_t last_accessed_block[2]; +} LD_LOAD_BALANCE_INFO, *PLD_LOAD_BALANCE_INFO; + +/* SPAN_SET is info caclulated from span info from Raid map per ld */ +typedef struct _LD_SPAN_SET { + u_int64_t log_start_lba; + u_int64_t log_end_lba; + u_int64_t span_row_start; + u_int64_t span_row_end; + u_int64_t data_strip_start; + u_int64_t data_strip_end; + u_int64_t data_row_start; + u_int64_t data_row_end; + u_int8_t strip_offset[MAX_SPAN_DEPTH]; + u_int32_t span_row_data_width; + u_int32_t diff; + u_int32_t reserved[2]; +}LD_SPAN_SET, *PLD_SPAN_SET; + +typedef struct LOG_BLOCK_SPAN_INFO { + LD_SPAN_SET span_set[MAX_SPAN_DEPTH]; +}LD_SPAN_INFO, *PLD_SPAN_INFO; + +#pragma pack(1) +typedef struct _MR_FW_RAID_MAP_ALL { + MR_FW_RAID_MAP raidMap; + MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES - 1]; +} MR_FW_RAID_MAP_ALL; +#pragma pack() + +struct IO_REQUEST_INFO { + u_int64_t ldStartBlock; + u_int32_t numBlocks; + u_int16_t ldTgtId; + u_int8_t isRead; + u_int16_t devHandle; + u_int64_t pdBlock; + u_int8_t fpOkForIo; + u_int8_t IoforUnevenSpan; + u_int8_t start_span; + u_int8_t reserved; + u_int64_t start_row; +}; + +typedef struct _MR_LD_TARGET_SYNC { + u_int8_t targetId; + u_int8_t reserved; + u_int16_t seqNum; +} MR_LD_TARGET_SYNC; + +#define IEEE_SGE_FLAGS_ADDR_MASK (0x03) +#define IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) +#define IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) +#define IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) +#define IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) +#define IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80) +#define IEEE_SGE_FLAGS_END_OF_LIST (0x40) + +union desc_value { + u_int64_t word; + struct { + u_int32_t low; + u_int32_t high; + } u; +}; + +/******************************************************************* + * Temporary command + ********************************************************************/ +struct mrsas_tmp_dcmd { + bus_dma_tag_t tmp_dcmd_tag; // tag for tmp DMCD cmd + bus_dmamap_t tmp_dcmd_dmamap; // dmamap for tmp DCMD cmd + void *tmp_dcmd_mem; // virtual addr of tmp DCMD cmd + bus_addr_t tmp_dcmd_phys_addr; //physical addr of tmp DCMD +}; + +/******************************************************************* + * Register set, included legacy controllers 1068 and 1078, + * structure extended for 1078 registers + ********************************************************************/ +#pragma pack(1) +typedef struct _mrsas_register_set { + u_int32_t doorbell; /*0000h*/ + u_int32_t fusion_seq_offset; /*0004h*/ + u_int32_t fusion_host_diag; /*0008h*/ + u_int32_t reserved_01; /*000Ch*/ + + u_int32_t inbound_msg_0; /*0010h*/ + u_int32_t inbound_msg_1; /*0014h*/ + u_int32_t outbound_msg_0; /*0018h*/ + u_int32_t outbound_msg_1; /*001Ch*/ + + u_int32_t inbound_doorbell; /*0020h*/ + u_int32_t inbound_intr_status; /*0024h*/ + u_int32_t inbound_intr_mask; /*0028h*/ + + u_int32_t outbound_doorbell; /*002Ch*/ + u_int32_t outbound_intr_status; /*0030h*/ + u_int32_t outbound_intr_mask; /*0034h*/ + + u_int32_t reserved_1[2]; /*0038h*/ + + u_int32_t inbound_queue_port; /*0040h*/ + u_int32_t outbound_queue_port; /*0044h*/ + + u_int32_t reserved_2[9]; /*0048h*/ + u_int32_t reply_post_host_index; /*006Ch*/ + u_int32_t reserved_2_2[12]; /*0070h*/ + + u_int32_t outbound_doorbell_clear; /*00A0h*/ + + u_int32_t reserved_3[3]; /*00A4h*/ + + u_int32_t outbound_scratch_pad ; /*00B0h*/ + u_int32_t outbound_scratch_pad_2; /*00B4h*/ + + u_int32_t reserved_4[2]; /*00B8h*/ + + u_int32_t inbound_low_queue_port ; /*00C0h*/ + + u_int32_t inbound_high_queue_port ; /*00C4h*/ + + u_int32_t reserved_5; /*00C8h*/ + u_int32_t res_6[11]; /*CCh*/ + u_int32_t host_diag; + u_int32_t seq_offset; + u_int32_t index_registers[807]; /*00CCh*/ + +} mrsas_reg_set; +#pragma pack() + +/******************************************************************* + * Firmware Interface Defines + ******************************************************************* + * MFI stands for MegaRAID SAS FW Interface. This is just a moniker + * for protocol between the software and firmware. Commands are + * issued using "message frames". + ******************************************************************/ +/* + * FW posts its state in upper 4 bits of outbound_msg_0 register + */ +#define MFI_STATE_MASK 0xF0000000 +#define MFI_STATE_UNDEFINED 0x00000000 +#define MFI_STATE_BB_INIT 0x10000000 +#define MFI_STATE_FW_INIT 0x40000000 +#define MFI_STATE_WAIT_HANDSHAKE 0x60000000 +#define MFI_STATE_FW_INIT_2 0x70000000 +#define MFI_STATE_DEVICE_SCAN 0x80000000 +#define MFI_STATE_BOOT_MESSAGE_PENDING 0x90000000 +#define MFI_STATE_FLUSH_CACHE 0xA0000000 +#define MFI_STATE_READY 0xB0000000 +#define MFI_STATE_OPERATIONAL 0xC0000000 +#define MFI_STATE_FAULT 0xF0000000 +#define MFI_RESET_REQUIRED 0x00000001 +#define MFI_RESET_ADAPTER 0x00000002 +#define MEGAMFI_FRAME_SIZE 64 +#define MRSAS_MFI_FRAME_SIZE 1024 +#define MRSAS_MFI_SENSE_SIZE 128 + +/* + * During FW init, clear pending cmds & reset state using inbound_msg_0 + * + * ABORT : Abort all pending cmds + * READY : Move from OPERATIONAL to READY state; discard queue info + * MFIMODE : Discard (possible) low MFA posted in 64-bit mode (??) + * CLR_HANDSHAKE: FW is waiting for HANDSHAKE from BIOS or Driver + * HOTPLUG : Resume from Hotplug + * MFI_STOP_ADP : Send signal to FW to stop processing + */ + +#define WRITE_SEQUENCE_OFFSET (0x0000000FC) // I20 +#define HOST_DIAGNOSTIC_OFFSET (0x000000F8) // I20 +#define DIAG_WRITE_ENABLE (0x00000080) +#define DIAG_RESET_ADAPTER (0x00000004) + +#define MFI_ADP_RESET 0x00000040 +#define MFI_INIT_ABORT 0x00000001 +#define MFI_INIT_READY 0x00000002 +#define MFI_INIT_MFIMODE 0x00000004 +#define MFI_INIT_CLEAR_HANDSHAKE 0x00000008 +#define MFI_INIT_HOTPLUG 0x00000010 +#define MFI_STOP_ADP 0x00000020 +#define MFI_RESET_FLAGS MFI_INIT_READY| \ + MFI_INIT_MFIMODE| \ + MFI_INIT_ABORT + +/* + * MFI frame flags + */ +#define MFI_FRAME_POST_IN_REPLY_QUEUE 0x0000 +#define MFI_FRAME_DONT_POST_IN_REPLY_QUEUE 0x0001 +#define MFI_FRAME_SGL32 0x0000 +#define MFI_FRAME_SGL64 0x0002 +#define MFI_FRAME_SENSE32 0x0000 +#define MFI_FRAME_SENSE64 0x0004 +#define MFI_FRAME_DIR_NONE 0x0000 +#define MFI_FRAME_DIR_WRITE 0x0008 +#define MFI_FRAME_DIR_READ 0x0010 +#define MFI_FRAME_DIR_BOTH 0x0018 +#define MFI_FRAME_IEEE 0x0020 + +/* + * Definition for cmd_status + */ +#define MFI_CMD_STATUS_POLL_MODE 0xFF + +/* + * MFI command opcodes + */ +#define MFI_CMD_INIT 0x00 +#define MFI_CMD_LD_READ 0x01 +#define MFI_CMD_LD_WRITE 0x02 +#define MFI_CMD_LD_SCSI_IO 0x03 +#define MFI_CMD_PD_SCSI_IO 0x04 +#define MFI_CMD_DCMD 0x05 +#define MFI_CMD_ABORT 0x06 +#define MFI_CMD_SMP 0x07 +#define MFI_CMD_STP 0x08 +#define MFI_CMD_INVALID 0xff + +#define MR_DCMD_CTRL_GET_INFO 0x01010000 +#define MR_DCMD_LD_GET_LIST 0x03010000 +#define MR_DCMD_CTRL_CACHE_FLUSH 0x01101000 +#define MR_FLUSH_CTRL_CACHE 0x01 +#define MR_FLUSH_DISK_CACHE 0x02 + +#define MR_DCMD_CTRL_SHUTDOWN 0x01050000 +#define MR_DCMD_HIBERNATE_SHUTDOWN 0x01060000 +#define MR_ENABLE_DRIVE_SPINDOWN 0x01 + +#define MR_DCMD_CTRL_EVENT_GET_INFO 0x01040100 +#define MR_DCMD_CTRL_EVENT_GET 0x01040300 +#define MR_DCMD_CTRL_EVENT_WAIT 0x01040500 +#define MR_DCMD_LD_GET_PROPERTIES 0x03030000 + +#define MR_DCMD_CLUSTER 0x08000000 +#define MR_DCMD_CLUSTER_RESET_ALL 0x08010100 +#define MR_DCMD_CLUSTER_RESET_LD 0x08010200 +#define MR_DCMD_PD_LIST_QUERY 0x02010100 + +#define MR_DCMD_CTRL_MISC_CPX 0x0100e200 +#define MR_DCMD_CTRL_MISC_CPX_INIT_DATA_GET 0x0100e201 +#define MR_DCMD_CTRL_MISC_CPX_QUEUE_DATA 0x0100e202 +#define MR_DCMD_CTRL_MISC_CPX_UNREGISTER 0x0100e203 +#define MAX_MR_ROW_SIZE 32 +#define MR_CPX_DIR_WRITE 1 +#define MR_CPX_DIR_READ 0 +#define MR_CPX_VERSION 1 + +#define MR_DCMD_CTRL_IO_METRICS_GET 0x01170200 // get IO metrics + +#define MR_EVT_CFG_CLEARED 0x0004 + +#define MR_EVT_LD_STATE_CHANGE 0x0051 +#define MR_EVT_PD_INSERTED 0x005b +#define MR_EVT_PD_REMOVED 0x0070 +#define MR_EVT_LD_CREATED 0x008a +#define MR_EVT_LD_DELETED 0x008b +#define MR_EVT_FOREIGN_CFG_IMPORTED 0x00db +#define MR_EVT_LD_OFFLINE 0x00fc +#define MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED 0x0152 +#define MR_EVT_CTRL_PERF_COLLECTION 0x017e + +/* + * MFI command completion codes + */ +enum MFI_STAT { + MFI_STAT_OK = 0x00, + MFI_STAT_INVALID_CMD = 0x01, + MFI_STAT_INVALID_DCMD = 0x02, + MFI_STAT_INVALID_PARAMETER = 0x03, + MFI_STAT_INVALID_SEQUENCE_NUMBER = 0x04, + MFI_STAT_ABORT_NOT_POSSIBLE = 0x05, + MFI_STAT_APP_HOST_CODE_NOT_FOUND = 0x06, + MFI_STAT_APP_IN_USE = 0x07, + MFI_STAT_APP_NOT_INITIALIZED = 0x08, + MFI_STAT_ARRAY_INDEX_INVALID = 0x09, + MFI_STAT_ARRAY_ROW_NOT_EMPTY = 0x0a, + MFI_STAT_CONFIG_RESOURCE_CONFLICT = 0x0b, + MFI_STAT_DEVICE_NOT_FOUND = 0x0c, + MFI_STAT_DRIVE_TOO_SMALL = 0x0d, + MFI_STAT_FLASH_ALLOC_FAIL = 0x0e, + MFI_STAT_FLASH_BUSY = 0x0f, + MFI_STAT_FLASH_ERROR = 0x10, + MFI_STAT_FLASH_IMAGE_BAD = 0x11, + MFI_STAT_FLASH_IMAGE_INCOMPLETE = 0x12, + MFI_STAT_FLASH_NOT_OPEN = 0x13, + MFI_STAT_FLASH_NOT_STARTED = 0x14, + MFI_STAT_FLUSH_FAILED = 0x15, + MFI_STAT_HOST_CODE_NOT_FOUNT = 0x16, + MFI_STAT_LD_CC_IN_PROGRESS = 0x17, + MFI_STAT_LD_INIT_IN_PROGRESS = 0x18, + MFI_STAT_LD_LBA_OUT_OF_RANGE = 0x19, + MFI_STAT_LD_MAX_CONFIGURED = 0x1a, + MFI_STAT_LD_NOT_OPTIMAL = 0x1b, + MFI_STAT_LD_RBLD_IN_PROGRESS = 0x1c, + MFI_STAT_LD_RECON_IN_PROGRESS = 0x1d, + MFI_STAT_LD_WRONG_RAID_LEVEL = 0x1e, + MFI_STAT_MAX_SPARES_EXCEEDED = 0x1f, + MFI_STAT_MEMORY_NOT_AVAILABLE = 0x20, + MFI_STAT_MFC_HW_ERROR = 0x21, + MFI_STAT_NO_HW_PRESENT = 0x22, + MFI_STAT_NOT_FOUND = 0x23, + MFI_STAT_NOT_IN_ENCL = 0x24, + MFI_STAT_PD_CLEAR_IN_PROGRESS = 0x25, + MFI_STAT_PD_TYPE_WRONG = 0x26, + MFI_STAT_PR_DISABLED = 0x27, + MFI_STAT_ROW_INDEX_INVALID = 0x28, + MFI_STAT_SAS_CONFIG_INVALID_ACTION = 0x29, + MFI_STAT_SAS_CONFIG_INVALID_DATA = 0x2a, + MFI_STAT_SAS_CONFIG_INVALID_PAGE = 0x2b, + MFI_STAT_SAS_CONFIG_INVALID_TYPE = 0x2c, + MFI_STAT_SCSI_DONE_WITH_ERROR = 0x2d, + MFI_STAT_SCSI_IO_FAILED = 0x2e, + MFI_STAT_SCSI_RESERVATION_CONFLICT = 0x2f, + MFI_STAT_SHUTDOWN_FAILED = 0x30, + MFI_STAT_TIME_NOT_SET = 0x31, + MFI_STAT_WRONG_STATE = 0x32, + MFI_STAT_LD_OFFLINE = 0x33, + MFI_STAT_PEER_NOTIFICATION_REJECTED = 0x34, + MFI_STAT_PEER_NOTIFICATION_FAILED = 0x35, + MFI_STAT_RESERVATION_IN_PROGRESS = 0x36, + MFI_STAT_I2C_ERRORS_DETECTED = 0x37, + MFI_STAT_PCI_ERRORS_DETECTED = 0x38, + MFI_STAT_CONFIG_SEQ_MISMATCH = 0x67, + + MFI_STAT_INVALID_STATUS = 0xFF +}; + +/* + * Number of mailbox bytes in DCMD message frame + */ +#define MFI_MBOX_SIZE 12 + +enum MR_EVT_CLASS { + + MR_EVT_CLASS_DEBUG = -2, + MR_EVT_CLASS_PROGRESS = -1, + MR_EVT_CLASS_INFO = 0, + MR_EVT_CLASS_WARNING = 1, + MR_EVT_CLASS_CRITICAL = 2, + MR_EVT_CLASS_FATAL = 3, + MR_EVT_CLASS_DEAD = 4, + +}; + +enum MR_EVT_LOCALE { + + MR_EVT_LOCALE_LD = 0x0001, + MR_EVT_LOCALE_PD = 0x0002, + MR_EVT_LOCALE_ENCL = 0x0004, + MR_EVT_LOCALE_BBU = 0x0008, + MR_EVT_LOCALE_SAS = 0x0010, + MR_EVT_LOCALE_CTRL = 0x0020, + MR_EVT_LOCALE_CONFIG = 0x0040, + MR_EVT_LOCALE_CLUSTER = 0x0080, + MR_EVT_LOCALE_ALL = 0xffff, + +}; + +enum MR_EVT_ARGS { + + MR_EVT_ARGS_NONE, + MR_EVT_ARGS_CDB_SENSE, + MR_EVT_ARGS_LD, + MR_EVT_ARGS_LD_COUNT, + MR_EVT_ARGS_LD_LBA, + MR_EVT_ARGS_LD_OWNER, + MR_EVT_ARGS_LD_LBA_PD_LBA, + MR_EVT_ARGS_LD_PROG, + MR_EVT_ARGS_LD_STATE, + MR_EVT_ARGS_LD_STRIP, + MR_EVT_ARGS_PD, + MR_EVT_ARGS_PD_ERR, + MR_EVT_ARGS_PD_LBA, + MR_EVT_ARGS_PD_LBA_LD, + MR_EVT_ARGS_PD_PROG, + MR_EVT_ARGS_PD_STATE, + MR_EVT_ARGS_PCI, + MR_EVT_ARGS_RATE, + MR_EVT_ARGS_STR, + MR_EVT_ARGS_TIME, + MR_EVT_ARGS_ECC, + MR_EVT_ARGS_LD_PROP, + MR_EVT_ARGS_PD_SPARE, + MR_EVT_ARGS_PD_INDEX, + MR_EVT_ARGS_DIAG_PASS, + MR_EVT_ARGS_DIAG_FAIL, + MR_EVT_ARGS_PD_LBA_LBA, + MR_EVT_ARGS_PORT_PHY, + MR_EVT_ARGS_PD_MISSING, + MR_EVT_ARGS_PD_ADDRESS, + MR_EVT_ARGS_BITMAP, + MR_EVT_ARGS_CONNECTOR, + MR_EVT_ARGS_PD_PD, + MR_EVT_ARGS_PD_FRU, + MR_EVT_ARGS_PD_PATHINFO, + MR_EVT_ARGS_PD_POWER_STATE, + MR_EVT_ARGS_GENERIC, +}; + + +/* + * Thunderbolt (and later) Defines + */ +#define MRSAS_MAX_SZ_CHAIN_FRAME 1024 +#define MFI_FUSION_ENABLE_INTERRUPT_MASK (0x00000009) +#define MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE 256 +#define MRSAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST 0xF0 +#define MRSAS_MPI2_FUNCTION_LD_IO_REQUEST 0xF1 +#define MRSAS_LOAD_BALANCE_FLAG 0x1 +#define MRSAS_DCMD_MBOX_PEND_FLAG 0x1 +#define HOST_DIAG_WRITE_ENABLE 0x80 +#define HOST_DIAG_RESET_ADAPTER 0x4 +#define MRSAS_TBOLT_MAX_RESET_TRIES 3 +#define MRSAS_MAX_MFI_CMDS 32 + +/* + * Invader Defines + */ +#define MPI2_TYPE_CUDA 0x2 +#define MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH 0x4000 +#define MR_RL_FLAGS_GRANT_DESTINATION_CPU0 0x00 +#define MR_RL_FLAGS_GRANT_DESTINATION_CPU1 0x10 +#define MR_RL_FLAGS_GRANT_DESTINATION_CUDA 0x80 +#define MR_RL_FLAGS_SEQ_NUM_ENABLE 0x8 + +/* + * T10 PI defines + */ +#define MR_PROT_INFO_TYPE_CONTROLLER 0x8 +#define MRSAS_SCSI_VARIABLE_LENGTH_CMD 0x7f +#define MRSAS_SCSI_SERVICE_ACTION_READ32 0x9 +#define MRSAS_SCSI_SERVICE_ACTION_WRITE32 0xB +#define MRSAS_SCSI_ADDL_CDB_LEN 0x18 +#define MRSAS_RD_WR_PROTECT_CHECK_ALL 0x20 +#define MRSAS_RD_WR_PROTECT_CHECK_NONE 0x60 +#define MRSAS_SCSIBLOCKSIZE 512 + +/* + * Raid context flags + */ +#define MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT 0x4 +#define MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_MASK 0x30 +typedef enum MR_RAID_FLAGS_IO_SUB_TYPE { + MR_RAID_FLAGS_IO_SUB_TYPE_NONE = 0, + MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD = 1, +} MR_RAID_FLAGS_IO_SUB_TYPE; + +/* + * Request descriptor types + */ +#define MRSAS_REQ_DESCRIPT_FLAGS_LD_IO 0x7 +#define MRSAS_REQ_DESCRIPT_FLAGS_MFA 0x1 +#define MRSAS_REQ_DESCRIPT_FLAGS_NO_LOCK 0x2 +#define MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT 1 +#define MRSAS_FP_CMD_LEN 16 +#define MRSAS_FUSION_IN_RESET 0 + +#define RAID_CTX_SPANARM_ARM_SHIFT (0) +#define RAID_CTX_SPANARM_ARM_MASK (0x1f) +#define RAID_CTX_SPANARM_SPAN_SHIFT (5) +#define RAID_CTX_SPANARM_SPAN_MASK (0xE0) + +/* + * Define region lock types + */ +typedef enum _REGION_TYPE { + REGION_TYPE_UNUSED = 0, // lock is currently not active + REGION_TYPE_SHARED_READ = 1, // shared lock (for reads) + REGION_TYPE_SHARED_WRITE = 2, + REGION_TYPE_EXCLUSIVE = 3, // exclusive lock (for writes) +} REGION_TYPE; + +/* + * MR private defines + */ +#define MR_PD_INVALID 0xFFFF +#define MAX_SPAN_DEPTH 8 +#define MAX_RAIDMAP_SPAN_DEPTH (MAX_SPAN_DEPTH) +#define MAX_ROW_SIZE 32 +#define MAX_RAIDMAP_ROW_SIZE (MAX_ROW_SIZE) +#define MAX_LOGICAL_DRIVES 64 +#define MAX_RAIDMAP_LOGICAL_DRIVES (MAX_LOGICAL_DRIVES) +#define MAX_RAIDMAP_VIEWS (MAX_LOGICAL_DRIVES) +#define MAX_ARRAYS 128 +#define MAX_RAIDMAP_ARRAYS (MAX_ARRAYS) +#define MAX_PHYSICAL_DEVICES 256 +#define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES) +#define MR_DCMD_LD_MAP_GET_INFO 0x0300e101 + +/* + * SCSI-CAM Related Defines + */ +#define MRSAS_SCSI_MAX_LUNS 0 //zero for now +#define MRSAS_SCSI_INITIATOR_ID 255 +#define MRSAS_SCSI_MAX_CMDS 8 +#define MRSAS_SCSI_MAX_CDB_LEN 16 +#define MRSAS_SCSI_SENSE_BUFFERSIZE 96 +#define MRSAS_MAX_SGL 70 +#define MRSAS_MAX_IO_SIZE (256 * 1024) +#define MRSAS_INTERNAL_CMDS 32 + +/* Request types */ +#define MRSAS_REQ_TYPE_INTERNAL_CMD 0x0 +#define MRSAS_REQ_TYPE_AEN_FETCH 0x1 +#define MRSAS_REQ_TYPE_PASSTHRU 0x2 +#define MRSAS_REQ_TYPE_GETSET_PARAM 0x3 +#define MRSAS_REQ_TYPE_SCSI_IO 0x4 + +/* Request states */ +#define MRSAS_REQ_STATE_FREE 0 +#define MRSAS_REQ_STATE_BUSY 1 +#define MRSAS_REQ_STATE_TRAN 2 +#define MRSAS_REQ_STATE_COMPLETE 3 + +enum mrsas_req_flags { + MRSAS_DIR_UNKNOWN = 0x1, + MRSAS_DIR_IN = 0x2, + MRSAS_DIR_OUT = 0x4, + MRSAS_DIR_NONE = 0x8, +}; + +/* + * Adapter Reset States + */ +enum { + MRSAS_HBA_OPERATIONAL = 0, + MRSAS_ADPRESET_SM_INFAULT = 1, + MRSAS_ADPRESET_SM_FW_RESET_SUCCESS = 2, + MRSAS_ADPRESET_SM_OPERATIONAL = 3, + MRSAS_HW_CRITICAL_ERROR = 4, + MRSAS_ADPRESET_INPROG_SIGN = 0xDEADDEAD, +}; + +/* + * MPT Command Structure + */ +struct mrsas_mpt_cmd { + MRSAS_RAID_SCSI_IO_REQUEST *io_request; + bus_addr_t io_request_phys_addr; + MPI2_SGE_IO_UNION *chain_frame; + bus_addr_t chain_frame_phys_addr; + u_int32_t sge_count; + u_int8_t *sense; + bus_addr_t sense_phys_addr; + u_int8_t retry_for_fw_reset; + MRSAS_REQUEST_DESCRIPTOR_UNION *request_desc; + u_int32_t sync_cmd_idx; //For getting MFI cmd from list when complete + u_int32_t index; + u_int8_t flags; + u_int8_t load_balance; + bus_size_t length; // request length + u_int32_t error_code; // error during request dmamap load + bus_dmamap_t data_dmamap; + void *data; + union ccb *ccb_ptr; // pointer to ccb + struct callout cm_callout; + struct mrsas_softc *sc; + TAILQ_ENTRY(mrsas_mpt_cmd) next; +}; + +/* + * MFI Command Structure + */ +struct mrsas_mfi_cmd { + union mrsas_frame *frame; + bus_dmamap_t frame_dmamap; // mfi frame dmamap + void *frame_mem; // mfi frame virtual addr + bus_addr_t frame_phys_addr; // mfi frame physical addr + u_int8_t *sense; + bus_dmamap_t sense_dmamap; // mfi sense dmamap + void *sense_mem; // mfi sense virtual addr + bus_addr_t sense_phys_addr; + u_int32_t index; + u_int8_t sync_cmd; + u_int8_t cmd_status; + u_int8_t abort_aen; + u_int8_t retry_for_fw_reset; + struct mrsas_softc *sc; + union ccb *ccb_ptr; + union { + struct { + u_int16_t smid; + u_int16_t resvd; + } context; + u_int32_t frame_count; + } cmd_id; + TAILQ_ENTRY(mrsas_mfi_cmd) next; +}; + + +/* + * define constants for device list query options + */ +enum MR_PD_QUERY_TYPE { + MR_PD_QUERY_TYPE_ALL = 0, + MR_PD_QUERY_TYPE_STATE = 1, + MR_PD_QUERY_TYPE_POWER_STATE = 2, + MR_PD_QUERY_TYPE_MEDIA_TYPE = 3, + MR_PD_QUERY_TYPE_SPEED = 4, + MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5, +}; + +#define MR_EVT_CFG_CLEARED 0x0004 +#define MR_EVT_LD_STATE_CHANGE 0x0051 +#define MR_EVT_PD_INSERTED 0x005b +#define MR_EVT_PD_REMOVED 0x0070 +#define MR_EVT_LD_CREATED 0x008a +#define MR_EVT_LD_DELETED 0x008b +#define MR_EVT_FOREIGN_CFG_IMPORTED 0x00db +#define MR_EVT_LD_OFFLINE 0x00fc +#define MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED 0x0152 + +enum MR_PD_STATE { + MR_PD_STATE_UNCONFIGURED_GOOD = 0x00, + MR_PD_STATE_UNCONFIGURED_BAD = 0x01, + MR_PD_STATE_HOT_SPARE = 0x02, + MR_PD_STATE_OFFLINE = 0x10, + MR_PD_STATE_FAILED = 0x11, + MR_PD_STATE_REBUILD = 0x14, + MR_PD_STATE_ONLINE = 0x18, + MR_PD_STATE_COPYBACK = 0x20, + MR_PD_STATE_SYSTEM = 0x40, + }; + + /* + * defines the physical drive address structure + */ +#pragma pack(1) +struct MR_PD_ADDRESS { + u_int16_t deviceId; + u_int16_t enclDeviceId; + + union { + struct { + u_int8_t enclIndex; + u_int8_t slotNumber; + } mrPdAddress; + struct { + u_int8_t enclPosition; + u_int8_t enclConnectorIndex; + } mrEnclAddress; + } u1; + u_int8_t scsiDevType; + union { + u_int8_t connectedPortBitmap; + u_int8_t connectedPortNumbers; + } u2; + u_int64_t sasAddr[2]; +}; +#pragma pack() + +/* + * defines the physical drive list structure + */ +#pragma pack(1) +struct MR_PD_LIST { + u_int32_t size; + u_int32_t count; + struct MR_PD_ADDRESS addr[1]; +}; +#pragma pack() + +#pragma pack(1) +struct mrsas_pd_list { + u_int16_t tid; + u_int8_t driveType; + u_int8_t driveState; +}; +#pragma pack() + + /* + * defines the logical drive reference structure + */ +typedef union _MR_LD_REF { // LD reference structure + struct { + u_int8_t targetId; // LD target id (0 to MAX_TARGET_ID) + u_int8_t reserved; // reserved to make in line with MR_PD_REF + u_int16_t seqNum; // Sequence Number + } ld_context; + u_int32_t ref; // shorthand reference to full 32-bits +} MR_LD_REF; // 4 bytes + + +/* + * defines the logical drive list structure + */ +#pragma pack(1) +struct MR_LD_LIST { + u_int32_t ldCount; // number of LDs + u_int32_t reserved; // pad to 8-byte boundary + struct { + MR_LD_REF ref; // LD reference + u_int8_t state; // current LD state (MR_LD_STATE) + u_int8_t reserved[3]; // pad to 8-byte boundary + u_int64_t size; // LD size + } ldList[MAX_LOGICAL_DRIVES]; +}; +#pragma pack() + +/* + * SAS controller properties + */ +#pragma pack(1) +struct mrsas_ctrl_prop { + u_int16_t seq_num; + u_int16_t pred_fail_poll_interval; + u_int16_t intr_throttle_count; + u_int16_t intr_throttle_timeouts; + u_int8_t rebuild_rate; + u_int8_t patrol_read_rate; + u_int8_t bgi_rate; + u_int8_t cc_rate; + u_int8_t recon_rate; + u_int8_t cache_flush_interval; + u_int8_t spinup_drv_count; + u_int8_t spinup_delay; + u_int8_t cluster_enable; + u_int8_t coercion_mode; + u_int8_t alarm_enable; + u_int8_t disable_auto_rebuild; + u_int8_t disable_battery_warn; + u_int8_t ecc_bucket_size; + u_int16_t ecc_bucket_leak_rate; + u_int8_t restore_hotspare_on_insertion; + u_int8_t expose_encl_devices; + u_int8_t maintainPdFailHistory; + u_int8_t disallowHostRequestReordering; + u_int8_t abortCCOnError; // set TRUE to abort CC on detecting an inconsistency + u_int8_t loadBalanceMode; // load balance mode (MR_LOAD_BALANCE_MODE) + u_int8_t disableAutoDetectBackplane; // 0 - use auto detect logic of backplanes + // like SGPIO, i2c SEP using h/w mechansim + // like GPIO pins. + // 1 - disable auto detect SGPIO, + // 2 - disable i2c SEP auto detect + // 3 - disable both auto detect + u_int8_t snapVDSpace; // % of source LD to be reserved for a VDs snapshot in + // snapshot repository, for metadata and user data. + // 1=5%, 2=10%, 3=15% and so on. + /* + * Add properties that can be controlled by a bit in the following structure. + */ + struct { + u_int32_t copyBackDisabled : 1; // set TRUE to disable copyBack + // (0=copback enabled) + u_int32_t SMARTerEnabled : 1; + u_int32_t prCorrectUnconfiguredAreas : 1; + u_int32_t useFdeOnly : 1; + u_int32_t disableNCQ : 1; + u_int32_t SSDSMARTerEnabled : 1; + u_int32_t SSDPatrolReadEnabled : 1; + u_int32_t enableSpinDownUnconfigured : 1; + u_int32_t autoEnhancedImport : 1; + u_int32_t enableSecretKeyControl : 1; + u_int32_t disableOnlineCtrlReset : 1; + u_int32_t allowBootWithPinnedCache : 1; + u_int32_t disableSpinDownHS : 1; + u_int32_t enableJBOD : 1; + u_int32_t reserved :18; + } OnOffProperties; + u_int8_t autoSnapVDSpace; // % of source LD to be reserved for auto + // snapshot in snapshot repository, for + // metadata and user data. + // 1=5%, 2=10%, 3=15% and so on. + u_int8_t viewSpace; // snapshot writeable VIEWs capacity as a % + // of source LD capacity. 0=READ only. + // 1=5%, 2=10%, 3=15% and so on + u_int16_t spinDownTime; // # of idle minutes before device is spun + // down (0=use FW defaults). + u_int8_t reserved[24]; + +}; +#pragma pack() + + +/* + * SAS controller information + */ +//#pragma pack(1) +struct mrsas_ctrl_info { + /* + * PCI device information + */ + struct { + u_int16_t vendor_id; + u_int16_t device_id; + u_int16_t sub_vendor_id; + u_int16_t sub_device_id; + u_int8_t reserved[24]; + } __packed pci; + /* + * Host interface information + */ + struct { + u_int8_t PCIX:1; + u_int8_t PCIE:1; + u_int8_t iSCSI:1; + u_int8_t SAS_3G:1; + u_int8_t reserved_0:4; + u_int8_t reserved_1[6]; + u_int8_t port_count; + u_int64_t port_addr[8]; + } __packed host_interface; + /* + * Device (backend) interface information + */ + struct { + u_int8_t SPI:1; + u_int8_t SAS_3G:1; + u_int8_t SATA_1_5G:1; + u_int8_t SATA_3G:1; + u_int8_t reserved_0:4; + u_int8_t reserved_1[6]; + u_int8_t port_count; + u_int64_t port_addr[8]; + } __packed device_interface; + + /* + * List of components residing in flash. All str are null terminated + */ + u_int32_t image_check_word; + u_int32_t image_component_count; + + struct { + char name[8]; + char version[32]; + char build_date[16]; + char built_time[16]; + } __packed image_component[8]; + /* + * List of flash components that have been flashed on the card, but + * are not in use, pending reset of the adapter. This list will be + * empty if a flash operation has not occurred. All stings are null + * terminated + */ + u_int32_t pending_image_component_count; + + struct { + char name[8]; + char version[32]; + char build_date[16]; + char build_time[16]; + } __packed pending_image_component[8]; + + u_int8_t max_arms; + u_int8_t max_spans; + u_int8_t max_arrays; + u_int8_t max_lds; + char product_name[80]; + char serial_no[32]; + + /* + * Other physical/controller/operation information. Indicates the + * presence of the hardware + */ + struct { + u_int32_t bbu:1; + u_int32_t alarm:1; + u_int32_t nvram:1; + u_int32_t uart:1; + u_int32_t reserved:28; + } __packed hw_present; + + u_int32_t current_fw_time; + + /* + * Maximum data transfer sizes + */ + u_int16_t max_concurrent_cmds; + u_int16_t max_sge_count; + u_int32_t max_request_size; + + /* + * Logical and physical device counts + */ + u_int16_t ld_present_count; + u_int16_t ld_degraded_count; + u_int16_t ld_offline_count; + + u_int16_t pd_present_count; + u_int16_t pd_disk_present_count; + u_int16_t pd_disk_pred_failure_count; + u_int16_t pd_disk_failed_count; + + /* + * Memory size information + */ + u_int16_t nvram_size; + u_int16_t memory_size; + u_int16_t flash_size; + + /* + * Error counters + */ + u_int16_t mem_correctable_error_count; + u_int16_t mem_uncorrectable_error_count; + + /* + * Cluster information + */ + u_int8_t cluster_permitted; + u_int8_t cluster_active; + + /* + * Additional max data transfer sizes + */ + u_int16_t max_strips_per_io; + + /* + * Controller capabilities structures + */ + struct { + u_int32_t raid_level_0:1; + u_int32_t raid_level_1:1; + u_int32_t raid_level_5:1; + u_int32_t raid_level_1E:1; + u_int32_t raid_level_6:1; + u_int32_t reserved:27; + } __packed raid_levels; + + struct { + u_int32_t rbld_rate:1; + u_int32_t cc_rate:1; + u_int32_t bgi_rate:1; + u_int32_t recon_rate:1; + u_int32_t patrol_rate:1; + u_int32_t alarm_control:1; + u_int32_t cluster_supported:1; + u_int32_t bbu:1; + u_int32_t spanning_allowed:1; + u_int32_t dedicated_hotspares:1; + u_int32_t revertible_hotspares:1; + u_int32_t foreign_config_import:1; + u_int32_t self_diagnostic:1; + u_int32_t mixed_redundancy_arr:1; + u_int32_t global_hot_spares:1; + u_int32_t reserved:17; + } __packed adapter_operations; + + struct { + u_int32_t read_policy:1; + u_int32_t write_policy:1; + u_int32_t io_policy:1; + u_int32_t access_policy:1; + u_int32_t disk_cache_policy:1; + u_int32_t reserved:27; + } __packed ld_operations; + + struct { + u_int8_t min; + u_int8_t max; + u_int8_t reserved[2]; + } __packed stripe_sz_ops; + + struct { + u_int32_t force_online:1; + u_int32_t force_offline:1; + u_int32_t force_rebuild:1; + u_int32_t reserved:29; + } __packed pd_operations; + + struct { + u_int32_t ctrl_supports_sas:1; + u_int32_t ctrl_supports_sata:1; + u_int32_t allow_mix_in_encl:1; + u_int32_t allow_mix_in_ld:1; + u_int32_t allow_sata_in_cluster:1; + u_int32_t reserved:27; + } __packed pd_mix_support; + + /* + * Define ECC single-bit-error bucket information + */ + u_int8_t ecc_bucket_count; + u_int8_t reserved_2[11]; + + /* + * Include the controller properties (changeable items) + */ + struct mrsas_ctrl_prop properties; + + /* + * Define FW pkg version (set in envt v'bles on OEM basis) + */ + char package_version[0x60]; + + /* + * If adapterOperations.supportMoreThan8Phys is set, and deviceInterface.portCount is greater than 8, + * SAS Addrs for first 8 ports shall be populated in deviceInterface.portAddr, and the rest shall be + * populated in deviceInterfacePortAddr2. + */ + u_int64_t deviceInterfacePortAddr2[8]; //0x6a0 + u_int8_t reserved3[128]; //0x6e0 + + struct { //0x760 + u_int16_t minPdRaidLevel_0 : 4; + u_int16_t maxPdRaidLevel_0 : 12; + + u_int16_t minPdRaidLevel_1 : 4; + u_int16_t maxPdRaidLevel_1 : 12; + + u_int16_t minPdRaidLevel_5 : 4; + u_int16_t maxPdRaidLevel_5 : 12; + + u_int16_t minPdRaidLevel_1E : 4; + u_int16_t maxPdRaidLevel_1E : 12; + + u_int16_t minPdRaidLevel_6 : 4; + u_int16_t maxPdRaidLevel_6 : 12; + + u_int16_t minPdRaidLevel_10 : 4; + u_int16_t maxPdRaidLevel_10 : 12; + + u_int16_t minPdRaidLevel_50 : 4; + u_int16_t maxPdRaidLevel_50 : 12; + + u_int16_t minPdRaidLevel_60 : 4; + u_int16_t maxPdRaidLevel_60 : 12; + + u_int16_t minPdRaidLevel_1E_RLQ0 : 4; + u_int16_t maxPdRaidLevel_1E_RLQ0 : 12; + + u_int16_t minPdRaidLevel_1E0_RLQ0 : 4; + u_int16_t maxPdRaidLevel_1E0_RLQ0 : 12; + + u_int16_t reserved[6]; + } pdsForRaidLevels; + + u_int16_t maxPds; //0x780 + u_int16_t maxDedHSPs; //0x782 + u_int16_t maxGlobalHSPs; //0x784 + u_int16_t ddfSize; //0x786 + u_int8_t maxLdsPerArray; //0x788 + u_int8_t partitionsInDDF; //0x789 + u_int8_t lockKeyBinding; //0x78a + u_int8_t maxPITsPerLd; //0x78b + u_int8_t maxViewsPerLd; //0x78c + u_int8_t maxTargetId; //0x78d + u_int16_t maxBvlVdSize; //0x78e + + u_int16_t maxConfigurableSSCSize; //0x790 + u_int16_t currentSSCsize; //0x792 + + char expanderFwVersion[12]; //0x794 + + u_int16_t PFKTrialTimeRemaining; //0x7A0 + + u_int16_t cacheMemorySize; //0x7A2 + + struct { //0x7A4 + u_int32_t supportPIcontroller :1; + u_int32_t supportLdPIType1 :1; + u_int32_t supportLdPIType2 :1; + u_int32_t supportLdPIType3 :1; + u_int32_t supportLdBBMInfo :1; + u_int32_t supportShieldState :1; + u_int32_t blockSSDWriteCacheChange :1; + u_int32_t supportSuspendResumeBGops :1; + u_int32_t supportEmergencySpares :1; + u_int32_t supportSetLinkSpeed :1; + u_int32_t supportBootTimePFKChange :1; + u_int32_t supportJBOD :1; + u_int32_t disableOnlinePFKChange :1; + u_int32_t supportPerfTuning :1; + u_int32_t supportSSDPatrolRead :1; + u_int32_t realTimeScheduler :1; + + u_int32_t supportResetNow :1; + u_int32_t supportEmulatedDrives :1; + u_int32_t headlessMode :1; + u_int32_t dedicatedHotSparesLimited :1; + + + u_int32_t supportUnevenSpans :1; + u_int32_t reserved :11; + } adapterOperations2; + + u_int8_t driverVersion[32]; //0x7A8 + u_int8_t maxDAPdCountSpinup60; //0x7C8 + u_int8_t temperatureROC; //0x7C9 + u_int8_t temperatureCtrl; //0x7CA + u_int8_t reserved4; //0x7CB + u_int16_t maxConfigurablePds; //0x7CC + + + u_int8_t reserved5[2]; //0x7CD reserved for future use + + /* + * HA cluster information + */ + struct { + u_int32_t peerIsPresent :1; + u_int32_t peerIsIncompatible :1; + + u_int32_t hwIncompatible :1; + u_int32_t fwVersionMismatch :1; + u_int32_t ctrlPropIncompatible :1; + u_int32_t premiumFeatureMismatch :1; + u_int32_t reserved :26; + } cluster; + + char clusterId[16]; //0x7D4 + + u_int8_t pad[0x800-0x7E4]; //0x7E4 +} __packed; + +/* + * Ld and PD Max Support Defines + */ +#define MRSAS_MAX_PD 256 +#define MRSAS_MAX_LD 64 + +/* + * When SCSI mid-layer calls driver's reset routine, driver waits for + * MRSAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note + * that the driver cannot _actually_ abort or reset pending commands. While + * it is waiting for the commands to complete, it prints a diagnostic message + * every MRSAS_RESET_NOTICE_INTERVAL seconds + */ +#define MRSAS_RESET_WAIT_TIME 180 +#define MRSAS_INTERNAL_CMD_WAIT_TIME 180 +#define MRSAS_IOC_INIT_WAIT_TIME 60 +#define MRSAS_RESET_NOTICE_INTERVAL 5 +#define MRSAS_IOCTL_CMD 0 +#define MRSAS_DEFAULT_CMD_TIMEOUT 90 +#define MRSAS_THROTTLE_QUEUE_DEPTH 16 + +/* + * FW reports the maximum of number of commands that it can accept (maximum + * commands that can be outstanding) at any time. The driver must report a + * lower number to the mid layer because it can issue a few internal commands + * itself (E.g, AEN, abort cmd, IOCTLs etc). The number of commands it needs + * is shown below + */ +#define MRSAS_INT_CMDS 32 +#define MRSAS_SKINNY_INT_CMDS 5 +#define MRSAS_MAX_MSIX_QUEUES 16 + +/* + * FW can accept both 32 and 64 bit SGLs. We want to allocate 32/64 bit + * SGLs based on the size of bus_addr_t + */ +#define IS_DMA64 (sizeof(bus_addr_t) == 8) + +#define MFI_XSCALE_OMR0_CHANGE_INTERRUPT 0x00000001 // MFI state change interrupt +#define MFI_INTR_FLAG_REPLY_MESSAGE 0x00000001 +#define MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE 0x00000002 +#define MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT 0x00000004 //MFI state change interrupt + +#define MFI_OB_INTR_STATUS_MASK 0x00000002 +#define MFI_POLL_TIMEOUT_SECS 60 + +#define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000 +#define MFI_REPLY_GEN2_MESSAGE_INTERRUPT 0x00000001 +#define MFI_GEN2_ENABLE_INTERRUPT_MASK 0x00000001 +#define MFI_REPLY_SKINNY_MESSAGE_INTERRUPT 0x40000000 +#define MFI_SKINNY_ENABLE_INTERRUPT_MASK (0x00000001) +#define MFI_1068_PCSR_OFFSET 0x84 +#define MFI_1068_FW_HANDSHAKE_OFFSET 0x64 +#define MFI_1068_FW_READY 0xDDDD0000 + +#pragma pack(1) +struct mrsas_sge32 { + u_int32_t phys_addr; + u_int32_t length; +}; +#pragma pack() + +#pragma pack(1) +struct mrsas_sge64 { + u_int64_t phys_addr; + u_int32_t length; +}; +#pragma pack() + +#pragma pack() +union mrsas_sgl { + struct mrsas_sge32 sge32[1]; + struct mrsas_sge64 sge64[1]; +}; +#pragma pack() + +#pragma pack(1) +struct mrsas_header { + u_int8_t cmd; /*00e */ + u_int8_t sense_len; /*01h */ + u_int8_t cmd_status; /*02h */ + u_int8_t scsi_status; /*03h */ + + u_int8_t target_id; /*04h */ + u_int8_t lun; /*05h */ + u_int8_t cdb_len; /*06h */ + u_int8_t sge_count; /*07h */ + + u_int32_t context; /*08h */ + u_int32_t pad_0; /*0Ch */ + + u_int16_t flags; /*10h */ + u_int16_t timeout; /*12h */ + u_int32_t data_xferlen; /*14h */ +}; +#pragma pack() + +#pragma pack(1) +struct mrsas_init_frame { + u_int8_t cmd; /*00h */ + u_int8_t reserved_0; /*01h */ + u_int8_t cmd_status; /*02h */ + + u_int8_t reserved_1; /*03h */ + u_int32_t reserved_2; /*04h */ + + u_int32_t context; /*08h */ + u_int32_t pad_0; /*0Ch */ + + u_int16_t flags; /*10h */ + u_int16_t reserved_3; /*12h */ + u_int32_t data_xfer_len; /*14h */ + + u_int32_t queue_info_new_phys_addr_lo; /*18h */ + u_int32_t queue_info_new_phys_addr_hi; /*1Ch */ + u_int32_t queue_info_old_phys_addr_lo; /*20h */ + u_int32_t queue_info_old_phys_addr_hi; /*24h */ + u_int32_t driver_ver_lo; /*28h */ + u_int32_t driver_ver_hi; /*2Ch */ + u_int32_t reserved_4[4]; /*30h */ +}; +#pragma pack() + +#pragma pack(1) +struct mrsas_io_frame { + u_int8_t cmd; /*00h */ + u_int8_t sense_len; /*01h */ + u_int8_t cmd_status; /*02h */ + u_int8_t scsi_status; /*03h */ + + u_int8_t target_id; /*04h */ + u_int8_t access_byte; /*05h */ + u_int8_t reserved_0; /*06h */ + u_int8_t sge_count; /*07h */ + + u_int32_t context; /*08h */ + u_int32_t pad_0; /*0Ch */ + + u_int16_t flags; /*10h */ + u_int16_t timeout; /*12h */ + u_int32_t lba_count; /*14h */ + + u_int32_t sense_buf_phys_addr_lo; /*18h */ + u_int32_t sense_buf_phys_addr_hi; /*1Ch */ + + u_int32_t start_lba_lo; /*20h */ + u_int32_t start_lba_hi; /*24h */ + + union mrsas_sgl sgl; /*28h */ +}; +#pragma pack() + +#pragma pack(1) +struct mrsas_pthru_frame { + u_int8_t cmd; /*00h */ + u_int8_t sense_len; /*01h */ + u_int8_t cmd_status; /*02h */ + u_int8_t scsi_status; /*03h */ + + u_int8_t target_id; /*04h */ + u_int8_t lun; /*05h */ + u_int8_t cdb_len; /*06h */ + u_int8_t sge_count; /*07h */ + + u_int32_t context; /*08h */ + u_int32_t pad_0; /*0Ch */ + + u_int16_t flags; /*10h */ + u_int16_t timeout; /*12h */ + u_int32_t data_xfer_len; /*14h */ + + u_int32_t sense_buf_phys_addr_lo; /*18h */ + u_int32_t sense_buf_phys_addr_hi; /*1Ch */ + + u_int8_t cdb[16]; /*20h */ + union mrsas_sgl sgl; /*30h */ +}; +#pragma pack() + +#pragma pack(1) +struct mrsas_dcmd_frame { + u_int8_t cmd; /*00h */ + u_int8_t reserved_0; /*01h */ + u_int8_t cmd_status; /*02h */ + u_int8_t reserved_1[4]; /*03h */ + u_int8_t sge_count; /*07h */ + + u_int32_t context; /*08h */ + u_int32_t pad_0; /*0Ch */ + + u_int16_t flags; /*10h */ + u_int16_t timeout; /*12h */ + + u_int32_t data_xfer_len; /*14h */ + u_int32_t opcode; /*18h */ + + union { /*1Ch */ + u_int8_t b[12]; + u_int16_t s[6]; + u_int32_t w[3]; + } mbox; + + union mrsas_sgl sgl; /*28h */ +}; +#pragma pack() + +#pragma pack(1) +struct mrsas_abort_frame { + u_int8_t cmd; /*00h */ + u_int8_t reserved_0; /*01h */ + u_int8_t cmd_status; /*02h */ + + u_int8_t reserved_1; /*03h */ + u_int32_t reserved_2; /*04h */ + + u_int32_t context; /*08h */ + u_int32_t pad_0; /*0Ch */ + + u_int16_t flags; /*10h */ + u_int16_t reserved_3; /*12h */ + u_int32_t reserved_4; /*14h */ + + u_int32_t abort_context; /*18h */ + u_int32_t pad_1; /*1Ch */ + + u_int32_t abort_mfi_phys_addr_lo; /*20h */ + u_int32_t abort_mfi_phys_addr_hi; /*24h */ + + u_int32_t reserved_5[6]; /*28h */ +}; +#pragma pack() + +#pragma pack(1) +struct mrsas_smp_frame { + u_int8_t cmd; /*00h */ + u_int8_t reserved_1; /*01h */ + u_int8_t cmd_status; /*02h */ + u_int8_t connection_status; /*03h */ + + u_int8_t reserved_2[3]; /*04h */ + u_int8_t sge_count; /*07h */ + + u_int32_t context; /*08h */ + u_int32_t pad_0; /*0Ch */ + + u_int16_t flags; /*10h */ + u_int16_t timeout; /*12h */ + + u_int32_t data_xfer_len; /*14h */ + u_int64_t sas_addr; /*18h */ + + union { + struct mrsas_sge32 sge32[2]; /* [0]: resp [1]: req */ + struct mrsas_sge64 sge64[2]; /* [0]: resp [1]: req */ + } sgl; +}; +#pragma pack() + + +#pragma pack(1) +struct mrsas_stp_frame { + u_int8_t cmd; /*00h */ + u_int8_t reserved_1; /*01h */ + u_int8_t cmd_status; /*02h */ + u_int8_t reserved_2; /*03h */ + + u_int8_t target_id; /*04h */ + u_int8_t reserved_3[2]; /*05h */ + u_int8_t sge_count; /*07h */ + + u_int32_t context; /*08h */ + u_int32_t pad_0; /*0Ch */ + + u_int16_t flags; /*10h */ + u_int16_t timeout; /*12h */ + + u_int32_t data_xfer_len; /*14h */ + + u_int16_t fis[10]; /*18h */ + u_int32_t stp_flags; + + union { + struct mrsas_sge32 sge32[2]; /* [0]: resp [1]: data */ + struct mrsas_sge64 sge64[2]; /* [0]: resp [1]: data */ + } sgl; +}; +#pragma pack() + +union mrsas_frame { + struct mrsas_header hdr; + struct mrsas_init_frame init; + struct mrsas_io_frame io; + struct mrsas_pthru_frame pthru; + struct mrsas_dcmd_frame dcmd; + struct mrsas_abort_frame abort; + struct mrsas_smp_frame smp; + struct mrsas_stp_frame stp; + u_int8_t raw_bytes[64]; +}; + +#pragma pack(1) +union mrsas_evt_class_locale { + + struct { + u_int16_t locale; + u_int8_t reserved; + int8_t class; + } __packed members; + + u_int32_t word; + +} __packed; + +#pragma pack() + + +#pragma pack(1) +struct mrsas_evt_log_info { + u_int32_t newest_seq_num; + u_int32_t oldest_seq_num; + u_int32_t clear_seq_num; + u_int32_t shutdown_seq_num; + u_int32_t boot_seq_num; + +} __packed; + +#pragma pack() + +struct mrsas_progress { + + u_int16_t progress; + u_int16_t elapsed_seconds; + +} __packed; + +struct mrsas_evtarg_ld { + + u_int16_t target_id; + u_int8_t ld_index; + u_int8_t reserved; + +} __packed; + +struct mrsas_evtarg_pd { + u_int16_t device_id; + u_int8_t encl_index; + u_int8_t slot_number; + +} __packed; + +struct mrsas_evt_detail { + + u_int32_t seq_num; + u_int32_t time_stamp; + u_int32_t code; + union mrsas_evt_class_locale cl; + u_int8_t arg_type; + u_int8_t reserved1[15]; + + union { + struct { + struct mrsas_evtarg_pd pd; + u_int8_t cdb_length; + u_int8_t sense_length; + u_int8_t reserved[2]; + u_int8_t cdb[16]; + u_int8_t sense[64]; + } __packed cdbSense; + + struct mrsas_evtarg_ld ld; + + struct { + struct mrsas_evtarg_ld ld; + u_int64_t count; + } __packed ld_count; + + struct { + u_int64_t lba; + struct mrsas_evtarg_ld ld; + } __packed ld_lba; + + struct { + struct mrsas_evtarg_ld ld; + u_int32_t prevOwner; + u_int32_t newOwner; + } __packed ld_owner; + + struct { + u_int64_t ld_lba; + u_int64_t pd_lba; + struct mrsas_evtarg_ld ld; + struct mrsas_evtarg_pd pd; + } __packed ld_lba_pd_lba; + + struct { + struct mrsas_evtarg_ld ld; + struct mrsas_progress prog; + } __packed ld_prog; + + struct { + struct mrsas_evtarg_ld ld; + u_int32_t prev_state; + u_int32_t new_state; + } __packed ld_state; + + struct { + u_int64_t strip; + struct mrsas_evtarg_ld ld; + } __packed ld_strip; + + struct mrsas_evtarg_pd pd; + + struct { + struct mrsas_evtarg_pd pd; + u_int32_t err; + } __packed pd_err; + + struct { + u_int64_t lba; + struct mrsas_evtarg_pd pd; + } __packed pd_lba; + + struct { + u_int64_t lba; + struct mrsas_evtarg_pd pd; + struct mrsas_evtarg_ld ld; + } __packed pd_lba_ld; + + struct { + struct mrsas_evtarg_pd pd; + struct mrsas_progress prog; + } __packed pd_prog; + + struct { + struct mrsas_evtarg_pd pd; + u_int32_t prevState; + u_int32_t newState; + } __packed pd_state; + + struct { + u_int16_t vendorId; + u_int16_t deviceId; + u_int16_t subVendorId; + u_int16_t subDeviceId; + } __packed pci; + + u_int32_t rate; + char str[96]; + + struct { + u_int32_t rtc; + u_int32_t elapsedSeconds; + } __packed time; + + struct { + u_int32_t ecar; + u_int32_t elog; + char str[64]; + } __packed ecc; + + u_int8_t b[96]; + u_int16_t s[48]; + u_int32_t w[24]; + u_int64_t d[12]; + } args; + + char description[128]; + +} __packed; + + +/******************************************************************* + * per-instance data + ********************************************************************/ +struct mrsas_softc { + device_t mrsas_dev; // bus device + struct cdev *mrsas_cdev; // controller device + uint16_t device_id; // pci device + struct resource *reg_res; // register interface window + int reg_res_id; // register resource id + bus_space_tag_t bus_tag; // bus space tag + bus_space_handle_t bus_handle; // bus space handle + bus_dma_tag_t mrsas_parent_tag; // bus dma parent tag + bus_dma_tag_t verbuf_tag; // verbuf tag + bus_dmamap_t verbuf_dmamap; // verbuf dmamap + void *verbuf_mem; // verbuf mem + bus_addr_t verbuf_phys_addr; // verbuf physical addr + bus_dma_tag_t sense_tag; // bus dma verbuf tag + bus_dmamap_t sense_dmamap; // bus dma verbuf dmamap + void *sense_mem; // pointer to sense buf + bus_addr_t sense_phys_addr; // bus dma verbuf mem + bus_dma_tag_t io_request_tag; // bus dma io request tag + bus_dmamap_t io_request_dmamap; // bus dma io request dmamap + void *io_request_mem; // bus dma io request mem + bus_addr_t io_request_phys_addr; // io request physical address + bus_dma_tag_t chain_frame_tag; // bus dma chain frame tag + bus_dmamap_t chain_frame_dmamap; // bus dma chain frame dmamap + void *chain_frame_mem; // bus dma chain frame mem + bus_addr_t chain_frame_phys_addr; // chain frame phys address + bus_dma_tag_t reply_desc_tag; // bus dma io request tag + bus_dmamap_t reply_desc_dmamap; // bus dma io request dmamap + void *reply_desc_mem; // bus dma io request mem + bus_addr_t reply_desc_phys_addr; // bus dma io request mem + bus_dma_tag_t ioc_init_tag; // bus dma io request tag + bus_dmamap_t ioc_init_dmamap; // bus dma io request dmamap + void *ioc_init_mem; // bus dma io request mem + bus_addr_t ioc_init_phys_mem; // io request physical address + bus_dma_tag_t data_tag; // bus dma data from OS tag + struct cam_sim *sim_0; // SIM pointer + struct cam_sim *sim_1; // SIM pointer + struct cam_path *path_0; // ldio path pointer to CAM + struct cam_path *path_1; // syspd path pointer to CAM + struct mtx sim_lock; // sim lock + struct mtx pci_lock; // serialize pci access + struct mtx io_lock; // IO lock + struct mtx ioctl_lock; // IOCTL lock + struct mtx mpt_cmd_pool_lock; // lock for cmd pool linked list + struct mtx mfi_cmd_pool_lock; // lock for cmd pool linked list + struct mtx raidmap_lock; // lock for raid map access/update + struct mtx aen_lock; // aen lock + uint32_t max_fw_cmds; // Max commands from FW + uint32_t max_num_sge; // Max number of SGEs + struct resource *mrsas_irq; // interrupt interface window + void *intr_handle; // handle + int irq_id; // intr resource id + struct mrsas_mpt_cmd **mpt_cmd_list; + struct mrsas_mfi_cmd **mfi_cmd_list; + TAILQ_HEAD(, mrsas_mpt_cmd) mrsas_mpt_cmd_list_head; + TAILQ_HEAD(, mrsas_mfi_cmd) mrsas_mfi_cmd_list_head; + bus_addr_t req_frames_desc_phys; + u_int8_t *req_frames_desc; + u_int8_t *req_desc; + bus_addr_t io_request_frames_phys; + u_int8_t *io_request_frames; + bus_addr_t reply_frames_desc_phys; + u_int16_t last_reply_idx; + u_int32_t reply_q_depth; + u_int32_t request_alloc_sz; + u_int32_t reply_alloc_sz; + u_int32_t io_frames_alloc_sz; + u_int32_t chain_frames_alloc_sz; + u_int16_t max_sge_in_main_msg; + u_int16_t max_sge_in_chain; + u_int8_t chain_offset_io_request; + u_int8_t chain_offset_mfi_pthru; + u_int32_t map_sz; + u_int64_t map_id; + struct mrsas_mfi_cmd *map_update_cmd; + struct mrsas_mfi_cmd *aen_cmd; + u_int8_t fast_path_io; + void* chan; + void* ocr_chan; + u_int8_t adprecovery; + u_int8_t remove_in_progress; + u_int8_t ocr_thread_active; + u_int8_t do_timedout_reset; + u_int32_t reset_in_progress; + u_int32_t reset_count; + bus_dma_tag_t raidmap_tag[2]; // bus dma tag for RAID map + bus_dmamap_t raidmap_dmamap[2]; // bus dma dmamap RAID map + void *raidmap_mem[2]; // bus dma mem RAID map + bus_addr_t raidmap_phys_addr[2]; // RAID map physical address + bus_dma_tag_t mficmd_frame_tag; // tag for mfi frame + bus_dma_tag_t mficmd_sense_tag; // tag for mfi sense + bus_dma_tag_t evt_detail_tag; // event detail tag + bus_dmamap_t evt_detail_dmamap; // event detail dmamap + struct mrsas_evt_detail *evt_detail_mem; // event detail mem + bus_addr_t evt_detail_phys_addr; // event detail physical addr + bus_dma_tag_t ctlr_info_tag; // tag for get ctlr info cmd + bus_dmamap_t ctlr_info_dmamap; // get ctlr info cmd dmamap + void *ctlr_info_mem; // get ctlr info cmd virtual addr + bus_addr_t ctlr_info_phys_addr; //get ctlr info cmd physical addr + u_int32_t max_sectors_per_req; + u_int8_t disableOnlineCtrlReset; + atomic_t fw_outstanding; + u_int32_t mrsas_debug; + u_int32_t mrsas_io_timeout; + u_int32_t mrsas_fw_fault_check_delay; + u_int32_t io_cmds_highwater; + u_int8_t UnevenSpanSupport; + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_tree; + struct proc *ocr_thread; + u_int32_t last_seq_num; + bus_dma_tag_t el_info_tag; // tag for get event log info cmd + bus_dmamap_t el_info_dmamap; // get event log info cmd dmamap + void *el_info_mem; // get event log info cmd virtual addr + bus_addr_t el_info_phys_addr; //get event log info cmd physical addr + struct mrsas_pd_list pd_list[MRSAS_MAX_PD]; + struct mrsas_pd_list local_pd_list[MRSAS_MAX_PD]; + u_int8_t ld_ids[MRSAS_MAX_LD]; + struct taskqueue *ev_tq; //taskqueue for events + struct task ev_task; + u_int32_t CurLdCount; + u_int64_t reset_flags; + LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES]; + LD_SPAN_INFO log_to_span[MAX_LOGICAL_DRIVES]; +}; + +/* Compatibility shims for different OS versions */ +#if __FreeBSD_version >= 800001 +#define mrsas_kproc_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg) \ + kproc_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg) +#define mrsas_kproc_exit(arg) kproc_exit(arg) +#else +#define mrsas_kproc_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg) \ + kthread_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg) +#define mrsas_kproc_exit(arg) kthread_exit(arg) +#endif + +static __inline void +clear_bit(int b, volatile void *p) +{ + atomic_clear_int(((volatile int *)p) + (b >> 5), 1 << (b & 0x1f)); +} + +static __inline void +set_bit(int b, volatile void *p) +{ + atomic_set_int(((volatile int *)p) + (b >> 5), 1 << (b & 0x1f)); +} + +static __inline int +test_bit(int b, volatile void *p) +{ + return ((volatile int *)p)[b >> 5] & (1 << (b & 0x1f)); +} + +#endif /* MRSAS_H */ diff --git a/sys/dev/mrsas/mrsas_cam.c b/sys/dev/mrsas/mrsas_cam.c new file mode 100644 index 0000000000000..81e8fcb13a3e5 --- /dev/null +++ b/sys/dev/mrsas/mrsas_cam.c @@ -0,0 +1,1179 @@ +/* + * Copyright (c) 2014, LSI Corp. + * All rights reserved. + * Author: Marian Choy + * Support: freebsdraid@lsi.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of the <ORGANIZATION> nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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 "dev/mrsas/mrsas.h" + +#include <cam/cam.h> +#include <cam/cam_ccb.h> +#include <cam/cam_sim.h> +#include <cam/cam_xpt_sim.h> +#include <cam/cam_debug.h> +#include <cam/cam_periph.h> +#include <cam/cam_xpt_periph.h> + +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_message.h> +#include <sys/taskqueue.h> + + +/* + * Function prototypes + */ +int mrsas_cam_attach(struct mrsas_softc *sc); +//int mrsas_ldio_inq(union ccb *ccb); +int mrsas_ldio_inq(struct cam_sim *sim, union ccb *ccb); +int mrsas_bus_scan(struct mrsas_softc *sc); +int mrsas_bus_scan_sim(struct mrsas_softc *sc, struct cam_sim *sim); +int mrsas_map_request(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd); +int mrsas_build_ldio(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd, + union ccb *ccb); +int mrsas_build_dcdb(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd, + union ccb *ccb, struct cam_sim *sim); +int mrsas_setup_io(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd, + union ccb *ccb, u_int32_t device_id, + MRSAS_RAID_SCSI_IO_REQUEST *io_request); +void mrsas_xpt_freeze(struct mrsas_softc *sc); +void mrsas_xpt_release(struct mrsas_softc *sc); +void mrsas_cam_detach(struct mrsas_softc *sc); +void mrsas_release_mpt_cmd(struct mrsas_mpt_cmd *cmd); +void mrsas_unmap_request(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd); +void mrsas_cmd_done(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd); +void mrsas_fire_cmd(struct mrsas_softc *sc, u_int32_t req_desc_lo, + u_int32_t req_desc_hi); +void mrsas_set_pd_lba(MRSAS_RAID_SCSI_IO_REQUEST *io_request, u_int8_t cdb_len, + struct IO_REQUEST_INFO *io_info, union ccb *ccb, + MR_FW_RAID_MAP_ALL *local_map_ptr, u_int32_t ref_tag, + u_int32_t ld_block_size); +static void mrsas_freeze_simq(struct mrsas_mpt_cmd *cmd, struct cam_sim *sim); +static void mrsas_poll(struct cam_sim *sim); +static void mrsas_action(struct cam_sim *sim, union ccb *ccb); +static void mrsas_scsiio_timeout(void *data); +static void mrsas_data_load_cb(void *arg, bus_dma_segment_t *segs, + int nseg, int error); +static int32_t mrsas_startio(struct mrsas_softc *sc, struct cam_sim *sim, + union ccb *ccb); +struct mrsas_mpt_cmd * mrsas_get_mpt_cmd(struct mrsas_softc *sc); +MRSAS_REQUEST_DESCRIPTOR_UNION *mrsas_get_request_desc(struct mrsas_softc *sc, + u_int16_t index); + +extern u_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map); +extern u_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map, + struct mrsas_softc *sc); +extern void mrsas_isr(void *arg); +extern void mrsas_aen_handler(struct mrsas_softc *sc); +extern u_int8_t MR_BuildRaidContext(struct mrsas_softc *sc, + struct IO_REQUEST_INFO *io_info,RAID_CONTEXT *pRAID_Context, + MR_FW_RAID_MAP_ALL *map); +extern u_int16_t MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span, + MR_FW_RAID_MAP_ALL *map); +extern u_int16_t mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo, + struct IO_REQUEST_INFO *io_info); +extern u_int8_t megasas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm, + u_int64_t block, u_int32_t count); + + +/** + * mrsas_cam_attach: Main entry to CAM subsystem + * input: Adapter instance soft state + * + * This function is called from mrsas_attach() during initialization + * to perform SIM allocations and XPT bus registration. If the kernel + * version is 7.4 or earlier, it would also initiate a bus scan. + */ +int mrsas_cam_attach(struct mrsas_softc *sc) +{ + struct cam_devq *devq; + int mrsas_cam_depth; + + mrsas_cam_depth = sc->max_fw_cmds - MRSAS_INTERNAL_CMDS; + + if ((devq = cam_simq_alloc(mrsas_cam_depth)) == NULL) { + device_printf(sc->mrsas_dev, "Cannot allocate SIM queue\n"); + return(ENOMEM); + } + + + /* + * Create SIM for bus 0 and register, also create path + */ + sc->sim_0 = cam_sim_alloc(mrsas_action, mrsas_poll, "mrsas", sc, + device_get_unit(sc->mrsas_dev), &sc->sim_lock, mrsas_cam_depth, + mrsas_cam_depth, devq); + if (sc->sim_0 == NULL){ + cam_simq_free(devq); + device_printf(sc->mrsas_dev, "Cannot register SIM\n"); + return(ENXIO); + } + /* Initialize taskqueue for Event Handling */ + TASK_INIT(&sc->ev_task, 0, (void *)mrsas_aen_handler, sc); + sc->ev_tq = taskqueue_create("mrsas_taskq", M_NOWAIT | M_ZERO, + taskqueue_thread_enqueue, &sc->ev_tq); + + /* Run the task queue with lowest priority */ + taskqueue_start_threads(&sc->ev_tq, 1, 255, "%s taskq", + device_get_nameunit(sc->mrsas_dev)); + mtx_lock(&sc->sim_lock); + if (xpt_bus_register(sc->sim_0, sc->mrsas_dev,0) != CAM_SUCCESS) + { + cam_sim_free(sc->sim_0, TRUE); // passing true frees the devq + mtx_unlock(&sc->sim_lock); + return(ENXIO); + } + if (xpt_create_path(&sc->path_0, NULL, cam_sim_path(sc->sim_0), + CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + xpt_bus_deregister(cam_sim_path(sc->sim_0)); + cam_sim_free(sc->sim_0, TRUE); // passing true will free the devq + mtx_unlock(&sc->sim_lock); + return(ENXIO); + } + mtx_unlock(&sc->sim_lock); + + /* + * Create SIM for bus 1 and register, also create path + */ + sc->sim_1 = cam_sim_alloc(mrsas_action, mrsas_poll, "mrsas", sc, + device_get_unit(sc->mrsas_dev), &sc->sim_lock, mrsas_cam_depth, + mrsas_cam_depth, devq); + if (sc->sim_1 == NULL){ + cam_simq_free(devq); + device_printf(sc->mrsas_dev, "Cannot register SIM\n"); + return(ENXIO); + } + + mtx_lock(&sc->sim_lock); + if (xpt_bus_register(sc->sim_1, sc->mrsas_dev, 1) != CAM_SUCCESS){ + cam_sim_free(sc->sim_1, TRUE); // passing true frees the devq + mtx_unlock(&sc->sim_lock); + return(ENXIO); + } + if (xpt_create_path(&sc->path_1, NULL, cam_sim_path(sc->sim_1), + CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + xpt_bus_deregister(cam_sim_path(sc->sim_1)); + cam_sim_free(sc->sim_1, TRUE); + mtx_unlock(&sc->sim_lock); + return(ENXIO); + } + mtx_unlock(&sc->sim_lock); + +#if (__FreeBSD_version <= 704000) + if (mrsas_bus_scan(sc)){ + device_printf(sc->mrsas_dev, "Error in bus scan.\n"); + return(1); + } +#endif + return(0); +} + +/** + * mrsas_cam_detach: De-allocates and teardown CAM + * input: Adapter instance soft state + * + * De-registers and frees the paths and SIMs. + */ +void mrsas_cam_detach(struct mrsas_softc *sc) +{ + if (sc->ev_tq != NULL) + taskqueue_free(sc->ev_tq); + mtx_lock(&sc->sim_lock); + if (sc->path_0) + xpt_free_path(sc->path_0); + if (sc->sim_0) { + xpt_bus_deregister(cam_sim_path(sc->sim_0)); + cam_sim_free(sc->sim_0, FALSE); + } + if (sc->path_1) + xpt_free_path(sc->path_1); + if (sc->sim_1) { + xpt_bus_deregister(cam_sim_path(sc->sim_1)); + cam_sim_free(sc->sim_1, TRUE); + } + mtx_unlock(&sc->sim_lock); +} + +/** + * mrsas_action: SIM callback entry point + * input: pointer to SIM + * pointer to CAM Control Block + * + * This function processes CAM subsystem requests. The type of request is + * stored in ccb->ccb_h.func_code. The preprocessor #ifdef is necessary + * because ccb->cpi.maxio is not supported for FreeBSD version 7.4 or + * earlier. + */ +static void mrsas_action(struct cam_sim *sim, union ccb *ccb) +{ + struct mrsas_softc *sc = (struct mrsas_softc *)cam_sim_softc(sim); + struct ccb_hdr *ccb_h = &(ccb->ccb_h); + u_int32_t device_id; + + switch (ccb->ccb_h.func_code) { + case XPT_SCSI_IO: + { + device_id = ccb_h->target_id; + + /* + * bus 0 is LD, bus 1 is for system-PD + */ + if (cam_sim_bus(sim) == 1 && + sc->pd_list[device_id].driveState != MR_PD_STATE_SYSTEM) { + ccb->ccb_h.status |= CAM_DEV_NOT_THERE; + xpt_done(ccb); + } + else { + if (mrsas_startio(sc, sim, ccb)){ + ccb->ccb_h.status |= CAM_REQ_INVALID; + xpt_done(ccb); + } + } + break; + } + case XPT_ABORT: + { + ccb->ccb_h.status = CAM_UA_ABORT; + xpt_done(ccb); + break; + } + case XPT_RESET_BUS: + { + xpt_done(ccb); + break; + } + case XPT_GET_TRAN_SETTINGS: + { + ccb->cts.protocol = PROTO_SCSI; + ccb->cts.protocol_version = SCSI_REV_2; + ccb->cts.transport = XPORT_SPI; + ccb->cts.transport_version = 2; + ccb->cts.xport_specific.spi.valid = CTS_SPI_VALID_DISC; + ccb->cts.xport_specific.spi.flags = CTS_SPI_FLAGS_DISC_ENB; + ccb->cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ; + ccb->cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB; + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + case XPT_SET_TRAN_SETTINGS: + { + ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; + xpt_done(ccb); + break; + } + case XPT_CALC_GEOMETRY: + { + cam_calc_geometry(&ccb->ccg, 1); + xpt_done(ccb); + break; + } + case XPT_PATH_INQ: + { + ccb->cpi.version_num = 1; + ccb->cpi.hba_inquiry = 0; + ccb->cpi.target_sprt = 0; + ccb->cpi.hba_misc = 0; + ccb->cpi.hba_eng_cnt = 0; + ccb->cpi.max_lun = MRSAS_SCSI_MAX_LUNS; + ccb->cpi.unit_number = cam_sim_unit(sim); + ccb->cpi.bus_id = cam_sim_bus(sim); + ccb->cpi.initiator_id = MRSAS_SCSI_INITIATOR_ID; + ccb->cpi.base_transfer_speed = 150000; + strncpy(ccb->cpi.sim_vid, "FreeBSD", SIM_IDLEN); + strncpy(ccb->cpi.hba_vid, "LSI", HBA_IDLEN); + strncpy(ccb->cpi.dev_name, cam_sim_name(sim), DEV_IDLEN); + ccb->cpi.transport = XPORT_SPI; + ccb->cpi.transport_version = 2; + ccb->cpi.protocol = PROTO_SCSI; + ccb->cpi.protocol_version = SCSI_REV_2; + if (ccb->cpi.bus_id == 0) + ccb->cpi.max_target = MRSAS_MAX_LD-1; + else + ccb->cpi.max_target = MRSAS_MAX_PD-1; +#if (__FreeBSD_version > 704000) + ccb->cpi.maxio = MRSAS_MAX_IO_SIZE; +#endif + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + default: + { + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; + } + } +} + +/** + * mrsas_scsiio_timeout Callback function for IO timed out + * input: mpt command context + * + * This function will execute after timeout value + * provided by ccb header from CAM layer, if timer expires. + * Driver will run timer for all DCDM and LDIO comming from CAM layer. + * This function is callback function for IO timeout and it runs in + * no-sleep context. Set do_timedout_reset in Adapter context so that + * it will execute OCR/Kill adpter from ocr_thread context. + */ +static void +mrsas_scsiio_timeout(void *data) +{ + struct mrsas_mpt_cmd *cmd; + struct mrsas_softc *sc; + + cmd = (struct mrsas_mpt_cmd *)data; + sc = cmd->sc; + + if (cmd->ccb_ptr == NULL) { + printf("command timeout with NULL ccb\n"); + return; + } + + /* Below callout is dummy entry so that it will be + * cancelled from mrsas_cmd_done(). Now Controller will + * go to OCR/Kill Adapter based on OCR enable/disable + * property of Controller from ocr_thread context. + */ + callout_reset(&cmd->cm_callout, (600000 * hz) / 1000, + mrsas_scsiio_timeout, cmd); + sc->do_timedout_reset = 1; + if(sc->ocr_thread_active) + wakeup(&sc->ocr_chan); +} + +/** + * mrsas_startio: SCSI IO entry point + * input: Adapter instance soft state + * pointer to CAM Control Block + * + * This function is the SCSI IO entry point and it initiates IO processing. + * It copies the IO and depending if the IO is read/write or inquiry, it would + * call mrsas_build_ldio() or mrsas_build_dcdb(), respectively. It returns + * 0 if the command is sent to firmware successfully, otherwise it returns 1. + */ +static int32_t mrsas_startio(struct mrsas_softc *sc, struct cam_sim *sim, + union ccb *ccb) +{ + struct mrsas_mpt_cmd *cmd; + struct ccb_hdr *ccb_h = &(ccb->ccb_h); + struct ccb_scsiio *csio = &(ccb->csio); + MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc; + + if ((csio->cdb_io.cdb_bytes[0]) == SYNCHRONIZE_CACHE){ + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + return(0); + } + + ccb_h->status |= CAM_SIM_QUEUED; + cmd = mrsas_get_mpt_cmd(sc); + + if (!cmd) { + ccb_h->status |= CAM_REQUEUE_REQ; + xpt_done(ccb); + return(0); + } + + if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { + if(ccb_h->flags & CAM_DIR_IN) + cmd->flags |= MRSAS_DIR_IN; + if(ccb_h->flags & CAM_DIR_OUT) + cmd->flags |= MRSAS_DIR_OUT; + } + else + cmd->flags = MRSAS_DIR_NONE; /* no data */ + +/* For FreeBSD 10.0 and higher */ +#if (__FreeBSD_version >= 1000000) +/* + * * XXX We don't yet support physical addresses here. + */ + switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) { + case CAM_DATA_PADDR: + case CAM_DATA_SG_PADDR: + printf("%s: physical addresses not supported\n", + __func__); + mrsas_release_mpt_cmd(cmd); + ccb_h->status = CAM_REQ_INVALID; + ccb_h->status &= ~CAM_SIM_QUEUED; + goto done; + case CAM_DATA_SG: + printf("%s: scatter gather is not supported\n", + __func__); + mrsas_release_mpt_cmd(cmd); + ccb_h->status = CAM_REQ_INVALID; + goto done; + case CAM_DATA_VADDR: + if (csio->dxfer_len > MRSAS_MAX_IO_SIZE) { + mrsas_release_mpt_cmd(cmd); + ccb_h->status = CAM_REQ_TOO_BIG; + goto done; + } + cmd->length = csio->dxfer_len; + if (cmd->length) + cmd->data = csio->data_ptr; + break; + default: + ccb->ccb_h.status = CAM_REQ_INVALID; + goto done; + } +#else + if (!(ccb_h->flags & CAM_DATA_PHYS)) { //Virtual data address + if (!(ccb_h->flags & CAM_SCATTER_VALID)) { + if (csio->dxfer_len > MRSAS_MAX_IO_SIZE) { + mrsas_release_mpt_cmd(cmd); + ccb_h->status = CAM_REQ_TOO_BIG; + goto done; + } + cmd->length = csio->dxfer_len; + if (cmd->length) + cmd->data = csio->data_ptr; + } + else { + mrsas_release_mpt_cmd(cmd); + ccb_h->status = CAM_REQ_INVALID; + goto done; + } + } + else { //Data addresses are physical. + mrsas_release_mpt_cmd(cmd); + ccb_h->status = CAM_REQ_INVALID; + ccb_h->status &= ~CAM_SIM_QUEUED; + goto done; + } +#endif + /* save ccb ptr */ + cmd->ccb_ptr = ccb; + + req_desc = mrsas_get_request_desc(sc, (cmd->index)-1); + if (!req_desc) { + device_printf(sc->mrsas_dev, "Cannot get request_descriptor.\n"); + return (FAIL); + } + memset(req_desc, 0, sizeof(MRSAS_REQUEST_DESCRIPTOR_UNION)); + cmd->request_desc = req_desc; + + if (ccb_h->flags & CAM_CDB_POINTER) + bcopy(csio->cdb_io.cdb_ptr, cmd->io_request->CDB.CDB32, csio->cdb_len); + else + bcopy(csio->cdb_io.cdb_bytes, cmd->io_request->CDB.CDB32, csio->cdb_len); + mtx_lock(&sc->raidmap_lock); + + if (mrsas_ldio_inq(sim, ccb)) { + if (mrsas_build_ldio(sc, cmd, ccb)){ + device_printf(sc->mrsas_dev, "Build LDIO failed.\n"); + mtx_unlock(&sc->raidmap_lock); + return(1); + } + } + else { + if (mrsas_build_dcdb(sc, cmd, ccb, sim)) { + device_printf(sc->mrsas_dev, "Build DCDB failed.\n"); + mtx_unlock(&sc->raidmap_lock); + return(1); + } + } + mtx_unlock(&sc->raidmap_lock); + + if (cmd->flags == MRSAS_DIR_IN) //from device + cmd->io_request->Control |= MPI2_SCSIIO_CONTROL_READ; + else if (cmd->flags == MRSAS_DIR_OUT) //to device + cmd->io_request->Control |= MPI2_SCSIIO_CONTROL_WRITE; + + cmd->io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING; + cmd->io_request->SGLOffset0 = offsetof(MRSAS_RAID_SCSI_IO_REQUEST, SGL)/4; + cmd->io_request->SenseBufferLowAddress = cmd->sense_phys_addr; + cmd->io_request->SenseBufferLength = MRSAS_SCSI_SENSE_BUFFERSIZE; + + req_desc = cmd->request_desc; + req_desc->SCSIIO.SMID = cmd->index; + + /* + * Start timer for IO timeout. Default timeout value is 90 second. + */ + callout_reset(&cmd->cm_callout, (sc->mrsas_io_timeout * hz) / 1000, + mrsas_scsiio_timeout, cmd); + atomic_inc(&sc->fw_outstanding); + + if(atomic_read(&sc->fw_outstanding) > sc->io_cmds_highwater) + sc->io_cmds_highwater++; + + mrsas_fire_cmd(sc, req_desc->addr.u.low, req_desc->addr.u.high); + return(0); + +done: + xpt_done(ccb); + return(0); +} + +/** + * mrsas_ldio_inq: Determines if IO is read/write or inquiry + * input: pointer to CAM Control Block + * + * This function determines if the IO is read/write or inquiry. It returns a + * 1 if the IO is read/write and 0 if it is inquiry. + */ +int mrsas_ldio_inq(struct cam_sim *sim, union ccb *ccb) +{ + struct ccb_scsiio *csio = &(ccb->csio); + + if (cam_sim_bus(sim) == 1) + return(0); + + switch (csio->cdb_io.cdb_bytes[0]) { + case READ_10: + case WRITE_10: + case READ_12: + case WRITE_12: + case READ_6: + case WRITE_6: + case READ_16: + case WRITE_16: + return 1; + default: + return 0; + } +} + +/** + * mrsas_get_mpt_cmd: Get a cmd from free command pool + * input: Adapter instance soft state + * + * This function removes an MPT command from the command free list and + * initializes it. + */ +struct mrsas_mpt_cmd* mrsas_get_mpt_cmd(struct mrsas_softc *sc) +{ + struct mrsas_mpt_cmd *cmd = NULL; + + mtx_lock(&sc->mpt_cmd_pool_lock); + if (!TAILQ_EMPTY(&sc->mrsas_mpt_cmd_list_head)){ + cmd = TAILQ_FIRST(&sc->mrsas_mpt_cmd_list_head); + TAILQ_REMOVE(&sc->mrsas_mpt_cmd_list_head, cmd, next); + } + memset((uint8_t *)cmd->io_request, 0, MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE); + cmd->data = NULL; + cmd->length = 0; + cmd->flags = 0; + cmd->error_code = 0; + cmd->load_balance = 0; + cmd->ccb_ptr = NULL; + mtx_unlock(&sc->mpt_cmd_pool_lock); + + return cmd; +} + +/** + * mrsas_release_mpt_cmd: Return a cmd to free command pool + * input: Command packet for return to free command pool + * + * This function returns an MPT command to the free command list. + */ +void mrsas_release_mpt_cmd(struct mrsas_mpt_cmd *cmd) +{ + struct mrsas_softc *sc = cmd->sc; + + mtx_lock(&sc->mpt_cmd_pool_lock); + cmd->sync_cmd_idx = (u_int32_t)MRSAS_ULONG_MAX; + TAILQ_INSERT_TAIL(&(sc->mrsas_mpt_cmd_list_head), cmd, next); + mtx_unlock(&sc->mpt_cmd_pool_lock); + + return; +} + +/** + * mrsas_get_request_desc: Get request descriptor from array + * input: Adapter instance soft state + * SMID index + * + * This function returns a pointer to the request descriptor. + */ +MRSAS_REQUEST_DESCRIPTOR_UNION * +mrsas_get_request_desc(struct mrsas_softc *sc, u_int16_t index) +{ + u_int8_t *p; + + if (index >= sc->max_fw_cmds) { + device_printf(sc->mrsas_dev, "Invalid SMID (0x%x)request for desc\n", index); + return NULL; + } + p = sc->req_desc + sizeof(MRSAS_REQUEST_DESCRIPTOR_UNION) * index; + + return (MRSAS_REQUEST_DESCRIPTOR_UNION *)p; +} + +/** + * mrsas_build_ldio: Builds an LDIO command + * input: Adapter instance soft state + * Pointer to command packet + * Pointer to CCB + * + * This function builds the LDIO command packet. It returns 0 if the + * command is built successfully, otherwise it returns a 1. + */ +int mrsas_build_ldio(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd, + union ccb *ccb) +{ + struct ccb_hdr *ccb_h = &(ccb->ccb_h); + struct ccb_scsiio *csio = &(ccb->csio); + u_int32_t device_id; + MRSAS_RAID_SCSI_IO_REQUEST *io_request; + + device_id = ccb_h->target_id; + + io_request = cmd->io_request; + io_request->RaidContext.VirtualDiskTgtId = device_id; + io_request->RaidContext.status = 0; + io_request->RaidContext.exStatus = 0; + + /* just the cdb len, other flags zero, and ORed-in later for FP */ + io_request->IoFlags = csio->cdb_len; + + if (mrsas_setup_io(sc, cmd, ccb, device_id, io_request) != SUCCESS) + device_printf(sc->mrsas_dev, "Build ldio or fpio error\n"); + + io_request->DataLength = cmd->length; + + if (mrsas_map_request(sc, cmd) == SUCCESS) { + if (cmd->sge_count > MRSAS_MAX_SGL) { + device_printf(sc->mrsas_dev, "Error: sge_count (0x%x) exceeds" + "max (0x%x) allowed\n", cmd->sge_count, sc->max_num_sge); + return (FAIL); + } + io_request->RaidContext.numSGE = cmd->sge_count; + } + else { + device_printf(sc->mrsas_dev, "Data map/load failed.\n"); + return(FAIL); + } + return(0); +} + +/** + * mrsas_setup_io: Set up data including Fast Path I/O + * input: Adapter instance soft state + * Pointer to command packet + * Pointer to CCB + * + * This function builds the DCDB inquiry command. It returns 0 if the + * command is built successfully, otherwise it returns a 1. + */ +int mrsas_setup_io(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd, + union ccb *ccb, u_int32_t device_id, + MRSAS_RAID_SCSI_IO_REQUEST *io_request) +{ + struct ccb_hdr *ccb_h = &(ccb->ccb_h); + struct ccb_scsiio *csio = &(ccb->csio); + struct IO_REQUEST_INFO io_info; + MR_FW_RAID_MAP_ALL *map_ptr; + u_int8_t fp_possible; + u_int32_t start_lba_hi, start_lba_lo, ld_block_size; + u_int32_t datalength = 0; + + start_lba_lo = 0; + start_lba_hi = 0; + fp_possible = 0; + + /* + * READ_6 (0x08) or WRITE_6 (0x0A) cdb + */ + if (csio->cdb_len == 6) { + datalength = (u_int32_t)csio->cdb_io.cdb_bytes[4]; + start_lba_lo = ((u_int32_t) csio->cdb_io.cdb_bytes[1] << 16) | + ((u_int32_t) csio->cdb_io.cdb_bytes[2] << 8) | + (u_int32_t) csio->cdb_io.cdb_bytes[3]; + start_lba_lo &= 0x1FFFFF; + } + /* + * READ_10 (0x28) or WRITE_6 (0x2A) cdb + */ + else if (csio->cdb_len == 10) { + datalength = (u_int32_t)csio->cdb_io.cdb_bytes[8] | + ((u_int32_t)csio->cdb_io.cdb_bytes[7] << 8); + start_lba_lo = ((u_int32_t) csio->cdb_io.cdb_bytes[2] << 24) | + ((u_int32_t) csio->cdb_io.cdb_bytes[3] << 16) | + (u_int32_t) csio->cdb_io.cdb_bytes[4] << 8 | + ((u_int32_t) csio->cdb_io.cdb_bytes[5]); + } + /* + * READ_12 (0xA8) or WRITE_12 (0xAA) cdb + */ + else if (csio->cdb_len == 12) { + datalength = (u_int32_t)csio->cdb_io.cdb_bytes[6] << 24 | + ((u_int32_t)csio->cdb_io.cdb_bytes[7] << 16) | + ((u_int32_t)csio->cdb_io.cdb_bytes[8] << 8) | + ((u_int32_t)csio->cdb_io.cdb_bytes[9]); + start_lba_lo = ((u_int32_t) csio->cdb_io.cdb_bytes[2] << 24) | + ((u_int32_t) csio->cdb_io.cdb_bytes[3] << 16) | + (u_int32_t) csio->cdb_io.cdb_bytes[4] << 8 | + ((u_int32_t) csio->cdb_io.cdb_bytes[5]); + } + /* + * READ_16 (0x88) or WRITE_16 (0xx8A) cdb + */ + else if (csio->cdb_len == 16) { + datalength = (u_int32_t)csio->cdb_io.cdb_bytes[10] << 24 | + ((u_int32_t)csio->cdb_io.cdb_bytes[11] << 16) | + ((u_int32_t)csio->cdb_io.cdb_bytes[12] << 8) | + ((u_int32_t)csio->cdb_io.cdb_bytes[13]); + start_lba_lo = ((u_int32_t) csio->cdb_io.cdb_bytes[6] << 24) | + ((u_int32_t) csio->cdb_io.cdb_bytes[7] << 16) | + (u_int32_t) csio->cdb_io.cdb_bytes[8] << 8 | + ((u_int32_t) csio->cdb_io.cdb_bytes[9]); + start_lba_hi = ((u_int32_t) csio->cdb_io.cdb_bytes[2] << 24) | + ((u_int32_t) csio->cdb_io.cdb_bytes[3] << 16) | + (u_int32_t) csio->cdb_io.cdb_bytes[4] << 8 | + ((u_int32_t) csio->cdb_io.cdb_bytes[5]); + } + + memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO)); + io_info.ldStartBlock = ((u_int64_t)start_lba_hi << 32) | start_lba_lo; + io_info.numBlocks = datalength; + io_info.ldTgtId = device_id; + + switch (ccb_h->flags & CAM_DIR_MASK) { + case CAM_DIR_IN: + io_info.isRead = 1; + break; + case CAM_DIR_OUT: + io_info.isRead = 0; + break; + case CAM_DIR_NONE: + default: + mrsas_dprint(sc, MRSAS_TRACE, "From %s : DMA Flag is %d \n", __func__, ccb_h->flags & CAM_DIR_MASK); + break; + } + + map_ptr = sc->raidmap_mem[(sc->map_id & 1)]; + ld_block_size = MR_LdBlockSizeGet(device_id, map_ptr, sc); + + if ((MR_TargetIdToLdGet(device_id, map_ptr) >= MAX_LOGICAL_DRIVES) || + (!sc->fast_path_io)) { + io_request->RaidContext.regLockFlags = 0; + fp_possible = 0; + } + else + { + if (MR_BuildRaidContext(sc, &io_info, &io_request->RaidContext, map_ptr)) + fp_possible = io_info.fpOkForIo; + } + + if (fp_possible) { + mrsas_set_pd_lba(io_request, csio->cdb_len, &io_info, ccb, map_ptr, + start_lba_lo, ld_block_size); + io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; + cmd->request_desc->SCSIIO.RequestFlags = + (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY + << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) { + if (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED) + cmd->request_desc->SCSIIO.RequestFlags = (MRSAS_REQ_DESCRIPT_FLAGS_NO_LOCK << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + io_request->RaidContext.Type = MPI2_TYPE_CUDA; + io_request->RaidContext.nseg = 0x1; + io_request->IoFlags |= MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH; + io_request->RaidContext.regLockFlags |= (MR_RL_FLAGS_GRANT_DESTINATION_CUDA | MR_RL_FLAGS_SEQ_NUM_ENABLE); + } + if ((sc->load_balance_info[device_id].loadBalanceFlag) && (io_info.isRead)) { + io_info.devHandle = mrsas_get_updated_dev_handle(&sc->load_balance_info[device_id], + &io_info); + cmd->load_balance = MRSAS_LOAD_BALANCE_FLAG; + } + else + cmd->load_balance = 0; + cmd->request_desc->SCSIIO.DevHandle = io_info.devHandle; + io_request->DevHandle = io_info.devHandle; + } + else { + /* Not FP IO */ + io_request->RaidContext.timeoutValue = map_ptr->raidMap.fpPdIoTimeoutSec; + cmd->request_desc->SCSIIO.RequestFlags = + (MRSAS_REQ_DESCRIPT_FLAGS_LD_IO << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) { + if (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED) + cmd->request_desc->SCSIIO.RequestFlags = (MRSAS_REQ_DESCRIPT_FLAGS_NO_LOCK << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + io_request->RaidContext.Type = MPI2_TYPE_CUDA; + io_request->RaidContext.regLockFlags |= (MR_RL_FLAGS_GRANT_DESTINATION_CPU0 | MR_RL_FLAGS_SEQ_NUM_ENABLE); + io_request->RaidContext.nseg = 0x1; + } + io_request->Function = MRSAS_MPI2_FUNCTION_LD_IO_REQUEST; + io_request->DevHandle = device_id; + } + return(0); +} + +/** + * mrsas_build_dcdb: Builds an DCDB command + * input: Adapter instance soft state + * Pointer to command packet + * Pointer to CCB + * + * This function builds the DCDB inquiry command. It returns 0 if the + * command is built successfully, otherwise it returns a 1. + */ +int mrsas_build_dcdb(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd, + union ccb *ccb, struct cam_sim *sim) +{ + struct ccb_hdr *ccb_h = &(ccb->ccb_h); + u_int32_t device_id; + MR_FW_RAID_MAP_ALL *map_ptr; + MRSAS_RAID_SCSI_IO_REQUEST *io_request; + + io_request = cmd->io_request; + device_id = ccb_h->target_id; + map_ptr = sc->raidmap_mem[(sc->map_id & 1)]; + + /* Check if this is for system PD */ + if (cam_sim_bus(sim) == 1 && + sc->pd_list[device_id].driveState == MR_PD_STATE_SYSTEM) { + io_request->Function = 0; + io_request->DevHandle = map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; + io_request->RaidContext.timeoutValue = map_ptr->raidMap.fpPdIoTimeoutSec; + io_request->RaidContext.regLockFlags = 0; + io_request->RaidContext.regLockRowLBA = 0; + io_request->RaidContext.regLockLength = 0; + io_request->RaidContext.RAIDFlags = MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD << + MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT; + if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) + io_request->IoFlags |= MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH; + cmd->request_desc->SCSIIO.RequestFlags = + (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << + MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + cmd->request_desc->SCSIIO.DevHandle = + map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; + } + else { + io_request->Function = MRSAS_MPI2_FUNCTION_LD_IO_REQUEST; + io_request->DevHandle = device_id; + cmd->request_desc->SCSIIO.RequestFlags = + (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + } + + io_request->RaidContext.VirtualDiskTgtId = device_id; + io_request->LUN[1] = ccb_h->target_lun & 0xF; + io_request->DataLength = cmd->length; + + if (mrsas_map_request(sc, cmd) == SUCCESS) { + if (cmd->sge_count > sc->max_num_sge) { + device_printf(sc->mrsas_dev, "Error: sge_count (0x%x) exceeds" + "max (0x%x) allowed\n", cmd->sge_count, sc->max_num_sge); + return (1); + } + io_request->RaidContext.numSGE = cmd->sge_count; + } + else { + device_printf(sc->mrsas_dev, "Data map/load failed.\n"); + return(1); + } + return(0); +} + +/** + * mrsas_map_request: Map and load data + * input: Adapter instance soft state + * Pointer to command packet + * + * For data from OS, map and load the data buffer into bus space. The + * SG list is built in the callback. If the bus dmamap load is not + * successful, cmd->error_code will contain the error code and a 1 is + * returned. + */ +int mrsas_map_request(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd) +{ + u_int32_t retcode = 0; + struct cam_sim *sim; + int flag = BUS_DMA_NOWAIT; + + sim = xpt_path_sim(cmd->ccb_ptr->ccb_h.path); + + if (cmd->data != NULL) { + mtx_lock(&sc->io_lock); + /* Map data buffer into bus space */ + retcode = bus_dmamap_load(sc->data_tag, cmd->data_dmamap, cmd->data, + cmd->length, mrsas_data_load_cb, cmd, flag); + mtx_unlock(&sc->io_lock); + if (retcode) + device_printf(sc->mrsas_dev, "bus_dmamap_load(): retcode = %d\n", retcode); + if (retcode == EINPROGRESS) { + device_printf(sc->mrsas_dev, "request load in progress\n"); + mrsas_freeze_simq(cmd, sim); + } + } + if (cmd->error_code) + return(1); + return(retcode); +} + +/** + * mrsas_unmap_request: Unmap and unload data + * input: Adapter instance soft state + * Pointer to command packet + * + * This function unmaps and unloads data from OS. + */ +void mrsas_unmap_request(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd) +{ + if (cmd->data != NULL) { + if (cmd->flags & MRSAS_DIR_IN) + bus_dmamap_sync(sc->data_tag, cmd->data_dmamap, BUS_DMASYNC_POSTREAD); + if (cmd->flags & MRSAS_DIR_OUT) + bus_dmamap_sync(sc->data_tag, cmd->data_dmamap, BUS_DMASYNC_POSTWRITE); + mtx_lock(&sc->io_lock); + bus_dmamap_unload(sc->data_tag, cmd->data_dmamap); + mtx_unlock(&sc->io_lock); + } +} + +/** + * mrsas_data_load_cb: Callback entry point + * input: Pointer to command packet as argument + * Pointer to segment + * Number of segments + * Error + * + * This is the callback function of the bus dma map load. It builds + * the SG list. + */ +static void +mrsas_data_load_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + struct mrsas_mpt_cmd *cmd = (struct mrsas_mpt_cmd *)arg; + struct mrsas_softc *sc = cmd->sc; + MRSAS_RAID_SCSI_IO_REQUEST *io_request; + pMpi25IeeeSgeChain64_t sgl_ptr; + int i=0, sg_processed=0; + + if (error) + { + cmd->error_code = error; + device_printf(sc->mrsas_dev, "mrsas_data_load_cb: error=%d\n", error); + if (error == EFBIG) { + cmd->ccb_ptr->ccb_h.status = CAM_REQ_TOO_BIG; + return; + } + } + + if (cmd->flags & MRSAS_DIR_IN) + bus_dmamap_sync(cmd->sc->data_tag, cmd->data_dmamap, + BUS_DMASYNC_PREREAD); + if (cmd->flags & MRSAS_DIR_OUT) + bus_dmamap_sync(cmd->sc->data_tag, cmd->data_dmamap, + BUS_DMASYNC_PREWRITE); + if (nseg > sc->max_num_sge) { + device_printf(sc->mrsas_dev, "SGE count is too large or 0.\n"); + return; + } + + io_request = cmd->io_request; + sgl_ptr = (pMpi25IeeeSgeChain64_t)&io_request->SGL; + + if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) { + pMpi25IeeeSgeChain64_t sgl_ptr_end = sgl_ptr; + sgl_ptr_end += sc->max_sge_in_main_msg - 1; + sgl_ptr_end->Flags = 0; + } + + if (nseg != 0) { + for (i=0; i < nseg; i++) { + sgl_ptr->Address = segs[i].ds_addr; + sgl_ptr->Length = segs[i].ds_len; + sgl_ptr->Flags = 0; + if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) { + if (i == nseg - 1) + sgl_ptr->Flags = IEEE_SGE_FLAGS_END_OF_LIST; + } + sgl_ptr++; + sg_processed = i + 1; + /* + * Prepare chain element + */ + if ((sg_processed == (sc->max_sge_in_main_msg - 1)) && + (nseg > sc->max_sge_in_main_msg)) { + pMpi25IeeeSgeChain64_t sg_chain; + if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) { + if ((cmd->io_request->IoFlags & MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) + != MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) + cmd->io_request->ChainOffset = sc->chain_offset_io_request; + else + cmd->io_request->ChainOffset = 0; + } else + cmd->io_request->ChainOffset = sc->chain_offset_io_request; + sg_chain = sgl_ptr; + if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) + sg_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT; + else + sg_chain->Flags = (IEEE_SGE_FLAGS_CHAIN_ELEMENT | MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR); + sg_chain->Length = (sizeof(MPI2_SGE_IO_UNION) * (nseg - sg_processed)); + sg_chain->Address = cmd->chain_frame_phys_addr; + sgl_ptr = (pMpi25IeeeSgeChain64_t)cmd->chain_frame; + } + } + } + cmd->sge_count = nseg; +} + +/** + * mrsas_freeze_simq: Freeze SIM queue + * input: Pointer to command packet + * Pointer to SIM + * + * This function freezes the sim queue. + */ +static void mrsas_freeze_simq(struct mrsas_mpt_cmd *cmd, struct cam_sim *sim) +{ + union ccb *ccb = (union ccb *)(cmd->ccb_ptr); + + xpt_freeze_simq(sim, 1); + ccb->ccb_h.status |= CAM_RELEASE_SIMQ; + ccb->ccb_h.status |= CAM_REQUEUE_REQ; +} + +void mrsas_xpt_freeze(struct mrsas_softc *sc) { + xpt_freeze_simq(sc->sim_0, 1); + xpt_freeze_simq(sc->sim_1, 1); +} + +void mrsas_xpt_release(struct mrsas_softc *sc) { + xpt_release_simq(sc->sim_0, 1); + xpt_release_simq(sc->sim_1, 1); +} + +/** + * mrsas_cmd_done: Perform remaining command completion + * input: Adapter instance soft state + * Pointer to command packet + * + * This function calls ummap request and releases the MPT command. + */ +void mrsas_cmd_done(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd) +{ + callout_stop(&cmd->cm_callout); + mrsas_unmap_request(sc, cmd); + mtx_lock(&sc->sim_lock); + xpt_done(cmd->ccb_ptr); + cmd->ccb_ptr = NULL; + mtx_unlock(&sc->sim_lock); + mrsas_release_mpt_cmd(cmd); +} + +/** + * mrsas_poll: Polling entry point + * input: Pointer to SIM + * + * This is currently a stub function. + */ +static void mrsas_poll(struct cam_sim *sim) +{ + struct mrsas_softc *sc = (struct mrsas_softc *)cam_sim_softc(sim); + mrsas_isr((void *) sc); +} + +/* + * mrsas_bus_scan: Perform bus scan + * input: Adapter instance soft state + * + * This mrsas_bus_scan function is needed for FreeBSD 7.x. Also, it should + * not be called in FreeBSD 8.x and later versions, where the bus scan is + * automatic. + */ +int mrsas_bus_scan(struct mrsas_softc *sc) +{ + union ccb *ccb_0; + union ccb *ccb_1; + + mtx_lock(&sc->sim_lock); + if ((ccb_0 = xpt_alloc_ccb()) == NULL) { + mtx_unlock(&sc->sim_lock); + return(ENOMEM); + } + + if ((ccb_1 = xpt_alloc_ccb()) == NULL) { + xpt_free_ccb(ccb_0); + mtx_unlock(&sc->sim_lock); + return(ENOMEM); + } + + if (xpt_create_path(&ccb_0->ccb_h.path, xpt_periph, cam_sim_path(sc->sim_0), + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP){ + xpt_free_ccb(ccb_0); + xpt_free_ccb(ccb_1); + mtx_unlock(&sc->sim_lock); + return(EIO); + } + + if (xpt_create_path(&ccb_1->ccb_h.path, xpt_periph, cam_sim_path(sc->sim_1), + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP){ + xpt_free_ccb(ccb_0); + xpt_free_ccb(ccb_1); + mtx_unlock(&sc->sim_lock); + return(EIO); + } + + xpt_rescan(ccb_0); + xpt_rescan(ccb_1); + mtx_unlock(&sc->sim_lock); + + return(0); +} + +/* + * mrsas_bus_scan_sim: Perform bus scan per SIM + * input: Adapter instance soft state + * This function will be called from Event handler + * on LD creation/deletion, JBOD on/off. + */ +int mrsas_bus_scan_sim(struct mrsas_softc *sc, struct cam_sim *sim) +{ + union ccb *ccb; + + mtx_lock(&sc->sim_lock); + if ((ccb = xpt_alloc_ccb()) == NULL) { + mtx_unlock(&sc->sim_lock); + return(ENOMEM); + } + if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(sim), + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP){ + xpt_free_ccb(ccb); + mtx_unlock(&sc->sim_lock); + return(EIO); + } + xpt_rescan(ccb); + mtx_unlock(&sc->sim_lock); + + return(0); +} diff --git a/sys/dev/mrsas/mrsas_fp.c b/sys/dev/mrsas/mrsas_fp.c new file mode 100644 index 0000000000000..69a996f782410 --- /dev/null +++ b/sys/dev/mrsas/mrsas_fp.c @@ -0,0 +1,1451 @@ +/* + * Copyright (c) 2014, LSI Corp. + * All rights reserved. + * Author: Marian Choy + * Support: freebsdraid@lsi.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of the <ORGANIZATION> nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Send feedback to: <megaraidfbsd@lsi.com> + * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035 + * ATTN: MegaRaid FreeBSD + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <dev/mrsas/mrsas.h> + +#include <cam/cam.h> +#include <cam/cam_ccb.h> +#include <cam/cam_sim.h> +#include <cam/cam_xpt_sim.h> +#include <cam/cam_debug.h> +#include <cam/cam_periph.h> +#include <cam/cam_xpt_periph.h> + + +/* + * Function prototypes + */ +u_int8_t MR_ValidateMapInfo(struct mrsas_softc *sc); +u_int8_t mrsas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm, + u_int64_t block, u_int32_t count); +u_int8_t MR_BuildRaidContext(struct mrsas_softc *sc, + struct IO_REQUEST_INFO *io_info, + RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map); +u_int8_t MR_GetPhyParams(struct mrsas_softc *sc, u_int32_t ld, + u_int64_t stripRow, u_int16_t stripRef, struct IO_REQUEST_INFO *io_info, + RAID_CONTEXT *pRAID_Context, + MR_FW_RAID_MAP_ALL *map); +u_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map); +u_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map); +u_int16_t MR_GetLDTgtId(u_int32_t ld, MR_FW_RAID_MAP_ALL *map); +u_int16_t mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo, + struct IO_REQUEST_INFO *io_info); +u_int32_t mega_mod64(u_int64_t dividend, u_int32_t divisor); +u_int32_t MR_GetSpanBlock(u_int32_t ld, u_int64_t row, u_int64_t *span_blk, + MR_FW_RAID_MAP_ALL *map, int *div_error); +u_int64_t mega_div64_32(u_int64_t dividend, u_int32_t divisor); +void mrsas_update_load_balance_params(MR_FW_RAID_MAP_ALL *map, + PLD_LOAD_BALANCE_INFO lbInfo); +void mrsas_set_pd_lba(MRSAS_RAID_SCSI_IO_REQUEST *io_request, + u_int8_t cdb_len, struct IO_REQUEST_INFO *io_info, union ccb *ccb, + MR_FW_RAID_MAP_ALL *local_map_ptr, u_int32_t ref_tag, + u_int32_t ld_block_size); +static u_int16_t MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span, + MR_FW_RAID_MAP_ALL *map); +static u_int16_t MR_PdDevHandleGet(u_int32_t pd, MR_FW_RAID_MAP_ALL *map); +static u_int16_t MR_ArPdGet(u_int32_t ar, u_int32_t arm, + MR_FW_RAID_MAP_ALL *map); +static MR_LD_SPAN *MR_LdSpanPtrGet(u_int32_t ld, u_int32_t span, + MR_FW_RAID_MAP_ALL *map); +static u_int8_t MR_LdDataArmGet(u_int32_t ld, u_int32_t armIdx, + MR_FW_RAID_MAP_ALL *map); +static MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u_int32_t ld, + MR_FW_RAID_MAP_ALL *map); +MR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map); + +/* + * Spanset related function prototypes + * Added for PRL11 configuration (Uneven span support) + */ +void mr_update_span_set(MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo); +static u_int8_t mr_spanset_get_phy_params(struct mrsas_softc *sc, u_int32_t ld, + u_int64_t stripRow, u_int16_t stripRef, struct IO_REQUEST_INFO *io_info, + RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map); +static u_int64_t get_row_from_strip(struct mrsas_softc *sc, u_int32_t ld, + u_int64_t strip, MR_FW_RAID_MAP_ALL *map); +static u_int32_t mr_spanset_get_span_block(struct mrsas_softc *sc, + u_int32_t ld, u_int64_t row, u_int64_t *span_blk, + MR_FW_RAID_MAP_ALL *map, int *div_error); +static u_int8_t get_arm(struct mrsas_softc *sc, u_int32_t ld, u_int8_t span, + u_int64_t stripe, MR_FW_RAID_MAP_ALL *map); + + +/* + * Spanset related defines + * Added for PRL11 configuration(Uneven span support) + */ +#define SPAN_ROW_SIZE(map, ld, index_) MR_LdSpanPtrGet(ld, index_, map)->spanRowSize +#define SPAN_ROW_DATA_SIZE(map_, ld, index_) MR_LdSpanPtrGet(ld, index_, map)->spanRowDataSize +#define SPAN_INVALID 0xff +#define SPAN_DEBUG 0 + +/* + * Related Defines + */ + +typedef u_int64_t REGION_KEY; +typedef u_int32_t REGION_LEN; + +#define MR_LD_STATE_OPTIMAL 3 +#define FALSE 0 +#define TRUE 1 + + +/* + * Related Macros + */ + +#define ABS_DIFF(a,b) ( ((a) > (b)) ? ((a) - (b)) : ((b) - (a)) ) + +#define swap32(x) \ + ((unsigned int)( \ + (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \ + (((unsigned int)(x) & (unsigned int)0x0000ff00UL) << 8) | \ + (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >> 8) | \ + (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) )) + + +/* + * In-line functions for mod and divide of 64-bit dividend and 32-bit divisor. + * Assumes a check for a divisor of zero is not possible. + * + * @param dividend : Dividend + * @param divisor : Divisor + * @return remainder + */ + +#define mega_mod64(dividend, divisor) ({ \ +int remainder; \ +remainder = ((u_int64_t) (dividend)) % (u_int32_t) (divisor); \ +remainder;}) + +#define mega_div64_32(dividend, divisor) ({ \ +int quotient; \ +quotient = ((u_int64_t) (dividend)) / (u_int32_t) (divisor); \ +quotient;}) + + +/* + * Various RAID map access functions. These functions access the various + * parts of the RAID map and returns the appropriate parameters. + */ + +MR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map) +{ + return (&map->raidMap.ldSpanMap[ld].ldRaid); +} + +u_int16_t MR_GetLDTgtId(u_int32_t ld, MR_FW_RAID_MAP_ALL *map) +{ + return (map->raidMap.ldSpanMap[ld].ldRaid.targetId); +} + +static u_int16_t MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span, MR_FW_RAID_MAP_ALL *map) +{ + return map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef; +} + +static u_int8_t MR_LdDataArmGet(u_int32_t ld, u_int32_t armIdx, MR_FW_RAID_MAP_ALL *map) +{ + return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx]; +} + +static u_int16_t MR_PdDevHandleGet(u_int32_t pd, MR_FW_RAID_MAP_ALL *map) +{ + return map->raidMap.devHndlInfo[pd].curDevHdl; +} + +static u_int16_t MR_ArPdGet(u_int32_t ar, u_int32_t arm, MR_FW_RAID_MAP_ALL *map) +{ + return map->raidMap.arMapInfo[ar].pd[arm]; +} + +static MR_LD_SPAN *MR_LdSpanPtrGet(u_int32_t ld, u_int32_t span, MR_FW_RAID_MAP_ALL *map) +{ + return &map->raidMap.ldSpanMap[ld].spanBlock[span].span; +} + +static MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map) +{ + return &map->raidMap.ldSpanMap[ld].spanBlock[0]; +} + +u_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map) +{ + return map->raidMap.ldTgtIdToLd[ldTgtId]; +} + +u_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map) +{ + MR_LD_RAID *raid; + u_int32_t ld, ldBlockSize = MRSAS_SCSIBLOCKSIZE; + + ld = MR_TargetIdToLdGet(ldTgtId, map); + + /* + * Check if logical drive was removed. + */ + if (ld >= MAX_LOGICAL_DRIVES) + return ldBlockSize; + + raid = MR_LdRaidGet(ld, map); + ldBlockSize = raid->logicalBlockLength; + if (!ldBlockSize) + ldBlockSize = MRSAS_SCSIBLOCKSIZE; + + return ldBlockSize; +} + +/** + * MR_ValidateMapInfo: Validate RAID map + * input: Adapter instance soft state + * + * This function checks and validates the loaded RAID map. It returns 0 if + * successful, and 1 otherwise. + */ +u_int8_t MR_ValidateMapInfo(struct mrsas_softc *sc) +{ + if (!sc) { + return 1; + } + uint32_t total_map_sz; + MR_FW_RAID_MAP_ALL *map = sc->raidmap_mem[(sc->map_id & 1)]; + MR_FW_RAID_MAP *pFwRaidMap = &map->raidMap; + PLD_SPAN_INFO ldSpanInfo = (PLD_SPAN_INFO) &sc->log_to_span; + + total_map_sz = (sizeof(MR_FW_RAID_MAP) - sizeof(MR_LD_SPAN_MAP) + + (sizeof(MR_LD_SPAN_MAP) * pFwRaidMap->ldCount)); + + if (pFwRaidMap->totalSize != total_map_sz) { + device_printf(sc->mrsas_dev, "map size %x not matching ld count\n", total_map_sz); + device_printf(sc->mrsas_dev, "span map= %x\n", (unsigned int)sizeof(MR_LD_SPAN_MAP)); + device_printf(sc->mrsas_dev, "pFwRaidMap->totalSize=%x\n", pFwRaidMap->totalSize); + return 1; + } + + if (sc->UnevenSpanSupport) { + mr_update_span_set(map, ldSpanInfo); + } + + mrsas_update_load_balance_params(map, sc->load_balance_info); + + return 0; +} + +/* + * ****************************************************************************** + * + * Function to print info about span set created in driver from FW raid map + * + * Inputs : + * map - LD map + * ldSpanInfo - ldSpanInfo per HBA instance + * + * + * */ +#if SPAN_DEBUG +static int getSpanInfo(MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo) +{ + + u_int8_t span; + u_int32_t element; + MR_LD_RAID *raid; + LD_SPAN_SET *span_set; + MR_QUAD_ELEMENT *quad; + int ldCount; + u_int16_t ld; + + for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) + { + ld = MR_TargetIdToLdGet(ldCount, map); + if (ld >= MAX_LOGICAL_DRIVES) { + continue; + } + raid = MR_LdRaidGet(ld, map); + printf("LD %x: span_depth=%x\n", ld, raid->spanDepth); + for (span=0; span<raid->spanDepth; span++) + printf("Span=%x, number of quads=%x\n", span, + map->raidMap.ldSpanMap[ld].spanBlock[span]. + block_span_info.noElements); + for (element=0; element < MAX_QUAD_DEPTH; element++) { + span_set = &(ldSpanInfo[ld].span_set[element]); + if (span_set->span_row_data_width == 0) break; + + printf(" Span Set %x: width=%x, diff=%x\n", element, + (unsigned int)span_set->span_row_data_width, + (unsigned int)span_set->diff); + printf(" logical LBA start=0x%08lx, end=0x%08lx\n", + (long unsigned int)span_set->log_start_lba, + (long unsigned int)span_set->log_end_lba); + printf(" span row start=0x%08lx, end=0x%08lx\n", + (long unsigned int)span_set->span_row_start, + (long unsigned int)span_set->span_row_end); + printf(" data row start=0x%08lx, end=0x%08lx\n", + (long unsigned int)span_set->data_row_start, + (long unsigned int)span_set->data_row_end); + printf(" data strip start=0x%08lx, end=0x%08lx\n", + (long unsigned int)span_set->data_strip_start, + (long unsigned int)span_set->data_strip_end); + + for (span=0; span<raid->spanDepth; span++) { + if (map->raidMap.ldSpanMap[ld].spanBlock[span]. + block_span_info.noElements >=element+1){ + quad = &map->raidMap.ldSpanMap[ld]. + spanBlock[span].block_span_info. + quad[element]; + printf(" Span=%x, Quad=%x, diff=%x\n", span, + element, quad->diff); + printf(" offset_in_span=0x%08lx\n", + (long unsigned int)quad->offsetInSpan); + printf(" logical start=0x%08lx, end=0x%08lx\n", + (long unsigned int)quad->logStart, + (long unsigned int)quad->logEnd); + } + } + } + } + return 0; +} +#endif +/* +****************************************************************************** +* +* This routine calculates the Span block for given row using spanset. +* +* Inputs : +* instance - HBA instance +* ld - Logical drive number +* row - Row number +* map - LD map +* +* Outputs : +* +* span - Span number +* block - Absolute Block number in the physical disk +* div_error - Devide error code. +*/ + +u_int32_t mr_spanset_get_span_block(struct mrsas_softc *sc, u_int32_t ld, u_int64_t row, + u_int64_t *span_blk, MR_FW_RAID_MAP_ALL *map, int *div_error) +{ + MR_LD_RAID *raid = MR_LdRaidGet(ld, map); + LD_SPAN_SET *span_set; + MR_QUAD_ELEMENT *quad; + u_int32_t span, info; + PLD_SPAN_INFO ldSpanInfo = sc->log_to_span; + + for (info=0; info < MAX_QUAD_DEPTH; info++) { + span_set = &(ldSpanInfo[ld].span_set[info]); + + if (span_set->span_row_data_width == 0) break; + if (row > span_set->data_row_end) continue; + + for (span=0; span<raid->spanDepth; span++) + if (map->raidMap.ldSpanMap[ld].spanBlock[span]. + block_span_info.noElements >= info+1) { + quad = &map->raidMap.ldSpanMap[ld]. + spanBlock[span]. + block_span_info.quad[info]; + if (quad->diff == 0) { + *div_error = 1; + return span; + } + if ( quad->logStart <= row && + row <= quad->logEnd && + (mega_mod64(row - quad->logStart, + quad->diff)) == 0 ) { + if (span_blk != NULL) { + u_int64_t blk; + blk = mega_div64_32 + ((row - quad->logStart), + quad->diff); + blk = (blk + quad->offsetInSpan) + << raid->stripeShift; + *span_blk = blk; + } + return span; + } + } + } + return SPAN_INVALID; +} + +/* +****************************************************************************** +* +* This routine calculates the row for given strip using spanset. +* +* Inputs : +* instance - HBA instance +* ld - Logical drive number +* Strip - Strip +* map - LD map +* +* Outputs : +* +* row - row associated with strip +*/ + +static u_int64_t get_row_from_strip(struct mrsas_softc *sc, + u_int32_t ld, u_int64_t strip, MR_FW_RAID_MAP_ALL *map) +{ + MR_LD_RAID *raid = MR_LdRaidGet(ld, map); + LD_SPAN_SET *span_set; + PLD_SPAN_INFO ldSpanInfo = sc->log_to_span; + u_int32_t info, strip_offset, span, span_offset; + u_int64_t span_set_Strip, span_set_Row; + + for (info=0; info < MAX_QUAD_DEPTH; info++) { + span_set = &(ldSpanInfo[ld].span_set[info]); + + if (span_set->span_row_data_width == 0) break; + if (strip > span_set->data_strip_end) continue; + + span_set_Strip = strip - span_set->data_strip_start; + strip_offset = mega_mod64(span_set_Strip, + span_set->span_row_data_width); + span_set_Row = mega_div64_32(span_set_Strip, + span_set->span_row_data_width) * span_set->diff; + for (span=0,span_offset=0; span<raid->spanDepth; span++) + if (map->raidMap.ldSpanMap[ld].spanBlock[span]. + block_span_info.noElements >=info+1) { + if (strip_offset >= + span_set->strip_offset[span]) + span_offset++; + else + break; + } + mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : Strip 0x%llx, span_set_Strip 0x%llx, span_set_Row 0x%llx " + "data width 0x%llx span offset 0x%llx\n", (unsigned long long)strip, + (unsigned long long)span_set_Strip, + (unsigned long long)span_set_Row, + (unsigned long long)span_set->span_row_data_width, (unsigned long long)span_offset); + mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : For strip 0x%llx row is 0x%llx\n", (unsigned long long)strip, + (unsigned long long) span_set->data_row_start + + (unsigned long long) span_set_Row + (span_offset - 1)); + return (span_set->data_row_start + span_set_Row + (span_offset - 1)); + } + return -1LLU; +} + + +/* +****************************************************************************** +* +* This routine calculates the Start Strip for given row using spanset. +* +* Inputs : +* instance - HBA instance +* ld - Logical drive number +* row - Row number +* map - LD map +* +* Outputs : +* +* Strip - Start strip associated with row +*/ + +static u_int64_t get_strip_from_row(struct mrsas_softc *sc, + u_int32_t ld, u_int64_t row, MR_FW_RAID_MAP_ALL *map) +{ + MR_LD_RAID *raid = MR_LdRaidGet(ld, map); + LD_SPAN_SET *span_set; + MR_QUAD_ELEMENT *quad; + PLD_SPAN_INFO ldSpanInfo = sc->log_to_span; + u_int32_t span, info; + u_int64_t strip; + + for (info=0; info<MAX_QUAD_DEPTH; info++) { + span_set = &(ldSpanInfo[ld].span_set[info]); + + if (span_set->span_row_data_width == 0) break; + if (row > span_set->data_row_end) continue; + + for (span=0; span<raid->spanDepth; span++) + if (map->raidMap.ldSpanMap[ld].spanBlock[span]. + block_span_info.noElements >=info+1) { + quad = &map->raidMap.ldSpanMap[ld]. + spanBlock[span].block_span_info.quad[info]; + if ( quad->logStart <= row && + row <= quad->logEnd && + mega_mod64((row - quad->logStart), + quad->diff) == 0 ) { + strip = mega_div64_32 + (((row - span_set->data_row_start) + - quad->logStart), + quad->diff); + strip *= span_set->span_row_data_width; + strip += span_set->data_strip_start; + strip += span_set->strip_offset[span]; + return strip; + } + } + } + mrsas_dprint(sc, MRSAS_PRL11,"LSI Debug - get_strip_from_row: returns invalid " + "strip for ld=%x, row=%lx\n", ld, (long unsigned int)row); + return -1; +} + +/* +****************************************************************************** +* +* This routine calculates the Physical Arm for given strip using spanset. +* +* Inputs : +* instance - HBA instance +* ld - Logical drive number +* strip - Strip +* map - LD map +* +* Outputs : +* +* Phys Arm - Phys Arm associated with strip +*/ + +static u_int32_t get_arm_from_strip(struct mrsas_softc *sc, + u_int32_t ld, u_int64_t strip, MR_FW_RAID_MAP_ALL *map) +{ + MR_LD_RAID *raid = MR_LdRaidGet(ld, map); + LD_SPAN_SET *span_set; + PLD_SPAN_INFO ldSpanInfo = sc->log_to_span; + u_int32_t info, strip_offset, span, span_offset; + + for (info=0; info<MAX_QUAD_DEPTH; info++) { + span_set = &(ldSpanInfo[ld].span_set[info]); + + if (span_set->span_row_data_width == 0) break; + if (strip > span_set->data_strip_end) continue; + + strip_offset = (u_int32_t)mega_mod64 + ((strip - span_set->data_strip_start), + span_set->span_row_data_width); + + for (span=0,span_offset=0; span<raid->spanDepth; span++) + if (map->raidMap.ldSpanMap[ld].spanBlock[span]. + block_span_info.noElements >=info+1) { + if (strip_offset >= + span_set->strip_offset[span]) + span_offset = + span_set->strip_offset[span]; + else + break; + } + mrsas_dprint(sc, MRSAS_PRL11, "LSI PRL11: get_arm_from_strip: " + " for ld=0x%x strip=0x%lx arm is 0x%x\n", ld, + (long unsigned int)strip, (strip_offset - span_offset)); + return (strip_offset - span_offset); + } + + mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: - get_arm_from_strip: returns invalid arm" + " for ld=%x strip=%lx\n", ld, (long unsigned int)strip); + + return -1; +} + + +/* This Function will return Phys arm */ +u_int8_t get_arm(struct mrsas_softc *sc, u_int32_t ld, u_int8_t span, u_int64_t stripe, + MR_FW_RAID_MAP_ALL *map) +{ + MR_LD_RAID *raid = MR_LdRaidGet(ld, map); + /* Need to check correct default value */ + u_int32_t arm = 0; + + switch (raid->level) { + case 0: + case 5: + case 6: + arm = mega_mod64(stripe, SPAN_ROW_SIZE(map, ld, span)); + break; + case 1: + // start with logical arm + arm = get_arm_from_strip(sc, ld, stripe, map); + arm *= 2; + break; + + } + + return arm; +} + +/* +****************************************************************************** +* +* This routine calculates the arm, span and block for the specified stripe and +* reference in stripe using spanset +* +* Inputs : +* +* ld - Logical drive number +* stripRow - Stripe number +* stripRef - Reference in stripe +* +* Outputs : +* +* span - Span number +* block - Absolute Block number in the physical disk +*/ +static u_int8_t mr_spanset_get_phy_params(struct mrsas_softc *sc, u_int32_t ld, u_int64_t stripRow, + u_int16_t stripRef, struct IO_REQUEST_INFO *io_info, + RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map) +{ + MR_LD_RAID *raid = MR_LdRaidGet(ld, map); + u_int32_t pd, arRef; + u_int8_t physArm, span; + u_int64_t row; + u_int8_t retval = TRUE; + u_int64_t *pdBlock = &io_info->pdBlock; + u_int16_t *pDevHandle = &io_info->devHandle; + u_int32_t logArm, rowMod, armQ, arm; + u_int8_t do_invader = 0; + + if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) + do_invader = 1; + + // Get row and span from io_info for Uneven Span IO. + row = io_info->start_row; + span = io_info->start_span; + + + if (raid->level == 6) { + logArm = get_arm_from_strip(sc, ld, stripRow, map); + rowMod = mega_mod64(row, SPAN_ROW_SIZE(map, ld, span)); + armQ = SPAN_ROW_SIZE(map,ld,span) - 1 - rowMod; + arm = armQ + 1 + logArm; + if (arm >= SPAN_ROW_SIZE(map, ld, span)) + arm -= SPAN_ROW_SIZE(map ,ld ,span); + physArm = (u_int8_t)arm; + } else + // Calculate the arm + physArm = get_arm(sc, ld, span, stripRow, map); + + + arRef = MR_LdSpanArrayGet(ld, span, map); + pd = MR_ArPdGet(arRef, physArm, map); + + if (pd != MR_PD_INVALID) + *pDevHandle = MR_PdDevHandleGet(pd, map); + else { + *pDevHandle = MR_PD_INVALID; + if ((raid->level >= 5) && ((!do_invader) || (do_invader && + raid->regTypeReqOnRead != REGION_TYPE_UNUSED))) + pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; + else if (raid->level == 1) { + pd = MR_ArPdGet(arRef, physArm + 1, map); + if (pd != MR_PD_INVALID) + *pDevHandle = MR_PdDevHandleGet(pd, map); + } + } + + *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk; + pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; + return retval; +} + +/** +* MR_BuildRaidContext: Set up Fast path RAID context +* +* This function will initiate command processing. The start/end row +* and strip information is calculated then the lock is acquired. +* This function will return 0 if region lock was acquired OR return +* num strips. +*/ +u_int8_t +MR_BuildRaidContext(struct mrsas_softc *sc, struct IO_REQUEST_INFO *io_info, + RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map) +{ + MR_LD_RAID *raid; + u_int32_t ld, stripSize, stripe_mask; + u_int64_t endLba, endStrip, endRow, start_row, start_strip; + REGION_KEY regStart; + REGION_LEN regSize; + u_int8_t num_strips, numRows; + u_int16_t ref_in_start_stripe, ref_in_end_stripe; + u_int64_t ldStartBlock; + u_int32_t numBlocks, ldTgtId; + u_int8_t isRead, stripIdx; + u_int8_t retval = 0; + u_int8_t startlba_span = SPAN_INVALID; + u_int64_t *pdBlock = &io_info->pdBlock; + int error_code = 0; + + ldStartBlock = io_info->ldStartBlock; + numBlocks = io_info->numBlocks; + ldTgtId = io_info->ldTgtId; + isRead = io_info->isRead; + + io_info->IoforUnevenSpan = 0; + io_info->start_span = SPAN_INVALID; + + ld = MR_TargetIdToLdGet(ldTgtId, map); + raid = MR_LdRaidGet(ld, map); + + /* + * if rowDataSize @RAID map and spanRowDataSize @SPAN INFO are zero + * return FALSE + */ + if (raid->rowDataSize == 0) { + if (MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize == 0) + return FALSE; + else if (sc->UnevenSpanSupport) { + io_info->IoforUnevenSpan = 1; + } + else { + mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: raid->rowDataSize is 0, but has SPAN[0] rowDataSize = 0x%0x," + " but there is _NO_ UnevenSpanSupport\n", + MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize); + return FALSE; + } + } + stripSize = 1 << raid->stripeShift; + stripe_mask = stripSize-1; + /* + * calculate starting row and stripe, and number of strips and rows + */ + start_strip = ldStartBlock >> raid->stripeShift; + ref_in_start_stripe = (u_int16_t)(ldStartBlock & stripe_mask); + endLba = ldStartBlock + numBlocks - 1; + ref_in_end_stripe = (u_int16_t)(endLba & stripe_mask); + endStrip = endLba >> raid->stripeShift; + num_strips = (u_int8_t)(endStrip - start_strip + 1); // End strip + if (io_info->IoforUnevenSpan) { + start_row = get_row_from_strip(sc, ld, start_strip, map); + endRow = get_row_from_strip(sc, ld, endStrip, map); + if (raid->spanDepth == 1) { + startlba_span = 0; + *pdBlock = start_row << raid->stripeShift; + } else { + startlba_span = (u_int8_t)mr_spanset_get_span_block(sc, ld, start_row, + pdBlock, map, &error_code); + if (error_code == 1) { + mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: return from %s %d. Send IO w/o region lock.\n", + __func__, __LINE__); + return FALSE; + } + } + if (startlba_span == SPAN_INVALID) { + mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: return from %s %d for row 0x%llx," + "start strip %llx endSrip %llx\n", __func__, + __LINE__, (unsigned long long)start_row, + (unsigned long long)start_strip, + (unsigned long long)endStrip); + return FALSE; + } + io_info->start_span = startlba_span; + io_info->start_row = start_row; + mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: Check Span number from %s %d for row 0x%llx, " + " start strip 0x%llx endSrip 0x%llx span 0x%x\n", + __func__, __LINE__, (unsigned long long)start_row, + (unsigned long long)start_strip, + (unsigned long long)endStrip, startlba_span); + mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : 1. start_row 0x%llx endRow 0x%llx Start span 0x%x\n", + (unsigned long long)start_row, (unsigned long long)endRow, startlba_span); + } else { + start_row = mega_div64_32(start_strip, raid->rowDataSize); // Start Row + endRow = mega_div64_32(endStrip, raid->rowDataSize); + } + + numRows = (u_int8_t)(endRow - start_row + 1); // get the row count + + /* + * Calculate region info. (Assume region at start of first row, and + * assume this IO needs the full row - will adjust if not true.) + */ + regStart = start_row << raid->stripeShift; + regSize = stripSize; + + /* Check if we can send this I/O via FastPath */ + if (raid->capability.fpCapable) { + if (isRead) + io_info->fpOkForIo = (raid->capability.fpReadCapable && + ((num_strips == 1) || + raid->capability. + fpReadAcrossStripe)); + else + io_info->fpOkForIo = (raid->capability.fpWriteCapable && + ((num_strips == 1) || + raid->capability. + fpWriteAcrossStripe)); + } + else + io_info->fpOkForIo = FALSE; + + if (numRows == 1) { + if (num_strips == 1) { + /* single-strip IOs can always lock only the data needed, + multi-strip IOs always need to full stripe locked */ + regStart += ref_in_start_stripe; + regSize = numBlocks; + } + } + else if (io_info->IoforUnevenSpan == 0){ + // For Even span region lock optimization. + // If the start strip is the last in the start row + if (start_strip == (start_row + 1) * raid->rowDataSize - 1) { + regStart += ref_in_start_stripe; + // initialize count to sectors from startRef to end of strip + regSize = stripSize - ref_in_start_stripe; + } + // add complete rows in the middle of the transfer + if (numRows > 2) + regSize += (numRows-2) << raid->stripeShift; + + // if IO ends within first strip of last row + if (endStrip == endRow*raid->rowDataSize) + regSize += ref_in_end_stripe+1; + else + regSize += stripSize; + } else { + //For Uneven span region lock optimization. + // If the start strip is the last in the start row + if (start_strip == (get_strip_from_row(sc, ld, start_row, map) + + SPAN_ROW_DATA_SIZE(map, ld, startlba_span) - 1)) { + regStart += ref_in_start_stripe; + // initialize count to sectors from startRef to end of strip + regSize = stripSize - ref_in_start_stripe; + } + // add complete rows in the middle of the transfer + if (numRows > 2) + regSize += (numRows-2) << raid->stripeShift; + + // if IO ends within first strip of last row + if (endStrip == get_strip_from_row(sc, ld, endRow, map)) + regSize += ref_in_end_stripe+1; + else + regSize += stripSize; + } + pRAID_Context->timeoutValue = map->raidMap.fpPdIoTimeoutSec; + if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) + pRAID_Context->regLockFlags = (isRead)? raid->regTypeReqOnRead : raid->regTypeReqOnWrite; + else + pRAID_Context->regLockFlags = (isRead)? REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite; + pRAID_Context->VirtualDiskTgtId = raid->targetId; + pRAID_Context->regLockRowLBA = regStart; + pRAID_Context->regLockLength = regSize; + pRAID_Context->configSeqNum = raid->seqNum; + + /* + * Get Phy Params only if FP capable, or else leave it to MR firmware + * to do the calculation. + */ + if (io_info->fpOkForIo) { + retval = io_info->IoforUnevenSpan ? + mr_spanset_get_phy_params(sc, ld, + start_strip, ref_in_start_stripe, io_info, + pRAID_Context, map) : + MR_GetPhyParams(sc, ld, start_strip, + ref_in_start_stripe, io_info, pRAID_Context, map); + /* If IO on an invalid Pd, then FP is not possible */ + if (io_info->devHandle == MR_PD_INVALID) + io_info->fpOkForIo = FALSE; + return retval; + } + else if (isRead) { + for (stripIdx=0; stripIdx<num_strips; stripIdx++) { + retval = io_info->IoforUnevenSpan ? + mr_spanset_get_phy_params(sc, ld, + start_strip + stripIdx, + ref_in_start_stripe, io_info, + pRAID_Context, map) : + MR_GetPhyParams(sc, ld, + start_strip + stripIdx, ref_in_start_stripe, + io_info, pRAID_Context, map); + if (!retval) + return TRUE; + } + } +#if SPAN_DEBUG + // Just for testing what arm we get for strip. + get_arm_from_strip(sc, ld, start_strip, map); +#endif + return TRUE; +} + +/* +****************************************************************************** +* +* This routine pepare spanset info from Valid Raid map and store it into +* local copy of ldSpanInfo per instance data structure. +* +* Inputs : +* map - LD map +* ldSpanInfo - ldSpanInfo per HBA instance +* +*/ +void mr_update_span_set(MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo) +{ + u_int8_t span,count; + u_int32_t element,span_row_width; + u_int64_t span_row; + MR_LD_RAID *raid; + LD_SPAN_SET *span_set, *span_set_prev; + MR_QUAD_ELEMENT *quad; + int ldCount; + u_int16_t ld; + + if (!ldSpanInfo) + return; + + for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) + { + ld = MR_TargetIdToLdGet(ldCount, map); + if (ld >= MAX_LOGICAL_DRIVES) + continue; + raid = MR_LdRaidGet(ld, map); + for (element=0; element < MAX_QUAD_DEPTH; element++) { + for (span=0; span < raid->spanDepth; span++) { + if (map->raidMap.ldSpanMap[ld].spanBlock[span]. + block_span_info.noElements < element+1) + continue; + // TO-DO + span_set = &(ldSpanInfo[ld].span_set[element]); + quad = &map->raidMap.ldSpanMap[ld]. + spanBlock[span].block_span_info. + quad[element]; + + span_set->diff = quad->diff; + + for (count=0,span_row_width=0; + count<raid->spanDepth; count++) { + if (map->raidMap.ldSpanMap[ld]. + spanBlock[count]. + block_span_info. + noElements >=element+1) { + span_set->strip_offset[count] = + span_row_width; + span_row_width += + MR_LdSpanPtrGet + (ld, count, map)->spanRowDataSize; +#if SPAN_DEBUG + printf("LSI Debug span %x rowDataSize %x\n", + count, MR_LdSpanPtrGet + (ld, count, map)->spanRowDataSize); +#endif + } + } + + span_set->span_row_data_width = span_row_width; + span_row = mega_div64_32(((quad->logEnd - + quad->logStart) + quad->diff), quad->diff); + + if (element == 0) { + span_set->log_start_lba = 0; + span_set->log_end_lba = + ((span_row << raid->stripeShift) * span_row_width) - 1; + + span_set->span_row_start = 0; + span_set->span_row_end = span_row - 1; + + span_set->data_strip_start = 0; + span_set->data_strip_end = + (span_row * span_row_width) - 1; + + span_set->data_row_start = 0; + span_set->data_row_end = + (span_row * quad->diff) - 1; + } else { + span_set_prev = &(ldSpanInfo[ld]. + span_set[element - 1]); + span_set->log_start_lba = + span_set_prev->log_end_lba + 1; + span_set->log_end_lba = + span_set->log_start_lba + + ((span_row << raid->stripeShift) * span_row_width) - 1; + + span_set->span_row_start = + span_set_prev->span_row_end + 1; + span_set->span_row_end = + span_set->span_row_start + span_row - 1; + + span_set->data_strip_start = + span_set_prev->data_strip_end + 1; + span_set->data_strip_end = + span_set->data_strip_start + + (span_row * span_row_width) - 1; + + span_set->data_row_start = + span_set_prev->data_row_end + 1; + span_set->data_row_end = + span_set->data_row_start + + (span_row * quad->diff) - 1; + } + break; + } + if (span == raid->spanDepth) break; // no quads remain + } + } +#if SPAN_DEBUG + getSpanInfo(map, ldSpanInfo); //to get span set info +#endif +} + +/** + * mrsas_update_load_balance_params: Update load balance parmas + * Inputs: map pointer + * Load balance info + * io_info pointer + * + * This function updates the load balance parameters for the LD config + * of a two drive optimal RAID-1. + */ +void mrsas_update_load_balance_params(MR_FW_RAID_MAP_ALL *map, + PLD_LOAD_BALANCE_INFO lbInfo) +{ + int ldCount; + u_int16_t ld; + u_int32_t pd, arRef; + MR_LD_RAID *raid; + + for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) + { + ld = MR_TargetIdToLdGet(ldCount, map); + if (ld >= MAX_LOGICAL_DRIVES) { + lbInfo[ldCount].loadBalanceFlag = 0; + continue; + } + + raid = MR_LdRaidGet(ld, map); + + /* Two drive Optimal RAID 1 */ + if ((raid->level == 1) && (raid->rowSize == 2) && + (raid->spanDepth == 1) + && raid->ldState == MR_LD_STATE_OPTIMAL) { + lbInfo[ldCount].loadBalanceFlag = 1; + + /* Get the array on which this span is present */ + arRef = MR_LdSpanArrayGet(ld, 0, map); + + /* Get the PD */ + pd = MR_ArPdGet(arRef, 0, map); + /* Get dev handle from PD */ + lbInfo[ldCount].raid1DevHandle[0] = MR_PdDevHandleGet(pd, map); + pd = MR_ArPdGet(arRef, 1, map); + lbInfo[ldCount].raid1DevHandle[1] = MR_PdDevHandleGet(pd, map); + } + else + lbInfo[ldCount].loadBalanceFlag = 0; + } +} + + +/** + * mrsas_set_pd_lba: Sets PD LBA + * input: io_request pointer + * CDB length + * io_info pointer + * Pointer to CCB + * Local RAID map pointer + * Start block of IO + * Block Size + * + * Used to set the PD logical block address in CDB for FP IOs. + */ +void mrsas_set_pd_lba(MRSAS_RAID_SCSI_IO_REQUEST *io_request, u_int8_t cdb_len, + struct IO_REQUEST_INFO *io_info, union ccb *ccb, + MR_FW_RAID_MAP_ALL *local_map_ptr, u_int32_t ref_tag, + u_int32_t ld_block_size) +{ + MR_LD_RAID *raid; + u_int32_t ld; + u_int64_t start_blk = io_info->pdBlock; + u_int8_t *cdb = io_request->CDB.CDB32; + u_int32_t num_blocks = io_info->numBlocks; + u_int8_t opcode = 0, flagvals = 0, groupnum = 0, control = 0; + struct ccb_hdr *ccb_h = &(ccb->ccb_h); + + /* Check if T10 PI (DIF) is enabled for this LD */ + ld = MR_TargetIdToLdGet(io_info->ldTgtId, local_map_ptr); + raid = MR_LdRaidGet(ld, local_map_ptr); + if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) { + memset(cdb, 0, sizeof(io_request->CDB.CDB32)); + cdb[0] = MRSAS_SCSI_VARIABLE_LENGTH_CMD; + cdb[7] = MRSAS_SCSI_ADDL_CDB_LEN; + + if (ccb_h->flags == CAM_DIR_OUT) + cdb[9] = MRSAS_SCSI_SERVICE_ACTION_READ32; + else + cdb[9] = MRSAS_SCSI_SERVICE_ACTION_WRITE32; + cdb[10] = MRSAS_RD_WR_PROTECT_CHECK_ALL; + + /* LBA */ + cdb[12] = (u_int8_t)((start_blk >> 56) & 0xff); + cdb[13] = (u_int8_t)((start_blk >> 48) & 0xff); + cdb[14] = (u_int8_t)((start_blk >> 40) & 0xff); + cdb[15] = (u_int8_t)((start_blk >> 32) & 0xff); + cdb[16] = (u_int8_t)((start_blk >> 24) & 0xff); + cdb[17] = (u_int8_t)((start_blk >> 16) & 0xff); + cdb[18] = (u_int8_t)((start_blk >> 8) & 0xff); + cdb[19] = (u_int8_t)(start_blk & 0xff); + + /* Logical block reference tag */ + io_request->CDB.EEDP32.PrimaryReferenceTag = swap32(ref_tag); + io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0xffff; + io_request->IoFlags = 32; /* Specify 32-byte cdb */ + + /* Transfer length */ + cdb[28] = (u_int8_t)((num_blocks >> 24) & 0xff); + cdb[29] = (u_int8_t)((num_blocks >> 16) & 0xff); + cdb[30] = (u_int8_t)((num_blocks >> 8) & 0xff); + cdb[31] = (u_int8_t)(num_blocks & 0xff); + + /* set SCSI IO EEDP Flags */ + if (ccb_h->flags == CAM_DIR_OUT) { + io_request->EEDPFlags = + MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | + MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | + MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP | + MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG | + MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; + } + else { + io_request->EEDPFlags = + MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | + MPI2_SCSIIO_EEDPFLAGS_INSERT_OP; + } + io_request->Control |= (0x4 << 26); + io_request->EEDPBlockSize = ld_block_size; + } + else { + /* Some drives don't support 16/12 byte CDB's, convert to 10 */ + if (((cdb_len == 12) || (cdb_len == 16)) && + (start_blk <= 0xffffffff)) { + if (cdb_len == 16) { + opcode = cdb[0] == READ_16 ? READ_10 : WRITE_10; + flagvals = cdb[1]; + groupnum = cdb[14]; + control = cdb[15]; + } + else { + opcode = cdb[0] == READ_12 ? READ_10 : WRITE_10; + flagvals = cdb[1]; + groupnum = cdb[10]; + control = cdb[11]; + } + + memset(cdb, 0, sizeof(io_request->CDB.CDB32)); + + cdb[0] = opcode; + cdb[1] = flagvals; + cdb[6] = groupnum; + cdb[9] = control; + + /* Transfer length */ + cdb[8] = (u_int8_t)(num_blocks & 0xff); + cdb[7] = (u_int8_t)((num_blocks >> 8) & 0xff); + + io_request->IoFlags = 10; /* Specify 10-byte cdb */ + cdb_len = 10; + } else if ((cdb_len < 16) && (start_blk > 0xffffffff)) { + /* Convert to 16 byte CDB for large LBA's */ + switch (cdb_len) { + case 6: + opcode = cdb[0] == READ_6 ? READ_16 : WRITE_16; + control = cdb[5]; + break; + case 10: + opcode = cdb[0] == READ_10 ? READ_16 : WRITE_16; + flagvals = cdb[1]; + groupnum = cdb[6]; + control = cdb[9]; + break; + case 12: + opcode = cdb[0] == READ_12 ? READ_16 : WRITE_16; + flagvals = cdb[1]; + groupnum = cdb[10]; + control = cdb[11]; + break; + } + + memset(cdb, 0, sizeof(io_request->CDB.CDB32)); + + cdb[0] = opcode; + cdb[1] = flagvals; + cdb[14] = groupnum; + cdb[15] = control; + + /* Transfer length */ + cdb[13] = (u_int8_t)(num_blocks & 0xff); + cdb[12] = (u_int8_t)((num_blocks >> 8) & 0xff); + cdb[11] = (u_int8_t)((num_blocks >> 16) & 0xff); + cdb[10] = (u_int8_t)((num_blocks >> 24) & 0xff); + + io_request->IoFlags = 16; /* Specify 16-byte cdb */ + cdb_len = 16; + } else if ((cdb_len == 6) && (start_blk > 0x1fffff)) { + /* convert to 10 byte CDB */ + opcode = cdb[0] == READ_6 ? READ_10 : WRITE_10; + control = cdb[5]; + + memset(cdb, 0, sizeof(cdb)); + cdb[0] = opcode; + cdb[9] = control; + + /* Set transfer length */ + cdb[8] = (u_int8_t)(num_blocks & 0xff); + cdb[7] = (u_int8_t)((num_blocks >> 8) & 0xff); + + /* Specify 10-byte cdb */ + cdb_len = 10; + } + + /* Fall through normal case, just load LBA here */ + switch (cdb_len) + { + case 6: + { + u_int8_t val = cdb[1] & 0xE0; + cdb[3] = (u_int8_t)(start_blk & 0xff); + cdb[2] = (u_int8_t)((start_blk >> 8) & 0xff); + cdb[1] = val | ((u_int8_t)(start_blk >> 16) & 0x1f); + break; + } + case 10: + cdb[5] = (u_int8_t)(start_blk & 0xff); + cdb[4] = (u_int8_t)((start_blk >> 8) & 0xff); + cdb[3] = (u_int8_t)((start_blk >> 16) & 0xff); + cdb[2] = (u_int8_t)((start_blk >> 24) & 0xff); + break; + case 12: + cdb[5] = (u_int8_t)(start_blk & 0xff); + cdb[4] = (u_int8_t)((start_blk >> 8) & 0xff); + cdb[3] = (u_int8_t)((start_blk >> 16) & 0xff); + cdb[2] = (u_int8_t)((start_blk >> 24) & 0xff); + break; + case 16: + cdb[9] = (u_int8_t)(start_blk & 0xff); + cdb[8] = (u_int8_t)((start_blk >> 8) & 0xff); + cdb[7] = (u_int8_t)((start_blk >> 16) & 0xff); + cdb[6] = (u_int8_t)((start_blk >> 24) & 0xff); + cdb[5] = (u_int8_t)((start_blk >> 32) & 0xff); + cdb[4] = (u_int8_t)((start_blk >> 40) & 0xff); + cdb[3] = (u_int8_t)((start_blk >> 48) & 0xff); + cdb[2] = (u_int8_t)((start_blk >> 56) & 0xff); + break; + } + } +} + +/** + * mrsas_get_best_arm Determine the best spindle arm + * Inputs: Load balance info + * + * This function determines and returns the best arm by looking at the + * parameters of the last PD access. + */ +u_int8_t mrsas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm, + u_int64_t block, u_int32_t count) +{ + u_int16_t pend0, pend1; + u_int64_t diff0, diff1; + u_int8_t bestArm; + + /* get the pending cmds for the data and mirror arms */ + pend0 = atomic_read(&lbInfo->scsi_pending_cmds[0]); + pend1 = atomic_read(&lbInfo->scsi_pending_cmds[1]); + + /* Determine the disk whose head is nearer to the req. block */ + diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[0]); + diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[1]); + bestArm = (diff0 <= diff1 ? 0 : 1); + + if ((bestArm == arm && pend0 > pend1 + 16) || (bestArm != arm && pend1 > pend0 + 16)) + bestArm ^= 1; + + /* Update the last accessed block on the correct pd */ + lbInfo->last_accessed_block[bestArm] = block + count - 1; + + return bestArm; +} + +/** + * mrsas_get_updated_dev_handle Get the update dev handle + * Inputs: Load balance info + * io_info pointer + * + * This function determines and returns the updated dev handle. + */ +u_int16_t mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo, + struct IO_REQUEST_INFO *io_info) +{ + u_int8_t arm, old_arm; + u_int16_t devHandle; + + old_arm = lbInfo->raid1DevHandle[0] == io_info->devHandle ? 0 : 1; + + /* get best new arm */ + arm = mrsas_get_best_arm(lbInfo, old_arm, io_info->ldStartBlock, io_info->numBlocks); + devHandle = lbInfo->raid1DevHandle[arm]; + atomic_inc(&lbInfo->scsi_pending_cmds[arm]); + + return devHandle; +} + +/** + * MR_GetPhyParams Calculates arm, span, and block + * Inputs: Adapter instance soft state + * Logical drive number (LD) + * Stripe number (stripRow) + * Reference in stripe (stripRef) + * Outputs: Span number + * Absolute Block number in the physical disk + * + * This routine calculates the arm, span and block for the specified stripe + * and reference in stripe. + */ +u_int8_t MR_GetPhyParams(struct mrsas_softc *sc, u_int32_t ld, + u_int64_t stripRow, + u_int16_t stripRef, struct IO_REQUEST_INFO *io_info, + RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map) +{ + MR_LD_RAID *raid = MR_LdRaidGet(ld, map); + u_int32_t pd, arRef; + u_int8_t physArm, span; + u_int64_t row; + u_int8_t retval = TRUE; + int error_code = 0; + u_int64_t *pdBlock = &io_info->pdBlock; + u_int16_t *pDevHandle = &io_info->devHandle; + u_int32_t rowMod, armQ, arm, logArm; + u_int8_t do_invader = 0; + + if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) + do_invader = 1; + + row = mega_div64_32(stripRow, raid->rowDataSize); + + if (raid->level == 6) { + logArm = mega_mod64(stripRow, raid->rowDataSize); // logical arm within row + if (raid->rowSize == 0) + return FALSE; + rowMod = mega_mod64(row, raid->rowSize); // get logical row mod + armQ = raid->rowSize-1-rowMod; // index of Q drive + arm = armQ+1+logArm; // data always logically follows Q + if (arm >= raid->rowSize) // handle wrap condition + arm -= raid->rowSize; + physArm = (u_int8_t)arm; + } + else { + if (raid->modFactor == 0) + return FALSE; + physArm = MR_LdDataArmGet(ld, mega_mod64(stripRow, raid->modFactor), map); + } + + if (raid->spanDepth == 1) { + span = 0; + *pdBlock = row << raid->stripeShift; + } + else { + span = (u_int8_t)MR_GetSpanBlock(ld, row, pdBlock, map, &error_code); + if (error_code == 1) + return FALSE; + } + + /* Get the array on which this span is present */ + arRef = MR_LdSpanArrayGet(ld, span, map); + + pd = MR_ArPdGet(arRef, physArm, map); // Get the Pd. + + if (pd != MR_PD_INVALID) + *pDevHandle = MR_PdDevHandleGet(pd, map); // Get dev handle from Pd. + else { + *pDevHandle = MR_PD_INVALID; // set dev handle as invalid. + if ((raid->level >= 5) && ((!do_invader) || (do_invader && + raid->regTypeReqOnRead != REGION_TYPE_UNUSED))) + pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; + else if (raid->level == 1) { + pd = MR_ArPdGet(arRef, physArm + 1, map); // Get Alternate Pd. + if (pd != MR_PD_INVALID) + *pDevHandle = MR_PdDevHandleGet(pd, map);//Get dev handle from Pd. + } + } + + *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk; + pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; + return retval; +} + +/** + * MR_GetSpanBlock Calculates span block + * Inputs: LD + * row + * PD span block + * RAID map pointer + * Outputs: Span number + * Error code + * + * This routine calculates the span from the span block info. + */ +u_int32_t MR_GetSpanBlock(u_int32_t ld, u_int64_t row, u_int64_t *span_blk, + MR_FW_RAID_MAP_ALL *map, int *div_error) +{ + MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map); + MR_QUAD_ELEMENT *quad; + MR_LD_RAID *raid = MR_LdRaidGet(ld, map); + u_int32_t span, j; + u_int64_t blk, debugBlk; + + for (span=0; span < raid->spanDepth; span++, pSpanBlock++) { + for (j=0; j < pSpanBlock->block_span_info.noElements; j++) { + quad = &pSpanBlock->block_span_info.quad[j]; + if (quad->diff == 0) { + *div_error = 1; + return span; + } + if (quad->logStart <= row && row <= quad->logEnd && + (mega_mod64(row-quad->logStart, quad->diff)) == 0) { + if (span_blk != NULL) { + blk = mega_div64_32((row-quad->logStart), quad->diff); + debugBlk = blk; + blk = (blk + quad->offsetInSpan) << raid->stripeShift; + *span_blk = blk; + } + return span; + } + } + } + return span; +} + diff --git a/sys/dev/mrsas/mrsas_ioctl.c b/sys/dev/mrsas/mrsas_ioctl.c new file mode 100644 index 0000000000000..6343aa5956042 --- /dev/null +++ b/sys/dev/mrsas/mrsas_ioctl.c @@ -0,0 +1,546 @@ +/* + * Copyright (c) 2014, LSI Corp. + * All rights reserved. + * Author: Marian Choy + * Support: freebsdraid@lsi.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of the <ORGANIZATION> nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Send feedback to: <megaraidfbsd@lsi.com> + * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035 + * ATTN: MegaRaid FreeBSD + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <dev/mrsas/mrsas.h> +#include <dev/mrsas/mrsas_ioctl.h> + +/* + * Function prototypes + */ +int mrsas_alloc_mfi_cmds(struct mrsas_softc *sc); +int mrsas_passthru(struct mrsas_softc *sc, void *arg); +void mrsas_free_ioc_cmd(struct mrsas_softc *sc); +void mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd); +void mrsas_dump_dcmd(struct mrsas_softc *sc, struct mrsas_dcmd_frame* dcmd); +void mrsas_dump_ioctl(struct mrsas_softc *sc, struct mrsas_iocpacket *user_ioc); +void * mrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd); +static int mrsas_create_frame_pool(struct mrsas_softc *sc); +static void mrsas_alloc_cb(void *arg, bus_dma_segment_t *segs, + int nsegs, int error); + +extern struct mrsas_mfi_cmd* mrsas_get_mfi_cmd(struct mrsas_softc *sc); +extern void mrsas_release_mfi_cmd(struct mrsas_mfi_cmd *cmd); +extern int mrsas_issue_blocked_cmd(struct mrsas_softc *sc, + struct mrsas_mfi_cmd *cmd); + + +/** + * mrsas_dump_ioctl: Print debug output for DCMDs + * input: Adapter instance soft state + * DCMD frame structure + * + * This function is called from mrsas_passthru() to print out debug information + * in the handling and routing of DCMD commands. + */ +void mrsas_dump_dcmd( struct mrsas_softc *sc, struct mrsas_dcmd_frame* dcmd ) +{ + int i; + + device_printf(sc->mrsas_dev, "dcmd->cmd: 0x%02hhx\n", dcmd->cmd); + device_printf(sc->mrsas_dev, "dcmd->cmd_status: 0x%02hhx\n", dcmd->cmd_status); + device_printf(sc->mrsas_dev, "dcmd->sge_count: 0x%02hhx\n", dcmd->sge_count); + device_printf(sc->mrsas_dev, "dcmd->context: 0x%08x\n", dcmd->context); + device_printf(sc->mrsas_dev, "dcmd->flags: 0x%04hx\n", dcmd->flags); + device_printf(sc->mrsas_dev, "dcmd->timeout: 0x%04hx\n", dcmd->timeout); + device_printf(sc->mrsas_dev, "dcmd->data_xfer_len: 0x%08x\n", dcmd->data_xfer_len); + device_printf(sc->mrsas_dev, "dcmd->opcode: 0x%08x\n", dcmd->opcode); + device_printf(sc->mrsas_dev, "dcmd->mbox.w[0]: 0x%08x\n", dcmd->mbox.w[0]); + device_printf(sc->mrsas_dev, "dcmd->mbox.w[1]: 0x%08x\n", dcmd->mbox.w[1]); + device_printf(sc->mrsas_dev, "dcmd->mbox.w[2]: 0x%08x\n", dcmd->mbox.w[2]); + for (i=0; i< MIN(MAX_IOCTL_SGE, dcmd->sge_count); i++) { + device_printf(sc->mrsas_dev, "sgl[%02d]\n", i); + device_printf(sc->mrsas_dev, " sge32[%02d].phys_addr: 0x%08x\n", + i, dcmd->sgl.sge32[i].phys_addr); + device_printf(sc->mrsas_dev, " sge32[%02d].length: 0x%08x\n", + i, dcmd->sgl.sge32[i].length); + device_printf(sc->mrsas_dev, " sge64[%02d].phys_addr: 0x%08llx\n", + i, (long long unsigned int) dcmd->sgl.sge64[i].phys_addr); + device_printf(sc->mrsas_dev, " sge64[%02d].length: 0x%08x\n", + i, dcmd->sgl.sge64[i].length); + } +} + +/** + * mrsas_dump_ioctl: Print debug output for ioctl + * input: Adapter instance soft state + * iocpacket structure + * + * This function is called from mrsas_passthru() to print out debug information + * in the handling and routing of ioctl commands. + */ +void mrsas_dump_ioctl(struct mrsas_softc *sc, struct mrsas_iocpacket *user_ioc) +{ + union mrsas_frame *in_cmd = (union mrsas_frame *) &(user_ioc->frame.raw); + struct mrsas_dcmd_frame* dcmd = (struct mrsas_dcmd_frame *) &(in_cmd->dcmd); + int i; + + device_printf(sc->mrsas_dev, + "====== In %s() ======================================\n", __func__); + device_printf(sc->mrsas_dev, "host_no: 0x%04hx\n", user_ioc->host_no); + device_printf(sc->mrsas_dev, " __pad1: 0x%04hx\n", user_ioc->__pad1); + device_printf(sc->mrsas_dev, "sgl_off: 0x%08x\n", user_ioc->sgl_off); + device_printf(sc->mrsas_dev, "sge_count: 0x%08x\n", user_ioc->sge_count); + device_printf(sc->mrsas_dev, "sense_off: 0x%08x\n", user_ioc->sense_off); + device_printf(sc->mrsas_dev, "sense_len: 0x%08x\n", user_ioc->sense_len); + + mrsas_dump_dcmd(sc, dcmd); + + for (i=0; i< MIN(MAX_IOCTL_SGE, user_ioc->sge_count); i++) { + device_printf(sc->mrsas_dev, "sge[%02d]\n", i); + device_printf(sc->mrsas_dev, + " iov_base: %p\n", user_ioc->sgl[i].iov_base); + device_printf(sc->mrsas_dev, " iov_len: %p\n", + (void*)user_ioc->sgl[i].iov_len); + } + device_printf(sc->mrsas_dev, + "==================================================================\n"); +} + +/** + * mrsas_passthru: Handle pass-through commands + * input: Adapter instance soft state + * argument pointer + * + * This function is called from mrsas_ioctl() to handle pass-through and + * ioctl commands to Firmware. + */ +int mrsas_passthru( struct mrsas_softc *sc, void *arg ) +{ + struct mrsas_iocpacket *user_ioc = (struct mrsas_iocpacket *)arg; + union mrsas_frame *in_cmd = (union mrsas_frame *) &(user_ioc->frame.raw); + struct mrsas_mfi_cmd *cmd = NULL; + bus_dma_tag_t ioctl_data_tag[MAX_IOCTL_SGE]; + bus_dmamap_t ioctl_data_dmamap[MAX_IOCTL_SGE]; + void *ioctl_data_mem[MAX_IOCTL_SGE]; // ioctl data virtual addr + bus_addr_t ioctl_data_phys_addr[MAX_IOCTL_SGE]; // ioctl data phys addr + bus_dma_tag_t ioctl_sense_tag = 0; + bus_dmamap_t ioctl_sense_dmamap = 0; + void *ioctl_sense_mem = 0; + bus_addr_t ioctl_sense_phys_addr = 0; + int i, adapter, ioctl_data_size, ioctl_sense_size, ret=0; + struct mrsas_sge32 *kern_sge32; + unsigned long *sense_ptr; + + /* For debug - uncomment the following line for debug output */ + //mrsas_dump_ioctl(sc, user_ioc); + + /* + * Check for NOP from MegaCli... MegaCli can issue a DCMD of 0. In this + * case do nothing and return 0 to it as status. + */ + if (in_cmd->dcmd.opcode == 0) { + device_printf(sc->mrsas_dev, "In %s() Got a NOP\n", __func__); + user_ioc->frame.hdr.cmd_status = MFI_STAT_OK; + return (0); + } + + /* Validate host_no */ + adapter = user_ioc->host_no; + if (adapter != device_get_unit(sc->mrsas_dev)) { + device_printf(sc->mrsas_dev, "In %s() IOCTL not for me!\n", __func__); + return(ENOENT); + } + + /* Validate SGL length */ + if (user_ioc->sge_count > MAX_IOCTL_SGE) { + device_printf(sc->mrsas_dev, "In %s() SGL is too long (%d > 8).\n", + __func__, user_ioc->sge_count); + return(ENOENT); + } + + /* Get a command */ + cmd = mrsas_get_mfi_cmd(sc); + if (!cmd) { + device_printf(sc->mrsas_dev, "Failed to get a free cmd for IOCTL\n"); + return(ENOMEM); + } + + /* + * User's IOCTL packet has 2 frames (maximum). Copy those two + * frames into our cmd's frames. cmd->frame's context will get + * overwritten when we copy from user's frames. So set that value + * alone separately + */ + memcpy(cmd->frame, user_ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE); + cmd->frame->hdr.context = cmd->index; + cmd->frame->hdr.pad_0 = 0; + cmd->frame->hdr.flags &= ~(MFI_FRAME_IEEE | MFI_FRAME_SGL64 | + MFI_FRAME_SENSE64); + + /* + * The management interface between applications and the fw uses + * MFI frames. E.g, RAID configuration changes, LD property changes + * etc are accomplishes through different kinds of MFI frames. The + * driver needs to care only about substituting user buffers with + * kernel buffers in SGLs. The location of SGL is embedded in the + * struct iocpacket itself. + */ + kern_sge32 = (struct mrsas_sge32 *) + ((unsigned long)cmd->frame + user_ioc->sgl_off); + + /* + * For each user buffer, create a mirror buffer and copy in + */ + for (i=0; i < user_ioc->sge_count; i++) { + if (!user_ioc->sgl[i].iov_len) + continue; + ioctl_data_size = user_ioc->sgl[i].iov_len; + if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent + 1, 0, // algnmnt, boundary + BUS_SPACE_MAXADDR_32BIT,// lowaddr + BUS_SPACE_MAXADDR, // highaddr + NULL, NULL, // filter, filterarg + ioctl_data_size, // maxsize + 1, // msegments + ioctl_data_size, // maxsegsize + BUS_DMA_ALLOCNOW, // flags + NULL, NULL, // lockfunc, lockarg + &ioctl_data_tag[i])) { + device_printf(sc->mrsas_dev, "Cannot allocate ioctl data tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(ioctl_data_tag[i], (void **)&ioctl_data_mem[i], + (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_data_dmamap[i])) { + device_printf(sc->mrsas_dev, "Cannot allocate ioctl data mem\n"); + return (ENOMEM); + } + if (bus_dmamap_load(ioctl_data_tag[i], ioctl_data_dmamap[i], + ioctl_data_mem[i], ioctl_data_size, mrsas_alloc_cb, + &ioctl_data_phys_addr[i], BUS_DMA_NOWAIT)) { + device_printf(sc->mrsas_dev, "Cannot load ioctl data mem\n"); + return (ENOMEM); + } + + /* Save the physical address and length */ + kern_sge32[i].phys_addr = (u_int32_t)ioctl_data_phys_addr[i]; + kern_sge32[i].length = user_ioc->sgl[i].iov_len; + + /* Copy in data from user space */ + ret = copyin(user_ioc->sgl[i].iov_base, ioctl_data_mem[i], + user_ioc->sgl[i].iov_len); + if (ret) { + device_printf(sc->mrsas_dev, "IOCTL copyin failed!\n"); + goto out; + } + } + + ioctl_sense_size = user_ioc->sense_len; + if (user_ioc->sense_len) { + if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent + 1, 0, // algnmnt, boundary + BUS_SPACE_MAXADDR_32BIT,// lowaddr + BUS_SPACE_MAXADDR, // highaddr + NULL, NULL, // filter, filterarg + ioctl_sense_size, // maxsize + 1, // msegments + ioctl_sense_size, // maxsegsize + BUS_DMA_ALLOCNOW, // flags + NULL, NULL, // lockfunc, lockarg + &ioctl_sense_tag)) { + device_printf(sc->mrsas_dev, "Cannot allocate ioctl sense tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(ioctl_sense_tag, (void **)&ioctl_sense_mem, + (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_sense_dmamap)) { + device_printf(sc->mrsas_dev, "Cannot allocate ioctl data mem\n"); + return (ENOMEM); + } + if (bus_dmamap_load(ioctl_sense_tag, ioctl_sense_dmamap, + ioctl_sense_mem, ioctl_sense_size, mrsas_alloc_cb, + &ioctl_sense_phys_addr, BUS_DMA_NOWAIT)) { + device_printf(sc->mrsas_dev, "Cannot load ioctl sense mem\n"); + return (ENOMEM); + } + sense_ptr = + (unsigned long *)((unsigned long)cmd->frame + user_ioc->sense_off); + sense_ptr = ioctl_sense_mem; + } + + /* + * Set the sync_cmd flag so that the ISR knows not to complete this + * cmd to the SCSI mid-layer + */ + cmd->sync_cmd = 1; + mrsas_issue_blocked_cmd(sc, cmd); + cmd->sync_cmd = 0; + + /* + * copy out the kernel buffers to user buffers + */ + for (i = 0; i < user_ioc->sge_count; i++) { + ret = copyout(ioctl_data_mem[i], user_ioc->sgl[i].iov_base, + user_ioc->sgl[i].iov_len); + if (ret) { + device_printf(sc->mrsas_dev, "IOCTL copyout failed!\n"); + goto out; + } + } + + /* + * copy out the sense + */ + if (user_ioc->sense_len) { + /* + * sense_buff points to the location that has the user + * sense buffer address + */ + sense_ptr = (unsigned long *) ((unsigned long)user_ioc->frame.raw + + user_ioc->sense_off); + ret = copyout(ioctl_sense_mem, (unsigned long*)*sense_ptr, + user_ioc->sense_len); + if (ret) { + device_printf(sc->mrsas_dev, "IOCTL sense copyout failed!\n"); + goto out; + } + } + + /* + * Return command status to user space + */ + memcpy(&user_ioc->frame.hdr.cmd_status, &cmd->frame->hdr.cmd_status, + sizeof(u_int8_t)); + +out: + /* + * Release sense buffer + */ + if (ioctl_sense_phys_addr) + bus_dmamap_unload(ioctl_sense_tag, ioctl_sense_dmamap); + if (ioctl_sense_mem) + bus_dmamem_free(ioctl_sense_tag, ioctl_sense_mem, ioctl_sense_dmamap); + if (ioctl_sense_tag) + bus_dma_tag_destroy(ioctl_sense_tag); + + /* + * Release data buffers + */ + for (i = 0; i < user_ioc->sge_count; i++) { + if (!user_ioc->sgl[i].iov_len) + continue; + if (ioctl_data_phys_addr[i]) + bus_dmamap_unload(ioctl_data_tag[i], ioctl_data_dmamap[i]); + if (ioctl_data_mem[i] != NULL) + bus_dmamem_free(ioctl_data_tag[i], ioctl_data_mem[i], + ioctl_data_dmamap[i]); + if (ioctl_data_tag[i] != NULL) + bus_dma_tag_destroy(ioctl_data_tag[i]); + } + + /* Free command */ + mrsas_release_mfi_cmd(cmd); + + return(ret); +} + +/** + * mrsas_alloc_mfi_cmds: Allocates the command packets + * input: Adapter instance soft state + * + * Each IOCTL or passthru command that is issued to the FW are wrapped in a + * local data structure called mrsas_mfi_cmd. The frame embedded in this + * mrsas_mfi is issued to FW. The array is used only to look up the + * mrsas_mfi_cmd given the context. The free commands are maintained in a + * linked list. + */ +int mrsas_alloc_mfi_cmds(struct mrsas_softc *sc) +{ + int i, j; + u_int32_t max_cmd; + struct mrsas_mfi_cmd *cmd; + + max_cmd = MRSAS_MAX_MFI_CMDS; + + /* + * sc->mfi_cmd_list is an array of struct mrsas_mfi_cmd pointers. Allocate the + * dynamic array first and then allocate individual commands. + */ + sc->mfi_cmd_list = malloc(sizeof(struct mrsas_mfi_cmd*)*max_cmd, M_MRSAS, M_NOWAIT); + if (!sc->mfi_cmd_list) { + device_printf(sc->mrsas_dev, "Cannot alloc memory for mfi_cmd cmd_list.\n"); + return(ENOMEM); + } + memset(sc->mfi_cmd_list, 0, sizeof(struct mrsas_mfi_cmd *)*max_cmd); + for (i = 0; i < max_cmd; i++) { + sc->mfi_cmd_list[i] = malloc(sizeof(struct mrsas_mfi_cmd), + M_MRSAS, M_NOWAIT); + if (!sc->mfi_cmd_list[i]) { + for (j = 0; j < i; j++) + free(sc->mfi_cmd_list[j],M_MRSAS); + free(sc->mfi_cmd_list, M_MRSAS); + sc->mfi_cmd_list = NULL; + return(ENOMEM); + } + } + + for (i = 0; i < max_cmd; i++) { + cmd = sc->mfi_cmd_list[i]; + memset(cmd, 0, sizeof(struct mrsas_mfi_cmd)); + cmd->index = i; + cmd->ccb_ptr = NULL; + cmd->sc = sc; + TAILQ_INSERT_TAIL(&(sc->mrsas_mfi_cmd_list_head), cmd, next); + } + + /* create a frame pool and assign one frame to each command */ + if (mrsas_create_frame_pool(sc)) { + device_printf(sc->mrsas_dev, "Cannot allocate DMA frame pool.\n"); + for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) { // Free the frames + cmd = sc->mfi_cmd_list[i]; + mrsas_free_frame(sc, cmd); + } + if (sc->mficmd_frame_tag != NULL) + bus_dma_tag_destroy(sc->mficmd_frame_tag); + return(ENOMEM); + } + + return(0); +} + +/** + * mrsas_create_frame_pool - Creates DMA pool for cmd frames + * input: Adapter soft state + * + * Each command packet has an embedded DMA memory buffer that is used for + * filling MFI frame and the SG list that immediately follows the frame. This + * function creates those DMA memory buffers for each command packet by using + * PCI pool facility. pad_0 is initialized to 0 to prevent corrupting value + * of context and could cause FW crash. + */ +static int mrsas_create_frame_pool(struct mrsas_softc *sc) +{ + int i; + struct mrsas_mfi_cmd *cmd; + + if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent + 1, 0, // algnmnt, boundary + BUS_SPACE_MAXADDR_32BIT,// lowaddr + BUS_SPACE_MAXADDR, // highaddr + NULL, NULL, // filter, filterarg + MRSAS_MFI_FRAME_SIZE, // maxsize + 1, // msegments + MRSAS_MFI_FRAME_SIZE, // maxsegsize + BUS_DMA_ALLOCNOW, // flags + NULL, NULL, // lockfunc, lockarg + &sc->mficmd_frame_tag)) { + device_printf(sc->mrsas_dev, "Cannot create MFI frame tag\n"); + return (ENOMEM); + } + + for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) { + cmd = sc->mfi_cmd_list[i]; + cmd->frame = mrsas_alloc_frame(sc, cmd); + if (cmd->frame == NULL) { + device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n"); + return (ENOMEM); + } + memset(cmd->frame, 0, MRSAS_MFI_FRAME_SIZE); + cmd->frame->io.context = cmd->index; + cmd->frame->io.pad_0 = 0; + } + + return(0); +} + +/** + * mrsas_alloc_frame - Allocates MFI Frames + * input: Adapter soft state + * + * Create bus DMA memory tag and dmamap and load memory for MFI frames. + * Returns virtual memory pointer to allocated region. + */ +void *mrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd) +{ + u_int32_t frame_size = MRSAS_MFI_FRAME_SIZE; + + if (bus_dmamem_alloc(sc->mficmd_frame_tag, (void **)&cmd->frame_mem, + BUS_DMA_NOWAIT, &cmd->frame_dmamap)) { + device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n"); + return (NULL); + } + if (bus_dmamap_load(sc->mficmd_frame_tag, cmd->frame_dmamap, + cmd->frame_mem, frame_size, mrsas_alloc_cb, + &cmd->frame_phys_addr, BUS_DMA_NOWAIT)) { + device_printf(sc->mrsas_dev, "Cannot load IO request memory\n"); + return (NULL); + } + + return(cmd->frame_mem); +} + +/* + * mrsas_alloc_cb: Callback function of bus_dmamap_load() + * input: callback argument, + * machine dependent type that describes DMA segments, + * number of segments, + * error code. + * + * This function is for the driver to receive mapping information resultant + * of the bus_dmamap_load(). The information is actually not being used, + * but the address is saved anyway. + */ +static void mrsas_alloc_cb(void *arg, bus_dma_segment_t *segs, + int nsegs, int error) +{ + bus_addr_t *addr; + + addr = arg; + *addr = segs[0].ds_addr; +} + +/** + * mrsas_free_frames: Frees memory for MFI frames + * input: Adapter soft state + * + * Deallocates MFI frames memory. Called from mrsas_free_mem() during + * detach and error case during creation of frame pool. + */ +void mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd) +{ + if (cmd->frame_phys_addr) + bus_dmamap_unload(sc->mficmd_frame_tag, cmd->frame_dmamap); + if (cmd->frame_mem != NULL) + bus_dmamem_free(sc->mficmd_frame_tag, cmd->frame_mem, cmd->frame_dmamap); +} diff --git a/sys/dev/mrsas/mrsas_ioctl.h b/sys/dev/mrsas/mrsas_ioctl.h new file mode 100644 index 0000000000000..360484277678b --- /dev/null +++ b/sys/dev/mrsas/mrsas_ioctl.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2014, LSI Corp. + * All rights reserved. + * Author: Marian Choy + * Support: freebsdraid@lsi.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of the <ORGANIZATION> nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Send feedback to: <megaraidfbsd@lsi.com> + * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035 + * ATTN: MegaRaid FreeBSD + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifndef MRSAS_IOCTL_H +#define MRSAS_IOCTL_H + +#ifndef _IOWR +#include <sys/ioccom.h> +#endif /* !_IOWR */ + +/* + * We need to use the same values as the mfi driver until MegaCli adds + * support for this (mrsas) driver: + * M is for MegaRAID. (This is typically the vendor or product initial) + * 1 arbitrary. (This may be used to segment kinds of commands. + * (1-9 status, 10-20 policy, etc.) + * struct mrsas_iocpacket (sizeof() this parameter will be used.) + * These three values are encoded into a somewhat unique, 32-bit value. + */ + +#define MRSAS_IOC_FIRMWARE_PASS_THROUGH _IOWR('M', 1, struct mrsas_iocpacket) + +#define MRSAS_IOC_SCAN_BUS _IO('M', 10) + +#define MAX_IOCTL_SGE 16 +#define MFI_FRAME_DIR_READ 0x0010 +#define MFI_CMD_LD_SCSI_IO 0x03 + +#define INQUIRY_CMD 0x12 +#define INQUIRY_CMDLEN 6 +#define INQUIRY_REPLY_LEN 96 +#define INQUIRY_VENDOR 8 /* Offset in reply data to vendor name */ +#define SCSI_SENSE_BUFFERSIZE 96 + +#define MEGAMFI_RAW_FRAME_SIZE 128 + + +#pragma pack(1) +struct mrsas_iocpacket { + u_int16_t host_no; + u_int16_t __pad1; + u_int32_t sgl_off; + u_int32_t sge_count; + u_int32_t sense_off; + u_int32_t sense_len; + union { + u_int8_t raw[MEGAMFI_RAW_FRAME_SIZE]; + struct mrsas_header hdr; + } frame; + struct iovec sgl[MAX_IOCTL_SGE]; +}; +#pragma pack() + +#endif /* MRSAS_IOCTL_H */ diff --git a/sys/dev/null/null.c b/sys/dev/null/null.c index c1208c119bbe7..f836147a773c9 100644 --- a/sys/dev/null/null.c +++ b/sys/dev/null/null.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2000 Mark R. V. Murray & Jeroen C. van Gelderen * Copyright (c) 2001-2004 Mark R. V. Murray + * Copyright (c) 2014 Eitan Adler * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,14 +46,24 @@ __FBSDID("$FreeBSD$"); #include <machine/vmparam.h> /* For use with destroy_dev(9). */ +static struct cdev *full_dev; static struct cdev *null_dev; static struct cdev *zero_dev; +static d_write_t full_write; static d_write_t null_write; static d_ioctl_t null_ioctl; static d_ioctl_t zero_ioctl; static d_read_t zero_read; +static struct cdevsw full_cdevsw = { + .d_version = D_VERSION, + .d_read = zero_read, + .d_write = full_write, + .d_ioctl = zero_ioctl, + .d_name = "full", +}; + static struct cdevsw null_cdevsw = { .d_version = D_VERSION, .d_read = (d_read_t *)nullop, @@ -70,6 +81,16 @@ static struct cdevsw zero_cdevsw = { .d_flags = D_MMAP_ANON, }; + + +/* ARGSUSED */ +static int +full_write(struct cdev *dev __unused, struct uio *uio __unused, int flags __unused) +{ + + return (ENOSPC); +} + /* ARGSUSED */ static int null_write(struct cdev *dev __unused, struct uio *uio, int flags __unused) @@ -155,7 +176,9 @@ null_modevent(module_t mod __unused, int type, void *data __unused) switch(type) { case MOD_LOAD: if (bootverbose) - printf("null: <null device, zero device>\n"); + printf("null: <full device, null device, zero device>\n"); + full_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &full_cdevsw, 0, + NULL, UID_ROOT, GID_WHEEL, 0666, "full"); null_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &null_cdevsw, 0, NULL, UID_ROOT, GID_WHEEL, 0666, "null"); zero_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &zero_cdevsw, 0, @@ -163,6 +186,7 @@ null_modevent(module_t mod __unused, int type, void *data __unused) break; case MOD_UNLOAD: + destroy_dev(full_dev); destroy_dev(null_dev); destroy_dev(zero_dev); break; diff --git a/sys/dev/ofw/ofw_bus.h b/sys/dev/ofw/ofw_bus.h index 7f0e50e7f347b..f7c72958d55fc 100644 --- a/sys/dev/ofw/ofw_bus.h +++ b/sys/dev/ofw/ofw_bus.h @@ -76,12 +76,4 @@ ofw_bus_map_intr(device_t dev, phandle_t iparent, int icells, pcell_t *intr) return (OFW_BUS_MAP_INTR(dev, dev, iparent, icells, intr)); } -static __inline int -ofw_bus_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells, - pcell_t *gpios, uint32_t *pin, uint32_t *flags) -{ - return (OFW_BUS_MAP_GPIOS(bus, dev, gparent, gcells, gpios, pin, - flags)); -} - #endif /* !_DEV_OFW_OFW_BUS_H_ */ diff --git a/sys/dev/ofw/ofw_bus_if.m b/sys/dev/ofw/ofw_bus_if.m index 86c9876181551..36d10e6168002 100644 --- a/sys/dev/ofw/ofw_bus_if.m +++ b/sys/dev/ofw/ofw_bus_if.m @@ -58,7 +58,6 @@ CODE { static ofw_bus_get_node_t ofw_bus_default_get_node; static ofw_bus_get_type_t ofw_bus_default_get_type; static ofw_bus_map_intr_t ofw_bus_default_map_intr; - static ofw_bus_map_gpios_t ofw_bus_default_map_gpios; static const struct ofw_bus_devinfo * ofw_bus_default_get_devinfo(device_t bus, device_t dev) @@ -114,24 +113,6 @@ CODE { /* If that fails, then assume a one-domain system */ return (interrupt[0]); } - - int - ofw_bus_default_map_gpios(device_t bus, phandle_t dev, - phandle_t gparent, int gcells, pcell_t *gpios, uint32_t *pin, - uint32_t *flags) - { - /* Propagate up the bus hierarchy until someone handles it. */ - if (device_get_parent(bus) != NULL) - return OFW_BUS_MAP_GPIOS(device_get_parent(bus), dev, - gparent, gcells, gpios, pin, flags); - - /* If that fails, then assume the FreeBSD defaults. */ - *pin = gpios[0]; - if (gcells == 2 || gcells == 3) - *flags = gpios[gcells - 1]; - - return (0); - } }; # Get the ofw_bus_devinfo struct for the device dev on the bus. Used for bus @@ -188,14 +169,3 @@ METHOD int map_intr { int icells; pcell_t *interrupt; } DEFAULT ofw_bus_default_map_intr; - -# Map the GPIO controller specific gpio-specifier to GPIO pin and flags. -METHOD int map_gpios { - device_t bus; - phandle_t dev; - phandle_t gparent; - int gcells; - pcell_t *gpios; - uint32_t *pin; - uint32_t *flags; -} DEFAULT ofw_bus_default_map_gpios; diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 9df891bedb07a..7d36b6261c708 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -3968,105 +3968,107 @@ static const struct { int class; int subclass; + int report; /* 0 = bootverbose, 1 = always */ const char *desc; } pci_nomatch_tab[] = { - {PCIC_OLD, -1, "old"}, - {PCIC_OLD, PCIS_OLD_NONVGA, "non-VGA display device"}, - {PCIC_OLD, PCIS_OLD_VGA, "VGA-compatible display device"}, - {PCIC_STORAGE, -1, "mass storage"}, - {PCIC_STORAGE, PCIS_STORAGE_SCSI, "SCSI"}, - {PCIC_STORAGE, PCIS_STORAGE_IDE, "ATA"}, - {PCIC_STORAGE, PCIS_STORAGE_FLOPPY, "floppy disk"}, - {PCIC_STORAGE, PCIS_STORAGE_IPI, "IPI"}, - {PCIC_STORAGE, PCIS_STORAGE_RAID, "RAID"}, - {PCIC_STORAGE, PCIS_STORAGE_ATA_ADMA, "ATA (ADMA)"}, - {PCIC_STORAGE, PCIS_STORAGE_SATA, "SATA"}, - {PCIC_STORAGE, PCIS_STORAGE_SAS, "SAS"}, - {PCIC_STORAGE, PCIS_STORAGE_NVM, "NVM"}, - {PCIC_NETWORK, -1, "network"}, - {PCIC_NETWORK, PCIS_NETWORK_ETHERNET, "ethernet"}, - {PCIC_NETWORK, PCIS_NETWORK_TOKENRING, "token ring"}, - {PCIC_NETWORK, PCIS_NETWORK_FDDI, "fddi"}, - {PCIC_NETWORK, PCIS_NETWORK_ATM, "ATM"}, - {PCIC_NETWORK, PCIS_NETWORK_ISDN, "ISDN"}, - {PCIC_DISPLAY, -1, "display"}, - {PCIC_DISPLAY, PCIS_DISPLAY_VGA, "VGA"}, - {PCIC_DISPLAY, PCIS_DISPLAY_XGA, "XGA"}, - {PCIC_DISPLAY, PCIS_DISPLAY_3D, "3D"}, - {PCIC_MULTIMEDIA, -1, "multimedia"}, - {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_VIDEO, "video"}, - {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_AUDIO, "audio"}, - {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_TELE, "telephony"}, - {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_HDA, "HDA"}, - {PCIC_MEMORY, -1, "memory"}, - {PCIC_MEMORY, PCIS_MEMORY_RAM, "RAM"}, - {PCIC_MEMORY, PCIS_MEMORY_FLASH, "flash"}, - {PCIC_BRIDGE, -1, "bridge"}, - {PCIC_BRIDGE, PCIS_BRIDGE_HOST, "HOST-PCI"}, - {PCIC_BRIDGE, PCIS_BRIDGE_ISA, "PCI-ISA"}, - {PCIC_BRIDGE, PCIS_BRIDGE_EISA, "PCI-EISA"}, - {PCIC_BRIDGE, PCIS_BRIDGE_MCA, "PCI-MCA"}, - {PCIC_BRIDGE, PCIS_BRIDGE_PCI, "PCI-PCI"}, - {PCIC_BRIDGE, PCIS_BRIDGE_PCMCIA, "PCI-PCMCIA"}, - {PCIC_BRIDGE, PCIS_BRIDGE_NUBUS, "PCI-NuBus"}, - {PCIC_BRIDGE, PCIS_BRIDGE_CARDBUS, "PCI-CardBus"}, - {PCIC_BRIDGE, PCIS_BRIDGE_RACEWAY, "PCI-RACEway"}, - {PCIC_SIMPLECOMM, -1, "simple comms"}, - {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_UART, "UART"}, /* could detect 16550 */ - {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_PAR, "parallel port"}, - {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MULSER, "multiport serial"}, - {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MODEM, "generic modem"}, - {PCIC_BASEPERIPH, -1, "base peripheral"}, - {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PIC, "interrupt controller"}, - {PCIC_BASEPERIPH, PCIS_BASEPERIPH_DMA, "DMA controller"}, - {PCIC_BASEPERIPH, PCIS_BASEPERIPH_TIMER, "timer"}, - {PCIC_BASEPERIPH, PCIS_BASEPERIPH_RTC, "realtime clock"}, - {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PCIHOT, "PCI hot-plug controller"}, - {PCIC_BASEPERIPH, PCIS_BASEPERIPH_SDHC, "SD host controller"}, - {PCIC_INPUTDEV, -1, "input device"}, - {PCIC_INPUTDEV, PCIS_INPUTDEV_KEYBOARD, "keyboard"}, - {PCIC_INPUTDEV, PCIS_INPUTDEV_DIGITIZER,"digitizer"}, - {PCIC_INPUTDEV, PCIS_INPUTDEV_MOUSE, "mouse"}, - {PCIC_INPUTDEV, PCIS_INPUTDEV_SCANNER, "scanner"}, - {PCIC_INPUTDEV, PCIS_INPUTDEV_GAMEPORT, "gameport"}, - {PCIC_DOCKING, -1, "docking station"}, - {PCIC_PROCESSOR, -1, "processor"}, - {PCIC_SERIALBUS, -1, "serial bus"}, - {PCIC_SERIALBUS, PCIS_SERIALBUS_FW, "FireWire"}, - {PCIC_SERIALBUS, PCIS_SERIALBUS_ACCESS, "AccessBus"}, - {PCIC_SERIALBUS, PCIS_SERIALBUS_SSA, "SSA"}, - {PCIC_SERIALBUS, PCIS_SERIALBUS_USB, "USB"}, - {PCIC_SERIALBUS, PCIS_SERIALBUS_FC, "Fibre Channel"}, - {PCIC_SERIALBUS, PCIS_SERIALBUS_SMBUS, "SMBus"}, - {PCIC_WIRELESS, -1, "wireless controller"}, - {PCIC_WIRELESS, PCIS_WIRELESS_IRDA, "iRDA"}, - {PCIC_WIRELESS, PCIS_WIRELESS_IR, "IR"}, - {PCIC_WIRELESS, PCIS_WIRELESS_RF, "RF"}, - {PCIC_INTELLIIO, -1, "intelligent I/O controller"}, - {PCIC_INTELLIIO, PCIS_INTELLIIO_I2O, "I2O"}, - {PCIC_SATCOM, -1, "satellite communication"}, - {PCIC_SATCOM, PCIS_SATCOM_TV, "sat TV"}, - {PCIC_SATCOM, PCIS_SATCOM_AUDIO, "sat audio"}, - {PCIC_SATCOM, PCIS_SATCOM_VOICE, "sat voice"}, - {PCIC_SATCOM, PCIS_SATCOM_DATA, "sat data"}, - {PCIC_CRYPTO, -1, "encrypt/decrypt"}, - {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, "network/computer crypto"}, - {PCIC_CRYPTO, PCIS_CRYPTO_ENTERTAIN, "entertainment crypto"}, - {PCIC_DASP, -1, "dasp"}, - {PCIC_DASP, PCIS_DASP_DPIO, "DPIO module"}, - {0, 0, NULL} + {PCIC_OLD, -1, 1, "old"}, + {PCIC_OLD, PCIS_OLD_NONVGA, 1, "non-VGA display device"}, + {PCIC_OLD, PCIS_OLD_VGA, 1, "VGA-compatible display device"}, + {PCIC_STORAGE, -1, 1, "mass storage"}, + {PCIC_STORAGE, PCIS_STORAGE_SCSI, 1, "SCSI"}, + {PCIC_STORAGE, PCIS_STORAGE_IDE, 1, "ATA"}, + {PCIC_STORAGE, PCIS_STORAGE_FLOPPY, 1, "floppy disk"}, + {PCIC_STORAGE, PCIS_STORAGE_IPI, 1, "IPI"}, + {PCIC_STORAGE, PCIS_STORAGE_RAID, 1, "RAID"}, + {PCIC_STORAGE, PCIS_STORAGE_ATA_ADMA, 1, "ATA (ADMA)"}, + {PCIC_STORAGE, PCIS_STORAGE_SATA, 1, "SATA"}, + {PCIC_STORAGE, PCIS_STORAGE_SAS, 1, "SAS"}, + {PCIC_STORAGE, PCIS_STORAGE_NVM, 1, "NVM"}, + {PCIC_NETWORK, -1, 1, "network"}, + {PCIC_NETWORK, PCIS_NETWORK_ETHERNET, 1, "ethernet"}, + {PCIC_NETWORK, PCIS_NETWORK_TOKENRING, 1, "token ring"}, + {PCIC_NETWORK, PCIS_NETWORK_FDDI, 1, "fddi"}, + {PCIC_NETWORK, PCIS_NETWORK_ATM, 1, "ATM"}, + {PCIC_NETWORK, PCIS_NETWORK_ISDN, 1, "ISDN"}, + {PCIC_DISPLAY, -1, 1, "display"}, + {PCIC_DISPLAY, PCIS_DISPLAY_VGA, 1, "VGA"}, + {PCIC_DISPLAY, PCIS_DISPLAY_XGA, 1, "XGA"}, + {PCIC_DISPLAY, PCIS_DISPLAY_3D, 1, "3D"}, + {PCIC_MULTIMEDIA, -1, 1, "multimedia"}, + {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_VIDEO, 1, "video"}, + {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_AUDIO, 1, "audio"}, + {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_TELE, 1, "telephony"}, + {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_HDA, 1, "HDA"}, + {PCIC_MEMORY, -1, 1, "memory"}, + {PCIC_MEMORY, PCIS_MEMORY_RAM, 1, "RAM"}, + {PCIC_MEMORY, PCIS_MEMORY_FLASH, 1, "flash"}, + {PCIC_BRIDGE, -1, 1, "bridge"}, + {PCIC_BRIDGE, PCIS_BRIDGE_HOST, 1, "HOST-PCI"}, + {PCIC_BRIDGE, PCIS_BRIDGE_ISA, 1, "PCI-ISA"}, + {PCIC_BRIDGE, PCIS_BRIDGE_EISA, 1, "PCI-EISA"}, + {PCIC_BRIDGE, PCIS_BRIDGE_MCA, 1, "PCI-MCA"}, + {PCIC_BRIDGE, PCIS_BRIDGE_PCI, 1, "PCI-PCI"}, + {PCIC_BRIDGE, PCIS_BRIDGE_PCMCIA, 1, "PCI-PCMCIA"}, + {PCIC_BRIDGE, PCIS_BRIDGE_NUBUS, 1, "PCI-NuBus"}, + {PCIC_BRIDGE, PCIS_BRIDGE_CARDBUS, 1, "PCI-CardBus"}, + {PCIC_BRIDGE, PCIS_BRIDGE_RACEWAY, 1, "PCI-RACEway"}, + {PCIC_SIMPLECOMM, -1, 1, "simple comms"}, + {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_UART, 1, "UART"}, /* could detect 16550 */ + {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_PAR, 1, "parallel port"}, + {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MULSER, 1, "multiport serial"}, + {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MODEM, 1, "generic modem"}, + {PCIC_BASEPERIPH, -1, 0, "base peripheral"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PIC, 1, "interrupt controller"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_DMA, 1, "DMA controller"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_TIMER, 1, "timer"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_RTC, 1, "realtime clock"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PCIHOT, 1, "PCI hot-plug controller"}, + {PCIC_BASEPERIPH, PCIS_BASEPERIPH_SDHC, 1, "SD host controller"}, + {PCIC_INPUTDEV, -1, 1, "input device"}, + {PCIC_INPUTDEV, PCIS_INPUTDEV_KEYBOARD, 1, "keyboard"}, + {PCIC_INPUTDEV, PCIS_INPUTDEV_DIGITIZER,1, "digitizer"}, + {PCIC_INPUTDEV, PCIS_INPUTDEV_MOUSE, 1, "mouse"}, + {PCIC_INPUTDEV, PCIS_INPUTDEV_SCANNER, 1, "scanner"}, + {PCIC_INPUTDEV, PCIS_INPUTDEV_GAMEPORT, 1, "gameport"}, + {PCIC_DOCKING, -1, 1, "docking station"}, + {PCIC_PROCESSOR, -1, 1, "processor"}, + {PCIC_SERIALBUS, -1, 1, "serial bus"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_FW, 1, "FireWire"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_ACCESS, 1, "AccessBus"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_SSA, 1, "SSA"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_USB, 1, "USB"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_FC, 1, "Fibre Channel"}, + {PCIC_SERIALBUS, PCIS_SERIALBUS_SMBUS, 0, "SMBus"}, + {PCIC_WIRELESS, -1, 1, "wireless controller"}, + {PCIC_WIRELESS, PCIS_WIRELESS_IRDA, 1, "iRDA"}, + {PCIC_WIRELESS, PCIS_WIRELESS_IR, 1, "IR"}, + {PCIC_WIRELESS, PCIS_WIRELESS_RF, 1, "RF"}, + {PCIC_INTELLIIO, -1, 1, "intelligent I/O controller"}, + {PCIC_INTELLIIO, PCIS_INTELLIIO_I2O, 1, "I2O"}, + {PCIC_SATCOM, -1, 1, "satellite communication"}, + {PCIC_SATCOM, PCIS_SATCOM_TV, 1, "sat TV"}, + {PCIC_SATCOM, PCIS_SATCOM_AUDIO, 1, "sat audio"}, + {PCIC_SATCOM, PCIS_SATCOM_VOICE, 1, "sat voice"}, + {PCIC_SATCOM, PCIS_SATCOM_DATA, 1, "sat data"}, + {PCIC_CRYPTO, -1, 1, "encrypt/decrypt"}, + {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, 1, "network/computer crypto"}, + {PCIC_CRYPTO, PCIS_CRYPTO_ENTERTAIN, 1, "entertainment crypto"}, + {PCIC_DASP, -1, 0, "dasp"}, + {PCIC_DASP, PCIS_DASP_DPIO, 1, "DPIO module"}, + {0, 0, 0, NULL} }; void pci_probe_nomatch(device_t dev, device_t child) { - int i; + int i, report; const char *cp, *scp; char *device; /* * Look for a listing for this device in a loaded device database. */ + report = 1; if ((device = pci_describe_device(child)) != NULL) { device_printf(dev, "<%s>", device); free(device, M_DEVBUF); @@ -4081,19 +4083,25 @@ pci_probe_nomatch(device_t dev, device_t child) if (pci_nomatch_tab[i].class == pci_get_class(child)) { if (pci_nomatch_tab[i].subclass == -1) { cp = pci_nomatch_tab[i].desc; + report = pci_nomatch_tab[i].report; } else if (pci_nomatch_tab[i].subclass == pci_get_subclass(child)) { scp = pci_nomatch_tab[i].desc; + report = pci_nomatch_tab[i].report; } } } - device_printf(dev, "<%s%s%s>", - cp ? cp : "", - ((cp != NULL) && (scp != NULL)) ? ", " : "", - scp ? scp : ""); + if (report || bootverbose) { + device_printf(dev, "<%s%s%s>", + cp ? cp : "", + ((cp != NULL) && (scp != NULL)) ? ", " : "", + scp ? scp : ""); + } + } + if (report || bootverbose) { + printf(" at device %d.%d (no driver attached)\n", + pci_get_slot(child), pci_get_function(child)); } - printf(" at device %d.%d (no driver attached)\n", - pci_get_slot(child), pci_get_function(child)); pci_cfg_save(child, device_get_ivars(child), 1); } diff --git a/sys/dev/pci/pci_if.m b/sys/dev/pci/pci_if.m index 0f19358d4a2ab..82864eb71bab9 100644 --- a/sys/dev/pci/pci_if.m +++ b/sys/dev/pci/pci_if.m @@ -161,7 +161,7 @@ METHOD int msix_count { } DEFAULT null_msi_count; METHOD uint16_t get_rid { - device_t dev; - device_t child; + device_t dev; + device_t child; }; diff --git a/sys/dev/pci/pcib_if.m b/sys/dev/pci/pcib_if.m index 835e2c39cdac1..0d7cf16087180 100644 --- a/sys/dev/pci/pcib_if.m +++ b/sys/dev/pci/pcib_if.m @@ -169,8 +169,8 @@ METHOD int power_for_sleep { # Return the PCI Routing Identifier (RID) for the device. # METHOD uint16_t get_rid { - device_t pcib; - device_t dev; + device_t pcib; + device_t dev; } DEFAULT pcib_get_rid; # diff --git a/sys/dev/proto/proto.h b/sys/dev/proto/proto.h new file mode 100644 index 0000000000000..db61da5486544 --- /dev/null +++ b/sys/dev/proto/proto.h @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2014 Marcel Moolenaar + * 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 ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_PROTO_H_ +#define _DEV_PROTO_H_ + +#define PROTO_RES_MAX 16 + +#define PROTO_RES_UNUSED 0 +#define PROTO_RES_PCICFG 10 + +struct proto_res { + int r_type; + int r_rid; + struct resource *r_res; + u_long r_size; + union { + void *cookie; + struct cdev *cdev; + } r_u; + uintptr_t r_opened; +}; + +struct proto_softc { + device_t sc_dev; + struct proto_res sc_res[PROTO_RES_MAX]; + int sc_rescnt; +}; + +extern devclass_t proto_devclass; +extern char proto_driver_name[]; + +int proto_add_resource(struct proto_softc *, int, int, struct resource *); + +int proto_attach(device_t dev); +int proto_detach(device_t dev); + +#endif /* _DEV_PROTO_H_ */ diff --git a/sys/dev/proto/proto_bus_pci.c b/sys/dev/proto/proto_bus_pci.c new file mode 100644 index 0000000000000..012469a2d712c --- /dev/null +++ b/sys/dev/proto/proto_bus_pci.c @@ -0,0 +1,112 @@ +/*- + * Copyright (c) 2014 Marcel Moolenaar + * 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 ``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/bus.h> +#include <sys/conf.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> +#include <sys/sbuf.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <dev/proto/proto.h> + +static int proto_pci_probe(device_t dev); +static int proto_pci_attach(device_t dev); + +static device_method_t proto_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, proto_pci_probe), + DEVMETHOD(device_attach, proto_pci_attach), + DEVMETHOD(device_detach, proto_detach), + DEVMETHOD_END +}; + +static driver_t proto_pci_driver = { + proto_driver_name, + proto_pci_methods, + sizeof(struct proto_softc), +}; + +static int +proto_pci_probe(device_t dev) +{ + struct sbuf *sb; + + /* For now we only attach to function 0 devices. */ + if (pci_get_function(dev) != 0) + return (ENXIO); + + sb = sbuf_new_auto(); + sbuf_printf(sb, "pci%d:%d:%d:%d", pci_get_domain(dev), + pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); + sbuf_finish(sb); + device_set_desc_copy(dev, sbuf_data(sb)); + sbuf_delete(sb); + return (BUS_PROBE_HOOVER); +} + +static int +proto_pci_attach(device_t dev) +{ + struct proto_softc *sc; + struct resource *res; + int bar, rid, type; + + sc = device_get_softc(dev); + + proto_add_resource(sc, PROTO_RES_PCICFG, 0, NULL); + + for (bar = 0; bar < PCIR_MAX_BAR_0; bar++) { + rid = PCIR_BAR(bar); + type = SYS_RES_MEMORY; + res = bus_alloc_resource_any(dev, type, &rid, RF_ACTIVE); + if (res == NULL) { + type = SYS_RES_IOPORT; + res = bus_alloc_resource_any(dev, type, &rid, + RF_ACTIVE); + } + if (res != NULL) + proto_add_resource(sc, type, rid, res); + } + + rid = 0; + type = SYS_RES_IRQ; + res = bus_alloc_resource_any(dev, type, &rid, RF_ACTIVE | RF_SHAREABLE); + if (res != NULL) + proto_add_resource(sc, type, rid, res); + return (proto_attach(dev)); +} + +DRIVER_MODULE(proto, pci, proto_pci_driver, proto_devclass, NULL, NULL); diff --git a/sys/dev/proto/proto_core.c b/sys/dev/proto/proto_core.c new file mode 100644 index 0000000000000..5ea0a6c126678 --- /dev/null +++ b/sys/dev/proto/proto_core.c @@ -0,0 +1,384 @@ +/*- + * Copyright (c) 2014 Marcel Moolenaar + * 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 ``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/bus.h> +#include <sys/conf.h> +#include <sys/cons.h> +#include <sys/fcntl.h> +#include <sys/interrupt.h> +#include <sys/kdb.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mman.h> +#include <sys/proc.h> +#include <sys/queue.h> +#include <sys/reboot.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <sys/uio.h> +#include <machine/resource.h> +#include <machine/stdarg.h> + +#include <dev/pci/pcivar.h> + +#include <dev/proto/proto.h> +#include <dev/proto/proto_dev.h> + +CTASSERT(SYS_RES_IRQ != PROTO_RES_UNUSED && + SYS_RES_MEMORY != PROTO_RES_UNUSED && + SYS_RES_IOPORT != PROTO_RES_UNUSED); +CTASSERT(SYS_RES_IRQ != PROTO_RES_PCICFG && + SYS_RES_MEMORY != PROTO_RES_PCICFG && + SYS_RES_IOPORT != PROTO_RES_PCICFG); + +devclass_t proto_devclass; +char proto_driver_name[] = "proto"; + +static d_open_t proto_open; +static d_close_t proto_close; +static d_read_t proto_read; +static d_write_t proto_write; +static d_ioctl_t proto_ioctl; +static d_mmap_t proto_mmap; + +struct cdevsw proto_devsw = { + .d_version = D_VERSION, + .d_flags = 0, + .d_name = proto_driver_name, + .d_open = proto_open, + .d_close = proto_close, + .d_read = proto_read, + .d_write = proto_write, + .d_ioctl = proto_ioctl, + .d_mmap = proto_mmap, +}; + +static MALLOC_DEFINE(M_PROTO, "PROTO", "PROTO driver"); + +int +proto_add_resource(struct proto_softc *sc, int type, int rid, + struct resource *res) +{ + struct proto_res *r; + + if (type == PROTO_RES_UNUSED) + return (EINVAL); + if (sc->sc_rescnt == PROTO_RES_MAX) + return (ENOSPC); + + r = sc->sc_res + sc->sc_rescnt++; + r->r_type = type; + r->r_rid = rid; + r->r_res = res; + return (0); +} + +#ifdef notyet +static int +proto_intr(void *arg) +{ + struct proto_softc *sc = arg; + + /* XXX TODO */ + return (FILTER_HANDLED); +} +#endif + +int +proto_attach(device_t dev) +{ + struct proto_softc *sc; + struct proto_res *r; + u_int res; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + for (res = 0; res < sc->sc_rescnt; res++) { + r = sc->sc_res + res; + switch (r->r_type) { + case SYS_RES_IRQ: + /* XXX TODO */ + break; + case SYS_RES_MEMORY: + case SYS_RES_IOPORT: + r->r_size = rman_get_size(r->r_res); + r->r_u.cdev = make_dev(&proto_devsw, res, 0, 0, 0666, + "proto/%s/%02x.%s", device_get_desc(dev), r->r_rid, + (r->r_type == SYS_RES_IOPORT) ? "io" : "mem"); + r->r_u.cdev->si_drv1 = sc; + r->r_u.cdev->si_drv2 = r; + break; + case PROTO_RES_PCICFG: + r->r_size = 4096; + r->r_u.cdev = make_dev(&proto_devsw, res, 0, 0, 0666, + "proto/%s/pcicfg", device_get_desc(dev)); + r->r_u.cdev->si_drv1 = sc; + r->r_u.cdev->si_drv2 = r; + break; + } + } + return (0); +} + +int +proto_detach(device_t dev) +{ + struct proto_softc *sc; + struct proto_res *r; + u_int res; + + sc = device_get_softc(dev); + + /* Don't detach if we have open device filess. */ + for (res = 0; res < sc->sc_rescnt; res++) { + r = sc->sc_res + res; + if (r->r_opened) + return (EBUSY); + } + + for (res = 0; res < sc->sc_rescnt; res++) { + r = sc->sc_res + res; + switch (r->r_type) { + case SYS_RES_IRQ: + /* XXX TODO */ + break; + case SYS_RES_MEMORY: + case SYS_RES_IOPORT: + case PROTO_RES_PCICFG: + destroy_dev(r->r_u.cdev); + break; + } + if (r->r_res != NULL) { + bus_release_resource(dev, r->r_type, r->r_rid, + r->r_res); + r->r_res = NULL; + } + r->r_type = PROTO_RES_UNUSED; + } + sc->sc_rescnt = 0; + return (0); +} + +/* + * Device functions + */ + +static int +proto_open(struct cdev *cdev, int oflags, int devtype, struct thread *td) +{ + struct proto_res *r; + + r = cdev->si_drv2; + if (!atomic_cmpset_acq_ptr(&r->r_opened, 0UL, (uintptr_t)td->td_proc)) + return (EBUSY); + return (0); +} + +static int +proto_close(struct cdev *cdev, int fflag, int devtype, struct thread *td) +{ + struct proto_res *r; + + r = cdev->si_drv2; + if (!atomic_cmpset_acq_ptr(&r->r_opened, (uintptr_t)td->td_proc, 0UL)) + return (ENXIO); + return (0); +} + +static int +proto_read(struct cdev *cdev, struct uio *uio, int ioflag) +{ + union { + uint8_t x1[8]; + uint16_t x2[4]; + uint32_t x4[2]; + uint64_t x8[1]; + } buf; + struct proto_softc *sc; + struct proto_res *r; + device_t dev; + off_t ofs; + u_long width; + int error; + + sc = cdev->si_drv1; + dev = sc->sc_dev; + r = cdev->si_drv2; + + width = uio->uio_resid; + if (width < 1 || width > 8 || bitcount16(width) > 1) + return (EIO); + ofs = uio->uio_offset; + if (ofs + width > r->r_size) + return (EIO); + + switch (width) { + case 1: + buf.x1[0] = (r->r_type == PROTO_RES_PCICFG) ? + pci_read_config(dev, ofs, 1) : bus_read_1(r->r_res, ofs); + break; + case 2: + buf.x2[0] = (r->r_type == PROTO_RES_PCICFG) ? + pci_read_config(dev, ofs, 2) : bus_read_2(r->r_res, ofs); + break; + case 4: + buf.x4[0] = (r->r_type == PROTO_RES_PCICFG) ? + pci_read_config(dev, ofs, 4) : bus_read_4(r->r_res, ofs); + break; +#ifndef __i386__ + case 8: + if (r->r_type == PROTO_RES_PCICFG) + return (EINVAL); + buf.x8[0] = bus_read_8(r->r_res, ofs); + break; +#endif + default: + return (EIO); + } + + error = uiomove(&buf, width, uio); + return (error); +} + +static int +proto_write(struct cdev *cdev, struct uio *uio, int ioflag) +{ + union { + uint8_t x1[8]; + uint16_t x2[4]; + uint32_t x4[2]; + uint64_t x8[1]; + } buf; + struct proto_softc *sc; + struct proto_res *r; + device_t dev; + off_t ofs; + u_long width; + int error; + + sc = cdev->si_drv1; + dev = sc->sc_dev; + r = cdev->si_drv2; + + width = uio->uio_resid; + if (width < 1 || width > 8 || bitcount16(width) > 1) + return (EIO); + ofs = uio->uio_offset; + if (ofs + width > r->r_size) + return (EIO); + + error = uiomove(&buf, width, uio); + if (error) + return (error); + + switch (width) { + case 1: + if (r->r_type == PROTO_RES_PCICFG) + pci_write_config(dev, ofs, buf.x1[0], 1); + else + bus_write_1(r->r_res, ofs, buf.x1[0]); + break; + case 2: + if (r->r_type == PROTO_RES_PCICFG) + pci_write_config(dev, ofs, buf.x2[0], 2); + else + bus_write_2(r->r_res, ofs, buf.x2[0]); + break; + case 4: + if (r->r_type == PROTO_RES_PCICFG) + pci_write_config(dev, ofs, buf.x4[0], 4); + else + bus_write_4(r->r_res, ofs, buf.x4[0]); + break; +#ifndef __i386__ + case 8: + if (r->r_type == PROTO_RES_PCICFG) + return (EINVAL); + bus_write_8(r->r_res, ofs, buf.x8[0]); + break; +#endif + default: + return (EIO); + } + + return (0); +} + +static int +proto_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, + struct thread *td) +{ + struct proto_ioc_region *region; + struct proto_res *r; + int error; + + r = cdev->si_drv2; + + error = 0; + switch (cmd) { + case PROTO_IOC_REGION: + region = (struct proto_ioc_region *)data; + region->size = r->r_size; + if (r->r_type == PROTO_RES_PCICFG) + region->address = 0; + else + region->address = rman_get_start(r->r_res); + break; + default: + error = ENOIOCTL; + break; + } + return (error); +} + +static int +proto_mmap(struct cdev *cdev, vm_ooffset_t offset, vm_paddr_t *paddr, + int prot, vm_memattr_t *memattr) +{ + struct proto_res *r; + + r = cdev->si_drv2; + + if (r->r_type != SYS_RES_MEMORY) + return (ENXIO); + if (offset & PAGE_MASK) + return (EINVAL); + if (prot & PROT_EXEC) + return (EACCES); + if (offset >= r->r_size) + return (EINVAL); + *paddr = rman_get_start(r->r_res) + offset; +#ifndef __sparc64__ + *memattr = VM_MEMATTR_UNCACHEABLE; +#endif + return (0); +} diff --git a/sys/dev/proto/proto_dev.h b/sys/dev/proto/proto_dev.h new file mode 100644 index 0000000000000..0ea37495ce3be --- /dev/null +++ b/sys/dev/proto/proto_dev.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2014 Marcel Moolenaar + * 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 ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_PROTO_DEV_H_ +#define _DEV_PROTO_DEV_H_ + +#include <sys/ioccom.h> + +#define PROTO_IOC_CLASS 'h' + +struct proto_ioc_region { + unsigned long address; + unsigned long size; +}; + +#define PROTO_IOC_REGION _IOWR(PROTO_IOC_CLASS, 1, struct proto_ioc_region) + +#endif /* _DEV_PROTO_H_ */ diff --git a/sys/dev/sdhci/sdhci_fdt.c b/sys/dev/sdhci/sdhci_fdt.c index 65eac6df8b6aa..6a3d702a4c4fb 100644 --- a/sys/dev/sdhci/sdhci_fdt.c +++ b/sys/dev/sdhci/sdhci_fdt.c @@ -66,6 +66,7 @@ struct sdhci_fdt_softc { device_t dev; /* Controller device */ u_int quirks; /* Chip specific quirks */ u_int caps; /* If we override SDHCI_CAPABILITIES */ + uint32_t max_clk; /* Max possible freq */ struct resource *irq_res; /* IRQ resource */ void *intrhand; /* Interrupt handle */ @@ -156,6 +157,7 @@ sdhci_fdt_probe(device_t dev) sc->quirks = 0; sc->num_slots = 1; + sc->max_clk = 0; if (!ofw_bus_status_okay(dev)) return (ENXIO); @@ -170,11 +172,14 @@ sdhci_fdt_probe(device_t dev) node = ofw_bus_get_node(dev); - /* Allow dts to patch quirks and slots. */ - if ((OF_getprop(node, "quirks", &cid, sizeof(cid))) > 0) - sc->quirks = fdt32_to_cpu(cid); - if ((OF_getprop(node, "num-slots", &cid, sizeof(cid))) > 0) - sc->num_slots = fdt32_to_cpu(cid); + /* Allow dts to patch quirks, slots, and max-frequency. */ + if ((OF_getencprop(node, "quirks", &cid, sizeof(cid))) > 0) + sc->quirks = cid; + if ((OF_getencprop(node, "num-slots", &cid, sizeof(cid))) > 0) + sc->num_slots = cid; + if ((OF_getencprop(node, "max-frequency", &cid, sizeof(cid))) > 0) + sc->max_clk = cid; + return (0); } @@ -214,6 +219,7 @@ sdhci_fdt_attach(device_t dev) slot->quirks = sc->quirks; slot->caps = sc->caps; + slot->max_clk = sc->max_clk; if (sdhci_init_slot(dev, slot, i) != 0) continue; diff --git a/sys/dev/usb/controller/dwc_otg.c b/sys/dev/usb/controller/dwc_otg.c index 8c708019ad70e..d8bf7ea39be70 100644 --- a/sys/dev/usb/controller/dwc_otg.c +++ b/sys/dev/usb/controller/dwc_otg.c @@ -93,15 +93,13 @@ DWC_OTG_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus) #define DWC_OTG_MSK_GINT_ENABLED \ - (GINTSTS_ENUMDONE | \ - GINTSTS_USBRST | \ - GINTSTS_USBSUSP | \ - GINTSTS_IEPINT | \ - GINTSTS_RXFLVL | \ - GINTSTS_SESSREQINT | \ + (GINTMSK_ENUMDONEMSK | \ + GINTMSK_USBRSTMSK | \ + GINTMSK_USBSUSPMSK | \ + GINTMSK_IEPINTMSK | \ + GINTMSK_SESSREQINTMSK | \ GINTMSK_OTGINTMSK | \ - GINTMSK_HCHINTMSK | \ - GINTSTS_PRTINT) + GINTMSK_PRTINTMSK) static int dwc_otg_use_hsic; @@ -207,6 +205,12 @@ dwc_otg_init_fifo(struct dwc_otg_softc *sc, uint8_t mode) /* reset active endpoints */ sc->sc_active_rx_ep = 0; + /* reset TX size */ + sc->sc_tx_cur_size = 0; + + /* reset TT info */ + memset(sc->sc_tt_info, 0, sizeof(sc->sc_tt_info)); + fifo_size /= 2; DWC_OTG_WRITE_4(sc, DOTG_GNPTXFSIZ, @@ -215,23 +219,20 @@ dwc_otg_init_fifo(struct dwc_otg_softc *sc, uint8_t mode) tx_start += fifo_size; + for (x = 0; x != sc->sc_host_ch_max; x++) { + /* disable all host interrupts */ + DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(x), 0); + } + DWC_OTG_WRITE_4(sc, DOTG_HPTXFSIZ, ((fifo_size / 4) << 16) | (tx_start / 4)); - for (x = 0; x != sc->sc_host_ch_max; x++) { - /* enable interrupts */ - DWC_OTG_WRITE_4(sc, DOTG_HCINTMSK(x), - HCINT_STALL | HCINT_BBLERR | - HCINT_XACTERR | - HCINT_NAK | HCINT_ACK | HCINT_NYET | - HCINT_CHHLTD | HCINT_FRMOVRUN | - HCINT_DATATGLERR); - } + /* store maximum TX FIFO size */ + sc->sc_tx_max_size = fifo_size; - /* enable host channel interrupts */ - DWC_OTG_WRITE_4(sc, DOTG_HAINTMSK, - (1U << sc->sc_host_ch_max) - 1U); + /* disable all host channel interrupts */ + DWC_OTG_WRITE_4(sc, DOTG_HAINTMSK, 0); } if (mode == DWC_MODE_DEVICE) { @@ -309,11 +310,47 @@ dwc_otg_init_fifo(struct dwc_otg_softc *sc, uint8_t mode) } else { /* reset active endpoints */ sc->sc_active_rx_ep = 0; + + /* reset TX size */ + sc->sc_tx_cur_size = 0; + + /* reset TT info */ + memset(sc->sc_tt_info, 0, sizeof(sc->sc_tt_info)); } return (0); } static void +dwc_otg_update_host_frame_interval(struct dwc_otg_softc *sc) +{ + uint32_t temp; + + /* setup HOST frame interval register, based on existing value */ + temp = DWC_OTG_READ_4(sc, DOTG_HFIR) & HFIR_FRINT_MASK; + if (temp >= 10000) + temp /= 1000; + else + temp /= 125; + + /* figure out nearest X-tal value */ + if (temp >= 54) + temp = 60; /* MHz */ + else if (temp >= 39) + temp = 48; /* MHz */ + else + temp = 30; /* MHz */ + + if (sc->sc_flags.status_high_speed) + temp *= 125; + else + temp *= 1000; + + DPRINTF("HFIR=0x%08x\n", temp); + + DWC_OTG_WRITE_4(sc, DOTG_HFIR, temp); +} + +static void dwc_otg_clocks_on(struct dwc_otg_softc *sc) { if (sc->sc_flags.clocks_off && @@ -376,9 +413,11 @@ dwc_otg_pull_down(struct dwc_otg_softc *sc) static void dwc_otg_enable_sof_irq(struct dwc_otg_softc *sc) { - if (sc->sc_irq_mask & GINTSTS_SOF) + /* In device mode we don't use the SOF interrupt */ + if (sc->sc_flags.status_device_mode != 0 || + (sc->sc_irq_mask & GINTMSK_SOFMSK) != 0) return; - sc->sc_irq_mask |= GINTSTS_SOF; + sc->sc_irq_mask |= GINTMSK_SOFMSK; DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); } @@ -395,8 +434,8 @@ dwc_otg_resume_irq(struct dwc_otg_softc *sc) * Disable resume interrupt and enable suspend * interrupt: */ - sc->sc_irq_mask &= ~GINTSTS_WKUPINT; - sc->sc_irq_mask |= GINTSTS_USBSUSP; + sc->sc_irq_mask &= ~GINTMSK_WKUPINTMSK; + sc->sc_irq_mask |= GINTMSK_USBSUSPMSK; DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); } @@ -418,8 +457,8 @@ dwc_otg_suspend_irq(struct dwc_otg_softc *sc) * Disable suspend interrupt and enable resume * interrupt: */ - sc->sc_irq_mask &= ~GINTSTS_USBSUSP; - sc->sc_irq_mask |= GINTSTS_WKUPINT; + sc->sc_irq_mask &= ~GINTMSK_USBSUSPMSK; + sc->sc_irq_mask |= GINTMSK_WKUPINTMSK; DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); } @@ -493,9 +532,11 @@ dwc_otg_common_rx_ack(struct dwc_otg_softc *sc) { DPRINTFN(5, "RX status clear\n"); - /* enable RX FIFO level interrupt */ - sc->sc_irq_mask |= GINTSTS_RXFLVL; - DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); + if (sc->sc_flags.status_device_mode != 0) { + /* enable RX FIFO level interrupt */ + sc->sc_irq_mask |= GINTMSK_RXFLVLMSK; + DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); + } /* clear cached status */ sc->sc_last_rx_status = 0; @@ -506,6 +547,7 @@ dwc_otg_clear_hcint(struct dwc_otg_softc *sc, uint8_t x) { uint32_t hcint; + /* clear all pending interrupts */ hcint = DWC_OTG_READ_4(sc, DOTG_HCINT(x)); DWC_OTG_WRITE_4(sc, DOTG_HCINT(x), hcint); @@ -513,6 +555,10 @@ dwc_otg_clear_hcint(struct dwc_otg_softc *sc, uint8_t x) sc->sc_chan_state[x].hcint = 0; } +/* + * This function waits until a DWC OTG host channel is ready to be + * used again: + */ static uint8_t dwc_otg_host_channel_wait(struct dwc_otg_td *td) { @@ -545,6 +591,9 @@ dwc_otg_host_channel_wait(struct dwc_otg_td *td) sc->sc_chan_state[td->channel].allocated = 0; sc->sc_chan_state[x].allocated = 1; + sc->sc_chan_state[x].tx_size = + sc->sc_chan_state[td->channel].tx_size; + if (sc->sc_chan_state[td->channel].suspended) { sc->sc_chan_state[td->channel].suspended = 0; sc->sc_chan_state[x].suspended = 1; @@ -579,6 +628,7 @@ static uint8_t dwc_otg_host_channel_alloc(struct dwc_otg_td *td) { struct dwc_otg_softc *sc; + uint32_t tx_size; uint8_t x; uint8_t max_channel; @@ -591,9 +641,25 @@ dwc_otg_host_channel_alloc(struct dwc_otg_td *td) if ((td->hcchar & HCCHAR_EPNUM_MASK) == 0) { max_channel = 1; x = 0; + tx_size = td->max_packet_size; + if ((sc->sc_tx_cur_size + tx_size) > sc->sc_tx_max_size) { + DPRINTF("Too little FIFO space\n"); + return (1); /* too little FIFO */ + } } else { max_channel = sc->sc_host_ch_max; x = 1; + if ((td->hcchar & HCCHAR_EPDIR) == HCCHAR_EPDIR_OUT) { + tx_size = td->max_packet_size; + if (td->hcsplt != 0 && tx_size > HCSPLT_XACTLEN_MAX) + tx_size = HCSPLT_XACTLEN_MAX; + if ((sc->sc_tx_cur_size + tx_size) > sc->sc_tx_max_size) { + DPRINTF("Too little FIFO space\n"); + return (1); /* too little FIFO */ + } + } else { + tx_size = 0; + } } for (; x != max_channel; x++) { @@ -604,6 +670,10 @@ dwc_otg_host_channel_alloc(struct dwc_otg_td *td) continue; sc->sc_chan_state[x].allocated = 1; + sc->sc_chan_state[x].tx_size = tx_size; + + /* keep track of used FIFO */ + sc->sc_tx_cur_size += tx_size; /* clear interrupts */ dwc_otg_clear_hcint(sc, x); @@ -635,8 +705,6 @@ dwc_otg_host_channel_disable(struct dwc_otg_softc *sc, uint8_t x) HCCHAR_CHENA | HCCHAR_CHDIS); /* don't re-use channel until next SOF is transmitted */ sc->sc_chan_state[x].wait_sof = 2; - /* enable SOF interrupt */ - dwc_otg_enable_sof_irq(sc); } } @@ -663,6 +731,9 @@ dwc_otg_host_channel_free(struct dwc_otg_td *td) sc->sc_chan_state[x].allocated = 0; sc->sc_chan_state[x].suspended = 0; + /* keep track of used FIFO */ + sc->sc_tx_cur_size -= sc->sc_chan_state[x].tx_size; + /* ack any pending messages */ if (sc->sc_last_rx_status != 0 && GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status) == x) { @@ -682,7 +753,7 @@ dwc_otg_host_setup_tx(struct dwc_otg_td *td) uint32_t hcchar; if (dwc_otg_host_channel_alloc(td)) - return (1); /* busy */ + goto busy; /* get pointer to softc */ sc = DWC_OTG_PC2SC(td->pc); @@ -701,13 +772,13 @@ dwc_otg_host_setup_tx(struct dwc_otg_td *td) DPRINTF("CH=%d STALL\n", td->channel); td->error_stall = 1; td->error_any = 1; - return (0); /* complete */ + goto complete; } else if (hcint & HCINT_ERRORS) { DPRINTF("CH=%d ERROR\n", td->channel); td->errcnt++; if (td->hcsplt != 0 || td->errcnt >= 3) { td->error_any = 1; - return (0); /* complete */ + goto complete; } } @@ -724,6 +795,8 @@ dwc_otg_host_setup_tx(struct dwc_otg_td *td) switch (td->state) { case DWC_CHAN_ST_START: + if (!dwc_otg_host_channel_wait(td)) + break; goto send_pkt; case DWC_CHAN_ST_WAIT_ANE: @@ -731,6 +804,7 @@ dwc_otg_host_setup_tx(struct dwc_otg_td *td) if (!dwc_otg_host_channel_wait(td)) break; td->did_nak = 1; + td->tt_scheduled = 0; goto send_pkt; } if (hcint & (HCINT_ACK | HCINT_NYET)) { @@ -739,14 +813,17 @@ dwc_otg_host_setup_tx(struct dwc_otg_td *td) td->offset += td->tx_bytes; td->remainder -= td->tx_bytes; td->toggle = 1; - return (0); /* complete */ + td->tt_scheduled = 0; + goto complete; } break; + case DWC_CHAN_ST_WAIT_S_ANE: if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { if (!dwc_otg_host_channel_wait(td)) break; td->did_nak = 1; + td->tt_scheduled = 0; goto send_pkt; } if (hcint & (HCINT_ACK | HCINT_NYET)) { @@ -755,6 +832,7 @@ dwc_otg_host_setup_tx(struct dwc_otg_td *td) goto send_cpkt; } break; + case DWC_CHAN_ST_WAIT_C_ANE: if (hcint & HCINT_NYET) { if (!dwc_otg_host_channel_wait(td)) @@ -765,6 +843,7 @@ dwc_otg_host_setup_tx(struct dwc_otg_td *td) if (!dwc_otg_host_channel_wait(td)) break; td->did_nak = 1; + td->tt_scheduled = 0; goto send_pkt; } if (hcint & HCINT_ACK) { @@ -773,35 +852,33 @@ dwc_otg_host_setup_tx(struct dwc_otg_td *td) td->offset += td->tx_bytes; td->remainder -= td->tx_bytes; td->toggle = 1; - return (0); /* complete */ + goto complete; } break; - case DWC_CHAN_ST_TX_PKT_SYNC: - goto send_pkt_sync; + + case DWC_CHAN_ST_WAIT_C_PKT: + if (!dwc_otg_host_channel_wait(td)) + break; + goto send_cpkt; + default: break; } - return (1); /* busy */ + goto busy; send_pkt: if (sizeof(req) != td->remainder) { td->error_any = 1; - return (0); /* complete */ + goto complete; } -send_pkt_sync: if (td->hcsplt != 0) { - uint32_t count; - - count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; - /* check for not first microframe */ - if (count != 0) { - /* enable SOF interrupt */ - dwc_otg_enable_sof_irq(sc); - /* set state */ - td->state = DWC_CHAN_ST_TX_PKT_SYNC; - dwc_otg_host_channel_free(td); - return (1); /* busy */ + /* Wait for our turn, if TT transfer */ + if (td->tt_scheduled == 0 || + (sc->sc_last_frame_num & 7) < td->tt_start_slot) { + /* set return state */ + td->state = DWC_CHAN_ST_START; + goto tt_wait; } td->hcsplt &= ~HCSPLT_COMPSPLT; @@ -832,9 +909,19 @@ send_pkt_sync: /* store number of bytes transmitted */ td->tx_bytes = sizeof(req); - return (1); /* busy */ + goto busy; send_cpkt: + /* Wait for our turn, if TT transfer */ + if (td->tt_scheduled == 0 || + (sc->sc_last_frame_num & 7) < td->tt_complete_slot) { + /* set return state */ + td->state = DWC_CHAN_ST_WAIT_C_PKT; + goto tt_wait; + } + /* wait until next slot before trying again */ + td->tt_complete_slot++; + td->hcsplt |= HCSPLT_COMPSPLT; td->state = DWC_CHAN_ST_WAIT_C_ANE; @@ -848,8 +935,15 @@ send_cpkt: /* must enable channel before writing data to FIFO */ DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); + goto busy; +tt_wait: + /* free allocated channel */ + dwc_otg_host_channel_free(td); +busy: return (1); /* busy */ +complete: + return (0); /* complete */ } static uint8_t @@ -984,6 +1078,25 @@ not_complete: } static uint8_t +dwc_otg_host_rate_check_interrupt(struct dwc_otg_softc *sc, struct dwc_otg_td *td) +{ + uint8_t delta; + + delta = sc->sc_tmr_val - td->tmr_val; + if (delta >= 128) + return (1); /* busy */ + + td->tmr_val = sc->sc_tmr_val + td->tmr_res; + + /* set toggle, if any */ + if (td->set_toggle) { + td->set_toggle = 0; + td->toggle = 1; + } + return (0); +} + +static uint8_t dwc_otg_host_rate_check(struct dwc_otg_td *td) { struct dwc_otg_softc *sc; @@ -992,31 +1105,29 @@ dwc_otg_host_rate_check(struct dwc_otg_td *td) /* get pointer to softc */ sc = DWC_OTG_PC2SC(td->pc); + if (td->channel < DWC_OTG_MAX_CHANNELS && + sc->sc_chan_state[td->channel].suspended) + goto busy; + ep_type = ((td->hcchar & HCCHAR_EPTYPE_MASK) >> HCCHAR_EPTYPE_SHIFT); - if (sc->sc_chan_state[td->channel].suspended) - goto busy; - if (ep_type == UE_ISOCHRONOUS) { - if (td->tmr_val & 1) - td->hcchar |= HCCHAR_ODDFRM; - else - td->hcchar &= ~HCCHAR_ODDFRM; - td->tmr_val += td->tmr_res; - } else if (ep_type == UE_INTERRUPT) { - uint8_t delta; - delta = sc->sc_tmr_val - td->tmr_val; - if (delta >= 128) + /* non TT isochronous traffic */ + if ((td->tmr_val != 0) || + (sc->sc_last_frame_num & (td->tmr_res - 1))) { goto busy; - td->tmr_val = sc->sc_tmr_val + td->tmr_res; + } + td->tmr_val = 1; /* executed */ + td->toggle = 0; + + } else if (ep_type == UE_INTERRUPT) { + if (!td->tt_scheduled) + goto busy; + td->tt_scheduled = 0; } else if (td->did_nak != 0) { goto busy; - } - - if (ep_type == UE_ISOCHRONOUS) { - td->toggle = 0; } else if (td->set_toggle) { td->set_toggle = 0; td->toggle = 1; @@ -1036,7 +1147,7 @@ dwc_otg_host_data_rx(struct dwc_otg_td *td) uint8_t ep_type; if (dwc_otg_host_channel_alloc(td)) - return (1); /* busy */ + goto busy; /* get pointer to softc */ sc = DWC_OTG_PC2SC(td->pc); @@ -1060,13 +1171,15 @@ dwc_otg_host_data_rx(struct dwc_otg_td *td) DPRINTF("CH=%d STALL\n", td->channel); td->error_stall = 1; td->error_any = 1; - return (0); /* complete */ + goto complete; } else if (hcint & HCINT_ERRORS) { DPRINTF("CH=%d ERROR\n", td->channel); td->errcnt++; if (td->hcsplt != 0 || td->errcnt >= 3) { - td->error_any = 1; - return (0); /* complete */ + if (ep_type != UE_ISOCHRONOUS) { + td->error_any = 1; + goto complete; + } } } @@ -1103,25 +1216,42 @@ dwc_otg_host_data_rx(struct dwc_otg_td *td) break; } - td->toggle ^= 1; - /* get the packet byte count */ count = GRXSTSRD_BCNT_GET(sc->sc_last_rx_status); - /* verify the packet byte count */ - if (count != td->max_packet_size) { - if (count < td->max_packet_size) { - /* we have a short packet */ - td->short_pkt = 1; - td->got_short = 1; + /* check for isochronous transfer or high-speed bandwidth endpoint */ + if (ep_type == UE_ISOCHRONOUS || td->max_packet_count > 1) { + if ((sc->sc_last_rx_status & GRXSTSRD_DPID_MASK) != GRXSTSRD_DPID_DATA0) { + td->tt_xactpos = HCSPLT_XACTPOS_MIDDLE; } else { - /* invalid USB packet */ - td->error_any = 1; + td->tt_xactpos = HCSPLT_XACTPOS_BEGIN; + + /* verify the packet byte count */ + if (count < td->max_packet_size) { + /* we have a short packet */ + td->short_pkt = 1; + td->got_short = 1; + } + } + td->toggle = 0; + } else { + /* verify the packet byte count */ + if (count != td->max_packet_size) { + if (count < td->max_packet_size) { + /* we have a short packet */ + td->short_pkt = 1; + td->got_short = 1; + } else { + /* invalid USB packet */ + td->error_any = 1; - /* release FIFO */ - dwc_otg_common_rx_ack(sc); - return (0); /* we are complete */ + /* release FIFO */ + dwc_otg_common_rx_ack(sc); + goto complete; + } } + td->toggle ^= 1; + td->tt_scheduled = 0; } /* verify the packet byte count */ @@ -1131,7 +1261,7 @@ dwc_otg_host_data_rx(struct dwc_otg_td *td) /* release FIFO */ dwc_otg_common_rx_ack(sc); - return (0); /* we are complete */ + goto complete; } usbd_copy_in(td->pc, td->offset, @@ -1144,7 +1274,6 @@ dwc_otg_host_data_rx(struct dwc_otg_td *td) break; default: - DPRINTF("OTHER\n"); break; } /* release FIFO */ @@ -1153,6 +1282,8 @@ dwc_otg_host_data_rx(struct dwc_otg_td *td) check_state: switch (td->state) { case DWC_CHAN_ST_START: + if (!dwc_otg_host_channel_wait(td)) + break; if (td->hcsplt != 0) goto receive_spkt; else @@ -1164,6 +1295,7 @@ check_state: break; td->did_nak = 1; + td->tt_scheduled = 0; if (td->hcsplt != 0) goto receive_spkt; else @@ -1171,11 +1303,13 @@ check_state: } if (!(hcint & HCINT_SOFTWARE_ONLY)) { if (hcint & HCINT_NYET) { - if (td->hcsplt != 0) { - if (!dwc_otg_host_channel_wait(td)) - break; - goto receive_pkt; + if (ep_type == UE_ISOCHRONOUS) { + /* we missed the service interval */ + goto complete; } + if (!dwc_otg_host_channel_wait(td)) + break; + goto receive_pkt; } break; } @@ -1183,29 +1317,44 @@ check_state: if (!dwc_otg_host_channel_wait(td)) break; - /* check if we are complete */ - if ((td->remainder == 0) || (td->got_short != 0)) { - if (td->short_pkt) - return (0); /* complete */ + if (ep_type == UE_ISOCHRONOUS) { + /* check if we are complete */ + if ((td->remainder == 0) || + (td->tt_xactpos == HCSPLT_XACTPOS_BEGIN)) + goto complete; - /* - * Else need to receive a zero length - * packet. - */ - } - if (td->hcsplt != 0) - goto receive_spkt; - else goto receive_pkt; + } else { + /* check if we are complete */ + if ((td->remainder == 0) || (td->got_short != 0)) { + if (td->short_pkt) + goto complete; + + /* + * Else need to receive a zero length + * packet. + */ + } + td->tt_scheduled = 0; + if (td->hcsplt != 0) + goto receive_spkt; + else + goto receive_pkt; + } } break; case DWC_CHAN_ST_WAIT_S_ANE: + /* + * NOTE: The DWC OTG hardware provides a fake ACK in + * case of interrupt and isochronous transfers: + */ if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { if (!dwc_otg_host_channel_wait(td)) break; td->did_nak = 1; + td->tt_scheduled = 0; goto receive_spkt; } if (hcint & (HCINT_ACK | HCINT_NYET)) { @@ -1215,100 +1364,91 @@ check_state: } break; - case DWC_CHAN_ST_RX_PKT: + case DWC_CHAN_ST_WAIT_C_PKT: + if (!dwc_otg_host_channel_wait(td)) + break; goto receive_pkt; - case DWC_CHAN_ST_RX_SPKT: - goto receive_spkt; - - case DWC_CHAN_ST_RX_SPKT_SYNC: - goto receive_spkt_sync; - default: break; } goto busy; receive_pkt: - if (td->hcsplt != 0) { - count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; - - /* check for even microframes */ - if (count == td->curr_frame) { - td->state = DWC_CHAN_ST_RX_PKT; - dwc_otg_host_channel_free(td); - /* enable SOF interrupt */ - dwc_otg_enable_sof_irq(sc); - goto busy; - } else if (count == 0) { - /* check for start split timeout */ - goto receive_spkt; + if (td->hcsplt != 0) { + /* Wait for our turn, if TT transfer */ + if (td->tt_scheduled == 0 || + (sc->sc_last_frame_num & 7) < td->tt_complete_slot) { + /* set return state */ + td->state = DWC_CHAN_ST_WAIT_C_PKT; + goto tt_wait; } + /* wait until next slot before trying again */ + td->tt_complete_slot++; - td->curr_frame = count; + /* set toggle, if any */ + if (td->set_toggle) { + td->set_toggle = 0; + td->toggle = 1; + } td->hcsplt |= HCSPLT_COMPSPLT; - } else if (dwc_otg_host_rate_check(td)) { - td->state = DWC_CHAN_ST_RX_PKT; + count = HCSPLT_XACTLEN_MAX; + } else if (td->tt_xactpos == HCSPLT_XACTPOS_BEGIN && + dwc_otg_host_rate_check(td)) { + td->state = DWC_CHAN_ST_START; dwc_otg_host_channel_free(td); goto busy; + } else { + count = td->max_packet_size; } - td->state = DWC_CHAN_ST_WAIT_ANE; /* receive one packet */ DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), - (td->max_packet_size << HCTSIZ_XFERSIZE_SHIFT) | + (count << HCTSIZ_XFERSIZE_SHIFT) | (1 << HCTSIZ_PKTCNT_SHIFT) | (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); + /* send ASAP */ + if ((ep_type == UE_ISOCHRONOUS) && !(sc->sc_last_frame_num & 1)) + td->hcchar |= HCCHAR_ODDFRM; + else + td->hcchar &= ~HCCHAR_ODDFRM; + hcchar = td->hcchar; hcchar |= HCCHAR_EPDIR_IN; /* must enable channel before data can be received */ DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); - goto busy; receive_spkt: - if (dwc_otg_host_rate_check(td)) { - td->state = DWC_CHAN_ST_RX_SPKT; - dwc_otg_host_channel_free(td); - goto busy; - } - -receive_spkt_sync: - if (ep_type == UE_INTERRUPT || - ep_type == UE_ISOCHRONOUS) { - count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; - td->curr_frame = count; - - /* check for non-zero microframe */ - if (count != 0) { - /* enable SOF interrupt */ - dwc_otg_enable_sof_irq(sc); - /* set state */ - td->state = DWC_CHAN_ST_RX_SPKT_SYNC; - dwc_otg_host_channel_free(td); - goto busy; - } - } else { - count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; - td->curr_frame = count; - - /* check for two last frames */ - if (count >= 6) { - /* enable SOF interrupt */ - dwc_otg_enable_sof_irq(sc); - /* set state */ - td->state = DWC_CHAN_ST_RX_SPKT_SYNC; + /* Wait for our turn, if TT transfer */ + if (td->tt_scheduled == 0) { + if (ep_type == UE_INTERRUPT) { + td->state = DWC_CHAN_ST_START; dwc_otg_host_channel_free(td); goto busy; } + /* set return state */ + td->state = DWC_CHAN_ST_START; + goto tt_wait; + } + if ((sc->sc_last_frame_num & 7) < td->tt_start_slot) { + /* set return state */ + td->state = DWC_CHAN_ST_START; + goto tt_wait; } + /* send ASAP */ + if ((ep_type == UE_ISOCHRONOUS) && !(sc->sc_last_frame_num & 1)) + td->hcchar |= HCCHAR_ODDFRM; + else + td->hcchar &= ~HCCHAR_ODDFRM; + td->hcsplt &= ~HCSPLT_COMPSPLT; td->state = DWC_CHAN_ST_WAIT_S_ANE; @@ -1324,9 +1464,15 @@ receive_spkt_sync: /* must enable channel before data can be received */ DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); + goto busy; +tt_wait: + /* free allocated channel */ + dwc_otg_host_channel_free(td); busy: return (1); /* busy */ +complete: + return (0); /* complete */ } static uint8_t @@ -1452,7 +1598,7 @@ dwc_otg_host_data_tx(struct dwc_otg_td *td) uint8_t ep_type; if (dwc_otg_host_channel_alloc(td)) - return (1); /* busy */ + goto busy; /* get pointer to softc */ sc = DWC_OTG_PC2SC(td->pc); @@ -1474,13 +1620,13 @@ dwc_otg_host_data_tx(struct dwc_otg_td *td) DPRINTF("CH=%d STALL\n", td->channel); td->error_stall = 1; td->error_any = 1; - return (0); /* complete */ + goto complete; } else if (hcint & HCINT_ERRORS) { DPRINTF("CH=%d ERROR\n", td->channel); td->errcnt++; if (td->hcsplt != 0 || td->errcnt >= 3) { td->error_any = 1; - return (0); /* complete */ + goto complete; } } @@ -1497,6 +1643,8 @@ dwc_otg_host_data_tx(struct dwc_otg_td *td) switch (td->state) { case DWC_CHAN_ST_START: + if (!dwc_otg_host_channel_wait(td)) + break; goto send_pkt; case DWC_CHAN_ST_WAIT_ANE: @@ -1504,6 +1652,7 @@ dwc_otg_host_data_tx(struct dwc_otg_td *td) if (!dwc_otg_host_channel_wait(td)) break; td->did_nak = 1; + td->tt_scheduled = 0; goto send_pkt; } if (hcint & (HCINT_ACK | HCINT_NYET)) { @@ -1513,11 +1662,12 @@ dwc_otg_host_data_tx(struct dwc_otg_td *td) td->offset += td->tx_bytes; td->remainder -= td->tx_bytes; td->toggle ^= 1; + td->tt_scheduled = 0; /* check remainder */ if (td->remainder == 0) { if (td->short_pkt) - return (0); /* complete */ + goto complete; /* * Else we need to transmit a short @@ -1527,11 +1677,13 @@ dwc_otg_host_data_tx(struct dwc_otg_td *td) goto send_pkt; } break; + case DWC_CHAN_ST_WAIT_S_ANE: if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { if (!dwc_otg_host_channel_wait(td)) break; td->did_nak = 1; + td->tt_scheduled = 0; goto send_pkt; } if (hcint & (HCINT_ACK | HCINT_NYET)) { @@ -1540,6 +1692,7 @@ dwc_otg_host_data_tx(struct dwc_otg_td *td) goto send_cpkt; } break; + case DWC_CHAN_ST_WAIT_C_ANE: if (hcint & HCINT_NYET) { if (!dwc_otg_host_channel_wait(td)) @@ -1550,6 +1703,7 @@ dwc_otg_host_data_tx(struct dwc_otg_td *td) if (!dwc_otg_host_channel_wait(td)) break; td->did_nak = 1; + td->tt_scheduled = 0; goto send_pkt; } if (hcint & HCINT_ACK) { @@ -1558,11 +1712,12 @@ dwc_otg_host_data_tx(struct dwc_otg_td *td) td->offset += td->tx_bytes; td->remainder -= td->tx_bytes; td->toggle ^= 1; + td->tt_scheduled = 0; /* check remainder */ if (td->remainder == 0) { if (td->short_pkt) - return (0); /* complete */ + goto complete; /* else we need to transmit a short packet */ } @@ -1570,64 +1725,204 @@ dwc_otg_host_data_tx(struct dwc_otg_td *td) } break; - case DWC_CHAN_ST_TX_PKT: - goto send_pkt; + case DWC_CHAN_ST_WAIT_C_PKT: + if (!dwc_otg_host_channel_wait(td)) + break; + goto send_cpkt; - case DWC_CHAN_ST_TX_PKT_SYNC: - goto send_pkt_sync; + case DWC_CHAN_ST_TX_WAIT_ISOC: - case DWC_CHAN_ST_TX_CPKT: - goto send_cpkt; + /* Check if isochronous OUT traffic is complete */ + if ((hcint & HCINT_ACK) == 0) + break; + + td->offset += td->tx_bytes; + td->remainder -= td->tx_bytes; + /* Update split token according to specification */ + if (td->hcsplt != 0) { + if (td->tt_xactpos == HCSPLT_XACTPOS_BEGIN) + td->tt_xactpos = HCSPLT_XACTPOS_MIDDLE; + } else if (td->max_packet_count > 1) { + td->tt_xactpos++; + } + + dwc_otg_host_channel_disable(sc, td->channel); + + if (td->remainder == 0) + goto complete; + + td->state = DWC_CHAN_ST_TX_PKT_ISOC; + + /* FALLTHROUGH */ + + case DWC_CHAN_ST_TX_PKT_ISOC: + if (!dwc_otg_host_channel_wait(td)) + break; + + if (td->hcsplt != 0) { + if ((sc->sc_last_frame_num & 7) < td->tt_start_slot) + goto tt_wait; + /* packets must be 125us apart */ + td->tt_start_slot++; + } + goto send_isoc_pkt; default: break; } goto busy; send_pkt: - if (dwc_otg_host_rate_check(td)) { - td->state = DWC_CHAN_ST_TX_PKT; + if (td->hcsplt != 0) { + /* Wait for our turn, if TT transfer */ + if (td->tt_scheduled == 0) { + if (ep_type == UE_INTERRUPT) { + td->state = DWC_CHAN_ST_START; + dwc_otg_host_channel_free(td); + goto busy; + } + /* set return state */ + td->state = DWC_CHAN_ST_START; + goto tt_wait; + } + if ((sc->sc_last_frame_num & 7) < td->tt_start_slot) { + /* set return state */ + td->state = DWC_CHAN_ST_START; + goto tt_wait; + } + + /* packets must be 125us apart */ + td->tt_start_slot++; + + /* set toggle, if any */ + if (td->set_toggle) { + td->set_toggle = 0; + td->toggle = 1; + } + } else if (dwc_otg_host_rate_check(td)) { + td->state = DWC_CHAN_ST_START; dwc_otg_host_channel_free(td); goto busy; } -send_pkt_sync: - if (td->hcsplt != 0) { - count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; - /* check for first or last microframe */ - if (count == 7 || count == 0) { - /* enable SOF interrupt */ - dwc_otg_enable_sof_irq(sc); - /* set state */ - td->state = DWC_CHAN_ST_TX_PKT_SYNC; - dwc_otg_host_channel_free(td); - goto busy; + if (ep_type == UE_ISOCHRONOUS) { +send_isoc_pkt: + /* Isochronous OUT transfers don't have any ACKs */ + td->state = DWC_CHAN_ST_TX_WAIT_ISOC; + td->hcsplt &= ~HCSPLT_COMPSPLT; + if (td->hcsplt != 0) { + /* get maximum transfer length */ + count = td->remainder; + + /* Update split token according to specification */ + if (td->tt_xactpos == HCSPLT_XACTPOS_BEGIN) { + if (count <= HCSPLT_XACTLEN_MAX) + td->tt_xactpos = HCSPLT_XACTPOS_ALL; + else + count = HCSPLT_XACTLEN_MAX; + } else if (td->tt_xactpos == HCSPLT_XACTPOS_MIDDLE) { + if (count <= HCSPLT_XACTLEN_MAX) + td->tt_xactpos = HCSPLT_XACTPOS_LAST; + else + count = HCSPLT_XACTLEN_MAX; + } + + /* Update transaction position */ + td->hcsplt &= ~HCSPLT_XACTPOS_MASK; + td->hcsplt |= ((uint32_t)td->tt_xactpos << HCSPLT_XACTPOS_SHIFT); + } else { + /* send one packet at a time */ + count = td->max_packet_size; + if (td->remainder < count) { + /* we have a short packet */ + td->short_pkt = 1; + count = td->remainder; + } } + } else if (td->hcsplt != 0) { td->hcsplt &= ~HCSPLT_COMPSPLT; + + /* Wait for ACK/NAK/ERR from TT */ td->state = DWC_CHAN_ST_WAIT_S_ANE; + + /* send one packet at a time */ + count = td->max_packet_size; + if (td->remainder < count) { + /* we have a short packet */ + td->short_pkt = 1; + count = td->remainder; + } } else { + /* Wait for ACK/NAK/STALL from device */ td->state = DWC_CHAN_ST_WAIT_ANE; - } - /* send one packet at a time */ - count = td->max_packet_size; - if (td->remainder < count) { - /* we have a short packet */ - td->short_pkt = 1; - count = td->remainder; + /* send one packet at a time */ + count = td->max_packet_size; + if (td->remainder < count) { + /* we have a short packet */ + td->short_pkt = 1; + count = td->remainder; + } } - /* TODO: HCTSIZ_DOPNG */ + /* check for High-Speed multi-packets */ + if ((td->hcsplt == 0) && (td->max_packet_count > 1)) { + if (td->npkt == 0) { + if (td->remainder >= (3 * td->max_packet_size)) + td->npkt = 3; + else if (td->remainder >= (2 * td->max_packet_size)) + td->npkt = 2; + else + td->npkt = 1; - DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), - (count << HCTSIZ_XFERSIZE_SHIFT) | - (1 << HCTSIZ_PKTCNT_SHIFT) | - (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : - (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); + if (td->npkt > td->max_packet_count) + td->npkt = td->max_packet_count; + + td->tt_xactpos = 1; /* overload */ + } + if (td->tt_xactpos == td->npkt) { + if (td->npkt == 1) { + DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), + (count << HCTSIZ_XFERSIZE_SHIFT) | + (1 << HCTSIZ_PKTCNT_SHIFT) | + (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT)); + } else if (td->npkt == 2) { + DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), + (count << HCTSIZ_XFERSIZE_SHIFT) | + (1 << HCTSIZ_PKTCNT_SHIFT) | + (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT)); + } else { + DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), + (count << HCTSIZ_XFERSIZE_SHIFT) | + (1 << HCTSIZ_PKTCNT_SHIFT) | + (HCTSIZ_PID_DATA2 << HCTSIZ_PID_SHIFT)); + } + td->npkt = 0; + } else { + DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), + (count << HCTSIZ_XFERSIZE_SHIFT) | + (1 << HCTSIZ_PKTCNT_SHIFT) | + (HCTSIZ_PID_MDATA << HCTSIZ_PID_SHIFT)); + } + } else { + /* TODO: HCTSIZ_DOPNG */ + + DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), + (count << HCTSIZ_XFERSIZE_SHIFT) | + (1 << HCTSIZ_PKTCNT_SHIFT) | + (td->toggle ? (HCTSIZ_PID_DATA1 << HCTSIZ_PID_SHIFT) : + (HCTSIZ_PID_DATA0 << HCTSIZ_PID_SHIFT))); + } DWC_OTG_WRITE_4(sc, DOTG_HCSPLT(td->channel), td->hcsplt); + /* send ASAP */ + if ((ep_type == UE_ISOCHRONOUS) && !(sc->sc_last_frame_num & 1)) + td->hcchar |= HCCHAR_ODDFRM; + else + td->hcchar &= ~HCCHAR_ODDFRM; + hcchar = td->hcchar; hcchar &= ~HCCHAR_EPDIR_IN; @@ -1651,18 +1946,20 @@ send_pkt_sync: /* store number of bytes transmitted */ td->tx_bytes = count; - goto busy; send_cpkt: - count = DWC_OTG_READ_4(sc, DOTG_HFNUM) & 7; - /* check for first microframe */ - if (count == 0) { - /* send packet again */ - goto send_pkt; + /* Wait for our turn, if TT transfer */ + if (td->tt_scheduled == 0 || + (sc->sc_last_frame_num & 7) < td->tt_complete_slot) { + /* set return state */ + td->state = DWC_CHAN_ST_WAIT_C_PKT; + goto tt_wait; } + /* wait until next slot before trying again */ + td->tt_complete_slot++; - td->hcsplt |= HCSPLT_COMPSPLT; + td->hcsplt |= HCSPLT_COMPSPLT; td->state = DWC_CHAN_ST_WAIT_C_ANE; DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel), @@ -1676,9 +1973,15 @@ send_cpkt: /* must enable channel before writing data to FIFO */ DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(td->channel), hcchar); + goto busy; +tt_wait: + /* free allocated channel */ + dwc_otg_host_channel_free(td); busy: return (1); /* busy */ +complete: + return (0); /* complete */ } static uint8_t @@ -2003,8 +2306,8 @@ dwc_otg_timer(void *_sc) td->did_nak = 0; } - /* poll jobs */ - dwc_otg_interrupt_poll(sc); + /* enable SOF interrupt, which will poll jobs */ + dwc_otg_enable_sof_irq(sc); if (sc->sc_timer_active) { /* restart timer */ @@ -2041,6 +2344,238 @@ dwc_otg_timer_stop(struct dwc_otg_softc *sc) } static void +dwc_otg_update_host_transfer_schedule(struct dwc_otg_softc *sc) +{ + TAILQ_HEAD(, usb_xfer) head; + struct usb_xfer *xfer; + struct usb_xfer *xfer_next; + struct dwc_otg_td *td; + uint8_t needsof; + uint16_t temp; + + /* FS/LS TT frames are one behind, so add one here */ + temp = (DWC_OTG_READ_4(sc, DOTG_HFNUM) + 1) & HFNUM_FRNUM_MASK; + + if (sc->sc_last_frame_num == temp) + return; + + sc->sc_last_frame_num = temp; + + needsof = 0; + + TAILQ_INIT(&head); + + if (sc->sc_irq_mask & GINTMSK_SOFMSK) { + uint8_t x; + + for (x = 0; x != sc->sc_host_ch_max; x++) { + if (sc->sc_chan_state[x].wait_sof != 0) { + if (--(sc->sc_chan_state[x].wait_sof) != 0) + needsof = 1; + } + } + } + + if ((temp & 7) == 0) { + + /* reset TT info */ + memset(sc->sc_tt_info, 0, sizeof(sc->sc_tt_info)); + + /* + * Plan ahead FULL speed transfers going through the + * transaction translator, according to the USB + * specified priority: + */ + TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) { + struct dwc_otg_tt_info *pinfo; + + td = xfer->td_transfer_cache; + if (td == NULL || td->did_nak != 0 || + (td->hcchar & HCCHAR_EPTYPE_MASK) != + (UE_CONTROL << HCCHAR_EPTYPE_SHIFT)) + continue; + + needsof = 1; + + if (td->hcsplt == 0) + continue; + + /* Reset state if stuck waiting for complete split */ + if (td->state == DWC_CHAN_ST_WAIT_C_PKT) + td->state = DWC_CHAN_ST_START; + + pinfo = sc->sc_tt_info + td->tt_index; + + td->tt_start_slot = pinfo->slot_index; + pinfo->bytes_used += td->max_packet_size; + while (pinfo->bytes_used >= HCSPLT_XACTLEN_MAX) { + pinfo->bytes_used -= HCSPLT_XACTLEN_MAX; + pinfo->slot_index ++; + } + + td->tt_complete_slot = pinfo->slot_index + 2; + if (td->tt_complete_slot < 8) { + td->tt_scheduled = 1; + TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry); + TAILQ_INSERT_TAIL(&head, xfer, wait_entry); + } else { + td->tt_scheduled = 0; + } + } + + TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) { + struct dwc_otg_tt_info *pinfo; + + td = xfer->td_transfer_cache; + if (td == NULL || + (td->hcchar & HCCHAR_EPTYPE_MASK) != + (UE_ISOCHRONOUS << HCCHAR_EPTYPE_SHIFT)) + continue; + + /* execute more frames */ + td->tmr_val = 0; + + needsof = 1; + + if (td->hcsplt == 0) + continue; + + /* Reset state if stuck waiting for complete split */ + if (td->state == DWC_CHAN_ST_WAIT_C_PKT) + td->state = DWC_CHAN_ST_START; + + pinfo = sc->sc_tt_info + td->tt_index; + + td->tt_start_slot = pinfo->slot_index; + pinfo->bytes_used += td->remainder; + while (pinfo->bytes_used >= HCSPLT_XACTLEN_MAX) { + pinfo->bytes_used -= HCSPLT_XACTLEN_MAX; + pinfo->slot_index ++; + } + + td->tt_complete_slot = pinfo->slot_index + 2; + if (td->tt_complete_slot < 8) { + td->tt_scheduled = 1; + TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry); + TAILQ_INSERT_TAIL(&head, xfer, wait_entry); + } else { + td->tt_scheduled = 0; + } + } + + TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) { + struct dwc_otg_tt_info *pinfo; + + td = xfer->td_transfer_cache; + if (td == NULL || + (td->hcchar & HCCHAR_EPTYPE_MASK) != + (UE_INTERRUPT << HCCHAR_EPTYPE_SHIFT)) { + continue; + } + + if (dwc_otg_host_rate_check_interrupt(sc, td)) + continue; + + needsof = 1; + + if (td->hcsplt == 0) { + td->tt_scheduled = 1; + continue; + } + + /* Reset state if stuck waiting for complete split */ + if (td->state == DWC_CHAN_ST_WAIT_C_PKT) + td->state = DWC_CHAN_ST_START; + + pinfo = sc->sc_tt_info + td->tt_index; + + td->tt_start_slot = pinfo->slot_index; + pinfo->bytes_used += td->remainder; + while (pinfo->bytes_used >= HCSPLT_XACTLEN_MAX) { + pinfo->bytes_used -= HCSPLT_XACTLEN_MAX; + pinfo->slot_index ++; + } + + td->tt_complete_slot = pinfo->slot_index + 2; + if (td->tt_complete_slot < 8) { + td->tt_scheduled = 1; + TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry); + TAILQ_INSERT_TAIL(&head, xfer, wait_entry); + } else { + td->tt_scheduled = 0; + } + } + } + + if ((temp & 7) < 6) { + TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) { + struct dwc_otg_tt_info *pinfo; + + td = xfer->td_transfer_cache; + if (td == NULL || td->did_nak != 0 || + (td->hcchar & HCCHAR_EPTYPE_MASK) != + (UE_BULK << HCCHAR_EPTYPE_SHIFT)) { + continue; + } + + needsof = 1; + + if (td->hcsplt == 0) + continue; + + if ((temp & 7) == 0) { + /* Reset state if stuck waiting for complete split */ + if (td->state == DWC_CHAN_ST_WAIT_C_PKT) + td->state = DWC_CHAN_ST_START; + } else if (td->tt_scheduled != 0) + continue; /* already scheduled */ + + pinfo = sc->sc_tt_info + td->tt_index; + + td->tt_start_slot = pinfo->slot_index; + pinfo->bytes_used += td->remainder; + while (pinfo->bytes_used >= HCSPLT_XACTLEN_MAX) { + pinfo->bytes_used -= HCSPLT_XACTLEN_MAX; + pinfo->slot_index ++; + } + + td->tt_complete_slot = pinfo->slot_index + 2; + if (td->tt_complete_slot < 8) { + td->tt_scheduled = 1; + TAILQ_REMOVE(&sc->sc_bus.intr_q.head, xfer, wait_entry); + TAILQ_INSERT_TAIL(&head, xfer, wait_entry); + } else { + td->tt_scheduled = 0; + } + } + } + + /* TT transfers need to be executed in a specific order */ + TAILQ_CONCAT(&head, &sc->sc_bus.intr_q.head, wait_entry); + + /* Put TT transfers first in the queue */ + TAILQ_CONCAT(&sc->sc_bus.intr_q.head, &head, wait_entry); + + if ((temp & 7) == 0) { + DPRINTFN(12, "SOF interrupt #%d, needsof=%d\n", + (int)temp, (int)needsof); + + /* update SOF IRQ mask */ + if (sc->sc_irq_mask & GINTMSK_SOFMSK) { + if (needsof == 0) { + sc->sc_irq_mask &= ~GINTMSK_SOFMSK; + DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); + } + } else { + if (needsof != 0) { + sc->sc_irq_mask |= GINTMSK_SOFMSK; + DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); + } + } + } +} + +static void dwc_otg_interrupt_poll(struct dwc_otg_softc *sc) { struct usb_xfer *xfer; @@ -2126,6 +2661,7 @@ repeat: got_rx_status = 1; } + /* scan for completion events first */ TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { if (!dwc_otg_xfer_do_fifo(xfer)) { /* queue has been modified */ @@ -2133,13 +2669,26 @@ repeat: } } + if (sc->sc_flags.status_device_mode == 0) { + /* update host transfer schedule, so that new transfers can be issued */ + dwc_otg_update_host_transfer_schedule(sc); + + /* start re-scheduled transfers */ + TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { + if (!dwc_otg_xfer_do_fifo(xfer)) { + /* queue has been modified */ + goto repeat; + } + } + } + if (got_rx_status) { /* check if data was consumed */ if (sc->sc_last_rx_status == 0) goto repeat; /* disable RX FIFO level interrupt */ - sc->sc_irq_mask &= ~GINTSTS_RXFLVL; + sc->sc_irq_mask &= ~GINTMSK_RXFLVLMSK; DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); } } @@ -2201,6 +2750,12 @@ dwc_otg_interrupt(struct dwc_otg_softc *sc) sc->sc_flags.change_suspend = 0; sc->sc_flags.change_connect = 1; + /* Disable SOF interrupt */ + sc->sc_irq_mask &= ~GINTMSK_SOFMSK; + /* Enable RX frame interrupt */ + sc->sc_irq_mask |= GINTMSK_RXFLVLMSK; + DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); + /* complete root HUB interrupt endpoint */ dwc_otg_root_intr(sc); } @@ -2234,10 +2789,12 @@ dwc_otg_interrupt(struct dwc_otg_softc *sc) else sc->sc_flags.status_high_speed = 0; - /* disable resume interrupt and enable suspend interrupt */ - - sc->sc_irq_mask &= ~GINTSTS_WKUPINT; - sc->sc_irq_mask |= GINTSTS_USBSUSP; + /* + * Disable resume and SOF interrupt, and enable + * suspend and RX frame interrupt: + */ + sc->sc_irq_mask &= ~(GINTMSK_WKUPINTMSK | GINTMSK_SOFMSK); + sc->sc_irq_mask |= (GINTMSK_USBSUSPMSK | GINTMSK_RXFLVLMSK); DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); /* complete root HUB interrupt endpoint */ @@ -2307,6 +2864,13 @@ dwc_otg_interrupt(struct dwc_otg_softc *sc) /* complete root HUB interrupt endpoint */ dwc_otg_root_intr(sc); + + /* disable RX FIFO level interrupt */ + sc->sc_irq_mask &= ~GINTMSK_RXFLVLMSK; + DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); + + /* update host frame interval */ + dwc_otg_update_host_frame_interval(sc); } /* @@ -2355,27 +2919,6 @@ dwc_otg_interrupt(struct dwc_otg_softc *sc) } } - /* check for SOF interrupt */ - if (status & GINTSTS_SOF) { - if (sc->sc_irq_mask & GINTMSK_SOFMSK) { - uint8_t x; - uint8_t y; - - DPRINTFN(12, "SOF interrupt\n"); - - for (x = y = 0; x != sc->sc_host_ch_max; x++) { - if (sc->sc_chan_state[x].wait_sof != 0) { - if (--(sc->sc_chan_state[x].wait_sof) != 0) - y = 1; - } - } - if (y == 0) { - sc->sc_irq_mask &= ~GINTMSK_SOFMSK; - DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); - } - } - } - /* poll FIFO(s) */ dwc_otg_interrupt_poll(sc); @@ -2412,6 +2955,9 @@ dwc_otg_setup_standard_chain_sub(struct dwc_otg_std_temp *temp) td->channel = DWC_OTG_MAX_CHANNELS; td->state = 0; td->errcnt = 0; + td->tt_scheduled = 0; + td->tt_index = temp->tt_index; + td->tt_xactpos = HCSPLT_XACTPOS_BEGIN; } static void @@ -2419,6 +2965,7 @@ dwc_otg_setup_standard_chain(struct usb_xfer *xfer) { struct dwc_otg_std_temp temp; struct dwc_otg_td *td; + struct usb_device *udev; uint32_t x; uint8_t need_sync; uint8_t is_host; @@ -2429,6 +2976,16 @@ dwc_otg_setup_standard_chain(struct usb_xfer *xfer) temp.max_frame_size = xfer->max_frame_size; + udev = xfer->xroot->udev; + if (udev->parent_hs_hub != NULL && udev->speed != USB_SPEED_HIGH) { + if (udev->parent_hs_hub->ddesc.bDeviceProtocol == UDPROTO_HSHUBMTT) + temp.tt_index = udev->device_index; + else + temp.tt_index = udev->parent_hs_hub->device_index; + } else { + temp.tt_index = udev->device_index; + } + td = xfer->td_start[0]; xfer->td_transfer_first = td; xfer->td_transfer_cache = td; @@ -2439,7 +2996,8 @@ dwc_otg_setup_standard_chain(struct usb_xfer *xfer) temp.td = NULL; temp.td_next = xfer->td_start[0]; temp.offset = 0; - temp.setup_alt_next = xfer->flags_int.short_frames_ok; + temp.setup_alt_next = xfer->flags_int.short_frames_ok || + xfer->flags_int.isochronous_xfr; temp.did_stall = !xfer->flags_int.control_stall; is_host = (xfer->xroot->udev->flags.usb_mode == USB_MODE_HOST); @@ -2637,14 +3195,12 @@ dwc_otg_setup_standard_chain(struct usb_xfer *xfer) case USB_SPEED_FULL: case USB_SPEED_LOW: /* check if root HUB port is running High Speed */ - if (sc->sc_flags.status_high_speed != 0) { + if (xfer->xroot->udev->parent_hs_hub != NULL) { hcsplt = HCSPLT_SPLTENA | (xfer->xroot->udev->hs_port_no << HCSPLT_PRTADDR_SHIFT) | (xfer->xroot->udev->hs_hub_addr << HCSPLT_HUBADDR_SHIFT); - if (xfer_type == UE_ISOCHRONOUS) /* XXX */ - hcsplt |= (3 << HCSPLT_XACTPOS_SHIFT); } else { hcsplt = 0; } @@ -2657,6 +3213,12 @@ dwc_otg_setup_standard_chain(struct usb_xfer *xfer) ival = 127; td->tmr_val = sc->sc_tmr_val + ival; td->tmr_res = ival; + } else if (xfer_type == UE_ISOCHRONOUS) { + td->tmr_val = 0; + td->tmr_res = 1; + } else { + td->tmr_val = 0; + td->tmr_res = 0; } break; case USB_SPEED_HIGH: @@ -2675,19 +3237,19 @@ dwc_otg_setup_standard_chain(struct usb_xfer *xfer) ival = 127; td->tmr_val = sc->sc_tmr_val + ival; td->tmr_res = ival; + } else if (xfer_type == UE_ISOCHRONOUS) { + td->tmr_val = 0; + td->tmr_res = 1 << usbd_xfer_get_fps_shift(xfer); + } else { + td->tmr_val = 0; + td->tmr_res = 0; } break; default: hcsplt = 0; - break; - } - - if (xfer_type == UE_ISOCHRONOUS) { - td->tmr_val = xfer->endpoint->isoc_next & 0xFF; - td->tmr_res = 1 << usbd_xfer_get_fps_shift(xfer); - } else if (xfer_type != UE_INTERRUPT) { td->tmr_val = 0; td->tmr_res = 0; + break; } /* store configuration in all TD's */ @@ -2719,6 +3281,8 @@ dwc_otg_timeout(void *arg) static void dwc_otg_start_standard_chain(struct usb_xfer *xfer) { + struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus); + DPRINTFN(9, "\n"); /* poll one time - will turn on interrupts */ @@ -2732,6 +3296,9 @@ dwc_otg_start_standard_chain(struct usb_xfer *xfer) usbd_transfer_timeout_ms(xfer, &dwc_otg_timeout, xfer->timeout); } + + /* enable SOF interrupt, if any */ + dwc_otg_enable_sof_irq(sc); } } @@ -2787,7 +3354,8 @@ dwc_otg_standard_done_sub(struct usb_xfer *xfer) } /* Check for short transfer */ if (len > 0) { - if (xfer->flags_int.short_frames_ok) { + if (xfer->flags_int.short_frames_ok || + xfer->flags_int.isochronous_xfr) { /* follow alt next */ if (td->alt_next) { td = td->obj_next; @@ -3357,9 +3925,15 @@ dwc_otg_device_isoc_close(struct usb_xfer *xfer) static void dwc_otg_device_isoc_enter(struct usb_xfer *xfer) { +} + +static void +dwc_otg_device_isoc_start(struct usb_xfer *xfer) +{ struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus); uint32_t temp; - uint32_t nframes; + uint32_t msframes; + uint32_t framenum; uint8_t shift = usbd_xfer_get_fps_shift(xfer); DPRINTFN(6, "xfer=%p next=%d nframes=%d\n", @@ -3369,34 +3943,42 @@ dwc_otg_device_isoc_enter(struct usb_xfer *xfer) temp = DWC_OTG_READ_4(sc, DOTG_HFNUM); /* get the current frame index */ - nframes = (temp & HFNUM_FRNUM_MASK); + framenum = (temp & HFNUM_FRNUM_MASK); } else { temp = DWC_OTG_READ_4(sc, DOTG_DSTS); /* get the current frame index */ - nframes = DSTS_SOFFN_GET(temp); + framenum = DSTS_SOFFN_GET(temp); } - if (sc->sc_flags.status_high_speed) - nframes /= 8; + if (xfer->xroot->udev->parent_hs_hub != NULL) + framenum /= 8; + + framenum &= DWC_OTG_FRAME_MASK; - nframes &= DWC_OTG_FRAME_MASK; + /* + * Compute number of milliseconds worth of data traffic for + * this USB transfer: + */ + if (xfer->xroot->udev->speed == USB_SPEED_HIGH) + msframes = ((xfer->nframes << shift) + 7) / 8; + else + msframes = xfer->nframes; /* * check if the frame index is within the window where the frames * will be inserted */ - temp = (nframes - xfer->endpoint->isoc_next) & DWC_OTG_FRAME_MASK; + temp = (framenum - xfer->endpoint->isoc_next) & DWC_OTG_FRAME_MASK; - if ((xfer->endpoint->is_synced == 0) || - (temp < (((xfer->nframes << shift) + 7) / 8))) { + if ((xfer->endpoint->is_synced == 0) || (temp < msframes)) { /* * If there is data underflow or the pipe queue is * empty we schedule the transfer a few frames ahead * of the current frame position. Else two isochronous * transfers might overlap. */ - xfer->endpoint->isoc_next = (nframes + 3) & DWC_OTG_FRAME_MASK; + xfer->endpoint->isoc_next = (framenum + 3) & DWC_OTG_FRAME_MASK; xfer->endpoint->is_synced = 1; DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next); } @@ -3404,25 +3986,20 @@ dwc_otg_device_isoc_enter(struct usb_xfer *xfer) * compute how many milliseconds the insertion is ahead of the * current frame position: */ - temp = (xfer->endpoint->isoc_next - nframes) & DWC_OTG_FRAME_MASK; + temp = (xfer->endpoint->isoc_next - framenum) & DWC_OTG_FRAME_MASK; /* * pre-compute when the isochronous transfer will be finished: */ xfer->isoc_time_complete = - usb_isoc_time_expand(&sc->sc_bus, nframes) + temp + - (((xfer->nframes << shift) + 7) / 8); + usb_isoc_time_expand(&sc->sc_bus, framenum) + temp + msframes; /* setup TDs */ dwc_otg_setup_standard_chain(xfer); /* compute frame number for next insertion */ - xfer->endpoint->isoc_next += (xfer->nframes << shift); -} + xfer->endpoint->isoc_next += msframes; -static void -dwc_otg_device_isoc_start(struct usb_xfer *xfer) -{ /* start TD chain */ dwc_otg_start_standard_chain(xfer); } @@ -3987,8 +4564,8 @@ dwc_otg_xfer_setup(struct usb_setup_params *parm) * reasonable dummies: */ parm->hc_max_packet_size = 0x500; - parm->hc_max_packet_count = 1; - parm->hc_max_frame_size = 0x500; + parm->hc_max_packet_count = 3; + parm->hc_max_frame_size = 3 * 0x500; usbd_transfer_setup_sub(parm); @@ -4045,6 +4622,7 @@ dwc_otg_xfer_setup(struct usb_setup_params *parm) /* init TD */ td->max_packet_size = xfer->max_packet_size; + td->max_packet_count = xfer->max_packet_count; td->ep_no = ep_no; td->obj_next = last_obj; @@ -4081,40 +4659,7 @@ dwc_otg_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, /* not supported */ return; } - } else { - uint16_t mps; - - mps = UGETW(edesc->wMaxPacketSize); - - /* Apply limitations of our USB host driver */ - - switch (udev->speed) { - case USB_SPEED_HIGH: - if (mps > 512) { - DPRINTF("wMaxPacketSize=0x%04x" - "is not supported\n", (int)mps); - /* not supported */ - return; - } - break; - - case USB_SPEED_FULL: - case USB_SPEED_LOW: - if (mps > 188) { - DPRINTF("wMaxPacketSize=0x%04x" - "is not supported\n", (int)mps); - /* not supported */ - return; - } - break; - - default: - DPRINTF("Invalid device speed\n"); - /* not supported */ - return; - } } - if ((edesc->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS) ep->methods = &dwc_otg_device_isoc_methods; else diff --git a/sys/dev/usb/controller/dwc_otg.h b/sys/dev/usb/controller/dwc_otg.h index a301698519710..2ae2eaeb60141 100644 --- a/sys/dev/usb/controller/dwc_otg.h +++ b/sys/dev/usb/controller/dwc_otg.h @@ -57,23 +57,24 @@ struct dwc_otg_td { uint32_t hcsplt; /* HOST CFG */ uint16_t max_packet_size; /* packet_size */ uint16_t npkt; + uint8_t max_packet_count; /* packet_count */ uint8_t errcnt; uint8_t tmr_res; uint8_t tmr_val; - uint8_t curr_frame; uint8_t ep_no; uint8_t channel; + uint8_t tt_index; /* TT data */ + uint8_t tt_start_slot; /* TT data */ + uint8_t tt_complete_slot; /* TT data */ + uint8_t tt_xactpos; /* TT data */ uint8_t state; #define DWC_CHAN_ST_START 0 #define DWC_CHAN_ST_WAIT_ANE 1 #define DWC_CHAN_ST_WAIT_S_ANE 2 #define DWC_CHAN_ST_WAIT_C_ANE 3 -#define DWC_CHAN_ST_RX_PKT 4 -#define DWC_CHAN_ST_RX_SPKT 5 -#define DWC_CHAN_ST_RX_SPKT_SYNC 6 -#define DWC_CHAN_ST_TX_PKT 4 -#define DWC_CHAN_ST_TX_CPKT 5 -#define DWC_CHAN_ST_TX_PKT_SYNC 6 +#define DWC_CHAN_ST_WAIT_C_PKT 4 +#define DWC_CHAN_ST_TX_PKT_ISOC 5 +#define DWC_CHAN_ST_TX_WAIT_ISOC 6 uint8_t error:1; uint8_t error_any:1; uint8_t error_stall:1; @@ -84,6 +85,7 @@ struct dwc_otg_td { uint8_t set_toggle:1; uint8_t got_short:1; uint8_t did_nak:1; + uint8_t tt_scheduled:1; }; struct dwc_otg_std_temp { @@ -103,6 +105,7 @@ struct dwc_otg_std_temp { uint8_t setup_alt_next; uint8_t did_stall; uint8_t bulk_or_control; + uint8_t tt_index; }; struct dwc_otg_config_desc { @@ -143,11 +146,18 @@ struct dwc_otg_profile { struct dwc_otg_chan_state { uint32_t hcint; + uint32_t tx_size; uint8_t wait_sof; uint8_t allocated; uint8_t suspended; }; +struct dwc_otg_tt_info { + uint16_t bytes_used; + uint8_t slot_index; + uint8_t dummy; +}; + struct dwc_otg_softc { struct usb_bus sc_bus; union dwc_otg_hub_temp sc_hub_temp; @@ -163,9 +173,11 @@ struct dwc_otg_softc { bus_space_handle_t sc_io_hdl; uint32_t sc_rx_bounce_buffer[1024 / 4]; - uint32_t sc_tx_bounce_buffer[(512 * DWC_OTG_MAX_TXP) / 4]; + uint32_t sc_tx_bounce_buffer[MAX(512 * DWC_OTG_MAX_TXP, 1024) / 4]; uint32_t sc_fifo_size; + uint32_t sc_tx_max_size; + uint32_t sc_tx_cur_size; uint32_t sc_irq_mask; uint32_t sc_last_rx_status; uint32_t sc_out_ctl[DWC_OTG_MAX_ENDPOINTS]; @@ -174,7 +186,9 @@ struct dwc_otg_softc { uint32_t sc_tmr_val; uint32_t sc_hprt_val; + struct dwc_otg_tt_info sc_tt_info[DWC_OTG_MAX_DEVICES]; uint16_t sc_active_rx_ep; + uint16_t sc_last_frame_num; uint8_t sc_timer_active; uint8_t sc_dev_ep_max; diff --git a/sys/dev/usb/controller/dwc_otgreg.h b/sys/dev/usb/controller/dwc_otgreg.h index f59f48c89c023..cd2f45de32a60 100644 --- a/sys/dev/usb/controller/dwc_otgreg.h +++ b/sys/dev/usb/controller/dwc_otgreg.h @@ -536,6 +536,11 @@ #define HCSPLT_COMPSPLT (1<<16) #define HCSPLT_XACTPOS_SHIFT 14 #define HCSPLT_XACTPOS_MASK 0x0000c000 +#define HCSPLT_XACTPOS_MIDDLE 0 +#define HCSPLT_XACTPOS_LAST 1 +#define HCSPLT_XACTPOS_BEGIN 2 +#define HCSPLT_XACTPOS_ALL 3 +#define HCSPLT_XACTLEN_MAX 188 /* bytes */ #define HCSPLT_HUBADDR_SHIFT 7 #define HCSPLT_HUBADDR_MASK 0x00003f80 #define HCSPLT_PRTADDR_SHIFT 0 @@ -545,6 +550,11 @@ (HCINT_BBLERR | HCINT_XACTERR) #define HCINT_RETRY \ (HCINT_DATATGLERR | HCINT_FRMOVRUN | HCINT_NAK) +#define HCINT_DEFAULT_MASK \ + (HCINT_STALL | HCINT_BBLERR | \ + HCINT_XACTERR | HCINT_NAK | HCINT_ACK | HCINT_NYET | \ + HCINT_CHHLTD | HCINT_FRMOVRUN | \ + HCINT_DATATGLERR) #define HCINT_SOFTWARE_ONLY (1<<20) /* BSD only */ #define HCINT_DATATGLERR (1<<10) diff --git a/sys/dev/usb/net/if_smsc.c b/sys/dev/usb/net/if_smsc.c index 6a02925304a8f..55d3560759b1e 100644 --- a/sys/dev/usb/net/if_smsc.c +++ b/sys/dev/usb/net/if_smsc.c @@ -86,6 +86,9 @@ __FBSDID("$FreeBSD$"); #include <net/if.h> #include <net/if_var.h> +#include <netinet/in.h> +#include <netinet/ip.h> + #include "opt_platform.h" #ifdef FDT @@ -1025,25 +1028,32 @@ smsc_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) * * Ignore H/W csum for non-IPv4 packets. */ - if (be16toh(eh->ether_type) == ETHERTYPE_IP && pktlen > ETHER_MIN_LEN) { - - /* Indicate the UDP/TCP csum has been calculated */ - m->m_pkthdr.csum_flags |= CSUM_DATA_VALID; - - /* Copy the TCP/UDP checksum from the last 2 bytes - * of the transfer and put in the csum_data field. - */ - usbd_copy_out(pc, (off + pktlen), - &m->m_pkthdr.csum_data, 2); - - /* The data is copied in network order, but the - * csum algorithm in the kernel expects it to be - * in host network order. - */ - m->m_pkthdr.csum_data = ntohs(m->m_pkthdr.csum_data); - - smsc_dbg_printf(sc, "RX checksum offloaded (0x%04x)\n", - m->m_pkthdr.csum_data); + if ((be16toh(eh->ether_type) == ETHERTYPE_IP) && + (pktlen > ETHER_MIN_LEN)) { + struct ip *ip; + + ip = (struct ip *)(eh + 1); + if ((ip->ip_v == IPVERSION) && + ((ip->ip_p == IPPROTO_TCP) || + (ip->ip_p == IPPROTO_UDP))) { + /* Indicate the UDP/TCP csum has been calculated */ + m->m_pkthdr.csum_flags |= CSUM_DATA_VALID; + + /* Copy the TCP/UDP checksum from the last 2 bytes + * of the transfer and put in the csum_data field. + */ + usbd_copy_out(pc, (off + pktlen), + &m->m_pkthdr.csum_data, 2); + + /* The data is copied in network order, but the + * csum algorithm in the kernel expects it to be + * in host network order. + */ + m->m_pkthdr.csum_data = ntohs(m->m_pkthdr.csum_data); + + smsc_dbg_printf(sc, "RX checksum offloaded (0x%04x)\n", + m->m_pkthdr.csum_data); + } } /* Need to adjust the offset as well or we'll be off diff --git a/sys/dev/vt/hw/efifb/efifb.c b/sys/dev/vt/hw/efifb/efifb.c index 4a6eeb798fc0c..683cecbabc4d7 100644 --- a/sys/dev/vt/hw/efifb/efifb.c +++ b/sys/dev/vt/hw/efifb/efifb.c @@ -51,36 +51,58 @@ __FBSDID("$FreeBSD$"); #include <dev/vt/hw/fb/vt_fb.h> #include <dev/vt/colors/vt_termcolors.h> -static vd_init_t vt_efb_init; +static vd_init_t vt_efifb_init; +static vd_probe_t vt_efifb_probe; -static struct vt_driver vt_efb_driver = { - .vd_init = vt_efb_init, +static struct vt_driver vt_efifb_driver = { + .vd_name = "efifb", + .vd_probe = vt_efifb_probe, + .vd_init = vt_efifb_init, .vd_blank = vt_fb_blank, .vd_bitbltchr = vt_fb_bitbltchr, + .vd_maskbitbltchr = vt_fb_maskbitbltchr, /* Better than VGA, but still generic driver. */ .vd_priority = VD_PRIORITY_GENERIC + 1, }; -static struct fb_info info; -VT_CONSDEV_DECLARE(vt_efb_driver, - MAX(80, PIXEL_WIDTH(VT_FB_DEFAULT_WIDTH)), - MAX(25, PIXEL_HEIGHT(VT_FB_DEFAULT_HEIGHT)), &info); +static struct fb_info local_info; +VT_DRIVER_DECLARE(vt_efifb, vt_efifb_driver); static int -vt_efb_init(struct vt_device *vd) +vt_efifb_probe(struct vt_device *vd) { - int depth, d, disable, i, len; - struct fb_info *info; + int disabled; struct efi_fb *efifb; caddr_t kmdp; - info = vd->vd_softc; + disabled = 0; + TUNABLE_INT_FETCH("hw.syscons.disable", &disabled); + if (disabled != 0) + return (CN_DEAD); - disable = 0; - TUNABLE_INT_FETCH("hw.syscons.disable", &disable); - if (disable != 0) + kmdp = preload_search_by_type("elf kernel"); + if (kmdp == NULL) + kmdp = preload_search_by_type("elf64 kernel"); + efifb = (struct efi_fb *)preload_search_info(kmdp, + MODINFO_METADATA | MODINFOMD_EFI_FB); + if (efifb == NULL) return (CN_DEAD); + return (CN_INTERNAL); +} + +static int +vt_efifb_init(struct vt_device *vd) +{ + int depth, d, i, len; + struct fb_info *info; + struct efi_fb *efifb; + caddr_t kmdp; + + info = vd->vd_softc; + if (info == NULL) + info = vd->vd_softc = (void *)&local_info; + kmdp = preload_search_by_type("elf kernel"); if (kmdp == NULL) kmdp = preload_search_by_type("elf64 kernel"); @@ -136,7 +158,8 @@ vt_efb_init(struct vt_device *vd) fb_probe(info); vt_fb_init(vd); + /* Clear the screen. */ + vt_fb_blank(vd, TC_BLACK); return (CN_INTERNAL); } - diff --git a/sys/dev/vt/hw/fb/vt_early_fb.c b/sys/dev/vt/hw/fb/vt_early_fb.c index 4a81f4f41f741..64b2122f3ee37 100644 --- a/sys/dev/vt/hw/fb/vt_early_fb.c +++ b/sys/dev/vt/hw/fb/vt_early_fb.c @@ -52,18 +52,19 @@ __FBSDID("$FreeBSD$"); #include <dev/vt/colors/vt_termcolors.h> static vd_init_t vt_efb_init; +static vd_probe_t vt_efb_probe; static struct vt_driver vt_fb_early_driver = { + .vd_name = "efb", + .vd_probe = vt_efb_probe, .vd_init = vt_efb_init, .vd_blank = vt_fb_blank, .vd_bitbltchr = vt_fb_bitbltchr, .vd_priority = VD_PRIORITY_GENERIC, }; -static struct fb_info info; -VT_CONSDEV_DECLARE(vt_fb_early_driver, - MAX(80, PIXEL_WIDTH(VT_FB_DEFAULT_WIDTH)), - MAX(25, PIXEL_HEIGHT(VT_FB_DEFAULT_HEIGHT)), &info); +static struct fb_info local_info; +VT_DRIVER_DECLARE(vt_efb, vt_fb_early_driver); static void #ifdef FDT @@ -126,30 +127,62 @@ vt_efb_initialize(struct fb_info *info) } } -static int -vt_efb_init(struct vt_device *vd) +static phandle_t +vt_efb_get_fbnode() { - struct ofw_pci_register pciaddrs[8]; - struct fb_info *info; - int i, len, n_pciaddrs; phandle_t chosen, node; ihandle_t stdout; char type[64]; - info = vd->vd_softc; - chosen = OF_finddevice("/chosen"); OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)); node = OF_instance_to_package(stdout); - if (node == -1) { - /* - * The "/chosen/stdout" does not exist try - * using "screen" directly. - */ - node = OF_finddevice("screen"); + if (node != -1) { + /* The "/chosen/stdout" present. */ + OF_getprop(node, "device_type", type, sizeof(type)); + /* Check if it has "display" type. */ + if (strcmp(type, "display") == 0) + return (node); } - OF_getprop(node, "device_type", type, sizeof(type)); - if (strcmp(type, "display") != 0) + /* Try device with name "screen". */ + node = OF_finddevice("screen"); + + return (node); +} + +static int +vt_efb_probe(struct vt_device *vd) +{ + phandle_t node; + + node = vt_efb_get_fbnode(); + if (node == -1) + return (CN_DEAD); + + if ((OF_getproplen(node, "height") <= 0) || + (OF_getproplen(node, "width") <= 0) || + (OF_getproplen(node, "depth") <= 0) || + (OF_getproplen(node, "linebytes") <= 0)) + return (CN_DEAD); + + return (CN_INTERNAL); +} + +static int +vt_efb_init(struct vt_device *vd) +{ + struct ofw_pci_register pciaddrs[8]; + struct fb_info *info; + int i, len, n_pciaddrs; + phandle_t node; + + if (vd->vd_softc == NULL) + vd->vd_softc = (void *)&local_info; + + info = vd->vd_softc; + + node = vt_efb_get_fbnode(); + if (node == -1) return (CN_DEAD); #define GET(name, var) \ @@ -249,7 +282,6 @@ vt_efb_init(struct vt_device *vd) #endif } - /* blank full size */ len = info->fb_size / 4; for (i = 0; i < len; i++) { @@ -259,13 +291,6 @@ vt_efb_init(struct vt_device *vd) /* Get pixel storage size. */ info->fb_bpp = info->fb_stride / info->fb_width * 8; - /* - * Early FB driver work with static window buffer 80x25, so reduce - * size to 640x480. - */ - info->fb_width = VT_FB_DEFAULT_WIDTH; - info->fb_height = VT_FB_DEFAULT_HEIGHT; - #ifdef FDT vt_efb_initialize(info, node); #else @@ -274,6 +299,5 @@ vt_efb_init(struct vt_device *vd) fb_probe(info); vt_fb_init(vd); - return (CN_INTERNAL); } diff --git a/sys/dev/vt/hw/fb/vt_fb.c b/sys/dev/vt/hw/fb/vt_fb.c index 7163bdc786acc..3ffba40a1adbd 100644 --- a/sys/dev/vt/hw/fb/vt_fb.c +++ b/sys/dev/vt/hw/fb/vt_fb.c @@ -50,9 +50,11 @@ void vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, void vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color); static struct vt_driver vt_fb_driver = { + .vd_name = "fb", .vd_init = vt_fb_init, .vd_blank = vt_fb_blank, .vd_bitbltchr = vt_fb_bitbltchr, + .vd_maskbitbltchr = vt_fb_maskbitbltchr, .vd_drawrect = vt_fb_drawrect, .vd_setpixel = vt_fb_setpixel, .vd_postswitch = vt_fb_postswitch, @@ -61,6 +63,8 @@ static struct vt_driver vt_fb_driver = { .vd_fb_mmap = vt_fb_mmap, }; +VT_DRIVER_DECLARE(vt_fb, vt_fb_driver); + static int vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td) { @@ -189,6 +193,68 @@ vt_fb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask, uint32_t fgc, bgc, cc, o; int c, l, bpp; u_long line; + uint8_t b; + const uint8_t *ch; + + info = vd->vd_softc; + bpp = FBTYPE_GET_BYTESPP(info); + fgc = info->fb_cmap[fg]; + bgc = info->fb_cmap[bg]; + b = 0; + if (bpl == 0) + bpl = (width + 7) >> 3; /* Bytes per sorce line. */ + + /* Don't try to put off screen pixels */ + if (((left + width) > info->fb_width) || ((top + height) > + info->fb_height)) + return; + + line = (info->fb_stride * top) + (left * bpp); + for (l = 0; l < height; l++) { + ch = src; + for (c = 0; c < width; c++) { + if (c % 8 == 0) + b = *ch++; + else + b <<= 1; + o = line + (c * bpp); + cc = b & 0x80 ? fgc : bgc; + + switch(bpp) { + case 1: + info->wr1(info, o, cc); + break; + case 2: + info->wr2(info, o, cc); + break; + case 3: + /* Packed mode, so unaligned. Byte access. */ + info->wr1(info, o, (cc >> 16) & 0xff); + info->wr1(info, o + 1, (cc >> 8) & 0xff); + info->wr1(info, o + 2, cc & 0xff); + break; + case 4: + info->wr4(info, o, cc); + break; + default: + /* panic? */ + break; + } + } + line += info->fb_stride; + src += bpl; + } +} + +void +vt_fb_maskbitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask, + int bpl, vt_axis_t top, vt_axis_t left, unsigned int width, + unsigned int height, term_color_t fg, term_color_t bg) +{ + struct fb_info *info; + uint32_t fgc, bgc, cc, o; + int c, l, bpp; + u_long line; uint8_t b, m; const uint8_t *ch; diff --git a/sys/dev/vt/hw/fb/vt_fb.h b/sys/dev/vt/hw/fb/vt_fb.h index 9b3aa0d965249..10dd2389319ac 100644 --- a/sys/dev/vt/hw/fb/vt_fb.h +++ b/sys/dev/vt/hw/fb/vt_fb.h @@ -41,7 +41,7 @@ int fb_probe(struct fb_info *info); vd_init_t vt_fb_init; vd_blank_t vt_fb_blank; vd_bitbltchr_t vt_fb_bitbltchr; +vd_maskbitbltchr_t vt_fb_maskbitbltchr; vd_postswitch_t vt_fb_postswitch; - #endif /* _DEV_VT_HW_FB_VT_FB_H_ */ diff --git a/sys/dev/vt/hw/ofwfb/ofwfb.c b/sys/dev/vt/hw/ofwfb/ofwfb.c index b5f8e59897574..7245725444674 100644 --- a/sys/dev/vt/hw/ofwfb/ofwfb.c +++ b/sys/dev/vt/hw/ofwfb/ofwfb.c @@ -63,6 +63,7 @@ static vd_blank_t ofwfb_blank; static vd_bitbltchr_t ofwfb_bitbltchr; static const struct vt_driver vt_ofwfb_driver = { + .vd_name = "ofwfb", .vd_init = ofwfb_init, .vd_blank = ofwfb_blank, .vd_bitbltchr = ofwfb_bitbltchr, diff --git a/sys/dev/vt/hw/vga/vga.c b/sys/dev/vt/hw/vga/vga.c index 16e07512f8b9c..986dde9323ab6 100644 --- a/sys/dev/vt/hw/vga/vga.c +++ b/sys/dev/vt/hw/vga/vga.c @@ -45,10 +45,8 @@ __FBSDID("$FreeBSD$"); #if defined(__amd64__) || defined(__i386__) #include <vm/vm.h> #include <vm/pmap.h> -#include <machine/metadata.h> #include <machine/pmap.h> #include <machine/vmparam.h> -#include <sys/linker.h> #endif /* __amd64__ || __i386__ */ struct vga_softc { @@ -73,6 +71,7 @@ struct vga_softc { #define VT_VGA_HEIGHT 480 #define VT_VGA_MEMSIZE (VT_VGA_WIDTH * VT_VGA_HEIGHT / 8) +static vd_probe_t vga_probe; static vd_init_t vga_init; static vd_blank_t vga_blank; static vd_bitbltchr_t vga_bitbltchr; @@ -83,6 +82,8 @@ static vd_putchar_t vga_putchar; static vd_postswitch_t vga_postswitch; static const struct vt_driver vt_vga_driver = { + .vd_name = "vga", + .vd_probe = vga_probe, .vd_init = vga_init, .vd_blank = vga_blank, .vd_bitbltchr = vga_bitbltchr, @@ -99,8 +100,7 @@ static const struct vt_driver vt_vga_driver = { * buffer is always big enough to support both. */ static struct vga_softc vga_conssoftc; -VT_CONSDEV_DECLARE(vt_vga_driver, MAX(80, PIXEL_WIDTH(VT_VGA_WIDTH)), - MAX(25, PIXEL_HEIGHT(VT_VGA_HEIGHT)), &vga_conssoftc); +VT_DRIVER_DECLARE(vt_vga, vt_vga_driver); static inline void vga_setcolor(struct vt_device *vd, term_color_t color) @@ -633,23 +633,22 @@ vga_initialize(struct vt_device *vd, int textmode) } static int +vga_probe(struct vt_device *vd) +{ + + return (CN_INTERNAL); +} + +static int vga_init(struct vt_device *vd) { - struct vga_softc *sc = vd->vd_softc; - int textmode = 0; - -#if defined(__amd64__) - /* Disable if EFI framebuffer present. Should be handled by priority - * logic in vt(9), but this will do for now. XXX */ - - caddr_t kmdp, efifb; - kmdp = preload_search_by_type("elf kernel"); - if (kmdp == NULL) - kmdp = preload_search_by_type("elf64 kernel"); - efifb = preload_search_info(kmdp, MODINFO_METADATA | MODINFOMD_EFI_FB); - if (efifb != NULL) - return (CN_DEAD); -#endif + struct vga_softc *sc; + int textmode; + + if (vd->vd_softc == NULL) + vd->vd_softc = (void *)&vga_conssoftc; + sc = vd->vd_softc; + textmode = 0; #if defined(__amd64__) || defined(__i386__) sc->vga_fb_tag = X86_BUS_SPACE_MEM; diff --git a/sys/dev/vt/vt.h b/sys/dev/vt/vt.h index caab70908fd8a..eb0ce1fab7f85 100644 --- a/sys/dev/vt/vt.h +++ b/sys/dev/vt/vt.h @@ -78,7 +78,13 @@ one 'device sc' or 'device vt'" #endif /* defined(SC_TWOBUTTON_MOUSE) || defined(VT_TWOBUTTON_MOUSE) */ #define SC_DRIVER_NAME "vt" +#ifdef VT_DEBUG #define DPRINTF(_l, ...) if (vt_debug > (_l)) printf( __VA_ARGS__ ) +#define VT_CONSOLECTL_DEBUG +#define VT_SYSMOUSE_DEBUG +#else +#define DPRINTF(_l, ...) do {} while (0) +#endif #define ISSIGVALID(sig) ((sig) > 0 && (sig) < NSIG) #define VT_SYSCTL_INT(_name, _default, _descr) \ @@ -277,6 +283,7 @@ struct vt_window { */ typedef int vd_init_t(struct vt_device *vd); +typedef int vd_probe_t(struct vt_device *vd); typedef void vd_postswitch_t(struct vt_device *vd); typedef void vd_blank_t(struct vt_device *vd, term_color_t color); typedef void vd_bitbltchr_t(struct vt_device *vd, const uint8_t *src, @@ -295,7 +302,9 @@ typedef void vd_drawrect_t(struct vt_device *, int, int, int, int, int, typedef void vd_setpixel_t(struct vt_device *, int, int, term_color_t); struct vt_driver { + char vd_name[16]; /* Console attachment. */ + vd_probe_t *vd_probe; vd_init_t *vd_init; /* Drawing. */ @@ -391,6 +400,9 @@ TERMINAL_DECLARE_EARLY(driver ## _consterm, vt_termclass, \ SYSINIT(vt_early_cons, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_ANY, \ vt_upgrade, &driver ## _consdev) +/* name argument is not used yet. */ +#define VT_DRIVER_DECLARE(name, drv) DATA_SET(vt_drv_set, drv) + /* * Fonts. * diff --git a/sys/dev/vt/vt_buf.c b/sys/dev/vt/vt_buf.c index 0b078ecbfd6c0..598126f46d65c 100644 --- a/sys/dev/vt/vt_buf.c +++ b/sys/dev/vt/vt_buf.c @@ -448,8 +448,9 @@ vtbuf_grow(struct vt_buf *vb, const term_pos_t *p, int history_size) history_size = MAX(history_size, p->tp_row); - if (history_size > vb->vb_history_size || p->tp_col > - vb->vb_scr_size.tp_col) { + /* If new screen/history size bigger or buffer is VBF_STATIC. */ + if ((history_size > vb->vb_history_size) || (p->tp_col > + vb->vb_scr_size.tp_col) || (vb->vb_flags & VBF_STATIC)) { /* Allocate new buffer. */ bufsize = history_size * p->tp_col * sizeof(term_char_t); new = malloc(bufsize, M_VTBUF, M_WAITOK | M_ZERO); diff --git a/sys/dev/vt/vt_consolectl.c b/sys/dev/vt/vt_consolectl.c index f9c451780fc77..df8b341d41323 100644 --- a/sys/dev/vt/vt_consolectl.c +++ b/sys/dev/vt/vt_consolectl.c @@ -61,8 +61,10 @@ consolectl_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, return (0); } default: +#ifdef VT_CONSOLECTL_DEBUG printf("consolectl: unknown ioctl: %c:%lx\n", (char)IOCGROUP(cmd), IOCBASECMD(cmd)); +#endif return (ENOIOCTL); } } diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c index eb2843edaabf2..4b006a2addd56 100644 --- a/sys/dev/vt/vt_core.c +++ b/sys/dev/vt/vt_core.c @@ -144,6 +144,83 @@ static int vt_window_switch(struct vt_window *); static int vt_late_window_switch(struct vt_window *); static int vt_proc_alive(struct vt_window *); static void vt_resize(struct vt_device *); +static void vt_update_static(void *); + +SET_DECLARE(vt_drv_set, struct vt_driver); + +#define _VTDEFH MAX(100, PIXEL_HEIGHT(VT_FB_DEFAULT_HEIGHT)) +#define _VTDEFW MAX(200, PIXEL_WIDTH(VT_FB_DEFAULT_WIDTH)) + +static struct terminal vt_consterm; +static struct vt_window vt_conswindow; +static struct vt_device vt_consdev = { + .vd_driver = NULL, + .vd_softc = NULL, + .vd_flags = VDF_INVALID, + .vd_windows = { [VT_CONSWINDOW] = &vt_conswindow, }, + .vd_curwindow = &vt_conswindow, + .vd_markedwin = NULL, + .vd_kbstate = 0, +}; +static term_char_t vt_constextbuf[(_VTDEFW) * (VBF_DEFAULT_HISTORY_SIZE)]; +static term_char_t *vt_constextbufrows[VBF_DEFAULT_HISTORY_SIZE]; +static struct vt_window vt_conswindow = { + .vw_number = VT_CONSWINDOW, + .vw_flags = VWF_CONSOLE, + .vw_buf = { + .vb_buffer = vt_constextbuf, + .vb_rows = vt_constextbufrows, + .vb_history_size = VBF_DEFAULT_HISTORY_SIZE, + .vb_curroffset = 0, + .vb_roffset = 0, + .vb_flags = VBF_STATIC, + .vb_mark_start = {.tp_row = 0, .tp_col = 0,}, + .vb_mark_end = {.tp_row = 0, .tp_col = 0,}, + .vb_scr_size = { + .tp_row = _VTDEFH, + .tp_col = _VTDEFW, + }, + }, + .vw_device = &vt_consdev, + .vw_terminal = &vt_consterm, + .vw_kbdmode = K_XLATE, +}; +static struct terminal vt_consterm = { + .tm_class = &vt_termclass, + .tm_softc = &vt_conswindow, + .tm_flags = TF_CONS, +}; +static struct consdev vt_consterm_consdev = { + .cn_ops = &termcn_cnops, + .cn_arg = &vt_consterm, + .cn_name = "ttyv0", +}; + +/* Add to set of consoles. */ +DATA_SET(cons_set, vt_consterm_consdev); + +/* + * Right after kmem is done to allow early drivers to use locking and allocate + * memory. + */ +SYSINIT(vt_update_static, SI_SUB_KMEM, SI_ORDER_ANY, vt_update_static, + &vt_consdev); +/* Delay until all devices attached, to not waste time. */ +SYSINIT(vt_early_cons, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_ANY, vt_upgrade, + &vt_consdev); + +/* Initialize locks/mem depended members. */ +static void +vt_update_static(void *dummy) +{ + + if (main_vd != NULL) { + printf("VT: running with driver \"%s\".\n", + main_vd->vd_driver->vd_name); + mtx_init(&main_vd->vd_lock, "vtdev", NULL, MTX_DEF); + cv_init(&main_vd->vd_winswitch, "vtwswt"); + } +} static void vt_switch_timer(void *arg) @@ -601,6 +678,22 @@ vtterm_bell(struct terminal *tm) } static void +vtterm_beep(struct terminal *tm, u_int param) +{ + u_int freq, period; + + if ((param == 0) || ((param & 0xffff) == 0)) { + vtterm_bell(tm); + return; + } + + period = ((param >> 16) & 0xffff) * hz / 1000; + freq = 1193182 / (param & 0xffff); + + sysbeep(freq, period); +} + +static void vtterm_cursor(struct terminal *tm, const term_pos_t *p) { struct vt_window *vw = tm->tm_softc; @@ -775,7 +868,7 @@ vt_flush(struct vt_device *vd) if ((vd->vd_flags & (VDF_MOUSECURSOR|VDF_TEXTMODE)) == VDF_MOUSECURSOR) { m = &vt_default_mouse_pointer; - bpl = (m->w + 7) >> 3; /* Bytes per sorce line. */ + bpl = (m->w + 7) >> 3; /* Bytes per source line. */ w = m->w; h = m->h; @@ -851,9 +944,11 @@ vtterm_splash(struct vt_device *vd) } #endif + static void vtterm_cnprobe(struct terminal *tm, struct consdev *cp) { + struct vt_driver *vtd, **vtdlist, *vtdbest = NULL; struct vt_window *vw = tm->tm_softc; struct vt_device *vd = vw->vw_device; struct winsize wsz; @@ -862,6 +957,24 @@ vtterm_cnprobe(struct terminal *tm, struct consdev *cp) /* Initialization already done. */ return; + SET_FOREACH(vtdlist, vt_drv_set) { + vtd = *vtdlist; + if (vtd->vd_probe == NULL) + continue; + if (vtd->vd_probe(vd) == CN_DEAD) + continue; + if ((vtdbest == NULL) || + (vtd->vd_priority > vtdbest->vd_priority)) + vtdbest = vtd; + } + if (vtdbest == NULL) { + cp->cn_pri = CN_DEAD; + vd->vd_flags |= VDF_DEAD; + return; + } + + vd->vd_driver = vtdbest; + cp->cn_pri = vd->vd_driver->vd_init(vd); if (cp->cn_pri == CN_DEAD) { vd->vd_flags |= VDF_DEAD; @@ -1636,7 +1749,7 @@ skip_thunk: #endif return (0); case KDMKTONE: /* sound the bell */ - /* TODO */ + vtterm_beep(tm, *(u_int *)data); return (0); case KIOCSOUND: /* make tone (*data) hz */ /* TODO */ @@ -1705,6 +1818,7 @@ skip_thunk: vw->vw_flags |= VWF_VTYLOCK; else vw->vw_flags &= ~VWF_VTYLOCK; + return (0); case VT_OPENQRY: VT_LOCK(vd); for (i = 0; i < VT_MAXWINDOWS; i++) { @@ -1871,12 +1985,6 @@ vt_upgrade(struct vt_device *vd) return; vd->vd_flags |= VDF_ASYNC; - mtx_init(&vd->vd_lock, "vtdev", NULL, MTX_DEF); - cv_init(&vd->vd_winswitch, "vtwswt"); - - /* Init 25 Hz timer. */ - callout_init_mtx(&vd->vd_timer, &vd->vd_lock, 0); - for (i = 0; i < VT_MAXWINDOWS; i++) { vw = vd->vd_windows[i]; if (vw == NULL) { @@ -1894,6 +2002,7 @@ vt_upgrade(struct vt_device *vd) terminal_maketty(vw->vw_terminal, "v%r", VT_UNIT(vw)); } + VT_LOCK(vd); if (vd->vd_curwindow == NULL) vd->vd_curwindow = vd->vd_windows[VT_CONSWINDOW]; @@ -1901,8 +2010,16 @@ vt_upgrade(struct vt_device *vd) vt_allocate_keyboard(vd); DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard); + /* Init 25 Hz timer. */ + callout_init_mtx(&vd->vd_timer, &vd->vd_lock, 0); + /* Start timer when everything ready. */ callout_reset(&vd->vd_timer, hz / VT_TIMERFREQ, vt_timer, vd); + VT_UNLOCK(vd); + + /* Refill settings with new sizes. */ + vt_resize(vd); + } static void @@ -1913,9 +2030,11 @@ vt_resize(struct vt_device *vd) for (i = 0; i < VT_MAXWINDOWS; i++) { vw = vd->vd_windows[i]; + VT_LOCK(vd); /* Assign default font to window, if not textmode. */ if (!(vd->vd_flags & VDF_TEXTMODE) && vw->vw_font == NULL) vw->vw_font = vtfont_ref(&vt_font_default); + VT_UNLOCK(vd); /* Resize terminal windows */ vt_change_font(vw, vw->vw_font); } @@ -1929,21 +2048,26 @@ vt_allocate(struct vt_driver *drv, void *softc) if (main_vd == NULL) { main_vd = malloc(sizeof *vd, M_VT, M_WAITOK|M_ZERO); - printf("%s: VT initialize with new VT driver.\n", __func__); + printf("VT: initialize with new VT driver \"%s\".\n", + drv->vd_name); + mtx_init(&main_vd->vd_lock, "vtdev", NULL, MTX_DEF); + cv_init(&main_vd->vd_winswitch, "vtwswt"); + } else { /* * Check if have rights to replace current driver. For example: * it is bad idea to replace KMS driver with generic VGA one. */ if (drv->vd_priority <= main_vd->vd_driver->vd_priority) { - printf("%s: Driver priority %d too low. Current %d\n ", - __func__, drv->vd_priority, - main_vd->vd_driver->vd_priority); + printf("VT: Driver priority %d too low. Current %d\n ", + drv->vd_priority, main_vd->vd_driver->vd_priority); return; } - printf("%s: Replace existing VT driver.\n", __func__); + printf("VT: Replacing driver \"%s\" with new \"%s\".\n", + main_vd->vd_driver->vd_name, drv->vd_name); } vd = main_vd; + VT_LOCK(vd); if (drv->vd_maskbitbltchr == NULL) drv->vd_maskbitbltchr = drv->vd_bitbltchr; @@ -1966,12 +2090,10 @@ vt_allocate(struct vt_driver *drv, void *softc) vd->vd_driver = drv; vd->vd_softc = softc; vd->vd_driver->vd_init(vd); + VT_UNLOCK(vd); vt_upgrade(vd); - /* Refill settings with new sizes. */ - vt_resize(vd); - #ifdef DEV_SPLASH if (vd->vd_flags & VDF_SPLASH) vtterm_splash(vd); diff --git a/sys/dev/vt/vt_sysmouse.c b/sys/dev/vt/vt_sysmouse.c index 73ef39d735f23..92eee3c4b8c12 100644 --- a/sys/dev/vt/vt_sysmouse.c +++ b/sys/dev/vt/vt_sysmouse.c @@ -376,8 +376,10 @@ sysmouse_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, case MOUSE_MOUSECHAR: return (0); default: +#ifdef VT_SYSMOUSE_DEBUG printf("sysmouse: unknown ioctl: %c:%lx\n", (char)IOCGROUP(cmd), IOCBASECMD(cmd)); +#endif return (ENOIOCTL); } } diff --git a/sys/fs/fifofs/fifo_vnops.c b/sys/fs/fifofs/fifo_vnops.c index d3eb281779a48..a3e81792df874 100644 --- a/sys/fs/fifofs/fifo_vnops.c +++ b/sys/fs/fifofs/fifo_vnops.c @@ -146,9 +146,7 @@ fifo_open(ap) if (fp == NULL || (ap->a_mode & FEXEC) != 0) return (EINVAL); if ((fip = vp->v_fifoinfo) == NULL) { - error = pipe_named_ctor(&fpipe, td); - if (error != 0) - return (error); + pipe_named_ctor(&fpipe, td); fip = malloc(sizeof(*fip), M_VNODE, M_WAITOK); fip->fi_pipe = fpipe; fpipe->pipe_wgen = fip->fi_readers = fip->fi_writers = 0; diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c index 04cb3721e5beb..856ec7cbf5bac 100644 --- a/sys/fs/msdosfs/msdosfs_vnops.c +++ b/sys/fs/msdosfs/msdosfs_vnops.c @@ -1240,6 +1240,17 @@ abortit: VOP_UNLOCK(fvp, 0); goto bad; } + /* + * If ip is for a directory, then its name should always + * be "." since it is for the directory entry in the + * directory itself (msdosfs_lookup() always translates + * to the "." entry so as to get a unique denode, except + * for the root directory there are different + * complications). However, we just corrupted its name + * to pass the correct name to createde(). Undo this. + */ + if ((ip->de_Attributes & ATTR_DIRECTORY) != 0) + bcopy(oldname, ip->de_Name, 11); ip->de_refcnt++; zp->de_fndoffset = from_diroffset; error = removede(zp, ip); diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c index 76ee9e2c82bdc..5c50dfd430a27 100644 --- a/sys/fs/nfs/nfs_commonsubs.c +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -65,6 +65,7 @@ uid_t nfsrv_defaultuid; gid_t nfsrv_defaultgid; int nfsrv_lease = NFSRV_LEASE; int ncl_mbuf_mlen = MLEN; +int nfsd_enable_stringtouid = 0; NFSNAMEIDMUTEX; NFSSOCKMUTEX; @@ -2640,9 +2641,14 @@ nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp, /* If a string of digits and an AUTH_SYS mount, just convert it. */ str0 = str; tuid = (uid_t)strtoul(str0, &endstr, 10); - if ((endstr - str0) == len && - (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) { - *uidp = tuid; + if ((endstr - str0) == len) { + /* A numeric string. */ + if ((nd->nd_flag & ND_KERBV) == 0 && + ((nd->nd_flag & ND_NFSCL) != 0 || + nfsd_enable_stringtouid != 0)) + *uidp = tuid; + else + error = NFSERR_BADOWNER; goto out; } /* @@ -2845,9 +2851,14 @@ nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp, /* If a string of digits and an AUTH_SYS mount, just convert it. */ str0 = str; tgid = (gid_t)strtoul(str0, &endstr, 10); - if ((endstr - str0) == len && - (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) { - *gidp = tgid; + if ((endstr - str0) == len) { + /* A numeric string. */ + if ((nd->nd_flag & ND_KERBV) == 0 && + ((nd->nd_flag & ND_NFSCL) != 0 || + nfsd_enable_stringtouid != 0)) + *gidp = tgid; + else + error = NFSERR_BADOWNER; goto out; } /* diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index 5f8b884a6041a..0979864c70dbf 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -80,6 +80,7 @@ static int nfs_commit_blks; static int nfs_commit_miss; extern int nfsrv_issuedelegs; extern int nfsrv_dolocallocks; +extern int nfsd_enable_stringtouid; SYSCTL_NODE(_vfs, OID_AUTO, nfsd, CTLFLAG_RW, 0, "New NFS server"); SYSCTL_INT(_vfs_nfsd, OID_AUTO, mirrormnt, CTLFLAG_RW, @@ -92,6 +93,8 @@ SYSCTL_INT(_vfs_nfsd, OID_AUTO, issue_delegations, CTLFLAG_RW, &nfsrv_issuedelegs, 0, "Enable nfsd to issue delegations"); SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_locallocks, CTLFLAG_RW, &nfsrv_dolocallocks, 0, "Enable nfsd to acquire local locks on files"); +SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_stringtouid, CTLFLAG_RW, + &nfsd_enable_stringtouid, 0, "Enable nfsd to accept numeric owner_names"); #define MAX_REORDERED_RPC 16 #define NUM_HEURISTIC 1031 diff --git a/sys/geom/geom_disk.c b/sys/geom/geom_disk.c index 9548555913105..f2181ba755f01 100644 --- a/sys/geom/geom_disk.c +++ b/sys/geom/geom_disk.c @@ -47,7 +47,6 @@ __FBSDID("$FreeBSD$"); #include <sys/fcntl.h> #include <sys/malloc.h> #include <sys/sbuf.h> -#include <sys/sysctl.h> #include <sys/devicestat.h> #include <machine/md_var.h> diff --git a/sys/geom/label/g_label_ufs.c b/sys/geom/label/g_label_ufs.c index 46a3cb1bf5e71..ef012a98ef6fb 100644 --- a/sys/geom/label/g_label_ufs.c +++ b/sys/geom/label/g_label_ufs.c @@ -81,13 +81,15 @@ g_label_ufs_taste_common(struct g_consumer *cp, char *label, size_t size, int wh fs = (struct fs *)g_read_data(cp, superblock, SBLOCKSIZE, NULL); if (fs == NULL) continue; - /* Check for magic. We also need to check if file system size is equal + /* + * Check for magic. We also need to check if file system size is equal * to providers size, because sysinstall(8) used to bogusly put first * partition at offset 0 instead of 16, and glabel/ufs would find file * system on slice instead of partition. */ if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_fsize > 0 && - pp->mediasize / fs->fs_fsize == fs->fs_old_size) { + ((pp->mediasize / fs->fs_fsize == fs->fs_old_size) || + (pp->mediasize / fs->fs_fsize == fs->fs_providersize))) { /* Valid UFS1. */ } else if (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_fsize > 0 && ((pp->mediasize / fs->fs_fsize == fs->fs_size) || diff --git a/sys/geom/part/g_part.c b/sys/geom/part/g_part.c index 3c4519860ac5b..d5862a0d4a706 100644 --- a/sys/geom/part/g_part.c +++ b/sys/geom/part/g_part.c @@ -1316,7 +1316,9 @@ g_part_ctl_resize(struct gctl_req *req, struct g_part_parms *gpp) error = G_PART_RESIZE(table, entry, gpp); if (error) { - gctl_error(req, "%d", error); + gctl_error(req, "%d%s", error, error != EBUSY ? "": + " resizing will lead to unexpected shrinking" + " due to alignment"); return (error); } @@ -2063,8 +2065,10 @@ g_part_resize(struct g_consumer *cp) table->gpt_opened = 1; } if (G_PART_RESIZE(table, NULL, NULL) == 0) - printf("GEOM_PART: %s was automatically resized\n", - cp->geom->name); + printf("GEOM_PART: %s was automatically resized.\n" + " Use `gpart commit %s` to save changes or " + "`gpart undo %s` to revert them.\n", cp->geom->name, + cp->geom->name, cp->geom->name); if (g_part_check_integrity(table, cp) != 0) { g_access(cp, -1, -1, -1); table->gpt_opened = 0; diff --git a/sys/geom/part/g_part_ebr.c b/sys/geom/part/g_part_ebr.c index a8a940d77a49b..dfeda58538f38 100644 --- a/sys/geom/part/g_part_ebr.c +++ b/sys/geom/part/g_part_ebr.c @@ -220,47 +220,54 @@ ebr_set_chs(struct g_part_table *table, uint32_t lba, u_char *cylp, u_char *hdp, } static int +ebr_align(struct g_part_table *basetable, uint32_t *start, uint32_t *size) +{ + uint32_t sectors; + + sectors = basetable->gpt_sectors; + if (*size < 2 * sectors) + return (EINVAL); + if (*start % sectors) { + *size += (*start % sectors) - sectors; + *start -= (*start % sectors) - sectors; + } + if (*size % sectors) + *size -= (*size % sectors); + if (*size < 2 * sectors) + return (EINVAL); + return (0); +} + + +static int g_part_ebr_add(struct g_part_table *basetable, struct g_part_entry *baseentry, struct g_part_parms *gpp) { - struct g_geom *gp; struct g_provider *pp; struct g_part_ebr_entry *entry; - uint32_t start, size, sectors; + uint32_t start, size; if (gpp->gpp_parms & G_PART_PARM_LABEL) return (EINVAL); - gp = basetable->gpt_gp; - pp = LIST_FIRST(&gp->consumer)->provider; - sectors = basetable->gpt_sectors; - + pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; entry = (struct g_part_ebr_entry *)baseentry; - start = gpp->gpp_start; size = gpp->gpp_size; - if (size < 2 * sectors) - return (EINVAL); - if (start % sectors) { - size = size - sectors + (start % sectors); - start = start - (start % sectors) + sectors; - } - if (size % sectors) - size = size - (size % sectors); - if (size < 2 * sectors) + if (ebr_align(basetable, &start, &size) != 0) return (EINVAL); - if (baseentry->gpe_deleted) bzero(&entry->ent, sizeof(entry->ent)); KASSERT(baseentry->gpe_start <= start, ("%s", __func__)); KASSERT(baseentry->gpe_end >= start + size - 1, ("%s", __func__)); - baseentry->gpe_index = (start / sectors) + 1; - baseentry->gpe_offset = (off_t)(start + sectors) * pp->sectorsize; + baseentry->gpe_index = (start / basetable->gpt_sectors) + 1; + baseentry->gpe_offset = + (off_t)(start + basetable->gpt_sectors) * pp->sectorsize; baseentry->gpe_start = start; baseentry->gpe_end = start + size - 1; - entry->ent.dp_start = sectors; - entry->ent.dp_size = size - sectors; + entry->ent.dp_start = basetable->gpt_sectors; + entry->ent.dp_size = size - basetable->gpt_sectors; ebr_set_chs(basetable, entry->ent.dp_start, &entry->ent.dp_scyl, &entry->ent.dp_shd, &entry->ent.dp_ssect); ebr_set_chs(basetable, baseentry->gpe_end, &entry->ent.dp_ecyl, diff --git a/sys/geom/part/g_part_mbr.c b/sys/geom/part/g_part_mbr.c index e9085b120980a..73101ff6929bb 100644 --- a/sys/geom/part/g_part_mbr.c +++ b/sys/geom/part/g_part_mbr.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/sysctl.h> #include <geom/geom.h> +#include <geom/geom_int.h> #include <geom/part/g_part.h> #include "g_part_if.h" @@ -195,34 +196,39 @@ mbr_set_chs(struct g_part_table *table, uint32_t lba, u_char *cylp, u_char *hdp, } static int +mbr_align(struct g_part_table *basetable, uint32_t *start, uint32_t *size) +{ + uint32_t sectors; + + sectors = basetable->gpt_sectors; + if (*size < sectors) + return (EINVAL); + if (start != NULL && (*start % sectors)) { + *size += (*start % sectors) - sectors; + *start -= (*start % sectors) - sectors; + } + if (*size % sectors) + *size -= (*size % sectors); + if (*size < sectors) + return (EINVAL); + return (0); +} + +static int g_part_mbr_add(struct g_part_table *basetable, struct g_part_entry *baseentry, struct g_part_parms *gpp) { struct g_part_mbr_entry *entry; - struct g_part_mbr_table *table; - uint32_t start, size, sectors; + uint32_t start, size; if (gpp->gpp_parms & G_PART_PARM_LABEL) return (EINVAL); - sectors = basetable->gpt_sectors; - entry = (struct g_part_mbr_entry *)baseentry; - table = (struct g_part_mbr_table *)basetable; - start = gpp->gpp_start; size = gpp->gpp_size; - if (size < sectors) - return (EINVAL); - if (start % sectors) { - size = size - sectors + (start % sectors); - start = start - (start % sectors) + sectors; - } - if (size % sectors) - size = size - (size % sectors); - if (size < sectors) + if (mbr_align(basetable, &start, &size) != 0) return (EINVAL); - if (baseentry->gpe_deleted) bzero(&entry->ent, sizeof(entry->ent)); @@ -337,7 +343,7 @@ g_part_mbr_resize(struct g_part_table *basetable, { struct g_part_mbr_entry *entry; struct g_provider *pp; - uint32_t size, sectors; + uint32_t size; if (baseentry == NULL) { pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; @@ -345,16 +351,14 @@ g_part_mbr_resize(struct g_part_table *basetable, UINT32_MAX) - 1; return (0); } - sectors = basetable->gpt_sectors; size = gpp->gpp_size; - - if (size < sectors) + if (mbr_align(basetable, NULL, &size) != 0) return (EINVAL); - if (size % sectors) - size = size - (size % sectors); - if (size < sectors) - return (EINVAL); - + /* XXX: prevent unexpected shrinking. */ + pp = baseentry->gpe_pp; + if ((g_debugflags & 0x10) == 0 && size < gpp->gpp_size && + pp->mediasize / pp->sectorsize > size) + return (EBUSY); entry = (struct g_part_mbr_entry *)baseentry; baseentry->gpe_end = baseentry->gpe_start + size - 1; entry->ent.dp_size = size; diff --git a/sys/geom/part/g_part_pc98.c b/sys/geom/part/g_part_pc98.c index bd594313b7dad..07d6a628803ba 100644 --- a/sys/geom/part/g_part_pc98.c +++ b/sys/geom/part/g_part_pc98.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/sysctl.h> #include <geom/geom.h> +#include <geom/geom_int.h> #include <geom/part/g_part.h> #include "g_part_if.h" @@ -175,32 +176,37 @@ pc98_set_chs(struct g_part_table *table, uint32_t lba, u_short *cylp, } static int +pc98_align(struct g_part_table *basetable, uint32_t *start, uint32_t *size) +{ + uint32_t cyl; + + cyl = basetable->gpt_heads * basetable->gpt_sectors; + if (*size < cyl) + return (EINVAL); + if (start != NULL && (*start % cyl)) { + *size += (*start % cyl) - cyl; + *start -= (*start % cyl) - cyl; + } + if (*size % cyl) + *size -= (*size % cyl); + if (*size < cyl) + return (EINVAL); + return (0); +} + +static int g_part_pc98_add(struct g_part_table *basetable, struct g_part_entry *baseentry, struct g_part_parms *gpp) { struct g_part_pc98_entry *entry; - struct g_part_pc98_table *table; - uint32_t cyl, start, size; + uint32_t start, size; int error; - cyl = basetable->gpt_heads * basetable->gpt_sectors; - entry = (struct g_part_pc98_entry *)baseentry; - table = (struct g_part_pc98_table *)basetable; - start = gpp->gpp_start; size = gpp->gpp_size; - if (size < cyl) - return (EINVAL); - if (start % cyl) { - size = size - cyl + (start % cyl); - start = start - (start % cyl) + cyl; - } - if (size % cyl) - size = size - (size % cyl); - if (size < cyl) + if (pc98_align(basetable, &start, &size) != 0) return (EINVAL); - if (baseentry->gpe_deleted) bzero(&entry->ent, sizeof(entry->ent)); else @@ -344,7 +350,7 @@ g_part_pc98_resize(struct g_part_table *basetable, { struct g_part_pc98_entry *entry; struct g_provider *pp; - uint32_t size, cyl; + uint32_t size; if (baseentry == NULL) { pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; @@ -352,16 +358,14 @@ g_part_pc98_resize(struct g_part_table *basetable, UINT32_MAX) - 1; return (0); } - cyl = basetable->gpt_heads * basetable->gpt_sectors; size = gpp->gpp_size; - - if (size < cyl) + if (pc98_align(basetable, NULL, &size) != 0) return (EINVAL); - if (size % cyl) - size = size - (size % cyl); - if (size < cyl) - return (EINVAL); - + /* XXX: prevent unexpected shrinking. */ + pp = baseentry->gpe_pp; + if ((g_debugflags & 0x10) == 0 && size < gpp->gpp_size && + pp->mediasize / pp->sectorsize > size) + return (EBUSY); entry = (struct g_part_pc98_entry *)baseentry; baseentry->gpe_end = baseentry->gpe_start + size - 1; pc98_set_chs(basetable, baseentry->gpe_end, &entry->ent.dp_ecyl, diff --git a/sys/geom/part/g_part_vtoc8.c b/sys/geom/part/g_part_vtoc8.c index 833eceb7d1c47..514e3f7f1baa9 100644 --- a/sys/geom/part/g_part_vtoc8.c +++ b/sys/geom/part/g_part_vtoc8.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/vtoc.h> #include <geom/geom.h> +#include <geom/geom_int.h> #include <geom/part/g_part.h> #include "g_part_if.h" @@ -143,6 +144,23 @@ vtoc8_parse_type(const char *type, uint16_t *tag) } static int +vtoc8_align(struct g_part_vtoc8_table *table, uint64_t *start, uint64_t *size) +{ + + if (*size < table->secpercyl) + return (EINVAL); + if (start != NULL && (*start % table->secpercyl)) { + *size += (*start % table->secpercyl) - table->secpercyl; + *start -= (*start % table->secpercyl) - table->secpercyl; + } + if (*size % table->secpercyl) + *size -= (*size % table->secpercyl); + if (*size < table->secpercyl) + return (EINVAL); + return (0); +} + +static int g_part_vtoc8_add(struct g_part_table *basetable, struct g_part_entry *entry, struct g_part_parms *gpp) { @@ -160,16 +178,9 @@ g_part_vtoc8_add(struct g_part_table *basetable, struct g_part_entry *entry, table = (struct g_part_vtoc8_table *)basetable; index = entry->gpe_index - 1; - start = gpp->gpp_start; size = gpp->gpp_size; - if (start % table->secpercyl) { - size = size - table->secpercyl + (start % table->secpercyl); - start = start - (start % table->secpercyl) + table->secpercyl; - } - if (size % table->secpercyl) - size = size - (size % table->secpercyl); - if (size < table->secpercyl) + if (vtoc8_align(table, &start, &size) != 0) return (EINVAL); KASSERT(entry->gpe_start <= start, (__func__)); @@ -355,11 +366,13 @@ g_part_vtoc8_resize(struct g_part_table *basetable, } table = (struct g_part_vtoc8_table *)basetable; size = gpp->gpp_size; - if (size % table->secpercyl) - size = size - (size % table->secpercyl); - if (size < table->secpercyl) + if (vtoc8_align(table, NULL, &size) != 0) return (EINVAL); - + /* XXX: prevent unexpected shrinking. */ + pp = entry->gpe_pp; + if ((g_debugflags & 0x10) == 0 && size < gpp->gpp_size && + pp->mediasize / pp->sectorsize > size) + return (EBUSY); entry->gpe_end = entry->gpe_start + size - 1; be32enc(&table->vtoc.map[entry->gpe_index - 1].nblks, size); diff --git a/sys/geom/raid/g_raid.c b/sys/geom/raid/g_raid.c index a161f8a1004aa..858cf4c75b271 100644 --- a/sys/geom/raid/g_raid.c +++ b/sys/geom/raid/g_raid.c @@ -2251,6 +2251,8 @@ g_raid_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) return (NULL); G_RAID_DEBUG(2, "Tasting provider %s.", pp->name); + geom = NULL; + status = G_RAID_MD_TASTE_FAIL; gp = g_new_geomf(mp, "raid:taste"); /* * This orphan function should be never called. @@ -2259,8 +2261,9 @@ g_raid_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) cp = g_new_consumer(gp); cp->flags |= G_CF_DIRECT_RECEIVE; g_attach(cp, pp); + if (g_access(cp, 1, 0, 0) != 0) + goto ofail; - geom = NULL; LIST_FOREACH(class, &g_raid_md_classes, mdc_list) { if (!class->mdc_enable) continue; @@ -2276,6 +2279,9 @@ g_raid_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) break; } + if (status == G_RAID_MD_TASTE_FAIL) + (void)g_access(cp, -1, 0, 0); +ofail: g_detach(cp); g_destroy_consumer(cp); g_destroy_geom(gp); diff --git a/sys/geom/raid/md_ddf.c b/sys/geom/raid/md_ddf.c index 63d767ddcc91b..eed048da32fc3 100644 --- a/sys/geom/raid/md_ddf.c +++ b/sys/geom/raid/md_ddf.c @@ -2120,13 +2120,10 @@ g_raid_md_taste_ddf(struct g_raid_md_object *md, struct g_class *mp, pp = cp->provider; /* Read metadata from device. */ - if (g_access(cp, 1, 0, 0) != 0) - return (G_RAID_MD_TASTE_FAIL); g_topology_unlock(); bzero(&meta, sizeof(meta)); error = ddf_meta_read(cp, &meta); g_topology_lock(); - g_access(cp, -1, 0, 0); if (error != 0) return (G_RAID_MD_TASTE_FAIL); be = meta.bigendian; @@ -2164,6 +2161,9 @@ g_raid_md_taste_ddf(struct g_raid_md_object *md, struct g_class *mp, geom = sc->sc_geom; } + /* There is no return after this point, so we close passed consumer. */ + g_access(cp, -1, 0, 0); + rcp = g_new_consumer(geom); rcp->flags |= G_CF_DIRECT_RECEIVE; g_attach(rcp, pp); diff --git a/sys/geom/raid/md_intel.c b/sys/geom/raid/md_intel.c index 11917f578e37a..7e6173e28d176 100644 --- a/sys/geom/raid/md_intel.c +++ b/sys/geom/raid/md_intel.c @@ -1382,8 +1382,6 @@ g_raid_md_taste_intel(struct g_raid_md_object *md, struct g_class *mp, meta = NULL; vendor = 0xffff; disk_pos = 0; - if (g_access(cp, 1, 0, 0) != 0) - return (G_RAID_MD_TASTE_FAIL); g_topology_unlock(); error = g_raid_md_get_label(cp, serial, sizeof(serial)); if (error != 0) { @@ -1396,7 +1394,6 @@ g_raid_md_taste_intel(struct g_raid_md_object *md, struct g_class *mp, g_io_getattr("GEOM::hba_vendor", cp, &len, &vendor); meta = intel_meta_read(cp); g_topology_lock(); - g_access(cp, -1, 0, 0); if (meta == NULL) { if (g_raid_aggressive_spare) { if (vendor != 0x8086) { @@ -1476,6 +1473,9 @@ search: G_RAID_DEBUG1(1, sc, "root_mount_hold %p", mdi->mdio_rootmount); } + /* There is no return after this point, so we close passed consumer. */ + g_access(cp, -1, 0, 0); + rcp = g_new_consumer(geom); rcp->flags |= G_CF_DIRECT_RECEIVE; g_attach(rcp, pp); @@ -1512,7 +1512,6 @@ search: return (result); fail2: g_topology_lock(); - g_access(cp, -1, 0, 0); fail1: free(meta, M_MD_INTEL); return (G_RAID_MD_TASTE_FAIL); diff --git a/sys/geom/raid/md_jmicron.c b/sys/geom/raid/md_jmicron.c index 2da4a33a799e1..d4748e068b6d9 100644 --- a/sys/geom/raid/md_jmicron.c +++ b/sys/geom/raid/md_jmicron.c @@ -837,15 +837,12 @@ g_raid_md_taste_jmicron(struct g_raid_md_object *md, struct g_class *mp, /* Read metadata from device. */ meta = NULL; vendor = 0xffff; - if (g_access(cp, 1, 0, 0) != 0) - return (G_RAID_MD_TASTE_FAIL); g_topology_unlock(); len = 2; if (pp->geom->rank == 1) g_io_getattr("GEOM::hba_vendor", cp, &len, &vendor); meta = jmicron_meta_read(cp); g_topology_lock(); - g_access(cp, -1, 0, 0); if (meta == NULL) { if (g_raid_aggressive_spare) { if (vendor == 0x197b) { @@ -922,6 +919,9 @@ search: G_RAID_DEBUG1(1, sc, "root_mount_hold %p", mdi->mdio_rootmount); } + /* There is no return after this point, so we close passed consumer. */ + g_access(cp, -1, 0, 0); + rcp = g_new_consumer(geom); rcp->flags |= G_CF_DIRECT_RECEIVE; g_attach(rcp, pp); diff --git a/sys/geom/raid/md_nvidia.c b/sys/geom/raid/md_nvidia.c index 25cc2cc099db3..eb2e4931a4559 100644 --- a/sys/geom/raid/md_nvidia.c +++ b/sys/geom/raid/md_nvidia.c @@ -841,15 +841,12 @@ g_raid_md_taste_nvidia(struct g_raid_md_object *md, struct g_class *mp, /* Read metadata from device. */ meta = NULL; vendor = 0xffff; - if (g_access(cp, 1, 0, 0) != 0) - return (G_RAID_MD_TASTE_FAIL); g_topology_unlock(); len = 2; if (pp->geom->rank == 1) g_io_getattr("GEOM::hba_vendor", cp, &len, &vendor); meta = nvidia_meta_read(cp); g_topology_lock(); - g_access(cp, -1, 0, 0); if (meta == NULL) { if (g_raid_aggressive_spare) { if (vendor == 0x10de) { @@ -918,6 +915,9 @@ search: G_RAID_DEBUG1(1, sc, "root_mount_hold %p", mdi->mdio_rootmount); } + /* There is no return after this point, so we close passed consumer. */ + g_access(cp, -1, 0, 0); + rcp = g_new_consumer(geom); rcp->flags |= G_CF_DIRECT_RECEIVE; g_attach(rcp, pp); diff --git a/sys/geom/raid/md_promise.c b/sys/geom/raid/md_promise.c index b1e442702815f..73a2520be12aa 100644 --- a/sys/geom/raid/md_promise.c +++ b/sys/geom/raid/md_promise.c @@ -1106,15 +1106,12 @@ g_raid_md_taste_promise(struct g_raid_md_object *md, struct g_class *mp, /* Read metadata from device. */ meta = NULL; vendor = 0xffff; - if (g_access(cp, 1, 0, 0) != 0) - return (G_RAID_MD_TASTE_FAIL); g_topology_unlock(); len = 2; if (pp->geom->rank == 1) g_io_getattr("GEOM::hba_vendor", cp, &len, &vendor); subdisks = promise_meta_read(cp, metaarr); g_topology_lock(); - g_access(cp, -1, 0, 0); if (subdisks == 0) { if (g_raid_aggressive_spare) { if (vendor == 0x105a || vendor == 0x1002) { @@ -1175,6 +1172,9 @@ search: geom = sc->sc_geom; } + /* There is no return after this point, so we close passed consumer. */ + g_access(cp, -1, 0, 0); + rcp = g_new_consumer(geom); rcp->flags |= G_CF_DIRECT_RECEIVE; g_attach(rcp, pp); diff --git a/sys/geom/raid/md_sii.c b/sys/geom/raid/md_sii.c index 149b3369c6bd6..5012dc5813935 100644 --- a/sys/geom/raid/md_sii.c +++ b/sys/geom/raid/md_sii.c @@ -923,15 +923,12 @@ g_raid_md_taste_sii(struct g_raid_md_object *md, struct g_class *mp, /* Read metadata from device. */ meta = NULL; vendor = 0xffff; - if (g_access(cp, 1, 0, 0) != 0) - return (G_RAID_MD_TASTE_FAIL); g_topology_unlock(); len = 2; if (pp->geom->rank == 1) g_io_getattr("GEOM::hba_vendor", cp, &len, &vendor); meta = sii_meta_read(cp); g_topology_lock(); - g_access(cp, -1, 0, 0); if (meta == NULL) { if (g_raid_aggressive_spare) { if (vendor == 0x1095) { @@ -1011,6 +1008,9 @@ search: G_RAID_DEBUG1(1, sc, "root_mount_hold %p", mdi->mdio_rootmount); } + /* There is no return after this point, so we close passed consumer. */ + g_access(cp, -1, 0, 0); + rcp = g_new_consumer(geom); rcp->flags |= G_CF_DIRECT_RECEIVE; g_attach(rcp, pp); diff --git a/sys/geom/uncompress/g_uncompress.c b/sys/geom/uncompress/g_uncompress.c index 629e9d5d1d9c3..5bc8d30bc1dec 100644 --- a/sys/geom/uncompress/g_uncompress.c +++ b/sys/geom/uncompress/g_uncompress.c @@ -116,7 +116,7 @@ g_uncompress_softc_free(struct g_uncompress_softc *sc, struct g_geom *gp) } if (sc->offsets != NULL) { free(sc->offsets, M_GEOM_UNCOMPRESS); - sc->offsets = 0; + sc->offsets = NULL; } switch (sc->type) { @@ -150,6 +150,7 @@ z_alloc(void *nil, u_int type, u_int size) void *ptr; ptr = malloc(type * size, M_GEOM_UNCOMPRESS, M_NOWAIT); + return (ptr); } @@ -221,11 +222,11 @@ g_uncompress_done(struct bio *bp) (intmax_t)bp2->bio_offset, sc->blksz, bsize)); for (i = start_blk; upos < bp2->bio_length; i++) { - off_t len, dlen, ulen, uoff; + off_t len, ulen, uoff; uoff = i == start_blk ? bp2->bio_offset % sc->blksz : 0; ulen = MIN(sc->blksz - uoff, bp2->bio_length - upos); - dlen = len = sc->offsets[i + 1] - sc->offsets[i]; + len = sc->offsets[i + 1] - sc->offsets[i]; DPRINTF(( "%s: done: inflate block %d, start %ju, end %ju len %jd\n", @@ -239,19 +240,17 @@ g_uncompress_done(struct bio *bp) bp2->bio_completed += ulen; continue; } - if (len > iolen) { DPRINTF(("%s: done: early termination: len (%jd) > " "iolen (%jd)\n", gp->name, (intmax_t)len, (intmax_t)iolen)); break; } - mtx_lock(&sc->last_mtx); #ifdef GEOM_UNCOMPRESS_DEBUG if (g_debugflags & 32) - hexdump(bp->bio_data + pos, dlen, 0, 0); + hexdump(bp->bio_data + pos, len, 0, 0); #endif switch (sc->type) { @@ -259,7 +258,7 @@ g_uncompress_done(struct bio *bp) sc->b->in = bp->bio_data + pos; sc->b->out = sc->last_buf; sc->b->in_pos = sc->b->out_pos = 0; - sc->b->in_size = dlen; + sc->b->in_size = len; sc->b->out_size = (size_t)-1; err = (xz_dec_run(sc->s, sc->b) != XZ_STREAM_END) ? @@ -268,7 +267,7 @@ g_uncompress_done(struct bio *bp) break; case GEOM_UZIP: sc->zs->next_in = bp->bio_data + pos; - sc->zs->avail_in = dlen; + sc->zs->avail_in = len; sc->zs->next_out = sc->last_buf; sc->zs->avail_out = sc->blksz; @@ -328,7 +327,6 @@ g_uncompress_start(struct bio *bp) uint32_t start_blk, end_blk; size_t bsize; - pp = bp->bio_to; gp = pp->geom; DPRINTF(("%s: start (%d:%s) to %s off=%jd len=%jd\n", @@ -347,10 +345,8 @@ g_uncompress_start(struct bio *bp) start_blk = bp->bio_offset / sc->blksz; end_blk = howmany(bp->bio_offset + bp->bio_length, sc->blksz); - KASSERT(start_blk < sc->nblocks, - ("start_blk out of range")); - KASSERT(end_blk <= sc->nblocks, - ("end_blk out of range")); + KASSERT(start_blk < sc->nblocks, ("start_blk out of range")); + KASSERT(end_blk <= sc->nblocks, ("end_blk out of range")); sc->req_total++; if (start_blk + 1 == end_blk) { @@ -385,9 +381,7 @@ g_uncompress_start(struct bio *bp) gp->name, start_blk, end_blk, pp->name, pp->sectorsize, (intmax_t)pp->mediasize, pp2->name, pp2->sectorsize, (intmax_t)pp2->mediasize)); - bsize = pp2->sectorsize; - bp2->bio_done = g_uncompress_done; bp2->bio_offset = rounddown(sc->offsets[start_blk], bsize); while (1) { @@ -401,14 +395,12 @@ g_uncompress_start(struct bio *bp) "%s: bio_length (%jd) > MAXPHYS: lowering end_blk to %u\n", gp->name, (intmax_t)bp2->bio_length, end_blk)); } - DPRINTF(("%s: start %jd + %jd -> %ju + %ju -> %jd + %jd\n", gp->name, (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length, (uintmax_t)sc->offsets[start_blk], (uintmax_t)sc->offsets[end_blk] - sc->offsets[start_blk], (intmax_t)bp2->bio_offset, (intmax_t)bp2->bio_length)); - bp2->bio_data = malloc(bp2->bio_length, M_GEOM_UNCOMPRESS, M_NOWAIT); if (bp2->bio_data == NULL) { g_destroy_bio(bp2); @@ -425,8 +417,7 @@ g_uncompress_orphan(struct g_consumer *cp) { struct g_geom *gp; - g_trace(G_T_TOPOLOGY, "%s(%p/%s)", __func__, cp, - cp->provider->name); + g_trace(G_T_TOPOLOGY, "%s(%p/%s)", __func__, cp, cp->provider->name); g_topology_assert(); gp = cp->geom; @@ -508,15 +499,13 @@ g_uncompress_taste(struct g_class *mp, struct g_provider *pp, int flags) */ DPRINTF(("%s: media sectorsize %u, mediasize %jd\n", gp->name, pp->sectorsize, (intmax_t)pp->mediasize)); - i = roundup(sizeof(struct cloop_header), pp->sectorsize); buf = g_read_data(cp, 0, i, NULL); if (buf == NULL) goto err; - header = (struct cloop_header *) buf; if (strncmp(header->magic, CLOOP_MAGIC_START, - sizeof(CLOOP_MAGIC_START) - 1) != 0) { + sizeof(CLOOP_MAGIC_START) - 1) != 0) { DPRINTF(("%s: no CLOOP magic\n", gp->name)); goto err; } @@ -571,7 +560,7 @@ g_uncompress_taste(struct g_class *mp, struct g_provider *pp, int flags) free(buf, M_GEOM); i = roundup((sizeof(struct cloop_header) + - total_offsets * sizeof(uint64_t)),pp->sectorsize); + total_offsets * sizeof(uint64_t)), pp->sectorsize); buf = g_read_data(cp, 0, i, NULL); if (buf == NULL) goto err; @@ -581,6 +570,7 @@ g_uncompress_taste(struct g_class *mp, struct g_provider *pp, int flags) sc->offsets[i] = be64toh(((uint64_t *) (buf+sizeof(struct cloop_header)))[i]); } + free(buf, M_GEOM); DPRINTF(("%s: done reading offsets\n", gp->name)); mtx_init(&sc->last_mtx, "geom_uncompress cache", NULL, MTX_DEF); sc->last_blk = -1; @@ -615,15 +605,13 @@ g_uncompress_taste(struct g_class *mp, struct g_provider *pp, int flags) pp2->stripeoffset = pp->stripeoffset; } g_error_provider(pp2, 0); - free(buf, M_GEOM); g_access(cp, -1, 0, 0); DPRINTF(("%s: taste ok (%d, %jd), (%d, %d), %x\n", gp->name, pp2->sectorsize, (intmax_t)pp2->mediasize, pp2->stripeoffset, pp2->stripesize, pp2->flags)); - printf("%s: %u x %u blocks\n", - gp->name, sc->nblocks, sc->blksz); + printf("%s: %u x %u blocks\n", gp->name, sc->nblocks, sc->blksz); return (gp); err: @@ -638,6 +626,7 @@ err: g_detach(cp); g_destroy_consumer(cp); g_destroy_geom(gp); + return (NULL); } @@ -664,6 +653,7 @@ g_uncompress_destroy_geom(struct gctl_req *req, struct g_class *mp, g_uncompress_softc_free(gp->softc, gp); gp->softc = NULL; g_wither_geom(gp, ENXIO); + return (0); } diff --git a/sys/geom/uzip/g_uzip.c b/sys/geom/uzip/g_uzip.c index 7ba347712ab13..1dacfa0b4e9e7 100644 --- a/sys/geom/uzip/g_uzip.c +++ b/sys/geom/uzip/g_uzip.c @@ -35,8 +35,8 @@ __FBSDID("$FreeBSD$"); #include <sys/lock.h> #include <sys/mutex.h> #include <sys/malloc.h> -#include <sys/systm.h> #include <sys/sysctl.h> +#include <sys/systm.h> #include <geom/geom.h> #include <net/zlib.h> @@ -45,19 +45,19 @@ FEATURE(geom_uzip, "GEOM uzip read-only compressed disks support"); #undef GEOM_UZIP_DEBUG #ifdef GEOM_UZIP_DEBUG -#define DPRINTF(a) printf a +#define DPRINTF(a) printf a #else -#define DPRINTF(a) +#define DPRINTF(a) #endif static MALLOC_DEFINE(M_GEOM_UZIP, "geom_uzip", "GEOM UZIP data structures"); -#define UZIP_CLASS_NAME "UZIP" +#define UZIP_CLASS_NAME "UZIP" /* * Maximum allowed valid block size (to prevent foot-shooting) */ -#define MAX_BLKSZ (MAXPHYS - MAXPHYS / 1000 - 12) +#define MAX_BLKSZ (MAXPHYS - MAXPHYS / 1000 - 12) /* * Integer values (block size, number of blocks, offsets) @@ -65,7 +65,7 @@ static MALLOC_DEFINE(M_GEOM_UZIP, "geom_uzip", "GEOM UZIP data structures"); * and in native order in struct g_uzip_softc */ -#define CLOOP_MAGIC_LEN 128 +#define CLOOP_MAGIC_LEN 128 static char CLOOP_MAGIC_START[] = "#!/bin/sh\n"; struct cloop_header { @@ -89,12 +89,15 @@ struct g_uzip_softc { static void g_uzip_softc_free(struct g_uzip_softc *sc, struct g_geom *gp) { + if (gp != NULL) { printf("%s: %d requests, %d cached\n", gp->name, sc->req_total, sc->req_cached); } - if (sc->offsets != NULL) + if (sc->offsets != NULL) { free(sc->offsets, M_GEOM_UZIP); + sc->offsets = NULL; + } mtx_destroy(&sc->last_mtx); free(sc->last_buf, M_GEOM_UZIP); free(sc, M_GEOM_UZIP); @@ -106,12 +109,14 @@ z_alloc(void *nil, u_int type, u_int size) void *ptr; ptr = malloc(type * size, M_GEOM_UZIP, M_NOWAIT); - return ptr; + + return (ptr); } static void z_free(void *nil, void *ptr) { + free(ptr, M_GEOM_UZIP); } @@ -258,10 +263,8 @@ g_uzip_start(struct bio *bp) start_blk = bp->bio_offset / sc->blksz; end_blk = (bp->bio_offset + bp->bio_length + sc->blksz - 1) / sc->blksz; - KASSERT(start_blk < sc->nblocks, - ("start_blk out of range")); - KASSERT(end_blk <= sc->nblocks, - ("end_blk out of range")); + KASSERT(start_blk < sc->nblocks, ("start_blk out of range")); + KASSERT(end_blk <= sc->nblocks, ("end_blk out of range")); sc->req_total++; if (start_blk + 1 == end_blk) { @@ -331,7 +334,7 @@ g_uzip_orphan(struct g_consumer *cp) { struct g_geom *gp; - g_trace(G_T_TOPOLOGY, "g_uzip_orphan(%p/%s)", cp, cp->provider->name); + g_trace(G_T_TOPOLOGY, "%s(%p/%s)", __func__, cp, cp->provider->name); g_topology_assert(); gp = cp->geom; @@ -351,7 +354,7 @@ g_uzip_access(struct g_provider *pp, int dr, int dw, int de) KASSERT (cp != NULL, ("g_uzip_access but no consumer")); if (cp->acw + dw > 0) - return EROFS; + return (EROFS); return (g_access(cp, dr, dw, de)); } @@ -362,7 +365,7 @@ g_uzip_spoiled(struct g_consumer *cp) struct g_geom *gp; gp = cp->geom; - g_trace(G_T_TOPOLOGY, "g_uzip_spoiled(%p/%s)", cp, gp->name); + g_trace(G_T_TOPOLOGY, "%s(%p/%s)", __func__, cp, gp->name); g_topology_assert(); g_uzip_softc_free(gp->softc, gp); @@ -382,7 +385,7 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags) struct g_provider *pp2; struct g_uzip_softc *sc; - g_trace(G_T_TOPOLOGY, "g_uzip_taste(%s,%s)", mp->name, pp->name); + g_trace(G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name); g_topology_assert(); /* Skip providers that are already open for writing. */ @@ -418,7 +421,7 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags) goto err; header = (struct cloop_header *) buf; if (strncmp(header->magic, CLOOP_MAGIC_START, - sizeof(CLOOP_MAGIC_START) - 1) != 0) { + sizeof(CLOOP_MAGIC_START) - 1) != 0) { DPRINTF(("%s: no CLOOP magic\n", gp->name)); goto err; } @@ -447,7 +450,7 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags) if (sizeof(struct cloop_header) + total_offsets * sizeof(uint64_t) > pp->mediasize) { printf("%s: media too small for %u blocks\n", - gp->name, sc->nblocks); + gp->name, sc->nblocks); goto err; } sc->offsets = malloc( @@ -476,6 +479,7 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags) } offsets_read += nread; } + free(buf, M_GEOM); DPRINTF(("%s: done reading offsets\n", gp->name)); mtx_init(&sc->last_mtx, "geom_uzip cache", NULL, MTX_DEF); sc->last_blk = -1; @@ -487,8 +491,8 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags) pp2 = g_new_providerf(gp, "%s", gp->name); pp2->sectorsize = 512; pp2->mediasize = (off_t)sc->nblocks * sc->blksz; - pp2->stripesize = pp->stripesize; - pp2->stripeoffset = pp->stripeoffset; + pp2->stripesize = pp->stripesize; + pp2->stripeoffset = pp->stripeoffset; g_error_provider(pp2, 0); g_access(cp, -1, 0, 0); @@ -496,8 +500,7 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags) gp->name, pp2->sectorsize, (intmax_t)pp2->mediasize, pp2->stripeoffset, pp2->stripesize, pp2->flags)); - printf("%s: %u x %u blocks\n", - gp->name, sc->nblocks, sc->blksz); + printf("%s: %u x %u blocks\n", gp->name, sc->nblocks, sc->blksz); return (gp); err: @@ -512,6 +515,7 @@ err: g_detach(cp); g_destroy_consumer(cp); g_destroy_geom(gp); + return (NULL); } @@ -520,7 +524,7 @@ g_uzip_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) { struct g_provider *pp; - g_trace(G_T_TOPOLOGY, "g_uzip_destroy_geom(%s, %s)", mp->name, gp->name); + g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, gp->name); g_topology_assert(); if (gp->softc == NULL) { @@ -537,6 +541,7 @@ g_uzip_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) g_uzip_softc_free(gp->softc, gp); gp->softc = NULL; g_wither_geom(gp, ENXIO); + return (0); } diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC index 29b11de5f915f..62d1acef16b89 100644 --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -119,6 +119,7 @@ device isp # Qlogic family #device ispfw # Firmware for QLogic HBAs- normally a module device mpt # LSI-Logic MPT-Fusion device mps # LSI-Logic MPT-Fusion 2 +device mpr # LSI-Logic MPT-Fusion 3 #device ncr # NCR/Symbios Logic device sym # NCR/Symbios Logic (newer chipsets + those of `ncr') device trm # Tekram DC395U/UW/F DC315U adapters diff --git a/sys/i386/conf/GENERIC.hints b/sys/i386/conf/GENERIC.hints index 98c906d339896..fb302408048bb 100644 --- a/sys/i386/conf/GENERIC.hints +++ b/sys/i386/conf/GENERIC.hints @@ -39,3 +39,5 @@ hint.attimer.0.at="isa" hint.attimer.0.port="0x40" hint.attimer.0.irq="0" hint.wbwd.0.at="isa" +hint.acpi_throttle.0.disabled="1" +hint.p4tcc.0.disabled="1" diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index 58787227167a5..6ce701c432f9d 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -1002,9 +1002,6 @@ device streams # STREAMS network driver (required for svr4). options NDISAPI device ndis -# Linux-specific pseudo devices support -device lindev - ##################################################################### # VM OPTIONS diff --git a/sys/i386/conf/XEN b/sys/i386/conf/XEN index 29939b42a79bc..17226dcd5eb53 100644 --- a/sys/i386/conf/XEN +++ b/sys/i386/conf/XEN @@ -7,7 +7,7 @@ cpu I686_CPU ident XEN makeoptions DEBUG=-g -makeoptions WITHOUT_MODULES="aha ahb amd ctl cxgb dpt drm drm2 hptnr hptmv ida malo mps mwl rdma sound sym trm xfs" +makeoptions WITHOUT_MODULES="aha ahb amd ctl cxgb dpt drm drm2 hptnr hptmv ida malo mpr mps mwl rdma sound sym trm xfs" options SCHED_ULE # ULE scheduler options PREEMPTION # Enable kernel thread preemption diff --git a/sys/ia64/conf/GENERIC b/sys/ia64/conf/GENERIC index bb53cf9883fca..7225f9284f593 100644 --- a/sys/ia64/conf/GENERIC +++ b/sys/ia64/conf/GENERIC @@ -94,6 +94,8 @@ device ahd # AHA39320/29320 and AIC79xx devices device hptiop # Highpoint RocketRaid 3xxx series device isp # Qlogic family device mpt # LSI-Logic MPT-Fusion +device mps # LSI-Logic MPT-Fusion 2 +device mpr # LSI-Logic MPT-Fusion 3 device sym # NCR/Symbios Logic # RAID controllers interfaced to the SCSI subsystem diff --git a/sys/kern/kern_cpu.c b/sys/kern/kern_cpu.c index b0de2a23f892e..b4ba635ed1293 100644 --- a/sys/kern/kern_cpu.c +++ b/sys/kern/kern_cpu.c @@ -1037,6 +1037,7 @@ cpufreq_unregister(device_t dev) if (cf_dev == NULL) { device_printf(dev, "warning: cpufreq_unregister called with no cpufreq device active\n"); + free(devs, M_TEMP); return (0); } cfcount = 0; diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index bc78785aea90d..88b26af30cc50 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -3010,7 +3010,7 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) struct tty *tp; name = (int *)arg1; - error = pget((pid_t)name[0], PGET_CANDEBUG, &p); + error = pget((pid_t)name[0], PGET_CANDEBUG | PGET_NOTWEXIT, &p); if (error != 0) return (error); fdp = fdhold(p); @@ -3503,7 +3503,7 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS) name = (int *)arg1; sbuf_new_for_sysctl(&sb, NULL, FILEDESC_SBUF_SIZE, req); - error = pget((pid_t)name[0], PGET_CANDEBUG, &p); + error = pget((pid_t)name[0], PGET_CANDEBUG | PGET_NOTWEXIT, &p); if (error != 0) { sbuf_delete(&sb); return (error); diff --git a/sys/kern/kern_mtxpool.c b/sys/kern/kern_mtxpool.c index 23b41bbb2fbc9..0c6f95bd27769 100644 --- a/sys/kern/kern_mtxpool.c +++ b/sys/kern/kern_mtxpool.c @@ -59,9 +59,6 @@ __FBSDID("$FreeBSD$"); static MALLOC_DEFINE(M_MTXPOOL, "mtx_pool", "mutex pool"); /* Pool sizes must be a power of two */ -#ifndef MTX_POOL_LOCKBUILDER_SIZE -#define MTX_POOL_LOCKBUILDER_SIZE 128 -#endif #ifndef MTX_POOL_SLEEP_SIZE #define MTX_POOL_SLEEP_SIZE 128 #endif @@ -78,18 +75,12 @@ struct mtx_pool { struct mtx mtx_pool_ary[1]; }; -static struct mtx_pool_lockbuilder { - struct mtxpool_header mtx_pool_header; - struct mtx mtx_pool_ary[MTX_POOL_LOCKBUILDER_SIZE]; -} lockbuilder_pool; - #define mtx_pool_size mtx_pool_header.mtxpool_size #define mtx_pool_mask mtx_pool_header.mtxpool_mask #define mtx_pool_shift mtx_pool_header.mtxpool_shift #define mtx_pool_next mtx_pool_header.mtxpool_next struct mtx_pool *mtxpool_sleep; -struct mtx_pool *mtxpool_lockbuilder; #if UINTPTR_MAX == UINT64_MAX /* 64 bits */ # define POINTER_BITS 64 @@ -166,15 +157,6 @@ mtx_pool_destroy(struct mtx_pool **poolp) } static void -mtx_pool_setup_static(void *dummy __unused) -{ - mtx_pool_initialize((struct mtx_pool *)&lockbuilder_pool, - "lockbuilder mtxpool", MTX_POOL_LOCKBUILDER_SIZE, - MTX_DEF | MTX_NOWITNESS | MTX_QUIET); - mtxpool_lockbuilder = (struct mtx_pool *)&lockbuilder_pool; -} - -static void mtx_pool_setup_dynamic(void *dummy __unused) { mtxpool_sleep = mtx_pool_create("sleep mtxpool", @@ -202,17 +184,5 @@ mtx_pool_alloc(struct mtx_pool *pool) return (&pool->mtx_pool_ary[i]); } -/* - * The lockbuilder pool must be initialized early because the lockmgr - * and sx locks depend on it. The sx locks are used in the kernel - * memory allocator. The lockmgr subsystem is initialized by - * SYSINIT(..., SI_SUB_LOCKMGR, ...). - * - * We can't call malloc() to dynamically allocate the sleep pool - * until after kmeminit() has been called, which is done by - * SYSINIT(..., SI_SUB_KMEM, ...). - */ -SYSINIT(mtxpooli1, SI_SUB_MTX_POOL_STATIC, SI_ORDER_FIRST, - mtx_pool_setup_static, NULL); SYSINIT(mtxpooli2, SI_SUB_MTX_POOL_DYNAMIC, SI_ORDER_FIRST, mtx_pool_setup_dynamic, NULL); diff --git a/sys/kern/sched_4bsd.c b/sys/kern/sched_4bsd.c index 3d1ff6902a667..2309ecb1d0bcb 100644 --- a/sys/kern/sched_4bsd.c +++ b/sys/kern/sched_4bsd.c @@ -116,7 +116,7 @@ struct td_sched { CPU_ISSET((cpu), &(td)->td_cpuset->cs_mask) static struct td_sched td_sched0; -struct mtx sched_lock; +static struct mtx sched_lock; static int realstathz = 127; /* stathz is sometimes 0 and run off of hz. */ static int sched_tdcnt; /* Total runnable threads in the system. */ diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c index dbe88b227a8c6..53b10ec1fa205 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -355,6 +355,13 @@ device_sysctl_fini(device_t dev) * tested since 3.4 or 2.2.8! */ +/* Deprecated way to adjust queue length */ +static int sysctl_devctl_disable(SYSCTL_HANDLER_ARGS); +/* XXX Need to support old-style tunable hw.bus.devctl_disable" */ +SYSCTL_PROC(_hw_bus, OID_AUTO, devctl_disable, CTLTYPE_INT | CTLFLAG_RW | + CTLFLAG_MPSAFE, NULL, 0, sysctl_devctl_disable, "I", + "devctl disable -- deprecated"); + #define DEVCTL_DEFAULT_QUEUE_LEN 1000 static int sysctl_devctl_queue(SYSCTL_HANDLER_ARGS); static int devctl_queue_length = DEVCTL_DEFAULT_QUEUE_LEN; @@ -685,9 +692,9 @@ devctl_notify(const char *system, const char *subsystem, const char *type, * Common routine that tries to make sending messages as easy as possible. * We allocate memory for the data, copy strings into that, but do not * free it unless there's an error. The dequeue part of the driver should - * free the data. We don't send data when queue length is 0. We do send - * data, even when we have no listeners, because we wish to avoid races - * relating to startup and restart of listening applications. + * free the data. We don't send data when the device is disabled. We do + * send data, even when we have no listeners, because we wish to avoid + * races relating to startup and restart of listening applications. * * devaddq is designed to string together the type of event, with the * object of that event, plus the plug and play info and location info @@ -779,6 +786,33 @@ devnomatch(device_t dev) } static int +sysctl_devctl_disable(SYSCTL_HANDLER_ARGS) +{ + struct dev_event_info *n1; + int dis, error; + + dis = devctl_queue_length == 0; + error = sysctl_handle_int(oidp, &dis, 0, req); + if (error || !req->newptr) + return (error); + mtx_lock(&devsoftc.mtx); + if (dis) { + while (!TAILQ_EMPTY(&devsoftc.devq)) { + n1 = TAILQ_FIRST(&devsoftc.devq); + TAILQ_REMOVE(&devsoftc.devq, n1, dei_link); + free(n1->dei_data, M_BUS); + free(n1, M_BUS); + } + devsoftc.queued = 0; + devctl_queue_length = 0; + } else { + devctl_queue_length = DEVCTL_DEFAULT_QUEUE_LEN; + } + mtx_unlock(&devsoftc.mtx); + return (0); +} + +static int sysctl_devctl_queue(SYSCTL_HANDLER_ARGS) { struct dev_event_info *n1; diff --git a/sys/kern/subr_clock.c b/sys/kern/subr_clock.c index dbd74f7562757..f30f529dbdbac 100644 --- a/sys/kern/subr_clock.c +++ b/sys/kern/subr_clock.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/bus.h> #include <sys/clock.h> +#include <sys/limits.h> #include <sys/sysctl.h> #include <sys/timetc.h> @@ -147,7 +148,7 @@ clock_ct_to_ts(struct clocktime *ct, struct timespec *ts) if (ct->mon < 1 || ct->mon > 12 || ct->day < 1 || ct->day > days_in_month(year, ct->mon) || ct->hour > 23 || ct->min > 59 || ct->sec > 59 || - ct->year > 2037) { /* time_t overflow */ + (sizeof(time_t) == 4 && year > 2037)) { /* time_t overflow */ if (ct_debug) printf(" = EINVAL\n"); return (EINVAL); diff --git a/sys/kern/subr_rman.c b/sys/kern/subr_rman.c index e43dfcff0da42..30e97c3496291 100644 --- a/sys/kern/subr_rman.c +++ b/sys/kern/subr_rman.c @@ -456,7 +456,7 @@ rman_reserve_resource_bound(struct rman *rm, u_long start, u_long end, mtx_lock(rm->rm_mtx); for (r = TAILQ_FIRST(&rm->rm_list); - r && r->r_end < start; + r && r->r_end < start + count - 1; r = TAILQ_NEXT(r, r_link)) ; @@ -466,6 +466,11 @@ rman_reserve_resource_bound(struct rman *rm, u_long start, u_long end, } amask = (1ul << RF_ALIGNMENT(flags)) - 1; + if (start + amask < start) { + DPRINTF(("start+amask wrapped around\n")); + goto out; + } + /* If bound is 0, bmask will also be 0 */ bmask = ~(bound - 1); /* @@ -473,11 +478,20 @@ rman_reserve_resource_bound(struct rman *rm, u_long start, u_long end, */ for (s = r; s; s = TAILQ_NEXT(s, r_link)) { DPRINTF(("considering [%#lx, %#lx]\n", s->r_start, s->r_end)); - if (s->r_start + count - 1 > end) { + /* + * The resource list is sorted, so there is no point in + * searching further once r_start is too large. + */ + if (s->r_start > end - (count - 1)) { DPRINTF(("s->r_start (%#lx) + count - 1> end (%#lx)\n", s->r_start, end)); break; } + if (s->r_start + amask < s->r_start) { + DPRINTF(("s->r_start (%#lx) + amask (%#lx) wrapped\n", + s->r_start, amask)); + break; + } if (s->r_flags & RF_ALLOCATED) { DPRINTF(("region is allocated\n")); continue; diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c index 34db6d4b1b6ab..86e1b16015e05 100644 --- a/sys/kern/subr_witness.c +++ b/sys/kern/subr_witness.c @@ -135,7 +135,7 @@ __FBSDID("$FreeBSD$"); #define WITNESS_COUNT 1536 #define WITNESS_CHILDCOUNT (WITNESS_COUNT * 4) #define WITNESS_HASH_SIZE 251 /* Prime, gives load factor < 2 */ -#define WITNESS_PENDLIST 1024 +#define WITNESS_PENDLIST (1024 + MAXCPU) /* Allocate 256 KB of stack data space */ #define WITNESS_LO_DATA_COUNT 2048 diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index 6ba52e37c5f2b..f3c3c0e01d611 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -221,8 +221,8 @@ SYSCTL_INT(_kern_ipc, OID_AUTO, piperesizeallowed, CTLFLAG_RW, static void pipeinit(void *dummy __unused); static void pipeclose(struct pipe *cpipe); static void pipe_free_kmem(struct pipe *cpipe); -static int pipe_create(struct pipe *pipe, int backing); -static int pipe_paircreate(struct thread *td, struct pipepair **p_pp); +static void pipe_create(struct pipe *pipe, int backing); +static void pipe_paircreate(struct thread *td, struct pipepair **p_pp); static __inline int pipelock(struct pipe *cpipe, int catch); static __inline void pipeunlock(struct pipe *cpipe); #ifndef PIPE_NODIRECT @@ -331,12 +331,11 @@ pipe_zone_fini(void *mem, int size) mtx_destroy(&pp->pp_mtx); } -static int +static void pipe_paircreate(struct thread *td, struct pipepair **p_pp) { struct pipepair *pp; struct pipe *rpipe, *wpipe; - int error; *p_pp = pp = uma_zalloc(pipe_zone, M_WAITOK); #ifdef MAC @@ -355,30 +354,21 @@ pipe_paircreate(struct thread *td, struct pipepair **p_pp) knlist_init_mtx(&wpipe->pipe_sel.si_note, PIPE_MTX(wpipe)); /* Only the forward direction pipe is backed by default */ - if ((error = pipe_create(rpipe, 1)) != 0 || - (error = pipe_create(wpipe, 0)) != 0) { - pipeclose(rpipe); - pipeclose(wpipe); - return (error); - } + pipe_create(rpipe, 1); + pipe_create(wpipe, 0); rpipe->pipe_state |= PIPE_DIRECTOK; wpipe->pipe_state |= PIPE_DIRECTOK; - return (0); } -int +void pipe_named_ctor(struct pipe **ppipe, struct thread *td) { struct pipepair *pp; - int error; - error = pipe_paircreate(td, &pp); - if (error != 0) - return (error); + pipe_paircreate(td, &pp); pp->pp_rpipe.pipe_state |= PIPE_NAMED; *ppipe = &pp->pp_rpipe; - return (0); } void @@ -419,9 +409,7 @@ kern_pipe2(struct thread *td, int fildes[2], int flags) int fd, fflags, error; fdp = td->td_proc->p_fd; - error = pipe_paircreate(td, &pp); - if (error != 0) - return (error); + pipe_paircreate(td, &pp); rpipe = &pp->pp_rpipe; wpipe = &pp->pp_wpipe; error = falloc(td, &rf, &fd, flags); @@ -642,24 +630,27 @@ pipeselwakeup(cpipe) * Initialize and allocate VM and memory for pipe. The structure * will start out zero'd from the ctor, so we just manage the kmem. */ -static int +static void pipe_create(pipe, backing) struct pipe *pipe; int backing; { - int error; if (backing) { + /* + * Note that these functions can fail if pipe map is exhausted + * (as a result of too many pipes created), but we ignore the + * error as it is not fatal and could be provoked by + * unprivileged users. The only consequence is worse performance + * with given pipe. + */ if (amountpipekva > maxpipekva / 2) - error = pipespace_new(pipe, SMALL_PIPE_SIZE); + (void)pipespace_new(pipe, SMALL_PIPE_SIZE); else - error = pipespace_new(pipe, PIPE_SIZE); - } else { - /* If we're not backing this pipe, no need to do anything. */ - error = 0; + (void)pipespace_new(pipe, PIPE_SIZE); } + pipe->pipe_ino = -1; - return (error); } /* ARGSUSED */ diff --git a/sys/mips/beri/beri_machdep.c b/sys/mips/beri/beri_machdep.c index b4c810fd3dc41..f532f609d1929 100644 --- a/sys/mips/beri/beri_machdep.c +++ b/sys/mips/beri/beri_machdep.c @@ -132,6 +132,46 @@ platform_reset(void) __asm__ __volatile("wait"); } +#ifdef FDT +/* Parse cmd line args as env - copied from xlp_machdep. */ +/* XXX-BZ this should really be centrally provided for all (boot) code. */ +static void +_parse_bootargs(char *cmdline) +{ + char *n, *v; + + while ((v = strsep(&cmdline, " \n")) != NULL) { + if (*v == '\0') + continue; + if (*v == '-') { + while (*v != '\0') { + v++; + switch (*v) { + case 'a': boothowto |= RB_ASKNAME; break; + /* Someone should simulate that ;-) */ + case 'C': boothowto |= RB_CDROM; break; + case 'd': boothowto |= RB_KDB; break; + case 'D': boothowto |= RB_MULTIPLE; break; + case 'm': boothowto |= RB_MUTE; break; + case 'g': boothowto |= RB_GDB; break; + case 'h': boothowto |= RB_SERIAL; break; + case 'p': boothowto |= RB_PAUSE; break; + case 'r': boothowto |= RB_DFLTROOT; break; + case 's': boothowto |= RB_SINGLE; break; + case 'v': boothowto |= RB_VERBOSE; break; + } + } + } else { + n = strsep(&v, "="); + if (v == NULL) + setenv(n, "1"); + else + setenv(n, v); + } + } +} +#endif + void platform_start(__register_t a0, __register_t a1, __register_t a2, __register_t a3) @@ -144,7 +184,9 @@ platform_start(__register_t a0, __register_t a1, __register_t a2, char **envp = (char **)a2; long memsize; #ifdef FDT + char buf[2048]; /* early stack supposedly big enough */ vm_offset_t dtbp; + phandle_t chosen; void *kmdp; #endif int i; @@ -201,7 +243,6 @@ platform_start(__register_t a0, __register_t a1, __register_t a2, while (1); if (OF_init((void *)dtbp) != 0) while (1); -#endif /* * Configure more boot-time parameters passed in by loader. @@ -210,6 +251,14 @@ platform_start(__register_t a0, __register_t a1, __register_t a2, kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *); /* + * Get bootargs from FDT if specified. + */ + chosen = OF_finddevice("/chosen"); + if (OF_getprop(chosen, "bootargs", buf, sizeof(buf)) != -1) + _parse_bootargs(buf); +#endif + + /* * XXXRW: We have no way to compare wallclock time to cycle rate on * BERI, so for now assume we run at the MALTA default (100MHz). */ diff --git a/sys/mips/conf/OCTEON1 b/sys/mips/conf/OCTEON1 index e96619f051fad..fb417cfccc0cd 100644 --- a/sys/mips/conf/OCTEON1 +++ b/sys/mips/conf/OCTEON1 @@ -129,6 +129,7 @@ device isp # Qlogic family #device ispfw # Firmware for QLogic HBAs- normally a module device mpt # LSI-Logic MPT-Fusion device mps # LSI-Logic MPT-Fusion 2 +device mpr # LSI-Logic MPT-Fusion 3 #device ncr # NCR/Symbios Logic device trm # Tekram DC395U/UW/F DC315U adapters diff --git a/sys/mips/mips/vm_machdep.c b/sys/mips/mips/vm_machdep.c index 0ef83a409f921..dd294e954897f 100644 --- a/sys/mips/mips/vm_machdep.c +++ b/sys/mips/mips/vm_machdep.c @@ -438,7 +438,7 @@ cpu_set_upcall(struct thread *td, struct thread *td0) * that are needed. */ - /* SMP Setup to release sched_lock in fork_exit(). */ + /* Setup to release spin count in in fork_exit(). */ td->td_md.md_spinlock_count = 1; td->td_md.md_saved_intr = MIPS_SR_INT_IE; #if 0 diff --git a/sys/modules/Makefile b/sys/modules/Makefile index f0034ee765f14..15a516373f447 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> # Modules that include binary-only blobs of microcode should be selectable by # MK_SOURCELESS_UCODE option (see below). @@ -186,7 +186,6 @@ SUBDIR= \ libiconv \ libmbpool \ libmchain \ - ${_lindev} \ ${_linprocfs} \ ${_linsysfs} \ ${_linux} \ @@ -216,9 +215,11 @@ SUBDIR= \ ${_mly} \ mmc \ mmcsd \ + mpr \ mps \ mpt \ mqueue \ + mrsas \ msdosfs \ msdosfs_iconv \ ${_mse} \ @@ -272,6 +273,7 @@ SUBDIR= \ ppi \ pps \ procfs \ + proto \ pseudofs \ ${_pst} \ pty \ @@ -513,7 +515,6 @@ _io= io .if ${MK_OFED} != "no" || defined(ALL_MODULES) _ipoib= ipoib .endif -_lindev= lindev _linprocfs= linprocfs _linsysfs= linsysfs _linux= linux @@ -715,7 +716,6 @@ _iwnfw= iwnfw .endif _ixgb= ixgb _ixgbe= ixgbe -_lindev= lindev _linprocfs= linprocfs _linsysfs= linsysfs _linux= linux diff --git a/sys/modules/aic7xxx/ahc/Makefile b/sys/modules/aic7xxx/ahc/Makefile index f04c0352d7e70..cb59d9aa4c95f 100644 --- a/sys/modules/aic7xxx/ahc/Makefile +++ b/sys/modules/aic7xxx/ahc/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../../dev/aic7xxx KMOD= ahc diff --git a/sys/modules/bce/Makefile b/sys/modules/bce/Makefile index 1be2a3f98ce2a..44b0713fdca88 100644 --- a/sys/modules/bce/Makefile +++ b/sys/modules/bce/Makefile @@ -5,4 +5,9 @@ SRCS= opt_bce.h if_bce.c miibus_if.h miidevs.h device_if.h bus_if.h pci_if.h #CFLAGS += -DBCE_DEBUG=0 +clean: + rm -f opt_bdg.h device_if.h bus_if.h pci_if.h export_syms + rm -f *.o *.kld *.ko + rm -f @ machine x86 miibus_if.h miidevs.h opt_bce.h + .include <bsd.kmod.mk> diff --git a/sys/modules/bxe/Makefile b/sys/modules/bxe/Makefile index 021b15d8e185f..2d2d662a11550 100644 --- a/sys/modules/bxe/Makefile +++ b/sys/modules/bxe/Makefile @@ -15,4 +15,9 @@ SRCS += bxe.c \ CFLAGS += -I${BXE} +clean: + rm -f opt_bdg.h device_if.h bus_if.h pci_if.h export_syms + rm -f *.o *.kld *.ko + rm -f @ machine x86 + .include <bsd.kmod.mk> diff --git a/sys/modules/carp/Makefile b/sys/modules/carp/Makefile index ca3d5da51320c..6b1bde0c4345a 100644 --- a/sys/modules/carp/Makefile +++ b/sys/modules/carp/Makefile @@ -3,7 +3,7 @@ .PATH: ${.CURDIR}/../../netinet .PATH: ${.CURDIR}/../../crypto -.include <bsd.own.mk> +.include <src.opts.mk> KMOD= carp SRCS= ip_carp.c sha1.c diff --git a/sys/modules/cxgb/Makefile b/sys/modules/cxgb/Makefile index a84dbaf233595..b866287b2d8b6 100644 --- a/sys/modules/cxgb/Makefile +++ b/sys/modules/cxgb/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= cxgb SUBDIR+= cxgb_t3fw diff --git a/sys/modules/cxgb/cxgb/Makefile b/sys/modules/cxgb/cxgb/Makefile index d24ff08da46ed..3f0f68af2de4b 100644 --- a/sys/modules/cxgb/cxgb/Makefile +++ b/sys/modules/cxgb/cxgb/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> CXGB = ${.CURDIR}/../../../dev/cxgb .PATH: ${CXGB} ${CXGB}/common ${CXGB}/sys diff --git a/sys/modules/cxgb/iw_cxgb/Makefile b/sys/modules/cxgb/iw_cxgb/Makefile index f633bd5c663a8..2ee4990b46467 100644 --- a/sys/modules/cxgb/iw_cxgb/Makefile +++ b/sys/modules/cxgb/iw_cxgb/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> CXGB = ${.CURDIR}/../../../dev/cxgb .PATH: ${CXGB}/ulp/iw_cxgb diff --git a/sys/modules/cxgb/tom/Makefile b/sys/modules/cxgb/tom/Makefile index 8b08fe273e1e1..f4a277641fdbd 100644 --- a/sys/modules/cxgb/tom/Makefile +++ b/sys/modules/cxgb/tom/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> CXGB = ${.CURDIR}/../../../dev/cxgb .PATH: ${CXGB}/ulp/tom diff --git a/sys/modules/cxgbe/Makefile b/sys/modules/cxgbe/Makefile index 86ce82e9e45d5..b46bf224a1c39 100644 --- a/sys/modules/cxgbe/Makefile +++ b/sys/modules/cxgbe/Makefile @@ -2,7 +2,7 @@ # $FreeBSD$ # -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR = if_cxgbe SUBDIR+= t4_firmware diff --git a/sys/modules/cxgbe/if_cxgbe/Makefile b/sys/modules/cxgbe/if_cxgbe/Makefile index f4ebcdd39dc39..665feb9ff9d9b 100644 --- a/sys/modules/cxgbe/if_cxgbe/Makefile +++ b/sys/modules/cxgbe/if_cxgbe/Makefile @@ -2,7 +2,7 @@ # $FreeBSD$ # -.include <bsd.own.mk> +.include <src.opts.mk> CXGBE = ${.CURDIR}/../../../dev/cxgbe .PATH: ${CXGBE} ${CXGBE}/common diff --git a/sys/modules/cxgbe/iw_cxgbe/Makefile b/sys/modules/cxgbe/iw_cxgbe/Makefile index 7704650ed05f0..fdf50639ab55f 100644 --- a/sys/modules/cxgbe/iw_cxgbe/Makefile +++ b/sys/modules/cxgbe/iw_cxgbe/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> CXGBE = ${.CURDIR}/../../../dev/cxgbe .PATH: ${CXGBE}/iw_cxgbe diff --git a/sys/modules/cxgbe/tom/Makefile b/sys/modules/cxgbe/tom/Makefile index d02afd4cc3f21..99c1f4e685965 100644 --- a/sys/modules/cxgbe/tom/Makefile +++ b/sys/modules/cxgbe/tom/Makefile @@ -2,7 +2,7 @@ # $FreeBSD$ # -.include <bsd.own.mk> +.include <src.opts.mk> CXGBE = ${.CURDIR}/../../../dev/cxgbe .PATH: ${CXGBE}/tom diff --git a/sys/modules/dpt/Makefile b/sys/modules/dpt/Makefile index 85475933d5e90..c96bb4b016e52 100644 --- a/sys/modules/dpt/Makefile +++ b/sys/modules/dpt/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../dev/dpt KMOD= dpt diff --git a/sys/modules/drm/Makefile b/sys/modules/drm/Makefile index 21328fcca9514..f75eb3b815d45 100644 --- a/sys/modules/drm/Makefile +++ b/sys/modules/drm/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> # Modules that include binary-only blobs of microcode should be selectable by # MK_SOURCELESS_UCODE option (see below). diff --git a/sys/modules/drm2/Makefile b/sys/modules/drm2/Makefile index 62414dbd978ad..a0ee800e07874 100644 --- a/sys/modules/drm2/Makefile +++ b/sys/modules/drm2/Makefile @@ -1,5 +1,6 @@ # $FreeBSD$ +.include <src.opts.mk> .include <bsd.own.mk> .if ${MACHINE_CPUARCH} == "amd64" diff --git a/sys/modules/drm2/radeonkms/Makefile b/sys/modules/drm2/radeonkms/Makefile index 3786a5e94fd84..6315a85dc5d28 100644 --- a/sys/modules/drm2/radeonkms/Makefile +++ b/sys/modules/drm2/radeonkms/Makefile @@ -88,7 +88,10 @@ SRCS += \ si.c \ si_blit_shaders.c -#radeon_ioc32.c +.if ${MACHINE_CPUARCH} == "amd64" +SRCS += radeon_ioc32.c +.endif + #radeon_prime.c #--radeon_trace_points.c diff --git a/sys/modules/dummynet/Makefile b/sys/modules/dummynet/Makefile index dfddbce893325..c1f8bb1cfad75 100644 --- a/sys/modules/dummynet/Makefile +++ b/sys/modules/dummynet/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../netpfil/ipfw KMOD= dummynet diff --git a/sys/modules/em/Makefile b/sys/modules/em/Makefile index 545e37d809b95..5e71f2f00eafa 100644 --- a/sys/modules/em/Makefile +++ b/sys/modules/em/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../dev/e1000 KMOD = if_em diff --git a/sys/modules/ep/Makefile b/sys/modules/ep/Makefile index 8db77d3beb13c..99281a46421d0 100644 --- a/sys/modules/ep/Makefile +++ b/sys/modules/ep/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../dev/ep diff --git a/sys/modules/if_bridge/Makefile b/sys/modules/if_bridge/Makefile index 1ddb4c87ef081..0cc231e3da1be 100644 --- a/sys/modules/if_bridge/Makefile +++ b/sys/modules/if_bridge/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../net KMOD= if_bridge diff --git a/sys/modules/if_gif/Makefile b/sys/modules/if_gif/Makefile index 1cde56cbcd0db..f2db9136f5fa8 100644 --- a/sys/modules/if_gif/Makefile +++ b/sys/modules/if_gif/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../net ${.CURDIR}/../../netinet ${.CURDIR}/../../netinet6 diff --git a/sys/modules/if_lagg/Makefile b/sys/modules/if_lagg/Makefile index 4d84c92d17020..f2f1a6e484064 100644 --- a/sys/modules/if_lagg/Makefile +++ b/sys/modules/if_lagg/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../net KMOD= if_lagg diff --git a/sys/modules/igb/Makefile b/sys/modules/igb/Makefile index 1ff127467bca7..5da3cf5152400 100644 --- a/sys/modules/igb/Makefile +++ b/sys/modules/igb/Makefile @@ -1,6 +1,6 @@ #$FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../dev/e1000 KMOD = if_igb diff --git a/sys/modules/ipdivert/Makefile b/sys/modules/ipdivert/Makefile index 39500ceca19ac..9e1e89d29d0a1 100644 --- a/sys/modules/ipdivert/Makefile +++ b/sys/modules/ipdivert/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../netinet diff --git a/sys/modules/ipfilter/Makefile b/sys/modules/ipfilter/Makefile index c14469507e15a..0bdfbf2dfceec 100644 --- a/sys/modules/ipfilter/Makefile +++ b/sys/modules/ipfilter/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../contrib/ipfilter/netinet diff --git a/sys/modules/ipfw/Makefile b/sys/modules/ipfw/Makefile index 48f9ce163747f..46cd70b98f3b0 100644 --- a/sys/modules/ipfw/Makefile +++ b/sys/modules/ipfw/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../netpfil/ipfw diff --git a/sys/modules/ipoib/Makefile b/sys/modules/ipoib/Makefile index bcbafc83a8b54..6cf805dcde1b1 100644 --- a/sys/modules/ipoib/Makefile +++ b/sys/modules/ipoib/Makefile @@ -2,7 +2,7 @@ .PATH: ${.CURDIR}/../../ofed/drivers/infiniband/ulp/ipoib .PATH: ${.CURDIR}/../../ofed/include/linux -.include <bsd.own.mk> +.include <src.opts.mk> KMOD = ipoib SRCS = device_if.h bus_if.h opt_ofed.h vnode_if.h opt_inet.h opt_inet6.h diff --git a/sys/modules/ixgbe/Makefile b/sys/modules/ixgbe/Makefile index 68d887e3e93e6..d7409d7e37e71 100644 --- a/sys/modules/ixgbe/Makefile +++ b/sys/modules/ixgbe/Makefile @@ -1,6 +1,6 @@ #$FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../dev/ixgbe diff --git a/sys/modules/lindev/Makefile b/sys/modules/lindev/Makefile deleted file mode 100644 index 704cac331dce9..0000000000000 --- a/sys/modules/lindev/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# $FreeBSD$ - -.PATH: ${.CURDIR}/../../dev/lindev - -KMOD= lindev -SRCS= full.c lindev.c - -.include <bsd.kmod.mk> diff --git a/sys/modules/mlx4/Makefile b/sys/modules/mlx4/Makefile index 02ee17687eb19..1af961ff81cac 100644 --- a/sys/modules/mlx4/Makefile +++ b/sys/modules/mlx4/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ .PATH: ${.CURDIR}/../../ofed/drivers/net/mlx4 -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../ofed/include/linux KMOD = mlx4 diff --git a/sys/modules/mlx4ib/Makefile b/sys/modules/mlx4ib/Makefile index bdde60fb8708c..68a8cd826096d 100644 --- a/sys/modules/mlx4ib/Makefile +++ b/sys/modules/mlx4ib/Makefile @@ -2,7 +2,7 @@ .PATH: ${.CURDIR}/../../ofed/drivers/infiniband/hw/mlx4 .PATH: ${.CURDIR}/../../ofed/include/linux -.include <bsd.own.mk> +.include <src.opts.mk> KMOD = mlx4ib SRCS = device_if.h bus_if.h pci_if.h vnode_if.h diff --git a/sys/modules/mlxen/Makefile b/sys/modules/mlxen/Makefile index 73208d5cce7a5..3611f25fa8e11 100644 --- a/sys/modules/mlxen/Makefile +++ b/sys/modules/mlxen/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ .PATH: ${.CURDIR}/../../ofed/drivers/net/mlx4 -.include <bsd.own.mk> +.include <src.opts.mk> KMOD = mlxen SRCS = device_if.h bus_if.h pci_if.h vnode_if.h diff --git a/sys/modules/mpr/Makefile b/sys/modules/mpr/Makefile new file mode 100644 index 0000000000000..2fb7a391c0d21 --- /dev/null +++ b/sys/modules/mpr/Makefile @@ -0,0 +1,18 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/mpr + +KMOD= mpr +SRCS= mpr_pci.c mpr.c mpr_sas.c mpr_table.c mpr_user.c +SRCS+= mpr_config.c mpr_mapping.c mpr_sas_lsi.c +SRCS+= opt_cam.h opt_compat.h +SRCS+= device_if.h bus_if.h pci_if.h + +#CFLAGS += -DMPR_DEBUG + +.include <bsd.kmod.mk> + +CWARNFLAGS.mpr_sas.c= ${NO_WUNNEEDED_INTERNAL_DECL} +# XXX Work around clang warning, until maintainer approves fix. +CWARNFLAGS.mpr_mapping.c= ${NO_WSOMETIMES_UNINITIALIZED} +CWARNFLAGS+= ${CWARNFLAGS.${.IMPSRC:T}} diff --git a/sys/modules/mrsas/Makefile b/sys/modules/mrsas/Makefile new file mode 100644 index 0000000000000..7ff6c811f407c --- /dev/null +++ b/sys/modules/mrsas/Makefile @@ -0,0 +1,20 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/mrsas + +KMOD= mrsas +SRCS= mrsas.c mrsas_cam.c mrsas_ioctl.c mrsas_fp.c +SRCS+= device_if.h bus_if.h pci_if.h opt_cam.h opt_scsi.h + +#CFLAGS+= -MRSAS_DEBUG +.include <bsd.kmod.mk> +#CFLAGS+= -fgnu89-inline + +clean_cscope: + rm -f cscope* + +cscope: clean_cscope + /usr/local/bin/cscope -b *.[ch] + +cleanall: clean clean_cscope + rm -f '@' machine diff --git a/sys/modules/mthca/Makefile b/sys/modules/mthca/Makefile index a306289a3f6ba..dd34d70114f3e 100644 --- a/sys/modules/mthca/Makefile +++ b/sys/modules/mthca/Makefile @@ -2,7 +2,7 @@ .PATH: ${.CURDIR}/../../ofed/drivers/infiniband/hw/mthca -.include <bsd.own.mk> +.include <src.opts.mk> KMOD = mthca SRCS = device_if.h bus_if.h pci_if.h vnode_if.h diff --git a/sys/modules/netgraph/Makefile b/sys/modules/netgraph/Makefile index 0703c242f5ca7..cccbd656c1516 100644 --- a/sys/modules/netgraph/Makefile +++ b/sys/modules/netgraph/Makefile @@ -1,7 +1,7 @@ # $Whistle: Makefile,v 1.5 1999/01/24 06:48:37 archie Exp $ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= async \ atm \ diff --git a/sys/modules/netgraph/ipfw/Makefile b/sys/modules/netgraph/ipfw/Makefile index cc3f0f24e2a0a..5805c09f8a496 100644 --- a/sys/modules/netgraph/ipfw/Makefile +++ b/sys/modules/netgraph/ipfw/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> KMOD= ng_ipfw SRCS= ng_ipfw.c opt_inet.h opt_inet6.h diff --git a/sys/modules/netgraph/netflow/Makefile b/sys/modules/netgraph/netflow/Makefile index fb38b241e5cc2..2a8fd626cc02f 100644 --- a/sys/modules/netgraph/netflow/Makefile +++ b/sys/modules/netgraph/netflow/Makefile @@ -3,7 +3,7 @@ # Author: Gleb Smirnoff <glebius@freebsd.org> # -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../../netgraph/netflow diff --git a/sys/modules/pf/Makefile b/sys/modules/pf/Makefile index 9dc6c0dac72f7..e327b5c5c3eaf 100644 --- a/sys/modules/pf/Makefile +++ b/sys/modules/pf/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../netpfil/pf diff --git a/sys/modules/pflog/Makefile b/sys/modules/pflog/Makefile index 70a5234698a12..4da24b3a0dfa0 100644 --- a/sys/modules/pflog/Makefile +++ b/sys/modules/pflog/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../netpfil/pf diff --git a/sys/modules/pfsync/Makefile b/sys/modules/pfsync/Makefile index 92c6edb2fd532..9c085fceafdd6 100644 --- a/sys/modules/pfsync/Makefile +++ b/sys/modules/pfsync/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../netpfil/pf diff --git a/sys/modules/proto/Makefile b/sys/modules/proto/Makefile new file mode 100644 index 0000000000000..4cfbd72a0bdf2 --- /dev/null +++ b/sys/modules/proto/Makefile @@ -0,0 +1,20 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/proto + +KMOD= proto +SRCS= \ + proto_bus_pci.c \ + proto_core.c + +SRCS+= \ + bus_if.h \ + device_if.h \ + pci_if.h \ + +MFILES= \ + dev/pci/pci_if.m \ + kern/bus_if.m \ + kern/device_if.m + +.include <bsd.kmod.mk> diff --git a/sys/modules/sound/driver/Makefile b/sys/modules/sound/driver/Makefile index 481aa8e91c779..2c51f45f85578 100644 --- a/sys/modules/sound/driver/Makefile +++ b/sys/modules/sound/driver/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> # Modules that include binary-only blobs of microcode should be selectable by # MK_SOURCELESS_UCODE option (see below). diff --git a/sys/modules/sound/sound/Makefile b/sys/modules/sound/sound/Makefile index 42cfc24f011da..cf0b53055eceb 100644 --- a/sys/modules/sound/sound/Makefile +++ b/sys/modules/sound/sound/Makefile @@ -44,7 +44,8 @@ CLEANFILES+= feeder_eq_gen.h feeder_rate_gen.h snd_fxdiv_gen.h EXPORT_SYMS= YES # XXX evaluate -.if ${MACHINE_CPUARCH} == "sparc64" || ${MACHINE_CPUARCH} == "powerpc" +.if ${MACHINE_CPUARCH} == "sparc64" || ${MACHINE_CPUARCH} == "powerpc" || \ + ${MACHINE_CPUARCH} == "arm" || ${MACHINE_CPUARCH} == "mips" # Create an empty opt_isa.h in order to keep kmod.mk from linking in an # existing one from KERNBUILDDIR which possibly has DEV_ISA defined so # sound.ko is always built without isadma support. diff --git a/sys/modules/usb/Makefile b/sys/modules/usb/Makefile index eacd2ebcc1d00..6b3c9d4540e35 100644 --- a/sys/modules/usb/Makefile +++ b/sys/modules/usb/Makefile @@ -25,7 +25,7 @@ # SUCH DAMAGE. # -.include <bsd.own.mk> +.include <src.opts.mk> # # Check for common USB debug flags to pass when building the USB diff --git a/sys/modules/virtio/network/Makefile b/sys/modules/virtio/network/Makefile index f124d996342fa..41a5101b8d72d 100644 --- a/sys/modules/virtio/network/Makefile +++ b/sys/modules/virtio/network/Makefile @@ -23,7 +23,7 @@ # SUCH DAMAGE. # -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../../dev/virtio/network diff --git a/sys/modules/vmware/vmxnet3/Makefile b/sys/modules/vmware/vmxnet3/Makefile index 2a3ffbf7cad33..9d4299707ec96 100644 --- a/sys/modules/vmware/vmxnet3/Makefile +++ b/sys/modules/vmware/vmxnet3/Makefile @@ -23,7 +23,7 @@ # SUCH DAMAGE. # -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../../dev/vmware/vmxnet3 diff --git a/sys/modules/vx/Makefile b/sys/modules/vx/Makefile index 2d7bc18a66cb4..e700efe3780ce 100644 --- a/sys/modules/vx/Makefile +++ b/sys/modules/vx/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../dev/vx diff --git a/sys/net/ieee8023ad_lacp.c b/sys/net/ieee8023ad_lacp.c index b023c6caa119c..aa38efabd50da 100644 --- a/sys/net/ieee8023ad_lacp.c +++ b/sys/net/ieee8023ad_lacp.c @@ -590,10 +590,20 @@ lacp_req(struct lagg_softc *sc, caddr_t data) { struct lacp_opreq *req = (struct lacp_opreq *)data; struct lacp_softc *lsc = LACP_SOFTC(sc); - struct lacp_aggregator *la = lsc->lsc_active_aggregator; + struct lacp_aggregator *la; - LACP_LOCK(lsc); bzero(req, sizeof(struct lacp_opreq)); + + /* + * If the LACP softc is NULL, return with the opreq structure full of + * zeros. It is normal for the softc to be NULL while the lagg is + * being destroyed. + */ + if (NULL == lsc) + return; + + la = lsc->lsc_active_aggregator; + LACP_LOCK(lsc); if (la != NULL) { req->actor_prio = ntohs(la->la_actor.lip_systemid.lsi_prio); memcpy(&req->actor_mac, &la->la_actor.lip_systemid.lsi_mac, diff --git a/sys/net/radix.c b/sys/net/radix.c index 2f52c3a1eeb27..62f57f80dac23 100644 --- a/sys/net/radix.c +++ b/sys/net/radix.c @@ -971,6 +971,8 @@ rn_walktree_from(struct radix_node_head *h, void *a, void *m, int stopping = 0; int lastb; + KASSERT(m != NULL, ("%s: mask needs to be specified", __func__)); + /* * rn_search_m is sort-of-open-coded here. We cannot use the * function because we need to keep track of the last node seen. @@ -994,11 +996,11 @@ rn_walktree_from(struct radix_node_head *h, void *a, void *m, /* * Two cases: either we stepped off the end of our mask, * in which case last == rn, or we reached a leaf, in which - * case we want to start from the last node we looked at. - * Either way, last is the node we want to start from. + * case we want to start from the leaf. */ - rn = last; - lastb = rn->rn_bit; + if (rn->rn_bit >= 0) + rn = last; + lastb = last->rn_bit; /* printf("rn %p, lastb %d\n", rn, lastb);*/ diff --git a/sys/net/route.c b/sys/net/route.c index 0feadb8f7f7c5..d6e6d932ed52e 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -142,6 +142,7 @@ static VNET_DEFINE(uma_zone_t, rtzone); /* Routing table UMA zone. */ static int rtrequest1_fib_change(struct radix_node_head *, struct rt_addrinfo *, struct rtentry **, u_int); +static void rt_setmetrics(const struct rt_addrinfo *, struct rtentry *); /* * handler for net.my_fibnum @@ -401,15 +402,6 @@ rtalloc1_fib(struct sockaddr *dst, int report, u_long ignflags, int needlock; KASSERT((fibnum < rt_numfibs), ("rtalloc1_fib: bad fibnum")); - switch (dst->sa_family) { - case AF_INET6: - case AF_INET: - /* We support multiple FIBs. */ - break; - default: - fibnum = RT_DEFAULT_FIB; - break; - } rnh = rt_tables_get_rnh(fibnum, dst->sa_family); newrt = NULL; if (rnh == NULL) @@ -897,7 +889,7 @@ rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum) * The route must be locked. */ int -rtexpunge(struct rtentry *rt) +rt_expunge(struct radix_node_head *rnh, struct rtentry *rt) { #if !defined(RADIX_MPATH) struct radix_node *rn; @@ -906,17 +898,10 @@ rtexpunge(struct rtentry *rt) int fib; struct rtentry *rt0; #endif - struct radix_node_head *rnh; struct ifaddr *ifa; int error = 0; - /* - * Find the correct routing tree to use for this Address Family - */ - rnh = rt_tables_get_rnh(rt->rt_fibnum, rt_key(rt)->sa_family); RT_LOCK_ASSERT(rt); - if (rnh == NULL) - return (EAFNOSUPPORT); RADIX_NODE_HEAD_LOCK_ASSERT(rnh); #ifdef RADIX_MPATH @@ -1401,6 +1386,8 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, if (ifa->ifa_rtrequest) ifa->ifa_rtrequest(req, rt, info); + rt_setmetrics(info, rt); + /* * actually return a resultant rtentry and * give the caller a single reference. @@ -1431,7 +1418,6 @@ bad: #undef ifpaddr #undef flags -#define senderr(e) { error = e; goto bad; } static int rtrequest1_fib_change(struct radix_node_head *rnh, struct rt_addrinfo *info, struct rtentry **ret_nrt, u_int fibnum) @@ -1476,7 +1462,7 @@ rtrequest1_fib_change(struct radix_node_head *rnh, struct rt_addrinfo *info, free_ifa = 1; if (error != 0) - senderr(error); + goto bad; } /* Check if outgoing interface has changed */ @@ -1489,7 +1475,7 @@ rtrequest1_fib_change(struct radix_node_head *rnh, struct rt_addrinfo *info, if (info->rti_info[RTAX_GATEWAY] != NULL) { error = rt_setgate(rt, rt_key(rt), info->rti_info[RTAX_GATEWAY]); if (error != 0) - senderr(error); + goto bad; rt->rt_flags &= ~RTF_GATEWAY; rt->rt_flags |= (RTF_GATEWAY & info->rti_flags); @@ -1507,6 +1493,8 @@ rtrequest1_fib_change(struct radix_node_head *rnh, struct rt_addrinfo *info, if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest != NULL) rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, info); + rt_setmetrics(info, rt); + if (ret_nrt) { *ret_nrt = rt; RT_ADDREF(rt); @@ -1517,8 +1505,20 @@ bad: ifa_free(info->rti_ifa); return (error); } -#undef senderr +static void +rt_setmetrics(const struct rt_addrinfo *info, struct rtentry *rt) +{ + + if (info->rti_mflags & RTV_MTU) + rt->rt_mtu = info->rti_rmx->rmx_mtu; + if (info->rti_mflags & RTV_WEIGHT) + rt->rt_weight = info->rti_rmx->rmx_weight; + /* Kernel -> userland timebase conversion. */ + if (info->rti_mflags & RTV_EXPIRE) + rt->rt_expire = info->rti_rmx->rmx_expire ? + info->rti_rmx->rmx_expire - time_second + time_uptime : 0; +} int rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate) diff --git a/sys/net/route.h b/sys/net/route.h index 913828a5ccce5..df2fc5864a575 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -261,6 +261,8 @@ struct rt_addrinfo { int rti_flags; struct ifaddr *rti_ifa; struct ifnet *rti_ifp; + u_long rti_mflags; + struct rt_metrics *rti_rmx; }; /* @@ -369,7 +371,7 @@ int rtsock_routemsg(int, struct ifnet *ifp, int, struct rtentry *, int); * RTFREE() uses an unlocked entry. */ -int rtexpunge(struct rtentry *); +int rt_expunge(struct radix_node_head *, struct rtentry *); void rtfree(struct rtentry *); int rt_check(struct rtentry **, struct rtentry **, struct sockaddr *); diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index a40f067325b11..3a6afcaba6d71 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -151,7 +151,7 @@ struct walkarg { }; static void rts_input(struct mbuf *m); -static struct mbuf *rt_msg1(int type, struct rt_addrinfo *rtinfo); +static struct mbuf *rtsock_msg_mbuf(int type, struct rt_addrinfo *rtinfo); static int rtsock_msg_buffer(int type, struct rt_addrinfo *rtinfo, struct walkarg *w, int *plen); static int rt_xaddrs(caddr_t cp, caddr_t cplim, @@ -160,9 +160,10 @@ static int sysctl_dumpentry(struct radix_node *rn, void *vw); static int sysctl_iflist(int af, struct walkarg *w); static int sysctl_ifmalist(int af, struct walkarg *w); static int route_output(struct mbuf *m, struct socket *so); -static void rt_setmetrics(const struct rt_msghdr *rtm, struct rtentry *rt); static void rt_getmetrics(const struct rtentry *rt, struct rt_metrics *out); static void rt_dispatch(struct mbuf *, sa_family_t); +static struct sockaddr *rtsock_fix_netmask(struct sockaddr *dst, + struct sockaddr *smask, struct sockaddr_storage *dmask); static struct netisr_handler rtsock_nh = { .nh_name = "rtsock", @@ -521,8 +522,8 @@ route_output(struct mbuf *m, struct socket *so) struct rtentry *rt = NULL; struct radix_node_head *rnh; struct rt_addrinfo info; -#ifdef INET6 struct sockaddr_storage ss; +#ifdef INET6 struct sockaddr_in6 *sin6; int i, rti_need_deembed = 0; #endif @@ -532,7 +533,6 @@ route_output(struct mbuf *m, struct socket *so) sa_family_t saf = AF_UNSPEC; struct rawcb *rp = NULL; struct walkarg w; - char msgbuf[512]; fibnum = so->so_fibnum; @@ -549,20 +549,12 @@ route_output(struct mbuf *m, struct socket *so) /* * Most of current messages are in range 200-240 bytes, - * minimize possible failures by using on-stack buffer - * which should fit for most messages. - * However, use stable memory if we need to handle - * something large. + * minimize possible re-allocation on reply using larger size + * buffer aligned on 1k boundaty. */ - if (len < sizeof(msgbuf)) { - alloc_len = sizeof(msgbuf); - rtm = (struct rt_msghdr *)msgbuf; - } else { - alloc_len = roundup2(len, 1024); - rtm = malloc(alloc_len, M_TEMP, M_NOWAIT); - if (rtm == NULL) - senderr(ENOBUFS); - } + alloc_len = roundup2(len, 1024); + if ((rtm = malloc(alloc_len, M_TEMP, M_NOWAIT)) == NULL) + senderr(ENOBUFS); m_copydata(m, 0, len, (caddr_t)rtm); bzero(&info, sizeof(info)); @@ -570,8 +562,7 @@ route_output(struct mbuf *m, struct socket *so) if (rtm->rtm_version != RTM_VERSION) { /* Do not touch message since format is unknown */ - if ((char *)rtm != msgbuf) - free(rtm, M_TEMP); + free(rtm, M_TEMP); rtm = NULL; senderr(EPROTONOSUPPORT); } @@ -584,6 +575,10 @@ route_output(struct mbuf *m, struct socket *so) rtm->rtm_pid = curproc->p_pid; info.rti_addrs = rtm->rtm_addrs; + + info.rti_mflags = rtm->rtm_inits; + info.rti_rmx = &rtm->rtm_rmx; + /* * rt_xaddrs() performs s6_addr[2] := sin6_scope_id for AF_INET6 * link-local address because rtrequest requires addresses with @@ -670,7 +665,6 @@ route_output(struct mbuf *m, struct socket *so) rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; #endif RT_LOCK(saved_nrt); - rt_setmetrics(rtm, saved_nrt); rtm->rtm_index = saved_nrt->rt_ifp->if_index; RT_REMREF(saved_nrt); RT_UNLOCK(saved_nrt); @@ -792,7 +786,8 @@ report: } info.rti_info[RTAX_DST] = rt_key(rt); info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; - info.rti_info[RTAX_NETMASK] = rt_mask(rt); + info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(rt_key(rt), + rt_mask(rt), &ss); info.rti_info[RTAX_GENMASK] = 0; if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { ifp = rt->rt_ifp; @@ -859,7 +854,7 @@ flush: */ if ((so->so_options & SO_USELOOPBACK) == 0) { if (V_route_cb.any_count <= 1) { - if (rtm != NULL && (char *)rtm != msgbuf) + if (rtm != NULL) free(rtm, M_TEMP); m_freem(m); return (error); @@ -897,8 +892,7 @@ flush: } else if (m->m_pkthdr.len > rtm->rtm_msglen) m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); - if ((char *)rtm != msgbuf) - free(rtm, M_TEMP); + free(rtm, M_TEMP); } if (m != NULL) { M_SETFIB(m, fibnum); @@ -920,20 +914,6 @@ flush: } static void -rt_setmetrics(const struct rt_msghdr *rtm, struct rtentry *rt) -{ - - if (rtm->rtm_inits & RTV_MTU) - rt->rt_mtu = rtm->rtm_rmx.rmx_mtu; - if (rtm->rtm_inits & RTV_WEIGHT) - rt->rt_weight = rtm->rtm_rmx.rmx_weight; - /* Kernel -> userland timebase conversion. */ - if (rtm->rtm_inits & RTV_EXPIRE) - rt->rt_expire = rtm->rtm_rmx.rmx_expire ? - rtm->rtm_rmx.rmx_expire - time_second + time_uptime : 0; -} - -static void rt_getmetrics(const struct rtentry *rt, struct rt_metrics *out) { @@ -990,10 +970,33 @@ rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) } /* - * Used by the routing socket. + * Fill in @dmask with valid netmask leaving original @smask + * intact. Mostly used with radix netmasks. + */ +static struct sockaddr * +rtsock_fix_netmask(struct sockaddr *dst, struct sockaddr *smask, + struct sockaddr_storage *dmask) +{ + if (dst == NULL || smask == NULL) + return (NULL); + + memset(dmask, 0, dst->sa_len); + memcpy(dmask, smask, smask->sa_len); + dmask->ss_len = dst->sa_len; + dmask->ss_family = dst->sa_family; + + return ((struct sockaddr *)dmask); +} + +/* + * Writes information related to @rtinfo object to newly-allocated mbuf. + * Assumes MCLBYTES is enough to construct any message. + * Used for OS notifications of vaious events (if/ifa announces,etc) + * + * Returns allocated mbuf or NULL on failure. */ static struct mbuf * -rt_msg1(int type, struct rt_addrinfo *rtinfo) +rtsock_msg_mbuf(int type, struct rt_addrinfo *rtinfo) { struct rt_msghdr *rtm; struct mbuf *m; @@ -1205,7 +1208,7 @@ rt_missmsg_fib(int type, struct rt_addrinfo *rtinfo, int flags, int error, if (V_route_cb.any_count == 0) return; - m = rt_msg1(type, rtinfo); + m = rtsock_msg_mbuf(type, rtinfo); if (m == NULL) return; @@ -1244,7 +1247,7 @@ rt_ifmsg(struct ifnet *ifp) if (V_route_cb.any_count == 0) return; bzero((caddr_t)&info, sizeof(info)); - m = rt_msg1(RTM_IFINFO, &info); + m = rtsock_msg_mbuf(RTM_IFINFO, &info); if (m == NULL) return; ifm = mtod(m, struct if_msghdr *); @@ -1270,6 +1273,7 @@ rtsock_addrmsg(int cmd, struct ifaddr *ifa, int fibnum) struct mbuf *m; struct ifa_msghdr *ifam; struct ifnet *ifp = ifa->ifa_ifp; + struct sockaddr_storage ss; if (V_route_cb.any_count == 0) return (0); @@ -1279,9 +1283,10 @@ rtsock_addrmsg(int cmd, struct ifaddr *ifa, int fibnum) bzero((caddr_t)&info, sizeof(info)); info.rti_info[RTAX_IFA] = sa = ifa->ifa_addr; info.rti_info[RTAX_IFP] = ifp->if_addr->ifa_addr; - info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; + info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask( + info.rti_info[RTAX_IFP], ifa->ifa_netmask, &ss); info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; - if ((m = rt_msg1(ncmd, &info)) == NULL) + if ((m = rtsock_msg_mbuf(ncmd, &info)) == NULL) return (ENOBUFS); ifam = mtod(m, struct ifa_msghdr *); ifam->ifam_index = ifp->if_index; @@ -1318,15 +1323,16 @@ rtsock_routemsg(int cmd, struct ifnet *ifp, int error, struct rtentry *rt, struct sockaddr *sa; struct mbuf *m; struct rt_msghdr *rtm; + struct sockaddr_storage ss; if (V_route_cb.any_count == 0) return (0); bzero((caddr_t)&info, sizeof(info)); - info.rti_info[RTAX_NETMASK] = rt_mask(rt); info.rti_info[RTAX_DST] = sa = rt_key(rt); + info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(sa, rt_mask(rt), &ss); info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; - if ((m = rt_msg1(cmd, &info)) == NULL) + if ((m = rtsock_msg_mbuf(cmd, &info)) == NULL) return (ENOBUFS); rtm = mtod(m, struct rt_msghdr *); rtm->rtm_index = ifp->if_index; @@ -1368,7 +1374,7 @@ rt_newmaddrmsg(int cmd, struct ifmultiaddr *ifma) * (similarly to how ARP entries, e.g., are presented). */ info.rti_info[RTAX_GATEWAY] = ifma->ifma_lladdr; - m = rt_msg1(cmd, &info); + m = rtsock_msg_mbuf(cmd, &info); if (m == NULL) return; ifmam = mtod(m, struct ifma_msghdr *); @@ -1389,7 +1395,7 @@ rt_makeifannouncemsg(struct ifnet *ifp, int type, int what, if (V_route_cb.any_count == 0) return NULL; bzero((caddr_t)info, sizeof(*info)); - m = rt_msg1(type, info); + m = rtsock_msg_mbuf(type, info); if (m != NULL) { ifan = mtod(m, struct if_announcemsghdr *); ifan->ifan_index = ifp->if_index; @@ -1496,6 +1502,7 @@ sysctl_dumpentry(struct radix_node *rn, void *vw) struct rtentry *rt = (struct rtentry *)rn; int error = 0, size; struct rt_addrinfo info; + struct sockaddr_storage ss; if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) return 0; @@ -1506,7 +1513,8 @@ sysctl_dumpentry(struct radix_node *rn, void *vw) bzero((caddr_t)&info, sizeof(info)); info.rti_info[RTAX_DST] = rt_key(rt); info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; - info.rti_info[RTAX_NETMASK] = rt_mask(rt); + info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask(rt_key(rt), + rt_mask(rt), &ss); info.rti_info[RTAX_GENMASK] = 0; if (rt->rt_ifp) { info.rti_info[RTAX_IFP] = rt->rt_ifp->if_addr->ifa_addr; @@ -1682,6 +1690,7 @@ sysctl_iflist(int af, struct walkarg *w) struct ifaddr *ifa; struct rt_addrinfo info; int len, error = 0; + struct sockaddr_storage ss; bzero((caddr_t)&info, sizeof(info)); IFNET_RLOCK_NOSLEEP(); @@ -1710,7 +1719,8 @@ sysctl_iflist(int af, struct walkarg *w) ifa->ifa_addr) != 0) continue; info.rti_info[RTAX_IFA] = ifa->ifa_addr; - info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; + info.rti_info[RTAX_NETMASK] = rtsock_fix_netmask( + ifa->ifa_addr, ifa->ifa_netmask, &ss); info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; error = rtsock_msg_buffer(RTM_NEWADDR, &info, w, &len); if (error != 0) @@ -1727,8 +1737,9 @@ sysctl_iflist(int af, struct walkarg *w) } } IF_ADDR_RUNLOCK(ifp); - info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] = - info.rti_info[RTAX_BRD] = NULL; + info.rti_info[RTAX_IFA] = NULL; + info.rti_info[RTAX_NETMASK] = NULL; + info.rti_info[RTAX_BRD] = NULL; } done: if (ifp != NULL) @@ -1764,7 +1775,7 @@ sysctl_ifmalist(int af, struct walkarg *w) info.rti_info[RTAX_GATEWAY] = (ifma->ifma_addr->sa_family != AF_LINK) ? ifma->ifma_lladdr : NULL; - error = rtsock_msg_buffer(RTM_NEWADDR, &info, w, &len); + error = rtsock_msg_buffer(RTM_NEWMADDR, &info, w, &len); if (error != 0) goto done; if (w->w_req && w->w_tmem) { diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 1cb4f09507d54..336c9e5490282 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -696,11 +696,9 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags) { struct in_ifaddr *ia; struct in_addr prefix, mask, p, m; - int error = 0, fibnum; + int error = 0; struct sockaddr_in prefix0, mask0; - fibnum = rt_add_addr_allfibs ? RT_ALL_FIBS : target->ia_ifp->if_fib; - /* * Remove the loopback route to the interface address. */ @@ -712,6 +710,8 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags) eia = in_localip_more(target); if (eia != NULL) { + int fibnum = target->ia_ifp->if_fib; + error = ifa_switch_loopback_route((struct ifaddr *)eia, (struct sockaddr *)&target->ia_addr, fibnum); ifa_free(&eia->ia_ifa); @@ -736,6 +736,10 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags) } if ((target->ia_flags & IFA_ROUTE) == 0) { + int fibnum; + + fibnum = rt_add_addr_allfibs ? RT_ALL_FIBS : + target->ia_ifp->if_fib; rt_addrmsg(RTM_DELETE, &target->ia_ifa, fibnum); return (0); } diff --git a/sys/netinet/in_rmx.c b/sys/netinet/in_rmx.c index 2771ad0f68d00..bd5835ea29c87 100644 --- a/sys/netinet/in_rmx.c +++ b/sys/netinet/in_rmx.c @@ -169,9 +169,8 @@ in_clsroute(struct radix_node *rn, struct radix_node_head *head) if (V_rtq_reallyold != 0) { rt->rt_flags |= RTPRF_OURS; rt->rt_expire = time_uptime + V_rtq_reallyold; - } else { - rtexpunge(rt); - } + } else + rt_expunge(head, rt); } struct rtqk_arg { @@ -388,6 +387,7 @@ in_detachhead(void **head, int off) * plug back in. */ struct in_ifadown_arg { + struct radix_node_head *rnh; struct ifaddr *ifa; int del; }; @@ -411,7 +411,7 @@ in_ifadownkill(struct radix_node *rn, void *xap) * Disconnect it from the tree and permit protocols * to cleanup. */ - rtexpunge(rt); + rt_expunge(ap->rnh, rt); /* * At this point it is an rttrash node, and in case * the above is the only reference we must free it. @@ -441,6 +441,7 @@ in_ifadown(struct ifaddr *ifa, int delete) for ( fibnum = 0; fibnum < rt_numfibs; fibnum++) { rnh = rt_tables_get_rnh(fibnum, AF_INET); + arg.rnh = rnh; arg.ifa = ifa; arg.del = delete; RADIX_NODE_HEAD_LOCK(rnh); diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 40e6435559adb..8039196d0a49b 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -887,17 +887,13 @@ in_delayed_cksum(struct mbuf *m) csum = 0xffff; offset += m->m_pkthdr.csum_data; /* checksum offset */ - if (offset + sizeof(u_short) > m->m_len) { - printf("delayed m_pullup, m->len: %d off: %d p: %d\n", - m->m_len, offset, ip->ip_p); - /* - * XXX - * this shouldn't happen, but if it does, the - * correct behavior may be to insert the checksum - * in the appropriate next mbuf in the chain. - */ - return; + /* find the mbuf in the chain where the checksum starts*/ + while ((m != NULL) && (offset >= m->m_len)) { + offset -= m->m_len; + m = m->m_next; } + KASSERT(m != NULL, ("in_delayed_cksum: checksum outside mbuf chain.")); + KASSERT(offset + sizeof(u_short) <= m->m_len, ("in_delayed_cksum: checksum split between mbufs.")); *(u_short *)(m->m_data + offset) = csum; } diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index 3dbaa8a942977..861455c40b8d4 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -2735,7 +2735,6 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, uint32_t vrf_id; lport = 0; - error = 0; bindall = 1; inp = (struct sctp_inpcb *)so->so_pcb; ip_inp = (struct inpcb *)so->so_pcb; @@ -2856,13 +2855,6 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, return (error); } } - if (p == NULL) { - SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); - SCTP_INP_INFO_WUNLOCK(); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); - return (error); - } SCTP_INP_WUNLOCK(inp); if (bindall) { vrf_id = inp->def_vrf_id; diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index f01da0033a5e8..aac430dbad3c3 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1639,8 +1639,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, tp->snd_nxt == tp->snd_max && tiwin && tiwin == tp->snd_wnd && ((tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN)) == 0) && - LIST_EMPTY(&tp->t_segq) && - ((to.to_flags & TOF_TS) == 0 || + tp->t_segq == NULL && ((to.to_flags & TOF_TS) == 0 || TSTMP_GEQ(to.to_tsval, tp->ts_recent)) ) { /* @@ -2908,8 +2907,7 @@ dodata: /* XXX */ * immediately when segments are out of order (so * fast retransmit can work). */ - if (th->th_seq == tp->rcv_nxt && - LIST_EMPTY(&tp->t_segq) && + if (th->th_seq == tp->rcv_nxt && tp->t_segq == NULL && TCPS_HAVEESTABLISHED(tp->t_state)) { if (DELAY_ACK(tp, tlen)) tp->t_flags |= TF_DELACK; diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index 43153c83a2423..14f0e93fe1763 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -71,98 +71,33 @@ __FBSDID("$FreeBSD$"); #include <netinet/tcp_var.h> #include <netinet6/tcp6_var.h> #include <netinet/tcpip.h> -#ifdef TCPDEBUG -#include <netinet/tcp_debug.h> -#endif /* TCPDEBUG */ - -static SYSCTL_NODE(_net_inet_tcp, OID_AUTO, reass, CTLFLAG_RW, 0, - "TCP Segment Reassembly Queue"); - -static VNET_DEFINE(int, tcp_reass_maxseg) = 0; -#define V_tcp_reass_maxseg VNET(tcp_reass_maxseg) -SYSCTL_VNET_INT(_net_inet_tcp_reass, OID_AUTO, maxsegments, CTLFLAG_RDTUN, - &VNET_NAME(tcp_reass_maxseg), 0, - "Global maximum number of TCP Segments in Reassembly Queue"); - -static VNET_DEFINE(int, tcp_reass_overflows) = 0; -#define V_tcp_reass_overflows VNET(tcp_reass_overflows) -SYSCTL_VNET_INT(_net_inet_tcp_reass, OID_AUTO, overflows, - CTLTYPE_INT | CTLFLAG_RD, - &VNET_NAME(tcp_reass_overflows), 0, - "Global number of TCP Segment Reassembly Queue Overflows"); - -static VNET_DEFINE(uma_zone_t, tcp_reass_zone); -#define V_tcp_reass_zone VNET(tcp_reass_zone) -SYSCTL_UMA_CUR(_net_inet_tcp_reass, OID_AUTO, cursegments, CTLFLAG_VNET, - &VNET_NAME(tcp_reass_zone), - "Global number of TCP Segments currently in Reassembly Queue"); - -/* Initialize TCP reassembly queue */ -static void -tcp_reass_zone_change(void *tag) -{ - - /* Set the zone limit and read back the effective value. */ - V_tcp_reass_maxseg = nmbclusters / 16; - V_tcp_reass_maxseg = uma_zone_set_max(V_tcp_reass_zone, - V_tcp_reass_maxseg); -} - -void -tcp_reass_init(void) -{ - - V_tcp_reass_maxseg = nmbclusters / 16; - TUNABLE_INT_FETCH("net.inet.tcp.reass.maxsegments", - &V_tcp_reass_maxseg); - V_tcp_reass_zone = uma_zcreate("tcpreass", sizeof (struct tseg_qent), - NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); - /* Set the zone limit and read back the effective value. */ - V_tcp_reass_maxseg = uma_zone_set_max(V_tcp_reass_zone, - V_tcp_reass_maxseg); - EVENTHANDLER_REGISTER(nmbclusters_change, - tcp_reass_zone_change, NULL, EVENTHANDLER_PRI_ANY); -} - -#ifdef VIMAGE -void -tcp_reass_destroy(void) -{ - - uma_zdestroy(V_tcp_reass_zone); -} -#endif void tcp_reass_flush(struct tcpcb *tp) { - struct tseg_qent *qe; + struct mbuf *m; INP_WLOCK_ASSERT(tp->t_inpcb); - while ((qe = LIST_FIRST(&tp->t_segq)) != NULL) { - LIST_REMOVE(qe, tqe_q); - m_freem(qe->tqe_m); - uma_zfree(V_tcp_reass_zone, qe); - tp->t_segqlen--; + while ((m = tp->t_segq) != NULL) { + tp->t_segq = m->m_nextpkt; + tp->t_segqlen -= m->m_pkthdr.len; + m_freem(m); } KASSERT((tp->t_segqlen == 0), - ("TCP reass queue %p segment count is %d instead of 0 after flush.", + ("TCP reass queue %p length is %d instead of 0 after flush.", tp, tp->t_segqlen)); } +#define M_TCPHDR(m) ((struct tcphdr *)((m)->m_pkthdr.pkt_tcphdr)) + int tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m) { - struct tseg_qent *q; - struct tseg_qent *p = NULL; - struct tseg_qent *nq; - struct tseg_qent *te = NULL; struct socket *so = tp->t_inpcb->inp_socket; - char *s = NULL; - int flags; - struct tseg_qent tqs; + struct mbuf *mq, *mp; + int flags, wakeup; INP_WLOCK_ASSERT(tp->t_inpcb); @@ -178,6 +113,10 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m) if (th == NULL) goto present; + M_ASSERTPKTHDR(m); + KASSERT(*tlenp == m->m_pkthdr.len, ("%s: tlenp %u len %u", __func__, + *tlenp, m->m_pkthdr.len)); + /* * Limit the number of segments that can be queued to reduce the * potential for mbuf exhaustion. For best performance, we want to be @@ -188,67 +127,31 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m) * Always let the missing segment through which caused this queue. * NB: Access to the socket buffer is left intentionally unlocked as we * can tolerate stale information here. - * - * XXXLAS: Using sbspace(so->so_rcv) instead of so->so_rcv.sb_hiwat - * should work but causes packets to be dropped when they shouldn't. - * Investigate why and re-evaluate the below limit after the behaviour - * is understood. */ - if (th->th_seq != tp->rcv_nxt && - tp->t_segqlen >= (so->so_rcv.sb_hiwat / tp->t_maxseg) + 1) { - V_tcp_reass_overflows++; - TCPSTAT_INC(tcps_rcvmemdrop); - m_freem(m); + if ((th->th_seq != tp->rcv_nxt || !TCPS_HAVEESTABLISHED(tp->t_state)) && + tp->t_segqlen + m->m_pkthdr.len >= sbspace(&so->so_rcv)) { + char *s; + + TCPSTAT_INC(tcps_rcvreassfull); *tlenp = 0; - if ((s = tcp_log_addrs(&tp->t_inpcb->inp_inc, th, NULL, NULL))) { + if ((s = tcp_log_addrs(&tp->t_inpcb->inp_inc, th, NULL, + NULL))) { log(LOG_DEBUG, "%s; %s: queue limit reached, " "segment dropped\n", s, __func__); free(s, M_TCPLOG); } + m_freem(m); return (0); } /* - * Allocate a new queue entry. If we can't, or hit the zone limit - * just drop the pkt. - * - * Use a temporary structure on the stack for the missing segment - * when the zone is exhausted. Otherwise we may get stuck. - */ - te = uma_zalloc(V_tcp_reass_zone, M_NOWAIT); - if (te == NULL) { - if (th->th_seq != tp->rcv_nxt) { - TCPSTAT_INC(tcps_rcvmemdrop); - m_freem(m); - *tlenp = 0; - if ((s = tcp_log_addrs(&tp->t_inpcb->inp_inc, th, NULL, - NULL))) { - log(LOG_DEBUG, "%s; %s: global zone limit " - "reached, segment dropped\n", s, __func__); - free(s, M_TCPLOG); - } - return (0); - } else { - bzero(&tqs, sizeof(struct tseg_qent)); - te = &tqs; - if ((s = tcp_log_addrs(&tp->t_inpcb->inp_inc, th, NULL, - NULL))) { - log(LOG_DEBUG, - "%s; %s: global zone limit reached, using " - "stack for missing segment\n", s, __func__); - free(s, M_TCPLOG); - } - } - } - tp->t_segqlen++; - - /* * Find a segment which begins after this one does. */ - LIST_FOREACH(q, &tp->t_segq, tqe_q) { - if (SEQ_GT(q->tqe_th->th_seq, th->th_seq)) + mp = NULL; + for (mq = tp->t_segq; mq != NULL; mq = mq->m_nextpkt) { + if (SEQ_GT(M_TCPHDR(mq)->th_seq, th->th_seq)) break; - p = q; + mp = mq; } /* @@ -256,17 +159,16 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m) * our data already. If so, drop the data from the incoming * segment. If it provides all of our data, drop us. */ - if (p != NULL) { + if (mp != NULL) { int i; + /* conversion to int (in i) handles seq wraparound */ - i = p->tqe_th->th_seq + p->tqe_len - th->th_seq; + i = M_TCPHDR(mp)->th_seq + mp->m_pkthdr.len - th->th_seq; if (i > 0) { if (i >= *tlenp) { TCPSTAT_INC(tcps_rcvduppack); TCPSTAT_ADD(tcps_rcvdupbyte, *tlenp); m_freem(m); - uma_zfree(V_tcp_reass_zone, te); - tp->t_segqlen--; /* * Try to present any queued data * at the left window edge to the user. @@ -288,37 +190,40 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m) * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ - while (q) { - int i = (th->th_seq + *tlenp) - q->tqe_th->th_seq; + while (mq) { + struct mbuf *nq; + int i; + + i = (th->th_seq + *tlenp) - M_TCPHDR(mq)->th_seq; if (i <= 0) break; - if (i < q->tqe_len) { - q->tqe_th->th_seq += i; - q->tqe_len -= i; - m_adj(q->tqe_m, i); + if (i < mq->m_pkthdr.len) { + M_TCPHDR(mq)->th_seq += i; + m_adj(mq, i); + tp->t_segqlen -= i; break; } - nq = LIST_NEXT(q, tqe_q); - LIST_REMOVE(q, tqe_q); - m_freem(q->tqe_m); - uma_zfree(V_tcp_reass_zone, q); - tp->t_segqlen--; - q = nq; + nq = mq->m_nextpkt; + tp->t_segqlen -= mq->m_pkthdr.len; + m_freem(mq); + if (mp) + mp->m_nextpkt = nq; + else + tp->t_segq = nq; + mq = nq; } /* Insert the new segment queue entry into place. */ - te->tqe_m = m; - te->tqe_th = th; - te->tqe_len = *tlenp; - - if (p == NULL) { - LIST_INSERT_HEAD(&tp->t_segq, te, tqe_q); + if (mp) { + m->m_nextpkt = mp->m_nextpkt; + mp->m_nextpkt = m; } else { - KASSERT(te != &tqs, ("%s: temporary stack based entry not " - "first element in queue", __func__)); - LIST_INSERT_AFTER(p, te, tqe_q); + m->m_nextpkt = tp->t_segq; + tp->t_segq = m ; } + m->m_pkthdr.pkt_tcphdr = th; + tp->t_segqlen += m->m_pkthdr.len; present: /* @@ -327,25 +232,30 @@ present: */ if (!TCPS_HAVEESTABLISHED(tp->t_state)) return (0); - q = LIST_FIRST(&tp->t_segq); - if (!q || q->tqe_th->th_seq != tp->rcv_nxt) - return (0); + + flags = 0; + wakeup = 0; SOCKBUF_LOCK(&so->so_rcv); - do { - tp->rcv_nxt += q->tqe_len; - flags = q->tqe_th->th_flags & TH_FIN; - nq = LIST_NEXT(q, tqe_q); - LIST_REMOVE(q, tqe_q); + while ((mq = tp->t_segq) != NULL && + M_TCPHDR(mq)->th_seq == tp->rcv_nxt) { + tp->t_segq = mq->m_nextpkt; + + tp->rcv_nxt += mq->m_pkthdr.len; + tp->t_segqlen -= mq->m_pkthdr.len; + flags = M_TCPHDR(mq)->th_flags & TH_FIN; + if (so->so_rcv.sb_state & SBS_CANTRCVMORE) - m_freem(q->tqe_m); - else - sbappendstream_locked(&so->so_rcv, q->tqe_m); - if (q != &tqs) - uma_zfree(V_tcp_reass_zone, q); - tp->t_segqlen--; - q = nq; - } while (q && q->tqe_th->th_seq == tp->rcv_nxt); + m_freem(mq); + else { + mq->m_nextpkt = NULL; + sbappendstream_locked(&so->so_rcv, mq); + wakeup = 1; + } + } ND6_HINT(tp); - sorwakeup_locked(so); + if (wakeup) + sorwakeup_locked(so); + else + SOCKBUF_UNLOCK(&so->so_rcv); return (flags); } diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index c73cb97691245..fb2c415aee986 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -375,7 +375,6 @@ tcp_init(void) tcp_tw_init(); syncache_init(); tcp_hc_init(); - tcp_reass_init(); TUNABLE_INT_FETCH("net.inet.tcp.sack.enable", &V_tcp_do_sack); V_sack_hole_zone = uma_zcreate("sackhole", sizeof(struct sackhole), @@ -433,7 +432,6 @@ tcp_destroy(void) { int error; - tcp_reass_destroy(); tcp_hc_destroy(); syncache_destroy(); tcp_tw_destroy(); diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index a8dcb320f450e..42c1e1d6ccd6c 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -1949,7 +1949,7 @@ db_print_tcpcb(struct tcpcb *tp, const char *name, int indent) db_print_indent(indent); db_printf("t_segq first: %p t_segqlen: %d t_dupacks: %d\n", - LIST_FIRST(&tp->t_segq), tp->t_segqlen, tp->t_dupacks); + tp->t_segq, tp->t_segqlen, tp->t_dupacks); db_print_indent(indent); db_printf("tt_rexmt: %p tt_persist: %p tt_keep: %p\n", diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index 25426f5ce3476..4d7074a4213cf 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -46,15 +46,6 @@ VNET_DECLARE(int, tcp_do_rfc1323); #endif /* _KERNEL */ -/* TCP segment queue entry */ -struct tseg_qent { - LIST_ENTRY(tseg_qent) tqe_q; - int tqe_len; /* TCP segment data length */ - struct tcphdr *tqe_th; /* a pointer to tcp header */ - struct mbuf *tqe_m; /* mbuf contains packet */ -}; -LIST_HEAD(tsegqe_head, tseg_qent); - struct sackblk { tcp_seq start; /* start seq no. of sack block */ tcp_seq end; /* end seq no. */ @@ -100,7 +91,7 @@ do { \ * Organized for 16 byte cacheline efficiency. */ struct tcpcb { - struct tsegqe_head t_segq; /* segment reassembly queue */ + struct mbuf *t_segq; /* segment reassembly queue */ void *t_pspare[2]; /* new reassembly queue */ int t_segqlen; /* segment reassembly queue length */ int t_dupacks; /* consecutive dup acks recd */ @@ -435,7 +426,7 @@ struct tcpstat { uint64_t tcps_rcvbyte; /* bytes received in sequence */ uint64_t tcps_rcvbadsum; /* packets received with ccksum errs */ uint64_t tcps_rcvbadoff; /* packets received with bad offset */ - uint64_t tcps_rcvmemdrop; /* packets dropped for lack of memory */ + uint64_t tcps_rcvreassfull; /* packets dropped for no reass space */ uint64_t tcps_rcvshort; /* packets received too short */ uint64_t tcps_rcvduppack; /* duplicate-only packets received */ uint64_t tcps_rcvdupbyte; /* duplicate-only bytes received */ @@ -663,11 +654,7 @@ char *tcp_log_addrs(struct in_conninfo *, struct tcphdr *, void *, char *tcp_log_vain(struct in_conninfo *, struct tcphdr *, void *, const void *); int tcp_reass(struct tcpcb *, struct tcphdr *, int *, struct mbuf *); -void tcp_reass_init(void); void tcp_reass_flush(struct tcpcb *); -#ifdef VIMAGE -void tcp_reass_destroy(void); -#endif void tcp_input(struct mbuf *, int); u_long tcp_maxmtu(struct in_conninfo *, struct tcp_ifcap *); u_long tcp_maxmtu6(struct in_conninfo *, struct tcp_ifcap *); diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index 01fff7bfddba2..6eb737e813a14 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -863,7 +863,7 @@ in6_ifdetach(struct ifnet *ifp) RT_DEFAULT_FIB); if (rt) { if (rt->rt_ifp == ifp) - rtexpunge(rt); + rt_expunge(rnh, rt); RTFREE_LOCKED(rt); } RADIX_NODE_HEAD_UNLOCK(rnh); diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/Makefile b/sys/ofed/drivers/infiniband/hw/mlx4/Makefile index 6b03ea319128a..7b81da0c060c7 100644 --- a/sys/ofed/drivers/infiniband/hw/mlx4/Makefile +++ b/sys/ofed/drivers/infiniband/hw/mlx4/Makefile @@ -2,7 +2,7 @@ #.PATH: ${.CURDIR}/../../ofed/drivers/infiniband/hw/mlx4 #.PATH: ${.CURDIR}/../../../../include/linux -.include <bsd.own.mk> +.include <src.opts.mk> KMOD = mlx4ib SRCS = device_if.h bus_if.h pci_if.h vnode_if.h diff --git a/sys/ofed/drivers/net/mlx4/Makefile b/sys/ofed/drivers/net/mlx4/Makefile index 2e2ba35d7bb57..d6fe775348170 100644 --- a/sys/ofed/drivers/net/mlx4/Makefile +++ b/sys/ofed/drivers/net/mlx4/Makefile @@ -2,7 +2,7 @@ #.PATH: ${.CURDIR}/../../ofed/drivers/net/mlx4:${.CURDIR}/../../ofed/include/linux .PATH: ${.CURDIR}/../../../../../include/linux -.include <bsd.own.mk> +.include <src.opts.mk> KMOD = mlx4 diff --git a/sys/pc98/conf/NOTES b/sys/pc98/conf/NOTES index 98a28b1e8a919..5442002cdf13f 100644 --- a/sys/pc98/conf/NOTES +++ b/sys/pc98/conf/NOTES @@ -545,9 +545,6 @@ options COMPAT_SVR4 # build emulator statically options DEBUG_SVR4 # enable verbose debugging device streams # STREAMS network driver (required for svr4). -# Linux-specific pseudo devices support -device lindev - ##################################################################### # VM OPTIONS diff --git a/sys/rpc/clnt_vc.c b/sys/rpc/clnt_vc.c index 44d1097566af8..67ad58f5cd1ba 100644 --- a/sys/rpc/clnt_vc.c +++ b/sys/rpc/clnt_vc.c @@ -270,14 +270,12 @@ clnt_vc_create( return (cl); err: - if (cl) { - if (ct) { - mtx_destroy(&ct->ct_lock); - mem_free(ct, sizeof (struct ct_data)); - } - if (cl) - mem_free(cl, sizeof (CLIENT)); + if (ct) { + mtx_destroy(&ct->ct_lock); + mem_free(ct, sizeof (struct ct_data)); } + if (cl) + mem_free(cl, sizeof (CLIENT)); return ((CLIENT *)NULL); } diff --git a/sys/sparc64/conf/GENERIC b/sys/sparc64/conf/GENERIC index 24d54a38e89b3..de100c8150ec2 100644 --- a/sys/sparc64/conf/GENERIC +++ b/sys/sparc64/conf/GENERIC @@ -109,6 +109,7 @@ device isp # Qlogic family device ispfw # Firmware module for Qlogic host adapters device mpt # LSI-Logic MPT-Fusion device mps # LSI-Logic MPT-Fusion 2 +device mpr # LSI-Logic MPT-Fusion 3 device sym # NCR/Symbios/LSI Logic 53C8XX/53C1010/53C1510D # ATA/SCSI peripherals diff --git a/sys/sys/kernel.h b/sys/sys/kernel.h index 68e0858ac6119..3c5258ab205f0 100644 --- a/sys/sys/kernel.h +++ b/sys/sys/kernel.h @@ -92,10 +92,8 @@ enum sysinit_sub_id { SI_SUB_COPYRIGHT = 0x0800001, /* first use of console*/ SI_SUB_SETTINGS = 0x0880000, /* check and recheck settings */ SI_SUB_MTX_POOL_STATIC = 0x0900000, /* static mutex pool */ - SI_SUB_LOCKMGR = 0x0980000, /* lockmgr locks */ SI_SUB_VM = 0x1000000, /* virtual memory system init*/ SI_SUB_KMEM = 0x1800000, /* kernel memory*/ - SI_SUB_KVM_RSRC = 0x1A00000, /* kvm operational limits*/ SI_SUB_HYPERVISOR = 0x1A40000, /* * Hypervisor detection and * virtualization support @@ -139,7 +137,6 @@ enum sysinit_sub_id { SI_SUB_CONFIGURE = 0x3800000, /* Configure devices */ SI_SUB_VFS = 0x4000000, /* virtual filesystem*/ SI_SUB_CLOCKS = 0x4800000, /* real time and stat clocks*/ - SI_SUB_CLIST = 0x5800000, /* clists*/ SI_SUB_SYSV_SHM = 0x6400000, /* System V shared memory*/ SI_SUB_SYSV_SEM = 0x6800000, /* System V semaphores*/ SI_SUB_SYSV_MSG = 0x6C00000, /* System V message queues*/ @@ -169,7 +166,7 @@ enum sysinit_sub_id { SI_SUB_KTHREAD_UPDATE = 0xec00000, /* update daemon*/ SI_SUB_KTHREAD_IDLE = 0xee00000, /* idle procs*/ SI_SUB_SMP = 0xf000000, /* start the APs*/ - SI_SUB_RACCTD = 0xf100000, /* start raccd*/ + SI_SUB_RACCTD = 0xf100000, /* start racctd*/ SI_SUB_LAST = 0xfffffff /* final initialization */ }; diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index 815732ebfa76f..e056bc7ee94f7 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -159,6 +159,7 @@ struct pkthdr { #define tso_segsz PH_per.sixteen[1] #define csum_phsum PH_per.sixteen[2] #define csum_data PH_per.thirtytwo[1] +#define pkt_tcphdr PH_loc.ptr /* * Description of external storage mapped into mbuf; valid only if M_EXT is diff --git a/sys/sys/mutex.h b/sys/sys/mutex.h index 3d5f08c1405d2..467860092e62e 100644 --- a/sys/sys/mutex.h +++ b/sys/sys/mutex.h @@ -323,12 +323,8 @@ struct mtx *mtx_pool_alloc(struct mtx_pool *pool); mtx_unlock_spin(mtx_pool_find((pool), (ptr))) /* - * mtxpool_lockbuilder is a pool of sleep locks that is not witness - * checked and should only be used for building higher level locks. - * * mtxpool_sleep is a general purpose pool of sleep mutexes. */ -extern struct mtx_pool *mtxpool_lockbuilder; extern struct mtx_pool *mtxpool_sleep; #ifndef LOCK_DEBUG diff --git a/sys/sys/param.h b/sys/sys/param.h index 92a9d10eb9733..0a5616e10dfcb 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -58,7 +58,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1100019 /* Master, propagated to newvers */ +#define __FreeBSD_version 1100020 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, diff --git a/sys/sys/pipe.h b/sys/sys/pipe.h index dfe7f2f44f3b6..ee7c128d249b2 100644 --- a/sys/sys/pipe.h +++ b/sys/sys/pipe.h @@ -142,6 +142,6 @@ struct pipepair { #define PIPE_LOCK_ASSERT(pipe, type) mtx_assert(PIPE_MTX(pipe), (type)) void pipe_dtor(struct pipe *dpipe); -int pipe_named_ctor(struct pipe **ppipe, struct thread *td); +void pipe_named_ctor(struct pipe **ppipe, struct thread *td); void pipeselwakeup(struct pipe *cpipe); #endif /* !_SYS_PIPE_H_ */ diff --git a/sys/sys/select.h b/sys/sys/select.h index 511895b3c81fb..8a899acb68367 100644 --- a/sys/sys/select.h +++ b/sys/sys/select.h @@ -56,7 +56,7 @@ typedef __sigset_t sigset_t; * be enough for most uses. */ #ifndef FD_SETSIZE -#define FD_SETSIZE 1024U +#define FD_SETSIZE 1024 #endif #define _NFDBITS (sizeof(__fd_mask) * 8) /* bits per mask */ diff --git a/sys/sys/user.h b/sys/sys/user.h index 8576f6d4d4b8c..f7b18dffc21a8 100644 --- a/sys/sys/user.h +++ b/sys/sys/user.h @@ -271,7 +271,7 @@ struct user { #define KF_FD_TYPE_CWD -1 /* Current working directory */ #define KF_FD_TYPE_ROOT -2 /* Root directory */ #define KF_FD_TYPE_JAIL -3 /* Jail directory */ -#define KF_FD_TYPE_TRACE -4 /* ptrace vnode */ +#define KF_FD_TYPE_TRACE -4 /* Ktrace vnode */ #define KF_FD_TYPE_TEXT -5 /* Text vnode */ #define KF_FD_TYPE_CTTY -6 /* Controlling terminal */ diff --git a/sys/tools/fdt/make_dtb.sh b/sys/tools/fdt/make_dtb.sh index 900ad9bd399c8..7724c95f32334 100755 --- a/sys/tools/fdt/make_dtb.sh +++ b/sys/tools/fdt/make_dtb.sh @@ -4,8 +4,17 @@ # Script generates dtb file ($3) from dts source ($2) in build tree S ($1) S=$1 -dts=$2 -dtb=$3 +dts="$2" +dtb_path=$3 -cpp -x assembler-with-cpp -I $S/gnu/dts/include -I $S/boot/fdt/dts/${MACHINE} -I $S/gnu/dts/${MACHINE} -include $dts /dev/null | +if [ -z "$dts" ]; then + echo "No DTS specified" + exit 1 +fi + +for d in ${dts}; do + dtb=${dtb_path}/`basename $d .dts`.dtb + echo "converting $d -> $dtb" + cpp -x assembler-with-cpp -I $S/gnu/dts/include -I $S/boot/fdt/dts/${MACHINE} -I $S/gnu/dts/${MACHINE} -include $d /dev/null | dtc -O dtb -o $dtb -b 0 -p 1024 -i $S/boot/fdt/dts/${MACHINE} -i $S/gnu/dts/${MACHINE} +done diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index c5fa7488f7f32..0760f3ec969fc 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -1275,6 +1275,7 @@ static int stat_cleanup_blkrequests; /* Number of block cleanup requests */ static int stat_cleanup_inorequests; /* Number of inode cleanup requests */ static int stat_cleanup_retries; /* Number of cleanups that needed to flush */ static int stat_cleanup_failures; /* Number of cleanup requests that failed */ +static int stat_emptyjblocks; /* Number of potentially empty journal blocks */ SYSCTL_INT(_debug_softdep, OID_AUTO, max_softdeps, CTLFLAG_RW, &max_softdeps, 0, ""); @@ -1334,6 +1335,8 @@ SYSCTL_INT(_debug_softdep, OID_AUTO, cleanup_failures, CTLFLAG_RW, &stat_cleanup_failures, 0, ""); SYSCTL_INT(_debug_softdep, OID_AUTO, flushcache, CTLFLAG_RW, &softdep_flushcache, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, emptyjblocks, CTLFLAG_RD, + &stat_emptyjblocks, 0, ""); SYSCTL_DECL(_vfs_ffs); @@ -3328,6 +3331,24 @@ softdep_process_journal(mp, needwk, flags) */ data = bp->b_data; off = 0; + + /* + * Always put a header on the first block. + * XXX As with below, there might not be a chance to get + * into the loop. Ensure that something valid is written. + */ + jseg_write(ump, jseg, data); + off += JREC_SIZE; + data = bp->b_data + off; + + /* + * XXX Something is wrong here. There's no work to do, + * but we need to perform and I/O and allow it to complete + * anyways. + */ + if (LIST_EMPTY(&ump->softdep_journal_pending)) + stat_emptyjblocks++; + while ((wk = LIST_FIRST(&ump->softdep_journal_pending)) != NULL) { if (cnt == 0) @@ -3377,6 +3398,11 @@ softdep_process_journal(mp, needwk, flags) data = bp->b_data + off; cnt--; } + + /* Clear any remaining space so we don't leak kernel data */ + if (size > off) + bzero(data, size - off); + /* * Write this one buffer and continue. */ diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index 6a9f29b0ffbde..60aa6211981e8 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -556,7 +556,7 @@ sys_msync(td, uap) case KERN_SUCCESS: return (0); case KERN_INVALID_ADDRESS: - return (EINVAL); /* Sun returns ENOMEM? */ + return (ENOMEM); case KERN_INVALID_ARGUMENT: return (EBUSY); case KERN_FAILURE: diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c index 7f8011584900d..65743d79eb327 100644 --- a/sys/vm/vm_pageout.c +++ b/sys/vm/vm_pageout.c @@ -942,13 +942,15 @@ vm_pageout_scan(struct vm_domain *vmd, int pass) */ addl_page_shortage = 0; - deficit = atomic_readandclear_int(&vm_pageout_deficit); - /* * Calculate the number of pages we want to either free or move * to the cache. */ - page_shortage = vm_paging_target() + deficit; + if (pass > 0) { + deficit = atomic_readandclear_int(&vm_pageout_deficit); + page_shortage = vm_paging_target() + deficit; + } else + page_shortage = deficit = 0; /* * maxlaunder limits the number of dirty pages we flush per scan. diff --git a/sys/vm/vm_phys.c b/sys/vm/vm_phys.c index d8fe232c0c099..14960c8857342 100644 --- a/sys/vm/vm_phys.c +++ b/sys/vm/vm_phys.c @@ -551,7 +551,9 @@ vm_phys_fictitious_reg_range(vm_paddr_t start, vm_paddr_t end, #ifdef VM_PHYSSEG_DENSE pi = atop(start); - if (pi >= first_page && atop(end) < vm_page_array_size) { + if (pi >= first_page && pi < vm_page_array_size + first_page) { + if (atop(end) >= vm_page_array_size + first_page) + return (EINVAL); fp = &vm_page_array[pi - first_page]; malloced = FALSE; } else diff --git a/tests/sys/netinet/fibs_test.sh b/tests/sys/netinet/fibs_test.sh index dc51b54bd83c5..d8b18e22177ef 100755 --- a/tests/sys/netinet/fibs_test.sh +++ b/tests/sys/netinet/fibs_test.sh @@ -213,6 +213,98 @@ default_route_with_multiple_fibs_on_same_subnet_cleanup() } +# Regression test for PR kern/189089 +# Create two tap interfaces and assign them both the same IP address but with +# different netmasks, and both on the default FIB. Then remove one's IP +# address. Hopefully the machine won't panic. +atf_test_case same_ip_multiple_ifaces_fib0 cleanup +same_ip_multiple_ifaces_fib0_head() +{ + atf_set "descr" "Can remove an IP alias from an interface when the same IP is also assigned to another interface." + atf_set "require.user" "root" + atf_set "require.config" "fibs" +} +same_ip_multiple_ifaces_fib0_body() +{ + ADDR="192.0.2.2" + MASK0="24" + MASK1="32" + + # Unlike most of the tests in this file, this is applicable regardless + # of net.add_addr_allfibs + + # Setup the interfaces, then remove one alias. It should not panic. + setup_tap 0 ${ADDR} ${MASK0} + TAP0=${TAP} + setup_tap 0 ${ADDR} ${MASK1} + TAP1=${TAP} + ifconfig ${TAP1} -alias ${ADDR} + + # Do it again, in the opposite order. It should not panic. + setup_tap 0 ${ADDR} ${MASK0} + TAP0=${TAP} + setup_tap 0 ${ADDR} ${MASK1} + TAP1=${TAP} + ifconfig ${TAP0} -alias ${ADDR} +} +same_ip_multiple_ifaces_fib0_cleanup() +{ + cleanup_tap +} + +# Regression test for PR kern/189088 +# Test that removing an IP address works even if the same IP is assigned to a +# different interface, on a different FIB. Tests the same code that whose +# panic was regressed by same_ip_multiple_ifaces_fib0. +# Create two tap interfaces and assign them both the same IP address but with +# different netmasks, and on different FIBs. Then remove one's IP +# address. Hopefully the machine won't panic. Also, the IP's hostroute should +# dissappear from the correct fib. +atf_test_case same_ip_multiple_ifaces cleanup +same_ip_multiple_ifaces_head() +{ + atf_set "descr" "Can remove an IP alias from an interface when the same IP is also assigned to another interface, on non-default FIBs." + atf_set "require.user" "root" + atf_set "require.config" "fibs" +} +same_ip_multiple_ifaces_body() +{ + atf_expect_fail "kern/189088 Assigning the same IP to multiple interfaces in different FIBs creates a host route for only one" + ADDR="192.0.2.2" + MASK0="24" + MASK1="32" + + # Unlike most of the tests in this file, this is applicable regardless + # of net.add_addr_allfibs + get_fibs 2 + + # Setup the interfaces, then remove one alias. It should not panic. + setup_tap ${FIB0} ${ADDR} ${MASK0} + TAP0=${TAP} + setup_tap ${FIB1} ${ADDR} ${MASK1} + TAP1=${TAP} + ifconfig ${TAP1} -alias ${ADDR} + atf_check -o not-match:"^${ADDR}[[:space:]]" \ + setfib ${FIB1} netstat -rn -f inet + + # Do it again, in the opposite order. It should not panic. + setup_tap ${FIB0} ${ADDR} ${MASK0} + TAP0=${TAP} + setup_tap ${FIB1} ${ADDR} ${MASK1} + TAP1=${TAP} + ifconfig ${TAP0} -alias ${ADDR} + atf_check -o not-match:"^${ADDR}[[:space:]]" \ + setfib ${FIB0} netstat -rn -f inet +} +same_ip_multiple_ifaces_cleanup() +{ + # Due to PR kern/189088, we must destroy the interfaces in LIFO order + # in order for the routes to be correctly cleaned up. + for TAPD in `tail -r "tap_devices_to_cleanup"`; do + ifconfig ${TAPD} destroy + done +} + # Regression test for kern/187550 atf_test_case subnet_route_with_multiple_fibs_on_same_subnet cleanup subnet_route_with_multiple_fibs_on_same_subnet_head() @@ -309,6 +401,8 @@ atf_init_test_cases() atf_add_test_case arpresolve_checks_interface_fib atf_add_test_case loopback_and_network_routes_on_nondefault_fib atf_add_test_case default_route_with_multiple_fibs_on_same_subnet + atf_add_test_case same_ip_multiple_ifaces_fib0 + atf_add_test_case same_ip_multiple_ifaces atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet atf_add_test_case udp_dontroute } diff --git a/tools/bus_space/C/Makefile b/tools/bus_space/C/Makefile new file mode 100644 index 0000000000000..9d767e82dd909 --- /dev/null +++ b/tools/bus_space/C/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +LIB= bus_space +SHLIB_MAJOR= 0 +SRCS= lang.c + +CFLAGS+= -I${.CURDIR}/.. + +.include <bsd.lib.mk> diff --git a/tools/bus_space/C/lang.c b/tools/bus_space/C/lang.c new file mode 100644 index 0000000000000..6408343bd596b --- /dev/null +++ b/tools/bus_space/C/lang.c @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 2014 Marcel Moolenaar + * 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 ``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/types.h> +#include <errno.h> + +#include "bus_space.h" +#include "libbus_space.h" + +int +bus_space_read_1(int rid, long ofs) +{ + uint8_t val; + + return ((!bs_read(rid, ofs, &val, sizeof(val))) ? -1 : (int)val); +} + +int +bus_space_read_2(int rid, long ofs) +{ + uint16_t val; + + return ((!bs_read(rid, ofs, &val, sizeof(val))) ? -1 : (int)val); +} + +int64_t +bus_space_read_4(int rid, long ofs) +{ + uint32_t val; + + return ((!bs_read(rid, ofs, &val, sizeof(val))) ? -1 : (int64_t)val); +} + +int +bus_space_write_1(int rid, long ofs, uint8_t val) +{ + + return ((!bs_write(rid, ofs, &val, sizeof(val))) ? errno : 0); +} + +int +bus_space_write_2(int rid, long ofs, uint16_t val) +{ + + return ((!bs_write(rid, ofs, &val, sizeof(val))) ? errno : 0); +} + +int +bus_space_write_4(int rid, long ofs, uint32_t val) +{ + + return ((!bs_write(rid, ofs, &val, sizeof(val))) ? errno : 0); +} + +int +bus_space_map(const char *dev) +{ + + return (bs_map(dev)); +} + +int +bus_space_unmap(int rid) +{ + + return ((!bs_unmap(rid)) ? errno : 0); +} + +int +bus_space_subregion(int rid, long ofs, long sz) +{ + + return (bs_subregion(rid, ofs, sz)); +} diff --git a/tools/bus_space/C/libbus_space.h b/tools/bus_space/C/libbus_space.h new file mode 100644 index 0000000000000..3e8860f003bbb --- /dev/null +++ b/tools/bus_space/C/libbus_space.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2014 Marcel Moolenaar + * 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 ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _LIBBUS_SPACE_H_ +#define _LIBBUS_SPACE_H_ + +int bus_space_map(const char *dev); +int bus_space_read_1(int rid, long ofs); +int bus_space_read_2(int rid, long ofs); +int64_t bus_space_read_4(int rid, long ofs); +int bus_space_subregion(int rid, long ofs, long sz); +int bus_space_unmap(int rid); +int bus_space_write_1(int rid, long ofs, uint8_t val); +int bus_space_write_2(int rid, long ofs, uint16_t val); +int bus_space_write_4(int rid, long ofs, uint32_t val); + +#endif /* _LIBBUS_SPACE_H_ */ diff --git a/tools/bus_space/Makefile b/tools/bus_space/Makefile new file mode 100644 index 0000000000000..b13e3cfd7146f --- /dev/null +++ b/tools/bus_space/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +SUBDIR= \ + C \ + Python + +.include <bsd.subdir.mk> diff --git a/tools/bus_space/Makefile.inc b/tools/bus_space/Makefile.inc new file mode 100644 index 0000000000000..a448e3377582c --- /dev/null +++ b/tools/bus_space/Makefile.inc @@ -0,0 +1,4 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/.. +SRCS+= bus_space.c diff --git a/tools/bus_space/Python/Makefile b/tools/bus_space/Python/Makefile new file mode 100644 index 0000000000000..8e38ed3dab3f0 --- /dev/null +++ b/tools/bus_space/Python/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +SHLIB_NAME= bus_space.so +SRCS= lang.c + +CFLAGS+= -I${.CURDIR}/.. -I/usr/local/include/python2.7 +LDFLAGS+= -L/usr/local/lib -lpython2.7 + +.include <bsd.lib.mk> diff --git a/tools/bus_space/Python/lang.c b/tools/bus_space/Python/lang.c new file mode 100644 index 0000000000000..f328a77101199 --- /dev/null +++ b/tools/bus_space/Python/lang.c @@ -0,0 +1,200 @@ +/*- + * Copyright (c) 2014 Marcel Moolenaar + * 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 ``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 <Python.h> + +#include "bus_space.h" + +static PyObject * +bus_read_1(PyObject *self, PyObject *args) +{ + long ofs; + int rid; + uint8_t val; + + if (!PyArg_ParseTuple(args, "il", &rid, &ofs)) + return (NULL); + if (!bs_read(rid, ofs, &val, sizeof(val))) { + PyErr_SetString(PyExc_IOError, strerror(errno)); + return (NULL); + } + return (Py_BuildValue("B", val)); +} + +static PyObject * +bus_read_2(PyObject *self, PyObject *args) +{ + long ofs; + int rid; + uint16_t val; + + if (!PyArg_ParseTuple(args, "il", &rid, &ofs)) + return (NULL); + if (!bs_read(rid, ofs, &val, sizeof(val))) { + PyErr_SetString(PyExc_IOError, strerror(errno)); + return (NULL); + } + return (Py_BuildValue("H", val)); +} + +static PyObject * +bus_read_4(PyObject *self, PyObject *args) +{ + long ofs; + int rid; + uint32_t val; + + if (!PyArg_ParseTuple(args, "il", &rid, &ofs)) + return (NULL); + if (!bs_read(rid, ofs, &val, sizeof(val))) { + PyErr_SetString(PyExc_IOError, strerror(errno)); + return (NULL); + } + return (Py_BuildValue("I", val)); +} + +static PyObject * +bus_write_1(PyObject *self, PyObject *args) +{ + long ofs; + int rid; + uint8_t val; + + if (!PyArg_ParseTuple(args, "ilB", &rid, &ofs, &val)) + return (NULL); + if (!bs_write(rid, ofs, &val, sizeof(val))) { + PyErr_SetString(PyExc_IOError, strerror(errno)); + return (NULL); + } + Py_RETURN_NONE; +} + +static PyObject * +bus_write_2(PyObject *self, PyObject *args) +{ + long ofs; + int rid; + uint16_t val; + + if (!PyArg_ParseTuple(args, "ilH", &rid, &ofs, &val)) + return (NULL); + if (!bs_write(rid, ofs, &val, sizeof(val))) { + PyErr_SetString(PyExc_IOError, strerror(errno)); + return (NULL); + } + Py_RETURN_NONE; +} + +static PyObject * +bus_write_4(PyObject *self, PyObject *args) +{ + long ofs; + int rid; + uint32_t val; + + if (!PyArg_ParseTuple(args, "ilI", &rid, &ofs, &val)) + return (NULL); + if (!bs_write(rid, ofs, &val, sizeof(val))) { + PyErr_SetString(PyExc_IOError, strerror(errno)); + return (NULL); + } + Py_RETURN_NONE; +} + +static PyObject * +bus_map(PyObject *self, PyObject *args) +{ + char *dev; + int rid; + + if (!PyArg_ParseTuple(args, "s", &dev)) + return (NULL); + rid = bs_map(dev); + if (rid == -1) { + PyErr_SetString(PyExc_IOError, strerror(errno)); + return (NULL); + } + return (Py_BuildValue("i", rid)); +} + +static PyObject * +bus_unmap(PyObject *self, PyObject *args) +{ + int rid; + + if (!PyArg_ParseTuple(args, "i", &rid)) + return (NULL); + if (!bs_unmap(rid)) { + PyErr_SetString(PyExc_IOError, strerror(errno)); + return (NULL); + } + Py_RETURN_NONE; +} + +static PyObject * +bus_subregion(PyObject *self, PyObject *args) +{ + long ofs, sz; + int rid0, rid; + + if (!PyArg_ParseTuple(args, "ill", &rid0, &ofs, &sz)) + return (NULL); + rid = bs_subregion(rid0, ofs, sz); + if (rid == -1) { + PyErr_SetString(PyExc_IOError, strerror(errno)); + return (NULL); + } + return (Py_BuildValue("i", rid)); +} + +static PyMethodDef bus_space_methods[] = { + { "read_1", bus_read_1, METH_VARARGS, "Read a 1-byte data item." }, + { "read_2", bus_read_2, METH_VARARGS, "Read a 2-byte data item." }, + { "read_4", bus_read_4, METH_VARARGS, "Read a 4-byte data item." }, + + { "write_1", bus_write_1, METH_VARARGS, "Write a 1-byte data item." }, + { "write_2", bus_write_2, METH_VARARGS, "Write a 2-byte data item." }, + { "write_4", bus_write_4, METH_VARARGS, "Write a 4-byte data item." }, + + { "map", bus_map, METH_VARARGS, + "Return a resource ID for a device file created by proto(4)" }, + { "unmap", bus_unmap, METH_VARARGS, + "Free a resource ID" }, + { "subregion", bus_subregion, METH_VARARGS, + "Return a resource ID for a subregion of another resource ID" }, + + { NULL, NULL, 0, NULL } +}; + +PyMODINIT_FUNC +initbus_space(void) +{ + + Py_InitModule("bus_space", bus_space_methods); +} diff --git a/tools/bus_space/bus_space.c b/tools/bus_space/bus_space.c new file mode 100644 index 0000000000000..260222c46eb58 --- /dev/null +++ b/tools/bus_space/bus_space.c @@ -0,0 +1,263 @@ +/*- + * Copyright (c) 2014 Marcel Moolenaar + * 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 ``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/ioctl.h> +#include <sys/mman.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdlib.h> +#include <unistd.h> + +#include "bus_space.h" + +#include "../../sys/dev/proto/proto_dev.h" + +struct resource { + int rid; + int fd; + long addr; + long size; + off_t ofs; + caddr_t ptr; +}; + +static struct resource *ridtbl = NULL; +static int nrids = 0; + +static int +rid_alloc(void) +{ + void *newtbl; + int rid; + + for (rid = 0; rid < nrids; rid++) { + if (ridtbl[rid].fd == -1) + break; + } + if (rid == nrids) { + nrids++; + newtbl = realloc(ridtbl, sizeof(struct resource) * nrids); + if (newtbl == NULL) { + nrids--; + return (-1); + } else + ridtbl = newtbl; + } + ridtbl[rid].fd = INT_MAX; + return (rid); +} + +static struct resource * +rid_lookup(int rid) +{ + struct resource *r; + + if (rid < 0 || rid >= nrids) { + errno = EINVAL; + return (NULL); + } + r = ridtbl + rid; + if (r->fd == -1) { + errno = ENXIO; + return (NULL); + } + return (r); +} + +int +bs_map(const char *dev) +{ + struct proto_ioc_region region; + struct resource *r; + int rid; + + rid = rid_alloc(); + if (rid == -1) + return (-1); + r = rid_lookup(rid); + if (r == NULL) + return (-1); + r->fd = open(dev, O_RDWR); + if (r->fd == -1) + return (-1); + r->rid = -1; + if (ioctl(r->fd, PROTO_IOC_REGION, ®ion) == -1) { + close(r->fd); + r->fd = -1; + return (-1); + } + r->addr = region.address; + r->size = region.size; + r->ofs = 0; + r->ptr = mmap(NULL, r->size, PROT_READ | PROT_WRITE, + MAP_NOCORE | MAP_SHARED, r->fd, r->ofs); + return (rid); +} + +int +bs_read(int rid, off_t ofs, void *buf, ssize_t bufsz) +{ + struct resource *r; + volatile void *ptr; + off_t o; + ssize_t s; + + r = rid_lookup(rid); + if (r == NULL) + return (0); + if (ofs < 0 || ofs > r->size - bufsz) { + errno = ESPIPE; + return (0); + } + ofs += r->ofs; + if (r->ptr != MAP_FAILED) { + ptr = r->ptr + ofs; + switch (bufsz) { + case 1: + *((uint8_t *)buf) = *((volatile uint8_t *)ptr); + break; + case 2: + *((uint16_t *)buf) = *((volatile uint16_t *)ptr); + break; + case 4: + *((uint32_t *)buf) = *((volatile uint32_t *)ptr); + break; + default: + errno = EIO; + return (0); + } + } else { + o = lseek(r->fd, ofs, SEEK_SET); + if (o != ofs) + return (0); + s = read(r->fd, buf, bufsz); + if (s != bufsz) + return (0); + } + return (1); +} + +int +bs_subregion(int rid0, long ofs, long sz) +{ + struct resource *r; + void *ptr0; + long addr0, ofs0; + int fd0, rid; + + r = rid_lookup(rid0); + if (r == NULL) + return (-1); + if (ofs < 0 || sz < 1) { + errno = EINVAL; + return (-1); + } + if (ofs + sz > r->size) { + errno = ENOSPC; + return (-1); + } + fd0 = r->fd; + addr0 = r->addr; + ofs0 = r->ofs; + ptr0 = r->ptr; + rid = rid_alloc(); + if (rid == -1) + return (-1); + r = rid_lookup(rid); + if (r == NULL) + return (-1); + r->rid = rid0; + r->fd = fd0; + r->addr = addr0 + ofs; + r->size = sz; + r->ofs = ofs0 + ofs; + r->ptr = ptr0; + return (rid); +} + +int +bs_unmap(int rid) +{ + struct resource *r; + + r = rid_lookup(rid); + if (r == NULL) + return (0); + if (r->rid == -1) { + if (r->ptr != MAP_FAILED) + munmap(r->ptr, r->size); + close(r->fd); + } + r->fd = -1; + return (1); +} + +int +bs_write(int rid, off_t ofs, void *buf, ssize_t bufsz) +{ + struct resource *r; + volatile void *ptr; + off_t o; + ssize_t s; + + r = rid_lookup(rid); + if (r == NULL) + return (0); + if (ofs < 0 || ofs > r->size - bufsz) { + errno = ESPIPE; + return (0); + } + ofs += r->ofs; + if (r->ptr != MAP_FAILED) { + ptr = r->ptr + ofs; + switch (bufsz) { + case 1: + *((volatile uint8_t *)ptr) = *((uint8_t *)buf); + break; + case 2: + *((volatile uint16_t *)ptr) = *((uint16_t *)buf); + break; + case 4: + *((volatile uint32_t *)ptr) = *((uint32_t *)buf); + break; + default: + errno = EIO; + return (0); + } + } else { + o = lseek(r->fd, ofs, SEEK_SET); + if (o != ofs) + return (0); + s = write(r->fd, buf, bufsz); + if (s != bufsz) + return (0); + } + return (1); +} diff --git a/tools/bus_space/bus_space.h b/tools/bus_space/bus_space.h new file mode 100644 index 0000000000000..d34710641c660 --- /dev/null +++ b/tools/bus_space/bus_space.h @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2014 Marcel Moolenaar + * 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 ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _TOOLS_BUS_SPACE_H_ +#define _TOOLS_BUS_SPACE_H_ + +int bs_map(const char *dev); +int bs_read(int rid, off_t ofs, void *buf, ssize_t bufsz); +int bs_subregion(int rid0, long ofs, long sz); +int bs_unmap(int rid); +int bs_write(int rid, off_t ofs, void *buf, ssize_t bufsz); + +#endif /* _TOOLS_BUS_SPACE_H_ */ diff --git a/tools/kerneldoc/subsys/Doxyfile-dev_lindev b/tools/kerneldoc/subsys/Doxyfile-dev_lindev deleted file mode 100644 index 449a23fc9e77a..0000000000000 --- a/tools/kerneldoc/subsys/Doxyfile-dev_lindev +++ /dev/null @@ -1,21 +0,0 @@ -# Doxyfile 1.5.2 - -# $FreeBSD$ - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- -PROJECT_NAME = "FreeBSD kernel LINDEV device code" -OUTPUT_DIRECTORY = $(DOXYGEN_DEST_PATH)/dev_lindev/ -EXTRACT_ALL = YES # for undocumented src, no warnings enabled -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- -INPUT = $(DOXYGEN_SRC_PATH)/dev/lindev/ \ - $(NOTREVIEWED) - -GENERATE_TAGFILE = dev_lindev/dev_lindev.tag - -@INCLUDE_PATH = $(DOXYGEN_INCLUDE_PATH) -@INCLUDE = common-Doxyfile - diff --git a/tools/regression/priv/Makefile b/tools/regression/priv/Makefile index 9ed28a7f6cb23..a1fbcc668f57b 100644 --- a/tools/regression/priv/Makefile +++ b/tools/regression/priv/Makefile @@ -2,7 +2,7 @@ # $FreeBSD$ # -.include <bsd.own.mk> +.include <src.opts.mk> PROG= priv SRCS= main.c \ diff --git a/tools/tools/nanobsd/nanobsd.sh b/tools/tools/nanobsd/nanobsd.sh index 3f7fbe29ab58e..274132c274305 100644 --- a/tools/tools/nanobsd/nanobsd.sh +++ b/tools/tools/nanobsd/nanobsd.sh @@ -233,7 +233,7 @@ build_kernel ( ) ( ( if [ -f ${NANO_KERNEL} ] ; then - extra="KERNCONFDIR=$(realpath $(dirname ${NANO_KERNEL}))" + kernconfdir_arg="KERNCONFDIR='$(realpath $(dirname ${NANO_KERNEL}))'" kernconf=$(basename ${NANO_KERNEL}) else kernconf=${NANO_KERNEL} @@ -245,10 +245,10 @@ build_kernel ( ) ( unset TARGET_CPUTYPE # Note: We intentionally build all modules, not only the ones in # NANO_MODULES so the built world can be reused by multiple images. - env TARGET_ARCH=${NANO_ARCH} ${NANO_PMAKE} buildkernel \ - SRCCONF=${SRCCONF} \ - ${extra} __MAKE_CONF=${NANO_MAKE_CONF_BUILD} \ - KERNCONF=${kernconf} + eval "TARGET_ARCH=${NANO_ARCH} ${NANO_PMAKE} buildkernel \ + SRCCONF='${SRCCONF}' \ + __MAKE_CONF='${NANO_MAKE_CONF_BUILD}' \ + ${kernconfdir_arg} KERNCONF=${kernconf}" ) > ${MAKEOBJDIRPREFIX}/_.bk 2>&1 ) @@ -315,19 +315,19 @@ install_kernel ( ) ( ( if [ -f ${NANO_KERNEL} ] ; then - extra="KERNCONFDIR=$(realpath $(dirname ${NANO_KERNEL}))" + kernconfdir_arg="KERNCONFDIR='$(realpath $(dirname ${NANO_KERNEL}))'" kernconf=$(basename ${NANO_KERNEL}) else kernconf=${NANO_KERNEL} fi cd ${NANO_SRC} - env TARGET_ARCH=${NANO_ARCH} ${NANO_MAKE} installkernel \ - DESTDIR=${NANO_WORLDDIR} \ - SRCCONF=${SRCCONF} \ - ${extra} __MAKE_CONF=${NANO_MAKE_CONF_INSTALL} \ - KERNCONF=${kernconf} \ - MODULES_OVERRIDE="${NANO_MODULES}" + eval "TARGET_ARCH=${NANO_ARCH} ${NANO_MAKE} installkernel \ + DESTDIR='${NANO_WORLDDIR}' \ + SRCCONF='${SRCCONF}' \ + __MAKE_CONF='${NANO_MAKE_CONF_INSTALL}' \ + ${kernconfdir_arg} KERNCONF=${kernconf} \ + MODULES_OVERRIDE='${NANO_MODULES}'" ) > ${NANO_OBJ}/_.ik 2>&1 ) diff --git a/tools/tools/net80211/wlanwatch/Makefile b/tools/tools/net80211/wlanwatch/Makefile index 57f2332dd4e61..7cd0550071b40 100644 --- a/tools/tools/net80211/wlanwatch/Makefile +++ b/tools/tools/net80211/wlanwatch/Makefile @@ -4,7 +4,7 @@ PROG= wlanwatch BINDIR= /usr/local/bin MAN= -.include <bsd.own.mk> +.include <src.opts.mk> .if ${MK_INET6_SUPPORT} != "no" CFLAGS+= -DINET6 diff --git a/usr.bin/Makefile b/usr.bin/Makefile index ef9381b271071..6df995ae8afab 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -1,7 +1,7 @@ # From: @(#)Makefile 8.3 (Berkeley) 1/7/94 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> # XXX MISSING: deroff diction graph learn plot # spell spline struct xsend @@ -279,11 +279,7 @@ SUBDIR+= msgs .endif .if ${MK_MAKE} != "no" -.if ${MK_BMAKE} != "no" SUBDIR+= bmake -.else -SUBDIR+= make -.endif .endif .if ${MK_MAN_UTILS} != "no" diff --git a/usr.bin/apply/Makefile b/usr.bin/apply/Makefile index bf37b9cff8eb6..3ecf038f9282b 100644 --- a/usr.bin/apply/Makefile +++ b/usr.bin/apply/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= apply DPADD= ${LIBSBUF} diff --git a/usr.bin/ar/Makefile b/usr.bin/ar/Makefile index 03d9814c10182..157d4113309c0 100644 --- a/usr.bin/ar/Makefile +++ b/usr.bin/ar/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ar SRCS= ar.c acplex.l acpyacc.y read.c util.c write.c y.tab.h diff --git a/usr.bin/atf/atf-sh/Makefile b/usr.bin/atf/atf-sh/Makefile index de2e51e807f94..845521c80420b 100644 --- a/usr.bin/atf/atf-sh/Makefile +++ b/usr.bin/atf/atf-sh/Makefile @@ -25,6 +25,7 @@ # # $FreeBSD$ +.include <src.opts.mk> .include <bsd.init.mk> ATF= ${.CURDIR:H:H:H}/contrib/atf diff --git a/usr.bin/bmake/Makefile.inc b/usr.bin/bmake/Makefile.inc index 75678878da8ce..25f9a3a96b88a 100644 --- a/usr.bin/bmake/Makefile.inc +++ b/usr.bin/bmake/Makefile.inc @@ -1,21 +1,13 @@ # $FreeBSD$ -.include "bsd.own.mk" +.sinclude <src.opts.mk> .if defined(.PARSEDIR) # make sure this is available to unit-tests/Makefile .export SRCTOP .endif -# Sadly, we cannot assume bsd.own.mk did its job, -# nor can we safely include the one we want -.if !defined(WITHOUT_BMAKE) -MK_BMAKE= yes -.endif - -.if defined(MK_BMAKE) && ${MK_BMAKE} != "no" PROG= make -.endif .if !defined(MK_SHARED_TOOLCHAIN) || ${MK_SHARED_TOOLCHAIN} == "no" NO_SHARED?= YES diff --git a/usr.bin/calendar/Makefile b/usr.bin/calendar/Makefile index b347a52a0f3bb..32a107a322476 100644 --- a/usr.bin/calendar/Makefile +++ b/usr.bin/calendar/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= calendar SRCS= calendar.c locale.c events.c dates.c parsedata.c io.c day.c \ diff --git a/usr.bin/chkey/Makefile b/usr.bin/chkey/Makefile index 847e5c960106b..a9e00e8a3d91b 100644 --- a/usr.bin/chkey/Makefile +++ b/usr.bin/chkey/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../newkey diff --git a/usr.bin/chpass/Makefile b/usr.bin/chpass/Makefile index 566173e14d8d0..cf3acc6bee158 100644 --- a/usr.bin/chpass/Makefile +++ b/usr.bin/chpass/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.2 (Berkeley) 4/2/94 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../usr.sbin/pwd_mkdb ${.CURDIR}/../../lib/libc/gen diff --git a/usr.bin/clang/Makefile b/usr.bin/clang/Makefile index f3e29578ca116..9655b06c4c658 100644 --- a/usr.bin/clang/Makefile +++ b/usr.bin/clang/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= clang clang-tblgen tblgen diff --git a/usr.bin/clang/clang/Makefile b/usr.bin/clang/clang/Makefile index ac6e685311e3d..74ef867b441cf 100644 --- a/usr.bin/clang/clang/Makefile +++ b/usr.bin/clang/clang/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG_CXX=clang diff --git a/usr.bin/comm/Makefile b/usr.bin/comm/Makefile index 59c97514e3948..ca91343581885 100644 --- a/usr.bin/comm/Makefile +++ b/usr.bin/comm/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= comm diff --git a/usr.bin/cpio/Makefile b/usr.bin/cpio/Makefile index 635f4bce11ada..16446c4b4defe 100644 --- a/usr.bin/cpio/Makefile +++ b/usr.bin/cpio/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIBARCHIVEDIR= ${.CURDIR}/../../contrib/libarchive LIBARCHIVECONFDIR= ${.CURDIR}/../../lib/libarchive diff --git a/usr.bin/elfdump/elfdump.c b/usr.bin/elfdump/elfdump.c index 23d1487a6246a..c86e6fca0608b 100644 --- a/usr.bin/elfdump/elfdump.c +++ b/usr.bin/elfdump/elfdump.c @@ -368,7 +368,7 @@ static u_int64_t elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member); static u_int64_t elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member); static u_int64_t elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member); -static void elf_print_ehdr(Elf32_Ehdr *e); +static void elf_print_ehdr(Elf32_Ehdr *e, void *sh); static void elf_print_phdr(Elf32_Ehdr *e, void *p); static void elf_print_shdr(Elf32_Ehdr *e, void *sh); static void elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str); @@ -382,6 +382,33 @@ static void elf_print_note(Elf32_Ehdr *e, void *sh); static void usage(void); +/* + * Helpers for ELF files with shnum or shstrndx values that don't fit in the + * ELF header. If the values are too large then an escape value is used to + * indicate that the actual value is found in one of section 0's fields. + */ +static uint64_t +elf_get_shnum(Elf32_Ehdr *e, void *sh) +{ + uint64_t shnum; + + shnum = elf_get_quarter(e, e, E_SHNUM); + if (shnum == 0) + shnum = elf_get_word(e, (char *)sh, SH_SIZE); + return shnum; +} + +static uint64_t +elf_get_shstrndx(Elf32_Ehdr *e, void *sh) +{ + uint64_t shstrndx; + + shstrndx = elf_get_quarter(e, e, E_SHSTRNDX); + if (shstrndx == SHN_XINDEX) + shstrndx = elf_get_word(e, (char *)sh, SH_LINK); + return shstrndx; +} + int main(int ac, char **av) { @@ -467,10 +494,10 @@ main(int ac, char **av) phentsize = elf_get_quarter(e, e, E_PHENTSIZE); phnum = elf_get_quarter(e, e, E_PHNUM); shentsize = elf_get_quarter(e, e, E_SHENTSIZE); - shnum = elf_get_quarter(e, e, E_SHNUM); - shstrndx = elf_get_quarter(e, e, E_SHSTRNDX); p = (char *)e + phoff; sh = (char *)e + shoff; + shnum = elf_get_shnum(e, sh); + shstrndx = elf_get_shstrndx(e, sh); offset = elf_get_off(e, (char *)sh + shstrndx * shentsize, SH_OFFSET); shstrtab = (char *)e + offset; for (i = 0; (u_int64_t)i < shnum; i++) { @@ -482,7 +509,7 @@ main(int ac, char **av) dynstr = (char *)e + offset; } if (flags & ED_EHDR) - elf_print_ehdr(e); + elf_print_ehdr(e, sh); if (flags & ED_PHDR) elf_print_phdr(e, p); if (flags & ED_SHDR) @@ -556,7 +583,7 @@ main(int ac, char **av) } static void -elf_print_ehdr(Elf32_Ehdr *e) +elf_print_ehdr(Elf32_Ehdr *e, void *sh) { u_int64_t class; u_int64_t data; @@ -589,8 +616,8 @@ elf_print_ehdr(Elf32_Ehdr *e) phentsize = elf_get_quarter(e, e, E_PHENTSIZE); phnum = elf_get_quarter(e, e, E_PHNUM); shentsize = elf_get_quarter(e, e, E_SHENTSIZE); - shnum = elf_get_quarter(e, e, E_SHNUM); - shstrndx = elf_get_quarter(e, e, E_SHSTRNDX); + shnum = elf_get_shnum(e, sh); + shstrndx = elf_get_shstrndx(e, sh); fprintf(out, "\nelf header:\n"); fprintf(out, "\n"); fprintf(out, "\te_ident: %s %s %s\n", ei_classes[class], ei_data[data], @@ -671,7 +698,7 @@ elf_print_shdr(Elf32_Ehdr *e, void *sh) int i; shentsize = elf_get_quarter(e, e, E_SHENTSIZE); - shnum = elf_get_quarter(e, e, E_SHNUM); + shnum = elf_get_shnum(e, sh); fprintf(out, "\nsection header:\n"); for (i = 0; (u_int64_t)i < shnum; i++) { v = (char *)sh + i * shentsize; diff --git a/usr.bin/fetch/Makefile b/usr.bin/fetch/Makefile index 687f3eac73d11..ed56f2f40c516 100644 --- a/usr.bin/fetch/Makefile +++ b/usr.bin/fetch/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= fetch CSTD?= c99 diff --git a/usr.bin/file2c/Makefile b/usr.bin/file2c/Makefile index 4a80e58a91fc9..214d0336a015b 100644 --- a/usr.bin/file2c/Makefile +++ b/usr.bin/file2c/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= file2c diff --git a/usr.bin/ftp/Makefile b/usr.bin/ftp/Makefile index 55a36beecaa81..abdd6b7cdf742 100644 --- a/usr.bin/ftp/Makefile +++ b/usr.bin/ftp/Makefile @@ -2,7 +2,7 @@ # $NetBSD: Makefile,v 1.15 1997/10/18 15:31:20 lukem Exp $ # from: @(#)Makefile 8.2 (Berkeley) 4/3/94 -.include <bsd.own.mk> +.include <src.opts.mk> # Uncomment the following to provide defaults for gate-ftp operation # diff --git a/usr.bin/grep/Makefile b/usr.bin/grep/Makefile index abc2f447073f4..c0c24dc27c171 100644 --- a/usr.bin/grep/Makefile +++ b/usr.bin/grep/Makefile @@ -2,7 +2,7 @@ # $FreeBSD$ # $OpenBSD: Makefile,v 1.6 2003/06/25 15:00:04 millert Exp $ -.include <bsd.own.mk> +.include <src.opts.mk> .if ${MK_BSD_GREP} == "yes" PROG= grep diff --git a/usr.bin/gzip/Makefile b/usr.bin/gzip/Makefile index 6dcd62f8671a6..73724358a560b 100644 --- a/usr.bin/gzip/Makefile +++ b/usr.bin/gzip/Makefile @@ -1,7 +1,7 @@ # $NetBSD: Makefile,v 1.16 2011/06/21 13:25:45 joerg Exp $ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= gzip MAN= gzip.1 gzexe.1 zdiff.1 zforce.1 zmore.1 znew.1 diff --git a/usr.bin/id/Makefile b/usr.bin/id/Makefile index 7d78b50c7440e..d7e40493bfba1 100644 --- a/usr.bin/id/Makefile +++ b/usr.bin/id/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= id LINKS= ${BINDIR}/id ${BINDIR}/groups diff --git a/usr.bin/join/Makefile b/usr.bin/join/Makefile index 61634ee2ec095..c3f40e4be6b81 100644 --- a/usr.bin/join/Makefile +++ b/usr.bin/join/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ # @(#)Makefile 8.1 (Berkeley) 6/6/93 -.include <bsd.own.mk> +.include <src.opts.mk> PROG= join diff --git a/usr.bin/jot/Makefile b/usr.bin/jot/Makefile index ca646495316b6..206c89312f457 100644 --- a/usr.bin/jot/Makefile +++ b/usr.bin/jot/Makefile @@ -1,7 +1,7 @@ # From: @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= jot diff --git a/usr.bin/kdump/Makefile b/usr.bin/kdump/Makefile index 0e52763d37600..e91a8eaa210ec 100644 --- a/usr.bin/kdump/Makefile +++ b/usr.bin/kdump/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .if (${MACHINE_ARCH} == "amd64") SFX= 32 diff --git a/usr.bin/lastcomm/Makefile b/usr.bin/lastcomm/Makefile index 88253757b7f1a..54341caa69900 100644 --- a/usr.bin/lastcomm/Makefile +++ b/usr.bin/lastcomm/Makefile @@ -1,7 +1,7 @@ # From: @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= lastcomm SRCS= lastcomm.c readrec.c diff --git a/usr.bin/lex/lib/Makefile b/usr.bin/lex/lib/Makefile index d7e430f3e43f8..4c28593aada9f 100644 --- a/usr.bin/lex/lib/Makefile +++ b/usr.bin/lex/lib/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../../contrib/flex diff --git a/usr.bin/logger/Makefile b/usr.bin/logger/Makefile index 922192ce919f8..cbdd0b433b2bf 100644 --- a/usr.bin/logger/Makefile +++ b/usr.bin/logger/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= logger diff --git a/usr.bin/login/Makefile b/usr.bin/login/Makefile index bd34ed9c6269e..1ebc7602ad6d1 100644 --- a/usr.bin/login/Makefile +++ b/usr.bin/login/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 7/19/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= login SRCS= login.c login_fbtab.c diff --git a/usr.bin/m4/Makefile b/usr.bin/m4/Makefile index e6cf0b6b8c4c4..13b99c8d02694 100644 --- a/usr.bin/m4/Makefile +++ b/usr.bin/m4/Makefile @@ -4,7 +4,7 @@ # -DEXTENDED # if you want the paste & spaste macros. -.include <bsd.own.mk> +.include <src.opts.mk> PROG= m4 CFLAGS+=-DEXTENDED -I${.CURDIR} -I${.CURDIR}/lib diff --git a/usr.bin/make/Makefile b/usr.bin/make/Makefile index 9b8290c5b64a5..bd9d58dd3538f 100644 --- a/usr.bin/make/Makefile +++ b/usr.bin/make/Makefile @@ -2,7 +2,7 @@ # $Id: Makefile,v 1.6 1994/06/30 05:33:39 cgd Exp $ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= make CFLAGS+=-I${.CURDIR} @@ -111,12 +111,10 @@ CFLAGS+= -DDEFSHELLNAME=\"${MAKE_SHELL}\" .error "MAKE_SHELL must be set to one of \"csh\", \"sh\" or \"ksh\"." .endif -.if defined(MK_BMAKE) && ${MK_BMAKE} != "no" # if we are here we don't want this called 'make' PROG= fmake fmake.1: make.1 cp ${.ALLSRC} ${.TARGET} -.endif .if ${MK_TESTS} != "no" SUBDIR+= tests diff --git a/usr.bin/mkimg/apm.c b/usr.bin/mkimg/apm.c index f0660d25bef4b..36d6ab8d289ca 100644 --- a/usr.bin/mkimg/apm.c +++ b/usr.bin/mkimg/apm.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); static struct mkimg_alias apm_aliases[] = { { ALIAS_FREEBSD, ALIAS_PTR2TYPE(APM_ENT_TYPE_FREEBSD) }, + { ALIAS_FREEBSD_BOOT, ALIAS_PTR2TYPE(APM_ENT_TYPE_APPLE_BOOT) }, { ALIAS_FREEBSD_NANDFS, ALIAS_PTR2TYPE(APM_ENT_TYPE_FREEBSD_NANDFS) }, { ALIAS_FREEBSD_SWAP, ALIAS_PTR2TYPE(APM_ENT_TYPE_FREEBSD_SWAP) }, { ALIAS_FREEBSD_UFS, ALIAS_PTR2TYPE(APM_ENT_TYPE_FREEBSD_UFS) }, @@ -62,13 +63,12 @@ apm_metadata(u_int where) } static int -apm_write(int fd __unused, lba_t imgsz __unused, void *bootcode __unused) +apm_write(int fd, lba_t imgsz, void *bootcode __unused) { u_char *buf; struct apm_ddr *ddr; struct apm_ent *ent; struct part *part; - ssize_t nbytes; int error; buf = calloc(nparts + 2, secsz); @@ -99,12 +99,7 @@ apm_write(int fd __unused, lba_t imgsz __unused, void *bootcode __unused) strcpy(ent->ent_name, part->label); } - error = mkimg_seek(fd, 0); - if (error == 0) { - nbytes = (nparts + 2) * secsz; - if (write(fd, buf, nbytes) != nbytes) - error = errno; - } + error = mkimg_write(fd, 0, buf, nparts + 2); free(buf); return (error); } diff --git a/usr.bin/mkimg/bsd.c b/usr.bin/mkimg/bsd.c index 052e6c16de5e6..df9913076d940 100644 --- a/usr.bin/mkimg/bsd.c +++ b/usr.bin/mkimg/bsd.c @@ -111,11 +111,7 @@ bsd_write(int fd, lba_t imgsz, void *bootcode) checksum ^= le16dec(p); le16enc(&d->d_checksum, checksum); - error = mkimg_seek(fd, 0); - if (error == 0) { - if (write(fd, buf, BBSIZE) != BBSIZE) - error = errno; - } + error = mkimg_write(fd, 0, buf, BBSIZE / secsz); free(buf); return (error); } diff --git a/usr.bin/mkimg/ebr.c b/usr.bin/mkimg/ebr.c index 33aacc27741d0..372dbbd4c337b 100644 --- a/usr.bin/mkimg/ebr.c +++ b/usr.bin/mkimg/ebr.c @@ -104,11 +104,7 @@ ebr_write(int fd, lba_t imgsz __unused, void *bootcode __unused) le32enc(&dp->dp_size, next->size + nsecs); } - error = mkimg_seek(fd, block); - if (error == 0) { - if (write(fd, ebr, secsz) != (ssize_t)secsz) - error = errno; - } + error = mkimg_write(fd, block, ebr, 1); if (error) break; diff --git a/usr.bin/mkimg/gpt.c b/usr.bin/mkimg/gpt.c index 9657a555fafb7..5385228b6fb56 100644 --- a/usr.bin/mkimg/gpt.c +++ b/usr.bin/mkimg/gpt.c @@ -166,19 +166,6 @@ gpt_metadata(u_int where) } static int -gpt_filewrite(int fd, lba_t blk, void *buf, ssize_t bufsz) -{ - int error; - - error = mkimg_seek(fd, blk); - if (error == 0) { - if (write(fd, buf, bufsz) != bufsz) - error = errno; - } - return (error); -} - -static int gpt_write_pmbr(int fd, lba_t blks, void *bootcode) { u_char *pmbr; @@ -203,7 +190,7 @@ gpt_write_pmbr(int fd, lba_t blks, void *bootcode) le32enc(pmbr + DOSPARTOFF + 8, 1); le32enc(pmbr + DOSPARTOFF + 12, secs); le16enc(pmbr + DOSMAGICOFFSET, DOSMAGIC); - error = gpt_filewrite(fd, 0, pmbr, secsz); + error = mkimg_write(fd, 0, pmbr, 1); free(pmbr); return (error); } @@ -250,7 +237,7 @@ gpt_write_hdr(int fd, struct gpt_hdr *hdr, uint64_t self, uint64_t alt, hdr->hdr_crc_self = 0; crc = crc32(hdr, offsetof(struct gpt_hdr, padding)); le64enc(&hdr->hdr_crc_self, crc); - return (gpt_filewrite(fd, self, hdr, secsz)); + return (mkimg_write(fd, self, hdr, 1)); } static int @@ -273,10 +260,10 @@ gpt_write(int fd, lba_t imgsz, void *bootcode) tbl = gpt_mktbl(tblsz); if (tbl == NULL) return (errno); - error = gpt_filewrite(fd, 2, tbl, tblsz * secsz); + error = mkimg_write(fd, 2, tbl, tblsz); if (error) goto out; - error = gpt_filewrite(fd, imgsz - (tblsz + 1), tbl, tblsz * secsz); + error = mkimg_write(fd, imgsz - (tblsz + 1), tbl, tblsz); if (error) goto out; diff --git a/usr.bin/mkimg/mbr.c b/usr.bin/mkimg/mbr.c index ba8476c3b42b2..0f890576a6f98 100644 --- a/usr.bin/mkimg/mbr.c +++ b/usr.bin/mkimg/mbr.c @@ -96,11 +96,7 @@ mbr_write(int fd, lba_t imgsz __unused, void *bootcode) le32enc(&dp->dp_start, part->block); le32enc(&dp->dp_size, part->size); } - error = mkimg_seek(fd, 0); - if (error == 0) { - if (write(fd, mbr, secsz) != (ssize_t)secsz) - error = errno; - } + error = mkimg_write(fd, 0, mbr, 1); free(mbr); return (error); } diff --git a/usr.bin/mkimg/mkimg.c b/usr.bin/mkimg/mkimg.c index 79443426f2811..e767471e502b9 100644 --- a/usr.bin/mkimg/mkimg.c +++ b/usr.bin/mkimg/mkimg.c @@ -302,7 +302,7 @@ fdcopy(int src, int dst, uint64_t *count) return (errno); } -int +static int mkimg_seek(int fd, lba_t blk) { off_t off; @@ -313,6 +313,19 @@ mkimg_seek(int fd, lba_t blk) return (0); } +int +mkimg_write(int fd, lba_t blk, void *buf, ssize_t len) +{ + + blk *= secsz; + if (lseek(fd, blk, SEEK_SET) != blk) + return (errno); + len *= secsz; + if (write(fd, buf, len) != len) + return (errno); + return (0); +} + static void mkimg(int bfd) { diff --git a/usr.bin/mkimg/mkimg.h b/usr.bin/mkimg/mkimg.h index 7262bdb5451d1..3be345d7cd530 100644 --- a/usr.bin/mkimg/mkimg.h +++ b/usr.bin/mkimg/mkimg.h @@ -67,6 +67,6 @@ round_block(lba_t n) return ((n + b - 1) & ~(b - 1)); } -int mkimg_seek(int fd, lba_t blk); +int mkimg_write(int fd, lba_t blk, void *buf, ssize_t len); #endif /* _MKIMG_MKIMG_H_ */ diff --git a/usr.bin/mkimg/pc98.c b/usr.bin/mkimg/pc98.c index bce6c3cea6b01..7eb0a8e312652 100644 --- a/usr.bin/mkimg/pc98.c +++ b/usr.bin/mkimg/pc98.c @@ -106,11 +106,7 @@ pc98_write(int fd, lba_t imgsz __unused, void *bootcode) if (part->label != NULL) memcpy(dp->dp_name, part->label, strlen(part->label)); } - error = mkimg_seek(fd, 0); - if (error == 0) { - if (write(fd, buf, PC98_BOOTCODESZ) != PC98_BOOTCODESZ) - error = errno; - } + error = mkimg_write(fd, 0, buf, PC98_BOOTCODESZ / secsz); free(buf); return (error); } diff --git a/usr.bin/mkimg/vtoc8.c b/usr.bin/mkimg/vtoc8.c index e5385f6b7d16b..231f0a296ad38 100644 --- a/usr.bin/mkimg/vtoc8.c +++ b/usr.bin/mkimg/vtoc8.c @@ -103,11 +103,7 @@ vtoc8_write(int fd, lba_t imgsz, void *bootcode __unused) sum ^= be16dec(p + ofs); be16enc(&vtoc8.cksum, sum); - error = mkimg_seek(fd, 0); - if (error == 0) { - if (write(fd, &vtoc8, sizeof(vtoc8)) != sizeof(vtoc8)) - error = errno; - } + error = mkimg_write(fd, 0, &vtoc8, 1); return (error); } diff --git a/usr.bin/ncal/Makefile b/usr.bin/ncal/Makefile index 27aa5678ef30e..b26605fbac215 100644 --- a/usr.bin/ncal/Makefile +++ b/usr.bin/ncal/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ncal diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile index ff97074e553ae..2d50a495428b9 100644 --- a/usr.bin/netstat/Makefile +++ b/usr.bin/netstat/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/12/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= netstat SRCS= if.c inet.c main.c mbuf.c mroute.c netisr.c route.c \ diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c index 09b3110b5c700..9f8f1d2913f20 100644 --- a/usr.bin/netstat/inet.c +++ b/usr.bin/netstat/inet.c @@ -660,7 +660,8 @@ tcp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) p(tcps_rcvbadsum, "\t\t%ju discarded for bad checksum%s\n"); p(tcps_rcvbadoff, "\t\t%ju discarded for bad header offset field%s\n"); p1a(tcps_rcvshort, "\t\t%ju discarded because packet too short\n"); - p1a(tcps_rcvmemdrop, "\t\t%ju discarded due to memory problems\n"); + p1a(tcps_rcvreassfull, + "\t\t%ju discarded due to no space in reassembly queue\n"); p(tcps_connattempt, "\t%ju connection request%s\n"); p(tcps_accepts, "\t%ju connection accept%s\n"); p(tcps_badsyn, "\t%ju bad connection attempt%s\n"); diff --git a/usr.bin/netstat/mroute.c b/usr.bin/netstat/mroute.c index 376641503e3fb..3ec716dc20649 100644 --- a/usr.bin/netstat/mroute.c +++ b/usr.bin/netstat/mroute.c @@ -236,16 +236,7 @@ mroutepr() * functionality was deprecated, as PIM does not use it. */ maxvif = 0; - - kresolve_list(mrl); - pmfchashtbl = mrl[N_MFCHASHTBL].n_value; - pmfctablesize = mrl[N_MFCTABLESIZE].n_value; - pviftbl = mrl[N_VIFTABLE].n_value; - - if (pmfchashtbl == 0 || pmfctablesize == 0 || pviftbl == 0) { - fprintf(stderr, "No IPv4 MROUTING kernel support.\n"); - return; - } + pmfchashtbl = pmfctablesize = pviftbl = 0; len = sizeof(viftable); if (live) { @@ -254,8 +245,19 @@ mroutepr() warn("sysctl: net.inet.ip.viftable"); return; } - } else + } else { + kresolve_list(mrl); + pmfchashtbl = mrl[N_MFCHASHTBL].n_value; + pmfctablesize = mrl[N_MFCTABLESIZE].n_value; + pviftbl = mrl[N_VIFTABLE].n_value; + + if (pmfchashtbl == 0 || pmfctablesize == 0 || pviftbl == 0) { + fprintf(stderr, "No IPv4 MROUTING kernel support.\n"); + return; + } + kread(pviftbl, (char *)viftable, sizeof(viftable)); + } banner_printed = 0; for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) { diff --git a/usr.bin/newkey/Makefile b/usr.bin/newkey/Makefile index b3b5b51d8c9fe..bf4651352eed0 100644 --- a/usr.bin/newkey/Makefile +++ b/usr.bin/newkey/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= newkey SRCS= newkey.c generic.c update.c diff --git a/usr.bin/nl/nl.1 b/usr.bin/nl/nl.1 index 554e18d241d0a..cb67c046a118c 100644 --- a/usr.bin/nl/nl.1 +++ b/usr.bin/nl/nl.1 @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd January 26, 2005 +.Dd May 4, 2014 .Dt NL 1 .Os .Sh NAME @@ -71,12 +71,16 @@ The .Nm utility reads lines from the named +.Ar file , +applies a configurable line numbering filter operation, +and writes the result to the standard output. +If .Ar file -or the standard input if the -.Ar file -argument is omitted, -applies a configurable line numbering filter operation and writes the result -to the standard output. +is a single dash +.Pq Sq Fl +or absent, +.Nm +reads from the standard input. .Pp The .Nm diff --git a/usr.bin/nl/nl.c b/usr.bin/nl/nl.c index 9c2ae64ac9136..1770b7808be81 100644 --- a/usr.bin/nl/nl.c +++ b/usr.bin/nl/nl.c @@ -242,7 +242,8 @@ main(int argc, char *argv[]) case 0: break; case 1: - if (freopen(argv[0], "r", stdin) == NULL) + if (strcmp(argv[0], "-") != 0 && + freopen(argv[0], "r", stdin) == NULL) err(EXIT_FAILURE, "%s", argv[0]); break; default: diff --git a/usr.bin/passwd/Makefile b/usr.bin/passwd/Makefile index d657c804a5494..3e6dc9393950d 100644 --- a/usr.bin/passwd/Makefile +++ b/usr.bin/passwd/Makefile @@ -1,7 +1,7 @@ # From: @(#)Makefile 8.3 (Berkeley) 4/2/94 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG = passwd BINOWN = root diff --git a/usr.bin/printf/Makefile b/usr.bin/printf/Makefile index 31047c53f931b..759bcf75e982f 100644 --- a/usr.bin/printf/Makefile +++ b/usr.bin/printf/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= printf diff --git a/usr.bin/printf/printf.c b/usr.bin/printf/printf.c index 7ed0c215f5d4a..ac122f78c1d9d 100644 --- a/usr.bin/printf/printf.c +++ b/usr.bin/printf/printf.c @@ -1,4 +1,5 @@ /*- + * Copyright 2014 Garrett D'Amore <garrett@damore.org> * Copyright 2010 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -50,6 +51,7 @@ static const char rcsid[] = #include <sys/types.h> +#include <ctype.h> #include <err.h> #include <errno.h> #include <inttypes.h> @@ -70,11 +72,6 @@ static const char rcsid[] = #define PF(f, func) do { \ char *b = NULL; \ - int dollar = 0; \ - if (*f == '$') { \ - dollar++; \ - *f = '%'; \ - } \ if (havewidth) \ if (haveprec) \ (void)asprintf(&b, f, fieldwidth, precision, func); \ @@ -88,8 +85,6 @@ static const char rcsid[] = (void)fputs(b, stdout); \ free(b); \ } \ - if (dollar) \ - *f = '$'; \ } while (0) static int asciicode(void); @@ -104,15 +99,18 @@ static const char static char *mknum(char *, char); static void usage(void); +static const char digits[] = "0123456789"; + static int myargc; static char **myargv; static char **gargv; +static char **maxargv; int main(int argc, char *argv[]) { size_t len; - int chopped, end, rval; + int end, rval; char *format, *fmt, *start; #ifndef SHELL int ch; @@ -153,12 +151,12 @@ main(int argc, char *argv[]) * up the format string. */ fmt = format = *argv; - chopped = escape(fmt, 1, &len); /* backslash interpretation */ + escape(fmt, 1, &len); /* backslash interpretation */ rval = end = 0; gargv = ++argv; for (;;) { - char **maxargv = gargv; + maxargv = gargv; myargv = gargv; for (myargc = 0; gargv[myargc]; myargc++) @@ -197,7 +195,7 @@ main(int argc, char *argv[]) return (1); } fwrite(start, 1, fmt - start, stdout); - if (chopped || !*gargv) { + if (!*gargv) { #ifdef SHELL INTON; #endif @@ -212,57 +210,115 @@ main(int argc, char *argv[]) static char * -printf_doformat(char *start, int *rval) +printf_doformat(char *fmt, int *rval) { static const char skip1[] = "#'-+ 0"; - static const char skip2[] = "0123456789"; - char *fmt; int fieldwidth, haveprec, havewidth, mod_ldbl, precision; char convch, nextch; + char *start; + char **fargv; + char *dptr; + int l; + + start = alloca(strlen(fmt) + 1); + + dptr = start; + *dptr++ = '%'; + *dptr = 0; - fmt = start + 1; + fmt++; /* look for "n$" field index specifier */ - fmt += strspn(fmt, skip2); - if ((*fmt == '$') && (fmt != (start + 1))) { - int idx = atoi(start + 1); + l = strspn(fmt, digits); + if ((l > 0) && (fmt[l] == '$')) { + int idx = atoi(fmt); if (idx <= myargc) { gargv = &myargv[idx - 1]; } else { gargv = &myargv[myargc]; } - start = fmt; - fmt++; + if (gargv > maxargv) + maxargv = gargv; + fmt += l + 1; + + /* save format argument */ + fargv = gargv; } else { - fmt = start + 1; + fargv = NULL; } /* skip to field width */ - fmt += strspn(fmt, skip1); + while (strchr(skip1, *fmt) != NULL) { + *dptr++ = *fmt++; + *dptr = 0; + } + if (*fmt == '*') { + + fmt++; + l = strspn(fmt, digits); + if ((l > 0) && (fmt[l] == '$')) { + int idx = atoi(fmt); + if (idx <= myargc) { + gargv = &myargv[idx - 1]; + } else { + gargv = &myargv[myargc]; + } + fmt += l + 1; + } + if (getint(&fieldwidth)) return (NULL); + if (gargv > maxargv) + maxargv = gargv; havewidth = 1; - ++fmt; + + *dptr++ = '*'; + *dptr = 0; } else { havewidth = 0; /* skip to possible '.', get following precision */ - fmt += strspn(fmt, skip2); + while (isdigit(*fmt)) { + *dptr++ = *fmt++; + *dptr = 0; + } } + if (*fmt == '.') { /* precision present? */ - ++fmt; + fmt++; + *dptr++ = '.'; + if (*fmt == '*') { + + fmt++; + l = strspn(fmt, digits); + if ((l > 0) && (fmt[l] == '$')) { + int idx = atoi(fmt); + if (idx <= myargc) { + gargv = &myargv[idx - 1]; + } else { + gargv = &myargv[myargc]; + } + fmt += l + 1; + } + if (getint(&precision)) return (NULL); + if (gargv > maxargv) + maxargv = gargv; haveprec = 1; - ++fmt; + *dptr++ = '*'; + *dptr = 0; } else { haveprec = 0; /* skip to conversion char */ - fmt += strspn(fmt, skip2); + while (isdigit(*fmt)) { + *dptr++ = *fmt++; + *dptr = 0; + } } } else haveprec = 0; @@ -270,6 +326,8 @@ printf_doformat(char *start, int *rval) warnx("missing format character"); return (NULL); } + *dptr++ = *fmt; + *dptr = 0; /* * Look for a length modifier. POSIX doesn't have these, so @@ -292,8 +350,14 @@ printf_doformat(char *start, int *rval) mod_ldbl = 0; } + /* save the current arg offset, and set to the format arg */ + if (fargv != NULL) { + gargv = fargv; + } + convch = *fmt; nextch = *++fmt; + *fmt = '\0'; switch (convch) { case 'b': { @@ -307,12 +371,10 @@ printf_doformat(char *start, int *rval) return (NULL); } getout = escape(p, 0, &len); - *(fmt - 1) = 's'; - PF(start, p); - *(fmt - 1) = 'b'; + fputs(p, stdout); free(p); if (getout) - return (fmt); + exit(*rval); break; } case 'c': { @@ -365,6 +427,7 @@ printf_doformat(char *start, int *rval) return (NULL); } *fmt = nextch; + /* return the gargv to the next element */ return (fmt); } @@ -423,9 +486,13 @@ escape(char *fmt, int percent, size_t *len) *store = '\b'; break; case 'c': - *store = '\0'; - *len = store - save; - return (1); + if (!percent) { + *store = '\0'; + *len = store - save; + return (1); + } + *store = 'c'; + break; case 'f': /* form-feed */ *store = '\f'; break; @@ -508,7 +575,7 @@ getnum(intmax_t *ip, uintmax_t *uip, int signedconv) int rval; if (!*gargv) { - *ip = *uip = 0; + *ip = 0; return (0); } if (**gargv == '"' || **gargv == '\'') { diff --git a/usr.bin/sed/Makefile b/usr.bin/sed/Makefile index b635c89ad5764..a741da3233e62 100644 --- a/usr.bin/sed/Makefile +++ b/usr.bin/sed/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= sed SRCS= compile.c main.c misc.c process.c diff --git a/usr.bin/sort/Makefile b/usr.bin/sort/Makefile index 3b257c2236a75..c6eef85610101 100644 --- a/usr.bin/sort/Makefile +++ b/usr.bin/sort/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= sort diff --git a/usr.bin/ssh-copy-id/ssh-copy-id.sh b/usr.bin/ssh-copy-id/ssh-copy-id.sh index e16cfaa8456af..09fb3cca6ed98 100755 --- a/usr.bin/ssh-copy-id/ssh-copy-id.sh +++ b/usr.bin/ssh-copy-id/ssh-copy-id.sh @@ -45,7 +45,7 @@ sendkey() { if ! grep -sqwF "$key" "$keyfile"; then \ printf "$alg $key $comment\n" >> "$keyfile" ; \ fi ; \ - done \ + done ; \ if [ -x /sbin/restorecon ]; then \ /sbin/restorecon -F "$HOME/.ssh/" "$keyfile" >/dev/null 2>&1 || true ; \ fi diff --git a/usr.bin/stat/stat.1 b/usr.bin/stat/stat.1 index 7d591b88a03a5..eb8894ca8cda0 100644 --- a/usr.bin/stat/stat.1 +++ b/usr.bin/stat/stat.1 @@ -38,7 +38,7 @@ .Nd display file status .Sh SYNOPSIS .Nm -.Op Fl FLnq +.Op Fl FHLnq .Op Fl f Ar format | Fl l | r | s | x .Op Fl t Ar timefmt .Op Ar @@ -124,6 +124,12 @@ The use of .Fl F implies .Fl l . +.It Fl H +Treat each argument as the hexadecimal representation of an NFS file handle, +and use +.Xr fhstat 2 +instead of +.Xr lstat 2 . .It Fl L Use .Xr stat 2 diff --git a/usr.bin/stat/stat.c b/usr.bin/stat/stat.c index 984ec7b493b85..7b43882c606e0 100644 --- a/usr.bin/stat/stat.c +++ b/usr.bin/stat/stat.c @@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/types.h> #include <sys/stat.h> +#include <sys/mount.h> #include <ctype.h> #include <err.h> @@ -203,15 +204,17 @@ main(int argc, char *argv[]) { struct stat st; int ch, rc, errs, am_readlink; - int lsF, fmtchar, usestat, fn, nonl, quiet; + int lsF, fmtchar, usestat, nfs_handle, fn, nonl, quiet; const char *statfmt, *options, *synopsis; char dname[sizeof _PATH_DEV + SPECNAMELEN] = _PATH_DEV; + fhandle_t fhnd; const char *file; am_readlink = 0; lsF = 0; fmtchar = '\0'; usestat = 0; + nfs_handle = 0; nonl = 0; quiet = 0; linkfail = 0; @@ -226,9 +229,9 @@ main(int argc, char *argv[]) fmtchar = 'f'; quiet = 1; } else { - options = "f:FlLnqrst:x"; + options = "f:FHlLnqrst:x"; synopsis = "[-FLnq] [-f format | -l | -r | -s | -x] " - "[-t timefmt] [file ...]"; + "[-t timefmt] [file|handle ...]"; } while ((ch = getopt(argc, argv, options)) != -1) @@ -236,6 +239,9 @@ main(int argc, char *argv[]) case 'F': lsF = 1; break; + case 'H': + nfs_handle = 1; + break; case 'L': usestat = 1; break; @@ -320,8 +326,35 @@ main(int argc, char *argv[]) file = "(stdin)"; rc = fstat(STDIN_FILENO, &st); } else { + int j; + char *inval; + file = argv[0]; - if (usestat) { + if (nfs_handle) { + rc = 0; + bzero (&fhnd, sizeof fhnd); + j = MIN(2 * sizeof fhnd, strlen(file)); + if (j & 1) { + rc = -1; + } else { + while (j) { + ((char*) &fhnd)[j / 2 - 1] = + strtol(&file[j - 2], + &inval, 16); + if (inval != NULL) { + rc = -1; + break; + } + argv[0][j - 2] = '\0'; + j -= 2; + } + if (!rc) + rc = fhstat(&fhnd, &st); + else + errno = EINVAL; + } + + } else if (usestat) { /* * Try stat() and if it fails, fall back to * lstat() just in case we're examining a diff --git a/usr.bin/su/Makefile b/usr.bin/su/Makefile index 0002e869c4711..d5eb805e3f6e1 100644 --- a/usr.bin/su/Makefile +++ b/usr.bin/su/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 7/19/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= su diff --git a/usr.bin/svn/Makefile.inc b/usr.bin/svn/Makefile.inc index fb50b227567c7..203b8175bd947 100644 --- a/usr.bin/svn/Makefile.inc +++ b/usr.bin/svn/Makefile.inc @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .if ${MK_SVN} == "yes" SVNLITE?= diff --git a/usr.bin/svn/lib/libapr_util/Makefile b/usr.bin/svn/lib/libapr_util/Makefile index 4f25e8f5bfacc..df2d1f9a21043 100644 --- a/usr.bin/svn/lib/libapr_util/Makefile +++ b/usr.bin/svn/lib/libapr_util/Makefile @@ -28,7 +28,7 @@ CFLAGS+= -DHAVE_CONFIG_H \ -I${APR}/include/arch/unix \ -I${APR}/include -.include <bsd.own.mk> +.include <src.opts.mk> .if ${MK_ICONV} == "yes" CFLAGS+= -DHAVE_ICONV_H=1 -DAPU_HAVE_ICONV=1 diff --git a/usr.bin/systat/Makefile b/usr.bin/systat/Makefile index 5773c36adf2d1..8d024ffca9ccd 100644 --- a/usr.bin/systat/Makefile +++ b/usr.bin/systat/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= systat SRCS= cmds.c cmdtab.c devs.c fetch.c iostat.c keyboard.c main.c \ diff --git a/usr.bin/tar/Makefile b/usr.bin/tar/Makefile index d1f400bfa0756..a289ea49a7ce3 100644 --- a/usr.bin/tar/Makefile +++ b/usr.bin/tar/Makefile @@ -1,5 +1,5 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> LIBARCHIVEDIR= ${.CURDIR}/../../contrib/libarchive diff --git a/usr.bin/telnet/Makefile b/usr.bin/telnet/Makefile index 0ef55c50e2961..d47bb91c4eb7b 100644 --- a/usr.bin/telnet/Makefile +++ b/usr.bin/telnet/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> TELNETDIR= ${.CURDIR}/../../contrib/telnet .PATH: ${TELNETDIR}/telnet diff --git a/usr.bin/top/Makefile b/usr.bin/top/Makefile index 977b3c3b71b60..0f8d980701402 100644 --- a/usr.bin/top/Makefile +++ b/usr.bin/top/Makefile @@ -21,8 +21,8 @@ WARNS?= 0 CFLAGS+= -D"Table_size=${TOP_TABLE_SIZE}" .endif -DPADD= ${LIBTERMCAP} ${LIBM} ${LIBKVM} -LDADD= -ltermcap -lm -lkvm +DPADD= ${LIBTERMCAP} ${LIBM} ${LIBKVM} ${LIBJAIL} +LDADD= -ltermcap -lm -lkvm -ljail CLEANFILES= sigdesc.h SIGCONV_AWK= ${.CURDIR}/../../contrib/top/sigconv.awk diff --git a/usr.bin/top/machine.c b/usr.bin/top/machine.c index 190ea26f3b2a4..cf4714c7025a7 100644 --- a/usr.bin/top/machine.c +++ b/usr.bin/top/machine.c @@ -67,6 +67,9 @@ static int namelength = TOP_USERNAME_LEN; #else static int namelength = 8; #endif +/* TOP_JID_LEN based on max of 999999 */ +#define TOP_JID_LEN 7 +static int jidlength; static int cmdlengthdelta; /* Prototypes for top internals */ @@ -101,26 +104,26 @@ struct handle { */ static char io_header[] = - " PID%s %-*.*s VCSW IVCSW READ WRITE FAULT TOTAL PERCENT COMMAND"; + " PID%*s %-*.*s VCSW IVCSW READ WRITE FAULT TOTAL PERCENT COMMAND"; #define io_Proc_format \ - "%5d%s %-*.*s %6ld %6ld %6ld %6ld %6ld %6ld %6.2f%% %.*s" + "%5d%*s %-*.*s %6ld %6ld %6ld %6ld %6ld %6ld %6.2f%% %.*s" static char smp_header_thr[] = - " PID%s %-*.*s THR PRI NICE SIZE RES STATE C TIME %7s COMMAND"; + " PID%*s %-*.*s THR PRI NICE SIZE RES STATE C TIME %7s COMMAND"; static char smp_header[] = - " PID%s %-*.*s " "PRI NICE SIZE RES STATE C TIME %7s COMMAND"; + " PID%*s %-*.*s " "PRI NICE SIZE RES STATE C TIME %7s COMMAND"; #define smp_Proc_format \ - "%5d%s %-*.*s %s%3d %4s%7s %6s %-6.6s %2d%7s %6.2f%% %.*s" + "%5d%*s %-*.*s %s%3d %4s%7s %6s %-6.6s %2d%7s %6.2f%% %.*s" static char up_header_thr[] = - " PID%s %-*.*s THR PRI NICE SIZE RES STATE TIME %7s COMMAND"; + " PID%*s %-*.*s THR PRI NICE SIZE RES STATE TIME %7s COMMAND"; static char up_header[] = - " PID%s %-*.*s " "PRI NICE SIZE RES STATE TIME %7s COMMAND"; + " PID%*s %-*.*s " "PRI NICE SIZE RES STATE TIME %7s COMMAND"; #define up_Proc_format \ - "%5d%s %-*.*s %s%3d %4s%7s %6s %-6.6s%.0d%7s %6.2f%% %.*s" + "%5d%*s %-*.*s %s%3d %4s%7s %6s %-6.6s%.0d%7s %6.2f%% %.*s" /* process state names for the "STATE" column of the display */ @@ -393,6 +396,11 @@ format_header(char *uname_field) { static char Header[128]; const char *prehead; + + if (ps.jail) + jidlength = TOP_JID_LEN + 1; /* +1 for extra left space. */ + else + jidlength = 0; switch (displaymode) { case DISP_CPU: @@ -406,14 +414,14 @@ format_header(char *uname_field) (ps.thread ? smp_header : smp_header_thr) : (ps.thread ? up_header : up_header_thr); snprintf(Header, sizeof(Header), prehead, - ps.jail ? " JID" : "", + jidlength, ps.jail ? " JID" : "", namelength, namelength, uname_field, ps.wcpu ? "WCPU" : "CPU"); break; case DISP_IO: prehead = io_header; snprintf(Header, sizeof(Header), prehead, - ps.jail ? " JID" : "", + jidlength, ps.jail ? " JID" : "", namelength, namelength, uname_field); break; } @@ -668,6 +676,7 @@ get_process_info(struct system_info *si, struct process_select *sel, /* these are copied out of sel for speed */ int show_idle; + int show_jid; int show_self; int show_system; int show_uid; @@ -710,6 +719,7 @@ get_process_info(struct system_info *si, struct process_select *sel, /* set up flags which define what we are going to select */ show_idle = sel->idle; + show_jid = sel->jid != -1; show_self = sel->self == -1; show_system = sel->system; show_uid = sel->uid != -1; @@ -764,6 +774,10 @@ get_process_info(struct system_info *si, struct process_select *sel, /* skip processes that aren't doing I/O */ continue; + if (show_jid && pp->ki_jid != sel->jid) + /* skip proc. that don't belong to the selected JID */ + continue; + if (show_uid && pp->ki_ruid != (uid_t)sel->uid) /* skip proc. that don't belong to the selected UID */ continue; @@ -800,7 +814,7 @@ format_next_process(caddr_t handle, char *(*get_userid)(int), int flags) int cpu, state; struct rusage ru, *rup; long p_tot, s_tot; - char *proc_fmt, thr_buf[6], jid_buf[6]; + char *proc_fmt, thr_buf[6], jid_buf[TOP_JID_LEN + 1]; char *cmdbuf = NULL; char **args; const int cmdlen = 128; @@ -956,8 +970,8 @@ format_next_process(caddr_t handle, char *(*get_userid)(int), int flags) if (ps.jail == 0) jid_buf[0] = '\0'; else - snprintf(jid_buf, sizeof(jid_buf), " %*d", - sizeof(jid_buf) - 3, pp->ki_jid); + snprintf(jid_buf, sizeof(jid_buf), "%*d", + jidlength - 1, pp->ki_jid); if (displaymode == DISP_IO) { oldp = get_old_proc(pp); @@ -978,7 +992,7 @@ format_next_process(caddr_t handle, char *(*get_userid)(int), int flags) snprintf(fmt, sizeof(fmt), io_Proc_format, pp->ki_pid, - jid_buf, + jidlength, jid_buf, namelength, namelength, (*get_userid)(pp->ki_ruid), rup->ru_nvcsw, rup->ru_nivcsw, @@ -1013,7 +1027,7 @@ format_next_process(caddr_t handle, char *(*get_userid)(int), int flags) snprintf(fmt, sizeof(fmt), proc_fmt, pp->ki_pid, - jid_buf, + jidlength, jid_buf, namelength, namelength, (*get_userid)(pp->ki_ruid), thr_buf, pp->ki_pri.pri_level - PZERO, diff --git a/usr.bin/tr/Makefile b/usr.bin/tr/Makefile index 7c65daeb8dba1..393b446614fde 100644 --- a/usr.bin/tr/Makefile +++ b/usr.bin/tr/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= tr SRCS= cmap.c cset.c str.c tr.c diff --git a/usr.bin/uudecode/Makefile b/usr.bin/uudecode/Makefile index 7f3dde00e1967..7063d6f719a4c 100644 --- a/usr.bin/uudecode/Makefile +++ b/usr.bin/uudecode/Makefile @@ -1,12 +1,11 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -MAN= - -.include <bsd.own.mk> +.include <src.opts.mk> PROG= uudecode LINKS= ${BINDIR}/uudecode ${BINDIR}/b64decode +MAN= .if ${MK_TESTS} != "no" SUBDIR+= tests diff --git a/usr.bin/uuencode/Makefile b/usr.bin/uuencode/Makefile index 9c5e7291d367d..eb2152f8bd8f8 100644 --- a/usr.bin/uuencode/Makefile +++ b/usr.bin/uuencode/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= uuencode MAN= uuencode.1 uuencode.format.5 diff --git a/usr.bin/vi/Makefile b/usr.bin/vi/Makefile index 445d79fba2f76..16675c9f73d2b 100644 --- a/usr.bin/vi/Makefile +++ b/usr.bin/vi/Makefile @@ -2,7 +2,7 @@ # $FreeBSD$ # -.include <bsd.own.mk> +.include <src.opts.mk> SRCDIR= ${.CURDIR}/../../contrib/nvi SUBDIR+= catalog diff --git a/usr.bin/xargs/Makefile b/usr.bin/xargs/Makefile index b627bf5e73b43..034a0a6de3535 100644 --- a/usr.bin/xargs/Makefile +++ b/usr.bin/xargs/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= xargs SRCS= xargs.c strnsubst.c diff --git a/usr.bin/yacc/Makefile b/usr.bin/yacc/Makefile index 03f0d01225e6f..45e7929db00b9 100644 --- a/usr.bin/yacc/Makefile +++ b/usr.bin/yacc/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 5.3 (Berkeley) 5/12/90 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> BYACC_SRC= ${.CURDIR}/../../contrib/byacc .PATH: ${BYACC_SRC} diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index b06dba709b35c..fa0c9951440d3 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -1,7 +1,7 @@ # From: @(#)Makefile 5.20 (Berkeley) 6/12/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SUBDIR= adduser \ arp \ diff --git a/usr.sbin/amd/Makefile.inc b/usr.sbin/amd/Makefile.inc index cc616f1592f8f..e4425f52a2c5e 100644 --- a/usr.sbin/amd/Makefile.inc +++ b/usr.sbin/amd/Makefile.inc @@ -9,7 +9,7 @@ # Portions derived from amd/libamu/Makefile # $NetBSD: Makefile,v 1.8 1998/08/08 22:33:37 christos Exp $ -.include <bsd.own.mk> +.include <src.opts.mk> CFLAGS+= -I. -I${.CURDIR} CFLAGS+= -I${.CURDIR}/../include diff --git a/usr.sbin/amd/amd/Makefile b/usr.sbin/amd/amd/Makefile index c7200037f6287..1fc41bfe20d0f 100644 --- a/usr.sbin/amd/amd/Makefile +++ b/usr.sbin/amd/amd/Makefile @@ -6,7 +6,7 @@ # $FreeBSD$ # -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../../contrib/amd/amd diff --git a/usr.sbin/amd/include/Makefile b/usr.sbin/amd/include/Makefile index df770d1caf816..e594d71a4fb37 100644 --- a/usr.sbin/amd/include/Makefile +++ b/usr.sbin/amd/include/Makefile @@ -7,7 +7,7 @@ # Portions derived from amd/libamu/Makefile # $NetBSD: Makefile,v 1.8 1998/08/08 22:33:37 christos Exp $ -.include <bsd.own.mk> +.include <src.opts.mk> SRCS= config_local.h .if ${MK_NIS} == "no" diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8 index 88e72142b2ca5..aa97a670997dd 100644 --- a/usr.sbin/bhyve/bhyve.8 +++ b/usr.sbin/bhyve/bhyve.8 @@ -35,7 +35,7 @@ .Op Fl aehwxAHPW .Op Fl c Ar numcpus .Op Fl g Ar gdbport -.Op Fl p Ar pinnedcpu +.Op Fl p Ar vcpu:hostcpu .Op Fl s Ar slot,emulation Ns Op , Ns Ar conf .Op Fl l Ar lpcdev Ns Op , Ns Ar conf .Ar vmname @@ -80,12 +80,11 @@ For allow a remote kernel kgdb to be relayed to the guest kernel gdb stub via a local IPv4 address and this port. This option will be deprecated in a future version. -.It Fl p Ar pinnedcpu -Force guest virtual CPUs to be pinned to host CPUs. -Virtual CPU -.Em n -is pinned to host CPU -.Em pinnedcpu+n . +.It Fl p Ar vcpu:hostcpu +Pin guest's virtual CPU +.Em vcpu +to +.Em hostcpu . .It Fl P Force the guest virtual CPU to exit when a PAUSE instruction is detected. .It Fl W @@ -236,6 +235,8 @@ This is intended for debug purposes. Ignore accesses to unimplemented Model Specific Registers (MSRs). This is intended for debug purposes. .It Fl x The guest's local APIC is configured in x2APIC mode. +.It Fl Y +Disable MPtable generation. .It Fl h Print help message and exit. .It Ar vmname diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c index e8010e6fbfa8d..e662ca39d9c4b 100644 --- a/usr.sbin/bhyve/bhyverun.c +++ b/usr.sbin/bhyve/bhyverun.c @@ -85,7 +85,6 @@ char *vmname; int guest_ncpus; char *guest_uuid_str; -static int pincpu = -1; static int guest_vmexit_on_hlt, guest_vmexit_on_pause; static int virtio_msix = 1; static int x2apic_mode = 0; /* default is xAPIC */ @@ -114,6 +113,7 @@ struct bhyvestats { uint64_t cpu_switch_rotate; uint64_t cpu_switch_direct; int io_reset; + int io_poweroff; } stats; struct mt_vmm_info { @@ -122,18 +122,20 @@ struct mt_vmm_info { int mt_vcpu; } mt_vmm_info[VM_MAXCPU]; +static cpuset_t *vcpumap[VM_MAXCPU] = { NULL }; + static void usage(int code) { fprintf(stderr, - "Usage: %s [-aehwAHIPW] [-g <gdb port>] [-s <pci>]\n" - " %*s [-c vcpus] [-p pincpu] [-m mem] [-l <lpc>] <vm>\n" + "Usage: %s [-aehwAHIPW] [-g <gdb port>] [-s <pci>] [-c vcpus]\n" + " %*s [-p vcpu:hostcpu] [-m mem] [-l <lpc>] <vm>\n" " -a: local apic is in xAPIC mode (deprecated)\n" " -A: create an ACPI table\n" " -g: gdb port\n" " -c: # cpus (default 1)\n" - " -p: pin vcpu 'n' to host cpu 'pincpu + n'\n" + " -p: pin 'vcpu' to 'hostcpu'\n" " -H: vmexit from the guest on hlt\n" " -P: vmexit from the guest on pause\n" " -W: force virtio to use single-vector MSI\n" @@ -144,12 +146,46 @@ usage(int code) " -m: memory size in MB\n" " -w: ignore unimplemented MSRs\n" " -x: local apic is in x2APIC mode\n" + " -Y: disable MPtable generation\n" " -U: uuid\n", progname, (int)strlen(progname), ""); exit(code); } +static int +pincpu_parse(const char *opt) +{ + int vcpu, pcpu; + + if (sscanf(opt, "%d:%d", &vcpu, &pcpu) != 2) { + fprintf(stderr, "invalid format: %s\n", opt); + return (-1); + } + + if (vcpu < 0 || vcpu >= VM_MAXCPU) { + fprintf(stderr, "vcpu '%d' outside valid range from 0 to %d\n", + vcpu, VM_MAXCPU - 1); + return (-1); + } + + if (pcpu < 0 || pcpu >= CPU_SETSIZE) { + fprintf(stderr, "hostcpu '%d' outside valid range from " + "0 to %d\n", pcpu, CPU_SETSIZE - 1); + return (-1); + } + + if (vcpumap[vcpu] == NULL) { + if ((vcpumap[vcpu] = malloc(sizeof(cpuset_t))) == NULL) { + perror("malloc"); + return (-1); + } + CPU_ZERO(vcpumap[vcpu]); + } + CPU_SET(pcpu, vcpumap[vcpu]); + return (0); +} + void * paddr_guest2host(struct vmctx *ctx, uintptr_t gaddr, size_t len) { @@ -227,8 +263,7 @@ fbsdrun_deletecpu(struct vmctx *ctx, int vcpu) { if (!CPU_ISSET(vcpu, &cpumask)) { - fprintf(stderr, "addcpu: attempting to delete unknown cpu %d\n", - vcpu); + fprintf(stderr, "Attempting to delete unknown cpu %d\n", vcpu); exit(1); } @@ -237,13 +272,6 @@ fbsdrun_deletecpu(struct vmctx *ctx, int vcpu) } static int -vmexit_catch_reset(void) -{ - stats.io_reset++; - return (VMEXIT_RESET); -} - -static int vmexit_catch_inout(void) { return (VMEXIT_ABORT); @@ -293,8 +321,10 @@ vmexit_inout(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) case INOUT_OK: return (VMEXIT_CONTINUE); case INOUT_RESET: + stats.io_reset++; return (VMEXIT_RESET); case INOUT_POWEROFF: + stats.io_poweroff++; return (VMEXIT_POWEROFF); default: fprintf(stderr, "Unhandled %s%c 0x%04x\n", @@ -365,17 +395,6 @@ vmexit_spinup_ap(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) } static int -vmexit_spindown_cpu(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu) -{ - int lastcpu; - - lastcpu = fbsdrun_deletecpu(ctx, *pvcpu); - if (!lastcpu) - pthread_exit(NULL); - return (vmexit_catch_reset()); -} - -static int vmexit_vmx(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { @@ -461,17 +480,17 @@ vmexit_inst_emul(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) static pthread_mutex_t resetcpu_mtx = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t resetcpu_cond = PTHREAD_COND_INITIALIZER; -static int resetcpu = -1; static int vmexit_suspend(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { - - assert(resetcpu != -1); + enum vm_suspend_how how; + + how = vmexit->u.suspended.how; fbsdrun_deletecpu(ctx, *pvcpu); - if (*pvcpu != resetcpu) { + if (*pvcpu != BSP) { pthread_mutex_lock(&resetcpu_mtx); pthread_cond_signal(&resetcpu_cond); pthread_mutex_unlock(&resetcpu_mtx); @@ -483,7 +502,19 @@ vmexit_suspend(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) pthread_cond_wait(&resetcpu_cond, &resetcpu_mtx); } pthread_mutex_unlock(&resetcpu_mtx); - exit(0); + + switch (how) { + case VM_SUSPEND_RESET: + exit(0); + case VM_SUSPEND_POWEROFF: + exit(1); + case VM_SUSPEND_HALT: + exit(2); + default: + fprintf(stderr, "vmexit_suspend: invalid reason %d\n", how); + exit(100); + } + return (0); /* NOTREACHED */ } static vmexit_handler_t handler[VM_EXITCODE_MAX] = { @@ -495,22 +526,19 @@ static vmexit_handler_t handler[VM_EXITCODE_MAX] = { [VM_EXITCODE_MTRAP] = vmexit_mtrap, [VM_EXITCODE_INST_EMUL] = vmexit_inst_emul, [VM_EXITCODE_SPINUP_AP] = vmexit_spinup_ap, - [VM_EXITCODE_SPINDOWN_CPU] = vmexit_spindown_cpu, [VM_EXITCODE_SUSPENDED] = vmexit_suspend }; static void vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip) { - cpuset_t mask; int error, rc, prevcpu; enum vm_exitcode exitcode; + enum vm_suspend_how how; - if (pincpu >= 0) { - CPU_ZERO(&mask); - CPU_SET(pincpu + vcpu, &mask); + if (vcpumap[vcpu] != NULL) { error = pthread_setaffinity_np(pthread_self(), - sizeof(mask), &mask); + sizeof(cpuset_t), vcpumap[vcpu]); assert(error == 0); } @@ -538,10 +566,13 @@ vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip) rip = vmexit[vcpu].rip; break; case VMEXIT_RESET: - if (vm_suspend(ctx) == 0) { - assert(resetcpu == -1); - resetcpu = vcpu; - } + case VMEXIT_POWEROFF: + if (rc == VMEXIT_RESET) + how = VM_SUSPEND_RESET; + else + how = VM_SUSPEND_POWEROFF; + error = vm_suspend(ctx, how); + assert(error == 0 || errno == EALREADY); rip = vmexit[vcpu].rip + vmexit[vcpu].inst_length; break; default: @@ -616,7 +647,7 @@ int main(int argc, char *argv[]) { int c, error, gdb_port, err, bvmcons; - int max_vcpus; + int max_vcpus, mptgen; struct vmctx *ctx; uint64_t rip; size_t memsize; @@ -626,8 +657,9 @@ main(int argc, char *argv[]) gdb_port = 0; guest_ncpus = 1; memsize = 256 * MB; + mptgen = 1; - while ((c = getopt(argc, argv, "abehwxAHIPWp:g:c:s:m:l:U:")) != -1) { + while ((c = getopt(argc, argv, "abehwxAHIPWYp:g:c:s:m:l:U:")) != -1) { switch (c) { case 'a': x2apic_mode = 0; @@ -639,7 +671,10 @@ main(int argc, char *argv[]) bvmcons = 1; break; case 'p': - pincpu = atoi(optarg); + if (pincpu_parse(optarg) != 0) { + errx(EX_USAGE, "invalid vcpu pinning " + "configuration '%s'", optarg); + } break; case 'c': guest_ncpus = atoi(optarg); @@ -693,6 +728,9 @@ main(int argc, char *argv[]) case 'x': x2apic_mode = 1; break; + case 'Y': + mptgen = 0; + break; case 'h': usage(0); default: @@ -752,7 +790,11 @@ main(int argc, char *argv[]) /* * build the guest tables, MP etc. */ - mptable_build(ctx, guest_ncpus); + if (mptgen) { + error = mptable_build(ctx, guest_ncpus); + if (error) + exit(1); + } error = smbios_build(ctx); assert(error == 0); diff --git a/usr.sbin/bhyve/mevent.c b/usr.sbin/bhyve/mevent.c index b83ec6904d631..07d3baf727212 100644 --- a/usr.sbin/bhyve/mevent.c +++ b/usr.sbin/bhyve/mevent.c @@ -52,9 +52,10 @@ __FBSDID("$FreeBSD$"); #define MEVENT_MAX 64 -#define MEV_ENABLE 1 -#define MEV_DISABLE 2 -#define MEV_DEL_PENDING 3 +#define MEV_ADD 1 +#define MEV_ENABLE 2 +#define MEV_DISABLE 3 +#define MEV_DEL_PENDING 4 extern char *vmname; @@ -147,10 +148,11 @@ mevent_kq_flags(struct mevent *mevp) int ret; switch (mevp->me_state) { + case MEV_ADD: + ret = EV_ADD; /* implicitly enabled */ + break; case MEV_ENABLE: - ret = EV_ADD; - if (mevp->me_type == EVF_TIMER) - ret |= EV_ENABLE; + ret = EV_ENABLE; break; case MEV_DISABLE: ret = EV_DISABLE; @@ -158,6 +160,9 @@ mevent_kq_flags(struct mevent *mevp) case MEV_DEL_PENDING: ret = EV_DELETE; break; + default: + assert(0); + break; } return (ret); @@ -284,7 +289,7 @@ mevent_add(int tfd, enum ev_type type, LIST_INSERT_HEAD(&change_head, mevp, me_list); mevp->me_cq = 1; - mevp->me_state = MEV_ENABLE; + mevp->me_state = MEV_ADD; mevent_notify(); exit: diff --git a/usr.sbin/bhyve/mptbl.c b/usr.sbin/bhyve/mptbl.c index e8958359adb63..4c2167e98c859 100644 --- a/usr.sbin/bhyve/mptbl.c +++ b/usr.sbin/bhyve/mptbl.c @@ -303,16 +303,31 @@ mptable_build(struct vmctx *ctx, int ncpu) proc_entry_ptr mpep; mpfps_t mpfp; int_entry_ptr mpie; - int ioints; + int ioints, bus; char *curraddr; char *startaddr; startaddr = paddr_guest2host(ctx, MPTABLE_BASE, MPTABLE_MAX_LENGTH); if (startaddr == NULL) { - printf("mptable requires mapped mem\n"); + fprintf(stderr, "mptable requires mapped mem\n"); return (ENOMEM); } + /* + * There is no way to advertise multiple PCI hierarchies via MPtable + * so require that there is no PCI hierarchy with a non-zero bus + * number. + */ + for (bus = 1; bus <= PCI_BUSMAX; bus++) { + if (pci_bus_configured(bus)) { + fprintf(stderr, "MPtable is incompatible with " + "multiple PCI hierarchies.\r\n"); + fprintf(stderr, "MPtable generation can be disabled " + "by passing the -Y option to bhyve(8).\r\n"); + return (EINVAL); + } + } + curraddr = startaddr; mpfp = (mpfps_t)curraddr; mpt_build_mpfp(mpfp, MPTABLE_BASE); diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c index 3f9fc7f1c33c6..9f6110730b09e 100644 --- a/usr.sbin/bhyve/pci_ahci.c +++ b/usr.sbin/bhyve/pci_ahci.c @@ -192,6 +192,7 @@ struct pci_ahci_softc { uint32_t em_ctl; uint32_t cap2; uint32_t bohc; + uint32_t lintr; struct ahci_port port[MAX_PORTS]; }; #define ahci_ctx(sc) ((sc)->asc_pi->pi_vmctx) @@ -211,8 +212,11 @@ static inline void lba_to_msf(uint8_t *buf, int lba) static void ahci_generate_intr(struct pci_ahci_softc *sc) { + struct pci_devinst *pi; int i; + pi = sc->asc_pi; + for (i = 0; i < sc->ports; i++) { struct ahci_port *pr; pr = &sc->port[i]; @@ -222,8 +226,28 @@ ahci_generate_intr(struct pci_ahci_softc *sc) DPRINTF("%s %x\n", __func__, sc->is); - if (sc->is && (sc->ghc & AHCI_GHC_IE)) - pci_generate_msi(sc->asc_pi, 0); + if (sc->is && (sc->ghc & AHCI_GHC_IE)) { + if (pci_msi_enabled(pi)) { + /* + * Generate an MSI interrupt on every edge + */ + pci_generate_msi(pi, 0); + } else if (!sc->lintr) { + /* + * Only generate a pin-based interrupt if one wasn't + * in progress + */ + sc->lintr = 1; + pci_lintr_assert(pi); + } + } else if (sc->lintr) { + /* + * No interrupts: deassert pin-based signal if it had + * been asserted + */ + pci_lintr_deassert(pi); + sc->lintr = 0; + } } static void @@ -367,6 +391,12 @@ ahci_reset(struct pci_ahci_softc *sc) sc->ghc = AHCI_GHC_AE; sc->is = 0; + + if (sc->lintr) { + pci_lintr_deassert(sc->asc_pi); + sc->lintr = 0; + } + for (i = 0; i < sc->ports; i++) { sc->port[i].ie = 0; sc->port[i].is = 0; @@ -1814,6 +1844,8 @@ pci_ahci_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts, int atapi) pci_emul_alloc_bar(pi, 5, PCIBAR_MEM32, AHCI_OFFSET + sc->ports * AHCI_STEP); + pci_lintr_request(pi); + open_fail: if (ret) { blockif_close(sc->port[0].bctx); diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c index 15f2fad534858..5b87da7f0604c 100644 --- a/usr.sbin/bhyve/pci_emul.c +++ b/usr.sbin/bhyve/pci_emul.c @@ -1261,6 +1261,13 @@ pci_write_dsdt(void) } int +pci_bus_configured(int bus) +{ + assert(bus >= 0 && bus < MAXBUSES); + return (pci_businfo[bus] != NULL); +} + +int pci_msi_enabled(struct pci_devinst *pi) { return (pi->pi_msi.enabled); diff --git a/usr.sbin/bhyve/pci_emul.h b/usr.sbin/bhyve/pci_emul.h index 7ad0a5d1f6b2a..e1040a8b715ad 100644 --- a/usr.sbin/bhyve/pci_emul.h +++ b/usr.sbin/bhyve/pci_emul.h @@ -233,6 +233,7 @@ uint64_t pci_emul_msix_tread(struct pci_devinst *pi, uint64_t offset, int size); int pci_count_lintr(int bus); void pci_walk_lintr(int bus, pci_lintr_cb cb, void *arg); void pci_write_dsdt(void); +int pci_bus_configured(int bus); static __inline void pci_set_cfgdata8(struct pci_devinst *pi, int offset, uint8_t val) diff --git a/usr.sbin/bhyve/uart_emul.c b/usr.sbin/bhyve/uart_emul.c index 38e14a95ab038..4242e5ce95481 100644 --- a/usr.sbin/bhyve/uart_emul.c +++ b/usr.sbin/bhyve/uart_emul.c @@ -110,6 +110,7 @@ struct uart_softc { uint8_t dlh; /* Baudrate divisor latch MSB */ struct fifo rxfifo; + struct mevent *mev; struct ttyfd tty; bool thre_int_pending; /* THRE interrupt pending */ @@ -145,34 +146,15 @@ ttyopen(struct ttyfd *tf) } } -static bool -tty_char_available(struct ttyfd *tf) -{ - fd_set rfds; - struct timeval tv; - - FD_ZERO(&rfds); - FD_SET(tf->fd, &rfds); - tv.tv_sec = 0; - tv.tv_usec = 0; - if (select(tf->fd + 1, &rfds, NULL, NULL, &tv) > 0 ) { - return (true); - } else { - return (false); - } -} - static int ttyread(struct ttyfd *tf) { - char rb; + unsigned char rb; - if (tty_char_available(tf)) { - read(tf->fd, &rb, 1); - return (rb & 0xff); - } else { + if (read(tf->fd, &rb, 1) == 1) + return (rb); + else return (-1); - } } static void @@ -183,62 +165,111 @@ ttywrite(struct ttyfd *tf, unsigned char wb) } static void -fifo_reset(struct fifo *fifo, int size) +rxfifo_reset(struct uart_softc *sc, int size) { + char flushbuf[32]; + struct fifo *fifo; + ssize_t nread; + int error; + fifo = &sc->rxfifo; bzero(fifo, sizeof(struct fifo)); fifo->size = size; + + if (sc->tty.opened) { + /* + * Flush any unread input from the tty buffer. + */ + while (1) { + nread = read(sc->tty.fd, flushbuf, sizeof(flushbuf)); + if (nread != sizeof(flushbuf)) + break; + } + + /* + * Enable mevent to trigger when new characters are available + * on the tty fd. + */ + error = mevent_enable(sc->mev); + assert(error == 0); + } } static int -fifo_putchar(struct fifo *fifo, uint8_t ch) +rxfifo_available(struct uart_softc *sc) { + struct fifo *fifo; + + fifo = &sc->rxfifo; + return (fifo->num < fifo->size); +} + +static int +rxfifo_putchar(struct uart_softc *sc, uint8_t ch) +{ + struct fifo *fifo; + int error; + + fifo = &sc->rxfifo; if (fifo->num < fifo->size) { fifo->buf[fifo->windex] = ch; fifo->windex = (fifo->windex + 1) % fifo->size; fifo->num++; + if (!rxfifo_available(sc)) { + if (sc->tty.opened) { + /* + * Disable mevent callback if the FIFO is full. + */ + error = mevent_disable(sc->mev); + assert(error == 0); + } + } return (0); } else return (-1); } static int -fifo_getchar(struct fifo *fifo) +rxfifo_getchar(struct uart_softc *sc) { - int c; + struct fifo *fifo; + int c, error, wasfull; + wasfull = 0; + fifo = &sc->rxfifo; if (fifo->num > 0) { + if (!rxfifo_available(sc)) + wasfull = 1; c = fifo->buf[fifo->rindex]; fifo->rindex = (fifo->rindex + 1) % fifo->size; fifo->num--; + if (wasfull) { + if (sc->tty.opened) { + error = mevent_enable(sc->mev); + assert(error == 0); + } + } return (c); } else return (-1); } static int -fifo_numchars(struct fifo *fifo) +rxfifo_numchars(struct uart_softc *sc) { + struct fifo *fifo = &sc->rxfifo; return (fifo->num); } -static int -fifo_available(struct fifo *fifo) -{ - - return (fifo->num < fifo->size); -} - static void uart_opentty(struct uart_softc *sc) { - struct mevent *mev; ttyopen(&sc->tty); - mev = mevent_add(sc->tty.fd, EVF_READ, uart_drain, sc); - assert(mev); + sc->mev = mevent_add(sc->tty.fd, EVF_READ, uart_drain, sc); + assert(sc->mev != NULL); } /* @@ -255,7 +286,7 @@ uart_intr_reason(struct uart_softc *sc) if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0) return (IIR_RLS); - else if (fifo_numchars(&sc->rxfifo) > 0 && (sc->ier & IER_ERXRDY) != 0) + else if (rxfifo_numchars(sc) > 0 && (sc->ier & IER_ERXRDY) != 0) return (IIR_RXTOUT); else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0) return (IIR_TXRDY); @@ -274,7 +305,7 @@ uart_reset(struct uart_softc *sc) sc->dll = divisor; sc->dlh = divisor >> 16; - fifo_reset(&sc->rxfifo, 1); /* no fifo until enabled by software */ + rxfifo_reset(sc, 1); /* no fifo until enabled by software */ } /* @@ -315,9 +346,9 @@ uart_drain(int fd, enum ev_type ev, void *arg) if ((sc->mcr & MCR_LOOPBACK) != 0) { (void) ttyread(&sc->tty); } else { - while (fifo_available(&sc->rxfifo) && + while (rxfifo_available(sc) && ((ch = ttyread(&sc->tty)) != -1)) { - fifo_putchar(&sc->rxfifo, ch); + rxfifo_putchar(sc, ch); } uart_toggle_intr(sc); } @@ -351,7 +382,7 @@ uart_write(struct uart_softc *sc, int offset, uint8_t value) switch (offset) { case REG_DATA: if (sc->mcr & MCR_LOOPBACK) { - if (fifo_putchar(&sc->rxfifo, value) != 0) + if (rxfifo_putchar(sc, value) != 0) sc->lsr |= LSR_OE; } else if (sc->tty.opened) { ttywrite(&sc->tty, value); @@ -372,7 +403,7 @@ uart_write(struct uart_softc *sc, int offset, uint8_t value) */ if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) { fifosz = (value & FCR_ENABLE) ? FIFOSZ : 1; - fifo_reset(&sc->rxfifo, fifosz); + rxfifo_reset(sc, fifosz); } /* @@ -383,7 +414,7 @@ uart_write(struct uart_softc *sc, int offset, uint8_t value) sc->fcr = 0; } else { if ((value & FCR_RCV_RST) != 0) - fifo_reset(&sc->rxfifo, FIFOSZ); + rxfifo_reset(sc, FIFOSZ); sc->fcr = value & (FCR_ENABLE | FCR_DMA | FCR_RX_MASK); @@ -480,7 +511,7 @@ uart_read(struct uart_softc *sc, int offset) switch (offset) { case REG_DATA: - reg = fifo_getchar(&sc->rxfifo); + reg = rxfifo_getchar(sc); break; case REG_IER: reg = sc->ier; @@ -511,7 +542,7 @@ uart_read(struct uart_softc *sc, int offset) sc->lsr |= LSR_TEMT | LSR_THRE; /* Check for new receive data */ - if (fifo_numchars(&sc->rxfifo) > 0) + if (rxfifo_numchars(sc) > 0) sc->lsr |= LSR_RXRDY; else sc->lsr &= ~LSR_RXRDY; @@ -615,6 +646,10 @@ uart_set_backend(struct uart_softc *sc, const char *opts) retval = 0; } + /* Make the backend file descriptor non-blocking */ + if (retval == 0) + retval = fcntl(sc->tty.fd, F_SETFL, O_NONBLOCK); + if (retval == 0) uart_opentty(sc); diff --git a/usr.sbin/bhyve/xmsr.c b/usr.sbin/bhyve/xmsr.c index ba94125a09001..63522bf023beb 100644 --- a/usr.sbin/bhyve/xmsr.c +++ b/usr.sbin/bhyve/xmsr.c @@ -47,6 +47,8 @@ emulate_wrmsr(struct vmctx *ctx, int vcpu, uint32_t code, uint64_t val) case 0xd04: /* Sandy Bridge uncore PMC MSRs */ case 0xc24: return (0); + case 0x79: + return (0); /* IA32_BIOS_UPDT_TRIG MSR */ default: break; } diff --git a/usr.sbin/bhyvectl/bhyvectl.c b/usr.sbin/bhyvectl/bhyvectl.c index 2e732b5125955..ceee33a2aeeb0 100644 --- a/usr.sbin/bhyvectl/bhyvectl.c +++ b/usr.sbin/bhyvectl/bhyvectl.c @@ -191,13 +191,16 @@ usage(void) " [--get-highmem]\n" " [--get-gpa-pmap]\n" " [--assert-lapic-lvt=<pin>]\n" - " [--inject-nmi]\n", + " [--inject-nmi]\n" + " [--force-reset]\n" + " [--force-poweroff]\n", progname); exit(1); } static int get_stats, getcap, setcap, capval, get_gpa_pmap; static int inject_nmi, assert_lapic_lvt; +static int force_reset, force_poweroff; static const char *capname; static int create, destroy, get_lowmem, get_highmem; static uint64_t memsize; @@ -565,6 +568,8 @@ main(int argc, char *argv[]) { "create", NO_ARG, &create, 1 }, { "destroy", NO_ARG, &destroy, 1 }, { "inject-nmi", NO_ARG, &inject_nmi, 1 }, + { "force-reset", NO_ARG, &force_reset, 1 }, + { "force-poweroff", NO_ARG, &force_poweroff, 1 }, { NULL, 0, NULL, 0 } }; @@ -1535,6 +1540,12 @@ main(int argc, char *argv[]) printf("vm_run error %d\n", error); } + if (!error && force_reset) + error = vm_suspend(ctx, VM_SUSPEND_RESET); + + if (!error && force_poweroff) + error = vm_suspend(ctx, VM_SUSPEND_POWEROFF); + if (error) printf("errno = %d\n", errno); diff --git a/usr.sbin/bootparamd/bootparamd/Makefile b/usr.sbin/bootparamd/bootparamd/Makefile index a5163a3873ab7..0596993ec67c4 100644 --- a/usr.sbin/bootparamd/bootparamd/Makefile +++ b/usr.sbin/bootparamd/bootparamd/Makefile @@ -1,7 +1,7 @@ # from: @(#)Makefile 5.8 (Berkeley) 7/28/90 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= bootparamd MAN= bootparams.5 bootparamd.8 diff --git a/usr.sbin/bsdinstall/distextract/Makefile b/usr.sbin/bsdinstall/distextract/Makefile index 1910b23d956cc..e359bba590e57 100644 --- a/usr.sbin/bsdinstall/distextract/Makefile +++ b/usr.sbin/bsdinstall/distextract/Makefile @@ -8,7 +8,7 @@ LDADD= -larchive -ldialog -lm WARNS?= 6 MAN= -.include <bsd.own.mk> +.include <src.opts.mk> .if ${MK_NCURSESW} == "no" DPADD+= ${LIBNCURSES} diff --git a/usr.sbin/bsdinstall/distfetch/Makefile b/usr.sbin/bsdinstall/distfetch/Makefile index 08eb91c07352e..2ac9eb611b733 100644 --- a/usr.sbin/bsdinstall/distfetch/Makefile +++ b/usr.sbin/bsdinstall/distfetch/Makefile @@ -8,7 +8,7 @@ LDADD= -lfetch -ldialog -lm WARNS?= 6 MAN= -.include <bsd.own.mk> +.include <src.opts.mk> .if ${MK_NCURSESW} == "no" DPADD+= ${LIBNCURSES} diff --git a/usr.sbin/bsdinstall/partedit/Makefile b/usr.sbin/bsdinstall/partedit/Makefile index 3eb0d3f8946d9..328259c1ec11a 100644 --- a/usr.sbin/bsdinstall/partedit/Makefile +++ b/usr.sbin/bsdinstall/partedit/Makefile @@ -22,7 +22,7 @@ SRCS= diskeditor.c partedit.c gpart_ops.c partedit_${PARTEDIT_ARCH}.c \ WARNS?= 3 MAN= sade.8 -.include <bsd.own.mk> +.include <src.opts.mk> .if ${MK_NCURSESW} == "no" DPADD+= ${LIBNCURSES} diff --git a/usr.sbin/bsnmpd/bsnmpd/Makefile b/usr.sbin/bsnmpd/bsnmpd/Makefile index 3e6df47fadaca..b20ba31d604c1 100644 --- a/usr.sbin/bsnmpd/bsnmpd/Makefile +++ b/usr.sbin/bsnmpd/bsnmpd/Makefile @@ -2,7 +2,7 @@ # # Author: Harti Brandt <harti@freebsd.org> -.include <bsd.own.mk> +.include <src.opts.mk> CONTRIB=${.CURDIR}/../../../contrib/bsnmp .PATH: ${CONTRIB}/snmpd diff --git a/usr.sbin/bsnmpd/modules/Makefile b/usr.sbin/bsnmpd/modules/Makefile index 45558b7abcc02..24f9f0298c840 100644 --- a/usr.sbin/bsnmpd/modules/Makefile +++ b/usr.sbin/bsnmpd/modules/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../../contrib/bsnmp/snmpd diff --git a/usr.sbin/bsnmpd/modules/snmp_hast/Makefile b/usr.sbin/bsnmpd/modules/snmp_hast/Makefile index 6369918361374..e05ce31020edb 100644 --- a/usr.sbin/bsnmpd/modules/snmp_hast/Makefile +++ b/usr.sbin/bsnmpd/modules/snmp_hast/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../../../sbin/hastd diff --git a/usr.sbin/bsnmpd/tools/bsnmptools/Makefile b/usr.sbin/bsnmpd/tools/bsnmptools/Makefile index 94a1cea172428..3310420a4f380 100644 --- a/usr.sbin/bsnmpd/tools/bsnmptools/Makefile +++ b/usr.sbin/bsnmpd/tools/bsnmptools/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ # Author: Shteryana Shopova <syrinx@FreeBSD.org> -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR} diff --git a/usr.sbin/etcupdate/Makefile b/usr.sbin/etcupdate/Makefile index 765533a331ad2..155151de02f82 100644 --- a/usr.sbin/etcupdate/Makefile +++ b/usr.sbin/etcupdate/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SCRIPTS=etcupdate.sh MAN= etcupdate.8 diff --git a/usr.sbin/flowctl/Makefile b/usr.sbin/flowctl/Makefile index a2dd37788c382..acee16ba8eff1 100644 --- a/usr.sbin/flowctl/Makefile +++ b/usr.sbin/flowctl/Makefile @@ -2,7 +2,7 @@ # $FreeBSD$ # -.include <bsd.own.mk> +.include <src.opts.mk> PROG= flowctl MAN= flowctl.8 diff --git a/usr.sbin/gssd/Makefile b/usr.sbin/gssd/Makefile index 3663bf9e8040c..9573702b1b623 100644 --- a/usr.sbin/gssd/Makefile +++ b/usr.sbin/gssd/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= gssd MAN= gssd.8 diff --git a/usr.sbin/ifmcstat/Makefile b/usr.sbin/ifmcstat/Makefile index fab7ea69e2e68..5b967c7b9eaf9 100644 --- a/usr.sbin/ifmcstat/Makefile +++ b/usr.sbin/ifmcstat/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/5/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ifmcstat SRCS= ifmcstat.c printb.c diff --git a/usr.sbin/inetd/Makefile b/usr.sbin/inetd/Makefile index 29aacd1813d63..f31027af8765f 100644 --- a/usr.sbin/inetd/Makefile +++ b/usr.sbin/inetd/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= inetd MAN= inetd.8 diff --git a/usr.sbin/jail/Makefile b/usr.sbin/jail/Makefile index fb36defa8bf68..58324ac3c088b 100644 --- a/usr.sbin/jail/Makefile +++ b/usr.sbin/jail/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= jail MAN= jail.8 jail.conf.5 diff --git a/usr.sbin/jls/Makefile b/usr.sbin/jls/Makefile index b297cc46d6531..431fd0c80c1d6 100644 --- a/usr.sbin/jls/Makefile +++ b/usr.sbin/jls/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= jls MAN= jls.8 diff --git a/usr.sbin/kldxref/ef.c b/usr.sbin/kldxref/ef.c index b68389801345b..88fbc34a43b65 100644 --- a/usr.sbin/kldxref/ef.c +++ b/usr.sbin/kldxref/ef.c @@ -47,6 +47,7 @@ #include "ef.h" +#define MAXSEGS 2 struct ef_file { char* ef_name; struct elf_file *ef_efile; @@ -68,7 +69,7 @@ struct ef_file { Elf_Off ef_symoff; Elf_Sym* ef_symtab; int ef_nsegs; - Elf_Phdr * ef_segs[2]; + Elf_Phdr * ef_segs[MAXSEGS]; int ef_verbose; Elf_Rel * ef_rel; /* relocation table */ int ef_relsz; /* number of entries */ @@ -580,12 +581,9 @@ ef_open(const char *filename, struct elf_file *efile, int verbose) ef_print_phdr(phdr); switch (phdr->p_type) { case PT_LOAD: - if (nsegs == 2) { - warnx("%s: too many sections", - filename); - break; - } - ef->ef_segs[nsegs++] = phdr; + if (nsegs < MAXSEGS) + ef->ef_segs[nsegs] = phdr; + nsegs++; break; case PT_PHDR: break; @@ -597,12 +595,15 @@ ef_open(const char *filename, struct elf_file *efile, int verbose) } if (verbose > 1) printf("\n"); - ef->ef_nsegs = nsegs; if (phdyn == NULL) { warnx("Skipping %s: not dynamically-linked", filename); break; + } else if (nsegs > MAXSEGS) { + warnx("%s: too many sections", filename); + break; } + ef->ef_nsegs = nsegs; if (ef_read_entry(ef, phdyn->p_offset, phdyn->p_filesz, (void**)&ef->ef_dyn) != 0) { printf("ef_read_entry failed\n"); diff --git a/usr.sbin/lpr/Makefile.inc b/usr.sbin/lpr/Makefile.inc index ab667dd119a1a..65535e6abac0d 100644 --- a/usr.sbin/lpr/Makefile.inc +++ b/usr.sbin/lpr/Makefile.inc @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .if ${MK_INET6_SUPPORT} != "no" CFLAGS+= -DINET6 diff --git a/usr.sbin/mailwrapper/Makefile b/usr.sbin/mailwrapper/Makefile index 8811f6f175877..8e49db7edd552 100644 --- a/usr.sbin/mailwrapper/Makefile +++ b/usr.sbin/mailwrapper/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .if ${MK_MAILWRAPPER} != "no" PROG= mailwrapper diff --git a/usr.sbin/mtest/Makefile b/usr.sbin/mtest/Makefile index 9104c682002b5..22c417c8141fc 100644 --- a/usr.sbin/mtest/Makefile +++ b/usr.sbin/mtest/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= mtest MAN= mtest.8 diff --git a/usr.sbin/newsyslog/Makefile b/usr.sbin/newsyslog/Makefile index 4e3ae557034e6..1c63e73e0a871 100644 --- a/usr.sbin/newsyslog/Makefile +++ b/usr.sbin/newsyslog/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= newsyslog MAN= newsyslog.8 newsyslog.conf.5 diff --git a/usr.sbin/ngctl/Makefile b/usr.sbin/ngctl/Makefile index 071f1c38ab95e..a1d1e6b375c85 100644 --- a/usr.sbin/ngctl/Makefile +++ b/usr.sbin/ngctl/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ # $Whistle: Makefile,v 1.3 1999/01/16 00:10:11 archie Exp $ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ngctl MAN= ngctl.8 diff --git a/usr.sbin/ntp/Makefile.inc b/usr.sbin/ntp/Makefile.inc index 5095e89bbfbc5..cadd4c7a941ca 100644 --- a/usr.sbin/ntp/Makefile.inc +++ b/usr.sbin/ntp/Makefile.inc @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> DEFS_LOCAL= -DPARSE -DHAVE_CONFIG_H NTPDEFS= -DSYS_FREEBSD diff --git a/usr.sbin/ntp/doc/Makefile b/usr.sbin/ntp/doc/Makefile index 64e357155bea0..9c42b09701748 100644 --- a/usr.sbin/ntp/doc/Makefile +++ b/usr.sbin/ntp/doc/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> FILESDIR= ${SHAREDIR}/doc/ntp diff --git a/usr.sbin/ntp/ntp-keygen/Makefile b/usr.sbin/ntp/ntp-keygen/Makefile index 26716c2ff0010..fea148cb076c8 100644 --- a/usr.sbin/ntp/ntp-keygen/Makefile +++ b/usr.sbin/ntp/ntp-keygen/Makefile @@ -2,7 +2,7 @@ MAN= -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../../contrib/ntp/util \ ${.CURDIR}/../../../contrib/ntp/ntpd diff --git a/usr.sbin/ntp/ntpd/Makefile b/usr.sbin/ntp/ntpd/Makefile index 1ac4c7249f71c..53f537f713432 100644 --- a/usr.sbin/ntp/ntpd/Makefile +++ b/usr.sbin/ntp/ntpd/Makefile @@ -2,7 +2,7 @@ MAN= -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../../contrib/ntp/ntpd diff --git a/usr.sbin/pmcstat/pmcstat.8 b/usr.sbin/pmcstat/pmcstat.8 index 5555759939adc..97a2f626ca6dc 100644 --- a/usr.sbin/pmcstat/pmcstat.8 +++ b/usr.sbin/pmcstat/pmcstat.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 19, 2008 +.Dd April 29, 2014 .Dt PMCSTAT 8 .Os .Sh NAME @@ -46,6 +46,7 @@ .Op Fl S Ar event-spec .Op Fl T .Op Fl W +.Op Fl a Ar pathname .Op Fl c Ar cpu-spec .Op Fl d .Op Fl f Ar pluginopt @@ -221,6 +222,21 @@ This is an experimental feature intended to help analyse the dynamic behaviour of processes in the system. It may incur substantial overhead if enabled. The default is for this feature to be disabled. +.It Fl a Ar pathname +Perform a symbol and file:line lookup for each address in each +callgraph and save the output to +.Ar pathname . +Unlike +.Fl m +that only resolves the first symbol in the graph, this resolves +every node in the callgraph, or prints out addresses if no +lookup information is available. +This option requires the +.Fl R +option to read in samples that were previously collected and +saved with the +.Fl o +option. .It Fl c Ar cpu-spec Set the cpus for subsequent system mode PMCs specified on the command line to diff --git a/usr.sbin/pmcstat/pmcstat.c b/usr.sbin/pmcstat/pmcstat.c index 3edba3f20db45..ae93b9387da2f 100644 --- a/usr.sbin/pmcstat/pmcstat.c +++ b/usr.sbin/pmcstat/pmcstat.c @@ -503,7 +503,7 @@ pmcstat_show_usage(void) "\t -S spec\t allocate a system-wide sampling PMC\n" "\t -T\t\t start in top mode\n" "\t -W\t\t (toggle) show counts per context switch\n" - "\t -a <file>\t print sampled PCs and callgraph to \"file\"\n" + "\t -a file\t print sampled PCs and callgraph to \"file\"\n" "\t -c cpu-list\t set cpus for subsequent system-wide PMCs\n" "\t -d\t\t (toggle) track descendants\n" "\t -f spec\t pass \"spec\" to as plugin option\n" diff --git a/usr.sbin/ppp/Makefile b/usr.sbin/ppp/Makefile index 99436659344b0..a61ebf57501e6 100644 --- a/usr.sbin/ppp/Makefile +++ b/usr.sbin/ppp/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= ppp MAN= ppp.8 diff --git a/usr.sbin/rpcbind/Makefile b/usr.sbin/rpcbind/Makefile index dd042f217a981..278000160fbb0 100644 --- a/usr.sbin/rpcbind/Makefile +++ b/usr.sbin/rpcbind/Makefile @@ -1,7 +1,7 @@ # $NetBSD: Makefile,v 1.3 2000/06/20 13:56:43 fvdl Exp $ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= rpcbind MAN= rpcbind.8 diff --git a/usr.sbin/sa/Makefile b/usr.sbin/sa/Makefile index 23f9bf274a858..c3c79b0b7350a 100644 --- a/usr.sbin/sa/Makefile +++ b/usr.sbin/sa/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../usr.bin/lastcomm diff --git a/usr.sbin/sendmail/Makefile b/usr.sbin/sendmail/Makefile index a9f7fbbafd697..f8a910bc18448 100644 --- a/usr.sbin/sendmail/Makefile +++ b/usr.sbin/sendmail/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.8 (Berkeley) 3/28/97 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> SENDMAIL_DIR=${.CURDIR}/../../contrib/sendmail SMDIR= ${SENDMAIL_DIR}/src diff --git a/usr.sbin/syslogd/Makefile b/usr.sbin/syslogd/Makefile index 47640130bb144..069e093ccd213 100644 --- a/usr.sbin/syslogd/Makefile +++ b/usr.sbin/syslogd/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../usr.bin/wall diff --git a/usr.sbin/tcpdchk/Makefile b/usr.sbin/tcpdchk/Makefile index a49ffc60b748f..e9799165c61fe 100644 --- a/usr.sbin/tcpdchk/Makefile +++ b/usr.sbin/tcpdchk/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../contrib/tcp_wrappers diff --git a/usr.sbin/tcpdmatch/Makefile b/usr.sbin/tcpdmatch/Makefile index caae746805d87..f8ccf8adc7da3 100644 --- a/usr.sbin/tcpdmatch/Makefile +++ b/usr.sbin/tcpdmatch/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> .PATH: ${.CURDIR}/../../contrib/tcp_wrappers diff --git a/usr.sbin/tcpdump/tcpdump/Makefile b/usr.sbin/tcpdump/tcpdump/Makefile index ac7636acb1645..4982873207375 100644 --- a/usr.sbin/tcpdump/tcpdump/Makefile +++ b/usr.sbin/tcpdump/tcpdump/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> TCPDUMP_DISTDIR?= ${.CURDIR}/../../../contrib/tcpdump .PATH: ${TCPDUMP_DISTDIR} diff --git a/usr.sbin/trpt/Makefile b/usr.sbin/trpt/Makefile index 5c62ce049a6a7..e49fff1e9d33d 100644 --- a/usr.sbin/trpt/Makefile +++ b/usr.sbin/trpt/Makefile @@ -1,7 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ -.include <bsd.own.mk> +.include <src.opts.mk> PROG= trpt MAN= trpt.8 diff --git a/usr.sbin/tzsetup/Makefile b/usr.sbin/tzsetup/Makefile index 5c80a480058b8..5646b2acec042 100644 --- a/usr.sbin/tzsetup/Makefile +++ b/usr.sbin/tzsetup/Makefile @@ -10,7 +10,7 @@ WARNS?= 3 DPADD= ${LIBDIALOG} ${LIBM} LDADD= -ldialog -lm -.include <bsd.own.mk> +.include <src.opts.mk> .if ${MK_NCURSESW} == "no" DPADD+= ${LIBNCURSES} diff --git a/usr.sbin/wpa/hostapd/Makefile b/usr.sbin/wpa/hostapd/Makefile index 530cf020d2c50..7f0304c6af156 100644 --- a/usr.sbin/wpa/hostapd/Makefile +++ b/usr.sbin/wpa/hostapd/Makefile @@ -1,5 +1,6 @@ # $FreeBSD$ +.include <src.opts.mk> .include "${.CURDIR}/../Makefile.inc" .PATH.c:${HOSTAPD_DISTDIR} \ diff --git a/usr.sbin/wpa/wpa_supplicant/Makefile b/usr.sbin/wpa/wpa_supplicant/Makefile index 3424413f827ba..11cccf3ee4921 100644 --- a/usr.sbin/wpa/wpa_supplicant/Makefile +++ b/usr.sbin/wpa/wpa_supplicant/Makefile @@ -1,5 +1,7 @@ # $FreeBSD$ +.include <src.opts.mk> + .include "${.CURDIR}/../Makefile.inc" .PATH.c:${WPA_SUPPLICANT_DISTDIR} \ |