mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-06 17:18:32 +00:00
Merge ^/head r305220 through r305300.
This commit is contained in:
commit
2aeb03806a
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/clang390-import/; revision=305301
|
@ -1628,8 +1628,10 @@ _crunchide= usr.sbin/crunch/crunchide
|
|||
|
||||
# r285986 crunchen: use STRIPBIN rather than STRIP
|
||||
# 1100113: Support MK_AUTO_OBJ
|
||||
# 1200006: META_MODE fixes
|
||||
.if ${BOOTSTRAPPING} < 1100078 || \
|
||||
(${MK_AUTO_OBJ} == "yes" && ${BOOTSTRAPPING} < 1100114)
|
||||
(${MK_AUTO_OBJ} == "yes" && ${BOOTSTRAPPING} < 1100114) || \
|
||||
(${MK_META_MODE} == "yes" && ${BOOTSTRAPPING} < 1200006)
|
||||
_crunchgen= usr.sbin/crunch/crunchgen
|
||||
.endif
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
# xargs -n1 | sort | uniq -d;
|
||||
# done
|
||||
|
||||
# 20160901: Remove digi(4)
|
||||
OLD_FILES+=usr/share/man/man4/digi.4.gz
|
||||
# 20160819: Remove ie(4)
|
||||
OLD_FILES+=usr/share/man/man4/i386/ie.4.gz
|
||||
# 20160819: Remove spic(4)
|
||||
|
|
|
@ -60,7 +60,7 @@ SUBDIR= ${SUBDIR_BOOTSTRAP} \
|
|||
${_libgssapi} \
|
||||
${_librpcsec_gss} \
|
||||
${_libiconv_modules} \
|
||||
libifc \
|
||||
libifconfig \
|
||||
libipsec \
|
||||
libjail \
|
||||
libkiconv \
|
||||
|
|
|
@ -36,72 +36,72 @@ __FBSDID("$FreeBSD$");
|
|||
#include <signal.h>
|
||||
|
||||
const char *const sys_signame[NSIG] = {
|
||||
"Signal 0",
|
||||
"HUP", /* SIGHUP */
|
||||
"INT", /* SIGINT */
|
||||
"QUIT", /* SIGQUIT */
|
||||
"ILL", /* SIGILL */
|
||||
"TRAP", /* SIGTRAP */
|
||||
"ABRT", /* SIGABRT */
|
||||
"EMT", /* SIGEMT */
|
||||
"FPE", /* SIGFPE */
|
||||
"KILL", /* SIGKILL */
|
||||
"BUS", /* SIGBUS */
|
||||
"SEGV", /* SIGSEGV */
|
||||
"SYS", /* SIGSYS */
|
||||
"PIPE", /* SIGPIPE */
|
||||
"ALRM", /* SIGALRM */
|
||||
"TERM", /* SIGTERM */
|
||||
"URG", /* SIGURG */
|
||||
"STOP", /* SIGSTOP */
|
||||
"TSTP", /* SIGTSTP */
|
||||
"CONT", /* SIGCONT */
|
||||
"CHLD", /* SIGCHLD */
|
||||
"TTIN", /* SIGTTIN */
|
||||
"TTOU", /* SIGTTOU */
|
||||
"IO", /* SIGIO */
|
||||
"XCPU", /* SIGXCPU */
|
||||
"XFSZ", /* SIGXFSZ */
|
||||
"VTALRM", /* SIGVTALRM */
|
||||
"PROF", /* SIGPROF */
|
||||
"WINCH", /* SIGWINCH */
|
||||
"INFO", /* SIGINFO */
|
||||
"USR1", /* SIGUSR1 */
|
||||
"USR2" /* SIGUSR2 */
|
||||
[0] = "Signal 0",
|
||||
[SIGHUP] = "HUP",
|
||||
[SIGINT] = "INT",
|
||||
[SIGQUIT] = "QUIT",
|
||||
[SIGILL] = "ILL",
|
||||
[SIGTRAP] = "TRAP",
|
||||
[SIGABRT] = "ABRT",
|
||||
[SIGEMT] = "EMT",
|
||||
[SIGFPE] = "FPE",
|
||||
[SIGKILL] = "KILL",
|
||||
[SIGBUS] = "BUS",
|
||||
[SIGSEGV] = "SEGV",
|
||||
[SIGSYS] = "SYS",
|
||||
[SIGPIPE] = "PIPE",
|
||||
[SIGALRM] = "ALRM",
|
||||
[SIGTERM] = "TERM",
|
||||
[SIGURG] = "URG",
|
||||
[SIGSTOP] = "STOP",
|
||||
[SIGTSTP] = "TSTP",
|
||||
[SIGCONT] = "CONT",
|
||||
[SIGCHLD] = "CHLD",
|
||||
[SIGTTIN] = "TTIN",
|
||||
[SIGTTOU] = "TTOU",
|
||||
[SIGIO] = "IO",
|
||||
[SIGXCPU] = "XCPU",
|
||||
[SIGXFSZ] = "XFSZ",
|
||||
[SIGVTALRM] = "VTALRM",
|
||||
[SIGPROF] = "PROF",
|
||||
[SIGWINCH] = "WINCH",
|
||||
[SIGINFO] = "INFO",
|
||||
[SIGUSR1] = "USR1",
|
||||
[SIGUSR2] = "USR2",
|
||||
};
|
||||
|
||||
const char *const sys_siglist[NSIG] = {
|
||||
"Signal 0",
|
||||
"Hangup", /* SIGHUP */
|
||||
"Interrupt", /* SIGINT */
|
||||
"Quit", /* SIGQUIT */
|
||||
"Illegal instruction", /* SIGILL */
|
||||
"Trace/BPT trap", /* SIGTRAP */
|
||||
"Abort trap", /* SIGABRT */
|
||||
"EMT trap", /* SIGEMT */
|
||||
"Floating point exception", /* SIGFPE */
|
||||
"Killed", /* SIGKILL */
|
||||
"Bus error", /* SIGBUS */
|
||||
"Segmentation fault", /* SIGSEGV */
|
||||
"Bad system call", /* SIGSYS */
|
||||
"Broken pipe", /* SIGPIPE */
|
||||
"Alarm clock", /* SIGALRM */
|
||||
"Terminated", /* SIGTERM */
|
||||
"Urgent I/O condition", /* SIGURG */
|
||||
"Suspended (signal)", /* SIGSTOP */
|
||||
"Suspended", /* SIGTSTP */
|
||||
"Continued", /* SIGCONT */
|
||||
"Child exited", /* SIGCHLD */
|
||||
"Stopped (tty input)", /* SIGTTIN */
|
||||
"Stopped (tty output)", /* SIGTTOU */
|
||||
"I/O possible", /* SIGIO */
|
||||
"Cputime limit exceeded", /* SIGXCPU */
|
||||
"Filesize limit exceeded", /* SIGXFSZ */
|
||||
"Virtual timer expired", /* SIGVTALRM */
|
||||
"Profiling timer expired", /* SIGPROF */
|
||||
"Window size changes", /* SIGWINCH */
|
||||
"Information request", /* SIGINFO */
|
||||
"User defined signal 1", /* SIGUSR1 */
|
||||
"User defined signal 2" /* SIGUSR2 */
|
||||
[0] = "Signal 0",
|
||||
[SIGHUP] = "Hangup",
|
||||
[SIGINT] = "Interrupt",
|
||||
[SIGQUIT] = "Quit",
|
||||
[SIGILL] = "Illegal instruction",
|
||||
[SIGTRAP] = "Trace/BPT trap",
|
||||
[SIGABRT] = "Abort trap",
|
||||
[SIGEMT] = "EMT trap",
|
||||
[SIGFPE] = "Floating point exception",
|
||||
[SIGKILL] = "Killed",
|
||||
[SIGBUS] = "Bus error",
|
||||
[SIGSEGV] = "Segmentation fault",
|
||||
[SIGSYS] = "Bad system call",
|
||||
[SIGPIPE] = "Broken pipe",
|
||||
[SIGALRM] = "Alarm clock",
|
||||
[SIGTERM] = "Terminated",
|
||||
[SIGURG] = "Urgent I/O condition",
|
||||
[SIGSTOP] = "Suspended (signal)",
|
||||
[SIGTSTP] = "Suspended",
|
||||
[SIGCONT] = "Continued",
|
||||
[SIGCHLD] = "Child exited",
|
||||
[SIGTTIN] = "Stopped (tty input)",
|
||||
[SIGTTOU] = "Stopped (tty output)",
|
||||
[SIGIO] = "I/O possible",
|
||||
[SIGXCPU] = "Cputime limit exceeded",
|
||||
[SIGXFSZ] = "Filesize limit exceeded",
|
||||
[SIGVTALRM] = "Virtual timer expired",
|
||||
[SIGPROF] = "Profiling timer expired",
|
||||
[SIGWINCH] = "Window size changes",
|
||||
[SIGINFO] = "Information request",
|
||||
[SIGUSR1] = "User defined signal 1",
|
||||
[SIGUSR2] = "User defined signal 2",
|
||||
};
|
||||
const int sys_nsig = sizeof(sys_siglist) / sizeof(sys_siglist[0]);
|
||||
|
|
|
@ -47,11 +47,16 @@ fgetwln_l(FILE * __restrict fp, size_t *lenp, locale_t locale)
|
|||
{
|
||||
wint_t wc;
|
||||
size_t len;
|
||||
int savserr;
|
||||
|
||||
FIX_LOCALE(locale);
|
||||
|
||||
FLOCKFILE(fp);
|
||||
ORIENT(fp, 1);
|
||||
|
||||
savserr = fp->_flags & __SERR;
|
||||
fp->_flags &= ~__SERR;
|
||||
|
||||
len = 0;
|
||||
while ((wc = __fgetwc(fp, locale)) != WEOF) {
|
||||
#define GROW 512
|
||||
|
@ -64,7 +69,12 @@ fgetwln_l(FILE * __restrict fp, size_t *lenp, locale_t locale)
|
|||
if (wc == L'\n')
|
||||
break;
|
||||
}
|
||||
if (len == 0 || (wc == WEOF && !__sfeof(fp)))
|
||||
/* fgetwc(3) may set both __SEOF and __SERR at once. */
|
||||
if (__sferror(fp))
|
||||
goto error;
|
||||
|
||||
fp->_flags |= savserr;
|
||||
if (len == 0)
|
||||
goto error;
|
||||
|
||||
FUNLOCKFILE(fp);
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
# $FreeBSD$
|
||||
|
||||
PACKAGE= lib${LIB}
|
||||
LIB= ifc
|
||||
LIB= ifconfig
|
||||
# Don't build shared library, for now.
|
||||
NO_PIC=
|
||||
|
||||
SHLIBDIR?= /lib
|
||||
SHLIB_MAJOR= 1
|
||||
SRCS= libifc.c libifc_internal.c
|
||||
SRCS= libifconfig.c libifconfig_internal.c
|
||||
|
||||
INCSDIR= ${INCLUDEDIR}
|
||||
INCS= libifc.h
|
||||
INCS= libifconfig.h
|
||||
|
||||
#MAN= libifco.3
|
||||
#MAN= libifconfig.3
|
||||
|
||||
CFLAGS+= -I${.CURDIR}
|
||||
WARNS?=6
|
|
@ -71,16 +71,16 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libifc.h"
|
||||
#include "libifc_internal.h"
|
||||
#include "libifconfig.h"
|
||||
#include "libifconfig_internal.h"
|
||||
|
||||
|
||||
libifc_handle_t *
|
||||
libifc_open(void)
|
||||
ifconfig_handle_t *
|
||||
ifconfig_open(void)
|
||||
{
|
||||
struct libifc_handle *h;
|
||||
struct ifconfig_handle *h;
|
||||
|
||||
h = calloc(1, sizeof(struct libifc_handle));
|
||||
h = calloc(1, sizeof(struct ifconfig_handle));
|
||||
|
||||
for (int i = 0; i <= AF_MAX; i++) {
|
||||
h->sockets[i] = -1;
|
||||
|
@ -91,7 +91,7 @@ libifc_open(void)
|
|||
|
||||
|
||||
void
|
||||
libifc_close(libifc_handle_t *h)
|
||||
ifconfig_close(ifconfig_handle_t *h)
|
||||
{
|
||||
for (int i = 0; i <= AF_MAX; i++) {
|
||||
if (h->sockets[i] != -1) {
|
||||
|
@ -102,29 +102,29 @@ libifc_close(libifc_handle_t *h)
|
|||
}
|
||||
|
||||
|
||||
libifc_errtype
|
||||
libifc_err_errtype(libifc_handle_t *h)
|
||||
ifconfig_errtype
|
||||
ifconfig_err_errtype(ifconfig_handle_t *h)
|
||||
{
|
||||
return (h->error.errtype);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
libifc_err_errno(libifc_handle_t *h)
|
||||
ifconfig_err_errno(ifconfig_handle_t *h)
|
||||
{
|
||||
return (h->error.errcode);
|
||||
}
|
||||
|
||||
|
||||
unsigned long
|
||||
libifc_err_ioctlreq(libifc_handle_t *h)
|
||||
ifconfig_err_ioctlreq(ifconfig_handle_t *h)
|
||||
{
|
||||
return (h->error.ioctl_request);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
libifc_get_description(libifc_handle_t *h, const char *name, char **description)
|
||||
ifconfig_get_description(ifconfig_handle_t *h, const char *name, char **description)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
char *descr = NULL;
|
||||
|
@ -141,7 +141,7 @@ libifc_get_description(libifc_handle_t *h, const char *name, char **description)
|
|||
|
||||
ifr.ifr_buffer.buffer = descr;
|
||||
ifr.ifr_buffer.length = descrlen;
|
||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCGIFDESCR,
|
||||
if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFDESCR,
|
||||
&ifr) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ libifc_get_description(libifc_handle_t *h, const char *name, char **description)
|
|||
|
||||
|
||||
int
|
||||
libifc_set_description(libifc_handle_t *h, const char *name,
|
||||
ifconfig_set_description(ifconfig_handle_t *h, const char *name,
|
||||
const char *newdescription)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
@ -180,7 +180,7 @@ libifc_set_description(libifc_handle_t *h, const char *name,
|
|||
* TODO: Decide whether this should be an error condition instead.
|
||||
*/
|
||||
if (desclen == 0) {
|
||||
return (libifc_unset_description(h, name));
|
||||
return (ifconfig_unset_description(h, name));
|
||||
}
|
||||
|
||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
||||
|
@ -193,7 +193,7 @@ libifc_set_description(libifc_handle_t *h, const char *name,
|
|||
return (-1);
|
||||
}
|
||||
|
||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, &ifr) != 0) {
|
||||
if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, &ifr) != 0) {
|
||||
free(ifr.ifr_buffer.buffer);
|
||||
return (-1);
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ libifc_set_description(libifc_handle_t *h, const char *name,
|
|||
}
|
||||
|
||||
|
||||
int libifc_unset_description(libifc_handle_t *h, const char *name)
|
||||
int ifconfig_unset_description(ifconfig_handle_t *h, const char *name)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
|
@ -211,14 +211,14 @@ int libifc_unset_description(libifc_handle_t *h, const char *name)
|
|||
ifr.ifr_buffer.length = 0;
|
||||
ifr.ifr_buffer.buffer = NULL;
|
||||
|
||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, &ifr) < 0) {
|
||||
if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, &ifr) < 0) {
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int libifc_set_name(libifc_handle_t *h, const char *name, const char *newname)
|
||||
int ifconfig_set_name(ifconfig_handle_t *h, const char *name, const char *newname)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
char *tmpname;
|
||||
|
@ -234,7 +234,7 @@ int libifc_set_name(libifc_handle_t *h, const char *name, const char *newname)
|
|||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
||||
ifr.ifr_data = tmpname;
|
||||
|
||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCSIFNAME, &ifr) != 0) {
|
||||
if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFNAME, &ifr) != 0) {
|
||||
free(tmpname);
|
||||
return (-1);
|
||||
}
|
||||
|
@ -243,27 +243,27 @@ int libifc_set_name(libifc_handle_t *h, const char *name, const char *newname)
|
|||
}
|
||||
|
||||
|
||||
int libifc_set_mtu(libifc_handle_t *h, const char *name, const int mtu)
|
||||
int ifconfig_set_mtu(ifconfig_handle_t *h, const char *name, const int mtu)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
memset(&ifr, 0, sizeof(struct ifreq));
|
||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
||||
ifr.ifr_mtu = mtu;
|
||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCSIFMTU, &ifr) < 0) {
|
||||
if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMTU, &ifr) < 0) {
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int libifc_get_mtu(libifc_handle_t *h, const char *name, int *mtu)
|
||||
int ifconfig_get_mtu(ifconfig_handle_t *h, const char *name, int *mtu)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
memset(&ifr, 0, sizeof(struct ifreq));
|
||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCGIFMTU, &ifr) == -1) {
|
||||
if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMTU, &ifr) == -1) {
|
||||
return (-1);
|
||||
}
|
||||
*mtu = ifr.ifr_mtu;
|
||||
|
@ -271,27 +271,27 @@ int libifc_get_mtu(libifc_handle_t *h, const char *name, int *mtu)
|
|||
}
|
||||
|
||||
|
||||
int libifc_set_metric(libifc_handle_t *h, const char *name, const int mtu)
|
||||
int ifconfig_set_metric(ifconfig_handle_t *h, const char *name, const int mtu)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
memset(&ifr, 0, sizeof(struct ifreq));
|
||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
||||
ifr.ifr_mtu = mtu;
|
||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCSIFMETRIC, &ifr) < 0) {
|
||||
if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMETRIC, &ifr) < 0) {
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int libifc_get_metric(libifc_handle_t *h, const char *name, int *metric)
|
||||
int ifconfig_get_metric(ifconfig_handle_t *h, const char *name, int *metric)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
memset(&ifr, 0, sizeof(struct ifreq));
|
||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCGIFMETRIC, &ifr) == -1) {
|
||||
if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMETRIC, &ifr) == -1) {
|
||||
return (-1);
|
||||
}
|
||||
*metric = ifr.ifr_metric;
|
||||
|
@ -299,16 +299,16 @@ int libifc_get_metric(libifc_handle_t *h, const char *name, int *metric)
|
|||
}
|
||||
|
||||
|
||||
int libifc_set_capability(libifc_handle_t *h, const char *name,
|
||||
int ifconfig_set_capability(ifconfig_handle_t *h, const char *name,
|
||||
const int capability)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct libifc_capabilities ifcap;
|
||||
struct ifconfig_capabilities ifcap;
|
||||
int flags;
|
||||
int value;
|
||||
|
||||
memset(&ifr, 0, sizeof(struct ifreq));
|
||||
if (libifc_get_capability(h, name, &ifcap) != 0) {
|
||||
if (ifconfig_get_capability(h, name, &ifcap) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
@ -329,22 +329,22 @@ int libifc_set_capability(libifc_handle_t *h, const char *name,
|
|||
* set for this request.
|
||||
*/
|
||||
ifr.ifr_reqcap = flags;
|
||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCSIFCAP, &ifr) < 0) {
|
||||
if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFCAP, &ifr) < 0) {
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int libifc_get_capability(libifc_handle_t *h, const char *name,
|
||||
struct libifc_capabilities *capability)
|
||||
int ifconfig_get_capability(ifconfig_handle_t *h, const char *name,
|
||||
struct ifconfig_capabilities *capability)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
memset(&ifr, 0, sizeof(struct ifreq));
|
||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
||||
|
||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCGIFCAP, &ifr) < 0) {
|
||||
if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFCAP, &ifr) < 0) {
|
||||
return (-1);
|
||||
}
|
||||
capability->curcap = ifr.ifr_curcap;
|
||||
|
@ -353,21 +353,21 @@ int libifc_get_capability(libifc_handle_t *h, const char *name,
|
|||
}
|
||||
|
||||
|
||||
int libifc_destroy_interface(libifc_handle_t *h, const char *name)
|
||||
int ifconfig_destroy_interface(ifconfig_handle_t *h, const char *name)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
memset(&ifr, 0, sizeof(struct ifreq));
|
||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
||||
|
||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCIFDESTROY, &ifr) < 0) {
|
||||
if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFDESTROY, &ifr) < 0) {
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int libifc_create_interface(libifc_handle_t *h, const char *name, char **ifname)
|
||||
int ifconfig_create_interface(ifconfig_handle_t *h, const char *name, char **ifname)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
|
@ -389,7 +389,7 @@ int libifc_create_interface(libifc_handle_t *h, const char *name, char **ifname)
|
|||
|
||||
/* No special handling for this interface type. */
|
||||
|
||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) {
|
||||
if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) {
|
||||
return (-1);
|
||||
}
|
||||
*ifname = strdup(ifr.ifr_name);
|
|
@ -34,16 +34,16 @@
|
|||
|
||||
typedef enum {
|
||||
OTHER, IOCTL, SOCKET
|
||||
} libifc_errtype;
|
||||
} ifconfig_errtype;
|
||||
|
||||
/*
|
||||
* Opaque definition so calling application can just pass a
|
||||
* pointer to it for library use.
|
||||
*/
|
||||
struct libifc_handle;
|
||||
typedef struct libifc_handle libifc_handle_t;
|
||||
struct ifconfig_handle;
|
||||
typedef struct ifconfig_handle ifconfig_handle_t;
|
||||
|
||||
struct libifc_capabilities {
|
||||
struct ifconfig_capabilities {
|
||||
/** Current capabilities (ifconfig prints this as 'options')*/
|
||||
int curcap;
|
||||
/** Requested capabilities (ifconfig prints this as 'capabilities')*/
|
||||
|
@ -55,57 +55,57 @@ struct libifc_capabilities {
|
|||
* Example usage:
|
||||
*{@code
|
||||
* // Create state object
|
||||
* libifc_handle_t *lifh = libifc_open();
|
||||
* ifconfig_handle_t *lifh = ifconfig_open();
|
||||
*
|
||||
* // Do stuff with it
|
||||
*
|
||||
* // Dispose of the state object
|
||||
* libifc_close(lifh);
|
||||
* ifconfig_close(lifh);
|
||||
* lifh = NULL;
|
||||
*}
|
||||
*/
|
||||
libifc_handle_t *libifc_open(void);
|
||||
ifconfig_handle_t *ifconfig_open(void);
|
||||
|
||||
/** Frees resources held in the provided state object.
|
||||
* @param h The state object to close.
|
||||
* @see #libifc_open(void)
|
||||
* @see #ifconfig_open(void)
|
||||
*/
|
||||
void libifc_close(libifc_handle_t *h);
|
||||
void ifconfig_close(ifconfig_handle_t *h);
|
||||
|
||||
/** Identifies what kind of error occured. */
|
||||
libifc_errtype libifc_err_errtype(libifc_handle_t *h);
|
||||
ifconfig_errtype ifconfig_err_errtype(ifconfig_handle_t *h);
|
||||
|
||||
/** Retrieves the errno associated with the error, if any. */
|
||||
int libifc_err_errno(libifc_handle_t *h);
|
||||
int ifconfig_err_errno(ifconfig_handle_t *h);
|
||||
|
||||
/** If error type was IOCTL, this identifies which request failed. */
|
||||
unsigned long libifc_err_ioctlreq(libifc_handle_t *h);
|
||||
unsigned long ifconfig_err_ioctlreq(ifconfig_handle_t *h);
|
||||
|
||||
int libifc_get_description(libifc_handle_t *h, const char *name,
|
||||
int ifconfig_get_description(ifconfig_handle_t *h, const char *name,
|
||||
char **description);
|
||||
int libifc_set_description(libifc_handle_t *h, const char *name,
|
||||
int ifconfig_set_description(ifconfig_handle_t *h, const char *name,
|
||||
const char *newdescription);
|
||||
int libifc_unset_description(libifc_handle_t *h, const char *name);
|
||||
int libifc_set_name(libifc_handle_t *h, const char *name, const char *newname);
|
||||
int libifc_set_mtu(libifc_handle_t *h, const char *name, const int mtu);
|
||||
int libifc_get_mtu(libifc_handle_t *h, const char *name, int *mtu);
|
||||
int ifconfig_unset_description(ifconfig_handle_t *h, const char *name);
|
||||
int ifconfig_set_name(ifconfig_handle_t *h, const char *name, const char *newname);
|
||||
int ifconfig_set_mtu(ifconfig_handle_t *h, const char *name, const int mtu);
|
||||
int ifconfig_get_mtu(ifconfig_handle_t *h, const char *name, int *mtu);
|
||||
|
||||
int libifc_set_metric(libifc_handle_t *h, const char *name, const int metric);
|
||||
int libifc_get_metric(libifc_handle_t *h, const char *name, int *metric);
|
||||
int ifconfig_set_metric(ifconfig_handle_t *h, const char *name, const int metric);
|
||||
int ifconfig_get_metric(ifconfig_handle_t *h, const char *name, int *metric);
|
||||
|
||||
int libifc_set_capability(libifc_handle_t *h, const char *name,
|
||||
int ifconfig_set_capability(ifconfig_handle_t *h, const char *name,
|
||||
const int capability);
|
||||
int libifc_get_capability(libifc_handle_t *h, const char *name,
|
||||
struct libifc_capabilities *capability);
|
||||
int ifconfig_get_capability(ifconfig_handle_t *h, const char *name,
|
||||
struct ifconfig_capabilities *capability);
|
||||
|
||||
/** Destroy a virtual interface
|
||||
* @param name Interface to destroy
|
||||
*/
|
||||
int libifc_destroy_interface(libifc_handle_t *h, const char *name);
|
||||
int ifconfig_destroy_interface(ifconfig_handle_t *h, const char *name);
|
||||
|
||||
/** Creates a (virtual) interface
|
||||
* @param name Name of interface to create. Example: bridge or bridge42
|
||||
* @param name ifname Is set to actual name of created interface
|
||||
*/
|
||||
int libifc_create_interface(libifc_handle_t *h, const char *name,
|
||||
int ifconfig_create_interface(ifconfig_handle_t *h, const char *name,
|
||||
char **ifname);
|
|
@ -40,11 +40,11 @@
|
|||
#include <unistd.h>
|
||||
|
||||
|
||||
#include "libifc.h" // Needed for libifc_errstate
|
||||
#include "libifc_internal.h"
|
||||
#include "libifconfig.h" // Needed for ifconfig_errstate
|
||||
#include "libifconfig_internal.h"
|
||||
|
||||
int
|
||||
libifc_ioctlwrap_ret(libifc_handle_t *h, unsigned long request, int rcode)
|
||||
ifconfig_ioctlwrap_ret(ifconfig_handle_t *h, unsigned long request, int rcode)
|
||||
{
|
||||
if (rcode != 0) {
|
||||
h->error.errtype = IOCTL;
|
||||
|
@ -56,17 +56,17 @@ libifc_ioctlwrap_ret(libifc_handle_t *h, unsigned long request, int rcode)
|
|||
|
||||
|
||||
int
|
||||
libifc_ioctlwrap(libifc_handle_t *h, const int addressfamily,
|
||||
ifconfig_ioctlwrap(ifconfig_handle_t *h, const int addressfamily,
|
||||
unsigned long request, struct ifreq *ifr)
|
||||
{
|
||||
int s;
|
||||
|
||||
if (libifc_socket(h, addressfamily, &s) != 0) {
|
||||
if (ifconfig_socket(h, addressfamily, &s) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int rcode = ioctl(s, request, ifr);
|
||||
return (libifc_ioctlwrap_ret(h, request, rcode));
|
||||
return (ifconfig_ioctlwrap_ret(h, request, rcode));
|
||||
}
|
||||
|
||||
|
||||
|
@ -74,7 +74,7 @@ libifc_ioctlwrap(libifc_handle_t *h, const int addressfamily,
|
|||
* Function to get socket for the specified address family.
|
||||
* If the socket doesn't already exist, attempt to create it.
|
||||
*/
|
||||
int libifc_socket(libifc_handle_t *h, const int addressfamily, int *s)
|
||||
int ifconfig_socket(ifconfig_handle_t *h, const int addressfamily, int *s)
|
||||
{
|
||||
if (addressfamily > AF_MAX) {
|
||||
h->error.errtype = SOCKET;
|
|
@ -32,14 +32,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "libifc.h"
|
||||
#include "libifconfig.h"
|
||||
|
||||
|
||||
struct errstate {
|
||||
/**
|
||||
* Type of error.
|
||||
*/
|
||||
libifc_errtype errtype;
|
||||
ifconfig_errtype errtype;
|
||||
|
||||
/**
|
||||
* The error occured in this ioctl() request.
|
||||
|
@ -53,7 +53,7 @@ struct errstate {
|
|||
int errcode;
|
||||
};
|
||||
|
||||
struct libifc_handle {
|
||||
struct ifconfig_handle {
|
||||
struct errstate error;
|
||||
int sockets[AF_MAX + 1];
|
||||
};
|
||||
|
@ -69,7 +69,7 @@ struct libifc_handle {
|
|||
* {@code
|
||||
* static void myfunc() \{
|
||||
* int s;
|
||||
* if (libifc_socket(AF_LOCAL, &s) != 0) \{
|
||||
* if (ifconfig_socket(AF_LOCAL, &s) != 0) \{
|
||||
* // Handle error state here
|
||||
* \}
|
||||
* // user code here
|
||||
|
@ -77,11 +77,11 @@ struct libifc_handle {
|
|||
* }
|
||||
* }
|
||||
*/
|
||||
int libifc_socket(libifc_handle_t *h, const int addressfamily, int *s);
|
||||
int ifconfig_socket(ifconfig_handle_t *h, const int addressfamily, int *s);
|
||||
|
||||
/** Function used by other wrapper functions to populate _errstate when appropriate.*/
|
||||
int libifc_ioctlwrap_ret(libifc_handle_t *h, unsigned long request, int rcode);
|
||||
int ifconfig_ioctlwrap_ret(ifconfig_handle_t *h, unsigned long request, int rcode);
|
||||
|
||||
/** Function to wrap ioctl() and automatically populate libifc_errstate when appropriate.*/
|
||||
int libifc_ioctlwrap(libifc_handle_t *h, const int addressfamily,
|
||||
/** Function to wrap ioctl() and automatically populate ifconfig_errstate when appropriate.*/
|
||||
int ifconfig_ioctlwrap(ifconfig_handle_t *h, const int addressfamily,
|
||||
unsigned long request, struct ifreq *ifr);
|
|
@ -176,6 +176,12 @@ libusb20_tr_open_stream(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
|
|||
return (LIBUSB20_ERROR_BUSY);
|
||||
if (MaxFrameCount & LIBUSB20_MAX_FRAME_PRE_SCALE) {
|
||||
MaxFrameCount &= ~LIBUSB20_MAX_FRAME_PRE_SCALE;
|
||||
/*
|
||||
* The kernel can setup 8 times more frames when
|
||||
* pre-scaling ISOCHRONOUS transfers. Make sure the
|
||||
* length and pointer buffers are big enough:
|
||||
*/
|
||||
MaxFrameCount *= 8;
|
||||
pre_scale = 1;
|
||||
} else {
|
||||
pre_scale = 0;
|
||||
|
@ -200,8 +206,13 @@ libusb20_tr_open_stream(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
|
|||
}
|
||||
memset(xfer->ppBuffer, 0, size);
|
||||
|
||||
error = xfer->pdev->methods->tr_open(xfer, MaxBufSize,
|
||||
MaxFrameCount, ep_no, stream_id, pre_scale);
|
||||
if (pre_scale) {
|
||||
error = xfer->pdev->methods->tr_open(xfer, MaxBufSize,
|
||||
MaxFrameCount / 8, ep_no, stream_id, 1);
|
||||
} else {
|
||||
error = xfer->pdev->methods->tr_open(xfer, MaxBufSize,
|
||||
MaxFrameCount, ep_no, stream_id, 0);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
free(xfer->ppBuffer);
|
||||
|
|
|
@ -427,7 +427,6 @@ test_large(void)
|
|||
test_odd_tol(ctanh, z,
|
||||
CMPLXL(1.0, 8.95257245135025991216632140458264468e-309L),
|
||||
DBL_ULP());
|
||||
#if !defined(__i386__)
|
||||
z = CMPLXL(30, 0x1p1023L);
|
||||
test_odd_tol(ctanh, z,
|
||||
CMPLXL(1.0, -1.62994325413993477997492170229268382e-26L),
|
||||
|
@ -437,7 +436,6 @@ test_large(void)
|
|||
CMPLXL(0.878606311888306869546254022621986509L,
|
||||
-0.225462792499754505792678258169527424L),
|
||||
DBL_ULP());
|
||||
#endif
|
||||
|
||||
z = CMPLXL(710.6, 0.78539816339744830961566084581987572L);
|
||||
test_odd_tol(csinh, z,
|
||||
|
@ -475,8 +473,12 @@ main(int argc, char *argv[])
|
|||
test_small();
|
||||
printf("ok 5 - ctrig small\n");
|
||||
|
||||
#if defined(__i386__)
|
||||
printf("ok 6 # SKIP ctrig large # fails on i386 because of bug 205446\n");
|
||||
#else
|
||||
test_large();
|
||||
printf("ok 6 - ctrig large\n");
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
|
@ -1098,9 +1098,6 @@
|
|||
|
||||
<para>[&arch.i386;] STB 4 port card using shared IRQ</para>
|
||||
|
||||
<para>[&arch.i386;] DigiBoard intelligent serial cards (digi
|
||||
driver)</para>
|
||||
|
||||
<para>[&arch.amd64;, &arch.i386;] PCI-Based multi-port serial
|
||||
boards (&man.puc.4; driver)</para>
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ DIRDEPS = \
|
|||
usr.bin/lex/lib \
|
||||
usr.bin/yacc.host \
|
||||
usr.sbin/crunch/crunchgen.host \
|
||||
usr.sbin/crunch/crunchide.host \
|
||||
|
||||
|
||||
.include <dirdeps.mk>
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
# $FreeBSD$
|
||||
|
||||
default:
|
||||
$(CC) -Wall -fPIC -lifc -g -o example_setdescription setdescription.c
|
||||
$(CC) -Wall -fPIC -lifc -g -o example_setmtu setmtu.c
|
||||
$(CC) -Wall -fPIC -lifc -g -o example_ifdestroy ifdestroy.c
|
||||
$(CC) -Wall -fPIC -lifc -g -o example_ifcreate ifcreate.c
|
||||
clean:
|
||||
rm -f example_*
|
8
share/examples/libifconfig/Makefile
Normal file
8
share/examples/libifconfig/Makefile
Normal file
|
@ -0,0 +1,8 @@
|
|||
# $FreeBSD$
|
||||
default:
|
||||
$(CC) -Wall -fPIC -lifconfig -g -o example_setdescription setdescription.c
|
||||
$(CC) -Wall -fPIC -lifconfig -g -o example_setmtu setmtu.c
|
||||
$(CC) -Wall -fPIC -lifconfig -g -o example_ifdestroy ifdestroy.c
|
||||
$(CC) -Wall -fPIC -lifconfig -g -o example_ifcreate ifcreate.c
|
||||
clean:
|
||||
rm -f example_*
|
|
@ -37,7 +37,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libifc.h>
|
||||
#include <libifconfig.h>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
@ -55,21 +55,21 @@ int main(int argc, char *argv[])
|
|||
|
||||
printf("Requested interface name: %s\n", ifname);
|
||||
|
||||
libifc_handle_t *lifh = libifc_open();
|
||||
if (libifc_create_interface(lifh, ifname, &ifactualname) == 0) {
|
||||
ifconfig_handle_t *lifh = ifconfig_open();
|
||||
if (ifconfig_create_interface(lifh, ifname, &ifactualname) == 0) {
|
||||
printf("Successfully created interface '%s'\n", ifactualname);
|
||||
libifc_close(lifh);
|
||||
ifconfig_close(lifh);
|
||||
lifh = NULL;
|
||||
free(ifname);
|
||||
free(ifactualname);
|
||||
return (0);
|
||||
} else {
|
||||
switch (libifc_err_errtype(lifh)) {
|
||||
switch (ifconfig_err_errtype(lifh)) {
|
||||
case SOCKET:
|
||||
warnx("couldn't create socket. This shouldn't happen.\n");
|
||||
break;
|
||||
case IOCTL:
|
||||
if (libifc_err_ioctlreq(lifh) == SIOCIFCREATE2) {
|
||||
if (ifconfig_err_ioctlreq(lifh) == SIOCIFCREATE2) {
|
||||
warnx(
|
||||
"Failed to create interface (SIOCIFCREATE2)\n");
|
||||
}
|
||||
|
@ -79,12 +79,12 @@ int main(int argc, char *argv[])
|
|||
"This is a thorough example accommodating for temporary"
|
||||
" 'not implemented yet' errors. That's likely what happened"
|
||||
" now. If not, your guess is as good as mine. ;)"
|
||||
" Error code: %d\n", libifc_err_errno(
|
||||
" Error code: %d\n", ifconfig_err_errno(
|
||||
lifh));
|
||||
break;
|
||||
}
|
||||
|
||||
libifc_close(lifh);
|
||||
ifconfig_close(lifh);
|
||||
lifh = NULL;
|
||||
free(ifname);
|
||||
free(ifactualname);
|
|
@ -37,7 +37,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libifc.h>
|
||||
#include <libifconfig.h>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
@ -55,20 +55,20 @@ int main(int argc, char *argv[])
|
|||
|
||||
printf("Interface name: %s\n", ifname);
|
||||
|
||||
libifc_handle_t *lifh = libifc_open();
|
||||
if (libifc_destroy_interface(lifh, ifname) == 0) {
|
||||
ifconfig_handle_t *lifh = ifconfig_open();
|
||||
if (ifconfig_destroy_interface(lifh, ifname) == 0) {
|
||||
printf("Successfully destroyed interface '%s'.", ifname);
|
||||
libifc_close(lifh);
|
||||
ifconfig_close(lifh);
|
||||
lifh = NULL;
|
||||
free(ifname);
|
||||
return (0);
|
||||
} else {
|
||||
switch (libifc_err_errtype(lifh)) {
|
||||
switch (ifconfig_err_errtype(lifh)) {
|
||||
case SOCKET:
|
||||
warnx("couldn't create socket. This shouldn't happen.\n");
|
||||
break;
|
||||
case IOCTL:
|
||||
if (libifc_err_ioctlreq(lifh) == SIOCIFDESTROY) {
|
||||
if (ifconfig_err_ioctlreq(lifh) == SIOCIFDESTROY) {
|
||||
warnx(
|
||||
"Failed to destroy interface (SIOCIFDESTROY)\n");
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ int main(int argc, char *argv[])
|
|||
break;
|
||||
}
|
||||
|
||||
libifc_close(lifh);
|
||||
ifconfig_close(lifh);
|
||||
lifh = NULL;
|
||||
free(ifname);
|
||||
return (-1);
|
|
@ -35,7 +35,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libifc.h>
|
||||
#include <libifconfig.h>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
@ -54,27 +54,27 @@ int main(int argc, char *argv[])
|
|||
|
||||
printf("Interface name: %s\n", ifname);
|
||||
|
||||
libifc_handle_t *lifh = libifc_open();
|
||||
if (libifc_get_description(lifh, ifname, &curdescr) == 0) {
|
||||
ifconfig_handle_t *lifh = ifconfig_open();
|
||||
if (ifconfig_get_description(lifh, ifname, &curdescr) == 0) {
|
||||
printf("Old description: %s\n", curdescr);
|
||||
}
|
||||
|
||||
printf("New description: %s\n\n", ifdescr);
|
||||
|
||||
if (libifc_set_description(lifh, ifname, ifdescr) == 0) {
|
||||
if (ifconfig_set_description(lifh, ifname, ifdescr) == 0) {
|
||||
printf("New description successfully set.\n");
|
||||
} else {
|
||||
switch (libifc_err_errtype(lifh)) {
|
||||
switch (ifconfig_err_errtype(lifh)) {
|
||||
case SOCKET:
|
||||
err(libifc_err_errno(lifh), "Socket error");
|
||||
err(ifconfig_err_errno(lifh), "Socket error");
|
||||
break;
|
||||
case IOCTL:
|
||||
err(libifc_err_errno(
|
||||
err(ifconfig_err_errno(
|
||||
lifh), "IOCTL(%lu) error",
|
||||
libifc_err_ioctlreq(lifh));
|
||||
ifconfig_err_ioctlreq(lifh));
|
||||
break;
|
||||
case OTHER:
|
||||
err(libifc_err_errno(lifh), "Other error");
|
||||
err(ifconfig_err_errno(lifh), "Other error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -86,6 +86,6 @@ int main(int argc, char *argv[])
|
|||
ifdescr = NULL;
|
||||
curdescr = NULL;
|
||||
|
||||
libifc_close(lifh);
|
||||
ifconfig_close(lifh);
|
||||
return (0);
|
||||
}
|
|
@ -37,7 +37,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libifc.h>
|
||||
#include <libifconfig.h>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
@ -58,26 +58,26 @@ int main(int argc, char *argv[])
|
|||
printf("Interface name: %s\n", ifname);
|
||||
printf("New MTU: %d", mtu);
|
||||
|
||||
libifc_handle_t *lifh = libifc_open();
|
||||
if (libifc_set_mtu(lifh, ifname, mtu) == 0) {
|
||||
ifconfig_handle_t *lifh = ifconfig_open();
|
||||
if (ifconfig_set_mtu(lifh, ifname, mtu) == 0) {
|
||||
printf("Successfully changed MTU of %s to %d\n", ifname, mtu);
|
||||
libifc_close(lifh);
|
||||
ifconfig_close(lifh);
|
||||
lifh = NULL;
|
||||
free(ifname);
|
||||
return (0);
|
||||
} else {
|
||||
switch (libifc_err_errtype(lifh)) {
|
||||
switch (ifconfig_err_errtype(lifh)) {
|
||||
case SOCKET:
|
||||
warnx("couldn't create socket. This shouldn't happen.\n");
|
||||
break;
|
||||
case IOCTL:
|
||||
if (libifc_err_ioctlreq(lifh) == SIOCSIFMTU) {
|
||||
if (ifconfig_err_ioctlreq(lifh) == SIOCSIFMTU) {
|
||||
warnx("Failed to set MTU (SIOCSIFMTU)\n");
|
||||
} else {
|
||||
warnx(
|
||||
"Failed to set MTU due to error in unexpected ioctl() call %lu. Error code: %i.\n",
|
||||
libifc_err_ioctlreq(lifh),
|
||||
libifc_err_errno(lifh));
|
||||
ifconfig_err_ioctlreq(lifh),
|
||||
ifconfig_err_errno(lifh));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -86,7 +86,7 @@ int main(int argc, char *argv[])
|
|||
break;
|
||||
}
|
||||
|
||||
libifc_close(lifh);
|
||||
ifconfig_close(lifh);
|
||||
lifh = NULL;
|
||||
free(ifname);
|
||||
return (-1);
|
|
@ -122,7 +122,6 @@ MAN= aac.4 \
|
|||
ddb.4 \
|
||||
de.4 \
|
||||
devctl.4 \
|
||||
digi.4 \
|
||||
disc.4 \
|
||||
divert.4 \
|
||||
${_dpms.4} \
|
||||
|
|
|
@ -1,377 +0,0 @@
|
|||
.\" Copyright (c) 1990, 1991 The Regents of the University of California.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software contributed to Berkeley by
|
||||
.\" the Systems Programming Group of the University of Utah Computer
|
||||
.\" Science Department.
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" from: @(#)dca.4 5.2 (Berkeley) 3/27/91
|
||||
.\" from: com.4,v 1.1 1993/08/06 11:19:07 cgd Exp
|
||||
.\" from: sio.4,v 1.15 1994/12/06 20:14:30 bde Exp
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd December 7, 2003
|
||||
.Dt DIGI 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm digi
|
||||
.Nd DigiBoard intelligent serial cards driver
|
||||
.Sh SYNOPSIS
|
||||
.Cd "device digi"
|
||||
.Pp
|
||||
This man page was originally written for the dgb driver, and should
|
||||
likely be gone over with a fine tooth comb to reflect differences
|
||||
with the digi driver.
|
||||
.Pp
|
||||
When not defined the number is computed:
|
||||
.Bd -ragged -offset 4n
|
||||
default
|
||||
.Dv NDGBPORTS
|
||||
= number_of_described_DigiBoard_cards * 16
|
||||
.Ed
|
||||
.Pp
|
||||
If it is less than the actual number of ports
|
||||
the system will be able to use only the
|
||||
first
|
||||
.Dv NDGBPORTS
|
||||
ports.
|
||||
If it is greater then all ports will be usable
|
||||
but some memory will be wasted.
|
||||
.Pp
|
||||
Meaning of
|
||||
.Cm flags :
|
||||
.Bl -tag -width indent -compact
|
||||
.It 0x0001
|
||||
use alternate pinout (exchange DCD and DSR lines)
|
||||
.It 0x0002
|
||||
do not use 8K window mode of PC/Xe
|
||||
.El
|
||||
.Pp
|
||||
Device numbering:
|
||||
.Bd -literal -compact
|
||||
0b\fICC\fPmmmmmmmm\fIOLIPPPPP\fP
|
||||
\fBCC\fPard number
|
||||
\fRmmmmmmmm\fPajor number
|
||||
call\fBO\fPut
|
||||
\fBL\fPock
|
||||
\fBI\fPnitial
|
||||
\fBPPPPP\fPort number
|
||||
.Ed
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
driver provides support for DigiBoard PC/Xe and PC/Xi series intelligent
|
||||
serial multiport cards with asynchronous interfaces based on the
|
||||
.Tn EIA
|
||||
.Tn RS-232C
|
||||
.Pf ( Tn CCITT
|
||||
.Tn V.24 )
|
||||
standard.
|
||||
.Pp
|
||||
Input and output for each line may set to one of following baud rates;
|
||||
50, 75, 110, 134.5, 150, 300, 600, 1200, 1800, 2400, 4800, 9600,
|
||||
19200, 38400, 57600, or for newer versions of cards 115200.
|
||||
.Pp
|
||||
The driver does not use any interrupts, it is
|
||||
.Dq polling-based .
|
||||
This means that
|
||||
it uses clock interrupts instead of interrupts generated by DigiBoard cards and
|
||||
checks the state of cards 25 times per second.
|
||||
This is practical because the
|
||||
DigiBoard cards have large input and output buffers (more than 1Kbyte per
|
||||
port) and hardware that allows efficiently finding the port that needs
|
||||
attention.
|
||||
The only problem seen with this policy is slower
|
||||
SLIP and PPP response.
|
||||
.Pp
|
||||
Each line in the kernel configuration file describes one card, not one port
|
||||
as in the
|
||||
.Xr sio 4
|
||||
driver.
|
||||
.Pp
|
||||
The
|
||||
.Cm flags
|
||||
keyword may be used on each
|
||||
.Dq Li "device dgb"
|
||||
line in the kernel configuration file
|
||||
to change the pinout of the interface or to use new PC/Xe cards
|
||||
which can work with an 8K memory window in compatibility mode
|
||||
(with a 64K memory window).
|
||||
Note
|
||||
that using 8K memory window does not mean shorter input/output buffers, it means
|
||||
only that all buffers will be mapped to the same memory address and switched as
|
||||
needed.
|
||||
.Pp
|
||||
The
|
||||
.Cm port
|
||||
value must be the same
|
||||
as the
|
||||
port
|
||||
set on the card by jumpers.
|
||||
For PC/Xi cards the same rule is applicable to the
|
||||
.Cm iomem
|
||||
value.
|
||||
It must be the same as the memory address set on the card
|
||||
by jumpers.
|
||||
.\"Some documentation gives the address as a ``paragraph'' or ``segment'';
|
||||
.\"you can get the value of address by adding the digit "0" at end of
|
||||
.\"paragraph value, e.g., 0xfc000 -> 0xfc0000.
|
||||
For PC/Xe cards there is no need to use jumpers for this purpose.
|
||||
In fact there are no jumpers to do it.
|
||||
Just
|
||||
write the address you want as the
|
||||
.Cm iomem
|
||||
value in kernel config file and the card will be programmed
|
||||
to use this address.
|
||||
.Pp
|
||||
The same range of memory addresses may be used
|
||||
for all the DigiBoards installed
|
||||
(but not for any other card or real memory).
|
||||
DigiBoards
|
||||
with a large amount of memory (256K or 512K and perhaps
|
||||
even 128K) must be mapped
|
||||
to memory addresses outside of the first megabyte.
|
||||
If the computer
|
||||
has more than 15 megabytes of memory then there is no free address space
|
||||
outside of the first megabyte where such DigiBoards can be mapped.
|
||||
In this case you
|
||||
may need to reduce the amount of memory in the computer.
|
||||
But many machines provide a better solution.
|
||||
They have the ability to
|
||||
.Dq "turn off"
|
||||
the memory in the 16th megabyte (addresses 0xF00000 - 0xFFFFFF)
|
||||
using the
|
||||
BIOS setup.
|
||||
Then the DigiBoard's address space can be set to this
|
||||
.Dq hole .
|
||||
.\" XXX the following should be true for all serial drivers and
|
||||
.\" should not be repeated in the man pages for all serial drivers.
|
||||
.\" It was copied from sio.4. The only changes were s/sio/dgb/g.
|
||||
.Pp
|
||||
Serial ports controlled by the
|
||||
.Nm
|
||||
driver can be used for both
|
||||
.Dq callin
|
||||
and
|
||||
.Dq callout .
|
||||
For each port there is a callin device and a callout device.
|
||||
The minor number of the callout device is 128 higher
|
||||
than that of the corresponding callin port.
|
||||
The callin device is general purpose.
|
||||
Processes opening it normally wait for carrier
|
||||
and for the callout device to become inactive.
|
||||
The callout device is used to steal the port from
|
||||
processes waiting for carrier on the callin device.
|
||||
Processes opening it do not wait for carrier
|
||||
and put any processes waiting for carrier on the callin device into
|
||||
a deeper sleep so that they do not conflict with the callout session.
|
||||
The callout device is abused for handling programs that are supposed
|
||||
to work on general ports and need to open the port without waiting
|
||||
but are too stupid to do so.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
driver also supports an initial-state and a lock-state control
|
||||
device for each of the callin and the callout
|
||||
.Dq data
|
||||
devices.
|
||||
The minor number of the initial-state device is 32 higher
|
||||
than that of the corresponding data device.
|
||||
The minor number of the lock-state device is 64 higher
|
||||
than that of the corresponding data device.
|
||||
The termios settings of a data device are copied
|
||||
from those of the corresponding initial-state device
|
||||
on first opens and are not inherited from previous opens.
|
||||
Use
|
||||
.Xr stty 1
|
||||
in the normal way on the initial-state devices to program
|
||||
initial termios states suitable for your setup.
|
||||
.Pp
|
||||
The lock termios state acts as flags to disable changing
|
||||
the termios state.
|
||||
E.g., to lock a flag variable such as
|
||||
.Dv CRTSCTS ,
|
||||
use
|
||||
.Dq Li "stty crtscts"
|
||||
on the lock-state device.
|
||||
Speeds and special characters
|
||||
may be locked by setting the corresponding value in the lock-state
|
||||
device to any nonzero value.
|
||||
.Pp
|
||||
Correct programs talking to correctly wired external devices
|
||||
.\" XXX change next line in other man pages too, and rewrite this paragraph.
|
||||
work with almost arbitrary initial states and no locking,
|
||||
but other setups may benefit from changing some of the default
|
||||
initial state and locking the state.
|
||||
In particular, the initial states for non (POSIX) standard flags
|
||||
should be set to suit the devices attached and may need to be
|
||||
locked to prevent buggy programs from changing them.
|
||||
E.g.,
|
||||
.Dv CRTSCTS
|
||||
should be locked on for devices that support
|
||||
RTS/CTS handshaking at all times and off for devices that do not
|
||||
support it at all.
|
||||
.Dv CLOCAL
|
||||
should be locked on for devices
|
||||
that do not support carrier.
|
||||
.Dv HUPCL
|
||||
may be locked off if you do not
|
||||
want to hang up for some reason.
|
||||
In general, very bad things happen
|
||||
if something is locked to the wrong state, and things should not
|
||||
be locked for devices that support more than one setting.
|
||||
The
|
||||
.Dv CLOCAL
|
||||
flag on callin ports should be locked off for logins
|
||||
to avoid certain security holes, but this needs to be done by
|
||||
getty if the callin port is used for anything else.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /dev/ttyiD?? -compact
|
||||
.It Pa /dev/ttyD??
|
||||
for callin ports
|
||||
.It Pa /dev/ttyiD??
|
||||
.It Pa /dev/ttylD??
|
||||
corresponding callin initial-state and lock-state devices
|
||||
.Pp
|
||||
.It Pa /dev/cuaD??
|
||||
for callout ports
|
||||
.It Pa /dev/cuaiD??
|
||||
.It Pa /dev/cualD??
|
||||
corresponding callout initial-state and lock-state devices
|
||||
.El
|
||||
.Pp
|
||||
.Bl -tag -width /etc/rc.serial -compact
|
||||
.It Pa /etc/rc.serial
|
||||
examples of setting the initial-state and lock-state devices
|
||||
.El
|
||||
.Pp
|
||||
The first question mark in these device names is short for the
|
||||
card number
|
||||
(a decimal number between 0 and 65535 inclusive).
|
||||
The second question mark is short for the port number
|
||||
(a letter in the range [0-9a-v]).
|
||||
.Sh DIAGNOSTICS
|
||||
You may enable extended diagnostics by defining DEBUG at the
|
||||
start of the source file
|
||||
.Pa dgb.c .
|
||||
.Bl -diag
|
||||
.It dgb\fIX\fP: warning: address \fIN\fP truncated to \fIM\fP
|
||||
The memory address for the PC/Xe's 8K window is misaligned (it should be
|
||||
on an 8K boundary) or outside of the first megabyte.
|
||||
.It dgb\fIX\fP: 1st reset failed
|
||||
Problems with accessing I/O port of the card, probably
|
||||
the wrong
|
||||
.Cm port
|
||||
value is specified in the kernel config file.
|
||||
.It dgb\fIX\fP: 2nd reset failed
|
||||
Problems with hardware.
|
||||
.It dgb\fIX\fP: \fIN\fP[st,nd,rd,th] memory test failed
|
||||
Problems with accessing the memory of the card, probably
|
||||
the wrong
|
||||
.Cm iomem
|
||||
value is specified in the kernel config file.
|
||||
.It dgb\fIX\fP: BIOS start failed
|
||||
Problems with starting the on-board BIOS.
|
||||
Probably the memory addresses of the
|
||||
DigiBoard overlap with some other device or with RAM.
|
||||
.It dgb\fIX\fP: BIOS download failed
|
||||
Problems with the on-board BIOS.
|
||||
Probably the memory addresses of the
|
||||
DigiBoard overlap with some other device or with RAM.
|
||||
.It dgb\fIX\fP: FEP code download failed
|
||||
Problems with downloading of the Front-End Processor's micro-OS.
|
||||
Probably the memory addresses of the
|
||||
DigiBoard overlap with some other device or with RAM.
|
||||
.It dgb\fIX\fP: FEP/OS start failed
|
||||
Problems with starting of the Front-End Processor's micro-OS.
|
||||
Probably the memory addresses of the
|
||||
DigiBoard overlap with some other device or with RAM.
|
||||
.It dgb\fIX\fP: too many ports
|
||||
This DigiBoard reports that it has more than 32 ports.
|
||||
Perhaps a hardware problem or
|
||||
the memory addresses of the
|
||||
DigiBoard overlap with some other device or with RAM.
|
||||
.It dgb\fIX\fP: only \fIN\fP ports are usable
|
||||
The
|
||||
.Dv NDGBPORTS
|
||||
parameter is too small and there is only enough space allocated
|
||||
for
|
||||
.Ar N
|
||||
ports on this card.
|
||||
.It dgb\fIX\fP: port \fIY\fP is broken
|
||||
The on-board diagnostic has reported that the specified port has hardware
|
||||
problems.
|
||||
.It dgb\fIX\fP: polling of disabled board stopped
|
||||
Internal problems in the polling logic of driver.
|
||||
.It dgb\fIX\fP: event queue's head or tail is wrong!
|
||||
Internal problems in the driver or hardware.
|
||||
.It dgb\fIX\fP: port \fIY\fP: got event on nonexisting port
|
||||
Some status changed on a port that is physically present but is
|
||||
unusable due to misconfiguration.
|
||||
.It dgb\fIX\fP: port \fIY\fP: event \fIN\fP mstat \fIM\fP lstat \fIK\fP
|
||||
The driver got a strange event from card.
|
||||
Probably this means that you have a
|
||||
newer card with an extended list of events or some other hardware problem.
|
||||
.It dgb\fIX\fP: port \fIY\fP: overrun
|
||||
Input buffer has filled up.
|
||||
Problems in polling logic of driver.
|
||||
.It dgb\fIX\fP: port \fIY\fP: FEP command on disabled port
|
||||
Internal problems in driver.
|
||||
.It dgb\fIX\fP: port \fIY\fP: timeout on FEP command
|
||||
Problems in hardware.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr stty 1 ,
|
||||
.Xr termios 4 ,
|
||||
.Xr tty 4 ,
|
||||
.Xr comcontrol 8
|
||||
.\" XXX add next line to many other drivers.
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
driver is derived from the
|
||||
.Xr sio 4
|
||||
driver and the DigiBoard driver from
|
||||
.Tn Linux
|
||||
and is
|
||||
.Ud
|
||||
.Sh BUGS
|
||||
The implementation of sending
|
||||
.Dv BREAK
|
||||
is broken.
|
||||
.Dv BREAK
|
||||
of fixed length of 1/4 s
|
||||
is sent anyway.
|
||||
.Pp
|
||||
There was a bug in implementation of
|
||||
.Xr select 2 .
|
||||
It is fixed now but not widely tested yet.
|
||||
.Pp
|
||||
There is no ditty command.
|
||||
Most of its functions (alternate pinout,
|
||||
speed up to 115200 baud, etc.) are implemented in the driver itself.
|
||||
Some
|
||||
other functions are missing.
|
|
@ -25,7 +25,7 @@
|
|||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd August 3, 2016
|
||||
.Dd September 1, 2016
|
||||
.Dt PCI 9
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -910,11 +910,6 @@ with one in the new distribution.
|
|||
The
|
||||
.Fn pci_remap_msix
|
||||
function will fail if this condition is not met.
|
||||
.Sh IMPLEMENTATION NOTES
|
||||
The
|
||||
.Vt pci_addr_t
|
||||
type varies according to the size of the PCI bus address
|
||||
space on the target architecture.
|
||||
.Sh SEE ALSO
|
||||
.Xr pci 4 ,
|
||||
.Xr pciconf 8 ,
|
||||
|
|
|
@ -112,6 +112,7 @@ CRUNCHENV+= MK_TESTS=no \
|
|||
_RECURSING_CRUNCH=1
|
||||
.ORDER: ${OUTPUTS} objs
|
||||
${OUTPUTS:[1]}: .META
|
||||
${OUTPUTS:[2..-1]}: .NOMETA
|
||||
${OUTPUTS}: ${CONF}
|
||||
MAKE=${MAKE} ${CRUNCHENV:NMK_AUTO_OBJ=*} MAKEOBJDIRPREFIX=${CRUNCHOBJS} \
|
||||
MK_AUTO_OBJ=${MK_AUTO_OBJ} \
|
||||
|
@ -122,11 +123,13 @@ ${OUTPUTS}: ${CONF}
|
|||
|
||||
# These 2 targets cannot use .MAKE since they depend on the generated
|
||||
# ${OUTMK} above.
|
||||
${PROG}: ${OUTPUTS} objs .META
|
||||
${PROG}: ${OUTPUTS} objs .NOMETA .PHONY
|
||||
${CRUNCHENV} \
|
||||
CC="${CC} ${CFLAGS} ${LDFLAGS}" \
|
||||
CXX="${CXX} ${CXXFLAGS} ${LDFLAGS}" \
|
||||
${MAKE} .MAKE.MODE=normal -f ${OUTMK} exe
|
||||
${MAKE} .MAKE.MODE="${.MAKE.MODE} curdirOk=yes" \
|
||||
.MAKE.META.IGNORE_PATHS="${.MAKE.META.IGNORE_PATHS}" \
|
||||
-f ${OUTMK} exe
|
||||
|
||||
objs: ${OUTMK} .META
|
||||
${CRUNCHENV} MAKEOBJDIRPREFIX=${CRUNCHOBJS} \
|
||||
|
@ -166,3 +169,5 @@ clean:
|
|||
fi
|
||||
|
||||
META_XTRAS+= ${find ${CRUNCHOBJS}${SRCTOP} -name '*.meta' 2>/dev/null || true:L:sh}
|
||||
META_XTRAS+= ${echo ${CRUNCHOBJS}/*.lo.meta 2>/dev/null || true:L:sh}
|
||||
META_XTRAS+= ${PROG}.meta
|
||||
|
|
|
@ -82,7 +82,7 @@ LIBIBMAD?= ${DESTDIR}${LIBDIR}/libibmad.a
|
|||
LIBIBSDP?= ${DESTDIR}${LIBDIR}/libibsdp.a
|
||||
LIBIBUMAD?= ${DESTDIR}${LIBDIR}/libibumad.a
|
||||
LIBIBVERBS?= ${DESTDIR}${LIBDIR}/libibverbs.a
|
||||
LIBIFC?= ${DESTDIR}${LIBDIR}/libifc.a
|
||||
LIBIFCONFIG?= ${DESTDIR}${LIBDIR}/libifconfig.a
|
||||
LIBIPSEC?= ${DESTDIR}${LIBDIR}/libipsec.a
|
||||
LIBJAIL?= ${DESTDIR}${LIBDIR}/libjail.a
|
||||
LIBKADM5CLNT?= ${DESTDIR}${LIBDIR}/libkadm5clnt.a
|
||||
|
|
|
@ -105,7 +105,7 @@ _LIBRARIES= \
|
|||
heimntlm \
|
||||
heimsqlite \
|
||||
hx509 \
|
||||
ifc \
|
||||
ifconfig \
|
||||
ipsec \
|
||||
jail \
|
||||
kadm5clnt \
|
||||
|
|
|
@ -4,18 +4,18 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
#
|
||||
# Short month names
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
10
|
||||
11
|
||||
12
|
||||
!!#1TB
|
||||
!!#2TB
|
||||
!!#3TB
|
||||
!!#4TB
|
||||
!!#5TB
|
||||
!!#6TB
|
||||
!!#7TB
|
||||
!!#8TB
|
||||
!!#9TB
|
||||
#1#0TB
|
||||
#1#1TB
|
||||
#1#2TB
|
||||
#
|
||||
# Long month names (as in a date)
|
||||
一月
|
||||
|
@ -63,7 +63,7 @@
|
|||
下午
|
||||
#
|
||||
# date_fmt
|
||||
%Y年%b月%e日 %A %X %Z
|
||||
%Y年%_m月%e日 %A %X %Z
|
||||
#
|
||||
# Long month names (without case ending)
|
||||
一月
|
||||
|
|
|
@ -4,18 +4,18 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
#
|
||||
# Short month names
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
10
|
||||
11
|
||||
12
|
||||
1月
|
||||
2月
|
||||
3月
|
||||
4月
|
||||
5月
|
||||
6月
|
||||
7月
|
||||
8月
|
||||
9月
|
||||
10月
|
||||
11月
|
||||
12月
|
||||
#
|
||||
# Long month names (as in a date)
|
||||
一月
|
||||
|
@ -63,7 +63,7 @@
|
|||
下午
|
||||
#
|
||||
# date_fmt
|
||||
%Y年%b月%e日 %A %X %Z
|
||||
%Y年%_m月%e日 %A %X %Z
|
||||
#
|
||||
# Long month names (without case ending)
|
||||
一月
|
||||
|
|
|
@ -4,18 +4,18 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
#
|
||||
# Short month names
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
10
|
||||
11
|
||||
12
|
||||
1月
|
||||
2月
|
||||
3月
|
||||
4月
|
||||
5月
|
||||
6月
|
||||
7月
|
||||
8月
|
||||
9月
|
||||
10月
|
||||
11月
|
||||
12月
|
||||
#
|
||||
# Long month names (as in a date)
|
||||
一月
|
||||
|
@ -63,7 +63,7 @@
|
|||
下午
|
||||
#
|
||||
# date_fmt
|
||||
%Y年%b月%e日 %A %X %Z
|
||||
%Y年%_m月%e日 %A %X %Z
|
||||
#
|
||||
# Long month names (without case ending)
|
||||
一月
|
||||
|
|
|
@ -4,18 +4,18 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
#
|
||||
# Short month names
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
10
|
||||
11
|
||||
12
|
||||
1月
|
||||
2月
|
||||
3月
|
||||
4月
|
||||
5月
|
||||
6月
|
||||
7月
|
||||
8月
|
||||
9月
|
||||
10月
|
||||
11月
|
||||
12月
|
||||
#
|
||||
# Long month names (as in a date)
|
||||
一月
|
||||
|
@ -63,7 +63,7 @@
|
|||
下午
|
||||
#
|
||||
# date_fmt
|
||||
%Y年%b月%e日 %A %X %Z
|
||||
%Y年%_m月%e日 %A %X %Z
|
||||
#
|
||||
# Long month names (without case ending)
|
||||
一月
|
||||
|
|
|
@ -4,18 +4,18 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
#
|
||||
# Short month names
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
10
|
||||
11
|
||||
12
|
||||
1月
|
||||
2月
|
||||
3月
|
||||
4月
|
||||
5月
|
||||
6月
|
||||
7月
|
||||
8月
|
||||
9月
|
||||
10月
|
||||
11月
|
||||
12月
|
||||
#
|
||||
# Long month names (as in a date)
|
||||
1¤ë
|
||||
|
@ -63,7 +63,7 @@
|
|||
¤U¤È
|
||||
#
|
||||
# date_fmt
|
||||
%Y¦~%b¤ë%e¤é %A %X %Z
|
||||
%Y年%_m月%e日 %A %X %Z
|
||||
#
|
||||
# Long month names (without case ending)
|
||||
1¤ë
|
||||
|
|
|
@ -4,18 +4,18 @@
|
|||
# -----------------------------------------------------------------------------
|
||||
#
|
||||
# Short month names
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
10
|
||||
11
|
||||
12
|
||||
1月
|
||||
2月
|
||||
3月
|
||||
4月
|
||||
5月
|
||||
6月
|
||||
7月
|
||||
8月
|
||||
9月
|
||||
10月
|
||||
11月
|
||||
12月
|
||||
#
|
||||
# Long month names (as in a date)
|
||||
1月
|
||||
|
@ -63,7 +63,7 @@
|
|||
下午
|
||||
#
|
||||
# date_fmt
|
||||
%Y年%b月%e日 %A %X %Z
|
||||
%Y年%_m月%e日 %A %X %Z
|
||||
#
|
||||
# Long month names (without case ending)
|
||||
1月
|
||||
|
|
|
@ -61,8 +61,13 @@ __FBSDID("$FreeBSD$");
|
|||
MALLOC_DEFINE(M_AXP81X_REG, "AXP81x regulator", "AXP81x power regulator");
|
||||
|
||||
#define AXP_ICTYPE 0x03
|
||||
#define AXP_POWERCTL1 0x10
|
||||
#define AXP_POWERCTL1_DCDC2 (1 << 1)
|
||||
#define AXP_POWERCTL2 0x12
|
||||
#define AXP_POWERCTL2_DC1SW (1 << 7)
|
||||
#define AXP_VOLTCTL_DCDC2 0x21
|
||||
#define AXP_VOLTCTL_STATUS (1 << 7)
|
||||
#define AXP_VOLTCTL_MASK 0x7f
|
||||
#define AXP_POWERBAT 0x32
|
||||
#define AXP_POWERBAT_SHUTDOWN (1 << 7)
|
||||
#define AXP_IRQEN1 0x40
|
||||
|
@ -109,10 +114,18 @@ struct axp81x_regdef {
|
|||
char *supply_name;
|
||||
uint8_t enable_reg;
|
||||
uint8_t enable_mask;
|
||||
uint8_t voltage_reg;
|
||||
int voltage_min;
|
||||
int voltage_max;
|
||||
int voltage_step1;
|
||||
int voltage_nstep1;
|
||||
int voltage_step2;
|
||||
int voltage_nstep2;
|
||||
};
|
||||
|
||||
enum axp81x_reg_id {
|
||||
AXP81X_REG_ID_DC1SW
|
||||
AXP81X_REG_ID_DC1SW,
|
||||
AXP81X_REG_ID_DCDC2,
|
||||
};
|
||||
|
||||
static struct axp81x_regdef axp81x_regdefs[] = {
|
||||
|
@ -122,6 +135,19 @@ static struct axp81x_regdef axp81x_regdefs[] = {
|
|||
.enable_reg = AXP_POWERCTL2,
|
||||
.enable_mask = AXP_POWERCTL2_DC1SW,
|
||||
},
|
||||
{
|
||||
.id = AXP81X_REG_ID_DCDC2,
|
||||
.name = "dcdc2",
|
||||
.enable_reg = AXP_POWERCTL1,
|
||||
.enable_mask = AXP_POWERCTL1_DCDC2,
|
||||
.voltage_reg = AXP_VOLTCTL_DCDC2,
|
||||
.voltage_min = 500,
|
||||
.voltage_max = 1300,
|
||||
.voltage_step1 = 10,
|
||||
.voltage_nstep1 = 70,
|
||||
.voltage_step2 = 20,
|
||||
.voltage_nstep2 = 5,
|
||||
},
|
||||
};
|
||||
|
||||
struct axp81x_softc;
|
||||
|
@ -218,17 +244,82 @@ axp81x_regnode_enable(struct regnode *regnode, bool enable, int *udelay)
|
|||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
axp81x_regnode_reg_to_voltage(struct axp81x_reg_sc *sc, uint8_t val, int *uv)
|
||||
{
|
||||
if (val < sc->def->voltage_nstep1)
|
||||
*uv = sc->def->voltage_min + val * sc->def->voltage_step1;
|
||||
else
|
||||
*uv = sc->def->voltage_min +
|
||||
(sc->def->voltage_nstep1 * sc->def->voltage_step1) +
|
||||
((val - sc->def->voltage_nstep1) * sc->def->voltage_step2);
|
||||
*uv *= 1000;
|
||||
}
|
||||
|
||||
static int
|
||||
axp81x_regnode_voltage_to_reg(struct axp81x_reg_sc *sc, int min_uvolt,
|
||||
int max_uvolt, uint8_t *val)
|
||||
{
|
||||
uint8_t nval;
|
||||
int nstep, uvolt;
|
||||
|
||||
nval = 0;
|
||||
uvolt = sc->def->voltage_min * 1000;
|
||||
|
||||
for (nstep = 0; nstep < sc->def->voltage_nstep1 && uvolt < min_uvolt;
|
||||
nstep++) {
|
||||
++nval;
|
||||
uvolt += (sc->def->voltage_step1 * 1000);
|
||||
}
|
||||
for (nstep = 0; nstep < sc->def->voltage_nstep2 && uvolt < min_uvolt;
|
||||
nstep++) {
|
||||
++nval;
|
||||
uvolt += (sc->def->voltage_step2 * 1000);
|
||||
}
|
||||
if (uvolt > max_uvolt)
|
||||
return (EINVAL);
|
||||
|
||||
*val = nval;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
axp81x_regnode_set_voltage(struct regnode *regnode, int min_uvolt,
|
||||
int max_uvolt, int *udelay)
|
||||
{
|
||||
return (ENXIO);
|
||||
struct axp81x_reg_sc *sc;
|
||||
uint8_t val;
|
||||
|
||||
sc = regnode_get_softc(regnode);
|
||||
|
||||
if (!sc->def->voltage_step1 || !sc->def->voltage_step2)
|
||||
return (ENXIO);
|
||||
|
||||
if (axp81x_regnode_voltage_to_reg(sc, min_uvolt, max_uvolt, &val) != 0)
|
||||
return (ERANGE);
|
||||
|
||||
axp81x_write(sc->base_dev, sc->def->voltage_reg, val);
|
||||
|
||||
*udelay = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
axp81x_regnode_get_voltage(struct regnode *regnode, int *uvolt)
|
||||
{
|
||||
return (ENXIO);
|
||||
struct axp81x_reg_sc *sc;
|
||||
uint8_t val;
|
||||
|
||||
sc = regnode_get_softc(regnode);
|
||||
|
||||
if (!sc->def->voltage_step1 || !sc->def->voltage_step2)
|
||||
return (ENXIO);
|
||||
|
||||
axp81x_read(sc->base_dev, sc->def->voltage_reg, &val, 1);
|
||||
axp81x_regnode_reg_to_voltage(sc, val & AXP_VOLTCTL_MASK, uvolt);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static regnode_method_t axp81x_regnode_methods[] = {
|
||||
|
@ -519,6 +610,10 @@ axp81x_reg_attach(device_t dev, phandle_t node,
|
|||
|
||||
memset(&initdef, 0, sizeof(initdef));
|
||||
regulator_parse_ofw_stdparam(dev, node, &initdef);
|
||||
if (initdef.std_param.min_uvolt == 0)
|
||||
initdef.std_param.min_uvolt = def->voltage_min * 1000;
|
||||
if (initdef.std_param.max_uvolt == 0)
|
||||
initdef.std_param.max_uvolt = def->voltage_max * 1000;
|
||||
initdef.id = def->id;
|
||||
initdef.ofw_node = node;
|
||||
regnode = regnode_create(dev, &axp81x_regnode_class, &initdef);
|
||||
|
|
|
@ -110,14 +110,14 @@ __FBSDID("$FreeBSD$");
|
|||
#define A13_PLL2_PRE_DIV (0x1f << 0)
|
||||
#define A13_PLL2_PRE_DIV_SHIFT 0
|
||||
|
||||
#define A23_PLL1_FACTOR_P (0x3 << 16)
|
||||
#define A23_PLL1_FACTOR_P_SHIFT 16
|
||||
#define A23_PLL1_FACTOR_N (0x1f << 8)
|
||||
#define A23_PLL1_FACTOR_N_SHIFT 8
|
||||
#define A23_PLL1_FACTOR_K (0x3 << 4)
|
||||
#define A23_PLL1_FACTOR_K_SHIFT 4
|
||||
#define A23_PLL1_FACTOR_M (0x3 << 0)
|
||||
#define A23_PLL1_FACTOR_M_SHIFT 0
|
||||
#define A23_PLL1_FACTOR_P (0x3 << 16)
|
||||
#define A23_PLL1_FACTOR_P_SHIFT 16
|
||||
|
||||
#define A31_PLL1_LOCK (1 << 28)
|
||||
#define A31_PLL1_CPU_SIGMA_DELTA_EN (1 << 24)
|
||||
|
@ -171,6 +171,24 @@ __FBSDID("$FreeBSD$");
|
|||
#define CLKID_A31_PLL6 0
|
||||
#define CLKID_A31_PLL6_X2 1
|
||||
|
||||
struct aw_pll_factor {
|
||||
unsigned int n;
|
||||
unsigned int k;
|
||||
unsigned int m;
|
||||
unsigned int p;
|
||||
uint64_t freq;
|
||||
};
|
||||
#define PLLFACTOR(_n, _k, _m, _p, _freq) \
|
||||
{ .n = (_n), .k = (_k), .m = (_m), .p = (_p), .freq = (_freq) }
|
||||
|
||||
static struct aw_pll_factor aw_a23_pll1_factors[] = {
|
||||
PLLFACTOR(16, 0, 0, 0, 408000000),
|
||||
PLLFACTOR(26, 0, 0, 0, 648000000),
|
||||
PLLFACTOR(16, 1, 0, 0, 816000000),
|
||||
PLLFACTOR(20, 1, 0, 0, 1008000000),
|
||||
PLLFACTOR(24, 1, 0, 0, 1200000000),
|
||||
};
|
||||
|
||||
enum aw_pll_type {
|
||||
AWPLL_A10_PLL1 = 1,
|
||||
AWPLL_A10_PLL2,
|
||||
|
@ -556,6 +574,39 @@ a13_pll2_set_freq(struct aw_pll_sc *sc, uint64_t fin, uint64_t *fout,
|
|||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
a23_pll1_set_freq(struct aw_pll_sc *sc, uint64_t fin, uint64_t *fout,
|
||||
int flags)
|
||||
{
|
||||
struct aw_pll_factor *f;
|
||||
uint32_t val;
|
||||
int n;
|
||||
|
||||
f = NULL;
|
||||
for (n = 0; n < nitems(aw_a23_pll1_factors); n++) {
|
||||
if (aw_a23_pll1_factors[n].freq == *fout) {
|
||||
f = &aw_a23_pll1_factors[n];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (f == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
DEVICE_LOCK(sc);
|
||||
PLL_READ(sc, &val);
|
||||
val &= ~(A23_PLL1_FACTOR_N|A23_PLL1_FACTOR_K|A23_PLL1_FACTOR_M|
|
||||
A23_PLL1_FACTOR_P);
|
||||
val |= (f->n << A23_PLL1_FACTOR_N_SHIFT);
|
||||
val |= (f->k << A23_PLL1_FACTOR_K_SHIFT);
|
||||
val |= (f->m << A23_PLL1_FACTOR_M_SHIFT);
|
||||
val |= (f->p << A23_PLL1_FACTOR_P_SHIFT);
|
||||
PLL_WRITE(sc, val);
|
||||
DEVICE_UNLOCK(sc);
|
||||
|
||||
return (0);
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
a23_pll1_recalc(struct aw_pll_sc *sc, uint64_t *freq)
|
||||
{
|
||||
|
@ -719,7 +770,7 @@ static struct aw_pll_funcs aw_pll_func[] = {
|
|||
PLL(AWPLL_A10_PLL5, a10_pll5_recalc, NULL, NULL),
|
||||
PLL(AWPLL_A10_PLL6, a10_pll6_recalc, a10_pll6_set_freq, a10_pll6_init),
|
||||
PLL(AWPLL_A13_PLL2, a13_pll2_recalc, a13_pll2_set_freq, NULL),
|
||||
PLL(AWPLL_A23_PLL1, a23_pll1_recalc, NULL, NULL),
|
||||
PLL(AWPLL_A23_PLL1, a23_pll1_recalc, a23_pll1_set_freq, NULL),
|
||||
PLL(AWPLL_A31_PLL1, a31_pll1_recalc, NULL, NULL),
|
||||
PLL(AWPLL_A31_PLL6, a31_pll6_recalc, NULL, a31_pll6_init),
|
||||
PLL(AWPLL_A80_PLL4, a80_pll4_recalc, NULL, NULL),
|
||||
|
|
|
@ -416,8 +416,17 @@ cpu_flush_dcache(void *ptr, size_t len)
|
|||
int
|
||||
cpu_est_clockrate(int cpu_id, uint64_t *rate)
|
||||
{
|
||||
struct pcpu *pc;
|
||||
|
||||
panic("ARM64TODO: cpu_est_clockrate");
|
||||
pc = pcpu_find(cpu_id);
|
||||
if (pc == NULL || rate == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
if (pc->pc_clock == 0)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
*rate = pc->pc_clock;
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -38,7 +38,8 @@
|
|||
#define PCPU_MD_FIELDS \
|
||||
u_int pc_acpi_id; /* ACPI CPU id */ \
|
||||
u_int pc_midr; /* stored MIDR value */ \
|
||||
char __pad[121]
|
||||
uint64_t pc_clock; \
|
||||
char __pad[113]
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
|
|
|
@ -791,11 +791,17 @@ dmu_objset_create_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
|
|||
|
||||
/*
|
||||
* Determine the number of levels necessary for the meta-dnode
|
||||
* to contain DN_MAX_OBJECT dnodes.
|
||||
* to contain DN_MAX_OBJECT dnodes. Note that in order to
|
||||
* ensure that we do not overflow 64 bits, there has to be
|
||||
* a nlevels that gives us a number of blocks > DN_MAX_OBJECT
|
||||
* but < 2^64. Therefore,
|
||||
* (mdn->dn_indblkshift - SPA_BLKPTRSHIFT) (10) must be
|
||||
* less than (64 - log2(DN_MAX_OBJECT)) (16).
|
||||
*/
|
||||
while ((uint64_t)mdn->dn_nblkptr << (mdn->dn_datablkshift +
|
||||
while ((uint64_t)mdn->dn_nblkptr <<
|
||||
(mdn->dn_datablkshift - DNODE_SHIFT +
|
||||
(levels - 1) * (mdn->dn_indblkshift - SPA_BLKPTRSHIFT)) <
|
||||
DN_MAX_OBJECT * sizeof (dnode_phys_t))
|
||||
DN_MAX_OBJECT)
|
||||
levels++;
|
||||
|
||||
mdn->dn_next_nlevels[tx->tx_txg & TXG_MASK] =
|
||||
|
|
|
@ -151,6 +151,8 @@ const zio_taskq_info_t zio_taskqs[ZIO_TYPES][ZIO_TASKQ_TYPES] = {
|
|||
{ ZTI_ONE, ZTI_NULL, ZTI_ONE, ZTI_NULL }, /* IOCTL */
|
||||
};
|
||||
|
||||
static sysevent_t *spa_event_create(spa_t *spa, vdev_t *vd, const char *name);
|
||||
static void spa_event_post(sysevent_t *ev);
|
||||
static void spa_sync_version(void *arg, dmu_tx_t *tx);
|
||||
static void spa_sync_props(void *arg, dmu_tx_t *tx);
|
||||
static boolean_t spa_has_active_shared_spare(spa_t *spa);
|
||||
|
@ -5738,6 +5740,7 @@ int
|
|||
spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare)
|
||||
{
|
||||
vdev_t *vd;
|
||||
sysevent_t *ev = NULL;
|
||||
metaslab_group_t *mg;
|
||||
nvlist_t **spares, **l2cache, *nv;
|
||||
uint64_t txg = 0;
|
||||
|
@ -5761,6 +5764,9 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare)
|
|||
* in this pool.
|
||||
*/
|
||||
if (vd == NULL || unspare) {
|
||||
if (vd == NULL)
|
||||
vd = spa_lookup_by_guid(spa, guid, B_TRUE);
|
||||
ev = spa_event_create(spa, vd, ESC_ZFS_VDEV_REMOVE_AUX);
|
||||
spa_vdev_remove_aux(spa->spa_spares.sav_config,
|
||||
ZPOOL_CONFIG_SPARES, spares, nspares, nv);
|
||||
spa_load_spares(spa);
|
||||
|
@ -5768,7 +5774,6 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare)
|
|||
} else {
|
||||
error = SET_ERROR(EBUSY);
|
||||
}
|
||||
spa_event_notify(spa, vd, ESC_ZFS_VDEV_REMOVE_AUX);
|
||||
} else if (spa->spa_l2cache.sav_vdevs != NULL &&
|
||||
nvlist_lookup_nvlist_array(spa->spa_l2cache.sav_config,
|
||||
ZPOOL_CONFIG_L2CACHE, &l2cache, &nl2cache) == 0 &&
|
||||
|
@ -5776,11 +5781,12 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare)
|
|||
/*
|
||||
* Cache devices can always be removed.
|
||||
*/
|
||||
vd = spa_lookup_by_guid(spa, guid, B_TRUE);
|
||||
ev = spa_event_create(spa, vd, ESC_ZFS_VDEV_REMOVE_AUX);
|
||||
spa_vdev_remove_aux(spa->spa_l2cache.sav_config,
|
||||
ZPOOL_CONFIG_L2CACHE, l2cache, nl2cache, nv);
|
||||
spa_load_l2cache(spa);
|
||||
spa->spa_l2cache.sav_sync = B_TRUE;
|
||||
spa_event_notify(spa, vd, ESC_ZFS_VDEV_REMOVE_AUX);
|
||||
} else if (vd != NULL && vd->vdev_islog) {
|
||||
ASSERT(!locked);
|
||||
ASSERT(vd == vd->vdev_top);
|
||||
|
@ -5817,9 +5823,9 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare)
|
|||
/*
|
||||
* Clean up the vdev namespace.
|
||||
*/
|
||||
ev = spa_event_create(spa, vd, ESC_ZFS_VDEV_REMOVE_DEV);
|
||||
spa_vdev_remove_from_namespace(spa, vd);
|
||||
|
||||
spa_event_notify(spa, vd, ESC_ZFS_VDEV_REMOVE_DEV);
|
||||
} else if (vd != NULL) {
|
||||
/*
|
||||
* Normal vdevs cannot be removed (yet).
|
||||
|
@ -5835,6 +5841,9 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare)
|
|||
if (!locked)
|
||||
error = spa_vdev_exit(spa, NULL, txg, error);
|
||||
|
||||
if (ev)
|
||||
spa_event_post(ev);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -7229,24 +7238,17 @@ spa_has_active_shared_spare(spa_t *spa)
|
|||
return (B_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Post a sysevent corresponding to the given event. The 'name' must be one of
|
||||
* the event definitions in sys/sysevent/eventdefs.h. The payload will be
|
||||
* filled in from the spa and (optionally) the vdev. This doesn't do anything
|
||||
* in the userland libzpool, as we don't want consumers to misinterpret ztest
|
||||
* or zdb as real changes.
|
||||
*/
|
||||
void
|
||||
spa_event_notify(spa_t *spa, vdev_t *vd, const char *name)
|
||||
static sysevent_t *
|
||||
spa_event_create(spa_t *spa, vdev_t *vd, const char *name)
|
||||
{
|
||||
sysevent_t *ev = NULL;
|
||||
#ifdef _KERNEL
|
||||
sysevent_t *ev;
|
||||
sysevent_attr_list_t *attr = NULL;
|
||||
sysevent_value_t value;
|
||||
sysevent_id_t eid;
|
||||
|
||||
ev = sysevent_alloc(EC_ZFS, (char *)name, SUNW_KERN_PUB "zfs",
|
||||
SE_SLEEP);
|
||||
ASSERT(ev != NULL);
|
||||
|
||||
value.value_type = SE_DATA_TYPE_STRING;
|
||||
value.value.sv_string = spa_name(spa);
|
||||
|
@ -7278,11 +7280,34 @@ spa_event_notify(spa_t *spa, vdev_t *vd, const char *name)
|
|||
goto done;
|
||||
attr = NULL;
|
||||
|
||||
(void) log_sysevent(ev, SE_SLEEP, &eid);
|
||||
|
||||
done:
|
||||
if (attr)
|
||||
sysevent_free_attr(attr);
|
||||
|
||||
#endif
|
||||
return (ev);
|
||||
}
|
||||
|
||||
static void
|
||||
spa_event_post(sysevent_t *ev)
|
||||
{
|
||||
#ifdef _KERNEL
|
||||
sysevent_id_t eid;
|
||||
|
||||
(void) log_sysevent(ev, SE_SLEEP, &eid);
|
||||
sysevent_free(ev);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Post a sysevent corresponding to the given event. The 'name' must be one of
|
||||
* the event definitions in sys/sysevent/eventdefs.h. The payload will be
|
||||
* filled in from the spa and (optionally) the vdev. This doesn't do anything
|
||||
* in the userland libzpool, as we don't want consumers to misinterpret ztest
|
||||
* or zdb as real changes.
|
||||
*/
|
||||
void
|
||||
spa_event_notify(spa_t *spa, vdev_t *vd, const char *name)
|
||||
{
|
||||
spa_event_post(spa_event_create(spa, vd, name));
|
||||
}
|
||||
|
|
|
@ -411,12 +411,20 @@ zfs_deadman_init()
|
|||
* it is possible to run the pool completely out of space, causing it to
|
||||
* be permanently read-only.
|
||||
*
|
||||
* Note that on very small pools, the slop space will be larger than
|
||||
* 3.2%, in an effort to have it be at least spa_min_slop (128MB),
|
||||
* but we never allow it to be more than half the pool size.
|
||||
*
|
||||
* See also the comments in zfs_space_check_t.
|
||||
*/
|
||||
int spa_slop_shift = 5;
|
||||
SYSCTL_INT(_vfs_zfs, OID_AUTO, spa_slop_shift, CTLFLAG_RWTUN,
|
||||
&spa_slop_shift, 0,
|
||||
"Shift value of reserved space (1/(2^spa_slop_shift)).");
|
||||
uint64_t spa_min_slop = 128 * 1024 * 1024;
|
||||
SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, spa_min_slop, CTLFLAG_RWTUN,
|
||||
&spa_min_slop, 0,
|
||||
"Minimal value of reserved space");
|
||||
|
||||
/*
|
||||
* ==========================================================================
|
||||
|
@ -1723,14 +1731,16 @@ spa_get_asize(spa_t *spa, uint64_t lsize)
|
|||
|
||||
/*
|
||||
* Return the amount of slop space in bytes. It is 1/32 of the pool (3.2%),
|
||||
* or at least 32MB.
|
||||
* or at least 128MB, unless that would cause it to be more than half the
|
||||
* pool size.
|
||||
*
|
||||
* See the comment above spa_slop_shift for details.
|
||||
*/
|
||||
uint64_t
|
||||
spa_get_slop_space(spa_t *spa) {
|
||||
spa_get_slop_space(spa_t *spa)
|
||||
{
|
||||
uint64_t space = spa_get_dspace(spa);
|
||||
return (MAX(space >> spa_slop_shift, SPA_MINDEVSIZE >> 1));
|
||||
return (MAX(space >> spa_slop_shift, MIN(space >> 1, spa_min_slop)));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
|
|
|
@ -58,7 +58,7 @@ extern "C" {
|
|||
*/
|
||||
#define DNODE_SHIFT 9 /* 512 bytes */
|
||||
#define DN_MIN_INDBLKSHIFT 12 /* 4k */
|
||||
#define DN_MAX_INDBLKSHIFT 14 /* 16k */
|
||||
#define DN_MAX_INDBLKSHIFT 17 /* 128k */
|
||||
#define DNODE_BLOCK_SHIFT 14 /* 16k */
|
||||
#define DNODE_CORE_SIZE 64 /* 64 bytes for dnode sans blkptrs */
|
||||
#define DN_MAX_OBJECT_SHIFT 48 /* 256 trillion (zfs_fid_t limit) */
|
||||
|
@ -88,6 +88,11 @@ extern "C" {
|
|||
|
||||
#define DNODES_PER_BLOCK_SHIFT (DNODE_BLOCK_SHIFT - DNODE_SHIFT)
|
||||
#define DNODES_PER_BLOCK (1ULL << DNODES_PER_BLOCK_SHIFT)
|
||||
|
||||
/*
|
||||
* This is inaccurate if the indblkshift of the particular object is not the
|
||||
* max. But it's only used by userland to calculate the zvol reservation.
|
||||
*/
|
||||
#define DNODES_PER_LEVEL_SHIFT (DN_MAX_INDBLKSHIFT - SPA_BLKPTRSHIFT)
|
||||
#define DNODES_PER_LEVEL (1ULL << DNODES_PER_LEVEL_SHIFT)
|
||||
|
||||
|
|
|
@ -500,6 +500,14 @@ zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr)
|
|||
dsl_dataset_t *ds;
|
||||
dsl_pool_t *dp;
|
||||
|
||||
/*
|
||||
* First do a quick check for root in the global zone, which
|
||||
* is allowed to do all write_perms. This ensures that zfs_ioc_*
|
||||
* will get to handle nonexistent datasets.
|
||||
*/
|
||||
if (INGLOBALZONE(curthread) && secpolicy_zfs(cr) == 0)
|
||||
return (0);
|
||||
|
||||
error = dsl_pool_hold(name, FTAG, &dp);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
|
|
@ -610,6 +610,8 @@ typedef struct zpool_rewind_policy {
|
|||
|
||||
/*
|
||||
* This is needed in userland to report the minimum necessary device size.
|
||||
*
|
||||
* Note that the zfs test suite uses 64MB vdevs.
|
||||
*/
|
||||
#define SPA_MINDEVSIZE (64ULL << 20)
|
||||
|
||||
|
|
|
@ -1349,16 +1349,6 @@ dev/dcons/dcons.c optional dcons
|
|||
dev/dcons/dcons_crom.c optional dcons_crom
|
||||
dev/dcons/dcons_os.c optional dcons
|
||||
dev/de/if_de.c optional de pci
|
||||
dev/digi/CX.c optional digi_CX
|
||||
dev/digi/CX_PCI.c optional digi_CX_PCI
|
||||
dev/digi/EPCX.c optional digi_EPCX
|
||||
dev/digi/EPCX_PCI.c optional digi_EPCX_PCI
|
||||
dev/digi/Xe.c optional digi_Xe
|
||||
dev/digi/Xem.c optional digi_Xem
|
||||
dev/digi/Xr.c optional digi_Xr
|
||||
dev/digi/digi.c optional digi
|
||||
dev/digi/digi_isa.c optional digi isa
|
||||
dev/digi/digi_pci.c optional digi pci
|
||||
dev/dpt/dpt_eisa.c optional dpt eisa
|
||||
dev/dpt/dpt_pci.c optional dpt pci
|
||||
dev/dpt/dpt_scsi.c optional dpt
|
||||
|
|
|
@ -90,7 +90,6 @@ __FBSDID("$FreeBSD$");
|
|||
#include "common/t4_regs.h" /* for PCIE_MEM_ACCESS */
|
||||
#include "tom/t4_tom.h"
|
||||
#include "cxgbei.h"
|
||||
#include "cxgbei_ulp2_ddp.h"
|
||||
|
||||
static int worker_thread_count;
|
||||
static struct cxgbei_worker_thread_softc *cwt_softc;
|
||||
|
@ -101,374 +100,48 @@ struct icl_pdu *icl_cxgbei_new_pdu(int);
|
|||
void icl_cxgbei_new_pdu_set_conn(struct icl_pdu *, struct icl_conn *);
|
||||
void icl_cxgbei_conn_pdu_free(struct icl_conn *, struct icl_pdu *);
|
||||
|
||||
/*
|
||||
* Direct Data Placement -
|
||||
* Directly place the iSCSI Data-In or Data-Out PDU's payload into pre-posted
|
||||
* final destination host-memory buffers based on the Initiator Task Tag (ITT)
|
||||
* in Data-In or Target Task Tag (TTT) in Data-Out PDUs.
|
||||
* The host memory address is programmed into h/w in the format of pagepod
|
||||
* entries.
|
||||
* The location of the pagepod entry is encoded into ddp tag which is used as
|
||||
* the base for ITT/TTT.
|
||||
*/
|
||||
|
||||
/*
|
||||
* functions to program the pagepod in h/w
|
||||
*/
|
||||
static void inline
|
||||
ppod_set(struct pagepod *ppod,
|
||||
struct cxgbei_ulp2_pagepod_hdr *hdr,
|
||||
struct cxgbei_ulp2_gather_list *gl,
|
||||
unsigned int pidx)
|
||||
static void
|
||||
free_ci_counters(struct cxgbei_data *ci)
|
||||
{
|
||||
int i;
|
||||
|
||||
memcpy(ppod, hdr, sizeof(*hdr));
|
||||
#define FREE_CI_COUNTER(x) do { \
|
||||
if (ci->x != NULL) { \
|
||||
counter_u64_free(ci->x); \
|
||||
ci->x = NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
for (i = 0; i < (PPOD_PAGES + 1); i++, pidx++) {
|
||||
ppod->addr[i] = pidx < gl->nelem ?
|
||||
cpu_to_be64(gl->dma_sg[pidx].phys_addr) : 0ULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void inline
|
||||
ppod_clear(struct pagepod *ppod)
|
||||
{
|
||||
memset(ppod, 0, sizeof(*ppod));
|
||||
}
|
||||
|
||||
static inline void
|
||||
ulp_mem_io_set_hdr(struct adapter *sc, int tid, struct ulp_mem_io *req,
|
||||
unsigned int wr_len, unsigned int dlen,
|
||||
unsigned int pm_addr)
|
||||
{
|
||||
struct ulptx_idata *idata = (struct ulptx_idata *)(req + 1);
|
||||
|
||||
INIT_ULPTX_WR(req, wr_len, 0, 0);
|
||||
req->cmd = cpu_to_be32(V_ULPTX_CMD(ULP_TX_MEM_WRITE) |
|
||||
V_ULP_MEMIO_ORDER(is_t4(sc)) |
|
||||
V_T5_ULP_MEMIO_IMM(is_t5(sc)));
|
||||
req->dlen = htonl(V_ULP_MEMIO_DATA_LEN(dlen >> 5));
|
||||
req->len16 = htonl(DIV_ROUND_UP(wr_len - sizeof(req->wr), 16)
|
||||
| V_FW_WR_FLOWID(tid));
|
||||
req->lock_addr = htonl(V_ULP_MEMIO_ADDR(pm_addr >> 5));
|
||||
|
||||
idata->cmd_more = htonl(V_ULPTX_CMD(ULP_TX_SC_IMM));
|
||||
idata->len = htonl(dlen);
|
||||
}
|
||||
|
||||
#define ULPMEM_IDATA_MAX_NPPODS 1 /* 256/PPOD_SIZE */
|
||||
#define PCIE_MEMWIN_MAX_NPPODS 16 /* 1024/PPOD_SIZE */
|
||||
|
||||
static int
|
||||
ppod_write_idata(struct cxgbei_data *ci,
|
||||
struct cxgbei_ulp2_pagepod_hdr *hdr,
|
||||
unsigned int idx, unsigned int npods,
|
||||
struct cxgbei_ulp2_gather_list *gl,
|
||||
unsigned int gl_pidx, struct toepcb *toep)
|
||||
{
|
||||
u_int dlen = PPOD_SIZE * npods;
|
||||
u_int pm_addr = idx * PPOD_SIZE + ci->llimit;
|
||||
u_int wr_len = roundup(sizeof(struct ulp_mem_io) +
|
||||
sizeof(struct ulptx_idata) + dlen, 16);
|
||||
struct ulp_mem_io *req;
|
||||
struct ulptx_idata *idata;
|
||||
struct pagepod *ppod;
|
||||
u_int i;
|
||||
struct wrqe *wr;
|
||||
struct adapter *sc = toep->vi->pi->adapter;
|
||||
|
||||
wr = alloc_wrqe(wr_len, toep->ctrlq);
|
||||
if (wr == NULL) {
|
||||
CXGBE_UNIMPLEMENTED("ppod_write_idata: alloc_wrqe failure");
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
req = wrtod(wr);
|
||||
memset(req, 0, wr_len);
|
||||
ulp_mem_io_set_hdr(sc, toep->tid, req, wr_len, dlen, pm_addr);
|
||||
idata = (struct ulptx_idata *)(req + 1);
|
||||
|
||||
ppod = (struct pagepod *)(idata + 1);
|
||||
for (i = 0; i < npods; i++, ppod++, gl_pidx += PPOD_PAGES) {
|
||||
if (!hdr) /* clear the pagepod */
|
||||
ppod_clear(ppod);
|
||||
else /* set the pagepod */
|
||||
ppod_set(ppod, hdr, gl, gl_pidx);
|
||||
}
|
||||
|
||||
t4_wrq_tx(sc, wr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
t4_ddp_set_map(struct cxgbei_data *ci, void *iccp,
|
||||
struct cxgbei_ulp2_pagepod_hdr *hdr, u_int idx, u_int npods,
|
||||
struct cxgbei_ulp2_gather_list *gl, int reply)
|
||||
{
|
||||
struct icl_cxgbei_conn *icc = (struct icl_cxgbei_conn *)iccp;
|
||||
struct toepcb *toep = icc->toep;
|
||||
int err;
|
||||
unsigned int pidx = 0, w_npods = 0, cnt;
|
||||
|
||||
/*
|
||||
* on T4, if we use a mix of IMMD and DSGL with ULP_MEM_WRITE,
|
||||
* the order would not be guaranteed, so we will stick with IMMD
|
||||
*/
|
||||
gl->tid = toep->tid;
|
||||
gl->port_id = toep->vi->pi->port_id;
|
||||
gl->egress_dev = (void *)toep->vi->ifp;
|
||||
|
||||
/* send via immediate data */
|
||||
for (; w_npods < npods; idx += cnt, w_npods += cnt,
|
||||
pidx += PPOD_PAGES) {
|
||||
cnt = npods - w_npods;
|
||||
if (cnt > ULPMEM_IDATA_MAX_NPPODS)
|
||||
cnt = ULPMEM_IDATA_MAX_NPPODS;
|
||||
err = ppod_write_idata(ci, hdr, idx, cnt, gl, pidx, toep);
|
||||
if (err) {
|
||||
printf("%s: ppod_write_idata failed\n", __func__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void
|
||||
t4_ddp_clear_map(struct cxgbei_data *ci, struct cxgbei_ulp2_gather_list *gl,
|
||||
u_int tag, u_int idx, u_int npods, struct icl_cxgbei_conn *icc)
|
||||
{
|
||||
struct toepcb *toep = icc->toep;
|
||||
int err = -1;
|
||||
u_int pidx = 0;
|
||||
u_int w_npods = 0;
|
||||
u_int cnt;
|
||||
|
||||
for (; w_npods < npods; idx += cnt, w_npods += cnt,
|
||||
pidx += PPOD_PAGES) {
|
||||
cnt = npods - w_npods;
|
||||
if (cnt > ULPMEM_IDATA_MAX_NPPODS)
|
||||
cnt = ULPMEM_IDATA_MAX_NPPODS;
|
||||
err = ppod_write_idata(ci, NULL, idx, cnt, gl, 0, toep);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
FREE_CI_COUNTER(ddp_setup_ok);
|
||||
FREE_CI_COUNTER(ddp_setup_error);
|
||||
FREE_CI_COUNTER(ddp_bytes);
|
||||
FREE_CI_COUNTER(ddp_pdus);
|
||||
FREE_CI_COUNTER(fl_bytes);
|
||||
FREE_CI_COUNTER(fl_pdus);
|
||||
#undef FREE_CI_COUNTER
|
||||
}
|
||||
|
||||
static int
|
||||
cxgbei_map_sg(struct cxgbei_sgl *sgl, struct ccb_scsiio *csio)
|
||||
alloc_ci_counters(struct cxgbei_data *ci)
|
||||
{
|
||||
unsigned int data_len = csio->dxfer_len;
|
||||
unsigned int sgoffset = (uint64_t)csio->data_ptr & PAGE_MASK;
|
||||
unsigned int nsge;
|
||||
unsigned char *sgaddr = csio->data_ptr;
|
||||
unsigned int len = 0;
|
||||
|
||||
nsge = (csio->dxfer_len + sgoffset + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
sgl->sg_addr = sgaddr;
|
||||
sgl->sg_offset = sgoffset;
|
||||
if (data_len < (PAGE_SIZE - sgoffset))
|
||||
len = data_len;
|
||||
else
|
||||
len = PAGE_SIZE - sgoffset;
|
||||
#define ALLOC_CI_COUNTER(x) do { \
|
||||
ci->x = counter_u64_alloc(M_WAITOK); \
|
||||
if (ci->x == NULL) \
|
||||
goto fail; \
|
||||
} while (0)
|
||||
|
||||
sgl->sg_length = len;
|
||||
|
||||
data_len -= len;
|
||||
sgaddr += len;
|
||||
sgl = sgl+1;
|
||||
|
||||
while (data_len > 0) {
|
||||
sgl->sg_addr = sgaddr;
|
||||
len = (data_len < PAGE_SIZE)? data_len: PAGE_SIZE;
|
||||
sgl->sg_length = len;
|
||||
sgaddr += len;
|
||||
data_len -= len;
|
||||
sgl = sgl + 1;
|
||||
}
|
||||
|
||||
return nsge;
|
||||
}
|
||||
|
||||
static int
|
||||
cxgbei_map_sg_tgt(struct cxgbei_sgl *sgl, union ctl_io *io)
|
||||
{
|
||||
unsigned int data_len, sgoffset, nsge;
|
||||
unsigned char *sgaddr;
|
||||
unsigned int len = 0, index = 0, ctl_sg_count, i;
|
||||
struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
|
||||
|
||||
if (io->scsiio.kern_sg_entries > 0) {
|
||||
ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
|
||||
ctl_sg_count = io->scsiio.kern_sg_entries;
|
||||
} else {
|
||||
ctl_sglist = &ctl_sg_entry;
|
||||
ctl_sglist->addr = io->scsiio.kern_data_ptr;
|
||||
ctl_sglist->len = io->scsiio.kern_data_len;
|
||||
ctl_sg_count = 1;
|
||||
}
|
||||
|
||||
sgaddr = sgl->sg_addr = ctl_sglist[index].addr;
|
||||
sgoffset = sgl->sg_offset = (uint64_t)sgl->sg_addr & PAGE_MASK;
|
||||
data_len = ctl_sglist[index].len;
|
||||
|
||||
if (data_len < (PAGE_SIZE - sgoffset))
|
||||
len = data_len;
|
||||
else
|
||||
len = PAGE_SIZE - sgoffset;
|
||||
|
||||
sgl->sg_length = len;
|
||||
|
||||
data_len -= len;
|
||||
sgaddr += len;
|
||||
sgl = sgl+1;
|
||||
|
||||
len = 0;
|
||||
for (i = 0; i< ctl_sg_count; i++)
|
||||
len += ctl_sglist[i].len;
|
||||
nsge = (len + sgoffset + PAGE_SIZE -1) >> PAGE_SHIFT;
|
||||
while (data_len > 0) {
|
||||
sgl->sg_addr = sgaddr;
|
||||
len = (data_len < PAGE_SIZE)? data_len: PAGE_SIZE;
|
||||
sgl->sg_length = len;
|
||||
sgaddr += len;
|
||||
data_len -= len;
|
||||
sgl = sgl + 1;
|
||||
if (data_len == 0) {
|
||||
if (index == ctl_sg_count - 1)
|
||||
break;
|
||||
index++;
|
||||
sgaddr = ctl_sglist[index].addr;
|
||||
data_len = ctl_sglist[index].len;
|
||||
}
|
||||
}
|
||||
|
||||
return nsge;
|
||||
}
|
||||
|
||||
static int
|
||||
t4_sk_ddp_tag_reserve(struct cxgbei_data *ci, struct icl_cxgbei_conn *icc,
|
||||
u_int xferlen, struct cxgbei_sgl *sgl, u_int sgcnt, u_int *ddp_tag)
|
||||
{
|
||||
struct cxgbei_ulp2_gather_list *gl;
|
||||
int err = -EINVAL;
|
||||
struct toepcb *toep = icc->toep;
|
||||
|
||||
gl = cxgbei_ulp2_ddp_make_gl_from_iscsi_sgvec(xferlen, sgl, sgcnt, ci, 0);
|
||||
if (gl) {
|
||||
err = cxgbei_ulp2_ddp_tag_reserve(ci, icc, toep->tid,
|
||||
&ci->tag_format, ddp_tag, gl, 0, 0);
|
||||
if (err) {
|
||||
cxgbei_ulp2_ddp_release_gl(ci, gl);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
cxgbei_task_reserve_itt(struct icl_conn *ic, void **prv,
|
||||
struct ccb_scsiio *scmd, unsigned int *itt)
|
||||
{
|
||||
struct icl_cxgbei_conn *icc = ic_to_icc(ic);
|
||||
int xferlen = scmd->dxfer_len;
|
||||
struct cxgbei_task_data *tdata = NULL;
|
||||
struct cxgbei_sgl *sge = NULL;
|
||||
struct toepcb *toep = icc->toep;
|
||||
struct adapter *sc = td_adapter(toep->td);
|
||||
struct cxgbei_data *ci = sc->iscsi_ulp_softc;
|
||||
int err = -1;
|
||||
|
||||
MPASS(icc->icc_signature == CXGBEI_CONN_SIGNATURE);
|
||||
|
||||
tdata = (struct cxgbei_task_data *)*prv;
|
||||
if (xferlen == 0 || tdata == NULL)
|
||||
goto out;
|
||||
if (xferlen < DDP_THRESHOLD)
|
||||
goto out;
|
||||
|
||||
if ((scmd->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
|
||||
tdata->nsge = cxgbei_map_sg(tdata->sgl, scmd);
|
||||
if (tdata->nsge == 0) {
|
||||
CTR1(KTR_CXGBE, "%s: map_sg failed", __func__);
|
||||
return 0;
|
||||
}
|
||||
sge = tdata->sgl;
|
||||
|
||||
tdata->sc_ddp_tag = *itt;
|
||||
|
||||
CTR3(KTR_CXGBE, "%s: *itt:0x%x sc_ddp_tag:0x%x",
|
||||
__func__, *itt, tdata->sc_ddp_tag);
|
||||
if (cxgbei_ulp2_sw_tag_usable(&ci->tag_format,
|
||||
tdata->sc_ddp_tag)) {
|
||||
err = t4_sk_ddp_tag_reserve(ci, icc, scmd->dxfer_len,
|
||||
sge, tdata->nsge, &tdata->sc_ddp_tag);
|
||||
} else {
|
||||
CTR3(KTR_CXGBE,
|
||||
"%s: itt:0x%x sc_ddp_tag:0x%x not usable",
|
||||
__func__, *itt, tdata->sc_ddp_tag);
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (err < 0)
|
||||
tdata->sc_ddp_tag =
|
||||
cxgbei_ulp2_set_non_ddp_tag(&ci->tag_format, *itt);
|
||||
|
||||
return tdata->sc_ddp_tag;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
cxgbei_task_reserve_ttt(struct icl_conn *ic, void **prv, union ctl_io *io,
|
||||
unsigned int *ttt)
|
||||
{
|
||||
struct icl_cxgbei_conn *icc = ic_to_icc(ic);
|
||||
struct toepcb *toep = icc->toep;
|
||||
struct adapter *sc = td_adapter(toep->td);
|
||||
struct cxgbei_data *ci = sc->iscsi_ulp_softc;
|
||||
struct cxgbei_task_data *tdata = NULL;
|
||||
int xferlen, err = -1;
|
||||
struct cxgbei_sgl *sge = NULL;
|
||||
|
||||
MPASS(icc->icc_signature == CXGBEI_CONN_SIGNATURE);
|
||||
|
||||
xferlen = (io->scsiio.kern_data_len - io->scsiio.ext_data_filled);
|
||||
tdata = (struct cxgbei_task_data *)*prv;
|
||||
if ((xferlen == 0) || (tdata == NULL))
|
||||
goto out;
|
||||
if (xferlen < DDP_THRESHOLD)
|
||||
goto out;
|
||||
tdata->nsge = cxgbei_map_sg_tgt(tdata->sgl, io);
|
||||
if (tdata->nsge == 0) {
|
||||
CTR1(KTR_CXGBE, "%s: map_sg failed", __func__);
|
||||
return 0;
|
||||
}
|
||||
sge = tdata->sgl;
|
||||
|
||||
tdata->sc_ddp_tag = *ttt;
|
||||
if (cxgbei_ulp2_sw_tag_usable(&ci->tag_format, tdata->sc_ddp_tag)) {
|
||||
err = t4_sk_ddp_tag_reserve(ci, icc, xferlen, sge,
|
||||
tdata->nsge, &tdata->sc_ddp_tag);
|
||||
} else {
|
||||
CTR2(KTR_CXGBE, "%s: sc_ddp_tag:0x%x not usable",
|
||||
__func__, tdata->sc_ddp_tag);
|
||||
}
|
||||
out:
|
||||
if (err < 0)
|
||||
tdata->sc_ddp_tag =
|
||||
cxgbei_ulp2_set_non_ddp_tag(&ci->tag_format, *ttt);
|
||||
return tdata->sc_ddp_tag;
|
||||
}
|
||||
|
||||
static int
|
||||
t4_sk_ddp_tag_release(struct icl_cxgbei_conn *icc, unsigned int ddp_tag)
|
||||
{
|
||||
struct toepcb *toep = icc->toep;
|
||||
struct adapter *sc = td_adapter(toep->td);
|
||||
struct cxgbei_data *ci = sc->iscsi_ulp_softc;
|
||||
|
||||
cxgbei_ulp2_ddp_tag_release(ci, ddp_tag, icc);
|
||||
ALLOC_CI_COUNTER(ddp_setup_ok);
|
||||
ALLOC_CI_COUNTER(ddp_setup_error);
|
||||
ALLOC_CI_COUNTER(ddp_bytes);
|
||||
ALLOC_CI_COUNTER(ddp_pdus);
|
||||
ALLOC_CI_COUNTER(fl_bytes);
|
||||
ALLOC_CI_COUNTER(fl_pdus);
|
||||
#undef ALLOC_CI_COUNTER
|
||||
|
||||
return (0);
|
||||
fail:
|
||||
free_ci_counters(ci);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -504,58 +177,81 @@ read_pdu_limits(struct adapter *sc, uint32_t *max_tx_pdu_len,
|
|||
static int
|
||||
cxgbei_init(struct adapter *sc, struct cxgbei_data *ci)
|
||||
{
|
||||
int nppods, bits, rc;
|
||||
static const u_int pgsz_order[] = {0, 1, 2, 3};
|
||||
struct sysctl_oid *oid;
|
||||
struct sysctl_oid_list *children;
|
||||
struct ppod_region *pr;
|
||||
uint32_t r;
|
||||
int rc;
|
||||
|
||||
MPASS(sc->vres.iscsi.size > 0);
|
||||
MPASS(ci != NULL);
|
||||
|
||||
rc = alloc_ci_counters(ci);
|
||||
if (rc != 0)
|
||||
return (rc);
|
||||
|
||||
ci->llimit = sc->vres.iscsi.start;
|
||||
ci->ulimit = sc->vres.iscsi.start + sc->vres.iscsi.size - 1;
|
||||
read_pdu_limits(sc, &ci->max_tx_pdu_len, &ci->max_rx_pdu_len);
|
||||
|
||||
nppods = sc->vres.iscsi.size >> IPPOD_SIZE_SHIFT;
|
||||
if (nppods <= 1024)
|
||||
return (ENXIO);
|
||||
|
||||
bits = fls(nppods);
|
||||
if (bits > IPPOD_IDX_MAX_SIZE)
|
||||
bits = IPPOD_IDX_MAX_SIZE;
|
||||
nppods = (1 << (bits - 1)) - 1;
|
||||
|
||||
rc = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR,
|
||||
BUS_SPACE_MAXADDR, NULL, NULL, UINT32_MAX , 8, BUS_SPACE_MAXSIZE,
|
||||
BUS_DMA_ALLOCNOW, NULL, NULL, &ci->ulp_ddp_tag);
|
||||
pr = &ci->pr;
|
||||
r = t4_read_reg(sc, A_ULP_RX_ISCSI_PSZ);
|
||||
rc = t4_init_ppod_region(pr, &sc->vres.iscsi, r, "iSCSI page pods");
|
||||
if (rc != 0) {
|
||||
device_printf(sc->dev, "%s: failed to create DMA tag: %u.\n",
|
||||
device_printf(sc->dev,
|
||||
"%s: failed to initialize the iSCSI page pod region: %u.\n",
|
||||
__func__, rc);
|
||||
free_ci_counters(ci);
|
||||
return (rc);
|
||||
}
|
||||
|
||||
ci->colors = malloc(nppods * sizeof(char), M_CXGBE, M_NOWAIT | M_ZERO);
|
||||
ci->gl_map = malloc(nppods * sizeof(struct cxgbei_ulp2_gather_list *),
|
||||
M_CXGBE, M_NOWAIT | M_ZERO);
|
||||
if (ci->colors == NULL || ci->gl_map == NULL) {
|
||||
bus_dma_tag_destroy(ci->ulp_ddp_tag);
|
||||
free(ci->colors, M_CXGBE);
|
||||
free(ci->gl_map, M_CXGBE);
|
||||
return (ENOMEM);
|
||||
r = t4_read_reg(sc, A_ULP_RX_ISCSI_TAGMASK);
|
||||
r &= V_ISCSITAGMASK(M_ISCSITAGMASK);
|
||||
if (r != pr->pr_tag_mask) {
|
||||
/*
|
||||
* Recent firmwares are supposed to set up the the iSCSI tagmask
|
||||
* but we'll do it ourselves it the computed value doesn't match
|
||||
* what's in the register.
|
||||
*/
|
||||
device_printf(sc->dev,
|
||||
"tagmask 0x%08x does not match computed mask 0x%08x.\n", r,
|
||||
pr->pr_tag_mask);
|
||||
t4_set_reg_field(sc, A_ULP_RX_ISCSI_TAGMASK,
|
||||
V_ISCSITAGMASK(M_ISCSITAGMASK), pr->pr_tag_mask);
|
||||
}
|
||||
|
||||
mtx_init(&ci->map_lock, "ddp lock", NULL, MTX_DEF | MTX_DUPOK);
|
||||
ci->nppods = nppods;
|
||||
ci->idx_last = nppods;
|
||||
ci->idx_bits = bits;
|
||||
ci->idx_mask = (1 << bits) - 1;
|
||||
ci->rsvd_tag_mask = (1 << (bits + IPPOD_IDX_SHIFT)) - 1;
|
||||
sysctl_ctx_init(&ci->ctx);
|
||||
oid = device_get_sysctl_tree(sc->dev); /* dev.t5nex.X */
|
||||
children = SYSCTL_CHILDREN(oid);
|
||||
|
||||
ci->tag_format.sw_bits = bits;
|
||||
ci->tag_format.rsvd_bits = bits;
|
||||
ci->tag_format.rsvd_shift = IPPOD_IDX_SHIFT;
|
||||
ci->tag_format.rsvd_mask = ci->idx_mask;
|
||||
oid = SYSCTL_ADD_NODE(&ci->ctx, children, OID_AUTO, "iscsi", CTLFLAG_RD,
|
||||
NULL, "iSCSI ULP statistics");
|
||||
children = SYSCTL_CHILDREN(oid);
|
||||
|
||||
t4_iscsi_init(sc, ci->idx_mask << IPPOD_IDX_SHIFT, pgsz_order);
|
||||
SYSCTL_ADD_COUNTER_U64(&ci->ctx, children, OID_AUTO, "ddp_setup_ok",
|
||||
CTLFLAG_RD, &ci->ddp_setup_ok,
|
||||
"# of times DDP buffer was setup successfully.");
|
||||
|
||||
return (rc);
|
||||
SYSCTL_ADD_COUNTER_U64(&ci->ctx, children, OID_AUTO, "ddp_setup_error",
|
||||
CTLFLAG_RD, &ci->ddp_setup_error,
|
||||
"# of times DDP buffer setup failed.");
|
||||
|
||||
SYSCTL_ADD_COUNTER_U64(&ci->ctx, children, OID_AUTO, "ddp_bytes",
|
||||
CTLFLAG_RD, &ci->ddp_bytes, "# of bytes placed directly");
|
||||
|
||||
SYSCTL_ADD_COUNTER_U64(&ci->ctx, children, OID_AUTO, "ddp_pdus",
|
||||
CTLFLAG_RD, &ci->ddp_pdus, "# of PDUs with data placed directly.");
|
||||
|
||||
SYSCTL_ADD_COUNTER_U64(&ci->ctx, children, OID_AUTO, "fl_bytes",
|
||||
CTLFLAG_RD, &ci->fl_bytes, "# of data bytes delivered in freelist");
|
||||
|
||||
SYSCTL_ADD_COUNTER_U64(&ci->ctx, children, OID_AUTO, "fl_pdus",
|
||||
CTLFLAG_RD, &ci->fl_pdus,
|
||||
"# of PDUs with data delivered in freelist");
|
||||
|
||||
ci->ddp_threshold = 2048;
|
||||
SYSCTL_ADD_UINT(&ci->ctx, children, OID_AUTO, "ddp_threshold",
|
||||
CTLFLAG_RW, &ci->ddp_threshold, 0, "Rx zero copy threshold");
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -567,15 +263,18 @@ do_rx_iscsi_hdr(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
|
|||
struct toepcb *toep = lookup_tid(sc, tid);
|
||||
struct icl_pdu *ip;
|
||||
struct icl_cxgbei_pdu *icp;
|
||||
uint16_t len_ddp = be16toh(cpl->pdu_len_ddp);
|
||||
uint16_t len = be16toh(cpl->len);
|
||||
|
||||
M_ASSERTPKTHDR(m);
|
||||
MPASS(m->m_pkthdr.len == len + sizeof(*cpl));
|
||||
|
||||
ip = icl_cxgbei_new_pdu(M_NOWAIT);
|
||||
if (ip == NULL)
|
||||
CXGBE_UNIMPLEMENTED("PDU allocation failure");
|
||||
m_copydata(m, sizeof(*cpl), ISCSI_BHS_SIZE, (caddr_t)ip->ip_bhs);
|
||||
ip->ip_data_len = G_ISCSI_PDU_LEN(len_ddp) - len;
|
||||
icp = ip_to_icp(ip);
|
||||
bcopy(mtod(m, caddr_t) + sizeof(*cpl), icp->ip.ip_bhs, sizeof(struct
|
||||
iscsi_bhs));
|
||||
icp->icp_seq = ntohl(cpl->seq);
|
||||
icp->icp_flags = ICPF_RX_HDR;
|
||||
|
||||
|
@ -584,8 +283,8 @@ do_rx_iscsi_hdr(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
|
|||
toep->ulpcb2 = icp;
|
||||
|
||||
#if 0
|
||||
CTR4(KTR_CXGBE, "%s: tid %u, cpl->len hlen %u, m->m_len hlen %u",
|
||||
__func__, tid, ntohs(cpl->len), m->m_len);
|
||||
CTR5(KTR_CXGBE, "%s: tid %u, cpl->len %u, pdu_len_ddp 0x%04x, icp %p",
|
||||
__func__, tid, len, len_ddp, icp);
|
||||
#endif
|
||||
|
||||
m_freem(m);
|
||||
|
@ -596,28 +295,32 @@ static int
|
|||
do_rx_iscsi_data(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
|
||||
{
|
||||
struct adapter *sc = iq->adapter;
|
||||
struct cxgbei_data *ci = sc->iscsi_ulp_softc;
|
||||
struct cpl_iscsi_data *cpl = mtod(m, struct cpl_iscsi_data *);
|
||||
u_int tid = GET_TID(cpl);
|
||||
struct toepcb *toep = lookup_tid(sc, tid);
|
||||
struct icl_cxgbei_pdu *icp = toep->ulpcb2;
|
||||
|
||||
M_ASSERTPKTHDR(m);
|
||||
MPASS(m->m_pkthdr.len == be16toh(cpl->len) + sizeof(*cpl));
|
||||
|
||||
/* Must already have received the header (but not the data). */
|
||||
MPASS(icp != NULL);
|
||||
MPASS(icp->icp_flags == ICPF_RX_HDR);
|
||||
MPASS(icp->ip.ip_data_mbuf == NULL);
|
||||
MPASS(icp->ip.ip_data_len == 0);
|
||||
|
||||
|
||||
m_adj(m, sizeof(*cpl));
|
||||
MPASS(icp->ip.ip_data_len == m->m_pkthdr.len);
|
||||
|
||||
icp->icp_flags |= ICPF_RX_FLBUF;
|
||||
icp->ip.ip_data_mbuf = m;
|
||||
icp->ip.ip_data_len = m->m_pkthdr.len;
|
||||
counter_u64_add(ci->fl_pdus, 1);
|
||||
counter_u64_add(ci->fl_bytes, m->m_pkthdr.len);
|
||||
|
||||
#if 0
|
||||
CTR4(KTR_CXGBE, "%s: tid %u, cpl->len dlen %u, m->m_len dlen %u",
|
||||
__func__, tid, ntohs(cpl->len), m->m_len);
|
||||
CTR3(KTR_CXGBE, "%s: tid %u, cpl->len %u", __func__, tid,
|
||||
be16toh(cpl->len));
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
|
@ -627,6 +330,7 @@ static int
|
|||
do_rx_iscsi_ddp(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
|
||||
{
|
||||
struct adapter *sc = iq->adapter;
|
||||
struct cxgbei_data *ci = sc->iscsi_ulp_softc;
|
||||
const struct cpl_rx_data_ddp *cpl = (const void *)(rss + 1);
|
||||
u_int tid = GET_TID(cpl);
|
||||
struct toepcb *toep = lookup_tid(sc, tid);
|
||||
|
@ -645,20 +349,32 @@ do_rx_iscsi_ddp(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
|
|||
/* Must already be assembling a PDU. */
|
||||
MPASS(icp != NULL);
|
||||
MPASS(icp->icp_flags & ICPF_RX_HDR); /* Data is optional. */
|
||||
ip = &icp->ip;
|
||||
MPASS((icp->icp_flags & ICPF_RX_STATUS) == 0);
|
||||
|
||||
pdu_len = be16toh(cpl->len); /* includes everything. */
|
||||
val = be32toh(cpl->ddpvld);
|
||||
|
||||
#if 0
|
||||
CTR4(KTR_CXGBE,
|
||||
"%s: tid %u, cpl->len %u, ddpvld 0x%08x, icp_flags 0x%08x",
|
||||
__func__, tid, pdu_len, val, icp->icp_flags);
|
||||
#endif
|
||||
|
||||
icp->icp_flags |= ICPF_RX_STATUS;
|
||||
val = ntohl(cpl->ddpvld);
|
||||
ip = &icp->ip;
|
||||
if (val & F_DDP_PADDING_ERR)
|
||||
icp->icp_flags |= ICPF_PAD_ERR;
|
||||
if (val & F_DDP_HDRCRC_ERR)
|
||||
icp->icp_flags |= ICPF_HCRC_ERR;
|
||||
if (val & F_DDP_DATACRC_ERR)
|
||||
icp->icp_flags |= ICPF_DCRC_ERR;
|
||||
if (ip->ip_data_mbuf == NULL) {
|
||||
/* XXXNP: what should ip->ip_data_len be, and why? */
|
||||
if (val & F_DDP_PDU && ip->ip_data_mbuf == NULL) {
|
||||
MPASS((icp->icp_flags & ICPF_RX_FLBUF) == 0);
|
||||
MPASS(ip->ip_data_len > 0);
|
||||
icp->icp_flags |= ICPF_RX_DDP;
|
||||
counter_u64_add(ci->ddp_pdus, 1);
|
||||
counter_u64_add(ci->ddp_bytes, ip->ip_data_len);
|
||||
}
|
||||
pdu_len = ntohs(cpl->len); /* includes everything. */
|
||||
|
||||
INP_WLOCK(inp);
|
||||
if (__predict_false(inp->inp_flags & (INP_DROPPED | INP_TIMEWAIT))) {
|
||||
|
@ -744,11 +460,6 @@ do_rx_iscsi_ddp(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
|
|||
m_freem(m);
|
||||
}
|
||||
|
||||
#if 0
|
||||
CTR4(KTR_CXGBE, "%s: tid %u, pdu_len %u, pdu_flags 0x%x",
|
||||
__func__, tid, pdu_len, icp->icp_flags);
|
||||
#endif
|
||||
|
||||
STAILQ_INSERT_TAIL(&icc->rcvd_pdus, ip, ip_next);
|
||||
if ((icc->rx_flags & RXF_ACTIVE) == 0) {
|
||||
struct cxgbei_worker_thread_softc *cwt = &cwt_softc[icc->cwt];
|
||||
|
@ -772,47 +483,6 @@ do_rx_iscsi_ddp(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
|
|||
return (0);
|
||||
}
|
||||
|
||||
/* initiator */
|
||||
void
|
||||
cxgbei_conn_task_reserve_itt(void *conn, void **prv,
|
||||
void *scmd, unsigned int *itt)
|
||||
{
|
||||
unsigned int tag;
|
||||
tag = cxgbei_task_reserve_itt(conn, prv, scmd, itt);
|
||||
if (tag)
|
||||
*itt = htonl(tag);
|
||||
return;
|
||||
}
|
||||
|
||||
/* target */
|
||||
void
|
||||
cxgbei_conn_transfer_reserve_ttt(void *conn, void **prv,
|
||||
void *scmd, unsigned int *ttt)
|
||||
{
|
||||
unsigned int tag;
|
||||
tag = cxgbei_task_reserve_ttt(conn, prv, scmd, ttt);
|
||||
if (tag)
|
||||
*ttt = htonl(tag);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
cxgbei_cleanup_task(void *conn, void *ofld_priv)
|
||||
{
|
||||
struct icl_conn *ic = (struct icl_conn *)conn;
|
||||
struct icl_cxgbei_conn *icc = ic_to_icc(ic);
|
||||
struct cxgbei_task_data *tdata = ofld_priv;
|
||||
struct adapter *sc = icc->sc;
|
||||
struct cxgbei_data *ci = sc->iscsi_ulp_softc;
|
||||
|
||||
MPASS(icc->icc_signature == CXGBEI_CONN_SIGNATURE);
|
||||
MPASS(tdata != NULL);
|
||||
|
||||
if (cxgbei_ulp2_is_ddp_tag(&ci->tag_format, tdata->sc_ddp_tag))
|
||||
t4_sk_ddp_tag_release(icc, tdata->sc_ddp_tag);
|
||||
memset(tdata, 0, sizeof(*tdata));
|
||||
}
|
||||
|
||||
static int
|
||||
cxgbei_activate(struct adapter *sc)
|
||||
{
|
||||
|
@ -834,7 +504,7 @@ cxgbei_activate(struct adapter *sc)
|
|||
}
|
||||
|
||||
/* per-adapter softc for iSCSI */
|
||||
ci = malloc(sizeof(*ci), M_CXGBE, M_ZERO | M_NOWAIT);
|
||||
ci = malloc(sizeof(*ci), M_CXGBE, M_ZERO | M_WAITOK);
|
||||
if (ci == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
|
@ -852,12 +522,15 @@ cxgbei_activate(struct adapter *sc)
|
|||
static int
|
||||
cxgbei_deactivate(struct adapter *sc)
|
||||
{
|
||||
struct cxgbei_data *ci = sc->iscsi_ulp_softc;
|
||||
|
||||
ASSERT_SYNCHRONIZED_OP(sc);
|
||||
|
||||
if (sc->iscsi_ulp_softc != NULL) {
|
||||
cxgbei_ddp_cleanup(sc->iscsi_ulp_softc);
|
||||
free(sc->iscsi_ulp_softc, M_CXGBE);
|
||||
if (ci != NULL) {
|
||||
sysctl_ctx_free(&ci->ctx);
|
||||
t4_free_ppod_region(&ci->pr);
|
||||
free_ci_counters(ci);
|
||||
free(ci, M_CXGBE);
|
||||
sc->iscsi_ulp_softc = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,69 +105,25 @@ ip_to_icp(struct icl_pdu *ip)
|
|||
return (__containerof(ip, struct icl_cxgbei_pdu, ip));
|
||||
}
|
||||
|
||||
struct cxgbei_sgl {
|
||||
int sg_flag;
|
||||
void *sg_addr;
|
||||
void *sg_dma_addr;
|
||||
size_t sg_offset;
|
||||
size_t sg_length;
|
||||
};
|
||||
|
||||
#define cxgbei_scsi_for_each_sg(_sgl, _sgel, _n, _i) \
|
||||
for (_i = 0, _sgel = (cxgbei_sgl*) (_sgl); _i < _n; _i++, \
|
||||
_sgel++)
|
||||
#define sg_dma_addr(_sgel) _sgel->sg_dma_addr
|
||||
#define sg_virt(_sgel) _sgel->sg_addr
|
||||
#define sg_len(_sgel) _sgel->sg_length
|
||||
#define sg_off(_sgel) _sgel->sg_offset
|
||||
#define sg_next(_sgel) _sgel + 1
|
||||
|
||||
/* private data for each scsi task */
|
||||
struct cxgbei_task_data {
|
||||
struct cxgbei_sgl sgl[256];
|
||||
u_int nsge;
|
||||
u_int sc_ddp_tag;
|
||||
};
|
||||
|
||||
struct cxgbei_ulp2_tag_format {
|
||||
u_char sw_bits;
|
||||
u_char rsvd_bits;
|
||||
u_char rsvd_shift;
|
||||
u_char filler[1];
|
||||
uint32_t rsvd_mask;
|
||||
};
|
||||
|
||||
struct cxgbei_data {
|
||||
u_int llimit;
|
||||
u_int ulimit;
|
||||
u_int nppods;
|
||||
u_int idx_last;
|
||||
u_char idx_bits;
|
||||
uint32_t idx_mask;
|
||||
uint32_t rsvd_tag_mask;
|
||||
u_int max_tx_pdu_len;
|
||||
u_int max_rx_pdu_len;
|
||||
|
||||
struct mtx map_lock;
|
||||
bus_dma_tag_t ulp_ddp_tag;
|
||||
unsigned char *colors;
|
||||
struct cxgbei_ulp2_gather_list **gl_map;
|
||||
u_int ddp_threshold;
|
||||
struct ppod_region pr;
|
||||
|
||||
struct cxgbei_ulp2_tag_format tag_format;
|
||||
struct sysctl_ctx_list ctx; /* from uld_activate to deactivate */
|
||||
counter_u64_t ddp_setup_ok;
|
||||
counter_u64_t ddp_setup_error;
|
||||
counter_u64_t ddp_bytes;
|
||||
counter_u64_t ddp_pdus;
|
||||
counter_u64_t fl_bytes;
|
||||
counter_u64_t fl_pdus;
|
||||
};
|
||||
|
||||
void cxgbei_conn_task_reserve_itt(void *, void **, void *, unsigned int *);
|
||||
void cxgbei_conn_transfer_reserve_ttt(void *, void **, void *, unsigned int *);
|
||||
void cxgbei_cleanup_task(void *, void *);
|
||||
/* cxgbei.c */
|
||||
u_int cxgbei_select_worker_thread(struct icl_cxgbei_conn *);
|
||||
|
||||
struct cxgbei_ulp2_pagepod_hdr;
|
||||
int t4_ddp_set_map(struct cxgbei_data *, void *,
|
||||
struct cxgbei_ulp2_pagepod_hdr *, u_int, u_int,
|
||||
struct cxgbei_ulp2_gather_list *, int);
|
||||
void t4_ddp_clear_map(struct cxgbei_data *, struct cxgbei_ulp2_gather_list *,
|
||||
u_int, u_int, u_int, struct icl_cxgbei_conn *);
|
||||
|
||||
/* icl_cxgbei.c */
|
||||
int icl_cxgbei_mod_load(void);
|
||||
int icl_cxgbei_mod_unload(void);
|
||||
|
|
|
@ -1,417 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2012 Chelsio Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Chelsio T5xx iSCSI driver
|
||||
* cxgbei_ulp2_ddp.c: Chelsio iSCSI DDP Manager.
|
||||
*
|
||||
* 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 "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
|
||||
#ifdef TCP_OFFLOAD
|
||||
#include <sys/types.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/condvar.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_pcb.h>
|
||||
#include <netinet/toecore.h>
|
||||
#include <netinet/tcp_var.h>
|
||||
#include <netinet/tcp_fsm.h>
|
||||
|
||||
#include <dev/iscsi/icl.h>
|
||||
#include <dev/iscsi/iscsi_proto.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/t4_msg.h"
|
||||
#include "common/t4_regs.h" /* for PCIE_MEM_ACCESS */
|
||||
#include "tom/t4_tom.h"
|
||||
#include "cxgbei.h"
|
||||
#include "cxgbei_ulp2_ddp.h"
|
||||
|
||||
/*
|
||||
* Map a single buffer address.
|
||||
*/
|
||||
static void
|
||||
ulp2_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
|
||||
{
|
||||
bus_addr_t *ba = arg;
|
||||
if (error)
|
||||
return;
|
||||
|
||||
KASSERT(nseg == 1, ("%s: %d segments returned!", __func__, nseg));
|
||||
|
||||
*ba = segs->ds_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* iSCSI Direct Data Placement
|
||||
*
|
||||
* T4/5 ulp2 h/w can directly place the iSCSI Data-In or Data-Out PDU's
|
||||
* payload into pre-posted final destination host-memory buffers based on the
|
||||
* Initiator Task Tag (ITT) in Data-In or Target Task Tag (TTT) in Data-Out
|
||||
* PDUs.
|
||||
*
|
||||
* The host memory address is programmed into h/w in the format of pagepod
|
||||
* entries.
|
||||
* The location of the pagepod entry is encoded into ddp tag which is used or
|
||||
* is the base for ITT/TTT.
|
||||
*/
|
||||
|
||||
|
||||
static inline int
|
||||
ddp_find_unused_entries(struct cxgbei_data *ci, u_int start, u_int max,
|
||||
u_int count, u_int *idx, struct cxgbei_ulp2_gather_list *gl)
|
||||
{
|
||||
unsigned int i, j, k;
|
||||
|
||||
/* not enough entries */
|
||||
if (max - start < count)
|
||||
return (EBUSY);
|
||||
|
||||
max -= count;
|
||||
mtx_lock(&ci->map_lock);
|
||||
for (i = start; i < max;) {
|
||||
for (j = 0, k = i; j < count; j++, k++) {
|
||||
if (ci->gl_map[k])
|
||||
break;
|
||||
}
|
||||
if (j == count) {
|
||||
for (j = 0, k = i; j < count; j++, k++)
|
||||
ci->gl_map[k] = gl;
|
||||
mtx_unlock(&ci->map_lock);
|
||||
*idx = i;
|
||||
return (0);
|
||||
}
|
||||
i += j + 1;
|
||||
}
|
||||
mtx_unlock(&ci->map_lock);
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ddp_unmark_entries(struct cxgbei_data *ci, u_int start, u_int count)
|
||||
{
|
||||
|
||||
mtx_lock(&ci->map_lock);
|
||||
memset(&ci->gl_map[start], 0,
|
||||
count * sizeof(struct cxgbei_ulp2_gather_list *));
|
||||
mtx_unlock(&ci->map_lock);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ddp_gl_unmap(struct cxgbei_data *ci, struct cxgbei_ulp2_gather_list *gl)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!gl->pages[0])
|
||||
return;
|
||||
|
||||
for (i = 0; i < gl->nelem; i++) {
|
||||
bus_dmamap_unload(ci->ulp_ddp_tag, gl->dma_sg[i].bus_map);
|
||||
bus_dmamap_destroy(ci->ulp_ddp_tag, gl->dma_sg[i].bus_map);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
ddp_gl_map(struct cxgbei_data *ci, struct cxgbei_ulp2_gather_list *gl)
|
||||
{
|
||||
int i, rc;
|
||||
bus_addr_t pa;
|
||||
|
||||
MPASS(ci != NULL);
|
||||
|
||||
mtx_lock(&ci->map_lock);
|
||||
for (i = 0; i < gl->nelem; i++) {
|
||||
rc = bus_dmamap_create(ci->ulp_ddp_tag, 0,
|
||||
&gl->dma_sg[i].bus_map);
|
||||
if (rc != 0)
|
||||
goto unmap;
|
||||
rc = bus_dmamap_load(ci->ulp_ddp_tag, gl->dma_sg[i].bus_map,
|
||||
gl->pages[i], PAGE_SIZE, ulp2_dma_map_addr,
|
||||
&pa, BUS_DMA_NOWAIT);
|
||||
if (rc != 0)
|
||||
goto unmap;
|
||||
gl->dma_sg[i].phys_addr = pa;
|
||||
}
|
||||
mtx_unlock(&ci->map_lock);
|
||||
|
||||
return (0);
|
||||
|
||||
unmap:
|
||||
if (i) {
|
||||
u_int nelem = gl->nelem;
|
||||
|
||||
gl->nelem = i;
|
||||
ddp_gl_unmap(ci, gl);
|
||||
gl->nelem = nelem;
|
||||
}
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
/**
|
||||
* cxgbei_ulp2_ddp_make_gl_from_iscsi_sgvec - build ddp page buffer list
|
||||
* @xferlen: total buffer length
|
||||
* @sgl: page buffer scatter-gather list (struct cxgbei_sgl)
|
||||
* @sgcnt: # of page buffers
|
||||
* @gfp: allocation mode
|
||||
*
|
||||
* construct a ddp page buffer list from the scsi scattergather list.
|
||||
* coalesce buffers as much as possible, and obtain dma addresses for
|
||||
* each page.
|
||||
*
|
||||
* Return the cxgbei_ulp2_gather_list constructed from the page buffers if the
|
||||
* memory can be used for ddp. Return NULL otherwise.
|
||||
*/
|
||||
struct cxgbei_ulp2_gather_list *
|
||||
cxgbei_ulp2_ddp_make_gl_from_iscsi_sgvec(u_int xferlen, struct cxgbei_sgl *sgl,
|
||||
u_int sgcnt, struct cxgbei_data *ci, int gfp)
|
||||
{
|
||||
struct cxgbei_ulp2_gather_list *gl;
|
||||
struct cxgbei_sgl *sg = sgl;
|
||||
void *sgpage = (void *)((u64)sg->sg_addr & (~PAGE_MASK));
|
||||
unsigned int sglen = sg->sg_length;
|
||||
unsigned int sgoffset = (u64)sg->sg_addr & PAGE_MASK;
|
||||
unsigned int npages = (xferlen + sgoffset + PAGE_SIZE - 1) >>
|
||||
PAGE_SHIFT;
|
||||
int i = 1, j = 0;
|
||||
|
||||
if (xferlen <= DDP_THRESHOLD) {
|
||||
CTR2(KTR_CXGBE, "xfer %u < threshold %u, no ddp.",
|
||||
xferlen, DDP_THRESHOLD);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gl = malloc(sizeof(struct cxgbei_ulp2_gather_list) +
|
||||
npages * (sizeof(struct dma_segments) + sizeof(void *)),
|
||||
M_DEVBUF, M_NOWAIT | M_ZERO);
|
||||
if (gl == NULL)
|
||||
return (NULL);
|
||||
|
||||
gl->pages = (void **)&gl->dma_sg[npages];
|
||||
gl->length = xferlen;
|
||||
gl->offset = sgoffset;
|
||||
gl->pages[0] = sgpage;
|
||||
CTR6(KTR_CXGBE,
|
||||
"%s: xferlen:0x%x len:0x%x off:0x%x sg_addr:%p npages:%d",
|
||||
__func__, xferlen, gl->length, gl->offset, sg->sg_addr, npages);
|
||||
|
||||
for (i = 1, sg = sg_next(sg); i < sgcnt; i++, sg = sg_next(sg)) {
|
||||
void *page = sg->sg_addr;
|
||||
|
||||
if (sgpage == page && sg->sg_offset == sgoffset + sglen)
|
||||
sglen += sg->sg_length;
|
||||
else {
|
||||
/* make sure the sgl is fit for ddp:
|
||||
* each has the same page size, and
|
||||
* all of the middle pages are used completely
|
||||
*/
|
||||
if ((j && sgoffset) ||
|
||||
((i != sgcnt - 1) &&
|
||||
((sglen + sgoffset) & ~CXGBEI_PAGE_MASK))){
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
j++;
|
||||
if (j == gl->nelem || sg->sg_offset) {
|
||||
goto error_out;
|
||||
}
|
||||
gl->pages[j] = page;
|
||||
sglen = sg->sg_length;
|
||||
sgoffset = sg->sg_offset;
|
||||
sgpage = page;
|
||||
}
|
||||
}
|
||||
gl->nelem = ++j;
|
||||
|
||||
if (ddp_gl_map(ci, gl) < 0)
|
||||
goto error_out;
|
||||
|
||||
return gl;
|
||||
|
||||
error_out:
|
||||
free(gl, M_DEVBUF);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* cxgbei_ulp2_ddp_release_gl - release a page buffer list
|
||||
* @gl: a ddp page buffer list
|
||||
* @pdev: pci_dev used for pci_unmap
|
||||
* free a ddp page buffer list resulted from cxgbei_ulp2_ddp_make_gl().
|
||||
*/
|
||||
void
|
||||
cxgbei_ulp2_ddp_release_gl(struct cxgbei_data *ci,
|
||||
struct cxgbei_ulp2_gather_list *gl)
|
||||
{
|
||||
|
||||
ddp_gl_unmap(ci, gl);
|
||||
free(gl, M_DEVBUF);
|
||||
}
|
||||
|
||||
/**
|
||||
* cxgbei_ulp2_ddp_tag_reserve - set up ddp for a data transfer
|
||||
* @ci: adapter's ddp info
|
||||
* @tid: connection id
|
||||
* @tformat: tag format
|
||||
* @tagp: contains s/w tag initially, will be updated with ddp/hw tag
|
||||
* @gl: the page momory list
|
||||
* @gfp: allocation mode
|
||||
*
|
||||
* ddp setup for a given page buffer list and construct the ddp tag.
|
||||
* return 0 if success, < 0 otherwise.
|
||||
*/
|
||||
int
|
||||
cxgbei_ulp2_ddp_tag_reserve(struct cxgbei_data *ci, void *icc, u_int tid,
|
||||
struct cxgbei_ulp2_tag_format *tformat, u32 *tagp,
|
||||
struct cxgbei_ulp2_gather_list *gl, int gfp, int reply)
|
||||
{
|
||||
struct cxgbei_ulp2_pagepod_hdr hdr;
|
||||
u_int npods, idx;
|
||||
int rc;
|
||||
u32 sw_tag = *tagp;
|
||||
u32 tag;
|
||||
|
||||
MPASS(ci != NULL);
|
||||
|
||||
if (!gl || !gl->nelem || gl->length < DDP_THRESHOLD)
|
||||
return (EINVAL);
|
||||
|
||||
npods = (gl->nelem + IPPOD_PAGES_MAX - 1) >> IPPOD_PAGES_SHIFT;
|
||||
|
||||
if (ci->idx_last == ci->nppods)
|
||||
rc = ddp_find_unused_entries(ci, 0, ci->nppods, npods, &idx,
|
||||
gl);
|
||||
else {
|
||||
rc = ddp_find_unused_entries(ci, ci->idx_last + 1,
|
||||
ci->nppods, npods, &idx, gl);
|
||||
if (rc && ci->idx_last >= npods) {
|
||||
rc = ddp_find_unused_entries(ci, 0,
|
||||
min(ci->idx_last + npods, ci->nppods),
|
||||
npods, &idx, gl);
|
||||
}
|
||||
}
|
||||
if (rc) {
|
||||
CTR3(KTR_CXGBE, "xferlen %u, gl %u, npods %u NO DDP.",
|
||||
gl->length, gl->nelem, npods);
|
||||
return (rc);
|
||||
}
|
||||
|
||||
tag = cxgbei_ulp2_ddp_tag_base(idx, ci->colors, tformat, sw_tag);
|
||||
CTR4(KTR_CXGBE, "%s: sw_tag:0x%x idx:0x%x tag:0x%x",
|
||||
__func__, sw_tag, idx, tag);
|
||||
|
||||
hdr.rsvd = 0;
|
||||
hdr.vld_tid = htonl(F_IPPOD_VALID | V_IPPOD_TID(tid));
|
||||
hdr.pgsz_tag_clr = htonl(tag & ci->rsvd_tag_mask);
|
||||
hdr.maxoffset = htonl(gl->length);
|
||||
hdr.pgoffset = htonl(gl->offset);
|
||||
|
||||
rc = t4_ddp_set_map(ci, icc, &hdr, idx, npods, gl, reply);
|
||||
if (rc < 0)
|
||||
goto unmark_entries;
|
||||
|
||||
ci->idx_last = idx;
|
||||
*tagp = tag;
|
||||
return (0);
|
||||
|
||||
unmark_entries:
|
||||
ddp_unmark_entries(ci, idx, npods);
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/**
|
||||
* cxgbei_ulp2_ddp_tag_release - release a ddp tag
|
||||
* @ci: adapter's ddp info
|
||||
* @tag: ddp tag
|
||||
* ddp cleanup for a given ddp tag and release all the resources held
|
||||
*/
|
||||
void
|
||||
cxgbei_ulp2_ddp_tag_release(struct cxgbei_data *ci, uint32_t tag,
|
||||
struct icl_cxgbei_conn *icc)
|
||||
{
|
||||
uint32_t idx;
|
||||
|
||||
MPASS(ci != NULL);
|
||||
MPASS(icc != NULL);
|
||||
|
||||
idx = (tag >> IPPOD_IDX_SHIFT) & ci->idx_mask;
|
||||
CTR3(KTR_CXGBE, "tag:0x%x idx:0x%x nppods:0x%x",
|
||||
tag, idx, ci->nppods);
|
||||
if (idx < ci->nppods) {
|
||||
struct cxgbei_ulp2_gather_list *gl = ci->gl_map[idx];
|
||||
unsigned int npods;
|
||||
|
||||
if (!gl || !gl->nelem) {
|
||||
CTR4(KTR_CXGBE,
|
||||
"release 0x%x, idx 0x%x, gl 0x%p, %u.",
|
||||
tag, idx, gl, gl ? gl->nelem : 0);
|
||||
return;
|
||||
}
|
||||
npods = (gl->nelem + IPPOD_PAGES_MAX - 1) >> IPPOD_PAGES_SHIFT;
|
||||
CTR3(KTR_CXGBE, "ddp tag 0x%x, release idx 0x%x, npods %u.",
|
||||
tag, idx, npods);
|
||||
t4_ddp_clear_map(ci, gl, tag, idx, npods, icc);
|
||||
ddp_unmark_entries(ci, idx, npods);
|
||||
cxgbei_ulp2_ddp_release_gl(ci, gl);
|
||||
} else
|
||||
CTR3(KTR_CXGBE, "ddp tag 0x%x, idx 0x%x > max 0x%x.",
|
||||
tag, idx, ci->nppods);
|
||||
}
|
||||
|
||||
/**
|
||||
* cxgbei_ddp_cleanup - release the adapter's ddp resources
|
||||
*/
|
||||
void
|
||||
cxgbei_ddp_cleanup(struct cxgbei_data *ci)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (i < ci->nppods) {
|
||||
struct cxgbei_ulp2_gather_list *gl = ci->gl_map[i];
|
||||
if (gl) {
|
||||
int npods = (gl->nelem + IPPOD_PAGES_MAX - 1)
|
||||
>> IPPOD_PAGES_SHIFT;
|
||||
free(gl, M_DEVBUF);
|
||||
i += npods;
|
||||
} else
|
||||
i++;
|
||||
}
|
||||
free(ci->colors, M_CXGBE);
|
||||
free(ci->gl_map, M_CXGBE);
|
||||
}
|
||||
#endif
|
|
@ -1,217 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2012 Chelsio Communications, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Chelsio T5xx iSCSI driver
|
||||
* cxgbei_ulp2_ddp.c: Chelsio iSCSI DDP Manager.
|
||||
*
|
||||
* 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 __CXGBEI_ULP2_DDP_H__
|
||||
#define __CXGBEI_ULP2_DDP_H__
|
||||
|
||||
#define CXGBEI_PAGE_MASK (~(PAGE_SIZE-1))
|
||||
#define DDP_THRESHOLD 2048
|
||||
|
||||
/*
|
||||
* cxgbei ddp tag are 32 bits, it consists of reserved bits used by h/w and
|
||||
* non-reserved bits that can be used by the iscsi s/w.
|
||||
* The reserved bits are identified by the rsvd_bits and rsvd_shift fields
|
||||
* in struct cxgbei_ulp2_tag_format.
|
||||
*
|
||||
* The upper most reserved bit can be used to check if a tag is ddp tag or not:
|
||||
* if the bit is 0, the tag is a valid ddp tag
|
||||
*/
|
||||
|
||||
/*
|
||||
* cxgbei_ulp2_is_ddp_tag - check if a given tag is a hw/ddp tag
|
||||
* @tformat: tag format information
|
||||
* @tag: tag to be checked
|
||||
*
|
||||
* return true if the tag is a ddp tag, false otherwise.
|
||||
*/
|
||||
static inline int
|
||||
cxgbei_ulp2_is_ddp_tag(struct cxgbei_ulp2_tag_format *tformat, uint32_t tag)
|
||||
{
|
||||
|
||||
return (!(tag & (1 << (tformat->rsvd_bits + tformat->rsvd_shift - 1))));
|
||||
}
|
||||
|
||||
/*
|
||||
* cxgbei_ulp2_sw_tag_usable - check if s/w tag has enough bits left for hw bits
|
||||
* @tformat: tag format information
|
||||
* @sw_tag: s/w tag to be checked
|
||||
*
|
||||
* return true if the tag can be used for hw ddp tag, false otherwise.
|
||||
*/
|
||||
static inline int
|
||||
cxgbei_ulp2_sw_tag_usable(struct cxgbei_ulp2_tag_format *tformat,
|
||||
uint32_t sw_tag)
|
||||
{
|
||||
|
||||
return (1); /* XXXNP: huh? */
|
||||
|
||||
sw_tag >>= (32 - tformat->rsvd_bits + tformat->rsvd_shift);
|
||||
return !sw_tag;
|
||||
}
|
||||
|
||||
/*
|
||||
* cxgbei_ulp2_set_non_ddp_tag - mark a given s/w tag as an invalid ddp tag
|
||||
* @tformat: tag format information
|
||||
* @sw_tag: s/w tag to be checked
|
||||
*
|
||||
* insert 1 at the upper most reserved bit to mark it as an invalid ddp tag.
|
||||
*/
|
||||
static inline uint32_t
|
||||
cxgbei_ulp2_set_non_ddp_tag(struct cxgbei_ulp2_tag_format *tformat,
|
||||
uint32_t sw_tag)
|
||||
{
|
||||
uint32_t rsvd_bits = tformat->rsvd_bits + tformat->rsvd_shift;
|
||||
if (sw_tag) {
|
||||
u32 v1 = sw_tag & ((1 << (rsvd_bits - 1)) - 1);
|
||||
u32 v2 = (sw_tag >> (rsvd_bits - 1)) << rsvd_bits;
|
||||
return v2 | (1 << (rsvd_bits - 1)) | v1;
|
||||
}
|
||||
|
||||
return sw_tag | (1 << (rsvd_bits - 1)) ;
|
||||
}
|
||||
|
||||
struct dma_segments {
|
||||
bus_dmamap_t bus_map;
|
||||
bus_addr_t phys_addr;
|
||||
};
|
||||
/*
|
||||
* struct cxgbei_ulp2_gather_list - cxgbei direct data placement memory
|
||||
*
|
||||
* @tag: ddp tag
|
||||
* @length: total data buffer length
|
||||
* @offset: initial offset to the 1st page
|
||||
* @nelem: # of pages
|
||||
* @pages: page pointers
|
||||
* @phys_addr: physical address
|
||||
*/
|
||||
struct cxgbei_ulp2_gather_list {
|
||||
uint32_t tag;
|
||||
uint32_t tid;
|
||||
uint32_t port_id;
|
||||
void *egress_dev;
|
||||
unsigned int length;
|
||||
unsigned int offset;
|
||||
unsigned int nelem;
|
||||
bus_size_t mapsize;
|
||||
bus_dmamap_t bus_map;
|
||||
bus_dma_segment_t *segments;
|
||||
void **pages;
|
||||
struct dma_segments dma_sg[0];
|
||||
};
|
||||
|
||||
#define IPPOD_SIZE sizeof(struct cxgbei_ulp2_pagepod) /* 64 */
|
||||
#define IPPOD_SIZE_SHIFT 6
|
||||
|
||||
#define IPPOD_COLOR_SHIFT 0
|
||||
#define IPPOD_COLOR_SIZE 6
|
||||
#define IPPOD_COLOR_MASK ((1 << IPPOD_COLOR_SIZE) - 1)
|
||||
|
||||
#define IPPOD_IDX_SHIFT IPPOD_COLOR_SIZE
|
||||
#define IPPOD_IDX_MAX_SIZE 24
|
||||
|
||||
#define S_IPPOD_TID 0
|
||||
#define M_IPPOD_TID 0xFFFFFF
|
||||
#define V_IPPOD_TID(x) ((x) << S_IPPOD_TID)
|
||||
|
||||
#define S_IPPOD_VALID 24
|
||||
#define V_IPPOD_VALID(x) ((x) << S_IPPOD_VALID)
|
||||
#define F_IPPOD_VALID V_IPPOD_VALID(1U)
|
||||
|
||||
#define S_IPPOD_COLOR 0
|
||||
#define M_IPPOD_COLOR 0x3F
|
||||
#define V_IPPOD_COLOR(x) ((x) << S_IPPOD_COLOR)
|
||||
|
||||
#define S_IPPOD_TAG 6
|
||||
#define M_IPPOD_TAG 0xFFFFFF
|
||||
#define V_IPPOD_TAG(x) ((x) << S_IPPOD_TAG)
|
||||
|
||||
#define S_IPPOD_PGSZ 30
|
||||
#define M_IPPOD_PGSZ 0x3
|
||||
#define V_IPPOD_PGSZ(x) ((x) << S_IPPOD_PGSZ)
|
||||
|
||||
static inline uint32_t
|
||||
cxgbei_ulp2_ddp_tag_base(u_int idx, u_char *colors,
|
||||
struct cxgbei_ulp2_tag_format *tformat, uint32_t sw_tag)
|
||||
{
|
||||
if (__predict_false(++colors[idx] == 1 << IPPOD_IDX_SHIFT))
|
||||
colors[idx] = 0;
|
||||
|
||||
sw_tag <<= tformat->rsvd_bits + tformat->rsvd_shift;
|
||||
|
||||
return (sw_tag | idx << IPPOD_IDX_SHIFT | colors[idx]);
|
||||
}
|
||||
|
||||
#define ISCSI_PDU_NONPAYLOAD_LEN 312 /* bhs(48) + ahs(256) + digest(8) */
|
||||
|
||||
/*
|
||||
* align pdu size to multiple of 512 for better performance
|
||||
*/
|
||||
#define cxgbei_align_pdu_size(n) do { n = (n) & (~511); } while (0)
|
||||
|
||||
#define ULP2_MAX_PKT_SIZE 16224
|
||||
#define ULP2_MAX_PDU_PAYLOAD (ULP2_MAX_PKT_SIZE - ISCSI_PDU_NONPAYLOAD_LEN)
|
||||
#define IPPOD_PAGES_MAX 4
|
||||
#define IPPOD_PAGES_SHIFT 2 /* 4 pages per pod */
|
||||
|
||||
/*
|
||||
* struct pagepod_hdr, pagepod - pagepod format
|
||||
*/
|
||||
struct cxgbei_ulp2_pagepod_hdr {
|
||||
uint32_t vld_tid;
|
||||
uint32_t pgsz_tag_clr;
|
||||
uint32_t maxoffset;
|
||||
uint32_t pgoffset;
|
||||
uint64_t rsvd;
|
||||
};
|
||||
|
||||
struct cxgbei_ulp2_pagepod {
|
||||
struct cxgbei_ulp2_pagepod_hdr hdr;
|
||||
uint64_t addr[IPPOD_PAGES_MAX + 1];
|
||||
};
|
||||
|
||||
int cxgbei_ulp2_ddp_tag_reserve(struct cxgbei_data *, void *, unsigned int,
|
||||
struct cxgbei_ulp2_tag_format *, uint32_t *,
|
||||
struct cxgbei_ulp2_gather_list *, int , int );
|
||||
void cxgbei_ulp2_ddp_tag_release(struct cxgbei_data *, uint32_t,
|
||||
struct icl_cxgbei_conn *);
|
||||
|
||||
struct cxgbei_ulp2_gather_list *cxgbei_ulp2_ddp_make_gl_from_iscsi_sgvec(u_int,
|
||||
struct cxgbei_sgl *, u_int, struct cxgbei_data *, int);
|
||||
void cxgbei_ulp2_ddp_release_gl(struct cxgbei_data *,
|
||||
struct cxgbei_ulp2_gather_list *);
|
||||
|
||||
int cxgbei_ulp2_ddp_find_page_index(u_long);
|
||||
int cxgbei_ulp2_adapter_ddp_info(struct cxgbei_data *,
|
||||
struct cxgbei_ulp2_tag_format *);
|
||||
|
||||
void cxgbei_ddp_cleanup(struct cxgbei_data *);
|
||||
#endif
|
|
@ -60,6 +60,8 @@ __FBSDID("$FreeBSD$");
|
|||
#include <sys/uio.h>
|
||||
#include <machine/bus.h>
|
||||
#include <vm/uma.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_pcb.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
@ -70,6 +72,28 @@ __FBSDID("$FreeBSD$");
|
|||
#include <dev/iscsi/iscsi_proto.h>
|
||||
#include <icl_conn_if.h>
|
||||
|
||||
#include <cam/scsi/scsi_all.h>
|
||||
#include <cam/scsi/scsi_da.h>
|
||||
#include <cam/ctl/ctl_io.h>
|
||||
#include <cam/ctl/ctl.h>
|
||||
#include <cam/ctl/ctl_backend.h>
|
||||
#include <cam/ctl/ctl_error.h>
|
||||
#include <cam/ctl/ctl_frontend.h>
|
||||
#include <cam/ctl/ctl_debug.h>
|
||||
#include <cam/ctl/ctl_ha.h>
|
||||
#include <cam/ctl/ctl_ioctl.h>
|
||||
|
||||
#include <cam/cam.h>
|
||||
#include <cam/cam_ccb.h>
|
||||
#include <cam/cam_xpt.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/cam_compat.h>
|
||||
#include <cam/scsi/scsi_message.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/t4_tcb.h"
|
||||
#include "tom/t4_tom.h"
|
||||
|
@ -90,8 +114,7 @@ static int recvspace = 1048576;
|
|||
SYSCTL_INT(_kern_icl_cxgbei, OID_AUTO, recvspace, CTLFLAG_RWTUN,
|
||||
&recvspace, 0, "Default receive socket buffer size");
|
||||
|
||||
static uma_zone_t icl_transfer_zone;
|
||||
|
||||
static uma_zone_t prsv_zone;
|
||||
static volatile u_int icl_cxgbei_ncons;
|
||||
|
||||
#define ICL_CONN_LOCK(X) mtx_lock(X->ic_lock)
|
||||
|
@ -242,12 +265,6 @@ icl_cxgbei_conn_pdu_data_segment_length(struct icl_conn *ic,
|
|||
return (icl_pdu_data_segment_length(request));
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
icl_conn_build_tasktag(struct icl_conn *ic, uint32_t tag)
|
||||
{
|
||||
return tag;
|
||||
}
|
||||
|
||||
static struct mbuf *
|
||||
finalize_pdu(struct icl_cxgbei_conn *icc, struct icl_cxgbei_pdu *icp)
|
||||
{
|
||||
|
@ -776,55 +793,221 @@ icl_cxgbei_conn_close(struct icl_conn *ic)
|
|||
|
||||
int
|
||||
icl_cxgbei_conn_task_setup(struct icl_conn *ic, struct icl_pdu *ip,
|
||||
struct ccb_scsiio *csio, uint32_t *task_tagp, void **prvp)
|
||||
struct ccb_scsiio *csio, uint32_t *ittp, void **arg)
|
||||
{
|
||||
void *prv;
|
||||
struct icl_cxgbei_conn *icc = ic_to_icc(ic);
|
||||
struct toepcb *toep = icc->toep;
|
||||
struct adapter *sc = icc->sc;
|
||||
struct cxgbei_data *ci = sc->iscsi_ulp_softc;
|
||||
struct ppod_region *pr = &ci->pr;
|
||||
struct ppod_reservation *prsv;
|
||||
uint32_t itt;
|
||||
int rc = 0;
|
||||
|
||||
*task_tagp = icl_conn_build_tasktag(ic, *task_tagp);
|
||||
/* This is for the offload driver's state. Must not be set already. */
|
||||
MPASS(arg != NULL);
|
||||
MPASS(*arg == NULL);
|
||||
|
||||
prv = uma_zalloc(icl_transfer_zone, M_NOWAIT | M_ZERO);
|
||||
if (prv == NULL)
|
||||
return (ENOMEM);
|
||||
if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_IN ||
|
||||
csio->dxfer_len < ci->ddp_threshold) {
|
||||
no_ddp:
|
||||
/*
|
||||
* No DDP for this I/O. Allocate an ITT (based on the one
|
||||
* passed in) that cannot be a valid hardware DDP tag in the
|
||||
* iSCSI region.
|
||||
*/
|
||||
itt = *ittp & M_PPOD_TAG;
|
||||
itt = V_PPOD_TAG(itt) | pr->pr_invalid_bit;
|
||||
*ittp = htobe32(itt);
|
||||
MPASS(*arg == NULL); /* State is maintained for DDP only. */
|
||||
if (rc != 0)
|
||||
counter_u64_add(ci->ddp_setup_error, 1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
*prvp = prv;
|
||||
/*
|
||||
* Reserve resources for DDP, update the itt that should be used in the
|
||||
* PDU, and save DDP specific state for this I/O in *arg.
|
||||
*/
|
||||
|
||||
cxgbei_conn_task_reserve_itt(ic, prvp, csio, task_tagp);
|
||||
prsv = uma_zalloc(prsv_zone, M_NOWAIT);
|
||||
if (prsv == NULL) {
|
||||
rc = ENOMEM;
|
||||
goto no_ddp;
|
||||
}
|
||||
|
||||
/* XXX add support for all CAM_DATA_ types */
|
||||
MPASS((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR);
|
||||
rc = t4_alloc_page_pods_for_buf(pr, (vm_offset_t)csio->data_ptr,
|
||||
csio->dxfer_len, prsv);
|
||||
if (rc != 0) {
|
||||
uma_zfree(prsv_zone, prsv);
|
||||
goto no_ddp;
|
||||
}
|
||||
|
||||
rc = t4_write_page_pods_for_buf(sc, toep->ofld_txq, toep->tid, prsv,
|
||||
(vm_offset_t)csio->data_ptr, csio->dxfer_len);
|
||||
if (rc != 0) {
|
||||
t4_free_page_pods(prsv);
|
||||
uma_zfree(prsv_zone, prsv);
|
||||
goto no_ddp;
|
||||
}
|
||||
|
||||
*ittp = htobe32(prsv->prsv_tag);
|
||||
*arg = prsv;
|
||||
counter_u64_add(ci->ddp_setup_ok, 1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
icl_cxgbei_conn_task_done(struct icl_conn *ic, void *prv)
|
||||
icl_cxgbei_conn_task_done(struct icl_conn *ic, void *arg)
|
||||
{
|
||||
|
||||
cxgbei_cleanup_task(ic, prv);
|
||||
uma_zfree(icl_transfer_zone, prv);
|
||||
if (arg != NULL) {
|
||||
struct ppod_reservation *prsv = arg;
|
||||
|
||||
t4_free_page_pods(prsv);
|
||||
uma_zfree(prsv_zone, prsv);
|
||||
}
|
||||
}
|
||||
|
||||
/* XXXNP: PDU should be passed in as parameter, like on the initiator. */
|
||||
#define io_to_request_pdu(io) ((io)->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr)
|
||||
#define io_to_ppod_reservation(io) ((io)->io_hdr.ctl_private[CTL_PRIV_FRONTEND2].ptr)
|
||||
|
||||
int
|
||||
icl_cxgbei_conn_transfer_setup(struct icl_conn *ic, union ctl_io *io,
|
||||
uint32_t *transfer_tag, void **prvp)
|
||||
uint32_t *tttp, void **arg)
|
||||
{
|
||||
void *prv;
|
||||
struct icl_cxgbei_conn *icc = ic_to_icc(ic);
|
||||
struct toepcb *toep = icc->toep;
|
||||
struct ctl_scsiio *ctsio = &io->scsiio;
|
||||
struct adapter *sc = icc->sc;
|
||||
struct cxgbei_data *ci = sc->iscsi_ulp_softc;
|
||||
struct ppod_region *pr = &ci->pr;
|
||||
struct ppod_reservation *prsv;
|
||||
uint32_t ttt;
|
||||
int xferlen, rc = 0, alias;
|
||||
|
||||
*transfer_tag = icl_conn_build_tasktag(ic, *transfer_tag);
|
||||
/* This is for the offload driver's state. Must not be set already. */
|
||||
MPASS(arg != NULL);
|
||||
MPASS(*arg == NULL);
|
||||
|
||||
prv = uma_zalloc(icl_transfer_zone, M_NOWAIT | M_ZERO);
|
||||
if (prv == NULL)
|
||||
return (ENOMEM);
|
||||
if (ctsio->ext_data_filled == 0) {
|
||||
int first_burst;
|
||||
struct icl_pdu *ip = io_to_request_pdu(io);
|
||||
vm_offset_t buf;
|
||||
#ifdef INVARIANTS
|
||||
struct icl_cxgbei_pdu *icp = ip_to_icp(ip);
|
||||
|
||||
*prvp = prv;
|
||||
MPASS(icp->icp_signature == CXGBEI_PDU_SIGNATURE);
|
||||
MPASS(ic == ip->ip_conn);
|
||||
MPASS(ip->ip_bhs_mbuf != NULL);
|
||||
#endif
|
||||
first_burst = icl_pdu_data_segment_length(ip);
|
||||
|
||||
cxgbei_conn_transfer_reserve_ttt(ic, prvp, io, transfer_tag);
|
||||
/*
|
||||
* Note that ICL calls conn_transfer_setup even if the first
|
||||
* burst had everything and there's nothing left to transfer.
|
||||
*/
|
||||
MPASS(ctsio->kern_data_len >= first_burst);
|
||||
xferlen = ctsio->kern_data_len;
|
||||
if (xferlen - first_burst < ci->ddp_threshold) {
|
||||
no_ddp:
|
||||
/*
|
||||
* No DDP for this transfer. Allocate a TTT (based on
|
||||
* the one passed in) that cannot be a valid hardware
|
||||
* DDP tag in the iSCSI region.
|
||||
*/
|
||||
ttt = *tttp & M_PPOD_TAG;
|
||||
ttt = V_PPOD_TAG(ttt) | pr->pr_invalid_bit;
|
||||
*tttp = htobe32(ttt);
|
||||
MPASS(io_to_ppod_reservation(io) == NULL);
|
||||
if (rc != 0)
|
||||
counter_u64_add(ci->ddp_setup_error, 1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (ctsio->kern_sg_entries == 0)
|
||||
buf = (vm_offset_t)ctsio->kern_data_ptr;
|
||||
else if (ctsio->kern_sg_entries == 1) {
|
||||
struct ctl_sg_entry *sgl = (void *)ctsio->kern_data_ptr;
|
||||
|
||||
MPASS(sgl->len == xferlen);
|
||||
buf = (vm_offset_t)sgl->addr;
|
||||
} else {
|
||||
rc = EAGAIN; /* XXX implement */
|
||||
goto no_ddp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reserve resources for DDP, update the ttt that should be used
|
||||
* in the PDU, and save DDP specific state for this I/O.
|
||||
*/
|
||||
|
||||
MPASS(io_to_ppod_reservation(io) == NULL);
|
||||
prsv = uma_zalloc(prsv_zone, M_NOWAIT);
|
||||
if (prsv == NULL) {
|
||||
rc = ENOMEM;
|
||||
goto no_ddp;
|
||||
}
|
||||
|
||||
rc = t4_alloc_page_pods_for_buf(pr, buf, xferlen, prsv);
|
||||
if (rc != 0) {
|
||||
uma_zfree(prsv_zone, prsv);
|
||||
goto no_ddp;
|
||||
}
|
||||
|
||||
rc = t4_write_page_pods_for_buf(sc, toep->ofld_txq, toep->tid,
|
||||
prsv, buf, xferlen);
|
||||
if (rc != 0) {
|
||||
t4_free_page_pods(prsv);
|
||||
uma_zfree(prsv_zone, prsv);
|
||||
goto no_ddp;
|
||||
}
|
||||
|
||||
*tttp = htobe32(prsv->prsv_tag);
|
||||
io_to_ppod_reservation(io) = prsv;
|
||||
*arg = ctsio;
|
||||
counter_u64_add(ci->ddp_setup_ok, 1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* In the middle of an I/O. A non-NULL page pod reservation indicates
|
||||
* that a DDP buffer is being used for the I/O.
|
||||
*/
|
||||
|
||||
prsv = io_to_ppod_reservation(ctsio);
|
||||
if (prsv == NULL)
|
||||
goto no_ddp;
|
||||
|
||||
alias = (prsv->prsv_tag & pr->pr_alias_mask) >> pr->pr_alias_shift;
|
||||
alias++;
|
||||
prsv->prsv_tag &= ~pr->pr_alias_mask;
|
||||
prsv->prsv_tag |= alias << pr->pr_alias_shift & pr->pr_alias_mask;
|
||||
|
||||
*tttp = htobe32(prsv->prsv_tag);
|
||||
*arg = ctsio;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
icl_cxgbei_conn_transfer_done(struct icl_conn *ic, void *prv)
|
||||
icl_cxgbei_conn_transfer_done(struct icl_conn *ic, void *arg)
|
||||
{
|
||||
cxgbei_cleanup_task(ic, prv);
|
||||
uma_zfree(icl_transfer_zone, prv);
|
||||
struct ctl_scsiio *ctsio = arg;
|
||||
|
||||
if (ctsio != NULL && ctsio->kern_data_len == ctsio->ext_data_filled) {
|
||||
struct ppod_reservation *prsv;
|
||||
|
||||
prsv = io_to_ppod_reservation(ctsio);
|
||||
MPASS(prsv != NULL);
|
||||
|
||||
t4_free_page_pods(prsv);
|
||||
uma_zfree(prsv_zone, prsv);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -882,9 +1065,12 @@ icl_cxgbei_mod_load(void)
|
|||
{
|
||||
int rc;
|
||||
|
||||
icl_transfer_zone = uma_zcreate("icl_transfer",
|
||||
16 * 1024, NULL, NULL, NULL, NULL,
|
||||
UMA_ALIGN_PTR, 0);
|
||||
/*
|
||||
* Space to track pagepod reservations.
|
||||
*/
|
||||
prsv_zone = uma_zcreate("Pagepod reservations",
|
||||
sizeof(struct ppod_reservation), NULL, NULL, NULL, NULL,
|
||||
CACHE_LINE_SIZE, 0);
|
||||
|
||||
refcount_init(&icl_cxgbei_ncons, 0);
|
||||
|
||||
|
@ -903,7 +1089,7 @@ icl_cxgbei_mod_unload(void)
|
|||
|
||||
icl_unregister("cxgbei", false);
|
||||
|
||||
uma_zdestroy(icl_transfer_zone);
|
||||
uma_zdestroy(prsv_zone);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
|
@ -155,7 +155,6 @@ int t4_register_uld(struct uld_info *);
|
|||
int t4_unregister_uld(struct uld_info *);
|
||||
int t4_activate_uld(struct adapter *, int);
|
||||
int t4_deactivate_uld(struct adapter *, int);
|
||||
void t4_iscsi_init(struct adapter *, u_int, const u_int *);
|
||||
int uld_active(struct adapter *, int);
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -8929,16 +8929,6 @@ t4_db_dropped(struct adapter *sc)
|
|||
}
|
||||
|
||||
#ifdef TCP_OFFLOAD
|
||||
void
|
||||
t4_iscsi_init(struct adapter *sc, u_int tag_mask, const u_int *pgsz_order)
|
||||
{
|
||||
|
||||
t4_write_reg(sc, A_ULP_RX_ISCSI_TAGMASK, tag_mask);
|
||||
t4_write_reg(sc, A_ULP_RX_ISCSI_PSZ, V_HPZ0(pgsz_order[0]) |
|
||||
V_HPZ1(pgsz_order[1]) | V_HPZ2(pgsz_order[2]) |
|
||||
V_HPZ3(pgsz_order[3]));
|
||||
}
|
||||
|
||||
static int
|
||||
toe_capability(struct vi_info *vi, int enable)
|
||||
{
|
||||
|
|
|
@ -575,11 +575,20 @@ t4_tweak_chip_settings(struct adapter *sc)
|
|||
V_TIMERVALUE5(us_to_core_ticks(sc, intr_timer[5]));
|
||||
t4_write_reg(sc, A_SGE_TIMER_VALUE_4_AND_5, v);
|
||||
|
||||
/* 4K, 16K, 64K, 256K DDP "page sizes" */
|
||||
/* 4K, 16K, 64K, 256K DDP "page sizes" for TDDP */
|
||||
v = V_HPZ0(0) | V_HPZ1(2) | V_HPZ2(4) | V_HPZ3(6);
|
||||
t4_write_reg(sc, A_ULP_RX_TDDP_PSZ, v);
|
||||
|
||||
m = v = F_TDDPTAGTCB;
|
||||
/*
|
||||
* 4K, 8K, 16K, 64K DDP "page sizes" for iSCSI DDP. These have been
|
||||
* chosen with MAXPHYS = 128K in mind. The largest DDP buffer that we
|
||||
* may have to deal with is MAXPHYS + 1 page.
|
||||
*/
|
||||
v = V_HPZ0(0) | V_HPZ1(1) | V_HPZ2(2) | V_HPZ3(4);
|
||||
t4_write_reg(sc, A_ULP_RX_ISCSI_PSZ, v);
|
||||
|
||||
/* We use multiple DDP page sizes both in plain-TOE and ISCSI modes. */
|
||||
m = v = F_TDDPTAGTCB | F_ISCSITAGTCB;
|
||||
t4_set_reg_field(sc, A_ULP_RX_CTL, m, v);
|
||||
|
||||
m = V_INDICATESIZE(M_INDICATESIZE) | F_REARMDDPOFFSET |
|
||||
|
|
|
@ -1289,7 +1289,7 @@ netvsc_recv(struct hn_rx_ring *rxr, const void *data, int dlen,
|
|||
struct ifnet *ifp = rxr->hn_ifp;
|
||||
struct mbuf *m_new;
|
||||
int size, do_lro = 0, do_csum = 1;
|
||||
int hash_type = M_HASHTYPE_OPAQUE_HASH;
|
||||
int hash_type;
|
||||
|
||||
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
|
||||
return (0);
|
||||
|
@ -1335,28 +1335,29 @@ netvsc_recv(struct hn_rx_ring *rxr, const void *data, int dlen,
|
|||
do_csum = 0;
|
||||
|
||||
/* receive side checksum offload */
|
||||
if (info->csum_info != NULL) {
|
||||
if (info->csum_info != HN_NDIS_RXCSUM_INFO_INVALID) {
|
||||
/* IP csum offload */
|
||||
if (info->csum_info->receive.ip_csum_succeeded && do_csum) {
|
||||
if ((info->csum_info & NDIS_RXCSUM_INFO_IPCS_OK) && do_csum) {
|
||||
m_new->m_pkthdr.csum_flags |=
|
||||
(CSUM_IP_CHECKED | CSUM_IP_VALID);
|
||||
rxr->hn_csum_ip++;
|
||||
}
|
||||
|
||||
/* TCP/UDP csum offload */
|
||||
if ((info->csum_info->receive.tcp_csum_succeeded ||
|
||||
info->csum_info->receive.udp_csum_succeeded) && do_csum) {
|
||||
if ((info->csum_info & (NDIS_RXCSUM_INFO_UDPCS_OK |
|
||||
NDIS_RXCSUM_INFO_TCPCS_OK)) && do_csum) {
|
||||
m_new->m_pkthdr.csum_flags |=
|
||||
(CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
|
||||
m_new->m_pkthdr.csum_data = 0xffff;
|
||||
if (info->csum_info->receive.tcp_csum_succeeded)
|
||||
if (info->csum_info & NDIS_RXCSUM_INFO_TCPCS_OK)
|
||||
rxr->hn_csum_tcp++;
|
||||
else
|
||||
rxr->hn_csum_udp++;
|
||||
}
|
||||
|
||||
if (info->csum_info->receive.ip_csum_succeeded &&
|
||||
info->csum_info->receive.tcp_csum_succeeded)
|
||||
if ((info->csum_info &
|
||||
(NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK)) ==
|
||||
(NDIS_RXCSUM_INFO_TCPCS_OK | NDIS_RXCSUM_INFO_IPCS_OK))
|
||||
do_lro = 1;
|
||||
} else {
|
||||
const struct ether_header *eh;
|
||||
|
@ -1420,13 +1421,13 @@ netvsc_recv(struct hn_rx_ring *rxr, const void *data, int dlen,
|
|||
m_new->m_flags |= M_VLANTAG;
|
||||
}
|
||||
|
||||
if (info->hash_info != NULL && info->hash_value != NULL) {
|
||||
if (info->hash_info != HN_NDIS_HASH_INFO_INVALID) {
|
||||
rxr->hn_rss_pkts++;
|
||||
m_new->m_pkthdr.flowid = info->hash_value->hash_value;
|
||||
if ((info->hash_info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
|
||||
m_new->m_pkthdr.flowid = info->hash_value;
|
||||
hash_type = M_HASHTYPE_OPAQUE_HASH;
|
||||
if ((info->hash_info & NDIS_HASH_FUNCTION_MASK) ==
|
||||
NDIS_HASH_FUNCTION_TOEPLITZ) {
|
||||
uint32_t type =
|
||||
(info->hash_info->hash_info & NDIS_HASH_TYPE_MASK);
|
||||
uint32_t type = (info->hash_info & NDIS_HASH_TYPE_MASK);
|
||||
|
||||
switch (type) {
|
||||
case NDIS_HASH_IPV4:
|
||||
|
@ -1455,12 +1456,8 @@ netvsc_recv(struct hn_rx_ring *rxr, const void *data, int dlen,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if (info->hash_value != NULL) {
|
||||
m_new->m_pkthdr.flowid = info->hash_value->hash_value;
|
||||
} else {
|
||||
m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
|
||||
hash_type = M_HASHTYPE_OPAQUE;
|
||||
}
|
||||
m_new->m_pkthdr.flowid = rxr->hn_rx_idx;
|
||||
hash_type = M_HASHTYPE_OPAQUE;
|
||||
}
|
||||
M_HASHTYPE_SET(m_new, hash_type);
|
||||
|
||||
|
|
|
@ -157,9 +157,8 @@ hv_rf_find_recvinfo(const rndis_packet *rpkt, struct hn_recvinfo *info)
|
|||
uint32_t mask = 0, len;
|
||||
|
||||
info->vlan_info = HN_NDIS_VLAN_INFO_INVALID;
|
||||
info->csum_info = NULL;
|
||||
info->hash_info = NULL;
|
||||
info->hash_value = NULL;
|
||||
info->csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
|
||||
info->hash_info = HN_NDIS_HASH_INFO_INVALID;
|
||||
|
||||
if (rpkt->per_pkt_info_offset == 0)
|
||||
return (0);
|
||||
|
@ -192,34 +191,31 @@ hv_rf_find_recvinfo(const rndis_packet *rpkt, struct hn_recvinfo *info)
|
|||
data = pi->rm_data;
|
||||
|
||||
switch (pi->rm_type) {
|
||||
case ieee_8021q_info:
|
||||
case NDIS_PKTINFO_TYPE_VLAN:
|
||||
if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
|
||||
return (EINVAL);
|
||||
info->vlan_info = *((const uint32_t *)data);
|
||||
mask |= HV_RF_RECVINFO_VLAN;
|
||||
break;
|
||||
|
||||
case tcpip_chksum_info:
|
||||
if (__predict_false(dlen <
|
||||
sizeof(rndis_tcp_ip_csum_info)))
|
||||
case NDIS_PKTINFO_TYPE_CSUM:
|
||||
if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
|
||||
return (EINVAL);
|
||||
info->csum_info = data;
|
||||
info->csum_info = *((const uint32_t *)data);
|
||||
mask |= HV_RF_RECVINFO_CSUM;
|
||||
break;
|
||||
|
||||
case nbl_hash_value:
|
||||
if (__predict_false(dlen <
|
||||
sizeof(struct rndis_hash_value)))
|
||||
case HN_NDIS_PKTINFO_TYPE_HASHVAL:
|
||||
if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
|
||||
return (EINVAL);
|
||||
info->hash_value = data;
|
||||
info->hash_value = *((const uint32_t *)data);
|
||||
mask |= HV_RF_RECVINFO_HASHVAL;
|
||||
break;
|
||||
|
||||
case nbl_hash_info:
|
||||
if (__predict_false(dlen <
|
||||
sizeof(struct rndis_hash_info)))
|
||||
case HN_NDIS_PKTINFO_TYPE_HASHINF:
|
||||
if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
|
||||
return (EINVAL);
|
||||
info->hash_info = data;
|
||||
info->hash_info = *((const uint32_t *)data);
|
||||
mask |= HV_RF_RECVINFO_HASHINF;
|
||||
break;
|
||||
|
||||
|
@ -235,6 +231,13 @@ hv_rf_find_recvinfo(const rndis_packet *rpkt, struct hn_recvinfo *info)
|
|||
pi = (const struct rndis_pktinfo *)
|
||||
((const uint8_t *)pi + pi->rm_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Final fixup.
|
||||
* - If there is no hash value, invalidate the hash info.
|
||||
*/
|
||||
if ((mask & HV_RF_RECVINFO_HASHVAL) == 0)
|
||||
info->hash_info = HN_NDIS_HASH_INFO_INVALID;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
|
@ -208,4 +208,17 @@ struct hn_nvs_rndis_ack {
|
|||
} __packed;
|
||||
CTASSERT(sizeof(struct hn_nvs_rndis_ack) >= HN_NVS_REQSIZE_MIN);
|
||||
|
||||
/*
|
||||
* RNDIS extension
|
||||
*/
|
||||
|
||||
/* Per-packet hash info */
|
||||
#define HN_NDIS_HASH_INFO_SIZE sizeof(uint32_t)
|
||||
#define HN_NDIS_PKTINFO_TYPE_HASHINF NDIS_PKTINFO_TYPE_ORIG_NBLIST
|
||||
/* NDIS_HASH_ */
|
||||
|
||||
/* Per-packet hash value */
|
||||
#define HN_NDIS_HASH_VALUE_SIZE sizeof(uint32_t)
|
||||
#define HN_NDIS_PKTINFO_TYPE_HASHVAL NDIS_PKTINFO_TYPE_PKT_CANCELID
|
||||
|
||||
#endif /* !_IF_HNREG_H_ */
|
||||
|
|
|
@ -56,12 +56,14 @@ struct ndis_8021q_info_;
|
|||
struct rndis_tcp_ip_csum_info_;
|
||||
|
||||
#define HN_NDIS_VLAN_INFO_INVALID 0xffffffff
|
||||
#define HN_NDIS_RXCSUM_INFO_INVALID 0
|
||||
#define HN_NDIS_HASH_INFO_INVALID 0
|
||||
|
||||
struct hn_recvinfo {
|
||||
uint32_t vlan_info;
|
||||
const struct rndis_tcp_ip_csum_info_ *csum_info;
|
||||
const struct rndis_hash_info *hash_info;
|
||||
const struct rndis_hash_value *hash_value;
|
||||
uint32_t csum_info;
|
||||
uint32_t hash_info;
|
||||
uint32_t hash_value;
|
||||
};
|
||||
|
||||
#define HN_SEND_CTX_INITIALIZER(cb, cbarg) \
|
||||
|
|
|
@ -219,4 +219,16 @@ struct ndis_rssprm_toeplitz {
|
|||
#define NDIS_VLAN_INFO_CFI(inf) (((inf) & NDIS_VLAN_INFO_CFI_MASK) >> 3)
|
||||
#define NDIS_VLAN_INFO_PRI(inf) ((inf) & NDIS_VLAN_INFO_PRI_MASK)
|
||||
|
||||
/* Reception checksum */
|
||||
#define NDIS_RXCSUM_INFO_SIZE sizeof(uint32_t)
|
||||
#define NDIS_RXCSUM_INFO_TCPCS_FAILED 0x0001
|
||||
#define NDIS_RXCSUM_INFO_UDPCS_FAILED 0x0002
|
||||
#define NDIS_RXCSUM_INFO_IPCS_FAILED 0x0004
|
||||
#define NDIS_RXCSUM_INFO_TCPCS_OK 0x0008
|
||||
#define NDIS_RXCSUM_INFO_UDPCS_OK 0x0010
|
||||
#define NDIS_RXCSUM_INFO_IPCS_OK 0x0020
|
||||
#define NDIS_RXCSUM_INFO_LOOPBACK 0x0040
|
||||
#define NDIS_RXCSUM_INFO_TCPCS_INVAL 0x0080
|
||||
#define NDIS_RXCSUM_INFO_IPCS_INVAL 0x0100
|
||||
|
||||
#endif /* !_NET_NDIS_H_ */
|
||||
|
|
|
@ -69,7 +69,7 @@ vmbus_heartbeat_cb(struct vmbus_channel *chan, void *xsc)
|
|||
if (error)
|
||||
return;
|
||||
|
||||
if (dlen < sizeof(struct vmbus_icmsg_hdr)) {
|
||||
if (dlen < sizeof(*hdr)) {
|
||||
device_printf(sc->ic_dev, "invalid data len %d\n", dlen);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -22,28 +22,23 @@
|
|||
* 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$
|
||||
*/
|
||||
|
||||
/*
|
||||
* A common driver for all hyper-V util services.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/timetc.h>
|
||||
#include <sys/syscallsubr.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <dev/hyperv/include/hyperv.h>
|
||||
#include <dev/hyperv/include/vmbus.h>
|
||||
#include <dev/hyperv/utilities/hv_utilreg.h>
|
||||
#include "hv_util.h"
|
||||
#include <dev/hyperv/utilities/hv_util.h>
|
||||
#include <dev/hyperv/utilities/vmbus_icreg.h>
|
||||
|
||||
#include "vmbus_if.h"
|
||||
|
||||
static const struct vmbus_ic_desc vmbus_shutdown_descs[] = {
|
||||
|
@ -56,73 +51,78 @@ static const struct vmbus_ic_desc vmbus_shutdown_descs[] = {
|
|||
VMBUS_IC_DESC_END
|
||||
};
|
||||
|
||||
/**
|
||||
* Shutdown
|
||||
*/
|
||||
static void
|
||||
hv_shutdown_cb(struct vmbus_channel *channel, void *context)
|
||||
vmbus_shutdown_cb(struct vmbus_channel *chan, void *xsc)
|
||||
{
|
||||
uint8_t* buf;
|
||||
uint8_t execute_shutdown = 0;
|
||||
hv_vmbus_icmsg_hdr* icmsghdrp;
|
||||
uint32_t recv_len;
|
||||
uint64_t request_id;
|
||||
int ret;
|
||||
hv_vmbus_shutdown_msg_data* shutdown_msg;
|
||||
hv_util_sc *softc;
|
||||
struct hv_util_sc *sc = xsc;
|
||||
struct vmbus_icmsg_hdr *hdr;
|
||||
struct vmbus_icmsg_shutdown *msg;
|
||||
int dlen, error, do_shutdown = 0;
|
||||
uint64_t xactid;
|
||||
void *data;
|
||||
|
||||
softc = (hv_util_sc*)context;
|
||||
buf = softc->receive_buffer;
|
||||
/*
|
||||
* Receive request.
|
||||
*/
|
||||
data = sc->receive_buffer;
|
||||
dlen = sc->ic_buflen;
|
||||
error = vmbus_chan_recv(chan, data, &dlen, &xactid);
|
||||
KASSERT(error != ENOBUFS, ("icbuf is not large enough"));
|
||||
if (error)
|
||||
return;
|
||||
|
||||
recv_len = softc->ic_buflen;
|
||||
ret = vmbus_chan_recv(channel, buf, &recv_len, &request_id);
|
||||
KASSERT(ret != ENOBUFS, ("hvshutdown recvbuf is not large enough"));
|
||||
/* XXX check recv_len to make sure that it contains enough data */
|
||||
if (dlen < sizeof(*hdr)) {
|
||||
device_printf(sc->ic_dev, "invalid data len %d\n", dlen);
|
||||
return;
|
||||
}
|
||||
hdr = data;
|
||||
|
||||
if ((ret == 0) && recv_len > 0) {
|
||||
|
||||
icmsghdrp = (struct hv_vmbus_icmsg_hdr *)
|
||||
&buf[sizeof(struct hv_vmbus_pipe_hdr)];
|
||||
|
||||
if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
|
||||
int error;
|
||||
|
||||
error = vmbus_ic_negomsg(softc, buf, &recv_len);
|
||||
/*
|
||||
* Update request, which will be echoed back as response.
|
||||
*/
|
||||
switch (hdr->ic_type) {
|
||||
case VMBUS_ICMSG_TYPE_NEGOTIATE:
|
||||
error = vmbus_ic_negomsg(sc, data, &dlen);
|
||||
if (error)
|
||||
return;
|
||||
} else {
|
||||
shutdown_msg =
|
||||
(struct hv_vmbus_shutdown_msg_data *)
|
||||
&buf[sizeof(struct hv_vmbus_pipe_hdr) +
|
||||
sizeof(struct hv_vmbus_icmsg_hdr)];
|
||||
break;
|
||||
|
||||
switch (shutdown_msg->flags) {
|
||||
case 0:
|
||||
case 1:
|
||||
icmsghdrp->status = HV_S_OK;
|
||||
execute_shutdown = 1;
|
||||
if(bootverbose)
|
||||
printf("Shutdown request received -"
|
||||
" graceful shutdown initiated\n");
|
||||
break;
|
||||
default:
|
||||
icmsghdrp->status = HV_E_FAIL;
|
||||
execute_shutdown = 0;
|
||||
printf("Shutdown request received -"
|
||||
" Invalid request\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
case VMBUS_ICMSG_TYPE_SHUTDOWN:
|
||||
if (dlen < VMBUS_ICMSG_SHUTDOWN_SIZE_MIN) {
|
||||
device_printf(sc->ic_dev, "invalid shutdown len %d\n",
|
||||
dlen);
|
||||
return;
|
||||
}
|
||||
msg = data;
|
||||
|
||||
icmsghdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION |
|
||||
HV_ICMSGHDRFLAG_RESPONSE;
|
||||
/* XXX ic_flags definition? */
|
||||
if (msg->ic_haltflags == 0 || msg->ic_haltflags == 1) {
|
||||
device_printf(sc->ic_dev, "shutdown requested\n");
|
||||
hdr->ic_status = VMBUS_ICMSG_STATUS_OK;
|
||||
do_shutdown = 1;
|
||||
} else {
|
||||
device_printf(sc->ic_dev, "unknown shutdown flags "
|
||||
"0x%08x\n", msg->ic_haltflags);
|
||||
hdr->ic_status = VMBUS_ICMSG_STATUS_FAIL;
|
||||
}
|
||||
break;
|
||||
|
||||
vmbus_chan_send(channel, VMBUS_CHANPKT_TYPE_INBAND, 0,
|
||||
buf, recv_len, request_id);
|
||||
default:
|
||||
device_printf(sc->ic_dev, "got 0x%08x icmsg\n", hdr->ic_type);
|
||||
break;
|
||||
}
|
||||
|
||||
if (execute_shutdown)
|
||||
shutdown_nice(RB_POWEROFF);
|
||||
/*
|
||||
* Send response by echoing the updated request back.
|
||||
*/
|
||||
hdr->ic_flags = VMBUS_ICMSG_FLAG_XACT | VMBUS_ICMSG_FLAG_RESP;
|
||||
error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_INBAND, 0,
|
||||
data, dlen, xactid);
|
||||
if (error)
|
||||
device_printf(sc->ic_dev, "resp send failed: %d\n", error);
|
||||
|
||||
if (do_shutdown)
|
||||
shutdown_nice(RB_POWEROFF);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -135,7 +135,8 @@ hv_shutdown_probe(device_t dev)
|
|||
static int
|
||||
hv_shutdown_attach(device_t dev)
|
||||
{
|
||||
return hv_util_attach(dev, hv_shutdown_cb);
|
||||
|
||||
return (hv_util_attach(dev, vmbus_shutdown_cb));
|
||||
}
|
||||
|
||||
static device_method_t shutdown_methods[] = {
|
||||
|
|
|
@ -22,37 +22,25 @@
|
|||
* 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$
|
||||
*/
|
||||
|
||||
/*
|
||||
* A common driver for all hyper-V util services.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/timetc.h>
|
||||
#include <sys/syscallsubr.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <dev/hyperv/include/hyperv.h>
|
||||
#include <dev/hyperv/include/vmbus.h>
|
||||
#include <dev/hyperv/utilities/hv_utilreg.h>
|
||||
#include "hv_util.h"
|
||||
#include "vmbus_if.h"
|
||||
#include <dev/hyperv/utilities/hv_util.h>
|
||||
#include <dev/hyperv/utilities/vmbus_icreg.h>
|
||||
|
||||
#define HV_WLTIMEDELTA 116444736000000000L /* in 100ns unit */
|
||||
#define HV_ICTIMESYNCFLAG_PROBE 0
|
||||
#define HV_ICTIMESYNCFLAG_SYNC 1
|
||||
#define HV_ICTIMESYNCFLAG_SAMPLE 2
|
||||
#define HV_NANO_SEC_PER_SEC 1000000000
|
||||
#define HV_NANO_SEC_PER_MILLI_SEC 1000000
|
||||
#include "vmbus_if.h"
|
||||
|
||||
static const struct vmbus_ic_desc vmbus_timesync_descs[] = {
|
||||
{
|
||||
|
@ -64,135 +52,144 @@ static const struct vmbus_ic_desc vmbus_timesync_descs[] = {
|
|||
VMBUS_IC_DESC_END
|
||||
};
|
||||
|
||||
struct hv_ictimesync_data {
|
||||
uint64_t parenttime;
|
||||
uint64_t childtime;
|
||||
uint64_t roundtriptime;
|
||||
uint8_t flags;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Globals
|
||||
*/
|
||||
SYSCTL_NODE(_hw, OID_AUTO, hvtimesync, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL,
|
||||
"Hyper-V timesync interface");
|
||||
|
||||
/* Ignore the sync request when set to 1. */
|
||||
static int ignore_sync_req = 0;
|
||||
SYSCTL_INT(_hw_hvtimesync, OID_AUTO, ignore_sync_req, CTLFLAG_RWTUN,
|
||||
&ignore_sync_req, 0,
|
||||
"Ignore the sync request when set to 1.");
|
||||
static int vmbus_ts_ignore_sync = 0;
|
||||
SYSCTL_INT(_hw_hvtimesync, OID_AUTO, ignore_sync, CTLFLAG_RWTUN,
|
||||
&vmbus_ts_ignore_sync, 0, "Ignore the sync request.");
|
||||
|
||||
/*
|
||||
* Trigger sample sync when drift exceeds threshold (ms).
|
||||
* Ignore the sample request when set to 0.
|
||||
*/
|
||||
static int sample_drift = 100;
|
||||
SYSCTL_INT(_hw_hvtimesync, OID_AUTO, sample_drift, CTLFLAG_RWTUN,
|
||||
&sample_drift, 0,
|
||||
"Threshold that makes sample request trigger the sync.");
|
||||
static int vmbus_ts_sample_thresh = 100;
|
||||
SYSCTL_INT(_hw_hvtimesync, OID_AUTO, sample_thresh, CTLFLAG_RWTUN,
|
||||
&vmbus_ts_sample_thresh, 0,
|
||||
"Threshold that makes sample request trigger the sync (unit: ms).");
|
||||
|
||||
/**
|
||||
* @brief Synchronize time with host after reboot, restore, etc.
|
||||
*
|
||||
* ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM.
|
||||
* After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time
|
||||
* message after the timesync channel is opened. Since the hv_utils module is
|
||||
* loaded after hv_vmbus, the first message is usually missed. The other
|
||||
* thing is, systime is automatically set to emulated hardware clock which may
|
||||
* not be UTC time or in the same time zone. So, to override these effects, we
|
||||
* use the first 50 time samples for initial system time setting.
|
||||
*/
|
||||
static inline
|
||||
void hv_adj_guesttime(hv_util_sc *sc, uint64_t hosttime, uint8_t flags)
|
||||
static int vmbus_ts_sample_verbose = 0;
|
||||
SYSCTL_INT(_hw_hvtimesync, OID_AUTO, sample_verbose, CTLFLAG_RWTUN,
|
||||
&vmbus_ts_sample_verbose, 0, "Increase sample request verbosity.");
|
||||
|
||||
static void
|
||||
vmbus_timesync(struct hv_util_sc *sc, uint64_t hvtime, uint8_t tsflags)
|
||||
{
|
||||
struct timespec guest_ts, host_ts;
|
||||
uint64_t host_tns, guest_tns;
|
||||
int64_t diff;
|
||||
int error;
|
||||
struct timespec vm_ts;
|
||||
uint64_t hv_ns, vm_ns;
|
||||
|
||||
host_tns = (hosttime - HV_WLTIMEDELTA) * 100;
|
||||
host_ts.tv_sec = (time_t)(host_tns/HV_NANO_SEC_PER_SEC);
|
||||
host_ts.tv_nsec = (long)(host_tns%HV_NANO_SEC_PER_SEC);
|
||||
hv_ns = (hvtime - VMBUS_ICMSG_TS_BASE) * VMBUS_ICMSG_TS_FACTOR;
|
||||
nanotime(&vm_ts);
|
||||
vm_ns = (vm_ts.tv_sec * NANOSEC) + vm_ts.tv_nsec;
|
||||
|
||||
nanotime(&guest_ts);
|
||||
guest_tns = guest_ts.tv_sec * HV_NANO_SEC_PER_SEC + guest_ts.tv_nsec;
|
||||
if ((tsflags & VMBUS_ICMSG_TS_FLAG_SYNC) && !vmbus_ts_ignore_sync) {
|
||||
struct timespec hv_ts;
|
||||
|
||||
if ((flags & HV_ICTIMESYNCFLAG_SYNC) != 0 && ignore_sync_req == 0) {
|
||||
if (bootverbose) {
|
||||
device_printf(sc->ic_dev, "handle sync request "
|
||||
"{host: %ju, guest: %ju}\n",
|
||||
(uintmax_t)host_tns, (uintmax_t)guest_tns);
|
||||
device_printf(sc->ic_dev, "apply sync request, "
|
||||
"hv: %ju, vm: %ju\n",
|
||||
(uintmax_t)hv_ns, (uintmax_t)vm_ns);
|
||||
}
|
||||
|
||||
error = kern_clock_settime(curthread, CLOCK_REALTIME,
|
||||
&host_ts);
|
||||
hv_ts.tv_sec = hv_ns / NANOSEC;
|
||||
hv_ts.tv_nsec = hv_ns % NANOSEC;
|
||||
kern_clock_settime(curthread, CLOCK_REALTIME, &hv_ts);
|
||||
/* Done! */
|
||||
return;
|
||||
}
|
||||
|
||||
if ((flags & HV_ICTIMESYNCFLAG_SAMPLE) != 0 && sample_drift != 0) {
|
||||
if (bootverbose) {
|
||||
device_printf(sc->ic_dev, "handle sample request "
|
||||
"{host: %ju, guest: %ju}\n",
|
||||
(uintmax_t)host_tns, (uintmax_t)guest_tns);
|
||||
if ((tsflags & VMBUS_ICMSG_TS_FLAG_SAMPLE) &&
|
||||
vmbus_ts_sample_thresh > 0) {
|
||||
int64_t diff;
|
||||
|
||||
if (vmbus_ts_sample_verbose) {
|
||||
device_printf(sc->ic_dev, "sample request, "
|
||||
"hv: %ju, vm: %ju\n",
|
||||
(uintmax_t)hv_ns, (uintmax_t)vm_ns);
|
||||
}
|
||||
|
||||
diff = (int64_t)(host_tns - guest_tns) / HV_NANO_SEC_PER_MILLI_SEC;
|
||||
if (diff > sample_drift || diff < -sample_drift) {
|
||||
error = kern_clock_settime(curthread, CLOCK_REALTIME,
|
||||
&host_ts);
|
||||
if (bootverbose)
|
||||
device_printf(sc->ic_dev, "trigger sample sync");
|
||||
if (hv_ns > vm_ns)
|
||||
diff = hv_ns - vm_ns;
|
||||
else
|
||||
diff = vm_ns - hv_ns;
|
||||
/* nanosec -> millisec */
|
||||
diff /= 1000000;
|
||||
|
||||
if (diff > vmbus_ts_sample_thresh) {
|
||||
struct timespec hv_ts;
|
||||
|
||||
if (bootverbose) {
|
||||
device_printf(sc->ic_dev,
|
||||
"apply sample request, hv: %ju, vm: %ju\n",
|
||||
(uintmax_t)hv_ns, (uintmax_t)vm_ns);
|
||||
}
|
||||
hv_ts.tv_sec = hv_ns / NANOSEC;
|
||||
hv_ts.tv_nsec = hv_ns % NANOSEC;
|
||||
kern_clock_settime(curthread, CLOCK_REALTIME, &hv_ts);
|
||||
}
|
||||
/* Done */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Time Sync Channel message handler
|
||||
*/
|
||||
static void
|
||||
hv_timesync_cb(struct vmbus_channel *channel, void *context)
|
||||
vmbus_timesync_cb(struct vmbus_channel *chan, void *xsc)
|
||||
{
|
||||
hv_vmbus_icmsg_hdr* icmsghdrp;
|
||||
uint32_t recvlen;
|
||||
uint64_t requestId;
|
||||
int ret;
|
||||
uint8_t* time_buf;
|
||||
struct hv_ictimesync_data* timedatap;
|
||||
hv_util_sc *softc;
|
||||
struct hv_util_sc *sc = xsc;
|
||||
struct vmbus_icmsg_hdr *hdr;
|
||||
const struct vmbus_icmsg_timesync *msg;
|
||||
int dlen, error;
|
||||
uint64_t xactid;
|
||||
void *data;
|
||||
|
||||
softc = (hv_util_sc*)context;
|
||||
time_buf = softc->receive_buffer;
|
||||
/*
|
||||
* Receive request.
|
||||
*/
|
||||
data = sc->receive_buffer;
|
||||
dlen = sc->ic_buflen;
|
||||
error = vmbus_chan_recv(chan, data, &dlen, &xactid);
|
||||
KASSERT(error != ENOBUFS, ("icbuf is not large enough"));
|
||||
if (error)
|
||||
return;
|
||||
|
||||
recvlen = softc->ic_buflen;
|
||||
ret = vmbus_chan_recv(channel, time_buf, &recvlen, &requestId);
|
||||
KASSERT(ret != ENOBUFS, ("hvtimesync recvbuf is not large enough"));
|
||||
/* XXX check recvlen to make sure that it contains enough data */
|
||||
if (dlen < sizeof(*hdr)) {
|
||||
device_printf(sc->ic_dev, "invalid data len %d\n", dlen);
|
||||
return;
|
||||
}
|
||||
hdr = data;
|
||||
|
||||
if ((ret == 0) && recvlen > 0) {
|
||||
icmsghdrp = (struct hv_vmbus_icmsg_hdr *) &time_buf[
|
||||
sizeof(struct hv_vmbus_pipe_hdr)];
|
||||
|
||||
if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
|
||||
int error;
|
||||
|
||||
error = vmbus_ic_negomsg(softc, time_buf, &recvlen);
|
||||
/*
|
||||
* Update request, which will be echoed back as response.
|
||||
*/
|
||||
switch (hdr->ic_type) {
|
||||
case VMBUS_ICMSG_TYPE_NEGOTIATE:
|
||||
error = vmbus_ic_negomsg(sc, data, &dlen);
|
||||
if (error)
|
||||
return;
|
||||
} else {
|
||||
timedatap = (struct hv_ictimesync_data *) &time_buf[
|
||||
sizeof(struct hv_vmbus_pipe_hdr) +
|
||||
sizeof(struct hv_vmbus_icmsg_hdr)];
|
||||
hv_adj_guesttime(softc, timedatap->parenttime, timedatap->flags);
|
||||
}
|
||||
break;
|
||||
|
||||
icmsghdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION
|
||||
| HV_ICMSGHDRFLAG_RESPONSE;
|
||||
case VMBUS_ICMSG_TYPE_TIMESYNC:
|
||||
if (dlen < sizeof(*msg)) {
|
||||
device_printf(sc->ic_dev, "invalid timesync len %d\n",
|
||||
dlen);
|
||||
return;
|
||||
}
|
||||
msg = data;
|
||||
vmbus_timesync(sc, msg->ic_hvtime, msg->ic_tsflags);
|
||||
break;
|
||||
|
||||
vmbus_chan_send(channel, VMBUS_CHANPKT_TYPE_INBAND, 0,
|
||||
time_buf, recvlen, requestId);
|
||||
default:
|
||||
device_printf(sc->ic_dev, "got 0x%08x icmsg\n", hdr->ic_type);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send response by echoing the updated request back.
|
||||
*/
|
||||
hdr->ic_flags = VMBUS_ICMSG_FLAG_XACT | VMBUS_ICMSG_FLAG_RESP;
|
||||
error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_INBAND, 0,
|
||||
data, dlen, xactid);
|
||||
if (error)
|
||||
device_printf(sc->ic_dev, "resp send failed: %d\n", error);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -205,20 +202,15 @@ hv_timesync_probe(device_t dev)
|
|||
static int
|
||||
hv_timesync_attach(device_t dev)
|
||||
{
|
||||
return hv_util_attach(dev, hv_timesync_cb);
|
||||
}
|
||||
|
||||
static int
|
||||
hv_timesync_detach(device_t dev)
|
||||
{
|
||||
return hv_util_detach(dev);
|
||||
return (hv_util_attach(dev, vmbus_timesync_cb));
|
||||
}
|
||||
|
||||
static device_method_t timesync_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, hv_timesync_probe),
|
||||
DEVMETHOD(device_attach, hv_timesync_attach),
|
||||
DEVMETHOD(device_detach, hv_timesync_detach),
|
||||
DEVMETHOD(device_detach, hv_util_detach),
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
|
|
@ -91,4 +91,35 @@ struct vmbus_icmsg_heartbeat {
|
|||
#define VMBUS_ICMSG_HEARTBEAT_SIZE_MIN \
|
||||
__offsetof(struct vmbus_icmsg_heartbeat, ic_rsvd[0])
|
||||
|
||||
/* VMBUS_ICMSG_TYPE_SHUTDOWN */
|
||||
struct vmbus_icmsg_shutdown {
|
||||
struct vmbus_icmsg_hdr ic_hdr;
|
||||
uint32_t ic_code;
|
||||
uint32_t ic_timeo;
|
||||
uint32_t ic_haltflags;
|
||||
uint8_t ic_msg[2048];
|
||||
} __packed;
|
||||
|
||||
#define VMBUS_ICMSG_SHUTDOWN_SIZE_MIN \
|
||||
__offsetof(struct vmbus_icmsg_shutdown, ic_msg[0])
|
||||
|
||||
/* VMBUS_ICMSG_TYPE_TIMESYNC */
|
||||
struct vmbus_icmsg_timesync {
|
||||
struct vmbus_icmsg_hdr ic_hdr;
|
||||
uint64_t ic_hvtime;
|
||||
uint64_t ic_vmtime;
|
||||
uint64_t ic_rtt;
|
||||
uint8_t ic_tsflags; /* VMBUS_ICMSG_TS_FLAG_ */
|
||||
} __packed;
|
||||
|
||||
#define VMBUS_ICMSG_TS_FLAG_SYNC 0x01
|
||||
#define VMBUS_ICMSG_TS_FLAG_SAMPLE 0x02
|
||||
|
||||
/* XXX consolidate w/ hyperv */
|
||||
#define VMBUS_ICMSG_TS_BASE 116444736000000000ULL
|
||||
#define VMBUS_ICMSG_TS_FACTOR 100ULL
|
||||
#ifndef NANOSEC
|
||||
#define NANOSEC 1000000000ULL
|
||||
#endif
|
||||
|
||||
#endif /* !_VMBUS_ICREG_H_ */
|
||||
|
|
|
@ -750,13 +750,13 @@ ioat_process_events(struct ioat_softc *ioat)
|
|||
* Fatal programming error on this DMA channel. Flush any outstanding
|
||||
* work with error status and restart the engine.
|
||||
*/
|
||||
ioat_log_message(0, "Channel halted due to fatal programming error\n");
|
||||
mtx_lock(&ioat->submit_lock);
|
||||
mtx_lock(&ioat->cleanup_lock);
|
||||
ioat->quiescing = TRUE;
|
||||
|
||||
chanerr = ioat_read_4(ioat, IOAT_CHANERR_OFFSET);
|
||||
ioat_halted_debug(ioat, chanerr);
|
||||
if (1 <= g_ioat_debug_level)
|
||||
ioat_halted_debug(ioat, chanerr);
|
||||
ioat->stats.last_halt_chanerr = chanerr;
|
||||
|
||||
while (ioat_get_active(ioat) > 0) {
|
||||
|
|
|
@ -1678,13 +1678,39 @@ sccnkbdunlock(sc_softc_t *sc, struct sc_cnstate *sp)
|
|||
static void
|
||||
sccnscrlock(sc_softc_t *sc, struct sc_cnstate *sp)
|
||||
{
|
||||
SC_VIDEO_LOCK(sc);
|
||||
int retries;
|
||||
|
||||
/**
|
||||
* Locking method:
|
||||
* - if kdb_active and video_mtx is not owned by anyone, then lock
|
||||
* by kdb remaining active
|
||||
* - if !kdb_active, try to acquire video_mtx without blocking or
|
||||
* recursing; if we get it then it works normally.
|
||||
* Note that video_mtx is especially unusable if we already own it,
|
||||
* since then it is protecting something and syscons is not reentrant
|
||||
* enough to ignore the protection even in the kdb_active case.
|
||||
*/
|
||||
if (kdb_active) {
|
||||
sp->kdb_locked = sc->video_mtx.mtx_lock == MTX_UNOWNED || panicstr;
|
||||
sp->mtx_locked = FALSE;
|
||||
} else {
|
||||
sp->kdb_locked = FALSE;
|
||||
for (retries = 0; retries < 1000; retries++) {
|
||||
sp->mtx_locked = mtx_trylock_spin_flags(&sc->video_mtx,
|
||||
MTX_QUIET) != 0 || panicstr;
|
||||
if (sp->mtx_locked)
|
||||
break;
|
||||
DELAY(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sccnscrunlock(sc_softc_t *sc, struct sc_cnstate *sp)
|
||||
{
|
||||
SC_VIDEO_UNLOCK(sc);
|
||||
if (sp->mtx_locked)
|
||||
mtx_unlock_spin(&sc->video_mtx);
|
||||
sp->mtx_locked = sp->kdb_locked = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1721,6 +1747,8 @@ over_keyboard: ;
|
|||
|
||||
/* The screen is opened iff locking it succeeds. */
|
||||
sccnscrlock(sc, sp);
|
||||
if (!sp->kdb_locked && !sp->mtx_locked)
|
||||
return;
|
||||
sp->scr_opened = TRUE;
|
||||
|
||||
/* The screen switch is optional. */
|
||||
|
@ -1797,6 +1825,10 @@ sc_cnungrab(struct consdev *cp)
|
|||
atomic_add_int(&sc->grab_level, -1);
|
||||
}
|
||||
|
||||
static char sc_cnputc_log[0x1000];
|
||||
static u_int sc_cnputc_loghead;
|
||||
static u_int sc_cnputc_logtail;
|
||||
|
||||
static void
|
||||
sc_cnputc(struct consdev *cd, int c)
|
||||
{
|
||||
|
@ -1808,12 +1840,28 @@ sc_cnputc(struct consdev *cd, int c)
|
|||
struct tty *tp;
|
||||
#endif
|
||||
#endif /* !SC_NO_HISTORY */
|
||||
u_int head;
|
||||
int s;
|
||||
|
||||
/* assert(sc_console != NULL) */
|
||||
|
||||
sccnopen(scp->sc, &st, 0);
|
||||
|
||||
/*
|
||||
* Log the output.
|
||||
*
|
||||
* In the unlocked case, the logging is intentionally only
|
||||
* perfectly atomic for the indexes.
|
||||
*/
|
||||
head = atomic_fetchadd_int(&sc_cnputc_loghead, 1);
|
||||
sc_cnputc_log[head % sizeof(sc_cnputc_log)] = c;
|
||||
|
||||
/*
|
||||
* If we couldn't open, return to defer output.
|
||||
*/
|
||||
if (!st.scr_opened)
|
||||
return;
|
||||
|
||||
#ifndef SC_NO_HISTORY
|
||||
if (scp == scp->sc->cur_scp && scp->status & SLKED) {
|
||||
scp->status &= ~SLKED;
|
||||
|
@ -1841,8 +1889,14 @@ sc_cnputc(struct consdev *cd, int c)
|
|||
}
|
||||
#endif /* !SC_NO_HISTORY */
|
||||
|
||||
buf[0] = c;
|
||||
sc_puts(scp, buf, 1, 1);
|
||||
/* Play any output still in the log (our char may already be done). */
|
||||
while (sc_cnputc_logtail != atomic_load_acq_int(&sc_cnputc_loghead)) {
|
||||
buf[0] = sc_cnputc_log[sc_cnputc_logtail++ % sizeof(sc_cnputc_log)];
|
||||
if (atomic_load_acq_int(&sc_cnputc_loghead) - sc_cnputc_logtail >=
|
||||
sizeof(sc_cnputc_log))
|
||||
continue;
|
||||
sc_puts(scp, buf, 1, 1);
|
||||
}
|
||||
|
||||
s = spltty(); /* block sckbdevent and scrn_timer */
|
||||
sccnupdate(scp);
|
||||
|
@ -1883,9 +1937,11 @@ sc_cngetc_locked(struct sc_cnstate *sp)
|
|||
* Stop the screen saver and update the screen if necessary.
|
||||
* What if we have been running in the screen saver code... XXX
|
||||
*/
|
||||
sc_touch_scrn_saver();
|
||||
if (sp->scr_opened)
|
||||
sc_touch_scrn_saver();
|
||||
scp = sc_console->sc->cur_scp; /* XXX */
|
||||
sccnupdate(scp);
|
||||
if (sp->scr_opened)
|
||||
sccnupdate(scp);
|
||||
|
||||
if (fkeycp < fkey.len)
|
||||
return fkey.str[fkeycp++];
|
||||
|
|
|
@ -191,6 +191,8 @@ struct tty;
|
|||
|
||||
struct sc_cnstate {
|
||||
u_char kbd_locked;
|
||||
u_char kdb_locked;
|
||||
u_char mtx_locked;
|
||||
u_char kbd_opened;
|
||||
u_char scr_opened;
|
||||
};
|
||||
|
|
|
@ -189,46 +189,46 @@ SYSCTL_INT(_kern, OID_AUTO, coredump_devctl, CTLFLAG_RW, &coredump_devctl,
|
|||
* The array below categorizes the signals and their default actions
|
||||
* according to the following properties:
|
||||
*/
|
||||
#define SA_KILL 0x01 /* terminates process by default */
|
||||
#define SA_CORE 0x02 /* ditto and coredumps */
|
||||
#define SA_STOP 0x04 /* suspend process */
|
||||
#define SA_TTYSTOP 0x08 /* ditto, from tty */
|
||||
#define SA_IGNORE 0x10 /* ignore by default */
|
||||
#define SA_CONT 0x20 /* continue if suspended */
|
||||
#define SA_CANTMASK 0x40 /* non-maskable, catchable */
|
||||
#define SIGPROP_KILL 0x01 /* terminates process by default */
|
||||
#define SIGPROP_CORE 0x02 /* ditto and coredumps */
|
||||
#define SIGPROP_STOP 0x04 /* suspend process */
|
||||
#define SIGPROP_TTYSTOP 0x08 /* ditto, from tty */
|
||||
#define SIGPROP_IGNORE 0x10 /* ignore by default */
|
||||
#define SIGPROP_CONT 0x20 /* continue if suspended */
|
||||
#define SIGPROP_CANTMASK 0x40 /* non-maskable, catchable */
|
||||
|
||||
static int sigproptbl[NSIG] = {
|
||||
SA_KILL, /* SIGHUP */
|
||||
SA_KILL, /* SIGINT */
|
||||
SA_KILL|SA_CORE, /* SIGQUIT */
|
||||
SA_KILL|SA_CORE, /* SIGILL */
|
||||
SA_KILL|SA_CORE, /* SIGTRAP */
|
||||
SA_KILL|SA_CORE, /* SIGABRT */
|
||||
SA_KILL|SA_CORE, /* SIGEMT */
|
||||
SA_KILL|SA_CORE, /* SIGFPE */
|
||||
SA_KILL, /* SIGKILL */
|
||||
SA_KILL|SA_CORE, /* SIGBUS */
|
||||
SA_KILL|SA_CORE, /* SIGSEGV */
|
||||
SA_KILL|SA_CORE, /* SIGSYS */
|
||||
SA_KILL, /* SIGPIPE */
|
||||
SA_KILL, /* SIGALRM */
|
||||
SA_KILL, /* SIGTERM */
|
||||
SA_IGNORE, /* SIGURG */
|
||||
SA_STOP, /* SIGSTOP */
|
||||
SA_STOP|SA_TTYSTOP, /* SIGTSTP */
|
||||
SA_IGNORE|SA_CONT, /* SIGCONT */
|
||||
SA_IGNORE, /* SIGCHLD */
|
||||
SA_STOP|SA_TTYSTOP, /* SIGTTIN */
|
||||
SA_STOP|SA_TTYSTOP, /* SIGTTOU */
|
||||
SA_IGNORE, /* SIGIO */
|
||||
SA_KILL, /* SIGXCPU */
|
||||
SA_KILL, /* SIGXFSZ */
|
||||
SA_KILL, /* SIGVTALRM */
|
||||
SA_KILL, /* SIGPROF */
|
||||
SA_IGNORE, /* SIGWINCH */
|
||||
SA_IGNORE, /* SIGINFO */
|
||||
SA_KILL, /* SIGUSR1 */
|
||||
SA_KILL, /* SIGUSR2 */
|
||||
SIGPROP_KILL, /* SIGHUP */
|
||||
SIGPROP_KILL, /* SIGINT */
|
||||
SIGPROP_KILL | SIGPROP_CORE, /* SIGQUIT */
|
||||
SIGPROP_KILL | SIGPROP_CORE, /* SIGILL */
|
||||
SIGPROP_KILL | SIGPROP_CORE, /* SIGTRAP */
|
||||
SIGPROP_KILL | SIGPROP_CORE, /* SIGABRT */
|
||||
SIGPROP_KILL | SIGPROP_CORE, /* SIGEMT */
|
||||
SIGPROP_KILL | SIGPROP_CORE, /* SIGFPE */
|
||||
SIGPROP_KILL, /* SIGKILL */
|
||||
SIGPROP_KILL | SIGPROP_CORE, /* SIGBUS */
|
||||
SIGPROP_KILL | SIGPROP_CORE, /* SIGSEGV */
|
||||
SIGPROP_KILL | SIGPROP_CORE, /* SIGSYS */
|
||||
SIGPROP_KILL, /* SIGPIPE */
|
||||
SIGPROP_KILL, /* SIGALRM */
|
||||
SIGPROP_KILL, /* SIGTERM */
|
||||
SIGPROP_IGNORE, /* SIGURG */
|
||||
SIGPROP_STOP, /* SIGSTOP */
|
||||
SIGPROP_STOP | SIGPROP_TTYSTOP, /* SIGTSTP */
|
||||
SIGPROP_IGNORE | SIGPROP_CONT, /* SIGCONT */
|
||||
SIGPROP_IGNORE, /* SIGCHLD */
|
||||
SIGPROP_STOP | SIGPROP_TTYSTOP, /* SIGTTIN */
|
||||
SIGPROP_STOP | SIGPROP_TTYSTOP, /* SIGTTOU */
|
||||
SIGPROP_IGNORE, /* SIGIO */
|
||||
SIGPROP_KILL, /* SIGXCPU */
|
||||
SIGPROP_KILL, /* SIGXFSZ */
|
||||
SIGPROP_KILL, /* SIGVTALRM */
|
||||
SIGPROP_KILL, /* SIGPROF */
|
||||
SIGPROP_IGNORE, /* SIGWINCH */
|
||||
SIGPROP_IGNORE, /* SIGINFO */
|
||||
SIGPROP_KILL, /* SIGUSR1 */
|
||||
SIGPROP_KILL, /* SIGUSR2 */
|
||||
};
|
||||
|
||||
static void reschedule_signals(struct proc *p, sigset_t block, int flags);
|
||||
|
@ -755,7 +755,7 @@ kern_sigaction(struct thread *td, int sig, const struct sigaction *act,
|
|||
* have to restart the process.
|
||||
*/
|
||||
if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN ||
|
||||
(sigprop(sig) & SA_IGNORE &&
|
||||
(sigprop(sig) & SIGPROP_IGNORE &&
|
||||
ps->ps_sigact[_SIG_IDX(sig)] == SIG_DFL)) {
|
||||
/* never to be seen again */
|
||||
sigqueue_delete_proc(p, sig);
|
||||
|
@ -923,7 +923,7 @@ siginit(p)
|
|||
ps = p->p_sigacts;
|
||||
mtx_lock(&ps->ps_mtx);
|
||||
for (i = 1; i <= NSIG; i++) {
|
||||
if (sigprop(i) & SA_IGNORE && i != SIGCONT) {
|
||||
if (sigprop(i) & SIGPROP_IGNORE && i != SIGCONT) {
|
||||
SIGADDSET(ps->ps_sigignore, i);
|
||||
}
|
||||
}
|
||||
|
@ -940,7 +940,7 @@ sigdflt(struct sigacts *ps, int sig)
|
|||
|
||||
mtx_assert(&ps->ps_mtx, MA_OWNED);
|
||||
SIGDELSET(ps->ps_sigcatch, sig);
|
||||
if ((sigprop(sig) & SA_IGNORE) != 0 && sig != SIGCONT)
|
||||
if ((sigprop(sig) & SIGPROP_IGNORE) != 0 && sig != SIGCONT)
|
||||
SIGADDSET(ps->ps_sigignore, sig);
|
||||
ps->ps_sigact[_SIG_IDX(sig)] = SIG_DFL;
|
||||
SIGDELSET(ps->ps_siginfo, sig);
|
||||
|
@ -969,7 +969,7 @@ execsigs(struct proc *p)
|
|||
while (SIGNOTEMPTY(ps->ps_sigcatch)) {
|
||||
sig = sig_ffs(&ps->ps_sigcatch);
|
||||
sigdflt(ps, sig);
|
||||
if ((sigprop(sig) & SA_IGNORE) != 0)
|
||||
if ((sigprop(sig) & SIGPROP_IGNORE) != 0)
|
||||
sigqueue_delete_proc(p, sig);
|
||||
}
|
||||
|
||||
|
@ -2154,16 +2154,16 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi)
|
|||
intrval = ERESTART;
|
||||
mtx_unlock(&ps->ps_mtx);
|
||||
|
||||
if (prop & SA_CONT)
|
||||
if (prop & SIGPROP_CONT)
|
||||
sigqueue_delete_stopmask_proc(p);
|
||||
else if (prop & SA_STOP) {
|
||||
else if (prop & SIGPROP_STOP) {
|
||||
/*
|
||||
* If sending a tty stop signal to a member of an orphaned
|
||||
* process group, discard the signal here if the action
|
||||
* is default; don't stop the process below if sleeping,
|
||||
* and don't clear any pending SIGCONT.
|
||||
*/
|
||||
if ((prop & SA_TTYSTOP) &&
|
||||
if ((prop & SIGPROP_TTYSTOP) &&
|
||||
(p->p_pgrp->pg_jobc == 0) &&
|
||||
(action == SIG_DFL)) {
|
||||
if (ksi && (ksi->ksi_flags & KSI_INS))
|
||||
|
@ -2188,7 +2188,7 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi)
|
|||
* except that stopped processes must be continued by SIGCONT.
|
||||
*/
|
||||
if (action == SIG_HOLD &&
|
||||
!((prop & SA_CONT) && (p->p_flag & P_STOPPED_SIG)))
|
||||
!((prop & SIGPROP_CONT) && (p->p_flag & P_STOPPED_SIG)))
|
||||
return (ret);
|
||||
/*
|
||||
* SIGKILL: Remove procfs STOPEVENTs and ptrace events.
|
||||
|
@ -2228,7 +2228,7 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi)
|
|||
goto runfast;
|
||||
}
|
||||
|
||||
if (prop & SA_CONT) {
|
||||
if (prop & SIGPROP_CONT) {
|
||||
/*
|
||||
* If traced process is already stopped,
|
||||
* then no further action is necessary.
|
||||
|
@ -2278,7 +2278,7 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (prop & SA_STOP) {
|
||||
if (prop & SIGPROP_STOP) {
|
||||
/*
|
||||
* If traced process is already stopped,
|
||||
* then no further action is necessary.
|
||||
|
@ -2325,7 +2325,7 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi)
|
|||
|
||||
MPASS(action == SIG_DFL);
|
||||
|
||||
if (prop & SA_STOP) {
|
||||
if (prop & SIGPROP_STOP) {
|
||||
if (p->p_flag & (P_PPWAIT|P_WEXIT))
|
||||
goto out;
|
||||
p->p_flag |= P_STOPPED_SIG;
|
||||
|
@ -2394,7 +2394,7 @@ tdsigwakeup(struct thread *td, int sig, sig_t action, int intrval)
|
|||
* priority of the idle thread, since we still allow to signal
|
||||
* kernel processes.
|
||||
*/
|
||||
if (action == SIG_DFL && (prop & SA_KILL) != 0 &&
|
||||
if (action == SIG_DFL && (prop & SIGPROP_KILL) != 0 &&
|
||||
td->td_priority > PUSER && !TD_IS_IDLETHREAD(td))
|
||||
sched_prio(td, PUSER);
|
||||
if (TD_ON_SLEEPQ(td)) {
|
||||
|
@ -2411,7 +2411,7 @@ tdsigwakeup(struct thread *td, int sig, sig_t action, int intrval)
|
|||
* asleep, we are finished; the process should not
|
||||
* be awakened.
|
||||
*/
|
||||
if ((prop & SA_CONT) && action == SIG_DFL) {
|
||||
if ((prop & SIGPROP_CONT) && action == SIG_DFL) {
|
||||
thread_unlock(td);
|
||||
PROC_SUNLOCK(p);
|
||||
sigqueue_delete(&p->p_sigqueue, sig);
|
||||
|
@ -2427,7 +2427,7 @@ tdsigwakeup(struct thread *td, int sig, sig_t action, int intrval)
|
|||
* Don't awaken a sleeping thread for SIGSTOP if the
|
||||
* STOP signal is deferred.
|
||||
*/
|
||||
if ((prop & SA_STOP) != 0 && (td->td_flags & (TDF_SBDRY |
|
||||
if ((prop & SIGPROP_STOP) != 0 && (td->td_flags & (TDF_SBDRY |
|
||||
TDF_SERESTART | TDF_SEINTR)) == TDF_SBDRY)
|
||||
goto out;
|
||||
|
||||
|
@ -2858,10 +2858,10 @@ issignal(struct thread *td)
|
|||
* if process is member of an orphaned
|
||||
* process group, ignore tty stop signals.
|
||||
*/
|
||||
if (prop & SA_STOP) {
|
||||
if (prop & SIGPROP_STOP) {
|
||||
if (p->p_flag & (P_TRACED|P_WEXIT) ||
|
||||
(p->p_pgrp->pg_jobc == 0 &&
|
||||
prop & SA_TTYSTOP))
|
||||
prop & SIGPROP_TTYSTOP))
|
||||
break; /* == ignore */
|
||||
if (TD_SBDRY_INTR(td)) {
|
||||
KASSERT((td->td_flags & TDF_SBDRY) != 0,
|
||||
|
@ -2881,7 +2881,7 @@ issignal(struct thread *td)
|
|||
PROC_SUNLOCK(p);
|
||||
mtx_lock(&ps->ps_mtx);
|
||||
goto next;
|
||||
} else if (prop & SA_IGNORE) {
|
||||
} else if (prop & SIGPROP_IGNORE) {
|
||||
/*
|
||||
* Except for SIGCONT, shouldn't get here.
|
||||
* Default action is to ignore; drop it.
|
||||
|
@ -2897,7 +2897,7 @@ issignal(struct thread *td)
|
|||
* to take action on an ignored signal other
|
||||
* than SIGCONT, unless process is traced.
|
||||
*/
|
||||
if ((prop & SA_CONT) == 0 &&
|
||||
if ((prop & SIGPROP_CONT) == 0 &&
|
||||
(p->p_flag & P_TRACED) == 0)
|
||||
printf("issignal\n");
|
||||
break; /* == ignore */
|
||||
|
@ -3059,7 +3059,8 @@ sigexit(td, sig)
|
|||
* XXX If another thread attempts to single-thread before us
|
||||
* (e.g. via fork()), we won't get a dump at all.
|
||||
*/
|
||||
if ((sigprop(sig) & SA_CORE) && thread_single(p, SINGLE_NO_EXIT) == 0) {
|
||||
if ((sigprop(sig) & SIGPROP_CORE) &&
|
||||
thread_single(p, SINGLE_NO_EXIT) == 0) {
|
||||
p->p_sig = sig;
|
||||
/*
|
||||
* Log signals which would cause core dumps
|
||||
|
|
|
@ -6,7 +6,6 @@ CXGBE = ${.CURDIR}/../../../dev/cxgbe
|
|||
KMOD= cxgbei
|
||||
|
||||
SRCS= cxgbei.c
|
||||
SRCS+= cxgbei_ulp2_ddp.c
|
||||
SRCS+= icl_cxgbei.c
|
||||
SRCS+= bus_if.h
|
||||
SRCS+= device_if.h
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
# $FreeBSD$
|
||||
|
||||
SUBDIR= digi
|
||||
SUBDIR+=digi_CX
|
||||
SUBDIR+=digi_CX_PCI
|
||||
SUBDIR+=digi_EPCX
|
||||
SUBDIR+=digi_EPCX_PCI
|
||||
SUBDIR+=digi_Xe
|
||||
SUBDIR+=digi_Xem
|
||||
SUBDIR+=digi_Xr
|
||||
|
||||
.include <bsd.subdir.mk>
|
|
@ -1,3 +0,0 @@
|
|||
# $FreeBSD$
|
||||
|
||||
.include "../Makefile.inc"
|
|
@ -1,16 +0,0 @@
|
|||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../../dev/digi
|
||||
KMOD= digi
|
||||
SRCS= digi.c digi_pci.c digi_isa.c
|
||||
SRCS+= digi.h digi_pci.h digireg.h digi_mod.h
|
||||
SRCS+= bus_if.h pci_if.h device_if.h
|
||||
SRCS+= opt_compat.h
|
||||
|
||||
.if !defined(KERNBUILDDIR)
|
||||
opt_compat.h:
|
||||
echo "#define COMPAT_43 1" > ${.TARGET}
|
||||
echo "#define COMPAT_FREEBSD6 1" >> ${.TARGET}
|
||||
.endif
|
||||
|
||||
.include <bsd.kmod.mk>
|
|
@ -1,7 +0,0 @@
|
|||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../../dev/digi
|
||||
KMOD= digi_CX
|
||||
SRCS= CX.c CX.bios.h CX.fepos.h digi_mod.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
|
@ -1,7 +0,0 @@
|
|||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../../dev/digi
|
||||
KMOD= digi_CX_PCI
|
||||
SRCS= CX_PCI.c CX_PCI.bios.h CX_PCI.fepos.h digi_mod.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
|
@ -1,7 +0,0 @@
|
|||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../../dev/digi
|
||||
KMOD= digi_EPCX
|
||||
SRCS= EPCX.c EPCX.bios.h EPCX.fepos.h digi_mod.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
|
@ -1,7 +0,0 @@
|
|||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../../dev/digi
|
||||
KMOD= digi_EPCX_PCI
|
||||
SRCS= EPCX_PCI.c EPCX_PCI.bios.h EPCX_PCI.fepos.h digi_mod.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
|
@ -1,7 +0,0 @@
|
|||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../../dev/digi
|
||||
KMOD= digi_Xe
|
||||
SRCS= Xe.c Xe.bios.h Xe.fepos.h digi_mod.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
|
@ -1,7 +0,0 @@
|
|||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../../dev/digi
|
||||
KMOD= digi_Xem
|
||||
SRCS= Xem.c Xem.bios.h Xem.fepos.h digi_mod.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
|
@ -1,7 +0,0 @@
|
|||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../../dev/digi
|
||||
KMOD= digi_Xr
|
||||
SRCS= Xr.c Xr.bios.h Xr.fepos.h digi_mod.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
|
@ -92,6 +92,14 @@
|
|||
#define RNDIS_DF_CONNECTIONLESS 0x00000001
|
||||
#define RNDIS_DF_CONNECTION_ORIENTED 0x00000002
|
||||
|
||||
/*
|
||||
* Common RNDIS message header.
|
||||
*/
|
||||
struct rndis_msghdr {
|
||||
uint32_t rm_type;
|
||||
uint32_t rm_len;
|
||||
};
|
||||
|
||||
/*
|
||||
* RNDIS data message
|
||||
*/
|
||||
|
@ -147,6 +155,12 @@ struct rndis_pktinfo {
|
|||
/*
|
||||
* RNDIS control messages
|
||||
*/
|
||||
|
||||
/*
|
||||
* Common header for RNDIS completion messages.
|
||||
*
|
||||
* NOTE: It does not apply to REMOTE_NDIS_RESET_CMPLT.
|
||||
*/
|
||||
struct rndis_comp_hdr {
|
||||
uint32_t rm_type;
|
||||
uint32_t rm_len;
|
||||
|
@ -316,7 +330,7 @@ struct rndis_keepalive_comp {
|
|||
#define NDIS_PACKET_TYPE_MAC_FRAME 0x00008000
|
||||
|
||||
/* RNDIS offsets */
|
||||
#define RNDIS_HEADER_OFFSET 8 /* bytes */
|
||||
#define RNDIS_HEADER_OFFSET ((uint32_t)sizeof(struct rndis_msghdr))
|
||||
#define RNDIS_DATA_OFFSET \
|
||||
((uint32_t)(sizeof(struct rndis_packet_msg) - RNDIS_HEADER_OFFSET))
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
* in the range 5 to 9.
|
||||
*/
|
||||
#undef __FreeBSD_version
|
||||
#define __FreeBSD_version 1200005 /* Master, propagated to newvers */
|
||||
#define __FreeBSD_version 1200006 /* Master, propagated to newvers */
|
||||
|
||||
/*
|
||||
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
|
||||
|
|
|
@ -78,6 +78,8 @@ BSTCENV= \
|
|||
BSTCARGS= \
|
||||
${BSARGS:NDESTDIR=*:NOBJTOP=*:NOBJROOT=*:NMK_CROSS_COMPILER=*:NMK_CLANG=*:NMK_GCC=*} \
|
||||
BUILD_DIRDEPS=yes \
|
||||
LLVM_TBLGEN=${TOOLSDIR}/usr/bin/llvm-tblgen \
|
||||
CLANG_TBLGEN=${TOOLSDIR}/usr/bin/clang-tblgen \
|
||||
-DWITH_STAGING \
|
||||
-DWITH_TOOLSDIR
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ DIRDEPS = \
|
|||
usr.bin/xlint/xlint \
|
||||
usr.bin/yacc \
|
||||
usr.sbin/config \
|
||||
usr.sbin/crunch/crunchgen \
|
||||
usr.sbin/crunch/crunchide \
|
||||
|
||||
|
||||
.if ${MK_KERBEROS} != "no"
|
||||
DIRDEPS+= \
|
||||
|
|
|
@ -47,6 +47,9 @@ DIRDEPS = \
|
|||
secure/lib/libcrypto \
|
||||
secure/lib/libssl \
|
||||
usr.bin/lex/lib \
|
||||
usr.bin/yacc.host \
|
||||
usr.sbin/crunch/crunchgen.host \
|
||||
usr.sbin/crunch/crunchide.host \
|
||||
|
||||
|
||||
.include <dirdeps.mk>
|
||||
|
|
|
@ -243,7 +243,10 @@ sub callback_dtformat {
|
|||
|
||||
if ($nl eq 'ja_JP') {
|
||||
$s =~ s/(> )(%H)/$1%A $2/;
|
||||
} elsif ($nl eq 'ko_KR' || $nl eq 'zh_TW') {
|
||||
} elsif ($nl eq 'ko_KR' || $nl eq 'zh_CN' || $nl eq 'zh_TW') {
|
||||
if ($nl ne 'ko_KR') {
|
||||
$s =~ s/%m/%_m/;
|
||||
}
|
||||
$s =~ s/(> )(%p)/$1%A $2/;
|
||||
}
|
||||
$s =~ s/\.,/\./;
|
||||
|
|
|
@ -85,6 +85,10 @@ default
|
|||
Do not attempt to resolve network addresses (normally
|
||||
.Nm
|
||||
interprets addresses and attempts to display them as names).
|
||||
When
|
||||
.Fl n
|
||||
is specified more than once, hostnames stored in utmp are attempted to
|
||||
resolve to display them as network addresses.
|
||||
.El
|
||||
.Pp
|
||||
If one or more
|
||||
|
|
|
@ -180,7 +180,7 @@ main(int argc, char *argv[])
|
|||
nlistf = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
nflag = 1;
|
||||
nflag += 1;
|
||||
break;
|
||||
case 'f': case 'l': case 's': case 'u': case 'w':
|
||||
warnx("[-flsuw] no longer supported");
|
||||
|
@ -378,12 +378,12 @@ main(int argc, char *argv[])
|
|||
lsin->sin_family = AF_INET;
|
||||
isaddr = 1;
|
||||
}
|
||||
if (!nflag) {
|
||||
if (nflag == 0) {
|
||||
/* Attempt to change an IP address into a name */
|
||||
if (isaddr && realhostname_sa(fn, sizeof(fn), sa,
|
||||
sa->sa_len) == HOSTNAME_FOUND)
|
||||
p = fn;
|
||||
} else if (!isaddr) {
|
||||
} else if (!isaddr && nflag > 1) {
|
||||
/*
|
||||
* If a host has only one A/AAAA RR, change a
|
||||
* name into an IP address
|
||||
|
|
|
@ -73,7 +73,6 @@
|
|||
#define MAX_COMMAND 1000 /* max length of internally generated cmd */
|
||||
#define MAX_ENVSTR 1000 /* max length of envvar=value\0 strings */
|
||||
#define MAX_TEMPSTR 100 /* obvious */
|
||||
#define MAX_UNAME 20 /* max length of username, should be overkill */
|
||||
#define ROOT_UID 0 /* don't change this, it really must be root */
|
||||
#define ROOT_USER "root" /* ditto */
|
||||
#define SYS_NAME "*system*" /* magic owner name for system crontab */
|
||||
|
|
|
@ -28,6 +28,7 @@ static const char rcsid[] =
|
|||
|
||||
#define MAIN_PROGRAM
|
||||
|
||||
#include <sys/param.h>
|
||||
#include "cron.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
@ -57,7 +58,7 @@ static char *Options[] = { "???", "list", "delete", "edit", "replace" };
|
|||
|
||||
|
||||
static PID_T Pid;
|
||||
static char User[MAX_UNAME], RealUser[MAX_UNAME];
|
||||
static char User[MAXLOGNAME], RealUser[MAXLOGNAME];
|
||||
static char Filename[MAX_FNAME];
|
||||
static FILE *NewCrontab;
|
||||
static int CheckErrorCount;
|
||||
|
|
|
@ -1064,6 +1064,7 @@ prog_makefile_rules(FILE *outmk, prog_t *p)
|
|||
}
|
||||
fprintf(outmk, "\n");
|
||||
}
|
||||
fprintf(outmk, "$(%s_OBJPATHS): .NOMETA\n", p->ident);
|
||||
|
||||
if (p->srcdir && p->objs) {
|
||||
fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir);
|
||||
|
|
Loading…
Reference in a new issue