diff options
177 files changed, 5331 insertions, 1429 deletions
diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc index 3426485..c51cf7c 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -38,7 +38,7 @@ # xargs -n1 | sort | uniq -d; # done -# 20150529: new clang import which bumps version from 3.6.1 to 3.7.0. +# 2015mmdd: new clang import which bumps version from 3.6.1 to 3.7.0. OLD_FILES+=usr/lib/clang/3.6.1/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/3.6.1/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/3.6.1/include/__wmmintrin_pclmul.h @@ -99,6 +99,10 @@ OLD_FILES+=usr/lib/clang/3.6.1/lib/freebsd/libclang_rt.ubsan_cxx-x86_64.a OLD_DIRS+=usr/lib/clang/3.6.1/lib/freebsd OLD_DIRS+=usr/lib/clang/3.6.1/lib OLD_DIRS+=usr/lib/clang/3.6.1 +# 20150528: PCI IOV device driver methods moved to a separate kobj interface. +OLD_FILES+=usr/share/man/man9/PCI_ADD_VF.9 +OLD_FILES+=usr/share/man/man9/PCI_INIT_IOV.9 +OLD_FILES+=usr/share/man/man9/PCI_UNINIT_IOV.9 # 20150525: new clang import which bumps version from 3.6.0 to 3.6.1. OLD_FILES+=usr/lib/clang/3.6.0/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/3.6.0/include/__wmmintrin_aes.h diff --git a/bin/ps/ps.1 b/bin/ps/ps.1 index 369e1d7..c777a6b 100644 --- a/bin/ps/ps.1 +++ b/bin/ps/ps.1 @@ -29,7 +29,7 @@ .\" @(#)ps.1 8.3 (Berkeley) 4/18/94 .\" $FreeBSD$ .\" -.Dd May 22, 2015 +.Dd May 27, 2015 .Dt PS 1 .Os .Sh NAME @@ -350,6 +350,9 @@ the include file .In sys/proc.h : .Bl -column P2_INHERIT_PROTECTED 0x00000001 .It Dv "P2_INHERIT_PROTECTED" Ta No "0x00000001" Ta "New children get P_PROTECTED" +.It Dv "P2_NOTRACE" Ta No "0x00000002" Ta "No ptrace(2) attach or coredumps" +.It Dv "P2_NOTRACE_EXEC" Ta No "0x00000004" Ta "Keep P2_NOPTRACE on exec(2)" +.It Dv "P2_AST_SU" Ta No "0x00000008" Ta "Handles SU ast for kthreads" .El .It Cm label The MAC label of the process. diff --git a/contrib/elftoolchain/common/_elftc.h b/contrib/elftoolchain/common/_elftc.h index 45f0abd..6769519 100644 --- a/contrib/elftoolchain/common/_elftc.h +++ b/contrib/elftoolchain/common/_elftc.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: _elftc.h 3175 2015-03-27 17:21:24Z emaste $ + * $Id: _elftc.h 3209 2015-05-17 13:40:46Z kaiwang27 $ */ /** @@ -342,12 +342,13 @@ struct name { \ #if defined(__GLIBC__) || defined(__linux__) - +#ifndef _GNU_SOURCE /* * GLIBC based systems have a global 'char *' pointer referencing * the executable's name. */ extern const char *program_invocation_short_name; +#endif /* !_GNU_SOURCE */ #define ELFTC_GETPROGNAME() program_invocation_short_name diff --git a/contrib/elftoolchain/common/elfdefinitions.h b/contrib/elftoolchain/common/elfdefinitions.h index a53acde..58554fef 100644 --- a/contrib/elftoolchain/common/elfdefinitions.h +++ b/contrib/elftoolchain/common/elfdefinitions.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: elfdefinitions.h 3178 2015-03-30 18:29:13Z emaste $ + * $Id: elfdefinitions.h 3198 2015-05-14 18:36:19Z emaste $ */ /* @@ -565,6 +565,7 @@ _ELF_DEFINE_EM(EM_SPARC, 2, "SPARC") \ _ELF_DEFINE_EM(EM_386, 3, "Intel 80386") \ _ELF_DEFINE_EM(EM_68K, 4, "Motorola 68000") \ _ELF_DEFINE_EM(EM_88K, 5, "Motorola 88000") \ +_ELF_DEFINE_EM(EM_IAMCU, 6, "Intel MCU") \ _ELF_DEFINE_EM(EM_860, 7, "Intel 80860") \ _ELF_DEFINE_EM(EM_MIPS, 8, "MIPS I Architecture") \ _ELF_DEFINE_EM(EM_S370, 9, "IBM System/370 Processor") \ diff --git a/contrib/elftoolchain/elfcopy/elfcopy.h b/contrib/elftoolchain/elfcopy/elfcopy.h index b750246..48574b5 100644 --- a/contrib/elftoolchain/elfcopy/elfcopy.h +++ b/contrib/elftoolchain/elfcopy/elfcopy.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: elfcopy.h 3173 2015-03-27 16:46:13Z emaste $ + * $Id: elfcopy.h 3221 2015-05-24 23:42:43Z kaiwang27 $ */ #include <sys/queue.h> @@ -237,6 +237,7 @@ struct elfcopy { uint64_t *secndx; /* section index map. */ uint64_t *symndx; /* symbol index map. */ unsigned char *v_rel; /* symbols needed by relocation. */ + unsigned char *v_grp; /* symbols refered by section group. */ unsigned char *v_secsym; /* sections with section symbol. */ STAILQ_HEAD(, segment) v_seg; /* list of segments. */ STAILQ_HEAD(, sec_action) v_sac;/* list of section operations. */ diff --git a/contrib/elftoolchain/elfcopy/main.c b/contrib/elftoolchain/elfcopy/main.c index a48aea5..cbd48d3 100644 --- a/contrib/elftoolchain/elfcopy/main.c +++ b/contrib/elftoolchain/elfcopy/main.c @@ -39,7 +39,7 @@ #include "elfcopy.h" -ELFTC_VCSID("$Id: main.c 3174 2015-03-27 17:13:41Z emaste $"); +ELFTC_VCSID("$Id: main.c 3216 2015-05-23 21:16:36Z kaiwang27 $"); enum options { @@ -404,8 +404,19 @@ create_elf(struct elfcopy *ecp) * Insert SHDR table into the internal section list as a "pseudo" * section, so later it will get sorted and resynced just as "normal" * sections. + * + * Under FreeBSD, Binutils objcopy always put the section header + * at the end of all the sections. We want to do the same here. + * + * However, note that the behaviour is still different with Binutils: + * elfcopy checks the FreeBSD OSABI tag to tell whether it needs to + * move the section headers, while Binutils is probably configured + * this way when it's compiled on FreeBSD. */ - shtab = insert_shtab(ecp, 0); + if (oeh.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) + shtab = insert_shtab(ecp, 1); + else + shtab = insert_shtab(ecp, 0); /* * Resync section offsets in the output object. This is needed @@ -485,6 +496,11 @@ free_elf(struct elfcopy *ecp) free(sec); } } + + if (ecp->secndx != NULL) { + free(ecp->secndx); + ecp->secndx = NULL; + } } /* Create a temporary file. */ diff --git a/contrib/elftoolchain/elfcopy/sections.c b/contrib/elftoolchain/elfcopy/sections.c index 7c43a35..a407a42 100644 --- a/contrib/elftoolchain/elfcopy/sections.c +++ b/contrib/elftoolchain/elfcopy/sections.c @@ -34,7 +34,7 @@ #include "elfcopy.h" -ELFTC_VCSID("$Id: sections.c 3185 2015-04-11 08:56:34Z kaiwang27 $"); +ELFTC_VCSID("$Id: sections.c 3220 2015-05-24 23:42:39Z kaiwang27 $"); static void add_gnu_debuglink(struct elfcopy *ecp); static uint32_t calc_crc32(const char *p, size_t len, uint32_t crc); @@ -56,6 +56,7 @@ static void print_data(const char *d, size_t sz); static void print_section(struct section *s); static void *read_section(struct section *s, size_t *size); static void update_reloc(struct elfcopy *ecp, struct section *s); +static void update_section_group(struct elfcopy *ecp, struct section *s); int is_remove_section(struct elfcopy *ecp, const char *name) @@ -552,6 +553,14 @@ copy_content(struct elfcopy *ecp) (s->type == SHT_REL || s->type == SHT_RELA)) filter_reloc(ecp, s); + /* + * The section indices in the SHT_GROUP section needs + * to be updated since we might have stripped some + * sections and changed section numbering. + */ + if (s->type == SHT_GROUP) + update_section_group(ecp, s); + if (is_modify_section(ecp, s->name)) modify_section(ecp, s); @@ -571,6 +580,71 @@ copy_content(struct elfcopy *ecp) } } + +/* + * Update section group section. The section indices in the SHT_GROUP + * section need update after section numbering changed. + */ +static void +update_section_group(struct elfcopy *ecp, struct section *s) +{ + GElf_Shdr ish; + Elf_Data *id; + uint32_t *ws, *wd; + uint64_t n; + size_t ishnum; + int i, j; + + if (!elf_getshnum(ecp->ein, &ishnum)) + errx(EXIT_FAILURE, "elf_getshnum failed: %s", + elf_errmsg(-1)); + + if (gelf_getshdr(s->is, &ish) == NULL) + errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", + elf_errmsg(-1)); + + if ((id = elf_getdata(s->is, NULL)) == NULL) + errx(EXIT_FAILURE, "elf_getdata() failed: %s", + elf_errmsg(-1)); + + if (ish.sh_size == 0) + return; + + if (ish.sh_entsize == 0) + ish.sh_entsize = 4; + + ws = id->d_buf; + + /* We only support COMDAT section. */ +#ifndef GRP_COMDAT +#define GRP_COMDAT 0x1 +#endif + if ((*ws & GRP_COMDAT) == 0) + return; + + if ((s->buf = malloc(ish.sh_size)) == NULL) + err(EXIT_FAILURE, "malloc failed"); + + s->sz = ish.sh_size; + + wd = s->buf; + + /* Copy the flag word as-is. */ + *wd = *ws; + + /* Update the section indices. */ + n = ish.sh_size / ish.sh_entsize; + for(i = 1, j = 1; (uint64_t)i < n; i++) { + if (ws[i] != SHN_UNDEF && ws[i] < ishnum && + ecp->secndx[ws[i]] != 0) + wd[j++] = ecp->secndx[ws[i]]; + else + s->sz -= 4; + } + + s->nocopy = 1; +} + /* * Filter relocation entries, only keep those entries whose * symbol is in the keep list. @@ -1028,8 +1102,11 @@ copy_shdr(struct elfcopy *ecp, struct section *s, const char *name, int copy, osh.sh_flags |= SHF_WRITE; if (sec_flags & SF_CODE) osh.sh_flags |= SHF_EXECINSTR; - } else + } else { osh.sh_flags = ish.sh_flags; + if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA) + osh.sh_flags |= SHF_INFO_LINK; + } } if (name == NULL) diff --git a/contrib/elftoolchain/elfcopy/symbols.c b/contrib/elftoolchain/elfcopy/symbols.c index 4a7d38a..05bcd7a 100644 --- a/contrib/elftoolchain/elfcopy/symbols.c +++ b/contrib/elftoolchain/elfcopy/symbols.c @@ -33,7 +33,7 @@ #include "elfcopy.h" -ELFTC_VCSID("$Id: symbols.c 3191 2015-05-04 17:07:01Z jkoshy $"); +ELFTC_VCSID("$Id: symbols.c 3222 2015-05-24 23:47:23Z kaiwang27 $"); /* Symbol table buffer structure. */ struct symbuf { @@ -77,7 +77,8 @@ static int is_weak_symbol(unsigned char st_info); static int lookup_exact_string(hash_head *hash, const char *buf, const char *s); static int generate_symbols(struct elfcopy *ecp); -static void mark_symbols(struct elfcopy *ecp, size_t sc); +static void mark_reloc_symbols(struct elfcopy *ecp, size_t sc); +static void mark_section_group_symbols(struct elfcopy *ecp, size_t sc); static int match_wildcard(const char *name, const char *pattern); uint32_t str_hash(const char *s); @@ -160,6 +161,10 @@ is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s) if (BIT_ISSET(ecp->v_rel, i)) return (1); + /* Symbols refered by COMDAT sections are needed. */ + if (BIT_ISSET(ecp->v_grp, i)) + return (1); + /* * For relocatable files (.o files), global and weak symbols * are needed. @@ -207,7 +212,10 @@ is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, GElf_Sym *s, return (1); if (ecp->v_rel == NULL) - mark_symbols(ecp, sc); + mark_reloc_symbols(ecp, sc); + + if (ecp->v_grp == NULL) + mark_section_group_symbols(ecp, sc); if (is_needed_symbol(ecp, i, s)) return (0); @@ -233,7 +241,7 @@ is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, GElf_Sym *s, * Mark symbols refered by relocation entries. */ static void -mark_symbols(struct elfcopy *ecp, size_t sc) +mark_reloc_symbols(struct elfcopy *ecp, size_t sc) { const char *name; Elf_Data *d; @@ -311,6 +319,49 @@ mark_symbols(struct elfcopy *ecp, size_t sc) elf_errmsg(elferr)); } +static void +mark_section_group_symbols(struct elfcopy *ecp, size_t sc) +{ + const char *name; + Elf_Scn *s; + GElf_Shdr sh; + size_t indx; + int elferr; + + ecp->v_grp = calloc((sc + 7) / 8, 1); + if (ecp->v_grp == NULL) + err(EXIT_FAILURE, "calloc failed"); + + if (elf_getshstrndx(ecp->ein, &indx) == 0) + errx(EXIT_FAILURE, "elf_getshstrndx failed: %s", + elf_errmsg(-1)); + + s = NULL; + while ((s = elf_nextscn(ecp->ein, s)) != NULL) { + if (gelf_getshdr(s, &sh) != &sh) + errx(EXIT_FAILURE, "elf_getshdr failed: %s", + elf_errmsg(-1)); + + if (sh.sh_type != SHT_GROUP) + continue; + + if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == NULL) + errx(EXIT_FAILURE, "elf_strptr failed: %s", + elf_errmsg(-1)); + if (is_remove_section(ecp, name)) + continue; + + if (sh.sh_info > 0 && sh.sh_info < sc) + BIT_SET(ecp->v_grp, sh.sh_info); + else if (sh.sh_info != 0) + warnx("invalid symbox index"); + } + elferr = elf_errno(); + if (elferr != 0) + errx(EXIT_FAILURE, "elf_nextscn failed: %s", + elf_errmsg(elferr)); +} + static int generate_symbols(struct elfcopy *ecp) { @@ -351,6 +402,8 @@ generate_symbols(struct elfcopy *ecp) ecp->symtab->buf = sy_buf; ecp->strtab->buf = st_buf; + gsym = NULL; + /* * Create bit vector v_secsym, which is used to mark sections * that already have corresponding STT_SECTION symbols. @@ -384,7 +437,7 @@ generate_symbols(struct elfcopy *ecp) /* Symbol table should exist if this function is called. */ if (symndx == 0) { warnx("can't find .strtab section"); - return (0); + goto clean; } /* Locate .symtab of input object. */ @@ -413,7 +466,6 @@ generate_symbols(struct elfcopy *ecp) * output object, it is used by update_reloc() later to update * relocation information. */ - gsym = NULL; sc = ish.sh_size / ish.sh_entsize; if (sc > 0) { ecp->symndx = calloc(sc, sizeof(*ecp->symndx)); @@ -427,7 +479,7 @@ generate_symbols(struct elfcopy *ecp) if (elferr != 0) errx(EXIT_FAILURE, "elf_getdata failed: %s", elf_errmsg(elferr)); - return (0); + goto clean; } } else return (0); @@ -523,7 +575,7 @@ generate_symbols(struct elfcopy *ecp) * check if that only local symbol is the reserved symbol. */ if (sy_buf->nls <= 1 && sy_buf->ngs == 0) - return (0); + goto clean; /* * Create STT_SECTION symbols for sections that do not already @@ -550,6 +602,7 @@ generate_symbols(struct elfcopy *ecp) sym.st_value = s->vma; sym.st_size = 0; sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION); + sym.st_other = STV_DEFAULT; /* * Don't let add_to_symtab() touch sym.st_shndx. * In this case, we know the index already. @@ -583,6 +636,12 @@ generate_symbols(struct elfcopy *ecp) } return (1); + +clean: + free(gsym); + free_symtab(ecp); + + return (0); } void @@ -624,7 +683,9 @@ create_symtab(struct elfcopy *ecp) if (((ecp->flags & SYMTAB_INTACT) == 0) && !generate_symbols(ecp)) { TAILQ_REMOVE(&ecp->v_sec, ecp->symtab, sec_list); TAILQ_REMOVE(&ecp->v_sec, ecp->strtab, sec_list); + free(ecp->symtab->buf); free(ecp->symtab); + free(ecp->strtab->buf); free(ecp->strtab); ecp->symtab = NULL; ecp->strtab = NULL; @@ -697,6 +758,23 @@ free_symtab(struct elfcopy *ecp) } } } + + if (ecp->symndx != NULL) { + free(ecp->symndx); + ecp->symndx = NULL; + } + if (ecp->v_rel != NULL) { + free(ecp->v_rel); + ecp->v_rel = NULL; + } + if (ecp->v_grp != NULL) { + free(ecp->v_grp); + ecp->v_grp = NULL; + } + if (ecp->v_secsym != NULL) { + free(ecp->v_secsym); + ecp->v_secsym = NULL; + } } void diff --git a/contrib/elftoolchain/libdwarf/libdwarf_reloc.c b/contrib/elftoolchain/libdwarf/libdwarf_reloc.c index 96bb785..4ae8f5c 100644 --- a/contrib/elftoolchain/libdwarf/libdwarf_reloc.c +++ b/contrib/elftoolchain/libdwarf/libdwarf_reloc.c @@ -26,7 +26,7 @@ #include "_libdwarf.h" -ELFTC_VCSID("$Id: libdwarf_reloc.c 3149 2015-02-15 19:00:06Z emaste $"); +ELFTC_VCSID("$Id: libdwarf_reloc.c 3198 2015-05-14 18:36:19Z emaste $"); Dwarf_Unsigned _dwarf_get_reloc_type(Dwarf_P_Debug dbg, int is64) @@ -75,6 +75,7 @@ _dwarf_get_reloc_size(Dwarf_Debug dbg, Dwarf_Unsigned rel_type) return (4); break; case EM_386: + case EM_IAMCU: if (rel_type == R_386_32) return (4); break; diff --git a/contrib/elftoolchain/libelftc/libelftc_dem_gnu3.c b/contrib/elftoolchain/libelftc/libelftc_dem_gnu3.c index 1cdb0e7..e8fd78f 100644 --- a/contrib/elftoolchain/libelftc/libelftc_dem_gnu3.c +++ b/contrib/elftoolchain/libelftc/libelftc_dem_gnu3.c @@ -36,7 +36,7 @@ #include "_libelftc.h" -ELFTC_VCSID("$Id: libelftc_dem_gnu3.c 3194 2015-05-05 17:55:16Z emaste $"); +ELFTC_VCSID("$Id: libelftc_dem_gnu3.c 3212 2015-05-17 13:40:55Z kaiwang27 $"); /** * @file cpp_demangle.c @@ -50,7 +50,7 @@ ELFTC_VCSID("$Id: libelftc_dem_gnu3.c 3194 2015-05-05 17:55:16Z emaste $"); enum type_qualifier { TYPE_PTR, TYPE_REF, TYPE_CMX, TYPE_IMG, TYPE_EXT, TYPE_RST, TYPE_VAT, - TYPE_CST + TYPE_CST, TYPE_VEC }; struct vector_type_qualifier { @@ -84,6 +84,7 @@ struct cpp_demangle_data { int func_type; const char *cur; /* current mangled name ptr */ const char *last_sname; /* last source name */ + int push_head; }; #define CPP_DEMANGLE_TRY_LIMIT 128 @@ -112,6 +113,8 @@ static int cpp_demangle_read_array(struct cpp_demangle_data *); static int cpp_demangle_read_encoding(struct cpp_demangle_data *); static int cpp_demangle_read_expr_primary(struct cpp_demangle_data *); static int cpp_demangle_read_expression(struct cpp_demangle_data *); +static int cpp_demangle_read_expression_flat(struct cpp_demangle_data *, + char **); static int cpp_demangle_read_expression_binary(struct cpp_demangle_data *, const char *, size_t); static int cpp_demangle_read_expression_unary(struct cpp_demangle_data *, @@ -123,8 +126,12 @@ static int cpp_demangle_read_function(struct cpp_demangle_data *, int *, static int cpp_demangle_local_source_name(struct cpp_demangle_data *ddata); static int cpp_demangle_read_local_name(struct cpp_demangle_data *); static int cpp_demangle_read_name(struct cpp_demangle_data *); +static int cpp_demangle_read_name_flat(struct cpp_demangle_data *, + char**); static int cpp_demangle_read_nested_name(struct cpp_demangle_data *); static int cpp_demangle_read_number(struct cpp_demangle_data *, long *); +static int cpp_demangle_read_number_as_string(struct cpp_demangle_data *, + char **); static int cpp_demangle_read_nv_offset(struct cpp_demangle_data *); static int cpp_demangle_read_offset(struct cpp_demangle_data *); static int cpp_demangle_read_offset_number(struct cpp_demangle_data *); @@ -138,6 +145,8 @@ static int cpp_demangle_read_tmpl_arg(struct cpp_demangle_data *); static int cpp_demangle_read_tmpl_args(struct cpp_demangle_data *); static int cpp_demangle_read_tmpl_param(struct cpp_demangle_data *); static int cpp_demangle_read_type(struct cpp_demangle_data *, int); +static int cpp_demangle_read_type_flat(struct cpp_demangle_data *, + char **); static int cpp_demangle_read_uqname(struct cpp_demangle_data *); static int cpp_demangle_read_v_offset(struct cpp_demangle_data *); static char *decode_fp_to_double(const char *, size_t); @@ -156,8 +165,6 @@ static int vector_type_qualifier_init(struct vector_type_qualifier *); static int vector_type_qualifier_push(struct vector_type_qualifier *, enum type_qualifier); -static int cpp_demangle_gnu3_push_head; - /** * @brief Decode the input string by IA-64 C++ ABI style. * @@ -190,7 +197,6 @@ cpp_demangle_gnu3(const char *org) if (!cpp_demangle_data_init(&ddata, org + 2)) return (NULL); - cpp_demangle_gnu3_push_head = 0; rtn = NULL; if (!cpp_demangle_read_encoding(&ddata)) @@ -277,6 +283,7 @@ cpp_demangle_data_init(struct cpp_demangle_data *d, const char *cur) d->func_type = 0; d->cur = cur; d->last_sname = NULL; + d->push_head = 0; return (1); @@ -309,7 +316,6 @@ cpp_demangle_push_fp(struct cpp_demangle_data *ddata, fp = ddata->cur; while (*ddata->cur != 'E') ++ddata->cur; - ++ddata->cur; if ((f = decoder(fp, ddata->cur - fp)) == NULL) return (0); @@ -320,6 +326,8 @@ cpp_demangle_push_fp(struct cpp_demangle_data *ddata, free(f); + ++ddata->cur; + return (rtn); } @@ -331,7 +339,7 @@ cpp_demangle_push_str(struct cpp_demangle_data *ddata, const char *str, if (ddata == NULL || str == NULL || len == 0) return (0); - if (cpp_demangle_gnu3_push_head > 0) + if (ddata->push_head > 0) return (vector_str_push(&ddata->output_tmp, str, len)); return (vector_str_push(&ddata->output, str, len)); @@ -403,7 +411,8 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata, if (type_str != NULL) { if (!vector_str_push(&subst_v, "*", 1)) goto clean; - if (!cpp_demangle_push_subst_v(ddata, &subst_v)) + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) goto clean; } break; @@ -414,7 +423,8 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata, if (type_str != NULL) { if (!vector_str_push(&subst_v, "&", 1)) goto clean; - if (!cpp_demangle_push_subst_v(ddata, &subst_v)) + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) goto clean; } break; @@ -425,7 +435,8 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata, if (type_str != NULL) { if (!vector_str_push(&subst_v, " complex", 8)) goto clean; - if (!cpp_demangle_push_subst_v(ddata, &subst_v)) + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) goto clean; } break; @@ -434,23 +445,26 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata, if (!cpp_demangle_push_str(ddata, " imaginary", 10)) goto clean; if (type_str != NULL) { - if (!vector_str_push(&subst_v, " imaginary", 10)) + if (!vector_str_push(&subst_v, " imaginary", + 10)) goto clean; - if (!cpp_demangle_push_subst_v(ddata, &subst_v)) + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) goto clean; } break; case TYPE_EXT: - if (e_idx > v->ext_name.size - 1) + if (v->ext_name.size == 0 || + e_idx > v->ext_name.size - 1) goto clean; - if ((e_len = strlen(v->ext_name.container[e_idx])) == 0) + if ((e_len = strlen(v->ext_name.container[e_idx])) == + 0) goto clean; - if ((buf = malloc(sizeof(char) * (e_len + 1))) == NULL) + if ((buf = malloc(e_len + 2)) == NULL) goto clean; - - memcpy(buf, " ", 1); - memcpy(buf + 1, v->ext_name.container[e_idx], e_len); + snprintf(buf, e_len + 2, " %s", + v->ext_name.container[e_idx]); if (!cpp_demangle_push_str(ddata, buf, e_len + 1)) { free(buf); @@ -463,7 +477,8 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata, free(buf); goto clean; } - if (!cpp_demangle_push_subst_v(ddata, &subst_v)) { + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) { free(buf); goto clean; } @@ -478,7 +493,8 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata, if (type_str != NULL) { if (!vector_str_push(&subst_v, " restrict", 9)) goto clean; - if (!cpp_demangle_push_subst_v(ddata, &subst_v)) + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) goto clean; } break; @@ -489,7 +505,8 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata, if (type_str != NULL) { if (!vector_str_push(&subst_v, " volatile", 9)) goto clean; - if (!cpp_demangle_push_subst_v(ddata, &subst_v)) + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) goto clean; } break; @@ -500,11 +517,42 @@ cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata, if (type_str != NULL) { if (!vector_str_push(&subst_v, " const", 6)) goto clean; - if (!cpp_demangle_push_subst_v(ddata, &subst_v)) + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) goto clean; } break; + case TYPE_VEC: + if (v->ext_name.size == 0 || + e_idx > v->ext_name.size - 1) + goto clean; + if ((e_len = strlen(v->ext_name.container[e_idx])) == + 0) + goto clean; + if ((buf = malloc(e_len + 12)) == NULL) + goto clean; + snprintf(buf, e_len + 12, " __vector(%s)", + v->ext_name.container[e_idx]); + if (!cpp_demangle_push_str(ddata, buf, e_len + 11)) { + free(buf); + goto clean; + } + if (type_str != NULL) { + if (!vector_str_push(&subst_v, buf, + e_len + 11)) { + free(buf); + goto clean; + } + if (!cpp_demangle_push_subst_v(ddata, + &subst_v)) { + free(buf); + goto clean; + } + } + free(buf); + ++e_idx; + break; }; --idx; } @@ -655,10 +703,14 @@ cpp_demangle_read_expr_primary(struct cpp_demangle_data *ddata) switch (*ddata->cur) { case 'b': + if (*(ddata->cur + 2) != 'E') + return (0); switch (*(++ddata->cur)) { case '0': + ddata->cur += 2; return (cpp_demangle_push_str(ddata, "false", 5)); case '1': + ddata->cur += 2; return (cpp_demangle_push_str(ddata, "true", 4)); default: return (0); @@ -707,7 +759,8 @@ cpp_demangle_read_expr_primary(struct cpp_demangle_data *ddata) ++ddata->cur; } ++ddata->cur; - return (cpp_demangle_push_str(ddata, num, ddata->cur - num)); + return (cpp_demangle_push_str(ddata, num, + ddata->cur - num - 1)); default: return (0); @@ -999,6 +1052,38 @@ cpp_demangle_read_expression(struct cpp_demangle_data *ddata) } static int +cpp_demangle_read_expression_flat(struct cpp_demangle_data *ddata, char **str) +{ + struct vector_str *output; + size_t i, p_idx, idx, exp_len; + char *exp; + + output = ddata->push_head > 0 ? &ddata->output_tmp : + &ddata->output; + + p_idx = output->size; + + if (!cpp_demangle_read_expression(ddata)) + return (0); + + if ((exp = vector_str_substr(output, p_idx, output->size - 1, + &exp_len)) == NULL) + return (0); + + idx = output->size; + for (i = p_idx; i < idx; ++i) { + if (!vector_str_pop(output)) { + free(exp); + return (0); + } + } + + *str = exp; + + return (1); +} + +static int cpp_demangle_read_expression_binary(struct cpp_demangle_data *ddata, const char *name, size_t len) { @@ -1127,12 +1212,65 @@ cpp_demangle_read_function(struct cpp_demangle_data *ddata, int *ext_c, static int cpp_demangle_read_encoding(struct cpp_demangle_data *ddata) { + char *name, *type, *num_str; + long offset; + int rtn; if (ddata == NULL || *ddata->cur == '\0') return (0); /* special name */ switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) { + case SIMPLE_HASH('G', 'A'): + if (!cpp_demangle_push_str(ddata, "hidden alias for ", 17)) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + return (cpp_demangle_read_encoding(ddata)); + + case SIMPLE_HASH('G', 'R'): + if (!cpp_demangle_push_str(ddata, "reference temporary #", 21)) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + if (!cpp_demangle_read_name_flat(ddata, &name)) + return (0); + rtn = 0; + if (!cpp_demangle_read_number_as_string(ddata, &num_str)) + goto clean1; + if (!cpp_demangle_push_str(ddata, num_str, strlen(num_str))) + goto clean2; + if (!cpp_demangle_push_str(ddata, " for ", 5)) + goto clean2; + if (!cpp_demangle_push_str(ddata, name, strlen(name))) + goto clean2; + rtn = 1; + clean2: + free(num_str); + clean1: + free(name); + return (rtn); + + case SIMPLE_HASH('G', 'T'): + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + switch (*ddata->cur) { + case 'n': + if (!cpp_demangle_push_str(ddata, + "non-transaction clone for ", 26)) + return (0); + case 't': + default: + if (!cpp_demangle_push_str(ddata, + "transaction clone for ", 22)) + return (0); + } + ++ddata->cur; + return (cpp_demangle_read_encoding(ddata)); + case SIMPLE_HASH('G', 'V'): /* sentry object for 1 time init */ if (!cpp_demangle_push_str(ddata, "guard variable for ", 20)) @@ -1154,14 +1292,49 @@ cpp_demangle_read_encoding(struct cpp_demangle_data *ddata) return (0); return (cpp_demangle_read_encoding(ddata)); + case SIMPLE_HASH('T', 'C'): + /* construction vtable */ + if (!cpp_demangle_push_str(ddata, "construction vtable for ", + 24)) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + if (!cpp_demangle_read_type_flat(ddata, &type)) + return (0); + rtn = 0; + if (!cpp_demangle_read_number(ddata, &offset)) + goto clean3; + if (*ddata->cur++ != '_') + goto clean3; + if (!cpp_demangle_read_type(ddata, 0)) + goto clean3; + if (!cpp_demangle_push_str(ddata, "-in-", 4)) + goto clean3; + if (!cpp_demangle_push_str(ddata, type, strlen(type))) + goto clean3; + rtn = 1; + clean3: + free(type); + return (rtn); + case SIMPLE_HASH('T', 'D'): /* typeinfo common proxy */ break; + case SIMPLE_HASH('T', 'F'): + /* typeinfo fn */ + if (!cpp_demangle_push_str(ddata, "typeinfo fn for ", 16)) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + return (cpp_demangle_read_type(ddata, 0)); + case SIMPLE_HASH('T', 'h'): /* virtual function non-virtual override thunk */ - if (cpp_demangle_push_str(ddata, - "virtual function non-virtual override ", 38) == 0) + if (!cpp_demangle_push_str(ddata, + "virtual function non-virtual override ", 38)) return (0); ddata->cur += 2; if (*ddata->cur == '\0') @@ -1170,24 +1343,51 @@ cpp_demangle_read_encoding(struct cpp_demangle_data *ddata) return (0); return (cpp_demangle_read_encoding(ddata)); + case SIMPLE_HASH('T', 'H'): + /* TLS init function */ + if (!cpp_demangle_push_str(ddata, "TLS init function for ", + 22)) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + break; + case SIMPLE_HASH('T', 'I'): /* typeinfo structure */ - /* FALLTHROUGH */ + if (!cpp_demangle_push_str(ddata, "typeinfo for ", 13)) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + return (cpp_demangle_read_type(ddata, 0)); + + case SIMPLE_HASH('T', 'J'): + /* java class */ + if (!cpp_demangle_push_str(ddata, "java Class for ", 15)) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + return (cpp_demangle_read_type(ddata, 0)); + case SIMPLE_HASH('T', 'S'): /* RTTI name (NTBS) */ - if (!cpp_demangle_push_str(ddata, "typeinfo for ", 14)) + if (!cpp_demangle_push_str(ddata, "typeinfo name for ", 18)) return (0); ddata->cur += 2; if (*ddata->cur == '\0') return (0); - return (cpp_demangle_read_type(ddata, 1)); + return (cpp_demangle_read_type(ddata, 0)); case SIMPLE_HASH('T', 'T'): /* VTT table */ if (!cpp_demangle_push_str(ddata, "VTT for ", 8)) return (0); ddata->cur += 2; - return (cpp_demangle_read_type(ddata, 1)); + if (*ddata->cur == '\0') + return (0); + return (cpp_demangle_read_type(ddata, 0)); case SIMPLE_HASH('T', 'v'): /* virtual function virtual override thunk */ @@ -1208,7 +1408,17 @@ cpp_demangle_read_encoding(struct cpp_demangle_data *ddata) ddata->cur += 2; if (*ddata->cur == '\0') return (0); - return (cpp_demangle_read_type(ddata, 1)); + return (cpp_demangle_read_type(ddata, 0)); + + case SIMPLE_HASH('T', 'W'): + /* TLS wrapper function */ + if (!cpp_demangle_push_str(ddata, "TLS wrapper function for ", + 25)) + return (0); + ddata->cur += 2; + if (*ddata->cur == '\0') + return (0); + break; }; return (cpp_demangle_read_name(ddata)); @@ -1270,8 +1480,7 @@ cpp_demangle_read_name(struct cpp_demangle_data *ddata) if (ddata == NULL || *ddata->cur == '\0') return (0); - output = cpp_demangle_gnu3_push_head > 0 ? - &ddata->output_tmp : &ddata->output; + output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output; subst_str = NULL; @@ -1327,6 +1536,38 @@ clean: } static int +cpp_demangle_read_name_flat(struct cpp_demangle_data *ddata, char **str) +{ + struct vector_str *output; + size_t i, p_idx, idx, name_len; + char *name; + + output = ddata->push_head > 0 ? &ddata->output_tmp : + &ddata->output; + + p_idx = output->size; + + if (!cpp_demangle_read_name(ddata)) + return (0); + + if ((name = vector_str_substr(output, p_idx, output->size - 1, + &name_len)) == NULL) + return (0); + + idx = output->size; + for (i = p_idx; i < idx; ++i) { + if (!vector_str_pop(output)) { + free(name); + return (0); + } + } + + *str = name; + + return (1); +} + +static int cpp_demangle_read_nested_name(struct cpp_demangle_data *ddata) { struct vector_str *output, v; @@ -1355,8 +1596,7 @@ cpp_demangle_read_nested_name(struct cpp_demangle_data *ddata) ++ddata->cur; } - output = cpp_demangle_gnu3_push_head > 0 ? - &ddata->output_tmp : &ddata->output; + output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output; if (!vector_str_init(&v)) return (0); @@ -1453,6 +1693,24 @@ cpp_demangle_read_number(struct cpp_demangle_data *ddata, long *rtn) } static int +cpp_demangle_read_number_as_string(struct cpp_demangle_data *ddata, char **str) +{ + long n; + + if (!cpp_demangle_read_number(ddata, &n)) { + *str = NULL; + return (0); + } + + if (asprintf(str, "%ld", n) < 0) { + *str = NULL; + return (0); + } + + return (1); +} + +static int cpp_demangle_read_nv_offset(struct cpp_demangle_data *ddata) { @@ -1581,9 +1839,18 @@ static int cpp_demangle_read_sname(struct cpp_demangle_data *ddata) { long len; + int err; if (ddata == NULL || cpp_demangle_read_number(ddata, &len) == 0 || - len <= 0 || cpp_demangle_push_str(ddata, ddata->cur, len) == 0) + len <= 0) + return (0); + + if (len == 12 && (memcmp("_GLOBAL__N_1", ddata->cur, 12) == 0)) + err = cpp_demangle_push_str(ddata, "(anonymous namespace)", 21); + else + err = cpp_demangle_push_str(ddata, ddata->cur, len); + + if (err == 0) return (0); assert(ddata->output.size > 0); @@ -1732,8 +1999,7 @@ cpp_demangle_read_subst_std(struct cpp_demangle_data *ddata) ddata->cur += 2; - output = cpp_demangle_gnu3_push_head > 0 ? - &ddata->output_tmp : &ddata->output; + output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output; p_idx = output->size; if (!cpp_demangle_read_uqname(ddata)) @@ -1783,8 +2049,7 @@ cpp_demangle_read_subst_stdtmpl(struct cpp_demangle_data *ddata, if (ddata == NULL || str == NULL || len == 0) return (0); - output = cpp_demangle_gnu3_push_head > 0 ? &ddata->output_tmp : - &ddata->output; + output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output; p_idx = output->size; substr = NULL; @@ -1852,8 +2117,7 @@ cpp_demangle_read_tmpl_args(struct cpp_demangle_data *ddata) return (0); limit = 0; - v = cpp_demangle_gnu3_push_head > 0 ? - &ddata->output_tmp : &ddata->output; + v = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output; for (;;) { idx = v->size; if (!cpp_demangle_read_tmpl_arg(ddata)) @@ -1936,14 +2200,14 @@ cpp_demangle_read_type(struct cpp_demangle_data *ddata, int delimit) size_t p_idx, type_str_len; int extern_c, is_builtin; long len; - char *type_str; + char *type_str, *exp_str, *num_str; if (ddata == NULL) return (0); output = &ddata->output; if (!strncmp(ddata->output.container[ddata->output.size - 1], ">", 1)) { - cpp_demangle_gnu3_push_head++; + ddata->push_head++; output = &ddata->output_tmp; } else if (delimit == 1) { if (ddata->paren == false) { @@ -1978,7 +2242,7 @@ cpp_demangle_read_type(struct cpp_demangle_data *ddata, int delimit) extern_c = 0; is_builtin = 1; p_idx = output->size; - type_str = NULL; + type_str = exp_str = num_str = NULL; again: /* builtin type */ switch (*ddata->cur) { @@ -2024,6 +2288,82 @@ again: ++ddata->cur; goto rtn; + case 'D': + ++ddata->cur; + switch (*ddata->cur) { + case 'd': + /* IEEE 754r decimal floating point (64 bits) */ + if (!cpp_demangle_push_str(ddata, "decimal64", 9)) + goto clean; + ++ddata->cur; + break; + case 'e': + /* IEEE 754r decimal floating point (128 bits) */ + if (!cpp_demangle_push_str(ddata, "decimal128", 10)) + goto clean; + ++ddata->cur; + break; + case 'f': + /* IEEE 754r decimal floating point (32 bits) */ + if (!cpp_demangle_push_str(ddata, "decimal32", 9)) + goto clean; + ++ddata->cur; + break; + case 'h': + /* IEEE 754r half-precision floating point (16 bits) */ + if (!cpp_demangle_push_str(ddata, "half", 4)) + goto clean; + ++ddata->cur; + break; + case 'i': + /* char32_t */ + if (!cpp_demangle_push_str(ddata, "char32_t", 8)) + goto clean; + ++ddata->cur; + break; + case 'n': + /* std::nullptr_t (i.e., decltype(nullptr)) */ + if (!cpp_demangle_push_str(ddata, "decltype(nullptr)", + 17)) + goto clean; + ++ddata->cur; + break; + case 's': + /* char16_t */ + if (!cpp_demangle_push_str(ddata, "char16_t", 8)) + goto clean; + ++ddata->cur; + break; + case 'v': + /* gcc vector_size extension. */ + ++ddata->cur; + if (*ddata->cur == '_') { + ++ddata->cur; + if (!cpp_demangle_read_expression_flat(ddata, + &exp_str)) + goto clean; + if (!vector_str_push(&v.ext_name, exp_str, + strlen(exp_str))) + goto clean; + } else { + if (!cpp_demangle_read_number_as_string(ddata, + &num_str)) + goto clean; + if (!vector_str_push(&v.ext_name, num_str, + strlen(num_str))) + goto clean; + } + if (*ddata->cur != '_') + goto clean; + ++ddata->cur; + if (!vector_type_qualifier_push(&v, TYPE_VEC)) + goto clean; + goto again; + default: + goto clean; + } + goto rtn; + case 'e': /* long double */ if (!cpp_demangle_push_str(ddata, "long double", 11)) @@ -2118,7 +2458,7 @@ again: case 'o': /* unsigned __int128 */ - if (!cpp_demangle_push_str(ddata, "unsigned _;int128", 17)) + if (!cpp_demangle_push_str(ddata, "unsigned __int128", 17)) goto clean; ++ddata->cur; goto rtn; @@ -2189,6 +2529,8 @@ again: if (!vector_str_push(&v.ext_name, ddata->cur, len)) return (0); ddata->cur += len; + if (!vector_type_qualifier_push(&v, TYPE_EXT)) + goto clean; goto again; case 'v': @@ -2253,14 +2595,16 @@ rtn: goto clean; free(type_str); + free(exp_str); + free(num_str); vector_type_qualifier_dest(&v); - if (cpp_demangle_gnu3_push_head > 0) { + if (ddata->push_head > 0) { if (*ddata->cur == 'I' && cpp_demangle_read_tmpl_args(ddata) == 0) return (0); - if (--cpp_demangle_gnu3_push_head > 0) + if (--ddata->push_head > 0) return (1); if (!vector_str_push(&ddata->output_tmp, " ", 1)) @@ -2284,11 +2628,45 @@ rtn: return (1); clean: free(type_str); + free(exp_str); + free(num_str); vector_type_qualifier_dest(&v); return (0); } +static int +cpp_demangle_read_type_flat(struct cpp_demangle_data *ddata, char **str) +{ + struct vector_str *output; + size_t i, p_idx, idx, type_len; + char *type; + + output = ddata->push_head > 0 ? &ddata->output_tmp : + &ddata->output; + + p_idx = output->size; + + if (!cpp_demangle_read_type(ddata, 0)) + return (0); + + if ((type = vector_str_substr(output, p_idx, output->size - 1, + &type_len)) == NULL) + return (0); + + idx = output->size; + for (i = p_idx; i < idx; ++i) { + if (!vector_str_pop(output)) { + free(type); + return (0); + } + } + + *str = type; + + return (1); +} + /* * read unqualified-name, unqualified name are operator-name, ctor-dtor-name, * source-name diff --git a/contrib/elftoolchain/libelftc/os.Linux.mk b/contrib/elftoolchain/libelftc/os.Linux.mk index 9730bf6..d99117d 100644 --- a/contrib/elftoolchain/libelftc/os.Linux.mk +++ b/contrib/elftoolchain/libelftc/os.Linux.mk @@ -1,3 +1,3 @@ -# $Id: os.Linux.mk 994 2010-06-13 10:39:19Z jkoshy $ +# $Id: os.Linux.mk 3210 2015-05-17 13:40:49Z kaiwang27 $ -CFLAGS+= -Wall +CFLAGS+= -Wall -D_GNU_SOURCE diff --git a/contrib/elftoolchain/readelf/readelf.1 b/contrib/elftoolchain/readelf/readelf.1 index a71e85f..701d500 100644 --- a/contrib/elftoolchain/readelf/readelf.1 +++ b/contrib/elftoolchain/readelf/readelf.1 @@ -22,7 +22,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $Id: readelf.1 3195 2015-05-12 17:22:19Z emaste $ +.\" $Id: readelf.1 3219 2015-05-24 23:42:34Z kaiwang27 $ .\" .Dd September 13, 2012 .Os @@ -90,7 +90,7 @@ sections in the ELF object. .It Fl e | Fl -headers Print all program, file and section headers in the ELF object. .It Fl g | Fl -section-groups -This option is recognized, but is ignored. +Print the contents of the section groups in the ELF object. .It Fl h | Fl -file-header Print the file header of the ELF object. .It Fl l | Fl -program-headers diff --git a/contrib/elftoolchain/readelf/readelf.c b/contrib/elftoolchain/readelf/readelf.c index 29bc389..b1b81a3 100644 --- a/contrib/elftoolchain/readelf/readelf.c +++ b/contrib/elftoolchain/readelf/readelf.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2009-2014 Kai Wang + * Copyright (c) 2009-2015 Kai Wang * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,7 +46,7 @@ #include "_elftc.h" -ELFTC_VCSID("$Id: readelf.c 3189 2015-04-20 17:02:01Z emaste $"); +ELFTC_VCSID("$Id: readelf.c 3223 2015-05-25 20:37:57Z emaste $"); /* * readelf(1) options. @@ -302,6 +302,7 @@ static void dump_gnu_hash(struct readelf *re, struct section *s); static void dump_hash(struct readelf *re); static void dump_phdr(struct readelf *re); static void dump_ppc_attributes(uint8_t *p, uint8_t *pe); +static void dump_section_groups(struct readelf *re); static void dump_symtab(struct readelf *re, int i); static void dump_symtabs(struct readelf *re); static uint8_t *dump_unknown_tag(uint64_t tag, uint8_t *p); @@ -445,6 +446,7 @@ elf_machine(unsigned int mach) case EM_SPARC: return "Sun SPARC"; case EM_386: return "Intel i386"; case EM_68K: return "Motorola 68000"; + case EM_IAMCU: return "Intel MCU"; case EM_88K: return "Motorola 88000"; case EM_860: return "Intel i860"; case EM_MIPS: return "MIPS R3000 Big-Endian only"; @@ -1050,6 +1052,7 @@ r_type(unsigned int mach, unsigned int type) switch(mach) { case EM_NONE: return ""; case EM_386: + case EM_IAMCU: switch(type) { case 0: return "R_386_NONE"; case 1: return "R_386_32"; @@ -2381,6 +2384,7 @@ dwarf_reg(unsigned int mach, unsigned int reg) switch (mach) { case EM_386: + case EM_IAMCU: switch (reg) { case 0: return "eax"; case 1: return "ecx"; @@ -4047,6 +4051,61 @@ dump_liblist(struct readelf *re) #undef Elf_Lib +static void +dump_section_groups(struct readelf *re) +{ + struct section *s; + const char *symname; + Elf_Data *d; + uint32_t *w; + int i, j, elferr; + size_t n; + + for (i = 0; (size_t) i < re->shnum; i++) { + s = &re->sl[i]; + if (s->type != SHT_GROUP) + continue; + (void) elf_errno(); + if ((d = elf_getdata(s->scn, NULL)) == NULL) { + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_getdata failed: %s", + elf_errmsg(elferr)); + continue; + } + if (d->d_size <= 0) + continue; + + w = d->d_buf; + + /* We only support COMDAT section. */ +#ifndef GRP_COMDAT +#define GRP_COMDAT 0x1 +#endif + if ((*w++ & GRP_COMDAT) == 0) + return; + + if (s->entsize == 0) + s->entsize = 4; + + symname = get_symbol_name(re, s->link, s->info); + n = s->sz / s->entsize; + if (n-- < 1) + return; + + printf("\nCOMDAT group section [%5d] `%s' [%s] contains %ju" + " sections:\n", i, s->name, symname, (uintmax_t)n); + printf(" %-10.10s %s\n", "[Index]", "Name"); + for (j = 0; (size_t) j < n; j++, w++) { + if (*w >= re->shnum) { + warnx("invalid section index: %u", *w); + continue; + } + printf(" [%5u] %s\n", *w, re->sl[*w].name); + } + } +} + static uint8_t * dump_unknown_tag(uint64_t tag, uint8_t *p) { @@ -6838,6 +6897,8 @@ dump_elf(struct readelf *re) dump_phdr(re); if (re->options & RE_SS) dump_shdr(re); + if (re->options & RE_G) + dump_section_groups(re); if (re->options & RE_D) dump_dynamic(re); if (re->options & RE_R) @@ -7311,7 +7372,7 @@ Usage: %s [options] file...\n\ -c | --archive-index Print the archive symbol table for archives.\n\ -d | --dynamic Print the contents of SHT_DYNAMIC sections.\n\ -e | --headers Print all headers in the object.\n\ - -g | --section-groups (accepted, but ignored)\n\ + -g | --section-groups Print the contents of the section groups.\n\ -h | --file-header Print the file header for the object.\n\ -l | --program-headers Print the PHDR table for the object.\n\ -n | --notes Print the contents of SHT_NOTE sections.\n\ @@ -7365,8 +7426,8 @@ main(int argc, char **argv) re->options |= RE_AA; break; case 'a': - re->options |= RE_AA | RE_D | RE_H | RE_II | RE_L | - RE_R | RE_SS | RE_S | RE_VV; + re->options |= RE_AA | RE_D | RE_G | RE_H | RE_II | + RE_L | RE_R | RE_SS | RE_S | RE_VV; break; case 'c': re->options |= RE_C; diff --git a/lib/libc/gen/fpclassify.c b/lib/libc/gen/fpclassify.c index 754a1df..444b551 100644 --- a/lib/libc/gen/fpclassify.c +++ b/lib/libc/gen/fpclassify.c @@ -29,6 +29,8 @@ #include <sys/endian.h> +#include <machine/float.h> + #include <math.h> #include <stdint.h> @@ -84,10 +86,18 @@ __fpclassifyl(long double e) return (FP_SUBNORMAL); } mask_nbit_l(u); /* Mask normalization bit if applicable. */ +#if LDBL_MANT_DIG == 53 + if (u.bits.exp == 2047) { + if ((u.bits.manl | u.bits.manh) == 0) + return (FP_INFINITE); + return (FP_NAN); + } +#else if (u.bits.exp == 32767) { if ((u.bits.manl | u.bits.manh) == 0) return (FP_INFINITE); return (FP_NAN); } +#endif return (FP_NORMAL); } diff --git a/lib/libc/gen/isinf.c b/lib/libc/gen/isinf.c index 4a4152a..0eb8b9f 100644 --- a/lib/libc/gen/isinf.c +++ b/lib/libc/gen/isinf.c @@ -26,6 +26,8 @@ * $FreeBSD$ */ +#include <machine/float.h> + #include <math.h> #include "fpmath.h" @@ -62,9 +64,9 @@ __isinfl(long double e) u.e = e; mask_nbit_l(u); -#ifndef __alpha__ - return (u.bits.exp == 32767 && u.bits.manl == 0 && u.bits.manh == 0); -#else +#if LDBL_MANT_DIG == 53 return (u.bits.exp == 2047 && u.bits.manl == 0 && u.bits.manh == 0); +#else + return (u.bits.exp == 32767 && u.bits.manl == 0 && u.bits.manh == 0); #endif } diff --git a/lib/libc/mips/sys/Makefile.inc b/lib/libc/mips/sys/Makefile.inc index 460e69b..c0bd5ad9 100644 --- a/lib/libc/mips/sys/Makefile.inc +++ b/lib/libc/mips/sys/Makefile.inc @@ -3,7 +3,7 @@ SRCS+= trivial-vdso_tc.c MDASM= Ovfork.S brk.S cerror.S exect.S \ - fork.S pipe.S ptrace.S sbrk.S syscall.S + pipe.S ptrace.S sbrk.S syscall.S # Don't generate default code for these syscalls: NOASM= break.o exit.o getlogin.o openbsd_poll.o sstk.o vfork.o yield.o diff --git a/lib/libc/mips/sys/fork.S b/lib/libc/mips/sys/fork.S deleted file mode 100644 index 7636bd3..0000000 --- a/lib/libc/mips/sys/fork.S +++ /dev/null @@ -1,57 +0,0 @@ -/* $NetBSD: fork.S,v 1.11 2003/08/07 16:42:17 agc Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Ralph Campbell. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. 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. - */ - -#include <machine/asm.h> -__FBSDID("$FreeBSD$"); -#include "SYS.h" - -#if defined(LIBC_SCCS) && !defined(lint) - ASMSTR("from: @(#)fork.s 8.1 (Berkeley) 6/4/93") - ASMSTR("$NetBSD: fork.S,v 1.11 2003/08/07 16:42:17 agc Exp $") -#endif /* LIBC_SCCS and not lint */ - -LEAF(__sys_fork) - WEAK_ALIAS(fork, __sys_fork) - WEAK_ALIAS(_fork, __sys_fork) - PIC_PROLOGUE(__sys_fork) - li v0, SYS_fork # pid = fork() - syscall - bne a3, zero, 2f - beq v1, zero, 1f # v1 == 0 in parent, 1 in child - move v0, zero -1: - PIC_RETURN() -2: - PIC_TAILCALL(__cerror) -END(__sys_fork) diff --git a/lib/libelftc/elftc_version.c b/lib/libelftc/elftc_version.c index fb0a731..e8a11d4 100644 --- a/lib/libelftc/elftc_version.c +++ b/lib/libelftc/elftc_version.c @@ -6,5 +6,5 @@ const char * elftc_version(void) { - return "elftoolchain r3197M"; + return "elftoolchain r3223M"; } diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile index 7e5f1a3..2f68628 100644 --- a/lib/libutil/Makefile +++ b/lib/libutil/Makefile @@ -10,7 +10,8 @@ SHLIB_MAJOR= 9 SRCS= _secure_path.c auth.c expand_number.c flopen.c fparseln.c gr_util.c \ hexdump.c humanize_number.c kinfo_getfile.c kinfo_getfile.c \ - kinfo_getallproc.c kinfo_getproc.c kinfo_getvmmap.c kld.c \ + kinfo_getallproc.c kinfo_getproc.c kinfo_getvmmap.c \ + kinfo_getvmobject.c kld.c \ login_auth.c login_cap.c \ login_class.c login_crypt.c login_ok.c login_times.c login_tty.c \ pidfile.c property.c pty.c pw_util.c quotafile.c realhostname.c \ @@ -27,7 +28,8 @@ CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../libc/gen/ MAN+= expand_number.3 flopen.3 fparseln.3 hexdump.3 \ humanize_number.3 kinfo_getallproc.3 kinfo_getfile.3 \ - kinfo_getproc.3 kinfo_getvmmap.3 kld.3 login_auth.3 login_cap.3 \ + kinfo_getproc.3 kinfo_getvmmap.3 kinfo_getvmobject.3 kld.3 \ + login_auth.3 login_cap.3 \ login_class.3 login_ok.3 login_times.3 login_tty.3 pidfile.3 \ property.3 pty.3 quotafile.3 realhostname.3 realhostname_sa.3 \ _secure_path.3 trimdomain.3 uucplock.3 pw_util.3 diff --git a/lib/libutil/kinfo_getallproc.3 b/lib/libutil/kinfo_getallproc.3 index 56d4ad6..7005d4f 100644 --- a/lib/libutil/kinfo_getallproc.3 +++ b/lib/libutil/kinfo_getallproc.3 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 9, 2009 +.Dd May 27, 2015 .Dt KINFO_GETALLPROC 3 .Os .Sh NAME @@ -35,6 +35,7 @@ .Lb libutil .Sh SYNOPSIS .In sys/types.h +.In sys/user.h .In libutil.h .Ft struct kinfo_proc * .Fn kinfo_getallproc "int *cntp" diff --git a/lib/libutil/kinfo_getfile.3 b/lib/libutil/kinfo_getfile.3 index 1e0bab7..2a35687 100644 --- a/lib/libutil/kinfo_getfile.3 +++ b/lib/libutil/kinfo_getfile.3 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 6, 2008 +.Dd May 27, 2015 .Dt KINFO_GETFILE 3 .Os .Sh NAME @@ -35,6 +35,7 @@ .Lb libutil .Sh SYNOPSIS .In sys/types.h +.In sys/user.h .In libutil.h .Ft struct kinfo_file * .Fn kinfo_getfile "pid_t pid" "int *cntp" diff --git a/lib/libutil/kinfo_getproc.3 b/lib/libutil/kinfo_getproc.3 index 804cb6c..f5ccbc5 100644 --- a/lib/libutil/kinfo_getproc.3 +++ b/lib/libutil/kinfo_getproc.3 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 1, 2013 +.Dd May 27, 2015 .Dt KINFO_GETPROC 3 .Os .Sh NAME @@ -35,6 +35,7 @@ .Lb libutil .Sh SYNOPSIS .In sys/types.h +.In sys/user.h .In libutil.h .Ft struct kinfo_proc * .Fn kinfo_getproc "pid_t pid" diff --git a/lib/libutil/kinfo_getvmmap.3 b/lib/libutil/kinfo_getvmmap.3 index 165de60..c6a1370 100644 --- a/lib/libutil/kinfo_getvmmap.3 +++ b/lib/libutil/kinfo_getvmmap.3 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 6, 2008 +.Dd May 27, 2015 .Dt KINFO_GETVMMAP 3 .Os .Sh NAME @@ -35,6 +35,7 @@ .Lb libutil .Sh SYNOPSIS .In sys/types.h +.In sys/user.h .In libutil.h .Ft struct kinfo_vmentry * .Fn kinfo_getvmmap "pid_t pid" "int *cntp" diff --git a/lib/libutil/kinfo_getvmobject.3 b/lib/libutil/kinfo_getvmobject.3 new file mode 100644 index 0000000..dc0edd2 --- /dev/null +++ b/lib/libutil/kinfo_getvmobject.3 @@ -0,0 +1,74 @@ +.\" +.\" Copyright (c) 2015 John Baldwin <jhb@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd May 27, 2015 +.Dt KINFO_GETVMOBJECT 3 +.Os +.Sh NAME +.Nm kinfo_getvmobject +.Nd function for getting system-wide memory information +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.In sys/types.h +.In sys/user.h +.In libutil.h +.Ft struct kinfo_vmobject * +.Fn kinfo_getvmobject "int *cntp" +.Sh DESCRIPTION +This function is used to obtain information about the objects using memory +in the system. +.Pp +The +.Ar cntp +argument allows the caller to know how many records are returned. +.Pp +This function is a wrapper around the +.Dq vm.objects +.Xr sysctl 3 +MIB. +While the kernel returns a packed structure, this function expands the +data into a fixed record format. +.Sh RETURN VALUES +On success the +.Fn kinfo_getvmobject +function returns a pointer to an array of +.Vt struct kinfo_vmobject +structures as defined by +.In sys/user.h . +The array is allocated by an internal call to +.Xr malloc 3 +and must be freed by the caller with a call to +.Xr free 3 . +On failure the +.Fn kinfo_getvmobject +function returns +.Dv NULL . +.Sh SEE ALSO +.Xr free 3 , +.Xr kinfo_getvmmap 3 , +.Xr malloc 3 diff --git a/lib/libutil/kinfo_getvmobject.c b/lib/libutil/kinfo_getvmobject.c new file mode 100644 index 0000000..7e031da --- /dev/null +++ b/lib/libutil/kinfo_getvmobject.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2013 Hudson River Trading LLC + * Written by: John H. Baldwin <jhb@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/sysctl.h> +#include <sys/user.h> +#include <stdlib.h> +#include <string.h> + +#include "libutil.h" + +struct kinfo_vmobject * +kinfo_getvmobject(int *cntp) +{ + char *buf, *bp, *ep; + struct kinfo_vmobject *kvo, *list, *kp; + size_t len; + int cnt, i; + + buf = NULL; + for (i = 0; i < 3; i++) { + if (sysctlbyname("vm.objects", NULL, &len, NULL, 0) < 0) + return (NULL); + buf = reallocf(buf, len); + if (buf == NULL) + return (NULL); + if (sysctlbyname("vm.objects", buf, &len, NULL, 0) == 0) + goto unpack; + if (errno != ENOMEM) { + free(buf); + return (NULL); + } + } + free(buf); + return (NULL); + +unpack: + /* Count items */ + cnt = 0; + bp = buf; + ep = buf + len; + while (bp < ep) { + kvo = (struct kinfo_vmobject *)(uintptr_t)bp; + bp += kvo->kvo_structsize; + cnt++; + } + + list = calloc(cnt, sizeof(*list)); + if (list == NULL) { + free(buf); + return (NULL); + } + + /* Unpack */ + bp = buf; + kp = list; + while (bp < ep) { + kvo = (struct kinfo_vmobject *)(uintptr_t)bp; + memcpy(kp, kvo, kvo->kvo_structsize); + bp += kvo->kvo_structsize; + kp->kvo_structsize = sizeof(*kp); + kp++; + } + free(buf); + *cntp = cnt; + return (list); +} diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h index b8b9836..b20ffa2 100644 --- a/lib/libutil/libutil.h +++ b/lib/libutil/libutil.h @@ -102,6 +102,8 @@ struct kinfo_file * kinfo_getfile(pid_t _pid, int *_cntp); struct kinfo_vmentry * kinfo_getvmmap(pid_t _pid, int *_cntp); +struct kinfo_vmobject * + kinfo_getvmobject(int *_cntp); struct kinfo_proc * kinfo_getallproc(int *_cntp); struct kinfo_proc * diff --git a/release/Makefile.mirrors b/release/Makefile.mirrors index a050444..ed10c55 100644 --- a/release/Makefile.mirrors +++ b/release/Makefile.mirrors @@ -49,7 +49,7 @@ BUILDDATE!= cd ${.CURDIR} && date -j -f '%s' $$(stat -f "%c" ${.OBJDIR}/dist/ba BUILDDATE!= date +%Y%m%d . endif . endif -_SNAP_SUFFIX:= -r${SVNREVISION}-${BUILDDATE} +_SNAP_SUFFIX:= ${BUILDDATE}-r${SVNREVISION} .else # release SNAPSHOT= diff --git a/release/arm/PANDABOARD.conf b/release/arm/PANDABOARD.conf index b5a120e..6b75566 100644 --- a/release/arm/PANDABOARD.conf +++ b/release/arm/PANDABOARD.conf @@ -8,13 +8,13 @@ EMBEDDED_TARGET="arm" EMBEDDED_TARGET_ARCH="armv6" EMBEDDEDPORTS="sysutils/u-boot-pandaboard" KERNEL="PANDABOARD" -NODOC=1 WORLD_FLAGS="${WORLD_FLAGS} UBLDR_LOADADDR=0x88000000" IMAGE_SIZE="1G" PART_SCHEME="MBR" FAT_SIZE="2m" FAT_TYPE="12" MD_ARGS="-x 63 -y 255" +NODOC=1 arm_install_uboot() { UBOOT_DIR="/usr/local/share/u-boot/u-boot-pandaboard" diff --git a/release/arm/RPI2.conf b/release/arm/RPI2.conf index e1d15d1..2da7e96 100644 --- a/release/arm/RPI2.conf +++ b/release/arm/RPI2.conf @@ -8,13 +8,13 @@ EMBEDDED_TARGET="arm" EMBEDDED_TARGET_ARCH="armv6" EMBEDDEDPORTS="sysutils/u-boot-rpi2" KERNEL="RPI2" -NODOC=1 WORLD_FLAGS="${WORLD_FLAGS} UBLDR_LOADADDR=0x2000000" IMAGE_SIZE="1G" PART_SCHEME="MBR" FAT_SIZE="50m" FAT_TYPE="16" MD_ARGS="-x 63 -y 255" +NODOC=1 arm_install_uboot() { UBOOT_DIR="/usr/local/share/u-boot/u-boot-rpi2" diff --git a/release/arm/WANDBOARD.conf b/release/arm/WANDBOARD.conf index 42b4523..7ea3807 100644 --- a/release/arm/WANDBOARD.conf +++ b/release/arm/WANDBOARD.conf @@ -15,6 +15,7 @@ FAT_SIZE="50m -b 16384" FAT_TYPE="16" MD_ARGS="-x 63 -y 255" NODOC=1 +export BOARDNAME="WANDBOARD" arm_install_uboot() { UBOOT_DIR="/usr/local/share/u-boot/u-boot-wandboard" diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c index 22b21f1..7905813 100644 --- a/sbin/dhclient/dhclient.c +++ b/sbin/dhclient/dhclient.c @@ -1845,12 +1845,16 @@ rewrite_client_leases(void) leaseFile = fopen(path_dhclient_db, "w"); if (!leaseFile) error("can't create %s: %m", path_dhclient_db); - cap_rights_init(&rights, CAP_FSTAT, CAP_FSYNC, CAP_FTRUNCATE, - CAP_SEEK, CAP_WRITE); + cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_FSYNC, + CAP_FTRUNCATE, CAP_SEEK, CAP_WRITE); if (cap_rights_limit(fileno(leaseFile), &rights) < 0 && errno != ENOSYS) { error("can't limit lease descriptor: %m"); } + if (cap_fcntls_limit(fileno(leaseFile), CAP_FCNTL_GETFL) < 0 && + errno != ENOSYS) { + error("can't limit lease descriptor fcntls: %m"); + } } else { fflush(leaseFile); rewind(leaseFile); diff --git a/share/man/man3/pthread_setspecific.3 b/share/man/man3/pthread_setspecific.3 index 1ea3002..3153c99 100644 --- a/share/man/man3/pthread_setspecific.3 +++ b/share/man/man3/pthread_setspecific.3 @@ -67,7 +67,10 @@ is undefined. The .Fn pthread_setspecific function may be called from a thread-specific data destructor function, -however this may result in lost storage or infinite loops. +however this may result in lost storage or infinite loops if doing so +causes non-NULL key values to remain after +.Bq PTHREAD_DESTRUCTOR_ITERATIONS +iterations of destructor calls have been made. .Sh RETURN VALUES If successful, the .Fn pthread_setspecific diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 4291e7a..b892cbc 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -192,6 +192,7 @@ MAN= aac.4 \ icmp6.4 \ ida.4 \ ifmib.4 \ + ig4.4 \ igb.4 \ igmp.4 \ iic.4 \ diff --git a/share/man/man4/ig4.4 b/share/man/man4/ig4.4 new file mode 100644 index 0000000..d4d7300 --- /dev/null +++ b/share/man/man4/ig4.4 @@ -0,0 +1,79 @@ +.\" Copyright (c) 2015 Michael Gmelin <freebsd@grem.de> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd May 30, 2015 +.Dt IG4 4 +.Os +.Sh NAME +.Nm ig4 +.Nd Intel(R) fourth generation mobile CPU integrated I2C SMBus driver +.Sh SYNOPSIS +To compile this driver into the kernel, place the following lines into +the kernel configuration file: +.Bd -ragged -offset indent +.Cd "device ig4" +.Cd "device smbus" +.Ed +.Pp +Alternatively, to load the driver as a module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +ig4_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides access to peripherals attached to an I2C SMB controller. +.Nm +supports the SMBus controller found in fourth generation Intel(R) Core(TM) +processors based on the mobile U-processor line for intelligent systems. +This includes the i7-4650U, i5-4300U, i3-4010U, and 2980U. +.Sh SYSCTL VARIABLES +These +.Xr sysctl 8 +variables are available: +.Bl -tag -width "debug.ig4_dump" +.It Va debug.ig4_dump +Setting this to a non-zero value dumps controller registers to console and +syslog once. +The sysctl resets to zero immediately. +.El +.Sh SEE ALSO +.Xr smb 4 , +.Xr smbus 4 +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written for DragonFly BSD by +.An Matthew Dillon +and subsequently ported to +.Fx +by +.An Michael Gmelin Aq Mt freebsd@grem.de . +.Pp +This manual page was written by +.An Michael Gmelin Aq Mt freebsd@grem.de . diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index 11dcb01..d0e204f 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -195,10 +195,10 @@ MAN= accept_filter.9 \ p_candebug.9 \ p_cansee.9 \ pci.9 \ - PCI_ADD_VF.9 \ - PCI_INIT_IOV.9 \ + PCI_IOV_ADD_VF.9 \ + PCI_IOV_INIT.9 \ pci_iov_schema.9 \ - PCI_UNINIT_IOV.9 \ + PCI_IOV_UNINIT.9 \ pfil.9 \ pfind.9 \ pget.9 \ diff --git a/share/man/man9/PCI_ADD_VF.9 b/share/man/man9/PCI_IOV_ADD_VF.9 index 72a3a97..d99a106 100644 --- a/share/man/man9/PCI_ADD_VF.9 +++ b/share/man/man9/PCI_IOV_ADD_VF.9 @@ -25,38 +25,37 @@ .\" .\" $FreeBSD$ .\" -.Dd May 24, 2014 -.Dt PCI_ADD_VF 9 +.Dd May 28, 2015 +.Dt PCI_IOV_ADD_VF 9 .Os .Sh NAME -.Nm PCI_ADD_VF +.Nm PCI_IOV_ADD_VF .Nd inform a PF driver that a VF is being created .Sh SYNOPSIS .In sys/bus.h .In machine/stdarg.h .In sys/nv.h -.In dev/pci/pcireg.h -.In dev/pci/pcivar.h +.In dev/pci/pci_iov.h .Ft int -.Fn PCI_ADD_VF "device_t dev" "uint16_t vfnum" "const nvlist_t *vf_config" +.Fn PCI_IOV_ADD_VF "device_t dev" "uint16_t vfnum" "const nvlist_t *vf_config" .Sh DESCRIPTION The -.Fn PCI_ADD_VF +.Fn PCI_IOV_ADD_VF method is called by the PCI Single-Root I/O Virtualization .Pq SR-IOV infrastructure when it is initializating a new Virtual Function (VF) as a child of the given Physical Function (PF) device. This method will not be called until a successful call to -.Xr PCI_INIT_IOV 9 +.Xr PCI_IOV_INIT 9 has been made. It is not guaranteed that this method will be called following a successful call to -.Xr PCI_INIT_IOV 9 . +.Xr PCI_IOV_INIT 9 . If the infrastructure encounters a failure to allocate resources following the call to -.Xr PCI_INIT_IOV 9 , +.Xr PCI_IOV_INIT 9 , the VF creation will be aborted and -.Xr PCI_UNINIT_IOV 9 +.Xr PCI_IOV_UNINIT 9 will be called immediately without any preceding calls to .Nm . .Pp @@ -87,15 +86,15 @@ Note that it is possible for the user to set different configuration values on different VF devices that are children of the same PF. The PF driver must not cache configuration parameters passed in previous calls to -.Fn PCI_ADD_VF +.Fn PCI_IOV_ADD_VF for other VFs and apply those parameters to the current VF. .Pp This function will not be called twice for the same .Fa vf_num on the same PF device without -.Xr PCI_UNINIT_IOV 9 +.Xr PCI_IOV_UNINIT 9 and -.Xr PCI_INIT_IOV 9 +.Xr PCI_IOV_INIT 9 first being called, in that order. .Sh RETURN VALUES This method returns 0 on success, otherwise an appropriate error is returned. @@ -106,8 +105,8 @@ the PF. .Xr nv 9 , .Xr pci 9 , .Xr pci_iov_schema 9 , -.Xr PCI_INIT_IOV 9 , -.Xr PCI_UNINIT_IOV 9 +.Xr PCI_IOV_INIT 9 , +.Xr PCI_IOV_UNINIT 9 .Sh AUTHORS This manual page was written by .An Ryan Stone Aq Mt rstone@FreeBSD.org . diff --git a/share/man/man9/PCI_INIT_IOV.9 b/share/man/man9/PCI_IOV_INIT.9 index 1c8c64e..f9daa24 100644 --- a/share/man/man9/PCI_INIT_IOV.9 +++ b/share/man/man9/PCI_IOV_INIT.9 @@ -25,23 +25,22 @@ .\" .\" $FreeBSD$ .\" -.Dd May 24, 2014 -.Dt PCI_INIT_IOV 9 +.Dd May 28, 2015 +.Dt PCI_IOV_INIT 9 .Os .Sh NAME -.Nm PCI_INIT_IOV +.Nm PCI_IOV_INIT .Nd enable SR-IOV on a PF device .Sh SYNOPSIS .In sys/bus.h .In machine/stdarg.h .In sys/nv.h -.In dev/pci/pcireg.h -.In dev/pci/pcivar.h +.In dev/pci/pci_iov.h .Ft int -.Fn PCI_INIT_IOV "device_t dev" "uint16_t num_vfs" "const nvlist_t *pf_config" +.Fn PCI_IOV_INIT "device_t dev" "uint16_t num_vfs" "const nvlist_t *pf_config" .Sh DESCRIPTION The -.Fn PCI_INIT_IOV +.Fn PCI_IOV_INIT method is called by the PCI Single-Root I/O Virtualization (SR-IOV) infrastucture when the user requests that SR-IOV be enabled on a Physical Function (PF). @@ -70,7 +69,7 @@ valid values specified in the schema. .Pp If this method returns successfully, then this method will not be called again on the same device until after a call to -.Xr PCI_UNINIT_IOV . +.Xr PCI_IOV_UNINIT . .Sh RETURN VALUES Returns 0 on success, otherwise an appropriate error is returned. If this method returns an error then the SR-IOV configuration will be aborted @@ -79,8 +78,8 @@ and no VFs will be created. .Xr nv 9 , .Xr pci 9 , .Xr pci_iov_schema 9 , -.Xr PCI_ADD_VF 9 , -.Xr PCI_UNINIT_IOV 9 +.Xr PCI_IOV_ADD_VF 9 , +.Xr PCI_IOV_UNINIT 9 .Sh AUTHORS This manual page was written by .An Ryan Stone Aq Mt rstone@FreeBSD.org . diff --git a/share/man/man9/PCI_UNINIT_IOV.9 b/share/man/man9/PCI_IOV_UNINIT.9 index fc4cc85..b95914e 100644 --- a/share/man/man9/PCI_UNINIT_IOV.9 +++ b/share/man/man9/PCI_IOV_UNINIT.9 @@ -25,21 +25,20 @@ .\" .\" $FreeBSD$ .\" -.Dd May 24, 2014 -.Dt PCI_UNINIT_IOV 9 +.Dd May 28, 2015 +.Dt PCI_IOV_UNINIT 9 .Os .Sh NAME -.Nm PCI_UNINIT_IOV +.Nm PCI_IOV_UNINIT .Nd disable SR-IOV on a PF device .Sh SYNOPSIS .In sys/bus.h -.In dev/pci/pcireg.h -.In dev/pci/pcivar.h +.In dev/pci/pci_iov.h .Ft void -.Fn PCI_UNINIT_IOV "device_t dev" +.Fn PCI_IOV_UNINIT "device_t dev" .Sh DESCRIPTION The -.Fn PCI_UNINIT_IOV +.Fn PCI_IOV_UNINIT method is called by the PCI Single-Root I/O Virtualization (SR-IOV) infrastructure when the user requests that SR-IOV be disabled on a Physical Function (PF). @@ -48,17 +47,17 @@ resources that it has allocated and disable any device-specific SR-IOV configuration in the device. .Pp This method will only be called following a successful call to -.Xr PCI_INIT_IOV . +.Xr PCI_IOV_INIT . It is not guaranteed that -.Xr PCI_ADD_VF +.Xr PCI_IOV_ADD_VF will have been called for any Virtual Function (VF) after the call to -.Xr PCI_INIT_IOV +.Xr PCI_IOV_INIT and before the call to .Nm . .Sh SEE ALSO .Xr pci 9 , -.Xr PCI_ADD_VF 9 , -.Xr PCI_INIT_IOV 9 +.Xr PCI_IOV_ADD_VF 9 , +.Xr PCI_IOV_INIT 9 .Sh AUTHORS This manual page was written by .An Ryan Stone Aq Mt rstone@FreeBSD.org . diff --git a/share/man/man9/pci.9 b/share/man/man9/pci.9 index a33d2ed..14500b5 100644 --- a/share/man/man9/pci.9 +++ b/share/man/man9/pci.9 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 24, 2014 +.Dd May 28, 2015 .Dt PCI 9 .Os .Sh NAME @@ -97,10 +97,6 @@ .Ft int .Fn pci_get_vpd_readonly "device_t dev" "const char *kw" "const char **vptr" .Ft int -.Fn pci_iov_attach "device_t dev" "nvlist_t *pf_schema" "nvlist_t *vf_schema" -.Ft int -.Fn pci_iov_detach "device_t dev" -.Ft int .Fn pci_msi_count "device_t dev" .Ft int .Fn pci_msix_count "device_t dev" @@ -122,6 +118,11 @@ .Fn pci_set_powerstate "device_t dev" "int state" .Ft void .Fn pci_write_config "device_t dev" "int reg" "uint32_t val" "int width" +.In dev/pci/pci_iov.h +.Ft int +.Fn pci_iov_attach "device_t dev" "nvlist_t *pf_schema" "nvlist_t *vf_schema" +.Ft int +.Fn pci_iov_detach "device_t dev" .Sh DESCRIPTION The .Nm @@ -446,10 +447,10 @@ function is used to advertise that the given device supports PCI Single-Root I/O Virtualization .Po SR-IOV Pc . A driver that supports SR-IOV must implement the -.Xr PCI_INIT_IOV 9 , -.Xr PCI_ADD_VF 9 +.Xr PCI_IOV_INIT 9 , +.Xr PCI_IOV_ADD_VF 9 and -.Xr PCI_UNIT_IOV 9 +.Xr PCI_IOV_UNINIT 9 methods. This function should be called during the .Xr DEVICE_ATTACH 9 diff --git a/share/man/man9/pci_iov_schema.9 b/share/man/man9/pci_iov_schema.9 index f2f1f30..36c0189 100644 --- a/share/man/man9/pci_iov_schema.9 +++ b/share/man/man9/pci_iov_schema.9 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 25, 2014 +.Dd May 28, 2015 .Dt pci_iov_schema 9 .Os .Sh NAME @@ -258,8 +258,8 @@ The function returns a pointer to the allocated schema, or NULL if a failure occurs. .Sh SEE ALSO .Xr pci 9 , -.Xr PCI_ADD_VF 9 , -.Xr PCI_INIT_IOV 9 +.Xr PCI_IOV_ADD_VF 9 , +.Xr PCI_IOV_INIT 9 .Sh AUTHORS This manual page was written by .An Ryan Stone Aq rstone@FreeBSD.org . diff --git a/share/mk/src.libnames.mk b/share/mk/src.libnames.mk index bfb235c..e8c6dd2 100644 --- a/share/mk/src.libnames.mk +++ b/share/mk/src.libnames.mk @@ -9,8 +9,12 @@ .include <src.opts.mk> -ROOTSRCDIR= ${.MAKE.MAKEFILES:M*/src.libnames.mk:H:H:H} -ROOTOBJDIR= ${.OBJDIR:S/${.CURDIR}//}${ROOTSRCDIR} +.if ${.OBJDIR:S,${.CURDIR},,} != ${.OBJDIR} +ROOTOBJDIR= ${.OBJDIR:S,${.CURDIR},,}${SRCTOP} +.elif defined(OBJTOP) && ${.OBJDIR:M${OBJTOP}*} != "" +ROOTOBJDIR= ${OBJTOP} +.endif + _PRIVATELIBS= \ atf_c \ atf_cxx \ diff --git a/share/mk/src.sys.mk b/share/mk/src.sys.mk index 78a0c23..5804810 100644 --- a/share/mk/src.sys.mk +++ b/share/mk/src.sys.mk @@ -5,13 +5,16 @@ # to preserve historical (and useful) behavior. Changes here need to # be reflected there so SRCCONF isn't included multiple times. +# make sure this is defined in a consistent manner +SRCTOP:= ${.PARSEDIR:tA:H:H} + # Allow user to configure things that only effect src tree builds. SRCCONF?= /etc/src.conf .if (exists(${SRCCONF}) || ${SRCCONF} != "/etc/src.conf") && !target(_srcconf_included_) -.include "${SRCCONF}" +.sinclude "${SRCCONF}" _srcconf_included_: .NOTMAIN .endif -# If we were found via .../share/mk we need to replace that in +# If we were found via .../share/mk we need to replace that # with ${.PARSEDIR:tA} so that we can be found by # sub-makes launched from objdir. .if ${.MAKEFLAGS:M.../share/mk} != "" diff --git a/sys/Makefile b/sys/Makefile index 46d883e..7575746 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -8,9 +8,9 @@ CSCOPEDIRS= boot bsm cam cddl compat conf contrib crypto ddb dev fs gdb \ rpc security sys ufs vm xdr xen ${CSCOPE_ARCHDIR} .if !defined(CSCOPE_ARCHDIR) .if defined(ALL_ARCH) -CSCOPE_ARCHDIR = amd64 arm i386 mips pc98 powerpc sparc64 x86 +CSCOPE_ARCHDIR = amd64 arm arm64 i386 mips pc98 powerpc sparc64 x86 .else -CSCOPE_ARCHDIR = ${MACHINE} +CSCOPE_ARCHDIR = ${MACHINE} .if ${MACHINE} != ${MACHINE_CPUARCH} CSCOPE_ARCHDIR += ${MACHINE_CPUARCH} .endif diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index 118bb34..7f256cd 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -381,7 +381,7 @@ caddr_t CADDR1 = 0; static int pmap_flags = PMAP_PDE_SUPERPAGE; /* flags for x86 pmaps */ -int pmap_pcid_enabled = 0; +int pmap_pcid_enabled = 1; SYSCTL_INT(_vm_pmap, OID_AUTO, pcid_enabled, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, &pmap_pcid_enabled, 0, "Is TLB Context ID enabled ?"); int invpcid_works = 0; @@ -3935,7 +3935,6 @@ pmap_promote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va, pd_entry_t newpde; pt_entry_t *firstpte, oldpte, pa, *pte; pt_entry_t PG_G, PG_A, PG_M, PG_RW, PG_V; - vm_offset_t oldpteva; vm_page_t mpte; int PG_PTE_CACHE; @@ -3995,10 +3994,9 @@ setpte: if (!atomic_cmpset_long(pte, oldpte, oldpte & ~PG_RW)) goto setpte; oldpte &= ~PG_RW; - oldpteva = (oldpte & PG_FRAME & PDRMASK) | - (va & ~PDRMASK); CTR2(KTR_PMAP, "pmap_promote_pde: protect for va %#lx" - " in pmap %p", oldpteva, pmap); + " in pmap %p", (oldpte & PG_FRAME & PDRMASK) | + (va & ~PDRMASK), pmap); } if ((oldpte & PG_PTE_PROMOTE) != (newpde & PG_PTE_PROMOTE)) { atomic_add_long(&pmap_pde_p_failures, 1); diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c index 0d03ed6..1fb7016 100644 --- a/sys/amd64/amd64/vm_machdep.c +++ b/sys/amd64/amd64/vm_machdep.c @@ -155,7 +155,6 @@ cpu_fork(td1, p2, td2, flags) struct pcb *pcb2; struct mdproc *mdp1, *mdp2; struct proc_ldt *pldt; - pmap_t pmap2; p1 = td1->td_proc; if ((flags & RFPROC) == 0) { @@ -218,7 +217,6 @@ cpu_fork(td1, p2, td2, flags) * Set registers for trampoline to user mode. Leave space for the * return address on stack. These are the kernel mode register values. */ - pmap2 = vmspace_pmap(p2->p_vmspace); pcb2->pcb_r12 = (register_t)fork_return; /* fork_trampoline argument */ pcb2->pcb_rbp = 0; pcb2->pcb_rsp = (register_t)td2->td_frame - sizeof(void *); diff --git a/sys/amd64/ia32/ia32_reg.c b/sys/amd64/ia32/ia32_reg.c index 5bc18f1..d0e6bfe 100644 --- a/sys/amd64/ia32/ia32_reg.c +++ b/sys/amd64/ia32/ia32_reg.c @@ -79,11 +79,9 @@ __FBSDID("$FreeBSD$"); int fill_regs32(struct thread *td, struct reg32 *regs) { - struct pcb *pcb; struct trapframe *tp; tp = td->td_frame; - pcb = td->td_pcb; if (tp->tf_flags & TF_HASSEGS) { regs->r_gs = tp->tf_gs; regs->r_fs = tp->tf_fs; @@ -113,18 +111,16 @@ fill_regs32(struct thread *td, struct reg32 *regs) int set_regs32(struct thread *td, struct reg32 *regs) { - struct pcb *pcb; struct trapframe *tp; tp = td->td_frame; if (!EFL_SECURE(regs->r_eflags, tp->tf_rflags) || !CS_SECURE(regs->r_cs)) return (EINVAL); - pcb = td->td_pcb; tp->tf_gs = regs->r_gs; tp->tf_fs = regs->r_fs; tp->tf_es = regs->r_es; tp->tf_ds = regs->r_ds; - set_pcb_flags(pcb, PCB_FULL_IRET); + set_pcb_flags(td->td_pcb, PCB_FULL_IRET); tp->tf_flags = TF_HASSEGS; tp->tf_rdi = regs->r_edi; tp->tf_rsi = regs->r_esi; diff --git a/sys/amd64/include/vmm.h b/sys/amd64/include/vmm.h index d3798bc..1a4e5ab 100644 --- a/sys/amd64/include/vmm.h +++ b/sys/amd64/include/vmm.h @@ -120,13 +120,18 @@ struct vm_object; struct vm_guest_paging; struct pmap; +struct vm_eventinfo { + void *rptr; /* rendezvous cookie */ + int *sptr; /* suspend cookie */ + int *iptr; /* reqidle cookie */ +}; + typedef int (*vmm_init_func_t)(int ipinum); typedef int (*vmm_cleanup_func_t)(void); typedef void (*vmm_resume_func_t)(void); typedef void * (*vmi_init_func_t)(struct vm *vm, struct pmap *pmap); typedef int (*vmi_run_func_t)(void *vmi, int vcpu, register_t rip, - struct pmap *pmap, void *rendezvous_cookie, - void *suspend_cookie); + struct pmap *pmap, struct vm_eventinfo *info); typedef void (*vmi_cleanup_func_t)(void *vmi); typedef int (*vmi_get_register_t)(void *vmi, int vcpu, int num, uint64_t *retval); @@ -208,6 +213,7 @@ struct vm_exit *vm_exitinfo(struct vm *vm, int vcpuid); void vm_exit_suspended(struct vm *vm, int vcpuid, uint64_t rip); void vm_exit_rendezvous(struct vm *vm, int vcpuid, uint64_t rip); void vm_exit_astpending(struct vm *vm, int vcpuid, uint64_t rip); +void vm_exit_reqidle(struct vm *vm, int vcpuid, uint64_t rip); #ifdef _SYS__CPUSET_H_ /* @@ -232,17 +238,24 @@ cpuset_t vm_suspended_cpus(struct vm *vm); #endif /* _SYS__CPUSET_H_ */ static __inline int -vcpu_rendezvous_pending(void *rendezvous_cookie) +vcpu_rendezvous_pending(struct vm_eventinfo *info) +{ + + return (*((uintptr_t *)(info->rptr)) != 0); +} + +static __inline int +vcpu_suspended(struct vm_eventinfo *info) { - return (*(uintptr_t *)rendezvous_cookie != 0); + return (*info->sptr); } static __inline int -vcpu_suspended(void *suspend_cookie) +vcpu_reqidle(struct vm_eventinfo *info) { - return (*(int *)suspend_cookie); + return (*info->iptr); } /* @@ -506,6 +519,7 @@ enum vm_exitcode { VM_EXITCODE_MONITOR, VM_EXITCODE_MWAIT, VM_EXITCODE_SVM, + VM_EXITCODE_REQIDLE, VM_EXITCODE_MAX }; diff --git a/sys/amd64/vmm/amd/svm.c b/sys/amd64/vmm/amd/svm.c index 20e8f76..53b12b7 100644 --- a/sys/amd64/vmm/amd/svm.c +++ b/sys/amd64/vmm/amd/svm.c @@ -1900,7 +1900,7 @@ enable_gintr(void) */ static int svm_vmrun(void *arg, int vcpu, register_t rip, pmap_t pmap, - void *rend_cookie, void *suspended_cookie) + struct vm_eventinfo *evinfo) { struct svm_regctx *gctx; struct svm_softc *svm_sc; @@ -1975,18 +1975,24 @@ svm_vmrun(void *arg, int vcpu, register_t rip, pmap_t pmap, */ disable_gintr(); - if (vcpu_suspended(suspended_cookie)) { + if (vcpu_suspended(evinfo)) { enable_gintr(); vm_exit_suspended(vm, vcpu, state->rip); break; } - if (vcpu_rendezvous_pending(rend_cookie)) { + if (vcpu_rendezvous_pending(evinfo)) { enable_gintr(); vm_exit_rendezvous(vm, vcpu, state->rip); break; } + if (vcpu_reqidle(evinfo)) { + enable_gintr(); + vm_exit_reqidle(vm, vcpu, state->rip); + break; + } + /* We are asked to give the cpu by scheduler. */ if (vcpu_should_yield(vm, vcpu)) { enable_gintr(); diff --git a/sys/amd64/vmm/intel/vmx.c b/sys/amd64/vmm/intel/vmx.c index 4c3f20d..7ee50d4 100644 --- a/sys/amd64/vmm/intel/vmx.c +++ b/sys/amd64/vmm/intel/vmx.c @@ -2554,7 +2554,7 @@ vmx_exit_handle_nmi(struct vmx *vmx, int vcpuid, struct vm_exit *vmexit) static int vmx_run(void *arg, int vcpu, register_t rip, pmap_t pmap, - void *rendezvous_cookie, void *suspend_cookie) + struct vm_eventinfo *evinfo) { int rc, handled, launched; struct vmx *vmx; @@ -2623,18 +2623,24 @@ vmx_run(void *arg, int vcpu, register_t rip, pmap_t pmap, * vmx_inject_interrupts() can suspend the vcpu due to a * triple fault. */ - if (vcpu_suspended(suspend_cookie)) { + if (vcpu_suspended(evinfo)) { enable_intr(); vm_exit_suspended(vmx->vm, vcpu, rip); break; } - if (vcpu_rendezvous_pending(rendezvous_cookie)) { + if (vcpu_rendezvous_pending(evinfo)) { enable_intr(); vm_exit_rendezvous(vmx->vm, vcpu, rip); break; } + if (vcpu_reqidle(evinfo)) { + enable_intr(); + vm_exit_reqidle(vmx->vm, vcpu, rip); + break; + } + if (vcpu_should_yield(vm, vcpu)) { enable_intr(); vm_exit_astpending(vmx->vm, vcpu, rip); diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c index 2671295..2c37a1a 100644 --- a/sys/amd64/vmm/vmm.c +++ b/sys/amd64/vmm/vmm.c @@ -95,6 +95,7 @@ struct vcpu { struct mtx mtx; /* (o) protects 'state' and 'hostcpu' */ enum vcpu_state state; /* (o) vcpu state */ int hostcpu; /* (o) vcpu's host cpu */ + int reqidle; /* (i) request vcpu to idle */ struct vlapic *vlapic; /* (i) APIC device model */ enum x2apic_state x2apic_state; /* (i) APIC mode */ uint64_t exitintinfo; /* (i) events pending at VM exit */ @@ -164,8 +165,8 @@ static struct vmm_ops *ops; #define VMM_RESUME() (ops != NULL ? (*ops->resume)() : 0) #define VMINIT(vm, pmap) (ops != NULL ? (*ops->vminit)(vm, pmap): NULL) -#define VMRUN(vmi, vcpu, rip, pmap, rptr, sptr) \ - (ops != NULL ? (*ops->vmrun)(vmi, vcpu, rip, pmap, rptr, sptr) : ENXIO) +#define VMRUN(vmi, vcpu, rip, pmap, evinfo) \ + (ops != NULL ? (*ops->vmrun)(vmi, vcpu, rip, pmap, evinfo) : ENXIO) #define VMCLEANUP(vmi) (ops != NULL ? (*ops->vmcleanup)(vmi) : NULL) #define VMSPACE_ALLOC(min, max) \ (ops != NULL ? (*ops->vmspace_alloc)(min, max) : NULL) @@ -221,6 +222,28 @@ TUNABLE_INT("hw.vmm.force_iommu", &vmm_force_iommu); SYSCTL_INT(_hw_vmm, OID_AUTO, force_iommu, CTLFLAG_RDTUN, &vmm_force_iommu, 0, "Force use of I/O MMU even if no passthrough devices were found."); +static void vcpu_notify_event_locked(struct vcpu *vcpu, bool lapic_intr); + +#ifdef KTR +static const char * +vcpu_state2str(enum vcpu_state state) +{ + + switch (state) { + case VCPU_IDLE: + return ("idle"); + case VCPU_FROZEN: + return ("frozen"); + case VCPU_RUNNING: + return ("running"); + case VCPU_SLEEPING: + return ("sleeping"); + default: + return ("unknown"); + } +} +#endif + static void vcpu_cleanup(struct vm *vm, int i, bool destroy) { @@ -255,6 +278,7 @@ vcpu_init(struct vm *vm, int vcpu_id, bool create) vcpu->vlapic = VLAPIC_INIT(vm->cookie, vcpu_id); vm_set_x2apic_state(vm, vcpu_id, X2APIC_DISABLED); + vcpu->reqidle = 0; vcpu->exitintinfo = 0; vcpu->nmi_pending = 0; vcpu->extint_pending = 0; @@ -980,11 +1004,13 @@ save_guest_fpustate(struct vcpu *vcpu) static VMM_STAT(VCPU_IDLE_TICKS, "number of ticks vcpu was idle"); static int -vcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate, +vcpu_set_state_locked(struct vm *vm, int vcpuid, enum vcpu_state newstate, bool from_idle) { + struct vcpu *vcpu; int error; + vcpu = &vm->vcpu[vcpuid]; vcpu_assert_locked(vcpu); /* @@ -993,8 +1019,13 @@ vcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate, * ioctl() operating on a vcpu at any point. */ if (from_idle) { - while (vcpu->state != VCPU_IDLE) + while (vcpu->state != VCPU_IDLE) { + vcpu->reqidle = 1; + vcpu_notify_event_locked(vcpu, false); + VCPU_CTR1(vm, vcpuid, "vcpu state change from %s to " + "idle requested", vcpu_state2str(vcpu->state)); msleep_spin(&vcpu->state, &vcpu->mtx, "vmstat", hz); + } } else { KASSERT(vcpu->state != VCPU_IDLE, ("invalid transition from " "vcpu idle state")); @@ -1031,6 +1062,9 @@ vcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate, if (error) return (EBUSY); + VCPU_CTR2(vm, vcpuid, "vcpu state changed from %s to %s", + vcpu_state2str(vcpu->state), vcpu_state2str(newstate)); + vcpu->state = newstate; if (newstate == VCPU_RUNNING) vcpu->hostcpu = curcpu; @@ -1053,11 +1087,11 @@ vcpu_require_state(struct vm *vm, int vcpuid, enum vcpu_state newstate) } static void -vcpu_require_state_locked(struct vcpu *vcpu, enum vcpu_state newstate) +vcpu_require_state_locked(struct vm *vm, int vcpuid, enum vcpu_state newstate) { int error; - if ((error = vcpu_set_state_locked(vcpu, newstate, false)) != 0) + if ((error = vcpu_set_state_locked(vm, vcpuid, newstate, false)) != 0) panic("Error %d setting state to %d", error, newstate); } @@ -1145,7 +1179,7 @@ vm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled, bool *retu) * vcpu returned from VMRUN() and before it acquired the * vcpu lock above. */ - if (vm->rendezvous_func != NULL || vm->suspend) + if (vm->rendezvous_func != NULL || vm->suspend || vcpu->reqidle) break; if (vm_nmi_pending(vm, vcpuid)) break; @@ -1182,13 +1216,13 @@ vm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled, bool *retu) } t = ticks; - vcpu_require_state_locked(vcpu, VCPU_SLEEPING); + vcpu_require_state_locked(vm, vcpuid, VCPU_SLEEPING); /* * XXX msleep_spin() cannot be interrupted by signals so * wake up periodically to check pending signals. */ msleep_spin(vcpu, &vcpu->mtx, wmesg, hz); - vcpu_require_state_locked(vcpu, VCPU_FROZEN); + vcpu_require_state_locked(vm, vcpuid, VCPU_FROZEN); vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t); } @@ -1350,9 +1384,9 @@ vm_handle_suspend(struct vm *vm, int vcpuid, bool *retu) if (vm->rendezvous_func == NULL) { VCPU_CTR0(vm, vcpuid, "Sleeping during suspend"); - vcpu_require_state_locked(vcpu, VCPU_SLEEPING); + vcpu_require_state_locked(vm, vcpuid, VCPU_SLEEPING); msleep_spin(vcpu, &vcpu->mtx, "vmsusp", hz); - vcpu_require_state_locked(vcpu, VCPU_FROZEN); + vcpu_require_state_locked(vm, vcpuid, VCPU_FROZEN); } else { VCPU_CTR0(vm, vcpuid, "Rendezvous during suspend"); vcpu_unlock(vcpu); @@ -1375,6 +1409,19 @@ vm_handle_suspend(struct vm *vm, int vcpuid, bool *retu) return (0); } +static int +vm_handle_reqidle(struct vm *vm, int vcpuid, bool *retu) +{ + struct vcpu *vcpu = &vm->vcpu[vcpuid]; + + vcpu_lock(vcpu); + KASSERT(vcpu->reqidle, ("invalid vcpu reqidle %d", vcpu->reqidle)); + vcpu->reqidle = 0; + vcpu_unlock(vcpu); + *retu = true; + return (0); +} + int vm_suspend(struct vm *vm, enum vm_suspend_how how) { @@ -1432,6 +1479,18 @@ vm_exit_rendezvous(struct vm *vm, int vcpuid, uint64_t rip) } void +vm_exit_reqidle(struct vm *vm, int vcpuid, uint64_t rip) +{ + struct vm_exit *vmexit; + + vmexit = vm_exitinfo(vm, vcpuid); + vmexit->rip = rip; + vmexit->inst_length = 0; + vmexit->exitcode = VM_EXITCODE_REQIDLE; + vmm_stat_incr(vm, vcpuid, VMEXIT_REQIDLE, 1); +} + +void vm_exit_astpending(struct vm *vm, int vcpuid, uint64_t rip) { struct vm_exit *vmexit; @@ -1446,6 +1505,7 @@ vm_exit_astpending(struct vm *vm, int vcpuid, uint64_t rip) int vm_run(struct vm *vm, struct vm_run *vmrun) { + struct vm_eventinfo evinfo; int error, vcpuid; struct vcpu *vcpu; struct pcb *pcb; @@ -1453,7 +1513,6 @@ vm_run(struct vm *vm, struct vm_run *vmrun) struct vm_exit *vme; bool retu, intr_disabled; pmap_t pmap; - void *rptr, *sptr; vcpuid = vmrun->cpuid; @@ -1466,11 +1525,12 @@ vm_run(struct vm *vm, struct vm_run *vmrun) if (CPU_ISSET(vcpuid, &vm->suspended_cpus)) return (EINVAL); - rptr = &vm->rendezvous_func; - sptr = &vm->suspend; pmap = vmspace_pmap(vm->vmspace); vcpu = &vm->vcpu[vcpuid]; vme = &vcpu->exitinfo; + evinfo.rptr = &vm->rendezvous_func; + evinfo.sptr = &vm->suspend; + evinfo.iptr = &vcpu->reqidle; restart: critical_enter(); @@ -1485,7 +1545,7 @@ restart: restore_guest_fpustate(vcpu); vcpu_require_state(vm, vcpuid, VCPU_RUNNING); - error = VMRUN(vm->cookie, vcpuid, vcpu->nextrip, pmap, rptr, sptr); + error = VMRUN(vm->cookie, vcpuid, vcpu->nextrip, pmap, &evinfo); vcpu_require_state(vm, vcpuid, VCPU_FROZEN); save_guest_fpustate(vcpu); @@ -1498,6 +1558,9 @@ restart: retu = false; vcpu->nextrip = vme->rip + vme->inst_length; switch (vme->exitcode) { + case VM_EXITCODE_REQIDLE: + error = vm_handle_reqidle(vm, vcpuid, &retu); + break; case VM_EXITCODE_SUSPENDED: error = vm_handle_suspend(vm, vcpuid, &retu); break; @@ -1536,6 +1599,8 @@ restart: if (error == 0 && retu == false) goto restart; + VCPU_CTR2(vm, vcpuid, "retu %d/%d", error, vme->exitcode); + /* copy the exit information */ bcopy(vme, &vmrun->vm_exit, sizeof(struct vm_exit)); return (error); @@ -2072,7 +2137,7 @@ vcpu_set_state(struct vm *vm, int vcpuid, enum vcpu_state newstate, vcpu = &vm->vcpu[vcpuid]; vcpu_lock(vcpu); - error = vcpu_set_state_locked(vcpu, newstate, from_idle); + error = vcpu_set_state_locked(vm, vcpuid, newstate, from_idle); vcpu_unlock(vcpu); return (error); @@ -2168,15 +2233,11 @@ vm_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state) * - If the vcpu is running on a different host_cpu then an IPI will be directed * to the host_cpu to cause the vcpu to trap into the hypervisor. */ -void -vcpu_notify_event(struct vm *vm, int vcpuid, bool lapic_intr) +static void +vcpu_notify_event_locked(struct vcpu *vcpu, bool lapic_intr) { int hostcpu; - struct vcpu *vcpu; - - vcpu = &vm->vcpu[vcpuid]; - vcpu_lock(vcpu); hostcpu = vcpu->hostcpu; if (vcpu->state == VCPU_RUNNING) { KASSERT(hostcpu != NOCPU, ("vcpu running on invalid hostcpu")); @@ -2201,6 +2262,15 @@ vcpu_notify_event(struct vm *vm, int vcpuid, bool lapic_intr) if (vcpu->state == VCPU_SLEEPING) wakeup_one(vcpu); } +} + +void +vcpu_notify_event(struct vm *vm, int vcpuid, bool lapic_intr) +{ + struct vcpu *vcpu = &vm->vcpu[vcpuid]; + + vcpu_lock(vcpu); + vcpu_notify_event_locked(vcpu, lapic_intr); vcpu_unlock(vcpu); } diff --git a/sys/amd64/vmm/vmm_stat.c b/sys/amd64/vmm/vmm_stat.c index 4ae5fb9..7e2f64d 100644 --- a/sys/amd64/vmm/vmm_stat.c +++ b/sys/amd64/vmm/vmm_stat.c @@ -164,6 +164,7 @@ VMM_STAT(VMEXIT_NESTED_FAULT, "vm exits due to nested page fault"); VMM_STAT(VMEXIT_INST_EMUL, "vm exits for instruction emulation"); VMM_STAT(VMEXIT_UNKNOWN, "number of vm exits for unknown reason"); VMM_STAT(VMEXIT_ASTPENDING, "number of times astpending at exit"); +VMM_STAT(VMEXIT_REQIDLE, "number of times idle requested at exit"); VMM_STAT(VMEXIT_USERSPACE, "number of vm exits handled in userspace"); VMM_STAT(VMEXIT_RENDEZVOUS, "number of times rendezvous pending at exit"); VMM_STAT(VMEXIT_EXCEPTION, "number of vm exits due to exceptions"); diff --git a/sys/amd64/vmm/vmm_stat.h b/sys/amd64/vmm/vmm_stat.h index 1640ba3..c695840 100644 --- a/sys/amd64/vmm/vmm_stat.h +++ b/sys/amd64/vmm/vmm_stat.h @@ -157,4 +157,5 @@ VMM_STAT_DECLARE(VMEXIT_ASTPENDING); VMM_STAT_DECLARE(VMEXIT_USERSPACE); VMM_STAT_DECLARE(VMEXIT_RENDEZVOUS); VMM_STAT_DECLARE(VMEXIT_EXCEPTION); +VMM_STAT_DECLARE(VMEXIT_REQIDLE); #endif diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c index 9e0b8a0..c2dd020 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c @@ -697,6 +697,7 @@ zfsctl_unmount_snap(zfs_snapentry_t *sep, int fflags, cred_t *cr) return (0); #else + vfs_ref(vn_mountedvfs(svp)); return (dounmount(vn_mountedvfs(svp), fflags, curthread)); #endif } diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c index d4291ec..5800db0 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c @@ -3481,6 +3481,7 @@ zfs_unmount_snap(const char *snapname) #ifdef illumos (void) dounmount(vfsp, MS_FORCE, kcred); #else + vfs_ref(vfsp); (void) dounmount(vfsp, MS_FORCE, curthread); #endif return (0); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c index 5824828..1193e47 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c @@ -2314,8 +2314,10 @@ bail: * Since we couldn't setup the sa framework, try to force * unmount this file system. */ - if (vn_vfswlock(zfsvfs->z_vfs->vfs_vnodecovered) == 0) + if (vn_vfswlock(zfsvfs->z_vfs->vfs_vnodecovered) == 0) { + vfs_ref(zfsvfs->z_vfs); (void) dounmount(zfsvfs->z_vfs, MS_FORCE, curthread); + } } return (err); } diff --git a/sys/conf/files b/sys/conf/files index 0a63a1c..9660751 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1427,6 +1427,8 @@ dev/hptiop/hptiop.c optional hptiop scbus dev/hwpmc/hwpmc_logging.c optional hwpmc dev/hwpmc/hwpmc_mod.c optional hwpmc dev/hwpmc/hwpmc_soft.c optional hwpmc +dev/ichiic/ig4_iic.c optional ichiic +dev/ichiic/ig4_pci.c optional ichiic pci dev/ichsmb/ichsmb.c optional ichsmb dev/ichsmb/ichsmb_pci.c optional ichsmb pci dev/ida/ida.c optional ida @@ -2024,6 +2026,7 @@ dev/pci/isa_pci.c optional pci isa dev/pci/pci.c optional pci dev/pci/pci_if.m standard dev/pci/pci_iov.c optional pci pci_iov +dev/pci/pci_iov_if.m standard dev/pci/pci_iov_schema.c optional pci pci_iov dev/pci/pci_pci.c optional pci dev/pci/pci_subr.c optional pci diff --git a/sys/conf/kmod.mk b/sys/conf/kmod.mk index 0f27113..9009745 100644 --- a/sys/conf/kmod.mk +++ b/sys/conf/kmod.mk @@ -349,7 +349,7 @@ MFILES?= dev/acpica/acpi_if.m dev/acpi_support/acpi_wmi_if.m \ dev/mbox/mbox_if.m dev/mmc/mmcbr_if.m dev/mmc/mmcbus_if.m \ dev/mii/miibus_if.m dev/mvs/mvs_if.m dev/ofw/ofw_bus_if.m \ dev/pccard/card_if.m dev/pccard/power_if.m dev/pci/pci_if.m \ - dev/pci/pcib_if.m dev/ppbus/ppbus_if.m \ + dev/pci/pci_iov_if.m dev/pci/pcib_if.m dev/ppbus/ppbus_if.m \ dev/sdhci/sdhci_if.m dev/smbus/smbus_if.m dev/spibus/spibus_if.m \ dev/sound/pci/hda/hdac_if.m \ dev/sound/pcm/ac97_if.m dev/sound/pcm/channel_if.m \ diff --git a/sys/dev/acpi_support/acpi_ibm.c b/sys/dev/acpi_support/acpi_ibm.c index c2f90d1..1163681 100644 --- a/sys/dev/acpi_support/acpi_ibm.c +++ b/sys/dev/acpi_support/acpi_ibm.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include "opt_acpi.h" #include <sys/param.h> +#include <sys/systm.h> #include <sys/kernel.h> #include <sys/bus.h> #include <machine/cpufunc.h> @@ -261,6 +262,37 @@ static struct { { NULL, 0, NULL, 0 } }; +/* + * Per-model default list of event mask. + */ +#define ACPI_IBM_HKEY_RFKILL_MASK (1 << 4) +#define ACPI_IBM_HKEY_DSWITCH_MASK (1 << 6) +#define ACPI_IBM_HKEY_BRIGHTNESS_UP_MASK (1 << 15) +#define ACPI_IBM_HKEY_BRIGHTNESS_DOWN_MASK (1 << 16) +#define ACPI_IBM_HKEY_SEARCH_MASK (1 << 18) +#define ACPI_IBM_HKEY_MICMUTE_MASK (1 << 26) +#define ACPI_IBM_HKEY_SETTINGS_MASK (1 << 28) +#define ACPI_IBM_HKEY_VIEWOPEN_MASK (1 << 30) +#define ACPI_IBM_HKEY_VIEWALL_MASK (1 << 31) + +struct acpi_ibm_models { + const char *maker; + const char *product; + uint32_t eventmask; +} acpi_ibm_models[] = { + { "LENOVO", "20BSCTO1WW", + ACPI_IBM_HKEY_RFKILL_MASK | + ACPI_IBM_HKEY_DSWITCH_MASK | + ACPI_IBM_HKEY_BRIGHTNESS_UP_MASK | + ACPI_IBM_HKEY_BRIGHTNESS_DOWN_MASK | + ACPI_IBM_HKEY_SEARCH_MASK | + ACPI_IBM_HKEY_MICMUTE_MASK | + ACPI_IBM_HKEY_SETTINGS_MASK | + ACPI_IBM_HKEY_VIEWOPEN_MASK | + ACPI_IBM_HKEY_VIEWALL_MASK + } +}; + ACPI_SERIAL_DECL(ibm, "ACPI IBM extras"); static int acpi_ibm_probe(device_t dev); @@ -354,7 +386,9 @@ acpi_ibm_probe(device_t dev) static int acpi_ibm_attach(device_t dev) { + int i; struct acpi_ibm_softc *sc; + char *maker, *product; devclass_t ec_devclass; ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); @@ -448,6 +482,27 @@ acpi_ibm_attach(device_t dev) sc->led_dev = led_create_state(ibm_led, sc, "thinklight", (sc->light_val ? 1 : 0)); + /* Enable per-model events. */ + maker = kern_getenv("smbios.system.maker"); + product = kern_getenv("smbios.system.product"); + for (i = 0; i < nitems(acpi_ibm_models); i++) { + if (strcmp(maker, acpi_ibm_models[i].maker) == 0 && + strcmp(product, acpi_ibm_models[i].product) == 0) { + ACPI_SERIAL_BEGIN(ibm); + acpi_ibm_sysctl_set(sc, ACPI_IBM_METHOD_EVENTMASK, + acpi_ibm_models[i].eventmask); + ACPI_SERIAL_END(ibm); + } + } + freeenv(maker); + freeenv(product); + + /* Enable events by default. */ + ACPI_SERIAL_BEGIN(ibm); + acpi_ibm_sysctl_set(sc, ACPI_IBM_METHOD_EVENTS, 1); + ACPI_SERIAL_END(ibm); + + return (0); } @@ -770,7 +825,6 @@ acpi_ibm_sysctl_init(struct acpi_ibm_softc *sc, int method) switch (method) { case ACPI_IBM_METHOD_EVENTS: - /* Events are disabled by default */ return (TRUE); case ACPI_IBM_METHOD_EVENTMASK: @@ -1229,7 +1283,6 @@ acpi_ibm_notify(ACPI_HANDLE h, UINT32 notify, void *context) for (;;) { acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_EVENTS_GET, &event); - if (event == 0) break; diff --git a/sys/dev/ath/ath_rate/sample/sample.c b/sys/dev/ath/ath_rate/sample/sample.c index 36cd679..3606e14 100644 --- a/sys/dev/ath/ath_rate/sample/sample.c +++ b/sys/dev/ath/ath_rate/sample/sample.c @@ -843,9 +843,11 @@ update_stats(struct ath_softc *sc, struct ath_node *an, } static void -badrate(struct ifnet *ifp, int series, int hwrate, int tries, int status) +badrate(struct ath_softc *sc, int series, int hwrate, int tries, int status) { - if_printf(ifp, "bad series%d hwrate 0x%x, tries %u ts_status 0x%x\n", + + device_printf(sc->sc_dev, + "bad series%d hwrate 0x%x, tries %u ts_status 0x%x\n", series, hwrate, tries, status); } @@ -891,9 +893,10 @@ ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, if (!mrr || ts->ts_finaltsi == 0) { if (!IS_RATE_DEFINED(sn, final_rix)) { - device_printf(sc->sc_dev, "%s: ts_rate=%d ts_finaltsi=%d, final_rix=%d\n", + device_printf(sc->sc_dev, + "%s: ts_rate=%d ts_finaltsi=%d, final_rix=%d\n", __func__, ts->ts_rate, ts->ts_finaltsi, final_rix); - badrate(ifp, 0, ts->ts_rate, long_tries, status); + badrate(sc, 0, ts->ts_rate, long_tries, status); return; } /* @@ -945,7 +948,7 @@ ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, for (i = 0; i < 4; i++) { if (rc[i].tries && !IS_RATE_DEFINED(sn, rc[i].rix)) - badrate(ifp, 0, rc[i].ratecode, rc[i].tries, + badrate(sc, 0, rc[i].ratecode, rc[i].tries, status); } diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index 03c793e..4aac93b 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -595,7 +595,6 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) ic->ic_softc = sc; ic->ic_name = device_get_nameunit(sc->sc_dev); - /* set these up early for if_printf use */ if_initname(ifp, device_get_name(sc->sc_dev), device_get_unit(sc->sc_dev)); CURVNET_RESTORE(); @@ -612,8 +611,8 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) ah = ath_hal_attach(devid, sc, sc->sc_st, sc->sc_sh, sc->sc_eepromdata, &ah_config, &status); if (ah == NULL) { - if_printf(ifp, "unable to attach hardware; HAL status %u\n", - status); + device_printf(sc->sc_dev, + "unable to attach hardware; HAL status %u\n", status); error = ENXIO; goto bad; } @@ -664,8 +663,9 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) */ sc->sc_keymax = ath_hal_keycachesize(ah); if (sc->sc_keymax > ATH_KEYMAX) { - if_printf(ifp, "Warning, using only %u of %u key cache slots\n", - ATH_KEYMAX, sc->sc_keymax); + device_printf(sc->sc_dev, + "Warning, using only %u of %u key cache slots\n", + ATH_KEYMAX, sc->sc_keymax); sc->sc_keymax = ATH_KEYMAX; } /* @@ -704,14 +704,14 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) */ error = ath_desc_alloc(sc); if (error != 0) { - if_printf(ifp, "failed to allocate TX descriptors: %d\n", - error); + device_printf(sc->sc_dev, + "failed to allocate TX descriptors: %d\n", error); goto bad; } error = ath_txdma_setup(sc); if (error != 0) { - if_printf(ifp, "failed to allocate TX descriptors: %d\n", - error); + device_printf(sc->sc_dev, + "failed to allocate TX descriptors: %d\n", error); goto bad; } @@ -720,8 +720,8 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) */ error = ath_rxdma_setup(sc); if (error != 0) { - if_printf(ifp, "failed to allocate RX descriptors: %d\n", - error); + device_printf(sc->sc_dev, + "failed to allocate RX descriptors: %d\n", error); goto bad; } @@ -752,20 +752,22 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) */ sc->sc_bhalq = ath_beaconq_setup(sc); if (sc->sc_bhalq == (u_int) -1) { - if_printf(ifp, "unable to setup a beacon xmit queue!\n"); + device_printf(sc->sc_dev, + "unable to setup a beacon xmit queue!\n"); error = EIO; goto bad2; } sc->sc_cabq = ath_txq_setup(sc, HAL_TX_QUEUE_CAB, 0); if (sc->sc_cabq == NULL) { - if_printf(ifp, "unable to setup CAB xmit queue!\n"); + device_printf(sc->sc_dev, "unable to setup CAB xmit queue!\n"); error = EIO; goto bad2; } /* NB: insure BK queue is the lowest priority h/w queue */ if (!ath_tx_setup(sc, WME_AC_BK, HAL_WME_AC_BK)) { - if_printf(ifp, "unable to setup xmit queue for %s traffic!\n", - ieee80211_wme_acnames[WME_AC_BK]); + device_printf(sc->sc_dev, + "unable to setup xmit queue for %s traffic!\n", + ieee80211_wme_acnames[WME_AC_BK]); error = EIO; goto bad2; } @@ -1828,8 +1830,8 @@ ath_vap_delete(struct ieee80211vap *vap) * be reset if we just destroyed the last vap). */ if (ath_startrecv(sc) != 0) - if_printf(ifp, "%s: unable to restart recv logic\n", - __func__); + device_printf(sc->sc_dev, + "%s: unable to restart recv logic\n", __func__); if (sc->sc_beacons) { /* restart beacons */ #ifdef IEEE80211_SUPPORT_TDMA if (sc->sc_tdma) @@ -2316,7 +2318,7 @@ ath_fatal_proc(void *arg, int pending) u_int32_t len; void *sp; - if_printf(ifp, "hardware error; resetting\n"); + device_printf(sc->sc_dev, "hardware error; resetting\n"); /* * Fatal errors are unrecoverable. Typically these * are caused by DMA errors. Collect h/w state from @@ -2325,9 +2327,9 @@ ath_fatal_proc(void *arg, int pending) if (ath_hal_getfatalstate(sc->sc_ah, &sp, &len)) { KASSERT(len >= 6*sizeof(u_int32_t), ("len %u bytes", len)); state = sp; - if_printf(ifp, "0x%08x 0x%08x 0x%08x, 0x%08x 0x%08x 0x%08x\n", - state[0], state[1] , state[2], state[3], - state[4], state[5]); + device_printf(sc->sc_dev, + "0x%08x 0x%08x 0x%08x, 0x%08x 0x%08x 0x%08x\n", state[0], + state[1] , state[2], state[3], state[4], state[5]); } ath_reset(ifp, ATH_RESET_NOLOSS); } @@ -2434,7 +2436,8 @@ ath_bmiss_proc(void *arg, int pending) */ if (ath_hal_gethangstate(sc->sc_ah, 0xff, &hangs) && hangs != 0) { ath_reset(ifp, ATH_RESET_NOLOSS); - if_printf(ifp, "bb hang detected (0x%x), resetting\n", hangs); + device_printf(sc->sc_dev, + "bb hang detected (0x%x), resetting\n", hangs); } else { ath_reset(ifp, ATH_RESET_NOLOSS); ieee80211_beacon_miss(ifp->if_l2com); @@ -2509,9 +2512,10 @@ ath_init(void *arg) ath_hal_setchainmasks(sc->sc_ah, sc->sc_cur_txchainmask, sc->sc_cur_rxchainmask); - if (!ath_hal_reset(ah, sc->sc_opmode, ic->ic_curchan, AH_FALSE, &status)) { - if_printf(ifp, "unable to reset hardware; hal status %u\n", - status); + if (!ath_hal_reset(ah, sc->sc_opmode, ic->ic_curchan, AH_FALSE, + &status)) { + device_printf(sc->sc_dev, + "unable to reset hardware; hal status %u\n", status); ATH_UNLOCK(sc); return; } @@ -2569,7 +2573,7 @@ ath_init(void *arg) * here except setup the interrupt mask. */ if (ath_startrecv(sc) != 0) { - if_printf(ifp, "unable to start recv logic\n"); + device_printf(sc->sc_dev, "unable to start recv logic\n"); ath_power_restore_power_state(sc); ATH_UNLOCK(sc); return; @@ -2911,8 +2915,9 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) ath_hal_setchainmasks(sc->sc_ah, sc->sc_cur_txchainmask, sc->sc_cur_rxchainmask); if (!ath_hal_reset(ah, sc->sc_opmode, ic->ic_curchan, AH_TRUE, &status)) - if_printf(ifp, "%s: unable to reset hardware; hal status %u\n", - __func__, status); + device_printf(sc->sc_dev, + "%s: unable to reset hardware; hal status %u\n", + __func__, status); sc->sc_diversity = ath_hal_getdiversity(ah); ATH_RX_LOCK(sc); @@ -2941,7 +2946,8 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) ath_hal_setenforcetxop(sc->sc_ah, 0); if (ath_startrecv(sc) != 0) /* restart recv */ - if_printf(ifp, "%s: unable to start recv logic\n", __func__); + device_printf(sc->sc_dev, + "%s: unable to start recv logic\n", __func__); /* * We may be doing a reset in response to an ioctl * that changes the channel so update any state that @@ -3747,7 +3753,7 @@ ath_reset_proc(void *arg, int pending) struct ifnet *ifp = sc->sc_ifp; #if 0 - if_printf(ifp, "%s: resetting\n", __func__); + device_printf(sc->sc_dev, "%s: resetting\n", __func__); #endif ath_reset(ifp, ATH_RESET_NOLOSS); } @@ -3763,15 +3769,15 @@ ath_bstuck_proc(void *arg, int pending) uint32_t hangs = 0; if (ath_hal_gethangstate(sc->sc_ah, 0xff, &hangs) && hangs != 0) - if_printf(ifp, "bb hang detected (0x%x)\n", hangs); + device_printf(sc->sc_dev, "bb hang detected (0x%x)\n", hangs); #ifdef ATH_DEBUG_ALQ if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_STUCK_BEACON)) if_ath_alq_post(&sc->sc_alq, ATH_ALQ_STUCK_BEACON, 0, NULL); #endif - if_printf(ifp, "stuck beacon; resetting (bmiss count %u)\n", - sc->sc_bmisscount); + device_printf(sc->sc_dev, "stuck beacon; resetting (bmiss count %u)\n", + sc->sc_bmisscount); sc->sc_stats.ast_bstuck++; /* * This assumes that there's no simultaneous channel mode change @@ -3803,7 +3809,6 @@ ath_descdma_alloc_desc(struct ath_softc *sc, ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) #define ATH_DESC_4KB_BOUND_CHECK(_daddr, _len) \ ((((u_int32_t)(_daddr) & 0xFFF) > (0x1000 - (_len))) ? 1 : 0) - struct ifnet *ifp = sc->sc_ifp; int error; dd->dd_descsize = ds_size; @@ -3844,7 +3849,8 @@ ath_descdma_alloc_desc(struct ath_softc *sc, NULL, /* lockarg */ &dd->dd_dmat); if (error != 0) { - if_printf(ifp, "cannot allocate %s DMA tag\n", dd->dd_name); + device_printf(sc->sc_dev, + "cannot allocate %s DMA tag\n", dd->dd_name); return error; } @@ -3853,8 +3859,9 @@ ath_descdma_alloc_desc(struct ath_softc *sc, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dd->dd_dmamap); if (error != 0) { - if_printf(ifp, "unable to alloc memory for %u %s descriptors, " - "error %u\n", ndesc, dd->dd_name, error); + device_printf(sc->sc_dev, + "unable to alloc memory for %u %s descriptors, error %u\n", + ndesc, dd->dd_name, error); goto fail1; } @@ -3863,8 +3870,9 @@ ath_descdma_alloc_desc(struct ath_softc *sc, ath_load_cb, &dd->dd_desc_paddr, BUS_DMA_NOWAIT); if (error != 0) { - if_printf(ifp, "unable to map %s descriptors, error %u\n", - dd->dd_name, error); + device_printf(sc->sc_dev, + "unable to map %s descriptors, error %u\n", + dd->dd_name, error); goto fail2; } @@ -3894,7 +3902,6 @@ ath_descdma_setup(struct ath_softc *sc, ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) #define ATH_DESC_4KB_BOUND_CHECK(_daddr, _len) \ ((((u_int32_t)(_daddr) & 0xFFF) > (0x1000 - (_len))) ? 1 : 0) - struct ifnet *ifp = sc->sc_ifp; uint8_t *ds; struct ath_buf *bf; int i, bsize, error; @@ -3914,8 +3921,9 @@ ath_descdma_setup(struct ath_softc *sc, bsize = sizeof(struct ath_buf) * nbuf; bf = malloc(bsize, M_ATHDEV, M_NOWAIT | M_ZERO); if (bf == NULL) { - if_printf(ifp, "malloc of %s buffers failed, size %u\n", - dd->dd_name, bsize); + device_printf(sc->sc_dev, + "malloc of %s buffers failed, size %u\n", + dd->dd_name, bsize); goto fail3; } dd->dd_bufptr = bf; @@ -3941,8 +3949,9 @@ ath_descdma_setup(struct ath_softc *sc, error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT, &bf->bf_dmamap); if (error != 0) { - if_printf(ifp, "unable to create dmamap for %s " - "buffer %u, error %u\n", dd->dd_name, i, error); + device_printf(sc->sc_dev, "unable to create dmamap " + "for %s buffer %u, error %u\n", + dd->dd_name, i, error); ath_descdma_cleanup(sc, dd, head); return error; } @@ -3978,7 +3987,6 @@ ath_descdma_setup_rx_edma(struct ath_softc *sc, struct ath_descdma *dd, ath_bufhead *head, const char *name, int nbuf, int rx_status_len) { - struct ifnet *ifp = sc->sc_ifp; struct ath_buf *bf; int i, bsize, error; @@ -4001,8 +4009,9 @@ ath_descdma_setup_rx_edma(struct ath_softc *sc, bsize = sizeof(struct ath_buf) * nbuf; bf = malloc(bsize, M_ATHDEV, M_NOWAIT | M_ZERO); if (bf == NULL) { - if_printf(ifp, "malloc of %s buffers failed, size %u\n", - dd->dd_name, bsize); + device_printf(sc->sc_dev, + "malloc of %s buffers failed, size %u\n", + dd->dd_name, bsize); error = ENOMEM; goto fail3; } @@ -4017,8 +4026,9 @@ ath_descdma_setup_rx_edma(struct ath_softc *sc, error = bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT, &bf->bf_dmamap); if (error != 0) { - if_printf(ifp, "unable to create dmamap for %s " - "buffer %u, error %u\n", dd->dd_name, i, error); + device_printf(sc->sc_dev, "unable to create dmamap " + "for %s buffer %u, error %u\n", + dd->dd_name, i, error); ath_descdma_cleanup(sc, dd, head); return error; } @@ -4392,9 +4402,8 @@ ath_txq_update(struct ath_softc *sc, int ac) qi.tqi_aifs, qi.tqi_cwmin, qi.tqi_cwmax, qi.tqi_burstTime); if (!ath_hal_settxqueueprops(ah, txq->axq_qnum, &qi)) { - if_printf(ifp, "unable to update hardware queue " - "parameters for %s traffic!\n", - ieee80211_wme_acnames[ac]); + device_printf(sc->sc_dev, "unable to update hardware queue " + "parameters for %s traffic!\n", ieee80211_wme_acnames[ac]); return 0; } else { ath_hal_resettxqueue(ah, txq->axq_qnum); /* push to h/w */ @@ -5560,7 +5569,7 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan) ath_hal_setchainmasks(sc->sc_ah, sc->sc_cur_txchainmask, sc->sc_cur_rxchainmask); if (!ath_hal_reset(ah, sc->sc_opmode, chan, AH_TRUE, &status)) { - if_printf(ifp, "%s: unable to reset " + device_printf(sc->sc_dev, "%s: unable to reset " "channel %u (%u MHz, flags 0x%x), hal status %u\n", __func__, ieee80211_chan2ieee(ic, chan), chan->ic_freq, chan->ic_flags, status); @@ -5599,8 +5608,8 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan) * Re-enable rx framework. */ if (ath_startrecv(sc) != 0) { - if_printf(ifp, "%s: unable to restart recv logic\n", - __func__); + device_printf(sc->sc_dev, + "%s: unable to restart recv logic\n", __func__); ret = EIO; goto finish; } @@ -6375,8 +6384,9 @@ ath_getchannels(struct ath_softc *sc) status = ath_hal_init_channels(ah, ic->ic_channels, IEEE80211_CHAN_MAX, &ic->ic_nchans, HAL_MODE_ALL, CTRY_DEFAULT, SKU_NONE, AH_TRUE); if (status != HAL_OK) { - if_printf(ifp, "%s: unable to collect channel list from hal, " - "status %d\n", __func__, status); + device_printf(sc->sc_dev, + "%s: unable to collect channel list from hal, status %d\n", + __func__, status); return EINVAL; } (void) ath_hal_getregdomain(ah, &sc->sc_eerd); @@ -6538,10 +6548,10 @@ ath_watchdog(void *arg) if (ath_hal_gethangstate(sc->sc_ah, 0xffff, &hangs) && hangs != 0) { - if_printf(ifp, "%s hang detected (0x%x)\n", + device_printf(sc->sc_dev, "%s hang detected (0x%x)\n", hangs & 0xff ? "bb" : "mac", hangs); } else - if_printf(ifp, "device timeout\n"); + device_printf(sc->sc_dev, "device timeout\n"); do_reset = 1; if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); sc->sc_stats.ast_watchdog++; @@ -6786,31 +6796,32 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) static void ath_announce(struct ath_softc *sc) { - struct ifnet *ifp = sc->sc_ifp; struct ath_hal *ah = sc->sc_ah; - if_printf(ifp, "AR%s mac %d.%d RF%s phy %d.%d\n", + device_printf(sc->sc_dev, "AR%s mac %d.%d RF%s phy %d.%d\n", ath_hal_mac_name(ah), ah->ah_macVersion, ah->ah_macRev, ath_hal_rf_name(ah), ah->ah_phyRev >> 4, ah->ah_phyRev & 0xf); - if_printf(ifp, "2GHz radio: 0x%.4x; 5GHz radio: 0x%.4x\n", + device_printf(sc->sc_dev, "2GHz radio: 0x%.4x; 5GHz radio: 0x%.4x\n", ah->ah_analog2GhzRev, ah->ah_analog5GhzRev); if (bootverbose) { int i; for (i = 0; i <= WME_AC_VO; i++) { struct ath_txq *txq = sc->sc_ac2q[i]; - if_printf(ifp, "Use hw queue %u for %s traffic\n", - txq->axq_qnum, ieee80211_wme_acnames[i]); + device_printf(sc->sc_dev, + "Use hw queue %u for %s traffic\n", + txq->axq_qnum, ieee80211_wme_acnames[i]); } - if_printf(ifp, "Use hw queue %u for CAB traffic\n", - sc->sc_cabq->axq_qnum); - if_printf(ifp, "Use hw queue %u for beacons\n", sc->sc_bhalq); + device_printf(sc->sc_dev, "Use hw queue %u for CAB traffic\n", + sc->sc_cabq->axq_qnum); + device_printf(sc->sc_dev, "Use hw queue %u for beacons\n", + sc->sc_bhalq); } if (ath_rxbuf != ATH_RXBUF) - if_printf(ifp, "using %u rx buffers\n", ath_rxbuf); + device_printf(sc->sc_dev, "using %u rx buffers\n", ath_rxbuf); if (ath_txbuf != ATH_TXBUF) - if_printf(ifp, "using %u tx buffers\n", ath_txbuf); + device_printf(sc->sc_dev, "using %u tx buffers\n", ath_txbuf); if (sc->sc_mcastkey && bootverbose) - if_printf(ifp, "using multicast key search\n"); + device_printf(sc->sc_dev, "using multicast key search\n"); } static void diff --git a/sys/dev/ath/if_ath_rx.c b/sys/dev/ath/if_ath_rx.c index 07a4abe..2779b7a 100644 --- a/sys/dev/ath/if_ath_rx.c +++ b/sys/dev/ath/if_ath_rx.c @@ -1037,7 +1037,7 @@ ath_rx_proc(struct ath_softc *sc, int resched) bf = TAILQ_FIRST(&sc->sc_rxbuf); if (sc->sc_rxslink && bf == NULL) { /* NB: shouldn't happen */ - if_printf(ifp, "%s: no buffer!\n", __func__); + device_printf(sc->sc_dev, "%s: no buffer!\n", __func__); break; } else if (bf == NULL) { /* @@ -1054,7 +1054,7 @@ ath_rx_proc(struct ath_softc *sc, int resched) * will be no mbuf; try again to re-populate it. */ /* XXX make debug msg */ - if_printf(ifp, "%s: no mbuf!\n", __func__); + device_printf(sc->sc_dev, "%s: no mbuf!\n", __func__); TAILQ_REMOVE(&sc->sc_rxbuf, bf, bf_list); goto rx_proc_next; } diff --git a/sys/dev/ath/if_ath_tdma.c b/sys/dev/ath/if_ath_tdma.c index de1a91c..fd23db1 100644 --- a/sys/dev/ath/if_ath_tdma.c +++ b/sys/dev/ath/if_ath_tdma.c @@ -259,7 +259,7 @@ ath_tdma_config(struct ath_softc *sc, struct ieee80211vap *vap) if (vap == NULL) { vap = TAILQ_FIRST(&ic->ic_vaps); /* XXX */ if (vap == NULL) { - if_printf(ifp, "%s: no vaps?\n", __func__); + device_printf(sc->sc_dev, "%s: no vaps?\n", __func__); return; } } diff --git a/sys/dev/ath/if_ath_tx.c b/sys/dev/ath/if_ath_tx.c index 096278e..c15b158 100644 --- a/sys/dev/ath/if_ath_tx.c +++ b/sys/dev/ath/if_ath_tx.c @@ -1691,8 +1691,8 @@ ath_tx_normal_setup(struct ath_softc *sc, struct ieee80211_node *ni, flags |= HAL_TXDESC_NOACK; break; default: - if_printf(ifp, "bogus frame type 0x%x (%s)\n", - wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, __func__); + device_printf(sc->sc_dev, "bogus frame type 0x%x (%s)\n", + wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, __func__); /* XXX statistic */ /* XXX free tx dmamap */ ath_freetx(m0); diff --git a/sys/dev/bwi/bwimac.c b/sys/dev/bwi/bwimac.c index 849bf02..f39ef44 100644 --- a/sys/dev/bwi/bwimac.c +++ b/sys/dev/bwi/bwimac.c @@ -101,7 +101,6 @@ static void bwi_mac_opmode_init(struct bwi_mac *); static void bwi_mac_hostflags_init(struct bwi_mac *); static void bwi_mac_bss_param_init(struct bwi_mac *); -static int bwi_mac_fw_alloc(struct bwi_mac *); static void bwi_mac_fw_free(struct bwi_mac *); static int bwi_mac_fw_load(struct bwi_mac *); static int bwi_mac_fw_init(struct bwi_mac *); @@ -325,10 +324,6 @@ bwi_mac_init(struct bwi_mac *mac) /* * Load and initialize firmwares */ - error = bwi_mac_fw_alloc(mac); - if (error) - return error; - error = bwi_mac_fw_load(mac); if (error) return error; @@ -879,11 +874,10 @@ bwi_fwimage_is_valid(struct bwi_softc *sc, const struct firmware *fw, /* * XXX Error cleanup */ -static int +int bwi_mac_fw_alloc(struct bwi_mac *mac) { struct bwi_softc *sc = mac->mac_sc; - struct ifnet *ifp = sc->sc_ifp; char fwname[64]; int idx; @@ -895,10 +889,8 @@ bwi_mac_fw_alloc(struct bwi_mac *mac) snprintf(fwname, sizeof(fwname), BWI_FW_STUB_PATH, sc->sc_fw_version); mac->mac_stub = firmware_get(fwname); - if (mac->mac_stub == NULL) { - if_printf(ifp, "request firmware %s failed\n", fwname); - return ENOMEM; - } + if (mac->mac_stub == NULL) + goto no_firmware; } if (mac->mac_ucode == NULL) { @@ -907,11 +899,8 @@ bwi_mac_fw_alloc(struct bwi_mac *mac) mac->mac_rev >= 5 ? 5 : mac->mac_rev); mac->mac_ucode = firmware_get(fwname); - if (mac->mac_ucode == NULL) { - if_printf(ifp, "request firmware %s failed\n", fwname); - return ENOMEM; - } - + if (mac->mac_ucode == NULL) + goto no_firmware; if (!bwi_fwimage_is_valid(sc, mac->mac_ucode, BWI_FW_T_UCODE)) return EINVAL; } @@ -922,11 +911,8 @@ bwi_mac_fw_alloc(struct bwi_mac *mac) mac->mac_rev < 5 ? 4 : 5); mac->mac_pcm = firmware_get(fwname); - if (mac->mac_pcm == NULL) { - if_printf(ifp, "request firmware %s failed\n", fwname); - return ENOMEM; - } - + if (mac->mac_pcm == NULL) + goto no_firmware; if (!bwi_fwimage_is_valid(sc, mac->mac_pcm, BWI_FW_T_PCM)) return EINVAL; } @@ -938,8 +924,8 @@ bwi_mac_fw_alloc(struct bwi_mac *mac) } else if (mac->mac_rev >= 5 && mac->mac_rev <= 10) { idx = 5; } else { - if_printf(ifp, "no suitible IV for MAC rev %d\n", - mac->mac_rev); + device_printf(sc->sc_dev, + "no suitible IV for MAC rev %d\n", mac->mac_rev); return ENODEV; } @@ -947,10 +933,8 @@ bwi_mac_fw_alloc(struct bwi_mac *mac) sc->sc_fw_version, idx); mac->mac_iv = firmware_get(fwname); - if (mac->mac_iv == NULL) { - if_printf(ifp, "request firmware %s failed\n", fwname); - return ENOMEM; - } + if (mac->mac_iv == NULL) + goto no_firmware; if (!bwi_fwimage_is_valid(sc, mac->mac_iv, BWI_FW_T_IV)) return EINVAL; } @@ -960,12 +944,12 @@ bwi_mac_fw_alloc(struct bwi_mac *mac) if (mac->mac_rev == 2 || mac->mac_rev == 4 || mac->mac_rev >= 11) { /* No extended IV */ - goto back; + return (0); } else if (mac->mac_rev >= 5 && mac->mac_rev <= 10) { idx = 5; } else { - if_printf(ifp, "no suitible ExtIV for MAC rev %d\n", - mac->mac_rev); + device_printf(sc->sc_dev, + "no suitible ExtIV for MAC rev %d\n", mac->mac_rev); return ENODEV; } @@ -973,15 +957,16 @@ bwi_mac_fw_alloc(struct bwi_mac *mac) sc->sc_fw_version, idx); mac->mac_iv_ext = firmware_get(fwname); - if (mac->mac_iv_ext == NULL) { - if_printf(ifp, "request firmware %s failed\n", fwname); - return ENOMEM; - } + if (mac->mac_iv_ext == NULL) + goto no_firmware; if (!bwi_fwimage_is_valid(sc, mac->mac_iv_ext, BWI_FW_T_IV)) return EINVAL; } -back: - return 0; + return (0); + +no_firmware: + device_printf(sc->sc_dev, "request firmware %s failed\n", fwname); + return (ENOENT); } static void diff --git a/sys/dev/bwi/bwimac.h b/sys/dev/bwi/bwimac.h index 2c5275e..a6d9008 100644 --- a/sys/dev/bwi/bwimac.h +++ b/sys/dev/bwi/bwimac.h @@ -57,6 +57,7 @@ void bwi_mac_init_tpctl_11bg(struct bwi_mac *); void bwi_mac_dummy_xmit(struct bwi_mac *); void bwi_mac_reset_hwkeys(struct bwi_mac *); int bwi_mac_config_ps(struct bwi_mac *); +int bwi_mac_fw_alloc(struct bwi_mac *); uint16_t bwi_memobj_read_2(struct bwi_mac *, uint16_t, uint16_t); uint32_t bwi_memobj_read_4(struct bwi_mac *, uint16_t, uint16_t); diff --git a/sys/dev/bwi/if_bwi.c b/sys/dev/bwi/if_bwi.c index 97b7021..ad41bc6 100644 --- a/sys/dev/bwi/if_bwi.c +++ b/sys/dev/bwi/if_bwi.c @@ -446,6 +446,10 @@ bwi_attach(struct bwi_softc *sc) if (error) goto fail; + error = bwi_mac_fw_alloc(mac); + if (error) + goto fail; + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); if (ifp == NULL) { device_printf(dev, "can not if_alloc()\n"); @@ -1921,7 +1925,7 @@ bwi_dma_alloc(struct bwi_softc *sc) BUS_SPACE_MAXSIZE, /* maxsize */ BUS_SPACE_UNRESTRICTED, /* nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ - BUS_DMA_ALLOCNOW, /* flags */ + 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->sc_parent_dtag); if (error) { @@ -1941,8 +1945,8 @@ bwi_dma_alloc(struct bwi_softc *sc) NULL, NULL, tx_ring_sz, 1, - BUS_SPACE_MAXSIZE_32BIT, - BUS_DMA_ALLOCNOW, + tx_ring_sz, + 0, NULL, NULL, &sc->sc_txring_dtag); if (error) { @@ -1971,8 +1975,8 @@ bwi_dma_alloc(struct bwi_softc *sc) NULL, NULL, rx_ring_sz, 1, - BUS_SPACE_MAXSIZE_32BIT, - BUS_DMA_ALLOCNOW, + rx_ring_sz, + 0, NULL, NULL, &sc->sc_rxring_dtag); if (error) { @@ -2096,8 +2100,8 @@ bwi_dma_txstats_alloc(struct bwi_softc *sc, uint32_t ctrl_base, NULL, NULL, dma_size, 1, - BUS_SPACE_MAXSIZE_32BIT, - BUS_DMA_ALLOCNOW, + dma_size, + 0, NULL, NULL, &st->stats_ring_dtag); if (error) { @@ -2144,8 +2148,8 @@ bwi_dma_txstats_alloc(struct bwi_softc *sc, uint32_t ctrl_base, NULL, NULL, dma_size, 1, - BUS_SPACE_MAXSIZE_32BIT, - BUS_DMA_ALLOCNOW, + dma_size, + 0, NULL, NULL, &st->stats_dtag); if (error) { @@ -2227,7 +2231,7 @@ bwi_dma_mbuf_create(struct bwi_softc *sc) NULL, NULL, MCLBYTES, 1, - BUS_SPACE_MAXSIZE_32BIT, + MCLBYTES, BUS_DMA_ALLOCNOW, NULL, NULL, &sc->sc_buf_dtag); diff --git a/sys/dev/bwi/if_bwi_pci.c b/sys/dev/bwi/if_bwi_pci.c index 1977b93..c2badc5 100644 --- a/sys/dev/bwi/if_bwi_pci.c +++ b/sys/dev/bwi/if_bwi_pci.c @@ -161,12 +161,6 @@ bwi_pci_attach(device_t dev) device_printf(dev, "could not map interrupt\n"); goto bad1; } - if (bus_setup_intr(dev, sc->sc_irq_res, - INTR_TYPE_NET | INTR_MPSAFE, - NULL, bwi_intr, sc, &sc->sc_irq_handle)) { - device_printf(dev, "could not establish interrupt\n"); - goto bad2; - } /* Get more PCI information */ sc->sc_pci_did = pci_get_device(dev); @@ -174,11 +168,17 @@ bwi_pci_attach(device_t dev) sc->sc_pci_subvid = pci_get_subvendor(dev); sc->sc_pci_subdid = pci_get_subdevice(dev); - error = bwi_attach(sc); - if (error == 0) /* success */ - return 0; + if ((error = bwi_attach(sc)) != 0) + goto bad2; + + if (bus_setup_intr(dev, sc->sc_irq_res, + INTR_TYPE_NET | INTR_MPSAFE, + NULL, bwi_intr, sc, &sc->sc_irq_handle)) { + device_printf(dev, "could not establish interrupt\n"); + goto bad2; + } + return (0); - bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_handle); bad2: bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); bad1: diff --git a/sys/dev/ichiic/ig4_iic.c b/sys/dev/ichiic/ig4_iic.c new file mode 100644 index 0000000..e9081e3 --- /dev/null +++ b/sys/dev/ichiic/ig4_iic.c @@ -0,0 +1,966 @@ +/* + * Copyright (c) 2014 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Matthew Dillon <dillon@backplane.com> and was subsequently ported + * to FreeBSD by Michael Gmelin <freebsd@grem.de> + * + * 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 DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS 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$"); + +/* + * Intel fourth generation mobile cpus integrated I2C device, smbus driver. + * + * See ig4_reg.h for datasheet reference and notes. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/errno.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/syslog.h> +#include <sys/bus.h> +#include <sys/sysctl.h> + +#include <machine/bus.h> +#include <sys/rman.h> + +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> +#include <dev/smbus/smbconf.h> + +#include <dev/ichiic/ig4_reg.h> +#include <dev/ichiic/ig4_var.h> + +#define TRANS_NORMAL 1 +#define TRANS_PCALL 2 +#define TRANS_BLOCK 3 + +static void ig4iic_start(void *xdev); +static void ig4iic_intr(void *cookie); +static void ig4iic_dump(ig4iic_softc_t *sc); + +static int ig4_dump; +SYSCTL_INT(_debug, OID_AUTO, ig4_dump, CTLTYPE_INT | CTLFLAG_RW, + &ig4_dump, 0, ""); + +/* + * Low-level inline support functions + */ +static __inline void +reg_write(ig4iic_softc_t *sc, uint32_t reg, uint32_t value) +{ + bus_write_4(sc->regs_res, reg, value); + bus_barrier(sc->regs_res, reg, 4, BUS_SPACE_BARRIER_WRITE); +} + +static __inline uint32_t +reg_read(ig4iic_softc_t *sc, uint32_t reg) +{ + uint32_t value; + + bus_barrier(sc->regs_res, reg, 4, BUS_SPACE_BARRIER_READ); + value = bus_read_4(sc->regs_res, reg); + return (value); +} + +/* + * Enable or disable the controller and wait for the controller to acknowledge + * the state change. + */ +static int +set_controller(ig4iic_softc_t *sc, uint32_t ctl) +{ + int retry; + int error; + uint32_t v; + + reg_write(sc, IG4_REG_I2C_EN, ctl); + error = SMB_ETIMEOUT; + + for (retry = 100; retry > 0; --retry) { + v = reg_read(sc, IG4_REG_ENABLE_STATUS); + if (((v ^ ctl) & IG4_I2C_ENABLE) == 0) { + error = 0; + break; + } + mtx_sleep(sc, &sc->mutex, 0, "i2cslv", 1); + } + return (error); +} + +/* + * Wait up to 25ms for the requested status using a 25uS polling loop. + */ +static int +wait_status(ig4iic_softc_t *sc, uint32_t status) +{ + uint32_t v; + int error; + int txlvl = -1; + u_int count_us = 0; + u_int limit_us = 25000; /* 25ms */ + + error = SMB_ETIMEOUT; + + for (;;) { + /* + * Check requested status + */ + v = reg_read(sc, IG4_REG_I2C_STA); + if (v & status) { + error = 0; + break; + } + + /* + * When waiting for receive data break-out if the interrupt + * loaded data into the FIFO. + */ + if (status & IG4_STATUS_RX_NOTEMPTY) { + if (sc->rpos != sc->rnext) { + error = 0; + break; + } + } + + /* + * When waiting for the transmit FIFO to become empty, + * reset the timeout if we see a change in the transmit + * FIFO level as progress is being made. + */ + if (status & IG4_STATUS_TX_EMPTY) { + v = reg_read(sc, IG4_REG_TXFLR) & IG4_FIFOLVL_MASK; + if (txlvl != v) { + txlvl = v; + count_us = 0; + } + } + + /* + * Stop if we've run out of time. + */ + if (count_us >= limit_us) + break; + + /* + * When waiting for receive data let the interrupt do its + * work, otherwise poll with the lock held. + */ + if (status & IG4_STATUS_RX_NOTEMPTY) { + mtx_sleep(sc, &sc->mutex, PZERO, "i2cwait", + (hz + 99) / 100); /* sleep up to 10ms */ + count_us += 10000; + } else { + DELAY(25); + count_us += 25; + } + } + + return (error); +} + +/* + * Read I2C data. The data might have already been read by + * the interrupt code, otherwise it is sitting in the data + * register. + */ +static uint8_t +data_read(ig4iic_softc_t *sc) +{ + uint8_t c; + + if (sc->rpos == sc->rnext) { + c = (uint8_t)reg_read(sc, IG4_REG_DATA_CMD); + } else { + c = sc->rbuf[sc->rpos & IG4_RBUFMASK]; + ++sc->rpos; + } + return (c); +} + +/* + * Set the slave address. The controller must be disabled when + * changing the address. + * + * This operation does not issue anything to the I2C bus but sets + * the target address for when the controller later issues a START. + */ +static void +set_slave_addr(ig4iic_softc_t *sc, uint8_t slave, int trans_op) +{ + uint32_t tar; + uint32_t ctl; + int use_10bit; + + use_10bit = sc->use_10bit; + if (trans_op & SMB_TRANS_7BIT) + use_10bit = 0; + if (trans_op & SMB_TRANS_10BIT) + use_10bit = 1; + + if (sc->slave_valid && sc->last_slave == slave && + sc->use_10bit == use_10bit) { + return; + } + sc->use_10bit = use_10bit; + + /* + * Wait for TXFIFO to drain before disabling the controller. + * + * If a write message has not been completed it's really a + * programming error, but for now in that case issue an extra + * byte + STOP. + * + * If a read message has not been completed it's also a programming + * error, for now just ignore it. + */ + wait_status(sc, IG4_STATUS_TX_NOTFULL); + if (sc->write_started) { + reg_write(sc, IG4_REG_DATA_CMD, IG4_DATA_STOP); + sc->write_started = 0; + } + if (sc->read_started) + sc->read_started = 0; + wait_status(sc, IG4_STATUS_TX_EMPTY); + + set_controller(sc, 0); + ctl = reg_read(sc, IG4_REG_CTL); + ctl &= ~IG4_CTL_10BIT; + ctl |= IG4_CTL_RESTARTEN; + + tar = slave; + if (sc->use_10bit) { + tar |= IG4_TAR_10BIT; + ctl |= IG4_CTL_10BIT; + } + reg_write(sc, IG4_REG_CTL, ctl); + reg_write(sc, IG4_REG_TAR_ADD, tar); + set_controller(sc, IG4_I2C_ENABLE); + sc->slave_valid = 1; + sc->last_slave = slave; +} + +/* + * Issue START with byte command, possible count, and a variable length + * read or write buffer, then possible turn-around read. The read also + * has a possible count received. + * + * For SMBUS - + * + * Quick: START+ADDR+RD/WR STOP + * + * Normal: START+ADDR+WR CMD DATA..DATA STOP + * + * START+ADDR+RD CMD + * RESTART+ADDR RDATA..RDATA STOP + * (can also be used for I2C transactions) + * + * Process Call: START+ADDR+WR CMD DATAL DATAH + * RESTART+ADDR+RD RDATAL RDATAH STOP + * + * Block: START+ADDR+RD CMD + * RESTART+ADDR+RD RCOUNT DATA... STOP + * + * START+ADDR+WR CMD + * RESTART+ADDR+WR WCOUNT DATA... STOP + * + * For I2C - basically, no *COUNT fields, possibly no *CMD field. If the + * sender needs to issue a 2-byte command it will incorporate it + * into the write buffer and also set NOCMD. + * + * Generally speaking, the START+ADDR / RESTART+ADDR is handled automatically + * by the controller at the beginning of a command sequence or on a data + * direction turn-around, and we only need to tell it when to issue the STOP. + */ +static int +smb_transaction(ig4iic_softc_t *sc, char cmd, int op, + char *wbuf, int wcount, char *rbuf, int rcount, int *actualp) +{ + int error; + int unit; + uint32_t last; + + /* + * Debugging - dump registers + */ + if (ig4_dump) { + unit = device_get_unit(sc->dev); + if (ig4_dump & (1 << unit)) { + ig4_dump &= ~(1 << unit); + ig4iic_dump(sc); + } + } + + /* + * Issue START or RESTART with next data byte, clear any previous + * abort condition that may have been holding the txfifo in reset. + */ + last = IG4_DATA_RESTART; + reg_read(sc, IG4_REG_CLR_TX_ABORT); + if (actualp) + *actualp = 0; + + /* + * Issue command if not told otherwise (smbus). + */ + if ((op & SMB_TRANS_NOCMD) == 0) { + error = wait_status(sc, IG4_STATUS_TX_NOTFULL); + if (error) + goto done; + last |= (u_char)cmd; + if (wcount == 0 && rcount == 0 && (op & SMB_TRANS_NOSTOP) == 0) + last |= IG4_DATA_STOP; + reg_write(sc, IG4_REG_DATA_CMD, last); + last = 0; + } + + /* + * Clean out any previously received data. + */ + if (sc->rpos != sc->rnext && + (op & SMB_TRANS_NOREPORT) == 0) { + device_printf(sc->dev, + "discarding %d bytes of spurious data\n", + sc->rnext - sc->rpos); + } + sc->rpos = 0; + sc->rnext = 0; + + /* + * If writing and not told otherwise, issue the write count (smbus). + */ + if (wcount && (op & SMB_TRANS_NOCNT) == 0) { + error = wait_status(sc, IG4_STATUS_TX_NOTFULL); + if (error) + goto done; + last |= (u_char)cmd; + reg_write(sc, IG4_REG_DATA_CMD, last); + last = 0; + } + + /* + * Bulk write (i2c) + */ + while (wcount) { + error = wait_status(sc, IG4_STATUS_TX_NOTFULL); + if (error) + goto done; + last |= (u_char)*wbuf; + if (wcount == 1 && rcount == 0 && (op & SMB_TRANS_NOSTOP) == 0) + last |= IG4_DATA_STOP; + reg_write(sc, IG4_REG_DATA_CMD, last); + --wcount; + ++wbuf; + last = 0; + } + + /* + * Issue reads to xmit FIFO (strange, I know) to tell the controller + * to clock in data. At the moment just issue one read ahead to + * pipeline the incoming data. + * + * NOTE: In the case of NOCMD and wcount == 0 we still issue a + * RESTART here, even if the data direction has not changed + * from the previous CHAINing call. This we force the RESTART. + * (A new START is issued automatically by the controller in + * the other nominal cases such as a data direction change or + * a previous STOP was issued). + * + * If this will be the last byte read we must also issue the STOP + * at the end of the read. + */ + if (rcount) { + last = IG4_DATA_RESTART | IG4_DATA_COMMAND_RD; + if (rcount == 1 && + (op & (SMB_TRANS_NOSTOP | SMB_TRANS_NOCNT)) == + SMB_TRANS_NOCNT) { + last |= IG4_DATA_STOP; + } + reg_write(sc, IG4_REG_DATA_CMD, last); + last = IG4_DATA_COMMAND_RD; + } + + /* + * Bulk read (i2c) and count field handling (smbus) + */ + while (rcount) { + /* + * Maintain a pipeline by queueing the allowance for the next + * read before waiting for the current read. + */ + if (rcount > 1) { + if (op & SMB_TRANS_NOCNT) + last = (rcount == 2) ? IG4_DATA_STOP : 0; + else + last = 0; + reg_write(sc, IG4_REG_DATA_CMD, IG4_DATA_COMMAND_RD | + last); + } + error = wait_status(sc, IG4_STATUS_RX_NOTEMPTY); + if (error) { + if ((op & SMB_TRANS_NOREPORT) == 0) { + device_printf(sc->dev, + "rx timeout addr 0x%02x\n", + sc->last_slave); + } + goto done; + } + last = data_read(sc); + + if (op & SMB_TRANS_NOCNT) { + *rbuf = (u_char)last; + ++rbuf; + --rcount; + if (actualp) + ++*actualp; + } else { + /* + * Handle count field (smbus), which is not part of + * the rcount'ed buffer. The first read data in a + * bulk transfer is the count. + * + * XXX if rcount is loaded as 0 how do I generate a + * STOP now without issuing another RD or WR? + */ + if (rcount > (u_char)last) + rcount = (u_char)last; + op |= SMB_TRANS_NOCNT; + } + } + error = 0; +done: + /* XXX wait for xmit buffer to become empty */ + last = reg_read(sc, IG4_REG_TX_ABRT_SOURCE); + + return (error); +} + +/* + * SMBUS API FUNCTIONS + * + * Called from ig4iic_pci_attach/detach() + */ +int +ig4iic_attach(ig4iic_softc_t *sc) +{ + int error; + uint32_t v; + + v = reg_read(sc, IG4_REG_COMP_TYPE); + v = reg_read(sc, IG4_REG_COMP_PARAM1); + v = reg_read(sc, IG4_REG_GENERAL); + if ((v & IG4_GENERAL_SWMODE) == 0) { + v |= IG4_GENERAL_SWMODE; + reg_write(sc, IG4_REG_GENERAL, v); + v = reg_read(sc, IG4_REG_GENERAL); + } + + v = reg_read(sc, IG4_REG_SW_LTR_VALUE); + v = reg_read(sc, IG4_REG_AUTO_LTR_VALUE); + + v = reg_read(sc, IG4_REG_COMP_VER); + if (v != IG4_COMP_VER) { + error = ENXIO; + goto done; + } + v = reg_read(sc, IG4_REG_SS_SCL_HCNT); + v = reg_read(sc, IG4_REG_SS_SCL_LCNT); + v = reg_read(sc, IG4_REG_FS_SCL_HCNT); + v = reg_read(sc, IG4_REG_FS_SCL_LCNT); + v = reg_read(sc, IG4_REG_SDA_HOLD); + + v = reg_read(sc, IG4_REG_SS_SCL_HCNT); + reg_write(sc, IG4_REG_FS_SCL_HCNT, v); + v = reg_read(sc, IG4_REG_SS_SCL_LCNT); + reg_write(sc, IG4_REG_FS_SCL_LCNT, v); + + /* + * Program based on a 25000 Hz clock. This is a bit of a + * hack (obviously). The defaults are 400 and 470 for standard + * and 60 and 130 for fast. The defaults for standard fail + * utterly (presumably cause an abort) because the clock time + * is ~18.8ms by default. This brings it down to ~4ms (for now). + */ + reg_write(sc, IG4_REG_SS_SCL_HCNT, 100); + reg_write(sc, IG4_REG_SS_SCL_LCNT, 125); + reg_write(sc, IG4_REG_FS_SCL_HCNT, 100); + reg_write(sc, IG4_REG_FS_SCL_LCNT, 125); + + /* + * Use a threshold of 1 so we get interrupted on each character, + * allowing us to use mtx_sleep() in our poll code. Not perfect + * but this is better than using DELAY() for receiving data. + */ + reg_write(sc, IG4_REG_RX_TL, 1); + + reg_write(sc, IG4_REG_CTL, + IG4_CTL_MASTER | + IG4_CTL_SLAVE_DISABLE | + IG4_CTL_RESTARTEN | + IG4_CTL_SPEED_STD); + + sc->smb = device_add_child(sc->dev, "smbus", -1); + if (sc->smb == NULL) { + device_printf(sc->dev, "smbus driver not found\n"); + error = ENXIO; + goto done; + } + +#if 0 + /* + * Don't do this, it blows up the PCI config + */ + reg_write(sc, IG4_REG_RESETS, IG4_RESETS_ASSERT); + reg_write(sc, IG4_REG_RESETS, IG4_RESETS_DEASSERT); +#endif + + /* + * Interrupt on STOP detect or receive character ready + */ + reg_write(sc, IG4_REG_INTR_MASK, IG4_INTR_STOP_DET | + IG4_INTR_RX_FULL); + mtx_lock(&sc->mutex); + if (set_controller(sc, 0)) + device_printf(sc->dev, "controller error during attach-1\n"); + if (set_controller(sc, IG4_I2C_ENABLE)) + device_printf(sc->dev, "controller error during attach-2\n"); + mtx_unlock(&sc->mutex); + error = bus_setup_intr(sc->dev, sc->intr_res, INTR_TYPE_MISC | INTR_MPSAFE, + NULL, ig4iic_intr, sc, &sc->intr_handle); + if (error) { + device_printf(sc->dev, + "Unable to setup irq: error %d\n", error); + } + + sc->enum_hook.ich_func = ig4iic_start; + sc->enum_hook.ich_arg = sc->dev; + + /* We have to wait until interrupts are enabled. I2C read and write + * only works if the interrupts are available. + */ + if (config_intrhook_establish(&sc->enum_hook) != 0) + error = ENOMEM; + else + error = 0; + +done: + return (error); +} + +void +ig4iic_start(void *xdev) +{ + int error; + ig4iic_softc_t *sc; + device_t dev = (device_t)xdev; + + sc = device_get_softc(dev); + + config_intrhook_disestablish(&sc->enum_hook); + + /* Attach us to the smbus */ + error = bus_generic_attach(sc->dev); + if (error) { + device_printf(sc->dev, + "failed to attach child: error %d\n", error); + } +} + + + +int +ig4iic_detach(ig4iic_softc_t *sc) +{ + int error; + + if (device_is_attached(sc->dev)) { + error = bus_generic_detach(sc->dev); + if (error) + return (error); + } + if (sc->smb) + device_delete_child(sc->dev, sc->smb); + if (sc->intr_handle) + bus_teardown_intr(sc->dev, sc->intr_res, sc->intr_handle); + + mtx_lock(&sc->mutex); + + sc->smb = NULL; + sc->intr_handle = NULL; + reg_write(sc, IG4_REG_INTR_MASK, 0); + reg_read(sc, IG4_REG_CLR_INTR); + set_controller(sc, 0); + + mtx_unlock(&sc->mutex); + return (0); +} + +int +ig4iic_smb_callback(device_t dev, int index, void *data) +{ + ig4iic_softc_t *sc = device_get_softc(dev); + int error; + + mtx_lock(&sc->mutex); + + switch (index) { + case SMB_REQUEST_BUS: + error = 0; + break; + case SMB_RELEASE_BUS: + error = 0; + break; + default: + error = SMB_EABORT; + break; + } + + mtx_unlock(&sc->mutex); + + return (error); +} + +/* + * Quick command. i.e. START + cmd + R/W + STOP and no data. It is + * unclear to me how I could implement this with the intel i2c controller + * because the controler sends STARTs and STOPs automatically with data. + */ +int +ig4iic_smb_quick(device_t dev, u_char slave, int how) +{ + ig4iic_softc_t *sc = device_get_softc(dev); + int error; + + mtx_lock(&sc->mutex); + + switch (how) { + case SMB_QREAD: + error = SMB_ENOTSUPP; + break; + case SMB_QWRITE: + error = SMB_ENOTSUPP; + break; + default: + error = SMB_ENOTSUPP; + break; + } + mtx_unlock(&sc->mutex); + + return (error); +} + +/* + * Incremental send byte without stop (?). It is unclear why the slave + * address is specified if this presumably is used in combination with + * ig4iic_smb_quick(). + * + * (Also, how would this work anyway? Issue the last byte with writeb()?) + */ +int +ig4iic_smb_sendb(device_t dev, u_char slave, char byte) +{ + ig4iic_softc_t *sc = device_get_softc(dev); + uint32_t cmd; + int error; + + mtx_lock(&sc->mutex); + + set_slave_addr(sc, slave, 0); + cmd = byte; + if (wait_status(sc, IG4_STATUS_TX_NOTFULL) == 0) { + reg_write(sc, IG4_REG_DATA_CMD, cmd); + error = 0; + } else { + error = SMB_ETIMEOUT; + } + + mtx_unlock(&sc->mutex); + return (error); +} + +/* + * Incremental receive byte without stop (?). It is unclear why the slave + * address is specified if this presumably is used in combination with + * ig4iic_smb_quick(). + */ +int +ig4iic_smb_recvb(device_t dev, u_char slave, char *byte) +{ + ig4iic_softc_t *sc = device_get_softc(dev); + int error; + + mtx_lock(&sc->mutex); + + set_slave_addr(sc, slave, 0); + reg_write(sc, IG4_REG_DATA_CMD, IG4_DATA_COMMAND_RD); + if (wait_status(sc, IG4_STATUS_RX_NOTEMPTY) == 0) { + *byte = data_read(sc); + error = 0; + } else { + *byte = 0; + error = SMB_ETIMEOUT; + } + + mtx_unlock(&sc->mutex); + return (error); +} + +/* + * Write command and single byte in transaction. + */ +int +ig4iic_smb_writeb(device_t dev, u_char slave, char cmd, char byte) +{ + ig4iic_softc_t *sc = device_get_softc(dev); + int error; + + mtx_lock(&sc->mutex); + + set_slave_addr(sc, slave, 0); + error = smb_transaction(sc, cmd, SMB_TRANS_NOCNT, + &byte, 1, NULL, 0, NULL); + + mtx_unlock(&sc->mutex); + return (error); +} + +/* + * Write command and single word in transaction. + */ +int +ig4iic_smb_writew(device_t dev, u_char slave, char cmd, short word) +{ + ig4iic_softc_t *sc = device_get_softc(dev); + char buf[2]; + int error; + + mtx_lock(&sc->mutex); + + set_slave_addr(sc, slave, 0); + buf[0] = word & 0xFF; + buf[1] = word >> 8; + error = smb_transaction(sc, cmd, SMB_TRANS_NOCNT, + buf, 2, NULL, 0, NULL); + + mtx_unlock(&sc->mutex); + return (error); +} + +/* + * write command and read single byte in transaction. + */ +int +ig4iic_smb_readb(device_t dev, u_char slave, char cmd, char *byte) +{ + ig4iic_softc_t *sc = device_get_softc(dev); + int error; + + mtx_lock(&sc->mutex); + + set_slave_addr(sc, slave, 0); + error = smb_transaction(sc, cmd, SMB_TRANS_NOCNT, + NULL, 0, byte, 1, NULL); + + mtx_unlock(&sc->mutex); + return (error); +} + +/* + * write command and read word in transaction. + */ +int +ig4iic_smb_readw(device_t dev, u_char slave, char cmd, short *word) +{ + ig4iic_softc_t *sc = device_get_softc(dev); + char buf[2]; + int error; + + mtx_lock(&sc->mutex); + + set_slave_addr(sc, slave, 0); + if ((error = smb_transaction(sc, cmd, SMB_TRANS_NOCNT, + NULL, 0, buf, 2, NULL)) == 0) { + *word = (u_char)buf[0] | ((u_char)buf[1] << 8); + } + + mtx_unlock(&sc->mutex); + return (error); +} + +/* + * write command and word and read word in transaction + */ +int +ig4iic_smb_pcall(device_t dev, u_char slave, char cmd, + short sdata, short *rdata) +{ + ig4iic_softc_t *sc = device_get_softc(dev); + char rbuf[2]; + char wbuf[2]; + int error; + + mtx_lock(&sc->mutex); + + set_slave_addr(sc, slave, 0); + wbuf[0] = sdata & 0xFF; + wbuf[1] = sdata >> 8; + if ((error = smb_transaction(sc, cmd, SMB_TRANS_NOCNT, + wbuf, 2, rbuf, 2, NULL)) == 0) { + *rdata = (u_char)rbuf[0] | ((u_char)rbuf[1] << 8); + } + + mtx_unlock(&sc->mutex); + return (error); +} + +int +ig4iic_smb_bwrite(device_t dev, u_char slave, char cmd, + u_char wcount, char *buf) +{ + ig4iic_softc_t *sc = device_get_softc(dev); + int error; + + mtx_lock(&sc->mutex); + + set_slave_addr(sc, slave, 0); + error = smb_transaction(sc, cmd, 0, + buf, wcount, NULL, 0, NULL); + + mtx_unlock(&sc->mutex); + return (error); +} + +int +ig4iic_smb_bread(device_t dev, u_char slave, char cmd, + u_char *countp_char, char *buf) +{ + ig4iic_softc_t *sc = device_get_softc(dev); + int rcount = *countp_char; + int error; + + mtx_lock(&sc->mutex); + + set_slave_addr(sc, slave, 0); + error = smb_transaction(sc, cmd, 0, + NULL, 0, buf, rcount, &rcount); + *countp_char = rcount; + + mtx_unlock(&sc->mutex); + return (error); +} + +int +ig4iic_smb_trans(device_t dev, int slave, char cmd, int op, + char *wbuf, int wcount, char *rbuf, int rcount, + int *actualp) +{ + ig4iic_softc_t *sc = device_get_softc(dev); + int error; + + mtx_lock(&sc->mutex); + + set_slave_addr(sc, slave, op); + error = smb_transaction(sc, cmd, op, + wbuf, wcount, rbuf, rcount, actualp); + + mtx_unlock(&sc->mutex); + return (error); +} + +/* + * Interrupt Operation + */ +static void +ig4iic_intr(void *cookie) +{ + ig4iic_softc_t *sc = cookie; + uint32_t status; + + mtx_lock(&sc->mutex); +/* reg_write(sc, IG4_REG_INTR_MASK, IG4_INTR_STOP_DET);*/ + status = reg_read(sc, IG4_REG_I2C_STA); + while (status & IG4_STATUS_RX_NOTEMPTY) { + sc->rbuf[sc->rnext & IG4_RBUFMASK] = + (uint8_t)reg_read(sc, IG4_REG_DATA_CMD); + ++sc->rnext; + status = reg_read(sc, IG4_REG_I2C_STA); + } + reg_read(sc, IG4_REG_CLR_INTR); + wakeup(sc); + mtx_unlock(&sc->mutex); +} + +#define REGDUMP(sc, reg) \ + device_printf(sc->dev, " %-23s %08x\n", #reg, reg_read(sc, reg)) + +static void +ig4iic_dump(ig4iic_softc_t *sc) +{ + device_printf(sc->dev, "ig4iic register dump:\n"); + REGDUMP(sc, IG4_REG_CTL); + REGDUMP(sc, IG4_REG_TAR_ADD); + REGDUMP(sc, IG4_REG_SS_SCL_HCNT); + REGDUMP(sc, IG4_REG_SS_SCL_LCNT); + REGDUMP(sc, IG4_REG_FS_SCL_HCNT); + REGDUMP(sc, IG4_REG_FS_SCL_LCNT); + REGDUMP(sc, IG4_REG_INTR_STAT); + REGDUMP(sc, IG4_REG_INTR_MASK); + REGDUMP(sc, IG4_REG_RAW_INTR_STAT); + REGDUMP(sc, IG4_REG_RX_TL); + REGDUMP(sc, IG4_REG_TX_TL); + REGDUMP(sc, IG4_REG_I2C_EN); + REGDUMP(sc, IG4_REG_I2C_STA); + REGDUMP(sc, IG4_REG_TXFLR); + REGDUMP(sc, IG4_REG_RXFLR); + REGDUMP(sc, IG4_REG_SDA_HOLD); + REGDUMP(sc, IG4_REG_TX_ABRT_SOURCE); + REGDUMP(sc, IG4_REG_SLV_DATA_NACK); + REGDUMP(sc, IG4_REG_DMA_CTRL); + REGDUMP(sc, IG4_REG_DMA_TDLR); + REGDUMP(sc, IG4_REG_DMA_RDLR); + REGDUMP(sc, IG4_REG_SDA_SETUP); + REGDUMP(sc, IG4_REG_ENABLE_STATUS); + REGDUMP(sc, IG4_REG_COMP_PARAM1); + REGDUMP(sc, IG4_REG_COMP_VER); + REGDUMP(sc, IG4_REG_COMP_TYPE); + REGDUMP(sc, IG4_REG_CLK_PARMS); + REGDUMP(sc, IG4_REG_RESETS); + REGDUMP(sc, IG4_REG_GENERAL); + REGDUMP(sc, IG4_REG_SW_LTR_VALUE); + REGDUMP(sc, IG4_REG_AUTO_LTR_VALUE); +} +#undef REGDUMP + +DRIVER_MODULE(smbus, ig4iic, smbus_driver, smbus_devclass, NULL, NULL); diff --git a/sys/dev/ichiic/ig4_pci.c b/sys/dev/ichiic/ig4_pci.c new file mode 100644 index 0000000..42c3664 --- /dev/null +++ b/sys/dev/ichiic/ig4_pci.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2014 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Matthew Dillon <dillon@backplane.com> and was subsequently ported + * to FreeBSD by Michael Gmelin <freebsd@grem.de> + * + * 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 DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS 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$"); + +/* + * Intel fourth generation mobile cpus integrated I2C device, smbus driver. + * + * See ig4_reg.h for datasheet reference and notes. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/errno.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/syslog.h> +#include <sys/bus.h> + +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> +#include <dev/smbus/smbconf.h> + +#include "smbus_if.h" + +#include <dev/ichiic/ig4_reg.h> +#include <dev/ichiic/ig4_var.h> + +static int ig4iic_pci_detach(device_t dev); + +#define PCI_CHIP_LYNXPT_LP_I2C_1 0x9c618086 +#define PCI_CHIP_LYNXPT_LP_I2C_2 0x9c628086 + +static int +ig4iic_pci_probe(device_t dev) +{ + switch(pci_get_devid(dev)) { + case PCI_CHIP_LYNXPT_LP_I2C_1: + device_set_desc(dev, "Intel Lynx Point-LP I2C Controller-1"); + break; + case PCI_CHIP_LYNXPT_LP_I2C_2: + device_set_desc(dev, "Intel Lynx Point-LP I2C Controller-2"); + break; + default: + return (ENXIO); + } + return (BUS_PROBE_DEFAULT); +} + +static int +ig4iic_pci_attach(device_t dev) +{ + ig4iic_softc_t *sc = device_get_softc(dev); + int error; + + bzero(sc, sizeof(*sc)); + + mtx_init(&sc->mutex, device_get_nameunit(dev), "ig4iic", MTX_DEF); + + sc->dev = dev; + sc->regs_rid = PCIR_BAR(0); + sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->regs_rid, RF_ACTIVE); + if (sc->regs_res == NULL) { + device_printf(dev, "unable to map registers\n"); + ig4iic_pci_detach(dev); + return (ENXIO); + } + sc->intr_rid = 0; + if (pci_alloc_msi(dev, &sc->intr_rid)) { + device_printf(dev, "Using MSI\n"); + } + sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &sc->intr_rid, RF_SHAREABLE | RF_ACTIVE); + if (sc->intr_res == NULL) { + device_printf(dev, "unable to map interrupt\n"); + ig4iic_pci_detach(dev); + return (ENXIO); + } + sc->pci_attached = 1; + + error = ig4iic_attach(sc); + if (error) + ig4iic_pci_detach(dev); + + return (error); +} + +static int +ig4iic_pci_detach(device_t dev) +{ + ig4iic_softc_t *sc = device_get_softc(dev); + int error; + + if (sc->pci_attached) { + error = ig4iic_detach(sc); + if (error) + return (error); + sc->pci_attached = 0; + } + + if (sc->intr_res) { + bus_release_resource(dev, SYS_RES_IRQ, + sc->intr_rid, sc->intr_res); + sc->intr_res = NULL; + } + if (sc->intr_rid != 0) + pci_release_msi(dev); + if (sc->regs_res) { + bus_release_resource(dev, SYS_RES_MEMORY, + sc->regs_rid, sc->regs_res); + sc->regs_res = NULL; + } + mtx_destroy(&sc->mutex); + + return (0); +} + +static device_method_t ig4iic_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ig4iic_pci_probe), + DEVMETHOD(device_attach, ig4iic_pci_attach), + DEVMETHOD(device_detach, ig4iic_pci_detach), + + /* SMBus methods from ig4_smb.c */ + DEVMETHOD(smbus_callback, ig4iic_smb_callback), + DEVMETHOD(smbus_quick, ig4iic_smb_quick), + DEVMETHOD(smbus_sendb, ig4iic_smb_sendb), + DEVMETHOD(smbus_recvb, ig4iic_smb_recvb), + DEVMETHOD(smbus_writeb, ig4iic_smb_writeb), + DEVMETHOD(smbus_writew, ig4iic_smb_writew), + DEVMETHOD(smbus_readb, ig4iic_smb_readb), + DEVMETHOD(smbus_readw, ig4iic_smb_readw), + DEVMETHOD(smbus_pcall, ig4iic_smb_pcall), + DEVMETHOD(smbus_bwrite, ig4iic_smb_bwrite), + DEVMETHOD(smbus_bread, ig4iic_smb_bread), + DEVMETHOD(smbus_trans, ig4iic_smb_trans), + + DEVMETHOD_END +}; + +static driver_t ig4iic_pci_driver = { + "ig4iic", + ig4iic_pci_methods, + sizeof(struct ig4iic_softc) +}; + +static devclass_t ig4iic_pci_devclass; + +DRIVER_MODULE(ig4iic, pci, ig4iic_pci_driver, ig4iic_pci_devclass, 0, 0); +MODULE_DEPEND(ig4iic, pci, 1, 1, 1); +MODULE_DEPEND(ig4iic, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); +MODULE_VERSION(ig4iic, 1); diff --git a/sys/dev/ichiic/ig4_reg.h b/sys/dev/ichiic/ig4_reg.h new file mode 100644 index 0000000..c87d1d1 --- /dev/null +++ b/sys/dev/ichiic/ig4_reg.h @@ -0,0 +1,622 @@ +/* + * Copyright (c) 2014 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Matthew Dillon <dillon@backplane.com> and was subsequently ported + * to FreeBSD by Michael Gmelin <freebsd@grem.de> + * + * 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 DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS 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$ + */ +/* + * Intel fourth generation mobile cpus integrated I2C device. + * + * Datasheet reference: Section 22. + * + * http://www.intel.com/content/www/us/en/processors/core/4th-gen-core-family-mobile-i-o-datasheet.html?wapkw=datasheets+4th+generation + * + * This is a from-scratch driver under the BSD license using the Intel data + * sheet and the linux driver for reference. All code is freshly written + * without referencing the linux driver code. However, during testing + * I am also using the linux driver code as a reference to help resolve any + * issues that come. These will be specifically documented in the code. + * + * Please see protocol notes in section 5.21. This controller is an I2C + * master only and cannot act as a slave. The IO voltage should be set by + * the BIOS. Standard (100Kb/s) and Fast (400Kb/s) and fast mode plus + * (1MB/s) is supported. High speed mode (3.4 MB/s) is NOT supported. + */ + +#ifndef _BUS_SMBUS_INTELGEN4_IG4_REG_H_ +#define _BUS_SMBUS_INTELGEN4_IG4_REG_H_ + +/* + * 22.2 MMIO registers can be accessed through BAR0 in PCI mode or through + * BAR1 when in ACPI mode. + * + * Register width is 32-bits + * + * 22.2 Default Values on device reset are 0 except as specified here: + * TAR_ADD 0x00000055 + * SS_SCL_HCNT 0x00000264 + * SS_SCL_LCNT 0x000002C2 + * FS_SCL_HCNT 0x0000006E + * FS_SCL_LCNT 0x000000CF + * INTR_MASK 0x000008FF + * I2C_STA 0x00000006 + * SDA_HOLD 0x00000001 + * SDA_SETUP 0x00000064 + * COMP_PARAM1 0x00FFFF6E + * COMP_VER 0x3131352A + */ + +#define IG4_REG_CTL 0x0000 /* RW Control Register */ +#define IG4_REG_TAR_ADD 0x0004 /* RW Target Address */ +#define IG4_REG_DATA_CMD 0x0010 /* RW Data Buffer and Command */ +#define IG4_REG_SS_SCL_HCNT 0x0014 /* RW Std Speed clock High Count */ +#define IG4_REG_SS_SCL_LCNT 0x0018 /* RW Std Speed clock Low Count */ +#define IG4_REG_FS_SCL_HCNT 0x001C /* RW Fast Speed clock High Count */ +#define IG4_REG_FS_SCL_LCNT 0x0020 /* RW Fast Speed clock Low Count */ +#define IG4_REG_INTR_STAT 0x002C /* RO Interrupt Status */ +#define IG4_REG_INTR_MASK 0x0030 /* RW Interrupt Mask */ +#define IG4_REG_RAW_INTR_STAT 0x0034 /* RO Raw Interrupt Status */ +#define IG4_REG_RX_TL 0x0038 /* RW Receive FIFO Threshold */ +#define IG4_REG_TX_TL 0x003C /* RW Transmit FIFO Threshold */ +#define IG4_REG_CLR_INTR 0x0040 /* RO Clear Interrupt */ +#define IG4_REG_CLR_RX_UNDER 0x0044 /* RO Clear RX_Under Interrupt */ +#define IG4_REG_CLR_RX_OVER 0x0048 /* RO Clear RX_Over Interrupt */ +#define IG4_REG_CLR_TX_OVER 0x004C /* RO Clear TX_Over Interrupt */ +#define IG4_REG_CLR_TX_ABORT 0x0054 /* RO Clear TX_Abort Interrupt */ +#define IG4_REG_CLR_ACTIVITY 0x005C /* RO Clear Activity Interrupt */ +#define IG4_REG_CLR_STOP_DET 0x0060 /* RO Clear STOP Detection Int */ +#define IG4_REG_CLR_START_DET 0x0064 /* RO Clear START Detection Int */ +#define IG4_REG_CLR_GEN_CALL 0x0068 /* RO Clear General Call Interrupt */ +#define IG4_REG_I2C_EN 0x006C /* RW I2C Enable */ +#define IG4_REG_I2C_STA 0x0070 /* RO I2C Status */ +#define IG4_REG_TXFLR 0x0074 /* RO Transmit FIFO Level */ +#define IG4_REG_RXFLR 0x0078 /* RO Receive FIFO Level */ +#define IG4_REG_SDA_HOLD 0x007C /* RW SDA Hold Time Length */ +#define IG4_REG_TX_ABRT_SOURCE 0x0080 /* RO Transmit Abort Source */ +#define IG4_REG_SLV_DATA_NACK 0x0084 /* RW General Slave Data NACK */ +#define IG4_REG_DMA_CTRL 0x0088 /* RW DMA Control */ +#define IG4_REG_DMA_TDLR 0x008C /* RW DMA Transmit Data Level */ +#define IG4_REG_DMA_RDLR 0x0090 /* RW DMA Receive Data Level */ +#define IG4_REG_SDA_SETUP 0x0094 /* RW SDA Setup */ +#define IG4_REG_ENABLE_STATUS 0x009C /* RO Enable Status */ +#define IG4_REG_COMP_PARAM1 0x00F4 /* RO Component Parameter */ +#define IG4_REG_COMP_VER 0x00F8 /* RO Component Version */ +#define IG4_REG_COMP_TYPE 0x00FC /* RO Probe width/endian? (linux) */ +#define IG4_REG_CLK_PARMS 0x0800 /* RW Clock Parameters */ +#define IG4_REG_RESETS 0x0804 /* RW Reset Register */ +#define IG4_REG_GENERAL 0x0808 /* RW General Register */ +#define IG4_REG_SW_LTR_VALUE 0x0810 /* RW SW LTR Value */ +#define IG4_REG_AUTO_LTR_VALUE 0x0814 /* RW Auto LTR Value */ + +/* + * CTL - Control Register 22.2.1 + * Default Value: 0x0000007F. + * + * RESTARTEN - RW Restart Enable + * 10BIT - RW Controller operates in 10-bit mode, else 7-bit + * + * NOTE: When restart is disabled the controller is incapable of + * performing the following functions: + * + * Sending a START Byte + * Performing any high-speed mode op + * Performing direction changes in combined format mode + * Performing a read operation with a 10-bit address + * + * Attempting to perform the above operations will result in the + * TX_ABORT bit being set in RAW_INTR_STAT. + */ +#define IG4_CTL_SLAVE_DISABLE 0x0040 /* snarfed from linux */ +#define IG4_CTL_RESTARTEN 0x0020 /* Allow Restart when master */ +#define IG4_CTL_10BIT 0x0010 /* ctlr accepts 10-bit addresses */ +#define IG4_CTL_SPEED_FAST 0x0004 /* snarfed from linux */ +#define IG4_CTL_SPEED_STD 0x0002 /* snarfed from linux */ +#define IG4_CTL_MASTER 0x0001 /* snarfed from linux */ + +/* + * TAR_ADD - Target Address Register 22.2.2 + * Default Value: 0x00000055F + * + * 10BIT - RW controller starts its transfers in 10-bit + * address mode, else 7-bit. + * + * SPECIAL - RW Indicates whether software performs a General Call + * or START BYTE command. + * + * 0 Ignore GC_OR_START and use TAR address. + * + * 1 Perform special I2C Command based on GC_OR_START. + * + * GC_OR_START - RW (only if SPECIAL is set) + * + * 0 General Call Address. After issuing a General Call, + * only writes may be performed. Attempting to issue + * a read command results in IX_ABRT in RAW_INTR_STAT. + * The controller remains in General Call mode until + * bit 11 (SPECIAL) is cleared. + * + * 1 START BYTE. + * + * + * IC_TAR - RW when transmitting a general call, these bits are + * ignored. To generate a START BYTE, the address + * needs to be written into these bits once. + * + * This register should only be updated when the IIC is disabled (I2C_ENABLE=0) + */ +#define IG4_TAR_10BIT 0x1000 /* start xfer in 10-bit mode */ +#define IG4_TAR_SPECIAL 0x0800 /* Perform special command */ +#define IG4_TAR_GC_OR_START 0x0400 /* General Call or Start */ +#define IG4_TAR_ADDR_MASK 0x03FF /* Target address */ + +/* + * TAR_DATA_CMD - Data Buffer and Command Register 22.2.3 + * + * RESTART - RW This bit controls whether a forced RESTART is + * issued before the byte is sent or received. + * + * 0 If not set a RESTART is only issued if the tranfer + * direction is changing from the previous command. + * + * 1 A RESTART is issued before the byte is sent or + * received, regardless of whether or not the transfer + * direction is changing from the previous command. + * + * STOP - RW This bit controls whether a STOP is issued after + * the byte is sent or received. + * + * 0 STOP is not issued after this byte, regardless + * of whether or not the Tx FIFO is empty. + * + * 1 STOP is issued after this byte, regardless of + * whether or not the Tx FIFO is empty. If the + * Tx FIFO is not empty the master immediately tries + * to start a new transfer by issuing a START and + * arbitrating for the bus. + * + * i.e. the STOP is issued along with this byte, + * within the write stream. + * + * COMMAND - RW Control whether a read or write is performed. + * + * 0 WRITE + * + * 1 READ + * + * DATA (7:0) - RW Contains the data to be transmitted or received + * on the I2C bus. + * + * NOTE: Writing to this register causes a START + slave + RW to be + * issued if the direction has changed or the last data byte was + * sent with a STOP. + * + * NOTE: We control termination? so this register must be written + * for each byte we wish to receive. We can then drain the + * receive FIFO. + */ + +#define IG4_DATA_RESTART 0x0400 /* Force RESTART */ +#define IG4_DATA_STOP 0x0200 /* Force STOP[+START] */ +#define IG4_DATA_COMMAND_RD 0x0100 /* bus direction 0=write 1=read */ +#define IG4_DATA_MASK 0x00FF + +/* + * SS_SCL_HCNT - Standard Speed Clock High Count Register 22.2.4 + * SS_SCL_LCNT - Standard Speed Clock Low Count Register 22.2.5 + * FS_SCL_HCNT - Fast Speed Clock High Count Register 22.2.6 + * FS_SCL_LCNT - Fast Speed Clock Low Count Register 22.2.7 + * + * COUNT (15:0) - Set the period count to a value between 6 and + * 65525. + */ +#define IG4_SCL_CLOCK_MASK 0xFFFFU /* count bits in register */ + +/* + * INTR_STAT - (RO) Interrupt Status Register 22.2.8 + * INTR_MASK - (RW) Interrupt Mask Register 22.2.9 + * RAW_INTR_STAT- (RO) Raw Interrupt Status Register 22.2.10 + * + * GEN_CALL Set only when a general call (broadcast) address + * is received and acknowleged, stays set until + * cleared by reading CLR_GEN_CALL. + * + * START_DET Set when a START or RESTART condition has occurred + * on the interface. + * + * STOP_DET Set when a STOP condition has occurred on the + * interface. + * + * ACTIVITY Set by any activity on the interface. Cleared + * by reading CLR_ACTIVITY or CLR_INTR. + * + * TX_ABRT Indicates the controller as a transmitter is + * unable to complete the intended action. When set, + * the controller will hold the TX FIFO in a reset + * state (flushed) until CLR_TX_ABORT is read to + * clear the condition. Once cleared, the TX FIFO + * will be available again. + * + * TX_EMPTY Indicates that the transmitter is at or below + * the specified TX_TL threshold. Automatically + * cleared by HW when the buffer level goes above + * the threshold. + * + * TX_OVER Indicates that the processer attempted to write + * to the TX FIFO while the TX FIFO was full. Cleared + * by reading CLR_TX_OVER. + * + * RX_FULL Indicates that the receive FIFO has reached or + * exceeded the specified RX_TL threshold. Cleared + * by HW when the cpu drains the FIFO to below the + * threshold. + * + * RX_OVER Indicates that the receive FIFO was unable to + * accept new data and data was lost. Cleared by + * reading CLR_RX_OVER. + * + * RX_UNDER Indicates that the cpu attempted to read data + * from the receive buffer while the RX FIFO was + * empty. Cleared by reading CLR_RX_UNDER. + * + * NOTES ON RAW_INTR_STAT: + * + * This register can be used to monitor the GEN_CALL, START_DET, + * STOP_DET, ACTIVITY, TX_ABRT, TX_EMPTY, TX_OVER, RX_FULL, RX_OVER, + * and RX_UNDER bits. The documentation is a bit unclear but presumably + * this is the unlatched version. + * + * Code should test FIFO conditions using the I2C_STA (status) register, + * not the interrupt status registers. + */ + +#define IG4_INTR_GEN_CALL 0x0800 +#define IG4_INTR_START_DET 0x0400 +#define IG4_INTR_STOP_DET 0x0200 +#define IG4_INTR_ACTIVITY 0x0100 +#define IG4_INTR_TX_ABRT 0x0040 +#define IG4_INTR_TX_EMPTY 0x0010 +#define IG4_INTR_TX_OVER 0x0008 +#define IG4_INTR_RX_FULL 0x0004 +#define IG4_INTR_RX_OVER 0x0002 +#define IG4_INTR_RX_UNDER 0x0001 + +/* + * RX_TL - (RW) Receive FIFO Threshold Register 22.2.11 + * TX_TL - (RW) Transmit FIFO Threshold Register 22.2.12 + * + * Specify the receive and transmit FIFO threshold register. The + * FIFOs have 16 elements. The valid range is 0-15. Setting a + * value greater than 15 causes the actual value to be the maximum + * depth of the FIFO. + * + * Generally speaking since everything is messaged, we can use a + * mid-level setting for both parameters and (e.g.) fully drain the + * receive FIFO on the STOP_DET condition to handle loose ends. + */ +#define IG4_FIFO_MASK 0x00FF +#define IG4_FIFO_LIMIT 16 + +/* + * CLR_INTR - (RO) Clear Interrupt Register 22.2.13 + * CLR_RX_UNDER - (RO) Clear Interrupt Register (specific) 22.2.14 + * CLR_RX_OVER - (RO) Clear Interrupt Register (specific) 22.2.15 + * CLR_TX_OVER - (RO) Clear Interrupt Register (specific) 22.2.16 + * CLR_TX_ABORT - (RO) Clear Interrupt Register (specific) 22.2.17 + * CLR_ACTIVITY - (RO) Clear Interrupt Register (specific) 22.2.18 + * CLR_STOP_DET - (RO) Clear Interrupt Register (specific) 22.2.19 + * CLR_START_DET- (RO) Clear Interrupt Register (specific) 22.2.20 + * CLR_GEN_CALL - (RO) Clear Interrupt Register (specific) 22.2.21 + * + * CLR_* specific operations clear the appropriate bit in the + * RAW_INTR_STAT register. Intel does not really document whether + * these operations clear the normal interrupt status register. + * + * CLR_INTR clears bits in the normal interrupt status register and + * presumably also the raw(?) register? Intel is again unclear. + * + * NOTE: CLR_INTR only clears software-clearable interrupts. Hardware + * clearable interrupts are controlled entirely by the hardware. + * CLR_INTR also clears the TX_ABRT_SOURCE register. + * + * NOTE: CLR_TX_ABORT also clears the TX_ABRT_SOURCE register and releases + * the TX FIFO from its flushed/reset state, allowing more writes + * to the TX FIFO. + * + * NOTE: CLR_ACTIVITY has no effect if the I2C bus is still active. + * Intel documents that the bit is automatically cleared when + * there is no further activity on the bus. + */ +#define IG4_CLR_BIT 0x0001 /* Reflects source */ + +/* + * I2C_EN - (RW) I2C Enable Register 22.2.22 + * + * ABORT Software can abort an I2C transfer by setting this + * bit. Hardware will clear the bit once the STOP has + * been detected. This bit can only be set while the + * I2C interface is enabled. + * + * I2C_ENABLE Enable the controller, else disable it. + * (Use I2C_ENABLE_STATUS to poll enable status + * & wait for changes) + */ +#define IG4_I2C_ABORT 0x0002 +#define IG4_I2C_ENABLE 0x0001 + +/* + * I2C_STA - (RO) I2C Status Register 22.2.23 + */ +#define IG4_STATUS_ACTIVITY 0x0020 /* Controller is active */ +#define IG4_STATUS_RX_FULL 0x0010 /* RX FIFO completely full */ +#define IG4_STATUS_RX_NOTEMPTY 0x0008 /* RX FIFO not empty */ +#define IG4_STATUS_TX_EMPTY 0x0004 /* TX FIFO completely empty */ +#define IG4_STATUS_TX_NOTFULL 0x0002 /* TX FIFO not full */ +#define IG4_STATUS_I2C_ACTIVE 0x0001 /* I2C bus is active */ + +/* + * TXFLR - (RO) Transmit FIFO Level Register 22.2.24 + * RXFLR - (RO) Receive FIFO Level Register 22.2.25 + * + * Read the number of entries currently in the Transmit or Receive + * FIFOs. Note that for some reason the mask is 9 bits instead of + * the 8 bits the fill level controls. + */ +#define IG4_FIFOLVL_MASK 0x001F + +/* + * SDA_HOLD - (RW) SDA Hold Time Length Register 22.2.26 + * + * Set the SDA hold time length register in I2C clocks. + */ +#define IG4_SDA_HOLD_MASK 0x00FF + +/* + * TX_ABRT_SOURCE- (RO) Transmit Abort Source Register 22.2.27 + * + * Indicates the cause of a transmit abort. This can indicate a + * software programming error or a device expected address width + * mismatch or other issues. The NORESTART conditions and GENCALL_NOACK + * can only occur if a programming error was made in the driver software. + * + * In particular, it should be possible to detect whether any devices + * are on the bus by observing the GENCALL_READ status, and it might + * be possible to detect ADDR7 vs ADDR10 mismatches. + */ +#define IG4_ABRTSRC_TRANSFER 0x00010000 /* Abort initiated by user */ +#define IG4_ABRTSRC_ARBLOST 0x00001000 /* Arbitration lost */ +#define IG4_ABRTSRC_NORESTART_10 0x00000400 /* RESTART disabled */ +#define IG4_ABRTSRC_NORESTART_START 0x00000200 /* RESTART disabled */ +#define IG4_ABRTSRC_ACKED_START 0x00000080 /* Improper acked START */ +#define IG4_ABRTSRC_GENCALL_NOACK 0x00000020 /* Improper GENCALL */ +#define IG4_ABRTSRC_GENCALL_READ 0x00000010 /* Nobody acked GENCALL */ +#define IG4_ABRTSRC_TXNOACK_DATA 0x00000008 /* data phase no ACK */ +#define IG4_ABRTSRC_TXNOACK_ADDR10_2 0x00000004 /* addr10/1 phase no ACK */ +#define IG4_ABRTSRC_TXNOACK_ADDR10_1 0x00000002 /* addr10/2 phase no ACK */ +#define IG4_ABRTSRC_TXNOACK_ADDR7 0x00000001 /* addr7 phase no ACK */ + +/* + * SLV_DATA_NACK - (RW) Generate Slave DATA NACK Register 22.2.28 + * + * When the controller is a receiver a NACK can be generated on + * receipt of data. + * + * NACK_GENERATE Set to 0 for normal NACK/ACK generation. + * Set to 1 to generate a NACK after next data + * byte received. + * + */ +#define IG4_NACK_GENERATE 0x0001 + +/* + * DMA_CTRL - (RW) DMA Control Register 22.2.29 + * + * Enables DMA on the transmit and/or receive DMA channel. + */ +#define IG4_TX_DMA_ENABLE 0x0002 +#define IG4_RX_DMA_ENABLE 0x0001 + +/* + * DMA_TDLR - (RW) DMA Transmit Data Level Register 22.2.30 + * DMA_RDLR - (RW) DMA Receive Data Level Register 22.2.31 + * + * Similar to RX_TL and TX_TL but controls when a DMA burst occurs + * to empty or fill the FIFOs. Use the same IG4_FIFO_MASK and + * IG4_FIFO_LIMIT defines for RX_RL and TX_TL. + */ +/* empty */ + +/* + * SDA_SETUP - (RW) SDA Setup Time Length Register 22.2.32 + * + * Set the SDA setup time length register in I2C clocks. + * The register must be programmed with a value >=2. + * (Defaults to 0x64). + */ +#define IG4_SDA_SETUP_MASK 0x00FF + +/* + * ACK_GEN_CALL - (RW) ACK General Call Register 22.2.33 + * + * Control whether the controller responds with a ACK or NACK when + * it receives an I2C General Call address. + * + * If set to 0 a NACK is generated and a General Call interrupt is + * NOT generated. Otherwise an ACK + interrupt is generated. + */ +#define IG4_ACKGC_ACK 0x0001 + +/* + * ENABLE_STATUS - (RO) Enable Status Registger 22.2.34 + * + * DATA_LOST - Indicates that a slave receiver operation has + * been aborted with at least one data byte received + * from a transfer due to the I2C controller being + * disabled (IG4_I2C_ENABLE -> 0) + * + * ENABLED - Intel documentation is lacking but I assume this + * is a reflection of the IG4_I2C_ENABLE bit in the + * I2C_EN register. + * + */ +#define IG4_ENASTAT_DATA_LOST 0x0004 +#define IG4_ENASTAT_ENABLED 0x0001 + +/* + * COMP_PARAM1 - (RO) Component Parameter Register 22.2.35 + * Default Value 0x00FFFF6E + * + * VALID - Intel documentation is unclear but I believe this + * must be read as a 1 to indicate that the rest of + * the bits in the register are valid. + * + * HASDMA - Indicates that the chip is DMA-capable. Presumably + * in certain virtualization cases the chip might be + * set to not be DMA-capable. + * + * INTR_IO - Indicates that all interrupts are combined to + * generate one interrupt. If not set, interrupts + * are individual (more virtualization stuff?) + * + * HCCNT_RO - Indicates that the clock timing registers are + * RW. If not set, the registers are RO. + * (more virtualization stuff). + * + * MAXSPEED - Indicates the maximum speed supported. + * + * DATAW - Indicates the internal bus width in bits. + */ +#define IG4_PARAM1_TXFIFO_DEPTH(v) (((v) >> 16) & 0xFF) +#define IG4_PARAM1_RXFIFO_DEPTH(v) (((v) >> 8) & 0xFF) +#define IG4_PARAM1_CONFIG_VALID 0x00000080 +#define IG4_PARAM1_CONFIG_HASDMA 0x00000040 +#define IG4_PARAM1_CONFIG_INTR_IO 0x00000020 +#define IG4_PARAM1_CONFIG_HCCNT_RO 0x00000010 +#define IG4_PARAM1_CONFIG_MAXSPEED_MASK 0x0000000C +#define IG4_PARAM1_CONFIG_DATAW_MASK 0x00000003 + +#define IG4_CONFIG_MAXSPEED_RESERVED00 0x00000000 +#define IG4_CONFIG_MAXSPEED_STANDARD 0x00000004 +#define IG4_CONFIG_MAXSPEED_FAST 0x00000008 +#define IG4_CONFIG_MAXSPEED_HIGH 0x0000000C + +#define IG4_CONFIG_DATAW_8 0x00000000 +#define IG4_CONFIG_DATAW_16 0x00000001 +#define IG4_CONFIG_DATAW_32 0x00000002 +#define IG4_CONFIG_DATAW_RESERVED11 0x00000003 + +/* + * COMP_VER - (RO) Component Version Register 22.2.36 + * Default Value 0x3131352A + * + * Contains the chip version number. All 32 bits. + */ +#define IG4_COMP_VER 0x3131352A + +/* + * COMP_TYPE - (RO) (linux) Endian and bus width probe + * + * Read32 from this register and test against IG4_COMP_TYPE + * to determine the bus width. e.g. 01404457 = endian-reversed, + * and 00000140 or 00004457 means internal 16-bit bus (?). + * + * This register is not in the intel documentation, I pulled it + * from the linux driver i2c-designware-core.c. + */ +#define IG4_COMP_TYPE 0x44570140 + +/* + * RESETS - (RW) Resets Register 22.2.37 + * + * Used to reset the I2C host controller by SW. There is no timing + * requirement, software can assert and de-assert in back-to-back + * transactions. + * + * 00 I2C host controller is NOT in reset. + * 01 (reserved) + * 10 (reserved) + * 11 I2C host controller is in reset. + */ +#define IG4_RESETS_ASSERT 0x0003 +#define IG4_RESETS_DEASSERT 0x0000 + +/* + * GENERAL - (RW) General Reigster 22.2.38 + * + * IOVOLT 0=1.8V 1=3.3V + * + * LTR 0=Auto 1=SW + * + * In Auto mode the BIOS will write to the host controller's + * AUTO LTR Value register (offset 0x0814) with the active + * state LTR value, and will write to the SW LTR Value register + * (offset 0x0810) with the idle state LTR value. + * + * In SW mode the SW will write to the host controller SW LTR + * value (offset 0x0810). It is the SW responsibility to update + * the LTR with the appropriate value. + */ +#define IG4_GENERAL_IOVOLT3_3 0x0008 +#define IG4_GENERAL_SWMODE 0x0004 + +/* + * SW_LTR_VALUE - (RW) SW LTR Value Register 22.2.39 + * AUTO_LTR_VALUE - (RW) SW LTR Value Register 22.2.40 + * + * Default value is 0x00000800 which means the best possible + * service/response time. + * + * It isn't quite clear how the snooping works. There are two scale + * bits for both sets but two of the four codes are reserved. The + * *SNOOP_VALUE() is specified as a 10-bit latency value. If 0, it + * indicates that the device cannot tolerate any delay and needs the + * best possible service/response time. + * + * I think this is for snooping (testing) the I2C bus. The lowest + * delay (0) probably runs the controller polling at a high, power hungry + * rate. But I dunno. + */ +#define IG4_SWLTR_NSNOOP_REQ 0x80000000 /* (ro) */ +#define IG4_SWLTR_NSNOOP_SCALE_MASK 0x1C000000 /* (ro) */ +#define IG4_SWLTR_NSNOOP_SCALE_1US 0x08000000 /* (ro) */ +#define IG4_SWLTR_NSNOOP_SCALE_32US 0x0C000000 /* (ro) */ +#define IG4_SWLTR_NSNOOP_VALUE_DECODE(v) (((v) >> 16) & 0x3F) +#define IG4_SWLTR_NSNOOP_VALUE_ENCODE(v) (((v) & 0x3F) << 16) + +#define IG4_SWLTR_SNOOP_REQ 0x00008000 /* (rw) */ +#define IG4_SWLTR_SNOOP_SCALE_MASK 0x00001C00 /* (rw) */ +#define IG4_SWLTR_SNOOP_SCALE_1US 0x00000800 /* (rw) */ +#define IG4_SWLTR_SNOOP_SCALE_32US 0x00000C00 /* (rw) */ +#define IG4_SWLTR_SNOOP_VALUE_DECODE(v) ((v) & 0x3F) +#define IG4_SWLTR_SNOOP_VALUE_ENCODE(v) ((v) & 0x3F) + +#endif diff --git a/sys/dev/ichiic/ig4_var.h b/sys/dev/ichiic/ig4_var.h new file mode 100644 index 0000000..6c91055 --- /dev/null +++ b/sys/dev/ichiic/ig4_var.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2014 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Matthew Dillon <dillon@backplane.com> and was subsequently ported + * to FreeBSD by Michael Gmelin <freebsd@grem.de> + * + * 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 DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS 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 _BUS_SMBUS_INTELGEN4_IG4_VAR_H_ +#define _BUS_SMBUS_INTELGEN4_IG4_VAR_H_ + +#include "bus_if.h" +#include "device_if.h" +#include "pci_if.h" +#include "smbus_if.h" + +#define IG4_RBUFSIZE 128 +#define IG4_RBUFMASK (IG4_RBUFSIZE - 1) + +enum ig4_op { IG4_IDLE, IG4_READ, IG4_WRITE }; + +struct ig4iic_softc { + device_t dev; + struct intr_config_hook enum_hook; + device_t smb; + struct resource *regs_res; + int regs_rid; + struct resource *intr_res; + int intr_rid; + void *intr_handle; + int intr_type; + enum ig4_op op; + int cmd; + int rnext; + int rpos; + char rbuf[IG4_RBUFSIZE]; + int error; + uint8_t last_slave; + int pci_attached : 1; + int use_10bit : 1; + int slave_valid : 1; + int read_started : 1; + int write_started : 1; + struct mtx mutex; +}; + +typedef struct ig4iic_softc ig4iic_softc_t; + +/* Attach/Detach called from ig4iic_pci_*() */ +int ig4iic_attach(ig4iic_softc_t *sc); +int ig4iic_detach(ig4iic_softc_t *sc); + +/* SMBus methods */ +extern smbus_callback_t ig4iic_smb_callback; +extern smbus_quick_t ig4iic_smb_quick; +extern smbus_sendb_t ig4iic_smb_sendb; +extern smbus_recvb_t ig4iic_smb_recvb; +extern smbus_writeb_t ig4iic_smb_writeb; +extern smbus_writew_t ig4iic_smb_writew; +extern smbus_readb_t ig4iic_smb_readb; +extern smbus_readw_t ig4iic_smb_readw; +extern smbus_pcall_t ig4iic_smb_pcall; +extern smbus_bwrite_t ig4iic_smb_bwrite; +extern smbus_bread_t ig4iic_smb_bread; +extern smbus_trans_t ig4iic_smb_trans; + +#endif diff --git a/sys/dev/ixl/if_ixl.c b/sys/dev/ixl/if_ixl.c index de4ee24..026bc9e 100644 --- a/sys/dev/ixl/if_ixl.c +++ b/sys/dev/ixl/if_ixl.c @@ -199,8 +199,8 @@ static int ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS); #ifdef PCI_IOV static int ixl_adminq_err_to_errno(enum i40e_admin_queue_err err); -static int ixl_init_iov(device_t dev, uint16_t num_vfs, const nvlist_t*); -static void ixl_uninit_iov(device_t dev); +static int ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t*); +static void ixl_iov_uninit(device_t dev); static int ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t*); static void ixl_handle_vf_msg(struct ixl_pf *, @@ -222,9 +222,9 @@ static device_method_t ixl_methods[] = { DEVMETHOD(device_detach, ixl_detach), DEVMETHOD(device_shutdown, ixl_shutdown), #ifdef PCI_IOV - DEVMETHOD(pci_init_iov, ixl_init_iov), - DEVMETHOD(pci_uninit_iov, ixl_uninit_iov), - DEVMETHOD(pci_add_vf, ixl_add_vf), + DEVMETHOD(pci_iov_init, ixl_iov_init), + DEVMETHOD(pci_iov_uninit, ixl_iov_uninit), + DEVMETHOD(pci_iov_add_vf, ixl_add_vf), #endif {0, 0} }; @@ -6456,7 +6456,7 @@ ixl_adminq_err_to_errno(enum i40e_admin_queue_err err) } static int -ixl_init_iov(device_t dev, uint16_t num_vfs, const nvlist_t *params) +ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params) { struct ixl_pf *pf; struct i40e_hw *hw; @@ -6504,7 +6504,7 @@ fail: } static void -ixl_uninit_iov(device_t dev) +ixl_iov_uninit(device_t dev) { struct ixl_pf *pf; struct i40e_hw *hw; diff --git a/sys/dev/ixl/ixl.h b/sys/dev/ixl/ixl.h index 1ddfbca3..3348e1a 100644 --- a/sys/dev/ixl/ixl.h +++ b/sys/dev/ixl/ixl.h @@ -93,6 +93,7 @@ #ifdef PCI_IOV #include <sys/nv.h> #include <sys/iov_schema.h> +#include <dev/pci/pci_iov.h> #endif #include "i40e_type.h" diff --git a/sys/dev/mmc/mmcsd.c b/sys/dev/mmc/mmcsd.c index 3be2158..4ca0c24 100644 --- a/sys/dev/mmc/mmcsd.c +++ b/sys/dev/mmc/mmcsd.c @@ -163,33 +163,10 @@ mmcsd_attach(device_t dev) d->d_sectorsize = mmc_get_sector_size(dev); d->d_maxsize = mmc_get_max_data(dev) * d->d_sectorsize; d->d_mediasize = (off_t)mmc_get_media_size(dev) * d->d_sectorsize; - d->d_stripeoffset = 0; d->d_stripesize = mmc_get_erase_sector(dev) * d->d_sectorsize; d->d_unit = device_get_unit(dev); d->d_flags = DISKFLAG_CANDELETE; - d->d_delmaxsize = mmc_get_erase_sector(dev) * d->d_sectorsize * 1; /* conservative */ - /* - * The d_fw* values are fake. However, layout is aided by making the - * number of fwsectors equal to the erase sectors from the drive since - * we set the stripe size equal to that. We set fwheads such that there - * are ~20 cylinder groups since all values are somewhat arbitrary here - * and this gives good behavior with ffs without wasting too much - * space. Sadly, geom_part wants to round partitions to these - * values. While not bad, in and of itself, the values we present here - * will almost certainly be different then the values that USB SD - * adapters use and there's too much variation between brands to just - * use those values here. Also SD to ATA adapters favor traditional - * ata sizes, which are different again from the USB adapters (which - * favor SCSI values). This rounding leads to a loss of up to 5% of the - * usable space (usually much less, but that's why 20 was selected: to - * limit this effect at a few percent). gpart needs a way to override - * this behavior for situations like this, but doesn't provide - * one. Perhaps this behavior should be tunable as well, but maybe that - * belongs in the disk layer. These values will be much better than - * the default ones. - */ - d->d_fwsectors = mmc_get_erase_sector(dev); - d->d_fwheads = mmc_get_media_size(dev) / (d->d_fwsectors * 20); + d->d_delmaxsize = mmc_get_erase_sector(dev) * d->d_sectorsize; strlcpy(d->d_ident, mmc_get_card_sn_string(dev), sizeof(d->d_ident)); strlcpy(d->d_descr, mmc_get_card_id_string(dev), sizeof(d->d_descr)); diff --git a/sys/dev/mpr/mpi/mpi2.h b/sys/dev/mpr/mpi/mpi2.h index 10f17ab..42fdec2 100644 --- a/sys/dev/mpr/mpi/mpi2.h +++ b/sys/dev/mpr/mpi/mpi2.h @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2013 LSI Corp. + * Copyright (c) 2012-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,13 +27,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD * * $FreeBSD$ */ /* - * Copyright (c) 2000-2013 LSI Corporation. + * Copyright (c) 2000-2015 LSI Corporation. + * Copyright (c) 2013-2015 Avago Technologies * * * Name: mpi2.h diff --git a/sys/dev/mpr/mpi/mpi2_cnfg.h b/sys/dev/mpr/mpi/mpi2_cnfg.h index d82750f..3b0eb63 100644 --- a/sys/dev/mpr/mpi/mpi2_cnfg.h +++ b/sys/dev/mpr/mpi/mpi2_cnfg.h @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2013 LSI Corp. + * Copyright (c) 2012-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,13 +27,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD * * $FreeBSD$ */ /* - * Copyright (c) 2000-2013 LSI Corporation. + * Copyright (c) 2000-2015 LSI Corporation. + * Copyright (c) 2013-2015 Avago Technologies * * * Name: mpi2_cnfg.h diff --git a/sys/dev/mpr/mpi/mpi2_hbd.h b/sys/dev/mpr/mpi/mpi2_hbd.h index d0cc09f..520407b 100644 --- a/sys/dev/mpr/mpi/mpi2_hbd.h +++ b/sys/dev/mpr/mpi/mpi2_hbd.h @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2013 LSI Corp. + * Copyright (c) 2012-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,13 +27,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD * * $FreeBSD$ */ /* - * Copyright (c) 2009-2011 LSI Corporation. + * Copyright (c) 2009-2015 LSI Corporation. + * Copyright (c) 2013-2015 Avago Technologies * * * Name: mpi2_hbd.h diff --git a/sys/dev/mpr/mpi/mpi2_history.txt b/sys/dev/mpr/mpi/mpi2_history.txt index 296b75b..9fca796 100644 --- a/sys/dev/mpr/mpi/mpi2_history.txt +++ b/sys/dev/mpr/mpi/mpi2_history.txt @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2013 LSI Corp. + * Copyright (c) 2012-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,7 +27,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD * * $FreeBSD$ */ @@ -35,7 +36,8 @@ Fusion-MPT MPI 2.0 / 2.5 Header File Change History ============================== - Copyright (c) 2000-2013 LSI Corporation. + Copyright (c) 2000-2015 LSI Corporation. + Copyright (c) 2013-2015 Avago Technologies --------------------------------------- Header Set Release Version: 02.00.33 diff --git a/sys/dev/mpr/mpi/mpi2_init.h b/sys/dev/mpr/mpi/mpi2_init.h index 62b0cfe..5f475c0 100644 --- a/sys/dev/mpr/mpi/mpi2_init.h +++ b/sys/dev/mpr/mpi/mpi2_init.h @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2013 LSI Corp. + * Copyright (c) 2012-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,13 +27,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD * * $FreeBSD$ */ /* - * Copyright (c) 2000-2013 LSI Corporation. + * Copyright (c) 2000-2015 LSI Corporation. + * Copyright (c) 2013-2015 Avago Technologies * * * Name: mpi2_init.h diff --git a/sys/dev/mpr/mpi/mpi2_ioc.h b/sys/dev/mpr/mpi/mpi2_ioc.h index 38a46f5..54f39a5 100644 --- a/sys/dev/mpr/mpi/mpi2_ioc.h +++ b/sys/dev/mpr/mpi/mpi2_ioc.h @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2013 LSI Corp. + * Copyright (c) 2012-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,13 +27,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD * * $FreeBSD$ */ /* - * Copyright (c) 2000-2013 LSI Corporation. + * Copyright (c) 2000-2015 LSI Corporation. + * Copyright (c) 2013-2015 Avago Technologies * * * Name: mpi2_ioc.h diff --git a/sys/dev/mpr/mpi/mpi2_ra.h b/sys/dev/mpr/mpi/mpi2_ra.h index 76db06b..02304aa 100644 --- a/sys/dev/mpr/mpi/mpi2_ra.h +++ b/sys/dev/mpr/mpi/mpi2_ra.h @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2013 LSI Corp. + * Copyright (c) 2012-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,13 +27,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD * * $FreeBSD$ */ /* - * Copyright (c) 2009 LSI Corporation. + * Copyright (c) 2012-2015 LSI Corporation. + * Copyright (c) 2013-2015 Avago Technologies * * * Name: mpi2_ra.h diff --git a/sys/dev/mpr/mpi/mpi2_raid.h b/sys/dev/mpr/mpi/mpi2_raid.h index c6bb598..52ebf07 100644 --- a/sys/dev/mpr/mpi/mpi2_raid.h +++ b/sys/dev/mpr/mpi/mpi2_raid.h @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2013 LSI Corp. + * Copyright (c) 2012-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,13 +27,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD * * $FreeBSD$ */ /* - * Copyright (c) 2000-2013 LSI Corporation. + * Copyright (c) 2000-2015 LSI Corporation. + * Copyright (c) 2013-2015 Avago Technologies * * * Name: mpi2_raid.h diff --git a/sys/dev/mpr/mpi/mpi2_sas.h b/sys/dev/mpr/mpi/mpi2_sas.h index 2a107f1..7cae2c3 100644 --- a/sys/dev/mpr/mpi/mpi2_sas.h +++ b/sys/dev/mpr/mpi/mpi2_sas.h @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2013 LSI Corp. + * Copyright (c) 2012-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,13 +27,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD * * $FreeBSD$ */ /* - * Copyright (c) 2000-2013 LSI Corporation. + * Copyright (c) 2000-2015 LSI Corporation. + * Copyright (c) 2013-2015 Avago Technologies * * * Name: mpi2_sas.h diff --git a/sys/dev/mpr/mpi/mpi2_targ.h b/sys/dev/mpr/mpi/mpi2_targ.h index 506e64f..85b5ac5 100644 --- a/sys/dev/mpr/mpi/mpi2_targ.h +++ b/sys/dev/mpr/mpi/mpi2_targ.h @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2013 LSI Corp. + * Copyright (c) 2012-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,13 +27,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD * * $FreeBSD$ */ /* - * Copyright (c) 2000-2012 LSI Corporation. + * Copyright (c) 2000-2015 LSI Corporation. + * Copyright (c) 2013-2015 Avago Technologies * * * Name: mpi2_targ.h diff --git a/sys/dev/mpr/mpi/mpi2_tool.h b/sys/dev/mpr/mpi/mpi2_tool.h index 94542cc..59917c0 100644 --- a/sys/dev/mpr/mpi/mpi2_tool.h +++ b/sys/dev/mpr/mpi/mpi2_tool.h @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2013 LSI Corp. + * Copyright (c) 2012-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,13 +27,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD * * $FreeBSD$ */ /* - * Copyright (c) 2000-2013 LSI Corporation. + * Copyright (c) 2000-2015 LSI Corporation. + * Copyright (c) 2013-2015 Avago Technologies * * * Name: mpi2_tool.h diff --git a/sys/dev/mpr/mpi/mpi2_type.h b/sys/dev/mpr/mpi/mpi2_type.h index da3aefb..b063683 100644 --- a/sys/dev/mpr/mpi/mpi2_type.h +++ b/sys/dev/mpr/mpi/mpi2_type.h @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2013 LSI Corp. + * Copyright (c) 2012-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,13 +27,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD * * $FreeBSD$ */ /* - * Copyright (c) 2000-2007 LSI Corporation. + * Copyright (c) 2000-2015 LSI Corporation. + * Copyright (c) 2013-2015 Avago Technologies * * * Name: mpi2_type.h diff --git a/sys/dev/mpr/mpr.c b/sys/dev/mpr/mpr.c index d3fb9a0..07e73c5 100644 --- a/sys/dev/mpr/mpr.c +++ b/sys/dev/mpr/mpr.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2009 Yahoo! Inc. - * Copyright (c) 2012-2014 LSI Corp. + * Copyright (c) 2011-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,12 +25,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD + * */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/* Communications core for LSI MPT2 */ +/* Communications core for Avago Technologies (LSI) MPT3 */ /* TODO Move headers to mprvar */ #include <sys/types.h> @@ -72,7 +75,6 @@ __FBSDID("$FreeBSD$"); #include <dev/mpr/mpr_ioctl.h> #include <dev/mpr/mprvar.h> #include <dev/mpr/mpr_table.h> -#include <dev/mpr/mpr_sas.h> static int mpr_diag_reset(struct mpr_softc *sc, int sleep_flag); static int mpr_init_queues(struct mpr_softc *sc); @@ -352,11 +354,9 @@ mpr_transition_operational(struct mpr_softc *sc) static int mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t attaching) { - int error, i; + int error; Mpi2IOCFactsReply_t saved_facts; uint8_t saved_mode, reallocating; - struct mprsas_lun *lun, *lun_tmp; - struct mprsas_target *targ; mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); @@ -513,27 +513,7 @@ mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t attaching) */ if (reallocating) { mpr_iocfacts_free(sc); - - /* - * The number of targets is based on IOC Facts, so free all of - * the allocated LUNs for each target and then the target buffer - * itself. - */ - for (i=0; i< saved_facts.MaxTargets; i++) { - targ = &sc->sassc->targets[i]; - SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, - lun_tmp) { - free(lun, M_MPR); - } - } - free(sc->sassc->targets, M_MPR); - - sc->sassc->targets = malloc(sizeof(struct mprsas_target) * - sc->facts->MaxTargets, M_MPR, M_WAITOK|M_ZERO); - if (!sc->sassc->targets) { - panic("%s failed to alloc targets with error %d\n", - __func__, ENOMEM); - } + mprsas_realloc_targets(sc, saved_facts.MaxTargets); } /* @@ -775,7 +755,7 @@ mpr_reinit(struct mpr_softc *sc) /* the end of discovery will release the simq, so we're done. */ mpr_dprint(sc, MPR_INFO, "%s finished sc %p post %u free %u\n", __func__, sc, sc->replypostindex, sc->replyfreeindex); - mprsas_release_simq_reinit(sassc); + mprsas_release_simq_reinit(sassc); return 0; } @@ -816,7 +796,8 @@ mpr_wait_db_ack(struct mpr_softc *sc, int timeout, int sleep_flag) * 0.5 milisecond */ if (mtx_owned(&sc->mpr_mtx) && sleep_flag == CAN_SLEEP) - msleep(&sc->msleep_fake_chan, &sc->mpr_mtx, 0, "mprdba", hz/1000); + msleep(&sc->msleep_fake_chan, &sc->mpr_mtx, 0, "mprdba", + hz/1000); else if (sleep_flag == CAN_SLEEP) pause("mprdba", hz/1000); else @@ -982,7 +963,7 @@ mpr_enqueue_request(struct mpr_softc *sc, struct mpr_command *cm) reply_descriptor rd; MPR_FUNCTRACE(sc); - mpr_dprint(sc, MPR_TRACE, "%s SMID %u cm %p ccb %p\n", __func__, + mpr_dprint(sc, MPR_TRACE, "SMID %u cm %p ccb %p\n", cm->cm_desc.Default.SMID, cm, cm->cm_ccb); if (sc->mpr_flags & MPR_FLAGS_ATTACH_DONE && !(sc->mpr_flags & @@ -1372,6 +1353,8 @@ mpr_get_tunables(struct mpr_softc *sc) sc->disable_msix = 0; sc->disable_msi = 0; sc->max_chains = MPR_CHAIN_FRAMES; + sc->enable_ssu = MPR_SSU_ENABLE_SSD_DISABLE_HDD; + sc->spinup_wait_time = DEFAULT_SPINUP_WAIT; /* * Grab the global variables. @@ -1380,6 +1363,8 @@ mpr_get_tunables(struct mpr_softc *sc) TUNABLE_INT_FETCH("hw.mpr.disable_msix", &sc->disable_msix); TUNABLE_INT_FETCH("hw.mpr.disable_msi", &sc->disable_msi); TUNABLE_INT_FETCH("hw.mpr.max_chains", &sc->max_chains); + TUNABLE_INT_FETCH("hw.mpr.enable_ssu", &sc->enable_ssu); + TUNABLE_INT_FETCH("hw.mpr.spinup_wait_time", &sc->spinup_wait_time); /* Grab the unit-instance variables */ snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.debug_level", @@ -1402,6 +1387,14 @@ mpr_get_tunables(struct mpr_softc *sc) snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.exclude_ids", device_get_unit(sc->mpr_dev)); TUNABLE_STR_FETCH(tmpstr, sc->exclude_ids, sizeof(sc->exclude_ids)); + + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.enable_ssu", + device_get_unit(sc->mpr_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->enable_ssu); + + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.spinup_wait_time", + device_get_unit(sc->mpr_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->spinup_wait_time); } static void @@ -1474,11 +1467,20 @@ mpr_setup_sysctl(struct mpr_softc *sc) OID_AUTO, "max_chains", CTLFLAG_RD, &sc->max_chains, 0,"maximum chain frames that will be allocated"); + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "enable_ssu", CTLFLAG_RW, &sc->enable_ssu, 0, + "enable SSU to SATA SSD/HDD at shutdown"); + #if __FreeBSD_version >= 900030 SYSCTL_ADD_UQUAD(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "chain_alloc_fail", CTLFLAG_RD, &sc->chain_alloc_fail, "chain allocation failures"); #endif //FreeBSD_version >= 900030 + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "spinup_wait_time", CTLFLAG_RD, + &sc->spinup_wait_time, DEFAULT_SPINUP_WAIT, "seconds to wait for " + "spinup after SATA ID error"); } int @@ -2096,7 +2098,7 @@ mpr_update_events(struct mpr_softc *sc, struct mpr_event_handle *handle, (reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) error = ENXIO; - if(reply) + if (reply) mpr_print_event(sc, reply); mpr_dprint(sc, MPR_TRACE, "%s finished error %d\n", __func__, error); @@ -2163,8 +2165,8 @@ mpr_deregister_events(struct mpr_softc *sc, struct mpr_event_handle *handle) * Add a chain element as the next SGE for the specified command. * Reset cm_sge and cm_sgesize to indicate all the available space. Chains are * only required for IEEE commands. Therefore there is no code for commands - * that have the MPR_CM_FLAGS_SGE_SIMPLE flag set (and those commands shouldn't - * be requesting chains). + * that have the MPR_CM_FLAGS_SGE_SIMPLE flag set (and those commands + * shouldn't be requesting chains). */ static int mpr_add_chain(struct mpr_command *cm, int segsleft) @@ -2246,9 +2248,9 @@ mpr_add_chain(struct mpr_command *cm, int segsleft) /* * Add one scatter-gather element to the scatter-gather list for a command. - * Maintain cm_sglsize and cm_sge as the remaining size and pointer to the next - * SGE to fill in, respectively. In Gen3, the MPI SGL does not have a chain, - * so don't consider any chain additions. + * Maintain cm_sglsize and cm_sge as the remaining size and pointer to the + * next SGE to fill in, respectively. In Gen3, the MPI SGL does not have a + * chain, so don't consider any chain additions. */ int mpr_push_sge(struct mpr_command *cm, MPI2_SGE_SIMPLE64 *sge, size_t len, @@ -2660,7 +2662,7 @@ mpr_request_polled(struct mpr_softc *sc, struct mpr_command *cm) } } - if(error) { + if (error) { mpr_dprint(sc, MPR_FAULT, "Calling Reinit from %s\n", __func__); rc = mpr_reinit(sc); mpr_dprint(sc, MPR_FAULT, "Reinit %s\n", (rc == 0) ? @@ -2717,9 +2719,12 @@ mpr_read_config_page(struct mpr_softc *sc, struct mpr_config_params *params) cm->cm_data = params->buffer; cm->cm_length = params->length; - cm->cm_sge = &req->PageBufferSGE; - cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); - cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN; + if (cm->cm_data != NULL) { + cm->cm_sge = &req->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN; + } else + cm->cm_sge = NULL; cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; cm->cm_complete_data = params; @@ -2776,9 +2781,12 @@ mpr_config_complete(struct mpr_softc *sc, struct mpr_command *cm) goto done; } params->status = reply->IOCStatus; - if (params->hdr.Ext.ExtPageType != 0) { + if (params->hdr.Struct.PageType == MPI2_CONFIG_PAGETYPE_EXTENDED) { params->hdr.Ext.ExtPageType = reply->ExtPageType; params->hdr.Ext.ExtPageLength = reply->ExtPageLength; + params->hdr.Ext.PageType = reply->Header.PageType; + params->hdr.Ext.PageNumber = reply->Header.PageNumber; + params->hdr.Ext.PageVersion = reply->Header.PageVersion; } else { params->hdr.Struct.PageType = reply->Header.PageType; params->hdr.Struct.PageNumber = reply->Header.PageNumber; diff --git a/sys/dev/mpr/mpr_config.c b/sys/dev/mpr/mpr_config.c index 1254516..c0ea3d5 100644 --- a/sys/dev/mpr/mpr_config.c +++ b/sys/dev/mpr/mpr_config.c @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2011-2014 LSI Corp. + * Copyright (c) 2011-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD */ #include <sys/cdefs.h> diff --git a/sys/dev/mpr/mpr_ioctl.h b/sys/dev/mpr/mpr_ioctl.h index 5ec482f..aa1a4cb 100644 --- a/sys/dev/mpr/mpr_ioctl.h +++ b/sys/dev/mpr/mpr_ioctl.h @@ -27,12 +27,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD userland interface + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD userland interface * * $FreeBSD$ */ /*- - * Copyright (c) 2011-2014 LSI Corp. + * Copyright (c) 2011-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -56,7 +57,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD * * $FreeBSD$ */ diff --git a/sys/dev/mpr/mpr_mapping.c b/sys/dev/mpr/mpr_mapping.c index 7f0fc00..110e6a3 100644 --- a/sys/dev/mpr/mpr_mapping.c +++ b/sys/dev/mpr/mpr_mapping.c @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2011-2014 LSI Corp. + * Copyright (c) 2011-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD */ #include <sys/cdefs.h> @@ -326,11 +327,13 @@ _mapping_get_high_missing_mt_idx(struct mpr_softc *sc) { u32 map_idx, high_idx = MPR_ENCTABLE_BAD_IDX; u8 high_missing_count = 0; - u32 start_idx, end_idx, start_idx_ir = 0, end_idx_ir; + u32 start_idx, end_idx, start_idx_ir, end_idx_ir; struct dev_mapping_table *mt_entry; u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); start_idx = 0; + start_idx_ir = 0; + end_idx_ir = 0; end_idx = sc->max_devices; if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0) start_idx = 1; @@ -887,14 +890,14 @@ _mapping_get_dev_info(struct mpr_softc *sc, u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t sas_device_pg0; - u8 entry, enc_idx, phy_idx; + u8 entry, enc_idx, phy_idx, sata_end_device; u32 map_idx, index, device_info; struct _map_phy_change *phy_change, *tmp_phy_change; uint64_t sas_address; struct enc_mapping_table *et_entry; struct dev_mapping_table *mt_entry; u8 add_code = MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED; - int rc; + int rc = 1; for (entry = 0; entry < topo_change->num_entries; entry++) { phy_change = &topo_change->phy_details[entry]; @@ -908,41 +911,36 @@ _mapping_get_dev_info(struct mpr_softc *sc, continue; } + /* + * Always get SATA Identify information because this is used + * to determine if Start/Stop Unit should be sent to the drive + * when the system is shutdown. + */ device_info = le32toh(sas_device_pg0.DeviceInfo); - if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == - MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { - if ((device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE) && - (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)) { - rc = mprsas_get_sas_address_for_sata_disk(sc, - &sas_address, phy_change->dev_handle, - device_info); - if (rc) { - printf("%s: failed to compute the " - "hashed SAS Address for SATA " - "device with handle 0x%04x\n", - __func__, phy_change->dev_handle); - sas_address = - sas_device_pg0.SASAddress.High; - sas_address = (sas_address << 32) | - sas_device_pg0.SASAddress.Low; - } + sas_address = sas_device_pg0.SASAddress.High; + sas_address = (sas_address << 32) | + sas_device_pg0.SASAddress.Low; + sata_end_device = 0; + if ((device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE) && + (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)) { + sata_end_device = 1; + rc = mprsas_get_sas_address_for_sata_disk(sc, + &sas_address, phy_change->dev_handle, device_info, + &phy_change->is_SATA_SSD); + if (rc) { + mpr_dprint(sc, MPR_ERROR, "%s: failed to get " + "disk type (SSD or HDD) and SAS Address " + "for SATA device with handle 0x%04x\n", + __func__, phy_change->dev_handle); + } else { mpr_dprint(sc, MPR_INFO, "SAS Address for SATA " "device = %jx\n", sas_address); - } else { - sas_address = - sas_device_pg0.SASAddress.High; - sas_address = (sas_address << 32) | - sas_device_pg0.SASAddress.Low; } - } else { - sas_address = sas_device_pg0.SASAddress.High; - sas_address = (sas_address << 32) | - sas_device_pg0.SASAddress.Low; } + phy_change->physical_id = sas_address; phy_change->slot = le16toh(sas_device_pg0.Slot); - phy_change->device_info = - le32toh(sas_device_pg0.DeviceInfo); + phy_change->device_info = le32toh(sas_device_pg0.DeviceInfo); if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { @@ -950,10 +948,10 @@ _mapping_get_dev_info(struct mpr_softc *sc, topo_change->enc_handle); if (enc_idx == MPR_ENCTABLE_BAD_IDX) { phy_change->is_processed = 1; - printf("%s: failed to add the device with " - "handle 0x%04x because the enclosure is " - "not in the mapping table\n", __func__, - phy_change->dev_handle); + mpr_dprint(sc, MPR_MAPPING, "%s: failed to add " + "the device with handle 0x%04x because the " + "enclosure is not in the mapping table\n", + __func__, phy_change->dev_handle); continue; } if (!((phy_change->device_info & diff --git a/sys/dev/mpr/mpr_mapping.h b/sys/dev/mpr/mpr_mapping.h index 3250c42..c00a3b7 100644 --- a/sys/dev/mpr/mpr_mapping.h +++ b/sys/dev/mpr/mpr_mapping.h @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2011-2014 LSI Corp. + * Copyright (c) 2011-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD * * $FreeBSD$ */ @@ -38,6 +39,7 @@ * @dev_handle: device handle for the device pointed by this entry * @slot: slot ID * @is_processed: Flag to indicate whether this entry is processed or not + * @is_SATA_SSD: 1 if this is a SATA device AND an SSD, 0 otherwise */ struct _map_phy_change { uint64_t physical_id; @@ -46,6 +48,8 @@ struct _map_phy_change { uint16_t slot; uint8_t reason; uint8_t is_processed; + uint8_t is_SATA_SSD; + uint8_t reserved; }; /** @@ -66,6 +70,6 @@ struct _map_topology_change { extern int mprsas_get_sas_address_for_sata_disk(struct mpr_softc *ioc, - u64 *sas_address, u16 handle, u32 device_info); + u64 *sas_address, u16 handle, u32 device_info, u8 *is_SATA_SSD); #endif diff --git a/sys/dev/mpr/mpr_pci.c b/sys/dev/mpr/mpr_pci.c index e19f33a..7430eac 100644 --- a/sys/dev/mpr/mpr_pci.c +++ b/sys/dev/mpr/mpr_pci.c @@ -27,7 +27,7 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/* PCI/PCI-X/PCIe bus interface for the LSI MPT2 controllers */ +/* PCI/PCI-X/PCIe bus interface for the Avago Tech (LSI) MPT3 controllers */ /* TODO Move headers to mprvar */ #include <sys/types.h> @@ -99,17 +99,17 @@ struct mpr_ident { const char *desc; } mpr_identifiers[] = { { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3004, - 0xffff, 0xffff, 0, "LSI SAS3004" }, + 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3004" }, { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3008, - 0xffff, 0xffff, 0, "LSI SAS3008" }, + 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3008" }, { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_1, - 0xffff, 0xffff, 0, "LSI SAS3108_1" }, + 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3108_1" }, { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_2, - 0xffff, 0xffff, 0, "LSI SAS3108_2" }, + 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3108_2" }, { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_5, - 0xffff, 0xffff, 0, "LSI SAS3108_5" }, + 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3108_5" }, { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6, - 0xffff, 0xffff, 0, "LSI SAS3108_6" }, + 0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3108_6" }, { 0, 0, 0, 0, 0, NULL } }; diff --git a/sys/dev/mpr/mpr_sas.c b/sys/dev/mpr/mpr_sas.c index 32c3a46..eac3360 100644 --- a/sys/dev/mpr/mpr_sas.c +++ b/sys/dev/mpr/mpr_sas.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2009 Yahoo! Inc. - * Copyright (c) 2011-2014 LSI Corp. + * Copyright (c) 2011-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,12 +24,15 @@ * 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. + * + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD + * */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/* Communications core for LSI MPT2 */ +/* Communications core for Avago Technologies (LSI) MPT3 */ /* TODO Move headers to mprvar */ #include <sys/types.h> @@ -122,14 +126,10 @@ static void mprsas_scsiio_complete(struct mpr_softc *, struct mpr_command *); static void mprsas_action_resetdev(struct mprsas_softc *, union ccb *); static void mprsas_resetdev_complete(struct mpr_softc *, struct mpr_command *); -static int mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm, +static int mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm, struct mpr_command *cm); -static int mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, - uint8_t type); static void mprsas_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg); -static void mprsas_prepare_ssu(struct mpr_softc *sc, struct cam_path *path, - struct ccb_getdev *cgd); #if (__FreeBSD_version < 901503) || \ ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) static void mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path, @@ -142,13 +142,12 @@ static void mprsas_portenable_complete(struct mpr_softc *sc, struct mpr_command *cm); #if __FreeBSD_version >= 900026 -static void -mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm); +static void mprsas_smpio_complete(struct mpr_softc *sc, + struct mpr_command *cm); static void mprsas_send_smpcmd(struct mprsas_softc *sassc, - union ccb *ccb, uint64_t sasaddr); -static void -mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb); -#endif + union ccb *ccb, uint64_t sasaddr); +static void mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb); +#endif //FreeBSD_version >= 900026 struct mprsas_target * mprsas_find_target_by_handle(struct mprsas_softc *sassc, int start, @@ -230,7 +229,7 @@ mprsas_startup_decrement(struct mprsas_softc *sassc) } } -/* LSI's firmware requires us to stop sending commands when we're doing task +/* The firmware requires us to stop sending commands when we're doing task * management, so refcount the TMs and keep the simq frozen when any are in * use. */ @@ -241,35 +240,31 @@ mprsas_alloc_tm(struct mpr_softc *sc) MPR_FUNCTRACE(sc); tm = mpr_alloc_high_priority_command(sc); - if (tm != NULL) { - if (sc->sassc->tm_count++ == 0) { - mpr_dprint(sc, MPR_RECOVERY, - "%s freezing simq\n", __func__); - xpt_freeze_simq(sc->sassc->sim, 1); - } - mpr_dprint(sc, MPR_RECOVERY, "%s tm_count %u\n", __func__, - sc->sassc->tm_count); - } return tm; } void mprsas_free_tm(struct mpr_softc *sc, struct mpr_command *tm) { - mpr_dprint(sc, MPR_TRACE, "%s", __func__); + MPR_FUNCTRACE(sc); if (tm == NULL) return; - /* if there are no TMs in use, we can release the simq. We use our - * own refcount so that it's easier for a diag reset to cleanup and - * release the simq. + /* + * For TM's the devq is frozen for the device. Unfreeze it here and + * free the resources used for freezing the devq. Must clear the + * INRESET flag as well or scsi I/O will not work. */ - if (--sc->sassc->tm_count == 0) { - mpr_dprint(sc, MPR_RECOVERY, "%s releasing simq\n", __func__); - xpt_release_simq(sc->sassc->sim, 1); + if (tm->cm_targ != NULL) { + tm->cm_targ->flags &= ~MPRSAS_TARGET_INRESET; + } + if (tm->cm_ccb) { + mpr_dprint(sc, MPR_INFO, "Unfreezing devq for target ID %d\n", + tm->cm_targ->tid); + xpt_release_devq(tm->cm_ccb->ccb_h.path, 1, TRUE); + xpt_free_path(tm->cm_ccb->ccb_h.path); + xpt_free_ccb(tm->cm_ccb); } - mpr_dprint(sc, MPR_RECOVERY, "%s tm_count %u\n", __func__, - sc->sassc->tm_count); mpr_free_high_priority_command(sc, tm); } @@ -298,8 +293,8 @@ mprsas_rescan_target(struct mpr_softc *sc, struct mprsas_target *targ) return; } - if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, - targetid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, targetid, + CAM_LUN_WILDCARD) != CAM_REQ_CMP) { mpr_dprint(sc, MPR_ERROR, "unable to create path for rescan\n"); xpt_free_ccb(ccb); return; @@ -473,11 +468,16 @@ mprsas_prepare_volume_remove(struct mprsas_softc *sassc, uint16_t handle) MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; cm->cm_complete = mprsas_remove_volume; cm->cm_complete_data = (void *)(uintptr_t)handle; + + mpr_dprint(sc, MPR_INFO, "%s: Sending reset for target ID %d\n", + __func__, targ->tid); + mprsas_prepare_for_tm(sc, cm, targ, CAM_LUN_WILDCARD); + mpr_map_command(sc, cm); } /* - * The MPT2 firmware performs debounce on the link to avoid transient link + * The MPT3 firmware performs debounce on the link to avoid transient link * errors and false removals. When it does decide that link has been lost * and a device needs to go away, it expects that the host will perform a * target reset and then an op remove. The reset has the side-effect of @@ -532,6 +532,11 @@ mprsas_prepare_remove(struct mprsas_softc *sassc, uint16_t handle) MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; cm->cm_complete = mprsas_remove_device; cm->cm_complete_data = (void *)(uintptr_t)handle; + + mpr_dprint(sc, MPR_INFO, "%s: Sending reset for target ID %d\n", + __func__, targ->tid); + mprsas_prepare_for_tm(sc, cm, targ, CAM_LUN_WILDCARD); + mpr_map_command(sc, cm); } @@ -596,10 +601,10 @@ mprsas_remove_device(struct mpr_softc *sc, struct mpr_command *tm) mpr_map_command(sc, tm); - mpr_dprint(sc, MPR_XINFO, "clearing target %u handle 0x%04x\n", + mpr_dprint(sc, MPR_INFO, "clearing target %u handle 0x%04x\n", targ->tid, handle); if (targ->encl_level_valid) { - mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, " + mpr_dprint(sc, MPR_INFO, "At enclosure level %d, slot %d, " "connector name (%4s)\n", targ->encl_level, targ->encl_slot, targ->connector_name); } @@ -608,7 +613,7 @@ mprsas_remove_device(struct mpr_softc *sc, struct mpr_command *tm) mpr_dprint(sc, MPR_XINFO, "Completing missed command %p\n", tm); ccb = tm->cm_complete_data; - ccb->ccb_h.status = CAM_DEV_NOT_THERE; + mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); mprsas_scsiio_complete(sc, tm); } } @@ -726,7 +731,7 @@ mpr_attach_sas(struct mpr_softc *sc) } /* - * XXX MaxTargets could change during a reinit. since we don't + * XXX MaxTargets could change during a reinit. Since we don't * resize the targets[] array during such an event, cache the value * of MaxTargets here so that we don't get into trouble later. This * should move into the reinit logic. @@ -782,7 +787,7 @@ mpr_attach_sas(struct mpr_softc *sc) } /* - * Assume that discovery events will start right away. Freezing + * Assume that discovery events will start right away. * * Hold off boot until discovery is complete. */ @@ -790,9 +795,7 @@ mpr_attach_sas(struct mpr_softc *sc) sc->sassc->startup_refcount = 0; mprsas_startup_increment(sassc); - callout_init(&sassc->discovery_callout, 1 /*mprafe*/); - - sassc->tm_count = 0; + callout_init(&sassc->discovery_callout, 1 /*mpsafe*/); /* * Register for async events so we can determine the EEDP @@ -962,7 +965,7 @@ mprsas_action(struct cam_sim *sim, union ccb *ccb) sassc = cam_sim_softc(sim); MPR_FUNCTRACE(sassc->sc); - mpr_dprint(sassc->sc, MPR_TRACE, "%s func 0x%x\n", __func__, + mpr_dprint(sassc->sc, MPR_TRACE, "ccb func_code 0x%x\n", ccb->ccb_h.func_code); mtx_assert(&sassc->sc->mpr_mtx, MA_OWNED); @@ -985,7 +988,7 @@ mprsas_action(struct cam_sim *sim, union ccb *ccb) cpi->max_lun = 255; cpi->initiator_id = sassc->maxtargets - 1; strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); - strncpy(cpi->hba_vid, "LSILogic", HBA_IDLEN); + strncpy(cpi->hba_vid, "Avago Tech (LSI)", HBA_IDLEN); strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); cpi->unit_number = cam_sim_unit(sim); cpi->bus_id = cam_sim_bus(sim); @@ -1005,7 +1008,7 @@ mprsas_action(struct cam_sim *sim, union ccb *ccb) */ cpi->maxio = 256 * 1024; #endif - cpi->ccb_h.status = CAM_REQ_CMP; + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); break; } case XPT_GET_TRAN_SETTINGS: @@ -1024,7 +1027,7 @@ mprsas_action(struct cam_sim *sim, union ccb *ccb) cts->ccb_h.target_id)); targ = &sassc->targets[cts->ccb_h.target_id]; if (targ->handle == 0x0) { - cts->ccb_h.status = CAM_DEV_NOT_THERE; + mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); break; } @@ -1054,12 +1057,12 @@ mprsas_action(struct cam_sim *sim, union ccb *ccb) scsi->valid = CTS_SCSI_VALID_TQ; scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; - cts->ccb_h.status = CAM_REQ_CMP; + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); break; } case XPT_CALC_GEOMETRY: cam_calc_geometry(&ccb->ccg, /*extended*/1); - ccb->ccb_h.status = CAM_REQ_CMP; + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); break; case XPT_RESET_DEV: mpr_dprint(sassc->sc, MPR_XINFO, @@ -1071,7 +1074,7 @@ mprsas_action(struct cam_sim *sim, union ccb *ccb) case XPT_TERM_IO: mpr_dprint(sassc->sc, MPR_XINFO, "mprsas_action faking success for abort or reset\n"); - ccb->ccb_h.status = CAM_REQ_CMP; + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); break; case XPT_SCSI_IO: mprsas_action_scsiio(sassc, ccb); @@ -1082,7 +1085,7 @@ mprsas_action(struct cam_sim *sim, union ccb *ccb) return; #endif default: - ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; + mprsas_set_ccbstatus(ccb, CAM_FUNC_NOTAVAIL); break; } xpt_done(ccb); @@ -1102,7 +1105,7 @@ mprsas_announce_reset(struct mpr_softc *sc, uint32_t ac_code, if (xpt_create_path(&path, NULL, path_id, target_id, lun_id) != CAM_REQ_CMP) { mpr_dprint(sc, MPR_ERROR, "unable to create path for reset " - "notification\n"); + "notification\n"); return; } @@ -1131,8 +1134,8 @@ mprsas_complete_all_commands(struct mpr_softc *sc) if (cm->cm_complete != NULL) { mprsas_log_command(cm, MPR_RECOVERY, - "completing cm %p state %x ccb %p for diag reset\n", - cm, cm->cm_state, cm->cm_ccb); + "completing cm %p state %x ccb %p for diag " + "reset\n", cm, cm->cm_state, cm->cm_ccb); cm->cm_complete(sc, cm); completed = 1; } @@ -1145,6 +1148,14 @@ mprsas_complete_all_commands(struct mpr_softc *sc) completed = 1; } + if (cm->cm_sc->io_cmds_active != 0) { + cm->cm_sc->io_cmds_active--; + } else { + mpr_dprint(cm->cm_sc, MPR_INFO, "Warning: " + "io_cmds_active is out of sync - resynching to " + "0\n"); + } + if ((completed == 0) && (cm->cm_state != MPR_CM_STATE_FREE)) { /* this should never happen, but if it does, log */ mprsas_log_command(cm, MPR_RECOVERY, @@ -1180,9 +1191,8 @@ mprsas_handle_reinit(struct mpr_softc *sc) /* complete and cleanup after all outstanding commands */ mprsas_complete_all_commands(sc); - mpr_dprint(sc, MPR_INIT, "%s startup %u tm %u after command " - "completion\n", __func__, sc->sassc->startup_refcount, - sc->sassc->tm_count); + mpr_dprint(sc, MPR_INIT, "%s startup %u after command completion\n", + __func__, sc->sassc->startup_refcount); /* zero all the target handles, since they may change after the * reset, and we have to rediscover all the targets and use the new @@ -1244,7 +1254,6 @@ mprsas_logical_unit_reset_complete(struct mpr_softc *sc, "NULL reset reply for tm %p\n", tm); if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { /* this completion was due to a reset, just cleanup */ - targ->flags &= ~MPRSAS_TARGET_INRESET; targ->tm = NULL; mprsas_free_tm(sc, tm); } @@ -1322,8 +1331,8 @@ mprsas_target_reset_complete(struct mpr_softc *sc, struct mpr_command *tm) * task management commands don't have S/G lists. */ if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { - mpr_dprint(sc, MPR_ERROR,"%s: cm_flags = %#x for target reset! " - "This should not happen!\n", __func__, tm->cm_flags); + mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for target " + "reset! This should not happen!\n", __func__, tm->cm_flags); mprsas_free_tm(sc, tm); return; } @@ -1333,7 +1342,6 @@ mprsas_target_reset_complete(struct mpr_softc *sc, struct mpr_command *tm) "NULL reset reply for tm %p\n", tm); if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { /* this completion was due to a reset, just cleanup */ - targ->flags &= ~MPRSAS_TARGET_INRESET; targ->tm = NULL; mprsas_free_tm(sc, tm); } @@ -1349,8 +1357,6 @@ mprsas_target_reset_complete(struct mpr_softc *sc, struct mpr_command *tm) le16toh(reply->IOCStatus), le32toh(reply->ResponseCode), le32toh(reply->TerminationCount)); - targ->flags &= ~MPRSAS_TARGET_INRESET; - if (targ->outstanding == 0) { /* we've finished recovery for this target and all * of its logical units. @@ -1378,7 +1384,7 @@ mprsas_target_reset_complete(struct mpr_softc *sc, struct mpr_command *tm) #define MPR_RESET_TIMEOUT 30 -static int +int mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, uint8_t type) { MPI2_SCSI_TASK_MANAGE_REQUEST *req; @@ -1387,8 +1393,8 @@ mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, uint8_t type) target = tm->cm_targ; if (target->handle == 0) { - mpr_dprint(sc, MPR_ERROR,"%s null devhandle for target_id %d\n", - __func__, target->tid); + mpr_dprint(sc, MPR_ERROR, "%s null devhandle for target_id " + "%d\n", __func__, target->tid); return -1; } @@ -1404,6 +1410,7 @@ mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, uint8_t type) mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, "sending logical unit reset\n"); tm->cm_complete = mprsas_logical_unit_reset_complete; + mprsas_prepare_for_tm(sc, tm, target, tm->cm_lun); } else if (type == MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { /* @@ -1412,20 +1419,20 @@ mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, uint8_t type) */ req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; tm->cm_targ->target_resets++; - tm->cm_targ->flags |= MPRSAS_TARGET_INRESET; mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, "sending target reset\n"); tm->cm_complete = mprsas_target_reset_complete; + mprsas_prepare_for_tm(sc, tm, target, CAM_LUN_WILDCARD); } else { mpr_dprint(sc, MPR_ERROR, "unexpected reset type 0x%x\n", type); return -1; } - mpr_dprint(sc, MPR_XINFO, "to target %u handle 0x%04x\n", target->tid, + mpr_dprint(sc, MPR_INFO, "to target %u handle 0x%04x\n", target->tid, target->handle); if (target->encl_level_valid) { - mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, " + mpr_dprint(sc, MPR_INFO, "At enclosure level %d, slot %d, " "connector name (%4s)\n", target->encl_level, target->encl_slot, target->connector_name); } @@ -1441,8 +1448,7 @@ mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, uint8_t type) err = mpr_map_command(sc, tm); if (err) mprsas_log_command(tm, MPR_RECOVERY, - "error %d sending reset type %u\n", - err, type); + "error %d sending reset type %u\n", err, type); return err; } @@ -1573,6 +1579,10 @@ mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm, targ->aborts++; + mpr_dprint(sc, MPR_INFO, "Sending reset from %s for target ID %d\n", + __func__, targ->tid); + mprsas_prepare_for_tm(sc, tm, targ, tm->cm_lun); + err = mpr_map_command(sc, tm); if (err) mprsas_log_command(tm, MPR_RECOVERY, @@ -1581,7 +1591,6 @@ mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm, return err; } - static void mprsas_scsiio_timeout(void *data) { @@ -1617,11 +1626,11 @@ mprsas_scsiio_timeout(void *data) targ = cm->cm_targ; targ->timeouts++; - mprsas_log_command(cm, MPR_XINFO, "command timeout cm %p ccb %p " + mprsas_log_command(cm, MPR_ERROR, "command timeout cm %p ccb %p " "target %u, handle(0x%04x)\n", cm, cm->cm_ccb, targ->tid, targ->handle); if (targ->encl_level_valid) { - mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, " + mpr_dprint(sc, MPR_ERROR, "At enclosure level %d, slot %d, " "connector name (%4s)\n", targ->encl_level, targ->encl_slot, targ->connector_name); } @@ -1629,8 +1638,7 @@ mprsas_scsiio_timeout(void *data) /* XXX first, check the firmware state, to see if it's still * operational. if not, do a diag reset. */ - - cm->cm_ccb->ccb_h.status = CAM_CMD_TIMEOUT; + mprsas_set_ccbstatus(cm->cm_ccb, CAM_CMD_TIMEOUT); cm->cm_state = MPR_CM_STATE_TIMEDOUT; TAILQ_INSERT_TAIL(&targ->timedout_commands, cm, cm_recovery); @@ -1681,19 +1689,22 @@ mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb) mtx_assert(&sc->mpr_mtx, MA_OWNED); csio = &ccb->csio; + KASSERT(csio->ccb_h.target_id < sassc->maxtargets, + ("Target %d out of bounds in XPT_SCSI_IO\n", + csio->ccb_h.target_id)); targ = &sassc->targets[csio->ccb_h.target_id]; mpr_dprint(sc, MPR_TRACE, "ccb %p target flag %x\n", ccb, targ->flags); if (targ->handle == 0x0) { mpr_dprint(sc, MPR_ERROR, "%s NULL handle for target %u\n", __func__, csio->ccb_h.target_id); - csio->ccb_h.status = CAM_DEV_NOT_THERE; + mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); xpt_done(ccb); return; } if (targ->flags & MPR_TARGET_FLAGS_RAID_COMPONENT) { - mpr_dprint(sc, MPR_TRACE, "%s Raid component no SCSI IO " + mpr_dprint(sc, MPR_ERROR, "%s Raid component no SCSI IO " "supported %u\n", __func__, csio->ccb_h.target_id); - csio->ccb_h.status = CAM_DEV_NOT_THERE; + mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); xpt_done(ccb); return; } @@ -1702,7 +1713,7 @@ mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb) * Progress" and was actually aborted by the upper layer. Check for * this here and complete the command without error. */ - if (ccb->ccb_h.status != CAM_REQ_INPROG) { + if (mprsas_get_ccbstatus(ccb) != CAM_REQ_INPROG) { mpr_dprint(sc, MPR_TRACE, "%s Command is not in progress for " "target %u\n", __func__, csio->ccb_h.target_id); xpt_done(ccb); @@ -1715,16 +1726,29 @@ mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb) */ if (targ->flags & MPRSAS_TARGET_INREMOVAL) { if (targ->devinfo == 0) - csio->ccb_h.status = CAM_REQ_CMP; + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); else - csio->ccb_h.status = CAM_SEL_TIMEOUT; + mprsas_set_ccbstatus(ccb, CAM_SEL_TIMEOUT); xpt_done(ccb); return; } if ((sc->mpr_flags & MPR_FLAGS_SHUTDOWN) != 0) { - mpr_dprint(sc, MPR_TRACE, "%s shutting down\n", __func__); - csio->ccb_h.status = CAM_DEV_NOT_THERE; + mpr_dprint(sc, MPR_INFO, "%s shutting down\n", __func__); + mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); + xpt_done(ccb); + return; + } + + /* + * If target has a reset in progress, freeze the devq and return. The + * devq will be released when the TM reset is finished. + */ + if (targ->flags & MPRSAS_TARGET_INRESET) { + ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN; + mpr_dprint(sc, MPR_INFO, "%s: Freezing devq for target ID %d\n", + __func__, targ->tid); + xpt_freeze_devq(ccb->ccb_h.path, 1); xpt_done(ccb); return; } @@ -1807,7 +1831,7 @@ mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb) if (MPR_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) { mpr_free_command(sc, cm); - ccb->ccb_h.status = CAM_LUN_INVALID; + mprsas_set_ccbstatus(ccb, CAM_LUN_INVALID); xpt_done(ccb); return; } @@ -1904,7 +1928,7 @@ mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb) } callout_reset_sbt(&cm->cm_callout, SBT_1MS * ccb->ccb_h.timeout, 0, - mprsas_scsiio_timeout, cm, 0); + mprsas_scsiio_timeout, cm, 0); targ->issued++; targ->outstanding++; @@ -2102,7 +2126,7 @@ mpr_sc_failed_io_info(struct mpr_softc *sc, struct ccb_scsiio *csio, desc_scsi_state, scsi_state); if (sc->mpr_debug & MPR_XINFO && - scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { + scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { mpr_dprint(sc, MPR_XINFO, "-> Sense Buffer Data : Start :\n"); scsi_sense_print(csio); mpr_dprint(sc, MPR_XINFO, "-> Sense Buffer Data : End :\n"); @@ -2126,6 +2150,8 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) u8 *TLR_bits, TLR_on; int dir = 0, i; u16 alloc_len; + struct mprsas_target *target; + target_id_t target_id; MPR_FUNCTRACE(sc); mpr_dprint(sc, MPR_TRACE, @@ -2139,6 +2165,7 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) sassc = sc->sassc; ccb = cm->cm_complete_data; csio = &ccb->csio; + target_id = csio->ccb_h.target_id; rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply; /* * XXX KDM if the chain allocation fails, does it matter if we do @@ -2197,7 +2224,7 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) * because there can be no reply when we haven't actually * gone out to the hardware. */ - ccb->ccb_h.status = CAM_REQUEUE_REQ; + mprsas_set_ccbstatus(ccb, CAM_REQUEUE_REQ); /* * Currently the only error included in the mask is @@ -2214,7 +2241,7 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) xpt_freeze_simq(sassc->sim, 1); sassc->flags |= MPRSAS_QUEUE_FROZEN; mpr_dprint(sc, MPR_INFO, "Error sending command, " - "freezing SIM queue\n"); + "freezing SIM queue\n"); } } @@ -2224,7 +2251,7 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) * commands that were sent. All SSU commands should be completed before * shutdown completes, meaning SSU_refcount will be 0 after SSU_started * is TRUE. - */ + */ if (sc->SSU_started && (csio->cdb_io.cdb_bytes[0] == START_STOP_UNIT)) { mpr_dprint(sc, MPR_INFO, "Decrementing SSU count.\n"); sc->SSU_refcount--; @@ -2232,12 +2259,12 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) /* Take the fast path to completion */ if (cm->cm_reply == NULL) { - if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { + if (mprsas_get_ccbstatus(ccb) == CAM_REQ_INPROG) { if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) - ccb->ccb_h.status = CAM_SCSI_BUS_RESET; + mprsas_set_ccbstatus(ccb, CAM_SCSI_BUS_RESET); else { - ccb->ccb_h.status = CAM_REQ_CMP; - ccb->csio.scsi_status = SCSI_STATUS_OK; + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); + csio->scsi_status = SCSI_STATUS_OK; } if (sassc->flags & MPRSAS_QUEUE_FROZEN) { ccb->ccb_h.status |= CAM_RELEASE_SIMQ; @@ -2252,10 +2279,10 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) * CAM_REQ_CMP. The first is if MPR_CM_FLAGS_ERROR_MASK is * set, the second is in the MPR_FLAGS_DIAGRESET above. */ - if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + if (mprsas_get_ccbstatus(ccb) != CAM_REQ_CMP) { /* * Freeze the dev queue so that commands are - * executed in the correct order with after error + * executed in the correct order after error * recovery. */ ccb->ccb_h.status |= CAM_DEV_QFRZN; @@ -2285,7 +2312,7 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) /* Completion failed at the transport level. */ if (rep->SCSIState & (MPI2_SCSI_STATE_NO_SCSI_STATUS | MPI2_SCSI_STATE_TERMINATED)) { - ccb->ccb_h.status = CAM_REQ_CMP_ERR; + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); break; } @@ -2294,7 +2321,7 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) * recover the command. */ if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED) { - ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; + mprsas_set_ccbstatus(ccb, CAM_AUTOSENSE_FAIL); break; } @@ -2306,7 +2333,7 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) if ((rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) && ((le32toh(rep->ResponseInfo) & MPI2_SCSI_RI_MASK_REASONCODE) == MPR_SCSI_RI_INVALID_FRAME)) { - sc->mapping_table[csio->ccb_h.target_id].TLR_bits = + sc->mapping_table[target_id].TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR; } @@ -2318,16 +2345,16 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) */ if ((rep->SCSIStatus == MPI2_SCSI_STATUS_COMMAND_TERMINATED) || (rep->SCSIStatus == MPI2_SCSI_STATUS_TASK_ABORTED)) { - ccb->ccb_h.status = CAM_REQ_ABORTED; + mprsas_set_ccbstatus(ccb, CAM_REQ_ABORTED); break; } /* Handle normal status and sense */ csio->scsi_status = rep->SCSIStatus; if (rep->SCSIStatus == MPI2_SCSI_STATUS_GOOD) - ccb->ccb_h.status = CAM_REQ_CMP; + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); else - ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + mprsas_set_ccbstatus(ccb, CAM_SCSI_STATUS_ERROR); if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) { int sense_len, returned_sense_len; @@ -2362,12 +2389,11 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) (csio->data_ptr != NULL) && ((csio->data_ptr[0] & 0x1f) == T_SEQUENTIAL) && (sc->control_TLR) && - (sc->mapping_table[csio->ccb_h.target_id].device_info & + (sc->mapping_table[target_id].device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET)) { vpd_list = (struct scsi_vpd_supported_page_list *) csio->data_ptr; - TLR_bits = &sc->mapping_table[csio->ccb_h.target_id]. - TLR_bits; + TLR_bits = &sc->mapping_table[target_id].TLR_bits; *TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR; TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON; alloc_len = ((u16)csio->cdb_io.cdb_bytes[3] << 8) + @@ -2380,6 +2406,24 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) } } } + + /* + * If this is a SATA direct-access end device, mark it so that + * a SCSI StartStopUnit command will be sent to it when the + * driver is being shutdown. + */ + if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) && + ((csio->data_ptr[0] & 0x1f) == T_DIRECT) && + (sc->mapping_table[target_id].device_info & + MPI2_SAS_DEVICE_INFO_SATA_DEVICE) && + ((sc->mapping_table[target_id].device_info & + MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) == + MPI2_SAS_DEVICE_INFO_END_DEVICE)) { + target = &sassc->targets[target_id]; + target->supports_SSU = TRUE; + mpr_dprint(sc, MPR_XINFO, "Target %d supports SSU\n", + target_id); + } break; case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: @@ -2390,13 +2434,13 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) * failed. */ if (cm->cm_targ->devinfo == 0) - ccb->ccb_h.status = CAM_REQ_CMP; + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); else - ccb->ccb_h.status = CAM_DEV_NOT_THERE; + mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); break; case MPI2_IOCSTATUS_INVALID_SGL: mpr_print_scsiio_cmd(sc, cm); - ccb->ccb_h.status = CAM_UNREC_HBA_ERROR; + mprsas_set_ccbstatus(ccb, CAM_UNREC_HBA_ERROR); break; case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: /* @@ -2409,14 +2453,14 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) * on the console. */ if (cm->cm_state == MPR_CM_STATE_TIMEDOUT) - ccb->ccb_h.status = CAM_CMD_TIMEOUT; + mprsas_set_ccbstatus(ccb, CAM_CMD_TIMEOUT); else - ccb->ccb_h.status = CAM_REQ_ABORTED; + mprsas_set_ccbstatus(ccb, CAM_REQ_ABORTED); break; case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: /* resid is ignored for this condition */ csio->resid = 0; - ccb->ccb_h.status = CAM_DATA_RUN_ERR; + mprsas_set_ccbstatus(ccb, CAM_DATA_RUN_ERR); break; case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: @@ -2425,7 +2469,7 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) * transient transport-related) errors, retry these without * decrementing the retry count. */ - ccb->ccb_h.status = CAM_REQUEUE_REQ; + mprsas_set_ccbstatus(ccb, CAM_REQUEUE_REQ); mprsas_log_command(cm, MPR_INFO, "terminated ioc %x scsi %x state %x xfer %u\n", le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState, @@ -2447,7 +2491,7 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState, le32toh(rep->TransferCount)); csio->resid = cm->cm_length; - ccb->ccb_h.status = CAM_REQ_CMP_ERR; + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); break; } @@ -2460,7 +2504,7 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) "queue\n"); } - if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + if (mprsas_get_ccbstatus(ccb) != CAM_REQ_CMP) { ccb->ccb_h.status |= CAM_DEV_QFRZN; xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); } @@ -2487,16 +2531,16 @@ mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm) * in the standard request size. */ if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { - mpr_dprint(sc, MPR_ERROR,"%s: cm_flags = %#x on SMP request!\n", - __func__, cm->cm_flags); - ccb->ccb_h.status = CAM_REQ_CMP_ERR; + mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x on SMP " + "request!\n", __func__, cm->cm_flags); + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); goto bailout; } rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply; if (rpl == NULL) { mpr_dprint(sc, MPR_ERROR, "%s: NULL cm_reply!\n", __func__); - ccb->ccb_h.status = CAM_REQ_CMP_ERR; + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); goto bailout; } @@ -2509,17 +2553,17 @@ mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm) rpl->SASStatus != MPI2_SASSTATUS_SUCCESS) { mpr_dprint(sc, MPR_XINFO, "%s: IOCStatus %04x SASStatus %02x\n", __func__, le16toh(rpl->IOCStatus), rpl->SASStatus); - ccb->ccb_h.status = CAM_REQ_CMP_ERR; + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); goto bailout; } - mpr_dprint(sc, MPR_XINFO, "%s: SMP request to SAS address " - "%#jx completed successfully\n", __func__, (uintmax_t)sasaddr); + mpr_dprint(sc, MPR_XINFO, "%s: SMP request to SAS address %#jx " + "completed successfully\n", __func__, (uintmax_t)sasaddr); if (ccb->smpio.smp_response[2] == SMP_FR_ACCEPTED) - ccb->ccb_h.status = CAM_REQ_CMP; + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); else - ccb->ccb_h.status = CAM_SMP_STATUS_ERROR; + mprsas_set_ccbstatus(ccb, CAM_SMP_STATUS_ERROR); bailout: /* @@ -2558,7 +2602,7 @@ mprsas_send_smpcmd(struct mprsas_softc *sassc, union ccb *ccb, */ mpr_dprint(sc, MPR_ERROR, "%s: physical addresses not " "supported\n", __func__); - ccb->ccb_h.status = CAM_REQ_INVALID; + mprsas_set_ccbstatus(ccb, CAM_REQ_INVALID); xpt_done(ccb); return; case CAM_DATA_SG: @@ -2571,7 +2615,7 @@ mprsas_send_smpcmd(struct mprsas_softc *sassc, union ccb *ccb, mpr_dprint(sc, MPR_ERROR, "%s: multiple request or response buffer segments " "not supported for SMP\n", __func__); - ccb->ccb_h.status = CAM_REQ_INVALID; + mprsas_set_ccbstatus(ccb, CAM_REQ_INVALID); xpt_done(ccb); return; } @@ -2605,7 +2649,7 @@ mprsas_send_smpcmd(struct mprsas_softc *sassc, union ccb *ccb, response = ccb->smpio.smp_response; break; default: - ccb->ccb_h.status = CAM_REQ_INVALID; + mprsas_set_ccbstatus(ccb, CAM_REQ_INVALID); xpt_done(ccb); return; } @@ -2614,9 +2658,9 @@ mprsas_send_smpcmd(struct mprsas_softc *sassc, union ccb *ccb, * XXX We don't yet support physical addresses here. */ if (ccb->ccb_h.flags & (CAM_DATA_PHYS|CAM_SG_LIST_PHYS)) { - mpr_printf(sc, "%s: physical addresses not supported\n", - __func__); - ccb->ccb_h.status = CAM_REQ_INVALID; + mpr_dprint(sc, MPR_ERROR, "%s: physical addresses not " + "supported\n", __func__); + mprsas_set_ccbstatus(ccb, CAM_REQ_INVALID); xpt_done(ccb); return; } @@ -2635,7 +2679,7 @@ mprsas_send_smpcmd(struct mprsas_softc *sassc, union ccb *ccb, mpr_dprint(sc, MPR_ERROR, "%s: multiple request or " "response buffer segments not supported for SMP\n", __func__); - ccb->ccb_h.status = CAM_REQ_INVALID; + mprsas_set_ccbstatus(ccb, CAM_REQ_INVALID); xpt_done(ccb); return; } @@ -2673,7 +2717,7 @@ mprsas_send_smpcmd(struct mprsas_softc *sassc, union ccb *ccb, if (cm == NULL) { mpr_dprint(sc, MPR_ERROR, "%s: cannot allocate command\n", __func__); - ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + mprsas_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL); xpt_done(ccb); return; } @@ -2760,7 +2804,7 @@ mprsas_send_smpcmd(struct mprsas_softc *sassc, union ccb *ccb, bailout_error: mpr_free_command(sc, cm); - ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + mprsas_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL); xpt_done(ccb); return; } @@ -2783,7 +2827,7 @@ mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb) if (targ->handle == 0x0) { mpr_dprint(sc, MPR_ERROR, "%s: target %d does not exist!\n", __func__, ccb->ccb_h.target_id); - ccb->ccb_h.status = CAM_SEL_TIMEOUT; + mprsas_set_ccbstatus(ccb, CAM_SEL_TIMEOUT); xpt_done(ccb); return; } @@ -2831,7 +2875,7 @@ mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb) if (targ->parent_handle == 0x0) { mpr_dprint(sc, MPR_ERROR, "%s: handle %d does not have " "a valid parent handle!\n", __func__, targ->handle); - ccb->ccb_h.status = CAM_DEV_NOT_THERE; + mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); goto bailout; } #ifdef OLD_MPR_PROBE @@ -2841,7 +2885,7 @@ mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb) if (parent_target == NULL) { mpr_dprint(sc, MPR_ERROR, "%s: handle %d does not have " "a valid parent target!\n", __func__, targ->handle); - ccb->ccb_h.status = CAM_DEV_NOT_THERE; + mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); goto bailout; } @@ -2850,9 +2894,8 @@ mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb) mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent %d " "does not have an SMP target!\n", __func__, targ->handle, parent_target->handle); - ccb->ccb_h.status = CAM_DEV_NOT_THERE; + mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); goto bailout; - } sasaddr = parent_target->sasaddr; @@ -2862,7 +2905,7 @@ mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb) mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent %d " "does not have an SMP target!\n", __func__, targ->handle, targ->parent_handle); - ccb->ccb_h.status = CAM_DEV_NOT_THERE; + mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); goto bailout; } @@ -2870,7 +2913,7 @@ mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb) mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent handle " "%d does not have a valid SAS address!\n", __func__, targ->handle, targ->parent_handle); - ccb->ccb_h.status = CAM_DEV_NOT_THERE; + mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); goto bailout; } @@ -2882,7 +2925,7 @@ mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb) if (sasaddr == 0) { mpr_dprint(sc, MPR_INFO, "%s: unable to find SAS address for " "handle %d\n", __func__, targ->handle); - ccb->ccb_h.status = CAM_DEV_NOT_THERE; + mprsas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); goto bailout; } mprsas_send_smpcmd(sassc, ccb, sasaddr); @@ -2914,7 +2957,7 @@ mprsas_action_resetdev(struct mprsas_softc *sassc, union ccb *ccb) if (tm == NULL) { mpr_dprint(sc, MPR_ERROR, "command alloc failure in mprsas_action_resetdev\n"); - ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + mprsas_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL); xpt_done(ccb); return; } @@ -2933,7 +2976,12 @@ mprsas_action_resetdev(struct mprsas_softc *sassc, union ccb *ccb) MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; tm->cm_complete = mprsas_resetdev_complete; tm->cm_complete_data = ccb; + + mpr_dprint(sc, MPR_INFO, "%s: Sending reset for target ID %d\n", + __func__, targ->tid); tm->cm_targ = targ; + targ->flags |= MPRSAS_TARGET_INRESET; + mpr_map_command(sc, tm); } @@ -2962,7 +3010,7 @@ mprsas_resetdev_complete(struct mpr_softc *sc, struct mpr_command *tm) mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for reset of " "handle %#04x! This should not happen!\n", __func__, tm->cm_flags, req->DevHandle); - ccb->ccb_h.status = CAM_REQ_CMP_ERR; + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); goto bailout; } @@ -2971,12 +3019,12 @@ mprsas_resetdev_complete(struct mpr_softc *sc, struct mpr_command *tm) le16toh(resp->IOCStatus), le32toh(resp->ResponseCode)); if (le32toh(resp->ResponseCode) == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) { - ccb->ccb_h.status = CAM_REQ_CMP; + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, CAM_LUN_WILDCARD); } else - ccb->ccb_h.status = CAM_REQ_CMP_ERR; + mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); bailout: @@ -2995,7 +3043,8 @@ mprsas_poll(struct cam_sim *sim) /* frequent debug messages during a panic just slow * everything down too much. */ - mpr_printf(sassc->sc, "%s clearing MPR_TRACE\n", __func__); + mpr_dprint(sassc->sc, MPR_XINFO, "%s clearing MPR_TRACE\n", + __func__); sassc->sc->mpr_debug &= ~MPR_TRACE; } @@ -3094,7 +3143,7 @@ mprsas_async(void *callback_arg, uint32_t code, struct cam_path *path, if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); - if (((cdai.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) + if ((mprsas_get_ccbstatus((union ccb *)&cdai) == CAM_REQ_CMP) && (rcap_buf.prot & SRC16_PROT_EN)) { lun->eedp_formatted = TRUE; lun->eedp_block_size = scsi_4btoul(rcap_buf.length); @@ -3121,8 +3170,6 @@ mprsas_async(void *callback_arg, uint32_t code, struct cam_path *path, #endif cgd = arg; - mprsas_prepare_ssu(sc, path, cgd); - #if (__FreeBSD_version < 901503) || \ ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) mprsas_check_eedp(sc, path, cgd); @@ -3134,64 +3181,6 @@ mprsas_async(void *callback_arg, uint32_t code, struct cam_path *path, } } -static void -mprsas_prepare_ssu(struct mpr_softc *sc, struct cam_path *path, - struct ccb_getdev *cgd) -{ - struct mprsas_softc *sassc = sc->sassc; - path_id_t pathid; - target_id_t targetid; - lun_id_t lunid; - struct mprsas_target *target; - struct mprsas_lun *lun; - uint8_t found_lun; - - sassc = sc->sassc; - pathid = cam_sim_path(sassc->sim); - targetid = xpt_path_target_id(path); - lunid = xpt_path_lun_id(path); - - KASSERT(targetid < sassc->maxtargets, - ("Target %d out of bounds in mprsas_prepare_ssu\n", targetid)); - target = &sassc->targets[targetid]; - if (target->handle == 0x0) - return; - - /* - * If LUN is already in list, don't create a new one. - */ - found_lun = FALSE; - SLIST_FOREACH(lun, &target->luns, lun_link) { - if (lun->lun_id == lunid) { - found_lun = TRUE; - break; - } - } - if (!found_lun) { - lun = malloc(sizeof(struct mprsas_lun), M_MPR, - M_NOWAIT | M_ZERO); - if (lun == NULL) { - mpr_dprint(sc, MPR_ERROR, "Unable to alloc LUN for " - "preparing SSU.\n"); - return; - } - lun->lun_id = lunid; - SLIST_INSERT_HEAD(&target->luns, lun, lun_link); - } - - /* - * If this is a SATA direct-access end device, mark it so that a SCSI - * StartStopUnit command will be sent to it when the driver is being - * shutdown. - */ - if (((cgd->inq_data.device & 0x1F) == T_DIRECT) && - (target->devinfo & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) && - ((target->devinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) == - MPI2_SAS_DEVICE_INFO_END_DEVICE)) { - lun->stop_at_shutdown = TRUE; - } -} - #if (__FreeBSD_version < 901503) || \ ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) static void @@ -3212,7 +3201,6 @@ mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path, uint8_t found_lun; char path_str[64]; - sassc = sc->sassc; pathid = cam_sim_path(sassc->sim); targetid = xpt_path_target_id(path); lunid = xpt_path_lun_id(path); @@ -3288,7 +3276,7 @@ mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path, rcap_buf = malloc(sizeof(struct scsi_read_capacity_eedp), M_MPR, M_NOWAIT | M_ZERO); if (rcap_buf == NULL) { - mpr_dprint(sc, MPR_FAULT, "Unable to alloc read capacity " + mpr_dprint(sc, MPR_ERROR, "Unable to alloc read capacity " "buffer for EEDP support.\n"); xpt_free_path(ccb->ccb_h.path); xpt_free_ccb(ccb); @@ -3341,7 +3329,7 @@ mprsas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb) xpt_release_devq(done_ccb->ccb_h.path, /*count*/ 1, /*run_queue*/TRUE); } - + rcap_buf = (struct scsi_read_capacity_eedp *)done_ccb->csio.data_ptr; /* @@ -3359,21 +3347,21 @@ mprsas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb) /* * Got the LUN in the target's LUN list. Fill it in with EEDP - * info. If the READ CAP 16 command had some SCSI error (common + * info. If the READ CAP 16 command had some SCSI error (common * if command is not supported), mark the lun as not supporting * EEDP and set the block size to 0. */ - if (((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) - || (done_ccb->csio.scsi_status != SCSI_STATUS_OK)) { + if ((mprsas_get_ccbstatus(done_ccb) != CAM_REQ_CMP) || + (done_ccb->csio.scsi_status != SCSI_STATUS_OK)) { lun->eedp_formatted = FALSE; lun->eedp_block_size = 0; break; } if (rcap_buf->protect & 0x01) { - mpr_dprint(sassc->sc, MPR_INFO, "LUN %d for " - "target ID %d is formatted for EEDP " - "support.\n", done_ccb->ccb_h.target_lun, + mpr_dprint(sassc->sc, MPR_INFO, "LUN %d for target ID " + "%d is formatted for EEDP support.\n", + done_ccb->ccb_h.target_lun, done_ccb->ccb_h.target_id); lun->eedp_formatted = TRUE; lun->eedp_block_size = scsi_4btoul(rcap_buf->length); @@ -3389,6 +3377,34 @@ mprsas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb) #endif /* (__FreeBSD_version < 901503) || \ ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) */ +void +mprsas_prepare_for_tm(struct mpr_softc *sc, struct mpr_command *tm, + struct mprsas_target *target, lun_id_t lun_id) +{ + union ccb *ccb; + path_id_t path_id; + + /* + * Set the INRESET flag for this target so that no I/O will be sent to + * the target until the reset has completed. If an I/O request does + * happen, the devq will be frozen. The CCB holds the path which is + * used to release the devq. The devq is released and the CCB is freed + * when the TM completes. + */ + ccb = xpt_alloc_ccb_nowait(); + if (ccb) { + path_id = cam_sim_path(sc->sassc->sim); + if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, path_id, + target->tid, lun_id) != CAM_REQ_CMP) { + xpt_free_ccb(ccb); + } else { + tm->cm_ccb = ccb; + tm->cm_targ = target; + target->flags |= MPRSAS_TARGET_INRESET; + } + } +} + int mprsas_startup(struct mpr_softc *sc) { @@ -3489,3 +3505,33 @@ mprsas_check_id(struct mprsas_softc *sassc, int id) return (0); } + +void +mprsas_realloc_targets(struct mpr_softc *sc, int maxtargets) +{ + struct mprsas_softc *sassc; + struct mprsas_lun *lun, *lun_tmp; + struct mprsas_target *targ; + int i; + + sassc = sc->sassc; + /* + * The number of targets is based on IOC Facts, so free all of + * the allocated LUNs for each target and then the target buffer + * itself. + */ + for (i=0; i< maxtargets; i++) { + targ = &sassc->targets[i]; + SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, lun_tmp) { + free(lun, M_MPR); + } + } + free(sassc->targets, M_MPR); + + sassc->targets = malloc(sizeof(struct mprsas_target) * maxtargets, + M_MPR, M_WAITOK|M_ZERO); + if (!sassc->targets) { + panic("%s failed to alloc targets with error %d\n", + __func__, ENOMEM); + } +} diff --git a/sys/dev/mpr/mpr_sas.h b/sys/dev/mpr/mpr_sas.h index 9d3116a..ebeed30 100644 --- a/sys/dev/mpr/mpr_sas.h +++ b/sys/dev/mpr/mpr_sas.h @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2011-2014 LSI Corp. + * Copyright (c) 2011-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD * * $FreeBSD$ */ @@ -35,7 +36,6 @@ struct mprsas_lun { lun_id_t lun_id; uint8_t eedp_formatted; uint32_t eedp_block_size; - uint8_t stop_at_shutdown; }; struct mprsas_target { @@ -55,11 +55,10 @@ struct mprsas_target { #define MPRSAS_TARGET_INREMOVAL (1 << 3) #define MPR_TARGET_FLAGS_RAID_COMPONENT (1 << 4) #define MPR_TARGET_FLAGS_VOLUME (1 << 5) +#define MPR_TARGET_IS_SATA_SSD (1 << 6) #define MPRSAS_TARGET_INRECOVERY (MPRSAS_TARGET_INABORT | \ MPRSAS_TARGET_INRESET | MPRSAS_TARGET_INCHIPRESET) -#define MPRSAS_TARGET_ADD (1 << 29) -#define MPRSAS_TARGET_REMOVE (1 << 30) uint16_t tid; SLIST_HEAD(, mprsas_lun) luns; TAILQ_HEAD(, mpr_command) commands; @@ -82,6 +81,8 @@ struct mprsas_target { unsigned int logical_unit_resets; unsigned int target_resets; uint8_t scsi_req_desc_type; + uint8_t stop_at_shutdown; + uint8_t supports_SSU; }; struct mprsas_softc { @@ -92,7 +93,6 @@ struct mprsas_softc { #define MPRSAS_DISCOVERY_TIMEOUT_PENDING (1 << 2) #define MPRSAS_QUEUE_FROZEN (1 << 3) #define MPRSAS_SHUTDOWN (1 << 4) -#define MPRSAS_SCANTHREAD (1 << 5) u_int maxtargets; struct mprsas_target *targets; struct cam_devq *devq; @@ -103,7 +103,6 @@ struct mprsas_softc { struct mpr_event_handle *mprsas_eh; u_int startup_refcount; - u_int tm_count; struct proc *sysctl_proc; struct taskqueue *ev_tq; @@ -150,6 +149,19 @@ mprsas_set_lun(uint8_t *lun, u_int ccblun) return (0); } +static __inline void +mprsas_set_ccbstatus(union ccb *ccb, int status) +{ + ccb->ccb_h.status &= ~CAM_STATUS_MASK; + ccb->ccb_h.status |= status; +} + +static __inline int +mprsas_get_ccbstatus(union ccb *ccb) +{ + return (ccb->ccb_h.status & CAM_STATUS_MASK); +} + #define MPR_SET_SINGLE_LUN(req, lun) \ do { \ bzero((req)->LUN, 8); \ @@ -158,11 +170,10 @@ do { \ void mprsas_rescan_target(struct mpr_softc *sc, struct mprsas_target *targ); void mprsas_discovery_end(struct mprsas_softc *sassc); +void mprsas_prepare_for_tm(struct mpr_softc *sc, struct mpr_command *tm, + struct mprsas_target *target, lun_id_t lun_id); void mprsas_startup_increment(struct mprsas_softc *sassc); void mprsas_startup_decrement(struct mprsas_softc *sassc); -void mprsas_release_simq_reinit(struct mprsas_softc *sassc); -struct mpr_command * mprsas_alloc_tm(struct mpr_softc *sc); -void mprsas_free_tm(struct mpr_softc *sc, struct mpr_command *tm); void mprsas_firmware_event_work(void *arg, int pending); int mprsas_check_id(struct mprsas_softc *sassc, int id); diff --git a/sys/dev/mpr/mpr_sas_lsi.c b/sys/dev/mpr/mpr_sas_lsi.c index 32e9b3a..7d6ef70 100644 --- a/sys/dev/mpr/mpr_sas_lsi.c +++ b/sys/dev/mpr/mpr_sas_lsi.c @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2011-2014 LSI Corp. + * Copyright (c) 2011-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,13 +24,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/* Communications core for LSI MPT2 */ +/* Communications core for LSI MPT3 */ /* TODO Move headers to mprvar */ #include <sys/types.h> @@ -105,7 +106,9 @@ struct _ata_identify_device_data { u16 serial_number[10]; /* 10-19 */ u16 reserved2[7]; /* 20-26 */ u16 model_number[20]; /* 27-46*/ - u16 reserved3[209]; /* 47-255*/ + u16 reserved3[170]; /* 47-216 */ + u16 rotational_speed; /* 217 */ + u16 reserved4[38]; /* 218-255 */ }; static u32 event_count; static void mprsas_fw_work(struct mpr_softc *sc, @@ -116,8 +119,9 @@ static int mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate); static int mprsas_get_sata_identify(struct mpr_softc *sc, u16 handle, Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz, u32 devinfo); +static void mprsas_ata_id_timeout(void *data); int mprsas_get_sas_address_for_sata_disk(struct mpr_softc *sc, - u64 *sas_address, u16 handle, u32 device_info); + u64 *sas_address, u16 handle, u32 device_info, u8 *is_SATA_SSD); static int mprsas_volume_add(struct mpr_softc *sc, u16 handle); static void mprsas_SSU_to_SATA_devices(struct mpr_softc *sc); @@ -325,7 +329,7 @@ mprsas_fw_work(struct mpr_softc *sc, struct mpr_fw_event_work *fw_event) return; } - mpr_dprint(sc, MPR_INFO, "Sending FP action " + mpr_dprint(sc, MPR_EVENT, "Sending FP action " "from " "MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST " ":\n"); @@ -350,9 +354,9 @@ mprsas_fw_work(struct mpr_softc *sc, struct mpr_fw_event_work *fw_event) if (reply && (le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) { - mpr_dprint(sc, MPR_INFO, "%s: error " - "sending RaidActionPage; iocstatus " - "= 0x%x\n", __func__, + mpr_dprint(sc, MPR_ERROR, "%s: error " + "sending RaidActionPage; " + "iocstatus = 0x%x\n", __func__, le16toh(reply->IOCStatus)); } @@ -360,7 +364,7 @@ mprsas_fw_work(struct mpr_softc *sc, struct mpr_fw_event_work *fw_event) mpr_free_command(sc, cm); } skip_fp_send: - mpr_dprint(sc, MPR_INFO, "Received " + mpr_dprint(sc, MPR_EVENT, "Received " "MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST Reason " "code %x:\n", element->ReasonCode); switch (element->ReasonCode) { @@ -421,7 +425,6 @@ skip_fp_send: break; targ->flags |= MPR_TARGET_FLAGS_RAID_COMPONENT; mprsas_rescan_target(sc, targ); - break; case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: /* @@ -678,14 +681,13 @@ mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){ struct mprsas_target *targ; Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t config_page; - uint64_t sas_address, sata_sas_address; - uint64_t parent_sas_address = 0; - u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); + uint64_t sas_address, parent_sas_address = 0; u32 device_info, parent_devinfo = 0; unsigned int id; - int ret; - int error = 0; + int ret = 1, error = 0, i; struct mprsas_lun *lun; + u8 is_SATA_SSD = 0; + struct mpr_command *cm; sassc = sc->sassc; mprsas_startup_increment(sassc); @@ -717,26 +719,29 @@ mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){ } /* TODO Check proper endianess */ sas_address = config_page.SASAddress.High; - sas_address = (sas_address << 32) | - config_page.SASAddress.Low; - - if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) - == MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { - if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) { - ret = mprsas_get_sas_address_for_sata_disk(sc, - &sata_sas_address, handle, device_info); - if (!ret) - id = mpr_mapping_get_sas_id(sc, - sata_sas_address, handle); - else - id = mpr_mapping_get_sas_id(sc, - sas_address, handle); - } else - id = mpr_mapping_get_sas_id(sc, sas_address, - handle); - } else - id = mpr_mapping_get_sas_id(sc, sas_address, handle); + sas_address = (sas_address << 32) | config_page.SASAddress.Low; + mpr_dprint(sc, MPR_INFO, "SAS Address from SAS device page0 = %jx\n", + sas_address); + + /* + * Always get SATA Identify information because this is used to + * determine if Start/Stop Unit should be sent to the drive when the + * system is shutdown. + */ + if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) { + ret = mprsas_get_sas_address_for_sata_disk(sc, &sas_address, + handle, device_info, &is_SATA_SSD); + if (ret) { + mpr_dprint(sc, MPR_ERROR, "%s: failed to get disk type " + "(SSD or HDD) for SATA device with handle 0x%04x\n", + __func__, handle); + } else { + mpr_dprint(sc, MPR_INFO, "SAS Address from SATA " + "device = %jx\n", sas_address); + } + } + id = mpr_mapping_get_sas_id(sc, sas_address, handle); if (id == MPR_MAP_BAD_ID) { printf("failure at %s:%d/%s()! Could not get ID for device " "with handle 0x%04x\n", __FILE__, __LINE__, __func__, @@ -750,7 +755,7 @@ mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){ error = ENXIO; goto out; } - + mpr_dprint(sc, MPR_MAPPING, "SAS Address from SAS device page0 = %jx\n", sas_address); targ = &sassc->targets[id]; @@ -773,6 +778,9 @@ mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){ targ->tid = id; targ->linkrate = (linkrate>>4); targ->flags = 0; + if (is_SATA_SSD) { + targ->flags = MPR_TARGET_IS_SATA_SSD; + } if (le16toh(config_page.Flags) & MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) { targ->scsi_req_desc_type = @@ -792,12 +800,12 @@ mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){ SLIST_INIT(&targ->luns); mpr_describe_devinfo(targ->devinfo, devstring, 80); - mpr_dprint(sc, (MPR_XINFO|MPR_MAPPING), "Found device <%s> <%s> " + mpr_dprint(sc, (MPR_INFO|MPR_MAPPING), "Found device <%s> <%s> " "handle<0x%04x> enclosureHandle<0x%04x> slot %d\n", devstring, mpr_describe_table(mpr_linkrate_names, targ->linkrate), targ->handle, targ->encl_handle, targ->encl_slot); if (targ->encl_level_valid) { - mpr_dprint(sc, (MPR_XINFO|MPR_MAPPING), "At enclosure level %d " + mpr_dprint(sc, (MPR_INFO|MPR_MAPPING), "At enclosure level %d " "and connector name (%4s)\n", targ->encl_level, targ->connector_name); } @@ -807,15 +815,57 @@ mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){ #endif mprsas_rescan_target(sc, targ); mpr_dprint(sc, MPR_MAPPING, "Target id 0x%x added\n", targ->tid); + + /* + * Check all commands to see if the SATA_ID_TIMEOUT flag has been set. + * If so, send a Target Reset TM to the target that was just created. + * An Abort Task TM should be used instead of a Target Reset, but that + * would be much more difficult because targets have not been fully + * discovered yet, and LUN's haven't been setup. So, just reset the + * target instead of the LUN. + */ + for (i = 1; i < sc->num_reqs; i++) { + cm = &sc->commands[i]; + if (cm->cm_flags & MPR_CM_FLAGS_SATA_ID_TIMEOUT) { + targ->timeouts++; + cm->cm_state = MPR_CM_STATE_TIMEDOUT; + + if ((targ->tm = mprsas_alloc_tm(sc)) != NULL) { + mpr_dprint(sc, MPR_INFO, "%s: sending Target " + "Reset for stuck SATA identify command " + "(cm = %p)\n", __func__, cm); + targ->tm->cm_targ = targ; + mprsas_send_reset(sc, targ->tm, + MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET); + } else { + mpr_dprint(sc, MPR_ERROR, "Failed to allocate " + "tm for Target Reset after SATA ID " + "command timed out (cm %p)\n", cm); + } + /* + * No need to check for more since the target is + * already being reset. + */ + break; + } + } out: + /* + * Free the commands that may not have been freed from the SATA ID call + */ + for (i = 1; i < sc->num_reqs; i++) { + cm = &sc->commands[i]; + if (cm->cm_flags & MPR_CM_FLAGS_SATA_ID_TIMEOUT) { + mpr_free_command(sc, cm); + } + } mprsas_startup_decrement(sassc); return (error); - } int mprsas_get_sas_address_for_sata_disk(struct mpr_softc *sc, - u64 *sas_address, u16 handle, u32 device_info) + u64 *sas_address, u16 handle, u32 device_info, u8 *is_SATA_SSD) { Mpi2SataPassthroughReply_t mpi_reply; int i, rc, try_count; @@ -835,7 +885,16 @@ mprsas_get_sas_address_for_sata_disk(struct mpr_softc *sc, ioc_status = le16toh(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; sas_status = mpi_reply.SASStatus; - } while ((rc == -EAGAIN || ioc_status || sas_status) && + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + if (sc->spinup_wait_time > 0) { + mpr_dprint(sc, MPR_INFO, "Sleeping %d seconds " + "after SATA ID error to wait for spinup\n", + sc->spinup_wait_time); + msleep(&sc->msleep_fake_chan, &sc->mpr_mtx, 0, + "mprid", sc->spinup_wait_time * hz); + } + } + } while (((rc && (rc != EWOULDBLOCK)) || ioc_status || sas_status) && (try_count < 5)); if (rc == 0 && !ioc_status && !sas_status) { @@ -884,6 +943,10 @@ mprsas_get_sas_address_for_sata_disk(struct mpr_softc *sc, (u64)hash_address.wwid[3] << 32 | (u64)hash_address.wwid[4] << 24 | (u64)hash_address.wwid[5] << 16 | (u64)hash_address.wwid[6] << 8 | (u64)hash_address.wwid[7]; + if (ata_identify.rotational_speed == 1) { + *is_SATA_SSD = 1; + } + return 0; } @@ -923,14 +986,29 @@ mprsas_get_sata_identify(struct mpr_softc *sc, u16 handle, cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; cm->cm_data = buffer; cm->cm_length = htole32(sz); + + /* + * Start a timeout counter specifically for the SATA ID command. This + * is used to fix a problem where the FW does not send a reply sometimes + * when a bad disk is in the topology. So, this is used to timeout the + * command so that processing can continue normally. + */ + mpr_dprint(sc, MPR_XINFO, "%s start timeout counter for SATA ID " + "command\n", __func__); + callout_reset(&cm->cm_callout, MPR_ATA_ID_TIMEOUT * hz, + mprsas_ata_id_timeout, cm); error = mpr_wait_command(sc, cm, 60, CAN_SLEEP); + mpr_dprint(sc, MPR_XINFO, "%s stop timeout counter for SATA ID " + "command\n", __func__); + callout_stop(&cm->cm_callout); + reply = (Mpi2SataPassthroughReply_t *)cm->cm_reply; if (error || (reply == NULL)) { /* FIXME */ /* * If the request returns an error then we need to do a diag * reset - */ + */ printf("%s: request for page completed with error %d", __func__, error); error = ENXIO; @@ -946,11 +1024,66 @@ mprsas_get_sata_identify(struct mpr_softc *sc, u16 handle, goto out; } out: - mpr_free_command(sc, cm); - free(buffer, M_MPR); + /* + * If the SATA_ID_TIMEOUT flag has been set for this command, don't free + * it. The command will be freed after sending a target reset TM. If + * the command did timeout, use EWOULDBLOCK. + */ + if ((cm->cm_flags & MPR_CM_FLAGS_SATA_ID_TIMEOUT) == 0) + mpr_free_command(sc, cm); + else if (error == 0) + error = EWOULDBLOCK; + free(buffer, M_MPR); return (error); } +static void +mprsas_ata_id_timeout(void *data) +{ + struct mpr_softc *sc; + struct mpr_command *cm; + + cm = (struct mpr_command *)data; + sc = cm->cm_sc; + mtx_assert(&sc->mpr_mtx, MA_OWNED); + + mpr_dprint(sc, MPR_INFO, "%s checking ATA ID command %p sc %p\n", + __func__, cm, sc); + if ((callout_pending(&cm->cm_callout)) || + (!callout_active(&cm->cm_callout))) { + mpr_dprint(sc, MPR_INFO, "%s ATA ID command almost timed " + "out\n", __func__); + return; + } + callout_deactivate(&cm->cm_callout); + + /* + * Run the interrupt handler to make sure it's not pending. This + * isn't perfect because the command could have already completed + * and been re-used, though this is unlikely. + */ + mpr_intr_locked(sc); + if (cm->cm_state == MPR_CM_STATE_FREE) { + mpr_dprint(sc, MPR_INFO, "%s ATA ID command almost timed " + "out\n", __func__); + return; + } + + mpr_dprint(sc, MPR_INFO, "ATA ID command timeout cm %p\n", cm); + + /* + * Send wakeup() to the sleeping thread that issued this ATA ID + * command. wakeup() will cause msleep to return a 0 (not EWOULDBLOCK), + * and this will keep reinit() from being called. This way, an Abort + * Task TM can be issued so that the timed out command can be cleared. + * The Abort Task cannot be sent from here because the driver has not + * completed setting up targets. Instead, the command is flagged so + * that special handling will be used to send the abort. + */ + cm->cm_flags |= MPR_CM_FLAGS_SATA_ID_TIMEOUT; + wakeup(cm); +} + static int mprsas_volume_add(struct mpr_softc *sc, u16 handle) { @@ -1024,15 +1157,13 @@ mprsas_SSU_to_SATA_devices(struct mpr_softc *sc) path_id_t pathid = cam_sim_path(sassc->sim); target_id_t targetid; struct mprsas_target *target; - struct mprsas_lun *lun; char path_str[64]; struct timeval cur_time, start_time; mpr_lock(sc); /* - * For each LUN of each target, issue a StartStopUnit command to stop - * the device. + * For each target, issue a StartStopUnit command to stop the device. */ sc->SSU_started = TRUE; sc->SSU_refcount = 0; @@ -1042,59 +1173,52 @@ mprsas_SSU_to_SATA_devices(struct mpr_softc *sc) continue; } - SLIST_FOREACH(lun, &target->luns, lun_link) { - ccb = xpt_alloc_ccb_nowait(); - if (ccb == NULL) { - mpr_unlock(sc); - mpr_dprint(sc, MPR_FAULT, "Unable to alloc " - "CCB to stop unit.\n"); + ccb = xpt_alloc_ccb_nowait(); + if (ccb == NULL) { + mpr_dprint(sc, MPR_FAULT, "Unable to alloc CCB to stop " + "unit.\n"); + return; + } + + /* + * The stop_at_shutdown flag will be set if this device is + * a SATA direct-access end device. + */ + if (target->stop_at_shutdown) { + if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, + pathid, targetid, CAM_LUN_WILDCARD) != + CAM_REQ_CMP) { + mpr_dprint(sc, MPR_ERROR, "Unable to create " + "path to stop unit.\n"); + xpt_free_ccb(ccb); return; } + xpt_path_string(ccb->ccb_h.path, path_str, + sizeof(path_str)); + + mpr_dprint(sc, MPR_INFO, "Sending StopUnit: path %s " + "handle %d\n", path_str, target->handle); /* - * The stop_at_shutdown flag will be set if this LUN is - * a SATA direct-access end device. + * Issue a START STOP UNIT command for the target. + * Increment the SSU counter to be used to count the + * number of required replies. */ - if (lun->stop_at_shutdown) { - if (xpt_create_path(&ccb->ccb_h.path, - xpt_periph, pathid, targetid, - lun->lun_id) != CAM_REQ_CMP) { - mpr_dprint(sc, MPR_FAULT, "Unable to " - "create LUN path to stop unit.\n"); - xpt_free_ccb(ccb); - mpr_unlock(sc); - return; - } - xpt_path_string(ccb->ccb_h.path, path_str, - sizeof(path_str)); - - mpr_dprint(sc, MPR_INFO, "Sending StopUnit: " - "path %s handle %d\n", path_str, - target->handle); - - /* - * Issue a START STOP UNIT command for the LUN. - * Increment the SSU counter to be used to - * count the number of required replies. - */ - mpr_dprint(sc, MPR_INFO, "Incrementing SSU " - "count\n"); - sc->SSU_refcount++; - ccb->ccb_h.target_id = - xpt_path_target_id(ccb->ccb_h.path); - ccb->ccb_h.target_lun = lun->lun_id; - ccb->ccb_h.ppriv_ptr1 = sassc; - scsi_start_stop(&ccb->csio, - /*retries*/0, - mprsas_stop_unit_done, - MSG_SIMPLE_Q_TAG, - /*start*/FALSE, - /*load/eject*/0, - /*immediate*/FALSE, - MPR_SENSE_LEN, - /*timeout*/10000); - xpt_action(ccb); - } + mpr_dprint(sc, MPR_INFO, "Incrementing SSU count\n"); + sc->SSU_refcount++; + ccb->ccb_h.target_id = + xpt_path_target_id(ccb->ccb_h.path); + ccb->ccb_h.ppriv_ptr1 = sassc; + scsi_start_stop(&ccb->csio, + /*retries*/0, + mprsas_stop_unit_done, + MSG_SIMPLE_Q_TAG, + /*start*/FALSE, + /*load/eject*/0, + /*immediate*/FALSE, + MPR_SENSE_LEN, + /*timeout*/10000); + xpt_action(ccb); } } @@ -1102,7 +1226,7 @@ mprsas_SSU_to_SATA_devices(struct mpr_softc *sc) /* * Wait until all of the SSU commands have completed or time has - * expired (60 seconds). pause for 100ms each time through. If any + * expired (60 seconds). Pause for 100ms each time through. If any * command times out, the target will be reset in the SCSI command * timeout routine. */ @@ -1112,7 +1236,7 @@ mprsas_SSU_to_SATA_devices(struct mpr_softc *sc) getmicrotime(&cur_time); if ((cur_time.tv_sec - start_time.tv_sec) > 60) { - mpr_dprint(sc, MPR_FAULT, "Time has expired waiting " + mpr_dprint(sc, MPR_ERROR, "Time has expired waiting " "for SSU commands to complete.\n"); break; } @@ -1162,6 +1286,8 @@ mprsas_ir_shutdown(struct mpr_softc *sc) unsigned int id, found_volume = 0; struct mpr_command *cm; Mpi2RaidActionRequest_t *action; + target_id_t targetid; + struct mprsas_target *target; mpr_dprint(sc, MPR_TRACE, "%s\n", __func__); @@ -1214,5 +1340,47 @@ mprsas_ir_shutdown(struct mpr_softc *sc) mpr_free_command(sc, cm); out: + /* + * All of the targets must have the correct value set for + * 'stop_at_shutdown' for the current 'enable_ssu' sysctl variable. + * + * The possible values for the 'enable_ssu' variable are: + * 0: disable to SSD and HDD + * 1: disable only to HDD (default) + * 2: disable only to SSD + * 3: enable to SSD and HDD + * anything else will default to 1. + */ + for (targetid = 0; targetid < sc->facts->MaxTargets; targetid++) { + target = &sc->sassc->targets[targetid]; + if (target->handle == 0x0) { + continue; + } + + if (target->supports_SSU) { + switch (sc->enable_ssu) { + case MPR_SSU_DISABLE_SSD_DISABLE_HDD: + target->stop_at_shutdown = FALSE; + break; + case MPR_SSU_DISABLE_SSD_ENABLE_HDD: + target->stop_at_shutdown = TRUE; + if (target->flags & MPR_TARGET_IS_SATA_SSD) { + target->stop_at_shutdown = FALSE; + } + break; + case MPR_SSU_ENABLE_SSD_ENABLE_HDD: + target->stop_at_shutdown = TRUE; + break; + case MPR_SSU_ENABLE_SSD_DISABLE_HDD: + default: + target->stop_at_shutdown = TRUE; + if ((target->flags & + MPR_TARGET_IS_SATA_SSD) == 0) { + target->stop_at_shutdown = FALSE; + } + break; + } + } + } mprsas_SSU_to_SATA_devices(sc); } diff --git a/sys/dev/mpr/mpr_user.c b/sys/dev/mpr/mpr_user.c index 60680f5..37d9467 100644 --- a/sys/dev/mpr/mpr_user.c +++ b/sys/dev/mpr/mpr_user.c @@ -27,10 +27,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD userland interface + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD userland interface */ /*- - * Copyright (c) 2011-2014 LSI Corp. + * Copyright (c) 2011-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,7 +55,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * LSI MPT-Fusion Host Adapter FreeBSD + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD * * $FreeBSD$ */ @@ -90,7 +91,7 @@ __FBSDID("$FreeBSD$"); #include <sys/rman.h> #include <cam/cam.h> -#include <cam/scsi/scsi_all.h> +#include <cam/cam_ccb.h> #include <dev/mpr/mpi/mpi2_type.h> #include <dev/mpr/mpi/mpi2.h> @@ -284,8 +285,7 @@ mpr_user_read_cfg_header(struct mpr_softc *sc, static int mpr_user_read_cfg_page(struct mpr_softc *sc, - struct mpr_cfg_page_req *page_req, - void *buf) + struct mpr_cfg_page_req *page_req, void *buf) { MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr; struct mpr_config_params params; @@ -328,6 +328,10 @@ mpr_user_read_extcfg_header(struct mpr_softc *sc, hdr->PageNumber = ext_page_req->header.PageNumber; hdr->ExtPageType = ext_page_req->header.ExtPageType; params.page_address = le32toh(ext_page_req->page_address); + params.buffer = NULL; + params.length = 0; + params.callback = NULL; + if ((error = mpr_read_config_page(sc, ¶ms)) != 0) { /* * Leave the request. Without resetting the chip, it's @@ -365,8 +369,8 @@ mpr_user_read_extcfg_page(struct mpr_softc *sc, params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; params.page_address = le32toh(ext_page_req->page_address); hdr->PageVersion = reqhdr->PageVersion; - hdr->PageNumber = reqhdr->PageNumber; hdr->PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + hdr->PageNumber = reqhdr->PageNumber; hdr->ExtPageType = reqhdr->ExtPageType; hdr->ExtPageLength = reqhdr->ExtPageLength; params.buffer = buf; @@ -541,6 +545,8 @@ mpi_pre_fw_upload(struct mpr_command *cm, struct mpr_usr_command *cmd) req->ImageOffset = 0; req->ImageSize = cmd->len; + cm->cm_flags |= MPR_CM_FLAGS_DATAIN; + return (mpr_push_ieee_sge(cm, &req->SGL, 0)); } @@ -834,11 +840,22 @@ mpr_user_pass_thru(struct mpr_softc *sc, mpr_pass_thru_t *data) task->TaskMID = cm->cm_desc.Default.SMID; cm->cm_data = NULL; - cm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; + cm->cm_desc.HighPriority.RequestFlags = + MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; cm->cm_complete = NULL; cm->cm_complete_data = NULL; - err = mpr_wait_command(sc, cm, 30, CAN_SLEEP); + targ = mprsas_find_target_by_handle(sc->sassc, 0, + task->DevHandle); + if (targ == NULL) { + mpr_dprint(sc, MPR_INFO, + "%s %d : invalid handle for requested TM 0x%x \n", + __func__, __LINE__, task->DevHandle); + err = 1; + } else { + mprsas_prepare_for_tm(sc, cm, targ, CAM_LUN_WILDCARD); + err = mpr_wait_command(sc, cm, 30, CAN_SLEEP); + } if (err != 0) { err = EIO; @@ -1029,7 +1046,7 @@ mpr_user_pass_thru(struct mpr_softc *sc, mpr_pass_thru_t *data) if (cm->cm_flags & MPR_CM_FLAGS_DATAIN) dir = BUS_DMASYNC_POSTREAD; else if (cm->cm_flags & MPR_CM_FLAGS_DATAOUT) - dir = BUS_DMASYNC_POSTWRITE;; + dir = BUS_DMASYNC_POSTWRITE; bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); @@ -1351,8 +1368,8 @@ done: } static int -mpr_diag_register(struct mpr_softc *sc, - mpr_fw_diag_register_t *diag_register, uint32_t *return_code) +mpr_diag_register(struct mpr_softc *sc, mpr_fw_diag_register_t *diag_register, + uint32_t *return_code) { mpr_fw_diagnostic_buffer_t *pBuffer; uint8_t extended_type, buffer_type, i; diff --git a/sys/dev/mpr/mprvar.h b/sys/dev/mpr/mprvar.h index 9752dcd..acac44c 100644 --- a/sys/dev/mpr/mprvar.h +++ b/sys/dev/mpr/mprvar.h @@ -1,6 +1,7 @@ /*- * Copyright (c) 2009 Yahoo! Inc. - * Copyright (c) 2011-2014 LSI Corp. + * Copyright (c) 2011-2015 LSI Corp. + * Copyright (c) 2013-2015 Avago Technologies * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,13 +25,15 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD + * * $FreeBSD$ */ #ifndef _MPRVAR_H #define _MPRVAR_H -#define MPR_DRIVER_VERSION "05.255.05.00-fbsd" +#define MPR_DRIVER_VERSION "09.255.01.00-fbsd" #define MPR_DB_MAX_WAIT 2500 @@ -47,16 +50,19 @@ #define MPR_FUNCTRACE(sc) \ mpr_dprint((sc), MPR_TRACE, "%s\n", __func__) -#define CAN_SLEEP 1 -#define NO_SLEEP 0 +#define CAN_SLEEP 1 +#define NO_SLEEP 0 #define MPR_PERIODIC_DELAY 1 /* 1 second heartbeat/watchdog check */ +#define MPR_ATA_ID_TIMEOUT 5 /* 5 second timeout for SATA ID cmd */ #define IFAULT_IOP_OVER_TEMP_THRESHOLD_EXCEEDED 0x2810 #define MPR_SCSI_RI_INVALID_FRAME (0x00000002) #define MPR_STRING_LENGTH 64 +#define DEFAULT_SPINUP_WAIT 3 /* seconds to wait for spinup */ + #include <sys/endian.h> /* @@ -213,13 +219,14 @@ struct mpr_command { #define MPR_CM_FLAGS_CHAIN_FAILED (1 << 8) #define MPR_CM_FLAGS_ERROR_MASK MPR_CM_FLAGS_CHAIN_FAILED #define MPR_CM_FLAGS_USE_CCB (1 << 9) +#define MPR_CM_FLAGS_SATA_ID_TIMEOUT (1 << 10) u_int cm_state; #define MPR_CM_STATE_FREE 0 #define MPR_CM_STATE_BUSY 1 #define MPR_CM_STATE_TIMEDOUT 2 bus_dmamap_t cm_dmamap; struct scsi_sense_data *cm_sense; - TAILQ_HEAD(, mpr_chain) cm_chain_list; + TAILQ_HEAD(, mpr_chain) cm_chain_list; uint32_t cm_req_busaddr; uint32_t cm_sense_busaddr; struct callout cm_callout; @@ -256,6 +263,8 @@ struct mpr_softc { int chain_free; int max_chains; int chain_free_lowwater; + u_int enable_ssu; + int spinup_wait_time; #if __FreeBSD_version >= 900030 uint64_t chain_alloc_fail; #endif @@ -270,7 +279,7 @@ struct mpr_softc { char tmp_string[MPR_STRING_LENGTH]; TAILQ_HEAD(, mpr_command) req_list; TAILQ_HEAD(, mpr_command) high_priority_req_list; - TAILQ_HEAD(, mpr_chain) chain_list; + TAILQ_HEAD(, mpr_chain) chain_list; TAILQ_HEAD(, mpr_command) tm_list; int replypostindex; int replyfreeindex; @@ -291,7 +300,7 @@ struct mpr_softc { uint8_t event_mask[16]; TAILQ_HEAD(, mpr_event_handle) event_list; - struct mpr_event_handle *mpr_log_eh; + struct mpr_event_handle *mpr_log_eh; struct mtx mpr_mtx; struct intr_config_hook mpr_ich; @@ -565,6 +574,11 @@ mpr_unlock(struct mpr_softc *sc) #define MPR_MAPPING (1 << 9) /* Trace device mappings */ #define MPR_TRACE (1 << 10) /* Function-by-function trace */ +#define MPR_SSU_DISABLE_SSD_DISABLE_HDD 0 +#define MPR_SSU_ENABLE_SSD_DISABLE_HDD 1 +#define MPR_SSU_DISABLE_SSD_ENABLE_HDD 2 +#define MPR_SSU_ENABLE_SSD_ENABLE_HDD 3 + #define mpr_printf(sc, args...) \ device_printf((sc)->mpr_dev, ##args) @@ -600,9 +614,6 @@ do { \ #define MPR_EVENTFIELD(sc, facts, attr, fmt) \ mpr_dprint_field((sc), MPR_EVENT, #attr ": " #fmt "\n", (facts)->attr) -#define CAN_SLEEP 1 -#define NO_SLEEP 0 - static __inline void mpr_from_u64(uint64_t data, U64 *mpr) { @@ -613,7 +624,6 @@ mpr_from_u64(uint64_t data, U64 *mpr) static __inline uint64_t mpr_to_u64(U64 *data) { - return (((uint64_t)le32toh(data->High) << 32) | le32toh(data->Low)); } @@ -727,6 +737,12 @@ void mprsas_prepare_volume_remove(struct mprsas_softc *sassc, int mprsas_startup(struct mpr_softc *sc); struct mprsas_target * mprsas_find_target_by_handle(struct mprsas_softc *, int, uint16_t); +void mprsas_realloc_targets(struct mpr_softc *sc, int maxtargets); +struct mpr_command * mprsas_alloc_tm(struct mpr_softc *sc); +void mprsas_free_tm(struct mpr_softc *sc, struct mpr_command *tm); +void mprsas_release_simq_reinit(struct mprsas_softc *sassc); +int mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, + uint8_t type); SYSCTL_DECL(_hw_mpr); diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index b4c6151..98b6b53 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -2389,7 +2389,7 @@ pci_set_powerstate_method(device_t dev, device_t child, int state) struct pci_devinfo *dinfo = device_get_ivars(child); pcicfgregs *cfg = &dinfo->cfg; uint16_t status; - int result, oldstate, highest, delay; + int oldstate, highest, delay; if (cfg->pp.pp_cap == 0) return (EOPNOTSUPP); @@ -2424,7 +2424,6 @@ pci_set_powerstate_method(device_t dev, device_t child, int state) delay = 0; status = PCI_READ_CONFIG(dev, child, cfg->pp.pp_status, 2) & ~PCIM_PSTAT_DMASK; - result = 0; switch (state) { case PCI_POWERSTATE_D0: status |= PCIM_PSTAT_D0; @@ -2989,7 +2988,6 @@ static void pci_ata_maps(device_t bus, device_t dev, struct resource_list *rl, int force, uint32_t prefetchmask) { - struct resource *r; int rid, type, progif; #if 0 /* if this device supports PCI native addressing use it */ @@ -3012,11 +3010,11 @@ pci_ata_maps(device_t bus, device_t dev, struct resource_list *rl, int force, } else { rid = PCIR_BAR(0); resource_list_add(rl, type, rid, 0x1f0, 0x1f7, 8); - r = resource_list_reserve(rl, bus, dev, type, &rid, 0x1f0, + (void)resource_list_reserve(rl, bus, dev, type, &rid, 0x1f0, 0x1f7, 8, 0); rid = PCIR_BAR(1); resource_list_add(rl, type, rid, 0x3f6, 0x3f6, 1); - r = resource_list_reserve(rl, bus, dev, type, &rid, 0x3f6, + (void)resource_list_reserve(rl, bus, dev, type, &rid, 0x3f6, 0x3f6, 1, 0); } if (progif & PCIP_STORAGE_IDE_MODESEC) { @@ -3027,11 +3025,11 @@ pci_ata_maps(device_t bus, device_t dev, struct resource_list *rl, int force, } else { rid = PCIR_BAR(2); resource_list_add(rl, type, rid, 0x170, 0x177, 8); - r = resource_list_reserve(rl, bus, dev, type, &rid, 0x170, + (void)resource_list_reserve(rl, bus, dev, type, &rid, 0x170, 0x177, 8, 0); rid = PCIR_BAR(3); resource_list_add(rl, type, rid, 0x376, 0x376, 1); - r = resource_list_reserve(rl, bus, dev, type, &rid, 0x376, + (void)resource_list_reserve(rl, bus, dev, type, &rid, 0x376, 0x376, 1, 0); } pci_add_map(bus, dev, PCIR_BAR(4), rl, force, @@ -3727,7 +3725,6 @@ pci_detach(device_t dev) static void pci_set_power_child(device_t dev, device_t child, int state) { - struct pci_devinfo *dinfo; device_t pcib; int dstate; @@ -3739,7 +3736,6 @@ pci_set_power_child(device_t dev, device_t child, int state) * are handled separately. */ pcib = device_get_parent(dev); - dinfo = device_get_ivars(child); dstate = state; if (device_is_attached(child) && PCIB_POWER_FOR_SLEEP(pcib, child, &dstate) == 0) diff --git a/sys/dev/pci/pci_if.m b/sys/dev/pci/pci_if.m index 9f97d9a..aeeff2c 100644 --- a/sys/dev/pci/pci_if.m +++ b/sys/dev/pci/pci_if.m @@ -214,22 +214,6 @@ METHOD int iov_detach { device_t child; }; -METHOD int init_iov { - device_t dev; - uint16_t num_vfs; - const struct nvlist *config; -}; - -METHOD void uninit_iov { - device_t dev; -}; - -METHOD int add_vf { - device_t dev; - uint16_t vfnum; - const struct nvlist *config; -}; - METHOD device_t create_iov_child { device_t bus; device_t pf; @@ -237,4 +221,3 @@ METHOD device_t create_iov_child { uint16_t vid; uint16_t did; } DEFAULT null_create_iov_child; - diff --git a/sys/dev/pci/pci_iov.c b/sys/dev/pci/pci_iov.c index 4672e55..58e6926 100644 --- a/sys/dev/pci/pci_iov.c +++ b/sys/dev/pci/pci_iov.c @@ -53,11 +53,11 @@ __FBSDID("$FreeBSD$"); #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> +#include <dev/pci/pci_iov.h> #include <dev/pci/pci_private.h> #include <dev/pci/pci_iov_private.h> #include <dev/pci/schema_private.h> -#include "pci_if.h" #include "pcib_if.h" static MALLOC_DEFINE(M_SRIOV, "sr_iov", "PCI SR-IOV allocations"); @@ -483,13 +483,13 @@ pci_iov_config_page_size(struct pci_devinfo *dinfo) } static int -pci_init_iov(device_t dev, uint16_t num_vfs, const nvlist_t *config) +pci_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *config) { const nvlist_t *device, *driver_config; device = nvlist_get_nvlist(config, PF_CONFIG_NAME); driver_config = nvlist_get_nvlist(device, DRIVER_CONFIG_NAME); - return (PCI_INIT_IOV(dev, num_vfs, driver_config)); + return (PCI_IOV_INIT(dev, num_vfs, driver_config)); } static int @@ -595,7 +595,7 @@ pci_iov_enumerate_vfs(struct pci_devinfo *dinfo, const nvlist_t *config, pci_iov_add_bars(iov, vfinfo); - error = PCI_ADD_VF(dev, i, driver_config); + error = PCI_IOV_ADD_VF(dev, i, driver_config); if (error != 0) { device_printf(dev, "Failed to add VF %d\n", i); pci_delete_child(bus, vf); @@ -652,7 +652,7 @@ pci_iov_config(struct cdev *cdev, struct pci_iov_arg *arg) if (error != 0) goto out; - error = pci_init_iov(dev, num_vfs, config); + error = pci_iov_init(dev, num_vfs, config); if (error != 0) goto out; iov_inited = 1; @@ -700,7 +700,7 @@ pci_iov_config(struct cdev *cdev, struct pci_iov_arg *arg) return (0); out: if (iov_inited) - PCI_UNINIT_IOV(dev); + PCI_IOV_UNINIT(dev); for (i = 0; i <= PCIR_MAX_BAR_0; i++) { if (iov->iov_bar[i].res != NULL) { @@ -793,7 +793,7 @@ pci_iov_delete(struct cdev *cdev) if (pci_iov_is_child_vf(iov, vf)) pci_delete_child(bus, vf); } - PCI_UNINIT_IOV(dev); + PCI_IOV_UNINIT(dev); iov_ctl = IOV_READ(dinfo, PCIR_SRIOV_CTL, 2); iov_ctl &= ~(PCIM_SRIOV_VF_EN | PCIM_SRIOV_VF_MSE); diff --git a/lib/libc/arm/sys/fork.S b/sys/dev/pci/pci_iov.h index a5ae1f0..fd2f8fb 100644 --- a/lib/libc/arm/sys/fork.S +++ b/sys/dev/pci/pci_iov.h @@ -1,7 +1,5 @@ -/* $NetBSD: fork.S,v 1.5 2003/08/07 16:42:04 agc Exp $ */ - /*- - * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 2013-2015 Sandvine Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -12,14 +10,11 @@ * 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 + * 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 REGENTS OR CONTRIBUTORS BE LIABLE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -28,22 +23,27 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * from: @(#)fork.s 5.1 (Berkeley) 4/23/90 + * $FreeBSD$ */ -#include <machine/asm.h> -__FBSDID("$FreeBSD$"); -#include "SYS.h" +#ifndef _PCI_IOV_H_ +#define _PCI_IOV_H_ -/* - * pid = fork(); - * - * On return from the SWI: - * r1 == 0 in parent process, r1 == 1 in child process. - * r0 == pid of child in parent, r0 == pid of parent in child. - */ +#include "pci_iov_if.h" + +struct nvlist; + +static __inline int +pci_iov_attach(device_t dev, struct nvlist *pf_schema, struct nvlist *vf_schema) +{ + return (PCI_IOV_ATTACH(device_get_parent(dev), dev, pf_schema, + vf_schema)); +} + +static __inline int +pci_iov_detach(device_t dev) +{ + return (PCI_IOV_DETACH(device_get_parent(dev), dev)); +} -_SYSCALL(fork) - sub r1, r1, #1 /* r1 == 0xffffffff if parent, 0 if child */ - and r0, r0, r1 /* r0 == 0 if child, else unchanged */ - RET +#endif /* !_PCI_IOV_H_ */ diff --git a/sys/dev/pci/pci_iov_if.m b/sys/dev/pci/pci_iov_if.m new file mode 100644 index 0000000..3b6796b --- /dev/null +++ b/sys/dev/pci/pci_iov_if.m @@ -0,0 +1,52 @@ +#- +# Copyright (c) 2013-2015 Sandvine Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +#include <sys/bus.h> + +INTERFACE pci_iov; + +HEADER { + struct nvlist; +} + + +METHOD int init { + device_t dev; + uint16_t num_vfs; + const struct nvlist *config; +}; + +METHOD void uninit { + device_t dev; +}; + +METHOD int add_vf { + device_t dev; + uint16_t vfnum; + const struct nvlist *config; +}; diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h index 2fd76b6..7f2e958 100644 --- a/sys/dev/pci/pcivar.h +++ b/sys/dev/pci/pcivar.h @@ -39,8 +39,6 @@ typedef uint64_t pci_addr_t; -struct nvlist; - /* Config registers for PCI-PCI and PCI-Cardbus bridges. */ struct pcicfg_bridge { uint8_t br_seclat; @@ -536,19 +534,6 @@ pci_child_added(device_t dev) return (PCI_CHILD_ADDED(device_get_parent(dev), dev)); } -static __inline int -pci_iov_attach(device_t dev, struct nvlist *pf_schema, struct nvlist *vf_schema) -{ - return (PCI_IOV_ATTACH(device_get_parent(dev), dev, pf_schema, - vf_schema)); -} - -static __inline int -pci_iov_detach(device_t dev) -{ - return (PCI_IOV_DETACH(device_get_parent(dev), dev)); -} - device_t pci_find_bsf(uint8_t, uint8_t, uint8_t); device_t pci_find_dbsf(uint32_t, uint8_t, uint8_t, uint8_t); device_t pci_find_device(uint16_t, uint16_t); diff --git a/sys/dev/sfxge/sfxge_port.c b/sys/dev/sfxge/sfxge_port.c index 7ee102c..412f477 100644 --- a/sys/dev/sfxge/sfxge_port.c +++ b/sys/dev/sfxge/sfxge_port.c @@ -822,6 +822,8 @@ sfxge_link_mode_to_phy_cap(efx_link_mode_t mode) static int sfxge_phy_cap_mask(struct sfxge_softc *sc, int ifmedia, uint32_t *phy_cap_mask) { + /* Get global options (duplex), type and subtype bits */ + int ifmedia_masked = ifmedia & (IFM_GMASK | IFM_NMASK | IFM_TMASK); efx_phy_media_type_t medium_type; boolean_t mode_found = B_FALSE; uint32_t cap_mask, mode_cap_mask; @@ -837,7 +839,7 @@ sfxge_phy_cap_mask(struct sfxge_softc *sc, int ifmedia, uint32_t *phy_cap_mask) efx_phy_adv_cap_get(sc->enp, EFX_PHY_CAP_PERM, &cap_mask); for (mode = EFX_LINK_10HDX; mode < EFX_LINK_NMODES; mode++) { - if (ifmedia == sfxge_link_mode[medium_type][mode]) { + if (ifmedia_masked == sfxge_link_mode[medium_type][mode]) { mode_found = B_TRUE; break; } @@ -848,8 +850,8 @@ sfxge_phy_cap_mask(struct sfxge_softc *sc, int ifmedia, uint32_t *phy_cap_mask) * If media is not in the table, it must be IFM_AUTO. */ KASSERT((cap_mask & (1 << EFX_PHY_CAP_AN)) && - ifmedia == (IFM_ETHER | IFM_AUTO), - ("%s: no mode for media %d", __func__, ifmedia)); + ifmedia_masked == (IFM_ETHER | IFM_AUTO), + ("%s: no mode for media %#x", __func__, ifmedia)); *phy_cap_mask = (cap_mask & ~(1 << EFX_PHY_CAP_ASYM)); return (0); } diff --git a/sys/dev/sfxge/sfxge_version.h b/sys/dev/sfxge/sfxge_version.h index 5228fff..f5f4882 100644 --- a/sys/dev/sfxge/sfxge_version.h +++ b/sys/dev/sfxge/sfxge_version.h @@ -36,6 +36,6 @@ #ifndef _SFXGE_VERSION_H #define _SFXGE_VERSION_H -#define SFXGE_VERSION_STRING "v4.5.1.1018" +#define SFXGE_VERSION_STRING "v4.5.2.1000" #endif /* _SFXGE_DRIVER_VERSION_H */ diff --git a/sys/fs/ext2fs/ext2_vnops.c b/sys/fs/ext2fs/ext2_vnops.c index dd30aea..5b8990ee 100644 --- a/sys/fs/ext2fs/ext2_vnops.c +++ b/sys/fs/ext2fs/ext2_vnops.c @@ -128,6 +128,7 @@ struct vop_vector ext2_vnodeops = { .vop_create = ext2_create, .vop_fsync = ext2_fsync, .vop_getpages = vnode_pager_local_getpages, + .vop_getpages_async = vnode_pager_local_getpages_async, .vop_getattr = ext2_getattr, .vop_inactive = ext2_inactive, .vop_ioctl = ext2_ioctl, diff --git a/sys/fs/nfs/nfs.h b/sys/fs/nfs/nfs.h index 2ee9145..be60c1c 100644 --- a/sys/fs/nfs/nfs.h +++ b/sys/fs/nfs/nfs.h @@ -138,11 +138,11 @@ /* * This macro defines the high water mark for issuing V4 delegations. - * (It is currently set at a conservative 20% of NFSRV_V4STATELIMIT. This + * (It is currently set at a conservative 20% of nfsrv_v4statelimit. This * may want to increase when clients can make more effective use of * delegations.) */ -#define NFSRV_V4DELEGLIMIT(c) (((c) * 5) > NFSRV_V4STATELIMIT) +#define NFSRV_V4DELEGLIMIT(c) (((c) * 5) > nfsrv_v4statelimit) #define NFS_READDIRBLKSIZ DIRBLKSIZ /* Minimal nm_readdirsize */ diff --git a/sys/fs/nfs/nfsdport.h b/sys/fs/nfs/nfsdport.h index efa4b12..a20b554 100644 --- a/sys/fs/nfs/nfsdport.h +++ b/sys/fs/nfs/nfsdport.h @@ -88,7 +88,7 @@ struct nfsexstuff { bcmp(&(f1)->fh_fid, &(f2)->fh_fid, sizeof(struct fid)) == 0) #define NFSLOCKHASH(f) \ - (&nfslockhash[nfsrv_hashfh(f) % NFSLOCKHASHSIZE]) + (&nfslockhash[nfsrv_hashfh(f) % nfsrv_lockhashsize]) #define NFSFPVNODE(f) ((struct vnode *)((f)->f_data)) #define NFSFPCRED(f) ((f)->f_cred) diff --git a/sys/fs/nfs/nfsrvstate.h b/sys/fs/nfs/nfsrvstate.h index 59a0542..972fffe 100644 --- a/sys/fs/nfs/nfsrvstate.h +++ b/sys/fs/nfs/nfsrvstate.h @@ -52,9 +52,9 @@ LIST_HEAD(nfsuserhashhead, nfsusrgrp); TAILQ_HEAD(nfsuserlruhead, nfsusrgrp); #define NFSCLIENTHASH(id) \ - (&nfsclienthash[(id).lval[1] % NFSCLIENTHASHSIZE]) + (&nfsclienthash[(id).lval[1] % nfsrv_clienthashsize]) #define NFSSTATEHASH(clp, id) \ - (&((clp)->lc_stateid[(id).other[2] % NFSSTATEHASHSIZE])) + (&((clp)->lc_stateid[(id).other[2] % nfsrv_statehashsize])) #define NFSUSERHASH(id) \ (&nfsuserhash[(id) % NFSUSERHASHSIZE]) #define NFSUSERNAMEHASH(p, l) \ @@ -71,7 +71,7 @@ struct nfssessionhash { struct nfssessionhashhead list; }; #define NFSSESSIONHASH(f) \ - (&nfssessionhash[nfsrv_hashsessionid(f) % NFSSESSIONHASHSIZE]) + (&nfssessionhash[nfsrv_hashsessionid(f) % nfsrv_sessionhashsize]) /* * Client server structure for V4. It is doubly linked into two lists. @@ -81,7 +81,7 @@ struct nfssessionhash { */ struct nfsclient { LIST_ENTRY(nfsclient) lc_hash; /* Clientid hash list */ - struct nfsstatehead lc_stateid[NFSSTATEHASHSIZE]; /* stateid hash */ + struct nfsstatehead *lc_stateid; /* Stateid hash */ struct nfsstatehead lc_open; /* Open owner list */ struct nfsstatehead lc_deleg; /* Delegations */ struct nfsstatehead lc_olddeleg; /* and old delegations */ @@ -97,10 +97,10 @@ struct nfsclient { u_int32_t lc_cbref; /* Cnt of callbacks */ uid_t lc_uid; /* User credential */ gid_t lc_gid; - u_int16_t lc_namelen; + u_int16_t lc_idlen; /* Client ID and len */ + u_int16_t lc_namelen; /* plus GSS principal and len */ u_char *lc_name; struct nfssockreq lc_req; /* Callback info */ - u_short lc_idlen; /* Length of id string */ u_int32_t lc_flags; /* LCL_ flag bits */ u_char lc_verf[NFSX_VERF]; /* client verifier */ u_char lc_id[1]; /* Malloc'd correct size */ diff --git a/sys/fs/nfsserver/nfs_nfsdkrpc.c b/sys/fs/nfsserver/nfs_nfsdkrpc.c index f9b8eb8..0f60686 100644 --- a/sys/fs/nfsserver/nfs_nfsdkrpc.c +++ b/sys/fs/nfsserver/nfs_nfsdkrpc.c @@ -294,6 +294,8 @@ nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt) svc_freereq(rqst); out: + if (softdep_ast_cleanup != NULL) + softdep_ast_cleanup(); NFSEXITCODE(0); } @@ -464,6 +466,7 @@ int nfsrvd_nfsd(struct thread *td, struct nfsd_nfsd_args *args) { char principal[MAXHOSTNAMELEN + 5]; + struct proc *p; int error = 0; bool_t ret2, ret3, ret4; @@ -481,6 +484,10 @@ nfsrvd_nfsd(struct thread *td, struct nfsd_nfsd_args *args) */ NFSD_LOCK(); if (newnfs_numnfsd == 0) { + p = td->td_proc; + PROC_LOCK(p); + p->p_flag2 |= P2_AST_SU; + PROC_UNLOCK(p); newnfs_numnfsd++; NFSD_UNLOCK(); @@ -512,6 +519,9 @@ nfsrvd_nfsd(struct thread *td, struct nfsd_nfsd_args *args) NFSD_LOCK(); newnfs_numnfsd--; nfsrvd_init(1); + PROC_LOCK(p); + p->p_flag2 &= ~P2_AST_SU; + PROC_UNLOCK(p); } NFSD_UNLOCK(); diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index 94475d9..85b4466 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -58,7 +58,10 @@ extern struct nfsrv_stablefirst nfsrv_stablefirst; extern void (*nfsd_call_servertimer)(void); extern SVCPOOL *nfsrvd_pool; extern struct nfsv4lock nfsd_suspend_lock; -extern struct nfssessionhash nfssessionhash[NFSSESSIONHASHSIZE]; +extern struct nfsclienthashhead *nfsclienthash; +extern struct nfslockhashhead *nfslockhash; +extern struct nfssessionhash *nfssessionhash; +extern int nfsrv_sessionhashsize; struct vfsoptlist nfsv4root_opt, nfsv4root_newopt; NFSDLOCKMUTEX; struct nfsrchash_bucket nfsrchash_table[NFSRVCACHE_HASHSIZE]; @@ -3330,9 +3333,6 @@ nfsd_modevent(module_t mod, int type, void *data) mtx_init(&nfsrc_udpmtx, "nfsuc", NULL, MTX_DEF); mtx_init(&nfs_v4root_mutex, "nfs4rt", NULL, MTX_DEF); mtx_init(&nfsv4root_mnt.mnt_mtx, "nfs4mnt", NULL, MTX_DEF); - for (i = 0; i < NFSSESSIONHASHSIZE; i++) - mtx_init(&nfssessionhash[i].mtx, "nfssm", - NULL, MTX_DEF); lockinit(&nfsv4root_mnt.mnt_explock, PVFS, "explock", 0, 0); nfsrvd_initcache(); nfsd_init(); @@ -3380,9 +3380,12 @@ nfsd_modevent(module_t mod, int type, void *data) mtx_destroy(&nfsrc_udpmtx); mtx_destroy(&nfs_v4root_mutex); mtx_destroy(&nfsv4root_mnt.mnt_mtx); - for (i = 0; i < NFSSESSIONHASHSIZE; i++) + for (i = 0; i < nfsrv_sessionhashsize; i++) mtx_destroy(&nfssessionhash[i].mtx); lockdestroy(&nfsv4root_mnt.mnt_explock); + free(nfsclienthash, M_NFSDCLIENT); + free(nfslockhash, M_NFSDLOCKFILE); + free(nfssessionhash, M_NFSDSESSION); loaded = 0; break; default: diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c index bd0c2da..bd054c4 100644 --- a/sys/fs/nfsserver/nfs_nfsdserv.c +++ b/sys/fs/nfsserver/nfs_nfsdserv.c @@ -53,6 +53,7 @@ extern enum vtype nv34tov_type[8]; extern struct timeval nfsboottime; extern int nfs_rootfhset; extern int nfsrv_enable_crossmntpt; +extern int nfsrv_statehashsize; #endif /* !APPLEKEXT */ static int nfs_async = 0; @@ -3468,9 +3469,10 @@ nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, idlen = i; if (nd->nd_flag & ND_GSS) i += nd->nd_princlen; - MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i, - M_NFSDCLIENT, M_WAITOK); - NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i); + clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | + M_ZERO); + clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * + nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); NFSSOCKADDRALLOC(clp->lc_req.nr_nam); NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); @@ -3530,7 +3532,8 @@ nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, if (clp) { NFSSOCKADDRFREE(clp->lc_req.nr_nam); NFSFREEMUTEX(&clp->lc_req.nr_mtx); - free((caddr_t)clp, M_NFSDCLIENT); + free(clp->lc_stateid, M_NFSDCLIENT); + free(clp, M_NFSDCLIENT); } if (!nd->nd_repstat) { NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); @@ -3547,7 +3550,8 @@ nfsmout: if (clp) { NFSSOCKADDRFREE(clp->lc_req.nr_nam); NFSFREEMUTEX(&clp->lc_req.nr_mtx); - free((caddr_t)clp, M_NFSDCLIENT); + free(clp->lc_stateid, M_NFSDCLIENT); + free(clp, M_NFSDCLIENT); } NFSEXITCODE2(error, nd); return (error); @@ -3738,8 +3742,10 @@ nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, idlen = i; if (nd->nd_flag & ND_GSS) i += nd->nd_princlen; - clp = (struct nfsclient *)malloc(sizeof(struct nfsclient) + i, - M_NFSDCLIENT, M_WAITOK | M_ZERO); + clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | + M_ZERO); + clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * + nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); NFSSOCKADDRALLOC(clp->lc_req.nr_nam); NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); @@ -3796,6 +3802,7 @@ nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, if (clp != NULL) { NFSSOCKADDRFREE(clp->lc_req.nr_nam); NFSFREEMUTEX(&clp->lc_req.nr_mtx); + free(clp->lc_stateid, M_NFSDCLIENT); free(clp, M_NFSDCLIENT); } if (nd->nd_repstat == 0) { @@ -3828,6 +3835,7 @@ nfsmout: if (clp != NULL) { NFSSOCKADDRFREE(clp->lc_req.nr_nam); NFSFREEMUTEX(&clp->lc_req.nr_mtx); + free(clp->lc_stateid, M_NFSDCLIENT); free(clp, M_NFSDCLIENT); } NFSEXITCODE2(error, nd); diff --git a/sys/fs/nfsserver/nfs_nfsdsocket.c b/sys/fs/nfsserver/nfs_nfsdsocket.c index b15dfec..4497161 100644 --- a/sys/fs/nfsserver/nfs_nfsdsocket.c +++ b/sys/fs/nfsserver/nfs_nfsdsocket.c @@ -46,7 +46,8 @@ extern struct nfsrvfh nfs_pubfh, nfs_rootfh; extern int nfs_pubfhset, nfs_rootfhset; extern struct nfsv4lock nfsv4rootfs_lock; extern struct nfsrv_stablefirst nfsrv_stablefirst; -extern struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE]; +extern struct nfsclienthashhead *nfsclienthash; +extern int nfsrv_clienthashsize; extern int nfsrc_floodlevel, nfsrc_tcpsavedreplies; extern int nfsd_debuglevel; NFSV4ROOTLOCKMUTEX; @@ -439,9 +440,12 @@ nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen, if (nd->nd_procnum == NFSPROC_READ || nd->nd_procnum == NFSPROC_WRITE || nd->nd_procnum == NFSPROC_READDIR || + nd->nd_procnum == NFSPROC_READDIRPLUS || nd->nd_procnum == NFSPROC_READLINK || nd->nd_procnum == NFSPROC_GETATTR || - nd->nd_procnum == NFSPROC_ACCESS) + nd->nd_procnum == NFSPROC_ACCESS || + nd->nd_procnum == NFSPROC_FSSTAT || + nd->nd_procnum == NFSPROC_FSINFO) lktype = LK_SHARED; else lktype = LK_EXCLUSIVE; @@ -543,7 +547,7 @@ static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen, u_int32_t minorvers, NFSPROC_T *p) { - int i, op, op0 = 0; + int i, lktype, op, op0 = 0; u_int32_t *tl; struct nfsclient *clp, *nclp; int numops, error = 0, igotlock; @@ -610,7 +614,7 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag, */ if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) { nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT; - for (i = 0; i < NFSCLIENTHASHSIZE; i++) { + for (i = 0; i < nfsrv_clienthashsize; i++) { LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, nclp) { if (clp->lc_flags & LCL_EXPIREIT) { @@ -952,11 +956,15 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag, panic("nfsrvd_compound"); if (nfsv4_opflag[op].needscfh) { if (vp != NULL) { - if (nfsv4_opflag[op].modifyfs) + lktype = nfsv4_opflag[op].lktype; + if (nfsv4_opflag[op].modifyfs) { vn_start_write(vp, &temp_mp, V_WAIT); - if (NFSVOPLOCK(vp, nfsv4_opflag[op].lktype) - == 0) + if (op == NFSV4OP_WRITE && + MNT_SHARED_WRITES(temp_mp)) + lktype = LK_SHARED; + } + if (NFSVOPLOCK(vp, lktype) == 0) VREF(vp); else nd->nd_repstat = NFSERR_PERM; diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c index 5e9beeb..15f5243 100644 --- a/sys/fs/nfsserver/nfs_nfsdstate.c +++ b/sys/fs/nfsserver/nfs_nfsdstate.c @@ -44,14 +44,38 @@ extern u_int32_t newnfs_true, newnfs_false; NFSV4ROOTLOCKMUTEX; NFSSTATESPINLOCK; +SYSCTL_DECL(_vfs_nfsd); +int nfsrv_statehashsize = NFSSTATEHASHSIZE; +SYSCTL_INT(_vfs_nfsd, OID_AUTO, statehashsize, CTLFLAG_RDTUN, + &nfsrv_statehashsize, 0, + "Size of state hash table set via loader.conf"); + +int nfsrv_clienthashsize = NFSCLIENTHASHSIZE; +SYSCTL_INT(_vfs_nfsd, OID_AUTO, clienthashsize, CTLFLAG_RDTUN, + &nfsrv_clienthashsize, 0, + "Size of client hash table set via loader.conf"); + +int nfsrv_lockhashsize = NFSLOCKHASHSIZE; +SYSCTL_INT(_vfs_nfsd, OID_AUTO, fhhashsize, CTLFLAG_RDTUN, + &nfsrv_lockhashsize, 0, + "Size of file handle hash table set via loader.conf"); + +int nfsrv_sessionhashsize = NFSSESSIONHASHSIZE; +SYSCTL_INT(_vfs_nfsd, OID_AUTO, sessionhashsize, CTLFLAG_RDTUN, + &nfsrv_sessionhashsize, 0, + "Size of session hash table set via loader.conf"); + +static int nfsrv_v4statelimit = NFSRV_V4STATELIMIT; +SYSCTL_INT(_vfs_nfsd, OID_AUTO, v4statelimit, CTLFLAG_RWTUN, + &nfsrv_v4statelimit, 0, + "High water limit for NFSv4 opens+locks+delegations"); + /* * Hash lists for nfs V4. - * (Some would put them in the .h file, but I don't like declaring storage - * in a .h) */ -struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE]; -struct nfslockhashhead nfslockhash[NFSLOCKHASHSIZE]; -struct nfssessionhash nfssessionhash[NFSSESSIONHASHSIZE]; +struct nfsclienthashhead *nfsclienthash; +struct nfslockhashhead *nfslockhash; +struct nfssessionhash *nfssessionhash; #endif /* !APPLEKEXT */ static u_int32_t nfsrv_openpluslock = 0, nfsrv_delegatecnt = 0; @@ -153,7 +177,7 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp, /* * Check for state resource limit exceeded. */ - if (nfsrv_openpluslock > NFSRV_V4STATELIMIT) { + if (nfsrv_openpluslock > nfsrv_v4statelimit) { error = NFSERR_RESOURCE; goto out; } @@ -188,7 +212,7 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp, * Search for a match in the client list. */ gotit = i = 0; - while (i < NFSCLIENTHASHSIZE && !gotit) { + while (i < nfsrv_clienthashsize && !gotit) { LIST_FOREACH(clp, &nfsclienthash[i], lc_hash) { if (new_clp->lc_idlen == clp->lc_idlen && !NFSBCMP(new_clp->lc_id, clp->lc_id, clp->lc_idlen)) { @@ -215,7 +239,7 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp, /* * Get rid of the old one. */ - if (i != NFSCLIENTHASHSIZE) { + if (i != nfsrv_clienthashsize) { LIST_REMOVE(clp, lc_hash); nfsrv_cleanclient(clp, p); nfsrv_freedeleglist(&clp->lc_deleg); @@ -244,7 +268,7 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp, LIST_INIT(&new_clp->lc_deleg); LIST_INIT(&new_clp->lc_olddeleg); LIST_INIT(&new_clp->lc_session); - for (i = 0; i < NFSSTATEHASHSIZE; i++) + for (i = 0; i < nfsrv_statehashsize; i++) LIST_INIT(&new_clp->lc_stateid[i]); LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp, lc_hash); @@ -344,7 +368,7 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp, ls_list); LIST_FOREACH(tstp, &new_clp->lc_olddeleg, ls_list) tstp->ls_clp = new_clp; - for (i = 0; i < NFSSTATEHASHSIZE; i++) { + for (i = 0; i < nfsrv_statehashsize; i++) { LIST_NEWHEAD(&new_clp->lc_stateid[i], &clp->lc_stateid[i], ls_hash); LIST_FOREACH(tstp, &new_clp->lc_stateid[i], ls_hash) @@ -405,7 +429,7 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp, LIST_NEWHEAD(&new_clp->lc_olddeleg, &clp->lc_olddeleg, ls_list); LIST_FOREACH(tstp, &new_clp->lc_olddeleg, ls_list) tstp->ls_clp = new_clp; - for (i = 0; i < NFSSTATEHASHSIZE; i++) { + for (i = 0; i < nfsrv_statehashsize; i++) { LIST_NEWHEAD(&new_clp->lc_stateid[i], &clp->lc_stateid[i], ls_hash); LIST_FOREACH(tstp, &new_clp->lc_stateid[i], ls_hash) @@ -615,7 +639,7 @@ nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp, if (!error && (opflags & CLOPS_RENEWOP)) { if (nfsrv_notsamecredname(nd, clp)) { doneok = 0; - for (i = 0; i < NFSSTATEHASHSIZE && doneok == 0; i++) { + for (i = 0; i < nfsrv_statehashsize && doneok == 0; i++) { LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { if ((stp->ls_flags & NFSLCK_OPEN) && stp->ls_uid == nd->nd_cred->cr_uid) { @@ -687,7 +711,7 @@ nfsrv_destroyclient(nfsquad_t clientid, NFSPROC_T *p) } /* Scan for state on the clientid. */ - for (i = 0; i < NFSSTATEHASHSIZE; i++) + for (i = 0; i < nfsrv_statehashsize; i++) if (!LIST_EMPTY(&clp->lc_stateid[i])) { NFSLOCKV4ROOTMUTEX(); nfsv4_unlock(&nfsv4rootfs_lock, 1); @@ -744,7 +768,7 @@ nfsrv_adminrevoke(struct nfsd_clid *revokep, NFSPROC_T *p) * Search for a match in the client list. */ gotit = i = 0; - while (i < NFSCLIENTHASHSIZE && !gotit) { + while (i < nfsrv_clienthashsize && !gotit) { LIST_FOREACH(clp, &nfsclienthash[i], lc_hash) { if (revokep->nclid_idlen == clp->lc_idlen && !NFSBCMP(revokep->nclid_id, clp->lc_id, clp->lc_idlen)) { @@ -806,7 +830,7 @@ nfsrv_dumpclients(struct nfsd_dumpclients *dumpp, int maxcnt) /* * Rattle through the client lists until done. */ - while (i < NFSCLIENTHASHSIZE && cnt < maxcnt) { + while (i < nfsrv_clienthashsize && cnt < maxcnt) { clp = LIST_FIRST(&nfsclienthash[i]); while (clp != LIST_END(&nfsclienthash[i]) && cnt < maxcnt) { nfsrv_dumpaclient(clp, &dumpp[cnt]); @@ -1074,7 +1098,7 @@ nfsrv_servertimer(void) /* * For each client... */ - for (i = 0; i < NFSCLIENTHASHSIZE; i++) { + for (i = 0; i < nfsrv_clienthashsize; i++) { clp = LIST_FIRST(&nfsclienthash[i]); while (clp != LIST_END(&nfsclienthash[i])) { nclp = LIST_NEXT(clp, lc_hash); @@ -1085,7 +1109,7 @@ nfsrv_servertimer(void) nfsrv_clients > nfsrv_clienthighwater)) || (clp->lc_expiry + NFSRV_MOULDYLEASE) < NFSD_MONOSEC || (clp->lc_expiry < NFSD_MONOSEC && - (nfsrv_openpluslock * 10 / 9) > NFSRV_V4STATELIMIT)) { + (nfsrv_openpluslock * 10 / 9) > nfsrv_v4statelimit)) { /* * Lease has expired several nfsrv_lease times ago: * PLUS @@ -1124,7 +1148,7 @@ nfsrv_servertimer(void) stp->ls_noopens++; if (stp->ls_noopens > NFSNOOPEN || (nfsrv_openpluslock * 2) > - NFSRV_V4STATELIMIT) + nfsrv_v4statelimit) nfsrv_stablefirst.nsf_flags |= NFSNSF_NOOPENS; } else { @@ -1188,7 +1212,8 @@ nfsrv_zapclient(struct nfsclient *clp, NFSPROC_T *p) newnfs_disconnect(&clp->lc_req); NFSSOCKADDRFREE(clp->lc_req.nr_nam); NFSFREEMUTEX(&clp->lc_req.nr_mtx); - free((caddr_t)clp, M_NFSDCLIENT); + free(clp->lc_stateid, M_NFSDCLIENT); + free(clp, M_NFSDCLIENT); NFSLOCKSTATE(); newnfsstats.srvclients--; nfsrv_openpluslock--; @@ -1534,7 +1559,7 @@ nfsrv_lockctrl(vnode_t vp, struct nfsstate **new_stpp, * Check for state resource limit exceeded. */ if ((new_stp->ls_flags & NFSLCK_LOCK) && - nfsrv_openpluslock > NFSRV_V4STATELIMIT) { + nfsrv_openpluslock > nfsrv_v4statelimit) { error = NFSERR_RESOURCE; goto out; } @@ -2232,7 +2257,7 @@ nfsrv_opencheck(nfsquad_t clientid, nfsv4stateid_t *stateidp, * returns NFSERR_RESOURCE and the limit is just a rather * arbitrary high water mark, so no harm is done. */ - if (nfsrv_openpluslock > NFSRV_V4STATELIMIT) { + if (nfsrv_openpluslock > nfsrv_v4statelimit) { error = NFSERR_RESOURCE; goto out; } @@ -4298,7 +4323,7 @@ nfsrv_nextstateindex(struct nfsclient *clp) */ min_index = 0; max_index = 0xffffffff; - for (i = 0; i < NFSSTATEHASHSIZE; i++) { + for (i = 0; i < nfsrv_statehashsize; i++) { LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { if (stp->ls_stateid.other[2] > 0x80000000) { if (stp->ls_stateid.other[2] < max_index) @@ -4322,7 +4347,7 @@ nfsrv_nextstateindex(struct nfsclient *clp) * cleanest way to code the loop.) */ tryagain: - for (i = 0; i < NFSSTATEHASHSIZE; i++) { + for (i = 0; i < nfsrv_statehashsize; i++) { LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { if (stp->ls_stateid.other[2] == canuse) { canuse++; @@ -5319,13 +5344,13 @@ nfsrv_throwawayopens(NFSPROC_T *p) /* * For each client... */ - for (i = 0; i < NFSCLIENTHASHSIZE; i++) { + for (i = 0; i < nfsrv_clienthashsize; i++) { LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, nclp) { LIST_FOREACH_SAFE(stp, &clp->lc_open, ls_list, nstp) { if (LIST_EMPTY(&stp->ls_open) && (stp->ls_noopens > NFSNOOPEN || (nfsrv_openpluslock * 2) > - NFSRV_V4STATELIMIT)) + nfsrv_v4statelimit)) nfsrv_freeopenowner(stp, 0, p); } } @@ -5696,11 +5721,12 @@ nfsrv_throwawayallstate(NFSPROC_T *p) /* * For each client, clean out the state and then free the structure. */ - for (i = 0; i < NFSCLIENTHASHSIZE; i++) { + for (i = 0; i < nfsrv_clienthashsize; i++) { LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, nclp) { nfsrv_cleanclient(clp, p); nfsrv_freedeleglist(&clp->lc_deleg); nfsrv_freedeleglist(&clp->lc_olddeleg); + free(clp->lc_stateid, M_NFSDCLIENT); free(clp, M_NFSDCLIENT); } } @@ -5708,7 +5734,7 @@ nfsrv_throwawayallstate(NFSPROC_T *p) /* * Also, free up any remaining lock file structures. */ - for (i = 0; i < NFSLOCKHASHSIZE; i++) { + for (i = 0; i < nfsrv_lockhashsize; i++) { LIST_FOREACH_SAFE(lfp, &nfslockhash[i], lf_hash, nlfp) { printf("nfsd unload: fnd a lock file struct\n"); nfsrv_freenfslockfile(lfp); diff --git a/sys/fs/nfsserver/nfs_nfsdsubs.c b/sys/fs/nfsserver/nfs_nfsdsubs.c index 6bd1412..c0421e3 100644 --- a/sys/fs/nfsserver/nfs_nfsdsubs.c +++ b/sys/fs/nfsserver/nfs_nfsdsubs.c @@ -44,9 +44,12 @@ __FBSDID("$FreeBSD$"); extern u_int32_t newnfs_true, newnfs_false; extern int nfs_pubfhset; -extern struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE]; -extern struct nfslockhashhead nfslockhash[NFSLOCKHASHSIZE]; -extern struct nfssessionhash nfssessionhash[NFSSESSIONHASHSIZE]; +extern struct nfsclienthashhead *nfsclienthash; +extern int nfsrv_clienthashsize; +extern struct nfslockhashhead *nfslockhash; +extern int nfsrv_lockhashsize; +extern struct nfssessionhash *nfssessionhash; +extern int nfsrv_sessionhashsize; extern int nfsrv_useacl; extern uid_t nfsrv_defaultuid; extern gid_t nfsrv_defaultgid; @@ -2036,12 +2039,20 @@ nfsd_init(void) * Initialize client queues. Don't free/reinitialize * them when nfsds are restarted. */ - for (i = 0; i < NFSCLIENTHASHSIZE; i++) + nfsclienthash = malloc(sizeof(struct nfsclienthashhead) * + nfsrv_clienthashsize, M_NFSDCLIENT, M_WAITOK | M_ZERO); + for (i = 0; i < nfsrv_clienthashsize; i++) LIST_INIT(&nfsclienthash[i]); - for (i = 0; i < NFSLOCKHASHSIZE; i++) + nfslockhash = malloc(sizeof(struct nfslockhashhead) * + nfsrv_lockhashsize, M_NFSDLOCKFILE, M_WAITOK | M_ZERO); + for (i = 0; i < nfsrv_lockhashsize; i++) LIST_INIT(&nfslockhash[i]); - for (i = 0; i < NFSSESSIONHASHSIZE; i++) + nfssessionhash = malloc(sizeof(struct nfssessionhash) * + nfsrv_sessionhashsize, M_NFSDSESSION, M_WAITOK | M_ZERO); + for (i = 0; i < nfsrv_sessionhashsize; i++) { + mtx_init(&nfssessionhash[i].mtx, "nfssm", NULL, MTX_DEF); LIST_INIT(&nfssessionhash[i].list); + } /* and the v2 pubfh should be all zeros */ NFSBZERO(nfs_v2pubfh, NFSX_V2FH); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index caf31d7..9ce6d34 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -205,6 +205,12 @@ exit1(struct thread *td, int rv) } /* + * Deref SU mp, since the thread does not return to userspace. + */ + if (softdep_ast_cleanup != NULL) + softdep_ast_cleanup(); + + /* * MUST abort all other threads before proceeding past here. */ PROC_LOCK(p); @@ -958,12 +964,10 @@ proc_to_reap(struct thread *td, struct proc *p, idtype_t idtype, id_t id, int *status, int options, struct __wrusage *wrusage, siginfo_t *siginfo, int check_only) { - struct proc *q; struct rusage *rup; sx_assert(&proctree_lock, SA_XLOCKED); - q = td->td_proc; PROC_LOCK(p); switch (idtype) { diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index b30e1ed..5d48060 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -2368,9 +2368,12 @@ tdsigwakeup(struct thread *td, int sig, sig_t action, int intrval) thread_lock(td); /* * Bring the priority of a thread up if we want it to get - * killed in this lifetime. + * killed in this lifetime. Be careful to avoid bumping the + * priority of the idle thread, since we still allow to signal + * kernel processes. */ - if (action == SIG_DFL && (prop & SA_KILL) && td->td_priority > PUSER) + if (action == SIG_DFL && (prop & SA_KILL) != 0 && + td->td_priority > PUSER && !TD_IS_IDLETHREAD(td)) sched_prio(td, PUSER); if (TD_ON_SLEEPQ(td)) { /* @@ -2408,7 +2411,7 @@ tdsigwakeup(struct thread *td, int sig, sig_t action, int intrval) /* * Give low priority threads a better chance to run. */ - if (td->td_priority > PUSER) + if (td->td_priority > PUSER && !TD_IS_IDLETHREAD(td)) sched_prio(td, PUSER); wakeup_swapper = sleepq_abort(td, intrval); diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index e0ee2dc..8c84773 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -414,11 +414,9 @@ mi_switch(int flags, struct thread *newtd) { uint64_t runtime, new_switchtime; struct thread *td; - struct proc *p; td = curthread; /* XXX */ THREAD_LOCK_ASSERT(td, MA_OWNED | MA_NOTRECURSED); - p = td->td_proc; /* XXX */ KASSERT(!TD_ON_RUNQ(td), ("mi_switch: called by old code")); #ifdef INVARIANTS if (!TD_ON_LOCK(td) && !TD_IS_RUNNING(td)) @@ -458,7 +456,7 @@ mi_switch(int flags, struct thread *newtd) PCPU_INC(cnt.v_swtch); PCPU_SET(switchticks, ticks); CTR4(KTR_PROC, "mi_switch: old thread %ld (td_sched %p, pid %ld, %s)", - td->td_tid, td->td_sched, p->p_pid, td->td_name); + td->td_tid, td->td_sched, td->td_proc->p_pid, td->td_name); #if (KTR_COMPILE & KTR_SCHED) != 0 if (TD_IS_IDLETHREAD(td)) KTR_STATE1(KTR_SCHED, "thread", sched_tdname(td), "idle", @@ -474,7 +472,7 @@ mi_switch(int flags, struct thread *newtd) "prio:%d", td->td_priority); CTR4(KTR_PROC, "mi_switch: new thread %ld (td_sched %p, pid %ld, %s)", - td->td_tid, td->td_sched, p->p_pid, td->td_name); + td->td_tid, td->td_sched, td->td_proc->p_pid, td->td_name); /* * If the last thread was exiting, finish cleaning it up. diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index 93f7557..82387c2 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -86,6 +86,8 @@ __FBSDID("$FreeBSD$"); #include <security/mac/mac_framework.h> +void (*softdep_ast_cleanup)(void); + /* * Define the code needed before returning to user mode, for trap and * syscall. @@ -114,6 +116,9 @@ userret(struct thread *td, struct trapframe *frame) #ifdef KTRACE KTRUSERRET(td); #endif + if (softdep_ast_cleanup != NULL) + softdep_ast_cleanup(); + /* * If this thread tickled GEOM, we need to wait for the giggling to * stop before we return to userland @@ -157,6 +162,8 @@ userret(struct thread *td, struct trapframe *frame) ("userret: Returning while holding vnode reservation")); KASSERT((td->td_flags & TDF_SBDRY) == 0, ("userret: Returning with stop signals deferred")); + KASSERT(td->td_su == NULL, + ("userret: Returning with SU cleanup request not handled")); #ifdef VIMAGE /* Unfortunately td_vnet_lpush needs VNET_DEBUG. */ VNET_ASSERT(curvnet == NULL, diff --git a/sys/kern/vfs_cluster.c b/sys/kern/vfs_cluster.c index 9601082..362ebb7b 100644 --- a/sys/kern/vfs_cluster.c +++ b/sys/kern/vfs_cluster.c @@ -310,7 +310,6 @@ static struct buf * cluster_rbuild(struct vnode *vp, u_quad_t filesize, daddr_t lbn, daddr_t blkno, long size, int run, int gbflags, struct buf *fbp) { - struct bufobj *bo; struct buf *bp, *tbp; daddr_t bn; off_t off; @@ -376,7 +375,6 @@ cluster_rbuild(struct vnode *vp, u_quad_t filesize, daddr_t lbn, bp->b_npages = 0; inc = btodb(size); - bo = &vp->v_bufobj; for (bn = blkno, i = 0; i < run; ++i, bn += inc) { if (i == 0) { VM_OBJECT_WLOCK(tbp->b_bufobj->bo_object); diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c index cf3928e..f935954 100644 --- a/sys/kern/vfs_init.c +++ b/sys/kern/vfs_init.c @@ -311,9 +311,7 @@ static int vfs_unregister(struct vfsconf *vfc) { struct vfsconf *vfsp; - int error, i, maxtypenum; - - i = vfc->vfc_typenum; + int error, maxtypenum; vfsconf_lock(); vfsp = vfs_byname_locked(vfc->vfc_name); diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 09fa7ed..c86259b 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -1128,12 +1128,7 @@ struct unmount_args { #endif /* ARGSUSED */ int -sys_unmount(td, uap) - struct thread *td; - register struct unmount_args /* { - char *path; - int flags; - } */ *uap; +sys_unmount(struct thread *td, struct unmount_args *uap) { struct nameidata nd; struct mount *mp; @@ -1164,8 +1159,10 @@ sys_unmount(td, uap) mtx_lock(&mountlist_mtx); TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) { if (mp->mnt_stat.f_fsid.val[0] == id0 && - mp->mnt_stat.f_fsid.val[1] == id1) + mp->mnt_stat.f_fsid.val[1] == id1) { + vfs_ref(mp); break; + } } mtx_unlock(&mountlist_mtx); } else { @@ -1183,8 +1180,10 @@ sys_unmount(td, uap) } mtx_lock(&mountlist_mtx); TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) { - if (strcmp(mp->mnt_stat.f_mntonname, pathbuf) == 0) + if (strcmp(mp->mnt_stat.f_mntonname, pathbuf) == 0) { + vfs_ref(mp); break; + } } mtx_unlock(&mountlist_mtx); } @@ -1202,8 +1201,10 @@ sys_unmount(td, uap) /* * Don't allow unmounting the root filesystem. */ - if (mp->mnt_flag & MNT_ROOTFS) + if (mp->mnt_flag & MNT_ROOTFS) { + vfs_rel(mp); return (EINVAL); + } error = dounmount(mp, uap->flags, td); return (error); } @@ -1212,10 +1213,7 @@ sys_unmount(td, uap) * Do the actual filesystem unmount. */ int -dounmount(mp, flags, td) - struct mount *mp; - int flags; - struct thread *td; +dounmount(struct mount *mp, int flags, struct thread *td) { struct vnode *coveredvp, *fsrootvp; int error; @@ -1235,6 +1233,7 @@ dounmount(mp, flags, td) if (coveredvp->v_mountedhere != mp || coveredvp->v_mountedhere->mnt_gen != mnt_gen_r) { VOP_UNLOCK(coveredvp, 0); + vfs_rel(mp); return (EBUSY); } } @@ -1243,13 +1242,14 @@ dounmount(mp, flags, td) * original mount is permitted to unmount this filesystem. */ error = vfs_suser(mp, td); - if (error) { + if (error != 0) { if (coveredvp) VOP_UNLOCK(coveredvp, 0); + vfs_rel(mp); return (error); } - vn_start_write(NULL, &mp, V_WAIT); + vn_start_write(NULL, &mp, V_WAIT | V_MNTREF); MNT_ILOCK(mp); if ((mp->mnt_kern_flag & MNTK_UNMOUNT) != 0 || !TAILQ_EMPTY(&mp->mnt_uppers)) { diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 8e34456..625d193 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -3502,8 +3502,9 @@ vfs_unmountall(void) */ while(!TAILQ_EMPTY(&mountlist)) { mp = TAILQ_LAST(&mountlist, mntlist); + vfs_ref(mp); error = dounmount(mp, MNT_FORCE, td); - if (error) { + if (error != 0) { TAILQ_REMOVE(&mountlist, mp, mnt_list); /* * XXX: Due to the way in which we mount the root diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 01d448e..a00da51 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -1646,16 +1646,18 @@ unlock: } int -vn_start_write(vp, mpp, flags) - struct vnode *vp; - struct mount **mpp; - int flags; +vn_start_write(struct vnode *vp, struct mount **mpp, int flags) { struct mount *mp; int error; - if (!vn_suspendable(vp, mpp)) + KASSERT((flags & V_MNTREF) == 0 || (*mpp != NULL && vp == NULL), + ("V_MNTREF requires mp")); + if (!vn_suspendable(vp, mpp)) { + if ((flags & V_MNTREF) != 0) + vfs_rel(*mpp); return (0); + } error = 0; /* @@ -1681,7 +1683,7 @@ vn_start_write(vp, mpp, flags) * emulate a vfs_ref(). */ MNT_ILOCK(mp); - if (vp == NULL) + if (vp == NULL && (flags & V_MNTREF) == 0) MNT_REF(mp); return (vn_start_write_locked(mp, flags)); @@ -1695,16 +1697,18 @@ vn_start_write(vp, mpp, flags) * time, these operations are halted until the suspension is over. */ int -vn_start_secondary_write(vp, mpp, flags) - struct vnode *vp; - struct mount **mpp; - int flags; +vn_start_secondary_write(struct vnode *vp, struct mount **mpp, int flags) { struct mount *mp; int error; - if (!vn_suspendable(vp, mpp)) + KASSERT((flags & V_MNTREF) == 0 || (*mpp != NULL && vp == NULL), + ("V_MNTREF requires mp")); + if (!vn_suspendable(vp, mpp)) { + if ((flags & V_MNTREF) != 0) + vfs_rel(*mpp); return (0); + } retry: if (vp != NULL) { @@ -1730,7 +1734,7 @@ vn_start_secondary_write(vp, mpp, flags) * emulate a vfs_ref(). */ MNT_ILOCK(mp); - if (vp == NULL) + if (vp == NULL && (flags & V_MNTREF) == 0) MNT_REF(mp); if ((mp->mnt_kern_flag & (MNTK_SUSPENDED | MNTK_SUSPEND2)) == 0) { mp->mnt_secondary_writes++; diff --git a/sys/mips/include/pcpu.h b/sys/mips/include/pcpu.h index 89b6525..f4be33d 100644 --- a/sys/mips/include/pcpu.h +++ b/sys/mips/include/pcpu.h @@ -31,6 +31,7 @@ #ifndef _MACHINE_PCPU_H_ #define _MACHINE_PCPU_H_ +#include <machine/cpufunc.h> #include <machine/pte.h> #define PCPU_MD_COMMON_FIELDS \ diff --git a/sys/modules/Makefile b/sys/modules/Makefile index c0217cc..7091c3c 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -621,6 +621,8 @@ _x86bios= x86bios .if ${MACHINE_CPUARCH} == "amd64" _ixl= ixl _ixlv= ixlv +_linux64= linux64 +_linux_common= linux_common _ntb= ntb _qlxge= qlxge _qlxgb= qlxgb @@ -629,8 +631,6 @@ _sfxge= sfxge .if ${MK_BHYVE} != "no" || defined(ALL_MODULES) _vmm= vmm -_linux_common= linux_common -_linux64= linux64 .endif .endif diff --git a/sys/modules/i2c/controllers/Makefile b/sys/modules/i2c/controllers/Makefile index 2b4432f..132ff2d 100644 --- a/sys/modules/i2c/controllers/Makefile +++ b/sys/modules/i2c/controllers/Makefile @@ -3,7 +3,7 @@ .if ${MACHINE} == "pc98" SUBDIR = lpbb .else -SUBDIR = alpm amdpm amdsmb ichsmb intpm ismt nfsmb viapm lpbb pcf +SUBDIR = alpm amdpm amdsmb ichiic ichsmb intpm ismt nfsmb viapm lpbb pcf .endif .include <bsd.subdir.mk> diff --git a/sys/modules/i2c/controllers/ichiic/Makefile b/sys/modules/i2c/controllers/ichiic/Makefile new file mode 100644 index 0000000..288a79e --- /dev/null +++ b/sys/modules/i2c/controllers/ichiic/Makefile @@ -0,0 +1,8 @@ +#$FreeBSD$ + +.PATH: ${.CURDIR}/../../../../dev/ichiic +KMOD = ig4 +SRCS = device_if.h bus_if.h iicbb_if.h pci_if.h smbus_if.h \ + ig4_iic.c ig4_pci.c ig4_reg.h ig4_var.h + +.include <bsd.kmod.mk> diff --git a/sys/modules/ixl/Makefile b/sys/modules/ixl/Makefile index 7d2fca9..13be8ab 100755..100644 --- a/sys/modules/ixl/Makefile +++ b/sys/modules/ixl/Makefile @@ -3,7 +3,7 @@ .PATH: ${.CURDIR}/../../dev/ixl KMOD = if_ixl -SRCS = device_if.h bus_if.h pci_if.h opt_bdg.h +SRCS = device_if.h bus_if.h pci_if.h pci_iov_if.h opt_bdg.h SRCS += opt_inet.h opt_inet6.h opt_rss.h SRCS += if_ixl.c ixl_txrx.c i40e_osdep.c diff --git a/sys/modules/sfxge/Makefile b/sys/modules/sfxge/Makefile index 31d91be..b2116d8 100644 --- a/sys/modules/sfxge/Makefile +++ b/sys/modules/sfxge/Makefile @@ -34,6 +34,7 @@ SRCS+= hunt_nvram.c hunt_rx.c hunt_phy.c hunt_sram.c hunt_tx.c hunt_vpd.c SRCS+= hunt_filter.c SRCS+= hunt_impl.h -DEBUG_FLAGS= -DDEBUG=1 +# Extra debug checks +#CFLAGS += -DDEBUG=1 .include <bsd.kmod.mk> diff --git a/sys/net80211/ieee80211_crypto.c b/sys/net80211/ieee80211_crypto.c index e4656cc..d338506 100644 --- a/sys/net80211/ieee80211_crypto.c +++ b/sys/net80211/ieee80211_crypto.c @@ -33,8 +33,6 @@ __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include <sys/param.h> -#include <sys/systm.h> -#include <sys/counter.h> #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/mbuf.h> diff --git a/sys/net80211/ieee80211_crypto_ccmp.c b/sys/net80211/ieee80211_crypto_ccmp.c index e005a65..89ca6d0 100644 --- a/sys/net80211/ieee80211_crypto_ccmp.c +++ b/sys/net80211/ieee80211_crypto_ccmp.c @@ -37,7 +37,6 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> -#include <sys/counter.h> #include <sys/mbuf.h> #include <sys/malloc.h> #include <sys/kernel.h> diff --git a/sys/net80211/ieee80211_crypto_none.c b/sys/net80211/ieee80211_crypto_none.c index b28b7db..b1ffbb4 100644 --- a/sys/net80211/ieee80211_crypto_none.c +++ b/sys/net80211/ieee80211_crypto_none.c @@ -32,9 +32,8 @@ __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include <sys/param.h> -#include <sys/systm.h> -#include <sys/counter.h> #include <sys/kernel.h> +#include <sys/systm.h> #include <sys/mbuf.h> #include <sys/module.h> diff --git a/sys/net80211/ieee80211_crypto_tkip.c b/sys/net80211/ieee80211_crypto_tkip.c index c10dfd5..c6d2f54 100644 --- a/sys/net80211/ieee80211_crypto_tkip.c +++ b/sys/net80211/ieee80211_crypto_tkip.c @@ -37,7 +37,6 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> -#include <sys/counter.h> #include <sys/mbuf.h> #include <sys/malloc.h> #include <sys/kernel.h> diff --git a/sys/net80211/ieee80211_crypto_wep.c b/sys/net80211/ieee80211_crypto_wep.c index 675bb80..587cf39 100644 --- a/sys/net80211/ieee80211_crypto_wep.c +++ b/sys/net80211/ieee80211_crypto_wep.c @@ -33,7 +33,6 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> -#include <sys/counter.h> #include <sys/mbuf.h> #include <sys/malloc.h> #include <sys/kernel.h> diff --git a/sys/net80211/ieee80211_freebsd.h b/sys/net80211/ieee80211_freebsd.h index f9517da..0241720 100644 --- a/sys/net80211/ieee80211_freebsd.h +++ b/sys/net80211/ieee80211_freebsd.h @@ -28,7 +28,9 @@ #define _NET80211_IEEE80211_FREEBSD_H_ #ifdef _KERNEL -#include <sys/param.h> +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/counter.h> #include <sys/lock.h> #include <sys/mutex.h> #include <sys/rwlock.h> diff --git a/sys/net80211/ieee80211_hwmp.c b/sys/net80211/ieee80211_hwmp.c index 436ccd8..6bbc32c 100644 --- a/sys/net80211/ieee80211_hwmp.c +++ b/sys/net80211/ieee80211_hwmp.c @@ -41,7 +41,6 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> -#include <sys/counter.h> #include <sys/mbuf.h> #include <sys/malloc.h> #include <sys/kernel.h> diff --git a/sys/net80211/ieee80211_ratectl_none.c b/sys/net80211/ieee80211_ratectl_none.c index de7195d..5a45a74 100644 --- a/sys/net80211/ieee80211_ratectl_none.c +++ b/sys/net80211/ieee80211_ratectl_none.c @@ -30,7 +30,6 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> -#include <sys/counter.h> #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/module.h> diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c index 4569900..21add43 100644 --- a/sys/netinet/sctp_asconf.c +++ b/sys/netinet/sctp_asconf.c @@ -555,7 +555,9 @@ sctp_process_asconf_set_primary(struct sockaddr *src, (stcb->asoc.primary_destination->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) { - sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_TIMER + SCTP_LOC_7); + sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, + stcb->sctp_ep, stcb, NULL, + SCTP_FROM_SCTP_ASCONF + SCTP_LOC_1); if (sctp_is_mobility_feature_on(stcb->sctp_ep, SCTP_MOBILITY_FASTHANDOFF)) { sctp_assoc_immediate_retrans(stcb, @@ -991,7 +993,7 @@ sctp_assoc_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *dstnet) SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.primary_destination->ro._l_addr.sa); sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, stcb->asoc.deleted_primary, - SCTP_FROM_SCTP_TIMER + SCTP_LOC_8); + SCTP_FROM_SCTP_ASCONF + SCTP_LOC_3); stcb->asoc.num_send_timers_up--; if (stcb->asoc.num_send_timers_up < 0) { stcb->asoc.num_send_timers_up = 0; @@ -1030,7 +1032,7 @@ sctp_net_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *net) SCTPDBG(SCTP_DEBUG_ASCONF1, "net_immediate_retrans: RTO is %d\n", net->RTO); sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_TIMER + SCTP_LOC_5); + SCTP_FROM_SCTP_ASCONF + SCTP_LOC_4); stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); net->error_count = 0; TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { @@ -1684,7 +1686,7 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset, if (serial_num == asoc->asconf_seq_out - 1) { /* stop our timer */ sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_ASCONF + SCTP_LOC_3); + SCTP_FROM_SCTP_ASCONF + SCTP_LOC_5); } /* process the ASCONF-ACK contents */ ack_length = ntohs(cp->ch.chunk_length) - @@ -1975,7 +1977,8 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, * sent when the state goes open. */ if (status == 0 && - SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) { + ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || + (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED))) { #ifdef SCTP_TIMER_BASED_ASCONF sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, stcb->asoc.primary_destination); @@ -2223,7 +2226,8 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, * count of queued params. If in the non-open * state, these get sent when the assoc goes open. */ - if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) { + if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || + (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { if (status >= 0) { num_queued++; } @@ -2283,7 +2287,8 @@ sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa) "set_primary_ip_address_sa: queued on tcb=%p, ", (void *)stcb); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa); - if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) { + if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || + (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { #ifdef SCTP_TIMER_BASED_ASCONF sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, @@ -2319,7 +2324,8 @@ sctp_set_primary_ip_address(struct sctp_ifa *ifa) SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address: queued on stcb=%p, ", (void *)stcb); SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &ifa->address.sa); - if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) { + if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || + (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { #ifdef SCTP_TIMER_BASED_ASCONF sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, diff --git a/sys/netinet/sctp_cc_functions.c b/sys/netinet/sctp_cc_functions.c index 17a897b..d616d19 100644 --- a/sys/netinet/sctp_cc_functions.c +++ b/sys/netinet/sctp_cc_functions.c @@ -226,7 +226,8 @@ sctp_cwnd_update_after_fr(struct sctp_tcb *stcb, } sctp_timer_stop(SCTP_TIMER_TYPE_SEND, - stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); + stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_1); sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net); } @@ -1732,7 +1733,8 @@ sctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb, } sctp_timer_stop(SCTP_TIMER_TYPE_SEND, - stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); + stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_2); sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net); } @@ -2264,7 +2266,8 @@ sctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb, } sctp_timer_stop(SCTP_TIMER_TYPE_SEND, - stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); + stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_CC_FUNCTIONS + SCTP_LOC_3); sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net); } diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h index de45165..d90bd25 100644 --- a/sys/netinet/sctp_constants.h +++ b/sys/netinet/sctp_constants.h @@ -765,18 +765,19 @@ __FBSDID("$FreeBSD$"); */ /* File defines */ -#define SCTP_FROM_SCTP_INPUT 0x10000000 -#define SCTP_FROM_SCTP_PCB 0x20000000 -#define SCTP_FROM_SCTP_INDATA 0x30000000 -#define SCTP_FROM_SCTP_TIMER 0x40000000 -#define SCTP_FROM_SCTP_USRREQ 0x50000000 -#define SCTP_FROM_SCTPUTIL 0x60000000 -#define SCTP_FROM_SCTP6_USRREQ 0x70000000 -#define SCTP_FROM_SCTP_ASCONF 0x80000000 -#define SCTP_FROM_SCTP_OUTPUT 0x90000000 -#define SCTP_FROM_SCTP_PEELOFF 0xa0000000 -#define SCTP_FROM_SCTP_PANDA 0xb0000000 -#define SCTP_FROM_SCTP_SYSCTL 0xc0000000 +#define SCTP_FROM_SCTP_INPUT 0x10000000 +#define SCTP_FROM_SCTP_PCB 0x20000000 +#define SCTP_FROM_SCTP_INDATA 0x30000000 +#define SCTP_FROM_SCTP_TIMER 0x40000000 +#define SCTP_FROM_SCTP_USRREQ 0x50000000 +#define SCTP_FROM_SCTPUTIL 0x60000000 +#define SCTP_FROM_SCTP6_USRREQ 0x70000000 +#define SCTP_FROM_SCTP_ASCONF 0x80000000 +#define SCTP_FROM_SCTP_OUTPUT 0x90000000 +#define SCTP_FROM_SCTP_PEELOFF 0xa0000000 +#define SCTP_FROM_SCTP_PANDA 0xb0000000 +#define SCTP_FROM_SCTP_SYSCTL 0xc0000000 +#define SCTP_FROM_SCTP_CC_FUNCTIONS 0xd0000000 /* Location ID's */ #define SCTP_LOC_1 0x00000001 @@ -812,6 +813,8 @@ __FBSDID("$FreeBSD$"); #define SCTP_LOC_31 0x0000001f #define SCTP_LOC_32 0x00000020 #define SCTP_LOC_33 0x00000021 +#define SCTP_LOC_34 0x00000022 +#define SCTP_LOC_35 0x00000023 /* Free assoc codes */ diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index d3b4855..50a6628 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -1034,7 +1034,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, chk->rec.data.TSN_seq, (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) ? 1 : 0); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_7; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_8; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return; @@ -1056,7 +1056,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, chk->rec.data.stream_number, chk->rec.data.stream_seq); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_8; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_9; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return; @@ -1073,7 +1073,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, chk->rec.data.stream_number, chk->rec.data.stream_seq); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_9; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_10; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return; @@ -1100,7 +1100,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, chk->rec.data.stream_number, chk->rec.data.stream_seq); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_10; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_11; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return; @@ -1123,7 +1123,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, chk->rec.data.stream_number, chk->rec.data.stream_seq); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_11; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_12; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return; @@ -1144,7 +1144,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, chk->rec.data.stream_number, chk->rec.data.stream_seq); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_12; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_13; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return; @@ -1162,7 +1162,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, chk->rec.data.TSN_seq, (chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) ? 1 : 0); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_12; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_14; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return; @@ -1184,7 +1184,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, chk->rec.data.stream_number, chk->rec.data.stream_seq); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_13; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_15; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return; @@ -1476,7 +1476,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, asoc->strmin[strmno].last_sequence_delivered, tsn, strmno, strmseq); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_14; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_16; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; return (0); @@ -1713,7 +1713,7 @@ failed_pdapi_express_del: snprintf(msg, sizeof(msg), "Reas. queue emtpy, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", tsn, strmno, strmseq); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_15; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_17; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; if (last_chunk) { @@ -1732,7 +1732,7 @@ failed_pdapi_express_del: snprintf(msg, sizeof(msg), "PD ongoing, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", tsn, strmno, strmseq); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_16; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_18; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; if (last_chunk) { @@ -1761,7 +1761,7 @@ failed_pdapi_express_del: snprintf(msg, sizeof(msg), "No PD ongoing, got TSN=%8.8x, SID=%4.4x, SSN=%4.4x", tsn, strmno, strmseq); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_17; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_19; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); *abort_flag = 1; if (last_chunk) { @@ -2159,7 +2159,8 @@ sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap) */ if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_RECV, - stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_INDATA + SCTP_LOC_18); + stcb->sctp_ep, stcb, NULL, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_20); } sctp_send_shutdown(stcb, ((stcb->asoc.alternate) ? stcb->asoc.alternate : stcb->asoc.primary_destination)); @@ -2382,7 +2383,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, snprintf(msg, sizeof(msg), "DATA chunk of length %d", chk_length); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_19; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_21; sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err, mflowtype, mflowid, @@ -2397,7 +2398,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, struct mbuf *op_err; op_err = sctp_generate_no_user_data_cause(ch->dp.tsn); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_19; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_22; sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err, mflowtype, mflowid, @@ -3462,12 +3463,18 @@ sctp_fs_audit(struct sctp_association *asoc) { struct sctp_tmit_chunk *chk; int inflight = 0, resend = 0, inbetween = 0, acked = 0, above = 0; - int entry_flight, entry_cnt, ret; + int ret; + +#ifndef INVARIANTS + int entry_flight, entry_cnt; + +#endif + ret = 0; +#ifndef INVARIANTS entry_flight = asoc->total_flight; entry_cnt = asoc->total_flight_count; - ret = 0; - +#endif if (asoc->pr_sctp_cnt >= asoc->sent_queue_cnt) return (0); @@ -3622,7 +3629,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, snprintf(msg, sizeof(msg), "Cum ack %8.8x greater or equal than TSN %8.8x", cumack, send_s); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_23; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); return; } @@ -3818,7 +3825,9 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, } if (net->dest_state & SCTP_ADDR_PF) { net->dest_state &= ~SCTP_ADDR_PF; - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, + stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_24); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net); /* Done with this net */ @@ -3904,7 +3913,7 @@ again: } else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_22); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_25); } } } @@ -3978,7 +3987,7 @@ again: *abort_now = 1; /* XXX */ op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_26; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); } else { struct sctp_nets *netp; @@ -4191,7 +4200,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, snprintf(msg, sizeof(msg), "Cum ack %8.8x greater or equal than TSN %8.8x", cum_ack, send_s); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_27; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); return; } @@ -4223,7 +4232,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, /* stop any timers */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_26); + stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_28); net->partial_bytes_acked = 0; net->flight_size = 0; } @@ -4428,14 +4437,14 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, if (net->new_pseudo_cumack) sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_27); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_29); } } else { if (accum_moved) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_28); + stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_30); } } } @@ -4608,7 +4617,9 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, } if (net->dest_state & SCTP_ADDR_PF) { net->dest_state &= ~SCTP_ADDR_PF; - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, + stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_31); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); asoc->cc_functions.sctp_cwnd_update_exit_pf(stcb, net); /* Done with this net */ @@ -4631,7 +4642,8 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, TAILQ_FOREACH(net, &asoc->nets, sctp_next) { /* stop all timers */ sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_30); + stcb, net, + SCTP_FROM_SCTP_INDATA + SCTP_LOC_32); net->flight_size = 0; net->partial_bytes_acked = 0; } @@ -4687,7 +4699,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, *abort_now = 1; /* XXX */ op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_31; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_33; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); return; } else { @@ -4839,7 +4851,7 @@ again: } else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, - SCTP_FROM_SCTP_INDATA + SCTP_LOC_22); + SCTP_FROM_SCTP_INDATA + SCTP_LOC_34); } } } @@ -5129,7 +5141,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, "New cum ack %8.8x too high, highest TSN %8.8x", new_cum_tsn, asoc->highest_tsn_inside_map); op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg); - stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_33; + stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_35; sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED); return; } diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index 048dfd3..89047cb 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -513,7 +513,7 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset, * primary. */ sctp_timer_stop(SCTP_TIMER_TYPE_INIT, stcb->sctp_ep, stcb, - asoc->primary_destination, SCTP_FROM_SCTP_INPUT + SCTP_LOC_4); + asoc->primary_destination, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3); /* calculate the RTO */ net->RTO = sctp_calculate_rto(stcb, asoc, net, &asoc->time_entered, sctp_align_safe_nocopy, @@ -633,7 +633,8 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp, } sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED, stcb, 0, (void *)r_net, SCTP_SO_NOT_LOCKED); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, + r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_4); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net); } old_error_counter = r_net->error_count; @@ -654,7 +655,8 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp, stcb->asoc.cc_functions.sctp_cwnd_update_exit_pf(stcb, net); } if (old_error_counter > 0) { - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, + stcb, r_net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_5); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, r_net); } if (r_net == stcb->asoc.primary_destination) { @@ -673,7 +675,9 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp, sctp_is_mobility_feature_on(stcb->sctp_ep, SCTP_MOBILITY_PRIM_DELETED)) { - sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_TIMER + SCTP_LOC_7); + sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, + stcb->sctp_ep, stcb, NULL, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_6); if (sctp_is_mobility_feature_on(stcb->sctp_ep, SCTP_MOBILITY_FASTHANDOFF)) { sctp_assoc_immediate_retrans(stcb, @@ -795,7 +799,8 @@ sctp_handle_abort(struct sctp_abort_chunk *abort, error = 0; } /* stop any receive timers */ - sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_6); + sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_7); /* notify user of the abort and clean up... */ sctp_abort_notification(stcb, 1, error, abort, SCTP_SO_NOT_LOCKED); /* free the tcb */ @@ -817,7 +822,7 @@ sctp_handle_abort(struct sctp_abort_chunk *abort, #endif stcb->asoc.state |= SCTP_STATE_WAS_ABORTED; (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_6); + SCTP_FROM_SCTP_INPUT + SCTP_LOC_8); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -932,7 +937,8 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, * stop the shutdown timer, since we WILL move to * SHUTDOWN-ACK-SENT. */ - sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_8); + sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, + net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_9); } /* Now is there unsent data on a stream somewhere? */ some_on_streamwheel = sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED); @@ -1025,7 +1031,8 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED, } #endif /* stop the timer */ - sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_9); + sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_10); /* send SHUTDOWN-COMPLETE */ sctp_send_shutdown_complete(stcb, net, 0); /* notify upper layer protocol */ @@ -1046,7 +1053,7 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED, atomic_subtract_int(&stcb->asoc.refcnt, 1); #endif (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_10); + SCTP_FROM_SCTP_INPUT + SCTP_LOC_11); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -1206,7 +1213,7 @@ sctp_handle_error(struct sctp_chunkhdr *ch, atomic_subtract_int(&stcb->asoc.refcnt, 1); #endif (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_11); + SCTP_FROM_SCTP_INPUT + SCTP_LOC_12); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -1558,9 +1565,12 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, return (NULL); } /* we have already processed the INIT so no problem */ - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, - net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_12); - sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_13); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, + stcb, net, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_13); + sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, + stcb, net, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_14); /* update current state */ if (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED) SCTP_STAT_INCR_COUNTER32(sctps_activeestab); @@ -1720,7 +1730,8 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, } if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 8; - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_14); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_15); sctp_stop_all_cookie_timers(stcb); /* * since we did not send a HB make sure we don't double @@ -1865,8 +1876,10 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, /* temp code */ if (how_indx < sizeof(asoc->cookie_how)) asoc->cookie_how[how_indx] = 12; - sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_15); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_16); + sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_16); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_17); /* notify upper layer */ *notification = SCTP_NOTIFY_ASSOC_RESTART; @@ -2134,7 +2147,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, SCTP_TCB_LOCK(stcb); #endif (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, - SCTP_FROM_SCTP_INPUT + SCTP_LOC_16); + SCTP_FROM_SCTP_INPUT + SCTP_LOC_18); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -2165,7 +2178,8 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, SCTP_SOCKET_LOCK(so, 1); SCTP_TCB_LOCK(stcb); #endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_16); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_19); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -2182,7 +2196,8 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, SCTP_SOCKET_LOCK(so, 1); SCTP_TCB_LOCK(stcb); #endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_17); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_20); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -2211,7 +2226,8 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, SCTP_SOCKET_LOCK(so, 1); SCTP_TCB_LOCK(stcb); #endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_18); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_21); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -2271,7 +2287,8 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, SCTP_SOCKET_LOCK(so, 1); SCTP_TCB_LOCK(stcb); #endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_19); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_22); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -2741,7 +2758,8 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, SCTP_TCB_LOCK((*stcb)); atomic_subtract_int(&(*stcb)->asoc.refcnt, 1); #endif - (void)sctp_free_assoc(*inp_p, *stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_20); + (void)sctp_free_assoc(*inp_p, *stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_23); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(pcb_so, 1); #endif @@ -3173,7 +3191,8 @@ sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp SCTP_UNUSE } #endif /* stop the timer */ - sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWNACK, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_22); + sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWNACK, stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_24); SCTP_STAT_INCR_COUNTER32(sctps_shutdown); /* free the TCB */ SCTPDBG(SCTP_DEBUG_INPUT2, @@ -3186,7 +3205,8 @@ sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp SCTP_UNUSE SCTP_TCB_LOCK(stcb); atomic_subtract_int(&stcb->asoc.refcnt, 1); #endif - (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_23); + (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_25); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -3294,7 +3314,8 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc, /* restart the timer */ sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, - stcb, tp1->whoTo, SCTP_FROM_SCTP_INPUT + SCTP_LOC_24); + stcb, tp1->whoTo, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_26); sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, tp1->whoTo); @@ -3362,7 +3383,8 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc, * this, otherwise we let the timer fire. */ sctp_timer_stop(SCTP_TIMER_TYPE_INIT, stcb->sctp_ep, - stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_25); + stcb, net, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_27); sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); } break; @@ -3539,7 +3561,8 @@ sctp_clean_up_stream_reset(struct sctp_tcb *stcb) } asoc = &stcb->asoc; - sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, chk->whoTo, SCTP_FROM_SCTP_INPUT + SCTP_LOC_26); + sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, + chk->whoTo, SCTP_FROM_SCTP_INPUT + SCTP_LOC_28); TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next); @@ -4783,7 +4806,8 @@ process_control_chunks: SCTP_TCB_LOCK(stcb); atomic_subtract_int(&stcb->asoc.refcnt, 1); #endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_27); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_29); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -5203,7 +5227,8 @@ process_control_chunks: SCTP_TCB_LOCK(stcb); atomic_subtract_int(&stcb->asoc.refcnt, 1); #endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_27); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_30); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -5381,7 +5406,8 @@ process_control_chunks: SCTP_TCB_LOCK(stcb); atomic_subtract_int(&stcb->asoc.refcnt, 1); #endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_29); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_31); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index ed3b9ec..515ee13 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -3160,8 +3160,6 @@ again_with_private_addresses_allowed: sifa = NULL; continue; } - } else { - SCTP_PRINTF("Stcb is null - no print\n"); } atomic_add_int(&sifa->refcount, 1); goto out; @@ -4063,7 +4061,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, sctp_route_t iproute; int len; - len = sizeof(struct ip) + sizeof(struct sctphdr); + len = SCTP_MIN_V4_OVERHEAD; if (port) { len += sizeof(struct udphdr); } @@ -4345,7 +4343,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, flowlabel = ntohl(((struct in6pcb *)inp)->in6p_flowinfo); } flowlabel &= 0x000fffff; - len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr); + len = SCTP_MIN_OVERHEAD; if (port) { len += sizeof(struct udphdr); } @@ -5107,10 +5105,11 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, if (op_err == NULL) { /* Ok need to try to get a mbuf */ #ifdef INET6 - l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); + l_len = SCTP_MIN_OVERHEAD; #else - l_len = sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); + l_len = SCTP_MIN_V4_OVERHEAD; #endif + l_len += sizeof(struct sctp_chunkhdr); l_len += plen; l_len += sizeof(struct sctp_paramhdr); op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA); @@ -5176,10 +5175,11 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, /* Ok need to try to get an mbuf */ #ifdef INET6 - l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); + l_len = SCTP_MIN_OVERHEAD; #else - l_len = sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); + l_len = SCTP_MIN_V4_OVERHEAD; #endif + l_len += sizeof(struct sctp_chunkhdr); l_len += plen; l_len += sizeof(struct sctp_paramhdr); op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA); @@ -5251,10 +5251,11 @@ invalid_size: int l_len; #ifdef INET6 - l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); + l_len = SCTP_MIN_OVERHEAD; #else - l_len = sizeof(struct ip) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); + l_len = SCTP_MIN_V4_OVERHEAD; #endif + l_len += sizeof(struct sctp_chunkhdr); l_len += (2 * sizeof(struct sctp_paramhdr)); op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA); if (op_err) { @@ -5588,11 +5589,7 @@ do_a_abort: stc.ipv6_addr_legal = 0; stc.ipv4_addr_legal = 1; } -#ifdef SCTP_DONT_DO_PRIVADDR_SCOPE - stc.ipv4_scope = 1; -#else stc.ipv4_scope = 0; -#endif if (net == NULL) { to = src; switch (dst->sa_family) { @@ -5613,13 +5610,10 @@ do_a_abort: stc.laddr_type = SCTP_IPV4_ADDRESS; /* scope_id is only for v6 */ stc.scope_id = 0; -#ifndef SCTP_DONT_DO_PRIVADDR_SCOPE - if (IN4_ISPRIVATE_ADDRESS(&src4->sin_addr)) { + if ((IN4_ISPRIVATE_ADDRESS(&src4->sin_addr)) || + (IN4_ISPRIVATE_ADDRESS(&dst4->sin_addr))) { stc.ipv4_scope = 1; } -#else - stc.ipv4_scope = 1; -#endif /* SCTP_DONT_DO_PRIVADDR_SCOPE */ /* Must use the address in this case */ if (sctp_is_address_on_local_host(src, vrf_id)) { stc.loopback_scope = 1; @@ -5641,16 +5635,18 @@ do_a_abort: stc.local_scope = 0; stc.site_scope = 1; stc.ipv4_scope = 1; - } else if (IN6_IS_ADDR_LINKLOCAL(&src6->sin6_addr)) { + } else if (IN6_IS_ADDR_LINKLOCAL(&src6->sin6_addr) || + IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr)) { /* - * If the new destination is a - * LINK_LOCAL we must have common - * both site and local scope. Don't - * set local scope though since we - * must depend on the source to be - * added implicitly. We cannot - * assure just because we share one - * link that all links are common. + * If the new destination or source + * is a LINK_LOCAL we must have + * common both site and local scope. + * Don't set local scope though + * since we must depend on the + * source to be added implicitly. We + * cannot assure just because we + * share one link that all links are + * common. */ stc.local_scope = 0; stc.site_scope = 1; @@ -5666,11 +5662,12 @@ do_a_abort: * pull out the scope_id from * incoming pkt */ - } else if (IN6_IS_ADDR_SITELOCAL(&src6->sin6_addr)) { + } else if (IN6_IS_ADDR_SITELOCAL(&src6->sin6_addr) || + IN6_IS_ADDR_SITELOCAL(&dst6->sin6_addr)) { /* - * If the new destination is - * SITE_LOCAL then we must have site - * scope in common. + * If the new destination or source + * is SITE_LOCAL then we must have + * site scope in common. */ stc.site_scope = 1; } @@ -7961,12 +7958,12 @@ again_one_more_time: switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) { #ifdef INET case AF_INET: - mtu = net->mtu - (sizeof(struct ip) + sizeof(struct sctphdr)); + mtu = net->mtu - SCTP_MIN_V4_OVERHEAD; break; #endif #ifdef INET6 case AF_INET6: - mtu = net->mtu - (sizeof(struct ip6_hdr) + sizeof(struct sctphdr)); + mtu = net->mtu - SCTP_MIN_OVERHEAD; break; #endif default: @@ -8327,7 +8324,8 @@ again_one_more_time: /* turn off the timer */ if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_RECV, - inp, stcb, net, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_1); + inp, stcb, net, + SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_1); } } ctl_cnt++; @@ -8512,16 +8510,16 @@ again_one_more_time: switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) { #ifdef INET case AF_INET: - if (net->mtu > (sizeof(struct ip) + sizeof(struct sctphdr))) - omtu = net->mtu - (sizeof(struct ip) + sizeof(struct sctphdr)); + if (net->mtu > SCTP_MIN_V4_OVERHEAD) + omtu = net->mtu - SCTP_MIN_V4_OVERHEAD; else omtu = 0; break; #endif #ifdef INET6 case AF_INET6: - if (net->mtu > (sizeof(struct ip6_hdr) + sizeof(struct sctphdr))) - omtu = net->mtu - (sizeof(struct ip6_hdr) + sizeof(struct sctphdr)); + if (net->mtu > SCTP_MIN_OVERHEAD) + omtu = net->mtu - SCTP_MIN_OVERHEAD; else omtu = 0; break; @@ -8531,7 +8529,8 @@ again_one_more_time: omtu = 0; break; } - if ((((asoc->state & SCTP_STATE_OPEN) == SCTP_STATE_OPEN) && + if ((((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || + (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) && (skip_data_for_this_net == 0)) || (cookie)) { TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) { @@ -9780,7 +9779,7 @@ one_chunk_around: * t3-expiring. */ sctp_timer_stop(SCTP_TIMER_TYPE_SEND, inp, stcb, net, - SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_4); + SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_2); sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); } } @@ -10387,7 +10386,8 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked /* No memory so we drop the idea, and set a timer */ if (stcb->asoc.delayed_ack) { sctp_timer_stop(SCTP_TIMER_TYPE_RECV, - stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_5); + stcb->sctp_ep, stcb, NULL, + SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_3); sctp_timer_start(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL); } else { @@ -10455,7 +10455,8 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked /* sa_ignore NO_NULL_CHK */ if (stcb->asoc.delayed_ack) { sctp_timer_stop(SCTP_TIMER_TYPE_RECV, - stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6); + stcb->sctp_ep, stcb, NULL, + SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_4); sctp_timer_start(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL); } else { @@ -11996,9 +11997,6 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp, struct uio *uio, int resv_upfront) { - int left; - - left = sp->length; sp->data = m_uiotombuf(uio, M_WAITOK, sp->length, resv_upfront, 0); if (sp->data == NULL) { @@ -12427,7 +12425,8 @@ sctp_lower_sosend(struct socket *so, if (control) { if (sctp_process_cmsgs_for_init(stcb, control, &error)) { - sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_7); + sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, + SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_5); hold_tcblock = 0; stcb = NULL; goto out_unlocked; diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index 6edf33a..6fcb6d2 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -3544,7 +3544,8 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - if (sctp_free_assoc(inp, asoc, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_8) == 0) { + if (sctp_free_assoc(inp, asoc, SCTP_PCBFREE_FORCE, + SCTP_FROM_SCTP_PCB + SCTP_LOC_8) == 0) { cnt++; } } @@ -3791,13 +3792,9 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, /* assure len is set */ sin->sin_len = sizeof(struct sockaddr_in); if (set_scope) { -#ifdef SCTP_DONT_DO_PRIVADDR_SCOPE - stcb->asoc.scope.ipv4_local_scope = 1; -#else if (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) { stcb->asoc.scope.ipv4_local_scope = 1; } -#endif /* SCTP_DONT_DO_PRIVADDR_SCOPE */ } else { /* Validate the address is in scope */ if ((IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) && diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c index d8422b9..257d188 100644 --- a/sys/netinet/sctp_timer.c +++ b/sys/netinet/sctp_timer.c @@ -110,7 +110,9 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, net->dest_state |= SCTP_ADDR_PF; net->last_active = sctp_get_tick_count(); sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, + stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_TIMER + SCTP_LOC_1); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); } } @@ -153,7 +155,7 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, "Association error counter exceeded"); - inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_1; + inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_2; sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); return (1); } @@ -1046,7 +1048,7 @@ sctp_cookie_timer(struct sctp_inpcb *inp, op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, "Cookie timer expired, but no cookie"); - inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_4; + inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_3; sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); } else { #ifdef INVARIANTS diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index d252969..2a59e13 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -288,7 +288,8 @@ sctp_notify(struct sctp_inpcb *inp, SCTP_TCB_LOCK(stcb); atomic_subtract_int(&stcb->asoc.refcnt, 1); #endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */ @@ -777,7 +778,8 @@ sctp_disconnect(struct socket *so) (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3); /* No unlock tcb assoc is gone */ return (0); } @@ -862,7 +864,8 @@ sctp_disconnect(struct socket *so) SCTP_STAT_DECR_GAUGE32(sctps_currestab); } SCTP_INP_RUNLOCK(inp); - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5); return (0); } else { sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); @@ -1562,7 +1565,8 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error); /* Fill in the return id */ if (error) { - (void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6); + (void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); goto out_now; } a_id = (sctp_assoc_t *) optval; @@ -2435,17 +2439,23 @@ flags_out: /* Applies to the specific association */ paddrp->spp_flags = 0; if (net != NULL) { - int ovh; - - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - ovh = SCTP_MED_OVERHEAD; - } else { - ovh = SCTP_MED_V4_OVERHEAD; - } - paddrp->spp_hbinterval = net->heart_beat_delay; paddrp->spp_pathmaxrxt = net->failure_threshold; - paddrp->spp_pathmtu = net->mtu - ovh; + paddrp->spp_pathmtu = net->mtu; + switch (net->ro._l_addr.sa.sa_family) { +#ifdef INET + case AF_INET: + paddrp->spp_pathmtu -= SCTP_MIN_V4_OVERHEAD; + break; +#endif +#ifdef INET6 + case AF_INET6: + paddrp->spp_pathmtu -= SCTP_MIN_V4_OVERHEAD; + break; +#endif + default: + break; + } /* get flags for HB */ if (net->dest_state & SCTP_ADDR_NOHB) { paddrp->spp_flags |= SPP_HB_DISABLE; @@ -2475,7 +2485,7 @@ flags_out: * value */ paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure; - paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc); + paddrp->spp_pathmtu = 0; if (stcb->asoc.default_dscp & 0x01) { paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc; paddrp->spp_flags |= SPP_DSCP; @@ -2611,6 +2621,20 @@ flags_out: paddri->spinfo_rto = net->RTO; paddri->spinfo_assoc_id = sctp_get_associd(stcb); paddri->spinfo_mtu = net->mtu; + switch (addr->sa_family) { +#if defined(INET) + case AF_INET: + paddri->spinfo_mtu -= SCTP_MIN_V4_OVERHEAD; + break; +#endif +#if defined(INET6) + case AF_INET6: + paddri->spinfo_mtu -= SCTP_MIN_OVERHEAD; + break; +#endif + default: + break; + } SCTP_TCB_UNLOCK(stcb); *optsize = sizeof(struct sctp_paddrinfo); } else { @@ -2687,6 +2711,20 @@ flags_out: sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT; sstat->sstat_primary.spinfo_rto = net->RTO; sstat->sstat_primary.spinfo_mtu = net->mtu; + switch (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family) { +#if defined(INET) + case AF_INET: + sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_V4_OVERHEAD; + break; +#endif +#if defined(INET6) + case AF_INET6: + sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_OVERHEAD; + break; +#endif + default: + break; + } sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb); SCTP_TCB_UNLOCK(stcb); *optsize = sizeof(struct sctp_status); @@ -4785,7 +4823,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9); + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); } else { /* @@ -5184,26 +5222,13 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } if (stcb != NULL) { /************************TCB SPECIFIC SET ******************/ - /* - * do we change the timer for HB, we run - * only one? - */ - int ovh = 0; - - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - ovh = SCTP_MED_OVERHEAD; - } else { - ovh = SCTP_MED_V4_OVERHEAD; - } - - /* network sets ? */ if (net != NULL) { /************************NET SPECIFIC SET ******************/ if (paddrp->spp_flags & SPP_HB_DISABLE) { if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) && !(net->dest_state & SCTP_ADDR_NOHB)) { sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9); } net->dest_state |= SCTP_ADDR_NOHB; } @@ -5227,10 +5252,24 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11); } net->dest_state |= SCTP_ADDR_NO_PMTUD; - net->mtu = paddrp->spp_pathmtu + ovh; + net->mtu = paddrp->spp_pathmtu; + switch (net->ro._l_addr.sa.sa_family) { +#ifdef INET + case AF_INET: + net->mtu += SCTP_MIN_V4_OVERHEAD; + break; +#endif +#ifdef INET6 + case AF_INET6: + net->mtu += SCTP_MIN_OVERHEAD; + break; +#endif + default: + break; + } if (net->mtu < stcb->asoc.smallest_mtu) { sctp_pathmtu_adjustment(stcb, net->mtu); } @@ -5251,7 +5290,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, (net->error_count > net->pf_threshold)) { net->dest_state |= SCTP_ADDR_PF; sctp_send_hb(stcb, net, SCTP_SO_LOCKED); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, + stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); } } @@ -5294,7 +5335,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, (net->error_count > net->pf_threshold)) { net->dest_state |= SCTP_ADDR_PF; sctp_send_hb(stcb, net, SCTP_SO_LOCKED); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, + stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_13); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); } } @@ -5329,7 +5372,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, net->dest_state &= ~SCTP_ADDR_NOHB; } sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_14); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); } sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); @@ -5339,7 +5382,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if (!(net->dest_state & SCTP_ADDR_NOHB)) { net->dest_state |= SCTP_ADDR_NOHB; if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, + inp, stcb, net, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_15); } } } @@ -5349,10 +5394,24 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, - SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_16); } net->dest_state |= SCTP_ADDR_NO_PMTUD; - net->mtu = paddrp->spp_pathmtu + ovh; + net->mtu = paddrp->spp_pathmtu; + switch (net->ro._l_addr.sa.sa_family) { +#ifdef INET + case AF_INET: + net->mtu += SCTP_MIN_V4_OVERHEAD; + break; +#endif +#ifdef INET6 + case AF_INET6: + net->mtu += SCTP_MIN_OVERHEAD; + break; +#endif + default: + break; + } if (net->mtu < stcb->asoc.smallest_mtu) { sctp_pathmtu_adjustment(stcb, net->mtu); } @@ -6199,7 +6258,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, (net->error_count <= net->failure_threshold)) { net->dest_state |= SCTP_ADDR_PF; sctp_send_hb(stcb, net, SCTP_SO_LOCKED); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, + stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_17); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); } } @@ -6228,7 +6289,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, (net->error_count <= net->failure_threshold)) { net->dest_state |= SCTP_ADDR_PF; sctp_send_hb(stcb, net, SCTP_SO_LOCKED); - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, + stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_18); sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); } } @@ -7127,7 +7190,8 @@ sctp_accept(struct socket *so, struct sockaddr **addr) } if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { SCTP_TCB_LOCK(stcb); - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_19); } return (0); } diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index a30a942..24110dd 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -1449,7 +1449,7 @@ sctp_timeout_handler(void *t) struct socket *so; #endif - int did_output, type; + int did_output; tmr = (struct sctp_timer *)t; inp = (struct sctp_inpcb *)tmr->ep; @@ -1488,7 +1488,6 @@ sctp_timeout_handler(void *t) } /* if this is an iterator timeout, get the struct and clear inp */ tmr->stopped_from = 0xa003; - type = tmr->type; if (inp) { SCTP_INP_INCR_REF(inp); if ((inp->sctp_socket == NULL) && @@ -1809,7 +1808,8 @@ sctp_timeout_handler(void *t) SCTP_STAT_INCR(sctps_timoassockill); /* Can we free it yet? */ SCTP_INP_DECR_REF(inp); - sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_1); + sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL, + SCTP_FROM_SCTPUTIL + SCTP_LOC_1); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) so = SCTP_INP_SO(inp); atomic_add_int(&stcb->asoc.refcnt, 1); @@ -1818,7 +1818,8 @@ sctp_timeout_handler(void *t) SCTP_TCB_LOCK(stcb); atomic_subtract_int(&stcb->asoc.refcnt, 1); #endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_2); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTPUTIL + SCTP_LOC_2); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -1838,7 +1839,8 @@ sctp_timeout_handler(void *t) * killer */ SCTP_INP_DECR_REF(inp); - sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_3); + sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL, + SCTP_FROM_SCTPUTIL + SCTP_LOC_3); sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, SCTP_CALLED_FROM_INPKILL_TIMER); inp = NULL; @@ -1873,7 +1875,7 @@ out_decr: } out_no_decr: SCTPDBG(SCTP_DEBUG_TIMER1, "Timer now complete (type %d)\n", - type); + tmr->type); CURVNET_RESTORE(); } @@ -3910,7 +3912,8 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_4); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTPUTIL + SCTP_LOC_4); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); #endif @@ -4034,7 +4037,8 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, atomic_subtract_int(&stcb->asoc.refcnt, 1); } #endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_5); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTPUTIL + SCTP_LOC_5); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) if (!so_locked) { SCTP_SOCKET_UNLOCK(so, 1); @@ -5165,7 +5169,8 @@ sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t * freed_so_far, int hold_rlock, sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_USR_RCVD, SCTP_SO_LOCKED); /* make sure no timer is running */ - sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_6); + sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, + SCTP_FROM_SCTPUTIL + SCTP_LOC_6); SCTP_TCB_UNLOCK(stcb); } else { /* Update how much we have pending */ @@ -6323,14 +6328,16 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, (sin->sin_addr.s_addr == INADDR_BROADCAST) || IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTPUTIL + SCTP_LOC_7); *error = EINVAL; goto out_now; } if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { /* assoc gone no un-lock */ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTPUTIL + SCTP_LOC_8); *error = ENOBUFS; goto out_now; } @@ -6344,14 +6351,16 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL); - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTPUTIL + SCTP_LOC_9); *error = EINVAL; goto out_now; } if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { /* assoc gone no un-lock */ SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTPUTIL + SCTP_LOC_10); *error = ENOBUFS; goto out_now; } diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index d2570c4..fe98f0c 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -1279,6 +1279,7 @@ in6_broadcast_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, nd6_dad_start((struct ifaddr *)ia, delay); } + in6_newaddrmsg(ia, RTM_ADD); ifa_free(&ia->ia_ifa); return (error); } @@ -1327,6 +1328,7 @@ in6_purgeaddr(struct ifaddr *ifa) ia->ia_flags &= ~IFA_ROUTE; } + in6_newaddrmsg(ia, RTM_DELETE); in6_unlink_ifa(ia, ifp); } diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 83dda1a..daac188 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -2185,7 +2185,6 @@ nd6_add_ifa_lle(struct in6_ifaddr *ia) ln->la_expire = 0; /* for IPv6 this means permanent */ ln->ln_state = ND6_LLINFO_REACHABLE; LLE_WUNLOCK(ln); - in6_newaddrmsg(ia, RTM_ADD); return (0); } @@ -2205,8 +2204,6 @@ nd6_rem_ifa_lle(struct in6_ifaddr *ia) struct sockaddr_in6 mask, addr; struct ifnet *ifp; - in6_newaddrmsg(ia, RTM_DELETE); - ifp = ia->ia_ifa.ifa_ifp; memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c index f2b2322..54c65b6 100644 --- a/sys/netinet6/sctp6_usrreq.c +++ b/sys/netinet6/sctp6_usrreq.c @@ -211,7 +211,8 @@ sctp6_notify_mbuf(struct sctp_inpcb *inp, struct icmp6_hdr *icmp6, */ nxtsz = ntohl(icmp6->icmp6_mtu); /* Stop any PMTU timer */ - sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL, SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_1); + sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL, + SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_1); /* Adjust destination size limit */ if (net->mtu > nxtsz) { @@ -333,7 +334,8 @@ sctp6_notify(struct sctp_inpcb *inp, SCTP_TCB_LOCK(stcb); atomic_subtract_int(&stcb->asoc.refcnt, 1); #endif - (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_2); #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) SCTP_SOCKET_UNLOCK(so, 1); /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */ diff --git a/sys/ofed/drivers/net/mlx4/en_netdev.c b/sys/ofed/drivers/net/mlx4/en_netdev.c index 5988c0d..d8b2f4f 100644 --- a/sys/ofed/drivers/net/mlx4/en_netdev.c +++ b/sys/ofed/drivers/net/mlx4/en_netdev.c @@ -1967,6 +1967,29 @@ static int mlx4_en_ioctl(struct ifnet *dev, u_long command, caddr_t data) mutex_unlock(&mdev->state_lock); VLAN_CAPABILITIES(dev); break; + case SIOCGI2C: { + struct ifi2creq i2c; + + error = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); + if (error) + break; + if (i2c.len > sizeof(i2c.data)) { + error = EINVAL; + break; + } + /* + * Note that we ignore i2c.addr here. The driver hardcodes + * the address to 0x50, while standard expects it to be 0xA0. + */ + error = mlx4_get_module_info(mdev->dev, priv->port, + i2c.offset, i2c.len, i2c.data); + if (error < 0) { + error = -error; + break; + } + error = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); + break; + } default: error = ether_ioctl(dev, command, data); break; diff --git a/sys/ofed/drivers/net/mlx4/port.c b/sys/ofed/drivers/net/mlx4/port.c index c653d4b..4d7aa0b 100644 --- a/sys/ofed/drivers/net/mlx4/port.c +++ b/sys/ofed/drivers/net/mlx4/port.c @@ -1058,3 +1058,160 @@ int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, u } EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); +/* Cable Module Info */ +#define MODULE_INFO_MAX_READ 48 + +#define I2C_ADDR_LOW 0x50 +#define I2C_ADDR_HIGH 0x51 +#define I2C_PAGE_SIZE 256 + +/* Module Info Data */ +struct mlx4_cable_info { + u8 i2c_addr; + u8 page_num; + __be16 dev_mem_address; + __be16 reserved1; + __be16 size; + __be32 reserved2[2]; + u8 data[MODULE_INFO_MAX_READ]; +}; + +enum cable_info_err { + CABLE_INF_INV_PORT = 0x1, + CABLE_INF_OP_NOSUP = 0x2, + CABLE_INF_NOT_CONN = 0x3, + CABLE_INF_NO_EEPRM = 0x4, + CABLE_INF_PAGE_ERR = 0x5, + CABLE_INF_INV_ADDR = 0x6, + CABLE_INF_I2C_ADDR = 0x7, + CABLE_INF_QSFP_VIO = 0x8, + CABLE_INF_I2C_BUSY = 0x9, +}; + +#define MAD_STATUS_2_CABLE_ERR(mad_status) ((mad_status >> 8) & 0xFF) + +#ifdef DEBUG +static inline const char *cable_info_mad_err_str(u16 mad_status) +{ + u8 err = MAD_STATUS_2_CABLE_ERR(mad_status); + + switch (err) { + case CABLE_INF_INV_PORT: + return "invalid port selected"; + case CABLE_INF_OP_NOSUP: + return "operation not supported for this port (the port is of type CX4 or internal)"; + case CABLE_INF_NOT_CONN: + return "cable is not connected"; + case CABLE_INF_NO_EEPRM: + return "the connected cable has no EPROM (passive copper cable)"; + case CABLE_INF_PAGE_ERR: + return "page number is greater than 15"; + case CABLE_INF_INV_ADDR: + return "invalid device_address or size (that is, size equals 0 or address+size is greater than 256)"; + case CABLE_INF_I2C_ADDR: + return "invalid I2C slave address"; + case CABLE_INF_QSFP_VIO: + return "at least one cable violates the QSFP specification and ignores the modsel signal"; + case CABLE_INF_I2C_BUSY: + return "I2C bus is constantly busy"; + } + return "Unknown Error"; +} +#endif /* DEBUG */ + +/** + * mlx4_get_module_info - Read cable module eeprom data + * @dev: mlx4_dev. + * @port: port number. + * @offset: byte offset in eeprom to start reading data from. + * @size: num of bytes to read. + * @data: output buffer to put the requested data into. + * + * Reads cable module eeprom data, puts the outcome data into + * data pointer paramer. + * Returns num of read bytes on success or a negative error + * code. + */ +int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, u16 offset, + u16 size, u8 *data) +{ + struct mlx4_cmd_mailbox *inbox, *outbox; + struct mlx4_mad_ifc *inmad, *outmad; + struct mlx4_cable_info *cable_info; + u16 i2c_addr; + int ret; + + if (size > MODULE_INFO_MAX_READ) + size = MODULE_INFO_MAX_READ; + + inbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(inbox)) + return PTR_ERR(inbox); + + outbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(outbox)) { + mlx4_free_cmd_mailbox(dev, inbox); + return PTR_ERR(outbox); + } + + inmad = (struct mlx4_mad_ifc *)(inbox->buf); + outmad = (struct mlx4_mad_ifc *)(outbox->buf); + + inmad->method = 0x1; /* Get */ + inmad->class_version = 0x1; + inmad->mgmt_class = 0x1; + inmad->base_version = 0x1; + inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */ + + if (offset < I2C_PAGE_SIZE && offset + size > I2C_PAGE_SIZE) + /* Cross pages reads are not allowed + * read until offset 256 in low page + */ + size -= offset + size - I2C_PAGE_SIZE; + + i2c_addr = I2C_ADDR_LOW; + if (offset >= I2C_PAGE_SIZE) { + /* Reset offset to high page */ + i2c_addr = I2C_ADDR_HIGH; + offset -= I2C_PAGE_SIZE; + } + + cable_info = (struct mlx4_cable_info *)inmad->data; + cable_info->dev_mem_address = cpu_to_be16(offset); + cable_info->page_num = 0; + cable_info->i2c_addr = i2c_addr; + cable_info->size = cpu_to_be16(size); + + ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3, + MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); + if (ret) + goto out; + + if (be16_to_cpu(outmad->status)) { + /* Mad returned with bad status */ + ret = be16_to_cpu(outmad->status); +#ifdef DEBUG + mlx4_warn(dev, "MLX4_CMD_MAD_IFC Get Module info attr(%x) " + "port(%d) i2c_addr(%x) offset(%d) size(%d): Response " + "Mad Status(%x) - %s\n", 0xFF60, port, i2c_addr, offset, + size, ret, cable_info_mad_err_str(ret)); +#endif + if (i2c_addr == I2C_ADDR_HIGH && + MAD_STATUS_2_CABLE_ERR(ret) == CABLE_INF_I2C_ADDR) + /* Some SFP cables do not support i2c slave + * address 0x51 (high page), abort silently. + */ + ret = 0; + else + ret = -ret; + goto out; + } + cable_info = (struct mlx4_cable_info *)outmad->data; + memcpy(data, cable_info->data, size); + ret = size; +out: + mlx4_free_cmd_mailbox(dev, inbox); + mlx4_free_cmd_mailbox(dev, outbox); + return ret; +} +EXPORT_SYMBOL(mlx4_get_module_info); diff --git a/sys/ofed/include/linux/mlx4/device.h b/sys/ofed/include/linux/mlx4/device.h index 8c0db91..536c421 100644 --- a/sys/ofed/include/linux/mlx4/device.h +++ b/sys/ofed/include/linux/mlx4/device.h @@ -892,6 +892,26 @@ struct mlx4_init_port_param { u64 si_guid; }; +#define MAD_IFC_DATA_SZ 192 +/* MAD IFC Mailbox */ +struct mlx4_mad_ifc { + u8 base_version; + u8 mgmt_class; + u8 class_version; + u8 method; + __be16 status; + __be16 class_specific; + __be64 tid; + __be16 attr_id; + __be16 resv; + __be32 attr_mod; + __be64 mkey; + __be16 dr_slid; + __be16 dr_dlid; + u8 reserved[28]; + u8 data[MAD_IFC_DATA_SZ]; +} __packed; + #define mlx4_foreach_port(port, dev, type) \ for ((port) = 1; (port) <= (dev)->caps.num_ports; (port)++) \ if ((type) == (dev)->caps.port_mask[(port)]) @@ -1294,4 +1314,7 @@ int mlx4_read_clock(struct mlx4_dev *dev); int mlx4_get_internal_clock_params(struct mlx4_dev *dev, struct mlx4_clock_params *params); +int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, + u16 offset, u16 size, u8 *data); + #endif /* MLX4_DEVICE_H */ diff --git a/sys/sys/nlist_aout.h b/sys/sys/nlist_aout.h index fc7a3c7..cb3dd8591 100644 --- a/sys/sys/nlist_aout.h +++ b/sys/sys/nlist_aout.h @@ -56,8 +56,6 @@ struct nlist { } n_un; #else const char *n_name; /* symbol name (in memory) */ - int : 8 * (sizeof(long) > sizeof(char *) ? - sizeof(long) - sizeof(char *) : sizeof(char *) - sizeof(long)); #endif unsigned char n_type; /* type defines */ char n_other; /* ".type" and binding information */ diff --git a/sys/sys/param.h b/sys/sys/param.h index 960d1ca..9bd1dd7 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -58,7 +58,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1100074 /* Master, propagated to newvers */ +#define __FreeBSD_version 1100075 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, diff --git a/sys/sys/proc.h b/sys/sys/proc.h index b44d8f1..018b595 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -277,6 +277,7 @@ struct thread { u_int td_vp_reserv; /* (k) Count of reserved vnodes. */ int td_no_sleeping; /* (k) Sleeping disabled count. */ int td_dom_rr_idx; /* (k) RR Numa domain selection. */ + void *td_su; /* (k) FFS SU private */ #define td_endzero td_sigmask /* Copied during fork1() or create_thread(). */ @@ -677,6 +678,7 @@ struct proc { #define P2_INHERIT_PROTECTED 0x00000001 /* New children get P_PROTECTED. */ #define P2_NOTRACE 0x00000002 /* No ptrace(2) attach or coredumps. */ #define P2_NOTRACE_EXEC 0x00000004 /* Keep P2_NOPTRACE on exec(2). */ +#define P2_AST_SU 0x00000008 /* Handles SU ast for kthreads. */ /* Flags protected by proctree_lock, kept in p_treeflags. */ #define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */ diff --git a/sys/sys/systm.h b/sys/sys/systm.h index acea565..cb05a00 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -431,4 +431,6 @@ void free_unr(struct unrhdr *uh, u_int item); void intr_prof_stack_use(struct thread *td, struct trapframe *frame); +extern void (*softdep_ast_cleanup)(void); + #endif /* !_SYS_SYSTM_H_ */ diff --git a/sys/sys/user.h b/sys/sys/user.h index c3b3bc5..e831a37 100644 --- a/sys/sys/user.h +++ b/sys/sys/user.h @@ -486,6 +486,27 @@ struct kinfo_vmentry { }; /* + * The "vm.objects" sysctl provides a list of all VM objects in the system + * via an array of these entries. + */ +struct kinfo_vmobject { + int kvo_structsize; /* Variable size of record. */ + int kvo_type; /* Object type: KVME_TYPE_*. */ + uint64_t kvo_size; /* Object size in pages. */ + uint64_t kvo_vn_fileid; /* inode number if vnode. */ + uint32_t kvo_vn_fsid; /* dev_t of vnode location. */ + int kvo_ref_count; /* Reference count. */ + int kvo_shadow_count; /* Shadow count. */ + int kvo_memattr; /* Memory attribute. */ + uint64_t kvo_resident; /* Number of resident pages. */ + uint64_t kvo_active; /* Number of active pages. */ + uint64_t kvo_inactive; /* Number of inactive pages. */ + uint64_t _kvo_qspare[8]; + uint32_t _kvo_ispare[8]; + char kvo_path[PATH_MAX]; /* Pathname, if any. */ +}; + +/* * The KERN_PROC_KSTACK sysctl allows a process to dump the kernel stacks of * another process as a series of entries. Each stack is represented by a * series of symbol names and offsets as generated by stack_sbuf_print(9). diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index d70aa57..a30130f 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -397,6 +397,7 @@ extern int vttoif_tab[]; #define V_WAIT 0x0001 /* vn_start_write: sleep for suspend */ #define V_NOWAIT 0x0002 /* vn_start_write: don't sleep for suspend */ #define V_XSLEEP 0x0004 /* vn_start_write: just return after sleep */ +#define V_MNTREF 0x0010 /* vn_start_write: mp is already ref-ed */ #define VR_START_WRITE 0x0001 /* vfs_write_resume: start write atomically */ #define VR_NO_SUSPCLR 0x0002 /* vfs_write_resume: do not clear suspension */ diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index ab2bd41..515857d 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -900,6 +900,8 @@ static int pagedep_find(struct pagedep_hashhead *, ino_t, ufs_lbn_t, struct pagedep **); static void pause_timer(void *); static int request_cleanup(struct mount *, int); +static void schedule_cleanup(struct mount *); +static void softdep_ast_cleanup_proc(void); static int process_worklist_item(struct mount *, int, int); static void process_removes(struct vnode *); static void process_truncates(struct vnode *); @@ -921,6 +923,8 @@ static int journal_unsuspend(struct ufsmount *ump); static void softdep_prelink(struct vnode *, struct vnode *); static void add_to_journal(struct worklist *); static void remove_from_journal(struct worklist *); +static bool softdep_excess_inodes(struct ufsmount *); +static bool softdep_excess_dirrem(struct ufsmount *); static void softdep_process_journal(struct mount *, struct worklist *, int); static struct jremref *newjremref(struct dirrem *, struct inode *, struct inode *ip, off_t, nlink_t); @@ -2059,7 +2063,6 @@ retry_flush: * allocates a new structure if an existing one is not found. */ #define DEPALLOC 0x0001 /* allocate structure if lookup fails */ -#define NODELAY 0x0002 /* cannot do background work */ /* * Structures and routines associated with pagedep caching. @@ -2209,12 +2212,10 @@ inodedep_lookup(mp, inum, flags, inodedeppp) * responsible for more than our share of that usage and * we are not in a rush, request some inodedep cleanup. */ - while (dep_current[D_INODEDEP] > max_softdeps && - (flags & NODELAY) == 0 && - ump->softdep_curdeps[D_INODEDEP] > - max_softdeps / stat_flush_threads) - request_cleanup(mp, FLUSH_INODES); - FREE_LOCK(ump); + if (softdep_excess_inodes(ump)) + schedule_cleanup(mp); + else + FREE_LOCK(ump); inodedep = malloc(sizeof(struct inodedep), M_INODEDEP, M_SOFTDEP_FLAGS); workitem_alloc(&inodedep->id_list, D_INODEDEP, mp); @@ -2412,6 +2413,7 @@ softdep_initialize() bioops.io_complete = softdep_disk_write_complete; bioops.io_deallocate = softdep_deallocate_dependencies; bioops.io_countdeps = softdep_count_dependencies; + softdep_ast_cleanup = softdep_ast_cleanup_proc; /* Initialize the callout with an mtx. */ callout_init_mtx(&softdep_callout, &lk, 0); @@ -2430,6 +2432,7 @@ softdep_uninitialize() bioops.io_complete = NULL; bioops.io_deallocate = NULL; bioops.io_countdeps = NULL; + softdep_ast_cleanup = NULL; callout_drain(&softdep_callout); } @@ -4631,14 +4634,10 @@ inodedep_lookup_ip(ip) struct inode *ip; { struct inodedep *inodedep; - int dflags; KASSERT(ip->i_nlink >= ip->i_effnlink, ("inodedep_lookup_ip: bad delta")); - dflags = DEPALLOC; - if (IS_SNAPSHOT(ip)) - dflags |= NODELAY; - (void) inodedep_lookup(UFSTOVFS(ip->i_ump), ip->i_number, dflags, + (void) inodedep_lookup(UFSTOVFS(ip->i_ump), ip->i_number, DEPALLOC, &inodedep); inodedep->id_nlinkdelta = ip->i_nlink - ip->i_effnlink; KASSERT((inodedep->id_state & UNLINKED) == 0, ("inode unlinked")); @@ -4692,12 +4691,10 @@ softdep_setup_dotdot_link(dp, ip) struct inodedep *inodedep; struct jaddref *jaddref; struct vnode *dvp; - struct vnode *vp; KASSERT(MOUNTEDSOFTDEP(UFSTOVFS(dp->i_ump)) != 0, ("softdep_setup_dotdot_link called on non-softdep filesystem")); dvp = ITOV(dp); - vp = ITOV(ip); jaddref = NULL; /* * We don't set MKDIR_PARENT as this is not tied to a mkdir and @@ -5038,7 +5035,7 @@ softdep_setup_inomapdep(bp, ip, newinum, mode) M_BMSAFEMAP, M_SOFTDEP_FLAGS); workitem_alloc(&bmsafemap->sm_list, D_BMSAFEMAP, mp); ACQUIRE_LOCK(ip->i_ump); - if ((inodedep_lookup(mp, newinum, DEPALLOC | NODELAY, &inodedep))) + if ((inodedep_lookup(mp, newinum, DEPALLOC, &inodedep))) panic("softdep_setup_inomapdep: dependency %p for new" "inode already exists", inodedep); bmsafemap = bmsafemap_lookup(mp, bp, ino_to_cg(fs, newinum), bmsafemap); @@ -5335,7 +5332,7 @@ softdep_setup_allocdirect(ip, off, newblkno, oldblkno, newsize, oldsize, bp) if (freefrag && freefrag->ff_jdep != NULL && freefrag->ff_jdep->wk_type == D_JFREEFRAG) add_to_journal(freefrag->ff_jdep); - inodedep_lookup(mp, ip->i_number, DEPALLOC | NODELAY, &inodedep); + inodedep_lookup(mp, ip->i_number, DEPALLOC, &inodedep); adp->ad_inodedep = inodedep; WORKLIST_INSERT(&bp->b_dep, &newblk->nb_list); @@ -5693,7 +5690,7 @@ softdep_setup_allocext(ip, off, newblkno, oldblkno, newsize, oldsize, bp) if (freefrag && freefrag->ff_jdep != NULL && freefrag->ff_jdep->wk_type == D_JFREEFRAG) add_to_journal(freefrag->ff_jdep); - inodedep_lookup(mp, ip->i_number, DEPALLOC | NODELAY, &inodedep); + inodedep_lookup(mp, ip->i_number, DEPALLOC, &inodedep); adp->ad_inodedep = inodedep; WORKLIST_INSERT(&bp->b_dep, &newblk->nb_list); @@ -5818,7 +5815,6 @@ softdep_setup_allocindir_page(ip, lbn, bp, ptrno, newblkno, oldblkno, nbp) struct allocindir *aip; struct pagedep *pagedep; struct mount *mp; - int dflags; mp = UFSTOVFS(ip->i_ump); KASSERT(MOUNTEDSOFTDEP(mp) != 0, @@ -5831,10 +5827,7 @@ softdep_setup_allocindir_page(ip, lbn, bp, ptrno, newblkno, oldblkno, nbp) "lbn %jd", ip->i_number, newblkno, oldblkno, lbn); ASSERT_VOP_LOCKED(ITOV(ip), "softdep_setup_allocindir_page"); aip = newallocindir(ip, ptrno, newblkno, oldblkno, lbn); - dflags = DEPALLOC; - if (IS_SNAPSHOT(ip)) - dflags |= NODELAY; - (void) inodedep_lookup(mp, ip->i_number, dflags, &inodedep); + (void) inodedep_lookup(mp, ip->i_number, DEPALLOC, &inodedep); /* * If we are allocating a directory page, then we must * allocate an associated pagedep to track additions and @@ -5864,7 +5857,6 @@ softdep_setup_allocindir_meta(nbp, ip, bp, ptrno, newblkno) struct inodedep *inodedep; struct allocindir *aip; ufs_lbn_t lbn; - int dflags; KASSERT(MOUNTEDSOFTDEP(UFSTOVFS(ip->i_ump)) != 0, ("softdep_setup_allocindir_meta called on non-softdep filesystem")); @@ -5874,10 +5866,8 @@ softdep_setup_allocindir_meta(nbp, ip, bp, ptrno, newblkno) lbn = nbp->b_lblkno; ASSERT_VOP_LOCKED(ITOV(ip), "softdep_setup_allocindir_meta"); aip = newallocindir(ip, ptrno, newblkno, 0, lbn); - dflags = DEPALLOC; - if (IS_SNAPSHOT(ip)) - dflags |= NODELAY; - inodedep_lookup(UFSTOVFS(ip->i_ump), ip->i_number, dflags, &inodedep); + inodedep_lookup(UFSTOVFS(ip->i_ump), ip->i_number, DEPALLOC, + &inodedep); WORKLIST_INSERT(&nbp->b_dep, &aip->ai_block.nb_list); if (setup_allocindir_phase2(bp, ip, inodedep, aip, lbn)) panic("softdep_setup_allocindir_meta: Block already existed"); @@ -6490,7 +6480,7 @@ softdep_journal_freeblocks(ip, cred, length, flags) struct mount *mp; ufs2_daddr_t extblocks, datablocks; ufs_lbn_t tmpval, lbn, lastlbn; - int frags, lastoff, iboff, allocblock, needj, dflags, error, i; + int frags, lastoff, iboff, allocblock, needj, error, i; fs = ip->i_fs; ump = ip->i_ump; @@ -6511,10 +6501,7 @@ softdep_journal_freeblocks(ip, cred, length, flags) * we don't need to journal the block frees. The canceled journals * for the allocations will suffice. */ - dflags = DEPALLOC; - if (IS_SNAPSHOT(ip)) - dflags |= NODELAY; - inodedep_lookup(mp, ip->i_number, dflags, &inodedep); + inodedep_lookup(mp, ip->i_number, DEPALLOC, &inodedep); if ((inodedep->id_state & (UNLINKED | DEPCOMPLETE)) == UNLINKED && length == 0) needj = 0; @@ -6644,7 +6631,7 @@ softdep_journal_freeblocks(ip, cred, length, flags) *((struct ufs2_dinode *)bp->b_data + ino_to_fsbo(fs, ip->i_number)) = *ip->i_din2; ACQUIRE_LOCK(ump); - (void) inodedep_lookup(mp, ip->i_number, dflags, &inodedep); + (void) inodedep_lookup(mp, ip->i_number, DEPALLOC, &inodedep); if ((inodedep->id_state & IOSTARTED) != 0) panic("softdep_setup_freeblocks: inode busy"); /* @@ -6737,7 +6724,7 @@ softdep_journal_freeblocks(ip, cred, length, flags) } ACQUIRE_LOCK(ump); - inodedep_lookup(mp, ip->i_number, dflags, &inodedep); + inodedep_lookup(mp, ip->i_number, DEPALLOC, &inodedep); TAILQ_INSERT_TAIL(&inodedep->id_freeblklst, freeblks, fb_next); freeblks->fb_state |= DEPCOMPLETE | ONDEPLIST; /* @@ -6828,7 +6815,7 @@ softdep_setup_freeblocks(ip, length, flags) struct fs *fs; ufs2_daddr_t extblocks, datablocks; struct mount *mp; - int i, delay, error, dflags; + int i, delay, error; ufs_lbn_t tmpval; ufs_lbn_t lbn; @@ -6897,10 +6884,7 @@ softdep_setup_freeblocks(ip, length, flags) * Find and eliminate any inode dependencies. */ ACQUIRE_LOCK(ump); - dflags = DEPALLOC; - if (IS_SNAPSHOT(ip)) - dflags |= NODELAY; - (void) inodedep_lookup(mp, ip->i_number, dflags, &inodedep); + (void) inodedep_lookup(mp, ip->i_number, DEPALLOC, &inodedep); if ((inodedep->id_state & IOSTARTED) != 0) panic("softdep_setup_freeblocks: inode busy"); /* @@ -7066,7 +7050,6 @@ trunc_dependencies(ip, freeblks, lastlbn, lastoff, flags) struct bufobj *bo; struct vnode *vp; struct buf *bp; - struct fs *fs; int blkoff; /* @@ -7075,7 +7058,6 @@ trunc_dependencies(ip, freeblks, lastlbn, lastoff, flags) * Once they are all there, walk the list and get rid of * any dependencies. */ - fs = ip->i_fs; vp = ITOV(ip); bo = &vp->v_bufobj; BO_LOCK(bo); @@ -8506,7 +8488,7 @@ softdep_setup_directory_add(bp, dp, diroffset, newinum, newdirbp, isnewblk) dap->da_pagedep = pagedep; LIST_INSERT_HEAD(&pagedep->pd_diraddhd[DIRADDHASH(offset)], dap, da_pdlist); - inodedep_lookup(mp, newinum, DEPALLOC | NODELAY, &inodedep); + inodedep_lookup(mp, newinum, DEPALLOC, &inodedep); /* * If we're journaling, link the diradd into the jaddref so it * may be completed after the journal entry is written. Otherwise, @@ -9126,13 +9108,12 @@ newdirrem(bp, dp, ip, isrmdir, prevdirremp) * the number of freefile and freeblks structures. */ ACQUIRE_LOCK(ip->i_ump); - while (!IS_SNAPSHOT(ip) && dep_current[D_DIRREM] > max_softdeps / 2 && - ip->i_ump->softdep_curdeps[D_DIRREM] > - (max_softdeps / 2) / stat_flush_threads) - (void) request_cleanup(ITOV(dp)->v_mount, FLUSH_BLOCKS); - FREE_LOCK(ip->i_ump); - dirrem = malloc(sizeof(struct dirrem), - M_DIRREM, M_SOFTDEP_FLAGS|M_ZERO); + if (!IS_SNAPSHOT(ip) && softdep_excess_dirrem(ip->i_ump)) + schedule_cleanup(ITOV(dp)->v_mount); + else + FREE_LOCK(ip->i_ump); + dirrem = malloc(sizeof(struct dirrem), M_DIRREM, M_SOFTDEP_FLAGS | + M_ZERO); workitem_alloc(&dirrem->dm_list, D_DIRREM, dvp->v_mount); LIST_INIT(&dirrem->dm_jremrefhd); LIST_INIT(&dirrem->dm_jwork); @@ -9368,7 +9349,7 @@ softdep_setup_directory_change(bp, dp, ip, newinum, isrmdir) * inode is not yet written. If it is written, do the post-inode * write processing to put it on the id_pendinghd list. */ - inodedep_lookup(mp, newinum, DEPALLOC | NODELAY, &inodedep); + inodedep_lookup(mp, newinum, DEPALLOC, &inodedep); if (MOUNTEDSUJ(mp)) { jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, inoreflst); @@ -9410,15 +9391,12 @@ softdep_change_linkcnt(ip) struct inode *ip; /* the inode with the increased link count */ { struct inodedep *inodedep; - int dflags; KASSERT(MOUNTEDSOFTDEP(UFSTOVFS(ip->i_ump)) != 0, ("softdep_change_linkcnt called on non-softdep filesystem")); ACQUIRE_LOCK(ip->i_ump); - dflags = DEPALLOC; - if (IS_SNAPSHOT(ip)) - dflags |= NODELAY; - inodedep_lookup(UFSTOVFS(ip->i_ump), ip->i_number, dflags, &inodedep); + inodedep_lookup(UFSTOVFS(ip->i_ump), ip->i_number, DEPALLOC, + &inodedep); if (ip->i_nlink < ip->i_effnlink) panic("softdep_change_linkcnt: bad delta"); inodedep->id_nlinkdelta = ip->i_nlink - ip->i_effnlink; @@ -9511,12 +9489,10 @@ handle_written_sbdep(sbdep, bp) struct buf *bp; { struct inodedep *inodedep; - struct mount *mp; struct fs *fs; LOCK_OWNED(sbdep->sb_ump); fs = sbdep->sb_fs; - mp = UFSTOVFS(sbdep->sb_ump); /* * If the superblock doesn't match the in-memory list start over. */ @@ -13269,6 +13245,92 @@ retry: return (1); } +static bool +softdep_excess_inodes(struct ufsmount *ump) +{ + + return (dep_current[D_INODEDEP] > max_softdeps && + ump->softdep_curdeps[D_INODEDEP] > max_softdeps / + stat_flush_threads); +} + +static bool +softdep_excess_dirrem(struct ufsmount *ump) +{ + + return (dep_current[D_DIRREM] > max_softdeps / 2 && + ump->softdep_curdeps[D_DIRREM] > (max_softdeps / 2) / + stat_flush_threads); +} + +static void +schedule_cleanup(struct mount *mp) +{ + struct ufsmount *ump; + struct thread *td; + + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + FREE_LOCK(ump); + td = curthread; + if ((td->td_pflags & TDP_KTHREAD) != 0 && + (td->td_proc->p_flag2 & P2_AST_SU) == 0) { + /* + * No ast is delivered to kernel threads, so nobody + * would deref the mp. Some kernel threads + * explicitely check for AST, e.g. NFS daemon does + * this in the serving loop. + */ + return; + } + if (td->td_su != NULL) + vfs_rel(td->td_su); + vfs_ref(mp); + td->td_su = mp; + thread_lock(td); + td->td_flags |= TDF_ASTPENDING; + thread_unlock(td); +} + +static void +softdep_ast_cleanup_proc(void) +{ + struct thread *td; + struct mount *mp; + struct ufsmount *ump; + int error; + bool req; + + td = curthread; + mp = td->td_su; + if (mp == NULL) + return; + td->td_su = NULL; + error = vfs_busy(mp, MBF_NOWAIT); + vfs_rel(mp); + if (error != 0) + return; + if (ffs_own_mount(mp) && MOUNTEDSOFTDEP(mp)) { + ump = VFSTOUFS(mp); + for (;;) { + req = false; + ACQUIRE_LOCK(ump); + if (softdep_excess_inodes(ump)) { + req = true; + request_cleanup(mp, FLUSH_INODES); + } + if (softdep_excess_dirrem(ump)) { + req = true; + request_cleanup(mp, FLUSH_BLOCKS); + } + FREE_LOCK(ump); + if ((td->td_pflags & TDP_KTHREAD) != 0 || !req) + break; + } + } + vfs_unbusy(mp); +} + /* * If memory utilization has gotten too high, deliberately slow things * down and speed up the I/O processing. @@ -13355,7 +13417,8 @@ request_cleanup(mp, resource) callout_reset(&softdep_callout, tickdelay > 2 ? tickdelay : 2, pause_timer, 0); - msleep((caddr_t)&proc_waiting, &lk, PPAUSE, "softupdate", 0); + if ((td->td_pflags & TDP_KTHREAD) == 0) + msleep((caddr_t)&proc_waiting, &lk, PPAUSE, "softupdate", 0); proc_waiting -= 1; FREE_GBLLOCK(&lk); ACQUIRE_LOCK(ump); diff --git a/sys/ufs/ffs/ffs_suspend.c b/sys/ufs/ffs/ffs_suspend.c index b50fadc..450282c 100644 --- a/sys/ufs/ffs/ffs_suspend.c +++ b/sys/ufs/ffs/ffs_suspend.c @@ -177,7 +177,6 @@ out: static int ffs_susp_suspend(struct mount *mp) { - struct fs *fs; struct ufsmount *ump; int error; @@ -189,7 +188,6 @@ ffs_susp_suspend(struct mount *mp) return (EBUSY); ump = VFSTOUFS(mp); - fs = ump->um_fs; /* * Make sure the calling thread is permitted to access the mounted diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 2a368bd..ce43bcd 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -1486,7 +1486,7 @@ ffs_sync(mp, waitfor) struct inode *ip; struct ufsmount *ump = VFSTOUFS(mp); struct fs *fs; - int error, count, wait, lockreq, allerror = 0; + int error, count, lockreq, allerror = 0; int suspend; int suspended; int secondary_writes; @@ -1495,7 +1495,6 @@ ffs_sync(mp, waitfor) int softdep_accdeps; struct bufobj *bo; - wait = 0; suspend = 0; suspended = 0; td = curthread; @@ -1517,10 +1516,8 @@ ffs_sync(mp, waitfor) suspend = 1; waitfor = MNT_WAIT; } - if (waitfor == MNT_WAIT) { - wait = 1; + if (waitfor == MNT_WAIT) lockreq = LK_EXCLUSIVE; - } lockreq |= LK_INTERLOCK | LK_SLEEPFAIL; loop: /* Grab snapshot of secondary write counts */ @@ -2024,7 +2021,6 @@ static int ffs_bufwrite(struct buf *bp) { struct buf *newbp; - int oldflags; CTR3(KTR_BUF, "bufwrite(%p) vp %p flags %X", bp, bp->b_vp, bp->b_flags); if (bp->b_flags & B_INVAL) { @@ -2032,8 +2028,6 @@ ffs_bufwrite(struct buf *bp) return (0); } - oldflags = bp->b_flags; - if (!BUF_ISLOCKED(bp)) panic("bufwrite: buffer is not busy???"); /* diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index 6b34a40..80f3269 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -1366,11 +1366,6 @@ struct vop_openextattr_args { }; */ { - struct inode *ip; - struct fs *fs; - - ip = VTOI(ap->a_vp); - fs = ip->i_fs; if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) return (EOPNOTSUPP); @@ -1394,11 +1389,6 @@ struct vop_closeextattr_args { }; */ { - struct inode *ip; - struct fs *fs; - - ip = VTOI(ap->a_vp); - fs = ip->i_fs; if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) return (EOPNOTSUPP); @@ -1512,13 +1502,11 @@ vop_getextattr { */ { struct inode *ip; - struct fs *fs; u_char *eae, *p; unsigned easize; int error, ealen; ip = VTOI(ap->a_vp); - fs = ip->i_fs; if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) return (EOPNOTSUPP); @@ -1567,14 +1555,12 @@ vop_listextattr { */ { struct inode *ip; - struct fs *fs; u_char *eae, *p, *pe, *pn; unsigned easize; uint32_t ul; int error, ealen; ip = VTOI(ap->a_vp); - fs = ip->i_fs; if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) return (EOPNOTSUPP); diff --git a/sys/ufs/ufs/ufs_bmap.c b/sys/ufs/ufs/ufs_bmap.c index 22887c8..9819ef5 100644 --- a/sys/ufs/ufs/ufs_bmap.c +++ b/sys/ufs/ufs/ufs_bmap.c @@ -114,7 +114,6 @@ ufs_bmaparray(vp, bn, bnp, nbp, runp, runb) struct buf *bp; struct ufsmount *ump; struct mount *mp; - struct vnode *devvp; struct indir a[NIADDR+1], *ap; ufs2_daddr_t daddr; ufs_lbn_t metalbn; @@ -125,7 +124,6 @@ ufs_bmaparray(vp, bn, bnp, nbp, runp, runb) ip = VTOI(vp); mp = vp->v_mount; ump = VFSTOUFS(mp); - devvp = ump->um_devvp; if (runp) { maxrun = mp->mnt_iosize_max / mp->mnt_stat.f_iosize - 1; diff --git a/sys/ufs/ufs/ufs_dirhash.c b/sys/ufs/ufs/ufs_dirhash.c index 39f29d0..766fe54 100644 --- a/sys/ufs/ufs/ufs_dirhash.c +++ b/sys/ufs/ufs/ufs_dirhash.c @@ -190,9 +190,7 @@ ufsdirhash_create(struct inode *ip) struct dirhash *ndh; struct dirhash *dh; struct vnode *vp; - int error; - error = 0; ndh = dh = NULL; vp = ip->i_vnode; for (;;) { @@ -274,11 +272,9 @@ static struct dirhash * ufsdirhash_acquire(struct inode *ip) { struct dirhash *dh; - struct vnode *vp; ASSERT_VOP_ELOCKED(ip->i_vnode, __FUNCTION__); - vp = ip->i_vnode; dh = ip->i_dirhash; if (dh == NULL) return (NULL); diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index 78cea70..30623b2 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -79,6 +79,7 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <sys/resourcevar.h> #include <sys/rwlock.h> +#include <sys/user.h> #include <sys/vnode.h> #include <sys/vmmeter.h> #include <sys/sx.h> @@ -2286,6 +2287,142 @@ next_page: } } +static int +sysctl_vm_object_list(SYSCTL_HANDLER_ARGS) +{ + struct kinfo_vmobject kvo; + char *fullpath, *freepath; + struct vnode *vp; + struct vattr va; + vm_object_t obj; + vm_page_t m; + int count, error; + + if (req->oldptr == NULL) { + /* + * If an old buffer has not been provided, generate an + * estimate of the space needed for a subsequent call. + */ + mtx_lock(&vm_object_list_mtx); + count = 0; + TAILQ_FOREACH(obj, &vm_object_list, object_list) { + if (obj->type == OBJT_DEAD) + continue; + count++; + } + mtx_unlock(&vm_object_list_mtx); + return (SYSCTL_OUT(req, NULL, sizeof(struct kinfo_vmobject) * + count * 11 / 10)); + } + + error = 0; + + /* + * VM objects are type stable and are never removed from the + * list once added. This allows us to safely read obj->object_list + * after reacquiring the VM object lock. + */ + mtx_lock(&vm_object_list_mtx); + TAILQ_FOREACH(obj, &vm_object_list, object_list) { + if (obj->type == OBJT_DEAD) + continue; + VM_OBJECT_RLOCK(obj); + if (obj->type == OBJT_DEAD) { + VM_OBJECT_RUNLOCK(obj); + continue; + } + mtx_unlock(&vm_object_list_mtx); + kvo.kvo_size = ptoa(obj->size); + kvo.kvo_resident = obj->resident_page_count; + kvo.kvo_ref_count = obj->ref_count; + kvo.kvo_shadow_count = obj->shadow_count; + kvo.kvo_memattr = obj->memattr; + kvo.kvo_active = 0; + kvo.kvo_inactive = 0; + TAILQ_FOREACH(m, &obj->memq, listq) { + /* + * A page may belong to the object but be + * dequeued and set to PQ_NONE while the + * object lock is not held. This makes the + * reads of m->queue below racy, and we do not + * count pages set to PQ_NONE. However, this + * sysctl is only meant to give an + * approximation of the system anyway. + */ + if (m->queue == PQ_ACTIVE) + kvo.kvo_active++; + else if (m->queue == PQ_INACTIVE) + kvo.kvo_inactive++; + } + + kvo.kvo_vn_fileid = 0; + kvo.kvo_vn_fsid = 0; + freepath = NULL; + fullpath = ""; + vp = NULL; + switch (obj->type) { + case OBJT_DEFAULT: + kvo.kvo_type = KVME_TYPE_DEFAULT; + break; + case OBJT_VNODE: + kvo.kvo_type = KVME_TYPE_VNODE; + vp = obj->handle; + vref(vp); + break; + case OBJT_SWAP: + kvo.kvo_type = KVME_TYPE_SWAP; + break; + case OBJT_DEVICE: + kvo.kvo_type = KVME_TYPE_DEVICE; + break; + case OBJT_PHYS: + kvo.kvo_type = KVME_TYPE_PHYS; + break; + case OBJT_DEAD: + kvo.kvo_type = KVME_TYPE_DEAD; + break; + case OBJT_SG: + kvo.kvo_type = KVME_TYPE_SG; + break; + case OBJT_MGTDEVICE: + kvo.kvo_type = KVME_TYPE_MGTDEVICE; + break; + default: + kvo.kvo_type = KVME_TYPE_UNKNOWN; + break; + } + VM_OBJECT_RUNLOCK(obj); + if (vp != NULL) { + vn_fullpath(curthread, vp, &fullpath, &freepath); + vn_lock(vp, LK_SHARED | LK_RETRY); + if (VOP_GETATTR(vp, &va, curthread->td_ucred) == 0) { + kvo.kvo_vn_fileid = va.va_fileid; + kvo.kvo_vn_fsid = va.va_fsid; + } + vput(vp); + } + + strlcpy(kvo.kvo_path, fullpath, sizeof(kvo.kvo_path)); + if (freepath != NULL) + free(freepath, M_TEMP); + + /* Pack record size down */ + kvo.kvo_structsize = offsetof(struct kinfo_vmobject, kvo_path) + + strlen(kvo.kvo_path) + 1; + kvo.kvo_structsize = roundup(kvo.kvo_structsize, + sizeof(uint64_t)); + error = SYSCTL_OUT(req, &kvo, kvo.kvo_structsize); + mtx_lock(&vm_object_list_mtx); + if (error) + break; + } + mtx_unlock(&vm_object_list_mtx); + return (error); +} +SYSCTL_PROC(_vm, OID_AUTO, objects, CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_SKIP | + CTLFLAG_MPSAFE, NULL, 0, sysctl_vm_object_list, "S,kinfo_vmobject", + "List of VM objects"); + #include "opt_ddb.h" #ifdef DDB #include <sys/kernel.h> diff --git a/sys/x86/iommu/busdma_dmar.c b/sys/x86/iommu/busdma_dmar.c index 96b0bce..3ef8107 100644 --- a/sys/x86/iommu/busdma_dmar.c +++ b/sys/x86/iommu/busdma_dmar.c @@ -818,7 +818,6 @@ dmar_bus_task_dmamap(void *arg, int pending) struct bus_dma_tag_dmar *tag; struct bus_dmamap_dmar *map; struct dmar_unit *unit; - struct dmar_ctx *ctx; unit = arg; DMAR_LOCK(unit); @@ -826,7 +825,6 @@ dmar_bus_task_dmamap(void *arg, int pending) TAILQ_REMOVE(&unit->delayed_maps, map, delay_link); DMAR_UNLOCK(unit); tag = map->tag; - ctx = map->tag->ctx; map->cansleep = true; map->locked = false; bus_dmamap_load_mem((bus_dma_tag_t)tag, (bus_dmamap_t)map, @@ -847,9 +845,7 @@ dmar_bus_task_dmamap(void *arg, int pending) static void dmar_bus_schedule_dmamap(struct dmar_unit *unit, struct bus_dmamap_dmar *map) { - struct dmar_ctx *ctx; - ctx = map->tag->ctx; map->locked = false; DMAR_LOCK(unit); TAILQ_INSERT_TAIL(&unit->delayed_maps, map, delay_link); diff --git a/sys/x86/iommu/intel_idpgtbl.c b/sys/x86/iommu/intel_idpgtbl.c index 6621b17..b9492dd 100644 --- a/sys/x86/iommu/intel_idpgtbl.c +++ b/sys/x86/iommu/intel_idpgtbl.c @@ -108,7 +108,7 @@ static void ctx_idmap_nextlvl(struct idpgtbl *tbl, int lvl, vm_pindex_t idx, dmar_gaddr_t addr) { - vm_page_t m, m1; + vm_page_t m1; dmar_pte_t *pte; struct sf_buf *sf; dmar_gaddr_t f, pg_sz; @@ -118,7 +118,7 @@ ctx_idmap_nextlvl(struct idpgtbl *tbl, int lvl, vm_pindex_t idx, VM_OBJECT_ASSERT_LOCKED(tbl->pgtbl_obj); if (addr >= tbl->maxaddr) return; - m = dmar_pgalloc(tbl->pgtbl_obj, idx, DMAR_PGF_OBJL | DMAR_PGF_WAITOK | + (void)dmar_pgalloc(tbl->pgtbl_obj, idx, DMAR_PGF_OBJL | DMAR_PGF_WAITOK | DMAR_PGF_ZERO); base = idx * DMAR_NPTEPG + 1; /* Index of the first child page of idx */ pg_sz = pglvl_page_size(tbl->pglvl, lvl); @@ -598,7 +598,7 @@ ctx_unmap_buf_locked(struct dmar_ctx *ctx, dmar_gaddr_t base, dmar_pte_t *pte; struct sf_buf *sf; vm_pindex_t idx; - dmar_gaddr_t pg_sz, base1, size1; + dmar_gaddr_t pg_sz; int lvl; DMAR_CTX_ASSERT_PGLOCKED(ctx); @@ -625,8 +625,6 @@ ctx_unmap_buf_locked(struct dmar_ctx *ctx, dmar_gaddr_t base, KASSERT((flags & ~DMAR_PGF_WAITOK) == 0, ("invalid flags %x", flags)); pg_sz = 0; /* silence gcc */ - base1 = base; - size1 = size; flags |= DMAR_PGF_OBJL; TD_PREP_PINNED_ASSERT; diff --git a/sys/x86/iommu/intel_qi.c b/sys/x86/iommu/intel_qi.c index ce7b041..293e2be 100644 --- a/sys/x86/iommu/intel_qi.c +++ b/sys/x86/iommu/intel_qi.c @@ -411,6 +411,7 @@ dmar_init_qi(struct dmar_unit *unit) ics = DMAR_ICS_IWC; dmar_write4(unit, DMAR_ICS_REG, ics); } + dmar_enable_qi_intr(unit); DMAR_UNLOCK(unit); return (0); @@ -434,6 +435,7 @@ dmar_fini_qi(struct dmar_unit *unit) dmar_qi_advance_tail(unit); dmar_qi_wait_for_seq(unit, &gseq, false); /* only after the quisce, disable queue */ + dmar_disable_qi_intr(unit); dmar_disable_qi(unit); KASSERT(unit->inv_seq_waiters == 0, ("dmar%d: waiters on disabled queue", unit->unit)); diff --git a/tests/sys/kern/ptrace_test.c b/tests/sys/kern/ptrace_test.c index 6bd5eeb..321dc82 100644 --- a/tests/sys/kern/ptrace_test.c +++ b/tests/sys/kern/ptrace_test.c @@ -224,9 +224,9 @@ ATF_TC_BODY(ptrace__parent_sees_exit_after_child_debugger, tc) } /* - * This wait should return an empty pid. The parent should - * see the child as non-exited until the debugger sees the - * exit. + * This wait should return a pid of 0 to indicate no status to + * report. The parent should see the child as non-exited + * until the debugger sees the exit. */ wpid = waitpid(child, &status, WNOHANG); ATF_REQUIRE(wpid == 0); @@ -357,9 +357,9 @@ ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc) } /* - * This wait should return an empty pid. The parent should - * see the child as non-exited until the debugger sees the - * exit. + * This wait should return a pid of 0 to indicate no status to + * report. The parent should see the child as non-exited + * until the debugger sees the exit. */ wpid = waitpid(child, &status, WNOHANG); ATF_REQUIRE(wpid == 0); diff --git a/usr.bin/vmstat/vmstat.8 b/usr.bin/vmstat/vmstat.8 index 4566ad2..93e75b9 100644 --- a/usr.bin/vmstat/vmstat.8 +++ b/usr.bin/vmstat/vmstat.8 @@ -37,7 +37,7 @@ .Sh SYNOPSIS .Nm .\" .Op Fl fimst -.Op Fl afHhimPsz +.Op Fl afHhimoPsz .Op Fl M Ar core Op Fl N Ar system .Op Fl c Ar count .Op Fl n Ar devs @@ -119,6 +119,9 @@ Report on the usage of kernel dynamic memory allocated using by type. .It Fl n Change the maximum number of disks to display from the default of 2. +.It Fl o +Display a list of virtual memory objects in the system and the resident +memory used by each object. .It Fl P Report per-cpu system/user/idle cpu statistics. .It Fl p diff --git a/usr.bin/vmstat/vmstat.c b/usr.bin/vmstat/vmstat.c index 9049e44..0a3054a 100644 --- a/usr.bin/vmstat/vmstat.c +++ b/usr.bin/vmstat/vmstat.c @@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$"); #include <sys/resource.h> #include <sys/sysctl.h> #include <sys/time.h> +#include <sys/user.h> #include <sys/vmmeter.h> #include <sys/pcpu.h> @@ -143,12 +144,14 @@ static kvm_t *kd; #define TIMESTAT 0x10 #define VMSTAT 0x20 #define ZMEMSTAT 0x40 +#define OBJSTAT 0x80 static void cpustats(void); static void pcpustats(int, u_long, int); static void devstats(void); static void doforkst(void); static void dointr(unsigned int, int); +static void doobjstat(void); static void dosum(void); static void dovmstat(unsigned int, int); static void domemstat_malloc(void); @@ -181,7 +184,7 @@ main(int argc, char *argv[]) interval = reps = todo = 0; maxshowdevs = 2; hflag = isatty(1); - while ((c = getopt(argc, argv, "ac:fhHiM:mN:n:Pp:stw:z")) != -1) { + while ((c = getopt(argc, argv, "ac:fhHiM:mN:n:oPp:stw:z")) != -1) { switch (c) { case 'a': aflag++; @@ -220,6 +223,9 @@ main(int argc, char *argv[]) errx(1, "number of devices %d is < 0", maxshowdevs); break; + case 'o': + todo |= OBJSTAT; + break; case 'p': if (devstat_buildmatch(optarg, &matches, &num_matches) != 0) errx(1, "%s", devstat_errbuf); @@ -320,6 +326,8 @@ retry_nlist: domemstat_zone(); if (todo & SUMSTAT) dosum(); + if (todo & OBJSTAT) + doobjstat(); #ifdef notyet if (todo & TIMESTAT) dotimes(); @@ -1396,6 +1404,129 @@ domemstat_zone(void) printf("\n"); } +static void +display_object(struct kinfo_vmobject *kvo) +{ + const char *str; + + printf("%5jd ", (uintmax_t)kvo->kvo_resident); + printf("%5jd ", (uintmax_t)kvo->kvo_active); + printf("%5jd ", (uintmax_t)kvo->kvo_inactive); + printf("%3d ", kvo->kvo_ref_count); + printf("%3d ", kvo->kvo_shadow_count); + switch (kvo->kvo_memattr) { +#ifdef VM_MEMATTR_UNCACHEABLE + case VM_MEMATTR_UNCACHEABLE: + str = "UC"; + break; +#endif +#ifdef VM_MEMATTR_WRITE_COMBINING + case VM_MEMATTR_WRITE_COMBINING: + str = "WC"; + break; +#endif +#ifdef VM_MEMATTR_WRITE_THROUGH + case VM_MEMATTR_WRITE_THROUGH: + str = "WT"; + break; +#endif +#ifdef VM_MEMATTR_WRITE_PROTECTED + case VM_MEMATTR_WRITE_PROTECTED: + str = "WP"; + break; +#endif +#ifdef VM_MEMATTR_WRITE_BACK + case VM_MEMATTR_WRITE_BACK: + str = "WB"; + break; +#endif +#ifdef VM_MEMATTR_WEAK_UNCACHEABLE + case VM_MEMATTR_WEAK_UNCACHEABLE: + str = "UC-"; + break; +#endif +#ifdef VM_MEMATTR_WB_WA + case VM_MEMATTR_WB_WA: + str = "WB"; + break; +#endif +#ifdef VM_MEMATTR_NOCACHE + case VM_MEMATTR_NOCACHE: + str = "NC"; + break; +#endif +#ifdef VM_MEMATTR_DEVICE + case VM_MEMATTR_DEVICE: + str = "DEV"; + break; +#endif +#ifdef VM_MEMATTR_CACHEABLE + case VM_MEMATTR_CACHEABLE: + str = "C"; + break; +#endif +#ifdef VM_MEMATTR_PREFETCHABLE + case VM_MEMATTR_PREFETCHABLE: + str = "PRE"; + break; +#endif + default: + str = "??"; + break; + } + printf("%-3s ", str); + switch (kvo->kvo_type) { + case KVME_TYPE_NONE: + str = "--"; + break; + case KVME_TYPE_DEFAULT: + str = "df"; + break; + case KVME_TYPE_VNODE: + str = "vn"; + break; + case KVME_TYPE_SWAP: + str = "sw"; + break; + case KVME_TYPE_DEVICE: + str = "dv"; + break; + case KVME_TYPE_PHYS: + str = "ph"; + break; + case KVME_TYPE_DEAD: + str = "dd"; + break; + case KVME_TYPE_SG: + str = "sg"; + break; + case KVME_TYPE_UNKNOWN: + default: + str = "??"; + break; + } + printf("%-2s ", str); + printf("%-s\n", kvo->kvo_path); +} + +static void +doobjstat(void) +{ + struct kinfo_vmobject *kvo; + int cnt, i; + + kvo = kinfo_getvmobject(&cnt); + if (kvo == NULL) { + warn("Failed to fetch VM object list"); + return; + } + printf("%5s %5s %5s %3s %3s %3s %2s %s\n", "RES", "ACT", "INACT", + "REF", "SHD", "CM", "TP", "PATH"); + for (i = 0; i < cnt; i++) + display_object(&kvo[i]); + free(kvo); +} + /* * kread reads something from the kernel, given its nlist index. */ @@ -1448,7 +1579,7 @@ static void usage(void) { (void)fprintf(stderr, "%s%s", - "usage: vmstat [-afHhimPsz] [-M core [-N system]] [-c count] [-n devs]\n", + "usage: vmstat [-afHhimoPsz] [-M core [-N system]] [-c count] [-n devs]\n", " [-p type,if,pass] [-w wait] [disks] [wait [count]]\n"); exit(1); } diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c index 47a7699..ee0f106 100644 --- a/usr.sbin/bhyve/bhyverun.c +++ b/usr.sbin/bhyve/bhyverun.c @@ -100,7 +100,7 @@ static struct vm_exit vmexit[VM_MAXCPU]; struct bhyvestats { uint64_t vmexit_bogus; - uint64_t vmexit_bogus_switch; + uint64_t vmexit_reqidle; uint64_t vmexit_hlt; uint64_t vmexit_pause; uint64_t vmexit_mtrap; @@ -461,6 +461,17 @@ vmexit_bogus(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) } static int +vmexit_reqidle(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) +{ + + assert(vmexit->inst_length == 0); + + stats.vmexit_reqidle++; + + return (VMEXIT_CONTINUE); +} + +static int vmexit_hlt(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu) { @@ -571,6 +582,7 @@ static vmexit_handler_t handler[VM_EXITCODE_MAX] = { [VM_EXITCODE_VMX] = vmexit_vmx, [VM_EXITCODE_SVM] = vmexit_svm, [VM_EXITCODE_BOGUS] = vmexit_bogus, + [VM_EXITCODE_REQIDLE] = vmexit_reqidle, [VM_EXITCODE_RDMSR] = vmexit_rdmsr, [VM_EXITCODE_WRMSR] = vmexit_wrmsr, [VM_EXITCODE_MTRAP] = vmexit_mtrap, diff --git a/usr.sbin/pmcstat/pmcstat.8 b/usr.sbin/pmcstat/pmcstat.8 index 6478241..25ff7a6 100644 --- a/usr.sbin/pmcstat/pmcstat.8 +++ b/usr.sbin/pmcstat/pmcstat.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 8, 2015 +.Dd May 27, 2015 .Dt PMCSTAT 8 .Os .Sh NAME @@ -246,8 +246,8 @@ Argument .Ar cpu-spec is a comma separated list of CPU numbers, or the literal .Sq * -denoting all unhalted CPUs. -The default is to allocate system mode PMCs on all unhalted +denoting all available CPUs. +The default is to allocate system mode PMCs on all available CPUs. .It Fl d Toggle between process mode PMCs measuring events for the target diff --git a/usr.sbin/pmcstat/pmcstat.c b/usr.sbin/pmcstat/pmcstat.c index c7f36bc..c51c5fa 100644 --- a/usr.sbin/pmcstat/pmcstat.c +++ b/usr.sbin/pmcstat/pmcstat.c @@ -116,11 +116,10 @@ struct pmcstat_args args; static void pmcstat_clone_event_descriptor(struct pmcstat_ev *ev, const cpuset_t *cpumask) { - int cpu, mcpu; + int cpu; struct pmcstat_ev *ev_clone; - mcpu = sizeof(*cpumask) * NBBY; - for (cpu = 0; cpu < mcpu; cpu++) { + for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { if (!CPU_ISSET(cpu, cpumask)) continue; @@ -161,6 +160,7 @@ pmcstat_get_cpumask(const char *cpuspec, cpuset_t *cpumask) CPU_SET(cpu, cpumask); s = end + strspn(end, ", \t"); } while (*s); + assert(!CPU_EMPTY(cpumask)); } void @@ -550,10 +550,10 @@ pmcstat_topexit(void) int main(int argc, char **argv) { - cpuset_t cpumask; + cpuset_t cpumask, rootmask; double interval; double duration; - int hcpu, option, npmc, ncpu; + int option, npmc; int c, check_driver_stats, current_sampling_count; int do_callchain, do_descendants, do_logproccsw, do_logprocexit; int do_print, do_read; @@ -618,14 +618,13 @@ main(int argc, char **argv) err(EX_OSERR, "ERROR: Cannot determine path of running kernel"); /* - * The initial CPU mask specifies all non-halted CPUS in the - * system. + * The initial CPU mask specifies the root mask of this process + * which is usually all CPUs in the system. */ - len = sizeof(int); - if (sysctlbyname("hw.ncpu", &ncpu, &len, NULL, 0) < 0) - err(EX_OSERR, "ERROR: Cannot determine the number of CPUs"); - for (hcpu = 0; hcpu < ncpu; hcpu++) - CPU_SET(hcpu, &cpumask); + if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, + sizeof(rootmask), &rootmask) == -1) + err(EX_OSERR, "ERROR: Cannot determine the root set of CPUs"); + CPU_COPY(&rootmask, &cpumask); while ((option = getopt(argc, argv, "CD:EF:G:M:NO:P:R:S:TWa:c:df:gk:l:m:n:o:p:qr:s:t:vw:z:")) != -1) @@ -642,11 +641,9 @@ main(int argc, char **argv) break; case 'c': /* CPU */ - - if (optarg[0] == '*' && optarg[1] == '\0') { - for (hcpu = 0; hcpu < ncpu; hcpu++) - CPU_SET(hcpu, &cpumask); - } else + if (optarg[0] == '*' && optarg[1] == '\0') + CPU_COPY(&rootmask, &cpumask); + else pmcstat_get_cpumask(optarg, &cpumask); args.pa_flags |= FLAGS_HAS_CPUMASK; @@ -771,13 +768,9 @@ main(int argc, char **argv) else ev->ev_count = -1; - if (option == 'S' || option == 's') { - hcpu = sizeof(cpumask) * NBBY; - for (hcpu--; hcpu >= 0; hcpu--) - if (CPU_ISSET(hcpu, &cpumask)) - break; - ev->ev_cpu = hcpu; - } else + if (option == 'S' || option == 's') + ev->ev_cpu = CPU_FFS(&cpumask); + else ev->ev_cpu = PMC_CPU_ANY; ev->ev_flags = 0; @@ -804,11 +797,9 @@ main(int argc, char **argv) STAILQ_INSERT_TAIL(&args.pa_events, ev, ev_next); if (option == 's' || option == 'S') { - hcpu = CPU_ISSET(ev->ev_cpu, &cpumask); CPU_CLR(ev->ev_cpu, &cpumask); pmcstat_clone_event_descriptor(ev, &cpumask); - if (hcpu != 0) - CPU_SET(ev->ev_cpu, &cpumask); + CPU_SET(ev->ev_cpu, &cpumask); } break; diff --git a/usr.sbin/pw/pwupd.h b/usr.sbin/pw/pwupd.h index d6e39ce..1d13511 100644 --- a/usr.sbin/pw/pwupd.h +++ b/usr.sbin/pw/pwupd.h @@ -93,7 +93,6 @@ char * getpwpath(char const * file); int addgrent(struct group * grp); int delgrent(struct group * grp); int chggrent(char const * name, struct group * grp); -int editgroups(char *name, char **groups); int setgrdir(const char * dir); char * getgrpath(const char *file); |